1 | define([ |
---|
2 | "dojo/_base/kernel", |
---|
3 | "dojo/_base/lang", |
---|
4 | "dojo/_base/declare", |
---|
5 | "dojo/_base/array", |
---|
6 | "dojo/_base/connect", |
---|
7 | "dojo/_base/event", |
---|
8 | "dojo/_base/sniff", |
---|
9 | "dojo/_base/html", |
---|
10 | "dojo/keys", |
---|
11 | "dijit/a11y", |
---|
12 | "dijit/focus", |
---|
13 | "../_FocusManager" |
---|
14 | ], function(dojo, lang, declare, array, connect, event, has, html, keys, dijitA11y, dijitFocus, _FocusManager){ |
---|
15 | |
---|
16 | var _FocusArea = declare("dojox.grid.enhanced._FocusArea", null, { |
---|
17 | // summary: |
---|
18 | // This is a friend class of _FocusManager |
---|
19 | /*===== |
---|
20 | // name: string |
---|
21 | // Name of this area. |
---|
22 | name: "", |
---|
23 | |
---|
24 | onFocus: function(event, step){ |
---|
25 | // summary: |
---|
26 | // Called when this area logically gets focus. |
---|
27 | // event: Event object |
---|
28 | // May be unavailable, should check before use. |
---|
29 | // step: Integer |
---|
30 | // The distance in the tab sequence from last focused area to this area. |
---|
31 | // returns: |
---|
32 | // whether this area is successfully focused. If not, the next area will get focus. |
---|
33 | |
---|
34 | return true; |
---|
35 | }, |
---|
36 | |
---|
37 | onBlur: function(event, step){ |
---|
38 | // summary: |
---|
39 | // Called when this area logically loses focus. |
---|
40 | // event: Event object |
---|
41 | // May be unavailable, should check before use. |
---|
42 | // step: Integer |
---|
43 | // The distance in the tab sequence from this area to the area to focus. |
---|
44 | // returns: |
---|
45 | // If Boolean, means whether this area has successfully blurred. If not, the next area to focus is still this one. |
---|
46 | // If String, means the next area to focus is given by this returned name. |
---|
47 | |
---|
48 | return true; |
---|
49 | }, |
---|
50 | |
---|
51 | onMove: function(rowStep, colStep, event){ |
---|
52 | // summary: |
---|
53 | // Called when focus is moving around within this area. |
---|
54 | // rowStep: Integer |
---|
55 | // colStep: Integer |
---|
56 | // event: Event object |
---|
57 | // May be unavailable, should check before use. |
---|
58 | }, |
---|
59 | |
---|
60 | onKey: function(event, isBubble){ |
---|
61 | // summary: |
---|
62 | // Called when some key is pressed when focus is logically in this area. |
---|
63 | // event: Event object |
---|
64 | // isBubble: Boolean |
---|
65 | // Whether is in bubble stage (true) or catch stage (false). |
---|
66 | // returns: |
---|
67 | // If you do NOT want the event to propagate any further along the area stack, return exactly false. |
---|
68 | // So if you return nothing (undefined), this event is still propagating. |
---|
69 | return true; |
---|
70 | }, |
---|
71 | |
---|
72 | getRegions: function(){ |
---|
73 | // summary: |
---|
74 | // Define the small regions (dom nodes) in this area. |
---|
75 | // returns: |
---|
76 | // Array of dom nodes. |
---|
77 | }, |
---|
78 | |
---|
79 | onRegionFocus: function(event){ |
---|
80 | // summary: |
---|
81 | // Connected to the onfocus event of the defined regions (if any) |
---|
82 | }, |
---|
83 | |
---|
84 | onRegionBlur: function(event){ |
---|
85 | // summary: |
---|
86 | // Connected to the onblur event of the defined regions (if any) |
---|
87 | }, |
---|
88 | =====*/ |
---|
89 | constructor: function(area, focusManager){ |
---|
90 | this._fm = focusManager; |
---|
91 | this._evtStack = [area.name]; |
---|
92 | var dummy = function(){return true;}; |
---|
93 | area.onFocus = area.onFocus || dummy; |
---|
94 | area.onBlur = area.onBlur || dummy; |
---|
95 | area.onMove = area.onMove || dummy; |
---|
96 | area.onKeyUp = area.onKeyUp || dummy; |
---|
97 | area.onKeyDown = area.onKeyDown || dummy; |
---|
98 | lang.mixin(this, area); |
---|
99 | }, |
---|
100 | move: function(rowStep, colStep, evt){ |
---|
101 | if(this.name){ |
---|
102 | var i, len = this._evtStack.length; |
---|
103 | for(i = len - 1; i >= 0; --i){ |
---|
104 | if(this._fm._areas[this._evtStack[i]].onMove(rowStep, colStep, evt) === false){ |
---|
105 | return false; |
---|
106 | } |
---|
107 | } |
---|
108 | } |
---|
109 | return true; |
---|
110 | }, |
---|
111 | _onKeyEvent: function(evt, funcName){ |
---|
112 | if(this.name){ |
---|
113 | var i, len = this._evtStack.length; |
---|
114 | for(i = len - 1; i >= 0; --i){ |
---|
115 | if(this._fm._areas[this._evtStack[i]][funcName](evt, false) === false){ |
---|
116 | return false; |
---|
117 | } |
---|
118 | } |
---|
119 | for(i = 0; i < len; ++i){ |
---|
120 | if(this._fm._areas[this._evtStack[i]][funcName](evt, true) === false){ |
---|
121 | return false; |
---|
122 | } |
---|
123 | } |
---|
124 | } |
---|
125 | return true; |
---|
126 | }, |
---|
127 | keydown: function(evt){ |
---|
128 | return this._onKeyEvent(evt, "onKeyDown"); |
---|
129 | }, |
---|
130 | keyup: function(evt){ |
---|
131 | return this._onKeyEvent(evt, "onKeyUp"); |
---|
132 | }, |
---|
133 | contentMouseEventPlanner: function(){ |
---|
134 | return 0; |
---|
135 | }, |
---|
136 | headerMouseEventPlanner: function(){ |
---|
137 | return 0; |
---|
138 | } |
---|
139 | }); |
---|
140 | |
---|
141 | return declare("dojox.grid.enhanced._FocusManager", _FocusManager, { |
---|
142 | _stopEvent: function(evt){ |
---|
143 | try{ |
---|
144 | if(evt && evt.preventDefault){ |
---|
145 | event.stop(evt); |
---|
146 | } |
---|
147 | }catch(e){} |
---|
148 | }, |
---|
149 | |
---|
150 | constructor: function(grid){ |
---|
151 | this.grid = grid; |
---|
152 | this._areas = {}; |
---|
153 | this._areaQueue = []; |
---|
154 | this._contentMouseEventHandlers = []; |
---|
155 | this._headerMouseEventHandlers = []; |
---|
156 | this._currentAreaIdx = -1; |
---|
157 | this._gridBlured = true; |
---|
158 | this._connects.push(connect.connect(grid, "onBlur", this, "_doBlur")); |
---|
159 | this._connects.push(connect.connect(grid.scroller, "renderPage", this, "_delayedCellFocus")); |
---|
160 | |
---|
161 | this.addArea({ |
---|
162 | name: "header", |
---|
163 | onFocus: lang.hitch(this, this.focusHeader), |
---|
164 | onBlur: lang.hitch(this, this._blurHeader), |
---|
165 | onMove: lang.hitch(this, this._navHeader), |
---|
166 | getRegions: lang.hitch(this, this._findHeaderCells), |
---|
167 | onRegionFocus: lang.hitch(this, this.doColHeaderFocus), |
---|
168 | onRegionBlur: lang.hitch(this, this.doColHeaderBlur), |
---|
169 | onKeyDown: lang.hitch(this, this._onHeaderKeyDown) |
---|
170 | }); |
---|
171 | this.addArea({ |
---|
172 | name: "content", |
---|
173 | onFocus: lang.hitch(this, this._focusContent), |
---|
174 | onBlur: lang.hitch(this, this._blurContent), |
---|
175 | onMove: lang.hitch(this, this._navContent), |
---|
176 | onKeyDown: lang.hitch(this, this._onContentKeyDown) |
---|
177 | }); |
---|
178 | this.addArea({ |
---|
179 | name: "editableCell", |
---|
180 | onFocus: lang.hitch(this, this._focusEditableCell), |
---|
181 | onBlur: lang.hitch(this, this._blurEditableCell), |
---|
182 | onKeyDown: lang.hitch(this, this._onEditableCellKeyDown), |
---|
183 | onContentMouseEvent: lang.hitch(this, this._onEditableCellMouseEvent), |
---|
184 | contentMouseEventPlanner: function(evt, areas){ return -1; } |
---|
185 | }); |
---|
186 | this.placeArea("header"); |
---|
187 | this.placeArea("content"); |
---|
188 | this.placeArea("editableCell"); |
---|
189 | this.placeArea("editableCell","above","content"); |
---|
190 | }, |
---|
191 | destroy: function(){ |
---|
192 | for(var name in this._areas){ |
---|
193 | var area = this._areas[name]; |
---|
194 | array.forEach(area._connects, connect.disconnect); |
---|
195 | area._connects = null; |
---|
196 | if(area.uninitialize){ |
---|
197 | area.uninitialize(); |
---|
198 | } |
---|
199 | } |
---|
200 | this.inherited(arguments); |
---|
201 | }, |
---|
202 | addArea: function(area){ |
---|
203 | if(area.name && lang.isString(area.name)){ |
---|
204 | if(this._areas[area.name]){ |
---|
205 | //Just replace the original area, instead of remove it, so the position does not change. |
---|
206 | array.forEach(area._connects, connect.disconnect); |
---|
207 | } |
---|
208 | this._areas[area.name] = new _FocusArea(area, this); |
---|
209 | if(area.onHeaderMouseEvent){ |
---|
210 | this._headerMouseEventHandlers.push(area.name); |
---|
211 | } |
---|
212 | if(area.onContentMouseEvent){ |
---|
213 | this._contentMouseEventHandlers.push(area.name); |
---|
214 | } |
---|
215 | } |
---|
216 | }, |
---|
217 | getArea: function(areaName){ |
---|
218 | return this._areas[areaName]; |
---|
219 | }, |
---|
220 | _bindAreaEvents: function(){ |
---|
221 | var area, hdl, areas = this._areas; |
---|
222 | array.forEach(this._areaQueue, function(name){ |
---|
223 | area = areas[name]; |
---|
224 | if(!area._initialized && lang.isFunction(area.initialize)){ |
---|
225 | area.initialize(); |
---|
226 | area._initialized = true; |
---|
227 | } |
---|
228 | if(area.getRegions){ |
---|
229 | area._regions = area.getRegions() || []; |
---|
230 | array.forEach(area._connects || [], connect.disconnect); |
---|
231 | area._connects = []; |
---|
232 | array.forEach(area._regions, function(r){ |
---|
233 | if(area.onRegionFocus){ |
---|
234 | hdl = connect.connect(r, "onfocus", area.onRegionFocus); |
---|
235 | area._connects.push(hdl); |
---|
236 | } |
---|
237 | if(area.onRegionBlur){ |
---|
238 | hdl = connect.connect(r, "onblur", area.onRegionBlur); |
---|
239 | area._connects.push(hdl); |
---|
240 | } |
---|
241 | }); |
---|
242 | } |
---|
243 | }); |
---|
244 | }, |
---|
245 | removeArea: function(areaName){ |
---|
246 | var area = this._areas[areaName]; |
---|
247 | if(area){ |
---|
248 | this.ignoreArea(areaName); |
---|
249 | var i = array.indexOf(this._contentMouseEventHandlers, areaName); |
---|
250 | if(i >= 0){ |
---|
251 | this._contentMouseEventHandlers.splice(i, 1); |
---|
252 | } |
---|
253 | i = array.indexOf(this._headerMouseEventHandlers, areaName); |
---|
254 | if(i >= 0){ |
---|
255 | this._headerMouseEventHandlers.splice(i, 1); |
---|
256 | } |
---|
257 | array.forEach(area._connects, connect.disconnect); |
---|
258 | if(area.uninitialize){ |
---|
259 | area.uninitialize(); |
---|
260 | } |
---|
261 | delete this._areas[areaName]; |
---|
262 | } |
---|
263 | }, |
---|
264 | currentArea: function(areaName, toBlurOld){ |
---|
265 | // summary: |
---|
266 | // Set current area to the one areaName refers. |
---|
267 | // areaName: String |
---|
268 | var idx, cai = this._currentAreaIdx; |
---|
269 | if(lang.isString(areaName) && (idx = array.indexOf(this._areaQueue, areaName)) >= 0){ |
---|
270 | if(cai != idx){ |
---|
271 | this.tabbingOut = false; |
---|
272 | if(toBlurOld && cai >= 0 && cai < this._areaQueue.length){ |
---|
273 | this._areas[this._areaQueue[cai]].onBlur(); |
---|
274 | } |
---|
275 | this._currentAreaIdx = idx; |
---|
276 | } |
---|
277 | }else{ |
---|
278 | return (cai < 0 || cai >= this._areaQueue.length) ? |
---|
279 | new _FocusArea({}, this) : |
---|
280 | this._areas[this._areaQueue[this._currentAreaIdx]]; |
---|
281 | } |
---|
282 | return null; |
---|
283 | }, |
---|
284 | placeArea: function(name, pos, otherAreaName){ |
---|
285 | // summary: |
---|
286 | // Place the area refered by *name* at some logical position relative to an existing area. |
---|
287 | // example: |
---|
288 | // placeArea("myarea","before"|"after",...) |
---|
289 | // placeArea("myarea","below"|"above",...) |
---|
290 | if(!this._areas[name]){ return; } |
---|
291 | var idx = array.indexOf(this._areaQueue,otherAreaName); |
---|
292 | switch(pos){ |
---|
293 | case "after": |
---|
294 | if(idx >= 0){ ++idx; } |
---|
295 | //intentional drop through |
---|
296 | case "before": |
---|
297 | if(idx >= 0){ |
---|
298 | this._areaQueue.splice(idx,0,name); |
---|
299 | break; |
---|
300 | } |
---|
301 | //intentional drop through |
---|
302 | default: |
---|
303 | this._areaQueue.push(name); |
---|
304 | break; |
---|
305 | case "above": |
---|
306 | var isAbove = true; |
---|
307 | //intentional drop through |
---|
308 | case "below": |
---|
309 | var otherArea = this._areas[otherAreaName]; |
---|
310 | if(otherArea){ |
---|
311 | if(isAbove){ |
---|
312 | otherArea._evtStack.push(name); |
---|
313 | }else{ |
---|
314 | otherArea._evtStack.splice(0,0,name); |
---|
315 | } |
---|
316 | } |
---|
317 | } |
---|
318 | }, |
---|
319 | ignoreArea: function(name){ |
---|
320 | this._areaQueue = array.filter(this._areaQueue,function(areaName){ |
---|
321 | return areaName != name; |
---|
322 | }); |
---|
323 | }, |
---|
324 | focusArea: function(/* int|string|areaObj */areaId,evt){ |
---|
325 | var idx; |
---|
326 | if(typeof areaId == "number"){ |
---|
327 | idx = areaId < 0 ? this._areaQueue.length + areaId : areaId; |
---|
328 | }else{ |
---|
329 | idx = array.indexOf(this._areaQueue, |
---|
330 | lang.isString(areaId) ? areaId : (areaId && areaId.name)); |
---|
331 | } |
---|
332 | if(idx < 0){ idx = 0; } |
---|
333 | var step = idx - this._currentAreaIdx; |
---|
334 | this._gridBlured = false; |
---|
335 | if(step){ |
---|
336 | this.tab(step, evt); |
---|
337 | }else{ |
---|
338 | this.currentArea().onFocus(evt, step); |
---|
339 | } |
---|
340 | }, |
---|
341 | tab: function(step,evt){ |
---|
342 | //console.log("===========tab",step,"curArea",this._currentAreaIdx,"areaCnt",this._areaQueue.length); |
---|
343 | this._gridBlured = false; |
---|
344 | this.tabbingOut = false; |
---|
345 | if(step === 0){ |
---|
346 | return; |
---|
347 | } |
---|
348 | var cai = this._currentAreaIdx; |
---|
349 | var dir = step > 0 ? 1:-1; |
---|
350 | if(cai < 0 || cai >= this._areaQueue.length){ |
---|
351 | cai = (this._currentAreaIdx += step); |
---|
352 | }else{ |
---|
353 | var nextArea = this._areas[this._areaQueue[cai]].onBlur(evt,step); |
---|
354 | if(nextArea === true){ |
---|
355 | cai = (this._currentAreaIdx += step); |
---|
356 | }else if(lang.isString(nextArea) && this._areas[nextArea]){ |
---|
357 | cai = this._currentAreaIdx = array.indexOf(this._areaQueue,nextArea); |
---|
358 | } |
---|
359 | } |
---|
360 | //console.log("target area:",cai); |
---|
361 | for(; cai >= 0 && cai < this._areaQueue.length; cai += dir){ |
---|
362 | this._currentAreaIdx = cai; |
---|
363 | if(this._areaQueue[cai] && this._areas[this._areaQueue[cai]].onFocus(evt,step)){ |
---|
364 | //console.log("final target area:",this._currentAreaIdx); |
---|
365 | return; |
---|
366 | } |
---|
367 | } |
---|
368 | //console.log("tab out"); |
---|
369 | this.tabbingOut = true; |
---|
370 | if(step < 0){ |
---|
371 | this._currentAreaIdx = -1; |
---|
372 | dijitFocus.focus(this.grid.domNode); |
---|
373 | }else{ |
---|
374 | this._currentAreaIdx = this._areaQueue.length; |
---|
375 | dijitFocus.focus(this.grid.lastFocusNode); |
---|
376 | } |
---|
377 | }, |
---|
378 | _onMouseEvent: function(type, evt){ |
---|
379 | var lowercase = type.toLowerCase(), |
---|
380 | handlers = this["_" + lowercase + "MouseEventHandlers"], |
---|
381 | res = array.map(handlers, function(areaName){ |
---|
382 | return { |
---|
383 | "area": areaName, |
---|
384 | "idx": this._areas[areaName][lowercase + "MouseEventPlanner"](evt, handlers) |
---|
385 | }; |
---|
386 | }, this).sort(function(a, b){ |
---|
387 | return b.idx - a.idx; |
---|
388 | }), |
---|
389 | resHandlers = array.map(res, function(handler){ |
---|
390 | return res.area; |
---|
391 | }), |
---|
392 | i = res.length; |
---|
393 | while(--i >= 0){ |
---|
394 | if(this._areas[res[i].area]["on" + type + "MouseEvent"](evt, resHandlers) === false){ |
---|
395 | return; |
---|
396 | } |
---|
397 | } |
---|
398 | }, |
---|
399 | contentMouseEvent: function(evt){ |
---|
400 | this._onMouseEvent("Content", evt); |
---|
401 | }, |
---|
402 | headerMouseEvent: function(evt){ |
---|
403 | this._onMouseEvent("Header", evt); |
---|
404 | }, |
---|
405 | initFocusView: function(){ |
---|
406 | // summary: |
---|
407 | // Overwritten |
---|
408 | this.focusView = this.grid.views.getFirstScrollingView() || this.focusView || this.grid.views.views[0]; |
---|
409 | this._bindAreaEvents(); |
---|
410 | }, |
---|
411 | isNavHeader: function(){ |
---|
412 | // summary: |
---|
413 | // Overwritten |
---|
414 | // Check whether currently navigating among column headers. |
---|
415 | // returns: |
---|
416 | // true - focus is on a certain column header | false otherwise |
---|
417 | return this._areaQueue[this._currentAreaIdx] == "header"; |
---|
418 | }, |
---|
419 | previousKey: function(e){ |
---|
420 | // summary: |
---|
421 | // Overwritten |
---|
422 | this.tab(-1,e); |
---|
423 | }, |
---|
424 | nextKey: function(e){ |
---|
425 | // summary: |
---|
426 | // Overwritten |
---|
427 | this.tab(1,e); |
---|
428 | }, |
---|
429 | setFocusCell: function(/* Object */inCell, /* Integer */inRowIndex){ |
---|
430 | // summary: |
---|
431 | // Overwritten - focuses the given grid cell |
---|
432 | if(inCell){ |
---|
433 | this.currentArea(this.grid.edit.isEditing() ? "editableCell" : "content", true); |
---|
434 | //This is very slow when selecting cells! |
---|
435 | //this.focusGridView(); |
---|
436 | this._focusifyCellNode(false); |
---|
437 | this.cell = inCell; |
---|
438 | this.rowIndex = inRowIndex; |
---|
439 | this._focusifyCellNode(true); |
---|
440 | } |
---|
441 | this.grid.onCellFocus(this.cell, this.rowIndex); |
---|
442 | }, |
---|
443 | doFocus: function(e){ |
---|
444 | // summary: |
---|
445 | // Overwritten |
---|
446 | // trap focus only for grid dom node |
---|
447 | // do not focus for scrolling if grid is about to blur |
---|
448 | if(e && e.target == e.currentTarget && !this.tabbingOut){ |
---|
449 | if(this._gridBlured){ |
---|
450 | this._gridBlured = false; |
---|
451 | if(this._currentAreaIdx < 0 || this._currentAreaIdx >= this._areaQueue.length){ |
---|
452 | this.focusArea(0, e); |
---|
453 | }else{ |
---|
454 | this.focusArea(this._currentAreaIdx, e); |
---|
455 | } |
---|
456 | } |
---|
457 | }else{ |
---|
458 | this.tabbingOut = false; |
---|
459 | } |
---|
460 | event.stop(e); |
---|
461 | }, |
---|
462 | _doBlur: function(){ |
---|
463 | this._gridBlured = true; |
---|
464 | }, |
---|
465 | doLastNodeFocus: function(e){ |
---|
466 | // summary: |
---|
467 | // Overwritten |
---|
468 | if(this.tabbingOut){ |
---|
469 | this.tabbingOut = false; |
---|
470 | }else{ |
---|
471 | this.focusArea(-1, e); |
---|
472 | } |
---|
473 | }, |
---|
474 | _delayedHeaderFocus: function(){ |
---|
475 | // summary: |
---|
476 | // Overwritten |
---|
477 | if(this.isNavHeader() && !has('ie')){ |
---|
478 | this.focusHeader(); |
---|
479 | } |
---|
480 | }, |
---|
481 | _delayedCellFocus: function(){ |
---|
482 | // summary: |
---|
483 | // Overwritten |
---|
484 | |
---|
485 | //If focus header here, the page will scroll to grid when the grid is created. |
---|
486 | //this.focusArea("header"); |
---|
487 | }, |
---|
488 | _changeMenuBindNode: function(oldBindNode, newBindNode){ |
---|
489 | var hm = this.grid.headerMenu; |
---|
490 | if(hm && this._contextMenuBindNode == oldBindNode){ |
---|
491 | hm.unBindDomNode(oldBindNode); |
---|
492 | hm.bindDomNode(newBindNode); |
---|
493 | this._contextMenuBindNode = newBindNode; |
---|
494 | } |
---|
495 | }, |
---|
496 | //---------------Header Area------------------------------------------ |
---|
497 | focusHeader: function(evt, step){ //need a further look why these changes to parent's |
---|
498 | // summary: |
---|
499 | // Overwritten |
---|
500 | var didFocus = false; |
---|
501 | this.inherited(arguments); |
---|
502 | if(this._colHeadNode && html.style(this._colHeadNode, 'display') != "none"){ |
---|
503 | dijitFocus.focus(this._colHeadNode); |
---|
504 | this._stopEvent(evt); |
---|
505 | didFocus = true; |
---|
506 | } |
---|
507 | return didFocus; |
---|
508 | }, |
---|
509 | _blurHeader: function(evt,step){ |
---|
510 | // summary: |
---|
511 | // Overwritten |
---|
512 | if(this._colHeadNode){ |
---|
513 | html.removeClass(this._colHeadNode, this.focusClass); |
---|
514 | } |
---|
515 | html.removeAttr(this.grid.domNode,"aria-activedescendant"); |
---|
516 | // reset contextMenu onto viewsHeaderNode so right mouse on header will invoke (see focusHeader) |
---|
517 | this._changeMenuBindNode(this.grid.domNode,this.grid.viewsHeaderNode); |
---|
518 | //moved here from nextKey |
---|
519 | this._colHeadNode = this._colHeadFocusIdx = null; |
---|
520 | return true; |
---|
521 | }, |
---|
522 | _navHeader: function(rowStep, colStep, evt){ |
---|
523 | var colDir = colStep < 0 ? -1 : 1, |
---|
524 | savedIdx = array.indexOf(this._findHeaderCells(), this._colHeadNode); |
---|
525 | if(savedIdx >= 0 && (evt.shiftKey && evt.ctrlKey)){ |
---|
526 | this.colSizeAdjust(evt, savedIdx, colDir * 5); |
---|
527 | return; |
---|
528 | } |
---|
529 | this.move(rowStep, colStep); |
---|
530 | }, |
---|
531 | _onHeaderKeyDown: function(e, isBubble){ |
---|
532 | if(isBubble){ |
---|
533 | var dk = keys; |
---|
534 | switch(e.keyCode){ |
---|
535 | case dk.ENTER: |
---|
536 | case dk.SPACE: |
---|
537 | var colIdx = this.getHeaderIndex(); |
---|
538 | if(colIdx >= 0 && !this.grid.pluginMgr.isFixedCell(e.cell)/*TODO*/){ |
---|
539 | this.grid.setSortIndex(colIdx, null, e); |
---|
540 | event.stop(e); |
---|
541 | } |
---|
542 | break; |
---|
543 | } |
---|
544 | } |
---|
545 | return true; |
---|
546 | }, |
---|
547 | _setActiveColHeader: function(){ |
---|
548 | // summary: |
---|
549 | // Overwritten |
---|
550 | this.inherited(arguments); |
---|
551 | //EDG now will decorate event on header key events, if no focus, the cell will be wrong |
---|
552 | dijitFocus.focus(this._colHeadNode); |
---|
553 | }, |
---|
554 | //---------------Content Area------------------------------------------ |
---|
555 | findAndFocusGridCell: function(){ |
---|
556 | // summary: |
---|
557 | // Overwritten |
---|
558 | this._focusContent(); |
---|
559 | }, |
---|
560 | _focusContent: function(evt,step){ |
---|
561 | var didFocus = true; |
---|
562 | var isEmpty = (this.grid.rowCount === 0); // If grid is empty this.grid.rowCount == 0 |
---|
563 | if(this.isNoFocusCell() && !isEmpty){ |
---|
564 | //skip all the hidden cells |
---|
565 | for(var i = 0, cell = this.grid.getCell(0); cell && cell.hidden; cell = this.grid.getCell(++i)){} |
---|
566 | this.setFocusIndex(0, cell ? i : 0); |
---|
567 | }else if(this.cell && !isEmpty){ |
---|
568 | if(this.focusView && !this.focusView.rowNodes[this.rowIndex]){ |
---|
569 | // if rowNode for current index is undefined (likely as a result of a sort and because of #7304) |
---|
570 | // scroll to that row |
---|
571 | this.grid.scrollToRow(this.rowIndex); |
---|
572 | this.focusGrid(); |
---|
573 | }else{ |
---|
574 | this.setFocusIndex(this.rowIndex, this.cell.index); |
---|
575 | } |
---|
576 | }else{ |
---|
577 | didFocus = false; |
---|
578 | } |
---|
579 | if(didFocus){ this._stopEvent(evt); } |
---|
580 | return didFocus; |
---|
581 | }, |
---|
582 | _blurContent: function(evt,step){ |
---|
583 | this._focusifyCellNode(false); |
---|
584 | return true; |
---|
585 | }, |
---|
586 | _navContent: function(rowStep, colStep, evt){ |
---|
587 | if((this.rowIndex === 0 && rowStep < 0) || (this.rowIndex === this.grid.rowCount - 1 && rowStep > 0)){ |
---|
588 | return; |
---|
589 | } |
---|
590 | this._colHeadNode = null; |
---|
591 | this.move(rowStep, colStep, evt); |
---|
592 | if(evt){ |
---|
593 | event.stop(evt); |
---|
594 | } |
---|
595 | }, |
---|
596 | _onContentKeyDown: function(e, isBubble){ |
---|
597 | if(isBubble){ |
---|
598 | var dk = keys, s = this.grid.scroller; |
---|
599 | switch(e.keyCode){ |
---|
600 | case dk.ENTER: |
---|
601 | case dk.SPACE: |
---|
602 | var g = this.grid; |
---|
603 | if(g.indirectSelection){ break; } |
---|
604 | g.selection.clickSelect(this.rowIndex, connect.isCopyKey(e), e.shiftKey); |
---|
605 | g.onRowClick(e); |
---|
606 | event.stop(e); |
---|
607 | break; |
---|
608 | case dk.PAGE_UP: |
---|
609 | if(this.rowIndex !== 0){ |
---|
610 | if(this.rowIndex != s.firstVisibleRow + 1){ |
---|
611 | this._navContent(s.firstVisibleRow - this.rowIndex, 0); |
---|
612 | }else{ |
---|
613 | this.grid.setScrollTop(s.findScrollTop(this.rowIndex - 1)); |
---|
614 | this._navContent(s.firstVisibleRow - s.lastVisibleRow + 1, 0); |
---|
615 | } |
---|
616 | event.stop(e); |
---|
617 | } |
---|
618 | break; |
---|
619 | case dk.PAGE_DOWN: |
---|
620 | if(this.rowIndex + 1 != this.grid.rowCount){ |
---|
621 | event.stop(e); |
---|
622 | if(this.rowIndex != s.lastVisibleRow - 1){ |
---|
623 | this._navContent(s.lastVisibleRow - this.rowIndex - 1, 0); |
---|
624 | }else{ |
---|
625 | this.grid.setScrollTop(s.findScrollTop(this.rowIndex + 1)); |
---|
626 | this._navContent(s.lastVisibleRow - s.firstVisibleRow - 1, 0); |
---|
627 | } |
---|
628 | event.stop(e); |
---|
629 | } |
---|
630 | break; |
---|
631 | } |
---|
632 | } |
---|
633 | return true; |
---|
634 | }, |
---|
635 | //------------------editable content area------------------------- |
---|
636 | _blurFromEditableCell: false, |
---|
637 | _isNavigating: false, |
---|
638 | _navElems: null, |
---|
639 | _focusEditableCell: function(evt,step){ |
---|
640 | var didFocus = false; |
---|
641 | if(this._isNavigating){ |
---|
642 | didFocus = true; |
---|
643 | }else if(this.grid.edit.isEditing() && this.cell){ |
---|
644 | if(this._blurFromEditableCell || !this._blurEditableCell(evt, step)){ |
---|
645 | this.setFocusIndex(this.rowIndex,this.cell.index); |
---|
646 | didFocus = true; |
---|
647 | } |
---|
648 | this._stopEvent(evt); |
---|
649 | } |
---|
650 | return didFocus; |
---|
651 | }, |
---|
652 | _applyEditableCell: function(){ |
---|
653 | try{ |
---|
654 | this.grid.edit.apply(); |
---|
655 | }catch(e){ |
---|
656 | console.warn("_FocusManager._applyEditableCell() error:", e); |
---|
657 | } |
---|
658 | }, |
---|
659 | _blurEditableCell: function(evt,step){ |
---|
660 | this._blurFromEditableCell = false; |
---|
661 | if(this._isNavigating){ |
---|
662 | var toBlur = true; |
---|
663 | if(evt){ |
---|
664 | var elems = this._navElems; |
---|
665 | var firstElem = elems.lowest || elems.first; |
---|
666 | var lastElem = elems.last || elems.highest || firstElem; |
---|
667 | var target = has('ie') ? evt.srcElement : evt.target; |
---|
668 | toBlur = target == (step > 0 ? lastElem : firstElem); |
---|
669 | } |
---|
670 | if(toBlur){ |
---|
671 | this._isNavigating = false; |
---|
672 | html.setSelectable(this.cell.getNode(this.rowIndex), false); |
---|
673 | return "content"; |
---|
674 | } |
---|
675 | return false; |
---|
676 | }else if(this.grid.edit.isEditing() && this.cell){ |
---|
677 | if(!step || typeof step != "number"){ return false; } |
---|
678 | var dir = step > 0 ? 1 : -1; |
---|
679 | var cc = this.grid.layout.cellCount; |
---|
680 | for(var cell, col = this.cell.index + dir; col >= 0 && col < cc; col += dir){ |
---|
681 | cell = this.grid.getCell(col); |
---|
682 | if(cell.editable){ |
---|
683 | this.cell = cell; |
---|
684 | this._blurFromEditableCell = true; |
---|
685 | return false; |
---|
686 | } |
---|
687 | } |
---|
688 | if((this.rowIndex > 0 || dir == 1) && (this.rowIndex < this.grid.rowCount || dir == -1)){ |
---|
689 | this.rowIndex += dir; |
---|
690 | //this.cell = this.grid.getCell(0); //There must be an editable cell, so this is not necessary. |
---|
691 | for(col = dir > 0 ? 0 : cc - 1; col >= 0 && col < cc; col += dir){ |
---|
692 | cell = this.grid.getCell(col); |
---|
693 | if(cell.editable){ |
---|
694 | this.cell = cell; |
---|
695 | break; |
---|
696 | } |
---|
697 | } |
---|
698 | this._applyEditableCell(); |
---|
699 | return "content"; |
---|
700 | } |
---|
701 | } |
---|
702 | return true; |
---|
703 | }, |
---|
704 | _initNavigatableElems: function(){ |
---|
705 | this._navElems = dijitA11y._getTabNavigable(this.cell.getNode(this.rowIndex)); |
---|
706 | }, |
---|
707 | _onEditableCellKeyDown: function(e, isBubble){ |
---|
708 | var dk = keys, |
---|
709 | g = this.grid, |
---|
710 | edit = g.edit, |
---|
711 | editApplied = false, |
---|
712 | toPropagate = true; |
---|
713 | switch(e.keyCode){ |
---|
714 | case dk.ENTER: |
---|
715 | if(isBubble && edit.isEditing()){ |
---|
716 | this._applyEditableCell(); |
---|
717 | editApplied = true; |
---|
718 | event.stop(e); |
---|
719 | } |
---|
720 | //intentional drop through |
---|
721 | case dk.SPACE: |
---|
722 | if(!isBubble && this._isNavigating){ |
---|
723 | toPropagate = false; |
---|
724 | break; |
---|
725 | } |
---|
726 | if(isBubble){ |
---|
727 | if(!this.cell.editable && this.cell.navigatable){ |
---|
728 | this._initNavigatableElems(); |
---|
729 | var toFocus = this._navElems.lowest || this._navElems.first; |
---|
730 | if(toFocus){ |
---|
731 | this._isNavigating = true; |
---|
732 | html.setSelectable(this.cell.getNode(this.rowIndex), true); |
---|
733 | dijitFocus.focus(toFocus); |
---|
734 | event.stop(e); |
---|
735 | this.currentArea("editableCell", true); |
---|
736 | break; |
---|
737 | } |
---|
738 | } |
---|
739 | if(!editApplied && !edit.isEditing() && !g.pluginMgr.isFixedCell(this.cell)){ |
---|
740 | edit.setEditCell(this.cell, this.rowIndex); |
---|
741 | } |
---|
742 | if(editApplied){ |
---|
743 | this.currentArea("content", true); |
---|
744 | }else if(this.cell.editable && g.canEdit()){ |
---|
745 | this.currentArea("editableCell", true); |
---|
746 | } |
---|
747 | } |
---|
748 | break; |
---|
749 | case dk.PAGE_UP: |
---|
750 | case dk.PAGE_DOWN: |
---|
751 | if(!isBubble && edit.isEditing()){ |
---|
752 | //prevent propagating to content area |
---|
753 | toPropagate = false; |
---|
754 | } |
---|
755 | break; |
---|
756 | case dk.ESCAPE: |
---|
757 | if(!isBubble){ |
---|
758 | edit.cancel(); |
---|
759 | this.currentArea("content", true); |
---|
760 | } |
---|
761 | } |
---|
762 | return toPropagate; |
---|
763 | }, |
---|
764 | _onEditableCellMouseEvent: function(evt){ |
---|
765 | if(evt.type == "click"){ |
---|
766 | var cell = this.cell || evt.cell; |
---|
767 | if(cell && !cell.editable && cell.navigatable){ |
---|
768 | this._initNavigatableElems(); |
---|
769 | if(this._navElems.lowest || this._navElems.first){ |
---|
770 | var target = has('ie') ? evt.srcElement : evt.target; |
---|
771 | if(target != cell.getNode(evt.rowIndex)){ |
---|
772 | this._isNavigating = true; |
---|
773 | this.focusArea("editableCell", evt); |
---|
774 | html.setSelectable(cell.getNode(evt.rowIndex), true); |
---|
775 | dijitFocus.focus(target); |
---|
776 | return false; |
---|
777 | } |
---|
778 | } |
---|
779 | }else if(this.grid.singleClickEdit){ |
---|
780 | this.currentArea("editableCell"); |
---|
781 | return false; |
---|
782 | } |
---|
783 | } |
---|
784 | return true; |
---|
785 | } |
---|
786 | }); |
---|
787 | }); |
---|