mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-28 17:48:56 +01:00
implement et2-password web-component replacing passwd legacy widget
enabled Et2InvokerMixin to use an image instead of a textual label also remove et2_fullWidth CSS class from all web-components in the preprocessor
This commit is contained in:
parent
862d355e77
commit
888b518e9b
@ -270,6 +270,8 @@ function send_template()
|
|||||||
return $replace;
|
return $replace;
|
||||||
}, $str);
|
}, $str);
|
||||||
|
|
||||||
|
$str = preg_replace('#<passwd ([^/>]+)/>#', '<et2-password $1></et2-password>', $str);
|
||||||
|
|
||||||
// ^^^^^^^^^^^^^^^^ above widgets get transformed independent of legacy="true" set in overlay ^^^^^^^^^^^^^^^^^^
|
// ^^^^^^^^^^^^^^^^ above widgets get transformed independent of legacy="true" set in overlay ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
// eTemplate marked as legacy --> replace only some widgets (eg. requiring jQueryUI) with web-components
|
// eTemplate marked as legacy --> replace only some widgets (eg. requiring jQueryUI) with web-components
|
||||||
@ -368,6 +370,13 @@ function send_template()
|
|||||||
unset($attrs[$name]);
|
unset($attrs[$name]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove no longer necessary et2_fullWidth class, it's the default now anyway
|
||||||
|
if (isset($attrs['class']) && empty($attrs['class'] = trim(preg_replace('/(^| )et2_fullWidth( |$)/', ' ', $attrs['class']))))
|
||||||
|
{
|
||||||
|
unset($attrs['class']);
|
||||||
|
}
|
||||||
|
|
||||||
$ret = str_replace($matches[3], implode(' ', array_map(static function ($name, $value) {
|
$ret = str_replace($matches[3], implode(' ', array_map(static function ($name, $value) {
|
||||||
return $name . '="' . $value . '"';
|
return $name . '="' . $value . '"';
|
||||||
}, array_keys($attrs), $attrs)).(substr($matches[3], -1) === '/' ? '/' : ''), $matches[0]);
|
}, array_keys($attrs), $attrs)).(substr($matches[3], -1) === '/' ? '/' : ''), $matches[0]);
|
||||||
|
174
api/js/etemplate/Et2Textbox/Et2Password.ts
Normal file
174
api/js/etemplate/Et2Textbox/Et2Password.ts
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
* EGroupware eTemplate2 - Password input widget
|
||||||
|
*
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @package api
|
||||||
|
* @link https://www.egroupware.org
|
||||||
|
* @author Ralf Becker
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
import {Et2InvokerMixin} from "../Et2Url/Et2InvokerMixin";
|
||||||
|
import {Et2Textbox} from "./Et2Textbox";
|
||||||
|
import {Et2Dialog} from "../Et2Dialog/Et2Dialog";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @customElement et2-password
|
||||||
|
*/
|
||||||
|
export class Et2Password extends Et2InvokerMixin(Et2Textbox)
|
||||||
|
{
|
||||||
|
// The password is stored encrypted server side, and passed encrypted.
|
||||||
|
// This flag is for if we've decrypted the password to show it already
|
||||||
|
private encrypted = true;
|
||||||
|
private visible = false;
|
||||||
|
|
||||||
|
/** @type {any} */
|
||||||
|
static get properties()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
...super.properties,
|
||||||
|
/**
|
||||||
|
* Password is plaintext
|
||||||
|
*/
|
||||||
|
plaintext: Boolean,
|
||||||
|
/**
|
||||||
|
* Suggest password length (0 for off)
|
||||||
|
*/
|
||||||
|
suggest: Number,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.plaintext = true;
|
||||||
|
this.suggest = 0;
|
||||||
|
|
||||||
|
this._invokerLabel = '';
|
||||||
|
this._invokerTitle = this.egw().lang("Suggest password");
|
||||||
|
this._invokerAction = () =>
|
||||||
|
{
|
||||||
|
this.suggestPassword();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
transformAttributes(attrs)
|
||||||
|
{
|
||||||
|
attrs.suggest = parseInt(attrs.suggest);
|
||||||
|
attrs.type = 'password';
|
||||||
|
|
||||||
|
if (attrs.viewable)
|
||||||
|
{
|
||||||
|
attrs['toggle-password'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.transformAttributes(attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to check if invoker can be activated: not disabled, empty or invalid
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
* */
|
||||||
|
_toggleInvokerDisabled()
|
||||||
|
{
|
||||||
|
if (this._invokerNode)
|
||||||
|
{
|
||||||
|
const invokerNode = /** @type {HTMLElement & {disabled: boolean}} */ (this._invokerNode);
|
||||||
|
invokerNode.disabled = this.disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {PropertyKey} name
|
||||||
|
* @param {?} oldValue
|
||||||
|
*/
|
||||||
|
requestUpdate(name, oldValue)
|
||||||
|
{
|
||||||
|
super.requestUpdate(name, oldValue);
|
||||||
|
|
||||||
|
if (name === 'suggest' && this.suggest != oldValue)
|
||||||
|
{
|
||||||
|
this._invokerLabel = this.suggest ? 'generate_password' : '';
|
||||||
|
this._toggleInvokerDisabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask the server for a password suggestion
|
||||||
|
*/
|
||||||
|
suggestPassword()
|
||||||
|
{
|
||||||
|
// They need to see the suggestion
|
||||||
|
this.encrypted = false;
|
||||||
|
this.type = 'text';
|
||||||
|
//this.toggle_visibility(true);
|
||||||
|
|
||||||
|
let suggestion = "Suggestion";
|
||||||
|
let request = egw.request("EGroupware\\Api\\Etemplate\\Widget\\Password::ajax_suggest", [this.suggest])
|
||||||
|
.then(suggestion =>
|
||||||
|
{
|
||||||
|
this.encrypted = false;
|
||||||
|
this.value = suggestion;
|
||||||
|
|
||||||
|
// Check for second password, update it too
|
||||||
|
let two = this.getParent().getWidgetById(this.id+'_2');
|
||||||
|
if(two && two.getType() == this.getType())
|
||||||
|
{
|
||||||
|
two.type = 'text';
|
||||||
|
two.value = suggestion;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the password is viewable, toggle the visibility.
|
||||||
|
* If the password is still encrypted, we'll ask for the user's password then have the server decrypt it.
|
||||||
|
*/
|
||||||
|
handlePasswordToggle()
|
||||||
|
{
|
||||||
|
super.handlePasswordToggle();
|
||||||
|
|
||||||
|
this.visible = !this.visible; // can't access private isPasswordVisible
|
||||||
|
|
||||||
|
if (!this.visible || !this.encrypted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need username & password to decrypt
|
||||||
|
Et2Dialog.show_prompt(
|
||||||
|
(button, user_password) =>
|
||||||
|
{
|
||||||
|
if(button == Et2Dialog.CANCEL_BUTTON)
|
||||||
|
{
|
||||||
|
return this.handlePasswordToggle();
|
||||||
|
}
|
||||||
|
this.egw().request(
|
||||||
|
"EGroupware\\Api\\Etemplate\\Widget\\Password::ajax_decrypt",
|
||||||
|
[user_password, this.value]).then(decrypted =>
|
||||||
|
{
|
||||||
|
if (decrypted)
|
||||||
|
{
|
||||||
|
this.encrypted = false;
|
||||||
|
this.value = decrypted;
|
||||||
|
this.type = 'text';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.set_validation_error(this.egw().lang("invalid password"));
|
||||||
|
window.setTimeout(() =>
|
||||||
|
{
|
||||||
|
this.set_validation_error(false);
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
this.egw().lang("Enter your password"),
|
||||||
|
this.egw().lang("Authenticate")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// @ts-ignore TypeScript is not recognizing that this is a LitElement
|
||||||
|
customElements.define("et2-password", Et2Password);
|
@ -30,6 +30,9 @@ export const Et2InvokerMixin = dedupeMixin(<T extends Constructor<LitElement>>(s
|
|||||||
static get properties()
|
static get properties()
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
|
/**
|
||||||
|
* Textual label or image specifier for egw.image()
|
||||||
|
*/
|
||||||
_invokerLabel: {
|
_invokerLabel: {
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
@ -65,6 +68,11 @@ export const Et2InvokerMixin = dedupeMixin(<T extends Constructor<LitElement>>(s
|
|||||||
width: 14px;
|
width: 14px;
|
||||||
border: none !important;
|
border: none !important;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
background-position: center right;
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
::slotted(:disabled) {cursor: default !important;}
|
::slotted(:disabled) {cursor: default !important;}
|
||||||
:host(:hover) ::slotted([slot="suffix"]) {
|
:host(:hover) ::slotted([slot="suffix"]) {
|
||||||
@ -142,7 +150,17 @@ export const Et2InvokerMixin = dedupeMixin(<T extends Constructor<LitElement>>(s
|
|||||||
if (this._invokerNode)
|
if (this._invokerNode)
|
||||||
{
|
{
|
||||||
this._invokerNode.style.display = !this._invokerLabel ? 'none' : 'inline-block';
|
this._invokerNode.style.display = !this._invokerLabel ? 'none' : 'inline-block';
|
||||||
this._invokerNode.innerHTML = this._invokerLabel || '';
|
const img = this._invokerLabel ? this.egw().image(this._invokerLabel) : null;
|
||||||
|
if (img)
|
||||||
|
{
|
||||||
|
this._invokerNode.style.backgroundImage = 'url('+img+')';
|
||||||
|
this._invokerNode.innerHTML = '';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._invokerNode.style.backgroundImage = 'none';
|
||||||
|
this._invokerNode.innerHTML = this._invokerLabel || '';
|
||||||
|
}
|
||||||
this._invokerNode.title = this._invokerTitle || '';
|
this._invokerNode.title = this._invokerTitle || '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,8 @@ export class Et2Url extends Et2InvokerMixin(Et2Textbox)
|
|||||||
::slotted([slot="suffix"]) {
|
::slotted([slot="suffix"]) {
|
||||||
font-size: 133% !important;
|
font-size: 133% !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -27,6 +27,8 @@ export class Et2UrlEmail extends Et2InvokerMixin(Et2Textbox)
|
|||||||
css`
|
css`
|
||||||
::slotted([slot="suffix"]) {
|
::slotted([slot="suffix"]) {
|
||||||
font-size: 90% !important;
|
font-size: 90% !important;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -27,6 +27,8 @@ export class Et2UrlFax extends Et2UrlPhone
|
|||||||
::slotted([slot="suffix"]) {
|
::slotted([slot="suffix"]) {
|
||||||
font-size: 90% !important;
|
font-size: 90% !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -26,6 +26,7 @@ export class Et2UrlPhone extends Et2InvokerMixin(Et2Textbox)
|
|||||||
css`
|
css`
|
||||||
::slotted([slot="suffix"]) {
|
::slotted([slot="suffix"]) {
|
||||||
font-size: 133% !important;
|
font-size: 133% !important;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
@ -1,343 +0,0 @@
|
|||||||
/**
|
|
||||||
* EGroupware eTemplate2 - JS Textbox object
|
|
||||||
*
|
|
||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
||||||
* @package etemplate
|
|
||||||
* @subpackage api
|
|
||||||
* @link https://www.egroupware.org
|
|
||||||
* @author Andreas Stöckel
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*egw:uses
|
|
||||||
/vendor/bower-asset/jquery/dist/jquery.js;
|
|
||||||
et2_core_inputWidget;
|
|
||||||
et2_core_valueWidget;
|
|
||||||
*/
|
|
||||||
|
|
||||||
import './et2_core_common';
|
|
||||||
import {ClassWithAttributes} from "./et2_core_inheritance";
|
|
||||||
import {et2_createWidget, et2_register_widget, WidgetConfig} from "./et2_core_widget";
|
|
||||||
import {et2_inputWidget} from './et2_core_inputWidget'
|
|
||||||
import {et2_button} from './et2_widget_button'
|
|
||||||
import {et2_textbox, et2_textbox_ro} from "./et2_widget_textbox";
|
|
||||||
import {egw} from "../jsapi/egw_global";
|
|
||||||
import {Et2Dialog} from "./Et2Dialog/Et2Dialog";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class which implements the "textbox" XET-Tag
|
|
||||||
*
|
|
||||||
* @augments et2_inputWidget
|
|
||||||
*/
|
|
||||||
export class et2_password extends et2_textbox
|
|
||||||
{
|
|
||||||
static readonly _attributes : any = {
|
|
||||||
"autocomplete": {
|
|
||||||
"name": "Autocomplete",
|
|
||||||
"type": "string",
|
|
||||||
"default": "off",
|
|
||||||
"description": "Whether or not browser should autocomplete that field: 'on', 'off', 'default' (use attribute from form). Default value is set to off."
|
|
||||||
},
|
|
||||||
"viewable": {
|
|
||||||
"name": "Viewable",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false,
|
|
||||||
"description": "Allow password to be shown"
|
|
||||||
},
|
|
||||||
"plaintext": {
|
|
||||||
name: "Plaintext",
|
|
||||||
type: "boolean",
|
|
||||||
default: true,
|
|
||||||
description: "Password is plaintext"
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
name: "Suggest password",
|
|
||||||
type: "integer",
|
|
||||||
default: 0,
|
|
||||||
description: "Suggest password length (0 for off)"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static readonly DEFAULT_LENGTH = 16;
|
|
||||||
wrapper : JQuery;
|
|
||||||
private suggest_button: et2_button;
|
|
||||||
private show_button: et2_button;
|
|
||||||
|
|
||||||
// The password is stored encrypted server side, and passed encrypted.
|
|
||||||
// This flag is for if we've decrypted the password to show it already
|
|
||||||
private encrypted : boolean = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
constructor(_parent, _attrs? : WidgetConfig, _child? : object)
|
|
||||||
{
|
|
||||||
// Call the inherited constructor
|
|
||||||
super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_password._attributes, _child || {}));
|
|
||||||
|
|
||||||
if(this.options.plaintext)
|
|
||||||
{
|
|
||||||
this.encrypted = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createInputWidget()
|
|
||||||
{
|
|
||||||
this.wrapper = jQuery(document.createElement("div"))
|
|
||||||
.addClass("et2_password");
|
|
||||||
this.input = jQuery(document.createElement("input"))
|
|
||||||
|
|
||||||
this.input.attr("type", "password");
|
|
||||||
// Make autocomplete default value off for password field
|
|
||||||
// seems browsers not respecting 'off' anymore and started to
|
|
||||||
// implement a new key called "new-password" considered as switching
|
|
||||||
// autocomplete off.
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion
|
|
||||||
if (this.options.autocomplete === "" || this.options.autocomplete == "off") this.options.autocomplete = "new-password";
|
|
||||||
|
|
||||||
if(this.options.size) {
|
|
||||||
this.set_size(this.options.size);
|
|
||||||
}
|
|
||||||
if(this.options.blur) {
|
|
||||||
this.set_blur(this.options.blur);
|
|
||||||
}
|
|
||||||
if(this.options.readonly) {
|
|
||||||
this.set_readonly(true);
|
|
||||||
}
|
|
||||||
this.input.addClass("et2_textbox")
|
|
||||||
.appendTo(this.wrapper);
|
|
||||||
this.setDOMNode(this.wrapper[0]);
|
|
||||||
if(this.options.value)
|
|
||||||
{
|
|
||||||
this.set_value(this.options.value);
|
|
||||||
}
|
|
||||||
if (this.options.onkeypress && typeof this.options.onkeypress == 'function')
|
|
||||||
{
|
|
||||||
var self = this;
|
|
||||||
this.input.on('keypress', function(_ev)
|
|
||||||
{
|
|
||||||
return self.options.onkeypress.call(this, _ev, self);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.input.on('change', function() {
|
|
||||||
this.encrypted = false;
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
// Show button is needed from start as you can't turn viewable on via JS
|
|
||||||
let attrs = {
|
|
||||||
class: "show_hide",
|
|
||||||
image: "visibility",
|
|
||||||
onclick: this.toggle_visibility.bind(this),
|
|
||||||
statustext: this.egw().lang("Show password")
|
|
||||||
};
|
|
||||||
if(this.options.viewable)
|
|
||||||
{
|
|
||||||
this.show_button = <et2_button>et2_createWidget("button", attrs, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getInputNode()
|
|
||||||
{
|
|
||||||
return this.input[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the parent set_id method to manuipulate the input DOM node
|
|
||||||
*
|
|
||||||
* @param {type} _value
|
|
||||||
* @returns {undefined}
|
|
||||||
*/
|
|
||||||
set_id(_value)
|
|
||||||
{
|
|
||||||
super.set_id(_value);
|
|
||||||
|
|
||||||
// Remove the name attribute inorder to affect autocomplete="off"
|
|
||||||
// for no password save. ATM seems all browsers ignore autocomplete for
|
|
||||||
// input field inside the form
|
|
||||||
if (this.options.autocomplete === "off") this.input.removeAttr('name');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether or not the password is allowed to be shown in clear text.
|
|
||||||
*
|
|
||||||
* @param viewable
|
|
||||||
*/
|
|
||||||
set_viewable(viewable: boolean)
|
|
||||||
{
|
|
||||||
this.options.viewable = viewable;
|
|
||||||
|
|
||||||
if(viewable)
|
|
||||||
{
|
|
||||||
jQuery('.show_hide', this.wrapper).show();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
jQuery('.show_hide', this.wrapper).hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn on or off the suggest password button.
|
|
||||||
*
|
|
||||||
* When clicked, a password of the set length will be generated.
|
|
||||||
*
|
|
||||||
* @param length Length of password to generate. 0 to disable.
|
|
||||||
*/
|
|
||||||
set_suggest(length: number)
|
|
||||||
{
|
|
||||||
if(typeof length !== "number")
|
|
||||||
{
|
|
||||||
length = typeof length === "string" ? parseInt(length) : (length ? et2_password.DEFAULT_LENGTH : 0);
|
|
||||||
}
|
|
||||||
this.options.suggest = length;
|
|
||||||
|
|
||||||
if(length && !this.suggest_button)
|
|
||||||
{
|
|
||||||
let attrs = {
|
|
||||||
class: "generate_password",
|
|
||||||
image: "generate_password",
|
|
||||||
onclick: this.suggest_password.bind(this),
|
|
||||||
statustext: this.egw().lang("Suggest password")
|
|
||||||
};
|
|
||||||
this.suggest_button = <et2_button> et2_createWidget("button", attrs, this);
|
|
||||||
if(this.parentNode)
|
|
||||||
{
|
|
||||||
// Turned on after initial load, need to run loadingFinished()
|
|
||||||
this.suggest_button.loadingFinished();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(length)
|
|
||||||
{
|
|
||||||
jQuery('.generate_password', this.wrapper).show();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
jQuery('.generate_password', this.wrapper).hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the password is viewable, toggle the visibility.
|
|
||||||
* If the password is still encrypted, we'll ask for the user's password then have the server decrypt it.
|
|
||||||
*
|
|
||||||
* @param on
|
|
||||||
*/
|
|
||||||
toggle_visibility(on : boolean | undefined)
|
|
||||||
{
|
|
||||||
if(typeof on !== "boolean")
|
|
||||||
{
|
|
||||||
on = this.input.attr("type") == "password";
|
|
||||||
}
|
|
||||||
if(!this.options.viewable)
|
|
||||||
{
|
|
||||||
this.input.attr("type", "password");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(this.show_button)
|
|
||||||
{
|
|
||||||
this.show_button.set_image(this.egw().image(on ? 'visibility_off' : 'visibility'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are not encrypted or not showing it, we're done
|
|
||||||
if(!this.encrypted || !on)
|
|
||||||
{
|
|
||||||
this.input.attr("type",on ? "textbox" : "password");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Need username & password to decrypt
|
|
||||||
let callback = function(button, user_password)
|
|
||||||
{
|
|
||||||
if(button == Et2Dialog.CANCEL_BUTTON)
|
|
||||||
{
|
|
||||||
return this.toggle_visibility(false);
|
|
||||||
}
|
|
||||||
let request = egw.json(
|
|
||||||
"EGroupware\\Api\\Etemplate\\Widget\\Password::ajax_decrypt",
|
|
||||||
[user_password, this.options.value],
|
|
||||||
function(decrypted)
|
|
||||||
{
|
|
||||||
if(decrypted)
|
|
||||||
{
|
|
||||||
this.encrypted = false;
|
|
||||||
this.input.val(decrypted);
|
|
||||||
this.input.attr("type", "textbox");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.set_validation_error(this.egw().lang("invalid password"));
|
|
||||||
window.setTimeout(function()
|
|
||||||
{
|
|
||||||
this.set_validation_error(false);
|
|
||||||
}.bind(this), 2000);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
this, true, this
|
|
||||||
).sendRequest();
|
|
||||||
}.bind(this);
|
|
||||||
let prompt = Et2Dialog.show_prompt(
|
|
||||||
callback,
|
|
||||||
this.egw().lang("Enter your password"),
|
|
||||||
this.egw().lang("Authenticate")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Make the password prompt a password field
|
|
||||||
prompt.div.on("load", function() {
|
|
||||||
jQuery(prompt.template.widgetContainer.getWidgetById('value').getInputNode())
|
|
||||||
.attr("type","password");
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ask the server for a password suggestion
|
|
||||||
*/
|
|
||||||
suggest_password()
|
|
||||||
{
|
|
||||||
// They need to see the suggestion
|
|
||||||
this.encrypted = false;
|
|
||||||
this.options.viewable = true;
|
|
||||||
this.toggle_visibility(true);
|
|
||||||
|
|
||||||
let suggestion = "Suggestion";
|
|
||||||
let request = egw.json("EGroupware\\Api\\Etemplate\\Widget\\Password::ajax_suggest",
|
|
||||||
[this.options.suggest],
|
|
||||||
function(suggestion) {
|
|
||||||
this.encrypted = false;
|
|
||||||
this.input.val(suggestion);
|
|
||||||
this.input.trigger('change');
|
|
||||||
|
|
||||||
// Check for second password, update it too
|
|
||||||
let two = this.getParent().getWidgetById(this.id+'_2');
|
|
||||||
if(two && two.getType() == this.getType())
|
|
||||||
{
|
|
||||||
two.options.viewable = true;
|
|
||||||
two.toggle_visibility(true);
|
|
||||||
two.set_value(suggestion);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
this,true,this
|
|
||||||
).sendRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy()
|
|
||||||
{
|
|
||||||
super.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
getValue()
|
|
||||||
{
|
|
||||||
return this.input.val();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
et2_register_widget(et2_password, [ "passwd"]);
|
|
||||||
|
|
||||||
|
|
||||||
export class et2_password_ro extends et2_textbox_ro
|
|
||||||
{
|
|
||||||
set_value(value)
|
|
||||||
{
|
|
||||||
this.value_span.text(value ? "********" : "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
et2_register_widget(et2_password_ro, [ "passwd_ro"]);
|
|
@ -85,6 +85,7 @@ import "./Layout/Et2Split/Et2Split";
|
|||||||
import "./Layout/RowLimitedMixin";
|
import "./Layout/RowLimitedMixin";
|
||||||
import "./Et2Vfs/Et2VfsMime";
|
import "./Et2Vfs/Et2VfsMime";
|
||||||
import "./Et2Vfs/Et2VfsUid";
|
import "./Et2Vfs/Et2VfsUid";
|
||||||
|
import "./Et2Textbox/Et2Password";
|
||||||
|
|
||||||
/* Include all widget classes here, we only care about them registering, not importing anything*/
|
/* Include all widget classes here, we only care about them registering, not importing anything*/
|
||||||
import './et2_widget_vfs'; // Vfs must be first (before et2_widget_file) due to import cycle
|
import './et2_widget_vfs'; // Vfs must be first (before et2_widget_file) due to import cycle
|
||||||
@ -98,7 +99,6 @@ import './et2_widget_color';
|
|||||||
import './et2_widget_entry';
|
import './et2_widget_entry';
|
||||||
import './et2_widget_textbox';
|
import './et2_widget_textbox';
|
||||||
import './et2_widget_number';
|
import './et2_widget_number';
|
||||||
import './et2_widget_password';
|
|
||||||
import './et2_widget_url';
|
import './et2_widget_url';
|
||||||
import './et2_widget_selectbox';
|
import './et2_widget_selectbox';
|
||||||
import './et2_widget_checkbox';
|
import './et2_widget_checkbox';
|
||||||
|
Loading…
Reference in New Issue
Block a user