Added back button catching

This commit is contained in:
PMKuipers 2024-06-02 17:21:30 +02:00
parent 3d53966b5a
commit ebdb39c5ca
25 changed files with 24073 additions and 51 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
define("local_treestudyplan/util/browserbuttonevents",["exports","./debugger"],(function(_exports,_debugger){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.addBrowserButtonEvent=function(backwardCB){let forwardCB=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,reloadCB=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;debug.log("Registering navigation events",backwardCB,forwardCB,reloadCB);addEventListener("popstate",(e=>{const positionLastShown=Number(sessionStorage.getItem("positionLastShown"));let position=history.state;null===position&&(position=positionLastShown+1,history.replaceState(position,"")),sessionStorage.setItem("positionLastShown",String(position));const direction=Math.sign(position-positionLastShown);debug.log("Travel direction is "+direction),-1==direction&&backwardCB&&backwardCB(),1==direction&&forwardCB&&forwardCB(),0==direction&&reloadCB&&reloadCB()}))};const debug=new(_debugger=(obj=_debugger)&&obj.__esModule?obj:{default:obj}).default("browserbuttonevents")}));
//# sourceMappingURL=browserbuttonevents.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"browserbuttonevents.min.js","sources":["../../src/util/browserbuttonevents.js"],"sourcesContent":["/*eslint no-var: \"error\" */\n/*eslint no-unused-vars: \"off\" */\n/*eslint linebreak-style: \"off\" */\n/*eslint no-trailing-spaces: \"off\" */\n/*eslint-env es6*/\n\nimport Debugger from './debugger';\nconst debug = new Debugger(\"browserbuttonevents\");\n\n/**\n * \n * @param {function} backwardCB \n * @param {function} forwardCB \n * @param {function} reloadCB \n */\nexport function addBrowserButtonEvent(backwardCB, forwardCB = null, reloadCB = null) {\n debug.log(\"Registering navigation events\",backwardCB,forwardCB,reloadCB);\n const reorient = (e) => { // After travelling in the history stack\n const positionLastShown = Number( // If none, then zero\n sessionStorage.getItem( 'positionLastShown' ));\n// debug.log(\"Popstate event\",e,positionLastShown,history);\n let position = history.state; // Absolute position in stack\n if( position === null ) { // Meaning a new entry on the stack\n position = positionLastShown + 1; // Top of stack\n \n // (1) Stamp the entry with its own position in the stack\n history.replaceState( position, /*no title*/'' ); \n }\n \n // (2) Keep track of the last position shown\n sessionStorage.setItem( 'positionLastShown', String(position) );\n \n // (3) Discover the direction of travel by comparing the two\n const direction = Math.sign( position - positionLastShown );\n debug.log( 'Travel direction is ' + direction ); \n // One of backward (-1), reload (0) and forward (1)\n if (direction == -1 && backwardCB) {\n backwardCB();\n }\n if (direction == 1 && forwardCB) {\n forwardCB();\n }\n if (direction == 0 && reloadCB) {\n reloadCB();\n }\n };\n //addEventListener( 'pageshow', reorient );\n addEventListener( 'popstate', reorient ); // Travel in same page\n}"],"names":["backwardCB","forwardCB","reloadCB","debug","log","addEventListener","e","positionLastShown","Number","sessionStorage","getItem","position","history","state","replaceState","setItem","String","direction","Math","sign"],"mappings":"qNAesCA,gBAAYC,iEAAY,KAAMC,gEAAW,KAC3EC,MAAMC,IAAI,gCAAgCJ,WAAWC,UAAUC,UA+B/DG,iBAAkB,YA9BAC,UACRC,kBAAoBC,OACxBC,eAAeC,QAAS,0BAEtBC,SAAWC,QAAQC,MACN,OAAbF,WACAA,SAAWJ,kBAAoB,EAG/BK,QAAQE,aAAcH,SAAsB,KAIhDF,eAAeM,QAAS,oBAAqBC,OAAOL,iBAG9CM,UAAYC,KAAKC,KAAMR,SAAWJ,mBACxCJ,MAAMC,IAAK,uBAAyBa,YAElB,GAAdA,WAAmBjB,YACnBA,aAEa,GAAbiB,WAAkBhB,WAClBA,YAEa,GAAbgB,WAAkBf,UAClBA,qBApCNC,MAAQ,yEAAa"}

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/util/debugger",["exports","core/config"],(function(_exports,_config){var obj;return Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=function(handle){let output_enabled=_config.default.developerdebug;output_enabled?console.warn(`In development environment. Debugger output enabled for ${handle}`):console.warn(`In production environment. Debugger output disabled for ${handle}`);return{write(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.info.apply(console,args)}},info(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.info.apply(console,args)}},warn(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.warn.apply(console,args)}},error(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.error.apply(console,args)}},time(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.time.apply(console,args)}},timeEnd(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.timeEnd.apply(console,args)}},timeLog(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.timeLog.apply(console,args)}},timeStamp(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.timeStamp.apply(console,args)}},enable:function(){output_enabled=!0},disable:function(){output_enabled=!1}}},_config=(obj=_config)&&obj.__esModule?obj:{default:obj},_exports.default})); define("local_treestudyplan/util/debugger",["exports","core/config"],(function(_exports,_config){var obj;return Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=function(handle){let output_enabled=_config.default.developerdebug;output_enabled?console.warn(`In development environment. Debugger output enabled for ${handle}`):console.warn(`In production environment. Debugger output disabled for ${handle}`);return{write(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.info.apply(console,args)}},log(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.log.apply(console,args)}},info(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.info.apply(console,args)}},warn(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.warn.apply(console,args)}},error(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.error.apply(console,args)}},time(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.time.apply(console,args)}},timeEnd(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.timeEnd.apply(console,args)}},timeLog(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.timeLog.apply(console,args)}},timeStamp(){if(output_enabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.timeStamp.apply(console,args)}},enable:function(){output_enabled=!0},disable:function(){output_enabled=!1}}},_config=(obj=_config)&&obj.__esModule?obj:{default:obj},_exports.default}));
//# sourceMappingURL=debugger.min.js.map //# sourceMappingURL=debugger.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"debugger.min.js","sources":["../../src/util/debugger.js"],"sourcesContent":["/*eslint no-var: \"error\"*/\n/*eslint no-console: \"off\"*/\n/*eslint-env es6*/\n\nimport Config from \"core/config\";\n\n/**\n * Start a new debugger\n * @param {*} handle The string to attach to all messages from this debugger\n * @returns Debugger object\n */\nexport default function (handle) {\n let output_enabled = Config.developerdebug;\n if(output_enabled){\n console.warn(`In development environment. Debugger output enabled for ${handle}`);\n } else {\n console.warn(`In production environment. Debugger output disabled for ${handle}`);\n }\n\n return {\n write() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.info.apply(console, args);\n }\n },\n info() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.info.apply(console, args);\n }\n },\n warn() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.warn.apply(console, args);\n }\n },\n error() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.error.apply(console, args);\n }\n },\n time() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.time.apply(console, args);\n }\n },\n timeEnd() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.timeEnd.apply(console, args);\n }\n },\n timeLog() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.timeLog.apply(console, args);\n }\n },\n timeStamp() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.timeStamp.apply(console, args);\n }\n },\n enable: function debugger_enable() {\n output_enabled = true;\n },\n\n disable: function debugger_disable() {\n output_enabled = false;\n }\n };\n\n}\n"],"names":["handle","output_enabled","Config","developerdebug","console","warn","write","args","Array","prototype","slice","call","arguments","unshift","info","apply","error","time","timeEnd","timeLog","timeStamp","enable","disable"],"mappings":"kMAWyBA,YACjBC,eAAiBC,gBAAOC,eACzBF,eACCG,QAAQC,KAAM,2DAA0DL,UAExEI,QAAQC,KAAM,2DAA0DL,gBAGrE,CACHM,WACQL,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQU,KAAKC,MAAMX,QAASG,QAGpCO,UACQb,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQU,KAAKC,MAAMX,QAASG,QAGpCF,UACQJ,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQC,KAAKU,MAAMX,QAASG,QAGpCS,WACQf,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQY,MAAMD,MAAMX,QAASG,QAGrCU,UACQhB,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQa,KAAKF,MAAMX,QAASG,QAGpCW,aACQjB,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQc,QAAQH,MAAMX,QAASG,QAGvCY,aACQlB,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQe,QAAQJ,MAAMX,QAASG,QAGvCa,eACQnB,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQgB,UAAUL,MAAMX,QAASG,QAGzCc,OAAQ,WACJpB,gBAAiB,GAGrBqB,QAAS,WACLrB,gBAAiB"} {"version":3,"file":"debugger.min.js","sources":["../../src/util/debugger.js"],"sourcesContent":["/*eslint no-var: \"error\"*/\n/*eslint no-console: \"off\"*/\n/*eslint-env es6*/\n\nimport Config from \"core/config\";\n\n/**\n * Start a new debugger\n * @param {*} handle The string to attach to all messages from this debugger\n * @returns Debugger object\n */\nexport default function (handle) {\n let output_enabled = Config.developerdebug;\n if(output_enabled){\n console.warn(`In development environment. Debugger output enabled for ${handle}`);\n } else {\n console.warn(`In production environment. Debugger output disabled for ${handle}`);\n }\n\n return {\n write() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.info.apply(console, args);\n }\n },\n log() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.log.apply(console, args);\n }\n },\n info() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.info.apply(console, args);\n }\n },\n warn() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.warn.apply(console, args);\n }\n },\n error() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.error.apply(console, args);\n }\n },\n time() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.time.apply(console, args);\n }\n },\n timeEnd() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.timeEnd.apply(console, args);\n }\n },\n timeLog() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.timeLog.apply(console, args);\n }\n },\n timeStamp() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.timeStamp.apply(console, args);\n }\n },\n enable: function debugger_enable() {\n output_enabled = true;\n },\n\n disable: function debugger_disable() {\n output_enabled = false;\n }\n };\n\n}\n"],"names":["handle","output_enabled","Config","developerdebug","console","warn","write","args","Array","prototype","slice","call","arguments","unshift","info","apply","log","error","time","timeEnd","timeLog","timeStamp","enable","disable"],"mappings":"kMAWyBA,YACjBC,eAAiBC,gBAAOC,eACzBF,eACCG,QAAQC,KAAM,2DAA0DL,UAExEI,QAAQC,KAAM,2DAA0DL,gBAGrE,CACHM,WACQL,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQU,KAAKC,MAAMX,QAASG,QAGpCS,SACQf,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQY,IAAID,MAAMX,QAASG,QAGnCO,UACQb,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQU,KAAKC,MAAMX,QAASG,QAGpCF,UACQJ,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQC,KAAKU,MAAMX,QAASG,QAGpCU,WACQhB,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQa,MAAMF,MAAMX,QAASG,QAGrCW,UACQjB,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQc,KAAKH,MAAMX,QAASG,QAGpCY,aACQlB,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQe,QAAQJ,MAAMX,QAASG,QAGvCa,aACQnB,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQgB,QAAQL,MAAMX,QAASG,QAGvCc,eACQpB,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQiB,UAAUN,MAAMX,QAASG,QAGzCe,OAAQ,WACJrB,gBAAiB,GAGrBsB,QAAS,WACLtB,gBAAiB"}

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/util/premium",["exports","core/ajax","core/notification"],(function(_exports,_ajax,_notification){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.premiumenabled=function(){return!!premiumstatus().enabled},_notification=(obj=_notification)&&obj.__esModule?obj:{default:obj};let premiumstatus_cache=null;function premiumstatus(){return premiumstatus_cache||(0,_ajax.call)([{methodname:"local_treestudyplan_premiumstatus",args:{}}])[0].then((function(response){premiumstatus_cache=response})).catch(_notification.default.exception),premiumstatus_cache}premiumstatus()})); define("local_treestudyplan/util/premium",["exports","core/ajax","core/notification"],(function(_exports,_ajax,_notification){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.premiumenabled=function(){const premium=premiumstatus();return!premium||!!premium.enabled},_notification=(obj=_notification)&&obj.__esModule?obj:{default:obj};let premiumstatus_cache=null;function premiumstatus(){return premiumstatus_cache||(0,_ajax.call)([{methodname:"local_treestudyplan_premiumstatus",args:{}}])[0].then((function(response){premiumstatus_cache=response})).catch(_notification.default.exception),premiumstatus_cache}premiumstatus()}));
//# sourceMappingURL=premium.min.js.map //# sourceMappingURL=premium.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"premium.min.js","sources":["../../src/util/premium.js"],"sourcesContent":["/*eslint no-var: \"error\" */\n/*eslint-env es6*/\n\nimport {call} from 'core/ajax';\nimport notification from 'core/notification';\n\n// Prepare default value.\nlet premiumstatus_cache = null;\n\n/**\n * Check if premium status is enabled.\n * @returns {Bool} True/False\n */\nexport function premiumenabled (){\n const premium = premiumstatus();\n return (premium.enabled)?true:false;\n}\n\n/**\n * Get premium status object\n * @returns {Object} The premium status object\n */\nfunction premiumstatus() {\n if (!premiumstatus_cache) {\n // Retrieve premium status if needed.\n call([{\n methodname: 'local_treestudyplan_premiumstatus',\n args: {}\n }])[0].then(function(response){\n premiumstatus_cache = response;\n }).catch(notification.exception);\n }\n return premiumstatus_cache;\n}\n\n// Preload premium status.\npremiumstatus();"],"names":["premiumstatus","enabled","premiumstatus_cache","methodname","args","then","response","catch","notification","exception"],"mappings":"yOAcoBA,gBACAC,iFARhBC,oBAAsB,cAejBF,uBACAE,oCAEI,CAAC,CACFC,WAAY,oCACZC,KAAM,MACN,GAAGC,MAAK,SAASC,UACjBJ,oBAAsBI,YACvBC,MAAMC,sBAAaC,WAEnBP,oBAIXF"} {"version":3,"file":"premium.min.js","sources":["../../src/util/premium.js"],"sourcesContent":["/*eslint no-var: \"error\" */\n/*eslint-env es6*/\n\nimport {call} from 'core/ajax';\nimport notification from 'core/notification';\n\n// Prepare default value.\nlet premiumstatus_cache = null;\n\n/**\n * Check if premium status is enabled.\n * @returns {Bool} True/False\n */\nexport function premiumenabled (){\n const premium = premiumstatus();\n if (premium) {\n return (premium.enabled)?true:false;\n } else {\n return true; // Temporarily return true, that is easier than going full async.\n }\n}\n\n/**\n * Get premium status object\n * @returns {Object} The premium status object\n */\nfunction premiumstatus() {\n if (!premiumstatus_cache) {\n // Retrieve premium status if needed.\n call([{\n methodname: 'local_treestudyplan_premiumstatus',\n args: {}\n }])[0].then(function(response){\n premiumstatus_cache = response;\n }).catch(notification.exception);\n }\n return premiumstatus_cache;\n}\n\n// Preload premium status.\npremiumstatus();"],"names":["premium","premiumstatus","enabled","premiumstatus_cache","methodname","args","then","response","catch","notification","exception"],"mappings":"uOAcUA,QAAUC,uBACZD,WACQA,QAAQE,iFATpBC,oBAAsB,cAmBjBF,uBACAE,oCAEI,CAAC,CACFC,WAAY,oCACZC,KAAM,MACN,GAAGC,MAAK,SAASC,UACjBJ,oBAAsBI,YACvBC,MAAMC,sBAAaC,WAEnBP,oBAIXF"}

