diff --git a/blocks/accessreview/amd/build/module.min.js b/blocks/accessreview/amd/build/module.min.js index 8eca927ea81..568bbd7f306 100644 --- a/blocks/accessreview/amd/build/module.min.js +++ b/blocks/accessreview/amd/build/module.min.js @@ -1,2 +1,2 @@ -function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("block_accessreview/module",["exports","core/ajax","core/templates","core/notification"],function(a,b,c,d){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;c=f(c);function e(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;e=function(){return a};return a}function f(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=e();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in a){if(Object.prototype.hasOwnProperty.call(a,f)){var g=d?Object.getOwnPropertyDescriptor(a,f):null;if(g&&(g.get||g.set)){Object.defineProperty(c,f,g)}else{c[f]=a[f]}}}c.default=a;if(b){b.set(a,c)}return c}function g(a,b){return m(a)||l(a,b)||j(a,b)||h()}function h(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function j(a,b){if(!a)return;if("string"==typeof a)return k(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return k(a,b)}function k(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);cc.maxViews){c.maxViews=a.numerrors}c.totalUsers+=a.numchecks});c.viewDelta=c.maxViews-c.minViews+1;return c},t=function(a,b){document.addEventListener("click",function(c){if(c.target.closest("#toggle-accessmap")){c.preventDefault();r(a,b)}})},u=function(a){return{methodname:"core_user_update_user_preferences",args:{preferences:[{type:"block_accessreviewtogglestate",value:a}]}}},v=function(a){return(0,b.call)([u(a)])},w=function(a){var c=1a.length)b=a.length;for(var c=0,d=Array(b);cc.maxViews){c.maxViews=a.numerrors}c.totalUsers+=a.numchecks});c.viewDelta=c.maxViews-c.minViews+1;return c},t=function(a,b){document.addEventListener("click",function(c){if(c.target.closest("#toggle-accessmap")){c.preventDefault();r(a,b)}})},u=function(a){return{methodname:"core_user_update_user_preferences",args:{preferences:[{type:"block_accessreviewtogglestate",value:a}]}}},v=function(a){return(0,b.call)([u(a)])},w=function(a){var c=1.\n\n/**\n *\n * @package block_accessreview\n * @author Max Larkin \n * @copyright 2020 Brickfield Education Labs \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {call as fetchMany} from 'core/ajax';\nimport * as Templates from 'core/templates';\nimport {exception as displayError} from 'core/notification';\n\n/**\n * The number of colours used to represent the heatmap. (Indexed on 0.)\n * @type {number}\n */\nconst numColours = 2;\n\n/**\n * The toggle state of the heatmap.\n * @type {boolean}\n */\nlet toggleState = true;\n\n/**\n * Renders the HTML template onto a particular HTML element.\n * @param {HTMLElement} element The element to attach the HTML to.\n * @param {number} errorCount The number of errors on this module/section.\n * @param {number} checkCount The number of checks triggered on this module/section.\n * @param {String} displayFormat\n * @param {Number} minViews\n * @param {Number} viewDelta\n * @returns {Promise}\n */\nconst renderTemplate = (element, errorCount, checkCount, displayFormat, minViews, viewDelta) => {\n // Calculate a weight?\n const weight = parseInt((errorCount - minViews) / viewDelta * numColours);\n\n const context = {\n resultPassed: !errorCount,\n classList: '',\n passRate: {\n errorCount,\n checkCount,\n failureRate: Math.round(errorCount / checkCount * 100),\n },\n };\n\n if (!element) {\n return Promise.resolve();\n }\n\n const elementClassList = ['block_accessreview'];\n if (context.resultPassed) {\n elementClassList.push('block_accessreview_success');\n } else if (weight) {\n elementClassList.push('block_accessreview_danger');\n } else {\n elementClassList.push('block_accessreview_warning');\n }\n\n const showIcons = (displayFormat == 'showicons') || (displayFormat == 'showboth');\n const showBackground = (displayFormat == 'showbackground') || (displayFormat == 'showboth');\n\n if (showBackground && !showIcons) {\n // Only the background is displayed.\n // No need to display the template.\n // Note: The case where both the background and icons are shown is handled later to avoid jankiness.\n element.classList.add(...elementClassList, 'alert');\n\n return Promise.resolve();\n }\n\n if (showIcons && !showBackground) {\n context.classList = elementClassList.join(' ');\n }\n\n // The icons are displayed either with, or without, the background.\n return Templates.renderForPromise('block_accessreview/status', context)\n .then(({html, js}) => {\n Templates.appendNodeContents(element, html, js);\n\n if (showBackground) {\n element.classList.add(...elementClassList, 'alert');\n }\n\n return;\n })\n .catch();\n};\n\n/**\n * Applies the template to all sections and modules on the course page.\n *\n * @param {Number} courseId\n * @param {String} displayFormat\n * @param {Boolean} updatePreference\n * @returns {Promise}\n */\nconst showAccessMap = (courseId, displayFormat, updatePreference = false) => {\n // Get error data.\n return Promise.all(fetchReviewData(courseId, updatePreference))\n .then(([sectionData, moduleData]) => {\n // Get total data.\n const {minViews, viewDelta} = getErrorTotals(sectionData, moduleData);\n\n sectionData.forEach(section => {\n const element = document.querySelector(`#section-${section.section} .summary`);\n if (!element) {\n return;\n }\n\n renderTemplate(element, section.numerrors, section.numchecks, displayFormat, minViews, viewDelta);\n });\n\n moduleData.forEach(module => {\n const element = document.getElementById(`module-${module.cmid}`);\n if (!element) {\n return;\n }\n\n renderTemplate(element, module.numerrors, module.numchecks, displayFormat, minViews, viewDelta);\n });\n\n return {\n sectionData,\n moduleData,\n };\n })\n .catch(displayError);\n};\n\n\n/**\n * Hides or removes the templates from the HTML of the current page.\n *\n * @param {Boolean} updatePreference\n */\nconst hideAccessMap = (updatePreference = false) => {\n // Removes the added elements.\n document.querySelectorAll('.block_accessreview_view').forEach(node => node.remove());\n\n const classList = [\n 'block_accessreview',\n 'block_accessreview_success',\n 'block_accessreview_warning',\n 'block_accessreview_danger',\n 'block_accessreview_view',\n ];\n\n // Removes the added classes.\n document.querySelectorAll('.block_accessreview').forEach(node => node.classList.remove(...classList));\n\n if (updatePreference) {\n setToggleStatePreference(false);\n }\n};\n\n\n/**\n * Toggles the heatmap on/off.\n *\n * @param {Number} courseId\n * @param {String} displayFormat\n */\nconst toggleAccessMap = (courseId, displayFormat) => {\n toggleState = !toggleState;\n if (!toggleState) {\n hideAccessMap(true);\n } else {\n showAccessMap(courseId, displayFormat, true);\n }\n};\n\n/**\n * Parses information on the errors, generating the min, max and totals.\n *\n * @param {Object[]} sectionData The error data for course sections.\n * @param {Object[]} moduleData The error data for course modules.\n * @returns {Object} An object representing the extra error information.\n*/\nconst getErrorTotals = (sectionData, moduleData) => {\n const totals = {\n totalErrors: 0,\n totalUsers: 0,\n minViews: 0,\n maxViews: 0,\n viewDelta: 0,\n };\n\n [].concat(sectionData, moduleData).forEach(item => {\n totals.totalErrors += item.numerrors;\n if (item.numerrors < totals.minViews) {\n totals.minViews = item.numerrors;\n }\n\n if (item.numerrors > totals.maxViews) {\n totals.maxViews = item.numerrors;\n }\n totals.totalUsers += item.numchecks;\n });\n\n totals.viewDelta = totals.maxViews - totals.minViews + 1;\n\n return totals;\n};\n\nconst registerEventListeners = (courseId, displayFormat) => {\n document.addEventListener('click', e => {\n if (e.target.closest('#toggle-accessmap')) {\n e.preventDefault();\n toggleAccessMap(courseId, displayFormat);\n }\n });\n};\n\n/**\n * Set the user preference for the toggle value.\n *\n * @param {Boolean} toggleState\n * @returns {Promise}\n */\nconst getTogglePreferenceParams = toggleState => {\n return {\n methodname: 'core_user_update_user_preferences',\n args: {\n preferences: [{\n type: 'block_accessreviewtogglestate',\n value: toggleState,\n }],\n }\n };\n};\n\nconst setToggleStatePreference = toggleState => fetchMany([getTogglePreferenceParams(toggleState)]);\n\n/**\n * Fetch the review data.\n *\n * @param {Number} courseid\n * @param {Boolean} updatePreference\n * @returns {Promise[]}\n */\nconst fetchReviewData = (courseid, updatePreference = false) => {\n const calls = [\n {\n methodname: 'block_accessreview_get_section_data',\n args: {courseid}\n },\n {\n methodname: 'block_accessreview_get_module_data',\n args: {courseid}\n },\n ];\n\n if (updatePreference) {\n calls.push(getTogglePreferenceParams(true));\n }\n\n return fetchMany(calls);\n};\n\n/**\n * Setting up the access review module.\n * @param {number} toggled A number represnting the state of the review toggle.\n * @param {string} displayFormat A string representing the display format for icons.\n * @param {number} courseId The course ID.\n * @param {number} userId The id of the currently logged-in user.\n */\nexport const init = (toggled, displayFormat, courseId) => {\n // Settings consts.\n toggleState = toggled == 1;\n\n if (toggleState) {\n showAccessMap(courseId, displayFormat);\n }\n\n registerEventListeners(courseId, displayFormat);\n};\n"],"file":"module.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/module.js"],"names":["toggleState","renderTemplate","element","errorCount","checkCount","displayFormat","minViews","viewDelta","weight","parseInt","context","resultPassed","classList","passRate","failureRate","Math","round","Promise","resolve","elementClassList","push","showIcons","showBackground","add","join","Templates","renderForPromise","then","html","js","appendNodeContents","catch","showAccessMap","courseId","updatePreference","all","fetchReviewData","sectionData","moduleData","getErrorTotals","forEach","section","document","querySelector","numerrors","numchecks","module","getElementById","cmid","remove","displayError","hideAccessMap","querySelectorAll","node","setToggleStatePreference","toggleAccessMap","totals","totalErrors","totalUsers","maxViews","concat","item","registerEventListeners","addEventListener","e","target","closest","preventDefault","getTogglePreferenceParams","methodname","args","preferences","type","value","courseid","calls","init","toggled"],"mappings":"keAwBA,O,qgDAaIA,CAAAA,CAAW,G,CAYTC,CAAc,CAAG,SAACC,CAAD,CAAUC,CAAV,CAAsBC,CAAtB,CAAkCC,CAAlC,CAAiDC,CAAjD,CAA2DC,CAA3D,CAAyE,IAEtFC,CAAAA,CAAM,CAAGC,QAAQ,CAAC,CAACN,CAAU,CAAGG,CAAd,EAA0BC,CAA1B,EAAD,CAFqE,CAItFG,CAAO,CAAG,CACZC,YAAY,CAAE,CAACR,CADH,CAEZS,SAAS,CAAE,EAFC,CAGZC,QAAQ,CAAE,CACNV,UAAU,CAAVA,CADM,CAENC,UAAU,CAAVA,CAFM,CAGNU,WAAW,CAAEC,IAAI,CAACC,KAAL,CAAqC,GAA1B,EAAAb,CAAU,CAAGC,CAAb,CAAX,CAHP,CAHE,CAJ4E,CAc5F,GAAI,CAACF,CAAL,CAAc,CACV,MAAOe,CAAAA,OAAO,CAACC,OAAR,EACV,CAED,GAAMC,CAAAA,CAAgB,CAAG,CAAC,oBAAD,CAAzB,CACA,GAAIT,CAAO,CAACC,YAAZ,CAA0B,CACtBQ,CAAgB,CAACC,IAAjB,CAAsB,4BAAtB,CACH,CAFD,IAEO,IAAIZ,CAAJ,CAAY,CACfW,CAAgB,CAACC,IAAjB,CAAsB,2BAAtB,CACH,CAFM,IAEA,CACHD,CAAgB,CAACC,IAAjB,CAAsB,4BAAtB,CACH,CAzB2F,GA2BtFC,CAAAA,CAAS,CAAqB,WAAjB,EAAAhB,CAAD,EAAoD,UAAjB,EAAAA,CA3BuC,CA4BtFiB,CAAc,CAAqB,gBAAjB,EAAAjB,CAAD,EAAyD,UAAjB,EAAAA,CA5B6B,CA8B5F,GAAIiB,CAAc,EAAI,CAACD,CAAvB,CAAkC,OAI9B,GAAAnB,CAAO,CAACU,SAAR,EAAkBW,GAAlB,SAAyBJ,CAAzB,SAA2C,OAA3C,IAEA,MAAOF,CAAAA,OAAO,CAACC,OAAR,EACV,CAED,GAAIG,CAAS,EAAI,CAACC,CAAlB,CAAkC,CAC9BZ,CAAO,CAACE,SAAR,CAAoBO,CAAgB,CAACK,IAAjB,CAAsB,GAAtB,CACvB,CAGD,MAAOC,CAAAA,CAAS,CAACC,gBAAV,CAA2B,2BAA3B,CAAwDhB,CAAxD,EACNiB,IADM,CACD,WAAgB,IAAdC,CAAAA,CAAc,GAAdA,IAAc,CAARC,CAAQ,GAARA,EAAQ,CAClBJ,CAAS,CAACK,kBAAV,CAA6B5B,CAA7B,CAAsC0B,CAAtC,CAA4CC,CAA5C,EAEA,GAAIP,CAAJ,CAAoB,OAChB,GAAApB,CAAO,CAACU,SAAR,EAAkBW,GAAlB,SAAyBJ,CAAzB,SAA2C,OAA3C,GACH,CAGJ,CATM,EAUNY,KAVM,EAWV,C,CAUKC,CAAa,CAAG,SAACC,CAAD,CAAW5B,CAAX,CAAuD,IAA7B6B,CAAAA,CAA6B,2DAEzE,MAAOjB,CAAAA,OAAO,CAACkB,GAAR,CAAYC,CAAe,CAACH,CAAD,CAAWC,CAAX,CAA3B,EACNP,IADM,CACD,WAA+B,kBAA7BU,CAA6B,MAAhBC,CAAgB,QAEHC,CAAc,CAACF,CAAD,CAAcC,CAAd,CAFX,CAE1BhC,CAF0B,GAE1BA,QAF0B,CAEhBC,CAFgB,GAEhBA,SAFgB,CAIjC8B,CAAW,CAACG,OAAZ,CAAoB,SAAAC,CAAO,CAAI,CAC3B,GAAMvC,CAAAA,CAAO,CAAGwC,QAAQ,CAACC,aAAT,oBAAmCF,CAAO,CAACA,OAA3C,cAAhB,CACA,GAAI,CAACvC,CAAL,CAAc,CACV,MACH,CAEDD,CAAc,CAACC,CAAD,CAAUuC,CAAO,CAACG,SAAlB,CAA6BH,CAAO,CAACI,SAArC,CAAgDxC,CAAhD,CAA+DC,CAA/D,CAAyEC,CAAzE,CACjB,CAPD,EASA+B,CAAU,CAACE,OAAX,CAAmB,SAAAM,CAAM,CAAI,CACzB,GAAM5C,CAAAA,CAAO,CAAGwC,QAAQ,CAACK,cAAT,kBAAkCD,CAAM,CAACE,IAAzC,EAAhB,CACA,GAAI,CAAC9C,CAAL,CAAc,CACV,MACH,CAEDD,CAAc,CAACC,CAAD,CAAU4C,CAAM,CAACF,SAAjB,CAA4BE,CAAM,CAACD,SAAnC,CAA8CxC,CAA9C,CAA6DC,CAA7D,CAAuEC,CAAvE,CACjB,CAPD,EAUA,GAAAmC,QAAQ,CAACC,aAAT,CAAuB,iBAAvB,EAA0C/B,SAA1C,EAAoDqC,MAApD,SAA8D,CAAC,cAAD,CAA9D,EACA,GAAAP,QAAQ,CAACC,aAAT,CAAuB,iBAAvB,EAA0C/B,SAA1C,EAAoDW,GAApD,SAA2D,CAAC,QAAD,CAA3D,EAEA,MAAO,CACHc,WAAW,CAAXA,CADG,CAEHC,UAAU,CAAVA,CAFG,CAIV,CA/BM,EAgCNP,KAhCM,CAgCAmB,WAhCA,CAiCV,C,CAQKC,CAAa,CAAG,UAA8B,SAA7BjB,CAA6B,2DAEhDQ,QAAQ,CAACU,gBAAT,CAA0B,0BAA1B,EAAsDZ,OAAtD,CAA8D,SAAAa,CAAI,QAAIA,CAAAA,CAAI,CAACJ,MAAL,EAAJ,CAAlE,EAEA,GAAMrC,CAAAA,CAAS,CAAG,CACd,oBADc,CAEd,4BAFc,CAGd,4BAHc,CAId,2BAJc,CAKd,yBALc,CAAlB,CASA8B,QAAQ,CAACU,gBAAT,CAA0B,qBAA1B,EAAiDZ,OAAjD,CAAyD,SAAAa,CAAI,cAAI,GAAAA,CAAI,CAACzC,SAAL,EAAeqC,MAAf,SAAyBrC,CAAzB,CAAJ,CAA7D,EAEA,GAAIsB,CAAJ,CAAsB,CAClBoB,CAAwB,IAC3B,CAGD,GAAAZ,QAAQ,CAACC,aAAT,CAAuB,iBAAvB,EAA0C/B,SAA1C,EAAoDqC,MAApD,SAA8D,CAAC,QAAD,CAA9D,EACA,GAAAP,QAAQ,CAACC,aAAT,CAAuB,iBAAvB,EAA0C/B,SAA1C,EAAoDW,GAApD,SAA2D,CAAC,cAAD,CAA3D,CACH,C,CASKgC,CAAe,CAAG,SAACtB,CAAD,CAAW5B,CAAX,CAA6B,CACjDL,CAAW,CAAG,CAACA,CAAf,CACA,GAAI,CAACA,CAAL,CAAkB,CACdmD,CAAa,IAChB,CAFD,IAEO,CACHnB,CAAa,CAACC,CAAD,CAAW5B,CAAX,IAChB,CACJ,C,CASKkC,CAAc,CAAG,SAACF,CAAD,CAAcC,CAAd,CAA6B,CAChD,GAAMkB,CAAAA,CAAM,CAAG,CACXC,WAAW,CAAE,CADF,CAEXC,UAAU,CAAE,CAFD,CAGXpD,QAAQ,CAAE,CAHC,CAIXqD,QAAQ,CAAE,CAJC,CAKXpD,SAAS,CAAE,CALA,CAAf,CAQA,GAAGqD,MAAH,CAAUvB,CAAV,CAAuBC,CAAvB,EAAmCE,OAAnC,CAA2C,SAAAqB,CAAI,CAAI,CAC/CL,CAAM,CAACC,WAAP,EAAsBI,CAAI,CAACjB,SAA3B,CACA,GAAIiB,CAAI,CAACjB,SAAL,CAAiBY,CAAM,CAAClD,QAA5B,CAAsC,CAClCkD,CAAM,CAAClD,QAAP,CAAkBuD,CAAI,CAACjB,SAC1B,CAED,GAAIiB,CAAI,CAACjB,SAAL,CAAiBY,CAAM,CAACG,QAA5B,CAAsC,CAClCH,CAAM,CAACG,QAAP,CAAkBE,CAAI,CAACjB,SAC1B,CACDY,CAAM,CAACE,UAAP,EAAqBG,CAAI,CAAChB,SAC7B,CAVD,EAYAW,CAAM,CAACjD,SAAP,CAAmBiD,CAAM,CAACG,QAAP,CAAkBH,CAAM,CAAClD,QAAzB,CAAoC,CAAvD,CAEA,MAAOkD,CAAAA,CACV,C,CAEKM,CAAsB,CAAG,SAAC7B,CAAD,CAAW5B,CAAX,CAA6B,CACxDqC,QAAQ,CAACqB,gBAAT,CAA0B,OAA1B,CAAmC,SAAAC,CAAC,CAAI,CACpC,GAAIA,CAAC,CAACC,MAAF,CAASC,OAAT,CAAiB,mBAAjB,CAAJ,CAA2C,CACvCF,CAAC,CAACG,cAAF,GACAZ,CAAe,CAACtB,CAAD,CAAW5B,CAAX,CAClB,CACJ,CALD,CAMH,C,CAQK+D,CAAyB,CAAG,SAAApE,CAAW,CAAI,CAC7C,MAAO,CACHqE,UAAU,CAAE,mCADT,CAEHC,IAAI,CAAE,CACFC,WAAW,CAAE,CAAC,CACVC,IAAI,CAAE,+BADI,CAEVC,KAAK,CAAEzE,CAFG,CAAD,CADX,CAFH,CASV,C,CAEKsD,CAAwB,CAAG,SAAAtD,CAAW,QAAI,WAAU,CAACoE,CAAyB,CAACpE,CAAD,CAA1B,CAAV,CAAJ,C,CAStCoC,CAAe,CAAG,SAACsC,CAAD,CAAwC,IAA7BxC,CAAAA,CAA6B,2DACtDyC,CAAK,CAAG,CACV,CACIN,UAAU,CAAE,qCADhB,CAEIC,IAAI,CAAE,CAACI,QAAQ,CAARA,CAAD,CAFV,CADU,CAKV,CACIL,UAAU,CAAE,oCADhB,CAEIC,IAAI,CAAE,CAACI,QAAQ,CAARA,CAAD,CAFV,CALU,CAD8C,CAY5D,GAAIxC,CAAJ,CAAsB,CAClByC,CAAK,CAACvD,IAAN,CAAWgD,CAAyB,IAApC,CACH,CAED,MAAO,WAAUO,CAAV,CACV,C,CASYC,CAAI,CAAG,SAACC,CAAD,CAAUxE,CAAV,CAAyB4B,CAAzB,CAAsC,CAEtDjC,CAAW,CAAc,CAAX,EAAA6E,CAAd,CAEA,GAAI7E,CAAJ,CAAiB,CACbgC,CAAa,CAACC,CAAD,CAAW5B,CAAX,CAChB,CAEDyD,CAAsB,CAAC7B,CAAD,CAAW5B,CAAX,CACzB,C","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/**\n *\n * @package block_accessreview\n * @author Max Larkin \n * @copyright 2020 Brickfield Education Labs \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {call as fetchMany} from 'core/ajax';\nimport * as Templates from 'core/templates';\nimport {exception as displayError} from 'core/notification';\n\n/**\n * The number of colours used to represent the heatmap. (Indexed on 0.)\n * @type {number}\n */\nconst numColours = 2;\n\n/**\n * The toggle state of the heatmap.\n * @type {boolean}\n */\nlet toggleState = true;\n\n/**\n * Renders the HTML template onto a particular HTML element.\n * @param {HTMLElement} element The element to attach the HTML to.\n * @param {number} errorCount The number of errors on this module/section.\n * @param {number} checkCount The number of checks triggered on this module/section.\n * @param {String} displayFormat\n * @param {Number} minViews\n * @param {Number} viewDelta\n * @returns {Promise}\n */\nconst renderTemplate = (element, errorCount, checkCount, displayFormat, minViews, viewDelta) => {\n // Calculate a weight?\n const weight = parseInt((errorCount - minViews) / viewDelta * numColours);\n\n const context = {\n resultPassed: !errorCount,\n classList: '',\n passRate: {\n errorCount,\n checkCount,\n failureRate: Math.round(errorCount / checkCount * 100),\n },\n };\n\n if (!element) {\n return Promise.resolve();\n }\n\n const elementClassList = ['block_accessreview'];\n if (context.resultPassed) {\n elementClassList.push('block_accessreview_success');\n } else if (weight) {\n elementClassList.push('block_accessreview_danger');\n } else {\n elementClassList.push('block_accessreview_warning');\n }\n\n const showIcons = (displayFormat == 'showicons') || (displayFormat == 'showboth');\n const showBackground = (displayFormat == 'showbackground') || (displayFormat == 'showboth');\n\n if (showBackground && !showIcons) {\n // Only the background is displayed.\n // No need to display the template.\n // Note: The case where both the background and icons are shown is handled later to avoid jankiness.\n element.classList.add(...elementClassList, 'alert');\n\n return Promise.resolve();\n }\n\n if (showIcons && !showBackground) {\n context.classList = elementClassList.join(' ');\n }\n\n // The icons are displayed either with, or without, the background.\n return Templates.renderForPromise('block_accessreview/status', context)\n .then(({html, js}) => {\n Templates.appendNodeContents(element, html, js);\n\n if (showBackground) {\n element.classList.add(...elementClassList, 'alert');\n }\n\n return;\n })\n .catch();\n};\n\n/**\n * Applies the template to all sections and modules on the course page.\n *\n * @param {Number} courseId\n * @param {String} displayFormat\n * @param {Boolean} updatePreference\n * @returns {Promise}\n */\nconst showAccessMap = (courseId, displayFormat, updatePreference = false) => {\n // Get error data.\n return Promise.all(fetchReviewData(courseId, updatePreference))\n .then(([sectionData, moduleData]) => {\n // Get total data.\n const {minViews, viewDelta} = getErrorTotals(sectionData, moduleData);\n\n sectionData.forEach(section => {\n const element = document.querySelector(`#section-${section.section} .summary`);\n if (!element) {\n return;\n }\n\n renderTemplate(element, section.numerrors, section.numchecks, displayFormat, minViews, viewDelta);\n });\n\n moduleData.forEach(module => {\n const element = document.getElementById(`module-${module.cmid}`);\n if (!element) {\n return;\n }\n\n renderTemplate(element, module.numerrors, module.numchecks, displayFormat, minViews, viewDelta);\n });\n\n // Change the icon display.\n document.querySelector('.icon-accessmap').classList.remove(...['fa-eye-slash']);\n document.querySelector('.icon-accessmap').classList.add(...['fa-eye']);\n\n return {\n sectionData,\n moduleData,\n };\n })\n .catch(displayError);\n};\n\n\n/**\n * Hides or removes the templates from the HTML of the current page.\n *\n * @param {Boolean} updatePreference\n */\nconst hideAccessMap = (updatePreference = false) => {\n // Removes the added elements.\n document.querySelectorAll('.block_accessreview_view').forEach(node => node.remove());\n\n const classList = [\n 'block_accessreview',\n 'block_accessreview_success',\n 'block_accessreview_warning',\n 'block_accessreview_danger',\n 'block_accessreview_view',\n ];\n\n // Removes the added classes.\n document.querySelectorAll('.block_accessreview').forEach(node => node.classList.remove(...classList));\n\n if (updatePreference) {\n setToggleStatePreference(false);\n }\n\n // Change the icon display.\n document.querySelector('.icon-accessmap').classList.remove(...['fa-eye']);\n document.querySelector('.icon-accessmap').classList.add(...['fa-eye-slash']);\n};\n\n\n/**\n * Toggles the heatmap on/off.\n *\n * @param {Number} courseId\n * @param {String} displayFormat\n */\nconst toggleAccessMap = (courseId, displayFormat) => {\n toggleState = !toggleState;\n if (!toggleState) {\n hideAccessMap(true);\n } else {\n showAccessMap(courseId, displayFormat, true);\n }\n};\n\n/**\n * Parses information on the errors, generating the min, max and totals.\n *\n * @param {Object[]} sectionData The error data for course sections.\n * @param {Object[]} moduleData The error data for course modules.\n * @returns {Object} An object representing the extra error information.\n*/\nconst getErrorTotals = (sectionData, moduleData) => {\n const totals = {\n totalErrors: 0,\n totalUsers: 0,\n minViews: 0,\n maxViews: 0,\n viewDelta: 0,\n };\n\n [].concat(sectionData, moduleData).forEach(item => {\n totals.totalErrors += item.numerrors;\n if (item.numerrors < totals.minViews) {\n totals.minViews = item.numerrors;\n }\n\n if (item.numerrors > totals.maxViews) {\n totals.maxViews = item.numerrors;\n }\n totals.totalUsers += item.numchecks;\n });\n\n totals.viewDelta = totals.maxViews - totals.minViews + 1;\n\n return totals;\n};\n\nconst registerEventListeners = (courseId, displayFormat) => {\n document.addEventListener('click', e => {\n if (e.target.closest('#toggle-accessmap')) {\n e.preventDefault();\n toggleAccessMap(courseId, displayFormat);\n }\n });\n};\n\n/**\n * Set the user preference for the toggle value.\n *\n * @param {Boolean} toggleState\n * @returns {Promise}\n */\nconst getTogglePreferenceParams = toggleState => {\n return {\n methodname: 'core_user_update_user_preferences',\n args: {\n preferences: [{\n type: 'block_accessreviewtogglestate',\n value: toggleState,\n }],\n }\n };\n};\n\nconst setToggleStatePreference = toggleState => fetchMany([getTogglePreferenceParams(toggleState)]);\n\n/**\n * Fetch the review data.\n *\n * @param {Number} courseid\n * @param {Boolean} updatePreference\n * @returns {Promise[]}\n */\nconst fetchReviewData = (courseid, updatePreference = false) => {\n const calls = [\n {\n methodname: 'block_accessreview_get_section_data',\n args: {courseid}\n },\n {\n methodname: 'block_accessreview_get_module_data',\n args: {courseid}\n },\n ];\n\n if (updatePreference) {\n calls.push(getTogglePreferenceParams(true));\n }\n\n return fetchMany(calls);\n};\n\n/**\n * Setting up the access review module.\n * @param {number} toggled A number represnting the state of the review toggle.\n * @param {string} displayFormat A string representing the display format for icons.\n * @param {number} courseId The course ID.\n * @param {number} userId The id of the currently logged-in user.\n */\nexport const init = (toggled, displayFormat, courseId) => {\n // Settings consts.\n toggleState = toggled == 1;\n\n if (toggleState) {\n showAccessMap(courseId, displayFormat);\n }\n\n registerEventListeners(courseId, displayFormat);\n};\n"],"file":"module.min.js"} \ No newline at end of file diff --git a/blocks/accessreview/amd/src/module.js b/blocks/accessreview/amd/src/module.js index bbc45ee43eb..b62a7f9a67d 100755 --- a/blocks/accessreview/amd/src/module.js +++ b/blocks/accessreview/amd/src/module.js @@ -137,6 +137,10 @@ const showAccessMap = (courseId, displayFormat, updatePreference = false) => { renderTemplate(element, module.numerrors, module.numchecks, displayFormat, minViews, viewDelta); }); + // Change the icon display. + document.querySelector('.icon-accessmap').classList.remove(...['fa-eye-slash']); + document.querySelector('.icon-accessmap').classList.add(...['fa-eye']); + return { sectionData, moduleData, @@ -169,6 +173,10 @@ const hideAccessMap = (updatePreference = false) => { if (updatePreference) { setToggleStatePreference(false); } + + // Change the icon display. + document.querySelector('.icon-accessmap').classList.remove(...['fa-eye']); + document.querySelector('.icon-accessmap').classList.add(...['fa-eye-slash']); }; diff --git a/blocks/accessreview/block_accessreview.php b/blocks/accessreview/block_accessreview.php index 9bd366871c4..a6478bfc746 100755 --- a/blocks/accessreview/block_accessreview.php +++ b/blocks/accessreview/block_accessreview.php @@ -232,10 +232,16 @@ class block_accessreview extends block_base { protected function get_toggle_link(): string { global $OUTPUT; + if (get_user_preferences('block_accessreviewtogglestate')) { + $icon = 't/hide'; + } else { + $icon = 't/show'; + } + // Toggle overlay link. return html_writer::link( '#', - $OUTPUT->pix_icon('t/hide', get_string('togglealt', 'block_accessreview')), + $OUTPUT->pix_icon($icon, get_string('togglealt', 'block_accessreview'), 'moodle', ['class' => 'icon-accessmap']), [ 'title' => get_string('togglealt', 'block_accessreview'), 'style' => 'cursor: pointer;',