diff --git a/lib/amd/build/togglesensitive.min.js b/lib/amd/build/togglesensitive.min.js index 60aaba458c1..9a17394595d 100644 --- a/lib/amd/build/togglesensitive.min.js +++ b/lib/amd/build/togglesensitive.min.js @@ -1,10 +1,10 @@ -define("core/togglesensitive",["exports","core/pagehelpers","core/templates","core/pending","core/prefetch","core/notification"],(function(_exports,_pagehelpers,_templates,_pending,_prefetch,_notification){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +define("core/togglesensitive",["exports","core/pagehelpers","core/templates","core/pending","core/prefetch","core/notification","core_form/events"],(function(_exports,_pagehelpers,_templates,_pending,_prefetch,_notification,_events){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} /** * JS module for toggling the sensitive input visibility (e.g. passwords, keys). * * @module core/togglesensitive * @copyright 2023 David Woloszyn * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending),_prefetch=_interopRequireDefault(_prefetch),_notification=_interopRequireDefault(_notification);const SELECTORS_BUTTON=".toggle-sensitive-btn",PIX_EYE="t/hide",PIX_EYE_SLASH="t/show";let sensitiveElementId,smallScreensOnly;_exports.init=function(elementId){let isSmallScreensOnly=arguments.length>1&&void 0!==arguments[1]&&arguments[1];const sensitiveInput=document.getElementById(elementId);null!==sensitiveInput&&(sensitiveElementId=elementId,smallScreensOnly=isSmallScreensOnly,_prefetch.default.prefetchTemplate("core/form_input_toggle_sensitive"),renderSensitiveToggle(sensitiveInput).then((()=>{})).catch(_notification.default.exception),registerListenerEvents())};const renderSensitiveToggle=async sensitiveInput=>{const{html:html}=await _templates.default.renderForPromise("core/form_input_toggle_sensitive",{smallscreensonly:smallScreensOnly,sensitiveinput:sensitiveInput.outerHTML});sensitiveInput.outerHTML=html},registerListenerEvents=()=>{document.addEventListener("click",handleButtonInteraction),smallScreensOnly&&window.addEventListener("resize",handleScreenResizing)},handleButtonInteraction=event=>{const toggleButton=event.target.closest(SELECTORS_BUTTON);if(toggleButton){const sensitiveInput=document.getElementById(sensitiveElementId);toggleSensitiveVisibility(sensitiveInput,toggleButton)}},handleScreenResizing=()=>{if(!(0,_pagehelpers.isExtraSmall)()){const sensitiveInput=document.getElementById(sensitiveElementId),toggleButton=sensitiveInput.parentNode.querySelector(SELECTORS_BUTTON);toggleSensitiveVisibility(sensitiveInput,toggleButton,!0)}},toggleSensitiveVisibility=function(sensitiveInput,toggleButton){let force=arguments.length>2&&void 0!==arguments[2]&&arguments[2];const pendingPromise=new _pending.default("core/togglesensitive:toggle");let type,icon;!0===force?(type="password",icon=PIX_EYE):(type="password"===sensitiveInput.getAttribute("type")?"text":"password",icon="password"===sensitiveInput.getAttribute("type")?PIX_EYE_SLASH:PIX_EYE),sensitiveInput.setAttribute("type",type),_templates.default.renderPix(icon,"core").then((icon=>{toggleButton.innerHTML=icon,pendingPromise.resolve()})).catch(_notification.default.exception)}})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending),_prefetch=_interopRequireDefault(_prefetch),_notification=_interopRequireDefault(_notification);const SELECTORS_BUTTON=".toggle-sensitive-btn",PIX_EYE="t/hide",PIX_EYE_SLASH="t/show";let sensitiveElementId,smallScreensOnly;_exports.init=function(elementId){let isSmallScreensOnly=arguments.length>1&&void 0!==arguments[1]&&arguments[1];const sensitiveInput=document.getElementById(elementId);null!==sensitiveInput&&(sensitiveElementId=elementId,smallScreensOnly=isSmallScreensOnly,_prefetch.default.prefetchTemplate("core/form_input_toggle_sensitive"),renderSensitiveToggle(sensitiveInput).then((()=>{(0,_events.notifyFieldStructureChanged)(sensitiveInput.id)})).catch(_notification.default.exception),registerListenerEvents())};const renderSensitiveToggle=async sensitiveInput=>{const{html:html}=await _templates.default.renderForPromise("core/form_input_toggle_sensitive",{smallscreensonly:smallScreensOnly,sensitiveinput:sensitiveInput.outerHTML});sensitiveInput.outerHTML=html},registerListenerEvents=()=>{document.addEventListener("click",handleButtonInteraction),smallScreensOnly&&window.addEventListener("resize",handleScreenResizing)},handleButtonInteraction=event=>{const toggleButton=event.target.closest(SELECTORS_BUTTON);if(toggleButton){const sensitiveInput=document.getElementById(sensitiveElementId);toggleSensitiveVisibility(sensitiveInput,toggleButton)}},handleScreenResizing=()=>{if(!(0,_pagehelpers.isExtraSmall)()){const sensitiveInput=document.getElementById(sensitiveElementId),toggleButton=sensitiveInput.parentNode.querySelector(SELECTORS_BUTTON);toggleSensitiveVisibility(sensitiveInput,toggleButton,!0)}},toggleSensitiveVisibility=function(sensitiveInput,toggleButton){let force=arguments.length>2&&void 0!==arguments[2]&&arguments[2];const pendingPromise=new _pending.default("core/togglesensitive:toggle");let type,icon;!0===force?(type="password",icon=PIX_EYE):(type="password"===sensitiveInput.getAttribute("type")?"text":"password",icon="password"===sensitiveInput.getAttribute("type")?PIX_EYE_SLASH:PIX_EYE),sensitiveInput.setAttribute("type",type),_templates.default.renderPix(icon,"core").then((icon=>{toggleButton.innerHTML=icon,pendingPromise.resolve()})).catch(_notification.default.exception)}})); //# sourceMappingURL=togglesensitive.min.js.map \ No newline at end of file diff --git a/lib/amd/build/togglesensitive.min.js.map b/lib/amd/build/togglesensitive.min.js.map index 874832ab0ed..4e652ce8585 100644 --- a/lib/amd/build/togglesensitive.min.js.map +++ b/lib/amd/build/togglesensitive.min.js.map @@ -1 +1 @@ -{"version":3,"file":"togglesensitive.min.js","sources":["../src/togglesensitive.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/**\n * JS module for toggling the sensitive input visibility (e.g. passwords, keys).\n *\n * @module core/togglesensitive\n * @copyright 2023 David Woloszyn \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {isExtraSmall} from 'core/pagehelpers';\nimport Templates from 'core/templates';\nimport Pending from 'core/pending';\nimport Prefetch from 'core/prefetch';\nimport Notification from 'core/notification';\n\nconst SELECTORS = {\n BUTTON: '.toggle-sensitive-btn',\n ICON: '.toggle-sensitive-btn .icon',\n};\n\nconst PIX = {\n EYE: 't/hide',\n EYE_SLASH: 't/show',\n};\n\nlet sensitiveElementId;\nlet smallScreensOnly;\n\n/**\n * Entrypoint of the js.\n *\n * @method init\n * @param {String} elementId Form button element.\n * @param {boolean} isSmallScreensOnly Is this for small screens only?\n */\nexport const init = (elementId, isSmallScreensOnly = false) => {\n const sensitiveInput = document.getElementById(elementId);\n if (sensitiveInput === null) {\n // Exit early if invalid element id passed.\n return;\n }\n sensitiveElementId = elementId;\n smallScreensOnly = isSmallScreensOnly;\n Prefetch.prefetchTemplate('core/form_input_toggle_sensitive');\n // Render the sensitive input with a toggle button.\n renderSensitiveToggle(sensitiveInput).then(() => {\n return;\n }).catch(Notification.exception);\n // Register event listeners.\n registerListenerEvents();\n};\n\n/**\n * Render the new input html with toggle button and update the incoming html.\n *\n * @method renderSensitiveToggle\n * @param {HTMLElement} sensitiveInput HTML element for the sensitive input.\n */\nconst renderSensitiveToggle = async(sensitiveInput) => {\n const {html} = await Templates.renderForPromise(\n 'core/form_input_toggle_sensitive',\n {\n smallscreensonly: smallScreensOnly,\n sensitiveinput: sensitiveInput.outerHTML,\n }\n );\n sensitiveInput.outerHTML = html;\n};\n\n/**\n * Register event listeners.\n *\n * @method registerListenerEvents\n */\nconst registerListenerEvents = () => {\n // Toggle the sensitive input visibility when interacting with the toggle button.\n document.addEventListener('click', handleButtonInteraction);\n // For small screens only, hide all sensitive inputs when the screen is enlarged.\n if (smallScreensOnly) {\n window.addEventListener('resize', handleScreenResizing);\n }\n};\n\n/**\n * Handle events trigger by interacting with the toggle button.\n *\n * @method handleButtonInteraction\n * @param {Event} event The button event.\n */\nconst handleButtonInteraction = (event) => {\n const toggleButton = event.target.closest(SELECTORS.BUTTON);\n if (toggleButton) {\n const sensitiveInput = document.getElementById(sensitiveElementId);\n toggleSensitiveVisibility(sensitiveInput, toggleButton);\n }\n};\n\n/**\n * Handle events trigger by resizing the screen.\n *\n * @method handleScreenResizing\n */\nconst handleScreenResizing = () => {\n if (!isExtraSmall()) {\n const sensitiveInput = document.getElementById(sensitiveElementId);\n const toggleButton = sensitiveInput.parentNode.querySelector(SELECTORS.BUTTON);\n toggleSensitiveVisibility(sensitiveInput, toggleButton, true);\n }\n};\n\n/**\n * Toggle the sensitive input visibility and its associated icon.\n *\n * @method toggleSensitiveVisibility\n * @param {HTMLInputElement} sensitiveInput The sensitive input element.\n * @param {HTMLElement} toggleButton The toggle button.\n * @param {boolean} force Force the input back to password type.\n */\nconst toggleSensitiveVisibility = (sensitiveInput, toggleButton, force = false) => {\n const pendingPromise = new Pending('core/togglesensitive:toggle');\n let type;\n let icon;\n if (force === true) {\n type = 'password';\n icon = PIX.EYE;\n } else {\n type = sensitiveInput.getAttribute('type') === 'password' ? 'text' : 'password';\n icon = sensitiveInput.getAttribute('type') === 'password' ? PIX.EYE_SLASH : PIX.EYE;\n }\n sensitiveInput.setAttribute('type', type);\n Templates.renderPix(icon, 'core').then((icon) => {\n toggleButton.innerHTML = icon;\n pendingPromise.resolve();\n return;\n }).catch(Notification.exception);\n};\n"],"names":["SELECTORS","PIX","sensitiveElementId","smallScreensOnly","elementId","isSmallScreensOnly","sensitiveInput","document","getElementById","prefetchTemplate","renderSensitiveToggle","then","catch","Notification","exception","registerListenerEvents","async","html","Templates","renderForPromise","smallscreensonly","sensitiveinput","outerHTML","addEventListener","handleButtonInteraction","window","handleScreenResizing","event","toggleButton","target","closest","toggleSensitiveVisibility","parentNode","querySelector","force","pendingPromise","Pending","type","icon","getAttribute","setAttribute","renderPix","innerHTML","resolve"],"mappings":";;;;;;;gRA6BMA,iBACM,wBAINC,QACG,SADHA,cAES,aAGXC,mBACAC,+BASgB,SAACC,eAAWC,iFACtBC,eAAiBC,SAASC,eAAeJ,WACxB,OAAnBE,iBAIJJ,mBAAqBE,UACrBD,iBAAmBE,qCACVI,iBAAiB,oCAE1BC,sBAAsBJ,gBAAgBK,MAAK,SAExCC,MAAMC,sBAAaC,WAEtBC,iCASEL,sBAAwBM,MAAAA,uBACpBC,KAACA,YAAcC,mBAAUC,iBAC3B,mCACA,CACIC,iBAAkBjB,iBAClBkB,eAAgBf,eAAegB,YAGvChB,eAAegB,UAAYL,MAQzBF,uBAAyB,KAE3BR,SAASgB,iBAAiB,QAASC,yBAE/BrB,kBACAsB,OAAOF,iBAAiB,SAAUG,uBAUpCF,wBAA2BG,cACvBC,aAAeD,MAAME,OAAOC,QAAQ9B,qBACtC4B,aAAc,OACRtB,eAAiBC,SAASC,eAAeN,oBAC/C6B,0BAA0BzB,eAAgBsB,gBAS5CF,qBAAuB,UACpB,+BAAgB,OACXpB,eAAiBC,SAASC,eAAeN,oBACzC0B,aAAetB,eAAe0B,WAAWC,cAAcjC,kBAC7D+B,0BAA0BzB,eAAgBsB,cAAc,KAY1DG,0BAA4B,SAACzB,eAAgBsB,kBAAcM,oEACvDC,eAAiB,IAAIC,iBAAQ,mCAC/BC,KACAC,MACU,IAAVJ,OACAG,KAAO,WACPC,KAAOrC,UAEPoC,KAA+C,aAAxC/B,eAAeiC,aAAa,QAAyB,OAAS,WACrED,KAA+C,aAAxChC,eAAeiC,aAAa,QAAyBtC,cAAgBA,SAEhFK,eAAekC,aAAa,OAAQH,yBAC1BI,UAAUH,KAAM,QAAQ3B,MAAM2B,OACpCV,aAAac,UAAYJ,KACzBH,eAAeQ,aAEhB/B,MAAMC,sBAAaC"} \ No newline at end of file +{"version":3,"file":"togglesensitive.min.js","sources":["../src/togglesensitive.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/**\n * JS module for toggling the sensitive input visibility (e.g. passwords, keys).\n *\n * @module core/togglesensitive\n * @copyright 2023 David Woloszyn \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {isExtraSmall} from 'core/pagehelpers';\nimport Templates from 'core/templates';\nimport Pending from 'core/pending';\nimport Prefetch from 'core/prefetch';\nimport Notification from 'core/notification';\nimport {notifyFieldStructureChanged} from 'core_form/events';\n\nconst SELECTORS = {\n BUTTON: '.toggle-sensitive-btn',\n ICON: '.toggle-sensitive-btn .icon',\n};\n\nconst PIX = {\n EYE: 't/hide',\n EYE_SLASH: 't/show',\n};\n\nlet sensitiveElementId;\nlet smallScreensOnly;\n\n/**\n * Entrypoint of the js.\n *\n * @method init\n * @param {String} elementId Form button element.\n * @param {boolean} isSmallScreensOnly Is this for small screens only?\n */\nexport const init = (elementId, isSmallScreensOnly = false) => {\n const sensitiveInput = document.getElementById(elementId);\n if (sensitiveInput === null) {\n // Exit early if invalid element id passed.\n return;\n }\n sensitiveElementId = elementId;\n smallScreensOnly = isSmallScreensOnly;\n Prefetch.prefetchTemplate('core/form_input_toggle_sensitive');\n // Render the sensitive input with a toggle button.\n renderSensitiveToggle(sensitiveInput).then(() => {\n // Dispatch the event indicating the sensitive input has changed.\n notifyFieldStructureChanged(sensitiveInput.id);\n return;\n }).catch(Notification.exception);\n // Register event listeners.\n registerListenerEvents();\n};\n\n/**\n * Render the new input html with toggle button and update the incoming html.\n *\n * @method renderSensitiveToggle\n * @param {HTMLElement} sensitiveInput HTML element for the sensitive input.\n */\nconst renderSensitiveToggle = async(sensitiveInput) => {\n const {html} = await Templates.renderForPromise(\n 'core/form_input_toggle_sensitive',\n {\n smallscreensonly: smallScreensOnly,\n sensitiveinput: sensitiveInput.outerHTML,\n }\n );\n sensitiveInput.outerHTML = html;\n};\n\n/**\n * Register event listeners.\n *\n * @method registerListenerEvents\n */\nconst registerListenerEvents = () => {\n // Toggle the sensitive input visibility when interacting with the toggle button.\n document.addEventListener('click', handleButtonInteraction);\n // For small screens only, hide all sensitive inputs when the screen is enlarged.\n if (smallScreensOnly) {\n window.addEventListener('resize', handleScreenResizing);\n }\n};\n\n/**\n * Handle events trigger by interacting with the toggle button.\n *\n * @method handleButtonInteraction\n * @param {Event} event The button event.\n */\nconst handleButtonInteraction = (event) => {\n const toggleButton = event.target.closest(SELECTORS.BUTTON);\n if (toggleButton) {\n const sensitiveInput = document.getElementById(sensitiveElementId);\n toggleSensitiveVisibility(sensitiveInput, toggleButton);\n }\n};\n\n/**\n * Handle events trigger by resizing the screen.\n *\n * @method handleScreenResizing\n */\nconst handleScreenResizing = () => {\n if (!isExtraSmall()) {\n const sensitiveInput = document.getElementById(sensitiveElementId);\n const toggleButton = sensitiveInput.parentNode.querySelector(SELECTORS.BUTTON);\n toggleSensitiveVisibility(sensitiveInput, toggleButton, true);\n }\n};\n\n/**\n * Toggle the sensitive input visibility and its associated icon.\n *\n * @method toggleSensitiveVisibility\n * @param {HTMLInputElement} sensitiveInput The sensitive input element.\n * @param {HTMLElement} toggleButton The toggle button.\n * @param {boolean} force Force the input back to password type.\n */\nconst toggleSensitiveVisibility = (sensitiveInput, toggleButton, force = false) => {\n const pendingPromise = new Pending('core/togglesensitive:toggle');\n let type;\n let icon;\n if (force === true) {\n type = 'password';\n icon = PIX.EYE;\n } else {\n type = sensitiveInput.getAttribute('type') === 'password' ? 'text' : 'password';\n icon = sensitiveInput.getAttribute('type') === 'password' ? PIX.EYE_SLASH : PIX.EYE;\n }\n sensitiveInput.setAttribute('type', type);\n Templates.renderPix(icon, 'core').then((icon) => {\n toggleButton.innerHTML = icon;\n pendingPromise.resolve();\n return;\n }).catch(Notification.exception);\n};\n"],"names":["SELECTORS","PIX","sensitiveElementId","smallScreensOnly","elementId","isSmallScreensOnly","sensitiveInput","document","getElementById","prefetchTemplate","renderSensitiveToggle","then","id","catch","Notification","exception","registerListenerEvents","async","html","Templates","renderForPromise","smallscreensonly","sensitiveinput","outerHTML","addEventListener","handleButtonInteraction","window","handleScreenResizing","event","toggleButton","target","closest","toggleSensitiveVisibility","parentNode","querySelector","force","pendingPromise","Pending","type","icon","getAttribute","setAttribute","renderPix","innerHTML","resolve"],"mappings":";;;;;;;gRA8BMA,iBACM,wBAINC,QACG,SADHA,cAES,aAGXC,mBACAC,+BASgB,SAACC,eAAWC,iFACtBC,eAAiBC,SAASC,eAAeJ,WACxB,OAAnBE,iBAIJJ,mBAAqBE,UACrBD,iBAAmBE,qCACVI,iBAAiB,oCAE1BC,sBAAsBJ,gBAAgBK,MAAK,6CAEXL,eAAeM,OAE5CC,MAAMC,sBAAaC,WAEtBC,iCASEN,sBAAwBO,MAAAA,uBACpBC,KAACA,YAAcC,mBAAUC,iBAC3B,mCACA,CACIC,iBAAkBlB,iBAClBmB,eAAgBhB,eAAeiB,YAGvCjB,eAAeiB,UAAYL,MAQzBF,uBAAyB,KAE3BT,SAASiB,iBAAiB,QAASC,yBAE/BtB,kBACAuB,OAAOF,iBAAiB,SAAUG,uBAUpCF,wBAA2BG,cACvBC,aAAeD,MAAME,OAAOC,QAAQ/B,qBACtC6B,aAAc,OACRvB,eAAiBC,SAASC,eAAeN,oBAC/C8B,0BAA0B1B,eAAgBuB,gBAS5CF,qBAAuB,UACpB,+BAAgB,OACXrB,eAAiBC,SAASC,eAAeN,oBACzC2B,aAAevB,eAAe2B,WAAWC,cAAclC,kBAC7DgC,0BAA0B1B,eAAgBuB,cAAc,KAY1DG,0BAA4B,SAAC1B,eAAgBuB,kBAAcM,oEACvDC,eAAiB,IAAIC,iBAAQ,mCAC/BC,KACAC,MACU,IAAVJ,OACAG,KAAO,WACPC,KAAOtC,UAEPqC,KAA+C,aAAxChC,eAAekC,aAAa,QAAyB,OAAS,WACrED,KAA+C,aAAxCjC,eAAekC,aAAa,QAAyBvC,cAAgBA,SAEhFK,eAAemC,aAAa,OAAQH,yBAC1BI,UAAUH,KAAM,QAAQ5B,MAAM4B,OACpCV,aAAac,UAAYJ,KACzBH,eAAeQ,aAEhB/B,MAAMC,sBAAaC"} \ No newline at end of file diff --git a/lib/amd/src/togglesensitive.js b/lib/amd/src/togglesensitive.js index 1040b248e41..394778f5f41 100644 --- a/lib/amd/src/togglesensitive.js +++ b/lib/amd/src/togglesensitive.js @@ -26,6 +26,7 @@ import Templates from 'core/templates'; import Pending from 'core/pending'; import Prefetch from 'core/prefetch'; import Notification from 'core/notification'; +import {notifyFieldStructureChanged} from 'core_form/events'; const SELECTORS = { BUTTON: '.toggle-sensitive-btn', @@ -58,6 +59,8 @@ export const init = (elementId, isSmallScreensOnly = false) => { Prefetch.prefetchTemplate('core/form_input_toggle_sensitive'); // Render the sensitive input with a toggle button. renderSensitiveToggle(sensitiveInput).then(() => { + // Dispatch the event indicating the sensitive input has changed. + notifyFieldStructureChanged(sensitiveInput.id); return; }).catch(Notification.exception); // Register event listeners. diff --git a/lib/form/amd/build/events.min.js b/lib/form/amd/build/events.min.js index 1769f39faba..2dcca565d70 100644 --- a/lib/form/amd/build/events.min.js +++ b/lib/form/amd/build/events.min.js @@ -14,6 +14,6 @@ define("core_form/events",["exports","core/str","core/event_dispatcher","jquery" * window.console.log(e.target); // The form that was submitted. * window.console.log(e.detail.skipValidation); // Whether form validation was skipped. * }); - */let changesMadeString;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.types=_exports.triggerUploadStarted=_exports.triggerUploadCompleted=_exports.notifyUploadStarted=_exports.notifyUploadCompleted=_exports.notifyUploadChanged=_exports.notifyFormSubmittedByJavascript=_exports.notifyFormError=_exports.notifyFieldValidationFailure=_exports.eventTypes=void 0,_jquery=_interopRequireDefault(_jquery),_yui=_interopRequireDefault(_yui);const changesMadeCheck=e=>{e&&(e.returnValue=changesMadeString)},eventTypes={formError:"core_form/error",formSubmittedByJavascript:"core_form/submittedByJavascript",formFieldValidationFailed:"core_form/fieldValidationFailed",uploadStarted:"core_form/uploadStarted",uploadCompleted:"core_form/uploadCompleted",uploadChanged:"core_form/uploadChanged"};_exports.eventTypes=eventTypes;_exports.notifyFormError=field=>(0,_event_dispatcher.dispatchEvent)(eventTypes.formError,{},field);_exports.notifyFormSubmittedByJavascript=function(form){let skipValidation=arguments.length>1&&void 0!==arguments[1]&&arguments[1],fallbackHandled=arguments.length>2&&void 0!==arguments[2]&&arguments[2];skipValidation&&(window.skipClientValidation=!0);const customEvent=(0,_event_dispatcher.dispatchEvent)(eventTypes.formSubmittedByJavascript,{skipValidation:skipValidation,fallbackHandled:fallbackHandled},form);return skipValidation&&(window.skipClientValidation=!1),customEvent};_exports.notifyFieldValidationFailure=(field,message)=>(0,_event_dispatcher.dispatchEvent)(eventTypes.formFieldValidationFailed,{message:message},field,{cancelable:!0});const notifyUploadStarted=async elementId=>(changesMadeString=await(0,_str.getString)("changesmadereallygoaway","moodle"),window.addEventListener("beforeunload",changesMadeCheck),(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadStarted,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1}));_exports.notifyUploadStarted=notifyUploadStarted;const notifyUploadCompleted=elementId=>(window.removeEventListener("beforeunload",changesMadeCheck),(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadCompleted,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1}));_exports.notifyUploadCompleted=notifyUploadCompleted;const triggerUploadStarted=notifyUploadStarted;_exports.triggerUploadStarted=triggerUploadStarted;const triggerUploadCompleted=notifyUploadCompleted;_exports.triggerUploadCompleted=triggerUploadCompleted;_exports.types={uploadStarted:"core_form/uploadStarted",uploadCompleted:"core_form/uploadCompleted"};let legacyEventsRegistered=!1;legacyEventsRegistered||(_yui.default.use("event","moodle-core-event",(()=>{document.addEventListener(eventTypes.formError,(e=>{const element=_yui.default.one(e.target),formElement=_yui.default.one(e.target.closest("form"));_yui.default.Global.fire(M.core.globalEvents.FORM_ERROR,{formid:formElement.generateID(),elementid:element.generateID()})})),document.addEventListener(eventTypes.formSubmittedByJavascript,(e=>{if(e.detail.fallbackHandled)return;e.skipValidation&&(window.skipClientValidation=!0);const form=_yui.default.one(e.target);form.fire(M.core.event.FORM_SUBMIT_AJAX,{currentTarget:form,fallbackHandled:!0}),e.skipValidation&&(window.skipClientValidation=!1)}))})),document.addEventListener(eventTypes.formFieldValidationFailed,(e=>{const legacyEvent=_jquery.default.Event("core_form-field-validation");(0,_jquery.default)(e.target).trigger(legacyEvent,e.detail.message)})),legacyEventsRegistered=!0);_exports.notifyUploadChanged=elementId=>(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadChanged,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1})})); + */let changesMadeString;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.types=_exports.triggerUploadStarted=_exports.triggerUploadCompleted=_exports.notifyUploadStarted=_exports.notifyUploadCompleted=_exports.notifyUploadChanged=_exports.notifyFormSubmittedByJavascript=_exports.notifyFormError=_exports.notifyFieldValidationFailure=_exports.notifyFieldStructureChanged=_exports.eventTypes=void 0,_jquery=_interopRequireDefault(_jquery),_yui=_interopRequireDefault(_yui);const changesMadeCheck=e=>{e&&(e.returnValue=changesMadeString)},eventTypes={formError:"core_form/error",formSubmittedByJavascript:"core_form/submittedByJavascript",formFieldValidationFailed:"core_form/fieldValidationFailed",uploadStarted:"core_form/uploadStarted",uploadCompleted:"core_form/uploadCompleted",uploadChanged:"core_form/uploadChanged",fieldStructureChanged:"core_form/fieldStructureChanged"};_exports.eventTypes=eventTypes;_exports.notifyFormError=field=>(0,_event_dispatcher.dispatchEvent)(eventTypes.formError,{},field);_exports.notifyFormSubmittedByJavascript=function(form){let skipValidation=arguments.length>1&&void 0!==arguments[1]&&arguments[1],fallbackHandled=arguments.length>2&&void 0!==arguments[2]&&arguments[2];skipValidation&&(window.skipClientValidation=!0);const customEvent=(0,_event_dispatcher.dispatchEvent)(eventTypes.formSubmittedByJavascript,{skipValidation:skipValidation,fallbackHandled:fallbackHandled},form);return skipValidation&&(window.skipClientValidation=!1),customEvent};_exports.notifyFieldValidationFailure=(field,message)=>(0,_event_dispatcher.dispatchEvent)(eventTypes.formFieldValidationFailed,{message:message},field,{cancelable:!0});const notifyUploadStarted=async elementId=>(changesMadeString=await(0,_str.getString)("changesmadereallygoaway","moodle"),window.addEventListener("beforeunload",changesMadeCheck),(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadStarted,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1}));_exports.notifyUploadStarted=notifyUploadStarted;const notifyUploadCompleted=elementId=>(window.removeEventListener("beforeunload",changesMadeCheck),(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadCompleted,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1}));_exports.notifyUploadCompleted=notifyUploadCompleted;const triggerUploadStarted=notifyUploadStarted;_exports.triggerUploadStarted=triggerUploadStarted;const triggerUploadCompleted=notifyUploadCompleted;_exports.triggerUploadCompleted=triggerUploadCompleted;_exports.types={uploadStarted:"core_form/uploadStarted",uploadCompleted:"core_form/uploadCompleted"};let legacyEventsRegistered=!1;legacyEventsRegistered||(_yui.default.use("event","moodle-core-event",(()=>{document.addEventListener(eventTypes.formError,(e=>{const element=_yui.default.one(e.target),formElement=_yui.default.one(e.target.closest("form"));_yui.default.Global.fire(M.core.globalEvents.FORM_ERROR,{formid:formElement.generateID(),elementid:element.generateID()})})),document.addEventListener(eventTypes.formSubmittedByJavascript,(e=>{if(e.detail.fallbackHandled)return;e.skipValidation&&(window.skipClientValidation=!0);const form=_yui.default.one(e.target);form.fire(M.core.event.FORM_SUBMIT_AJAX,{currentTarget:form,fallbackHandled:!0}),e.skipValidation&&(window.skipClientValidation=!1)}))})),document.addEventListener(eventTypes.formFieldValidationFailed,(e=>{const legacyEvent=_jquery.default.Event("core_form-field-validation");(0,_jquery.default)(e.target).trigger(legacyEvent,e.detail.message)})),legacyEventsRegistered=!0);_exports.notifyUploadChanged=elementId=>(0,_event_dispatcher.dispatchEvent)(eventTypes.uploadChanged,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1});_exports.notifyFieldStructureChanged=elementId=>(0,_event_dispatcher.dispatchEvent)(eventTypes.fieldStructureChanged,{},document.getElementById(elementId),{bubbles:!0,cancellable:!1})})); //# sourceMappingURL=events.min.js.map \ No newline at end of file diff --git a/lib/form/amd/build/events.min.js.map b/lib/form/amd/build/events.min.js.map index f928286812d..5757b431f7d 100644 --- a/lib/form/amd/build/events.min.js.map +++ b/lib/form/amd/build/events.min.js.map @@ -1 +1 @@ -{"version":3,"file":"events.min.js","sources":["../src/events.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/**\n * Javascript events for the `core_form` subsystem.\n *\n * @module core_form/events\n * @copyright 2021 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.10\n *\n * @example Example of listening to a form event.\n * import {eventTypes as formEventTypes} from 'core_form/events';\n *\n * document.addEventListener(formEventTypes.formSubmittedByJavascript, e => {\n * window.console.log(e.target); // The form that was submitted.\n * window.console.log(e.detail.skipValidation); // Whether form validation was skipped.\n * });\n */\n\nimport {getString} from 'core/str';\nimport {dispatchEvent} from 'core/event_dispatcher';\n\nlet changesMadeString;\n\n/**\n * Prevent user navigate away when upload progress still running.\n * @param {Event} e The event\n */\nconst changesMadeCheck = e => {\n if (e) {\n e.returnValue = changesMadeString;\n }\n};\n\n/**\n * Events for `core_form`.\n *\n * @constant\n * @property {String} formError See {@link event:core_form/error}\n * @property {String} formFieldValidationFailed See {@link event:core_form/fieldValidationFailed}\n * @property {String} formSubmittedByJavascript See {@link event:core_form/submittedByJavascript}\n * @property {String} uploadChanged See {@link event:core_form/uploadChanged}\n */\nexport const eventTypes = {\n /**\n * An event triggered when a form contains an error\n *\n * @event formError\n * @type {CustomEvent}\n * @property {HTMLElement} target The form field which errored\n */\n formError: 'core_form/error',\n\n /**\n * An event triggered when an mform is about to be submitted via javascript.\n *\n * @event core_form/submittedByJavascript\n * @type {CustomEvent}\n * @property {HTMLElement} target The form that was submitted\n * @property {object} detail\n * @property {boolean} detail.skipValidation Whether the form was submitted without validation (i.e. via a Cancel button)\n * @property {boolean} detail.fallbackHandled Whether the legacy YUI event has been handled\n */\n formSubmittedByJavascript: 'core_form/submittedByJavascript',\n\n /**\n * An event triggered upon form field validation failure.\n *\n * @event core_form/fieldValidationFailed\n * @type {CustomEvent}\n * @property {HTMLElement} target The field that failed validation\n * @property {object} detail\n * @property {String} detail.message The message displayed upon failure\n */\n formFieldValidationFailed: 'core_form/fieldValidationFailed',\n\n /**\n * An event triggered when an upload is started\n *\n * @event core_form/uploadStarted\n * @type {CustomEvent}\n * @property {HTMLElement} target The location where the upload began\n */\n uploadStarted: 'core_form/uploadStarted',\n\n /**\n * An event triggered when an upload completes\n *\n * @event core_form/uploadCompleted\n * @type {CustomEvent}\n * @property {HTMLElement} target The location where the upload completed\n */\n uploadCompleted: 'core_form/uploadCompleted',\n\n /**\n * An event triggered when a file upload field has been changed.\n *\n * @event core_form/uploadChanged\n * @type {CustomEvent}\n * @property {HTMLElement} target The form field which was changed\n */\n uploadChanged: 'core_form/uploadChanged',\n};\n\n// These are only imported for legacy.\nimport jQuery from 'jquery';\nimport Y from 'core/yui';\n\n/**\n * Trigger an event to indicate that a form field contained an error.\n *\n * @method notifyFormError\n * @param {HTMLElement} field The form field causing the error\n * @returns {CustomEvent}\n * @fires formError\n */\nexport const notifyFormError = field => dispatchEvent(eventTypes.formError, {}, field);\n\n/**\n * Trigger an event to indiciate that a form was submitted by Javascript.\n *\n * @method\n * @param {HTMLElement} form The form that was submitted\n * @param {Boolean} skipValidation Submit the form without validation. E.g. \"Cancel\".\n * @param {Boolean} fallbackHandled The legacy YUI event has been handled\n * @returns {CustomEvent}\n * @fires formSubmittedByJavascript\n */\nexport const notifyFormSubmittedByJavascript = (form, skipValidation = false, fallbackHandled = false) => {\n if (skipValidation) {\n window.skipClientValidation = true;\n }\n\n const customEvent = dispatchEvent(\n eventTypes.formSubmittedByJavascript,\n {\n skipValidation,\n fallbackHandled,\n },\n form\n );\n\n if (skipValidation) {\n window.skipClientValidation = false;\n }\n\n return customEvent;\n};\n\n/**\n * Trigger an event to indicate that a form field contained an error.\n *\n * @method notifyFieldValidationFailure\n * @param {HTMLElement} field The field which failed validation\n * @param {String} message The message displayed\n * @returns {CustomEvent}\n * @fires formFieldValidationFailed\n */\nexport const notifyFieldValidationFailure = (field, message) => dispatchEvent(\n eventTypes.formFieldValidationFailed,\n {\n message,\n },\n field,\n {\n cancelable: true\n }\n);\n\n/**\n * Trigger an event to indicate that an upload was started.\n *\n * @method\n * @param {String} elementId The element which was uploaded to\n * @returns {CustomEvent}\n * @fires uploadStarted\n */\nexport const notifyUploadStarted = async elementId => {\n // Add an additional check for changes made.\n changesMadeString = await getString('changesmadereallygoaway', 'moodle');\n window.addEventListener('beforeunload', changesMadeCheck);\n\n return dispatchEvent(\n eventTypes.uploadStarted,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n );\n};\n\n/**\n * Trigger an event to indicate that an upload was completed.\n *\n * @method\n * @param {String} elementId The element which was uploaded to\n * @returns {CustomEvent}\n * @fires uploadCompleted\n */\nexport const notifyUploadCompleted = elementId => {\n // Remove the additional check for changes made.\n window.removeEventListener('beforeunload', changesMadeCheck);\n\n return dispatchEvent(\n eventTypes.uploadCompleted,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n );\n};\n\n/**\n * Trigger upload start event.\n *\n * @method\n * @param {String} elementId\n * @returns {CustomEvent}\n * @fires uploadStarted\n * @deprecated Since Moodle 4.0 See {@link module:core_form/events.notifyUploadStarted notifyUploadStarted}\n */\nexport const triggerUploadStarted = notifyUploadStarted;\n\n/**\n * Trigger upload complete event.\n *\n * @method\n * @param {String} elementId\n * @returns {CustomEvent}\n * @fires uploadCompleted\n * @deprecated Since Moodle 4.0 See {@link module:core_form/events.notifyUploadCompleted notifyUploadCompleted}\n */\nexport const triggerUploadCompleted = notifyUploadCompleted;\n\n/**\n * List of the events.\n *\n * @deprecated since Moodle 4.0. See {@link module:core_form/events.eventTypes eventTypes} instead.\n **/\nexport const types = {\n uploadStarted: 'core_form/uploadStarted',\n uploadCompleted: 'core_form/uploadCompleted',\n};\n\nlet legacyEventsRegistered = false;\nif (!legacyEventsRegistered) {\n // The following event triggers are legacy and will be removed in the future.\n // The following approach provides a backwards-compatability layer for the new events.\n // Code should be updated to make use of native events.\n Y.use('event', 'moodle-core-event', () => {\n\n // Watch for the new native formError event, and trigger the legacy YUI event.\n document.addEventListener(eventTypes.formError, e => {\n const element = Y.one(e.target);\n const formElement = Y.one(e.target.closest('form'));\n\n Y.Global.fire(\n M.core.globalEvents.FORM_ERROR,\n {\n formid: formElement.generateID(),\n elementid: element.generateID(),\n }\n );\n });\n\n // Watch for the new native formSubmittedByJavascript event, and trigger the legacy YUI event.\n document.addEventListener(eventTypes.formSubmittedByJavascript, e => {\n if (e.detail.fallbackHandled) {\n // This event was originally generated by a YUI event.\n // Do not generate another as this will recurse.\n return;\n }\n\n if (e.skipValidation) {\n window.skipClientValidation = true;\n }\n\n // Trigger the legacy YUI event.\n const form = Y.one(e.target);\n form.fire(\n M.core.event.FORM_SUBMIT_AJAX,\n {\n currentTarget: form,\n fallbackHandled: true,\n }\n );\n\n if (e.skipValidation) {\n window.skipClientValidation = false;\n }\n });\n });\n\n // Watch for the new native formFieldValidationFailed event, and trigger the legacy jQuery event.\n document.addEventListener(eventTypes.formFieldValidationFailed, e => {\n // Note: The \"core_form-field-validation\" event is hard-coded in core/event.\n // This is not included to prevent cyclic module dependencies.\n const legacyEvent = jQuery.Event(\"core_form-field-validation\");\n\n jQuery(e.target).trigger(legacyEvent, e.detail.message);\n });\n\n legacyEventsRegistered = true;\n}\n\n/**\n * Trigger an event to notify the file upload field has been changed.\n *\n * @method\n * @param {string} elementId The element which was changed\n * @returns {CustomEvent}\n * @fires uploadChanged\n */\nexport const notifyUploadChanged = elementId => dispatchEvent(\n eventTypes.uploadChanged,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n);\n"],"names":["changesMadeString","changesMadeCheck","e","returnValue","eventTypes","formError","formSubmittedByJavascript","formFieldValidationFailed","uploadStarted","uploadCompleted","uploadChanged","field","form","skipValidation","fallbackHandled","window","skipClientValidation","customEvent","message","cancelable","notifyUploadStarted","async","addEventListener","document","getElementById","elementId","bubbles","cancellable","notifyUploadCompleted","removeEventListener","triggerUploadStarted","triggerUploadCompleted","legacyEventsRegistered","use","element","Y","one","target","formElement","closest","Global","fire","M","core","globalEvents","FORM_ERROR","formid","generateID","elementid","detail","event","FORM_SUBMIT_AJAX","currentTarget","legacyEvent","jQuery","Event","trigger"],"mappings":";;;;;;;;;;;;;;;;SAmCIA,mcAMEC,iBAAmBC,IACjBA,IACAA,EAAEC,YAAcH,oBAaXI,WAAa,CAQtBC,UAAW,kBAYXC,0BAA2B,kCAW3BC,0BAA2B,kCAS3BC,cAAe,0BASfC,gBAAiB,4BASjBC,cAAe,mFAeYC,QAAS,mCAAcP,WAAWC,UAAW,GAAIM,gDAYjC,SAACC,UAAMC,uEAAwBC,wEACtED,iBACAE,OAAOC,sBAAuB,SAG5BC,aAAc,mCAChBb,WAAWE,0BACX,CACIO,eAAAA,eACAC,gBAAAA,iBAEJF,aAGAC,iBACAE,OAAOC,sBAAuB,GAG3BC,mDAYiC,CAACN,MAAOO,WAAY,mCAC5Dd,WAAWG,0BACX,CACIW,QAAAA,SAEJP,MACA,CACIQ,YAAY,UAYPC,oBAAsBC,MAAAA,YAE/BrB,wBAA0B,kBAAU,0BAA2B,UAC/De,OAAOO,iBAAiB,eAAgBrB,mBAEjC,mCACHG,WAAWI,cACX,GACAe,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa,4DAaZC,sBAAwBH,YAEjCV,OAAOc,oBAAoB,eAAgB5B,mBAEpC,mCACHG,WAAWK,gBACX,GACAc,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa,gEAcZG,qBAAuBV,6EAWvBW,uBAAyBH,4FAOjB,CACjBpB,cAAe,0BACfC,gBAAiB,iCAGjBuB,wBAAyB,EACxBA,sCAICC,IAAI,QAAS,qBAAqB,KAGhCV,SAASD,iBAAiBlB,WAAWC,WAAWH,UACtCgC,QAAUC,aAAEC,IAAIlC,EAAEmC,QAClBC,YAAcH,aAAEC,IAAIlC,EAAEmC,OAAOE,QAAQ,sBAEzCC,OAAOC,KACLC,EAAEC,KAAKC,aAAaC,WACpB,CACIC,OAAQR,YAAYS,aACpBC,UAAWd,QAAQa,kBAM/BxB,SAASD,iBAAiBlB,WAAWE,2BAA2BJ,OACxDA,EAAE+C,OAAOnC,uBAMTZ,EAAEW,iBACFE,OAAOC,sBAAuB,SAI5BJ,KAAOuB,aAAEC,IAAIlC,EAAEmC,QACrBzB,KAAK6B,KACDC,EAAEC,KAAKO,MAAMC,iBACb,CACIC,cAAexC,KACfE,iBAAiB,IAIrBZ,EAAEW,iBACFE,OAAOC,sBAAuB,SAM1CO,SAASD,iBAAiBlB,WAAWG,2BAA2BL,UAGtDmD,YAAcC,gBAAOC,MAAM,kDAE1BrD,EAAEmC,QAAQmB,QAAQH,YAAanD,EAAE+C,OAAO/B,YAGnDc,wBAAyB,gCAWMP,YAAa,mCAC5CrB,WAAWM,cACX,GACAa,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa"} \ No newline at end of file +{"version":3,"file":"events.min.js","sources":["../src/events.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/**\n * Javascript events for the `core_form` subsystem.\n *\n * @module core_form/events\n * @copyright 2021 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.10\n *\n * @example Example of listening to a form event.\n * import {eventTypes as formEventTypes} from 'core_form/events';\n *\n * document.addEventListener(formEventTypes.formSubmittedByJavascript, e => {\n * window.console.log(e.target); // The form that was submitted.\n * window.console.log(e.detail.skipValidation); // Whether form validation was skipped.\n * });\n */\n\nimport {getString} from 'core/str';\nimport {dispatchEvent} from 'core/event_dispatcher';\n\nlet changesMadeString;\n\n/**\n * Prevent user navigate away when upload progress still running.\n * @param {Event} e The event\n */\nconst changesMadeCheck = e => {\n if (e) {\n e.returnValue = changesMadeString;\n }\n};\n\n/**\n * Events for `core_form`.\n *\n * @constant\n * @property {String} formError See {@link event:core_form/error}\n * @property {String} formFieldValidationFailed See {@link event:core_form/fieldValidationFailed}\n * @property {String} formSubmittedByJavascript See {@link event:core_form/submittedByJavascript}\n * @property {String} uploadChanged See {@link event:core_form/uploadChanged}\n * @property {String} fieldStructureChanged See {@link event:core_form/fieldStructureChanged}\n */\nexport const eventTypes = {\n /**\n * An event triggered when a form contains an error\n *\n * @event formError\n * @type {CustomEvent}\n * @property {HTMLElement} target The form field which errored\n */\n formError: 'core_form/error',\n\n /**\n * An event triggered when an mform is about to be submitted via javascript.\n *\n * @event core_form/submittedByJavascript\n * @type {CustomEvent}\n * @property {HTMLElement} target The form that was submitted\n * @property {object} detail\n * @property {boolean} detail.skipValidation Whether the form was submitted without validation (i.e. via a Cancel button)\n * @property {boolean} detail.fallbackHandled Whether the legacy YUI event has been handled\n */\n formSubmittedByJavascript: 'core_form/submittedByJavascript',\n\n /**\n * An event triggered upon form field validation failure.\n *\n * @event core_form/fieldValidationFailed\n * @type {CustomEvent}\n * @property {HTMLElement} target The field that failed validation\n * @property {object} detail\n * @property {String} detail.message The message displayed upon failure\n */\n formFieldValidationFailed: 'core_form/fieldValidationFailed',\n\n /**\n * An event triggered when an upload is started\n *\n * @event core_form/uploadStarted\n * @type {CustomEvent}\n * @property {HTMLElement} target The location where the upload began\n */\n uploadStarted: 'core_form/uploadStarted',\n\n /**\n * An event triggered when an upload completes\n *\n * @event core_form/uploadCompleted\n * @type {CustomEvent}\n * @property {HTMLElement} target The location where the upload completed\n */\n uploadCompleted: 'core_form/uploadCompleted',\n\n /**\n * An event triggered when a file upload field has been changed.\n *\n * @event core_form/uploadChanged\n * @type {CustomEvent}\n * @property {HTMLElement} target The form field which was changed\n */\n uploadChanged: 'core_form/uploadChanged',\n\n /**\n * An event triggered when a form field structure has changed.\n *\n * @event core_form/fieldStructureChanged\n * @type {CustomEvent}\n * @property {HTMLElement} target The form field that has changed\n */\n fieldStructureChanged: 'core_form/fieldStructureChanged',\n};\n\n// These are only imported for legacy.\nimport jQuery from 'jquery';\nimport Y from 'core/yui';\n\n/**\n * Trigger an event to indicate that a form field contained an error.\n *\n * @method notifyFormError\n * @param {HTMLElement} field The form field causing the error\n * @returns {CustomEvent}\n * @fires formError\n */\nexport const notifyFormError = field => dispatchEvent(eventTypes.formError, {}, field);\n\n/**\n * Trigger an event to indiciate that a form was submitted by Javascript.\n *\n * @method\n * @param {HTMLElement} form The form that was submitted\n * @param {Boolean} skipValidation Submit the form without validation. E.g. \"Cancel\".\n * @param {Boolean} fallbackHandled The legacy YUI event has been handled\n * @returns {CustomEvent}\n * @fires formSubmittedByJavascript\n */\nexport const notifyFormSubmittedByJavascript = (form, skipValidation = false, fallbackHandled = false) => {\n if (skipValidation) {\n window.skipClientValidation = true;\n }\n\n const customEvent = dispatchEvent(\n eventTypes.formSubmittedByJavascript,\n {\n skipValidation,\n fallbackHandled,\n },\n form\n );\n\n if (skipValidation) {\n window.skipClientValidation = false;\n }\n\n return customEvent;\n};\n\n/**\n * Trigger an event to indicate that a form field contained an error.\n *\n * @method notifyFieldValidationFailure\n * @param {HTMLElement} field The field which failed validation\n * @param {String} message The message displayed\n * @returns {CustomEvent}\n * @fires formFieldValidationFailed\n */\nexport const notifyFieldValidationFailure = (field, message) => dispatchEvent(\n eventTypes.formFieldValidationFailed,\n {\n message,\n },\n field,\n {\n cancelable: true\n }\n);\n\n/**\n * Trigger an event to indicate that an upload was started.\n *\n * @method\n * @param {String} elementId The element which was uploaded to\n * @returns {CustomEvent}\n * @fires uploadStarted\n */\nexport const notifyUploadStarted = async elementId => {\n // Add an additional check for changes made.\n changesMadeString = await getString('changesmadereallygoaway', 'moodle');\n window.addEventListener('beforeunload', changesMadeCheck);\n\n return dispatchEvent(\n eventTypes.uploadStarted,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n );\n};\n\n/**\n * Trigger an event to indicate that an upload was completed.\n *\n * @method\n * @param {String} elementId The element which was uploaded to\n * @returns {CustomEvent}\n * @fires uploadCompleted\n */\nexport const notifyUploadCompleted = elementId => {\n // Remove the additional check for changes made.\n window.removeEventListener('beforeunload', changesMadeCheck);\n\n return dispatchEvent(\n eventTypes.uploadCompleted,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n );\n};\n\n/**\n * Trigger upload start event.\n *\n * @method\n * @param {String} elementId\n * @returns {CustomEvent}\n * @fires uploadStarted\n * @deprecated Since Moodle 4.0 See {@link module:core_form/events.notifyUploadStarted notifyUploadStarted}\n */\nexport const triggerUploadStarted = notifyUploadStarted;\n\n/**\n * Trigger upload complete event.\n *\n * @method\n * @param {String} elementId\n * @returns {CustomEvent}\n * @fires uploadCompleted\n * @deprecated Since Moodle 4.0 See {@link module:core_form/events.notifyUploadCompleted notifyUploadCompleted}\n */\nexport const triggerUploadCompleted = notifyUploadCompleted;\n\n/**\n * List of the events.\n *\n * @deprecated since Moodle 4.0. See {@link module:core_form/events.eventTypes eventTypes} instead.\n **/\nexport const types = {\n uploadStarted: 'core_form/uploadStarted',\n uploadCompleted: 'core_form/uploadCompleted',\n};\n\nlet legacyEventsRegistered = false;\nif (!legacyEventsRegistered) {\n // The following event triggers are legacy and will be removed in the future.\n // The following approach provides a backwards-compatability layer for the new events.\n // Code should be updated to make use of native events.\n Y.use('event', 'moodle-core-event', () => {\n\n // Watch for the new native formError event, and trigger the legacy YUI event.\n document.addEventListener(eventTypes.formError, e => {\n const element = Y.one(e.target);\n const formElement = Y.one(e.target.closest('form'));\n\n Y.Global.fire(\n M.core.globalEvents.FORM_ERROR,\n {\n formid: formElement.generateID(),\n elementid: element.generateID(),\n }\n );\n });\n\n // Watch for the new native formSubmittedByJavascript event, and trigger the legacy YUI event.\n document.addEventListener(eventTypes.formSubmittedByJavascript, e => {\n if (e.detail.fallbackHandled) {\n // This event was originally generated by a YUI event.\n // Do not generate another as this will recurse.\n return;\n }\n\n if (e.skipValidation) {\n window.skipClientValidation = true;\n }\n\n // Trigger the legacy YUI event.\n const form = Y.one(e.target);\n form.fire(\n M.core.event.FORM_SUBMIT_AJAX,\n {\n currentTarget: form,\n fallbackHandled: true,\n }\n );\n\n if (e.skipValidation) {\n window.skipClientValidation = false;\n }\n });\n });\n\n // Watch for the new native formFieldValidationFailed event, and trigger the legacy jQuery event.\n document.addEventListener(eventTypes.formFieldValidationFailed, e => {\n // Note: The \"core_form-field-validation\" event is hard-coded in core/event.\n // This is not included to prevent cyclic module dependencies.\n const legacyEvent = jQuery.Event(\"core_form-field-validation\");\n\n jQuery(e.target).trigger(legacyEvent, e.detail.message);\n });\n\n legacyEventsRegistered = true;\n}\n\n/**\n * Trigger an event to notify the file upload field has been changed.\n *\n * @method\n * @param {string} elementId The element which was changed\n * @returns {CustomEvent}\n * @fires uploadChanged\n */\nexport const notifyUploadChanged = elementId => dispatchEvent(\n eventTypes.uploadChanged,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n);\n\n/**\n * Trigger an event to notify the field structure has changed.\n *\n * @method\n * @param {string} elementId The element which was changed\n * @returns {CustomEvent}\n * @fires fieldStructureChanged\n */\nexport const notifyFieldStructureChanged = elementId => dispatchEvent(\n eventTypes.fieldStructureChanged,\n {},\n document.getElementById(elementId),\n {\n bubbles: true,\n cancellable: false,\n }\n);\n"],"names":["changesMadeString","changesMadeCheck","e","returnValue","eventTypes","formError","formSubmittedByJavascript","formFieldValidationFailed","uploadStarted","uploadCompleted","uploadChanged","fieldStructureChanged","field","form","skipValidation","fallbackHandled","window","skipClientValidation","customEvent","message","cancelable","notifyUploadStarted","async","addEventListener","document","getElementById","elementId","bubbles","cancellable","notifyUploadCompleted","removeEventListener","triggerUploadStarted","triggerUploadCompleted","legacyEventsRegistered","use","element","Y","one","target","formElement","closest","Global","fire","M","core","globalEvents","FORM_ERROR","formid","generateID","elementid","detail","event","FORM_SUBMIT_AJAX","currentTarget","legacyEvent","jQuery","Event","trigger"],"mappings":";;;;;;;;;;;;;;;;SAmCIA,weAMEC,iBAAmBC,IACjBA,IACAA,EAAEC,YAAcH,oBAcXI,WAAa,CAQtBC,UAAW,kBAYXC,0BAA2B,kCAW3BC,0BAA2B,kCAS3BC,cAAe,0BASfC,gBAAiB,4BASjBC,cAAe,0BASfC,sBAAuB,2FAeIC,QAAS,mCAAcR,WAAWC,UAAW,GAAIO,gDAYjC,SAACC,UAAMC,uEAAwBC,wEACtED,iBACAE,OAAOC,sBAAuB,SAG5BC,aAAc,mCAChBd,WAAWE,0BACX,CACIQ,eAAAA,eACAC,gBAAAA,iBAEJF,aAGAC,iBACAE,OAAOC,sBAAuB,GAG3BC,mDAYiC,CAACN,MAAOO,WAAY,mCAC5Df,WAAWG,0BACX,CACIY,QAAAA,SAEJP,MACA,CACIQ,YAAY,UAYPC,oBAAsBC,MAAAA,YAE/BtB,wBAA0B,kBAAU,0BAA2B,UAC/DgB,OAAOO,iBAAiB,eAAgBtB,mBAEjC,mCACHG,WAAWI,cACX,GACAgB,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa,4DAaZC,sBAAwBH,YAEjCV,OAAOc,oBAAoB,eAAgB7B,mBAEpC,mCACHG,WAAWK,gBACX,GACAe,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa,gEAcZG,qBAAuBV,6EAWvBW,uBAAyBH,4FAOjB,CACjBrB,cAAe,0BACfC,gBAAiB,iCAGjBwB,wBAAyB,EACxBA,sCAICC,IAAI,QAAS,qBAAqB,KAGhCV,SAASD,iBAAiBnB,WAAWC,WAAWH,UACtCiC,QAAUC,aAAEC,IAAInC,EAAEoC,QAClBC,YAAcH,aAAEC,IAAInC,EAAEoC,OAAOE,QAAQ,sBAEzCC,OAAOC,KACLC,EAAEC,KAAKC,aAAaC,WACpB,CACIC,OAAQR,YAAYS,aACpBC,UAAWd,QAAQa,kBAM/BxB,SAASD,iBAAiBnB,WAAWE,2BAA2BJ,OACxDA,EAAEgD,OAAOnC,uBAMTb,EAAEY,iBACFE,OAAOC,sBAAuB,SAI5BJ,KAAOuB,aAAEC,IAAInC,EAAEoC,QACrBzB,KAAK6B,KACDC,EAAEC,KAAKO,MAAMC,iBACb,CACIC,cAAexC,KACfE,iBAAiB,IAIrBb,EAAEY,iBACFE,OAAOC,sBAAuB,SAM1CO,SAASD,iBAAiBnB,WAAWG,2BAA2BL,UAGtDoD,YAAcC,gBAAOC,MAAM,kDAE1BtD,EAAEoC,QAAQmB,QAAQH,YAAapD,EAAEgD,OAAO/B,YAGnDc,wBAAyB,gCAWMP,YAAa,mCAC5CtB,WAAWM,cACX,GACAc,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa,yCAYsBF,YAAa,mCACpDtB,WAAWO,sBACX,GACAa,SAASC,eAAeC,WACxB,CACIC,SAAS,EACTC,aAAa"} \ No newline at end of file diff --git a/lib/form/amd/src/events.js b/lib/form/amd/src/events.js index 2cbedb241e0..b5c3b4df82d 100644 --- a/lib/form/amd/src/events.js +++ b/lib/form/amd/src/events.js @@ -53,6 +53,7 @@ const changesMadeCheck = e => { * @property {String} formFieldValidationFailed See {@link event:core_form/fieldValidationFailed} * @property {String} formSubmittedByJavascript See {@link event:core_form/submittedByJavascript} * @property {String} uploadChanged See {@link event:core_form/uploadChanged} + * @property {String} fieldStructureChanged See {@link event:core_form/fieldStructureChanged} */ export const eventTypes = { /** @@ -113,6 +114,15 @@ export const eventTypes = { * @property {HTMLElement} target The form field which was changed */ uploadChanged: 'core_form/uploadChanged', + + /** + * An event triggered when a form field structure has changed. + * + * @event core_form/fieldStructureChanged + * @type {CustomEvent} + * @property {HTMLElement} target The form field that has changed + */ + fieldStructureChanged: 'core_form/fieldStructureChanged', }; // These are only imported for legacy. @@ -337,3 +347,21 @@ export const notifyUploadChanged = elementId => dispatchEvent( cancellable: false, } ); + +/** + * Trigger an event to notify the field structure has changed. + * + * @method + * @param {string} elementId The element which was changed + * @returns {CustomEvent} + * @fires fieldStructureChanged + */ +export const notifyFieldStructureChanged = elementId => dispatchEvent( + eventTypes.fieldStructureChanged, + {}, + document.getElementById(elementId), + { + bubbles: true, + cancellable: false, + } +); diff --git a/lib/templates/loginform.mustache b/lib/templates/loginform.mustache index 6dc17fa437c..9e5fd7aa72f 100644 --- a/lib/templates/loginform.mustache +++ b/lib/templates/loginform.mustache @@ -222,12 +222,18 @@ }); {{/togglepassword}} {{#autofocusform}} - var userNameField = document.getElementById('username'); - if (userNameField.value.length == 0) { - userNameField.focus(); - } else { - document.getElementById('password').focus(); - } + require(['core_form/events'], function(FormEvent) { + function autoFocus() { + const userNameField = document.getElementById('username'); + if (userNameField.value.length == 0) { + userNameField.focus(); + } else { + document.getElementById('password').focus(); + } + } + autoFocus(); + window.addEventListener(FormEvent.eventTypes.fieldStructureChanged, autoFocus); + }); {{/autofocusform}} {{/error}} {{#error}}