source: Dev/trunk/src/client/dojox/grid/_View.js @ 529

Last change on this file since 529 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 25.2 KB
Line 
1define([
2        "dojo",
3        "dijit/registry",
4        "../main",
5        "dojo/_base/declare",
6        "dojo/_base/array",
7        "dojo/_base/lang",
8        "dojo/_base/connect",
9        "dojo/_base/sniff",
10        "dojo/query",
11        "dojo/_base/window",
12        "dojo/text!./resources/View.html",
13        "dojo/dnd/Source",
14        "dijit/_Widget",
15        "dijit/_TemplatedMixin",
16        "dojox/html/metrics",
17        "./util",
18        "dojo/_base/html",
19        "./_Builder",
20        "dojo/dnd/Avatar",
21        "dojo/dnd/Manager"
22], function(dojo, dijit, dojox, declare, array, lang, connect, has, query,
23        win, template, Source, _Widget, _TemplatedMixin, metrics, util, html, _Builder, Avatar, Manager){
24
25        // a private function
26        var getStyleText = function(inNode, inStyleText){
27                return inNode.style.cssText == undefined ? inNode.getAttribute("style") : inNode.style.cssText;
28        };
29
30        // some public functions
31        var _View = declare('dojox.grid._View', [_Widget, _TemplatedMixin], {
32                // summary:
33                //              A collection of grid columns. A grid is comprised of a set of views that stack horizontally.
34                //              Grid creates views automatically based on grid's layout structure.
35                //              Users should typically not need to access individual views directly.
36                //
37                // defaultWidth: String
38                //              Default width of the view
39                defaultWidth: "18em",
40
41                // viewWidth: String
42                //              Width for the view, in valid css unit
43                viewWidth: "",
44
45                templateString: template,
46
47                classTag: 'dojoxGrid',
48                marginBottom: 0,
49                rowPad: 2,
50
51                // _togglingColumn: int
52                //              Width of the column being toggled (-1 for none)
53                _togglingColumn: -1,
54               
55                // _headerBuilderClass: Object
56                //              The class to use for our header builder
57                _headerBuilderClass: _Builder._HeaderBuilder,
58               
59                // _contentBuilderClass: Object
60                //              The class to use for our content builder
61                _contentBuilderClass: _Builder._ContentBuilder,
62               
63                postMixInProperties: function(){
64                        this.rowNodes = {};
65                },
66
67                postCreate: function(){
68                        this.connect(this.scrollboxNode,"onscroll","doscroll");
69                        util.funnelEvents(this.contentNode, this, "doContentEvent", [ 'mouseover', 'mouseout', 'click', 'dblclick', 'contextmenu', 'mousedown' ]);
70                        util.funnelEvents(this.headerNode, this, "doHeaderEvent", [ 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'click', 'contextmenu' ]);
71                        this.content = new this._contentBuilderClass(this);
72                        this.header = new this._headerBuilderClass(this);
73                        //BiDi: in RTL case, style width='9000em' causes scrolling problem in head node
74                        if(!this.grid.isLeftToRight()){
75                                this.headerNodeContainer.style.width = "";
76                        }
77                },
78
79                destroy: function(){
80                        html.destroy(this.headerNode);
81                        delete this.headerNode;
82                        for(var i in this.rowNodes){
83                                this._cleanupRowWidgets(this.rowNodes[i]);
84                                html.destroy(this.rowNodes[i]);
85                        }
86                        this.rowNodes = {};
87                        if(this.source){
88                                this.source.destroy();
89                        }
90                        this.inherited(arguments);
91                },
92
93                // focus
94                focus: function(){
95                        if(has('ie') || has('webkit') || has('opera')){
96                                this.hiddenFocusNode.focus();
97                        }else{
98                                this.scrollboxNode.focus();
99                        }
100                },
101
102                setStructure: function(inStructure){
103                        var vs = (this.structure = inStructure);
104                        // FIXME: similar logic is duplicated in layout
105                        if(vs.width && !isNaN(vs.width)){
106                                this.viewWidth = vs.width + 'em';
107                        }else{
108                                this.viewWidth = vs.width || (vs.noscroll ? 'auto' : this.viewWidth); //|| this.defaultWidth;
109                        }
110                        this._onBeforeRow = vs.onBeforeRow||function(){};
111                        this._onAfterRow = vs.onAfterRow||function(){};
112                        this.noscroll = vs.noscroll;
113                        if(this.noscroll){
114                                this.scrollboxNode.style.overflow = "hidden";
115                        }
116                        this.simpleStructure = Boolean(vs.cells.length == 1);
117                        // bookkeeping
118                        this.testFlexCells();
119                        // accomodate new structure
120                        this.updateStructure();
121                },
122               
123                _cleanupRowWidgets: function(inRowNode){
124                        // Summary:
125                        //              Cleans up the widgets for the given row node so that
126                        //              we can reattach them if needed
127                        if(inRowNode){
128                                array.forEach(query("[widgetId]", inRowNode).map(dijit.byNode), function(w){
129                                        if(w._destroyOnRemove){
130                                                w.destroy();
131                                                delete w;
132                                        }else if(w.domNode && w.domNode.parentNode){
133                                                w.domNode.parentNode.removeChild(w.domNode);
134                                        }
135                                });
136                        }
137                },
138               
139                onBeforeRow: function(inRowIndex, cells){
140                        this._onBeforeRow(inRowIndex, cells);
141                        if(inRowIndex >= 0){
142                                this._cleanupRowWidgets(this.getRowNode(inRowIndex));
143                        }
144                },
145               
146                onAfterRow: function(inRowIndex, cells, inRowNode){
147                        this._onAfterRow(inRowIndex, cells, inRowNode);
148                        var g = this.grid;
149                        array.forEach(query(".dojoxGridStubNode", inRowNode), function(n){
150                                if(n && n.parentNode){
151                                        var lw = n.getAttribute("linkWidget");
152                                        var cellIdx = window.parseInt(html.attr(n, "cellIdx"), 10);
153                                        var cellDef = g.getCell(cellIdx);
154                                        var w = dijit.byId(lw);
155                                        if(w){
156                                                n.parentNode.replaceChild(w.domNode, n);
157                                                if(!w._started){
158                                                        w.startup();
159                                                }
160                                                dojo.destroy(n);
161                                        }else{
162                                                n.innerHTML = "";
163                                        }
164                                }
165                        }, this);
166                },
167
168                testFlexCells: function(){
169                        // FIXME: cheater, this function does double duty as initializer and tester
170                        this.flexCells = false;
171                        for(var j=0, row; (row=this.structure.cells[j]); j++){
172                                for(var i=0, cell; (cell=row[i]); i++){
173                                        cell.view = this;
174                                        this.flexCells = this.flexCells || cell.isFlex();
175                                }
176                        }
177                        return this.flexCells;
178                },
179
180                updateStructure: function(){
181                        // header builder needs to update table map
182                        this.header.update();
183                        // content builder needs to update markup cache
184                        this.content.update();
185                },
186
187                getScrollbarWidth: function(){
188                        var hasScrollSpace = this.hasVScrollbar();
189                        var overflow = html.style(this.scrollboxNode, "overflow");
190                        if(this.noscroll || !overflow || overflow == "hidden"){
191                                hasScrollSpace = false;
192                        }else if(overflow == "scroll"){
193                                hasScrollSpace = true;
194                        }
195                        return (hasScrollSpace ? metrics.getScrollbar().w : 0); // Integer
196                },
197
198                getColumnsWidth: function(){
199                        var h = this.headerContentNode;
200                        return h && h.firstChild ? (h.firstChild.offsetWidth || html.style(h.firstChild, 'width')) : 0; // Integer
201                },
202
203                setColumnsWidth: function(width){
204                        this.headerContentNode.firstChild.style.width = width + 'px';
205                        if(this.viewWidth){
206                                this.viewWidth = width + 'px';
207                        }
208                },
209
210                getWidth: function(){
211                        return this.viewWidth || (this.getColumnsWidth()+this.getScrollbarWidth()) +'px'; // String
212                },
213
214                getContentWidth: function(){
215                        return Math.max(0, html._getContentBox(this.domNode).w - this.getScrollbarWidth()) + 'px'; // String
216                },
217
218                render: function(){
219                        this.scrollboxNode.style.height = '';
220                        this.renderHeader();
221                        if(this._togglingColumn >= 0){
222                                this.setColumnsWidth(this.getColumnsWidth() - this._togglingColumn);
223                                this._togglingColumn = -1;
224                        }
225                        var cells = this.grid.layout.cells;
226                        var getSibling = lang.hitch(this, function(node, before){
227                                !this.grid.isLeftToRight() && (before = !before);
228                                var inc = before?-1:1;
229                                var idx = this.header.getCellNodeIndex(node) + inc;
230                                var cell = cells[idx];
231                                while(cell && cell.getHeaderNode() && cell.getHeaderNode().style.display == "none"){
232                                        idx += inc;
233                                        cell = cells[idx];
234                                }
235                                if(cell){
236                                        return cell.getHeaderNode();
237                                }
238                                return null;
239                        });
240                        if(this.grid.columnReordering && this.simpleStructure){
241                                if(this.source){
242                                        this.source.destroy();
243                                }
244                               
245                                // Create the top and bottom markers
246                                var bottomMarkerId = "dojoxGrid_bottomMarker";
247                                var topMarkerId = "dojoxGrid_topMarker";
248                                if(this.bottomMarker){
249                                        html.destroy(this.bottomMarker);
250                                }
251                                this.bottomMarker = html.byId(bottomMarkerId);
252                                if(this.topMarker){
253                                        html.destroy(this.topMarker);
254                                }
255                                this.topMarker = html.byId(topMarkerId);
256                                if (!this.bottomMarker) {
257                                        this.bottomMarker = html.create("div", {
258                                                "id": bottomMarkerId,
259                                                "class": "dojoxGridColPlaceBottom"
260                                        }, win.body());
261                                        this._hide(this.bottomMarker);
262
263                                       
264                                        this.topMarker = html.create("div", {
265                                                "id": topMarkerId,
266                                                "class": "dojoxGridColPlaceTop"
267                                        }, win.body());
268                                        this._hide(this.topMarker);
269                                }
270                                this.arrowDim = html.contentBox(this.bottomMarker);
271
272                                var headerHeight = html.contentBox(this.headerContentNode.firstChild.rows[0]).h;
273                               
274                                this.source = new Source(this.headerContentNode.firstChild.rows[0], {
275                                        horizontal: true,
276                                        accept: [ "gridColumn_" + this.grid.id ],
277                                        viewIndex: this.index,
278                                        generateText: false,
279                                        onMouseDown: lang.hitch(this, function(e){
280                                                this.header.decorateEvent(e);
281                                                if((this.header.overRightResizeArea(e) || this.header.overLeftResizeArea(e)) &&
282                                                        this.header.canResize(e) && !this.header.moveable){
283                                                        this.header.beginColumnResize(e);
284                                                }else{
285                                                        if(this.grid.headerMenu){
286                                                                this.grid.headerMenu.onCancel(true);
287                                                        }
288                                                        // IE reports a left click as 1, where everything else reports 0
289                                                        if(e.button === (has('ie') < 9 ? 1 : 0)){
290                                                                Source.prototype.onMouseDown.call(this.source, e);
291                                                        }
292                                                }
293                                        }),
294                                        onMouseOver: lang.hitch(this, function(e){
295                                                var src = this.source;
296                                                if(src._getChildByEvent(e)){
297                                                        Source.prototype.onMouseOver.apply(src, arguments);
298                                                }
299                                        }),
300                                        _markTargetAnchor: lang.hitch(this, function(before){
301                                                var src = this.source;
302                                                if(src.current == src.targetAnchor && src.before == before){ return; }
303                                                if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
304                                                        src._removeItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
305                                                }
306                                                Source.prototype._markTargetAnchor.call(src, before);
307                                               
308                                                var target = before ? src.targetAnchor : getSibling(src.targetAnchor, src.before);
309                                                var endAdd = 0;
310
311                                                if (!target) {
312                                                        target = src.targetAnchor;
313                                                        endAdd = html.contentBox(target).w + this.arrowDim.w/2 + 2;
314                                                }
315
316                                                var pos = html.position(target, true);
317                                                var left = Math.floor(pos.x - this.arrowDim.w/2 + endAdd);
318
319                                                html.style(this.bottomMarker, "visibility", "visible");
320                                                html.style(this.topMarker, "visibility", "visible");
321                                                html.style(this.bottomMarker, {
322                                                        "left": left + "px",
323                                                        "top" : (headerHeight + pos.y) + "px"
324                                                });
325
326                                                html.style(this.topMarker, {
327                                                        "left": left + "px",
328                                                        "top" : (pos.y - this.arrowDim.h) + "px"
329                                                });
330
331                                                if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
332                                                        src._addItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
333                                                }
334                                        }),
335                                        _unmarkTargetAnchor: lang.hitch(this, function(){
336                                                var src = this.source;
337                                                if(!src.targetAnchor){ return; }
338                                                if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
339                                                        src._removeItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
340                                                }
341                                                this._hide(this.bottomMarker);
342                                                this._hide(this.topMarker);
343                                                Source.prototype._unmarkTargetAnchor.call(src);
344                                        }),
345                                        destroy: lang.hitch(this, function(){
346                                                connect.disconnect(this._source_conn);
347                                                connect.unsubscribe(this._source_sub);
348                                                Source.prototype.destroy.call(this.source);
349                                                if(this.bottomMarker){
350                                                        html.destroy(this.bottomMarker);
351                                                        delete this.bottomMarker;
352                                                }
353                                                if(this.topMarker){
354                                                        html.destroy(this.topMarker);
355                                                        delete this.topMarker;
356                                                }
357                                        }),
358                                        onDndCancel: lang.hitch(this, function(){
359                                                Source.prototype.onDndCancel.call(this.source);
360                                                this._hide(this.bottomMarker);
361                                                this._hide(this.topMarker);
362                                        })
363                                });
364
365                                this._source_conn = connect.connect(this.source, "onDndDrop", this, "_onDndDrop");
366                                this._source_sub = connect.subscribe("/dnd/drop/before", this, "_onDndDropBefore");
367                                this.source.startup();
368                        }
369                },
370               
371                _hide: function(node){
372                        html.style(node, {
373                                top: "-10000px",
374                                "visibility": "hidden"
375                        });
376                },
377
378                _onDndDropBefore: function(source, nodes, copy){
379                        if(Manager.manager().target !== this.source){
380                                return;
381                        }
382                        this.source._targetNode = this.source.targetAnchor;
383                        this.source._beforeTarget = this.source.before;
384                        var views = this.grid.views.views;
385                        var srcView = views[source.viewIndex];
386                        var tgtView = views[this.index];
387                        if(tgtView != srcView){
388                                srcView.convertColPctToFixed();
389                                tgtView.convertColPctToFixed();
390                        }
391                },
392
393                _onDndDrop: function(source, nodes, copy){
394                        if(Manager.manager().target !== this.source){
395                                if(Manager.manager().source === this.source){
396                                        this._removingColumn = true;
397                                }
398                                return;
399                        }
400                        this._hide(this.bottomMarker);
401                        this._hide(this.topMarker);
402
403                        var getIdx = function(n){
404                                return n ? html.attr(n, "idx") : null;
405                        };
406                        var w = html.marginBox(nodes[0]).w;
407                        if(source.viewIndex !== this.index){
408                                var views = this.grid.views.views;
409                                var srcView = views[source.viewIndex];
410                                var tgtView = views[this.index];
411                                if(srcView.viewWidth && srcView.viewWidth != "auto"){
412                                        srcView.setColumnsWidth(srcView.getColumnsWidth() - w);
413                                }
414                                if(tgtView.viewWidth && tgtView.viewWidth != "auto"){
415                                        tgtView.setColumnsWidth(tgtView.getColumnsWidth());
416                                }
417                        }
418                        var stn = this.source._targetNode;
419                        var stb = this.source._beforeTarget;
420                        !this.grid.isLeftToRight() && (stb = !stb);
421                        var layout = this.grid.layout;
422                        var idx = this.index;
423                        delete this.source._targetNode;
424                        delete this.source._beforeTarget;
425                       
426                        layout.moveColumn(
427                                source.viewIndex,
428                                idx,
429                                getIdx(nodes[0]),
430                                getIdx(stn),
431                                stb);
432                },
433
434                renderHeader: function(){
435                        this.headerContentNode.innerHTML = this.header.generateHtml(this._getHeaderContent);
436                        if(this.flexCells){
437                                this.contentWidth = this.getContentWidth();
438                                this.headerContentNode.firstChild.style.width = this.contentWidth;
439                        }
440                        util.fire(this, "onAfterRow", [-1, this.structure.cells, this.headerContentNode]);
441                },
442
443                // note: not called in 'view' context
444                _getHeaderContent: function(inCell){
445                        var n = inCell.name || inCell.grid.getCellName(inCell);
446                        if(/^\s+$/.test(n)){
447                                n = '&nbsp;'//otherwise arrow styles will be messed up
448                        }
449                        var ret = [ '<div class="dojoxGridSortNode' ];
450                       
451                        if(inCell.index != inCell.grid.getSortIndex()){
452                                ret.push('">');
453                        }else{
454                                ret = ret.concat([ ' ',
455                                                        inCell.grid.sortInfo > 0 ? 'dojoxGridSortUp' : 'dojoxGridSortDown',
456                                                        '"><div class="dojoxGridArrowButtonChar">',
457                                                        inCell.grid.sortInfo > 0 ? '&#9650;' : '&#9660;',
458                                                        '</div><div class="dojoxGridArrowButtonNode" role="presentation"></div>',
459                                                        '<div class="dojoxGridColCaption">']);
460                        }
461                        ret = ret.concat([n, '</div></div>']);
462                        return ret.join('');
463                },
464
465                resize: function(){
466                        this.adaptHeight();
467                        this.adaptWidth();
468                },
469
470                hasHScrollbar: function(reset){
471                        var hadScroll = this._hasHScroll||false;
472                        if(this._hasHScroll == undefined || reset){
473                                if(this.noscroll){
474                                        this._hasHScroll = false;
475                                }else{
476                                        var style = html.style(this.scrollboxNode, "overflow");
477                                        if(style == "hidden"){
478                                                this._hasHScroll = false;
479                                        }else if(style == "scroll"){
480                                                this._hasHScroll = true;
481                                        }else{
482                                                this._hasHScroll = (this.scrollboxNode.offsetWidth - this.getScrollbarWidth() < this.contentNode.offsetWidth );
483                                        }
484                                }
485                        }
486                        if(hadScroll !== this._hasHScroll){
487                                this.grid.update();
488                        }
489                        return this._hasHScroll; // Boolean
490                },
491
492                hasVScrollbar: function(reset){
493                        var hadScroll = this._hasVScroll||false;
494                        if(this._hasVScroll == undefined || reset){
495                                if(this.noscroll){
496                                        this._hasVScroll = false;
497                                }else{
498                                        var style = html.style(this.scrollboxNode, "overflow");
499                                        if(style == "hidden"){
500                                                this._hasVScroll = false;
501                                        }else if(style == "scroll"){
502                                                this._hasVScroll = true;
503                                        }else{
504                                                this._hasVScroll = (this.scrollboxNode.scrollHeight > this.scrollboxNode.clientHeight);
505                                        }
506                                }
507                        }
508                        if(hadScroll !== this._hasVScroll){
509                                this.grid.update();
510                        }
511                        return this._hasVScroll; // Boolean
512                },
513               
514                convertColPctToFixed: function(){
515                        // Fix any percentage widths to be pixel values
516                        var hasPct = false;
517                        this.grid.initialWidth = "";
518                        var cellNodes = query("th", this.headerContentNode);
519                        var fixedWidths = array.map(cellNodes, function(c, vIdx){
520                                var w = c.style.width;
521                                html.attr(c, "vIdx", vIdx);
522                                if(w && w.slice(-1) == "%"){
523                                        hasPct = true;
524                                }else if(w && w.slice(-2) == "px"){
525                                        return window.parseInt(w, 10);
526                                }
527                                return html.contentBox(c).w;
528                        });
529                        if(hasPct){
530                                array.forEach(this.grid.layout.cells, function(cell, idx){
531                                        if(cell.view == this){
532                                                var cellNode = cell.view.getHeaderCellNode(cell.index);
533                                                if(cellNode && html.hasAttr(cellNode, "vIdx")){
534                                                        var vIdx = window.parseInt(html.attr(cellNode, "vIdx"));
535                                                        this.setColWidth(idx, fixedWidths[vIdx]);
536                                                        html.removeAttr(cellNode, "vIdx");
537                                                }
538                                        }
539                                }, this);
540                                return true;
541                        }
542                        return false;
543                },
544
545                adaptHeight: function(minusScroll){
546                        if(!this.grid._autoHeight){
547                                var h = (this.domNode.style.height && parseInt(this.domNode.style.height.replace(/px/,''), 10)) || this.domNode.clientHeight;
548                                var self = this;
549                                var checkOtherViewScrollers = function(){
550                                        var v;
551                                        for(var i in self.grid.views.views){
552                                                v = self.grid.views.views[i];
553                                                if(v !== self && v.hasHScrollbar()){
554                                                        return true;
555                                                }
556                                        }
557                                        return false;
558                                };
559                                if(minusScroll || (this.noscroll && checkOtherViewScrollers())){
560                                        h -= metrics.getScrollbar().h;
561                                }
562                                util.setStyleHeightPx(this.scrollboxNode, h);
563                        }
564                        this.hasVScrollbar(true);
565                },
566
567                adaptWidth: function(){
568                        if(this.flexCells){
569                                // the view content width
570                                this.contentWidth = this.getContentWidth();
571                                this.headerContentNode.firstChild.style.width = this.contentWidth;
572                        }
573                        // FIXME: it should be easier to get w from this.scrollboxNode.clientWidth,
574                        // but clientWidth seemingly does not include scrollbar width in some cases
575                        var w = this.scrollboxNode.offsetWidth - this.getScrollbarWidth();
576                        if(!this._removingColumn){
577                                w = Math.max(w, this.getColumnsWidth()) + 'px';
578                        }else{
579                                w = Math.min(w, this.getColumnsWidth()) + 'px';
580                                this._removingColumn = false;
581                        }
582                        var cn = this.contentNode;
583                        cn.style.width = w;
584                        this.hasHScrollbar(true);
585                },
586
587                setSize: function(w, h){
588                        var ds = this.domNode.style;
589                        var hs = this.headerNode.style;
590
591                        if(w){
592                                ds.width = w;
593                                hs.width = w;
594                        }
595                        ds.height = (h >= 0 ? h + 'px' : '');
596                },
597
598                renderRow: function(inRowIndex){
599                        var rowNode = this.createRowNode(inRowIndex);
600                        this.buildRow(inRowIndex, rowNode);
601                        //this.grid.edit.restore(this, inRowIndex);
602                        return rowNode;
603                },
604
605                createRowNode: function(inRowIndex){
606                        var node = document.createElement("div");
607                        node.className = this.classTag + 'Row';
608                        if (this instanceof dojox.grid._RowSelector){
609                                html.attr(node,"role","presentation");
610                        }else{
611                                html.attr(node,"role","row");
612                                if (this.grid.selectionMode != "none") {
613                                        node.setAttribute("aria-selected", "false"); //rows can be selected so add aria-selected prop
614                                }
615                        }
616                        node[util.gridViewTag] = this.id;
617                        node[util.rowIndexTag] = inRowIndex;
618                        this.rowNodes[inRowIndex] = node;
619                        return node;
620                },
621
622                buildRow: function(inRowIndex, inRowNode){
623                       
624                        this.buildRowContent(inRowIndex, inRowNode);
625                       
626                        this.styleRow(inRowIndex, inRowNode);
627                 
628                 
629                },
630
631                buildRowContent: function(inRowIndex, inRowNode){
632                        inRowNode.innerHTML = this.content.generateHtml(inRowIndex, inRowIndex);
633                        if(this.flexCells && this.contentWidth){
634                                // FIXME: accessing firstChild here breaks encapsulation
635                                inRowNode.firstChild.style.width = this.contentWidth;
636                        }
637                        util.fire(this, "onAfterRow", [inRowIndex, this.structure.cells, inRowNode]);
638                },
639
640                rowRemoved:function(inRowIndex){
641                        if(inRowIndex >= 0){
642                                this._cleanupRowWidgets(this.getRowNode(inRowIndex));
643                        }
644                        this.grid.edit.save(this, inRowIndex);
645                        delete this.rowNodes[inRowIndex];
646                },
647
648                getRowNode: function(inRowIndex){
649                        return this.rowNodes[inRowIndex];
650                },
651
652                getCellNode: function(inRowIndex, inCellIndex){
653                        var row = this.getRowNode(inRowIndex);
654                        if(row){
655                                return this.content.getCellNode(row, inCellIndex);
656                        }
657                },
658
659                getHeaderCellNode: function(inCellIndex){
660                        if(this.headerContentNode){
661                                return this.header.getCellNode(this.headerContentNode, inCellIndex);
662                        }
663                },
664
665                // styling
666                styleRow: function(inRowIndex, inRowNode){
667                        inRowNode._style = getStyleText(inRowNode);
668                        this.styleRowNode(inRowIndex, inRowNode);
669                },
670
671                styleRowNode: function(inRowIndex, inRowNode){
672                        if(inRowNode){
673                                this.doStyleRowNode(inRowIndex, inRowNode);
674                        }
675                },
676
677                doStyleRowNode: function(inRowIndex, inRowNode){
678                        this.grid.styleRowNode(inRowIndex, inRowNode);
679                },
680
681                // updating
682                updateRow: function(inRowIndex){
683                        var rowNode = this.getRowNode(inRowIndex);
684                        if(rowNode){
685                                rowNode.style.height = '';
686                                this.buildRow(inRowIndex, rowNode);
687                        }
688                        return rowNode;
689                },
690
691                updateRowStyles: function(inRowIndex){
692                        this.styleRowNode(inRowIndex, this.getRowNode(inRowIndex));
693                },
694
695                // scrolling
696                lastTop: 0,
697                firstScroll:0,
698                _nativeScroll: false,
699
700                doscroll: function(inEvent){
701                        if(has('ff') >= 13 || has('chrome')){
702                                this._nativeScroll = true;
703                        }
704                        //var s = dojo.marginBox(this.headerContentNode.firstChild);
705                        var isLtr = this.grid.isLeftToRight();
706                        if(this.firstScroll < 2){
707                                if((!isLtr && this.firstScroll == 1) || (isLtr && this.firstScroll === 0)){
708                                        var s = html.marginBox(this.headerNodeContainer);
709                                        if(has('ie')){
710                                                this.headerNodeContainer.style.width = s.w + this.getScrollbarWidth() + 'px';
711                                        }else if(has('mozilla')){
712                                                //TODO currently only for FF, not sure for safari and opera
713                                                this.headerNodeContainer.style.width = s.w - this.getScrollbarWidth() + 'px';
714                                                //this.headerNodeContainer.style.width = s.w + 'px';
715                                                //set scroll to right in FF
716                                                this.scrollboxNode.scrollLeft = isLtr ?
717                                                        this.scrollboxNode.clientWidth - this.scrollboxNode.scrollWidth :
718                                                        this.scrollboxNode.scrollWidth - this.scrollboxNode.clientWidth;
719                                        }
720                                }
721                                this.firstScroll++;
722                        }
723                        this.headerNode.scrollLeft = this.scrollboxNode.scrollLeft;
724                        // 'lastTop' is a semaphore to prevent feedback-loop with setScrollTop below
725                        var top = this.scrollboxNode.scrollTop;
726                        if(top !== this.lastTop){
727                                this.grid.scrollTo(top);
728                        }
729                        this._nativeScroll = false;
730                },
731
732                setScrollTop: function(inTop){
733                        // 'lastTop' is a semaphore to prevent feedback-loop with doScroll above
734                        this.lastTop = inTop;
735                        if(!this._nativeScroll){
736                                //fix #15487
737                                this.scrollboxNode.scrollTop = inTop;
738                        }
739                        return this.scrollboxNode.scrollTop;
740                },
741
742                // event handlers (direct from DOM)
743                doContentEvent: function(e){
744                        if(this.content.decorateEvent(e)){
745                                this.grid.onContentEvent(e);
746                        }
747                },
748
749                doHeaderEvent: function(e){
750                        if(this.header.decorateEvent(e)){
751                                this.grid.onHeaderEvent(e);
752                        }
753                },
754
755                // event dispatch(from Grid)
756                dispatchContentEvent: function(e){
757                        return this.content.dispatchEvent(e);
758                },
759
760                dispatchHeaderEvent: function(e){
761                        return this.header.dispatchEvent(e);
762                },
763
764                // column resizing
765                setColWidth: function(inIndex, inWidth){
766                        this.grid.setCellWidth(inIndex, inWidth + 'px');
767                },
768
769                update: function(){
770                        if(!this.domNode){
771                                return;
772                        }
773                        this.content.update();
774                        this.grid.update();
775                        //get scroll after update or scroll left setting goes wrong on IE.
776                        //See trac: #8040
777                        var left = this.scrollboxNode.scrollLeft;
778                        this.scrollboxNode.scrollLeft = left;
779                        this.headerNode.scrollLeft = left;
780                }
781        });
782
783        var _GridAvatar = declare("dojox.grid._GridAvatar", Avatar, {
784                construct: function(){
785                        var dd = win.doc;
786
787                        var a = dd.createElement("table");
788                        a.cellPadding = a.cellSpacing = "0";
789                        a.className = "dojoxGridDndAvatar";
790                        a.style.position = "absolute";
791                        a.style.zIndex = 1999;
792                        a.style.margin = "0px"; // to avoid dojo.marginBox() problems with table's margins
793                        var b = dd.createElement("tbody");
794                        var tr = dd.createElement("tr");
795                        var td = dd.createElement("td");
796                        var img = dd.createElement("td");
797                        tr.className = "dojoxGridDndAvatarItem";
798                        img.className = "dojoxGridDndAvatarItemImage";
799                        img.style.width = "16px";
800                        var source = this.manager.source, node;
801                        if(source.creator){
802                                // create an avatar representation of the node
803                                node = source._normalizedCreator(source.getItem(this.manager.nodes[0].id).data, "avatar").node;
804                        }else{
805                                // or just clone the node and hope it works
806                                node = this.manager.nodes[0].cloneNode(true);
807                                var table, tbody;
808                                if(node.tagName.toLowerCase() == "tr"){
809                                        // insert extra table nodes
810                                        table = dd.createElement("table");
811                                        tbody = dd.createElement("tbody");
812                                        tbody.appendChild(node);
813                                        table.appendChild(tbody);
814                                        node = table;
815                                }else if(node.tagName.toLowerCase() == "th"){
816                                        // insert extra table nodes
817                                        table = dd.createElement("table");
818                                        tbody = dd.createElement("tbody");
819                                        var r = dd.createElement("tr");
820                                        table.cellPadding = table.cellSpacing = "0";
821                                        r.appendChild(node);
822                                        tbody.appendChild(r);
823                                        table.appendChild(tbody);
824                                        node = table;
825                                }
826                        }
827                        node.id = "";
828                        td.appendChild(node);
829                        tr.appendChild(img);
830                        tr.appendChild(td);
831                        html.style(tr, "opacity", 0.9);
832                        b.appendChild(tr);
833
834                        a.appendChild(b);
835                        this.node = a;
836
837                        var m = Manager.manager();
838                        this.oldOffsetY = m.OFFSET_Y;
839                        m.OFFSET_Y = 1;
840                },
841                destroy: function(){
842                        Manager.manager().OFFSET_Y = this.oldOffsetY;
843                        this.inherited(arguments);
844                }
845        });
846
847        var oldMakeAvatar = Manager.manager().makeAvatar;
848        Manager.manager().makeAvatar = function(){
849                var src = this.source;
850                if(src.viewIndex !== undefined && !html.hasClass(win.body(),"dijit_a11y")){
851                        return new _GridAvatar(this);
852                }
853                return oldMakeAvatar.call(Manager.manager());
854        };
855
856        return _View;
857
858});
Note: See TracBrowser for help on using the repository browser.