{"version":3,"file":"courseeditor.min.js","sources":["https:\/\/www.alsg.org\/home\/course\/format\/amd\/src\/local\/courseeditor\/courseeditor.js"],"sourcesContent":["\/\/ This file is part of Moodle - http:\/\/moodle.org\/\n\/\/\n\/\/ Moodle is free software: you can redistribute it and\/or modify\n\/\/ it under the terms of the GNU General Public License as published by\n\/\/ the Free Software Foundation, either version 3 of the License, or\n\/\/ (at your option) any later version.\n\/\/\n\/\/ Moodle is distributed in the hope that it will be useful,\n\/\/ but WITHOUT ANY WARRANTY; without even the implied warranty of\n\/\/ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\/\/ GNU General Public License for more details.\n\/\/\n\/\/ You should have received a copy of the GNU General Public License\n\/\/ along with Moodle. If not, see .\n\nimport {Reactive} from 'core\/reactive';\nimport notification from 'core\/notification';\nimport Exporter from 'core_courseformat\/local\/courseeditor\/exporter';\nimport log from 'core\/log';\nimport ajax from 'core\/ajax';\nimport * as Storage from 'core\/sessionstorage';\n\n\/**\n * Main course editor module.\n *\n * All formats can register new components on this object to create new reactive\n * UI components that watch the current course state.\n *\n * @module core_courseformat\/local\/courseeditor\/courseeditor\n * @class core_courseformat\/local\/courseeditor\/courseeditor\n * @copyright 2021 Ferran Recio \n * @license http:\/\/www.gnu.org\/copyleft\/gpl.html GNU GPL v3 or later\n *\/\nexport default class extends Reactive {\n\n \/**\n * The current state cache key\n *\n * The state cache is considered dirty if the state changes from the last page or\n * if the page has editing mode on.\n *\n * @attribute stateKey\n * @type number|null\n * @default 1\n * @package\n *\/\n stateKey = 1;\n\n \/**\n * The current page section return\n * @attribute sectionReturn\n * @type number\n * @default 0\n *\/\n sectionReturn = 0;\n\n \/**\n * Set up the course editor when the page is ready.\n *\n * The course can only be loaded once per instance. Otherwise an error is thrown.\n *\n * The backend can inform the module of the current state key. This key changes every time some\n * update in the course affect the current user state. Some examples are:\n * - The course content has been edited\n * - The user marks some activity as completed\n * - The user collapses or uncollapses a section (it is stored as a user preference)\n *\n * @param {number} courseId course id\n * @param {string} serverStateKey the current backend course cache reference\n *\/\n async loadCourse(courseId, serverStateKey) {\n\n if (this.courseId) {\n throw new Error(`Cannot load ${courseId}, course already loaded with id ${this.courseId}`);\n }\n\n if (!serverStateKey) {\n \/\/ The server state key is not provided, we use a invalid statekey to force reloading.\n serverStateKey = `invalidStateKey_${Date.now()}`;\n }\n\n \/\/ Default view format setup.\n this._editing = false;\n this._supportscomponents = false;\n\n this.courseId = courseId;\n\n let stateData;\n\n const storeStateKey = Storage.get(`course\/${courseId}\/stateKey`);\n try {\n \/\/ Check if the backend state key is the same we have in our session storage.\n if (!this.isEditing && serverStateKey == storeStateKey) {\n stateData = JSON.parse(Storage.get(`course\/${courseId}\/staticState`));\n }\n if (!stateData) {\n stateData = await this.getServerCourseState();\n }\n\n } catch (error) {\n log.error(\"EXCEPTION RAISED WHILE INIT COURSE EDITOR\");\n log.error(error);\n return;\n }\n\n this.setInitialState(stateData);\n\n \/\/ In editing mode, the session cache is considered dirty always.\n if (this.isEditing) {\n this.stateKey = null;\n } else {\n \/\/ Check if the last state is the same as the cached one.\n const newState = JSON.stringify(stateData);\n const previousState = Storage.get(`course\/${courseId}\/staticState`);\n if (previousState !== newState || storeStateKey !== serverStateKey) {\n Storage.set(`course\/${courseId}\/staticState`, newState);\n Storage.set(`course\/${courseId}\/stateKey`, stateData?.course?.statekey ?? serverStateKey);\n }\n this.stateKey = Storage.get(`course\/${courseId}\/stateKey`);\n }\n }\n\n \/**\n * Setup the current view settings\n *\n * @param {Object} setup format, page and course settings\n * @param {boolean} setup.editing if the page is in edit mode\n * @param {boolean} setup.supportscomponents if the format supports components for content\n * @param {string} setup.cacherev the backend cached state revision\n *\/\n setViewFormat(setup) {\n this._editing = setup.editing ?? false;\n this._supportscomponents = setup.supportscomponents ?? false;\n }\n\n \/**\n * Load the current course state from the server.\n *\n * @returns {Object} the current course state\n *\/\n async getServerCourseState() {\n const courseState = await ajax.call([{\n methodname: 'core_courseformat_get_state',\n args: {\n courseid: this.courseId,\n }\n }])[0];\n\n const stateData = JSON.parse(courseState);\n\n return {\n course: {},\n section: [],\n cm: [],\n ...stateData,\n };\n }\n\n \/**\n * Return the current edit mode.\n *\n * Components should use this method to check if edit mode is active.\n *\n * @return {boolean} if edit is enabled\n *\/\n get isEditing() {\n return this._editing ?? false;\n }\n\n \/**\n * Return a data exporter to transform state part into mustache contexts.\n *\n * @return {Exporter} the exporter class\n *\/\n getExporter() {\n return new Exporter(this);\n }\n\n \/**\n * Return if the current course support components to refresh the content.\n *\n * @returns {boolean} if the current content support components\n *\/\n get supportComponents() {\n return this._supportscomponents ?? false;\n }\n\n \/**\n * Get a value from the course editor static storage if any.\n *\n * The course editor static storage uses the sessionStorage to store values from the\n * components. This is used to prevent unnecesary template loadings on every page. However,\n * the storage does not work if no sessionStorage can be used (in debug mode for example),\n * if the page is in editing mode or if the initial state change from the last page.\n *\n * @param {string} key the key to get\n * @return {boolean|string} the storage value or false if cannot be loaded\n *\/\n getStorageValue(key) {\n if (this.isEditing || !this.stateKey) {\n return false;\n }\n const dataJson = Storage.get(`course\/${this.courseId}\/${key}`);\n if (!dataJson) {\n return false;\n }\n \/\/ Check the stateKey.\n try {\n const data = JSON.parse(dataJson);\n if (data?.stateKey !== this.stateKey) {\n return false;\n }\n return data.value;\n } catch (error) {\n return false;\n }\n }\n\n \/**\n * Stores a value into the course editor static storage if available\n *\n * @param {String} key the key to store\n * @param {*} value the value to store (must be compatible with JSON,stringify)\n * @returns {boolean} true if the value is stored\n *\/\n setStorageValue(key, value) {\n \/\/ Values cannot be stored on edit mode.\n if (this.isEditing) {\n return false;\n }\n const data = {\n stateKey: this.stateKey,\n value,\n };\n return Storage.set(`course\/${this.courseId}\/${key}`, JSON.stringify(data));\n }\n\n \/**\n * Dispatch a change in the state.\n *\n * Usually reactive modules throw an error directly to the components when something\n * goes wrong. However, course editor can directly display a notification.\n *\n * @method dispatch\n * @param {mixed} args any number of params the mutation needs.\n *\/\n async dispatch(...args) {\n try {\n await super.dispatch(...args);\n } catch (error) {\n \/\/ Display error modal.\n notification.exception(error);\n \/\/ Force unlock all elements.\n super.dispatch('unlockAll');\n }\n }\n}\n"],"names":["Reactive","courseId","serverStateKey","this","Error","stateData","Date","now","_editing","_supportscomponents","storeStateKey","Storage","get","isEditing","JSON","parse","getServerCourseState","error","setInitialState","stateKey","newState","stringify","set","_stateData","course","_stateData$course","statekey","setViewFormat","setup","editing","supportscomponents","courseState","ajax","call","methodname","args","courseid","section","cm","getExporter","Exporter","supportComponents","getStorageValue","key","dataJson","data","value","setStorageValue","super","dispatch","exception"],"mappings":";;;;;;;;;;;g7BAiC6BA,qFAad,wCAQK,oBAgBCC,SAAUC,mBAEnBC,KAAKF,eACC,IAAIG,4BAAqBH,oDAA2CE,KAAKF,eAc\/EI,UAXCH,iBAEDA,yCAAoCI,KAAKC,aAIxCC,UAAW,OACXC,qBAAsB,OAEtBR,SAAWA,eAIVS,cAAgBC,QAAQC,qBAAcX,2BAGnCE,KAAKU,WAAaX,gBAAkBQ,gBACrCL,UAAYS,KAAKC,MAAMJ,QAAQC,qBAAcX,4BAE5CI,YACDA,gBAAkBF,KAAKa,wBAG7B,MAAOC,2BACDA,MAAM,+DACNA,MAAMA,eAITC,gBAAgBb,WAGjBF,KAAKU,eACAM,SAAW,SACb,OAEGC,SAAWN,KAAKO,UAAUhB,qEACVM,QAAQC,qBAAcX,4BACtBmB,UAAYV,gBAAkBR,eAChDS,QAAQW,qBAAcrB,yBAAwBmB,UAC9CT,QAAQW,qBAAcrB,uEAAqBI,2DAAAkB,WAAWC,2CAAXC,kBAAmBC,gEAAYxB,qBAEzEiB,SAAWR,QAAQC,qBAAcX,wBAY9C0B,cAAcC,qDACLpB,gCAAWoB,MAAMC,uDACjBpB,kDAAsBmB,MAAME,8GAS3BC,kBAAoBC,cAAKC,KAAK,CAAC,CACjCC,WAAY,8BACZC,KAAM,CACFC,SAAUjC,KAAKF,aAEnB,SAIG,CACHuB,OAAQ,GACRa,QAAS,GACTC,GAAI,MALUxB,KAAKC,MAAMgB,cAiB7BlB,iEACOV,KAAKK,mDAQhB+B,qBACW,IAAIC,kBAASrC,MAQpBsC,uFACOtC,KAAKM,4EAchBiC,gBAAgBC,QACRxC,KAAKU,YAAcV,KAAKgB,gBACjB,QAELyB,SAAWjC,QAAQC,qBAAcT,KAAKF,qBAAY0C,UACnDC,gBACM,YAIDC,KAAO\/B,KAAKC,MAAM6B,iBACpBC,MAAAA,YAAAA,KAAM1B,YAAahB,KAAKgB,UAGrB0B,KAAKC,MACd,MAAO7B,cACE,GAWf8B,gBAAgBJ,IAAKG,UAEb3C,KAAKU,iBACE,QAELgC,KAAO,CACT1B,SAAUhB,KAAKgB,SACf2B,MAAAA,cAEGnC,QAAQW,qBAAcnB,KAAKF,qBAAY0C,KAAO7B,KAAKO,UAAUwB,kCAc1DG,MAAMC,uBACd,MAAOhC,6BAEQiC,UAAUjC,aAEjBgC,SAAS"}