source: Dev/branches/rest-dojo-ui/client/dojox/grid/_FocusManager.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 20.1 KB
Line 
1define([
2        "dojo/_base/array",
3        "dojo/_base/lang",
4        "dojo/_base/declare",
5        "dojo/_base/connect",
6        "dojo/_base/event",
7        "dojo/_base/sniff",
8        "dojo/query",
9        "./util",
10        "dojo/_base/html"
11], function(array, lang, declare, connect, event, has, query, util, html){
12
13// focus management
14return declare("dojox.grid._FocusManager", null, {
15        // summary:
16        //      Controls grid cell focus. Owned by grid and used internally for focusing.
17        //      Note: grid cell actually receives keyboard input only when cell is being edited.
18        constructor: function(inGrid){
19                this.grid = inGrid;
20                this.cell = null;
21                this.rowIndex = -1;
22                this._connects = [];
23                this._headerConnects = [];
24                this.headerMenu = this.grid.headerMenu;
25                this._connects.push(connect.connect(this.grid.domNode, "onfocus", this, "doFocus"));
26                this._connects.push(connect.connect(this.grid.domNode, "onblur", this, "doBlur"));
27                this._connects.push(connect.connect(this.grid.domNode, "mousedown", this, "_mouseDown"));
28                this._connects.push(connect.connect(this.grid.domNode, "mouseup", this, "_mouseUp"));
29                this._connects.push(connect.connect(this.grid.domNode, "oncontextmenu", this, "doContextMenu"));
30                this._connects.push(connect.connect(this.grid.lastFocusNode, "onfocus", this, "doLastNodeFocus"));
31                this._connects.push(connect.connect(this.grid.lastFocusNode, "onblur", this, "doLastNodeBlur"));
32                this._connects.push(connect.connect(this.grid,"_onFetchComplete", this, "_delayedCellFocus"));
33                this._connects.push(connect.connect(this.grid,"postrender", this, "_delayedHeaderFocus"));
34        },
35        destroy: function(){
36                array.forEach(this._connects, connect.disconnect);
37                array.forEach(this._headerConnects, connect.disconnect);
38                delete this.grid;
39                delete this.cell;
40        },
41        _colHeadNode: null,
42        _colHeadFocusIdx: null,
43        _contextMenuBindNode: null,
44        tabbingOut: false,
45        focusClass: "dojoxGridCellFocus",
46        focusView: null,
47        initFocusView: function(){
48                this.focusView = this.grid.views.getFirstScrollingView() || this.focusView || this.grid.views.views[0];
49                this._initColumnHeaders();
50        },
51        isFocusCell: function(inCell, inRowIndex){
52                // summary:
53                //      states if the given cell is focused
54                // inCell: object
55                //      grid cell object
56                // inRowIndex: int
57                //      grid row index
58                // returns:
59                //      true of the given grid cell is focused
60                return (this.cell == inCell) && (this.rowIndex == inRowIndex);
61        },
62        isLastFocusCell: function(){
63                if(this.cell){
64                        return (this.rowIndex == this.grid.rowCount-1) && (this.cell.index == this.grid.layout.cellCount-1);
65                }
66                return false;
67        },
68        isFirstFocusCell: function(){
69                if(this.cell){
70                        return (this.rowIndex === 0) && (this.cell.index === 0);
71                }
72                return false;
73        },
74        isNoFocusCell: function(){
75                return (this.rowIndex < 0) || !this.cell;
76        },
77        isNavHeader: function(){
78                // summary:
79                //      states whether currently navigating among column headers.
80                // returns:
81                //      true if focus is on a column header; false otherwise.
82                return (!!this._colHeadNode);
83        },
84        getHeaderIndex: function(){
85                // summary:
86                //      if one of the column headers currently has focus, return its index.
87                // returns:
88                //      index of the focused column header, or -1 if none have focus.
89                if(this._colHeadNode){
90                        return array.indexOf(this._findHeaderCells(), this._colHeadNode);
91                }else{
92                        return -1;
93                }
94        },
95        _focusifyCellNode: function(inBork){
96                var n = this.cell && this.cell.getNode(this.rowIndex);
97                if(n){
98                        html.toggleClass(n, this.focusClass, inBork);
99                        if(inBork){
100                                var sl = this.scrollIntoView();
101                                try{
102                                        if(!this.grid.edit.isEditing()){
103                                                util.fire(n, "focus");
104                                                if(sl){ this.cell.view.scrollboxNode.scrollLeft = sl; }
105                                        }
106                                }catch(e){}
107                        }
108                }
109        },
110        _delayedCellFocus: function(){
111                if(this.isNavHeader()||!this.grid.focused){
112                                return;
113                }
114                var n = this.cell && this.cell.getNode(this.rowIndex);
115                if(n){
116                        try{
117                                if(!this.grid.edit.isEditing()){
118                                        html.toggleClass(n, this.focusClass, true);
119                                        if(this._colHeadNode){
120                                                this.blurHeader();
121                                        }
122                                        util.fire(n, "focus");
123                                }
124                        }
125                        catch(e){}
126                }
127        },
128        _delayedHeaderFocus: function(){
129                if(this.isNavHeader()){
130                        this.focusHeader();
131                        this.grid.domNode.focus();
132                }
133        },
134        _initColumnHeaders: function(){
135                array.forEach(this._headerConnects, connect.disconnect);
136                this._headerConnects = [];
137                var headers = this._findHeaderCells();
138                for(var i = 0; i < headers.length; i++){
139                        this._headerConnects.push(connect.connect(headers[i], "onfocus", this, "doColHeaderFocus"));
140                        this._headerConnects.push(connect.connect(headers[i], "onblur", this, "doColHeaderBlur"));
141                }
142        },
143        _findHeaderCells: function(){
144                // This should be a one liner:
145                //      query("th[tabindex=-1]", this.grid.viewsHeaderNode);
146                // But there is a bug in query() for IE -- see trac #7037.
147                var allHeads = query("th", this.grid.viewsHeaderNode);
148                var headers = [];
149                for (var i = 0; i < allHeads.length; i++){
150                        var aHead = allHeads[i];
151                        var hasTabIdx = html.hasAttr(aHead, "tabIndex");
152                        var tabindex = html.attr(aHead, "tabIndex");
153                        if (hasTabIdx && tabindex < 0) {
154                                headers.push(aHead);
155                        }
156                }
157                return headers;
158        },
159        _setActiveColHeader: function(/*Node*/colHeaderNode, /*Integer*/colFocusIdx, /*Integer*/ prevColFocusIdx){
160                //console.log("setActiveColHeader() - colHeaderNode:colFocusIdx:prevColFocusIdx = " + colHeaderNode + ":" + colFocusIdx + ":" + prevColFocusIdx);
161                this.grid.domNode.setAttribute("aria-activedescendant",colHeaderNode.id);
162                if (prevColFocusIdx != null && prevColFocusIdx >= 0 && prevColFocusIdx != colFocusIdx){
163                        html.toggleClass(this._findHeaderCells()[prevColFocusIdx],this.focusClass,false);
164                }
165                html.toggleClass(colHeaderNode,this.focusClass, true);
166                this._colHeadNode = colHeaderNode;
167                this._colHeadFocusIdx = colFocusIdx;
168                this._scrollHeader(this._colHeadFocusIdx);
169        },
170        scrollIntoView: function(){
171                var info = (this.cell ? this._scrollInfo(this.cell) : null);
172                if(!info || !info.s){
173                        return null;
174                }
175                var rt = this.grid.scroller.findScrollTop(this.rowIndex);
176                // place cell within horizontal view
177                if(info.n && info.sr){
178                        if(info.n.offsetLeft + info.n.offsetWidth > info.sr.l + info.sr.w){
179                                info.s.scrollLeft = info.n.offsetLeft + info.n.offsetWidth - info.sr.w;
180                        }else if(info.n.offsetLeft < info.sr.l){
181                                info.s.scrollLeft = info.n.offsetLeft;
182                        }
183                }
184                // place cell within vertical view
185                if(info.r && info.sr){
186                        if(rt + info.r.offsetHeight > info.sr.t + info.sr.h){
187                                this.grid.setScrollTop(rt + info.r.offsetHeight - info.sr.h);
188                        }else if(rt < info.sr.t){
189                                this.grid.setScrollTop(rt);
190                        }
191                }
192
193                return info.s.scrollLeft;
194        },
195        _scrollInfo: function(cell, domNode){
196                if(cell){
197                        var cl = cell,
198                                sbn = cl.view.scrollboxNode,
199                                sbnr = {
200                                        w: sbn.clientWidth,
201                                        l: sbn.scrollLeft,
202                                        t: sbn.scrollTop,
203                                        h: sbn.clientHeight
204                                },
205                                rn = cl.view.getRowNode(this.rowIndex);
206                        return {
207                                c: cl,
208                                s: sbn,
209                                sr: sbnr,
210                                n: (domNode ? domNode : cell.getNode(this.rowIndex)),
211                                r: rn
212                        };
213                }
214                return null;
215        },
216        _scrollHeader: function(currentIdx){
217                var info = null;
218                if(this._colHeadNode){
219                        var cell = this.grid.getCell(currentIdx);
220                        if(!cell){ return; }
221                        info = this._scrollInfo(cell, cell.getNode(0));
222                }
223                if(info && info.s && info.sr && info.n){
224                        // scroll horizontally as needed.
225                        var scroll = info.sr.l + info.sr.w;
226                        if(info.n.offsetLeft + info.n.offsetWidth > scroll){
227                                info.s.scrollLeft = info.n.offsetLeft + info.n.offsetWidth - info.sr.w;
228                        }else if(info.n.offsetLeft < info.sr.l){
229                                info.s.scrollLeft = info.n.offsetLeft;
230                        }else if(has('ie') <= 7 && cell && cell.view.headerNode){
231                                // Trac 7158: scroll dojoxGridHeader for IE7 and lower
232                                cell.view.headerNode.scrollLeft = info.s.scrollLeft;
233                        }
234                }
235        },
236        _isHeaderHidden: function(){
237                // summary:
238                //              determine if the grid headers are hidden
239                //              relies on documented technique of setting .dojoxGridHeader { display:none; }
240                // returns: Boolean
241                //              true if headers are hidden
242                //              false if headers are not hidden
243               
244                var curView = this.focusView;
245                if (!curView){
246                        // find one so we can determine if headers are hidden
247                        // there is no focusView after adding items to empty grid (test_data_grid_empty.html)
248                        for (var i = 0, cView; (cView = this.grid.views.views[i]); i++) {
249                                if(cView.headerNode ){
250                                        curView=cView;
251                                        break;
252                                }
253                        }
254                }
255                return (curView && html.getComputedStyle(curView.headerNode).display == "none");
256        },
257        colSizeAdjust: function (e, colIdx, delta){ // adjust the column specified by colIdx by the specified delta px
258                var headers = this._findHeaderCells();
259                var view = this.focusView;
260                if (!view) {
261                        for (var i = 0, cView; (cView = this.grid.views.views[i]); i++) {
262                                // find first view with a tableMap in order to work with empty grid
263                                if(cView.header.tableMap.map ){
264                                        view=cView;
265                                        break;
266                                }
267                        }
268                }
269                var curHeader = headers[colIdx];
270                if (!view || (colIdx == headers.length-1 && colIdx === 0)){
271                        return; // can't adjust single col. grid
272                }
273                view.content.baseDecorateEvent(e);
274                // need to adjust event with header cell info since focus is no longer on header cell
275                e.cellNode = curHeader; //this.findCellTarget(e.target, e.rowNode);
276                e.cellIndex = view.content.getCellNodeIndex(e.cellNode);
277                e.cell = (e.cellIndex >= 0 ? this.grid.getCell(e.cellIndex) : null);
278                if (view.header.canResize(e)){
279                        var deltaObj = {
280                                l: delta
281                        };
282                        var drag = view.header.colResizeSetup(e,false);
283                        view.header.doResizeColumn(drag, null, deltaObj);
284                        view.update();
285                }
286        },
287        styleRow: function(inRow){
288                return;
289        },
290        setFocusIndex: function(inRowIndex, inCellIndex){
291                // summary:
292                //      focuses the given grid cell
293                // inRowIndex: int
294                //      grid row index
295                // inCellIndex: int
296                //      grid cell index
297                this.setFocusCell(this.grid.getCell(inCellIndex), inRowIndex);
298        },
299        setFocusCell: function(inCell, inRowIndex){
300                // summary:
301                //      focuses the given grid cell
302                // inCell: object
303                //      grid cell object
304                // inRowIndex: int
305                //      grid row index
306                if(inCell && !this.isFocusCell(inCell, inRowIndex)){
307                        this.tabbingOut = false;
308                        if (this._colHeadNode){
309                                this.blurHeader();
310                        }
311                        this._colHeadNode = this._colHeadFocusIdx = null;
312                        this.focusGridView();
313                        this._focusifyCellNode(false);
314                        this.cell = inCell;
315                        this.rowIndex = inRowIndex;
316                        this._focusifyCellNode(true);
317                }
318                // even if this cell isFocusCell, the document focus may need to be rejiggered
319                // call opera on delay to prevent keypress from altering focus
320                if(has('opera')){
321                        setTimeout(lang.hitch(this.grid, 'onCellFocus', this.cell, this.rowIndex), 1);
322                }else{
323                        this.grid.onCellFocus(this.cell, this.rowIndex);
324                }
325        },
326        next: function(){
327                // summary:
328                //      focus next grid cell
329                if(this.cell){
330                        var row=this.rowIndex, col=this.cell.index+1, cc=this.grid.layout.cellCount-1, rc=this.grid.rowCount-1;
331                        if(col > cc){
332                                col = 0;
333                                row++;
334                        }
335                        if(row > rc){
336                                col = cc;
337                                row = rc;
338                        }
339                        if(this.grid.edit.isEditing()){ //when editing, only navigate to editable cells
340                                var nextCell = this.grid.getCell(col);
341                                if (!this.isLastFocusCell() && (!nextCell.editable ||
342                                        this.grid.canEdit && !this.grid.canEdit(nextCell, row))){
343                                        this.cell=nextCell;
344                                        this.rowIndex=row;
345                                        this.next();
346                                        return;
347                                }
348                        }
349                        this.setFocusIndex(row, col);
350                }
351        },
352        previous: function(){
353                // summary:
354                //      focus previous grid cell
355                if(this.cell){
356                        var row=(this.rowIndex || 0), col=(this.cell.index || 0) - 1;
357                        if(col < 0){
358                                col = this.grid.layout.cellCount-1;
359                                row--;
360                        }
361                        if(row < 0){
362                                row = 0;
363                                col = 0;
364                        }
365                        if(this.grid.edit.isEditing()){ //when editing, only navigate to editable cells
366                                var prevCell = this.grid.getCell(col);
367                                if (!this.isFirstFocusCell() && !prevCell.editable){
368                                        this.cell=prevCell;
369                                        this.rowIndex=row;
370                                        this.previous();
371                                        return;
372                                }
373                        }
374                        this.setFocusIndex(row, col);
375                }
376        },
377        move: function(inRowDelta, inColDelta) {
378                // summary:
379                //      focus grid cell or  simulate focus to column header based on position relative to current focus
380                // inRowDelta: int
381                // vertical distance from current focus
382                // inColDelta: int
383                // horizontal distance from current focus
384
385                var colDir = inColDelta < 0 ? -1 : 1;
386                // Handle column headers.
387                if(this.isNavHeader()){
388                        var headers = this._findHeaderCells();
389                        var savedIdx = currentIdx = array.indexOf(headers, this._colHeadNode);
390                        currentIdx += inColDelta;
391                        while(currentIdx >=0 && currentIdx < headers.length && headers[currentIdx].style.display == "none"){
392                                // skip over hidden column headers
393                                currentIdx += colDir;
394                        }
395                        if((currentIdx >= 0) && (currentIdx < headers.length)){
396                                this._setActiveColHeader(headers[currentIdx],currentIdx, savedIdx);
397                        }
398                }else{
399                        if(this.cell){
400                                // Handle grid proper.
401                                var sc = this.grid.scroller,
402                                        r = this.rowIndex,
403                                        rc = this.grid.rowCount-1,
404                                        row = Math.min(rc, Math.max(0, r+inRowDelta));
405                                if(inRowDelta){
406                                        if(inRowDelta>0){
407                                                if(row > sc.getLastPageRow(sc.page)){
408                                                        //need to load additional data, let scroller do that
409                                                        this.grid.setScrollTop(this.grid.scrollTop+sc.findScrollTop(row)-sc.findScrollTop(r));
410                                                }
411                                        }else if(inRowDelta<0){
412                                                if(row <= sc.getPageRow(sc.page)){
413                                                        //need to load additional data, let scroller do that
414                                                        this.grid.setScrollTop(this.grid.scrollTop-sc.findScrollTop(r)-sc.findScrollTop(row));
415                                                }
416                                        }
417                                }
418                                var cc = this.grid.layout.cellCount-1,
419                                i = this.cell.index,
420                                col = Math.min(cc, Math.max(0, i+inColDelta));
421                                var cell = this.grid.getCell(col);
422                                while(col>=0 && col < cc && cell && cell.hidden === true){
423                                        // skip hidden cells
424                                        col += colDir;
425                                        cell = this.grid.getCell(col);
426                                }
427                                if (!cell || cell.hidden === true){
428                                        // don't change col if would move to hidden
429                                        col = i;
430                                }
431                                //skip hidden row|cell
432                                var n = cell.getNode(row);
433                                if(!n && inRowDelta){
434                                        if((row + inRowDelta) >= 0 && (row + inRowDelta) <= rc){
435                                                this.move(inRowDelta > 0 ? ++inRowDelta : --inRowDelta, inColDelta);
436                                        }
437                                        return;
438                                }else if((!n || html.style(n, "display") === "none") && inColDelta){
439                                        if((col + inRowDelta) >= 0 && (col + inRowDelta) <= cc){
440                                                this.move(inRowDelta, inColDelta > 0 ? ++inColDelta : --inColDelta);
441                                        }
442                                        return;
443                                }
444                                this.setFocusIndex(row, col);
445                                if(inRowDelta){
446                                        this.grid.updateRow(r);
447                                }
448                        }
449                }
450        },
451        previousKey: function(e){
452                if(this.grid.edit.isEditing()){
453                        event.stop(e);
454                        this.previous();
455                }else if(!this.isNavHeader() && !this._isHeaderHidden()) {
456                        this.grid.domNode.focus(); // will call doFocus and set focus into header.
457                        event.stop(e);
458                }else{
459                        this.tabOut(this.grid.domNode);
460                        if (this._colHeadFocusIdx != null) { // clear grid header focus
461                                html.toggleClass(this._findHeaderCells()[this._colHeadFocusIdx], this.focusClass, false);
462                                this._colHeadFocusIdx = null;
463                        }
464                        this._focusifyCellNode(false);
465                }
466        },
467        nextKey: function(e) {
468                var isEmpty = (this.grid.rowCount === 0);
469                if(e.target === this.grid.domNode && this._colHeadFocusIdx == null){
470                        this.focusHeader();
471                        event.stop(e);
472                }else if(this.isNavHeader()){
473                        // if tabbing from col header, then go to grid proper.
474                        this.blurHeader();
475                        if(!this.findAndFocusGridCell()){
476                                this.tabOut(this.grid.lastFocusNode);
477                        }
478                        this._colHeadNode = this._colHeadFocusIdx= null;
479                }else if(this.grid.edit.isEditing()){
480                        event.stop(e);
481                        this.next();
482                }else{
483                        this.tabOut(this.grid.lastFocusNode);
484                }
485        },
486        tabOut: function(inFocusNode){
487                this.tabbingOut = true;
488                inFocusNode.focus();
489        },
490        focusGridView: function(){
491                util.fire(this.focusView, "focus");
492        },
493        focusGrid: function(inSkipFocusCell){
494                this.focusGridView();
495                this._focusifyCellNode(true);
496        },
497        findAndFocusGridCell: function(){
498                // summary:
499                //              find the first focusable grid cell
500                // returns: Boolean
501                //              true if focus was set to a cell
502                //              false if no cell found to set focus onto
503               
504                var didFocus = true;
505                var isEmpty = (this.grid.rowCount === 0); // If grid is empty this.grid.rowCount == 0
506                if (this.isNoFocusCell() && !isEmpty){
507                        var cellIdx = 0;
508                        var cell = this.grid.getCell(cellIdx);
509                        if (cell.hidden) {
510                                // if first cell isn't visible, use _colHeadFocusIdx
511                                // could also use a while loop to find first visible cell - not sure that is worth it
512                                cellIdx = this.isNavHeader() ? this._colHeadFocusIdx : 0;
513                        }
514                        this.setFocusIndex(0, cellIdx);
515                }
516                else if (this.cell && !isEmpty){
517                        if (this.focusView && !this.focusView.rowNodes[this.rowIndex]){
518                                // if rowNode for current index is undefined (likely as a result of a sort and because of #7304)
519                                // scroll to that row
520                                this.grid.scrollToRow(this.rowIndex);
521                        }
522                        this.focusGrid();
523                }else {
524                        didFocus = false;
525                }
526                this._colHeadNode = this._colHeadFocusIdx= null;
527                return didFocus;
528        },
529        focusHeader: function(){
530                var headerNodes = this._findHeaderCells();
531                var saveColHeadFocusIdx = this._colHeadFocusIdx;
532                if (this._isHeaderHidden()){
533                        // grid header is hidden, focus a cell
534                        this.findAndFocusGridCell();
535                }
536                else if (!this._colHeadFocusIdx) {
537                        if (this.isNoFocusCell()) {
538                                this._colHeadFocusIdx = 0;
539                        }
540                        else {
541                                this._colHeadFocusIdx = this.cell.index;
542                        }
543                }
544                this._colHeadNode = headerNodes[this._colHeadFocusIdx];
545                while(this._colHeadNode && this._colHeadFocusIdx >=0 && this._colHeadFocusIdx < headerNodes.length &&
546                                this._colHeadNode.style.display == "none"){
547                        // skip over hidden column headers
548                        this._colHeadFocusIdx++;
549                        this._colHeadNode = headerNodes[this._colHeadFocusIdx];
550                }
551                if(this._colHeadNode && this._colHeadNode.style.display != "none"){
552                        // Column header cells know longer receive actual focus.  So, for keyboard invocation of
553                        // contextMenu to work, the contextMenu must be bound to the grid.domNode rather than the viewsHeaderNode.
554                        // unbind the contextmenu from the viewsHeaderNode and to the grid when header cells are active.  Reset
555                        // the binding back to the viewsHeaderNode when header cells are no longer acive (in blurHeader) #10483
556                        if (this.headerMenu && this._contextMenuBindNode != this.grid.domNode){
557                                this.headerMenu.unBindDomNode(this.grid.viewsHeaderNode);
558                                this.headerMenu.bindDomNode(this.grid.domNode);
559                                this._contextMenuBindNode = this.grid.domNode;
560                        }
561                        this._setActiveColHeader(this._colHeadNode, this._colHeadFocusIdx, saveColHeadFocusIdx);
562                        this._scrollHeader(this._colHeadFocusIdx);
563                        this._focusifyCellNode(false);
564                }else {
565                        // all col head nodes are hidden - focus the grid
566                        this.findAndFocusGridCell();
567                }
568        },
569        blurHeader: function(){
570                html.removeClass(this._colHeadNode, this.focusClass);
571                html.removeAttr(this.grid.domNode,"aria-activedescendant");
572                // reset contextMenu onto viewsHeaderNode so right mouse on header will invoke (see focusHeader)
573                if (this.headerMenu && this._contextMenuBindNode == this.grid.domNode) {
574                        var viewsHeader = this.grid.viewsHeaderNode;
575                        this.headerMenu.unBindDomNode(this.grid.domNode);
576                        this.headerMenu.bindDomNode(viewsHeader);
577                        this._contextMenuBindNode = viewsHeader;
578                }
579        },
580        doFocus: function(e){
581                // trap focus only for grid dom node
582                if(e && e.target != e.currentTarget){
583                        event.stop(e);
584                        return;
585                }
586                // don't change focus if clicking on scroller bar
587                if(this._clickFocus){
588                        return;
589                }
590                // do not focus for scrolling if grid is about to blur
591                if(!this.tabbingOut){
592                        this.focusHeader();
593                }
594                this.tabbingOut = false;
595                event.stop(e);
596        },
597        doBlur: function(e){
598                event.stop(e);  // FF2
599        },
600        doContextMenu: function(e){
601        //stop contextMenu event if no header Menu to prevent default/browser contextMenu
602                if (!this.headerMenu){
603                        event.stop(e);
604                }
605        },
606        doLastNodeFocus: function(e){
607                if (this.tabbingOut){
608                        this._focusifyCellNode(false);
609                }else if(this.grid.rowCount >0){
610                        if (this.isNoFocusCell()){
611                                this.setFocusIndex(0,0);
612                        }
613                        this._focusifyCellNode(true);
614                }else {
615                        this.focusHeader();
616                }
617                this.tabbingOut = false;
618                event.stop(e);   // FF2
619        },
620        doLastNodeBlur: function(e){
621                event.stop(e);   // FF2
622        },
623        doColHeaderFocus: function(e){
624                this._setActiveColHeader(e.target,html.attr(e.target, "idx"),this._colHeadFocusIdx);
625                this._scrollHeader(this.getHeaderIndex());
626                event.stop(e);
627        },
628        doColHeaderBlur: function(e){
629                html.toggleClass(e.target, this.focusClass, false);
630        },
631        _mouseDown: function(e){
632                // a flag indicating grid is being focused by clicking
633                this._clickFocus = dojo.some(this.grid.views.views, function(v){
634                        return v.scrollboxNode === e.target;
635                });
636        },
637        _mouseUp: function(e){
638                this._clickFocus = false;
639        }
640});
641});
Note: See TracBrowser for help on using the repository browser.