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