-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcombobox.js
343 lines (305 loc) · 10.6 KB
/
combobox.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
define([
"dojo/_base/kernel",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/_base/window",
"dojo/dom-geometry",
"dojo/dom-style",
"dojo/dom-attr",
"dojo/window",
"dojo/touch",
"dojo/store/Memory",
"dojo/store/Observable",
"dijit/form/_AutoCompleterMixin",
"dijit/popup",
"dojox/mobile/_ComboBoxMenu",
"dojox/mobile/TextBox",
"dojox/mobile/sniff"
], function(kernel, declare, lang, win, domGeometry, domStyle, domAttr, windowUtils, touch, Memory, Observable,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();
}
if(has("windows-theme")) {
this.domNode.blur();
}
},
onInput: function(e){
if(!e || e.charCode !== 0){ // #18047
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);
domAttr.remove(this.domNode, "aria-owns");
domAttr.set(this.domNode, "aria-expanded", "false");
popup.close(this.dropDown);
this._opened = false;
// Remove disable attribute to make input element clickable after context menu closed
if(has("windows-theme") && this.domNode.disabled){
this.defer(function(){
this.domNode.removeAttribute("disabled");
}, 300);
}
},
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;
domAttr.set(dropDown.domNode, "role", "listbox");
domAttr.set(this.domNode, "aria-expanded", "true");
if(dropDown.id){
domAttr.set(this.domNode, "aria-owns", dropDown.id);
}
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: has("windows-theme") ? ["above"] : 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, 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
}
// We need to disable input control in order to prevent opening the soft keyboard in IE
if(has("windows-theme")){
this.domNode.setAttribute("disabled", true);
}
return retVal;
},
postCreate: function(){
this.inherited(arguments);
this.connect(this.domNode, "onclick", "_onClick");
domAttr.set(this.domNode, "role", "combobox");
domAttr.set(this.domNode, "aria-expanded", "false");
var _this=this;
_this.serverstore= dojo.clone(this.store)
_this.serverstore.query({}).then(function(res) {
console.log(res)
_this.store = new Observable(new Memory({
data:res
}))
})
},
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();
}
}
}
});
});