From f0cfe83e3725f9a3928da97a6e3085e79cb25309 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Mon, 18 Mar 2013 10:26:24 +0400 Subject: upgrade dojo to 1.8.3 (refs #570) --- lib/dijit/form/_TextBoxMixin.js.uncompressed.js | 474 ++++++++++++++++++++++++ 1 file changed, 474 insertions(+) create mode 100644 lib/dijit/form/_TextBoxMixin.js.uncompressed.js (limited to 'lib/dijit/form/_TextBoxMixin.js.uncompressed.js') diff --git a/lib/dijit/form/_TextBoxMixin.js.uncompressed.js b/lib/dijit/form/_TextBoxMixin.js.uncompressed.js new file mode 100644 index 000000000..7c010bcb3 --- /dev/null +++ b/lib/dijit/form/_TextBoxMixin.js.uncompressed.js @@ -0,0 +1,474 @@ +define("dijit/form/_TextBoxMixin", [ + "dojo/_base/array", // array.forEach + "dojo/_base/declare", // declare + "dojo/dom", // dom.byId + "dojo/_base/event", // event.stop + "dojo/keys", // keys.ALT keys.CAPS_LOCK keys.CTRL keys.META keys.SHIFT + "dojo/_base/lang", // lang.mixin + "dojo/on", // on + "../main" // for exporting dijit._setSelectionRange, dijit.selectInputText +], function(array, declare, dom, event, keys, lang, on, dijit){ + +// module: +// dijit/form/_TextBoxMixin + +var _TextBoxMixin = declare("dijit.form._TextBoxMixin", null, { + // summary: + // A mixin for textbox form input widgets + + // 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: "", + + _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 /* and !undefined */ && ((typeof formattedValue) != "number" || !isNaN(formattedValue)) && this.textbox.value != formattedValue){ + this.textbox.value = formattedValue; + this._set("displayedValue", this.get("displayedValue")); + } + + if(this.textDir == "auto"){ + this.applyTextDir(this.focusNode, formattedValue); + } + + 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: "", + + _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); + }, + + _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 /* or 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')); + + // textDir support + if(this.textDir == "auto"){ + this.applyTextDir(this.focusNode, value); + } + }, + + format: function(value /*=====, constraints =====*/){ + // summary: + // Replaceable function to convert a value to a properly formatted string. + // value: String + // constraints: Object + // tags: + // protected extension + return value == null /* or undefined */ ? "" : (value.toString ? value.toString() : value); + }, + + parse: function(value /*=====, constraints =====*/){ + // summary: + // Replaceable function to convert a formatted string to a value + // value: String + // constraints: Object + // 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(event){ + // summary: + // Connect to this function to receive notifications of various user data-input events. + // Return false to cancel the event and prevent it from being processed. + // event: + // keydown | keypress | cut | paste | input + // tags: + // callback + }, + =====*/ + onInput: function(){}, + + __skipInputEvent: false, + _onInput: function(/*Event*/ evt){ + // summary: + // Called AFTER the input event has happened + + // set text direction according to textDir that was defined in creation + if(this.textDir == "auto"){ + this.applyTextDir(this.focusNode, this.focusNode.value); + } + + this._processInput(evt); + }, + + _processInput: function(/*Event*/ evt){ + // summary: + // Default action handler for user input events + + this._refreshState(); + + // In case someone is watch()'ing for changes to displayedValue + this._set("displayedValue", this.get("displayedValue")); + }, + + postCreate: function(){ + // 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); + + // normalize input events to reduce spurious event processing + // onkeydown: do not forward modifier keys + // set charOrCode to numeric keycode + // onkeypress: do not forward numeric charOrCode keys (already sent through onkeydown) + // onpaste & oncut: set charOrCode to 229 (IME) + // oninput: if primary event not already processed, set charOrCode to 229 (IME), else do not forward + var handleEvent = function(e){ + var charOrCode; + if(e.type == "keydown"){ + charOrCode = e.keyCode; + switch(charOrCode){ // ignore state keys + case keys.SHIFT: + case keys.ALT: + case keys.CTRL: + case keys.META: + case keys.CAPS_LOCK: + case keys.NUM_LOCK: + case keys.SCROLL_LOCK: + return; + } + if(!e.ctrlKey && !e.metaKey && !e.altKey){ // no modifiers + switch(charOrCode){ // ignore location keys + case keys.NUMPAD_0: + case keys.NUMPAD_1: + case keys.NUMPAD_2: + case keys.NUMPAD_3: + case keys.NUMPAD_4: + case keys.NUMPAD_5: + case keys.NUMPAD_6: + case keys.NUMPAD_7: + case keys.NUMPAD_8: + case keys.NUMPAD_9: + case keys.NUMPAD_MULTIPLY: + case keys.NUMPAD_PLUS: + case keys.NUMPAD_ENTER: + case keys.NUMPAD_MINUS: + case keys.NUMPAD_PERIOD: + case keys.NUMPAD_DIVIDE: + return; + } + if((charOrCode >= 65 && charOrCode <= 90) || (charOrCode >= 48 && charOrCode <= 57) || charOrCode == keys.SPACE){ + return; // keypress will handle simple non-modified printable keys + } + var named = false; + for(var i in keys){ + if(keys[i] === e.keyCode){ + named = true; + break; + } + } + if(!named){ return; } // only allow named ones through + } + } + charOrCode = e.charCode >= 32 ? String.fromCharCode(e.charCode) : e.charCode; + if(!charOrCode){ + charOrCode = (e.keyCode >= 65 && e.keyCode <= 90) || (e.keyCode >= 48 && e.keyCode <= 57) || e.keyCode == keys.SPACE ? String.fromCharCode(e.keyCode) : e.keyCode; + } + if(!charOrCode){ + charOrCode = 229; // IME + } + if(e.type == "keypress"){ + if(typeof charOrCode != "string"){ return; } + if((charOrCode >= 'a' && charOrCode <= 'z') || (charOrCode >= 'A' && charOrCode <= 'Z') || (charOrCode >= '0' && charOrCode <= '9') || (charOrCode === ' ')){ + if(e.ctrlKey || e.metaKey || e.altKey){ return; } // can only be stopped reliably in keydown + } + } + if(e.type == "input"){ + if(this.__skipInputEvent){ // duplicate event + this.__skipInputEvent = false; + return; + } + }else{ + this.__skipInputEvent = true; + } + // create fake event to set charOrCode and to know if preventDefault() was called + var faux = { faux: true }, attr; + for(attr in e){ + if(attr != "layerX" && attr != "layerY"){ // prevent WebKit warnings + var v = e[attr]; + if(typeof v != "function" && typeof v != "undefined"){ faux[attr] = v; } + } + } + lang.mixin(faux, { + charOrCode: charOrCode, + _wasConsumed: false, + preventDefault: function(){ + faux._wasConsumed = true; + e.preventDefault(); + }, + stopPropagation: function(){ e.stopPropagation(); } + }); + // give web page author a chance to consume the event + //console.log(faux.type + ', charOrCode = (' + (typeof charOrCode) + ') ' + charOrCode + ', ctrl ' + !!faux.ctrlKey + ', alt ' + !!faux.altKey + ', meta ' + !!faux.metaKey + ', shift ' + !!faux.shiftKey); + if(this.onInput(faux) === false){ // return false means stop + faux.preventDefault(); + faux.stopPropagation(); + } + if(faux._wasConsumed){ return; } // if preventDefault was called + this.defer(function(){ this._onInput(faux); }); // widget notification after key has posted + }; + this.own(on(this.textbox, "keydown, keypress, paste, cut, input, compositionend", lang.hitch(this, handleEvent))); + }, + + _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 = lang.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); + }, + + _isTextSelected: function(){ + return this.textbox.selectionStart != this.textbox.selectionEnd; + }, + + _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); + this._selectOnClickHandle = null; + + // Check if the user selected some text manually (mouse-down, mouse-move, mouse-up) + // and if not, then select all the text + if(!this._isTextSelected()){ + _TextBoxMixin.selectInputText(this.textbox); + } + }); + // in case the mouseup never comes + this.defer(function(){ + if(this._selectOnClickHandle){ + this.disconnect(this._selectOnClickHandle); + this._selectOnClickHandle = null; + } + }, 500); // if mouseup not received soon, then treat it as some gesture + } + // 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); + }, + + _setTextDirAttr: function(/*String*/ textDir){ + // summary: + // Setter for textDir. + // description: + // Users shouldn't call this function; they should be calling + // set('textDir', value) + // tags: + // private + + // only if new textDir is different from the old one + // and on widgets creation. + if(!this._created + || this.textDir != textDir){ + this._set("textDir", textDir); + // so the change of the textDir will take place immediately. + this.applyTextDir(this.focusNode, this.focusNode.value); + } + } +}); + + +_TextBoxMixin._setSelectionRange = dijit._setSelectionRange = function(/*DomNode*/ element, /*Number?*/ start, /*Number?*/ stop){ + if(element.setSelectionRange){ + element.setSelectionRange(start, stop); + } +}; + +_TextBoxMixin.selectInputText = 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? + element = dom.byId(element); + if(isNaN(start)){ start = 0; } + if(isNaN(stop)){ stop = element.value ? element.value.length : 0; } + try{ + element.focus(); + _TextBoxMixin._setSelectionRange(element, start, stop); + }catch(e){ /* squelch random errors (esp. on IE) from unexpected focus changes or DOM nodes being hidden */ } +}; + +return _TextBoxMixin; +}); -- cgit v1.2.3