polardbxengine/storage/ndb/mcc/frontend/dojo/dojox/mobile/ComboBox.js.uncompressed.js

303 lines
9.3 KiB
JavaScript

define("dojox/mobile/ComboBox", [
"dojo/_base/kernel",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/_base/window",
"dojo/dom-geometry",
"dojo/dom-style",
"dojo/window",
"dojo/touch",
"dijit/form/_AutoCompleterMixin",
"dijit/popup",
"./_ComboBoxMenu",
"./TextBox",
"./sniff"
], function(kernel, declare, lang, win, domGeometry, domStyle, windowUtils, touch, AutoCompleterMixin, popup, ComboBoxMenu, TextBox, has){
kernel.experimental("dojox.mobile.ComboBox"); // should be using a more native search-type UI
return declare("dojox.mobile.ComboBox", [TextBox, AutoCompleterMixin], {
// summary:
// A non-templated auto-completing text box widget.
// dropDownClass: [protected extension] String
// Name of the drop-down widget class used to select a date/time.
// Should be specified by subclasses.
dropDownClass: "dojox.mobile._ComboBoxMenu",
// initially disable selection since iphone displays selection handles
// that makes it hard to pick from the list
// selectOnClick: Boolean
// Flag which enables the selection on click.
selectOnClick: false,
// autoComplete: Boolean
// Flag which enables the auto-completion.
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] int
// The maximum height for the drop-down.
// Any drop-down taller than this value will have scrollbars.
// Set to -1 to limit the height to the available space in the viewport.
maxHeight: -1,
// dropDownPosition: [const] String[]
// This variable controls the position of the drop-down.
// It is 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(){
// summary:
// Prevents the open/close in rapid succession.
// tags:
// private
if(this._throttleHandler){
this._throttleHandler.remove();
}
this._throttleHandler = this.defer(function(){ this._throttleHandler = null; }, 500);
},
_onFocus: function(){
// summary:
// Shows drop-down if the user is selecting Next/Previous from the virtual keyboard.
// tags:
// private
this.inherited(arguments);
if(!this._opened && !this._throttleHandler){
this._startSearchAll();
}
},
onInput: function(e){
this._onKey(e);
this.inherited(arguments);
},
_setListAttr: function(v){
// tags:
// private
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.endHandler){
this.disconnect(this.startHandler);
this.disconnect(this.endHandler);
this.disconnect(this.moveHandler);
clearInterval(this.repositionTimer);
this.repositionTimer = this.endHandler = null;
}
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 (that is, its data is loaded).
// returns:
// Returns the value of popup.open().
// tags:
// protected
var wasClosed = !this._opened;
var dropDown = this.dropDown,
ddNode = dropDown.domNode,
aroundNode = this.domNode,
self = this;
if(has('touch')){
win.global.scrollBy(0, domGeometry.position(aroundNode, false).y); // don't call scrollIntoView since it messes up ScrollableView
}
// TODO: isn't maxHeight dependent on the return value from popup.open(),
// i.e., 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){
var isGesture = false,
skipReposition = false,
active = false,
wrapper = dropDown.domNode.parentNode,
aroundNodePos = domGeometry.position(aroundNode, false),
popupPos = domGeometry.position(wrapper, false),
deltaX = popupPos.x - aroundNodePos.x,
deltaY = popupPos.y - aroundNodePos.y,
startX = -1, startY = -1;
// touchstart isn't really needed since touchmove implies touchstart, but
// mousedown is needed since mousemove doesn't know if the left button is down or not
this.startHandler = this.connect(win.doc.documentElement, touch.press,
function(e){
skipReposition = true;
active = true;
isGesture = false;
startX = e.clientX;
startY = e.clientY;
}
);
this.moveHandler = this.connect(win.doc.documentElement, touch.move,
function(e){
skipReposition = true;
if(e.touches){
active = isGesture = true; // touchmove implies touchstart
}else if(active && (e.clientX != startX || e.clientY != startY)){
isGesture = true;
}
}
);
this.clickHandler = this.connect(dropDown.domNode, "onclick",
function(){
skipReposition = true;
active = isGesture = false; // click implies no gesture movement
}
);
this.endHandler = this.connect(win.doc.documentElement, "onmouseup",//touch.release,
function(){
this.defer(function(){ // allow onclick to go first
skipReposition = true;
if(!isGesture && active){ // if click without move, then close dropdown
this.closeDropDown();
}
active = false;
});
}
);
this.repositionTimer = setInterval(lang.hitch(this, function(){
if(skipReposition){ // don't reposition if busy
skipReposition = false;
return;
}
var currentAroundNodePos = domGeometry.position(aroundNode, false),
currentPopupPos = domGeometry.position(wrapper, false),
currentDeltaX = currentPopupPos.x - currentAroundNodePos.x,
currentDeltaY = currentPopupPos.y - currentAroundNodePos.y;
// if the popup is no longer placed correctly, relocate it
if(Math.abs(currentDeltaX - deltaX) >= 1 || Math.abs(currentDeltaY - deltaY) >= 1){ // Firefox plays with partial pixels
domStyle.set(wrapper, { left: parseInt(domStyle.get(wrapper, "left")) + deltaX - currentDeltaX + 'px', top: parseInt(domStyle.get(wrapper, "top")) + deltaY - currentDeltaY + 'px' });
}
}), 50); // yield a short time to allow for consolidation for better CPU throughput
}
return retVal;
},
postCreate: function(){
this.inherited(arguments);
this.connect(this.domNode, "onclick", "_onClick");
},
destroy: function(){
if(this.repositionTimer){
clearInterval(this.repositionTimer);
}
this.inherited(arguments);
},
_onClick: function(/*Event*/ e){
// tags:
// private
// throttle clicks to prevent double click from doing double actions
if(!this._throttleHandler){
if(this.opened){
this.closeDropDown();
}else{
this._startSearchAll();
}
}
}
});
});