diff options
Diffstat (limited to 'js/dojo/dojox/mobile/ComboBox.js')
| -rw-r--r-- | js/dojo/dojox/mobile/ComboBox.js | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/js/dojo/dojox/mobile/ComboBox.js b/js/dojo/dojox/mobile/ComboBox.js new file mode 100644 index 0000000..bdfad2c --- /dev/null +++ b/js/dojo/dojox/mobile/ComboBox.js @@ -0,0 +1,225 @@ +//>>built +define("dojox/mobile/ComboBox", [ + "dojo/_base/kernel", + "dojo/_base/declare", + "dojo/_base/lang", + "dojo/_base/window", + "dojo/dom-geometry", + "dojo/dom-style", + "dojo/window", + "dijit/form/_AutoCompleterMixin", + "dijit/popup", + "./_ComboBoxMenu", + "./TextBox", + "./sniff" +], function(kernel, declare, lang, win, domGeometry, domStyle, windowUtils, AutoCompleterMixin, popup, ComboBoxMenu, TextBox, has){ + kernel.experimental("dojox.mobile.ComboBox"); // should be using a more native search-type UI + + /*===== + TextBox = dojox.mobile.TextBox; + AutoCompleterMixin = dijit.form._AutoCompleterMixin; + =====*/ + return declare("dojox.mobile.ComboBox", [TextBox, AutoCompleterMixin], { + // summary: + // A non-templated auto-completing text box widget + // + + // dropDownClass: [protected extension] String + // Name of the dropdown widget class used to select a date/time. + // Subclasses should specify this. + dropDownClass: "dojox.mobile._ComboBoxMenu", + + // initially disable selection since iphone displays selection handles that makes it hard to pick from the list + selectOnClick: false, + autoComplete: false, + + // dropDown: [protected] Widget + // The widget to display as a popup. This widget *must* be + // defined before the startup function is called. + dropDown: null, + + // maxHeight: [protected] Integer + // The max height for our dropdown. + // Any dropdown taller than this will have scrollbars. + // Set to -1 to limit height to available space in viewport + maxHeight: -1, + + // dropDownPosition: [const] String[] + // This variable controls the position of the drop down. + // It's an array of strings with the following values: + // + // * before: places drop down to the left of the target node/widget, or to the right in + // the case of RTL scripts like Hebrew and Arabic + // * after: places drop down to the right of the target node/widget, or to the left in + // the case of RTL scripts like Hebrew and Arabic + // * above: drop down goes above target node + // * below: drop down goes below target node + // + // The list is positions is tried, in order, until a position is found where the drop down fits + // within the viewport. + // + dropDownPosition: ["below","above"], + + _throttleOpenClose: function(){ + // prevent open/close in rapid succession + if(this._throttleHandler){ + clearTimeout(this._throttleHandler); + } + this._throttleHandler = setTimeout(lang.hitch(this, function(){ this._throttleHandler = null; }), 500); + }, + + _onFocus: function(){ + this.inherited(arguments); + if(!this._opened && !this._throttleHandler){ + this._startSearchAll(); // show dropdown if user is selecting Next/Previous from virtual keyboard + } + }, + + onInput: function(e){ + this._onKey(e); + this.inherited(arguments); + }, + + _setListAttr: function(v){ + this._set('list', v); // needed for Firefox 4+ to prevent HTML5 mode + }, + + closeDropDown: function(){ + // summary: + // Closes the drop down on this widget + // tags: + // protected + + this._throttleOpenClose(); + if(this.startHandler){ + this.disconnect(this.startHandler); + this.startHandler = null; + if(this.moveHandler){ this.disconnect(this.moveHandler); } + if(this.endHandler){ this.disconnect(this.endHandler); } + } + this.inherited(arguments); + popup.close(this.dropDown); + this._opened = false; + }, + + openDropDown: function(){ + // summary: + // Opens the dropdown for this widget. To be called only when this.dropDown + // has been created and is ready to display (ie, it's data is loaded). + // returns: + // return value of popup.open() + // tags: + // protected + + var wasClosed = !this._opened; + var dropDown = this.dropDown, + ddNode = dropDown.domNode, + aroundNode = this.domNode, + self = this; + + + // TODO: isn't maxHeight dependent on the return value from popup.open(), + // ie, dependent on how much space is available (BK) + + if(!this._preparedNode){ + this._preparedNode = true; + // Check if we have explicitly set width and height on the dropdown widget dom node + if(ddNode.style.width){ + this._explicitDDWidth = true; + } + if(ddNode.style.height){ + this._explicitDDHeight = true; + } + } + + // Code for resizing dropdown (height limitation, or increasing width to match my width) + var myStyle = { + display: "", + overflow: "hidden", + visibility: "hidden" + }; + if(!this._explicitDDWidth){ + myStyle.width = ""; + } + if(!this._explicitDDHeight){ + myStyle.height = ""; + } + domStyle.set(ddNode, myStyle); + + // Figure out maximum height allowed (if there is a height restriction) + var maxHeight = this.maxHeight; + if(maxHeight == -1){ + // limit height to space available in viewport either above or below my domNode + // (whichever side has more room) + var viewport = windowUtils.getBox(), + position = domGeometry.position(aroundNode, false); + maxHeight = Math.floor(Math.max(position.y, viewport.h - (position.y + position.h))); + } + + // Attach dropDown to DOM and make make visibility:hidden rather than display:none + // so we call startup() and also get the size + popup.moveOffScreen(dropDown); + + if(dropDown.startup && !dropDown._started){ + dropDown.startup(); // this has to be done after being added to the DOM + } + // Get size of drop down, and determine if vertical scroll bar needed + var mb = domGeometry.position(this.dropDown.containerNode, false); + var overHeight = (maxHeight && mb.h > maxHeight); + if(overHeight){ + mb.h = maxHeight; + } + + // Adjust dropdown width to match or be larger than my width + mb.w = Math.max(mb.w, aroundNode.offsetWidth); + domGeometry.setMarginBox(ddNode, mb); + + var retVal = popup.open({ + parent: this, + popup: dropDown, + around: aroundNode, + orient: this.dropDownPosition, + onExecute: function(){ + self.closeDropDown(); + }, + onCancel: function(){ + self.closeDropDown(); + }, + onClose: function(){ + self._opened = false; + } + }); + this._opened=true; + + if(wasClosed){ + if(retVal.aroundCorner.charAt(0) == 'B'){ // is popup below? + this.domNode.scrollIntoView(true); // scroll to top + } + this.startHandler = this.connect(win.doc.documentElement, has("touch") ? "ontouchstart" : "onmousedown", + lang.hitch(this, function(){ + var isMove = false; + this.moveHandler = this.connect(win.doc.documentElement, has("touch") ? "ontouchmove" : "onmousemove", function(){ isMove = true; }); + this.endHandler = this.connect(win.doc.documentElement, has("touch") ? "ontouchend" : "onmouseup", function(){ if(!isMove){ this.closeDropDown(); } }); + }) + ); + } + return retVal; + }, + + postCreate: function(){ + this.inherited(arguments); + this.connect(this.domNode, "onclick", "_onClick"); + }, + + _onClick: function(/*Event*/ e){ + // throttle clicks to prevent double click from doing double actions + if(!this._throttleHandler){ + if(this.opened){ + this.closeDropDown(); + }else{ + this._startSearchAll(); + } + } + } + }); +}); |
