[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/datatable-core/ -> datatable-core-debug.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                  else {Y.log('Key of column matches existing key or name: ' + key, 'warn', NAME);}
 679                  if (map[col._id]) {Y.log('Key of column matches existing key or name: ' + col._id, 'warn', NAME);}
 680                  //TODO: named columns can conflict with keyed columns
 681                  map[col._id] = col;
 682  
 683                  if (col.children) {
 684                      process(col.children);
 685                  }
 686              }
 687          }
 688  
 689          process(columns);
 690  
 691          this._columnMap = map;
 692      },
 693  
 694      /**
 695      Translates string columns into objects with that string as the value of its
 696      `key` property.
 697  
 698      All columns are assigned a `_yuid` stamp and `_id` property corresponding
 699      to the column's configured `name` or `key` property with any spaces
 700      replaced with dashes.  If the same `name` or `key` appears in multiple
 701      columns, subsequent appearances will have their `_id` appended with an
 702      incrementing number (e.g. if column "foo" is included in the `columns`
 703      attribute twice, the first will get `_id` of "foo", and the second an `_id`
 704      of "foo1").  Columns that are children of other columns will have the
 705      `_parent` property added, assigned the column object to which they belong.
 706  
 707      @method _setColumns
 708      @param {null|Object[]|String[]} val Array of config objects or strings
 709      @return {null|Object[]}
 710      @protected
 711      **/
 712      _setColumns: function (val) {
 713          var keys = {},
 714              known = [],
 715              knownCopies = [],
 716              arrayIndex = Y.Array.indexOf;
 717  
 718          function copyObj(o) {
 719              var copy = {},
 720                  key, val, i;
 721  
 722              known.push(o);
 723              knownCopies.push(copy);
 724  
 725              for (key in o) {
 726                  if (o.hasOwnProperty(key)) {
 727                      val = o[key];
 728  
 729                      if (isArray(val)) {
 730                          copy[key] = val.slice();
 731                      } else if (isObject(val, true)) {
 732                          i = arrayIndex(known, val);
 733  
 734                          copy[key] = i === -1 ? copyObj(val) : knownCopies[i];
 735                      } else {
 736                          copy[key] = o[key];
 737                      }
 738                  }
 739              }
 740  
 741              return copy;
 742          }
 743  
 744          function genId(name) {
 745              // Sanitize the name for use in generated CSS classes.
 746              // TODO: is there more to do for other uses of _id?
 747              name = name.replace(/\s+/, '-');
 748  
 749              if (keys[name]) {
 750                  name += (keys[name]++);
 751              } else {
 752                  keys[name] = 1;
 753              }
 754  
 755              return name;
 756          }
 757  
 758          function process(cols, parent) {
 759              var columns = [],
 760                  i, len, col, yuid;
 761  
 762              for (i = 0, len = cols.length; i < len; ++i) {
 763                  columns[i] = // chained assignment
 764                  col = isString(cols[i]) ? { key: cols[i] } : copyObj(cols[i]);
 765  
 766                  yuid = Y.stamp(col);
 767  
 768                  // For backward compatibility
 769                  if (!col.id) {
 770                      // Implementers can shoot themselves in the foot by setting
 771                      // this config property to a non-unique value
 772                      col.id = yuid;
 773                  }
 774                  if (col.field) {
 775                      // Field is now known as "name" to avoid confusion with data
 776                      // fields or schema.resultFields
 777                      col.name = col.field;
 778                  }
 779  
 780                  if (parent) {
 781                      col._parent = parent;
 782                  } else {
 783                      delete col._parent;
 784                  }
 785  
 786                  // Unique id based on the column's configured name or key,
 787                  // falling back to the yuid.  Duplicates will have a counter
 788                  // added to the end.
 789                  col._id = genId(col.name || col.key || col.id);
 790  
 791                  if (isArray(col.children)) {
 792                      col.children = process(col.children, col);
 793                  }
 794              }
 795  
 796              return columns;
 797          }
 798  
 799          return val && process(val);
 800      },
 801  
 802      /**
 803      Relays attribute assignments of the deprecated `columnset` attribute to the
 804      `columns` attribute.  If a Columnset is object is passed, its basic object
 805      structure is mined.
 806  
 807      @method _setColumnset
 808      @param {Array|Columnset} val The columnset value to relay
 809      @deprecated This will be removed with the deprecated `columnset` attribute
 810                  in a later version.
 811      @protected
 812      @since 3.5.0
 813      **/
 814      _setColumnset: function (val) {
 815          this.set('columns', val);
 816  
 817          return isArray(val) ? val : INVALID;
 818      },
 819  
 820      /**
 821      Accepts an object with `each` and `getAttrs` (preferably a ModelList or
 822      subclass) or an array of data objects.  If an array is passes, it will
 823      create a ModelList to wrap the data.  In doing so, it will set the created
 824      ModelList's `model` property to the class in the `recordType` attribute,
 825      which will be defaulted if not yet set.
 826  
 827      If the `data` property is already set with a ModelList, passing an array as
 828      the value will call the ModelList's `reset()` method with that array rather
 829      than replacing the stored ModelList wholesale.
 830  
 831      Any non-ModelList-ish and non-array value is invalid.
 832  
 833      @method _setData
 834      @protected
 835      @since 3.5.0
 836      **/
 837      _setData: function (val) {
 838          if (val === null) {
 839              val = [];
 840          }
 841  
 842          if (isArray(val)) {
 843              this._initDataProperty();
 844  
 845              // silent to prevent subscribers to both reset and dataChange
 846              // from reacting to the change twice.
 847              // TODO: would it be better to return INVALID to silence the
 848              // dataChange event, or even allow both events?
 849              this.data.reset(val, { silent: true });
 850  
 851              // Return the instance ModelList to avoid storing unprocessed
 852              // data in the state and their vivified Model representations in
 853              // the instance's data property.  Decreases memory consumption.
 854              val = this.data;
 855          } else if (!val || !val.each || !val.toJSON) {
 856              // ModelList/ArrayList duck typing
 857              val = INVALID;
 858          }
 859  
 860          return val;
 861      },
 862  
 863      /**
 864      Relays the value assigned to the deprecated `recordset` attribute to the
 865      `data` attribute.  If a Recordset instance is passed, the raw object data
 866      will be culled from it.
 867  
 868      @method _setRecordset
 869      @param {Object[]|Recordset} val The recordset value to relay
 870      @deprecated This will be removed with the deprecated `recordset` attribute
 871                  in a later version.
 872      @protected
 873      @since 3.5.0
 874      **/
 875      _setRecordset: function (val) {
 876          var data;
 877  
 878          if (val && Y.Recordset && val instanceof Y.Recordset) {
 879              data = [];
 880              val.each(function (record) {
 881                  data.push(record.get('data'));
 882              });
 883              val = data;
 884          }
 885  
 886          this.set('data', val);
 887  
 888          return val;
 889      },
 890  
 891      /**
 892      Accepts a Base subclass (preferably a Model subclass). Alternately, it will
 893      generate a custom Model subclass from an array of attribute names or an
 894      object defining attributes and their respective configurations (it is
 895      assigned as the `ATTRS` of the new class).
 896  
 897      Any other value is invalid.
 898  
 899      @method _setRecordType
 900      @param {Function|String[]|Object} val The Model subclass, array of
 901              attribute names, or the `ATTRS` definition for a custom model
 902              subclass
 903      @return {Function} A Base/Model subclass
 904      @protected
 905      @since 3.5.0
 906      **/
 907      _setRecordType: function (val) {
 908          var modelClass;
 909  
 910          // Duck type based on known/likely consumed APIs
 911          if (isFunction(val) && val.prototype.toJSON && val.prototype.setAttrs) {
 912              modelClass = val;
 913          } else if (isObject(val)) {
 914              modelClass = this._createRecordClass(val);
 915          }
 916  
 917          return modelClass || INVALID;
 918      }
 919  
 920  });
 921  
 922  
 923  
 924  /**
 925  _This is a documentation entry only_
 926  
 927  Columns are described by object literals with a set of properties.
 928  There is not an actual `DataTable.Column` class.
 929  However, for the purpose of documenting it, this pseudo-class is declared here.
 930  
 931  DataTables accept an array of column definitions in their [columns](DataTable.html#attr_columns)
 932  attribute.  Each entry in this array is a column definition which may contain
 933  any combination of the properties listed below.
 934  
 935  There are no mandatory properties though a column will usually have a
 936  [key](#property_key) property to reference the data it is supposed to show.
 937  The [columns](DataTable.html#attr_columns) attribute can accept a plain string
 938  in lieu of an object literal, which is the equivalent of an object with the
 939  [key](#property_key) property set to that string.
 940  
 941  @class DataTable.Column
 942  */
 943  
 944  /**
 945  Binds the column values to the named property in the [data](DataTable.html#attr_data).
 946  
 947  Optional if [formatter](#property_formatter), [nodeFormatter](#property_nodeFormatter),
 948  or [cellTemplate](#property_cellTemplate) is used to populate the content.
 949  
 950  It should not be set if [children](#property_children) is set.
 951  
 952  The value is used for the [\_id](#property__id) property unless the [name](#property_name)
 953  property is also set.
 954  
 955      { key: 'username' }
 956  
 957  The above column definition can be reduced to this:
 958  
 959      'username'
 960  
 961  @property key
 962  @type String
 963   */
 964  /**
 965  An identifier that can be used to locate a column via
 966  [getColumn](DataTable.html#method_getColumn)
 967  or style columns with class `yui3-datatable-col-NAME` after dropping characters
 968  that are not valid for CSS class names.
 969  
 970  It defaults to the [key](#property_key).
 971  
 972  The value is used for the [\_id](#property__id) property.
 973  
 974      { name: 'fullname', formatter: ... }
 975  
 976  @property name
 977  @type String
 978  */
 979  /**
 980  An alias for [name](#property_name) for backward compatibility.
 981  
 982      { field: 'fullname', formatter: ... }
 983  
 984  @property field
 985  @type String
 986  */
 987  /**
 988  Overrides the default unique id assigned `<th id="HERE">`.
 989  
 990  __Use this with caution__, since it can result in
 991  duplicate ids in the DOM.
 992  
 993      {
 994          name: 'checkAll',
 995          id: 'check-all',
 996          label: ...
 997          formatter: ...
 998      }
 999  
1000  @property id
1001  @type String
1002   */
1003  /**
1004  HTML to populate the header `<th>` for the column.
1005  It defaults to the value of the [key](#property_key) property or the text
1006  `Column n` where _n_ is an ordinal number.
1007  
1008      { key: 'MfgvaPrtNum', label: 'Part Number' }
1009  
1010  @property label
1011  @type {String}
1012   */
1013  /**
1014  Used to create stacked headers.
1015  
1016  Child columns may also contain `children`. There is no limit
1017  to the depth of nesting.
1018  
1019  Columns configured with `children` are for display only and
1020  <strong>should not</strong> be configured with a [key](#property_key).
1021  Configurations relating to the display of data, such as
1022  [formatter](#property_formatter), [nodeFormatter](#property_nodeFormatter),
1023  [emptyCellValue](#property_emptyCellValue), etc. are ignored.
1024  
1025      { label: 'Name', children: [
1026          { key: 'firstName', label: 'First`},
1027          { key: 'lastName', label: 'Last`}
1028      ]}
1029  
1030  @property  children
1031  @type Array
1032  */
1033  /**
1034  Assigns the value `<th abbr="HERE">`.
1035  
1036      {
1037        key  : 'forecast',
1038        label: '1yr Target Forecast',
1039        abbr : 'Forecast'
1040      }
1041  
1042  @property abbr
1043  @type String
1044   */
1045  /**
1046  Assigns the value `<th title="HERE">`.
1047  
1048      {
1049        key  : 'forecast',
1050        label: '1yr Target Forecast',
1051        title: 'Target Forecast for the Next 12 Months'
1052      }
1053  
1054  @property title
1055  @type String
1056   */
1057  /**
1058  Overrides the default [CELL_TEMPLATE](DataTable.HeaderView.html#property_CELL_TEMPLATE)
1059  used by `Y.DataTable.HeaderView` to render the header cell
1060  for this column.  This is necessary when more control is
1061  needed over the markup for the header itself, rather than
1062  its content.
1063  
1064  Use the [label](#property_label) configuration if you don't need to
1065  customize the `<th>` iteself.
1066  
1067  Implementers are strongly encouraged to preserve at least
1068  the `{id}` and `{_id}` placeholders in the custom value.
1069  
1070      {
1071          headerTemplate:
1072              '<th id="{id}" ' +
1073                  'title="Unread" ' +
1074                  'class="{className}" ' +
1075                  '{_id}>&#9679;</th>'
1076      }
1077  
1078  @property headerTemplate
1079  @type HTML
1080   */
1081  /**
1082  Overrides the default [CELL_TEMPLATE](DataTable.BodyView.html#property_CELL_TEMPLATE)
1083  used by `Y.DataTable.BodyView` to render the data cells
1084  for this column.  This is necessary when more control is
1085  needed over the markup for the `<td>` itself, rather than
1086  its content.
1087  
1088      {
1089          key: 'id',
1090          cellTemplate:
1091              '<td class="{className}">' +
1092                '<input type="checkbox" ' +
1093                       'id="{content}">' +
1094              '</td>'
1095      }
1096  
1097  
1098  @property cellTemplate
1099  @type String
1100   */
1101  /**
1102  String or function used to translate the raw record data for each cell in a
1103  given column into a format better suited to display.
1104  
1105  If it is a string, it will initially be assumed to be the name of one of the
1106  formatting functions in
1107  [Y.DataTable.BodyView.Formatters](DataTable.BodyView.Formatters.html).
1108  If one such formatting function exists, it will be used.
1109  
1110  If no such named formatter is found, it will be assumed to be a template
1111  string and will be expanded.  The placeholders can contain the key to any
1112  field in the record or the placeholder `{value}` which represents the value
1113  of the current field.
1114  
1115  If the value is a function, it will be assumed to be a formatting function.
1116  A formatting function receives a single argument, an object with the following properties:
1117  
1118  * __value__ The raw value from the record Model to populate this cell.
1119    Equivalent to `o.record.get(o.column.key)` or `o.data[o.column.key]`.
1120  * __data__ The Model data for this row in simple object format.
1121  * __record__ The Model for this row.
1122  * __column__ The column configuration object.
1123  * __className__ A string of class names to add `<td class="HERE">` in addition to
1124    the column class and any classes in the column's className configuration.
1125  * __rowIndex__ The index of the current Model in the ModelList.
1126    Typically correlates to the row index as well.
1127  * __rowClass__ A string of css classes to add `<tr class="HERE"><td....`
1128    This is useful to avoid the need for nodeFormatters to add classes to the containing row.
1129  
1130  The formatter function may return a string value that will be used for the cell
1131  contents or it may change the value of the `value`, `className` or `rowClass`
1132  properties which well then be used to format the cell.  If the value for the cell
1133  is returned in the `value` property of the input argument, no value should be returned.
1134  
1135      {
1136          key: 'name',
1137          formatter: 'link',  // named formatter
1138          linkFrom: 'website' // extra column property for link formatter
1139      },
1140      {
1141          key: 'cost',
1142          formatter: '${value}' // formatter template string
1143        //formatter: '${cost}'  // same result but less portable
1144      },
1145      {
1146          name: 'Name',          // column does not have associated field value
1147                                 // thus, it uses name instead of key
1148          formatter: '{firstName} {lastName}' // template references other fields
1149      },
1150      {
1151          key: 'price',
1152          formatter: function (o) { // function both returns a string to show
1153              if (o.value > 3) {    // and a className to apply to the cell
1154                  o.className += 'expensive';
1155              }
1156  
1157              return '$' + o.value.toFixed(2);
1158          }
1159      },
1160  @property formatter
1161  @type String || Function
1162  
1163  */
1164  /**
1165  Used to customize the content of the data cells for this column.
1166  
1167  `nodeFormatter` is significantly slower than [formatter](#property_formatter)
1168  and should be avoided if possible. Unlike [formatter](#property_formatter),
1169  `nodeFormatter` has access to the `<td>` element and its ancestors.
1170  
1171  The function provided is expected to fill in the `<td>` element itself.
1172  __Node formatters should return `false`__ except in certain conditions as described
1173  in the users guide.
1174  
1175  The function receives a single object
1176  argument with the following properties:
1177  
1178  * __td__    The `<td>` Node for this cell.
1179  * __cell__    If the cell `<td> contains an element with class `yui3-datatable-liner,
1180    this will refer to that Node. Otherwise, it is equivalent to `td` (default behavior).
1181  * __value__    The raw value from the record Model to populate this cell.
1182    Equivalent to `o.record.get(o.column.key)` or `o.data[o.column.key]`.
1183  * __data__    The Model data for this row in simple object format.
1184  * __record__    The Model for this row.
1185  * __column__    The column configuration object.
1186  * __rowIndex__    The index of the current Model in the ModelList.
1187   _Typically_ correlates to the row index as well.
1188  
1189  @example
1190      nodeFormatter: function (o) {
1191          if (o.value < o.data.quota) {
1192              o.td.setAttribute('rowspan', 2);
1193              o.td.setAttribute('data-term-id', this.record.get('id'));
1194  
1195              o.td.ancestor().insert(
1196                  '<tr><td colspan"3">' +
1197                      '<button class="term">terminate</button>' +
1198                  '</td></tr>',
1199                  'after');
1200          }
1201  
1202          o.cell.setHTML(o.value);
1203          return false;
1204      }
1205  
1206  @property nodeFormatter
1207  @type Function
1208  */
1209  /**
1210  Provides the default value to populate the cell if the data
1211  for that cell is `undefined`, `null`, or an empty string.
1212  
1213      {
1214          key: 'price',
1215          emptyCellValue: '???'
1216      }
1217  
1218  @property emptyCellValue
1219  @type {String} depending on the setting of allowHTML
1220   */
1221  /**
1222  Skips the security step of HTML escaping the value for cells
1223  in this column.
1224  
1225  This is also necessary if [emptyCellValue](#property_emptyCellValue)
1226  is set with an HTML string.
1227  `nodeFormatter`s ignore this configuration.  If using a
1228  `nodeFormatter`, it is recommended to use
1229  [Y.Escape.html()](Escape.html#method_html)
1230  on any user supplied content that is to be displayed.
1231  
1232      {
1233          key: 'preview',
1234          allowHTML: true
1235      }
1236  
1237  @property allowHTML
1238  @type Boolean
1239  */
1240  /**
1241  A string of CSS classes that will be added to the `<td>`'s
1242  `class` attribute.
1243  
1244  Note, all cells will automatically have a class in the
1245  form of "yui3-datatable-col-XXX" added to the `<td>`, where
1246  XXX is the column's configured `name`, `key`, or `id` (in
1247  that order of preference) sanitized from invalid characters.
1248  
1249      {
1250          key: 'symbol',
1251          className: 'no-hide'
1252      }
1253  
1254  @property className
1255  @type String
1256  */
1257  /**
1258  (__read-only__) The unique identifier assigned
1259  to each column.  This is used for the `id` if not set, and
1260  the `_id` if none of [name](#property_name),
1261  [field](#property_field), [key](#property_key), or [id](#property_id) are
1262  set.
1263  
1264  @property _yuid
1265  @type String
1266  @protected
1267   */
1268  /**
1269  (__read-only__) A unique-to-this-instance name
1270  used extensively in the rendering process.  It is also used
1271  to create the column's classname, as the input name
1272  `table.getColumn(HERE)`, and in the column header's
1273  `<th data-yui3-col-id="HERE">`.
1274  
1275  The value is populated by the first of [name](#property_name),
1276  [field](#property_field), [key](#property_key), [id](#property_id),
1277   or [_yuid](#property__yuid) to have a value.  If that value
1278  has already been used (such as when multiple columns have
1279  the same `key`), an incrementer is added to the end.  For
1280  example, two columns with `key: "id"` will have `_id`s of
1281  "id" and "id2".  `table.getColumn("id")` will return the
1282  first column, and `table.getColumn("id2")` will return the
1283  second.
1284  
1285  @property _id
1286  @type String
1287  @protected
1288   */
1289  /**
1290  (__read-only__) Used by
1291  `Y.DataTable.HeaderView` when building stacked column
1292  headers.
1293  
1294  @property _colspan
1295  @type Integer
1296  @protected
1297   */
1298  /**
1299  (__read-only__) Used by
1300  `Y.DataTable.HeaderView` when building stacked column
1301  headers.
1302  
1303  @property _rowspan
1304  @type Integer
1305  @protected
1306   */
1307  /**
1308  (__read-only__) Assigned to all columns in a
1309  column's `children` collection.  References the parent
1310  column object.
1311  
1312  @property _parent
1313  @type DataTable.Column
1314  @protected
1315   */
1316  /**
1317  (__read-only__) Array of the `id`s of the
1318  column and all parent columns.  Used by
1319  `Y.DataTable.BodyView` to populate `<td headers="THIS">`
1320  when a cell references more than one header.
1321  
1322  @property _headers
1323  @type Array
1324  @protected
1325  */
1326  
1327  
1328  }, '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