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