From d1f0ca6e3c06fe71c7d8fca2237ab1a0df4ebe23 Mon Sep 17 00:00:00 2001 From: Michael Hawkins Date: Tue, 27 Oct 2020 18:51:28 +0800 Subject: [PATCH] MDL-70033 course: Update download content event handling for Classic --- course/amd/build/downloadcontent.min.js | 2 +- course/amd/build/downloadcontent.min.js.map | 2 +- course/amd/src/downloadcontent.js | 10 +++++----- course/classes/output/content_export_link.php | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/course/amd/build/downloadcontent.min.js b/course/amd/build/downloadcontent.min.js index 8e9932041e9..901c7c8b6d2 100644 --- a/course/amd/build/downloadcontent.min.js +++ b/course/amd/build/downloadcontent.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 ("core_course/downloadcontent",["exports","core/config","core/custom_interaction_events","core/modal_factory","jquery","core/pending"],function(a,b,c,d,e,f){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=i(b);c=i(c);d=h(d);e=i(e);f=i(f);function g(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;g=function(){return a};return a}function h(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=g();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function i(a){return a&&a.__esModule?a:{default:a}}var j=function(){var a=new f.default;document.addEventListener("click",function(a){var b=a.target.closest("[data-downloadcourse]");if(b){a.preventDefault();k(b)}});a.resolve()};a.init=j;var k=function(a){d.create({title:a.dataset.downloadTitle,type:d.types.SAVE_CANCEL,body:"

".concat(a.dataset.downloadBody,"

"),buttons:{save:a.dataset.downloadButtonText},templateContext:{classes:"downloadcoursecontentmodal"}}).then(function(b){b.show();var d=document.querySelector(".modal .downloadcoursecontentmodal [data-action=\"save\"]"),f=document.querySelector(".modal .downloadcoursecontentmodal [data-action=\"cancel\"]"),g=document.querySelector(".modal[data-region=\"modal-container\"]");(0,e.default)(d).on(c.default.events.activate,function(c){return l(c,a,b)});(0,e.default)(f).on(c.default.events.activate,function(){b.destroy()});if(g.querySelector(".downloadcoursecontentmodal")){(0,e.default)(g).on(c.default.events.activate,function(){b.destroy()})}})},l=function(a,c,d){a.preventDefault();var e=document.createElement("form");e.action=c.dataset.downloadLink;e.method="POST";e.target="_blank";var f=document.createElement("input");f.name="sesskey";f.value=b.default.sesskey;e.appendChild(f);e.style.display="none";document.body.appendChild(e);e.submit();document.body.removeChild(e);d.destroy()}}); +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 ("core_course/downloadcontent",["exports","core/config","core/custom_interaction_events","core/modal_factory","jquery","core/pending","core/key_codes"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=j(b);c=j(c);d=i(d);e=j(e);f=j(f);function h(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;h=function(){return a};return a}function i(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=h();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function j(a){return a&&a.__esModule?a:{default:a}}var k=function(){var a=new f.default;(0,e.default)("[data-downloadcourse]").on("click keydown",function(a){if("click"===a.type||a.which===g.enter||a.which===g.space){a.preventDefault();l(a.currentTarget)}});a.resolve()};a.init=k;var l=function(a){d.create({title:a.dataset.downloadTitle,type:d.types.SAVE_CANCEL,body:"

".concat(a.dataset.downloadBody,"

"),buttons:{save:a.dataset.downloadButtonText},templateContext:{classes:"downloadcoursecontentmodal"}}).then(function(b){b.show();var d=document.querySelector(".modal .downloadcoursecontentmodal [data-action=\"save\"]"),f=document.querySelector(".modal .downloadcoursecontentmodal [data-action=\"cancel\"]"),g=document.querySelector(".modal[data-region=\"modal-container\"]");(0,e.default)(d).on(c.default.events.activate,function(c){return m(c,a,b)});(0,e.default)(f).on(c.default.events.activate,function(){b.destroy()});if(g.querySelector(".downloadcoursecontentmodal")){(0,e.default)(g).on(c.default.events.activate,function(){b.destroy()})}})},m=function(a,c,d){a.preventDefault();var e=document.createElement("form");e.action=c.dataset.downloadLink;e.method="POST";e.target="_blank";var f=document.createElement("input");f.name="sesskey";f.value=b.default.sesskey;e.appendChild(f);e.style.display="none";document.body.appendChild(e);e.submit();document.body.removeChild(e);d.destroy()}}); //# sourceMappingURL=downloadcontent.min.js.map diff --git a/course/amd/build/downloadcontent.min.js.map b/course/amd/build/downloadcontent.min.js.map index 29cc63d7624..b6c5863f84f 100644 --- a/course/amd/build/downloadcontent.min.js.map +++ b/course/amd/build/downloadcontent.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/downloadcontent.js"],"names":["init","pendingPromise","Pending","document","addEventListener","e","downloadModalTrigger","target","closest","preventDefault","displayDownloadConfirmation","resolve","ModalFactory","create","title","dataset","downloadTitle","type","types","SAVE_CANCEL","body","downloadBody","buttons","save","downloadButtonText","templateContext","classes","then","modal","show","saveButton","querySelector","cancelButton","modalContainer","on","CustomEvents","events","activate","downloadContent","destroy","downloadForm","createElement","action","downloadLink","method","downloadSesskey","name","value","Config","sesskey","appendChild","style","display","submit","removeChild"],"mappings":"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","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 * Functions related to downloading course content.\n *\n * @module core_course/downloadcontent\n * @package core_course\n * @copyright 2020 Michael Hawkins \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Config from 'core/config';\nimport CustomEvents from 'core/custom_interaction_events';\nimport * as ModalFactory from 'core/modal_factory';\nimport jQuery from 'jquery';\nimport Pending from 'core/pending';\n\n/**\n * Set up listener to trigger the download course content modal.\n *\n * @return {void}\n */\nexport const init = () => {\n const pendingPromise = new Pending();\n\n document.addEventListener('click', (e) => {\n const downloadModalTrigger = e.target.closest('[data-downloadcourse]');\n\n if (downloadModalTrigger) {\n e.preventDefault();\n displayDownloadConfirmation(downloadModalTrigger);\n }\n });\n\n pendingPromise.resolve();\n};\n\n/**\n * Display the download course content modal.\n *\n * @method displayDownloadConfirmation\n * @param {Object} downloadModalTrigger The DOM element that triggered the download modal.\n * @return {void}\n */\nconst displayDownloadConfirmation = (downloadModalTrigger) => {\n ModalFactory.create({\n title: downloadModalTrigger.dataset.downloadTitle,\n type: ModalFactory.types.SAVE_CANCEL,\n body: `

${downloadModalTrigger.dataset.downloadBody}

`,\n buttons: {\n save: downloadModalTrigger.dataset.downloadButtonText\n },\n templateContext: {\n classes: 'downloadcoursecontentmodal'\n }\n })\n .then(modal => {\n // Display the modal.\n modal.show();\n\n const saveButton = document.querySelector('.modal .downloadcoursecontentmodal [data-action=\"save\"]');\n const cancelButton = document.querySelector('.modal .downloadcoursecontentmodal [data-action=\"cancel\"]');\n const modalContainer = document.querySelector('.modal[data-region=\"modal-container\"]');\n\n // Create listener to trigger the download when the \"Download\" button is pressed.\n jQuery(saveButton).on(CustomEvents.events.activate, (e) => downloadContent(e, downloadModalTrigger, modal));\n\n // Create listener to destroy the modal when closing modal by cancelling.\n jQuery(cancelButton).on(CustomEvents.events.activate, () => {\n modal.destroy();\n });\n\n // Create listener to destroy the modal when closing modal by clicking outside of it.\n if (modalContainer.querySelector('.downloadcoursecontentmodal')) {\n jQuery(modalContainer).on(CustomEvents.events.activate, () => {\n modal.destroy();\n });\n }\n });\n};\n\n/**\n * Trigger downloading of course content.\n *\n * @method downloadContent\n * @param {Event} e The event triggering the download.\n * @param {Object} downloadModalTrigger The DOM element that triggered the download modal.\n * @param {Object} modal The modal object.\n * @return {void}\n */\nconst downloadContent = (e, downloadModalTrigger, modal) => {\n e.preventDefault();\n\n // Create a form to submit the file download request, so we can avoid sending sesskey over GET.\n const downloadForm = document.createElement('form');\n downloadForm.action = downloadModalTrigger.dataset.downloadLink;\n downloadForm.method = 'POST';\n // Open download in a new tab, so current course view is not disrupted.\n downloadForm.target = '_blank';\n const downloadSesskey = document.createElement('input');\n downloadSesskey.name = 'sesskey';\n downloadSesskey.value = Config.sesskey;\n downloadForm.appendChild(downloadSesskey);\n downloadForm.style.display = 'none';\n\n document.body.appendChild(downloadForm);\n downloadForm.submit();\n document.body.removeChild(downloadForm);\n\n // Destroy the modal to prevent duplicates if reopened later.\n modal.destroy();\n};\n"],"file":"downloadcontent.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/downloadcontent.js"],"names":["init","pendingPromise","Pending","on","e","type","which","enter","space","preventDefault","displayDownloadConfirmation","currentTarget","resolve","downloadModalTrigger","ModalFactory","create","title","dataset","downloadTitle","types","SAVE_CANCEL","body","downloadBody","buttons","save","downloadButtonText","templateContext","classes","then","modal","show","saveButton","document","querySelector","cancelButton","modalContainer","CustomEvents","events","activate","downloadContent","destroy","downloadForm","createElement","action","downloadLink","method","target","downloadSesskey","name","value","Config","sesskey","appendChild","style","display","submit","removeChild"],"mappings":"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","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 * Functions related to downloading course content.\n *\n * @module core_course/downloadcontent\n * @package core_course\n * @copyright 2020 Michael Hawkins \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Config from 'core/config';\nimport CustomEvents from 'core/custom_interaction_events';\nimport * as ModalFactory from 'core/modal_factory';\nimport jQuery from 'jquery';\nimport Pending from 'core/pending';\nimport {enter, space} from 'core/key_codes';\n\n/**\n * Set up listener to trigger the download course content modal.\n *\n * @return {void}\n */\nexport const init = () => {\n const pendingPromise = new Pending();\n\n // Add event listeners for click and enter/space keys.\n jQuery('[data-downloadcourse]').on('click keydown', (e) => {\n if (e.type === 'click' || e.which === enter || e.which === space) {\n e.preventDefault();\n displayDownloadConfirmation(e.currentTarget);\n }\n });\n\n pendingPromise.resolve();\n};\n\n/**\n * Display the download course content modal.\n *\n * @method displayDownloadConfirmation\n * @param {Object} downloadModalTrigger The DOM element that triggered the download modal.\n * @return {void}\n */\nconst displayDownloadConfirmation = (downloadModalTrigger) => {\n ModalFactory.create({\n title: downloadModalTrigger.dataset.downloadTitle,\n type: ModalFactory.types.SAVE_CANCEL,\n body: `

${downloadModalTrigger.dataset.downloadBody}

`,\n buttons: {\n save: downloadModalTrigger.dataset.downloadButtonText\n },\n templateContext: {\n classes: 'downloadcoursecontentmodal'\n }\n })\n .then(modal => {\n // Display the modal.\n modal.show();\n\n const saveButton = document.querySelector('.modal .downloadcoursecontentmodal [data-action=\"save\"]');\n const cancelButton = document.querySelector('.modal .downloadcoursecontentmodal [data-action=\"cancel\"]');\n const modalContainer = document.querySelector('.modal[data-region=\"modal-container\"]');\n\n // Create listener to trigger the download when the \"Download\" button is pressed.\n jQuery(saveButton).on(CustomEvents.events.activate, (e) => downloadContent(e, downloadModalTrigger, modal));\n\n // Create listener to destroy the modal when closing modal by cancelling.\n jQuery(cancelButton).on(CustomEvents.events.activate, () => {\n modal.destroy();\n });\n\n // Create listener to destroy the modal when closing modal by clicking outside of it.\n if (modalContainer.querySelector('.downloadcoursecontentmodal')) {\n jQuery(modalContainer).on(CustomEvents.events.activate, () => {\n modal.destroy();\n });\n }\n });\n};\n\n/**\n * Trigger downloading of course content.\n *\n * @method downloadContent\n * @param {Event} e The event triggering the download.\n * @param {Object} downloadModalTrigger The DOM element that triggered the download modal.\n * @param {Object} modal The modal object.\n * @return {void}\n */\nconst downloadContent = (e, downloadModalTrigger, modal) => {\n e.preventDefault();\n\n // Create a form to submit the file download request, so we can avoid sending sesskey over GET.\n const downloadForm = document.createElement('form');\n downloadForm.action = downloadModalTrigger.dataset.downloadLink;\n downloadForm.method = 'POST';\n // Open download in a new tab, so current course view is not disrupted.\n downloadForm.target = '_blank';\n const downloadSesskey = document.createElement('input');\n downloadSesskey.name = 'sesskey';\n downloadSesskey.value = Config.sesskey;\n downloadForm.appendChild(downloadSesskey);\n downloadForm.style.display = 'none';\n\n document.body.appendChild(downloadForm);\n downloadForm.submit();\n document.body.removeChild(downloadForm);\n\n // Destroy the modal to prevent duplicates if reopened later.\n modal.destroy();\n};\n"],"file":"downloadcontent.min.js"} \ No newline at end of file diff --git a/course/amd/src/downloadcontent.js b/course/amd/src/downloadcontent.js index 67a6d831f9e..2c5899ab875 100644 --- a/course/amd/src/downloadcontent.js +++ b/course/amd/src/downloadcontent.js @@ -27,6 +27,7 @@ import CustomEvents from 'core/custom_interaction_events'; import * as ModalFactory from 'core/modal_factory'; import jQuery from 'jquery'; import Pending from 'core/pending'; +import {enter, space} from 'core/key_codes'; /** * Set up listener to trigger the download course content modal. @@ -36,12 +37,11 @@ import Pending from 'core/pending'; export const init = () => { const pendingPromise = new Pending(); - document.addEventListener('click', (e) => { - const downloadModalTrigger = e.target.closest('[data-downloadcourse]'); - - if (downloadModalTrigger) { + // Add event listeners for click and enter/space keys. + jQuery('[data-downloadcourse]').on('click keydown', (e) => { + if (e.type === 'click' || e.which === enter || e.which === space) { e.preventDefault(); - displayDownloadConfirmation(downloadModalTrigger); + displayDownloadConfirmation(e.currentTarget); } }); diff --git a/course/classes/output/content_export_link.php b/course/classes/output/content_export_link.php index 6b3deea0ddd..cfa667a7896 100644 --- a/course/classes/output/content_export_link.php +++ b/course/classes/output/content_export_link.php @@ -53,6 +53,7 @@ class content_export_link { 'data-download-button-text' => get_string('download'), 'data-download-link' => $downloadlink->out(false), 'data-download-title' => get_string('downloadcoursecontent', 'course'), + 'data-overrides-tree-activation-key-handler' => 1, ]; return $downloadattr;