ÿØÿà JFIF    ÿÛ „  ( %"1!%)+...383,7(-.+  -+++--++++---+-+-----+---------------+---+-++7-----ÿÀ  ß â" ÿÄ     ÿÄ H    !1AQaq"‘¡2B±ÁÑð#R“Ò Tbr‚²á3csƒ’ÂñDS¢³$CÿÄ   ÿÄ %  !1AQa"23‘ÿÚ   ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6  öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ "Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷󲍷˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz ¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%ÌÁ²h´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ǍýʏTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆѪQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»& î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$˝Úsäÿ ÷Û #°xŸëí(l »ý3—¥5m! rt`†0~'j2(]S¦¦kv,ÚÇ l¦øJA£Šƒ J3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡* ….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉ䢍mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±b Lô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U  Z©RÊ ÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD é©¤&‡ïDbàÁôMÁ.// This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /** * Submit button JavaScript. All submit buttons will be automatically disabled once the form is * submitted, unless that submission results in an error/cancelling the submit. * * @module core_form/submit * @copyright 2019 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since 3.8 */ import {eventTypes} from 'core_form/events'; /** @property {number} ID for setInterval used when polling for download cookie */ let cookieListener = 0; /** @property {Array} Array of buttons that need re-enabling if we get a download cookie */ const cookieListeningButtons = []; /** @property {number} Number of files uploading. */ let currentUploadCount = 0; /** @property {Array} Array of buttons that need re-enabling if we get a upload process. */ const uploadListeningButtons = []; /** @property {Boolean} Is upload listeners registered? */ let uploadListenersRegistered = false; /** * Listens in case a download cookie is provided. * * This function is used to detect file downloads. If there is a file download then we get a * beforeunload event, but the page is never unloaded and when the file download completes we * should re-enable the buttons. We detect this by watching for a specific cookie. * * PHP function \core_form\util::form_download_complete() can be used to send this cookie. * * @param {HTMLElement} button Button to re-enable */ const listenForDownloadCookie = (button) => { cookieListeningButtons.push(button); if (!cookieListener) { cookieListener = setInterval(() => { // Look for cookie. const parts = document.cookie.split(getCookieName() + '='); if (parts.length == 2) { // We found the cookie, so the file is ready. Expire the cookie and cancel polling. clearDownloadCookie(); clearInterval(cookieListener); cookieListener = 0; // Re-enable all the buttons. cookieListeningButtons.forEach((button) => { button.disabled = false; }); } }, 500); } }; /** * Gets a unique name for the download cookie. * * @returns {string} Cookie name */ const getCookieName = () => { return 'moodledownload_' + M.cfg.sesskey; }; /** * Clears the download cookie if there is one. */ const clearDownloadCookie = () => { document.cookie = encodeURIComponent(getCookieName()) + '=deleted; expires=' + new Date(0).toUTCString(); }; /** * Enable submit buttons when all files are uploaded. */ const checkUploadCount = () => { if (currentUploadCount) { uploadListeningButtons.forEach(button => { button.disabled = true; }); } else { uploadListeningButtons.forEach(button => { button.disabled = false; }); } }; /** * Initialises submit buttons. * * @param {String} elementId Form button element * @listens event:uploadStarted * @listens event:uploadCompleted */ export const init = (elementId) => { const button = document.getElementById(elementId); if (button === null) { // Exit early if invalid element id passed. return; } // If buttons are disabled by default, we do not enable them when file upload completed event is fired. if (!button.disabled) { uploadListeningButtons.push(button); } if (!uploadListenersRegistered) { // Add event listener for file upload start. document.addEventListener(eventTypes.uploadStarted, () => { currentUploadCount++; checkUploadCount(); }); // Add event listener for file upload complete. document.addEventListener(eventTypes.uploadCompleted, () => { currentUploadCount--; checkUploadCount(); }); uploadListenersRegistered = true; } // If the form has double submit protection disabled, do nothing. if (button.form.dataset.doubleSubmitProtection === 'off') { return; } button.form.addEventListener('submit', function(event) { // Only disable it if the browser is really going to another page as a result of the // submit. const disableAction = function() { // If the submit was cancelled, or the button is already disabled, don't do anything. if (event.defaultPrevented || button.disabled) { return; } button.disabled = true; clearDownloadCookie(); listenForDownloadCookie(button); }; window.addEventListener('beforeunload', disableAction); // If there is no beforeunload event as a result of this form submit, then the form // submit must have been cancelled, so don't disable the button if the page is // unloaded later. setTimeout(function() { window.removeEventListener('beforeunload', disableAction); }, 1); }, false); };