[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/datatable-base/ -> datatable-base-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-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>`&mdash;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  });


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