[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/datatable-core/ -> datatable-core.js (source)

   1  /*
   2  YUI 3.17.2 (build 9c3c78e)
   3  Copyright 2014 Yahoo! Inc. All rights reserved.
   4  Licensed under the BSD License.
   5  http://yuilibrary.com/license/
   6  */
   7  
   8  YUI.add('datatable-core', function (Y, NAME) {
   9  
  10  /**
  11  The core implementation of the `DataTable` and `DataTable.Base` Widgets.
  12  
  13  @module datatable
  14  @submodule datatable-core
  15  @since 3.5.0
  16  **/
  17  
  18  var INVALID = Y.Attribute.INVALID_VALUE,
  19  
  20      Lang         = Y.Lang,
  21      isFunction   = Lang.isFunction,
  22      isObject     = Lang.isObject,
  23      isArray      = Lang.isArray,
  24      isString     = Lang.isString,
  25      isNumber     = Lang.isNumber,
  26  
  27      toArray = Y.Array,
  28  
  29      keys = Y.Object.keys,
  30  
  31      Table;
  32  
  33  /**
  34  _API docs for this extension are included in the DataTable class._
  35  
  36  Class extension providing the core API and structure for the DataTable Widget.
  37  
  38  Use this class extension with Widget or another Base-based superclass to create
  39  the basic DataTable model API and composing class structure.
  40  
  41  @class DataTable.Core
  42  @for DataTable
  43  @since 3.5.0
  44  **/
  45  Table = Y.namespace('DataTable').Core = function () {};
  46  
  47  Table.ATTRS = {
  48      /**
  49      Columns to include in the rendered table.
  50  
  51      If omitted, the attributes on the configured `recordType` or the first item
  52      in the `data` collection will be used as a source.
  53  
  54      This attribute takes an array of strings or objects (mixing the two is
  55      fine).  Each string or object is considered a column to be rendered.
  56      Strings are converted to objects, so `columns: ['first', 'last']` becomes
  57      `columns: [{ key: 'first' }, { key: 'last' }]`.
  58  
  59      DataTable.Core only concerns itself with a few properties of columns.
  60      These properties are:
  61  
  62      * `key` - Used to identify the record field/attribute containing content for
  63        this column.  Also used to create a default Model if no `recordType` or
  64        `data` are provided during construction.  If `name` is not specified, this
  65        is assigned to the `_id` property (with added incrementer if the key is
  66        used by multiple columns).
  67      * `children` - Traversed to initialize nested column objects
  68      * `name` - Used in place of, or in addition to, the `key`.  Useful for
  69        columns that aren't bound to a field/attribute in the record data.  This
  70        is assigned to the `_id` property.
  71      * `id` - For backward compatibility.  Implementers can specify the id of
  72        the header cell.  This should be avoided, if possible, to avoid the
  73        potential for creating DOM elements with duplicate IDs.
  74      * `field` - For backward compatibility.  Implementers should use `name`.
  75      * `_id` - Assigned unique-within-this-instance id for a column.  By order
  76        of preference, assumes the value of `name`, `key`, `id`, or `_yuid`.
  77        This is used by the rendering views as well as feature module
  78        as a means to identify a specific column without ambiguity (such as
  79        multiple columns using the same `key`.
  80      * `_yuid` - Guid stamp assigned to the column object.
  81      * `_parent` - Assigned to all child columns, referencing their parent
  82        column.
  83  
  84      @attribute columns
  85      @type {Object[]|String[]}
  86      @default (from `recordType` ATTRS or first item in the `data`)
  87      @since 3.5.0
  88      **/
  89      columns: {
  90          // TODO: change to setter to clone input array/objects
  91          validator: isArray,
  92          setter: '_setColumns',
  93          getter: '_getColumns'
  94      },
  95  
  96      /**
  97      Model subclass to use as the `model` for the ModelList stored in the `data`
  98      attribute.
  99  
 100      If not provided, it will try really hard to figure out what to use.  The
 101      following attempts will be made to set a default value:
 102  
 103      1. If the `data` attribute is set with a ModelList instance and its `model`
 104         property is set, that will be used.
 105      2. If the `data` attribute is set with a ModelList instance, and its
 106         `model` property is unset, but it is populated, the `ATTRS` of the
 107         `constructor of the first item will be used.
 108      3. If the `data` attribute is set with a non-empty array, a Model subclass
 109         will be generated using the keys of the first item as its `ATTRS` (see
 110         the `_createRecordClass` method).
 111      4. If the `columns` attribute is set, a Model subclass will be generated
 112         using the columns defined with a `key`. This is least desirable because
 113         columns can be duplicated or nested in a way that's not parsable.
 114      5. If neither `data` nor `columns` is set or populated, a change event
 115         subscriber will listen for the first to be changed and try all over
 116         again.
 117  
 118      @attribute recordType
 119      @type {Function}
 120      @default (see description)
 121      @since 3.5.0
 122      **/
 123      recordType: {
 124          getter: '_getRecordType',
 125          setter: '_setRecordType'
 126      },
 127  
 128      /**
 129      The collection of data records to display.  This attribute is a pass
 130      through to a `data` property, which is a ModelList instance.
 131  
 132      If this attribute is passed a ModelList or subclass, it will be assigned to
 133      the property directly.  If an array of objects is passed, a new ModelList
 134      will be created using the configured `recordType` as its `model` property
 135      and seeded with the array.
 136  
 137      Retrieving this attribute will return the ModelList stored in the `data`
 138      property.
 139  
 140      @attribute data
 141      @type {ModelList|Object[]}
 142      @default `new ModelList()`
 143      @since 3.5.0
 144      **/
 145      data: {
 146          valueFn: '_initData',
 147          setter : '_setData',
 148          lazyAdd: false
 149      },
 150  
 151      /**
 152      Content for the `<table summary="ATTRIBUTE VALUE HERE">`.  Values assigned
 153      to this attribute will be HTML escaped for security.
 154  
 155      @attribute summary
 156      @type {String}
 157      @default '' (empty string)
 158      @since 3.5.0
 159      **/
 160      //summary: {},
 161  
 162      /**
 163      HTML content of an optional `<caption>` element to appear above the table.
 164      Leave this config unset or set to a falsy value to remove the caption.
 165  
 166      @attribute caption
 167      @type HTML
 168      @default '' (empty string)
 169      @since 3.5.0
 170      **/
 171      //caption: {},
 172  
 173      /**
 174      Deprecated as of 3.5.0. Passes through to the `data` attribute.
 175  
 176      WARNING: `get('recordset')` will NOT return a Recordset instance as of
 177      3.5.0.  This is a break in backward compatibility.
 178  
 179      @attribute recordset
 180      @type {Object[]|Recordset}
 181      @deprecated Use the `data` attribute
 182      @since 3.5.0
 183      **/
 184      recordset: {
 185          setter: '_setRecordset',
 186          getter: '_getRecordset',
 187          lazyAdd: false
 188      },
 189  
 190      /**
 191      Deprecated as of 3.5.0. Passes through to the `columns` attribute.
 192  
 193      WARNING: `get('columnset')` will NOT return a Columnset instance as of
 194      3.5.0.  This is a break in backward compatibility.
 195  
 196      @attribute columnset
 197      @type {Object[]}
 198      @deprecated Use the `columns` attribute
 199      @since 3.5.0
 200      **/
 201      columnset: {
 202          setter: '_setColumnset',
 203          getter: '_getColumnset',
 204          lazyAdd: false
 205      }
 206  };
 207  
 208  Y.mix(Table.prototype, {
 209      // -- Instance properties -------------------------------------------------
 210      /**
 211      The ModelList that manages the table's data.
 212  
 213      @property data
 214      @type {ModelList}
 215      @default undefined (initially unset)
 216      @since 3.5.0
 217      **/
 218      //data: null,
 219  
 220      // -- Public methods ------------------------------------------------------
 221  
 222      /**
 223      Gets the column configuration object for the given key, name, or index.  For
 224      nested columns, `name` can be an array of indexes, each identifying the index
 225      of that column in the respective parent's "children" array.
 226  
 227      If you pass a column object, it will be returned.
 228  
 229      For columns with keys, you can also fetch the column with
 230      `instance.get('columns.foo')`.
 231  
 232      @method getColumn
 233      @param {String|Number|Number[]} name Key, "name", index, or index array to
 234                  identify the column
 235      @return {Object} the column configuration object
 236      @since 3.5.0
 237      **/
 238      getColumn: function (name) {
 239          var col, columns, i, len, cols;
 240  
 241          if (isObject(name) && !isArray(name)) {
 242              if (name && name._node) {
 243                  col = this.body.getColumn(name);
 244              } else {
 245                  col = name;
 246              }
 247          } else {
 248              col = this.get('columns.' + name);
 249          }
 250  
 251          if (col) {
 252              return col;
 253          }
 254  
 255          columns = this.get('columns');
 256  
 257          if (isNumber(name) || isArray(name)) {
 258              name = toArray(name);
 259              cols = columns;
 260  
 261              for (i = 0, len = name.length - 1; cols && i < len; ++i) {
 262                  cols = cols[name[i]] && cols[name[i]].children;
 263              }
 264  
 265              return (cols && cols[name[i]]) || null;
 266          }
 267  
 268          return null;
 269      },
 270  
 271      /**
 272      Returns the Model associated to the record `id`, `clientId`, or index (not
 273      row index).  If none of those yield a Model from the `data` ModelList, the
 274      arguments will be passed to the `view` instance's `getRecord` method
 275      if it has one.
 276  
 277      If no Model can be found, `null` is returned.
 278  
 279      @method getRecord
 280      @param {Number|String|Node} seed Record `id`, `clientId`, index, Node, or
 281          identifier for a row or child element
 282      @return {Model}
 283      @since 3.5.0
 284      **/
 285      getRecord: function (seed) {
 286          var record = this.data.getById(seed) || this.data.getByClientId(seed);
 287  
 288          if (!record) {
 289              if (isNumber(seed)) {
 290                  record = this.data.item(seed);
 291              }
 292  
 293              // TODO: this should be split out to base somehow
 294              if (!record && this.view && this.view.getRecord) {
 295                  record = this.view.getRecord.apply(this.view, arguments);
 296              }
 297          }
 298  
 299          return record || null;
 300      },
 301  
 302      // -- Protected and private properties and methods ------------------------
 303  
 304      /**
 305      This tells `Y.Base` that it should create ad-hoc attributes for config
 306      properties passed to DataTable's constructor. This is useful for setting
 307      configurations on the DataTable that are intended for the rendering View(s).
 308  
 309      @property _allowAdHocAttrs
 310      @type Boolean
 311      @default true
 312      @protected
 313      @since 3.6.0
 314      **/
 315      _allowAdHocAttrs: true,
 316  
 317      /**
 318      A map of column key to column configuration objects parsed from the
 319      `columns` attribute.
 320  
 321      @property _columnMap
 322      @type {Object}
 323      @default undefined (initially unset)
 324      @protected
 325      @since 3.5.0
 326      **/
 327      //_columnMap: null,
 328  
 329      /**
 330      The Node instance of the table containing the data rows.  This is set when
 331      the table is rendered.  It may also be set by progressive enhancement,
 332      though this extension does not provide the logic to parse from source.
 333  
 334      @property _tableNode
 335      @type {Node}
 336      @default undefined (initially unset)
 337      @protected
 338      @since 3.5.0
 339      **/
 340      //_tableNode: null,
 341  
 342      /**
 343      Updates the `_columnMap` property in response to changes in the `columns`
 344      attribute.
 345  
 346      @method _afterColumnsChange
 347      @param {EventFacade} e The `columnsChange` event object
 348      @protected
 349      @since 3.5.0
 350      **/
 351      _afterColumnsChange: function (e) {
 352          this._setColumnMap(e.newVal);
 353      },
 354  
 355      /**
 356      Updates the `modelList` attributes of the rendered views in response to the
 357      `data` attribute being assigned a new ModelList.
 358  
 359      @method _afterDataChange
 360      @param {EventFacade} e the `dataChange` event
 361      @protected
 362      @since 3.5.0
 363      **/
 364      _afterDataChange: function (e) {
 365          var modelList = e.newVal;
 366  
 367          this.data = e.newVal;
 368  
 369          if (!this.get('columns') && modelList.size()) {
 370              // TODO: this will cause a re-render twice because the Views are
 371              // subscribed to columnsChange
 372              this._initColumns();
 373          }
 374      },
 375  
 376      /**
 377      Assigns to the new recordType as the model for the data ModelList
 378  
 379      @method _afterRecordTypeChange
 380      @param {EventFacade} e recordTypeChange event
 381      @protected
 382      @since 3.6.0
 383      **/
 384      _afterRecordTypeChange: function (e) {
 385          var data = this.data.toJSON();
 386  
 387          this.data.model = e.newVal;
 388  
 389          this.data.reset(data);
 390  
 391          if (!this.get('columns') && data) {
 392              if (data.length) {
 393                  this._initColumns();
 394              } else {
 395                  this.set('columns', keys(e.newVal.ATTRS));
 396              }
 397          }
 398      },
 399  
 400      /**
 401      Creates a Model subclass from an array of attribute names or an object of
 402      attribute definitions.  This is used to generate a class suitable to
 403      represent the data passed to the `data` attribute if no `recordType` is
 404      set.
 405  
 406      @method _createRecordClass
 407      @param {String[]|Object} attrs Names assigned to the Model subclass's
 408                  `ATTRS` or its entire `ATTRS` definition object
 409      @return {Model}
 410      @protected
 411      @since 3.5.0
 412      **/
 413      _createRecordClass: function (attrs) {
 414          var ATTRS, i, len;
 415  
 416          if (isArray(attrs)) {
 417              ATTRS = {};
 418  
 419              for (i = 0, len = attrs.length; i < len; ++i) {
 420                  ATTRS[attrs[i]] = {};
 421              }
 422          } else if (isObject(attrs)) {
 423              ATTRS = attrs;
 424          }
 425  
 426          return Y.Base.create('record', Y.Model, [], null, { ATTRS: ATTRS });
 427      },
 428  
 429      /**
 430      Tears down the instance.
 431  
 432      @method destructor
 433      @protected
 434      @since 3.6.0
 435      **/
 436      destructor: function () {
 437          new Y.EventHandle(Y.Object.values(this._eventHandles)).detach();
 438      },
 439  
 440      /**
 441      The getter for the `columns` attribute.  Returns the array of column
 442      configuration objects if `instance.get('columns')` is called, or the
 443      specific column object if `instance.get('columns.columnKey')` is called.
 444  
 445      @method _getColumns
 446      @param {Object[]} columns The full array of column objects
 447      @param {String} name The attribute name requested
 448                           (e.g. 'columns' or 'columns.foo');
 449      @protected
 450      @since 3.5.0
 451      **/
 452      _getColumns: function (columns, name) {
 453          // Workaround for an attribute oddity (ticket #2529254)
 454          // getter is expected to return an object if get('columns.foo') is called.
 455          // Note 'columns.' is 8 characters
 456          return name.length > 8 ? this._columnMap : columns;
 457      },
 458  
 459      /**
 460      Relays the `get()` request for the deprecated `columnset` attribute to the
 461      `columns` attribute.
 462  
 463      THIS BREAKS BACKWARD COMPATIBILITY.  3.4.1 and prior implementations will
 464      expect a Columnset instance returned from `get('columnset')`.
 465  
 466      @method _getColumnset
 467      @param {Object} ignored The current value stored in the `columnset` state
 468      @param {String} name The attribute name requested
 469                           (e.g. 'columnset' or 'columnset.foo');
 470      @deprecated This will be removed with the `columnset` attribute in a future
 471                  version.
 472      @protected
 473      @since 3.5.0
 474      **/
 475      _getColumnset: function (_, name) {
 476          return this.get(name.replace(/^columnset/, 'columns'));
 477      },
 478  
 479      /**
 480      Returns the Model class of the instance's `data` attribute ModelList.  If
 481      not set, returns the explicitly configured value.
 482  
 483      @method _getRecordType
 484      @param {Model} val The currently configured value
 485      @return {Model}
 486      **/
 487      _getRecordType: function (val) {
 488          // Prefer the value stored in the attribute because the attribute
 489          // change event defaultFn sets e.newVal = this.get('recordType')
 490          // before notifying the after() subs.  But if this getter returns
 491          // this.data.model, then after() subs would get e.newVal === previous
 492          // model before _afterRecordTypeChange can set
 493          // this.data.model = e.newVal
 494          return val || (this.data && this.data.model);
 495      },
 496  
 497      /**
 498      Initializes the `_columnMap` property from the configured `columns`
 499      attribute.  If `columns` is not set, but there are records in the `data`
 500      ModelList, use
 501      `ATTRS` of that class.
 502  
 503      @method _initColumns
 504      @protected
 505      @since 3.5.0
 506      **/
 507      _initColumns: function () {
 508          var columns = this.get('columns') || [],
 509              item;
 510  
 511          // Default column definition from the configured recordType
 512          if (!columns.length && this.data.size()) {
 513              // TODO: merge superclass attributes up to Model?
 514              item = this.data.item(0);
 515  
 516              if (item.toJSON) {
 517                  item = item.toJSON();
 518              }
 519  
 520              this.set('columns', keys(item));
 521          }
 522  
 523          this._setColumnMap(columns);
 524      },
 525  
 526      /**
 527      Sets up the change event subscriptions to maintain internal state.
 528  
 529      @method _initCoreEvents
 530      @protected
 531      @since 3.6.0
 532      **/
 533      _initCoreEvents: function () {
 534          this._eventHandles.coreAttrChanges = this.after({
 535              columnsChange   : Y.bind('_afterColumnsChange', this),
 536              recordTypeChange: Y.bind('_afterRecordTypeChange', this),
 537              dataChange      : Y.bind('_afterDataChange', this)
 538          });
 539      },
 540  
 541      /**
 542      Defaults the `data` attribute to an empty ModelList if not set during
 543      construction.  Uses the configured `recordType` for the ModelList's `model`
 544      proeprty if set.
 545  
 546      @method _initData
 547      @protected
 548      @return {ModelList}
 549      @since 3.6.0
 550      **/
 551      _initData: function () {
 552          var recordType = this.get('recordType'),
 553              // TODO: LazyModelList if recordType doesn't have complex ATTRS
 554              modelList = new Y.ModelList();
 555  
 556          if (recordType) {
 557              modelList.model = recordType;
 558          }
 559  
 560          return modelList;
 561      },
 562  
 563      /**
 564      Initializes the instance's `data` property from the value of the `data`
 565      attribute.  If the attribute value is a ModelList, it is assigned directly
 566      to `this.data`.  If it is an array, a ModelList is created, its `model`
 567      property is set to the configured `recordType` class, and it is seeded with
 568      the array data.  This ModelList is then assigned to `this.data`.
 569  
 570      @method _initDataProperty
 571      @param {Array|ModelList|ArrayList} data Collection of data to populate the
 572              DataTable
 573      @protected
 574      @since 3.6.0
 575      **/
 576      _initDataProperty: function (data) {
 577          var recordType;
 578  
 579          if (!this.data) {
 580              recordType = this.get('recordType');
 581  
 582              if (data && data.each && data.toJSON) {
 583                  this.data = data;
 584  
 585                  if (recordType) {
 586                      this.data.model = recordType;
 587                  }
 588              } else {
 589                  // TODO: customize the ModelList or read the ModelList class
 590                  // from a configuration option?
 591                  this.data = new Y.ModelList();
 592  
 593                  if (recordType) {
 594                      this.data.model = recordType;
 595                  }
 596              }
 597  
 598              // TODO: Replace this with an event relay for specific events.
 599              // Using bubbling causes subscription conflicts with the models'
 600              // aggregated change event and 'change' events from DOM elements
 601              // inside the table (via Widget UI event).
 602              this.data.addTarget(this);
 603          }
 604      },
 605  
 606      /**
 607      Initializes the columns, `recordType` and data ModelList.
 608  
 609      @method initializer
 610      @param {Object} config Configuration object passed to constructor
 611      @protected
 612      @since 3.5.0
 613      **/
 614      initializer: function (config) {
 615          var data       = config.data,
 616              columns    = config.columns,
 617              recordType;
 618  
 619          // Referencing config.data to allow _setData to be more stringent
 620          // about its behavior
 621          this._initDataProperty(data);
 622  
 623          // Default columns from recordType ATTRS if recordType is supplied at
 624          // construction.  If no recordType is supplied, but the data is
 625          // supplied as a non-empty array, use the keys of the first item
 626          // as the columns.
 627          if (!columns) {
 628              recordType = (config.recordType || config.data === this.data) &&
 629                              this.get('recordType');
 630  
 631              if (recordType) {
 632                  columns = keys(recordType.ATTRS);
 633              } else if (isArray(data) && data.length) {
 634                  columns = keys(data[0]);
 635              }
 636  
 637              if (columns) {
 638                  this.set('columns', columns);
 639              }
 640          }
 641  
 642          this._initColumns();
 643  
 644          this._eventHandles = {};
 645  
 646          this._initCoreEvents();
 647      },
 648  
 649      /**
 650      Iterates the array of column configurations to capture all columns with a
 651      `key` property.  An map is built with column keys as the property name and
 652      the corresponding column object as the associated value.  This map is then
 653      assigned to the instance's `_columnMap` property.
 654  
 655      @method _setColumnMap
 656      @param {Object[]|String[]} columns The array of column config objects
 657      @protected
 658      @since 3.6.0
 659      **/
 660      _setColumnMap: function (columns) {
 661          var map = {};
 662  
 663          function process(cols) {
 664              var i, len, col, key;
 665  
 666              for (i = 0, len = cols.length; i < len; ++i) {
 667                  col = cols[i];
 668                  key = col.key;
 669  
 670                  // First in wins for multiple columns with the same key
 671                  // because the first call to genId (in _setColumns) will
 672                  // return the same key, which will then be overwritten by the
 673                  // subsequent same-keyed column.  So table.getColumn(key) would
 674                  // return the last same-keyed column.
 675                  if (key && !map[key]) {
 676                      map[key] = col;
 677                  }
 678                  //TODO: named columns can conflict with keyed columns
 679                  map[col._id] = col;
 680  
 681                  if (col.children) {
 682                      process(col.children);
 683                  }
 684              }
 685          }
 686  
 687          process(columns);
 688  
 689          this._columnMap = map;
 690      },
 691  
 692      /**
 693      Translates string columns into objects with that string as the value of its
 694      `key` property.
 695  
 696      All columns are assigned a `_yuid` stamp and `_id` property corresponding
 697      to the column's configured `name` or `key` property with any spaces
 698      replaced with dashes.  If the same `name` or `key` appears in multiple
 699      columns, subsequent appearances will have their `_id` appended with an
 700      incrementing number (e.g. if column "foo" is included in the `columns`
 701      attribute twice, the first will get `_id` of "foo", and the second an `_id`
 702      of "foo1").  Columns that are children of other columns will have the
 703      `_parent` property added, assigned the column object to which they belong.
 704  
 705      @method _setColumns
 706      @param {null|Object[]|String[]} val Array of config objects or strings
 707      @return {null|Object[]}
 708      @protected
 709      **/
 710      _setColumns: function (val) {
 711          var keys = {},
 712              known = [],
 713              knownCopies = [],
 714              arrayIndex = Y.Array.indexOf;
 715  
 716          function copyObj(o) {
 717              var copy = {},
 718                  key, val, i;
 719  
 720              known.push(o);
 721              knownCopies.push(copy);
 722  
 723              for (key in o) {
 724                  if (o.hasOwnProperty(key)) {
 725                      val = o[key];
 726  
 727                      if (isArray(val)) {
 728                          copy[key] = val.slice();
 729                      } else if (isObject(val, true)) {
 730                          i = arrayIndex(known, val);
 731  
 732                          copy[key] = i === -1 ? copyObj(val) : knownCopies[i];
 733                      } else {
 734                          copy[key] = o[key];
 735                      }
 736                  }
 737              }
 738  
 739              return copy;
 740          }
 741  
 742          function genId(name) {
 743              // Sanitize the name for use in generated CSS classes.
 744              // TODO: is there more to do for other uses of _id?
 745              name = name.replace(/\s+/, '-');
 746  
 747              if (keys[name]) {
 748                  name += (keys[name]++);
 749              } else {
 750                  keys[name] = 1;
 751              }
 752  
 753              return name;
 754          }
 755  
 756          function process(cols, parent) {
 757              var columns = [],
 758                  i, len, col, yuid;
 759  
 760              for (i = 0, len = cols.length; i < len; ++i) {
 761                  columns[i] = // chained assignment
 762                  col = isString(cols[i]) ? { key: cols[i] } : copyObj(cols[i]);
 763  
 764                  yuid = Y.stamp(col);
 765  
 766                  // For backward compatibility
 767                  if (!col.id) {
 768                      // Implementers can shoot themselves in the foot by setting
 769                      // this config property to a non-unique value
 770                      col.id = yuid;
 771                  }
 772                  if (col.field) {
 773                      // Field is now known as "name" to avoid confusion with data
 774                      // fields or schema.resultFields
 775                      col.name = col.field;
 776                  }
 777  
 778                  if (parent) {
 779                      col._parent = parent;
 780                  } else {
 781                      delete col._parent;
 782                  }
 783  
 784                  // Unique id based on the column's configured name or key,
 785                  // falling back to the yuid.  Duplicates will have a counter
 786                  // added to the end.
 787                  col._id = genId(col.name || col.key || col.id);
 788  
 789                  if (isArray(col.children)) {
 790                      col.children = process(col.children, col);
 791                  }
 792              }
 793  
 794              return columns;
 795          }
 796  
 797          return val && process(val);
 798      },
 799  
 800      /**
 801      Relays attribute assignments of the deprecated `columnset` attribute to the
 802      `columns` attribute.  If a Columnset is object is passed, its basic object
 803      structure is mined.
 804  
 805      @method _setColumnset
 806      @param {Array|Columnset} val The columnset value to relay
 807      @deprecated This will be removed with the deprecated `columnset` attribute
 808                  in a later version.
 809      @protected
 810      @since 3.5.0
 811      **/
 812      _setColumnset: function (val) {
 813          this.set('columns', val);
 814  
 815          return isArray(val) ? val : INVALID;
 816      },
 817  
 818      /**
 819      Accepts an object with `each` and `getAttrs` (preferably a ModelList or
 820      subclass) or an array of data objects.  If an array is passes, it will
 821      create a ModelList to wrap the data.  In doing so, it will set the created
 822      ModelList's `model` property to the class in the `recordType` attribute,
 823      which will be defaulted if not yet set.
 824  
 825      If the `data` property is already set with a ModelList, passing an array as
 826      the value will call the ModelList's `reset()` method with that array rather
 827      than replacing the stored ModelList wholesale.
 828  
 829      Any non-ModelList-ish and non-array value is invalid.
 830  
 831      @method _setData
 832      @protected
 833      @since 3.5.0
 834      **/
 835      _setData: function (val) {
 836          if (val === null) {
 837              val = [];
 838          }
 839  
 840          if (isArray(val)) {
 841              this._initDataProperty();
 842  
 843              // silent to prevent subscribers to both reset and dataChange
 844              // from reacting to the change twice.
 845              // TODO: would it be better to return INVALID to silence the
 846              // dataChange event, or even allow both events?
 847              this.data.reset(val, { silent: true });
 848  
 849              // Return the instance ModelList to avoid storing unprocessed
 850              // data in the state and their vivified Model representations in
 851              // the instance's data property.  Decreases memory consumption.
 852              val = this.data;
 853          } else if (!val || !val.each || !val.toJSON) {
 854              // ModelList/ArrayList duck typing
 855              val = INVALID;
 856          }
 857  
 858          return val;
 859      },
 860  
 861      /**
 862      Relays the value assigned to the deprecated `recordset` attribute to the
 863      `data` attribute.  If a Recordset instance is passed, the raw object data
 864      will be culled from it.
 865  
 866      @method _setRecordset
 867      @param {Object[]|Recordset} val The recordset value to relay
 868      @deprecated This will be removed with the deprecated `recordset` attribute
 869                  in a later version.
 870      @protected
 871      @since 3.5.0
 872      **/
 873      _setRecordset: function (val) {
 874          var data;
 875  
 876          if (val && Y.Recordset && val instanceof Y.Recordset) {
 877              data = [];
 878              val.each(function (record) {
 879                  data.push(record.get('data'));
 880              });
 881              val = data;
 882          }
 883  
 884          this.set('data', val);
 885  
 886          return val;
 887      },
 888  
 889      /**
 890      Accepts a Base subclass (preferably a Model subclass). Alternately, it will
 891      generate a custom Model subclass from an array of attribute names or an
 892      object defining attributes and their respective configurations (it is
 893      assigned as the `ATTRS` of the new class).
 894  
 895      Any other value is invalid.
 896  
 897      @method _setRecordType
 898      @param {Function|String[]|Object} val The Model subclass, array of
 899              attribute names, or the `ATTRS` definition for a custom model
 900              subclass
 901      @return {Function} A Base/Model subclass
 902      @protected
 903      @since 3.5.0
 904      **/
 905      _setRecordType: function (val) {
 906          var modelClass;
 907  
 908          // Duck type based on known/likely consumed APIs
 909          if (isFunction(val) && val.prototype.toJSON && val.prototype.setAttrs) {
 910              modelClass = val;
 911          } else if (isObject(val)) {
 912              modelClass = this._createRecordClass(val);
 913          }
 914  
 915          return modelClass || INVALID;
 916      }
 917  
 918  });
 919  
 920  
 921  
 922  /**
 923  _This is a documentation entry only_
 924  
 925  Columns are described by object literals with a set of properties.
 926  There is not an actual `DataTable.Column` class.
 927  However, for the purpose of documenting it, this pseudo-class is declared here.
 928  
 929  DataTables accept an array of column definitions in their [columns](DataTable.html#attr_columns)
 930  attribute.  Each entry in this array is a column definition which may contain
 931  any combination of the properties listed below.
 932  
 933  There are no mandatory properties though a column will usually have a
 934  [key](#property_key) property to reference the data it is supposed to show.
 935  The [columns](DataTable.html#attr_columns) attribute can accept a plain string
 936  in lieu of an object literal, which is the equivalent of an object with the
 937  [key](#property_key) property set to that string.
 938  
 939  @class DataTable.Column
 940  */
 941  
 942  /**
 943  Binds the column values to the named property in the [data](DataTable.html#attr_data).
 944  
 945  Optional if [formatter](#property_formatter), [nodeFormatter](#property_nodeFormatter),
 946  or [cellTemplate](#property_cellTemplate) is used to populate the content.
 947  
 948  It should not be set if [children](#property_children) is set.
 949  
 950  The value is used for the [\_id](#property__id) property unless the [name](#property_name)
 951  property is also set.
 952  
 953      { key: 'username' }
 954  
 955  The above column definition can be reduced to this:
 956  
 957      'username'
 958  
 959  @property key
 960  @type String
 961   */
 962  /**
 963  An identifier that can be used to locate a column via
 964  [getColumn](DataTable.html#method_getColumn)
 965  or style columns with class `yui3-datatable-col-NAME` after dropping characters
 966  that are not valid for CSS class names.
 967  
 968  It defaults to the [key](#property_key).
 969  
 970  The value is used for the [\_id](#property__id) property.
 971  
 972      { name: 'fullname', formatter: ... }
 973  
 974  @property name
 975  @type String
 976  */
 977  /**
 978  An alias for [name](#property_name) for backward compatibility.
 979  
 980      { field: 'fullname', formatter: ... }
 981  
 982  @property field
 983  @type String
 984  */
 985  /**
 986  Overrides the default unique id assigned `<th id="HERE">`.
 987  
 988  __Use this with caution__, since it can result in
 989  duplicate ids in the DOM.
 990  
 991      {
 992          name: 'checkAll',
 993          id: 'check-all',
 994          label: ...
 995          formatter: ...
 996      }
 997  
 998  @property id
 999  @type String
1000   */
1001  /**
1002  HTML to populate the header `<th>` for the column.
1003  It defaults to the value of the [key](#property_key) property or the text
1004  `Column n` where _n_ is an ordinal number.
1005  
1006      { key: 'MfgvaPrtNum', label: 'Part Number' }
1007  
1008  @property label
1009  @type {String}
1010   */
1011  /**
1012  Used to create stacked headers.
1013  
1014  Child columns may also contain `children`. There is no limit
1015  to the depth of nesting.
1016  
1017  Columns configured with `children` are for display only and
1018  <strong>should not</strong> be configured with a [key](#property_key).
1019  Configurations relating to the display of data, such as
1020  [formatter](#property_formatter), [nodeFormatter](#property_nodeFormatter),
1021  [emptyCellValue](#property_emptyCellValue), etc. are ignored.
1022  
1023      { label: 'Name', children: [
1024          { key: 'firstName', label: 'First`},
1025          { key: 'lastName', label: 'Last`}
1026      ]}
1027  
1028  @property  children
1029  @type Array
1030  */
1031  /**
1032  Assigns the value `<th abbr="HERE">`.
1033  
1034      {
1035        key  : 'forecast',
1036        label: '1yr Target Forecast',
1037        abbr : 'Forecast'
1038      }
1039  
1040  @property abbr
1041  @type String
1042   */
1043  /**
1044  Assigns the value `<th title="HERE">`.
1045  
1046      {
1047        key  : 'forecast',
1048        label: '1yr Target Forecast',
1049        title: 'Target Forecast for the Next 12 Months'
1050      }
1051  
1052  @property title
1053  @type String
1054   */
1055  /**
1056  Overrides the default [CELL_TEMPLATE](DataTable.HeaderView.html#property_CELL_TEMPLATE)
1057  used by `Y.DataTable.HeaderView` to render the header cell
1058  for this column.  This is necessary when more control is
1059  needed over the markup for the header itself, rather than
1060  its content.
1061  
1062  Use the [label](#property_label) configuration if you don't need to
1063  customize the `<th>` iteself.
1064  
1065  Implementers are strongly encouraged to preserve at least
1066  the `{id}` and `{_id}` placeholders in the custom value.
1067  
1068      {
1069          headerTemplate:
1070              '<th id="{id}" ' +
1071                  'title="Unread" ' +
1072                  'class="{className}" ' +
1073                  '{_id}>&#9679;</th>'
1074      }
1075  
1076  @property headerTemplate
1077  @type HTML
1078   */
1079  /**
1080  Overrides the default [CELL_TEMPLATE](DataTable.BodyView.html#property_CELL_TEMPLATE)
1081  used by `Y.DataTable.BodyView` to render the data cells
1082  for this column.  This is necessary when more control is
1083  needed over the markup for the `<td>` itself, rather than
1084  its content.
1085  
1086      {
1087          key: 'id',
1088          cellTemplate:
1089              '<td class="{className}">' +
1090                '<input type="checkbox" ' +
1091                       'id="{content}">' +
1092              '</td>'
1093      }
1094  
1095  
1096  @property cellTemplate
1097  @type String
1098   */
1099  /**
1100  String or function used to translate the raw record data for each cell in a
1101  given column into a format better suited to display.
1102  
1103  If it is a string, it will initially be assumed to be the name of one of the
1104  formatting functions in
1105  [Y.DataTable.BodyView.Formatters](DataTable.BodyView.Formatters.html).
1106  If one such formatting function exists, it will be used.
1107  
1108  If no such named formatter is found, it will be assumed to be a template
1109  string and will be expanded.  The placeholders can contain the key to any
1110  field in the record or the placeholder `{value}` which represents the value
1111  of the current field.
1112  
1113  If the value is a function, it will be assumed to be a formatting function.
1114  A formatting function receives a single argument, an object with the following properties:
1115  
1116  * __value__ The raw value from the record Model to populate this cell.
1117    Equivalent to `o.record.get(o.column.key)` or `o.data[o.column.key]`.
1118  * __data__ The Model data for this row in simple object format.
1119  * __record__ The Model for this row.
1120  * __column__ The column configuration object.
1121  * __className__ A string of class names to add `<td class="HERE">` in addition to
1122    the column class and any classes in the column's className configuration.
1123  * __rowIndex__ The index of the current Model in the ModelList.
1124    Typically correlates to the row index as well.
1125  * __rowClass__ A string of css classes to add `<tr class="HERE"><td....`
1126    This is useful to avoid the need for nodeFormatters to add classes to the containing row.
1127  
1128  The formatter function may return a string value that will be used for the cell
1129  contents or it may change the value of the `value`, `className` or `rowClass`
1130  properties which well then be used to format the cell.  If the value for the cell
1131  is returned in the `value` property of the input argument, no value should be returned.
1132  
1133      {
1134          key: 'name',
1135          formatter: 'link',  // named formatter
1136          linkFrom: 'website' // extra column property for link formatter
1137      },
1138      {
1139          key: 'cost',
1140          formatter: '${value}' // formatter template string
1141        //formatter: '${cost}'  // same result but less portable
1142      },
1143      {
1144          name: 'Name',          // column does not have associated field value
1145                                 // thus, it uses name instead of key
1146          formatter: '{firstName} {lastName}' // template references other fields
1147      },
1148      {
1149          key: 'price',
1150          formatter: function (o) { // function both returns a string to show
1151              if (o.value > 3) {    // and a className to apply to the cell
1152                  o.className += 'expensive';
1153              }
1154  
1155              return '$' + o.value.toFixed(2);
1156          }
1157      },
1158  @property formatter
1159  @type String || Function
1160  
1161  */
1162  /**
1163  Used to customize the content of the data cells for this column.
1164  
1165  `nodeFormatter` is significantly slower than [formatter](#property_formatter)
1166  and should be avoided if possible. Unlike [formatter](#property_formatter),
1167  `nodeFormatter` has access to the `<td>` element and its ancestors.
1168  
1169  The function provided is expected to fill in the `<td>` element itself.
1170  __Node formatters should return `false`__ except in certain conditions as described
1171  in the users guide.
1172  
1173  The function receives a single object
1174  argument with the following properties:
1175  
1176  * __td__    The `<td>` Node for this cell.
1177  * __cell__    If the cell `<td> contains an element with class `yui3-datatable-liner,
1178    this will refer to that Node. Otherwise, it is equivalent to `td` (default behavior).
1179  * __value__    The raw value from the record Model to populate this cell.
1180    Equivalent to `o.record.get(o.column.key)` or `o.data[o.column.key]`.
1181  * __data__    The Model data for this row in simple object format.
1182  * __record__    The Model for this row.
1183  * __column__    The column configuration object.
1184  * __rowIndex__    The index of the current Model in the ModelList.
1185   _Typically_ correlates to the row index as well.
1186  
1187  @example
1188      nodeFormatter: function (o) {
1189          if (o.value < o.data.quota) {
1190              o.td.setAttribute('rowspan', 2);
1191              o.td.setAttribute('data-term-id', this.record.get('id'));
1192  
1193              o.td.ancestor().insert(
1194                  '<tr><td colspan"3">' +
1195                      '<button class="term">terminate</button>' +
1196                  '</td></tr>',
1197                  'after');
1198          }
1199  
1200          o.cell.setHTML(o.value);
1201          return false;
1202      }
1203  
1204  @property nodeFormatter
1205  @type Function
1206  */
1207  /**
1208  Provides the default value to populate the cell if the data
1209  for that cell is `undefined`, `null`, or an empty string.
1210  
1211      {
1212          key: 'price',
1213          emptyCellValue: '???'
1214      }
1215  
1216  @property emptyCellValue
1217  @type {String} depending on the setting of allowHTML
1218   */
1219  /**
1220  Skips the security step of HTML escaping the value for cells
1221  in this column.
1222  
1223  This is also necessary if [emptyCellValue](#property_emptyCellValue)
1224  is set with an HTML string.
1225  `nodeFormatter`s ignore this configuration.  If using a
1226  `nodeFormatter`, it is recommended to use
1227  [Y.Escape.html()](Escape.html#method_html)
1228  on any user supplied content that is to be displayed.
1229  
1230      {
1231          key: 'preview',
1232          allowHTML: true
1233      }
1234  
1235  @property allowHTML
1236  @type Boolean
1237  */
1238  /**
1239  A string of CSS classes that will be added to the `<td>`'s
1240  `class` attribute.
1241  
1242  Note, all cells will automatically have a class in the
1243  form of "yui3-datatable-col-XXX" added to the `<td>`, where
1244  XXX is the column's configured `name`, `key`, or `id` (in
1245  that order of preference) sanitized from invalid characters.
1246  
1247      {
1248          key: 'symbol',
1249          className: 'no-hide'
1250      }
1251  
1252  @property className
1253  @type String
1254  */
1255  /**
1256  (__read-only__) The unique identifier assigned
1257  to each column.  This is used for the `id` if not set, and
1258  the `_id` if none of [name](#property_name),
1259  [field](#property_field), [key](#property_key), or [id](#property_id) are
1260  set.
1261  
1262  @property _yuid
1263  @type String
1264  @protected
1265   */
1266  /**
1267  (__read-only__) A unique-to-this-instance name
1268  used extensively in the rendering process.  It is also used
1269  to create the column's classname, as the input name
1270  `table.getColumn(HERE)`, and in the column header's
1271  `<th data-yui3-col-id="HERE">`.
1272  
1273  The value is populated by the first of [name](#property_name),
1274  [field](#property_field), [key](#property_key), [id](#property_id),
1275   or [_yuid](#property__yuid) to have a value.  If that value
1276  has already been used (such as when multiple columns have
1277  the same `key`), an incrementer is added to the end.  For
1278  example, two columns with `key: "id"` will have `_id`s of
1279  "id" and "id2".  `table.getColumn("id")` will return the
1280  first column, and `table.getColumn("id2")` will return the
1281  second.
1282  
1283  @property _id
1284  @type String
1285  @protected
1286   */
1287  /**
1288  (__read-only__) Used by
1289  `Y.DataTable.HeaderView` when building stacked column
1290  headers.
1291  
1292  @property _colspan
1293  @type Integer
1294  @protected
1295   */
1296  /**
1297  (__read-only__) Used by
1298  `Y.DataTable.HeaderView` when building stacked column
1299  headers.
1300  
1301  @property _rowspan
1302  @type Integer
1303  @protected
1304   */
1305  /**
1306  (__read-only__) Assigned to all columns in a
1307  column's `children` collection.  References the parent
1308  column object.
1309  
1310  @property _parent
1311  @type DataTable.Column
1312  @protected
1313   */
1314  /**
1315  (__read-only__) Array of the `id`s of the
1316  column and all parent columns.  Used by
1317  `Y.DataTable.BodyView` to populate `<td headers="THIS">`
1318  when a cell references more than one header.
1319  
1320  @property _headers
1321  @type Array
1322  @protected
1323  */
1324  
1325  
1326  }, '3.17.2', {"requires": ["escape", "model-list", "node-event-delegate"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1