echo "<div>\n";
echo "<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />\n";
echo "<input type=\"hidden\" name=\"auth\" value=\"".$auth."\" />\n";
-// HACK to prevent browsers from automatically inserting the user's password into the wrong fields.
-echo prevent_form_autofill_password();
// auth plugin description
echo $OUTPUT->box_start();
}
}}
<div class="form-password">
- <input type="password" name="{{name}}" size="{{size}}" id="{{id}}" value="{{value}}">
- <div class="unmask" id="{{id}}unmaskdiv"></div>
+ <span data-passwordunmask="wrapper" data-passwordunmaskid="{{ id }}">
+ <noscript>
+ <!-- Backwards compatability for Behat -->
+ <input type="password"
+ name="{{ name }}"
+ id="{{ id }}"
+ value="{{ value }}"
+ size="{{ size }}"
+ >
+ </noscript>
+ <span class="visibleifjs">
+ <span data-passwordunmask="editor">
+ <!-- The input in the noscript will be moved here as part of the page load -->
+ </span>
+ <a href="#" data-passwordunmask="edit" title="{{ edithint }}">
+ <span data-passwordunmask="displayvalue">{{> core_form/element-passwordunmask-fill }}</span>
+ {{# pix }} t/passwordunmask-edit, core, {{# str }} passwordunmaskedithint, form {{/ str }}{{/ pix }}
+ </a>
+ <a href="#" data-passwordunmask="unmask" title="{{ unmaskhint }}">
+ {{# pix }} t/passwordunmask-reveal, core, {{# str }} passwordunmaskrevealhint, form {{/ str }}{{/ pix }}
+ </a>
+ <span data-passwordunmask="instructions" class="form-text text-muted" style="display: none;">
+ {{# str }} passwordunmaskinstructions, form {{/ str }}
+ </span>
+ </span>
+ </span>
</div>
{{#js}}
-(function() {
- var id = '{{id}}';
- var unmaskid = id + 'unmask';
- var unmaskdivid = id + 'unmaskdiv';
- var unmaskstr = {{#quote}}{{#str}}unmaskpassword, form{{/str}}{{/quote}};
- var is_ie = (navigator.userAgent.toLowerCase().indexOf("msie") != -1);
-
- document.getElementById(id).setAttribute("autocomplete", "off");
-
- var unmaskdiv = document.getElementById(unmaskdivid);
-
- var unmaskchb = document.createElement("input");
- unmaskchb.setAttribute("type", "checkbox");
- unmaskchb.setAttribute("id", unmaskid);
- unmaskchb.onchange = function() {unmaskPassword(id);};
- unmaskdiv.appendChild(unmaskchb);
-
- var unmasklbl = document.createElement("label");
- unmasklbl.innerHTML = unmaskstr;
- if (is_ie) {
- unmasklbl.setAttribute("htmlFor", unmaskid);
- } else {
- unmasklbl.setAttribute("for", unmaskid);
- }
- unmaskdiv.appendChild(unmasklbl);
-
- if (is_ie) {
- // Ugly hack to work around the famous onchange IE bug.
- unmaskchb.onclick = function() {this.blur();};
- unmaskdiv.onclick = function() {this.blur();};
- }
-})()
+require(['core_form/passwordunmask'], function(PasswordUnmask) {
+ new PasswordUnmask("{{ id }}");
+});
{{/js}}
{{/params}}
<input type="hidden" name="sesskey" value="{{sesskey}}">
<input type="hidden" name="return" value="{{return}}">
- {{>core/prevent_form_autofill_password}}
{{#title}}
<h2>{{title}}</h2>
{{/title}}
<form action="{{actionurl}}" method="post" id="adminsettings">
<div>
<input type="hidden" name="sesskey" value="{{sesskey}}">
- {{>core/prevent_form_autofill_password}}
</div>
<fieldset>
<div class="clearer"></div>
echo '<div>';
echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
echo '<input type="hidden" name="return" value="'.$return.'" />';
-// HACK to prevent browsers from automatically inserting the user's password into the wrong fields.
-echo prevent_form_autofill_password();
echo '<fieldset>';
echo '<div class="clearer"><!-- --></div>';
echo $newsettingshtml;
<div class="controls"><select></select></div>
</div>';
- // HACK to prevent browsers from automatically inserting the user's password into the wrong fields.
- $rv .= prevent_form_autofill_password();
$rv .= '
<div class="fp-login-input control-group clearfix">
<label class="control-label"></label>
downloadtsv,core_table
downloadxhtml,core_table
invalidpersistent,core_competency
+revealpassword,core_form
$string['nonexistentformelements'] = 'Trying to add help buttons to non-existent form elements : {$a}';
$string['noselection'] = 'No selection';
$string['nosuggestions'] = 'No suggestions';
+$string['novalue'] = 'Nothing entered';
+$string['novalueclicktoset'] = 'Click to enter text';
$string['optional'] = 'Optional';
$string['othersettings'] = 'Other settings';
+$string['passwordunmaskedithint'] = 'Edit password';
+$string['passwordunmaskrevealhint'] = 'Reveal';
+$string['passwordunmaskinstructions'] = 'Press enter to save changes';
$string['requiredelement'] = 'Required field';
-$string['revealpassword'] = 'Reveal';
$string['security'] = 'Security';
$string['selectallornone'] = 'Select all/none';
$string['selected'] = 'Selected';
$string['timing'] = 'Timing';
$string['unmaskpassword'] = 'Unmask';
$string['year'] = 'Year';
+
+// Deprecated since 3.2.
+$string['revealpassword'] = 'Reveal';
}
/**
- * Returns XHTML for the field
- * Writes Javascript into the HTML below right before the last div
+ * Returns HTML for the field.
*
- * @todo Make javascript available through newer methods if possible
- * @param string $data Value for the field
- * @param string $query Passed as final argument for format_admin_setting
- * @return string XHTML field
+ * @param string $data Value for the field
+ * @param string $query Passed as final argument for format_admin_setting
+ * @return string Rendered HTML
*/
public function output_html($data, $query='') {
global $OUTPUT;
return $type;
}
+ if (!empty($fieldnode->find('xpath', '/ancestor::*[@data-passwordunmaskid]'))) {
+ return 'passwordunmask';
+ }
+
// We look for a parent node with 'felement' class.
if ($class = $fieldnode->getParent()->getAttribute('class')) {
'filemanager' => <<<XPATH
.//*[@data-fieldtype = 'filemanager' or @data-fieldtype = 'filepicker']
/descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]
+XPATH
+ ,
+ 'passwordunmask' => <<<XPATH
+.//*[@data-passwordunmask='wrapper']
+ /descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]
XPATH
],
];
--- /dev/null
+<?php
+// 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 <http://www.gnu.org/licenses/>.
+
+/**
+ * Silly behat_form_select extension.
+ *
+ * @package core_form
+ * @category test
+ * @copyright 2013 David Monllaó
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+require_once(__DIR__ . '/behat_form_text.php');
+
+/**
+ * Allows interaction with passwordunmask form fields.
+ *
+ * Plain behat_form_select extension as it is the same
+ * kind of field.
+ *
+ * @package core_form
+ * @category test
+ * @copyright 2013 David Monllaó
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_form_passwordunmask extends behat_form_text {
+ /**
+ * Sets the value to a field.
+ *
+ * @param string $value
+ * @return void
+ */
+ public function set_value($value) {
+ if ($this->running_javascript()) {
+ $id = $this->field->getAttribute('id');
+ $js = <<<JS
+require(["jquery"], function($) {
+ var wrapper = $(document.getElementById("{$id}")).closest('[data-passwordunmask="wrapper"]');
+ wrapper.find('[data-passwordunmask="edit"]').trigger("click");
+});
+JS;
+ $this->session->executeScript($js);
+ }
+
+ $this->field->setValue($value);
+ }
+}
}
/**
+<<<<<<< 919b9dfabd69f71c088f565746c547e6e169a0b7
* Display logs.
*
* @deprecated since 3.2
$select
$order";
- return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum) ;
+ return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
+}
+
+/**
+ * Renders a hidden password field so that browsers won't incorrectly autofill password fields with the user's password.
+ *
+ * @deprecated since Moodle 3.2 MDL-53048
+ */
+function prevent_form_autofill_password() {
+ debugging('prevent_form_autofill_password has been deprecated and is no longer in use.', DEBUG_DEVELOPER);
+ return '';
}
--- /dev/null
+// 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 <http://www.gnu.org/licenses/>.
+
+/**
+ * Password Unmask functionality.
+ *
+ * @module core_form/passwordunmask
+ * @package core_form
+ * @class passwordunmask
+ * @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since 3.2
+ */
+define(['jquery', 'core/templates'], function($, Template) {
+
+ /**
+ * Constructor for PasswordUnmask.
+ *
+ * @param {String} elementid The element to apply the PasswordUnmask to
+ */
+ var PasswordUnmask = function(elementid) {
+ // Setup variables.
+ 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"]');
+
+ // Move and convert the input field to the editor, then remove the noscript.
+ // We only want a single input field.
+ var noscriptContent = $(this.wrapper.find('noscript').text());
+ this.inputField = noscriptContent.filter('input');
+ this.inputField.attr('type', 'hidden');
+ this.editorSpace.append(this.inputField);
+ this.wrapper.find('noscript').remove();
+
+ if (!this.editInstructions.attr('id')) {
+ this.editInstructions.attr('id', elementid + '_instructions');
+ }
+ this.editInstructions.hide();
+
+ this.setDisplayValue();
+
+ // Add the listeners.
+ this.addListeners();
+ };
+
+ /**
+ * Add the event listeners required for PasswordUnmask.
+ *
+ * @method addListeners
+ * @return {PasswordUnmask}
+ * @chainable
+ */
+ PasswordUnmask.prototype.addListeners = function() {
+ this.wrapper.on('click keypress', '[data-passwordunmask="edit"]', $.proxy(function(e) {
+ if (e.type === 'keypress' && e.keyCode !== 13) {
+ return;
+ }
+ e.stopImmediatePropagation();
+ e.preventDefault();
+
+ if (this.inputField.attr('type') !== 'hidden') {
+ // 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);
+ } else {
+ this.turnEditingOff(false);
+ }
+ } else {
+ this.turnEditingOn();
+ }
+ }, this));
+
+ this.wrapper.on('click keypress', '[data-passwordunmask="unmask"]', $.proxy(function(e) {
+ if (e.type === 'keypress' && e.keyCode !== 13) {
+ return;
+ }
+ e.stopImmediatePropagation();
+ e.preventDefault();
+
+ // Toggle the data attribute.
+ this.wrapper.data('unmasked', !this.wrapper.data('unmasked'));
+
+ this.setDisplayValue();
+ }, this));
+
+ this.wrapper.on('keydown', 'input', $.proxy(function(e) {
+ if (e.type === 'keydown' && e.keyCode !== 13) {
+ return;
+ }
+
+ e.stopImmediatePropagation();
+ e.preventDefault();
+
+ this.turnEditingOff(true);
+ }, this));
+
+ return this;
+ };
+
+ /**
+ * Check whether focus was lost from the PasswordUnmask and turn editing off if required.
+ *
+ * @method checkFocusOut
+ * @param {EventFacade} e The EventFacade generating the suspsected Focus Out
+ */
+ PasswordUnmask.prototype.checkFocusOut = function(e) {
+ if (!this.isEditing()) {
+ // Ignore - not editing.
+ return;
+ }
+
+ window.setTimeout($.proxy(function() {
+ // Firefox does not have the focusout event. Instead jQuery falls back to the 'blur' event.
+ // The blur event does not have a relatedTarget, so instead we use a timeout and the new activeElement.
+ var relatedTarget = e.relatedTarget || document.activeElement;
+ if (this.wrapper.has($(relatedTarget)).length) {
+ // Ignore, some part of the element is still active.
+ return;
+ }
+
+ // Only focus on the edit link if the new related target is not an input field or anchor.
+ this.turnEditingOff(!$(relatedTarget).is(':input,a'));
+ }, this), 100);
+ };
+
+ /**
+ * Whether the password is currently visible (unmasked).
+ *
+ * @method passwordVisible
+ * @return {Boolean} True if the password is unmasked
+ */
+ PasswordUnmask.prototype.passwordVisible = function() {
+ return !!this.wrapper.data('unmasked');
+ };
+
+ /**
+ * Whether the user is currently editing the field.
+ *
+ * @method isEditing
+ * @return {Boolean} True if edit mode is enabled
+ */
+ PasswordUnmask.prototype.isEditing = function() {
+ return this.inputField.attr('type') !== 'hidden';
+ };
+
+ /**
+ * Enable the editing functionality.
+ *
+ * @method turnEditingOn
+ * @return {PasswordUnmask}
+ * @chainable
+ */
+ PasswordUnmask.prototype.turnEditingOn = function() {
+ if (this.passwordVisible()) {
+ this.inputField.attr('type', 'text');
+ } else {
+ this.inputField.attr('type', 'password');
+ }
+
+ if (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();
+
+ // Note, this cannot be added as a delegated listener on init because Firefox does not support the FocusOut
+ // event (https://bugzilla.mozilla.org/show_bug.cgi?id=687787) and the blur event does not identify the
+ // relatedTarget.
+ // The act of focusing the this.inputField means that in Firefox the focusout will be triggered on blur of the edit
+ // link anchor.
+ $('body').on('focusout', this.wrapperSelector, $.proxy(this.checkFocusOut, this));
+
+ return this;
+ };
+
+ /**
+ * Disable the editing functionality, optionally focusing on the edit link.
+ *
+ * @method turnEditingOff
+ * @param {Boolean} focusOnEditLink Whether to focus on the edit link after disabling the editor
+ * @return {PasswordUnmask}
+ * @chainable
+ */
+ PasswordUnmask.prototype.turnEditingOff = function(focusOnEditLink) {
+ $('body').off('focusout', this.wrapperSelector, this.checkFocusOut);
+ this.inputField
+ // Hide the field again.
+ .attr('type', 'hidden')
+
+ // Ensure that the aria-describedby is removed.
+ .attr('aria-describedby', null);
+
+ this.editInstructions.hide();
+
+ // Remove the visible attr.
+ this.wrapper.removeAttr('data-passwordunmask-visible');
+
+ this.editLink.show();
+ this.setDisplayValue();
+
+ if (focusOnEditLink) {
+ this.editLink.focus();
+ }
+
+ return this;
+ };
+
+ /**
+ * Get the currently value.
+ *
+ * @method getDisplayValue
+ * @return {String}
+ */
+ PasswordUnmask.prototype.getDisplayValue = function() {
+ return this.inputField.val();
+ };
+
+ /**
+ * Set the currently value in the display, taking into account the current settings.
+ *
+ * @method setDisplayValue
+ * @return {PasswordUnmask}
+ * @chainable
+ */
+ PasswordUnmask.prototype.setDisplayValue = function() {
+ if (this.isEditing()) {
+ if (this.wrapper.data('unmasked')) {
+ this.inputField.attr('type', 'text');
+ } else {
+ this.inputField.attr('type', 'password');
+ }
+ }
+
+ // Update the display value.
+ // Note: This must always be updated.
+ // The unmask value can be changed whilst editing and the editing can then be disabled.
+ var value = this.getDisplayValue();
+ if (value && this.wrapper.data('unmasked')) {
+ // There is a value, and we will show it.
+ this.displayValue.text(value);
+ } else {
+ if (!value) {
+ value = "";
+ }
+ // There is a value, but it will be disguised.
+ // We use the passwordunmask-fill to allow modification of the fill and to ensure that the display does not
+ // change as the page loads the JS.
+ 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));
+ }
+
+ return this;
+ };
+
+ return PasswordUnmask;
+});
* or an associative array
*/
public function __construct($elementName=null, $elementLabel=null, $attributes=null) {
- global $CFG;
// no standard mform in moodle should allow autocomplete of passwords
if (empty($attributes)) {
$attributes = array('autocomplete'=>'off');
$attributes .= ' autocomplete="off" ';
}
}
+ $this->_persistantFreeze = true;
parent::__construct($elementName, $elementLabel, $attributes);
$this->setType('passwordunmask');
}
/**
- * Returns HTML for password form element.
+ * Function to export the renderer data in a format that is suitable for a mustache template.
*
- * @return string
+ * @param renderer_base $output Used to do a final render of any components that need to be rendered for export.
+ * @return stdClass|array
*/
- function toHtml() {
- global $PAGE;
+ public function export_for_template(renderer_base $output) {
+ $context = parent::export_for_template($output);
+ $context['valuechars'] = array_fill(0, strlen($context['value']), 'x');
- if ($this->_flagFrozen) {
- return $this->getFrozenHtml();
- } else {
- $unmask = get_string('unmaskpassword', 'form');
- //Pass id of the element, so that unmask checkbox can be attached.
- $attributes = array('formid' => $this->getAttribute('id'),
- 'checkboxlabel' => $unmask,
- 'checkboxname' => $this->getAttribute('name'));
- $PAGE->requires->yui_module('moodle-form-passwordunmask', 'M.form.passwordunmask',
- array($attributes));
- return $this->_getTabs() . '<input' . $this->_getAttrString($this->_attributes) . ' />';
- }
+ return $context;
}
-
}
// Special wierd named property.
$context['frozen'] = !empty($this->_flagFrozen);
+ $context['hardfrozen'] = !empty($this->_flagFrozen) && empty($this->_persistantFreeze);
// Other attributes.
$otherattributes = [];
--- /dev/null
+{{!
+ 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 <http://www.gnu.org/licenses/>.
+}}
+{{!
+ @template core_form/element-passwordunmask-fill
+
+ The fill for a passwordunmask form element.
+
+ The purpose of this template is to render the fill for a passwordunmask element.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Context variables required for this template:
+ * element
+ * valuechars (optional)
+
+ Example context (json):
+ {
+ "element": {
+ "valuechars": [
+ "E",
+ "x",
+ "a",
+ "m",
+ "p",
+ "l",
+ "e"
+ ]
+ }
+ }
+
+}}
+<span>
+{{# element.valuechars }}•{{/ element.valuechars }}
+{{^ element.valuechars }}<em>{{!
+ }}{{^ element.frozen }}{{# str }} novalueclicktoset, form {{/ str }}{{/ element.frozen }}{{!
+ }}{{# element.frozen }}{{# str }} novalue, form {{/ str }}{{/ element.frozen }}{{!
+}}</em>{{/ element.valuechars }}
+</span>
--- /dev/null
+{{!
+ 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 <http://www.gnu.org/licenses/>.
+}}
+{{!
+ @template core_form/element-passwordunmask
+
+ Moodle passwordunmask form element template.
+
+ The purpose of this template is to render a passwordunmask form element.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Context variables required for this template:
+ * element
+ * id
+ * name
+ * value
+ * size
+
+ Example context (json):
+ {
+ "element": {
+ "id": "example_password_unmask",
+ "name": "example",
+ "value": "Password1!",
+ "size": 40
+ }
+ }
+
+}}
+{{< core_form/element-template }}
+ {{$ element }}
+ <div data-passwordunmask="wrapper" data-passwordunmaskid="{{ element.id }}">
+ <noscript>
+ <!-- Backwards compatability for Behat -->
+ <input type="password"
+ {{# element.frozen }}readonly{{/ element.frozen }}
+ {{^ element.hardfrozen}} name="{{ element.name }}"{{/ element.hardfrozen }}
+ id="{{ element.id }}"
+ value="{{element.value }}"
+ size="{{ element.size }}"
+ {{# error }}
+ autofocus aria-describedby="id_error_{{ element.name }}"
+ {{/ error }}
+ {{{ attributes }}}
+ >
+ </noscript>
+ <span class="visibleifjs">
+ <span data-passwordunmask="editor">
+ <!-- The input in the noscript will be moved here as part of the page load -->
+ <span data-passwordunmask="instructions" class="editinstructions">
+ {{^ element.frozen }}
+ {{# str }} passwordunmaskinstructions, form {{/ str }}
+ {{/ element.frozen }}
+ </span>
+ </span>
+ {{^ element.frozen }}
+ <a href="#" data-passwordunmask="edit" title="{{ edithint }}">
+ {{/ element.frozen }}
+ <span data-passwordunmask="displayvalue">{{> core_form/element-passwordunmask-fill }}</span>
+ {{^ element.frozen }}
+ {{# pix }} t/passwordunmask-edit, core, {{ edithint }}{{/ pix }}
+ </a>
+ {{/ element.frozen }}
+ <a href="#" data-passwordunmask="unmask" title="{{ unmaskhint }}">
+ {{# pix }} t/passwordunmask-reveal, core, {{ edithint }}{{/ pix }}
+ </a>
+ </span>
+ </div>
+ {{/ element }}
+{{/ core_form/element-template }}
+{{# js }}
+require(['core_form/passwordunmask'], function(PasswordUnmask) {
+ new PasswordUnmask("{{ element.id }}");
+});
+{{/ js }}
--- /dev/null
+{{!
+ 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 <http://www.gnu.org/licenses/>.
+}}
+{{!
+ @template core_form/element-template
+
+ Moodle form element wrapper template.
+
+ The purpose of this template is to wrap a form element.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Context variables required for this template:
+ * label
+ * helpbutton
+ * error
+ * element
+ * id
+ * name
+
+ Example context (json):
+ {
+ "label": "Password",
+ "error": "No password set",
+ "element": {
+ "id": "example_password_unmask",
+ "name": "example"
+ }
+ }
+
+}}
+<div id="fitem_{{ element.id }}" class="fitem fitem_{{ element.type }}">
+ <div class="fitemtitle">
+ <label for="{{element.id}}">{{{ label }}}</label>
+ {{{ helpbutton }}}
+ </div>
+ <div class="felement {{# error }} error{{/ error }} f{{ element.type }}">
+ {{# error }}
+ <span class="error" tabindex="0" id="id_error_{{ element.name }}">
+ {{{ error }}}
+ </span>
+ {{/ error }}
+ {{$ element }}
+ <!-- Element goes here -->
+ {{/ element }}
+ </div>
+</div>
-var PASSWORDUNMASK = function() {
- PASSWORDUNMASK.superclass.constructor.apply(this, arguments);
-};
-
-Y.extend(PASSWORDUNMASK, Y.Base, {
- // Initialize checkbox if id is passed.
- initializer: function(params) {
- if (params && params.formid) {
- this.add_checkbox(params.formid, params.checkboxlabel, params.checkboxname);
- }
- },
-
- // Create checkbox for unmasking password.
- add_checkbox: function(elementid, checkboxlabel, checkboxname) {
- var node = Y.one('#' + elementid);
-
- // Retaining unmask div from previous implementation.
- var unmaskdiv = Y.Node.create('<div id="' + elementid + 'unmaskdiv" class="unmask"></div>');
-
- // Add checkbox for unmasking to unmaskdiv.
- var unmaskchb = Y.Node.create('<input id="' + elementid + 'unmask" type="checkbox" name="' +
- checkboxname + 'unmask">');
- unmaskdiv.appendChild(unmaskchb);
- // Attach event using static javascript function for unmasking password.
- unmaskchb.on('click', function() {
- window.unmaskPassword(elementid);
- });
-
- // Add label for checkbox to unmaskdiv.
- var unmasklabel = Y.Node.create('<label for="' + elementid + 'unmask">' + checkboxlabel + '</label>');
- unmaskdiv.appendChild(unmasklabel);
-
- // Insert unmask div in the same div as password input.
- node.get('parentNode').insert(unmaskdiv, node.get('lastNode'));
- }
-});
-
M.form = M.form || {};
-M.form.passwordunmask = function(params) {
- return new PASSWORDUNMASK(params);
+M.form.passwordunmask = function() {
+ Y.log("The moodle-form-passwordunmask module has been deprecated. " +
+ "Please use the core_forum/passwordunmask amd module instead.", 'moodle-form-passwordunmask', 'warn');
};
{
"moodle-form-passwordunmask": {
- "requires": [
- "node",
- "base"
- ]
+ "requires": []
}
}
$this->_collapseButtons = '';
$formid = $form->getAttribute('id');
parent::startForm($form);
- // HACK to prevent browsers from automatically inserting the user's password into the wrong fields.
- $this->_hiddenHtml .= prevent_form_autofill_password();
if ($form->isFrozen()){
$this->_formTemplate = "\n<div class=\"mform frozen\">\n{content}\n</div>";
} else {
+++ /dev/null
-{{!
- 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 <http://www.gnu.org/licenses/>.
-}}
-{{!
- Snippet to prevent browsers from autofilling password fields.
-}}
-<div class="hide">
- <input type="text" class="ignoredirty" />
- <input type="password" class="ignoredirty" />
-</div>
- get_logs() - See MDL-43681 for more information
- get_logs_usercourse() - See MDL-43681 for more information
- get_logs_userday() - See MDL-43681 for more information
+ - prevent_form_autofill_password() Please do not use anymore.
* The password_compat library was removed as it is no longer required.
* Phpunit has been upgraded to 5.4.x and following has been deprecated and is not used any more:
- setExpectedException(), use @expectedException or $this->expectException() and $this->expectExceptionMessage()
}
return $data;
}
-
-/**
- * Renders a hidden password field so that browsers won't incorrectly autofill password fields with the user's password.
- *
- * @since 3.0
- * @return string HTML to prevent password autofill
- */
-function prevent_form_autofill_password() {
- global $OUTPUT;
- return $OUTPUT->render_from_template('core/prevent_form_autofill_password', []);
-}
--- /dev/null
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+ <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M5.2 11H12v1H4.2l1-1zm1.4-8.4L0 9.1V12h2.8l6.6-6.6-2.8-2.8zm4.8.8l-1 1-2.8-2.8 1-1c.8-.8 2.1-.8 2.8 0 .8.8.8 2 0 2.8z" fill="#999"/></svg>
\ No newline at end of file
--- /dev/null
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\r
+ <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">\r
+]><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M11.4 9.4L9.9 7.9c-.1-.1-.2-.1-.3-.2.4-.8.7-1.6.7-2.5C10.3 2.3 8 0 5.2 0 2.3 0 0 2.3 0 5.2s2.3 5.2 5.2 5.2c.9 0 1.7-.2 2.4-.6.1 0 .1.1.2.2l1.5 1.5c.6.6 1.5.6 2.1 0s.6-1.5 0-2.1zM5.2 7.3C4 7.3 3 6.4 3 5.2 3 4 4 3 5.2 3c1.2 0 2.2 1 2.2 2.2-.1 1.2-1 2.1-2.2 2.1z" fill="#999"/></svg>
\ No newline at end of file
echo '<form method="post">';
echo '<input type="hidden" name="action" value="sign" />';
echo '<input type="hidden" name="repo_id" value="'.s($repo_id).'" />';
- // HACK to prevent browsers from automatically inserting the user's password into the wrong fields.
- echo prevent_form_autofill_password();
$repo->print_login();
echo '</form>';
}
* @return string
*/
protected function fp_js_template_loginform() {
- return $this->render_from_template('core/filemanager_loginform', ['autofillhack' => prevent_form_autofill_password()]);
+ return $this->render_from_template('core/filemanager_loginform', []);
}
/**
<label class="form-control-label"></label>
<select class="form-control"></select>
</div>
- {{{autofillhack}}}
<div class="fp-login-input form-group">
<label class="form-control-label"></label>
<input class="form-control"/>
<p class="mdl-align"><button class="fp-login-submit btn-primary btn">{{#str}}submit, repository{{/str}}</button></p>
</form>
</div>
-</div>
\ No newline at end of file
+</div>
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
- Setting configpasswordunmask.
-}}
-<div class="form-password">
- <input type="password" name="{{name}}" size="{{size}}" id="{{id}}" value="{{value}}" class="form-control d-inline-block">
- <div class="unmask" id="{{id}}unmaskdiv"></div>
-</div>
-{{#js}}
-(function() {
- var id = '{{id}}';
- var unmaskid = id + 'unmask';
- var unmaskdivid = id + 'unmaskdiv';
- var unmaskstr = {{#quote}}{{#str}}unmaskpassword, form{{/str}}{{/quote}};
- var is_ie = (navigator.userAgent.toLowerCase().indexOf("msie") != -1);
-
- document.getElementById(id).setAttribute("autocomplete", "off");
+ @template core_admin/setting_configpasswordunmask
- var unmaskdiv = document.getElementById(unmaskdivid);
+ Admin password unmask setting template.
- var unmaskchb = document.createElement("input");
- unmaskchb.setAttribute("type", "checkbox");
- unmaskchb.setAttribute("id", unmaskid);
- unmaskchb.onchange = function() {unmaskPassword(id);};
- unmaskdiv.appendChild(unmaskchb);
+ Context variables required for this template:
+ * name - form element name
+ * size - form element size
+ * value - form element value
+ * id - element id
- var unmasklbl = document.createElement("label");
- unmasklbl.innerHTML = unmaskstr;
- if (is_ie) {
- unmasklbl.setAttribute("htmlFor", unmaskid);
- } else {
- unmasklbl.setAttribute("for", unmaskid);
+ Example context (json):
+ {
+ "name": "test",
+ "id": "test0",
+ "size": "8",
+ "value": "secret"
}
- unmaskdiv.appendChild(unmasklbl);
-
- if (is_ie) {
- // Ugly hack to work around the famous onchange IE bug.
- unmaskchb.onclick = function() {this.blur();};
- unmaskdiv.onclick = function() {this.blur();};
- }
-})()
+}}
+<div class="form-password">
+ <span data-passwordunmask="wrapper" data-passwordunmaskid="{{ id }}">
+ <noscript>
+ <!-- Backwards compatability for Behat -->
+ <input type="password"
+ name="{{ name }}"
+ id="{{ id }}"
+ value="{{ value }}"
+ size="{{ size }}"
+ class="form-control d-inline-block"
+ >
+ </noscript>
+ <span class="visibleifjs">
+ <span data-passwordunmask="editor">
+ <!-- The input in the noscript will be moved here as part of the page load -->
+ </span>
+ <a href="#" data-passwordunmask="edit" title="{{ edithint }}">
+ <span data-passwordunmask="displayvalue">{{> core_form/element-passwordunmask-fill }}</span>
+ {{# pix }} t/passwordunmask-edit, core, {{# str }} passwordunmaskedithint, form {{/ str }}{{/ pix }}
+ </a>
+ <a href="#" data-passwordunmask="unmask" title="{{ unmaskhint }}">
+ {{# pix }} t/passwordunmask-reveal, core, {{# str }} passwordunmaskrevealhint, form {{/ str }}{{/ pix }}
+ </a>
+ <span data-passwordunmask="instructions" class="form-text text-muted" style="display: none;">
+ {{# str }} passwordunmaskinstructions, form {{/ str }}
+ </span>
+ </span>
+ </span>
+</div>
+{{#js}}
+require(['core_form/passwordunmask'], function(PasswordUnmask) {
+ new PasswordUnmask("{{ id }}");
+});
{{/js}}
{{/params}}
<input type="hidden" name="sesskey" value="{{sesskey}}">
<input type="hidden" name="return" value="{{return}}">
- {{>core/prevent_form_autofill_password}}
{{#title}}
<h2>{{title}}</h2>
{{/title}}
<form action="{{actionurl}}" method="post" id="adminsettings">
<div>
<input type="hidden" name="sesskey" value="{{sesskey}}">
- {{>core/prevent_form_autofill_password}}
</div>
<fieldset>
<div class="clearer"></div>
-{{> core_form/element-password }}
-{{^element.frozen}}
+{{!
+ 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 <http://www.gnu.org/licenses/>.
+}}
+{{!
+ @template core_form/element-passwordunmask
+
+ Moodle passwordunmask form element template.
+
+ The purpose of this template is to render a passwordunmask form element.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Context variables required for this template:
+ * element
+ * id
+ * name
+ * value
+ * size
+
+ Example context (json):
+ {
+ "element": {
+ "id": "example_password_unmask",
+ "name": "example",
+ "value": "Password1!",
+ "size": 40
+ }
+ }
+
+}}
+{{< core_form/element-template }}
+ {{$ element }}
+ <span data-passwordunmask="wrapper" data-passwordunmaskid="{{ element.id }}">
+ <noscript>
+ <!-- Backwards compatability for Behat -->
+ <input type="password"
+ {{# element.frozen }}readonly{{/ element.frozen }}
+ {{^ element.hardfrozen}} name="{{ element.name }}"{{/ element.hardfrozen }}
+ id="{{ element.id }}"
+ value="{{ element.value }}"
+ class="form-control d-inline-block {{# error }}form-control-danger{{/ error }}"
+ size="{{ element.size }}"
+ {{# error }}
+ autofocus aria-describedby="id_error_{{ element.name }}"
+ {{/ error }}
+ {{{ attributes }}}
+ >
+ </noscript>
+ <span class="visibleifjs">
+ <span data-passwordunmask="editor">
+ <!-- The input in the noscript will be moved here as part of the page load -->
+ </span>
+ {{^ element.frozen }}
+ <a href="#" data-passwordunmask="edit" title="{{ edithint }}">
+ {{/ element.frozen }}
+ <span data-passwordunmask="displayvalue">{{> core_form/element-passwordunmask-fill }}</span>
+ {{^ element.frozen }}
+ {{# pix }} t/passwordunmask-edit, core, {{# str }} passwordunmaskedithint, form {{/ str }}{{/ pix }}
+ </a>
+ {{/ element.frozen }}
+ <a href="#" data-passwordunmask="unmask" title="{{ unmaskhint }}">
+ {{# pix }} t/passwordunmask-reveal, core, {{# str }} passwordunmaskrevealhint, form {{/ str }}{{/ pix }}
+ </a>
+ <span data-passwordunmask="instructions" class="form-text text-muted" style="display: none;">
+ {{^ element.frozen }}
+ {{# str }} passwordunmaskinstructions, form {{/ str }}
+ {{/ element.frozen }}
+ </span>
+ </span>
+ </span>
+ {{/ element }}
+{{/ core_form/element-template }}
{{#js}}
-require(['core/yui'], function(Y) {
- Y.use('moodle-form-passwordunmask', function() {
- M.form.passwordunmask({ formid: {{#quote}}{{element.id}}{{/quote}},
- checkboxlabel: {{#quote}}{{#str}}unmaskpassword, form{{/str}}{{/quote}},
- checkboxname: {{#quote}}{{element.name}}{{/quote}} });
- });
+require(['core_form/passwordunmask'], function(PasswordUnmask) {
+ new PasswordUnmask("{{ element.id }}");
});
-{{/js}}
-{{/element.frozen}}
+{{/ js }}
textarea[data-auto-rows] {
overflow-x: hidden;
}
+
+div[data-passwordunmask="wrapper"] {
+ height: 30px;
+ line-height: 30px;
+ margin-bottom: 10px;
+}
textarea[data-auto-rows] {
overflow-x: hidden;
}
+div[data-passwordunmask="wrapper"] {
+ height: 30px;
+ line-height: 30px;
+ margin-bottom: 10px;
+}
body.modal-open {
overflow: hidden;
}