11912
amd/build/vue/vue.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,6 +15,7 @@ import Debugger from './util/debugger';
import {load_strings} from './util/string-helper'; import {load_strings} from './util/string-helper';
import {ProcessStudyplan} from './studyplan-processor'; import {ProcessStudyplan} from './studyplan-processor';
import {studyplanTiming} from './util/date-helper'; import {studyplanTiming} from './util/date-helper';
import {addBrowserButtonEvent} from './util/browserbuttonevents';
import EditorComponents from './studyplan-editor-components'; import EditorComponents from './studyplan-editor-components';
Vue.use(EditorComponents); Vue.use(EditorComponents);
@ -50,6 +51,10 @@ export function init() {
let app = new Vue({ let app = new Vue({
el: '#root', el: '#root',
data: { data: {
selected: {
planid: 0,
studentid: 0,
},
displayedstudyplan: null, displayedstudyplan: null,
activestudyplan: null, activestudyplan: null,
associatedstudents: [], associatedstudents: [],
@ -88,32 +93,73 @@ export function init() {
const hash = window.location.hash.replace('#',''); const hash = window.location.hash.replace('#','');
const parts = hash.split("-"); const parts = hash.split("-");
if(!!parts && parts.length > 0){ if(!!parts && parts.length > 0 && parts[0] != ''){
for(let idx in app.studyplans){ for(let idx in app.studyplans){
if(app.studyplans[idx].id == parts[0]){ if(app.studyplans[idx].id == parts[0]){
app.selectStudyplan(app.studyplans[idx],parts[1]); app.selectStudyplan(app.studyplans[idx],parts[1],false);
break; break;
} }
} }
} }
}).catch(notification.exception); }).catch(notification.exception);
addBrowserButtonEvent(this.navChanged, this.navChanged);
}, },
computed: { computed: {
}, },
methods: { methods: {
closeStudyplan() { navChanged() {
const hash = window.location.hash.replace('#','');
const parts = hash.split("-");
debug.log("Navigation changed",hash,parts);
if(!!parts && parts.length > 0){
const planid = Number(parts[0]);
const studentid = (parts.length > 1)?Number(parts[1]):0;
debug.log("Selected ids",planid,studentid,this.selected.planid,this.selected.studentid);
if ( planid == 0) {
if (planid != this.selected.planid) {
this.closeStudyplan(false);
}
} else if ( this.selected.planid != planid || (studentid == 0 && this.selected.studentid != 0) ) {
debug.info ("Requested plan changed - loading studyplan");
for(let idx in app.studyplans){
const plan = this.studyplans[idx];
if(Number(plan.id) == planid){
this.selectStudyplan(plan,studentid,false);
break;
}
}
} else if (this.selected.studentid != studentid) {
for(const group of app.associatedstudents) {
for(const student of group.users){
if(Number(student.id) == studentid){
app.showStudentView(student,false);
break;
}
}
}
}
}
},
closeStudyplan(updatehash=true) {
app.selected.planid = 0;
app.selected.studentid = 0;
app.activestudyplan = null; app.activestudyplan = null;
app.associatedstudents = []; app.associatedstudents = [];
app.studentstudyplan = []; app.studentstudyplan = [];
app.displayedstudyplan = null; app.displayedstudyplan = null;
window.location.hash = ''; if (updatehash) {
window.location.hash = '';
}
}, },
selectStudyplan(studyplan,studentid){ selectStudyplan(studyplan,studentid,updatehash=true){
app.selected.planid = Number(studyplan.id);
app.selected.studentid = studentid?Number(studentid):0;
// fetch studyplan // fetch studyplan
const self = this; const self = this;
self.loadingstudyplan = true; self.loadingstudyplan = true;
self.activestudyplan = null;
self.associatedstudents = []; self.associatedstudents = [];
self.selectedstudent = null; self.selectedstudent = null;
self.studentstudyplan = null; self.studentstudyplan = null;
@ -122,32 +168,42 @@ export function init() {
args: { id: studyplan.id} args: { id: studyplan.id}
}])[0].then(function(response){ }])[0].then(function(response){
self.activestudyplan = ProcessStudyplan(response,true); self.activestudyplan = ProcessStudyplan(response,true);
self.displayedstudyplan = self.activestudyplan;
self.loadingstudyplan = false;
window.location.hash = self.activestudyplan.id;
call([{ call([{
methodname: 'local_treestudyplan_all_associated_grouped', methodname: 'local_treestudyplan_all_associated_grouped',
args: { studyplan_id: studyplan.id} args: { studyplan_id: studyplan.id}
}])[0].then(function(response){ }])[0].then(function(response){
self.associatedstudents = response; self.associatedstudents = response;
let foundstudent = false;
if(studentid){ if(studentid){
for(const group of self.associatedstudents) { for(const group of self.associatedstudents) {
for(const student of group.users){ for(const student of group.users){
if(student.id == studentid){ if(student.id == studentid){
foundstudent = true;
self.showStudentView(student); self.showStudentView(student);
break; break;
} }
} }
} }
} else { }
if (!foundstudent) {
// Select first student available. // Select first student available.
for(const group of self.associatedstudents) { for(const group of self.associatedstudents) {
for(const student of group.users){ for(const student of group.users){
foundstudent = true;
self.showStudentView(student); self.showStudentView(student);
break; break;
} }
} }
} }
if (!foundstudent) { // update hash with just the studyplan if no student was available for display
app.selected.studentid = 0;
if (updatehash) {
window.location.hash = app.activestudyplan.id;
}
self.displayedstudyplan = self.activestudyplan;
self.loadingstudyplan = false;
}
}).catch(notification.exception); }).catch(notification.exception);
}).catch(function(error){ }).catch(function(error){
@ -155,10 +211,11 @@ export function init() {
app.loadingstudyplan = false; app.loadingstudyplan = false;
}); });
}, },
showStudentView(student){ showStudentView(student,updatehash=true){
app.selectedstudent = student; app.selected.studentid = student?Number(student.id):0;
app.studentstudyplan = null;
if (student) { if (student) {
app.selectedstudent = student;
app.studentstudyplan = null;
app.loadingstudyplan = true; app.loadingstudyplan = true;
call([{ call([{
methodname: 'local_treestudyplan_get_user_studyplan', methodname: 'local_treestudyplan_get_user_studyplan',
@ -167,18 +224,26 @@ export function init() {
app.studentstudyplan = ProcessStudyplan(response,false); app.studentstudyplan = ProcessStudyplan(response,false);
app.displayedstudyplan = app.studentstudyplan; app.displayedstudyplan = app.studentstudyplan;
app.loadingstudyplan = false; app.loadingstudyplan = false;
window.location.hash = app.activestudyplan.id + "-" + student.id; if (updatehash) {
window.location.hash = app.activestudyplan.id + "-" + student.id;
}
}).catch(function(error){ }).catch(function(error){
notification.exception(error); notification.exception(error);
app.loadingstudyplan = false; app.loadingstudyplan = false;
}); });
} else {
this.showOverview(updatehash);
} }
}, },
showOverview(){ showOverview(updatehash=true){
debug.info("Switch to overview",updatehash);
app.selected.studentid = 0;
app.selectedstudent = null; app.selectedstudent = null;
app.studentstudyplan = null; app.studentstudyplan = null;
app.displayedstudyplan = app.activestudyplan; app.displayedstudyplan = app.activestudyplan;
window.location.hash = app.activestudyplan.id; if (updatehash) {
window.location.hash = app.activestudyplan.id;
}
} }
}, },

View File

@ -23,6 +23,7 @@ Vue.use(TSComponents);
import ModalComponents from './modedit-modal'; import ModalComponents from './modedit-modal';
Vue.use(ModalComponents); Vue.use(ModalComponents);
import Debugger from './util/debugger'; import Debugger from './util/debugger';
import {addBrowserButtonEvent} from './util/browserbuttonevents';
import {load_strings} from './util/string-helper'; import {load_strings} from './util/string-helper';
import {ProcessStudyplan} from './studyplan-processor'; import {ProcessStudyplan} from './studyplan-processor';
@ -133,6 +134,10 @@ export function init(contextid,categoryid,options) {
}, },
mounted() { mounted() {
this.initialize(); this.initialize();
addBrowserButtonEvent(this.backPressed);
},
beforeunmount() {
}, },
computed: { computed: {
premiumenabled, premiumenabled,
@ -150,6 +155,13 @@ export function init(contextid,categoryid,options) {
}, },
methods: { methods: {
backPressed() {
debug.log("Back button pressed");
if (app.activestudyplan) {
debug.log("Closing studyplan");
this.closeStudyplan();
}
},
initialize() { initialize() {
call([{ call([{
methodname: 'local_treestudyplan_list_studyplans', methodname: 'local_treestudyplan_list_studyplans',

View File

@ -15,6 +15,7 @@ import Debugger from './util/debugger';
import {load_strings} from './util/string-helper'; import {load_strings} from './util/string-helper';
import {ProcessStudyplan} from './studyplan-processor'; import {ProcessStudyplan} from './studyplan-processor';
import {studyplanTiming} from './util/date-helper'; import {studyplanTiming} from './util/date-helper';
import {addBrowserButtonEvent} from './util/browserbuttonevents';
import RVComponents from './report-viewer-components'; import RVComponents from './report-viewer-components';
Vue.use(RVComponents); Vue.use(RVComponents);
@ -53,6 +54,10 @@ export function init(contextid,categoryid) {
let app = new Vue({ let app = new Vue({
el: '#root', el: '#root',
data: { data: {
selected: {
planid: 0,
studentid: 0,
},
displayedstudyplan: null, displayedstudyplan: null,
activestudyplan: null, activestudyplan: null,
associatedstudents: [], associatedstudents: [],
@ -90,7 +95,7 @@ export function init(contextid,categoryid) {
const hash = window.location.hash.replace('#',''); const hash = window.location.hash.replace('#','');
const parts = hash.split("-"); const parts = hash.split("-");
if(!!parts && parts.length > 0){ if(!!parts && parts.length > 0 && parts[0] != ''){
for(let idx in app.studyplans){ for(let idx in app.studyplans){
if(app.studyplans[idx].id == parts[0]){ if(app.studyplans[idx].id == parts[0]){
app.selectStudyplan(app.studyplans[idx],parts[1]); app.selectStudyplan(app.studyplans[idx],parts[1]);
@ -112,6 +117,7 @@ export function init(contextid,categoryid) {
} }
app.usedcontexts = contexts; app.usedcontexts = contexts;
}).catch(notification.exception); }).catch(notification.exception);
addBrowserButtonEvent(this.navChanged, this.navChanged);
}, },
computed: { computed: {
dropdown_title(){ dropdown_title(){
@ -127,6 +133,41 @@ export function init(contextid,categoryid) {
} }
}, },
methods: { methods: {
navChanged() {
const hash = window.location.hash.replace('#','');
const parts = hash.split("-");
debug.log("Navigation changed",hash,parts);
if(!!parts && parts.length > 0){
const planid = Number(parts[0]);
const studentid = (parts.length > 1)?Number(parts[1]):0;
debug.log("Selected ids",planid,studentid,this.selected.planid,this.selected.studentid);
if ( planid == 0) {
if (planid != this.selected.planid) {
this.closeStudyplan(false);
}
} else if ( this.selected.planid != planid || (studentid == 0 && this.selected.studentid != 0) ) {
debug.info ("Requested plan changed - loading studyplan");
for(let idx in app.studyplans){
const plan = this.studyplans[idx];
if(Number(plan.id) == planid){
this.selectStudyplan(plan,studentid,false);
break;
}
}
} else if (this.selected.studentid != studentid) {
for(const group of app.associatedstudents) {
for(const student of group.users){
if(Number(student.id) == studentid){
app.showStudentView(student,false);
break;
}
}
}
}
}
},
switchContext(ctxid){ switchContext(ctxid){
const params = new URLSearchParams(location.search); const params = new URLSearchParams(location.search);
params.delete('categoryid'); params.delete('categoryid');
@ -136,18 +177,23 @@ export function init(contextid,categoryid) {
window.location.href = window.location.pathname + "?" + params.toString(); window.location.href = window.location.pathname + "?" + params.toString();
},50); },50);
}, },
closeStudyplan() { closeStudyplan(updatehash=true) {
app.selected.planid = 0;
app.selected.studentid = 0;
app.activestudyplan = null; app.activestudyplan = null;
app.associatedstudents = []; app.associatedstudents = [];
app.studentstudyplan = []; app.studentstudyplan = [];
app.displayedstudyplan = null; app.displayedstudyplan = null;
window.location.hash = ''; if (updatehash) {
window.location.hash = '';
}
}, },
selectStudyplan(studyplan,studentid){ selectStudyplan(studyplan,studentid,updatehash=true){
app.selected.planid = Number(studyplan.id);
app.selected.studentid = studentid?Number(studentid):0;
// fetch studyplan // fetch studyplan
app.loadingstudyplan = true; app.loadingstudyplan = true;
app.activestudyplan = null;
app.associatedstudents = []; app.associatedstudents = [];
app.selectedstudent = null; app.selectedstudent = null;
app.studentstudyplan = null; app.studentstudyplan = null;
@ -156,24 +202,32 @@ export function init(contextid,categoryid) {
args: { id: studyplan.id} args: { id: studyplan.id}
}])[0].then(function(response){ }])[0].then(function(response){
app.activestudyplan = ProcessStudyplan(response,true); app.activestudyplan = ProcessStudyplan(response,true);
app.displayedstudyplan = app.activestudyplan;
app.loadingstudyplan = false;
window.location.hash = app.activestudyplan.id;
call([{ call([{
methodname: 'local_treestudyplan_all_associated_grouped', methodname: 'local_treestudyplan_all_associated_grouped',
args: { studyplan_id: studyplan.id} args: { studyplan_id: studyplan.id}
}])[0].then(function(response){ }])[0].then(function(response){
app.associatedstudents = response; app.associatedstudents = response;
let foundstudent = false;
if(studentid){ if(studentid){
for(const group of app.associatedstudents) { for(const group of app.associatedstudents) {
for(const student of group.users){ for(const student of group.users){
if(student.id == studentid){ if(student.id == studentid){
app.showStudentView(student); foundstudent = true;
app.showStudentView(student,updatehash);
break; break;
} }
} }
} }
} }
if (!foundstudent) {
app.selected.studentid = 0;
if (updatehash) {
window.location.hash = app.activestudyplan.id;
}
app.displayedstudyplan = app.activestudyplan;
app.loadingstudyplan = false;
}
}).catch(notification.exception); }).catch(notification.exception);
}).catch(function(error){ }).catch(function(error){
@ -181,30 +235,38 @@ export function init(contextid,categoryid) {
app.loadingstudyplan = false; app.loadingstudyplan = false;
}); });
}, },
showStudentView(student){ showStudentView(student,updatehash=true){
app.selectedstudent = student; app.selected.studentid = student?Number(student.id):0;
app.studentstudyplan = null;
if (student) { if (student) {
app.selectedstudent = student;
app.studentstudyplan = null;
app.loadingstudyplan = true; app.loadingstudyplan = true;
call([{ call([{
methodname: 'local_treestudyplan_get_user_studyplan', methodname: 'local_treestudyplan_get_user_studyplan',
args: { userid: student.id, studyplanid: app.activestudyplan.id} args: { userid: student.id, studyplanid: app.selected.planid}
}])[0].then(function(response){ }])[0].then(function(response){
app.studentstudyplan = ProcessStudyplan(response,false); app.studentstudyplan = ProcessStudyplan(response,false);
app.displayedstudyplan = app.studentstudyplan; app.displayedstudyplan = app.studentstudyplan;
app.loadingstudyplan = false; app.loadingstudyplan = false;
window.location.hash = app.activestudyplan.id + "-" + student.id; if (updatehash) {
window.location.hash = app.activestudyplan.id + "-" + student.id;
}
}).catch(function(error){ }).catch(function(error){
notification.exception(error); notification.exception(error);
app.loadingstudyplan = false; app.loadingstudyplan = false;
}); });
} else {
this.showOverview(updatehash);
} }
}, },
showOverview(){ showOverview(updatehash=true){
app.selected.studentid = 0;
app.selectedstudent = null; app.selectedstudent = null;
app.studentstudyplan = null; app.studentstudyplan = null;
app.displayedstudyplan = app.activestudyplan; app.displayedstudyplan = app.activestudyplan;
window.location.hash = app.activestudyplan.id; if (updatehash) {
window.location.hash = app.activestudyplan.id;
}
} }
}, },

View File

@ -10,6 +10,7 @@ import {SimpleLine} from './simpleline/simpleline';
import {get_strings} from 'core/str'; import {get_strings} from 'core/str';
import {load_strings} from './util/string-helper'; import {load_strings} from './util/string-helper';
import {format_date, format_datetime, studyplanPageTiming,studyplanTiming} from './util/date-helper'; import {format_date, format_datetime, studyplanPageTiming,studyplanTiming} from './util/date-helper';
import {addBrowserButtonEvent} from './util/browserbuttonevents';
import {call} from 'core/ajax'; import {call} from 'core/ajax';
import notification from 'core/notification'; import notification from 'core/notification';
import {svgarcpath} from './util/svgarc'; import {svgarcpath} from './util/svgarc';
@ -384,9 +385,17 @@ export default {
}, },
mounted() { mounted() {
this.loadStudyplans(); this.loadStudyplans();
addBrowserButtonEvent(this.backPressed);
}, },
methods: { methods: {
backPressed() {
debug.log("Back button pressed");
if (this.selectedstudyplan) {
debug.log("Closing studyplan");
this.deselectStudyplan();
}
},
call_args(o) { call_args(o) {
const args = {}; const args = {};
if (typeof o == 'object' && !Array.isArray(o) && o !== null) { if (typeof o == 'object' && !Array.isArray(o) && o !== null) {

View File

@ -0,0 +1,49 @@
/*eslint no-var: "error" */
/*eslint no-unused-vars: "off" */
/*eslint linebreak-style: "off" */
/*eslint no-trailing-spaces: "off" */
/*eslint-env es6*/
import Debugger from './debugger';
const debug = new Debugger("browserbuttonevents");
/**
*
* @param {function} backwardCB
* @param {function} forwardCB
* @param {function} reloadCB
*/
export function addBrowserButtonEvent(backwardCB, forwardCB = null, reloadCB = null) {
debug.log("Registering navigation events",backwardCB,forwardCB,reloadCB);
const reorient = (e) => { // After travelling in the history stack
const positionLastShown = Number( // If none, then zero
sessionStorage.getItem( 'positionLastShown' ));
// debug.log("Popstate event",e,positionLastShown,history);
let position = history.state; // Absolute position in stack
if( position === null ) { // Meaning a new entry on the stack
position = positionLastShown + 1; // Top of stack
// (1) Stamp the entry with its own position in the stack
history.replaceState( position, /*no title*/'' );
}
// (2) Keep track of the last position shown
sessionStorage.setItem( 'positionLastShown', String(position) );
// (3) Discover the direction of travel by comparing the two
const direction = Math.sign( position - positionLastShown );
debug.log( 'Travel direction is ' + direction );
// One of backward (-1), reload (0) and forward (1)
if (direction == -1 && backwardCB) {
backwardCB();
}
if (direction == 1 && forwardCB) {
forwardCB();
}
if (direction == 0 && reloadCB) {
reloadCB();
}
};
//addEventListener( 'pageshow', reorient );
addEventListener( 'popstate', reorient ); // Travel in same page
}

View File

@ -25,6 +25,13 @@ export default function (handle) {
console.info.apply(console, args); console.info.apply(console, args);
} }
}, },
log() {
if (output_enabled) {
let args = Array.prototype.slice.call(arguments);
args.unshift(handle + ": ");
console.log.apply(console, args);
}
},
info() { info() {
if (output_enabled) { if (output_enabled) {
let args = Array.prototype.slice.call(arguments); let args = Array.prototype.slice.call(arguments);

View File

@ -13,7 +13,11 @@ let premiumstatus_cache = null;
*/ */
export function premiumenabled (){ export function premiumenabled (){
const premium = premiumstatus(); const premium = premiumstatus();
return (premium.enabled)?true:false; if (premium) {
return (premium.enabled)?true:false;
} else {
return true; // Temporarily return true, that is easier than going full async.
}
} }
/** /**

File diff suppressed because one or more lines are too long

View File

@ -22,7 +22,7 @@
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
$plugin->component = 'local_treestudyplan'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494). $plugin->component = 'local_treestudyplan'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494).
$plugin->version = 2024053103; // YYYYMMDDHH (year, month, day, iteration). $plugin->version = 2024060200; // YYYYMMDDHH (year, month, day, iteration).
$plugin->requires = 2021051700; // YYYYMMDDHH (This is the release version for Moodle 3.11). $plugin->requires = 2021051700; // YYYYMMDDHH (This is the release version for Moodle 3.11).
$plugin->release = "1.3.0"; $plugin->release = "1.3.0";