{"version":3,"file":"loader.min.js","sources":["https:\/\/lms.svhs.co\/lib\/amd\/src\/local\/templates\/loader.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 $ from 'jquery';\nimport ajax from 'core\/ajax';\nimport * as str from 'core\/str';\nimport * as config from 'core\/config';\nimport mustache from 'core\/mustache';\nimport storage from 'core\/localstorage';\nimport {getNormalisedComponent} from 'core\/utils';\n\n\/**\n * Template this.\n *\n * @module core\/local\/templates\/loader\n * @copyright 2023 Andrew Lyons \n * @license http:\/\/www.gnu.org\/copyleft\/gpl.html GNU GPL v3 or later\n * @since 4.3\n *\/\nexport default class Loader {\n \/** @var {String} themeName for the current render *\/\n currentThemeName = '';\n\n \/** @var {Object[]} loadTemplateBuffer - List of templates to be loaded *\/\n static loadTemplateBuffer = [];\n\n \/** @var {Bool} isLoadingTemplates - Whether templates are currently being loaded *\/\n static isLoadingTemplates = false;\n\n \/** @var {Map} templateCache - Cache of already loaded template strings *\/\n static templateCache = new Map();\n\n \/** @var {Promise[]} templatePromises - Cache of already loaded template promises *\/\n static templatePromises = {};\n\n \/** @var {Promise[]} cachePartialPromises - Cache of already loaded template partial promises *\/\n static cachePartialPromises = [];\n\n \/**\n * A helper to get the search key\n *\n * @param {string} theme\n * @param {string} templateName\n * @returns {string}\n *\/\n static getSearchKey(theme, templateName) {\n return `${theme}\/${templateName}`;\n }\n\n \/**\n * Load a template.\n *\n * @method getTemplate\n * @param {string} templateName - should consist of the component and the name of the template like this:\n * core\/menu (lib\/templates\/menu.mustache) or\n * tool_bananas\/yellow (admin\/tool\/bananas\/templates\/yellow.mustache)\n * @param {string} [themeName=config.theme] - The theme to load the template from\n * @return {Promise} JQuery promise object resolved when the template has been fetched.\n *\/\n static getTemplate(templateName, themeName = config.theme) {\n const searchKey = this.getSearchKey(themeName, templateName);\n\n \/\/ If we haven't already seen this template then buffer it.\n const cachedPromise = this.getTemplatePromiseFromCache(searchKey);\n if (cachedPromise) {\n return cachedPromise;\n }\n\n \/\/ Check the buffer to see if this template has already been added.\n const existingBufferRecords = this.loadTemplateBuffer.filter((record) => record.searchKey === searchKey);\n if (existingBufferRecords.length) {\n \/\/ This template is already in the buffer so just return the existing\n \/\/ promise. No need to add it to the buffer again.\n return existingBufferRecords[0].deferred.promise();\n }\n\n \/\/ This is the first time this has been requested so let's add it to the buffer\n \/\/ to be loaded.\n const parts = templateName.split('\/');\n const component = getNormalisedComponent(parts.shift());\n const name = parts.join('\/');\n const deferred = $.Deferred();\n\n \/\/ Add this template to the buffer to be loaded.\n this.loadTemplateBuffer.push({\n component,\n name,\n theme: themeName,\n searchKey,\n deferred,\n });\n\n \/\/ We know there is at least one thing in the buffer so kick off a processing run.\n this.processLoadTemplateBuffer();\n return deferred.promise();\n }\n\n \/**\n * Store a template in the cache.\n *\n * @param {string} searchKey\n * @param {string} templateSource\n *\/\n static setTemplateInCache(searchKey, templateSource) {\n \/\/ Cache all of the dependent templates because we'll need them to render\n \/\/ the requested template.\n this.templateCache.set(searchKey, templateSource);\n }\n\n \/**\n * Fetch a template from the cache.\n *\n * @param {string} searchKey\n * @returns {string}\n *\/\n static getTemplateFromCache(searchKey) {\n return this.templateCache.get(searchKey);\n }\n\n \/**\n * Check whether a template is in the cache.\n *\n * @param {string} searchKey\n * @returns {bool}\n *\/\n static hasTemplateInCache(searchKey) {\n return this.templateCache.has(searchKey);\n }\n\n \/**\n * Prefetch a set of templates without rendering them.\n *\n * @param {Array} templateNames The list of templates to fetch\n * @param {string} themeName\n *\/\n static prefetchTemplates(templateNames, themeName) {\n templateNames.forEach((templateName) => this.prefetchTemplate(templateName, themeName));\n }\n\n \/**\n * Prefetech a sginle template without rendering it.\n *\n * @param {string} templateName\n * @param {string} themeName\n *\/\n static prefetchTemplate(templateName, themeName) {\n const searchKey = this.getSearchKey(themeName, templateName);\n\n \/\/ If we haven't already seen this template then buffer it.\n if (this.hasTemplateInCache(searchKey)) {\n return;\n }\n\n \/\/ Check the buffer to see if this template has already been added.\n const existingBufferRecords = this.loadTemplateBuffer.filter((record) => record.searchKey === searchKey);\n\n if (existingBufferRecords.length) {\n \/\/ This template is already in the buffer so just return the existing promise.\n \/\/ No need to add it to the buffer again.\n return;\n }\n\n \/\/ This is the first time this has been requested so let's add it to the buffer to be loaded.\n const parts = templateName.split('\/');\n const component = getNormalisedComponent(parts.shift());\n const name = parts.join('\/');\n\n \/\/ Add this template to the buffer to be loaded.\n this.loadTemplateBuffer.push({\n component,\n name,\n theme: themeName,\n searchKey,\n deferred: $.Deferred(),\n });\n\n this.processLoadTemplateBuffer();\n }\n\n \/**\n * Load a partial from the cache or ajax.\n *\n * @method partialHelper\n * @param {string} name The partial name to load.\n * @param {string} [themeName = config.theme] The theme to load the partial from.\n * @return {string}\n *\/\n static partialHelper(name, themeName = config.theme) {\n const searchKey = this.getSearchKey(themeName, name);\n\n if (!this.hasTemplateInCache(searchKey)) {\n new Error(`Failed to pre-fetch the template: ${name}`);\n }\n return this.getTemplateFromCache(searchKey);\n }\n\n \/**\n * Scan a template source for partial tags and return a list of the found partials.\n *\n * @method scanForPartials\n * @param {string} templateSource - source template to scan.\n * @return {Array} List of partials.\n *\/\n static scanForPartials(templateSource) {\n const tokens = mustache.parse(templateSource);\n const partials = [];\n\n const findPartial = (tokens, partials) => {\n let i;\n for (i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (token[0] == '>' || token[0] == '<') {\n partials.push(token[1]);\n }\n if (token.length > 4) {\n findPartial(token[4], partials);\n }\n }\n };\n\n findPartial(tokens, partials);\n\n return partials;\n }\n\n \/**\n * Load a template and scan it for partials. Recursively fetch the partials.\n *\n * @method cachePartials\n * @param {string} templateName - should consist of the component and the name of the template like this:\n * core\/menu (lib\/templates\/menu.mustache) or\n * tool_bananas\/yellow (admin\/tool\/bananas\/templates\/yellow.mustache)\n * @param {string} [themeName=config.theme]\n * @param {Array} parentage - A list of requested partials in this render chain.\n * @return {Promise} JQuery promise object resolved when all partials are in the cache.\n *\/\n static cachePartials(templateName, themeName = config.theme, parentage = []) {\n const searchKey = this.getSearchKey(themeName, templateName);\n\n if (searchKey in this.cachePartialPromises) {\n return this.cachePartialPromises[searchKey];\n }\n\n \/\/ This promise will not be resolved until all child partials are also resolved and ready.\n \/\/ We create it here to allow us to check for recursive inclusion of templates.\n \/\/ Keep track of the requested partials in this chain.\n if (!parentage.length) {\n parentage.push(searchKey);\n }\n\n this.cachePartialPromises[searchKey] = $.Deferred();\n this._cachePartials(templateName, themeName, parentage).catch((error) => {\n this.cachePartialPromises[searchKey].reject(error);\n });\n\n return this.cachePartialPromises[searchKey];\n }\n\n \/**\n * Cache the template partials for the specified template.\n *\n * @param {string} templateName\n * @param {string} themeName\n * @param {array} parentage\n * @returns {promise}\n *\/\n static async _cachePartials(templateName, themeName, parentage) {\n const searchKey = this.getSearchKey(themeName, templateName);\n const templateSource = await this.getTemplate(templateName, themeName);\n const partials = this.scanForPartials(templateSource);\n const uniquePartials = partials.filter((partialName) => {\n \/\/ Check for recursion.\n if (parentage.indexOf(`${themeName}\/${partialName}`) >= 0) {\n \/\/ Ignore templates which include a parent template already requested in the current chain.\n return false;\n }\n\n \/\/ Ignore templates that include themselves.\n return partialName !== templateName;\n });\n\n \/\/ Fetch any partial which has not already been fetched.\n const fetchThemAll = uniquePartials.map((partialName) => {\n parentage.push(`${themeName}\/${partialName}`);\n return this.cachePartials(partialName, themeName, parentage);\n });\n\n await Promise.all(fetchThemAll);\n return this.cachePartialPromises[searchKey].resolve(templateSource);\n }\n\n \/**\n * Take all of the templates waiting in the buffer and load them from the server\n * or from the cache.\n *\n * All of the templates that need to be loaded from the server will be batched up\n * and sent in a single network request.\n *\/\n static processLoadTemplateBuffer() {\n if (!this.loadTemplateBuffer.length) {\n return;\n }\n\n if (this.isLoadingTemplates) {\n return;\n }\n\n this.isLoadingTemplates = true;\n \/\/ Grab any templates waiting in the buffer.\n const templatesToLoad = this.loadTemplateBuffer.slice();\n \/\/ This will be resolved with the list of promises for the server request.\n const serverRequestsDeferred = $.Deferred();\n const requests = [];\n \/\/ Get a list of promises for each of the templates we need to load.\n const templatePromises = templatesToLoad.map((templateData) => {\n const component = getNormalisedComponent(templateData.component);\n const name = templateData.name;\n const searchKey = templateData.searchKey;\n const theme = templateData.theme;\n const templateDeferred = templateData.deferred;\n let promise = null;\n\n \/\/ Double check to see if this template happened to have landed in the\n \/\/ cache as a dependency of an earlier template.\n if (this.hasTemplateInCache(searchKey)) {\n \/\/ We've seen this template so immediately resolve the existing promise.\n promise = this.getTemplatePromiseFromCache(searchKey);\n } else {\n \/\/ We haven't seen this template yet so we need to request it from\n \/\/ the server.\n requests.push({\n methodname: 'core_output_load_template_with_dependencies',\n args: {\n component,\n template: name,\n themename: theme,\n lang: config.language,\n }\n });\n \/\/ Remember the index in the requests list for this template so that\n \/\/ we can get the appropriate promise back.\n const index = requests.length - 1;\n\n \/\/ The server deferred will be resolved with a list of all of the promises\n \/\/ that were sent in the order that they were added to the requests array.\n promise = serverRequestsDeferred.promise()\n .then((promises) => {\n \/\/ The promise for this template will be the one that matches the index\n \/\/ for it's entry in the requests array.\n \/\/\n \/\/ Make sure the promise is added to the promises cache for this template\n \/\/ search key so that we don't request it again.\n templatePromises[searchKey] = promises[index].then((response) => {\n \/\/ Process all of the template dependencies for this template and add\n \/\/ them to the caches so that we don't request them again later.\n response.templates.forEach((data) => {\n data.component = getNormalisedComponent(data.component);\n const tempSearchKey = this.getSearchKey(\n theme,\n [data.component, data.name].join('\/'),\n );\n\n \/\/ Cache all of the dependent templates because we'll need them to render\n \/\/ the requested template.\n this.setTemplateInCache(tempSearchKey, data.value);\n\n if (config.templaterev > 0) {\n \/\/ The template cache is enabled - set the value there.\n storage.set(`core_template\/${config.templaterev}:${tempSearchKey}`, data.value);\n }\n });\n\n if (response.strings.length) {\n \/\/ If we have strings that the template needs then warm the string cache\n \/\/ with them now so that we don't need to re-fetch them.\n str.cache_strings(response.strings.map(({component, name, value}) => ({\n component: getNormalisedComponent(component),\n key: name,\n value,\n })));\n }\n\n \/\/ Return the original template source that the user requested.\n if (this.hasTemplateInCache(searchKey)) {\n return this.getTemplateFromCache(searchKey);\n }\n\n return null;\n });\n\n return templatePromises[searchKey];\n });\n }\n\n return promise\n \/\/ When we've successfully loaded the template then resolve the deferred\n \/\/ in the buffer so that all of the calling code can proceed.\n .then((source) => templateDeferred.resolve(source))\n .catch((error) => {\n \/\/ If there was an error loading the template then reject the deferred\n \/\/ in the buffer so that all of the calling code can proceed.\n templateDeferred.reject(error);\n \/\/ Rethrow for anyone else listening.\n throw error;\n });\n });\n\n if (requests.length) {\n \/\/ We have requests to send so resolve the deferred with the promises.\n serverRequestsDeferred.resolve(ajax.call(requests, true, false, false, 0, config.templaterev));\n } else {\n \/\/ Nothing to load so we can resolve our deferred.\n serverRequestsDeferred.resolve();\n }\n\n \/\/ Once we've finished loading all of the templates then recurse to process\n \/\/ any templates that may have been added to the buffer in the time that we\n \/\/ were fetching.\n $.when.apply(null, templatePromises)\n .then(() => {\n \/\/ Remove the templates we've loaded from the buffer.\n this.loadTemplateBuffer.splice(0, templatesToLoad.length);\n this.isLoadingTemplates = false;\n this.processLoadTemplateBuffer();\n return;\n })\n .catch(() => {\n \/\/ Remove the templates we've loaded from the buffer.\n this.loadTemplateBuffer.splice(0, templatesToLoad.length);\n this.isLoadingTemplates = false;\n this.processLoadTemplateBuffer();\n });\n }\n\n \/**\n * Search the various caches for a template promise for the given search key.\n * The search key should be in the format \/\/ e.g. boost\/core\/modal.\n *\n * If the template is found in any of the caches it will populate the other caches with\n * the same data as well.\n *\n * @param {String} searchKey The template search key in the format \/\/ e.g. boost\/core\/modal\n * @returns {Object|null} jQuery promise resolved with the template source\n *\/\n static getTemplatePromiseFromCache(searchKey) {\n \/\/ First try the cache of promises.\n if (searchKey in this.templatePromises) {\n return this.templatePromises[searchKey];\n }\n\n \/\/ Check the module cache.\n if (this.hasTemplateInCache(searchKey)) {\n const templateSource = this.getTemplateFromCache(searchKey);\n \/\/ Add this to the promises cache for future.\n this.templatePromises[searchKey] = $.Deferred().resolve(templateSource).promise();\n return this.templatePromises[searchKey];\n }\n\n if (config.templaterev <= 0) {\n \/\/ Template caching is disabled. Do not store in persistent storage.\n return null;\n }\n\n \/\/ Now try local storage.\n const cached = storage.get(`core_template\/${config.templaterev}:${searchKey}`);\n if (cached) {\n \/\/ Add this to the module cache for future.\n this.setTemplateInCache(searchKey, cached);\n\n \/\/ Add to the promises cache for future.\n this.templatePromises[searchKey] = $.Deferred().resolve(cached).promise();\n return this.templatePromises[searchKey];\n }\n\n return null;\n }\n}\n"],"names":["Loader","theme","templateName","themeName","config","searchKey","this","getSearchKey","cachedPromise","getTemplatePromiseFromCache","existingBufferRecords","loadTemplateBuffer","filter","record","length","deferred","promise","parts","split","component","shift","name","join","$","Deferred","push","processLoadTemplateBuffer","templateSource","templateCache","set","get","has","templateNames","forEach","prefetchTemplate","hasTemplateInCache","Error","getTemplateFromCache","tokens","mustache","parse","partials","findPartial","i","token","parentage","cachePartialPromises","_cachePartials","catch","error","reject","getTemplate","fetchThemAll","scanForPartials","partialName","indexOf","map","cachePartials","Promise","all","resolve","isLoadingTemplates","templatesToLoad","slice","serverRequestsDeferred","requests","templatePromises","templateData","templateDeferred","methodname","args","template","themename","lang","language","index","then","promises","response","templates","data","tempSearchKey","setTemplateInCache","value","templaterev","strings","str","cache_strings","_ref","key","source","ajax","call","when","apply","splice","cached","storage","Map"],"mappings":"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"}