From 81bea17aefb26859f825b9293c7c99192874806e Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Tue, 8 Nov 2011 20:40:44 +0400 Subject: upgrade Dojo to 1.6.1 --- lib/dijit/form/TextBox.js | 616 +++++++++++++++++++++++++++++++--------------- 1 file changed, 417 insertions(+), 199 deletions(-) (limited to 'lib/dijit/form/TextBox.js') diff --git a/lib/dijit/form/TextBox.js b/lib/dijit/form/TextBox.js index 81c9b2a04..38a9c09d4 100644 --- a/lib/dijit/form/TextBox.js +++ b/lib/dijit/form/TextBox.js @@ -1,209 +1,427 @@ /* - Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. + Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ -if(!dojo._hasResource["dijit.form.TextBox"]){ -dojo._hasResource["dijit.form.TextBox"]=true; +if(!dojo._hasResource["dijit.form.TextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dijit.form.TextBox"] = true; dojo.provide("dijit.form.TextBox"); dojo.require("dijit.form._FormWidget"); -dojo.declare("dijit.form.TextBox",dijit.form._FormValueWidget,{trim:false,uppercase:false,lowercase:false,propercase:false,maxLength:"",selectOnClick:false,placeHolder:"",templateString:dojo.cache("dijit.form","templates/TextBox.html","
\n"),_singleNodeTemplate:"",_buttonInputDisabled:dojo.isIE?"disabled":"",baseClass:"dijitTextBox",attributeMap:dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap,{maxLength:"focusNode"}),postMixInProperties:function(){ -var _1=this.type.toLowerCase(); -if(this.templateString.toLowerCase()=="input"||((_1=="hidden"||_1=="file")&&this.templateString==dijit.form.TextBox.prototype.templateString)){ -this.templateString=this._singleNodeTemplate; -} -this.inherited(arguments); -},_setPlaceHolderAttr:function(v){ -this.placeHolder=v; -if(!this._phspan){ -this._attachPoints.push("_phspan"); -this._phspan=dojo.create("span",{className:"dijitPlaceHolder dijitInputField"},this.textbox,"after"); -} -this._phspan.innerHTML=""; -this._phspan.appendChild(document.createTextNode(v)); -this._updatePlaceHolder(); -},_updatePlaceHolder:function(){ -if(this._phspan){ -this._phspan.style.display=(this.placeHolder&&!this._focused&&!this.textbox.value)?"":"none"; -} -},_getValueAttr:function(){ -return this.parse(this.get("displayedValue"),this.constraints); -},_setValueAttr:function(_2,_3,_4){ -var _5; -if(_2!==undefined){ -_5=this.filter(_2); -if(typeof _4!="string"){ -if(_5!==null&&((typeof _5!="number")||!isNaN(_5))){ -_4=this.filter(this.format(_5,this.constraints)); -}else{ -_4=""; -} -} -} -if(_4!=null&&_4!=undefined&&((typeof _4)!="number"||!isNaN(_4))&&this.textbox.value!=_4){ -this.textbox.value=_4; -} -this._updatePlaceHolder(); -this.inherited(arguments,[_5,_3]); -},displayedValue:"",getDisplayedValue:function(){ -dojo.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.","","2.0"); -return this.get("displayedValue"); -},_getDisplayedValueAttr:function(){ -return this.filter(this.textbox.value); -},setDisplayedValue:function(_6){ -dojo.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.","","2.0"); -this.set("displayedValue",_6); -},_setDisplayedValueAttr:function(_7){ -if(_7===null||_7===undefined){ -_7=""; -}else{ -if(typeof _7!="string"){ -_7=String(_7); -} -} -this.textbox.value=_7; -this._setValueAttr(this.get("value"),undefined,_7); -},format:function(_8,_9){ -return ((_8==null||_8==undefined)?"":(_8.toString?_8.toString():_8)); -},parse:function(_a,_b){ -return _a; -},_refreshState:function(){ -},_onInput:function(e){ -if(e&&e.type&&/key/i.test(e.type)&&e.keyCode){ -switch(e.keyCode){ -case dojo.keys.SHIFT: -case dojo.keys.ALT: -case dojo.keys.CTRL: -case dojo.keys.TAB: -return; -} -} -if(this.intermediateChanges){ -var _c=this; -setTimeout(function(){ -_c._handleOnChange(_c.get("value"),false); -},0); -} -this._refreshState(); -},postCreate:function(){ -if(dojo.isIE){ -var s=dojo.getComputedStyle(this.domNode); -if(s){ -var ff=s.fontFamily; -if(ff){ -var _d=this.domNode.getElementsByTagName("INPUT"); -if(_d){ -for(var i=0;i<_d.length;i++){ -_d[i].style.fontFamily=ff; -} -} -} -} -} -this.textbox.setAttribute("value",this.textbox.value); -this.inherited(arguments); -if(dojo.isMoz||dojo.isOpera){ -this.connect(this.textbox,"oninput",this._onInput); -}else{ -this.connect(this.textbox,"onkeydown",this._onInput); -this.connect(this.textbox,"onkeyup",this._onInput); -this.connect(this.textbox,"onpaste",this._onInput); -this.connect(this.textbox,"oncut",this._onInput); -} -},_blankValue:"",filter:function(_e){ -if(_e===null){ -return this._blankValue; -} -if(typeof _e!="string"){ -return _e; -} -if(this.trim){ -_e=dojo.trim(_e); -} -if(this.uppercase){ -_e=_e.toUpperCase(); -} -if(this.lowercase){ -_e=_e.toLowerCase(); -} -if(this.propercase){ -_e=_e.replace(/[^\s]+/g,function(_f){ -return _f.substring(0,1).toUpperCase()+_f.substring(1); -}); -} -return _e; -},_setBlurValue:function(){ -this._setValueAttr(this.get("value"),true); -},_onBlur:function(e){ -if(this.disabled){ -return; -} -this._setBlurValue(); -this.inherited(arguments); -if(this._selectOnClickHandle){ -this.disconnect(this._selectOnClickHandle); -} -if(this.selectOnClick&&dojo.isMoz){ -this.textbox.selectionStart=this.textbox.selectionEnd=undefined; -} -this._updatePlaceHolder(); -},_onFocus:function(by){ -if(this.disabled||this.readOnly){ -return; -} -if(this.selectOnClick&&by=="mouse"){ -this._selectOnClickHandle=this.connect(this.domNode,"onmouseup",function(){ -this.disconnect(this._selectOnClickHandle); -var _10; -if(dojo.isIE){ -var _11=dojo.doc.selection.createRange(); -var _12=_11.parentElement(); -_10=_12==this.textbox&&_11.text.length==0; -}else{ -_10=this.textbox.selectionStart==this.textbox.selectionEnd; -} -if(_10){ -dijit.selectInputText(this.textbox); -} -}); -} -this._updatePlaceHolder(); -this._refreshState(); -this.inherited(arguments); -},reset:function(){ -this.textbox.value=""; -this.inherited(arguments); -}}); -dijit.selectInputText=function(_13,_14,_15){ -var _16=dojo.global; -var _17=dojo.doc; -_13=dojo.byId(_13); -if(isNaN(_14)){ -_14=0; -} -if(isNaN(_15)){ -_15=_13.value?_13.value.length:0; -} -dijit.focus(_13); -if(_17["selection"]&&dojo.body()["createTextRange"]){ -if(_13.createTextRange){ -var _18=_13.createTextRange(); -with(_18){ -collapse(true); -moveStart("character",-99999); -moveStart("character",_14); -moveEnd("character",_15-_14); -select(); -} -} -}else{ -if(_16["getSelection"]){ -if(_13.setSelectionRange){ -_13.setSelectionRange(_14,_15); -} -} -} + + +dojo.declare( + "dijit.form.TextBox", + dijit.form._FormValueWidget, + { + // summary: + // A base class for textbox form inputs + + // trim: Boolean + // Removes leading and trailing whitespace if true. Default is false. + trim: false, + + // uppercase: Boolean + // Converts all characters to uppercase if true. Default is false. + uppercase: false, + + // lowercase: Boolean + // Converts all characters to lowercase if true. Default is false. + lowercase: false, + + // propercase: Boolean + // Converts the first character of each word to uppercase if true. + propercase: false, + + // maxLength: String + // HTML INPUT tag maxLength declaration. + maxLength: "", + + // selectOnClick: [const] Boolean + // If true, all text will be selected when focused with mouse + selectOnClick: false, + + // placeHolder: String + // Defines a hint to help users fill out the input field (as defined in HTML 5). + // This should only contain plain text (no html markup). + placeHolder: "", + + templateString: dojo.cache("dijit.form", "templates/TextBox.html", "
\n"), + _singleNodeTemplate: '', + + _buttonInputDisabled: dojo.isIE ? "disabled" : "", // allows IE to disallow focus, but Firefox cannot be disabled for mousedown events + + baseClass: "dijitTextBox", + + attributeMap: dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap, { + maxLength: "focusNode" + }), + + postMixInProperties: function(){ + var type = this.type.toLowerCase(); + if(this.templateString && this.templateString.toLowerCase() == "input" || ((type == "hidden" || type == "file") && this.templateString == dijit.form.TextBox.prototype.templateString)){ + this.templateString = this._singleNodeTemplate; + } + this.inherited(arguments); + }, + + _setPlaceHolderAttr: function(v){ + this._set("placeHolder", v); + if(!this._phspan){ + this._attachPoints.push('_phspan'); + /* dijitInputField class gives placeHolder same padding as the input field + * parent node already has dijitInputField class but it doesn't affect this + * since it's position: absolute. + */ + this._phspan = dojo.create('span',{className:'dijitPlaceHolder dijitInputField'},this.textbox,'after'); + } + this._phspan.innerHTML=""; + this._phspan.appendChild(document.createTextNode(v)); + + this._updatePlaceHolder(); + }, + + _updatePlaceHolder: function(){ + if(this._phspan){ + this._phspan.style.display=(this.placeHolder&&!this._focused&&!this.textbox.value)?"":"none"; + } + }, + + _getValueAttr: function(){ + // summary: + // Hook so get('value') works as we like. + // description: + // For `dijit.form.TextBox` this basically returns the value of the . + // + // For `dijit.form.MappedTextBox` subclasses, which have both + // a "displayed value" and a separate "submit value", + // This treats the "displayed value" as the master value, computing the + // submit value from it via this.parse(). + return this.parse(this.get('displayedValue'), this.constraints); + }, + + _setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){ + // summary: + // Hook so set('value', ...) works. + // + // description: + // Sets the value of the widget to "value" which can be of + // any type as determined by the widget. + // + // value: + // The visual element value is also set to a corresponding, + // but not necessarily the same, value. + // + // formattedValue: + // If specified, used to set the visual element value, + // otherwise a computed visual value is used. + // + // priorityChange: + // If true, an onChange event is fired immediately instead of + // waiting for the next blur event. + + var filteredValue; + if(value !== undefined){ + // TODO: this is calling filter() on both the display value and the actual value. + // I added a comment to the filter() definition about this, but it should be changed. + filteredValue = this.filter(value); + if(typeof formattedValue != "string"){ + if(filteredValue !== null && ((typeof filteredValue != "number") || !isNaN(filteredValue))){ + formattedValue = this.filter(this.format(filteredValue, this.constraints)); + }else{ formattedValue = ''; } + } + } + if(formattedValue != null && formattedValue != undefined && ((typeof formattedValue) != "number" || !isNaN(formattedValue)) && this.textbox.value != formattedValue){ + this.textbox.value = formattedValue; + this._set("displayedValue", this.get("displayedValue")); + } + + this._updatePlaceHolder(); + + this.inherited(arguments, [filteredValue, priorityChange]); + }, + + // displayedValue: String + // For subclasses like ComboBox where the displayed value + // (ex: Kentucky) and the serialized value (ex: KY) are different, + // this represents the displayed value. + // + // Setting 'displayedValue' through set('displayedValue', ...) + // updates 'value', and vice-versa. Otherwise 'value' is updated + // from 'displayedValue' periodically, like onBlur etc. + // + // TODO: move declaration to MappedTextBox? + // Problem is that ComboBox references displayedValue, + // for benefit of FilteringSelect. + displayedValue: "", + + getDisplayedValue: function(){ + // summary: + // Deprecated. Use get('displayedValue') instead. + // tags: + // deprecated + dojo.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.", "", "2.0"); + return this.get('displayedValue'); + }, + + _getDisplayedValueAttr: function(){ + // summary: + // Hook so get('displayedValue') works. + // description: + // Returns the displayed value (what the user sees on the screen), + // after filtering (ie, trimming spaces etc.). + // + // For some subclasses of TextBox (like ComboBox), the displayed value + // is different from the serialized value that's actually + // sent to the server (see dijit.form.ValidationTextBox.serialize) + + // TODO: maybe we should update this.displayedValue on every keystroke so that we don't need + // this method + // TODO: this isn't really the displayed value when the user is typing + return this.filter(this.textbox.value); + }, + + setDisplayedValue: function(/*String*/ value){ + // summary: + // Deprecated. Use set('displayedValue', ...) instead. + // tags: + // deprecated + dojo.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.", "", "2.0"); + this.set('displayedValue', value); + }, + + _setDisplayedValueAttr: function(/*String*/ value){ + // summary: + // Hook so set('displayedValue', ...) works. + // description: + // Sets the value of the visual element to the string "value". + // The widget value is also set to a corresponding, + // but not necessarily the same, value. + + if(value === null || value === undefined){ value = '' } + else if(typeof value != "string"){ value = String(value) } + + this.textbox.value = value; + + // sets the serialized value to something corresponding to specified displayedValue + // (if possible), and also updates the textbox.value, for example converting "123" + // to "123.00" + this._setValueAttr(this.get('value'), undefined); + + this._set("displayedValue", this.get('displayedValue')); + }, + + format: function(/*String*/ value, /*Object*/ constraints){ + // summary: + // Replacable function to convert a value to a properly formatted string. + // tags: + // protected extension + return ((value == null || value == undefined) ? "" : (value.toString ? value.toString() : value)); + }, + + parse: function(/*String*/ value, /*Object*/ constraints){ + // summary: + // Replacable function to convert a formatted string to a value + // tags: + // protected extension + + return value; // String + }, + + _refreshState: function(){ + // summary: + // After the user types some characters, etc., this method is + // called to check the field for validity etc. The base method + // in `dijit.form.TextBox` does nothing, but subclasses override. + // tags: + // protected + }, + + _onInput: function(e){ + if(e && e.type && /key/i.test(e.type) && e.keyCode){ + switch(e.keyCode){ + case dojo.keys.SHIFT: + case dojo.keys.ALT: + case dojo.keys.CTRL: + case dojo.keys.TAB: + return; + } + } + if(this.intermediateChanges){ + var _this = this; + // the setTimeout allows the key to post to the widget input box + setTimeout(function(){ _this._handleOnChange(_this.get('value'), false); }, 0); + } + this._refreshState(); + + // In case someone is watch()'ing for changes to displayedValue + this._set("displayedValue", this.get("displayedValue")); + }, + + postCreate: function(){ + if(dojo.isIE){ // IE INPUT tag fontFamily has to be set directly using STYLE + // the setTimeout gives IE a chance to render the TextBox and to deal with font inheritance + setTimeout(dojo.hitch(this, function(){ + var s = dojo.getComputedStyle(this.domNode); + if(s){ + var ff = s.fontFamily; + if(ff){ + var inputs = this.domNode.getElementsByTagName("INPUT"); + if(inputs){ + for(var i=0; i < inputs.length; i++){ + inputs[i].style.fontFamily = ff; + } + } + } + } + }), 0); + } + + // setting the value here is needed since value="" in the template causes "undefined" + // and setting in the DOM (instead of the JS object) helps with form reset actions + this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values should be the same + + this.inherited(arguments); + + if(dojo.isMoz || dojo.isOpera){ + this.connect(this.textbox, "oninput", "_onInput"); + }else{ + this.connect(this.textbox, "onkeydown", "_onInput"); + this.connect(this.textbox, "onkeyup", "_onInput"); + this.connect(this.textbox, "onpaste", "_onInput"); + this.connect(this.textbox, "oncut", "_onInput"); + } + }, + + _blankValue: '', // if the textbox is blank, what value should be reported + filter: function(val){ + // summary: + // Auto-corrections (such as trimming) that are applied to textbox + // value on blur or form submit. + // description: + // For MappedTextBox subclasses, this is called twice + // - once with the display value + // - once the value as set/returned by set('value', ...) + // and get('value'), ex: a Number for NumberTextBox. + // + // In the latter case it does corrections like converting null to NaN. In + // the former case the NumberTextBox.filter() method calls this.inherited() + // to execute standard trimming code in TextBox.filter(). + // + // TODO: break this into two methods in 2.0 + // + // tags: + // protected extension + if(val === null){ return this._blankValue; } + if(typeof val != "string"){ return val; } + if(this.trim){ + val = dojo.trim(val); + } + if(this.uppercase){ + val = val.toUpperCase(); + } + if(this.lowercase){ + val = val.toLowerCase(); + } + if(this.propercase){ + val = val.replace(/[^\s]+/g, function(word){ + return word.substring(0,1).toUpperCase() + word.substring(1); + }); + } + return val; + }, + + _setBlurValue: function(){ + this._setValueAttr(this.get('value'), true); + }, + + _onBlur: function(e){ + if(this.disabled){ return; } + this._setBlurValue(); + this.inherited(arguments); + + if(this._selectOnClickHandle){ + this.disconnect(this._selectOnClickHandle); + } + if(this.selectOnClick && dojo.isMoz){ + this.textbox.selectionStart = this.textbox.selectionEnd = undefined; // clear selection so that the next mouse click doesn't reselect + } + + this._updatePlaceHolder(); + }, + + _onFocus: function(/*String*/ by){ + if(this.disabled || this.readOnly){ return; } + + // Select all text on focus via click if nothing already selected. + // Since mouse-up will clear the selection need to defer selection until after mouse-up. + // Don't do anything on focus by tabbing into the widget since there's no associated mouse-up event. + if(this.selectOnClick && by == "mouse"){ + this._selectOnClickHandle = this.connect(this.domNode, "onmouseup", function(){ + // Only select all text on first click; otherwise users would have no way to clear + // the selection. + this.disconnect(this._selectOnClickHandle); + + // Check if the user selected some text manually (mouse-down, mouse-move, mouse-up) + // and if not, then select all the text + var textIsNotSelected; + if(dojo.isIE){ + var range = dojo.doc.selection.createRange(); + var parent = range.parentElement(); + textIsNotSelected = parent == this.textbox && range.text.length == 0; + }else{ + textIsNotSelected = this.textbox.selectionStart == this.textbox.selectionEnd; + } + if(textIsNotSelected){ + dijit.selectInputText(this.textbox); + } + }); + } + + this._updatePlaceHolder(); + + // call this.inherited() before refreshState(), since this.inherited() will possibly scroll the viewport + // (to scroll the TextBox into view), which will affect how _refreshState() positions the tooltip + this.inherited(arguments); + + this._refreshState(); + }, + + reset: function(){ + // Overrides dijit._FormWidget.reset(). + // Additionally resets the displayed textbox value to '' + this.textbox.value = ''; + this.inherited(arguments); + } + } +); + +dijit.selectInputText = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){ + // summary: + // Select text in the input element argument, from start (default 0), to stop (default end). + + // TODO: use functions in _editor/selection.js? + var _window = dojo.global; + var _document = dojo.doc; + element = dojo.byId(element); + if(isNaN(start)){ start = 0; } + if(isNaN(stop)){ stop = element.value ? element.value.length : 0; } + dijit.focus(element); + if(_document["selection"] && dojo.body()["createTextRange"]){ // IE + if(element.createTextRange){ + var r = element.createTextRange(); + r.collapse(true); + r.moveStart("character", -99999); // move to 0 + r.moveStart("character", start); // delta from 0 is the correct position + r.moveEnd("character", stop-start); + r.select(); + } + }else if(_window["getSelection"]){ + if(element.setSelectionRange){ + element.setSelectionRange(start, stop); + } + } }; + } -- cgit v1.2.3