[ 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-base', function (Y, NAME) { 9 10 /** 11 A Widget for displaying tabular data. The base implementation of DataTable 12 provides the ability to dynamically generate an HTML table from a set of column 13 configurations and row data. 14 15 Two classes are included in the `datatable-base` module: `Y.DataTable` and 16 `Y.DataTable.Base`. 17 18 @module datatable 19 @submodule datatable-base 20 @main datatable 21 @since 3.5.0 22 **/ 23 24 // DataTable API docs included before DataTable.Base to make yuidoc work 25 /** 26 A Widget for displaying tabular data. Before feature modules are `use()`d, 27 this class is functionally equivalent to DataTable.Base. However, feature 28 modules can modify this class in non-destructive ways, expanding the API and 29 functionality. 30 31 This is the primary DataTable class. Out of the box, it provides the ability 32 to dynamically generate an HTML table from a set of column configurations and 33 row data. But feature module inclusion can add table sorting, pagintaion, 34 highlighting, selection, and more. 35 36 <pre><code> 37 // The functionality of this table would require additional modules be use()d, 38 // but the feature APIs are aggregated onto Y.DataTable. 39 // (Snippet is for illustration. Not all features are available today.) 40 var table = new Y.DataTable({ 41 columns: [ 42 { type: 'checkbox', defaultChecked: true }, 43 { key: 'firstName', sortable: true, resizable: true }, 44 { key: 'lastName', sortable: true }, 45 { key: 'role', formatter: toRoleName } 46 ], 47 data: { 48 source: 'http://myserver.com/service/json', 49 type: 'json', 50 schema: { 51 resultListLocator: 'results.users', 52 fields: [ 53 'username', 54 'firstName', 55 'lastName', 56 { key: 'role', type: 'number' } 57 ] 58 } 59 }, 60 recordType: UserModel, 61 pagedData: { 62 location: 'footer', 63 pageSizes: [20, 50, 'all'], 64 rowsPerPage: 20, 65 pageLinks: 5 66 }, 67 editable: true 68 }); 69 </code></pre> 70 71 ### Column Configuration 72 73 The column configurations are set in the form of an array of objects, where 74 each object corresponds to a column. For columns populated directly from the 75 row data, a 'key' property is required to bind the column to that property or 76 attribute in the row data. 77 78 Not all columns need to relate to row data, nor do all properties or attributes 79 of the row data need to have a corresponding column. However, only those 80 columns included in the `columns` configuration attribute will be rendered. 81 82 Other column configuration properties are supported by the configured 83 `view`, class as well as any features added by plugins or class extensions. 84 See the description of DataTable.TableView and its subviews 85 DataTable.HeaderView, DataTable.BodyView, and DataTable.FooterView (and other 86 DataTable feature classes) to see what column properties they support. 87 88 Some examples of column configurations would be: 89 90 <pre><code> 91 // Basic 92 var columns = [{ key: 'firstName' }, { key: 'lastName' }, { key: 'age' }]; 93 94 // For columns without any additional configuration, strings can be used 95 var columns = ['firstName', 'lastName', 'age']; 96 97 // Multi-row column headers (see DataTable.HeaderView for details) 98 var columns = [ 99 { 100 label: 'Name', 101 children: [ 102 { key: 'firstName' }, 103 { key: 'lastName' } 104 ] 105 }, 106 'age' // mixing and matching objects and strings is ok 107 ]; 108 109 // Including columns that are not related 1:1 to row data fields/attributes 110 // (See DataTable.BodyView for details) 111 var columns = [ 112 { 113 label: 'Name', // Needed for the column header 114 formatter: function (o) { 115 // Fill the column cells with data from firstName and lastName 116 if (o.data.age > 55) { 117 o.className += ' senior'; 118 } 119 return o.data.lastName + ', ' + o.data.firstName; 120 } 121 }, 122 'age' 123 ]; 124 125 // Columns that include feature configurations (for illustration; not all 126 // features are available today). 127 var columns = [ 128 { type: 'checkbox', defaultChecked: true }, 129 { key: 'firstName', sortable: true, resizable: true, min-width: '300px' }, 130 { key: 'lastName', sortable: true, resizable: true, min-width: '300px' }, 131 { key: 'age', emptyCellValue: '<em>unknown</em>' } 132 ]; 133 </code></pre> 134 135 ### Row Data Configuration 136 137 The `data` configuration attribute is responsible for housing the data objects 138 that will be rendered as rows. You can provide this information in two ways by default: 139 140 1. An array of simple objects with key:value pairs 141 2. A ModelList of Base-based class instances (presumably Model subclass 142 instances) 143 144 If an array of objects is passed, it will be translated into a ModelList filled 145 with instances of the class provided to the `recordType` attribute. This 146 attribute can also create a custom Model subclass from an array of field names 147 or an object of attribute configurations. If no `recordType` is provided, one 148 will be created for you from available information (see `_initRecordType`). 149 Providing either your own ModelList instance for `data`, or at least Model 150 class for `recordType`, is the best way to control client-server 151 synchronization when modifying data on the client side. 152 153 The ModelList instance that manages the table's data is available in the `data` 154 property on the DataTable instance. 155 156 157 ### Rendering 158 159 Table rendering is a collaborative process between the DataTable and its 160 configured `view`. The DataTable creates an instance of the configured `view` 161 (DataTable.TableView by default), and calls its `render()` method. 162 DataTable.TableView, for instance, then creates the `<table>` and `<caption>`, 163 then delegates the rendering of the specific sections of the table to subviews, 164 which can be configured as `headerView`, `bodyView`, and `footerView`. 165 DataTable.TableView defaults the `headerView` to DataTable.HeaderView and the 166 `bodyView` to DataTable.BodyView, but leaves the `footerView` unassigned. 167 Setting any subview to `null` will result in that table section not being 168 rendered. 169 170 @class DataTable 171 @extends DataTable.Base 172 @since 3.5.0 173 **/ 174 175 // DataTable API docs included before DataTable.Base to make yuidoc work 176 /** 177 The baseline implementation of a DataTable. This class should be used 178 primarily as a superclass for a custom DataTable with a specific set of 179 features. Because features can be composed onto `Y.DataTable`, custom 180 subclasses of DataTable.Base will remain unmodified when new feature modules 181 are loaded. 182 183 Example usage might look like this: 184 185 <pre><code> 186 // Custom subclass with only sorting and mutability added. If other datatable 187 // feature modules are loaded, this class will not be affected. 188 var MyTableClass = Y.Base.create('table', Y.DataTable.Base, 189 [ Y.DataTable.Sortable, Y.DataTable.Mutable ]); 190 191 var table = new MyTableClass({ 192 columns: ['firstName', 'lastName', 'age'], 193 data: [ 194 { firstName: 'Frank', lastName: 'Zappa', age: 71 }, 195 { firstName: 'Frank', lastName: 'Lloyd Wright', age: 144 }, 196 { firstName: 'Albert', lastName: 'Einstein', age: 132 }, 197 ... 198 ] 199 }); 200 201 table.render('#over-there'); 202 203 // DataTable.Base can be instantiated if a featureless table is needed. 204 var table = new Y.DataTable.Base({ 205 columns: ['firstName', 'lastName', 'age'], 206 data: [ 207 { firstName: 'Frank', lastName: 'Zappa', age: 71 }, 208 { firstName: 'Frank', lastName: 'Lloyd Wright', age: 144 }, 209 { firstName: 'Albert', lastName: 'Einstein', age: 132 }, 210 ... 211 ] 212 }); 213 214 table.render('#in-here'); 215 </code></pre> 216 217 DataTable.Base is built from DataTable.Core, and sets the default `view` 218 to `Y.DataTable.TableView`. 219 220 @class Base 221 @extends Widget 222 @uses DataTable.Core 223 @namespace DataTable 224 @since 3.5.0 225 **/ 226 Y.DataTable.Base = Y.Base.create('datatable', Y.Widget, [Y.DataTable.Core], { 227 228 /** 229 Pass through to `delegate()` called from the `contentBox`. 230 231 @method delegate 232 @param type {String} the event type to delegate 233 @param fn {Function} the callback function to execute. This function 234 will be provided the event object for the delegated event. 235 @param spec {String|Function} a selector that must match the target of the 236 event or a function to test target and its parents for a match 237 @param context {Object} optional argument that specifies what 'this' refers to 238 @param args* {any} 0..n additional arguments to pass on to the callback 239 function. These arguments will be added after the event object. 240 @return {EventHandle} the detach handle 241 @since 3.5.0 242 **/ 243 delegate: function () { 244 var contentBox = this.get('contentBox'); 245 246 return contentBox.delegate.apply(contentBox, arguments); 247 }, 248 249 /** 250 Destroys the table `View` if it's been created. 251 252 @method destructor 253 @protected 254 @since 3.6.0 255 **/ 256 destructor: function () { 257 if (this.view) { 258 this.view.destroy(); 259 } 260 }, 261 262 /** 263 Returns the `<td>` Node from the given row and column index. Alternately, 264 the `seed` can be a Node. If so, the nearest ancestor cell is returned. 265 If the `seed` is a cell, it is returned. If there is no cell at the given 266 coordinates, `null` is returned. 267 268 Optionally, include an offset array or string to return a cell near the 269 cell identified by the `seed`. The offset can be an array containing the 270 number of rows to shift followed by the number of columns to shift, or one 271 of "above", "below", "next", or "previous". 272 273 <pre><code>// Previous cell in the previous row 274 var cell = table.getCell(e.target, [-1, -1]); 275 276 // Next cell 277 var cell = table.getCell(e.target, 'next'); 278 var cell = table.getCell(e.taregt, [0, 1];</pre></code> 279 280 This is actually just a pass through to the `view` instance's method 281 by the same name. 282 283 @method getCell 284 @param {Number[]|Node} seed Array of row and column indexes, or a Node that 285 is either the cell itself or a descendant of one. 286 @param {Number[]|String} [shift] Offset by which to identify the returned 287 cell Node 288 @return {Node} 289 @since 3.5.0 290 **/ 291 getCell: function (/* seed, shift */) { 292 return this.view && this.view.getCell && 293 this.view.getCell.apply(this.view, arguments); 294 }, 295 296 /** 297 Returns the `<tr>` Node from the given row index, Model, or Model's 298 `clientId`. If the rows haven't been rendered yet, or if the row can't be 299 found by the input, `null` is returned. 300 301 This is actually just a pass through to the `view` instance's method 302 by the same name. 303 304 @method getRow 305 @param {Number|String|Model} id Row index, Model instance, or clientId 306 @return {Node} 307 @since 3.5.0 308 **/ 309 getRow: function (/* id */) { 310 return this.view && this.view.getRow && 311 this.view.getRow.apply(this.view, arguments); 312 }, 313 314 /** 315 Updates the `_displayColumns` property. 316 317 @method _afterDisplayColumnsChange 318 @param {EventFacade} e The `columnsChange` event 319 @protected 320 @since 3.6.0 321 **/ 322 // FIXME: This is a kludge for back compat with features that reference 323 // _displayColumns. They should be updated to TableView plugins. 324 _afterDisplayColumnsChange: function (e) { 325 this._extractDisplayColumns(e.newVal || []); 326 }, 327 328 /** 329 Attaches subscriptions to relay core change events to the view. 330 331 @method bindUI 332 @protected 333 @since 3.6.0 334 **/ 335 bindUI: function () { 336 this._eventHandles.relayCoreChanges = this.after( 337 ['columnsChange', 338 'dataChange', 339 'summaryChange', 340 'captionChange', 341 'widthChange'], 342 Y.bind('_relayCoreAttrChange', this)); 343 }, 344 345 /** 346 The default behavior of the `renderView` event. Calls `render()` on the 347 `View` instance on the event. 348 349 @method _defRenderViewFn 350 @param {EventFacade} e The `renderView` event 351 @protected 352 **/ 353 _defRenderViewFn: function (e) { 354 e.view.render(); 355 }, 356 357 /** 358 Processes the full column array, distilling the columns down to those that 359 correspond to cell data columns. 360 361 @method _extractDisplayColumns 362 @param {Object[]} columns The full set of table columns 363 @protected 364 **/ 365 // FIXME: this is a kludge for back compat, duplicating logic in the 366 // tableView 367 _extractDisplayColumns: function (columns) { 368 var displayColumns = []; 369 370 function process(cols) { 371 var i, len, col; 372 373 for (i = 0, len = cols.length; i < len; ++i) { 374 col = cols[i]; 375 376 if (Y.Lang.isArray(col.children)) { 377 process(col.children); 378 } else { 379 displayColumns.push(col); 380 } 381 } 382 } 383 384 process(columns); 385 386 /** 387 Array of the columns that correspond to those with value cells in the 388 data rows. Excludes colspan header columns (configured with `children`). 389 390 @property _displayColumns 391 @type {Object[]} 392 @since 3.5.0 393 **/ 394 this._displayColumns = displayColumns; 395 }, 396 397 /** 398 Sets up the instance's events. 399 400 @method initializer 401 @param {Object} [config] Configuration object passed at construction 402 @protected 403 @since 3.6.0 404 **/ 405 initializer: function () { 406 this.publish('renderView', { 407 defaultFn: Y.bind('_defRenderViewFn', this) 408 }); 409 410 // Have to use get('columns'), not config.columns because the setter 411 // needs to transform string columns to objects. 412 this._extractDisplayColumns(this.get('columns') || []); 413 414 // FIXME: kludge for back compat of features that reference 415 // _displayColumns on the instance. They need to be updated to 416 // TableView plugins, most likely. 417 this.after('columnsChange', Y.bind('_afterDisplayColumnsChange', this)); 418 }, 419 420 /** 421 Relays attribute changes to the instance's `view`. 422 423 @method _relayCoreAttrChange 424 @param {EventFacade} e The change event 425 @protected 426 @since 3.6.0 427 **/ 428 _relayCoreAttrChange: function (e) { 429 var attr = (e.attrName === 'data') ? 'modelList' : e.attrName; 430 431 this.view.set(attr, e.newVal); 432 }, 433 434 /** 435 Instantiates the configured `view` class that will be responsible for 436 setting up the View class. 437 438 @method @renderUI 439 @protected 440 @since 3.6.0 441 **/ 442 renderUI: function () { 443 var self = this, 444 View = this.get('view'); 445 446 if (View) { 447 this.view = new View( 448 Y.merge( 449 this.getAttrs(), 450 { 451 host : this, 452 container: this.get('contentBox'), 453 modelList: this.data 454 }, 455 this.get('viewConfig'))); 456 457 // For back compat, share the view instances and primary nodes 458 // on this instance. 459 // TODO: Remove this? 460 if (!this._eventHandles.legacyFeatureProps) { 461 this._eventHandles.legacyFeatureProps = this.view.after({ 462 renderHeader: function (e) { 463 self.head = e.view; 464 self._theadNode = e.view.theadNode; 465 // TODO: clean up the repetition. 466 // This is here so that subscribers to renderHeader etc 467 // have access to this._tableNode from the DT instance 468 self._tableNode = e.view.get('container'); 469 }, 470 renderFooter: function (e) { 471 self.foot = e.view; 472 self._tfootNode = e.view.tfootNode; 473 self._tableNode = e.view.get('container'); 474 }, 475 renderBody: function (e) { 476 self.body = e.view; 477 self._tbodyNode = e.view.tbodyNode; 478 self._tableNode = e.view.get('container'); 479 }, 480 // FIXME: guarantee that the properties are available, even 481 // if the configured (or omitted) views don't create them 482 renderTable: function () { 483 var contentBox = this.get('container'); 484 485 self._tableNode = this.tableNode || 486 contentBox.one('.' + this.getClassName('table') + 487 ', table'); 488 489 // FIXME: _captionNode isn't available until after 490 // renderTable unless in the renderX subs I look for 491 // it under the container's parentNode (to account for 492 // scroll breaking out the caption table). 493 self._captionNode = this.captionNode || 494 contentBox.one('caption'); 495 496 if (!self._theadNode) { 497 self._theadNode = contentBox.one( 498 '.' + this.getClassName('columns') + ', thead'); 499 } 500 501 if (!self._tbodyNode) { 502 self._tbodyNode = contentBox.one( 503 '.' + this.getClassName('data') + ', tbody'); 504 } 505 506 if (!self._tfootNode) { 507 self._tfootNode = contentBox.one( 508 '.' + this.getClassName('footer') + ', tfoot'); 509 } 510 } 511 }); 512 } 513 514 // To *somewhat* preserve table.on('renderHeader', fn) in the 515 // form of table.on('table:renderHeader', fn), because I couldn't 516 // figure out another option. 517 this.view.addTarget(this); 518 } 519 }, 520 521 /** 522 Fires the `renderView` event, delegating UI updates to the configured View. 523 524 @method syncUI 525 @since 3.5.0 526 **/ 527 syncUI: function () { 528 if (this.view) { 529 this.fire('renderView', { view: this.view }); 530 } 531 }, 532 533 /** 534 Verifies the input value is a function with a `render` method on its 535 prototype. `null` is also accepted to remove the default View. 536 537 @method _validateView 538 @protected 539 @since 3.5.0 540 **/ 541 _validateView: function (val) { 542 // TODO support View instances? 543 return val === null || (Y.Lang.isFunction(val) && val.prototype.render); 544 } 545 }, { 546 ATTRS: { 547 /** 548 The View class used to render the `<table>` into the Widget's 549 `contentBox`. This View can handle the entire table rendering itself 550 or delegate to other Views. 551 552 It is not strictly necessary that the class function assigned here be 553 a View subclass. It must however have a `render()` method. 554 555 When the DataTable is rendered, an instance of this View will be 556 created and its `render()` method called. The View instance will be 557 assigned to the DataTable instance's `view` property. 558 559 @attribute view 560 @type {Function} 561 @default Y.DataTable.TableView 562 @since 3.6.0 563 **/ 564 view: { 565 value: Y.DataTable.TableView, 566 validator: '_validateView' 567 }, 568 569 /** 570 Configuration object passed to the class constructor in `view` 571 during render. 572 573 @attribute viewConfig 574 @type {Object} 575 @default undefined (initially unset) 576 @protected 577 @since 3.6.0 578 **/ 579 viewConfig: {} 580 581 /** 582 If the View class assigned to the DataTable's `view` attribute supports 583 it, this class will be used for rendering the contents of the 584 `<thead>`—the column headers for the table. 585 586 Similar to `view`, the instance of this View will be assigned to the 587 DataTable instance's `head` property. 588 589 It is not strictly necessary that the class function assigned here be 590 a View subclass. It must however have a `render()` method. 591 592 @attribute headerView 593 @type {Function|Object} 594 @default Y.DataTable.HeaderView 595 @since 3.5.0 596 **/ 597 /* 598 headerView: { 599 value: Y.DataTable.HeaderView, 600 validator: '_validateView' 601 }, 602 */ 603 604 /** 605 Configuration object passed to the class constructor in `headerView` 606 during render. 607 608 @attribute headerConfig 609 @type {Object} 610 @default undefined (initially unset) 611 @protected 612 @since 3.6.0 613 **/ 614 //headConfig: {}, 615 616 /** 617 If the View class assigned to the DataTable's `view` attribute supports 618 it, this class will be used for rendering the contents of the `<tfoot>`. 619 620 Similar to `view`, the instance of this View will be assigned to the 621 DataTable instance's `foot` property. 622 623 It is not strictly necessary that the class function assigned here be 624 a View subclass. It must however have a `render()` method. 625 626 @attribute footerView 627 @type {Function|Object} 628 @since 3.5.0 629 **/ 630 /* 631 footerView: { 632 validator: '_validateView' 633 }, 634 */ 635 636 /** 637 Configuration object passed to the class constructor in `footerView` 638 during render. 639 640 @attribute footerConfig 641 @type {Object} 642 @default undefined (initially unset) 643 @protected 644 @since 3.6.0 645 **/ 646 //footerConfig: {}, 647 648 /** 649 If the View class assigned to the DataTable's `view` attribute supports 650 it, this class will be used for rendering the contents of the `<tbody>` 651 including all data rows. 652 653 Similar to `view`, the instance of this View will be assigned to the 654 DataTable instance's `body` property. 655 656 It is not strictly necessary that the class function assigned here be 657 a View subclass. It must however have a `render()` method. 658 659 @attribute bodyView 660 @type {Function} 661 @default Y.DataTable.BodyView 662 @since 3.5.0 663 **/ 664 /* 665 bodyView: { 666 value: Y.DataTable.BodyView, 667 validator: '_validateView' 668 }, 669 */ 670 671 /** 672 Configuration object passed to the class constructor in `bodyView` 673 during render. 674 675 @attribute bodyConfig 676 @type {Object} 677 @default undefined (initially unset) 678 @protected 679 @since 3.6.0 680 **/ 681 //bodyConfig: {} 682 } 683 }); 684 685 // The DataTable API docs are above DataTable.Base docs. 686 Y.DataTable = Y.mix( 687 Y.Base.create('datatable', Y.DataTable.Base, []), // Create the class 688 Y.DataTable); // Migrate static and namespaced classes 689 690 691 }, '3.17.2', { 692 "requires": [ 693 "datatable-core", 694 "datatable-table", 695 "datatable-head", 696 "datatable-body", 697 "base-build", 698 "widget" 699 ], 700 "skinnable": true 701 });
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 |