source: Dev/trunk/src/client/dojox/form/PasswordValidator.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 9.7 KB
Line 
1define([
2        "dojo/_base/array",
3        "dojo/_base/lang",
4        "dojo/dom-attr",
5        "dojo/i18n",
6        "dojo/query",
7        "dojo/keys",
8        "dijit/form/_FormValueWidget",
9        "dijit/form/ValidationTextBox",
10        "dojo/text!./resources/PasswordValidator.html",
11        "dojo/i18n!./nls/PasswordValidator",
12        "dojo/_base/declare"
13], function(array, lang, domAttr, i18n, query, keys, FormValueWidget, ValidationTextBox, template, formNlsPasswordValidator, declare){
14
15var _ChildTextBox = declare("dojox.form._ChildTextBox", ValidationTextBox, {
16        // summary:
17        //              A class that is shared between all our children - extends
18        //              ValidationTextBox and provides some shared functionality
19
20        // containerWidget: widget
21        //              Our parent (the PasswordValidator)
22        containerWidget: null,
23
24        // type: string
25        //              Don't override this - we are all "password" types
26        type: "password",
27
28        reset: function(){
29                // summary:
30                //              Force-set to empty string (we don't save passwords EVER)...and
31                //              since _OldPWBox overrides _setValueAttr to check for empty string,
32                //              call our parent class directly (not this.inherited())
33                ValidationTextBox.prototype._setValueAttr.call(this, "", true);
34                this._hasBeenBlurred = false;
35        },
36
37        postCreate: function(){
38                // summary:
39                //              We want to remove the "name" attribute from our focus node if
40                //              we don't have one set - this prevents all our extra values
41                //              from being posted on submit
42                this.inherited(arguments);
43                if(!this.name){
44                        domAttr.remove(this.focusNode, "name");
45                }
46                this.connect(this.focusNode, "onkeypress", "_onChildKeyPress");
47        },
48
49        _onChildKeyPress: function(e){
50                // Check if we pressed <enter> - if so, set our blur value so that
51                // the parent widget will be updated correctly.
52                if(e && e.keyCode == keys.ENTER){
53                        this._setBlurValue();
54                }
55        }
56});
57
58
59
60var _OldPWBox = declare("dojox.form._OldPWBox", _ChildTextBox, {
61        // summary:
62        //              A class representing our "old password" box.
63        //
64        // _isPWValid: boolean
65        //              Whether or not the password is valid
66        _isPWValid: false,
67
68        _setValueAttr: function(/*anything*/ newVal, /*Boolean?*/ priority){
69                // summary:
70                //              Updates _isPWValid if this isn't our initial update by calling
71                //              our PasswordValidator's pwCheck function
72                if(newVal === ""){
73                        newVal = _OldPWBox.superclass.attr.call(this, "value");
74                }
75                if(priority !== null){
76                        // Priority is passed in as null, explicitly when this is an
77                        // update (not initially set).  We want to check our password now.
78                        this._isPWValid = this.containerWidget.pwCheck(newVal);
79                }
80                this.inherited(arguments);
81                // Trigger the containerWidget to recheck its value, if needed
82                this.containerWidget._childValueAttr(this.containerWidget._inputWidgets[1].get("value"));
83        },
84
85        isValid: function(/*Boolean*/ isFocused){
86                // Take into account the isPWValid setting
87                return this.inherited("isValid", arguments) && this._isPWValid;
88        },
89
90        _update: function(/*Event*/ e){
91                // Only call validate() if we've been blurred or else we get popups
92                // too early.
93                if(this._hasBeenBlurred){ this.validate(true); }
94                this._onMouse(e);
95        },
96
97        _getValueAttr: function(){
98                if(this.containerWidget._started && this.containerWidget.isValid()){
99                        return this.inherited(arguments);
100                }
101                return "";
102        },
103
104        _setBlurValue: function(){
105                // TextBox._setBlurValue calls this._setValueAttr(this.get('value'), ...)
106                // Because we are overridding _getValueAttr to return "" when the containerWidget
107                // is not valid, TextBox._setBlurValue will cause OldPWBox's value to be set to ""
108                //
109                // So, we directly call ValidationTextBox._getValueAttr to bypass our _getValueAttr
110                var value = ValidationTextBox.prototype._getValueAttr.call(this);
111                this._setValueAttr(value, (this.isValid ? this.isValid() : true));
112        }
113});
114
115
116var _NewPWBox = declare("dojox.form._NewPWBox", _ChildTextBox, {
117        // summary:
118        //              A class representing our new password textbox
119
120        // required: boolean
121        //              Whether or not this widget is required (default: true)
122        required: true,
123
124        onChange: function(){
125                // summary:
126                //              Validates our verify box - to make sure that a change to me is
127                //              reflected there
128                this.containerWidget._inputWidgets[2].validate(false);
129                this.inherited(arguments);
130        }
131});
132
133var _VerifyPWBox = declare("dojox.form._VerifyPWBox", _ChildTextBox, {
134        // summary:
135        //              A class representing our verify textbox
136
137        isValid: function(isFocused){
138                // summary:
139                //              Validates that we match the "real" password
140                return this.inherited("isValid", arguments) &&
141                        (this.get("value") == this.containerWidget._inputWidgets[1].get("value"));
142        }
143});
144
145return declare("dojox.form.PasswordValidator", FormValueWidget, {
146        // summary:
147        //              A password validation widget that simplifies the "old/new/verify"
148        //              style of requesting passwords.  You will probably want to override
149        //              this class and implement your own pwCheck function.
150
151        // required: boolean
152        //              Whether or not it is required for form submission
153        required: true,
154
155        // inputWidgets: TextBox[]
156        //              An array of text boxes that are our components
157        _inputWidgets: null,
158
159        // oldName: string?
160        //              The name to send our old password as (when form is posted)
161        oldName: "",
162
163        templateString: template,
164
165        _hasBeenBlurred: false,
166
167        isValid: function(/*Boolean*/ isFocused){
168                // summary:
169                //              we are valid if ALL our children are valid
170                return array.every(this._inputWidgets, function(i){
171                        if(i && i._setStateClass){ i._setStateClass(); }
172                        return (!i || i.isValid());
173                });
174        },
175
176        validate: function(/*Boolean*/ isFocused){
177                // summary:
178                //              Validating this widget validates all our children
179                return array.every(array.map(this._inputWidgets, function(i){
180                        if(i && i.validate){
181                                i._hasBeenBlurred = (i._hasBeenBlurred || this._hasBeenBlurred);
182                                return i.validate();
183                        }
184                        return true;
185                }, this), function(item){ return item; });
186        },
187
188        reset: function(){
189                // summary:
190                //              Resetting this widget resets all our children
191                this._hasBeenBlurred = false;
192                array.forEach(this._inputWidgets, function(i){
193                        if(i && i.reset){ i.reset(); }
194                }, this);
195        },
196
197        _createSubWidgets: function(){
198                // summary:
199                //              Turns the inputs inside this widget into "real" validation
200                //              widgets - and sets up the needed connections.
201                var widgets = this._inputWidgets,
202                        msg = i18n.getLocalization("dojox.form", "PasswordValidator", this.lang);
203                array.forEach(widgets, function(i, idx){
204                        if(i){
205                                var p = {containerWidget: this}, c;
206                                if(idx === 0){
207                                        p.name = this.oldName;
208                                        p.invalidMessage = msg.badPasswordMessage;
209                                        c = _OldPWBox;
210                                }else if(idx === 1){
211                                        p.required = this.required;
212                                        c = _NewPWBox;
213                                }else if(idx === 2){
214                                        p.invalidMessage = msg.nomatchMessage;
215                                        c = _VerifyPWBox;
216                                }
217                                widgets[idx] = new c(p, i);
218                        }
219                }, this);
220        },
221
222        pwCheck: function(/*String*/ password){
223                // summary:
224                //              Overridable function for validation of the old password box.
225                //
226                //              This function is called and passed the old password.  Return
227                //              true if it's OK to continue, and false if it is not.
228                //
229                //              IMPORTANT SECURITY NOTE:  Do NOT EVER EVER EVER check this in
230                //              HTML or JavaScript!!!
231                //
232                //              You will probably want to override this function to callback
233                //              to a server to verify the password (the callback will need to
234                //              be synchronous) - and it's probably a good idea to validate
235                //              it again on form submission before actually doing
236                //              anything destructive - that's why the "oldName" value
237                //              is available.
238                //
239                //              And don't just fetch the password from the server
240                //              either :)  Send the test password (probably hashed, for
241                //              security) and return from the server a status instead.
242                //
243                //              Again - DON'T BE INSECURE!!!  Security is left as an exercise
244                //              for the reader :)
245                return false;
246        },
247
248        postCreate: function(){
249                // summary:
250                //              Sets up the correct widgets.  You *MUST* specify one child
251                //              text box (a simple HTML `<input>` element) with pwType="new"
252                //              *and* one child text box with pwType="verify".  You *MAY*
253                //              specify a third child text box with pwType="old" in order to
254                //              prompt the user to enter in their old password before the
255                //              widget returns that it is valid.
256
257                this.inherited(arguments);
258
259                // Turn my inputs into the correct stuff....
260                var widgets = this._inputWidgets = [];
261                array.forEach(["old","new","verify"], function(i){
262                        widgets.push(query("input[pwType=" + i + "]", this.containerNode)[0]);
263                }, this);
264                if(!widgets[1] || !widgets[2]){
265                        throw new Error("Need at least pwType=\"new\" and pwType=\"verify\"");
266                }
267                if(this.oldName && !widgets[0]){
268                        throw new Error("Need to specify pwType=\"old\" if using oldName");
269                }
270                this.containerNode = this.domNode;
271                this._createSubWidgets();
272                this.connect(this._inputWidgets[1], "_setValueAttr", "_childValueAttr");
273                this.connect(this._inputWidgets[2], "_setValueAttr", "_childValueAttr");
274        },
275
276        _childValueAttr: function(v){
277                this.set("value", this.isValid() ? v : "");
278        },
279
280        _setDisabledAttr: function(value){
281                this.inherited(arguments);
282                array.forEach(this._inputWidgets, function(i){
283                        if(i && i.set){ i.set("disabled", value);}
284                });
285        },
286
287        _setRequiredAttribute: function(value){
288                this.required = value;
289                domAttr.set(this.focusNode, "required", value);
290                this.focusNode.setAttribute("aria-required", value);
291                this._refreshState();
292                array.forEach(this._inputWidgets, function(i){
293                        if(i && i.set){ i.set("required", value);}
294                });
295        },
296
297        _setValueAttr: function(v){
298                this.inherited(arguments);
299                domAttr.set(this.focusNode, "value", v);
300        },
301
302        _getValueAttr: function(){
303                // Make sure we don't return undefined.... maybe should do conversion in _setValueAttr() instead?
304                return this.value||"";
305        },
306
307        focus: function(){
308                // summary:
309                //              places focus on the first invalid input widget - if all
310                //              input widgets are valid, the first widget is focused.
311                var f = false;
312                array.forEach(this._inputWidgets, function(i){
313                        if(i && !i.isValid() && !f){
314                                i.focus();
315                                f = true;
316                        }
317                });
318                if(!f){ this._inputWidgets[1].focus(); }
319        }
320});
321});
Note: See TracBrowser for help on using the repository browser.