~michael.nelson/ubuntu-webcatalog/1267731-import-sca-apps-error

« back to all changes in this revision

Viewing changes to src/webcatalog/static/yui/3.10.3/build/datatable-head/datatable-head.js

  • Committer: Tarmac
  • Author(s): Stephen Stewart
  • Date: 2013-06-26 09:19:32 UTC
  • mfrom: (184.1.4 ubuntu-global-nav)
  • Revision ID: tarmac-20130626091932-8urtuli368k8p7ds
[r=beuno,jonas-drange] add ubuntu global nav to apps.ubuntu.com

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
YUI 3.10.3 (build 2fb5187)
 
3
Copyright 2013 Yahoo! Inc. All rights reserved.
 
4
Licensed under the BSD License.
 
5
http://yuilibrary.com/license/
 
6
*/
 
7
 
 
8
YUI.add('datatable-head', function (Y, NAME) {
 
9
 
 
10
/**
 
11
View class responsible for rendering the `<thead>` section of a table. Used as
 
12
the default `headerView` for `Y.DataTable.Base` and `Y.DataTable` classes.
 
13
 
 
14
@module datatable
 
15
@submodule datatable-head
 
16
@since 3.5.0
 
17
**/
 
18
var Lang = Y.Lang,
 
19
    fromTemplate = Lang.sub,
 
20
    isArray = Lang.isArray,
 
21
    toArray = Y.Array;
 
22
 
 
23
/**
 
24
View class responsible for rendering the `<thead>` section of a table. Used as
 
25
the default `headerView` for `Y.DataTable.Base` and `Y.DataTable` classes.
 
26
 
 
27
Translates the provided array of column configuration objects into a rendered
 
28
`<thead>` based on the data in those objects.
 
29
    
 
30
 
 
31
The structure of the column data is expected to be a single array of objects,
 
32
where each object corresponds to a `<th>`.  Those objects may contain a
 
33
`children` property containing a similarly structured array to indicate the
 
34
nested cells should be grouped under the parent column's colspan in a separate
 
35
row of header cells. E.g.
 
36
 
 
37
<pre><code>
 
38
new Y.DataTable.HeaderView({
 
39
  container: tableNode,
 
40
  columns: [
 
41
    { key: 'id' }, // no nesting
 
42
    { key: 'name', children: [
 
43
      { key: 'firstName', label: 'First' },
 
44
      { key: 'lastName',  label: 'Last' } ] }
 
45
  ]
 
46
}).render();
 
47
</code></pre>
 
48
 
 
49
This would translate to the following visualization:
 
50
 
 
51
<pre>
 
52
---------------------
 
53
|    |     name     |
 
54
|    |---------------
 
55
| id | First | Last |
 
56
---------------------
 
57
</pre>
 
58
 
 
59
Supported properties of the column objects include:
 
60
 
 
61
  * `label`     - The HTML content of the header cell.
 
62
  * `key`       - If `label` is not specified, the `key` is used for content.
 
63
  * `children`  - Array of columns to appear below this column in the next
 
64
                  row.
 
65
  * `headerTemplate` - Overrides the instance's `CELL_TEMPLATE` for cells in this
 
66
    column only.
 
67
  * `abbr`      - The content of the 'abbr' attribute of the `<th>`
 
68
  * `title`     - The content of the 'title' attribute of the `<th>`
 
69
  * `className` - Adds this string of CSS classes to the column header
 
70
 
 
71
Through the life of instantiation and rendering, the column objects will have
 
72
the following properties added to them:
 
73
 
 
74
  * `id`       - (Defaulted by DataTable) The id to assign the rendered column
 
75
  * `_colspan` - To supply the `<th>` attribute
 
76
  * `_rowspan` - To supply the `<th>` attribute
 
77
  * `_parent`  - (Added by DataTable) If the column is a child of another
 
78
    column, this points to its parent column
 
79
 
 
80
The column object is also used to provide values for {placeholder} tokens in the
 
81
instance's `CELL_TEMPLATE`, so you can modify the template and include other
 
82
column object properties to populate them.
 
83
 
 
84
@class HeaderView
 
85
@namespace DataTable
 
86
@extends View
 
87
@since 3.5.0
 
88
**/
 
89
Y.namespace('DataTable').HeaderView = Y.Base.create('tableHeader', Y.View, [], {
 
90
    // -- Instance properties -------------------------------------------------
 
91
 
 
92
    /**
 
93
    Template used to create the table's header cell markup.  Override this to
 
94
    customize how header cell markup is created.
 
95
 
 
96
    @property CELL_TEMPLATE
 
97
    @type {HTML}
 
98
    @default '<th id="{id}" colspan="{_colspan}" rowspan="{_rowspan}" class="{className}" scope="col" {_id}{abbr}{title}>{content}</th>'
 
99
    @since 3.5.0
 
100
    **/
 
101
    CELL_TEMPLATE:
 
102
        '<th id="{id}" colspan="{_colspan}" rowspan="{_rowspan}" class="{className}" scope="col" {_id}{abbr}{title}>{content}</th>',
 
103
 
 
104
    /**
 
105
    The data representation of the header rows to render.  This is assigned by
 
106
    parsing the `columns` configuration array, and is used by the render()
 
107
    method.
 
108
 
 
109
    @property columns
 
110
    @type {Array[]}
 
111
    @default (initially unset)
 
112
    @since 3.5.0
 
113
    **/
 
114
    //TODO: should this be protected?
 
115
    //columns: null,
 
116
 
 
117
    /**
 
118
    Template used to create the table's header row markup.  Override this to
 
119
    customize the row markup.
 
120
 
 
121
    @property ROW_TEMPLATE
 
122
    @type {HTML}
 
123
    @default '<tr>{content}</tr>'
 
124
    @since 3.5.0
 
125
    **/
 
126
    ROW_TEMPLATE:
 
127
        '<tr>{content}</tr>',
 
128
 
 
129
    /**
 
130
    The object that serves as the source of truth for column and row data.
 
131
    This property is assigned at instantiation from the `source` property of
 
132
    the configuration object passed to the constructor.
 
133
 
 
134
    @property source
 
135
    @type {Object}
 
136
    @default (initially unset)
 
137
    @since 3.5.0
 
138
    **/
 
139
    //TODO: should this be protected?
 
140
    //source: null,
 
141
 
 
142
    /**
 
143
    HTML templates used to create the `<thead>` containing the table headers.
 
144
 
 
145
    @property THEAD_TEMPLATE
 
146
    @type {HTML}
 
147
    @default '<thead class="{className}">{content}</thead>'
 
148
    @since 3.6.0
 
149
    **/
 
150
    THEAD_TEMPLATE: '<thead class="{className}"></thead>',
 
151
 
 
152
    // -- Public methods ------------------------------------------------------
 
153
 
 
154
    /**
 
155
    Returns the generated CSS classname based on the input.  If the `host`
 
156
    attribute is configured, it will attempt to relay to its `getClassName`
 
157
    or use its static `NAME` property as a string base.
 
158
    
 
159
    If `host` is absent or has neither method nor `NAME`, a CSS classname
 
160
    will be generated using this class's `NAME`.
 
161
 
 
162
    @method getClassName
 
163
    @param {String} token* Any number of token strings to assemble the
 
164
        classname from.
 
165
    @return {String}
 
166
    @protected
 
167
    **/
 
168
    getClassName: function () {
 
169
        // TODO: add attribute with setter? to host to use property this.host
 
170
        // for performance
 
171
        var host = this.host,
 
172
            NAME = (host && host.constructor.NAME) ||
 
173
                    this.constructor.NAME;
 
174
 
 
175
        if (host && host.getClassName) {
 
176
            return host.getClassName.apply(host, arguments);
 
177
        } else {
 
178
            return Y.ClassNameManager.getClassName
 
179
                .apply(Y.ClassNameManager,
 
180
                       [NAME].concat(toArray(arguments, 0, true)));
 
181
        }
 
182
    },
 
183
 
 
184
    /**
 
185
    Creates the `<thead>` Node content by assembling markup generated by
 
186
    populating the `ROW_TEMPLATE` and `CELL_TEMPLATE` templates with content
 
187
    from the `columns` property.
 
188
    
 
189
    @method render
 
190
    @return {HeaderView} The instance
 
191
    @chainable
 
192
    @since 3.5.0
 
193
    **/
 
194
    render: function () {
 
195
        var table    = this.get('container'),
 
196
            thead    = this.theadNode ||
 
197
                        (this.theadNode = this._createTHeadNode()),
 
198
            columns  = this.columns,
 
199
            defaults = {
 
200
                _colspan: 1,
 
201
                _rowspan: 1,
 
202
                abbr: '',
 
203
                title: ''
 
204
            },
 
205
            i, len, j, jlen, col, html, content, values;
 
206
 
 
207
        if (thead && columns) {
 
208
            html = '';
 
209
 
 
210
            if (columns.length) {
 
211
                for (i = 0, len = columns.length; i < len; ++i) {
 
212
                    content = '';
 
213
 
 
214
                    for (j = 0, jlen = columns[i].length; j < jlen; ++j) {
 
215
                        col = columns[i][j];
 
216
                        values = Y.merge(
 
217
                            defaults,
 
218
                            col, {
 
219
                                className: this.getClassName('header'),
 
220
                                content  : col.label || col.key ||
 
221
                                           ("Column " + (j + 1))
 
222
                            }
 
223
                        );
 
224
 
 
225
                        values._id = col._id ?
 
226
                            ' data-yui3-col-id="' + col._id + '"' : '';
 
227
 
 
228
                        if (col.abbr) {
 
229
                            values.abbr = ' abbr="' + col.abbr + '"';
 
230
                        }
 
231
 
 
232
                        if (col.title) {
 
233
                            values.title = ' title="' + col.title + '"';
 
234
                        }
 
235
 
 
236
                        if (col.className) {
 
237
                            values.className += ' ' + col.className;
 
238
                        }
 
239
 
 
240
                        if (col._first) {
 
241
                            values.className += ' ' + this.getClassName('first', 'header');
 
242
                        }
 
243
 
 
244
                        if (col._id) {
 
245
                            values.className +=
 
246
                                ' ' + this.getClassName('col', col._id);
 
247
                        }
 
248
 
 
249
                        content += fromTemplate(
 
250
                            col.headerTemplate || this.CELL_TEMPLATE, values);
 
251
                    }
 
252
 
 
253
                    html += fromTemplate(this.ROW_TEMPLATE, {
 
254
                        content: content
 
255
                    });
 
256
                }
 
257
            }
 
258
 
 
259
            thead.setHTML(html);
 
260
 
 
261
            if (thead.get('parentNode') !== table) {
 
262
                table.insertBefore(thead, table.one('tfoot, tbody'));
 
263
            }
 
264
        }
 
265
 
 
266
        this.bindUI();
 
267
 
 
268
        return this;
 
269
    },
 
270
 
 
271
    // -- Protected and private properties and methods ------------------------
 
272
 
 
273
    /**
 
274
    Handles changes in the source's columns attribute.  Redraws the headers.
 
275
 
 
276
    @method _afterColumnsChange
 
277
    @param {EventFacade} e The `columnsChange` event object
 
278
    @protected
 
279
    @since 3.5.0
 
280
    **/
 
281
    _afterColumnsChange: function (e) {
 
282
        this.columns = this._parseColumns(e.newVal);
 
283
 
 
284
        this.render();
 
285
    },
 
286
 
 
287
    /**
 
288
    Binds event subscriptions from the UI and the source (if assigned).
 
289
 
 
290
    @method bindUI
 
291
    @protected
 
292
    @since 3.5.0
 
293
    **/
 
294
    bindUI: function () {
 
295
        if (!this._eventHandles.columnsChange) {
 
296
            // TODO: How best to decouple this?
 
297
            this._eventHandles.columnsChange =
 
298
                this.after('columnsChange',
 
299
                    Y.bind('_afterColumnsChange', this));
 
300
        }
 
301
    },
 
302
 
 
303
    /**
 
304
    Creates the `<thead>` node that will store the header rows and cells.
 
305
 
 
306
    @method _createTHeadNode
 
307
    @return {Node}
 
308
    @protected
 
309
    @since 3.6.0
 
310
    **/
 
311
    _createTHeadNode: function () {
 
312
        return Y.Node.create(fromTemplate(this.THEAD_TEMPLATE, {
 
313
            className: this.getClassName('columns')
 
314
        }));
 
315
    },
 
316
    
 
317
    /**
 
318
    Destroys the instance.
 
319
 
 
320
    @method destructor
 
321
    @protected
 
322
    @since 3.5.0
 
323
    **/
 
324
    destructor: function () {
 
325
        (new Y.EventHandle(Y.Object.values(this._eventHandles))).detach();
 
326
    },
 
327
 
 
328
    /**
 
329
    Holds the event subscriptions needing to be detached when the instance is
 
330
    `destroy()`ed.
 
331
 
 
332
    @property _eventHandles
 
333
    @type {Object}
 
334
    @default undefined (initially unset)
 
335
    @protected
 
336
    @since 3.5.0
 
337
    **/
 
338
    //_eventHandles: null,
 
339
 
 
340
    /**
 
341
    Initializes the instance. Reads the following configuration properties:
 
342
 
 
343
      * `columns` - (REQUIRED) The initial column information
 
344
      * `host`    - The object to serve as source of truth for column info
 
345
 
 
346
    @method initializer
 
347
    @param {Object} config Configuration data
 
348
    @protected
 
349
    @since 3.5.0
 
350
    **/
 
351
    initializer: function (config) {
 
352
        this.host  = config.host;
 
353
        this.columns = this._parseColumns(config.columns);
 
354
 
 
355
        this._eventHandles = [];
 
356
    },
 
357
 
 
358
    /**
 
359
    Translate the input column format into a structure useful for rendering a
 
360
    `<thead>`, rows, and cells.  The structure of the input is expected to be a
 
361
    single array of objects, where each object corresponds to a `<th>`.  Those
 
362
    objects may contain a `children` property containing a similarly structured
 
363
    array to indicate the nested cells should be grouped under the parent
 
364
    column's colspan in a separate row of header cells. E.g.
 
365
 
 
366
    <pre><code>
 
367
    [
 
368
      { key: 'id' }, // no nesting
 
369
      { key: 'name', children: [
 
370
        { key: 'firstName', label: 'First' },
 
371
        { key: 'lastName',  label: 'Last' } ] }
 
372
    ]
 
373
    </code></pre>
 
374
 
 
375
    would indicate two header rows with the first column 'id' being assigned a
 
376
    `rowspan` of `2`, the 'name' column appearing in the first row with a
 
377
    `colspan` of `2`, and the 'firstName' and 'lastName' columns appearing in
 
378
    the second row, below the 'name' column.
 
379
 
 
380
    <pre>
 
381
    ---------------------
 
382
    |    |     name     |
 
383
    |    |---------------
 
384
    | id | First | Last |
 
385
    ---------------------
 
386
    </pre>
 
387
 
 
388
    Supported properties of the column objects include:
 
389
 
 
390
      * `label`    - The HTML content of the header cell.
 
391
      * `key`      - If `label` is not specified, the `key` is used for content.
 
392
      * `children` - Array of columns to appear below this column in the next
 
393
                     row.
 
394
      * `abbr`     - The content of the 'abbr' attribute of the `<th>`
 
395
      * `title`    - The content of the 'title' attribute of the `<th>`
 
396
      * `headerTemplate` - Overrides the instance's `CELL_TEMPLATE` for cells
 
397
        in this column only.
 
398
 
 
399
    The output structure is basically a simulation of the `<thead>` structure
 
400
    with arrays for rows and objects for cells.  Column objects have the
 
401
    following properties added to them:
 
402
    
 
403
      * `id`       - (Defaulted by DataTable) The id to assign the rendered
 
404
                     column
 
405
      * `_colspan` - Per the `<th>` attribute
 
406
      * `_rowspan` - Per the `<th>` attribute
 
407
      * `_parent`  - (Added by DataTable) If the column is a child of another
 
408
        column, this points to its parent column
 
409
 
 
410
    The column object is also used to provide values for {placeholder}
 
411
    replacement in the `CELL_TEMPLATE`, so you can modify the template and
 
412
    include other column object properties to populate them.
 
413
 
 
414
    @method _parseColumns
 
415
    @param {Object[]} data Array of column object data
 
416
    @return {Array[]} An array of arrays corresponding to the header row
 
417
            structure to render
 
418
    @protected
 
419
    @since 3.5.0
 
420
    **/
 
421
    _parseColumns: function (data) {
 
422
        var columns = [],
 
423
            stack = [],
 
424
            rowSpan = 1,
 
425
            entry, row, col, children, parent, i, len, j;
 
426
        
 
427
        if (isArray(data) && data.length) {
 
428
            // don't modify the input array
 
429
            data = data.slice();
 
430
 
 
431
            // First pass, assign colspans and calculate row count for
 
432
            // non-nested headers' rowspan
 
433
            stack.push([data, -1]);
 
434
 
 
435
            while (stack.length) {
 
436
                entry = stack[stack.length - 1];
 
437
                row   = entry[0];
 
438
                i     = entry[1] + 1;
 
439
 
 
440
                for (len = row.length; i < len; ++i) {
 
441
                    row[i] = col = Y.merge(row[i]);
 
442
                    children = col.children;
 
443
 
 
444
                    Y.stamp(col);
 
445
 
 
446
                    if (!col.id) {
 
447
                        col.id = Y.guid();
 
448
                    }
 
449
 
 
450
                    if (isArray(children) && children.length) {
 
451
                        stack.push([children, -1]);
 
452
                        entry[1] = i;
 
453
 
 
454
                        rowSpan = Math.max(rowSpan, stack.length);
 
455
 
 
456
                        // break to let the while loop process the children
 
457
                        break;
 
458
                    } else {
 
459
                        col._colspan = 1;
 
460
                    }
 
461
                }
 
462
 
 
463
                if (i >= len) {
 
464
                    // All columns in this row are processed
 
465
                    if (stack.length > 1) {
 
466
                        entry  = stack[stack.length - 2];
 
467
                        parent = entry[0][entry[1]];
 
468
 
 
469
                        parent._colspan = 0;
 
470
 
 
471
                        for (i = 0, len = row.length; i < len; ++i) {
 
472
                            // Can't use .length because in 3+ rows, colspan
 
473
                            // needs to aggregate the colspans of children
 
474
                            row[i]._parent   = parent;
 
475
                            parent._colspan += row[i]._colspan;
 
476
                        }
 
477
                    }
 
478
                    stack.pop();
 
479
                }
 
480
            }
 
481
 
 
482
            // Second pass, build row arrays and assign rowspan
 
483
            for (i = 0; i < rowSpan; ++i) {
 
484
                columns.push([]);
 
485
            }
 
486
 
 
487
            stack.push([data, -1]);
 
488
 
 
489
            while (stack.length) {
 
490
                entry = stack[stack.length - 1];
 
491
                row   = entry[0];
 
492
                i     = entry[1] + 1;
 
493
 
 
494
                for (len = row.length; i < len; ++i) {
 
495
                    col = row[i];
 
496
                    children = col.children;
 
497
 
 
498
                    columns[stack.length - 1].push(col);
 
499
 
 
500
                    entry[1] = i;
 
501
 
 
502
                    // collect the IDs of parent cols
 
503
                    col._headers = [col.id];
 
504
 
 
505
                    for (j = stack.length - 2; j >= 0; --j) {
 
506
                        parent = stack[j][0][stack[j][1]];
 
507
 
 
508
                        col._headers.unshift(parent.id);
 
509
                    }
 
510
 
 
511
                    if (children && children.length) {
 
512
                        // parent cells must assume rowspan 1 (long story)
 
513
 
 
514
                        // break to let the while loop process the children
 
515
                        stack.push([children, -1]);
 
516
                        break;
 
517
                    } else {
 
518
                        col._rowspan = rowSpan - stack.length + 1;
 
519
                    }
 
520
                }
 
521
 
 
522
                if (i >= len) {
 
523
                    // All columns in this row are processed
 
524
                    stack.pop();
 
525
                }
 
526
            }
 
527
        }
 
528
 
 
529
        for (i = 0, len = columns.length; i < len; i += col._rowspan) {
 
530
            col = columns[i][0];
 
531
 
 
532
            col._first = true;
 
533
        }
 
534
 
 
535
        return columns;
 
536
    }
 
537
});
 
538
 
 
539
 
 
540
}, '3.10.3', {"requires": ["datatable-core", "view", "classnamemanager"]});