[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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}>●</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"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |