source: Dev/branches/rest-dojo-ui/client/dojox/grid/_Builder.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: 23.2 KB
Line 
1define([
2        "../main",
3        "dojo/_base/array",
4        "dojo/_base/lang",
5        "dojo/_base/window",
6        "dojo/_base/event",
7        "dojo/_base/sniff",
8        "dojo/_base/connect",
9        "dojo/dnd/Moveable",
10        "dojox/html/metrics",
11        "./util",
12        "dojo/_base/html"
13], function(dojox, array, lang, win, event, has, connect, Moveable, metrics, util, html){
14
15        var dg = dojox.grid;
16
17        var getTdIndex = function(td){
18                return td.cellIndex >=0 ? td.cellIndex : array.indexOf(td.parentNode.cells, td);
19        };
20       
21        var getTrIndex = function(tr){
22                return tr.rowIndex >=0 ? tr.rowIndex : array.indexOf(tr.parentNode.childNodes, tr);
23        };
24       
25        var getTr = function(rowOwner, index){
26                return rowOwner && ((rowOwner.rows||0)[index] || rowOwner.childNodes[index]);
27        };
28
29        var findTable = function(node){
30                for(var n=node; n && n.tagName!='TABLE'; n=n.parentNode){}
31                return n;
32        };
33       
34        var ascendDom = function(inNode, inWhile){
35                for(var n=inNode; n && inWhile(n); n=n.parentNode){}
36                return n;
37        };
38       
39        var makeNotTagName = function(inTagName){
40                var name = inTagName.toUpperCase();
41                return function(node){ return node.tagName != name; };
42        };
43
44        var rowIndexTag = util.rowIndexTag;
45        var gridViewTag = util.gridViewTag;
46
47        // base class for generating markup for the views
48        var _Builder = dg._Builder = lang.extend(function(view){
49                if(view){
50                        this.view = view;
51                        this.grid = view.grid;
52                }
53        },{
54                view: null,
55                // boilerplate HTML
56                _table: '<table class="dojoxGridRowTable" border="0" cellspacing="0" cellpadding="0" role="presentation"',
57
58                // Returns the table variable as an array - and with the view width, if specified
59                getTableArray: function(){
60                        var html = [this._table];
61                        if(this.view.viewWidth){
62                                html.push([' style="width:', this.view.viewWidth, ';"'].join(''));
63                        }
64                        html.push('>');
65                        return html;
66                },
67               
68                // generate starting tags for a cell
69                generateCellMarkup: function(inCell, inMoreStyles, inMoreClasses, isHeader){
70                        var result = [], html;
71                        if(isHeader){
72                                var sortInfo = inCell.index != inCell.grid.getSortIndex() ? "" : inCell.grid.sortInfo > 0 ? 'aria-sort="ascending"' : 'aria-sort="descending"';
73                                if (!inCell.id){
74                                        inCell.id = this.grid.id + "Hdr" + inCell.index;
75                                }
76                                // column headers are not editable, mark as aria-readonly=true
77                                html = ['<th tabIndex="-1" aria-readonly="true" role="columnheader"', sortInfo, 'id="', inCell.id, '"'];
78                        }else{
79                                // cells inherit grid aria-readonly property; default value for aria-readonly is false(grid is editable)
80                                // if grid is editable (had any editable cells), mark non editable cells as aria-readonly=true
81                                // if no editable cells, grid's aria-readonly value will have been set to true and cells will inherit
82                                var editInfo = this.grid.editable && !inCell.editable ? 'aria-readonly="true"' : "";
83                                html = ['<td tabIndex="-1" role="gridcell"', editInfo];
84                        }
85                        if(inCell.colSpan){
86                                html.push(' colspan="', inCell.colSpan, '"');
87                        }
88                        if(inCell.rowSpan){
89                                html.push(' rowspan="', inCell.rowSpan, '"');
90                        }
91                        html.push(' class="dojoxGridCell ');
92                        if(inCell.classes){
93                                html.push(inCell.classes, ' ');
94                        }
95                        if(inMoreClasses){
96                                html.push(inMoreClasses, ' ');
97                        }
98                        // result[0] => td opener, style
99                        result.push(html.join(''));
100                        // SLOT: result[1] => td classes
101                        result.push('');
102                        html = ['" idx="', inCell.index, '" style="'];
103                        if(inMoreStyles && inMoreStyles[inMoreStyles.length-1] != ';'){
104                                inMoreStyles += ';';
105                        }
106                        html.push(inCell.styles, inMoreStyles||'', inCell.hidden?'display:none;':'');
107                        if(inCell.unitWidth){
108                                html.push('width:', inCell.unitWidth, ';');
109                        }
110                        // result[2] => markup
111                        result.push(html.join(''));
112                        // SLOT: result[3] => td style
113                        result.push('');
114                        html = [ '"' ];
115                        if(inCell.attrs){
116                                html.push(" ", inCell.attrs);
117                        }
118                        html.push('>');
119                        // result[4] => td postfix
120                        result.push(html.join(''));
121                        // SLOT: result[5] => content
122                        result.push('');
123                        // result[6] => td closes
124                        result.push(isHeader?'</th>':'</td>');
125                        return result; // Array
126                },
127
128                // cell finding
129                isCellNode: function(inNode){
130                        return Boolean(inNode && inNode!=win.doc && html.attr(inNode, "idx"));
131                },
132               
133                getCellNodeIndex: function(inCellNode){
134                        return inCellNode ? Number(html.attr(inCellNode, "idx")) : -1;
135                },
136               
137                getCellNode: function(inRowNode, inCellIndex){
138                        for(var i=0, row; ((row = getTr(inRowNode.firstChild, i)) && row.cells); i++){
139                                for(var j=0, cell; (cell = row.cells[j]); j++){
140                                        if(this.getCellNodeIndex(cell) == inCellIndex){
141                                                return cell;
142                                        }
143                                }
144                        }
145                        return null;
146                },
147               
148                findCellTarget: function(inSourceNode, inTopNode){
149                        var n = inSourceNode;
150                        while(n && (!this.isCellNode(n) || (n.offsetParent && gridViewTag in n.offsetParent.parentNode && n.offsetParent.parentNode[gridViewTag] != this.view.id)) && (n!=inTopNode)){
151                                n = n.parentNode;
152                        }
153                        return n!=inTopNode ? n : null;
154                },
155               
156                // event decoration
157                baseDecorateEvent: function(e){
158                        e.dispatch = 'do' + e.type;
159                        e.grid = this.grid;
160                        e.sourceView = this.view;
161                        e.cellNode = this.findCellTarget(e.target, e.rowNode);
162                        e.cellIndex = this.getCellNodeIndex(e.cellNode);
163                        e.cell = (e.cellIndex >= 0 ? this.grid.getCell(e.cellIndex) : null);
164                },
165               
166                // event dispatch
167                findTarget: function(inSource, inTag){
168                        var n = inSource;
169                        while(n && (n!=this.domNode) && (!(inTag in n) || (gridViewTag in n && n[gridViewTag] != this.view.id))){
170                                n = n.parentNode;
171                        }
172                        return (n != this.domNode) ? n : null;
173                },
174
175                findRowTarget: function(inSource){
176                        return this.findTarget(inSource, rowIndexTag);
177                },
178
179                isIntraNodeEvent: function(e){
180                        try{
181                                return (e.cellNode && e.relatedTarget && html.isDescendant(e.relatedTarget, e.cellNode));
182                        }catch(x){
183                                // e.relatedTarget has permission problem in FF if it's an input: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
184                                return false;
185                        }
186                },
187
188                isIntraRowEvent: function(e){
189                        try{
190                                var row = e.relatedTarget && this.findRowTarget(e.relatedTarget);
191                                return !row && (e.rowIndex==-1) || row && (e.rowIndex==row.gridRowIndex);
192                        }catch(x){
193                                // e.relatedTarget on INPUT has permission problem in FF: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
194                                return false;
195                        }
196                },
197
198                dispatchEvent: function(e){
199                        if(e.dispatch in this){
200                                return this[e.dispatch](e);
201                        }
202                        return false;
203                },
204
205                // dispatched event handlers
206                domouseover: function(e){
207                        if(e.cellNode && (e.cellNode!=this.lastOverCellNode)){
208                                this.lastOverCellNode = e.cellNode;
209                                this.grid.onMouseOver(e);
210                        }
211                        this.grid.onMouseOverRow(e);
212                },
213
214                domouseout: function(e){
215                        if(e.cellNode && (e.cellNode==this.lastOverCellNode) && !this.isIntraNodeEvent(e, this.lastOverCellNode)){
216                                this.lastOverCellNode = null;
217                                this.grid.onMouseOut(e);
218                                if(!this.isIntraRowEvent(e)){
219                                        this.grid.onMouseOutRow(e);
220                                }
221                        }
222                },
223               
224                domousedown: function(e){
225                        if (e.cellNode)
226                                this.grid.onMouseDown(e);
227                        this.grid.onMouseDownRow(e);
228                }
229        });
230
231        // Produces html for grid data content. Owned by grid and used internally
232        // for rendering data. Override to implement custom rendering.
233        var _ContentBuilder = dg._ContentBuilder = lang.extend(function(view){
234                _Builder.call(this, view);
235        },_Builder.prototype,{
236                update: function(){
237                        this.prepareHtml();
238                },
239
240                // cache html for rendering data rows
241                prepareHtml: function(){
242                        var defaultGet=this.grid.get, cells=this.view.structure.cells;
243                        for(var j=0, row; (row=cells[j]); j++){
244                                for(var i=0, cell; (cell=row[i]); i++){
245                                        cell.get = cell.get || (cell.value == undefined) && defaultGet;
246                                        cell.markup = this.generateCellMarkup(cell, cell.cellStyles, cell.cellClasses, false);
247                                        if (!this.grid.editable && cell.editable){
248                                                this.grid.editable = true;
249                                        }
250                                }
251                        }
252                },
253
254                // time critical: generate html using cache and data source
255                generateHtml: function(inDataIndex, inRowIndex){
256                        var
257                                html = this.getTableArray(),
258                                v = this.view,
259                                cells = v.structure.cells,
260                                item = this.grid.getItem(inRowIndex);
261
262                        util.fire(this.view, "onBeforeRow", [inRowIndex, cells]);
263                        for(var j=0, row; (row=cells[j]); j++){
264                                if(row.hidden || row.header){
265                                        continue;
266                                }
267                                html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
268                                for(var i=0, cell, m, cc, cs; (cell=row[i]); i++){
269                                        m = cell.markup; cc = cell.customClasses = []; cs = cell.customStyles = [];
270                                        // content (format can fill in cc and cs as side-effects)
271                                        m[5] = cell.format(inRowIndex, item);
272                                        if(has('ie') < 8 && (m[5] === null || m[5] === '' || /^\s+$/.test(m[5]))){
273                                                //fix IE 6/7 quirks - border style not effective for empty td
274                                                m[5] = '&nbsp;'
275                                        }
276                                        // classes
277                                        m[1] = cc.join(' ');
278                                        // styles
279                                        m[3] = cs.join(';');
280                                        // in-place concat
281                                        html.push.apply(html, m);
282                                }
283                                html.push('</tr>');
284                        }
285                        html.push('</table>');
286                        return html.join(''); // String
287                },
288
289                decorateEvent: function(e){
290                        e.rowNode = this.findRowTarget(e.target);
291                        if(!e.rowNode){return false;}
292                        e.rowIndex = e.rowNode[rowIndexTag];
293                        this.baseDecorateEvent(e);
294                        e.cell = this.grid.getCell(e.cellIndex);
295                        return true; // Boolean
296                }
297        });
298
299        // Produces html for grid header content. Owned by grid and used internally
300        // for rendering data. Override to implement custom rendering.
301        var _HeaderBuilder = dg._HeaderBuilder = lang.extend(function(view){
302                this.moveable = null;
303                _Builder.call(this, view);
304        },_Builder.prototype,{
305                _skipBogusClicks: false,
306                overResizeWidth: 4,
307                minColWidth: 1,
308               
309                update: function(){
310                        if(this.tableMap){
311                                this.tableMap.mapRows(this.view.structure.cells);
312                        }else{
313                                this.tableMap = new dg._TableMap(this.view.structure.cells);
314                        }
315                },
316
317                generateHtml: function(inGetValue, inValue){
318                        var html = this.getTableArray(), cells = this.view.structure.cells;
319                       
320                        util.fire(this.view, "onBeforeRow", [-1, cells]);
321                        for(var j=0, row; (row=cells[j]); j++){
322                                if(row.hidden){
323                                        continue;
324                                }
325                                html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
326                                for(var i=0, cell, markup; (cell=row[i]); i++){
327                                        cell.customClasses = [];
328                                        cell.customStyles = [];
329                                        if(this.view.simpleStructure){
330                                                if(cell.draggable){
331                                                        if(cell.headerClasses){
332                                                                if(cell.headerClasses.indexOf('dojoDndItem') == -1){
333                                                                        cell.headerClasses += ' dojoDndItem';
334                                                                }
335                                                        }else{
336                                                                cell.headerClasses = 'dojoDndItem';
337                                                        }
338                                                }
339                                                if(cell.attrs){
340                                                        if(cell.attrs.indexOf("dndType='gridColumn_") == -1){
341                                                                cell.attrs += " dndType='gridColumn_" + this.grid.id + "'";
342                                                        }
343                                                }else{
344                                                        cell.attrs = "dndType='gridColumn_" + this.grid.id + "'";
345                                                }
346                                        }
347                                        markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true);
348                                        // content
349                                        markup[5] = (inValue != undefined ? inValue : inGetValue(cell));
350                                        // styles
351                                        markup[3] = cell.customStyles.join(';');
352                                        // classes
353                                        markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : '');
354                                        html.push(markup.join(''));
355                                }
356                                html.push('</tr>');
357                        }
358                        html.push('</table>');
359                        return html.join('');
360                },
361
362                // event helpers
363                getCellX: function(e){
364                        var n, x = e.layerX;
365                        if(has('mozilla') || has('ie') >= 9){
366                                n = ascendDom(e.target, makeNotTagName("th"));
367                                x -= (n && n.offsetLeft) || 0;
368                                var t = e.sourceView.getScrollbarWidth();
369                                if(!this.grid.isLeftToRight()/*&& e.sourceView.headerNode.scrollLeft < t*/){
370                                        //fix #11253
371                                        table = ascendDom(n,makeNotTagName("table"));
372                                        x -= (table && table.offsetLeft) || 0;
373                                }
374                                //x -= getProp(ascendDom(e.target, mkNotTagName("td")), "offsetLeft") || 0;
375                        }
376                        n = ascendDom(e.target, function(){
377                                if(!n || n == e.cellNode){
378                                        return false;
379                                }
380                                // Mozilla 1.8 (FF 1.5) has a bug that makes offsetLeft = -parent border width
381                                // when parent has border, overflow: hidden, and is positioned
382                                // handle this problem here ... not a general solution!
383                                x += (n.offsetLeft < 0 ? 0 : n.offsetLeft);
384                                return true;
385                        });
386                        return x;
387                },
388
389                // event decoration
390                decorateEvent: function(e){
391                        this.baseDecorateEvent(e);
392                        e.rowIndex = -1;
393                        e.cellX = this.getCellX(e);
394                        return true;
395                },
396
397                // event handlers
398                // resizing
399                prepareResize: function(e, mod){
400                        do{
401                                var i = e.cellIndex;
402                                e.cellNode = (i ? e.cellNode.parentNode.cells[i+mod] : null);
403                                e.cellIndex = (e.cellNode ? this.getCellNodeIndex(e.cellNode) : -1);
404                        }while(e.cellNode && e.cellNode.style.display == "none");
405                        return Boolean(e.cellNode);
406                },
407
408                canResize: function(e){
409                        if(!e.cellNode || e.cellNode.colSpan > 1){
410                                return false;
411                        }
412                        var cell = this.grid.getCell(e.cellIndex);
413                        return !cell.noresize && cell.canResize();
414                },
415
416                overLeftResizeArea: function(e){
417                        // We are never over a resize area if we are in the process of moving
418                        if(html.hasClass(win.body(), "dojoDndMove")){
419                                return false;
420                        }
421                        //Bugfix for crazy IE problem (#8807).  IE returns position information for the icon and text arrow divs
422                        //as if they were still on the left instead of returning the position they were 'float: right' to.
423                        //So, the resize check ends up checking the wrong adjacent cell.  This checks to see if the hover was over
424                        //the image or text nodes, then just ignored them/treat them not in scale range.
425                        if(has('ie')){
426                                var tN = e.target;
427                                if(html.hasClass(tN, "dojoxGridArrowButtonNode") ||
428                                        html.hasClass(tN, "dojoxGridArrowButtonChar") ||
429                                        html.hasClass(tN, "dojoxGridColCaption")){
430                                        return false;
431                                }
432                        }
433
434                        if(this.grid.isLeftToRight()){
435                                return (e.cellIndex>0) && (e.cellX > 0 && e.cellX < this.overResizeWidth) && this.prepareResize(e, -1);
436                        }
437                        var t = e.cellNode && (e.cellX > 0 && e.cellX < this.overResizeWidth);
438                        return t;
439                },
440
441                overRightResizeArea: function(e){
442                        // We are never over a resize area if we are in the process of moving
443                        if(html.hasClass(win.body(), "dojoDndMove")){
444                                return false;
445                        }
446                        //Bugfix for crazy IE problem (#8807).  IE returns position information for the icon and text arrow divs
447                        //as if they were still on the left instead of returning the position they were 'float: right' to.
448                        //So, the resize check ends up checking the wrong adjacent cell.  This checks to see if the hover was over
449                        //the image or text nodes, then just ignored them/treat them not in scale range.
450                        if(has('ie')){
451                                var tN = e.target;
452                                if(html.hasClass(tN, "dojoxGridArrowButtonNode") ||
453                                        html.hasClass(tN, "dojoxGridArrowButtonChar") ||
454                                        html.hasClass(tN, "dojoxGridColCaption")){
455                                        return false;
456                                }
457                        }
458
459                        if(this.grid.isLeftToRight()){
460                                return e.cellNode && (e.cellX >= e.cellNode.offsetWidth - this.overResizeWidth);
461                        }
462                        return (e.cellIndex>0) && (e.cellX >= e.cellNode.offsetWidth - this.overResizeWidth) && this.prepareResize(e, -1);
463                },
464
465                domousemove: function(e){
466                        //console.log(e.cellIndex, e.cellX, e.cellNode.offsetWidth);
467                        if(!this.moveable){
468                                var c = (this.overRightResizeArea(e) ? 'dojoxGridColResize' : (this.overLeftResizeArea(e) ? 'dojoxGridColResize' : ''));
469                                if(c && !this.canResize(e)){
470                                        c = 'dojoxGridColNoResize';
471                                }
472                                html.toggleClass(e.sourceView.headerNode, "dojoxGridColNoResize", (c == "dojoxGridColNoResize"));
473                                html.toggleClass(e.sourceView.headerNode, "dojoxGridColResize", (c == "dojoxGridColResize"));
474                                if(c){
475                                        event.stop(e);
476                                }
477                        }
478                },
479
480                domousedown: function(e){
481                        if(!this.moveable){
482                                if((this.overRightResizeArea(e) || this.overLeftResizeArea(e)) && this.canResize(e)){
483                                        this.beginColumnResize(e);
484                                }else{
485                                        this.grid.onMouseDown(e);
486                                        this.grid.onMouseOverRow(e);
487                                }
488                                //else{
489                                //      this.beginMoveColumn(e);
490                                //}
491                        }
492                },
493
494                doclick: function(e) {
495                        if(this._skipBogusClicks){
496                                event.stop(e);
497                                return true;
498                        }
499                        return false;
500                },
501
502                // column resizing
503                colResizeSetup: function(/*Event Object*/e, /*boolean*/ isMouse ){
504                        //Set up the drag object for column resizing
505                        // Called with mouse event in case of drag and drop,
506                        // Also called from keyboard shift-arrow event when focus is on a header
507                        var headContentBox = html.contentBox(e.sourceView.headerNode);
508                       
509                        if(isMouse){  //IE draws line even with no mouse down so separate from keyboard
510                                this.lineDiv = document.createElement('div');
511
512                                var vw = html.position(e.sourceView.headerNode, true);
513                                var bodyContentBox = html.contentBox(e.sourceView.domNode);
514                                //fix #11340
515                                var l = e.pageX;
516                                if(!this.grid.isLeftToRight() && has('ie') < 8){
517                                        l -= metrics.getScrollbar().w;
518                                }
519                                html.style(this.lineDiv, {
520                                        top: vw.y + "px",
521                                        left: l + "px",
522                                        height: (bodyContentBox.h + headContentBox.h) + "px"
523                                });
524                                html.addClass(this.lineDiv, "dojoxGridResizeColLine");
525                                this.lineDiv._origLeft = l;
526                                win.body().appendChild(this.lineDiv);
527                        }
528                        var spanners = [], nodes = this.tableMap.findOverlappingNodes(e.cellNode);
529                        for(var i=0, cell; (cell=nodes[i]); i++){
530                                spanners.push({ node: cell, index: this.getCellNodeIndex(cell), width: cell.offsetWidth });
531                                //console.log("spanner: " + this.getCellNodeIndex(cell));
532                        }
533
534                        var view = e.sourceView;
535                        var adj = this.grid.isLeftToRight() ? 1 : -1;
536                        var views = e.grid.views.views;
537                        var followers = [];
538                        for(var j=view.idx+adj, cView; (cView=views[j]); j=j+adj){
539                                followers.push({ node: cView.headerNode, left: window.parseInt(cView.headerNode.style.left) });
540                        }
541                        var table = view.headerContentNode.firstChild;
542                        var drag = {
543                                scrollLeft: e.sourceView.headerNode.scrollLeft,
544                                view: view,
545                                node: e.cellNode,
546                                index: e.cellIndex,
547                                w: html.contentBox(e.cellNode).w,
548                                vw: headContentBox.w,
549                                table: table,
550                                tw: html.contentBox(table).w,
551                                spanners: spanners,
552                                followers: followers
553                        };
554                        return drag;
555                },
556                beginColumnResize: function(e){
557                        this.moverDiv = document.createElement("div");
558                        html.style(this.moverDiv,{position: "absolute", left:0}); // to make DnD work with dir=rtl
559                        win.body().appendChild(this.moverDiv);
560                        html.addClass(this.grid.domNode, "dojoxGridColumnResizing");
561                        var m = (this.moveable = new Moveable(this.moverDiv));
562
563                        var drag = this.colResizeSetup(e,true);
564
565                        m.onMove = lang.hitch(this, "doResizeColumn", drag);
566
567                        connect.connect(m, "onMoveStop", lang.hitch(this, function(){
568                                this.endResizeColumn(drag);
569                                if(drag.node.releaseCapture){
570                                        drag.node.releaseCapture();
571                                }
572                                this.moveable.destroy();
573                                delete this.moveable;
574                                this.moveable = null;
575                                html.removeClass(this.grid.domNode, "dojoxGridColumnResizing");
576                        }));
577
578                        if(e.cellNode.setCapture){
579                                e.cellNode.setCapture();
580                        }
581                        m.onMouseDown(e);
582                },
583
584                doResizeColumn: function(inDrag, mover, leftTop){
585                        var changeX = leftTop.l;
586                        var data = {
587                                deltaX: changeX,
588                                w: inDrag.w + (this.grid.isLeftToRight() ? changeX : -changeX),//fix #11341
589                                vw: inDrag.vw + changeX,
590                                tw: inDrag.tw + changeX
591                        };
592                       
593                        this.dragRecord = {inDrag: inDrag, mover: mover, leftTop:leftTop};
594                       
595                        if(data.w >= this.minColWidth){
596                                if (!mover) { // we are using keyboard do immediate resize
597                                        this.doResizeNow(inDrag, data);
598                                }
599                                else{
600                                        html.style(this.lineDiv, "left", (this.lineDiv._origLeft + data.deltaX) + "px");
601                                }
602                        }
603                },
604
605                endResizeColumn: function(inDrag){
606                        if(this.dragRecord){
607                                var leftTop = this.dragRecord.leftTop;
608                                var changeX = this.grid.isLeftToRight() ? leftTop.l : -leftTop.l;
609                                // Make sure we are not under our minimum
610                                // http://bugs.dojotoolkit.org/ticket/9390
611                                changeX += Math.max(inDrag.w + changeX, this.minColWidth) - (inDrag.w + changeX);
612                                if(has('webkit') && inDrag.spanners.length){
613                                        // Webkit needs the pad border extents back in
614                                        changeX += html._getPadBorderExtents(inDrag.spanners[0].node).w;
615                                }
616                                var data = {
617                                        deltaX: changeX,
618                                        w: inDrag.w + changeX,
619                                        vw: inDrag.vw + changeX,
620                                        tw: inDrag.tw + changeX
621                                };
622                                // Only resize the columns when the drag has finished
623                                this.doResizeNow(inDrag, data);
624                                delete this.dragRecord;
625                        }
626                       
627                        html.destroy(this.lineDiv);
628                        html.destroy(this.moverDiv);
629                        html.destroy(this.moverDiv);
630                        delete this.moverDiv;
631                        this._skipBogusClicks = true;
632                        inDrag.view.update();
633                        this._skipBogusClicks = false;
634                        this.grid.onResizeColumn(inDrag.index);
635                },
636                doResizeNow: function(inDrag, data){
637                        inDrag.view.convertColPctToFixed();
638                        if(inDrag.view.flexCells && !inDrag.view.testFlexCells()){
639                                var t = findTable(inDrag.node);
640                                if(t){
641                                        (t.style.width = '');
642                                }
643                        }
644                        var i, s, sw, f, fl;
645                        for(i=0; (s=inDrag.spanners[i]); i++){
646                                sw = s.width + data.deltaX;
647                                if(sw > 0){
648                                        s.node.style.width = sw + 'px';
649                                        inDrag.view.setColWidth(s.index, sw);
650                                }
651                        }
652                        if(this.grid.isLeftToRight() || !has('ie')){//fix #11339
653                                for(i=0; (f=inDrag.followers[i]); i++){
654                                        fl = f.left + data.deltaX;
655                                        f.node.style.left = fl + 'px';
656                                }
657                        }
658                        inDrag.node.style.width = data.w + 'px';
659                        inDrag.view.setColWidth(inDrag.index, data.w);
660                        inDrag.view.headerNode.style.width = data.vw + 'px';
661                        inDrag.view.setColumnsWidth(data.tw);
662                        if(!this.grid.isLeftToRight()){
663                                inDrag.view.headerNode.scrollLeft = inDrag.scrollLeft + data.deltaX;
664                        }
665                }
666        });
667
668        // Maps an html table into a structure parsable for information about cell row and col spanning.
669        // Used by HeaderBuilder.
670        dg._TableMap = lang.extend(function(rows){
671                this.mapRows(rows);
672        },{
673                map: null,
674
675                mapRows: function(inRows){
676                        // summary: Map table topography
677
678                        //console.log('mapRows');
679                        // # of rows
680                        var rowCount = inRows.length;
681                        if(!rowCount){
682                                return;
683                        }
684                        // map which columns and rows fill which cells
685                        this.map = [];
686                        var row;
687                        for(var k=0; (row=inRows[k]); k++){
688                                this.map[k] = [];
689                        }
690                        for(var j=0; (row=inRows[j]); j++){
691                                for(var i=0, x=0, cell, colSpan, rowSpan; (cell=row[i]); i++){
692                                        while(this.map[j][x]){x++;}
693                                        this.map[j][x] = { c: i, r: j };
694                                        rowSpan = cell.rowSpan || 1;
695                                        colSpan = cell.colSpan || 1;
696                                        for(var y=0; y<rowSpan; y++){
697                                                for(var s=0; s<colSpan; s++){
698                                                        this.map[j+y][x+s] = this.map[j][x];
699                                                }
700                                        }
701                                        x += colSpan;
702                                }
703                        }
704                        //this.dumMap();
705                },
706
707                dumpMap: function(){
708                        for(var j=0, row, h=''; (row=this.map[j]); j++,h=''){
709                                for(var i=0, cell; (cell=row[i]); i++){
710                                        h += cell.r + ',' + cell.c + '   ';
711                                }
712                        }
713                },
714
715                getMapCoords: function(inRow, inCol){
716                        // summary: Find node's map coords by it's structure coords
717                        for(var j=0, row; (row=this.map[j]); j++){
718                                for(var i=0, cell; (cell=row[i]); i++){
719                                        if(cell.c==inCol && cell.r == inRow){
720                                                return { j: j, i: i };
721                                        }
722                                        //else{console.log(inRow, inCol, ' : ', i, j, " : ", cell.r, cell.c); };
723                                }
724                        }
725                        return { j: -1, i: -1 };
726                },
727               
728                getNode: function(inTable, inRow, inCol){
729                        // summary: Find a node in inNode's table with the given structure coords
730                        var row = inTable && inTable.rows[inRow];
731                        return row && row.cells[inCol];
732                },
733               
734                _findOverlappingNodes: function(inTable, inRow, inCol){
735                        var nodes = [];
736                        var m = this.getMapCoords(inRow, inCol);
737                        //console.log("node j: %d, i: %d", m.j, m.i);
738                        for(var j=0, row; (row=this.map[j]); j++){
739                                if(j == m.j){ continue; }
740                                var rw = row[m.i];
741                                //console.log("overlaps: r: %d, c: %d", rw.r, rw.c);
742                                var n = (rw?this.getNode(inTable, rw.r, rw.c):null);
743                                if(n){ nodes.push(n); }
744                        }
745                        //console.log(nodes);
746                        return nodes;
747                },
748               
749                findOverlappingNodes: function(inNode){
750                        return this._findOverlappingNodes(findTable(inNode), getTrIndex(inNode.parentNode), getTdIndex(inNode));
751                }
752        });
753
754        return {
755                _Builder: _Builder,
756                _HeaderBuilder: _HeaderBuilder,
757                _ContentBuilder: _ContentBuilder
758        };
759});
Note: See TracBrowser for help on using the repository browser.