{"version":3,"file":"course_mod_modal.min.js","sources":["https:\/\/shriveronline.org\/course\/format\/tiles\/amd\/src\/course_mod_modal.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\n\/* eslint space-before-function-paren: 0 *\/\n\n\/**\n * Javascript Module to handle rendering of course modules (e.g. resource\/PDF, resource\/html, page) in modal windows\n *\n * When the user clicks a PDF course module subtile or old style resource\n * if we are using modals for it (e.g. PDF) , create, populate, launch and size the modal\n *\n * @module format_tiles\/course_mod_modal\n * @copyright 2018 David Watson {@link http:\/\/evolutioncode.uk}\n * @license http:\/\/www.gnu.org\/copyleft\/gpl.html GNU GPL v3 or later\n * @since Moodle 3.3\n *\/\n\ndefine([\"jquery\", \"core\/modal_factory\", \"core\/config\", \"core\/templates\", \"core\/notification\", \"core\/ajax\",\n 'core\/fragment', \"core\/modal_events\"],\n function ($, modalFactory, config, Templates, Notification, ajax, Fragment, ModalEvents) {\n \"use strict\";\n\n var loadingIconHtml;\n const win = $(window);\n var courseId;\n var tilesConfig;\n const isSafari = \/^((?!chrome|android).)*safari\/i.test(navigator.userAgent);\n\n const Selector = {\n modal: \".modal\",\n modalDialog: \".modal-dialog\",\n modalBody: \".modal-body\",\n sectionMain: \".section.main\",\n pageContent: \"#page-content\",\n regionMain: \"#region-main\",\n completionState: \"#completion-check-\",\n cmModal: \".embed_cm_modal\",\n moodleMediaPlayer: \".mediaplugin_videojs\",\n closeBtn: \"button.close\",\n ACTIVITY: \"li.activity\",\n URLACTIVITYPOPUPLINK: \".activity.modtype_url.urlpopup a\",\n modalHeader: \".modal-header\",\n embedModuleButtons: \".embed-module-buttons\",\n iframe: \"iframe\"\n };\n\n const CLASS = {\n COMPLETION_ENABLED: \"completion-enabled\",\n COMPLETION_MANUAL: \"completion-manual\",\n COMPLETION_AUTO: \"completion-auto\", \/\/ E.g. grade based.\n COMPLETION_VIEW: \"completion-view\",\n COMPLETION_CHECK_BOX: \"completioncheckbox\",\n COMPLETION_DROPDOWN: \"completion-dropdown\"\n };\n\n const modalMinWidth = function () {\n return Math.min(win.width(), 1100);\n };\n\n \/**\n * Some modals contain videos in iframes or objects, which need to stop playing when dismissed.\n * @param {object} modal the modal which contains the video.\n *\/\n const stopAllVideosOnDismiss = function(modal) {\n modal.on(ModalEvents.hidden, function() {\n const iframes = modal.find(Selector.iframe);\n const objects = modal.find(\"object\");\n const moodleMediaPlayer = modal.find(Selector.moodleMediaPlayer);\n\n if (iframes.length || objects.length || moodleMediaPlayer.length) {\n modal.remove();\n }\n });\n };\n \/**\n *\n * @param {number} cmId\n * @param {number} moduleContextId\n * @param {number} sectionNum\n * @param {string} title\n * @param {string} objectType\n * @param {boolean} completionEnabled\n * @param {number} existingCompletionState\n * @param {boolean} isManualCompletion\n * @param {string} descriptionHTML\n * @returns {boolean}\n *\/\n const launchCmModal = function (\n cmId, moduleContextId, sectionNum, title, objectType,\n completionEnabled, existingCompletionState, isManualCompletion, descriptionHTML\n ) {\n modalFactory.create({\n type: modalFactory.types.DEFAULT,\n title: title,\n body: loadingIconHtml\n }).done(function (modal) {\n modal.setLarge();\n modal.show();\n const modalRoot = $(modal.root);\n const modalId = \"embed_mod_modal_\" + cmId;\n \/\/ If modal exists from previous launch, remove.\n $(`#${modalId}`).remove();\n modalRoot.attr(\"id\", modalId);\n modalRoot.data(\"cmid\", cmId);\n modalRoot.data(\"section\", sectionNum);\n modalRoot.addClass(\"embed_cm_modal\");\n\n \/\/ If it's a page activity, we simply add the page HTML as the modal body.\n \/\/ Otherwise, we set the body by rendering from a template.\n if (objectType === 'page') {\n modalRoot.addClass('mod_' + objectType);\n stopAllVideosOnDismiss(modalRoot);\n Fragment.loadFragment(\n 'format_tiles', `get_cm_content`, moduleContextId, {contextid: moduleContextId}\n )\n .done(function(html, js) {\n modal.setBody(html);\n Templates.runTemplateJS(js);\n });\n } else {\n \/\/ Render the modal body and set it to the page.\n \/\/ First a blank template data object.\n var templateData = {\n id: cmId,\n objectType: null,\n width: \"100%\",\n height: Math.round(win.height() - 60), \/\/ Embedded object height in modal - make as high as poss.\n cmid: cmId,\n tileid: sectionNum,\n isediting: 0,\n sesskey: config.sesskey,\n activityname: title,\n config: {wwwroot: config.wwwroot},\n completionstring: '',\n description: descriptionHTML\n };\n\n var template = null;\n if (objectType === \"html\") {\n templateData.objectType = \"text\/html\";\n template = 'format_tiles\/embed_file_modal_body';\n } else if (objectType === \"pdf\") {\n templateData.objectType = 'application\/pdf';\n \/\/ Issue #222 - Safari second page load of PDF.\n \/\/ Safari fails to re-load cached PDF, so for now bust cache by adding ?t={time}.\n \/\/ (Reason seems to be related to 'Accept-Ranges: bytes' in response from readfile_accel()).\n templateData.cachebustparam = isSafari ? Date.now() : null;\n template = 'format_tiles\/embed_file_modal_body';\n } else if (objectType === \"url\") {\n templateData.objectType = 'url';\n template = 'format_tiles\/embed_url_modal_body';\n }\n\n const redirectModule =\n ['pdf', 'html'].includes(objectType) ? 'resource' : objectType;\n if (template !== null) {\n Templates.render(template, templateData).done(function (html) {\n modal.setBody(html);\n modalRoot.find(Selector.modalBody).animate({\"min-height\": Math.round(win.height() + 20)}, \"fast\");\n\n if (objectType === \"html\" || objectType === 'url') {\n \/\/ HTML files only - set widths to 100% since they may contain embedded videos etc.\n modalRoot.find(Selector.modal).animate({\"max-width\": \"100%\"}, \"fast\");\n modalRoot.find(Selector.modalDialog).animate({\"max-width\": \"100%\"}, \"fast\");\n modalRoot.find(Selector.modalBody).animate({\"max-width\": \"100%\"}, \"fast\");\n stopAllVideosOnDismiss(modalRoot);\n if (objectType === 'url') {\n modalRoot.find(Selector.modalBody).addClass(\"text-center\");\n }\n } else if (objectType === \"pdf\") {\n \/\/ Otherwise (e.g. for PDF) we don't need 100% width.\n modalRoot.find(Selector.modal).animate({\"max-width\": modalMinWidth()}, \"fast\");\n \/\/ We do modal-dialog too since Moove theme uses it.\n modalRoot.find(Selector.modalDialog).animate({\"max-width\": modalMinWidth()}, \"fast\");\n }\n\n }).fail(() => {\n window.location.href = `${config.wwwroot}\/mod\/${redirectModule}\/view.php?id=${cmId}`;\n });\n } else {\n window.location.href = `${config.wwwroot}\/mod\/${redirectModule}\/view.php?id=${cmId}`;\n }\n }\n\n \/\/ Render the modal header \/ title and set it to the page.\n var headerTemplateData = {\n cmid: cmId,\n activityname: title,\n tileid: sectionNum,\n showDownload: objectType === \"pdf\" ? 1 : 0,\n showNewWindow: [\"pdf\", 'url'].includes(objectType) ? 1 : 0,\n forModal: true,\n config: {wwwroot: config.wwwroot}\n };\n if (completionEnabled) {\n headerTemplateData.istrackeduser = 1;\n headerTemplateData.hascompletion = 1;\n const oldState = existingCompletionState === 1;\n\n \/\/ Core completion button template has 'overallcomplete' arg relating to this cm.\n \/\/ See course\/templates\/completion_manual.mustache.\n headerTemplateData.overallcomplete = oldState ? 1 : 0;\n headerTemplateData.overallincomplete = oldState ? 0 : 1;\n headerTemplateData.completionIsManual = isManualCompletion;\n if (!headerTemplateData.completionIsManual) {\n \/\/ Auto completion has different vars for core template core_course\/completion_automatic.\n headerTemplateData.statuscomplete = headerTemplateData.overallcomplete;\n headerTemplateData.statusincomplete = headerTemplateData.overallincomplete;\n }\n \/\/ Trigger event to check if other items in course have updated availability.\n if (oldState !== headerTemplateData.completionstate) {\n require([\"format_tiles\/completion\"], function (completion) {\n completion.triggerCompletionChangedEvent(parseInt(sectionNum), parseInt(cmId));\n });\n }\n }\n\n Templates.render(\"format_tiles\/embed_module_modal_header_btns\", headerTemplateData).done(function (html) {\n modalRoot.find(Selector.embedModuleButtons).remove();\n modalRoot.find($('button.close')).remove();\n modalRoot.find($('button.btn-close')).remove(); \/\/ Moodle 4.5+.\n modalRoot.find(Selector.modalHeader).append(html);\n modalRoot.find(Selector.closeBtn).detach().appendTo(modalRoot.find(Selector.embedModuleButtons));\n const toggleCompletionSelector = '[data-action=\"toggle-manual-completion\"]';\n modalRoot.find(toggleCompletionSelector).on('click', () => {\n require([\"format_tiles\/completion\"], function (completion) {\n \/\/ In this case, core will handle the request to set the new completion value in the DB.\n \/\/ We wait a moment to allow that to get a head start.\n \/\/ Then we trigger an event which course.js will see and update section content to show new statuses.\n \/\/ Use will not notice this as they are looking at the modal, but it's ready when they dismiss modal.\n setTimeout(() => {\n completion.triggerCompletionChangedEvent(\n parseInt(modalRoot.data('section')), parseInt(modalRoot.data(\"cmid\"))\n );\n }, 300);\n });\n });\n }).fail(Notification.exception);\n\n \/\/ Allow a short delay before we resize the modal, and check a few times, as content may be loading.\n setTimeout(() => {\n modalHeightChangeWatcher(modalRoot, 3, 1000);\n }, 500);\n\n return true;\n });\n return false;\n };\n\n \/**\n * Resize the modal to account for its content.\n * @param {object} modalRoot\n *\/\n var resizeModal = function(modalRoot) {\n modalRoot.find(Selector.modal).animate({\"max-width\": modalMinWidth()}, \"fast\");\n\n var MODAL_MARGIN = 70;\n\n \/\/ If the modal contains a Moodle mediaplayer div, remove the max width css rule which Moodle applies.\n \/\/ Otherwise video will be 400px max wide.\n var mediaPlayer = $(Selector.moodleMediaPlayer);\n mediaPlayer.find(\"div\").each(function(index, child) {\n $(child).css(\"max-width\", \"\");\n });\n if (mediaPlayer.length > 0) {\n stopAllVideosOnDismiss(modalRoot);\n }\n\n \/\/ If the activity contains an iframe (e.g. is a page with a YouTube video in it, or H5P), ensure modal is big enough.\n \/\/ Do this for every iframe in the course module.\n modalRoot.find(Selector.iframe).each(function (index, iframe) {\n\n const iframeSelector = $(iframe);\n\n \/\/ Get the modal.\n var modal;\n \/\/ Boost calls the modal \"modal dialog\" so try this first.\n modal = modalRoot.find(Selector.modalDialog);\n\n \/\/ If no luck, try what Clean and Adaptable do instead.\n if (modal.length === 0) {\n modal = modalRoot.find(Selector.modal);\n }\n\n \/\/ Now check and adjust the width of the modal.\n var iframeWidth = Math.min(iframeSelector.width(), win.width());\n if (iframeWidth > modal.width() - MODAL_MARGIN) {\n modal.animate(\n {\"max-width\": Math.max(iframeWidth + MODAL_MARGIN, modalMinWidth())},\n \"fast\"\n );\n modalRoot.find(Selector.modal).animate(\n {\"max-width\": Math.max(iframeWidth + MODAL_MARGIN, modalMinWidth())},\n \"fast\"\n );\n }\n\n \/\/ Then the height of the modal body.\n var modalBody = modalRoot.find(Selector.modalBody);\n if (iframeSelector.height() > modalBody.height() - MODAL_MARGIN) {\n iframeSelector.attr('height', modalBody.height() - MODAL_MARGIN);\n }\n stopAllVideosOnDismiss(modalRoot);\n });\n };\n\n \/**\n * Check the modal height to see if the iframe in it is bigger. If it is, adjust modal height up.\n * Do this a few times so that, if iframe content is loading, we can check after it's loaded.\n * @param {object} modalRoot\n * @param {number} howManyChecks\n * @param {number}duration\n * @param {number} oldHeight\n *\/\n const modalHeightChangeWatcher = function (modalRoot, howManyChecks, duration, oldHeight = 0) {\n const iframe = modalRoot.find(Selector.modalBody);\n if (iframe) {\n const newHeight = Math.round(iframe.height());\n if (newHeight && newHeight > oldHeight + 10) {\n resizeModal(modalRoot);\n }\n if (howManyChecks > 0) {\n setTimeout(() => {\n modalHeightChangeWatcher(modalRoot, howManyChecks - 1, duration, newHeight);\n }, duration);\n }\n }\n };\n\n \/**\n * Do we need a modal for this cm?\n * @param {number} cmId course module ID\n * @param {string} url\n * @return boolean\n *\/\n const modalRequired = function(cmId, url) {\n if (tilesConfig.modalallowedmodnames === undefined) {\n return false;\n }\n if (tilesConfig.modalallowedcmids === undefined) {\n return false;\n }\n if (!(tilesConfig.modalallowedcmids).includes(cmId)) {\n return false;\n }\n\n return ((tilesConfig.modalallowedmodnames).includes('page') && url.startsWith(`${config.wwwroot}\/mod\/page\/view.php`))\n || ((tilesConfig.modalallowedmodnames).includes('url') && url.startsWith(`${config.wwwroot}\/mod\/url\/view.php`))\n || ((tilesConfig.modalallowedmodnames).includes('pdf') && url.startsWith(`${config.wwwroot}\/mod\/resource\/view.php`))\n || ((tilesConfig.modalallowedmodnames).includes('html')\n && url.startsWith(`${config.wwwroot}\/mod\/resource\/view.php`));\n };\n\n return {\n init: function (courseIdInit, isEditing, pageType, launchModalCmid, usingJsNav) {\n courseId = parseInt(courseIdInit);\n $(document).ready(function () {\n tilesConfig = $('#format-tiles-js-config').data();\n const courseIndex = $('nav#courseindex');\n\n if (['course-view-tiles', 'section-view-tiles'].includes(pageType)) {\n \/\/ We are on a main tiles page, \/course\/view.php or \/course\/section.php in Moodle 4.4+.\n \/\/ If any link in the course index on the left is clicked, check if it needs a modal.\n \/\/ If it does, launch the modal instead of following the link.\n \/\/ This isn't ideal but saves plugin re-implementing \/ maintaining large volume of course index code.\n \/\/ TODO use reactive UI - courseformat\/activity:openAnchor in course\/format\/amd\/src\/local\/courseindex.\n if (!isEditing && courseIndex.length > 0) {\n courseIndex.on('click', function(e) {\n const target = $(e.target);\n const link = target.hasClass('courseindex-link') ? target : target.find('a.courseindex-link');\n if (link && link.data('for') === 'cm_name') {\n e.preventDefault();\n const linkUrl = link.attr('href');\n if (linkUrl) {\n const cmId = link.closest('li.courseindex-item').data('id');\n ajax.call([{\n methodname: \"format_tiles_get_course_mod_info\", args: {cmid: cmId}\n }])[0].done(function (data) {\n const expandedSection = $(`li#section-${data.sectionnumber}.state-visible`);\n if (modalRequired(cmId, linkUrl)) {\n if (!data || !data.modalallowed) {\n window.location.href = linkUrl;\n return;\n }\n if (usingJsNav) {\n if (expandedSection.length === 0) {\n require([\"format_tiles\/course\"], function (course) {\n course.populateAndExpandSection(\n data.coursecontextid, data.sectionid, data.sectionnumber\n );\n });\n }\n launchCmModal(\n cmId,\n data.modulecontextid,\n data.sectionnumber,\n data.name,\n data.modaltype,\n data.completionenabled ? 1 : 0,\n data.iscomplete ? 1 : 0,\n data.ismanualcompletion,\n data.description,\n );\n } else {\n window.location.href = config.wwwroot\n + `\/course\/view.php?id=${courseId}`\n + `§ion=${data.sectionnumber}&cmid=${cmId}`;\n }\n } else {\n \/\/ Link URL may be anchor e.g. #module-138 if the item is a label.\n const isAnchorLink = link.data('anchor') || linkUrl.startsWith('#');\n if (!isAnchorLink) {\n window.location.href = linkUrl;\n } else {\n if (usingJsNav) {\n if (expandedSection.length === 0) {\n require([\"format_tiles\/course\"], function (course) {\n course.populateAndExpandSection(\n data.coursecontextid, data.sectionid, data.sectionnumber\n );\n });\n }\n } else {\n window.location.href = config.wwwroot\n + `\/course\/view.php?id=${courseId}`\n + `§ion=${data.sectionnumber}`;\n }\n }\n }\n })\n .fail(function() {\n window.location.href = linkUrl;\n });\n }\n }\n });\n }\n\n \/\/ If we are passing ?cmid=xxx in the URL this suggests we are trying to launch course mod modal.\n \/\/ This would be from clicking a course index link while in another activity.\n \/\/ E.g. from \/mod\/xxx\/view.php for another course module.\n \/\/ This isn't ideal but saves this plugin re-implementing \/ maintaining large volume of course index code.\n if (launchModalCmid) {\n ajax.call([{\n methodname: \"format_tiles_get_course_mod_info\", args: {cmid: launchModalCmid}\n }])[0].done(function (data) {\n if (data && data.modalallowed && data.courseid === courseId) {\n const expandedSection = $(`li#section-${data.sectionnumber}.state-visible`);\n if (expandedSection.length === 0) {\n if (usingJsNav) {\n require([\"format_tiles\/course\"], function (course) {\n course.populateAndExpandSection(\n data.coursecontextid, data.sectionid, data.sectionnumber\n );\n });\n }\n }\n\n launchCmModal(\n launchModalCmid,\n data.modulecontextid,\n data.sectionnumber,\n data.name,\n data.modaltype,\n data.completionenabled ? 1 : 0,\n data.iscomplete ? 1 : 0,\n data.ismanualcompletion,\n data.description,\n );\n }\n });\n }\n\n var pageContent = $(Selector.pageContent);\n if (pageContent.length === 0) {\n \/\/ Some themes e.g. RemUI do not have a #page-content div, so use #region-main.\n pageContent = $(Selector.regionMain);\n }\n\n pageContent.on(\"keydown\", `[data-action=\"launch-tiles-cm-modal\"]`, function (e) {\n const ENTER_KEY = 13;\n if (e.keyCode === ENTER_KEY) {\n \/\/ User has tabbed to a modal capable activity and pressed enter.\n \/\/ To improve accessibility, do not launch a modal but show them standard activity screen.\n e.preventDefault();\n const url = $(e.target).attr('href');\n if (url) {\n window.location.href = url;\n }\n }\n });\n\n pageContent.on(\"click\", `[data-action=\"launch-tiles-cm-modal\"]`, function (e) {\n \/\/ If click is on a completion checkbox within activity, ignore here as handled elsewhere.\n const tgt = $(e.target);\n const isExcludedControl = tgt.hasClass(CLASS.COMPLETION_CHECK_BOX)\n || tgt.parent().hasClass(CLASS.COMPLETION_CHECK_BOX)\n || tgt.hasClass(CLASS.COMPLETION_DROPDOWN)\n || tgt.parent().hasClass(CLASS.COMPLETION_DROPDOWN)\n || tgt.is(\":button\")\n || tgt.hasClass('expanded-content') \/\/ \"Show less\" link on restrictions.\n || tgt.hasClass('collapsed-content'); \/\/ \"Show more\" link on restrictions\n if (isExcludedControl) {\n return;\n }\n e.preventDefault();\n const currTgt = $(e.currentTarget);\n var clickedCmObject = currTgt.closest(\"li.activity\");\n const cmId = clickedCmObject.data('cmid');\n const moduleContextId = clickedCmObject.data('contextid');\n const sectionNum = clickedCmObject.closest(Selector.sectionMain).data('section');\n\n launchCmModal(\n cmId,\n moduleContextId,\n sectionNum,\n clickedCmObject.data('title'),\n clickedCmObject.data('modal'),\n clickedCmObject.hasClass(CLASS.COMPLETION_ENABLED),\n clickedCmObject.data('completion-state')\n ? parseInt(clickedCmObject.data('completion-state')) : null,\n clickedCmObject.hasClass(CLASS.COMPLETION_MANUAL),\n clickedCmObject.find('.modal-description').html(),\n );\n });\n\n \/\/ Render the loading icon and append it to body so that we can use it later.\n Templates.render(\"format_tiles\/loading\", {})\n .catch(Notification.exception)\n .done(function (html) {\n loadingIconHtml = html; \/\/ TODO get this from elsewhere.\n }).fail(Notification.exception);\n\n } else if (pageType.match('^mod-[a-z]+-view$')) {\n courseIndex.on('click', function (e) {\n const target = $(e.target);\n const link = target.hasClass('courseindex-link') ? target : target.find('a.courseindex-link');\n if (link && link.data('for') === 'cm_name') {\n e.preventDefault();\n const linkUrl = link.attr('href');\n if (linkUrl) {\n const link = $(e.target);\n const cmId = link.closest('li.courseindex-item').data('id');\n if (modalRequired(cmId, linkUrl)) {\n if (usingJsNav) {\n window.location.href = `${config.wwwroot}\/course\/view.php?id=${courseId}&cmid=${cmId}`;\n } else {\n const sectionElement = link.closest('.courseindex-section');\n const sectionNumber = sectionElement ? sectionElement.data('number') : 0;\n window.location.href = `${config.wwwroot}\/course\/view.php?id=${courseId}`\n + `§ion=${sectionNumber}&cmid=${cmId}`;\n }\n } else {\n window.location.href = linkUrl;\n }\n }\n }\n });\n }\n });\n }\n };\n }\n);\n"],"names":["define","$","modalFactory","config","Templates","Notification","ajax","Fragment","ModalEvents","loadingIconHtml","win","window","courseId","tilesConfig","isSafari","test","navigator","userAgent","Selector","CLASS","modalMinWidth","Math","min","width","stopAllVideosOnDismiss","modal","on","hidden","iframes","find","objects","moodleMediaPlayer","length","remove","launchCmModal","cmId","moduleContextId","sectionNum","title","objectType","completionEnabled","existingCompletionState","isManualCompletion","descriptionHTML","create","type","types","DEFAULT","body","done","setLarge","show","modalRoot","root","modalId","attr","data","addClass","loadFragment","contextid","html","js","setBody","runTemplateJS","templateData","id","height","round","cmid","tileid","isediting","sesskey","activityname","wwwroot","completionstring","description","template","cachebustparam","Date","now","redirectModule","includes","render","animate","fail","location","href","headerTemplateData","showDownload","showNewWindow","forModal","istrackeduser","hascompletion","oldState","overallcomplete","overallincomplete","completionIsManual","statuscomplete","statusincomplete","completionstate","require","completion","triggerCompletionChangedEvent","parseInt","append","detach","appendTo","setTimeout","exception","modalHeightChangeWatcher","resizeModal","mediaPlayer","each","index","child","css","iframe","iframeSelector","iframeWidth","max","modalBody","howManyChecks","duration","oldHeight","newHeight","modalRequired","url","undefined","modalallowedmodnames","modalallowedcmids","startsWith","init","courseIdInit","isEditing","pageType","launchModalCmid","usingJsNav","document","ready","courseIndex","e","target","link","hasClass","preventDefault","linkUrl","closest","call","methodname","args","expandedSection","sectionnumber","modalallowed","course","populateAndExpandSection","coursecontextid","sectionid","modulecontextid","name","modaltype","completionenabled","iscomplete","ismanualcompletion","courseid","pageContent","keyCode","tgt","parent","is","clickedCmObject","currentTarget","catch","match","sectionElement","sectionNumber"],"mappings":"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\/C,SAAS,SAAW6C,IAAII,qBAAc\/H,OAAOsE,gCAC\/E5D,YAAYmH,qBAAsB\/C,SAAS,QAAU6C,IAAII,qBAAc\/H,OAAOsE,+BAC9E5D,YAAYmH,qBAAsB\/C,SAAS,QAAU6C,IAAII,qBAAc\/H,OAAOsE,oCAC9E5D,YAAYmH,qBAAsB\/C,SAAS,SACzC6C,IAAII,qBAAc\/H,OAAOsE,6CAGjC,CACH0D,KAAM,SAAUC,aAAcC,UAAWC,SAAUC,gBAAiBC,YAChE5H,SAAW2F,SAAS6B,cACpBnI,EAAEwI,UAAUC,OAAM,WACd7H,YAAcZ,EAAE,2BAA2BuD,aACrCmF,YAAc1I,EAAE,sBAElB,CAAC,oBAAqB,sBAAsBgF,SAASqD,UAAW,EAM3DD,WAAaM,YAAY3G,OAAS,GACnC2G,YAAYjH,GAAG,SAAS,SAASkH,SACvBC,OAAS5I,EAAE2I,EAAEC,QACbC,KAAOD,OAAOE,SAAS,oBAAsBF,OAASA,OAAOhH,KAAK,yBACpEiH,MAA6B,YAArBA,KAAKtF,KAAK,OAAsB,CACxCoF,EAAEI,uBACIC,QAAUH,KAAKvF,KAAK,WACtB0F,QAAS,OACH9G,KAAO2G,KAAKI,QAAQ,uBAAuB1F,KAAK,MACtDlD,KAAK6I,KAAK,CAAC,CACPC,WAAY,mCAAoCC,KAAM,CAACjF,KAAMjC,SAC7D,GAAGc,MAAK,SAAUO,YACZ8F,gBAAkBrJ,uBAAgBuD,KAAK+F,oCACzC1B,cAAc1F,KAAM8G,SAAU,KACzBzF,OAASA,KAAKgG,yBACf7I,OAAO0E,SAASC,KAAO2D,SAGvBT,YAC+B,IAA3Bc,gBAAgBtH,QAChBoE,QAAQ,CAAC,wBAAwB,SAAUqD,QACvCA,OAAOC,yBACHlG,KAAKmG,gBAAiBnG,KAAKoG,UAAWpG,KAAK+F,kBAIvDrH,cACIC,KACAqB,KAAKqG,gBACLrG,KAAK+F,cACL\/F,KAAKsG,KACLtG,KAAKuG,UACLvG,KAAKwG,kBAAoB,EAAI,EAC7BxG,KAAKyG,WAAa,EAAI,EACtBzG,KAAK0G,mBACL1G,KAAKmB,cAGThE,OAAO0E,SAASC,KAAOnF,OAAOsE,sCACD7D,6BACX4C,KAAK+F,+BAAsBpH,UAE9C,CAEkB2G,KAAKtF,KAAK,WAAayF,QAAQf,WAAW,KAIvDM,WAC+B,IAA3Bc,gBAAgBtH,QAChBoE,QAAQ,CAAC,wBAAwB,SAAUqD,QACvCA,OAAOC,yBACHlG,KAAKmG,gBAAiBnG,KAAKoG,UAAWpG,KAAK+F,kBAKvD5I,OAAO0E,SAASC,KAAOnF,OAAOsE,sCACD7D,6BACX4C,KAAK+F,eAb3B5I,OAAO0E,SAASC,KAAO2D,YAkBlC7D,MAAK,WACFzE,OAAO0E,SAASC,KAAO2D,gBAWvCV,iBACAjI,KAAK6I,KAAK,CAAC,CACPC,WAAY,mCAAoCC,KAAM,CAACjF,KAAMmE,oBAC7D,GAAGtF,MAAK,SAAUO,SACdA,MAAQA,KAAKgG,cAAgBhG,KAAK2G,WAAavJ,SAAU,CAE1B,IADPX,uBAAgBuD,KAAK+F,iCACzBvH,QACZwG,YACApC,QAAQ,CAAC,wBAAwB,SAAUqD,QACvCA,OAAOC,yBACHlG,KAAKmG,gBAAiBnG,KAAKoG,UAAWpG,KAAK+F,kBAM3DrH,cACIqG,gBACA\/E,KAAKqG,gBACLrG,KAAK+F,cACL\/F,KAAKsG,KACLtG,KAAKuG,UACLvG,KAAKwG,kBAAoB,EAAI,EAC7BxG,KAAKyG,WAAa,EAAI,EACtBzG,KAAK0G,mBACL1G,KAAKmB,qBAMjByF,YAAcnK,EAAEiB,sBACO,IAAvBkJ,YAAYpI,SAEZoI,YAAcnK,EAAEiB,sBAGpBkJ,YAAY1I,GAAG,mDAAoD,SAAUkH,MACvD,KACdA,EAAEyB,QAAuB,CAGzBzB,EAAEI,uBACIlB,IAAM7H,EAAE2I,EAAEC,QAAQtF,KAAK,QACzBuE,MACAnH,OAAO0E,SAASC,KAAOwC,SAKnCsC,YAAY1I,GAAG,iDAAkD,SAAUkH,SAEjE0B,IAAMrK,EAAE2I,EAAEC,WACUyB,IAAIvB,SAAS5H,6BAChCmJ,IAAIC,SAASxB,SAAS5H,6BACtBmJ,IAAIvB,SAAS5H,4BACbmJ,IAAIC,SAASxB,SAAS5H,4BACtBmJ,IAAIE,GAAG,YACPF,IAAIvB,SAAS,qBACbuB,IAAIvB,SAAS,4BAIpBH,EAAEI,qBAEEyB,gBADYxK,EAAE2I,EAAE8B,eACUxB,QAAQ,qBAChC\/G,KAAOsI,gBAAgBjH,KAAK,QAC5BpB,gBAAkBqI,gBAAgBjH,KAAK,aACvCnB,WAAaoI,gBAAgBvB,QAAQhI,sBAAsBsC,KAAK,WAEtEtB,cACIC,KACAC,gBACAC,WACAoI,gBAAgBjH,KAAK,SACrBiH,gBAAgBjH,KAAK,SACrBiH,gBAAgB1B,SAAS5H,0BACzBsJ,gBAAgBjH,KAAK,oBACf+C,SAASkE,gBAAgBjH,KAAK,qBAAuB,KAC3DiH,gBAAgB1B,SAAS5H,yBACzBsJ,gBAAgB5I,KAAK,sBAAsB+B,WAKnDxD,UAAU8E,OAAO,uBAAwB,IACpCyF,MAAMtK,aAAauG,WACnB3D,MAAK,SAAUW,MACZnD,gBAAkBmD,QACnBwB,KAAK\/E,aAAauG,gBAElB0B,SAASsC,MAAM,sBACtBjC,YAAYjH,GAAG,SAAS,SAAUkH,SACxBC,OAAS5I,EAAE2I,EAAEC,QACbC,KAAOD,OAAOE,SAAS,oBAAsBF,OAASA,OAAOhH,KAAK,yBACpEiH,MAA6B,YAArBA,KAAKtF,KAAK,OAAsB,CACxCoF,EAAEI,uBACIC,QAAUH,KAAKvF,KAAK,WACtB0F,QAAS,OACHH,KAAO7I,EAAE2I,EAAEC,QACX1G,KAAO2G,KAAKI,QAAQ,uBAAuB1F,KAAK,SAClDqE,cAAc1F,KAAM8G,YAChBT,WACA7H,OAAO0E,SAASC,eAAUnF,OAAOsE,uCAA8B7D,0BAAiBuB,UAC7E,OACG0I,eAAiB\/B,KAAKI,QAAQ,wBAC9B4B,cAAgBD,eAAiBA,eAAerH,KAAK,UAAY,EACvE7C,OAAO0E,SAASC,KAAO,UAAGnF,OAAOsE,uCAA8B7D,6BAC7CkK,+BAAsB3I,WAG5CxB,OAAO0E,SAASC,KAAO2D"}