From d02c26772b448747a5d4249819957f564a19926a Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Tue, 28 Apr 2020 23:34:33 +0200 Subject: [PATCH] luci-base: ui.js: rework password input handling - Get rid of dummy element - Render password field as text input initially and later transform it to a password field - Use .control-group markup to allow better styling Signed-off-by: Jo-Philipp Wich --- .../htdocs/luci-static/resources/ui.js | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/modules/luci-base/htdocs/luci-static/resources/ui.js b/modules/luci-base/htdocs/luci-static/resources/ui.js index 612f74776..73f5b90bc 100644 --- a/modules/luci-base/htdocs/luci-static/resources/ui.js +++ b/modules/luci-base/htdocs/luci-static/resources/ui.js @@ -310,48 +310,45 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { /** @override */ render: function() { var frameEl = E('div', { 'id': this.options.id }); - - if (this.options.password) { - frameEl.classList.add('nowrap'); - frameEl.appendChild(E('input', { - 'type': 'password', - 'style': 'position:absolute; left:-100000px', - 'aria-hidden': true, - 'tabindex': -1, - 'name': this.options.name ? 'password.%s'.format(this.options.name) : null - })); - } - - frameEl.appendChild(E('input', { + var inputEl = E('input', { 'id': this.options.id ? 'widget.' + this.options.id : null, 'name': this.options.name, - 'type': this.options.password ? 'password' : 'text', + 'type': 'text', 'class': this.options.password ? 'cbi-input-password' : 'cbi-input-text', 'readonly': this.options.readonly ? '' : null, 'disabled': this.options.disabled ? '' : null, 'maxlength': this.options.maxlength, 'placeholder': this.options.placeholder, 'value': this.value, - })); + }); - if (this.options.password) - frameEl.appendChild(E('button', { - 'class': 'cbi-button cbi-button-neutral', - 'title': _('Reveal/hide password'), - 'aria-label': _('Reveal/hide password'), - 'click': function(ev) { - var e = this.previousElementSibling; - e.type = (e.type === 'password') ? 'text' : 'password'; - ev.preventDefault(); - } - }, '∗')); + if (this.options.password) { + frameEl.appendChild(E('div', { 'class': 'control-group' }, [ + inputEl, + E('button', { + 'class': 'cbi-button cbi-button-neutral', + 'title': _('Reveal/hide password'), + 'aria-label': _('Reveal/hide password'), + 'click': function(ev) { + var e = this.previousElementSibling; + e.type = (e.type === 'password') ? 'text' : 'password'; + ev.preventDefault(); + } + }, '∗') + ])); + + window.requestAnimationFrame(function() { inputEl.type = 'password' }); + } + else { + frameEl.appendChild(inputEl); + } return this.bind(frameEl); }, /** @private */ bind: function(frameEl) { - var inputEl = frameEl.childNodes[+!!this.options.password]; + var inputEl = frameEl.querySelector('input'); this.node = frameEl; @@ -365,7 +362,7 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { /** @override */ getValue: function() { - var inputEl = this.node.childNodes[+!!this.options.password]; + var inputEl = this.node.querySelector('input'); return inputEl.value; }, -- 2.25.1