You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
9.7 KiB
320 lines
9.7 KiB
define([ |
|
"dojo/_base/array", |
|
"dojo/_base/lang", |
|
"dojo/dom-attr", |
|
"dojo/i18n", |
|
"dojo/query", |
|
"dojo/keys", |
|
"dijit/form/_FormValueWidget", |
|
"dijit/form/ValidationTextBox", |
|
"dojo/text!./resources/PasswordValidator.html", |
|
"dojo/i18n!./nls/PasswordValidator", |
|
"dojo/_base/declare" |
|
], function(array, lang, domAttr, i18n, query, keys, FormValueWidget, ValidationTextBox, template, formNlsPasswordValidator, declare){ |
|
|
|
var _ChildTextBox = declare("dojox.form._ChildTextBox", ValidationTextBox, { |
|
// summary: |
|
// A class that is shared between all our children - extends |
|
// ValidationTextBox and provides some shared functionality |
|
|
|
// containerWidget: widget |
|
// Our parent (the PasswordValidator) |
|
containerWidget: null, |
|
|
|
// type: string |
|
// Don't override this - we are all "password" types |
|
type: "password", |
|
|
|
reset: function(){ |
|
// summary: |
|
// Force-set to empty string (we don't save passwords EVER)...and |
|
// since _OldPWBox overrides _setValueAttr to check for empty string, |
|
// call our parent class directly (not this.inherited()) |
|
ValidationTextBox.prototype._setValueAttr.call(this, "", true); |
|
this._hasBeenBlurred = false; |
|
}, |
|
|
|
postCreate: function(){ |
|
// summary: |
|
// We want to remove the "name" attribute from our focus node if |
|
// we don't have one set - this prevents all our extra values |
|
// from being posted on submit |
|
this.inherited(arguments); |
|
if(!this.name){ |
|
domAttr.remove(this.focusNode, "name"); |
|
} |
|
this.connect(this.focusNode, "onkeypress", "_onChildKeyPress"); |
|
}, |
|
|
|
_onChildKeyPress: function(e){ |
|
// Check if we pressed <enter> - if so, set our blur value so that |
|
// the parent widget will be updated correctly. |
|
if(e && e.keyCode == keys.ENTER){ |
|
this._setBlurValue(); |
|
} |
|
} |
|
}); |
|
|
|
|
|
|
|
var _OldPWBox = declare("dojox.form._OldPWBox", _ChildTextBox, { |
|
// summary: |
|
// A class representing our "old password" box. |
|
// |
|
// _isPWValid: boolean |
|
// Whether or not the password is valid |
|
_isPWValid: false, |
|
|
|
_setValueAttr: function(/*anything*/ newVal, /*Boolean?*/ priority){ |
|
// summary: |
|
// Updates _isPWValid if this isn't our initial update by calling |
|
// our PasswordValidator's pwCheck function |
|
if(newVal === ""){ |
|
newVal = _OldPWBox.superclass.attr.call(this, "value"); |
|
} |
|
if(priority !== null){ |
|
// Priority is passed in as null, explicitly when this is an |
|
// update (not initially set). We want to check our password now. |
|
this._isPWValid = this.containerWidget.pwCheck(newVal); |
|
} |
|
this.inherited(arguments); |
|
// Trigger the containerWidget to recheck its value, if needed |
|
this.containerWidget._childValueAttr(this.containerWidget._inputWidgets[1].get("value")); |
|
}, |
|
|
|
isValid: function(/*Boolean*/ isFocused){ |
|
// Take into account the isPWValid setting |
|
return this.inherited("isValid", arguments) && this._isPWValid; |
|
}, |
|
|
|
_update: function(/*Event*/ e){ |
|
// Only call validate() if we've been blurred or else we get popups |
|
// too early. |
|
if(this._hasBeenBlurred){ this.validate(true); } |
|
this._onMouse(e); |
|
}, |
|
|
|
_getValueAttr: function(){ |
|
if(this.containerWidget._started && this.containerWidget.isValid()){ |
|
return this.inherited(arguments); |
|
} |
|
return ""; |
|
}, |
|
|
|
_setBlurValue: function(){ |
|
// TextBox._setBlurValue calls this._setValueAttr(this.get('value'), ...) |
|
// Because we are overriding _getValueAttr to return "" when the containerWidget |
|
// is not valid, TextBox._setBlurValue will cause OldPWBox's value to be set to "" |
|
// |
|
// So, we directly call ValidationTextBox._getValueAttr to bypass our _getValueAttr |
|
var value = ValidationTextBox.prototype._getValueAttr.call(this); |
|
this._setValueAttr(value, (this.isValid ? this.isValid() : true)); |
|
} |
|
}); |
|
|
|
|
|
var _NewPWBox = declare("dojox.form._NewPWBox", _ChildTextBox, { |
|
// summary: |
|
// A class representing our new password textbox |
|
|
|
// required: boolean |
|
// Whether or not this widget is required (default: true) |
|
required: true, |
|
|
|
onChange: function(){ |
|
// summary: |
|
// Validates our verify box - to make sure that a change to me is |
|
// reflected there |
|
this.containerWidget._inputWidgets[2].validate(false); |
|
this.inherited(arguments); |
|
} |
|
}); |
|
|
|
var _VerifyPWBox = declare("dojox.form._VerifyPWBox", _ChildTextBox, { |
|
// summary: |
|
// A class representing our verify textbox |
|
|
|
isValid: function(isFocused){ |
|
// summary: |
|
// Validates that we match the "real" password |
|
return this.inherited("isValid", arguments) && |
|
(this.get("value") == this.containerWidget._inputWidgets[1].get("value")); |
|
} |
|
}); |
|
|
|
return declare("dojox.form.PasswordValidator", FormValueWidget, { |
|
// summary: |
|
// A password validation widget that simplifies the "old/new/verify" |
|
// style of requesting passwords. You will probably want to override |
|
// this class and implement your own pwCheck function. |
|
|
|
// required: boolean |
|
// Whether or not it is required for form submission |
|
required: true, |
|
|
|
// inputWidgets: TextBox[] |
|
// An array of text boxes that are our components |
|
_inputWidgets: null, |
|
|
|
// oldName: string? |
|
// The name to send our old password as (when form is posted) |
|
oldName: "", |
|
|
|
templateString: template, |
|
|
|
_hasBeenBlurred: false, |
|
|
|
isValid: function(/*Boolean*/ isFocused){ |
|
// summary: |
|
// we are valid if ALL our children are valid |
|
return array.every(this._inputWidgets, function(i){ |
|
if(i && i._setStateClass){ i._setStateClass(); } |
|
return (!i || i.isValid()); |
|
}); |
|
}, |
|
|
|
validate: function(/*Boolean*/ isFocused){ |
|
// summary: |
|
// Validating this widget validates all our children |
|
return array.every(array.map(this._inputWidgets, function(i){ |
|
if(i && i.validate){ |
|
i._hasBeenBlurred = (i._hasBeenBlurred || this._hasBeenBlurred); |
|
return i.validate(); |
|
} |
|
return true; |
|
}, this), function(item){ return item; }); |
|
}, |
|
|
|
reset: function(){ |
|
// summary: |
|
// Resetting this widget resets all our children |
|
this._hasBeenBlurred = false; |
|
array.forEach(this._inputWidgets, function(i){ |
|
if(i && i.reset){ i.reset(); } |
|
}, this); |
|
}, |
|
|
|
_createSubWidgets: function(){ |
|
// summary: |
|
// Turns the inputs inside this widget into "real" validation |
|
// widgets - and sets up the needed connections. |
|
var widgets = this._inputWidgets, |
|
msg = i18n.getLocalization("dojox.form", "PasswordValidator", this.lang); |
|
array.forEach(widgets, function(i, idx){ |
|
if(i){ |
|
var p = {containerWidget: this}, c; |
|
if(idx === 0){ |
|
p.name = this.oldName; |
|
p.invalidMessage = msg.badPasswordMessage; |
|
c = _OldPWBox; |
|
}else if(idx === 1){ |
|
p.required = this.required; |
|
c = _NewPWBox; |
|
}else if(idx === 2){ |
|
p.invalidMessage = msg.nomatchMessage; |
|
c = _VerifyPWBox; |
|
} |
|
widgets[idx] = new c(p, i); |
|
} |
|
}, this); |
|
}, |
|
|
|
pwCheck: function(/*String*/ password){ |
|
// summary: |
|
// Overridable function for validation of the old password box. |
|
// |
|
// This function is called and passed the old password. Return |
|
// true if it's OK to continue, and false if it is not. |
|
// |
|
// IMPORTANT SECURITY NOTE: Do NOT EVER EVER EVER check this in |
|
// HTML or JavaScript!!! |
|
// |
|
// You will probably want to override this function to callback |
|
// to a server to verify the password (the callback will need to |
|
// be synchronous) - and it's probably a good idea to validate |
|
// it again on form submission before actually doing |
|
// anything destructive - that's why the "oldName" value |
|
// is available. |
|
// |
|
// And don't just fetch the password from the server |
|
// either :) Send the test password (probably hashed, for |
|
// security) and return from the server a status instead. |
|
// |
|
// Again - DON'T BE INSECURE!!! Security is left as an exercise |
|
// for the reader :) |
|
return false; |
|
}, |
|
|
|
postCreate: function(){ |
|
// summary: |
|
// Sets up the correct widgets. You *MUST* specify one child |
|
// text box (a simple HTML `<input>` element) with pwType="new" |
|
// *and* one child text box with pwType="verify". You *MAY* |
|
// specify a third child text box with pwType="old" in order to |
|
// prompt the user to enter in their old password before the |
|
// widget returns that it is valid. |
|
|
|
this.inherited(arguments); |
|
|
|
// Turn my inputs into the correct stuff.... |
|
var widgets = this._inputWidgets = []; |
|
array.forEach(["old","new","verify"], function(i){ |
|
widgets.push(query("input[pwType=" + i + "]", this.containerNode)[0]); |
|
}, this); |
|
if(!widgets[1] || !widgets[2]){ |
|
throw new Error("Need at least pwType=\"new\" and pwType=\"verify\""); |
|
} |
|
if(this.oldName && !widgets[0]){ |
|
throw new Error("Need to specify pwType=\"old\" if using oldName"); |
|
} |
|
this.containerNode = this.domNode; |
|
this._createSubWidgets(); |
|
this.connect(this._inputWidgets[1], "_setValueAttr", "_childValueAttr"); |
|
this.connect(this._inputWidgets[2], "_setValueAttr", "_childValueAttr"); |
|
}, |
|
|
|
_childValueAttr: function(v){ |
|
this.set("value", this.isValid() ? v : ""); |
|
}, |
|
|
|
_setDisabledAttr: function(value){ |
|
this.inherited(arguments); |
|
array.forEach(this._inputWidgets, function(i){ |
|
if(i && i.set){ i.set("disabled", value);} |
|
}); |
|
}, |
|
|
|
_setRequiredAttr: function(value){ |
|
this.required = value; |
|
domAttr.set(this.focusNode, "required", value); |
|
this.focusNode.setAttribute("aria-required", value); |
|
array.forEach(this._inputWidgets, function(i){ |
|
if(i && i.set){ i.set("required", value);} |
|
}); |
|
}, |
|
|
|
_setValueAttr: function(v){ |
|
this.inherited(arguments); |
|
domAttr.set(this.focusNode, "value", v); |
|
}, |
|
|
|
_getValueAttr: function(){ |
|
// Make sure we don't return undefined.... maybe should do conversion in _setValueAttr() instead? |
|
return this.value||""; |
|
}, |
|
|
|
focus: function(){ |
|
// summary: |
|
// places focus on the first invalid input widget - if all |
|
// input widgets are valid, the first widget is focused. |
|
var f = false; |
|
array.forEach(this._inputWidgets, function(i){ |
|
if(i && !i.isValid() && !f){ |
|
i.focus(); |
|
f = true; |
|
} |
|
}); |
|
if(!f){ this._inputWidgets[1].focus(); } |
|
} |
|
}); |
|
});
|
|
|