~andreserl/maas/packaging_precise_rebase

« back to all changes in this revision

Viewing changes to debian/extras/jslibs/yui/datatable-base-deprecated/datatable-base-deprecated.js

  • Committer: Andres Rodriguez
  • Date: 2013-03-20 18:12:30 UTC
  • mfrom: (145.2.22 precise.sru)
  • Revision ID: andreserl@ubuntu.com-20130320181230-6l5guc0nhlv2z4p7
Re-base againts latest quantal released branch towards SRU

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
YUI 3.5.1 (build 22)
 
3
Copyright 2012 Yahoo! Inc. All rights reserved.
 
4
Licensed under the BSD License.
 
5
http://yuilibrary.com/license/
 
6
*/
 
7
YUI.add('datatable-base-deprecated', function(Y) {
 
8
 
 
9
var YLang = Y.Lang,
 
10
    YisValue = YLang.isValue,
 
11
    fromTemplate = Y.Lang.sub,
 
12
    YNode = Y.Node,
 
13
    Ycreate = YNode.create,
 
14
    YgetClassName = Y.ClassNameManager.getClassName,
 
15
 
 
16
    DATATABLE = "datatable",
 
17
    COLUMN = "column",
 
18
    
 
19
    FOCUS = "focus",
 
20
    KEYDOWN = "keydown",
 
21
    MOUSEENTER = "mouseenter",
 
22
    MOUSELEAVE = "mouseleave",
 
23
    MOUSEUP = "mouseup",
 
24
    MOUSEDOWN = "mousedown",
 
25
    CLICK = "click",
 
26
    DBLCLICK = "dblclick",
 
27
 
 
28
    CLASS_COLUMNS = YgetClassName(DATATABLE, "columns"),
 
29
    CLASS_DATA = YgetClassName(DATATABLE, "data"),
 
30
    CLASS_MSG = YgetClassName(DATATABLE, "msg"),
 
31
    CLASS_LINER = YgetClassName(DATATABLE, "liner"),
 
32
    CLASS_FIRST = YgetClassName(DATATABLE, "first"),
 
33
    CLASS_LAST = YgetClassName(DATATABLE, "last"),
 
34
    CLASS_EVEN = YgetClassName(DATATABLE, "even"),
 
35
    CLASS_ODD = YgetClassName(DATATABLE, "odd"),
 
36
 
 
37
    TEMPLATE_TABLE = '<table></table>',
 
38
    TEMPLATE_COL = '<col></col>',
 
39
    TEMPLATE_THEAD = '<thead class="'+CLASS_COLUMNS+'"></thead>',
 
40
    TEMPLATE_TBODY = '<tbody class="'+CLASS_DATA+'"></tbody>',
 
41
    TEMPLATE_TH = '<th id="{id}" rowspan="{rowspan}" colspan="{colspan}" class="{classnames}" abbr="{abbr}"><div class="'+CLASS_LINER+'">{value}</div></th>',
 
42
    TEMPLATE_TR = '<tr id="{id}"></tr>',
 
43
    TEMPLATE_TD = '<td headers="{headers}" class="{classnames}"><div class="'+CLASS_LINER+'">{value}</div></td>',
 
44
    TEMPLATE_VALUE = '{value}',
 
45
    TEMPLATE_MSG = '<tbody class="'+CLASS_MSG+'"></tbody>';
 
46
    
 
47
 
 
48
 
 
49
/**
 
50
 * The Column class defines and manages attributes of Columns for DataTable.
 
51
 *
 
52
 * @class Column
 
53
 * @extends Widget
 
54
 * @constructor
 
55
 */
 
56
function Column(config) {
 
57
    Column.superclass.constructor.apply(this, arguments);
 
58
}
 
59
 
 
60
/////////////////////////////////////////////////////////////////////////////
 
61
//
 
62
// STATIC PROPERTIES
 
63
//
 
64
/////////////////////////////////////////////////////////////////////////////
 
65
Y.mix(Column, {
 
66
    /**
 
67
     * Class name.
 
68
     *
 
69
     * @property NAME
 
70
     * @type {String}
 
71
     * @static
 
72
     * @final
 
73
     * @value "column"
 
74
     */
 
75
    NAME: "column",
 
76
 
 
77
/////////////////////////////////////////////////////////////////////////////
 
78
//
 
79
// ATTRIBUTES
 
80
//
 
81
/////////////////////////////////////////////////////////////////////////////
 
82
    ATTRS: {
 
83
        /**
 
84
        Unique internal identifier, used to stamp ID on TH element.
 
85
        
 
86
        @attribute id
 
87
        @type {String}
 
88
        @readOnly
 
89
        **/
 
90
        id: {
 
91
            valueFn: "_defaultId",
 
92
            readOnly: true
 
93
        },
 
94
        
 
95
        /**
 
96
        User-supplied identifier. Defaults to id.
 
97
        @attribute key
 
98
        @type {String}
 
99
        **/
 
100
        key: {
 
101
            valueFn: "_defaultKey"
 
102
        },
 
103
 
 
104
        /**
 
105
        Points to underlying data field (for sorting or formatting, for
 
106
        example). Useful when column doesn't hold any data itself, but is just
 
107
        a visual representation of data from another column or record field.
 
108
        Defaults to key.
 
109
 
 
110
        @attribute field
 
111
        @type {String}
 
112
        @default (column key)
 
113
        **/
 
114
        field: {
 
115
            valueFn: "_defaultField"
 
116
        },
 
117
 
 
118
        /**
 
119
        Display label for column header. Defaults to key.
 
120
 
 
121
        @attribute label
 
122
        @type {String}
 
123
        **/
 
124
        label: {
 
125
            valueFn: "_defaultLabel"
 
126
        },
 
127
        
 
128
        /**
 
129
        Array of child column definitions (for nested headers).
 
130
 
 
131
        @attribute children
 
132
        @type {String}
 
133
        @default null
 
134
        **/
 
135
        children: {
 
136
            value: null
 
137
        },
 
138
        
 
139
        /**
 
140
        TH abbr attribute.
 
141
 
 
142
        @attribute abbr
 
143
        @type {String}
 
144
        @default ""
 
145
        **/
 
146
        abbr: {
 
147
            value: ""
 
148
        },
 
149
 
 
150
        //TODO: support custom classnames
 
151
        // TH CSS classnames
 
152
        classnames: {
 
153
            readOnly: true,
 
154
            getter: "_getClassnames"
 
155
        },
 
156
        
 
157
        /**
 
158
        Formating template string or function for cells in this column.
 
159
 
 
160
        Function formatters receive a single object (described below) and are
 
161
        expected to output the `innerHTML` of the cell.
 
162
 
 
163
        String templates can include markup and {placeholder} tokens to be
 
164
        filled in from the object passed to function formatters.
 
165
 
 
166
        @attribute formatter
 
167
        @type {String|Function}
 
168
        @param {Object} data Data relevant to the rendering of this cell
 
169
            @param {String} data.classnames CSS classes to add to the cell
 
170
            @param {Column} data.column This Column instance
 
171
            @param {Object} data.data The raw object data from the Record
 
172
            @param {String} data.field This Column's "field" attribute value
 
173
            @param {String} data.headers TH ids to reference in the cell's
 
174
                            "headers" attribute
 
175
            @param {Record} data.record The Record instance for this row
 
176
            @param {Number} data.rowindex The index for this row
 
177
            @param {Node}   data.tbody The TBODY Node that will house the cell
 
178
            @param {Node}   data.tr The row TR Node that will house the cell
 
179
            @param {Any}    data.value The raw Record data for this cell
 
180
        **/
 
181
        formatter: {},
 
182
 
 
183
        /**
 
184
        The default markup to display in cells that have no corresponding record
 
185
        data or content from formatters.
 
186
 
 
187
        @attribute emptyCellValue
 
188
        @type {String}
 
189
        @default ''
 
190
        **/
 
191
        emptyCellValue: {
 
192
            value: '',
 
193
            validator: Y.Lang.isString
 
194
        },
 
195
 
 
196
        //requires datatable-sort
 
197
        sortable: {
 
198
            value: false
 
199
        },
 
200
        //sortOptions:defaultDir, sortFn, field
 
201
 
 
202
        //TODO: support editable columns
 
203
        // Column editor
 
204
        editor: {},
 
205
 
 
206
        //TODO: support resizeable columns
 
207
        //TODO: support setting widths
 
208
        // requires datatable-colresize
 
209
        width: {},
 
210
        resizeable: {},
 
211
        minimized: {},
 
212
        minWidth: {},
 
213
        maxAutoWidth: {}
 
214
    }
 
215
});
 
216
 
 
217
/////////////////////////////////////////////////////////////////////////////
 
218
//
 
219
// PROTOTYPE
 
220
//
 
221
/////////////////////////////////////////////////////////////////////////////
 
222
Y.extend(Column, Y.Widget, {
 
223
    /////////////////////////////////////////////////////////////////////////////
 
224
    //
 
225
    // ATTRIBUTE HELPERS
 
226
    //
 
227
    /////////////////////////////////////////////////////////////////////////////
 
228
    /**
 
229
    * Return ID for instance.
 
230
    *
 
231
    * @method _defaultId
 
232
    * @return {String}
 
233
    * @private
 
234
    */
 
235
    _defaultId: function() {
 
236
        return Y.guid();
 
237
    },
 
238
 
 
239
    /**
 
240
    * Return key for instance. Defaults to ID if one was not provided.
 
241
    *
 
242
    * @method _defaultKey
 
243
    * @return {String}
 
244
    * @private
 
245
    */
 
246
    _defaultKey: function() {
 
247
        return Y.guid();
 
248
    },
 
249
 
 
250
    /**
 
251
    * Return field for instance. Defaults to key if one was not provided.
 
252
    *
 
253
    * @method _defaultField
 
254
    * @return {String}
 
255
    * @private
 
256
    */
 
257
    _defaultField: function() {
 
258
        return this.get("key");
 
259
    },
 
260
 
 
261
    /**
 
262
    * Return label for instance. Defaults to key if one was not provided.
 
263
    *
 
264
    * @method _defaultLabel
 
265
    * @return {String}
 
266
    * @private
 
267
    */
 
268
    _defaultLabel: function() {
 
269
        return this.get("key");
 
270
    },
 
271
 
 
272
    /**
 
273
     * Updates the UI if changes are made to abbr.
 
274
     *
 
275
     * @method _afterAbbrChange
 
276
     * @param e {Event} Custom event for the attribute change.
 
277
     * @private
 
278
     */
 
279
    _afterAbbrChange: function (e) {
 
280
        this._uiSetAbbr(e.newVal);
 
281
    },
 
282
 
 
283
    /////////////////////////////////////////////////////////////////////////////
 
284
    //
 
285
    // PROPERTIES
 
286
    //
 
287
    /////////////////////////////////////////////////////////////////////////////
 
288
    /**
 
289
     * Reference to Column's current position index within its Columnset's keys
 
290
     * array, if applicable. This property only applies to non-nested and bottom-
 
291
     * level child Columns. Value is set by Columnset code.
 
292
     *
 
293
     * @property keyIndex
 
294
     * @type {Number}
 
295
     */
 
296
    keyIndex: null,
 
297
    
 
298
    /**
 
299
    * Array of TH IDs associated with this column, for TD "headers" attribute.
 
300
    * Value is set by Columnset code
 
301
    *
 
302
    * @property headers
 
303
    * @type {String[]}
 
304
    */
 
305
    headers: null,
 
306
 
 
307
    /**
 
308
     * Number of cells the header spans. Value is set by Columnset code.
 
309
     *
 
310
     * @property colSpan
 
311
     * @type {Number}
 
312
     * @default 1
 
313
     */
 
314
    colSpan: 1,
 
315
    
 
316
    /**
 
317
     * Number of rows the header spans. Value is set by Columnset code.
 
318
     *
 
319
     * @property rowSpan
 
320
     * @type {Number}
 
321
     * @default 1
 
322
     */
 
323
    rowSpan: 1,
 
324
 
 
325
    /**
 
326
     * Column's parent Column instance, if applicable. Value is set by Columnset
 
327
     * code.
 
328
     *
 
329
     * @property parent
 
330
     * @type {Column}
 
331
     */
 
332
    parent: null,
 
333
 
 
334
    /**
 
335
     * The Node reference to the associated TH element.
 
336
     *
 
337
     * @property thNode
 
338
     * @type {Node}
 
339
     */
 
340
     
 
341
    thNode: null,
 
342
 
 
343
    /*TODO
 
344
     * The Node reference to the associated liner element.
 
345
     *
 
346
     * @property thLinerNode
 
347
     * @type {Node}
 
348
     
 
349
    thLinerNode: null,*/
 
350
    
 
351
    /////////////////////////////////////////////////////////////////////////////
 
352
    //
 
353
    // METHODS
 
354
    //
 
355
    /////////////////////////////////////////////////////////////////////////////
 
356
    /**
 
357
    * Initializer.
 
358
    *
 
359
    * @method initializer
 
360
    * @param config {Object} Config object.
 
361
    * @private
 
362
    */
 
363
    initializer: function(config) {
 
364
    },
 
365
 
 
366
    /**
 
367
    * Destructor.
 
368
    *
 
369
    * @method destructor
 
370
    * @private
 
371
    */
 
372
    destructor: function() {
 
373
    },
 
374
 
 
375
    /**
 
376
     * Returns classnames for Column.
 
377
     *
 
378
     * @method _getClassnames
 
379
     * @private
 
380
     */
 
381
    _getClassnames: function () {
 
382
        return Y.ClassNameManager.getClassName(COLUMN, this.get("key").replace(/[^\w\-]/g,""));
 
383
    },
 
384
 
 
385
    ////////////////////////////////////////////////////////////////////////////
 
386
    //
 
387
    // SYNC
 
388
    //
 
389
    ////////////////////////////////////////////////////////////////////////////
 
390
    /**
 
391
    * Syncs UI to intial state.
 
392
    *
 
393
    * @method syncUI
 
394
    * @private
 
395
    */
 
396
    syncUI: function() {
 
397
        this._uiSetAbbr(this.get("abbr"));
 
398
    },
 
399
 
 
400
    /**
 
401
     * Updates abbr.
 
402
     *
 
403
     * @method _uiSetAbbr
 
404
     * @param val {String} New abbr.
 
405
     * @protected
 
406
     */
 
407
    _uiSetAbbr: function(val) {
 
408
        this.thNode.set("abbr", val);
 
409
    }
 
410
});
 
411
 
 
412
Y.Column = Column;
 
413
/**
 
414
 * The Columnset class defines and manages a collection of Columns.
 
415
 *
 
416
 * @class Columnset
 
417
 * @extends Base
 
418
 * @constructor
 
419
 */
 
420
function Columnset(config) {
 
421
    Columnset.superclass.constructor.apply(this, arguments);
 
422
}
 
423
 
 
424
/////////////////////////////////////////////////////////////////////////////
 
425
//
 
426
// STATIC PROPERTIES
 
427
//
 
428
/////////////////////////////////////////////////////////////////////////////
 
429
Y.mix(Columnset, {
 
430
    /**
 
431
     * Class name.
 
432
     *
 
433
     * @property NAME
 
434
     * @type String
 
435
     * @static
 
436
     * @final
 
437
     * @value "columnset"
 
438
     */
 
439
    NAME: "columnset",
 
440
 
 
441
    /////////////////////////////////////////////////////////////////////////////
 
442
    //
 
443
    // ATTRIBUTES
 
444
    //
 
445
    /////////////////////////////////////////////////////////////////////////////
 
446
    ATTRS: {
 
447
        /**
 
448
        * @attribute definitions
 
449
        * @description Array of column definitions that will populate this Columnset.
 
450
        * @type Array
 
451
        */
 
452
        definitions: {
 
453
            setter: "_setDefinitions"
 
454
        }
 
455
 
 
456
    }
 
457
});
 
458
 
 
459
/////////////////////////////////////////////////////////////////////////////
 
460
//
 
461
// PROTOTYPE
 
462
//
 
463
/////////////////////////////////////////////////////////////////////////////
 
464
Y.extend(Columnset, Y.Base, {
 
465
    /////////////////////////////////////////////////////////////////////////////
 
466
    //
 
467
    // ATTRIBUTE HELPERS
 
468
    //
 
469
    /////////////////////////////////////////////////////////////////////////////
 
470
    /**
 
471
    * @method _setDefinitions
 
472
    * @description Clones definitions before setting.
 
473
    * @param definitions {Array} Array of column definitions.
 
474
    * @return Array
 
475
    * @private
 
476
    */
 
477
    _setDefinitions: function(definitions) {
 
478
            return Y.clone(definitions);
 
479
    },
 
480
    
 
481
    /////////////////////////////////////////////////////////////////////////////
 
482
    //
 
483
    // PROPERTIES
 
484
    //
 
485
    /////////////////////////////////////////////////////////////////////////////
 
486
    /**
 
487
     * Top-down tree representation of Column hierarchy. Used to create DOM
 
488
     * elements.
 
489
     *
 
490
     * @property tree
 
491
     * @type {Column[]}
 
492
     */
 
493
    tree: null,
 
494
 
 
495
    /**
 
496
     * Hash of all Columns by ID.
 
497
     *
 
498
     * @property idHash
 
499
     * @type Object
 
500
     */
 
501
    idHash: null,
 
502
 
 
503
    /**
 
504
     * Hash of all Columns by key.
 
505
     *
 
506
     * @property keyHash
 
507
     * @type Object
 
508
     */
 
509
    keyHash: null,
 
510
 
 
511
    /**
 
512
     * Array of only Columns that are meant to be displayed in DOM.
 
513
     *
 
514
     * @property keys
 
515
     * @type {Column[]}
 
516
     */
 
517
    keys: null,
 
518
 
 
519
    /////////////////////////////////////////////////////////////////////////////
 
520
    //
 
521
    // METHODS
 
522
    //
 
523
    /////////////////////////////////////////////////////////////////////////////
 
524
    /**
 
525
    * Initializer. Generates all internal representations of the collection of
 
526
    * Columns.
 
527
    *
 
528
    * @method initializer
 
529
    * @param config {Object} Config object.
 
530
    * @private
 
531
    */
 
532
    initializer: function() {
 
533
 
 
534
        // DOM tree representation of all Columns
 
535
        var tree = [],
 
536
        // Hash of all Columns by ID
 
537
        idHash = {},
 
538
        // Hash of all Columns by key
 
539
        keyHash = {},
 
540
        // Flat representation of only Columns that are meant to display data
 
541
        keys = [],
 
542
        // Original definitions
 
543
        definitions = this.get("definitions"),
 
544
 
 
545
        self = this;
 
546
 
 
547
        // Internal recursive function to define Column instances
 
548
        function parseColumns(depth, currentDefinitions, parent) {
 
549
            var i=0,
 
550
                len = currentDefinitions.length,
 
551
                currentDefinition,
 
552
                column,
 
553
                currentChildren;
 
554
 
 
555
            // One level down
 
556
            depth++;
 
557
 
 
558
            // Create corresponding dom node if not already there for this depth
 
559
            if(!tree[depth]) {
 
560
                tree[depth] = [];
 
561
            }
 
562
 
 
563
            // Parse each node at this depth for attributes and any children
 
564
            for(; i<len; ++i) {
 
565
                currentDefinition = currentDefinitions[i];
 
566
 
 
567
                currentDefinition = YLang.isString(currentDefinition) ? {key:currentDefinition} : currentDefinition;
 
568
 
 
569
                // Instantiate a new Column for each node
 
570
                column = new Y.Column(currentDefinition);
 
571
 
 
572
                // Cross-reference Column ID back to the original object literal definition
 
573
                currentDefinition.yuiColumnId = column.get("id");
 
574
 
 
575
                // Add the new Column to the hash
 
576
                idHash[column.get("id")] = column;
 
577
                keyHash[column.get("key")] = column;
 
578
 
 
579
                // Assign its parent as an attribute, if applicable
 
580
                if(parent) {
 
581
                    column.parent = parent;
 
582
                }
 
583
 
 
584
                // The Column has descendants
 
585
                if(YLang.isArray(currentDefinition.children)) {
 
586
                    currentChildren = currentDefinition.children;
 
587
                    column._set("children", currentChildren);
 
588
 
 
589
                    self._setColSpans(column, currentDefinition);
 
590
 
 
591
                    self._cascadePropertiesToChildren(column, currentChildren);
 
592
 
 
593
                    // The children themselves must also be parsed for Column instances
 
594
                    if(!tree[depth+1]) {
 
595
                        tree[depth+1] = [];
 
596
                    }
 
597
                    parseColumns(depth, currentChildren, column);
 
598
                }
 
599
                // This Column does not have any children
 
600
                else {
 
601
                    column.keyIndex = keys.length;
 
602
                    // Default is already 1
 
603
                    //column.colSpan = 1;
 
604
                    keys.push(column);
 
605
                }
 
606
 
 
607
                // Add the Column to the top-down dom tree
 
608
                tree[depth].push(column);
 
609
            }
 
610
            depth--;
 
611
        }
 
612
 
 
613
        // Parse out Column instances from the array of object literals
 
614
        parseColumns(-1, definitions);
 
615
 
 
616
 
 
617
        // Save to the Columnset instance
 
618
        this.tree = tree;
 
619
        this.idHash = idHash;
 
620
        this.keyHash = keyHash;
 
621
        this.keys = keys;
 
622
 
 
623
        this._setRowSpans();
 
624
        this._setHeaders();
 
625
    },
 
626
 
 
627
    /**
 
628
    * Destructor.
 
629
    *
 
630
    * @method destructor
 
631
    * @private
 
632
    */
 
633
    destructor: function() {
 
634
    },
 
635
 
 
636
    /////////////////////////////////////////////////////////////////////////////
 
637
    //
 
638
    // COLUMN HELPERS
 
639
    //
 
640
    /////////////////////////////////////////////////////////////////////////////
 
641
    /**
 
642
    * Cascade certain properties to children if not defined on their own.
 
643
    *
 
644
    * @method _cascadePropertiesToChildren
 
645
    * @private
 
646
    */
 
647
    _cascadePropertiesToChildren: function(column, currentChildren) {
 
648
        //TODO: this is all a giant todo
 
649
        var i = 0,
 
650
            len = currentChildren.length,
 
651
            child;
 
652
 
 
653
        // Cascade certain properties to children if not defined on their own
 
654
        for(; i<len; ++i) {
 
655
            child = currentChildren[i];
 
656
            if(column.get("className") && (child.className === undefined)) {
 
657
                child.className = column.get("className");
 
658
            }
 
659
            if(column.get("editor") && (child.editor === undefined)) {
 
660
                child.editor = column.get("editor");
 
661
            }
 
662
            if(column.get("formatter") && (child.formatter === undefined)) {
 
663
                child.formatter = column.get("formatter");
 
664
            }
 
665
            if(column.get("resizeable") && (child.resizeable === undefined)) {
 
666
                child.resizeable = column.get("resizeable");
 
667
            }
 
668
            if(column.get("sortable") && (child.sortable === undefined)) {
 
669
                child.sortable = column.get("sortable");
 
670
            }
 
671
            if(column.get("hidden")) {
 
672
                child.hidden = true;
 
673
            }
 
674
            if(column.get("width") && (child.width === undefined)) {
 
675
                child.width = column.get("width");
 
676
            }
 
677
            if(column.get("minWidth") && (child.minWidth === undefined)) {
 
678
                child.minWidth = column.get("minWidth");
 
679
            }
 
680
            if(column.get("maxAutoWidth") && (child.maxAutoWidth === undefined)) {
 
681
                child.maxAutoWidth = column.get("maxAutoWidth");
 
682
            }
 
683
        }
 
684
    },
 
685
 
 
686
    /**
 
687
    * @method _setColSpans
 
688
    * @description Calculates and sets colSpan attribute on given Column.
 
689
    * @param column {Array} Column instance.
 
690
    * @param definition {Object} Column definition.
 
691
    * @private
 
692
    */
 
693
    _setColSpans: function(column, definition) {
 
694
        // Determine COLSPAN value for this Column
 
695
        var terminalChildNodes = 0;
 
696
 
 
697
        function countTerminalChildNodes(ancestor) {
 
698
            var descendants = ancestor.children,
 
699
                i = 0,
 
700
                len = descendants.length;
 
701
 
 
702
            // Drill down each branch and count terminal nodes
 
703
            for(; i<len; ++i) {
 
704
                // Keep drilling down
 
705
                if(YLang.isArray(descendants[i].children)) {
 
706
                    countTerminalChildNodes(descendants[i]);
 
707
                }
 
708
                // Reached branch terminus
 
709
                else {
 
710
                    terminalChildNodes++;
 
711
                }
 
712
            }
 
713
        }
 
714
        countTerminalChildNodes(definition);
 
715
        column.colSpan = terminalChildNodes;
 
716
    },
 
717
 
 
718
    /**
 
719
    * @method _setRowSpans
 
720
    * @description Calculates and sets rowSpan attribute on all Columns.
 
721
    * @private
 
722
    */
 
723
    _setRowSpans: function() {
 
724
        // Determine ROWSPAN value for each Column in the DOM tree
 
725
        function parseDomTreeForRowSpan(tree) {
 
726
            var maxRowDepth = 1,
 
727
                currentRow,
 
728
                currentColumn,
 
729
                m,p;
 
730
 
 
731
            // Calculate the max depth of descendants for this row
 
732
            function countMaxRowDepth(row, tmpRowDepth) {
 
733
                tmpRowDepth = tmpRowDepth || 1;
 
734
 
 
735
                var i = 0,
 
736
                    len = row.length,
 
737
                    col;
 
738
 
 
739
                for(; i<len; ++i) {
 
740
                    col = row[i];
 
741
                    // Column has children, so keep counting
 
742
                    if(YLang.isArray(col.children)) {
 
743
                        tmpRowDepth++;
 
744
                        countMaxRowDepth(col.children, tmpRowDepth);
 
745
                        tmpRowDepth--;
 
746
                    }
 
747
                    // Column has children, so keep counting
 
748
                    else if(col.get && YLang.isArray(col.get("children"))) {
 
749
                        tmpRowDepth++;
 
750
                        countMaxRowDepth(col.get("children"), tmpRowDepth);
 
751
                        tmpRowDepth--;
 
752
                    }
 
753
                    // No children, is it the max depth?
 
754
                    else {
 
755
                        if(tmpRowDepth > maxRowDepth) {
 
756
                            maxRowDepth = tmpRowDepth;
 
757
                        }
 
758
                    }
 
759
                }
 
760
            }
 
761
 
 
762
            // Count max row depth for each row
 
763
            for(m=0; m<tree.length; m++) {
 
764
                currentRow = tree[m];
 
765
                countMaxRowDepth(currentRow);
 
766
 
 
767
                // Assign the right ROWSPAN values to each Column in the row
 
768
                for(p=0; p<currentRow.length; p++) {
 
769
                    currentColumn = currentRow[p];
 
770
                    if(!YLang.isArray(currentColumn.get("children"))) {
 
771
                        currentColumn.rowSpan = maxRowDepth;
 
772
                    }
 
773
                    // Default is already 1
 
774
                    // else currentColumn.rowSpan =1;
 
775
                }
 
776
 
 
777
                // Reset counter for next row
 
778
                maxRowDepth = 1;
 
779
            }
 
780
        }
 
781
        parseDomTreeForRowSpan(this.tree);
 
782
    },
 
783
 
 
784
    /**
 
785
    * @method _setHeaders
 
786
    * @description Calculates and sets headers attribute on all Columns.
 
787
    * @private
 
788
    */
 
789
    _setHeaders: function() {
 
790
        var headers, column,
 
791
            allKeys = this.keys,
 
792
            i=0, len = allKeys.length;
 
793
 
 
794
        function recurseAncestorsForHeaders(headers, column) {
 
795
            headers.push(column.get("id"));
 
796
            if(column.parent) {
 
797
                recurseAncestorsForHeaders(headers, column.parent);
 
798
            }
 
799
        }
 
800
        for(; i<len; ++i) {
 
801
            headers = [];
 
802
            column = allKeys[i];
 
803
            recurseAncestorsForHeaders(headers, column);
 
804
            column.headers = headers.reverse().join(" ");
 
805
        }
 
806
    },
 
807
 
 
808
    //TODO
 
809
    getColumn: function() {
 
810
    }
 
811
});
 
812
 
 
813
Y.Columnset = Columnset;
 
814
/**
 
815
 * The DataTable widget provides a progressively enhanced DHTML control for
 
816
 * displaying tabular data across A-grade browsers.
 
817
 *
 
818
 * @module datatable
 
819
 * @main datatable
 
820
 */
 
821
 
 
822
/**
 
823
 * Provides the base DataTable implementation, which can be extended to add
 
824
 * additional functionality, such as sorting or scrolling.
 
825
 *
 
826
 * @module datatable
 
827
 * @submodule datatable-base
 
828
 */
 
829
 
 
830
/**
 
831
 * Base class for the DataTable widget.
 
832
 * @class DataTable.Base
 
833
 * @extends Widget
 
834
 * @constructor
 
835
 */
 
836
function DTBase(config) {
 
837
    DTBase.superclass.constructor.apply(this, arguments);
 
838
}
 
839
 
 
840
/////////////////////////////////////////////////////////////////////////////
 
841
//
 
842
// STATIC PROPERTIES
 
843
//
 
844
/////////////////////////////////////////////////////////////////////////////
 
845
Y.mix(DTBase, {
 
846
 
 
847
    /**
 
848
     * Class name.
 
849
     *
 
850
     * @property NAME
 
851
     * @type String
 
852
     * @static
 
853
     * @final
 
854
     * @value "dataTable"
 
855
     */
 
856
    NAME:  "dataTable",
 
857
 
 
858
/////////////////////////////////////////////////////////////////////////////
 
859
//
 
860
// ATTRIBUTES
 
861
//
 
862
/////////////////////////////////////////////////////////////////////////////
 
863
    ATTRS: {
 
864
        /**
 
865
        * @attribute columnset
 
866
        * @description Pointer to Columnset instance.
 
867
        * @type Array | Y.Columnset
 
868
        */
 
869
        columnset: {
 
870
            setter: "_setColumnset"
 
871
        },
 
872
 
 
873
        /**
 
874
        * @attribute recordset
 
875
        * @description Pointer to Recordset instance.
 
876
        * @type Array | Y.Recordset
 
877
        */
 
878
        recordset: {
 
879
            valueFn: '_initRecordset',
 
880
            setter: "_setRecordset"
 
881
        },
 
882
 
 
883
        /*TODO
 
884
        * @attribute state
 
885
        * @description Internal state.
 
886
        * @readonly
 
887
        * @type
 
888
        */
 
889
        /*state: {
 
890
            value: new Y.State(),
 
891
            readOnly: true
 
892
 
 
893
        },*/
 
894
 
 
895
        /**
 
896
        * @attribute summary
 
897
        * @description Summary.
 
898
        * @type String
 
899
        */
 
900
        summary: {
 
901
        },
 
902
 
 
903
        /**
 
904
        * @attribute caption
 
905
        * @description Caption
 
906
        * @type String
 
907
        */
 
908
        caption: {
 
909
        },
 
910
 
 
911
        /**
 
912
        * @attribute thValueTemplate
 
913
        * @description Tokenized markup template for TH value.
 
914
        * @type String
 
915
        * @default '{value}'
 
916
        */
 
917
        thValueTemplate: {
 
918
            value: TEMPLATE_VALUE
 
919
        },
 
920
 
 
921
        /**
 
922
        * @attribute tdValueTemplate
 
923
        * @description Tokenized markup template for TD value.
 
924
        * @type String
 
925
        * @default '{value}'
 
926
        */
 
927
        tdValueTemplate: {
 
928
            value: TEMPLATE_VALUE
 
929
        },
 
930
 
 
931
        /**
 
932
        * @attribute trTemplate
 
933
        * @description Tokenized markup template for TR node creation.
 
934
        * @type String
 
935
        * @default '<tr id="{id}"></tr>'
 
936
        */
 
937
        trTemplate: {
 
938
            value: TEMPLATE_TR
 
939
        }
 
940
    },
 
941
 
 
942
/////////////////////////////////////////////////////////////////////////////
 
943
//
 
944
// TODO: HTML_PARSER
 
945
//
 
946
/////////////////////////////////////////////////////////////////////////////
 
947
    HTML_PARSER: {
 
948
        /*caption: function (srcNode) {
 
949
            
 
950
        }*/
 
951
    }
 
952
});
 
953
 
 
954
/////////////////////////////////////////////////////////////////////////////
 
955
//
 
956
// PROTOTYPE
 
957
//
 
958
/////////////////////////////////////////////////////////////////////////////
 
959
Y.extend(DTBase, Y.Widget, {
 
960
    /**
 
961
    * @property thTemplate
 
962
    * @description Tokenized markup template for TH node creation.
 
963
    * @type String
 
964
    * @default '<th id="{id}" rowspan="{rowspan}" colspan="{colspan}" class="{classnames}" abbr="{abbr}"><div class="'+CLASS_LINER+'">{value}</div></th>'
 
965
    */
 
966
    thTemplate: TEMPLATE_TH,
 
967
 
 
968
    /**
 
969
    * @property tdTemplate
 
970
    * @description Tokenized markup template for TD node creation.
 
971
    * @type String
 
972
    * @default '<td headers="{headers}" class="{classnames}"><div class="yui3-datatable-liner">{value}</div></td>'
 
973
    */
 
974
    tdTemplate: TEMPLATE_TD,
 
975
    
 
976
    /**
 
977
    * @property _theadNode
 
978
    * @description Pointer to THEAD node.
 
979
    * @type {Node}
 
980
    * @private
 
981
    */
 
982
    _theadNode: null,
 
983
    
 
984
    /**
 
985
    * @property _tbodyNode
 
986
    * @description Pointer to TBODY node.
 
987
    * @type {Node}
 
988
    * @private
 
989
    */
 
990
    _tbodyNode: null,
 
991
    
 
992
    /**
 
993
    * @property _msgNode
 
994
    * @description Pointer to message display node.
 
995
    * @type {Node}
 
996
    * @private
 
997
    */
 
998
    _msgNode: null,
 
999
 
 
1000
    /////////////////////////////////////////////////////////////////////////////
 
1001
    //
 
1002
    // ATTRIBUTE HELPERS
 
1003
    //
 
1004
    /////////////////////////////////////////////////////////////////////////////
 
1005
    /**
 
1006
    * @method _setColumnset
 
1007
    * @description Converts Array to Y.Columnset.
 
1008
    * @param columns {Array | Y.Columnset}
 
1009
    * @return {Columnset}
 
1010
    * @private
 
1011
    */
 
1012
    _setColumnset: function(columns) {
 
1013
        return YLang.isArray(columns) ? new Y.Columnset({definitions:columns}) : columns;
 
1014
    },
 
1015
 
 
1016
    /**
 
1017
     * Updates the UI if Columnset is changed.
 
1018
     *
 
1019
     * @method _afterColumnsetChange
 
1020
     * @param e {Event} Custom event for the attribute change.
 
1021
     * @protected
 
1022
     */
 
1023
    _afterColumnsetChange: function (e) {
 
1024
        this._uiSetColumnset(e.newVal);
 
1025
    },
 
1026
 
 
1027
    /**
 
1028
    * @method _setRecordset
 
1029
    * @description Converts Array to Y.Recordset.
 
1030
    * @param records {Array | Recordset}
 
1031
    * @return {Recordset}
 
1032
    * @private
 
1033
    */
 
1034
    _setRecordset: function(rs) {
 
1035
        if(YLang.isArray(rs)) {
 
1036
            rs = new Y.Recordset({records:rs});
 
1037
        }
 
1038
 
 
1039
        rs.addTarget(this);
 
1040
        return rs;
 
1041
    },
 
1042
    
 
1043
    /**
 
1044
    * Updates the UI if Recordset is changed.
 
1045
    *
 
1046
    * @method _afterRecordsetChange
 
1047
    * @param e {Event} Custom event for the attribute change.
 
1048
    * @protected
 
1049
    */
 
1050
    _afterRecordsetChange: function (e) {
 
1051
        this._uiSetRecordset(e.newVal);
 
1052
    },
 
1053
 
 
1054
    /**
 
1055
    * Updates the UI if Recordset records are changed.
 
1056
    *
 
1057
    * @method _afterRecordsChange
 
1058
    * @param e {Event} Custom event for the attribute change.
 
1059
    * @protected
 
1060
    */
 
1061
    _afterRecordsChange: function (e) {
 
1062
        this._uiSetRecordset(this.get('recordset'));
 
1063
    },
 
1064
 
 
1065
    /**
 
1066
     * Updates the UI if summary is changed.
 
1067
     *
 
1068
     * @method _afterSummaryChange
 
1069
     * @param e {Event} Custom event for the attribute change.
 
1070
     * @protected
 
1071
     */
 
1072
    _afterSummaryChange: function (e) {
 
1073
        this._uiSetSummary(e.newVal);
 
1074
    },
 
1075
 
 
1076
    /**
 
1077
     * Updates the UI if caption is changed.
 
1078
     *
 
1079
     * @method _afterCaptionChange
 
1080
     * @param e {Event} Custom event for the attribute change.
 
1081
     * @protected
 
1082
     */
 
1083
    _afterCaptionChange: function (e) {
 
1084
        this._uiSetCaption(e.newVal);
 
1085
    },
 
1086
 
 
1087
    ////////////////////////////////////////////////////////////////////////////
 
1088
    //
 
1089
    // METHODS
 
1090
    //
 
1091
    ////////////////////////////////////////////////////////////////////////////
 
1092
 
 
1093
    /**
 
1094
    * Destructor.
 
1095
    *
 
1096
    * @method destructor
 
1097
    * @private
 
1098
    */
 
1099
    destructor: function() {
 
1100
         this.get("recordset").removeTarget(this);
 
1101
    },
 
1102
    
 
1103
    ////////////////////////////////////////////////////////////////////////////
 
1104
    //
 
1105
    // RENDER
 
1106
    //
 
1107
    ////////////////////////////////////////////////////////////////////////////
 
1108
 
 
1109
    /**
 
1110
    * Renders UI.
 
1111
    *
 
1112
    * @method renderUI
 
1113
    * @private
 
1114
    */
 
1115
    renderUI: function() {
 
1116
        // TABLE
 
1117
        this._addTableNode(this.get("contentBox"));
 
1118
 
 
1119
        // COLGROUP
 
1120
        this._addColgroupNode(this._tableNode);
 
1121
 
 
1122
        // THEAD
 
1123
        this._addTheadNode(this._tableNode);
 
1124
 
 
1125
        // Primary TBODY
 
1126
        this._addTbodyNode(this._tableNode);
 
1127
 
 
1128
        // Message TBODY
 
1129
        this._addMessageNode(this._tableNode);
 
1130
 
 
1131
        // CAPTION
 
1132
        this._addCaptionNode(this._tableNode);
 
1133
   },
 
1134
 
 
1135
    /**
 
1136
    * Creates and attaches TABLE element to given container.
 
1137
    *
 
1138
    * @method _addTableNode
 
1139
    * @param containerNode {Node} Parent node.
 
1140
    * @protected
 
1141
    * @return {Node}
 
1142
    */
 
1143
    _addTableNode: function(containerNode) {
 
1144
        if (!this._tableNode) {
 
1145
            this._tableNode = containerNode.appendChild(Ycreate(TEMPLATE_TABLE));
 
1146
        }
 
1147
        return this._tableNode;
 
1148
    },
 
1149
 
 
1150
    /**
 
1151
    * Creates and attaches COLGROUP element to given TABLE.
 
1152
    *
 
1153
    * @method _addColgroupNode
 
1154
    * @param tableNode {Node} Parent node.
 
1155
    * @protected
 
1156
    * @return {Node}
 
1157
    */
 
1158
    _addColgroupNode: function(tableNode) {
 
1159
        // Add COLs to DOCUMENT FRAGMENT
 
1160
        var len = this.get("columnset").keys.length,
 
1161
            i = 0,
 
1162
            allCols = ["<colgroup>"];
 
1163
 
 
1164
        for(; i<len; ++i) {
 
1165
            allCols.push(TEMPLATE_COL);
 
1166
        }
 
1167
 
 
1168
        allCols.push("</colgroup>");
 
1169
 
 
1170
        // Create COLGROUP
 
1171
        this._colgroupNode = tableNode.insertBefore(Ycreate(allCols.join("")), tableNode.get("firstChild"));
 
1172
 
 
1173
        return this._colgroupNode;
 
1174
    },
 
1175
 
 
1176
    /**
 
1177
    * Creates and attaches THEAD element to given container.
 
1178
    *
 
1179
    * @method _addTheadNode
 
1180
    * @param tableNode {Node} Parent node.
 
1181
    * @protected
 
1182
    * @return {Node}
 
1183
    */
 
1184
    _addTheadNode: function(tableNode) {
 
1185
        if(tableNode) {
 
1186
            this._theadNode = tableNode.insertBefore(Ycreate(TEMPLATE_THEAD), this._colgroupNode.next());
 
1187
            return this._theadNode;
 
1188
        }
 
1189
    },
 
1190
 
 
1191
    /**
 
1192
    * Creates and attaches TBODY element to given container.
 
1193
    *
 
1194
    * @method _addTbodyNode
 
1195
    * @param tableNode {Node} Parent node.
 
1196
    * @protected
 
1197
    * @return {Node}
 
1198
    */
 
1199
    _addTbodyNode: function(tableNode) {
 
1200
        this._tbodyNode = tableNode.appendChild(Ycreate(TEMPLATE_TBODY));
 
1201
        return this._tbodyNode;
 
1202
    },
 
1203
 
 
1204
    /**
 
1205
    * Creates and attaches message display element to given container.
 
1206
    *
 
1207
    * @method _addMessageNode
 
1208
    * @param tableNode {Node} Parent node.
 
1209
    * @protected
 
1210
    * @return {Node}
 
1211
    */
 
1212
    _addMessageNode: function(tableNode) {
 
1213
        this._msgNode = tableNode.insertBefore(Ycreate(TEMPLATE_MSG), this._tbodyNode);
 
1214
        return this._msgNode;
 
1215
    },
 
1216
 
 
1217
    /**
 
1218
    * Creates and attaches CAPTION element to given container.
 
1219
    *
 
1220
    * @method _addCaptionNode
 
1221
    * @param tableNode {Node} Parent node.
 
1222
    * @protected
 
1223
    * @return {Node}
 
1224
    */
 
1225
    _addCaptionNode: function(tableNode) {
 
1226
        this._captionNode = Y.Node.create('<caption></caption>');
 
1227
    },
 
1228
 
 
1229
    ////////////////////////////////////////////////////////////////////////////
 
1230
    //
 
1231
    // BIND
 
1232
    //
 
1233
    ////////////////////////////////////////////////////////////////////////////
 
1234
 
 
1235
    /**
 
1236
    * Binds events.
 
1237
    *
 
1238
    * @method bindUI
 
1239
    * @private
 
1240
    */
 
1241
    bindUI: function() {
 
1242
        this.after({
 
1243
            columnsetChange: this._afterColumnsetChange,
 
1244
            summaryChange  : this._afterSummaryChange,
 
1245
            captionChange  : this._afterCaptionChange,
 
1246
            recordsetChange: this._afterRecordsChange,
 
1247
            "recordset:tableChange": this._afterRecordsChange
 
1248
        });
 
1249
    },
 
1250
    
 
1251
    delegate: function(type) {
 
1252
        //TODO: is this necessary?
 
1253
        if(type==="dblclick") {
 
1254
            this.get("boundingBox").delegate.apply(this.get("boundingBox"), arguments);
 
1255
        }
 
1256
        else {
 
1257
            this.get("contentBox").delegate.apply(this.get("contentBox"), arguments);
 
1258
        }
 
1259
    },
 
1260
    
 
1261
 
 
1262
    ////////////////////////////////////////////////////////////////////////////
 
1263
    //
 
1264
    // SYNC
 
1265
    //
 
1266
    ////////////////////////////////////////////////////////////////////////////
 
1267
 
 
1268
    /**
 
1269
    * Syncs UI to intial state.
 
1270
    *
 
1271
    * @method syncUI
 
1272
    * @private
 
1273
    */
 
1274
    syncUI: function() {
 
1275
        // THEAD ROWS
 
1276
        this._uiSetColumnset(this.get("columnset"));
 
1277
        // DATA ROWS
 
1278
        this._uiSetRecordset(this.get("recordset"));
 
1279
        // SUMMARY
 
1280
        this._uiSetSummary(this.get("summary"));
 
1281
        // CAPTION
 
1282
        this._uiSetCaption(this.get("caption"));
 
1283
    },
 
1284
 
 
1285
    /**
 
1286
     * Updates summary.
 
1287
     *
 
1288
     * @method _uiSetSummary
 
1289
     * @param val {String} New summary.
 
1290
     * @protected
 
1291
     */
 
1292
    _uiSetSummary: function(val) {
 
1293
        val = YisValue(val) ? val : "";
 
1294
        this._tableNode.set("summary", val);
 
1295
    },
 
1296
 
 
1297
    /**
 
1298
     * Updates caption.
 
1299
     *
 
1300
     * @method _uiSetCaption
 
1301
     * @param val {String} New caption.
 
1302
     * @protected
 
1303
     */
 
1304
    _uiSetCaption: function(val) {
 
1305
        var caption = this._captionNode,
 
1306
            inDoc   = caption.inDoc(),
 
1307
            method  = val ? (!inDoc && 'prepend') : (inDoc && 'removeChild');
 
1308
 
 
1309
        caption.setContent(val || '');
 
1310
 
 
1311
        if (method) {
 
1312
            // prepend of remove necessary
 
1313
            this._tableNode[method](caption);
 
1314
        }
 
1315
    },
 
1316
 
 
1317
 
 
1318
    ////////////////////////////////////////////////////////////////////////////
 
1319
    //
 
1320
    // THEAD/COLUMNSET FUNCTIONALITY
 
1321
    //
 
1322
    ////////////////////////////////////////////////////////////////////////////
 
1323
    /**
 
1324
     * Updates THEAD.
 
1325
     *
 
1326
     * @method _uiSetColumnset
 
1327
     * @param cs {Columnset} New Columnset.
 
1328
     * @protected
 
1329
     */
 
1330
    _uiSetColumnset: function(cs) {
 
1331
        var tree = cs.tree,
 
1332
            thead = this._theadNode,
 
1333
            i = 0,
 
1334
            len = tree.length,
 
1335
            parent = thead.get("parentNode"),
 
1336
            nextSibling = thead.next();
 
1337
            
 
1338
        // Move THEAD off DOM
 
1339
        thead.remove();
 
1340
        
 
1341
        thead.get("children").remove(true);
 
1342
 
 
1343
        // Iterate tree of columns to add THEAD rows
 
1344
        for(; i<len; ++i) {
 
1345
            this._addTheadTrNode({
 
1346
                thead:   thead,
 
1347
                columns: tree[i],
 
1348
                id     : '' // to avoid {id} leftovers from the trTemplate
 
1349
            }, (i === 0), (i === len - 1));
 
1350
        }
 
1351
 
 
1352
        // Column helpers needs _theadNode to exist
 
1353
        //this._createColumnHelpers();
 
1354
 
 
1355
        
 
1356
        // Re-attach THEAD to DOM
 
1357
        parent.insert(thead, nextSibling);
 
1358
 
 
1359
     },
 
1360
     
 
1361
    /**
 
1362
    * Creates and attaches header row element.
 
1363
    *
 
1364
    * @method _addTheadTrNode
 
1365
    * @param o {Object} {thead, columns}.
 
1366
    * @param isFirst {Boolean} Is first row.
 
1367
    * @param isFirst {Boolean} Is last row.
 
1368
    * @protected
 
1369
    */
 
1370
     _addTheadTrNode: function(o, isFirst, isLast) {
 
1371
        o.tr = this._createTheadTrNode(o, isFirst, isLast);
 
1372
        this._attachTheadTrNode(o);
 
1373
     },
 
1374
     
 
1375
 
 
1376
    /**
 
1377
    * Creates header row element.
 
1378
    *
 
1379
    * @method _createTheadTrNode
 
1380
    * @param o {Object} {thead, columns}.
 
1381
    * @param isFirst {Boolean} Is first row.
 
1382
    * @param isLast {Boolean} Is last row.
 
1383
    * @protected
 
1384
    * @return {Node}
 
1385
    */
 
1386
    _createTheadTrNode: function(o, isFirst, isLast) {
 
1387
        //TODO: custom classnames
 
1388
        var tr = Ycreate(fromTemplate(this.get("trTemplate"), o)),
 
1389
            i = 0,
 
1390
            columns = o.columns,
 
1391
            len = columns.length,
 
1392
            column;
 
1393
 
 
1394
         // Set FIRST/LAST class
 
1395
        if(isFirst) {
 
1396
            tr.addClass(CLASS_FIRST);
 
1397
        }
 
1398
        if(isLast) {
 
1399
            tr.addClass(CLASS_LAST);
 
1400
        }
 
1401
 
 
1402
        for(; i<len; ++i) {
 
1403
            column = columns[i];
 
1404
            this._addTheadThNode({value:column.get("label"), column: column, tr:tr});
 
1405
        }
 
1406
 
 
1407
        return tr;
 
1408
    },
 
1409
 
 
1410
    /**
 
1411
    * Attaches header row element.
 
1412
    *
 
1413
    * @method _attachTheadTrNode
 
1414
    * @param o {Object} {thead, columns, tr}.
 
1415
    * @protected
 
1416
    */
 
1417
    _attachTheadTrNode: function(o) {
 
1418
        o.thead.appendChild(o.tr);
 
1419
    },
 
1420
 
 
1421
    /**
 
1422
    * Creates and attaches header cell element.
 
1423
    *
 
1424
    * @method _addTheadThNode
 
1425
    * @param o {Object} {value, column, tr}.
 
1426
    * @protected
 
1427
    */
 
1428
    _addTheadThNode: function(o) {
 
1429
        o.th = this._createTheadThNode(o);
 
1430
        this._attachTheadThNode(o);
 
1431
        //TODO: assign all node pointers: thNode, thLinerNode, thLabelNode
 
1432
        o.column.thNode = o.th;
 
1433
    },
 
1434
 
 
1435
    /**
 
1436
    * Creates header cell element.
 
1437
    *
 
1438
    * @method _createTheadThNode
 
1439
    * @param o {Object} {value, column, tr}.
 
1440
    * @protected
 
1441
    * @return {Node}
 
1442
    */
 
1443
    _createTheadThNode: function(o) {
 
1444
        var column = o.column;
 
1445
        
 
1446
        // Populate template object
 
1447
        o.id = column.get("id");//TODO: validate 1 column ID per document
 
1448
        o.colspan = column.colSpan;
 
1449
        o.rowspan = column.rowSpan;
 
1450
        o.abbr = column.get("abbr");
 
1451
        o.classnames = column.get("classnames");
 
1452
        o.value = fromTemplate(this.get("thValueTemplate"), o);
 
1453
 
 
1454
        /*TODO
 
1455
        // Clear minWidth on hidden Columns
 
1456
        if(column.get("hidden")) {
 
1457
            //this._clearMinWidth(column);
 
1458
        }
 
1459
        */
 
1460
        
 
1461
        return Ycreate(fromTemplate(this.thTemplate, o));
 
1462
    },
 
1463
 
 
1464
    /**
 
1465
    * Attaches header cell element.
 
1466
    *
 
1467
    * @method _attachTheadThNode
 
1468
    * @param o {Object} {value, column, tr}.
 
1469
    * @protected
 
1470
    */
 
1471
    _attachTheadThNode: function(o) {
 
1472
        o.tr.appendChild(o.th);
 
1473
    },
 
1474
 
 
1475
    ////////////////////////////////////////////////////////////////////////////
 
1476
    //
 
1477
    // TBODY/RECORDSET FUNCTIONALITY
 
1478
    //
 
1479
    ////////////////////////////////////////////////////////////////////////////
 
1480
    /**
 
1481
     * Updates TBODY.
 
1482
     *
 
1483
     * @method _uiSetRecordset
 
1484
     * @param rs {Recordset} New Recordset.
 
1485
     * @protected
 
1486
     */
 
1487
    _uiSetRecordset: function(rs) {
 
1488
        var self = this,
 
1489
            oldTbody = this._tbodyNode,
 
1490
            parent = oldTbody.get("parentNode"),
 
1491
            nextSibling = oldTbody.next(),
 
1492
            columns = this.get('columnset').keys,
 
1493
            cellValueTemplate = this.get('tdValueTemplate'),
 
1494
            o = {},
 
1495
            newTbody, i, len, column, formatter;
 
1496
 
 
1497
        // Replace TBODY with a new one
 
1498
        //TODO: split _addTbodyNode into create/attach
 
1499
        oldTbody.remove();
 
1500
        oldTbody = null;
 
1501
        newTbody = this._addTbodyNode(this._tableNode);
 
1502
        newTbody.remove();
 
1503
        this._tbodyNode = newTbody;
 
1504
        o.tbody = newTbody;
 
1505
 
 
1506
        o.rowTemplate = this.get('trTemplate');
 
1507
        o.columns = [];
 
1508
 
 
1509
        // Build up column data to avoid passing through Attribute APIs inside
 
1510
        // render loops for rows and cells
 
1511
        for (i = columns.length - 1; i >= 0; --i) {
 
1512
            column = columns[i];
 
1513
            o.columns[i] = {
 
1514
                column        : column,
 
1515
                fields        : column.get('field'),
 
1516
                classnames    : column.get('classnames'),
 
1517
                emptyCellValue: column.get('emptyCellValue')
 
1518
            }
 
1519
 
 
1520
            formatter = column.get('formatter');
 
1521
 
 
1522
            if (YLang.isFunction(formatter)) {
 
1523
                // function formatters need to run before checking if the value
 
1524
                // needs defaulting from column.emptyCellValue
 
1525
                formatter = Y.bind(this._functionFormatter, this, formatter);
 
1526
            } else {
 
1527
                if (!YLang.isString(formatter)) {
 
1528
                    formatter = cellValueTemplate;
 
1529
                }
 
1530
 
 
1531
                // string formatters need the value defaulted before processing
 
1532
                formatter = Y.bind(this._templateFormatter, this, formatter);
 
1533
            }
 
1534
 
 
1535
            o.columns[i].formatter = formatter;
 
1536
        }
 
1537
 
 
1538
 
 
1539
        // Iterate Recordset to use existing TR when possible or add new TR
 
1540
        // TODO i = this.get("state.offsetIndex")
 
1541
        // TODO len =this.get("state.pageLength")
 
1542
        for (i = 0, len = rs.size(); i < len; ++i) {
 
1543
            o.record = rs.item(i);
 
1544
            o.data   = o.record.get("data");
 
1545
            o.rowindex = i;
 
1546
            this._addTbodyTrNode(o); //TODO: sometimes rowindex != recordindex
 
1547
        }
 
1548
        
 
1549
        // TBODY to DOM
 
1550
        parent.insert(this._tbodyNode, nextSibling);
 
1551
    },
 
1552
 
 
1553
    _functionFormatter: function (formatter, o) {
 
1554
        var value = formatter.call(this, o);
 
1555
 
 
1556
        return (value !== undefined) ? value : o.emptyCellValue;
 
1557
    },
 
1558
 
 
1559
    _templateFormatter: function (template, o) {
 
1560
        if (o.value === undefined) {
 
1561
            o.value = o.emptyCellValue;
 
1562
        }
 
1563
 
 
1564
        return fromTemplate(template, o);
 
1565
    },
 
1566
 
 
1567
    /**
 
1568
    * Creates and attaches data row element.
 
1569
    *
 
1570
    * @method _addTbodyTrNode
 
1571
    * @param o {Object} {tbody, record}
 
1572
    * @protected
 
1573
    */
 
1574
    _addTbodyTrNode: function(o) {
 
1575
        var row = o.tbody.one("#" + o.record.get("id"));
 
1576
 
 
1577
        o.tr = row || this._createTbodyTrNode(o);
 
1578
 
 
1579
        this._attachTbodyTrNode(o);
 
1580
    },
 
1581
 
 
1582
    /**
 
1583
    * Creates data row element.
 
1584
    *
 
1585
    * @method _createTbodyTrNode
 
1586
    * @param o {Object} {tbody, record}
 
1587
    * @protected
 
1588
    * @return {Node}
 
1589
    */
 
1590
    _createTbodyTrNode: function(o) {
 
1591
        var columns = o.columns,
 
1592
            i, len, columnInfo;
 
1593
 
 
1594
        o.tr = Ycreate(fromTemplate(o.rowTemplate, { id: o.record.get('id') }));
 
1595
        
 
1596
        for (i = 0, len = columns.length; i < len; ++i) {
 
1597
            columnInfo      = columns[i];
 
1598
            o.column        = columnInfo.column;
 
1599
            o.field         = columnInfo.fields;
 
1600
            o.classnames    = columnInfo.classnames;
 
1601
            o.formatter     = columnInfo.formatter;
 
1602
            o.emptyCellValue= columnInfo.emptyCellValue;
 
1603
 
 
1604
            this._addTbodyTdNode(o);
 
1605
        }
 
1606
        
 
1607
        return o.tr;
 
1608
    },
 
1609
 
 
1610
    /**
 
1611
    * Attaches data row element.
 
1612
    *
 
1613
    * @method _attachTbodyTrNode
 
1614
    * @param o {Object} {tbody, record, tr}.
 
1615
    * @protected
 
1616
    */
 
1617
    _attachTbodyTrNode: function(o) {
 
1618
        var tbody = o.tbody,
 
1619
            tr = o.tr,
 
1620
            index = o.rowindex,
 
1621
            nextSibling = tbody.get("children").item(index) || null,
 
1622
            isOdd = (index % 2);
 
1623
            
 
1624
        if(isOdd) {
 
1625
            tr.replaceClass(CLASS_EVEN, CLASS_ODD);
 
1626
        } else {
 
1627
            tr.replaceClass(CLASS_ODD, CLASS_EVEN);
 
1628
        }
 
1629
        
 
1630
        tbody.insertBefore(tr, nextSibling);
 
1631
    },
 
1632
 
 
1633
    /**
 
1634
    * Creates and attaches data cell element.
 
1635
    *
 
1636
    * @method _addTbodyTdNode
 
1637
    * @param o {Object} {record, column, tr}.
 
1638
    * @protected
 
1639
    */
 
1640
    _addTbodyTdNode: function(o) {
 
1641
        o.td = this._createTbodyTdNode(o);
 
1642
        this._attachTbodyTdNode(o);
 
1643
        delete o.td;
 
1644
    },
 
1645
    
 
1646
    /**
 
1647
    Creates a TD Node from the tdTemplate property using the input object as
 
1648
    template {placeholder} values.  The created Node is also assigned to the
 
1649
    `td` property on the input object.
 
1650
 
 
1651
    If the input object already has a `td` property, it is returned an no new
 
1652
    Node is created.
 
1653
 
 
1654
    @method createCell
 
1655
    @param {Object} data Template values
 
1656
    @return {Node}
 
1657
    **/
 
1658
    createCell: function (data) {
 
1659
        return data && (data.td ||
 
1660
            (data.td = Ycreate(fromTemplate(this.tdTemplate, data))));
 
1661
    },
 
1662
 
 
1663
    /**
 
1664
    * Creates data cell element.
 
1665
    *
 
1666
    * @method _createTbodyTdNode
 
1667
    * @param o {Object} {record, column, tr}.
 
1668
    * @protected
 
1669
    * @return {Node}
 
1670
    */
 
1671
    _createTbodyTdNode: function(o) {
 
1672
        o.headers = o.column.headers;
 
1673
        o.value   = this.formatDataCell(o);
 
1674
 
 
1675
        return o.td || this.createCell(o);
 
1676
    },
 
1677
    
 
1678
    /**
 
1679
    * Attaches data cell element.
 
1680
    *
 
1681
    * @method _attachTbodyTdNode
 
1682
    * @param o {Object} {record, column, tr, headers, classnames, value}.
 
1683
    * @protected
 
1684
    */
 
1685
    _attachTbodyTdNode: function(o) {
 
1686
        o.tr.appendChild(o.td);
 
1687
    },
 
1688
 
 
1689
    /**
 
1690
     * Returns markup to insert into data cell element.
 
1691
     *
 
1692
     * @method formatDataCell
 
1693
     * @param @param o {Object} {record, column, tr, headers, classnames}.
 
1694
     */
 
1695
    formatDataCell: function (o) {
 
1696
        o.value = o.data[o.field];
 
1697
 
 
1698
        return o.formatter.call(this, o);
 
1699
    },
 
1700
 
 
1701
    _initRecordset: function () {
 
1702
        return new Y.Recordset({ records: [] });
 
1703
    }
 
1704
});
 
1705
 
 
1706
Y.namespace("DataTable").Base = DTBase;
 
1707
 
 
1708
 
 
1709
}, '3.5.1' ,{requires:['recordset-base','widget','substitute','event-mouseenter']});