]>
git.wh0rd.org - tt-rss.git/blob - lib/dijit/form/ValidationTextBox.js
2 Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
3 Available via Academic Free License >= 2.1 OR the modified BSD license.
4 see: http://dojotoolkit.org/license for details
8 if (! dojo
. _hasResource
[ "dijit.form.ValidationTextBox" ]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
9 dojo
. _hasResource
[ "dijit.form.ValidationTextBox" ] = true ;
10 dojo
. provide ( "dijit.form.ValidationTextBox" );
11 dojo
. require ( "dojo.i18n" );
12 dojo
. require ( "dijit.form.TextBox" );
13 dojo
. require ( "dijit.Tooltip" );
14 dojo
. requireLocalization ( "dijit.form" , "validate" , null , "ROOT,ar,ca,cs,da,de,el,es,fi,fr,he,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw" );
18 dijit.form.ValidationTextBox.__Constraints = function(){
20 // locale used for validation, picks up value from this widget's lang attribute
22 // various flags passed to regExpGen function
29 "dijit.form.ValidationTextBox" ,
33 // Base class for textbox widgets with the ability to validate content of various types and provide user feedback.
37 templateString
: dojo
. cache ( "dijit.form" , "templates/ValidationTextBox.html" , "<div class= \" dijit dijitReset dijitInlineTable dijitLeft \"\n\t id= \" widget_ ${id} \" role= \" presentation \"\n\t ><div class='dijitReset dijitValidationContainer' \n\t\t ><input class= \" dijitReset dijitInputField dijitValidationIcon dijitValidationInner \" value= \" Χ \" type= \" text \" tabIndex= \" -1 \" readonly= \" readonly \" role= \" presentation \"\n\t /></div \n\t ><div class= \" dijitReset dijitInputField dijitInputContainer \"\n\t\t ><input class= \" dijitReset dijitInputInner \" dojoAttachPoint='textbox,focusNode' autocomplete= \" off \"\n\t\t\t ${!nameAttrSetting} type=' ${type} ' \n\t /></div \n ></div> \n " ),
38 baseClass
: "dijitTextBox dijitValidationTextBox" ,
41 // User is required to enter data into this field.
44 // promptMessage: String
45 // If defined, display this hint string immediately on focus to the textbox, if empty.
46 // Also displays if the textbox value is Incomplete (not yet valid but will be with additional input).
47 // Think of this like a tooltip that tells the user what to do, not an error message
48 // that tells the user what they've done wrong.
50 // Message disappears when user starts typing.
53 // invalidMessage: String
54 // The message to display if value is invalid.
55 // The translated string value is read from the message file by default.
56 // Set to "" to use the promptMessage instead.
57 invalidMessage
: "$_unset_$" ,
59 // missingMessage: String
60 // The message to display if value is empty and the field is required.
61 // The translated string value is read from the message file by default.
62 // Set to "" to use the invalidMessage instead.
63 missingMessage
: "$_unset_$" ,
66 // Currently error/prompt message.
67 // When using the default tooltip implementation, this will only be
68 // displayed when the field is focused.
71 // constraints: dijit.form.ValidationTextBox.__Constraints
72 // user-defined object needed to pass parameters to the validator functions
75 // regExp: [extension protected] String
76 // regular expression string used to validate the input
77 // Do not specify both regExp and regExpGen
80 regExpGen : function ( /*dijit.form.ValidationTextBox.__Constraints*/ constraints
){
82 // Overridable function used to generate regExp when dependent on constraints.
83 // Do not specify both regExp and regExpGen.
85 // extension protected
86 return this . regExp
; // String
89 // state: [readonly] String
90 // Shows current state (ie, validation result) of input (""=Normal, Incomplete, or Error)
93 // tooltipPosition: String[]
94 // See description of `dijit.Tooltip.defaultPosition` for details on this parameter.
97 _setValueAttr : function (){
99 // Hook so set('value', ...) works.
100 this . inherited ( arguments
);
101 this . validate ( this . _focused
);
104 validator : function ( /*anything*/ value
, /*dijit.form.ValidationTextBox.__Constraints*/ constraints
){
106 // Overridable function used to validate the text input against the regular expression.
109 return ( new RegExp ( "^(?:" + this . regExpGen ( constraints
) + ")" +( this . required
? "" : "?" )+ "$" )). test ( value
) &&
110 (! this . required
|| ! this . _isEmpty ( value
)) &&
111 ( this . _isEmpty ( value
) || this . parse ( value
, constraints
) !== undefined ); // Boolean
114 _isValidSubset : function (){
116 // Returns true if the value is either already valid or could be made valid by appending characters.
117 // This is used for validation while the user [may be] still typing.
118 return this . textbox
. value
. search ( this . _partialre
) == 0 ;
121 isValid : function ( /*Boolean*/ isFocused
){
123 // Tests if value is valid.
124 // Can override with your own routine in a subclass.
127 return this . validator ( this . textbox
. value
, this . constraints
);
130 _isEmpty : function ( value
){
132 // Checks for whitespace
133 return ( this . trim
? /^\s*$/ : /^$/ ). test ( value
); // Boolean
136 getErrorMessage : function ( /*Boolean*/ isFocused
){
138 // Return an error message to show if appropriate
141 return ( this . required
&& this . _isEmpty ( this . textbox
. value
)) ? this . missingMessage
: this . invalidMessage
; // String
144 getPromptMessage : function ( /*Boolean*/ isFocused
){
146 // Return a hint message to show when widget is first focused
149 return this . promptMessage
; // String
152 _maskValidSubsetError
: true ,
153 validate : function ( /*Boolean*/ isFocused
){
155 // Called by oninit, onblur, and onkeypress.
157 // Show missing or invalid messages if appropriate, and highlight textbox field.
161 var isValid
= this . disabled
|| this . isValid ( isFocused
);
162 if ( isValid
){ this . _maskValidSubsetError
= true ; }
163 var isEmpty
= this . _isEmpty ( this . textbox
. value
);
164 var isValidSubset
= ! isValid
&& isFocused
&& this . _isValidSubset ();
165 this . _set ( "state" , isValid
? "" : (((((! this . _hasBeenBlurred
|| isFocused
) && isEmpty
) || isValidSubset
) && this . _maskValidSubsetError
) ? "Incomplete" : "Error" ));
166 dijit
. setWaiState ( this . focusNode
, "invalid" , isValid
? "false" : "true" );
168 if ( this . state
== "Error" ){
169 this . _maskValidSubsetError
= isFocused
&& isValidSubset
; // we want the error to show up after a blur and refocus
170 message
= this . getErrorMessage ( isFocused
);
171 } else if ( this . state
== "Incomplete" ){
172 message
= this . getPromptMessage ( isFocused
); // show the prompt whenever the value is not yet complete
173 this . _maskValidSubsetError
= ! this . _hasBeenBlurred
|| isFocused
; // no Incomplete warnings while focused
175 message
= this . getPromptMessage ( isFocused
); // show the prompt whenever there's no error and no text
177 this . set ( "message" , message
);
182 displayMessage : function ( /*String*/ message
){
184 // Overridable method to display validation errors/hints.
185 // By default uses a tooltip.
188 dijit
. hideTooltip ( this . domNode
);
189 if ( message
&& this . _focused
){
190 dijit
. showTooltip ( message
, this . domNode
, this . tooltipPosition
, ! this . isLeftToRight ());
194 _refreshState : function (){
195 // Overrides TextBox._refreshState()
196 this . validate ( this . _focused
);
197 this . inherited ( arguments
);
200 //////////// INITIALIZATION METHODS ///////////////////////////////////////
202 constructor : function (){
203 this . constraints
= {};
206 _setConstraintsAttr : function ( /*Object*/ constraints
){
207 if (! constraints
. locale
&& this . lang
){
208 constraints
. locale
= this . lang
;
210 this . _set ( "constraints" , constraints
);
211 this . _computePartialRE ();
214 _computePartialRE : function (){
215 var p
= this . regExpGen ( this . constraints
);
218 // parse the regexp and produce a new regexp that matches valid subsets
219 // if the regexp is .* then there's no use in matching subsets since everything is valid
220 if ( p
!= ".*" ){ this . regExp
. replace ( /\\.|\[\]|\[.*?[^\\]{1}\]|\{.*?\}|\(\?[=:!]|./g ,
222 switch ( re
. charAt ( 0 )){
237 partialre
+= "(?:" + re
+ "|$)" ;
242 try { // this is needed for now since the above regexp parsing needs more test verification
243 "" . search ( partialre
);
244 } catch ( e
){ // should never be here unless the original RE is bad or the parsing is bad
245 partialre
= this . regExp
;
246 console
. warn ( 'RegExp error in ' + this . declaredClass
+ ': ' + this . regExp
);
247 } // should never be here unless the original RE is bad or the parsing is bad
248 this . _partialre
= "^(?:" + partialre
+ ")$" ;
251 postMixInProperties : function (){
252 this . inherited ( arguments
);
253 this . messages
= dojo
. i18n
. getLocalization ( "dijit.form" , "validate" , this . lang
);
254 if ( this . invalidMessage
== "$_unset_$" ){ this . invalidMessage
= this . messages
. invalidMessage
; }
255 if (! this . invalidMessage
){ this . invalidMessage
= this . promptMessage
; }
256 if ( this . missingMessage
== "$_unset_$" ){ this . missingMessage
= this . messages
. missingMessage
; }
257 if (! this . missingMessage
){ this . missingMessage
= this . invalidMessage
; }
258 this . _setConstraintsAttr ( this . constraints
); // this needs to happen now (and later) due to codependency on _set*Attr calls attachPoints
261 _setDisabledAttr : function ( /*Boolean*/ value
){
262 this . inherited ( arguments
); // call FormValueWidget._setDisabledAttr()
263 this . _refreshState ();
266 _setRequiredAttr : function ( /*Boolean*/ value
){
267 this . _set ( "required" , value
);
268 dijit
. setWaiState ( this . focusNode
, "required" , value
);
269 this . _refreshState ();
272 _setMessageAttr : function ( /*String*/ message
){
273 this . _set ( "message" , message
);
274 this . displayMessage ( message
);
278 // Overrides dijit.form.TextBox.reset() by also
279 // hiding errors about partial matches
280 this . _maskValidSubsetError
= true ;
281 this . inherited ( arguments
);
285 // the message still exists but for back-compat, and to erase the tooltip
286 // (if the message is being displayed as a tooltip), call displayMessage('')
287 this . displayMessage ( '' );
289 this . inherited ( arguments
);
295 "dijit.form.MappedTextBox" ,
296 dijit
. form
. ValidationTextBox
,
299 // A dijit.form.ValidationTextBox subclass which provides a base class for widgets that have
300 // a visible formatted display value, and a serializable
301 // value in a hidden input field which is actually sent to the server.
303 // The visible display may
304 // be locale-dependent and interactive. The value sent to the server is stored in a hidden
305 // input field which uses the `name` attribute declared by the original widget. That value sent
306 // to the server is defined by the dijit.form.MappedTextBox.serialize method and is typically
311 postMixInProperties : function (){
312 this . inherited ( arguments
);
314 // we want the name attribute to go to the hidden <input>, not the displayed <input>,
315 // so override _FormWidget.postMixInProperties() setting of nameAttrSetting
316 this . nameAttrSetting
= "" ;
319 serialize : function ( /*anything*/ val
, /*Object?*/ options
){
321 // Overridable function used to convert the get('value') result to a canonical
322 // (non-localized) string. For example, will print dates in ISO format, and
323 // numbers the same way as they are represented in javascript.
325 // protected extension
326 return val
. toString
? val
. toString () : "" ; // String
329 toString : function (){
331 // Returns widget as a printable string using the widget's value
334 var val
= this . filter ( this . get ( 'value' )); // call filter in case value is nonstring and filter has been customized
335 return val
!= null ? ( typeof val
== "string" ? val
: this . serialize ( val
, this . constraints
)) : "" ; // String
338 validate : function (){
339 // Overrides `dijit.form.TextBox.validate`
340 this . valueNode
. value
= this . toString ();
341 return this . inherited ( arguments
);
344 buildRendering : function (){
345 // Overrides `dijit._Templated.buildRendering`
347 this . inherited ( arguments
);
349 // Create a hidden <input> node with the serialized value used for submit
350 // (as opposed to the displayed value).
351 // Passing in name as markup rather than calling dojo.create() with an attrs argument
352 // to make dojo.query(input[name=...]) work on IE. (see #8660)
353 this . valueNode
= dojo
. place ( "<input type='hidden'" + ( this . name
? " name='" + this . name
. replace ( /'/g, """) + "'" : "") + "/ > ", this.textbox, " after
");
357 // Overrides `dijit.form.ValidationTextBox.reset` to
358 // reset the hidden textbox value to ''
359 this.valueNode.value = '';
360 this.inherited(arguments);
366 dijit.form.RangeBoundTextBox.__Constraints = function(){
368 // Minimum signed value. Default is -Infinity
370 // Maximum signed value. Default is +Infinity
377 " dijit
. form
. RangeBoundTextBox
",
378 dijit.form.MappedTextBox,
381 // Base class for textbox form widgets which defines a range of valid values.
383 // rangeMessage: String
384 // The message to display if value is out-of-range
388 // constraints: dijit.form.RangeBoundTextBox.__Constraints
392 rangeCheck: function(/*Number*/ primitive, /*dijit.form.RangeBoundTextBox.__Constraints*/ constraints){
394 // Overridable function used to validate the range of the numeric input value.
397 return (" min
" in constraints? (this.compare(primitive,constraints.min) >= 0) : true) &&
398 (" max
" in constraints? (this.compare(primitive,constraints.max) <= 0) : true); // Boolean
401 isInRange: function(/*Boolean*/ isFocused){
403 // Tests if the value is in the min/max range specified in constraints
406 return this.rangeCheck(this.get('value'), this.constraints);
409 _isDefinitelyOutOfRange: function(){
411 // Returns true if the value is out of range and will remain
412 // out of range even if the user types more characters
413 var val = this.get('value');
414 var isTooLittle = false;
415 var isTooMuch = false;
416 if(" min
" in this.constraints){
417 var min = this.constraints.min;
418 min = this.compare(val, ((typeof min == " number
") && min >= 0 && val !=0) ? 0 : min);
419 isTooLittle = (typeof min == " number
") && min < 0;
421 if(" max
" in this.constraints){
422 var max = this.constraints.max;
423 max = this.compare(val, ((typeof max != " number
") || max > 0) ? max : 0);
424 isTooMuch = (typeof max == " number
") && max > 0;
426 return isTooLittle || isTooMuch;
429 _isValidSubset: function(){
431 // Overrides `dijit.form.ValidationTextBox._isValidSubset`.
432 // Returns true if the input is syntactically valid, and either within
433 // range or could be made in range by more typing.
434 return this.inherited(arguments) && !this._isDefinitelyOutOfRange();
437 isValid: function(/*Boolean*/ isFocused){
438 // Overrides dijit.form.ValidationTextBox.isValid to check that the value is also in range.
439 return this.inherited(arguments) &&
440 ((this._isEmpty(this.textbox.value) && !this.required) || this.isInRange(isFocused)); // Boolean
443 getErrorMessage: function(/*Boolean*/ isFocused){
444 // Overrides dijit.form.ValidationTextBox.getErrorMessage to print " out
of range
" message if appropriate
445 var v = this.get('value');
446 if(v !== null && v !== '' && v !== undefined && (typeof v != " number
" || !isNaN(v)) && !this.isInRange(isFocused)){ // don't check isInRange w/o a real value
447 return this.rangeMessage; // String
449 return this.inherited(arguments);
452 postMixInProperties: function(){
453 this.inherited(arguments);
454 if(!this.rangeMessage){
455 this.messages = dojo.i18n.getLocalization(" dijit
. form
", " validate
", this.lang);
456 this.rangeMessage = this.messages.rangeMessage;
460 _setConstraintsAttr: function(/*Object*/ constraints){
461 this.inherited(arguments);
462 if(this.focusNode){ // not set when called from postMixInProperties
463 if(this.constraints.min !== undefined){
464 dijit.setWaiState(this.focusNode, " valuemin
", this.constraints.min);
466 dijit.removeWaiState(this.focusNode, " valuemin
");
468 if(this.constraints.max !== undefined){
469 dijit.setWaiState(this.focusNode, " valuemax
", this.constraints.max);
471 dijit.removeWaiState(this.focusNode, " valuemax
");
476 _setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
478 // Hook so set('value', ...) works.
480 dijit.setWaiState(this.focusNode, " valuenow
", value);
481 this.inherited(arguments);