diff --git a/lib/form/amd/build/passwordunmask.min.js b/lib/form/amd/build/passwordunmask.min.js index d3f1f0facb6..d0fad809ac7 100644 --- a/lib/form/amd/build/passwordunmask.min.js +++ b/lib/form/amd/build/passwordunmask.min.js @@ -6,6 +6,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since 3.2 */ -define("core_form/passwordunmask",["jquery","core/templates"],(function($,Template){var PasswordUnmask=function(elementid){this.wrapperSelector='[data-passwordunmask="wrapper"][data-passwordunmaskid="'+elementid+'"]',this.wrapper=$(this.wrapperSelector),this.editorSpace=this.wrapper.find('[data-passwordunmask="editor"]'),this.editLink=this.wrapper.find('a[data-passwordunmask="edit"]'),this.editInstructions=this.wrapper.find('[data-passwordunmask="instructions"]'),this.displayValue=this.wrapper.find('[data-passwordunmask="displayvalue"]'),this.inputFieldLabel=$('label[for="'+elementid+'"]'),this.inputField=this.editorSpace.find(document.getElementById(elementid)),this.inputField.attr("type","hidden"),this.inputField.removeClass("hiddenifjs"),this.editInstructions.attr("id")||this.editInstructions.attr("id",elementid+"_instructions"),this.editInstructions.hide(),this.setDisplayValue(),this.addListeners()};return PasswordUnmask.prototype.addListeners=function(){return this.wrapper.on("click keypress",'[data-passwordunmask="edit"]',$.proxy((function(e){"keypress"===e.type&&13!==e.keyCode||(e.stopImmediatePropagation(),e.preventDefault(),"hidden"!==this.inputField.attr("type")?"click"===e.type||$(e.relatedTarget).is(":input")?this.turnEditingOff(!1):this.turnEditingOff(!0):this.turnEditingOn())}),this)),this.wrapper.on("click keypress",'[data-passwordunmask="unmask"]',$.proxy((function(e){"keypress"===e.type&&13!==e.keyCode||(e.stopImmediatePropagation(),e.preventDefault(),this.wrapper.data("unmasked",!this.wrapper.data("unmasked")),this.setDisplayValue())}),this)),this.wrapper.on("keydown","input",$.proxy((function(e){"keydown"===e.type&&13!==e.keyCode||(e.stopImmediatePropagation(),e.preventDefault(),this.turnEditingOff(!0))}),this)),this.inputFieldLabel.on("click",$.proxy((function(e){e.preventDefault(),this.turnEditingOn()}),this)),this},PasswordUnmask.prototype.checkFocusOut=function(e){this.isEditing()&&window.setTimeout($.proxy((function(){var relatedTarget=e.relatedTarget||document.activeElement;this.wrapper.has($(relatedTarget)).length||this.turnEditingOff(!$(relatedTarget).is(":input,a"))}),this),100)},PasswordUnmask.prototype.passwordVisible=function(){return!!this.wrapper.data("unmasked")},PasswordUnmask.prototype.isEditing=function(){return"hidden"!==this.inputField.attr("type")},PasswordUnmask.prototype.turnEditingOn=function(){var value=this.getDisplayValue();return this.passwordVisible()?this.inputField.attr("type","text"):this.inputField.attr("type","password"),this.inputField.val(value),this.inputField.attr("size",this.inputField.attr("data-size")),this.editInstructions.length&&(this.inputField.attr("aria-describedby",this.editInstructions.attr("id")),this.editInstructions.show()),this.wrapper.attr("data-passwordunmask-visible",1),this.editLink.hide(),this.inputField.focus().select(),$("body").on("focusout",this.wrapperSelector,$.proxy(this.checkFocusOut,this)),this},PasswordUnmask.prototype.turnEditingOff=function(focusOnEditLink){$("body").off("focusout",this.wrapperSelector,this.checkFocusOut);var value=this.getDisplayValue();return this.inputField.attr("type","hidden").attr("aria-describedby",null),this.inputField.val(value),this.editInstructions.hide(),this.wrapper.removeAttr("data-passwordunmask-visible"),this.inputField.removeAttr("size"),this.editLink.show(),this.setDisplayValue(),focusOnEditLink&&this.editLink.focus(),this},PasswordUnmask.prototype.getDisplayValue=function(){return this.inputField.val()},PasswordUnmask.prototype.setDisplayValue=function(){var value=this.getDisplayValue();return this.isEditing()&&(this.wrapper.data("unmasked")?this.inputField.attr("type","text"):this.inputField.attr("type","password"),this.inputField.val(value)),value&&this.wrapper.data("unmasked")?this.displayValue.text(value):(value||(value=""),Template.render("core_form/element-passwordunmask-fill",{element:{frozen:this.inputField.is("[readonly]"),value:value,valuechars:value.split("")}}).done($.proxy((function(html,js){this.displayValue.html(html),Template.runTemplateJS(js)}),this))),this},PasswordUnmask})); +define("core_form/passwordunmask",["jquery","core/templates"],(function($,Template){var PasswordUnmask=function(elementid){this.wrapperSelector='[data-passwordunmask="wrapper"][data-passwordunmaskid="'+elementid+'"]',this.wrapper=$(this.wrapperSelector),this.editorSpace=this.wrapper.find('[data-passwordunmask="editor"]'),this.editLink=this.wrapper.find('a[data-passwordunmask="edit"]'),this.editInstructions=this.wrapper.find('[data-passwordunmask="instructions"]'),this.displayValue=this.wrapper.find('[data-passwordunmask="displayvalue"]'),this.inputFieldLabel=$('label[for="'+elementid+'"]'),this.inputField=this.editorSpace.find(document.getElementById(elementid)),this.inputField.addClass("d-none"),this.inputField.removeClass("hiddenifjs"),this.editInstructions.attr("id")||this.editInstructions.attr("id",elementid+"_instructions"),this.editInstructions.hide(),this.setDisplayValue(),this.addListeners()};return PasswordUnmask.prototype.addListeners=function(){return this.wrapper.on("click keypress",'[data-passwordunmask="edit"]',$.proxy((function(e){"keypress"===e.type&&13!==e.keyCode||(e.stopImmediatePropagation(),e.preventDefault(),this.isEditing()?"click"===e.type||$(e.relatedTarget).is(":input")?this.turnEditingOff(!1):this.turnEditingOff(!0):this.turnEditingOn())}),this)),this.wrapper.on("click keypress",'[data-passwordunmask="unmask"]',$.proxy((function(e){"keypress"===e.type&&13!==e.keyCode||(e.stopImmediatePropagation(),e.preventDefault(),this.wrapper.data("unmasked",!this.wrapper.data("unmasked")),this.setDisplayValue())}),this)),this.wrapper.on("keydown","input",$.proxy((function(e){"keydown"===e.type&&13!==e.keyCode||(e.stopImmediatePropagation(),e.preventDefault(),this.turnEditingOff(!0))}),this)),this.inputFieldLabel.on("click",$.proxy((function(e){e.preventDefault(),this.turnEditingOn()}),this)),this},PasswordUnmask.prototype.checkFocusOut=function(e){this.isEditing()&&window.setTimeout($.proxy((function(){var relatedTarget=e.relatedTarget||document.activeElement;this.wrapper.has($(relatedTarget)).length||this.turnEditingOff(!$(relatedTarget).is(":input,a"))}),this),100)},PasswordUnmask.prototype.passwordVisible=function(){return!!this.wrapper.data("unmasked")},PasswordUnmask.prototype.isEditing=function(){return this.inputField.hasClass("d-inline-block")},PasswordUnmask.prototype.turnEditingOn=function(){var value=this.getDisplayValue();return this.passwordVisible()?this.inputField.attr("type","text"):this.inputField.attr("type","password"),this.inputField.val(value),this.inputField.attr("size",this.inputField.attr("data-size")),this.inputField.addClass("d-inline-block"),this.editInstructions.length&&(this.inputField.attr("aria-describedby",this.editInstructions.attr("id")),this.editInstructions.show()),this.wrapper.attr("data-passwordunmask-visible",1),this.editLink.hide(),this.inputField.focus().select(),$("body").on("focusout",this.wrapperSelector,$.proxy(this.checkFocusOut,this)),this},PasswordUnmask.prototype.turnEditingOff=function(focusOnEditLink){$("body").off("focusout",this.wrapperSelector,this.checkFocusOut);var value=this.getDisplayValue();return this.inputField.attr("aria-describedby",null),this.inputField.val(value),this.inputField.removeClass("d-inline-block"),this.editInstructions.hide(),this.wrapper.removeAttr("data-passwordunmask-visible"),this.inputField.removeAttr("size"),this.editLink.show(),this.setDisplayValue(),focusOnEditLink&&this.editLink.focus(),this},PasswordUnmask.prototype.getDisplayValue=function(){return this.inputField.val()},PasswordUnmask.prototype.setDisplayValue=function(){var value=this.getDisplayValue();return this.isEditing()&&(this.wrapper.data("unmasked")?this.inputField.attr("type","text"):this.inputField.attr("type","password"),this.inputField.val(value)),value&&this.wrapper.data("unmasked")?this.displayValue.text(value):(value||(value=""),Template.render("core_form/element-passwordunmask-fill",{element:{frozen:this.inputField.is("[readonly]"),value:value,valuechars:value.split("")}}).done($.proxy((function(html,js){this.displayValue.html(html),Template.runTemplateJS(js)}),this))),this},PasswordUnmask})); //# sourceMappingURL=passwordunmask.min.js.map \ No newline at end of file diff --git a/lib/form/amd/build/passwordunmask.min.js.map b/lib/form/amd/build/passwordunmask.min.js.map index 4489820644c..68c158b0287 100644 --- a/lib/form/amd/build/passwordunmask.min.js.map +++ b/lib/form/amd/build/passwordunmask.min.js.map @@ -1 +1 @@ -{"version":3,"file":"passwordunmask.min.js","sources":["../src/passwordunmask.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 * Password Unmask functionality.\n *\n * @module core_form/passwordunmask\n * @copyright 2016 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.2\n */\ndefine(['jquery', 'core/templates'], function($, Template) {\n\n /**\n * Constructor for PasswordUnmask.\n *\n * @class core_form/passwordunmask\n * @param {String} elementid The element to apply the PasswordUnmask to\n */\n var PasswordUnmask = function(elementid) {\n // Setup variables.\n this.wrapperSelector = '[data-passwordunmask=\"wrapper\"][data-passwordunmaskid=\"' + elementid + '\"]';\n this.wrapper = $(this.wrapperSelector);\n this.editorSpace = this.wrapper.find('[data-passwordunmask=\"editor\"]');\n this.editLink = this.wrapper.find('a[data-passwordunmask=\"edit\"]');\n this.editInstructions = this.wrapper.find('[data-passwordunmask=\"instructions\"]');\n this.displayValue = this.wrapper.find('[data-passwordunmask=\"displayvalue\"]');\n this.inputFieldLabel = $('label[for=\"' + elementid + '\"]');\n\n this.inputField = this.editorSpace.find(document.getElementById(elementid));\n this.inputField.attr('type', 'hidden');\n this.inputField.removeClass('hiddenifjs');\n\n if (!this.editInstructions.attr('id')) {\n this.editInstructions.attr('id', elementid + '_instructions');\n }\n this.editInstructions.hide();\n\n this.setDisplayValue();\n\n // Add the listeners.\n this.addListeners();\n };\n\n /**\n * Add the event listeners required for PasswordUnmask.\n *\n * @method addListeners\n * @return {PasswordUnmask}\n * @chainable\n */\n PasswordUnmask.prototype.addListeners = function() {\n this.wrapper.on('click keypress', '[data-passwordunmask=\"edit\"]', $.proxy(function(e) {\n if (e.type === 'keypress' && e.keyCode !== 13) {\n return;\n }\n e.stopImmediatePropagation();\n e.preventDefault();\n\n if (this.inputField.attr('type') !== 'hidden') {\n // Only focus on the edit link if the event was not a click, and the new target is not an input field.\n if (e.type !== 'click' && !$(e.relatedTarget).is(':input')) {\n this.turnEditingOff(true);\n } else {\n this.turnEditingOff(false);\n }\n } else {\n this.turnEditingOn();\n }\n }, this));\n\n this.wrapper.on('click keypress', '[data-passwordunmask=\"unmask\"]', $.proxy(function(e) {\n if (e.type === 'keypress' && e.keyCode !== 13) {\n return;\n }\n e.stopImmediatePropagation();\n e.preventDefault();\n\n // Toggle the data attribute.\n this.wrapper.data('unmasked', !this.wrapper.data('unmasked'));\n\n this.setDisplayValue();\n }, this));\n\n this.wrapper.on('keydown', 'input', $.proxy(function(e) {\n if (e.type === 'keydown' && e.keyCode !== 13) {\n return;\n }\n\n e.stopImmediatePropagation();\n e.preventDefault();\n\n this.turnEditingOff(true);\n }, this));\n\n this.inputFieldLabel.on('click', $.proxy(function(e) {\n e.preventDefault();\n\n this.turnEditingOn();\n }, this));\n\n return this;\n };\n\n /**\n * Check whether focus was lost from the PasswordUnmask and turn editing off if required.\n *\n * @method checkFocusOut\n * @param {EventFacade} e The EventFacade generating the suspsected Focus Out\n */\n PasswordUnmask.prototype.checkFocusOut = function(e) {\n if (!this.isEditing()) {\n // Ignore - not editing.\n return;\n }\n\n window.setTimeout($.proxy(function() {\n // Firefox does not have the focusout event. Instead jQuery falls back to the 'blur' event.\n // The blur event does not have a relatedTarget, so instead we use a timeout and the new activeElement.\n var relatedTarget = e.relatedTarget || document.activeElement;\n if (this.wrapper.has($(relatedTarget)).length) {\n // Ignore, some part of the element is still active.\n return;\n }\n\n // Only focus on the edit link if the new related target is not an input field or anchor.\n this.turnEditingOff(!$(relatedTarget).is(':input,a'));\n }, this), 100);\n };\n\n /**\n * Whether the password is currently visible (unmasked).\n *\n * @method passwordVisible\n * @return {Boolean} True if the password is unmasked\n */\n PasswordUnmask.prototype.passwordVisible = function() {\n return !!this.wrapper.data('unmasked');\n };\n\n /**\n * Whether the user is currently editing the field.\n *\n * @method isEditing\n * @return {Boolean} True if edit mode is enabled\n */\n PasswordUnmask.prototype.isEditing = function() {\n return this.inputField.attr('type') !== 'hidden';\n };\n\n /**\n * Enable the editing functionality.\n *\n * @method turnEditingOn\n * @return {PasswordUnmask}\n * @chainable\n */\n PasswordUnmask.prototype.turnEditingOn = function() {\n var value = this.getDisplayValue();\n if (this.passwordVisible()) {\n this.inputField.attr('type', 'text');\n } else {\n this.inputField.attr('type', 'password');\n }\n this.inputField.val(value);\n this.inputField.attr('size', this.inputField.attr('data-size'));\n\n if (this.editInstructions.length) {\n this.inputField.attr('aria-describedby', this.editInstructions.attr('id'));\n this.editInstructions.show();\n }\n\n this.wrapper.attr('data-passwordunmask-visible', 1);\n\n this.editLink.hide();\n this.inputField\n .focus()\n .select();\n\n // Note, this cannot be added as a delegated listener on init because Firefox does not support the FocusOut\n // event (https://bugzilla.mozilla.org/show_bug.cgi?id=687787) and the blur event does not identify the\n // relatedTarget.\n // The act of focusing the this.inputField means that in Firefox the focusout will be triggered on blur of the edit\n // link anchor.\n $('body').on('focusout', this.wrapperSelector, $.proxy(this.checkFocusOut, this));\n\n return this;\n };\n\n /**\n * Disable the editing functionality, optionally focusing on the edit link.\n *\n * @method turnEditingOff\n * @param {Boolean} focusOnEditLink Whether to focus on the edit link after disabling the editor\n * @return {PasswordUnmask}\n * @chainable\n */\n PasswordUnmask.prototype.turnEditingOff = function(focusOnEditLink) {\n $('body').off('focusout', this.wrapperSelector, this.checkFocusOut);\n var value = this.getDisplayValue();\n this.inputField\n // Hide the field again.\n .attr('type', 'hidden')\n\n // Ensure that the aria-describedby is removed.\n .attr('aria-describedby', null);\n this.inputField.val(value);\n\n this.editInstructions.hide();\n\n // Remove the visible attr.\n this.wrapper.removeAttr('data-passwordunmask-visible');\n\n // Remove the size attr.\n this.inputField.removeAttr('size');\n\n this.editLink.show();\n this.setDisplayValue();\n\n if (focusOnEditLink) {\n this.editLink.focus();\n }\n\n return this;\n };\n\n /**\n * Get the currently value.\n *\n * @method getDisplayValue\n * @return {String}\n */\n PasswordUnmask.prototype.getDisplayValue = function() {\n return this.inputField.val();\n };\n\n /**\n * Set the currently value in the display, taking into account the current settings.\n *\n * @method setDisplayValue\n * @return {PasswordUnmask}\n * @chainable\n */\n PasswordUnmask.prototype.setDisplayValue = function() {\n var value = this.getDisplayValue();\n if (this.isEditing()) {\n if (this.wrapper.data('unmasked')) {\n this.inputField.attr('type', 'text');\n } else {\n this.inputField.attr('type', 'password');\n }\n this.inputField.val(value);\n }\n\n // Update the display value.\n // Note: This must always be updated.\n // The unmask value can be changed whilst editing and the editing can then be disabled.\n if (value && this.wrapper.data('unmasked')) {\n // There is a value, and we will show it.\n this.displayValue.text(value);\n } else {\n if (!value) {\n value = \"\";\n }\n // There is a value, but it will be disguised.\n // We use the passwordunmask-fill to allow modification of the fill and to ensure that the display does not\n // change as the page loads the JS.\n Template.render('core_form/element-passwordunmask-fill', {\n element: {\n frozen: this.inputField.is('[readonly]'),\n value: value,\n valuechars: value.split(''),\n },\n }).done($.proxy(function(html, js) {\n this.displayValue.html(html);\n\n Template.runTemplateJS(js);\n }, this));\n }\n\n return this;\n };\n\n return PasswordUnmask;\n});\n"],"names":["define","$","Template","PasswordUnmask","elementid","wrapperSelector","wrapper","this","editorSpace","find","editLink","editInstructions","displayValue","inputFieldLabel","inputField","document","getElementById","attr","removeClass","hide","setDisplayValue","addListeners","prototype","on","proxy","e","type","keyCode","stopImmediatePropagation","preventDefault","relatedTarget","is","turnEditingOff","turnEditingOn","data","checkFocusOut","isEditing","window","setTimeout","activeElement","has","length","passwordVisible","value","getDisplayValue","val","show","focus","select","focusOnEditLink","off","removeAttr","text","render","element","frozen","valuechars","split","done","html","js","runTemplateJS"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"passwordunmask.min.js","sources":["../src/passwordunmask.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 * Password Unmask functionality.\n *\n * @module core_form/passwordunmask\n * @copyright 2016 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.2\n */\ndefine(['jquery', 'core/templates'], function($, Template) {\n\n /**\n * Constructor for PasswordUnmask.\n *\n * @class core_form/passwordunmask\n * @param {String} elementid The element to apply the PasswordUnmask to\n */\n var PasswordUnmask = function(elementid) {\n // Setup variables.\n this.wrapperSelector = '[data-passwordunmask=\"wrapper\"][data-passwordunmaskid=\"' + elementid + '\"]';\n this.wrapper = $(this.wrapperSelector);\n this.editorSpace = this.wrapper.find('[data-passwordunmask=\"editor\"]');\n this.editLink = this.wrapper.find('a[data-passwordunmask=\"edit\"]');\n this.editInstructions = this.wrapper.find('[data-passwordunmask=\"instructions\"]');\n this.displayValue = this.wrapper.find('[data-passwordunmask=\"displayvalue\"]');\n this.inputFieldLabel = $('label[for=\"' + elementid + '\"]');\n\n this.inputField = this.editorSpace.find(document.getElementById(elementid));\n // Hide the field.\n this.inputField.addClass('d-none');\n this.inputField.removeClass('hiddenifjs');\n\n if (!this.editInstructions.attr('id')) {\n this.editInstructions.attr('id', elementid + '_instructions');\n }\n this.editInstructions.hide();\n\n this.setDisplayValue();\n\n // Add the listeners.\n this.addListeners();\n };\n\n /**\n * Add the event listeners required for PasswordUnmask.\n *\n * @method addListeners\n * @return {PasswordUnmask}\n * @chainable\n */\n PasswordUnmask.prototype.addListeners = function() {\n this.wrapper.on('click keypress', '[data-passwordunmask=\"edit\"]', $.proxy(function(e) {\n if (e.type === 'keypress' && e.keyCode !== 13) {\n return;\n }\n e.stopImmediatePropagation();\n e.preventDefault();\n\n if (this.isEditing()) {\n // Only focus on the edit link if the event was not a click, and the new target is not an input field.\n if (e.type !== 'click' && !$(e.relatedTarget).is(':input')) {\n this.turnEditingOff(true);\n } else {\n this.turnEditingOff(false);\n }\n } else {\n this.turnEditingOn();\n }\n }, this));\n\n this.wrapper.on('click keypress', '[data-passwordunmask=\"unmask\"]', $.proxy(function(e) {\n if (e.type === 'keypress' && e.keyCode !== 13) {\n return;\n }\n e.stopImmediatePropagation();\n e.preventDefault();\n\n // Toggle the data attribute.\n this.wrapper.data('unmasked', !this.wrapper.data('unmasked'));\n\n this.setDisplayValue();\n }, this));\n\n this.wrapper.on('keydown', 'input', $.proxy(function(e) {\n if (e.type === 'keydown' && e.keyCode !== 13) {\n return;\n }\n\n e.stopImmediatePropagation();\n e.preventDefault();\n\n this.turnEditingOff(true);\n }, this));\n\n this.inputFieldLabel.on('click', $.proxy(function(e) {\n e.preventDefault();\n\n this.turnEditingOn();\n }, this));\n\n return this;\n };\n\n /**\n * Check whether focus was lost from the PasswordUnmask and turn editing off if required.\n *\n * @method checkFocusOut\n * @param {EventFacade} e The EventFacade generating the suspsected Focus Out\n */\n PasswordUnmask.prototype.checkFocusOut = function(e) {\n if (!this.isEditing()) {\n // Ignore - not editing.\n return;\n }\n\n window.setTimeout($.proxy(function() {\n // Firefox does not have the focusout event. Instead jQuery falls back to the 'blur' event.\n // The blur event does not have a relatedTarget, so instead we use a timeout and the new activeElement.\n var relatedTarget = e.relatedTarget || document.activeElement;\n if (this.wrapper.has($(relatedTarget)).length) {\n // Ignore, some part of the element is still active.\n return;\n }\n\n // Only focus on the edit link if the new related target is not an input field or anchor.\n this.turnEditingOff(!$(relatedTarget).is(':input,a'));\n }, this), 100);\n };\n\n /**\n * Whether the password is currently visible (unmasked).\n *\n * @method passwordVisible\n * @return {Boolean} True if the password is unmasked\n */\n PasswordUnmask.prototype.passwordVisible = function() {\n return !!this.wrapper.data('unmasked');\n };\n\n /**\n * Whether the user is currently editing the field.\n *\n * @method isEditing\n * @return {Boolean} True if edit mode is enabled\n */\n PasswordUnmask.prototype.isEditing = function() {\n return this.inputField.hasClass('d-inline-block');\n };\n\n /**\n * Enable the editing functionality.\n *\n * @method turnEditingOn\n * @return {PasswordUnmask}\n * @chainable\n */\n PasswordUnmask.prototype.turnEditingOn = function() {\n var value = this.getDisplayValue();\n if (this.passwordVisible()) {\n this.inputField.attr('type', 'text');\n } else {\n this.inputField.attr('type', 'password');\n }\n this.inputField.val(value);\n this.inputField.attr('size', this.inputField.attr('data-size'));\n // Show the field.\n this.inputField.addClass('d-inline-block');\n\n if (this.editInstructions.length) {\n this.inputField.attr('aria-describedby', this.editInstructions.attr('id'));\n this.editInstructions.show();\n }\n\n this.wrapper.attr('data-passwordunmask-visible', 1);\n\n this.editLink.hide();\n this.inputField\n .focus()\n .select();\n\n // Note, this cannot be added as a delegated listener on init because Firefox does not support the FocusOut\n // event (https://bugzilla.mozilla.org/show_bug.cgi?id=687787) and the blur event does not identify the\n // relatedTarget.\n // The act of focusing the this.inputField means that in Firefox the focusout will be triggered on blur of the edit\n // link anchor.\n $('body').on('focusout', this.wrapperSelector, $.proxy(this.checkFocusOut, this));\n\n return this;\n };\n\n /**\n * Disable the editing functionality, optionally focusing on the edit link.\n *\n * @method turnEditingOff\n * @param {Boolean} focusOnEditLink Whether to focus on the edit link after disabling the editor\n * @return {PasswordUnmask}\n * @chainable\n */\n PasswordUnmask.prototype.turnEditingOff = function(focusOnEditLink) {\n $('body').off('focusout', this.wrapperSelector, this.checkFocusOut);\n var value = this.getDisplayValue();\n this.inputField\n // Ensure that the aria-describedby is removed.\n .attr('aria-describedby', null);\n this.inputField.val(value);\n // Hide the field again.\n this.inputField.removeClass('d-inline-block');\n\n this.editInstructions.hide();\n\n // Remove the visible attr.\n this.wrapper.removeAttr('data-passwordunmask-visible');\n\n // Remove the size attr.\n this.inputField.removeAttr('size');\n\n this.editLink.show();\n this.setDisplayValue();\n\n if (focusOnEditLink) {\n this.editLink.focus();\n }\n\n return this;\n };\n\n /**\n * Get the currently value.\n *\n * @method getDisplayValue\n * @return {String}\n */\n PasswordUnmask.prototype.getDisplayValue = function() {\n return this.inputField.val();\n };\n\n /**\n * Set the currently value in the display, taking into account the current settings.\n *\n * @method setDisplayValue\n * @return {PasswordUnmask}\n * @chainable\n */\n PasswordUnmask.prototype.setDisplayValue = function() {\n var value = this.getDisplayValue();\n if (this.isEditing()) {\n if (this.wrapper.data('unmasked')) {\n this.inputField.attr('type', 'text');\n } else {\n this.inputField.attr('type', 'password');\n }\n this.inputField.val(value);\n }\n\n // Update the display value.\n // Note: This must always be updated.\n // The unmask value can be changed whilst editing and the editing can then be disabled.\n if (value && this.wrapper.data('unmasked')) {\n // There is a value, and we will show it.\n this.displayValue.text(value);\n } else {\n if (!value) {\n value = \"\";\n }\n // There is a value, but it will be disguised.\n // We use the passwordunmask-fill to allow modification of the fill and to ensure that the display does not\n // change as the page loads the JS.\n Template.render('core_form/element-passwordunmask-fill', {\n element: {\n frozen: this.inputField.is('[readonly]'),\n value: value,\n valuechars: value.split(''),\n },\n }).done($.proxy(function(html, js) {\n this.displayValue.html(html);\n\n Template.runTemplateJS(js);\n }, this));\n }\n\n return this;\n };\n\n return PasswordUnmask;\n});\n"],"names":["define","$","Template","PasswordUnmask","elementid","wrapperSelector","wrapper","this","editorSpace","find","editLink","editInstructions","displayValue","inputFieldLabel","inputField","document","getElementById","addClass","removeClass","attr","hide","setDisplayValue","addListeners","prototype","on","proxy","e","type","keyCode","stopImmediatePropagation","preventDefault","isEditing","relatedTarget","is","turnEditingOff","turnEditingOn","data","checkFocusOut","window","setTimeout","activeElement","has","length","passwordVisible","hasClass","value","getDisplayValue","val","show","focus","select","focusOnEditLink","off","removeAttr","text","render","element","frozen","valuechars","split","done","html","js","runTemplateJS"],"mappings":"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"} \ No newline at end of file diff --git a/lib/form/amd/src/passwordunmask.js b/lib/form/amd/src/passwordunmask.js index 3cf7893b333..884709bad60 100644 --- a/lib/form/amd/src/passwordunmask.js +++ b/lib/form/amd/src/passwordunmask.js @@ -40,7 +40,8 @@ define(['jquery', 'core/templates'], function($, Template) { this.inputFieldLabel = $('label[for="' + elementid + '"]'); this.inputField = this.editorSpace.find(document.getElementById(elementid)); - this.inputField.attr('type', 'hidden'); + // Hide the field. + this.inputField.addClass('d-none'); this.inputField.removeClass('hiddenifjs'); if (!this.editInstructions.attr('id')) { @@ -69,7 +70,7 @@ define(['jquery', 'core/templates'], function($, Template) { e.stopImmediatePropagation(); e.preventDefault(); - if (this.inputField.attr('type') !== 'hidden') { + if (this.isEditing()) { // Only focus on the edit link if the event was not a click, and the new target is not an input field. if (e.type !== 'click' && !$(e.relatedTarget).is(':input')) { this.turnEditingOff(true); @@ -157,7 +158,7 @@ define(['jquery', 'core/templates'], function($, Template) { * @return {Boolean} True if edit mode is enabled */ PasswordUnmask.prototype.isEditing = function() { - return this.inputField.attr('type') !== 'hidden'; + return this.inputField.hasClass('d-inline-block'); }; /** @@ -176,6 +177,8 @@ define(['jquery', 'core/templates'], function($, Template) { } this.inputField.val(value); this.inputField.attr('size', this.inputField.attr('data-size')); + // Show the field. + this.inputField.addClass('d-inline-block'); if (this.editInstructions.length) { this.inputField.attr('aria-describedby', this.editInstructions.attr('id')); @@ -211,12 +214,11 @@ define(['jquery', 'core/templates'], function($, Template) { $('body').off('focusout', this.wrapperSelector, this.checkFocusOut); var value = this.getDisplayValue(); this.inputField - // Hide the field again. - .attr('type', 'hidden') - // Ensure that the aria-describedby is removed. .attr('aria-describedby', null); this.inputField.val(value); + // Hide the field again. + this.inputField.removeClass('d-inline-block'); this.editInstructions.hide(); diff --git a/lib/form/selectgroups.php b/lib/form/selectgroups.php index 99ef7e011af..0719bedc617 100644 --- a/lib/form/selectgroups.php +++ b/lib/form/selectgroups.php @@ -561,6 +561,9 @@ class MoodleQuickForm_selectgroups extends HTML_QuickForm_element implements tem $optiongroups[] = $og; } $context['optiongroups'] = $optiongroups; + // If the select is a static element and does not allow the user to change the value (Ex: Auth method), + // we need to change the label to static. + $context['staticlabel'] = $this->_flagFrozen; return $context; } diff --git a/lib/form/templates/element-header.mustache b/lib/form/templates/element-header.mustache index 4508b093d98..f4332dc5e38 100644 --- a/lib/form/templates/element-header.mustache +++ b/lib/form/templates/element-header.mustache @@ -28,7 +28,8 @@ "helpbutton": "Help" } }} - +{{{header}}} +
{{#collapseable}}
{{{helpbutton}}} - +