[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/datatable-table/ -> datatable-table.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-table', function (Y, NAME) {
   9  
  10  /**
  11  View class responsible for rendering a `<table>` from provided data.  Used as
  12  the default `view` for `Y.DataTable.Base` and `Y.DataTable` classes.
  13  
  14  @module datatable
  15  @submodule datatable-table
  16  @since 3.6.0
  17  **/
  18  var toArray = Y.Array,
  19      YLang   = Y.Lang,
  20      fromTemplate = YLang.sub,
  21  
  22      isArray    = YLang.isArray,
  23      isFunction = YLang.isFunction;
  24  
  25  /**
  26  View class responsible for rendering a `<table>` from provided data.  Used as
  27  the default `view` for `Y.DataTable.Base` and `Y.DataTable` classes.
  28  
  29  
  30  
  31  @class TableView
  32  @namespace DataTable
  33  @extends View
  34  @since 3.6.0
  35  **/
  36  Y.namespace('DataTable').TableView = Y.Base.create('table', Y.View, [], {
  37  
  38      /**
  39      The HTML template used to create the caption Node if the `caption`
  40      attribute is set.
  41  
  42      @property CAPTION_TEMPLATE
  43      @type {String}
  44      @default '<caption class="{className}"></caption>'
  45      @since 3.6.0
  46      **/
  47      CAPTION_TEMPLATE: '<caption class="{className}"></caption>',
  48  
  49      /**
  50      The HTML template used to create the table Node.
  51  
  52      @property TABLE_TEMPLATE
  53      @type {String}
  54      @default '<table cellspacing="0" class="{className}"></table>'
  55      @since 3.6.0
  56      **/
  57      TABLE_TEMPLATE  : '<table cellspacing="0" class="{className}"></table>',
  58  
  59      /**
  60      The object or instance of the class assigned to `bodyView` that is
  61      responsible for rendering and managing the table's `<tbody>`(s) and its
  62      content.
  63  
  64      @property body
  65      @type {Object}
  66      @default undefined (initially unset)
  67      @since 3.5.0
  68      **/
  69      //body: null,
  70  
  71      /**
  72      The object or instance of the class assigned to `footerView` that is
  73      responsible for rendering and managing the table's `<tfoot>` and its
  74      content.
  75  
  76      @property foot
  77      @type {Object}
  78      @default undefined (initially unset)
  79      @since 3.5.0
  80      **/
  81      //foot: null,
  82  
  83      /**
  84      The object or instance of the class assigned to `headerView` that is
  85      responsible for rendering and managing the table's `<thead>` and its
  86      content.
  87  
  88      @property head
  89      @type {Object}
  90      @default undefined (initially unset)
  91      @since 3.5.0
  92      **/
  93      //head: null,
  94  
  95      //-----------------------------------------------------------------------//
  96      // Public methods
  97      //-----------------------------------------------------------------------//
  98  
  99      /**
 100      Returns the `<td>` Node from the given row and column index.  Alternately,
 101      the `seed` can be a Node.  If so, the nearest ancestor cell is returned.
 102      If the `seed` is a cell, it is returned.  If there is no cell at the given
 103      coordinates, `null` is returned.
 104  
 105      Optionally, include an offset array or string to return a cell near the
 106      cell identified by the `seed`.  The offset can be an array containing the
 107      number of rows to shift followed by the number of columns to shift, or one
 108      of "above", "below", "next", or "previous".
 109  
 110      <pre><code>// Previous cell in the previous row
 111      var cell = table.getCell(e.target, [-1, -1]);
 112  
 113      // Next cell
 114      var cell = table.getCell(e.target, 'next');
 115      var cell = table.getCell(e.taregt, [0, 1];</pre></code>
 116  
 117      This is actually just a pass through to the `bodyView` instance's method
 118      by the same name.
 119  
 120      @method getCell
 121      @param {Number[]|Node} seed Array of row and column indexes, or a Node that
 122          is either the cell itself or a descendant of one.
 123      @param {Number[]|String} [shift] Offset by which to identify the returned
 124          cell Node
 125      @return {Node}
 126      @since 3.5.0
 127      **/
 128      getCell: function (/* seed, shift */) {
 129          return this.body && this.body.getCell &&
 130              this.body.getCell.apply(this.body, arguments);
 131      },
 132  
 133      /**
 134      Returns the generated CSS classname based on the input.  If the `host`
 135      attribute is configured, it will attempt to relay to its `getClassName`
 136      or use its static `NAME` property as a string base.
 137  
 138      If `host` is absent or has neither method nor `NAME`, a CSS classname
 139      will be generated using this class's `NAME`.
 140  
 141      @method getClassName
 142      @param {String} token* Any number of token strings to assemble the
 143          classname from.
 144      @return {String}
 145      @protected
 146      **/
 147      getClassName: function () {
 148          // TODO: add attr with setter for host?
 149          var host = this.host,
 150              NAME = (host && host.constructor.NAME) ||
 151                      this.constructor.NAME;
 152  
 153          if (host && host.getClassName) {
 154              return host.getClassName.apply(host, arguments);
 155          } else {
 156              return Y.ClassNameManager.getClassName
 157                  .apply(Y.ClassNameManager,
 158                         [NAME].concat(toArray(arguments, 0, true)));
 159          }
 160      },
 161  
 162      /**
 163      Relays call to the `bodyView`'s `getRecord` method if it has one.
 164  
 165      @method getRecord
 166      @param {String|Node} seed Node or identifier for a row or child element
 167      @return {Model}
 168      @since 3.6.0
 169      **/
 170      getRecord: function () {
 171          return this.body && this.body.getRecord &&
 172              this.body.getRecord.apply(this.body, arguments);
 173      },
 174  
 175      /**
 176      Returns the `<tr>` Node from the given row index, Model, or Model's
 177      `clientId`.  If the rows haven't been rendered yet, or if the row can't be
 178      found by the input, `null` is returned.
 179  
 180      This is actually just a pass through to the `bodyView` instance's method
 181      by the same name.
 182  
 183      @method getRow
 184      @param {Number|String|Model} id Row index, Model instance, or clientId
 185      @return {Node}
 186      @since 3.5.0
 187      **/
 188      getRow: function (/* id */) {
 189          return this.body && this.body.getRow &&
 190              this.body.getRow.apply(this.body, arguments);
 191      },
 192  
 193  
 194      //-----------------------------------------------------------------------//
 195      // Protected and private methods
 196      //-----------------------------------------------------------------------//
 197      /**
 198      Updates the table's `summary` attribute.
 199  
 200      @method _afterSummaryChange
 201      @param {EventHandle} e The change event
 202      @protected
 203      @since 3.6.0
 204      **/
 205      _afterSummaryChange: function (e) {
 206          this._uiSetSummary(e.newVal);
 207      },
 208  
 209      /**
 210      Updates the table's `<caption>`.
 211  
 212      @method _afterCaptionChange
 213      @param {EventHandle} e The change event
 214      @protected
 215      @since 3.6.0
 216      **/
 217      _afterCaptionChange: function (e) {
 218          this._uiSetCaption(e.newVal);
 219      },
 220  
 221      /**
 222      Updates the table's width.
 223  
 224      @method _afterWidthChange
 225      @param {EventHandle} e The change event
 226      @protected
 227      @since 3.6.0
 228      **/
 229      _afterWidthChange: function (e) {
 230          this._uiSetWidth(e.newVal);
 231      },
 232  
 233      /**
 234      Attaches event subscriptions to relay attribute changes to the child Views.
 235  
 236      @method _bindUI
 237      @protected
 238      @since 3.6.0
 239      **/
 240      _bindUI: function () {
 241          var relay;
 242  
 243          if (!this._eventHandles) {
 244              relay = Y.bind('_relayAttrChange', this);
 245  
 246              this._eventHandles = this.after({
 247                  columnsChange  : relay,
 248                  modelListChange: relay,
 249                  summaryChange  : Y.bind('_afterSummaryChange', this),
 250                  captionChange  : Y.bind('_afterCaptionChange', this),
 251                  widthChange    : Y.bind('_afterWidthChange', this)
 252              });
 253          }
 254      },
 255  
 256      /**
 257      Creates the `<table>`.
 258  
 259      @method _createTable
 260      @return {Node} The `<table>` node
 261      @protected
 262      @since 3.5.0
 263      **/
 264      _createTable: function () {
 265          return Y.Node.create(fromTemplate(this.TABLE_TEMPLATE, {
 266              className: this.getClassName('table')
 267          })).empty();
 268      },
 269  
 270      /**
 271      Calls `render()` on the `bodyView` class instance.
 272  
 273      @method _defRenderBodyFn
 274      @param {EventFacade} e The renderBody event
 275      @protected
 276      @since 3.5.0
 277      **/
 278      _defRenderBodyFn: function (e) {
 279          e.view.render();
 280      },
 281  
 282      /**
 283      Calls `render()` on the `footerView` class instance.
 284  
 285      @method _defRenderFooterFn
 286      @param {EventFacade} e The renderFooter event
 287      @protected
 288      @since 3.5.0
 289      **/
 290      _defRenderFooterFn: function (e) {
 291          e.view.render();
 292      },
 293  
 294      /**
 295      Calls `render()` on the `headerView` class instance.
 296  
 297      @method _defRenderHeaderFn
 298      @param {EventFacade} e The renderHeader event
 299      @protected
 300      @since 3.5.0
 301      **/
 302      _defRenderHeaderFn: function (e) {
 303          e.view.render();
 304      },
 305  
 306      /**
 307      Renders the `<table>` and, if there are associated Views, the `<thead>`,
 308      `<tfoot>`, and `<tbody>` (empty until `syncUI`).
 309  
 310      Assigns the generated table nodes to the `tableNode`, `_theadNode`,
 311      `_tfootNode`, and `_tbodyNode` properties.  Assigns the instantiated Views
 312      to the `head`, `foot`, and `body` properties.
 313  
 314  
 315      @method _defRenderTableFn
 316      @param {EventFacade} e The renderTable event
 317      @protected
 318      @since 3.5.0
 319      **/
 320      _defRenderTableFn: function (e) {
 321          var container = this.get('container'),
 322              attrs = this.getAttrs();
 323  
 324          if (!this.tableNode) {
 325              this.tableNode = this._createTable();
 326          }
 327  
 328          attrs.host  = this.get('host') || this;
 329          attrs.table = this;
 330          attrs.container = this.tableNode;
 331  
 332          this._uiSetCaption(this.get('caption'));
 333          this._uiSetSummary(this.get('summary'));
 334          this._uiSetWidth(this.get('width'));
 335  
 336          if (this.head || e.headerView) {
 337              if (!this.head) {
 338                  this.head = new e.headerView(Y.merge(attrs, e.headerConfig));
 339              }
 340  
 341              this.fire('renderHeader', { view: this.head });
 342          }
 343  
 344          if (this.foot || e.footerView) {
 345              if (!this.foot) {
 346                  this.foot = new e.footerView(Y.merge(attrs, e.footerConfig));
 347              }
 348  
 349              this.fire('renderFooter', { view: this.foot });
 350          }
 351  
 352          attrs.columns = this.displayColumns;
 353  
 354          if (this.body || e.bodyView) {
 355              if (!this.body) {
 356                  this.body = new e.bodyView(Y.merge(attrs, e.bodyConfig));
 357              }
 358  
 359              this.fire('renderBody', { view: this.body });
 360          }
 361  
 362          if (!container.contains(this.tableNode)) {
 363              container.append(this.tableNode);
 364          }
 365  
 366          this._bindUI();
 367      },
 368  
 369      /**
 370      Cleans up state, destroys child views, etc.
 371  
 372      @method destructor
 373      @protected
 374      **/
 375      destructor: function () {
 376          if (this.head && this.head.destroy) {
 377              this.head.destroy();
 378          }
 379          delete this.head;
 380  
 381          if (this.foot && this.foot.destroy) {
 382              this.foot.destroy();
 383          }
 384          delete this.foot;
 385  
 386          if (this.body && this.body.destroy) {
 387              this.body.destroy();
 388          }
 389          delete this.body;
 390  
 391          if (this._eventHandles) {
 392              this._eventHandles.detach();
 393              delete this._eventHandles;
 394          }
 395  
 396          if (this.tableNode) {
 397              this.tableNode.remove().destroy(true);
 398          }
 399      },
 400  
 401      /**
 402      Processes the full column array, distilling the columns down to those that
 403      correspond to cell data columns.
 404  
 405      @method _extractDisplayColumns
 406      @protected
 407      **/
 408      _extractDisplayColumns: function () {
 409          var columns = this.get('columns'),
 410              displayColumns = [];
 411  
 412          function process(cols) {
 413              var i, len, col;
 414  
 415              for (i = 0, len = cols.length; i < len; ++i) {
 416                  col = cols[i];
 417  
 418                  if (isArray(col.children)) {
 419                      process(col.children);
 420                  } else {
 421                      displayColumns.push(col);
 422                  }
 423              }
 424          }
 425  
 426          if (columns) {
 427              process(columns);
 428          }
 429  
 430          /**
 431          Array of the columns that correspond to those with value cells in the
 432          data rows. Excludes colspan header columns (configured with `children`).
 433  
 434          @property displayColumns
 435          @type {Object[]}
 436          @since 3.6.0
 437          **/
 438          this.displayColumns = displayColumns;
 439      },
 440  
 441      /**
 442      Publishes core events.
 443  
 444      @method _initEvents
 445      @protected
 446      @since 3.5.0
 447      **/
 448      _initEvents: function () {
 449          this.publish({
 450              // Y.bind used to allow late binding for method override support
 451              renderTable : { defaultFn: Y.bind('_defRenderTableFn', this) },
 452              renderHeader: { defaultFn: Y.bind('_defRenderHeaderFn', this) },
 453              renderBody  : { defaultFn: Y.bind('_defRenderBodyFn', this) },
 454              renderFooter: { defaultFn: Y.bind('_defRenderFooterFn', this) }
 455          });
 456      },
 457  
 458      /**
 459      Constructor logic.
 460  
 461      @method intializer
 462      @param {Object} config Configuration object passed to the constructor
 463      @protected
 464      @since 3.6.0
 465      **/
 466      initializer: function (config) {
 467          this.host = config.host;
 468  
 469          this._initEvents();
 470  
 471          this._extractDisplayColumns();
 472  
 473          this.after('columnsChange', this._extractDisplayColumns, this);
 474      },
 475  
 476      /**
 477      Relays attribute changes to the child Views.
 478  
 479      @method _relayAttrChange
 480      @param {EventHandle} e The change event
 481      @protected
 482      @since 3.6.0
 483      **/
 484      _relayAttrChange: function (e) {
 485          var attr = e.attrName,
 486              val  = e.newVal;
 487  
 488          if (this.head) {
 489              this.head.set(attr, val);
 490          }
 491  
 492          if (this.foot) {
 493              this.foot.set(attr, val);
 494          }
 495  
 496          if (this.body) {
 497              if (attr === 'columns') {
 498                  val = this.displayColumns;
 499              }
 500  
 501              this.body.set(attr, val);
 502          }
 503      },
 504  
 505      /**
 506      Creates the UI in the configured `container`.
 507  
 508      @method render
 509      @chainable
 510      **/
 511      render: function () {
 512          if (this.get('container')) {
 513              this.fire('renderTable', {
 514                  headerView  : this.get('headerView'),
 515                  headerConfig: this.get('headerConfig'),
 516  
 517                  bodyView    : this.get('bodyView'),
 518                  bodyConfig  : this.get('bodyConfig'),
 519  
 520                  footerView  : this.get('footerView'),
 521                  footerConfig: this.get('footerConfig')
 522              });
 523          }
 524  
 525          return this;
 526      },
 527  
 528      /**
 529      Creates, removes, or updates the table's `<caption>` element per the input
 530      value.  Empty values result in the caption being removed.
 531  
 532      @method _uiSetCaption
 533      @param {String} htmlContent The content to populate the table caption
 534      @protected
 535      @since 3.5.0
 536      **/
 537      _uiSetCaption: function (htmlContent) {
 538          var table   = this.tableNode,
 539              caption = this.captionNode;
 540  
 541          if (htmlContent) {
 542              if (!caption) {
 543                  this.captionNode = caption = Y.Node.create(
 544                      fromTemplate(this.CAPTION_TEMPLATE, {
 545                          className: this.getClassName('caption')
 546                      }));
 547  
 548                  table.prepend(this.captionNode);
 549              }
 550  
 551              caption.setHTML(htmlContent);
 552  
 553          } else if (caption) {
 554              caption.remove(true);
 555  
 556              delete this.captionNode;
 557          }
 558      },
 559  
 560      /**
 561      Updates the table's `summary` attribute with the input value.
 562  
 563      @method _uiSetSummary
 564      @protected
 565      @since 3.5.0
 566      **/
 567      _uiSetSummary: function (summary) {
 568          if (summary) {
 569              this.tableNode.setAttribute('summary', summary);
 570          } else {
 571              this.tableNode.removeAttribute('summary');
 572          }
 573      },
 574  
 575      /**
 576      Sets the `boundingBox` and table width per the input value.
 577  
 578      @method _uiSetWidth
 579      @param {Number|String} width The width to make the table
 580      @protected
 581      @since 3.5.0
 582      **/
 583      _uiSetWidth: function (width) {
 584          var table = this.tableNode;
 585  
 586          // Table width needs to account for borders
 587          table.setStyle('width', !width ? '' :
 588              (this.get('container').get('offsetWidth') -
 589               (parseInt(table.getComputedStyle('borderLeftWidth'), 10)||0) -
 590               (parseInt(table.getComputedStyle('borderLeftWidth'), 10)||0)) +
 591               'px');
 592  
 593          table.setStyle('width', width);
 594      },
 595  
 596      /**
 597      Ensures that the input is a View class or at least has a `render` method.
 598  
 599      @method _validateView
 600      @param {View|Function} val The View class
 601      @return {Boolean}
 602      @protected
 603      **/
 604      _validateView: function (val) {
 605          return isFunction(val) && val.prototype.render;
 606      }
 607  }, {
 608      ATTRS: {
 609          /**
 610          Content for the `<table summary="ATTRIBUTE VALUE HERE">`.  Values
 611          assigned to this attribute will be HTML escaped for security.
 612  
 613          @attribute summary
 614          @type {String}
 615          @default '' (empty string)
 616          @since 3.5.0
 617          **/
 618          //summary: {},
 619  
 620          /**
 621          HTML content of an optional `<caption>` element to appear above the
 622          table.  Leave this config unset or set to a falsy value to remove the
 623          caption.
 624  
 625          @attribute caption
 626          @type HTML
 627          @default undefined (initially unset)
 628          @since 3.6.0
 629          **/
 630          //caption: {},
 631  
 632          /**
 633          Columns to include in the rendered table.
 634  
 635          This attribute takes an array of objects. Each object is considered a
 636          data column or header cell to be rendered.  How the objects are
 637          translated into markup is delegated to the `headerView`, `bodyView`,
 638          and `footerView`.
 639  
 640          The raw value is passed to the `headerView` and `footerView`.  The
 641          `bodyView` receives the instance's `displayColumns` array, which is
 642          parsed from the columns array.  If there are no nested columns (columns
 643          configured with a `children` array), the `displayColumns` is the same
 644          as the raw value.
 645  
 646          @attribute columns
 647          @type {Object[]}
 648          @since 3.6.0
 649          **/
 650          columns: {
 651              validator: isArray
 652          },
 653  
 654          /**
 655          Width of the table including borders.  This value requires units, so
 656          `200` is invalid, but `'200px'` is valid.  Setting the empty string
 657          (the default) will allow the browser to set the table width.
 658  
 659          @attribute width
 660          @type {String}
 661          @default ''
 662          @since 3.6.0
 663          **/
 664          width: {
 665              value: '',
 666              validator: YLang.isString
 667          },
 668  
 669          /**
 670          An instance of this class is used to render the contents of the
 671          `<thead>`&mdash;the column headers for the table.
 672  
 673          The instance of this View will be assigned to the instance's `head`
 674          property.
 675  
 676          It is not strictly necessary that the class function assigned here be
 677          a View subclass.  It must however have a `render()` method.
 678  
 679          @attribute headerView
 680          @type {Function|Object}
 681          @default Y.DataTable.HeaderView
 682          @since 3.6.0
 683          **/
 684          headerView: {
 685              value: Y.DataTable.HeaderView,
 686              validator: '_validateView'
 687          },
 688  
 689          /**
 690          Configuration overrides used when instantiating the `headerView`
 691          instance.
 692  
 693          @attribute headerConfig
 694          @type {Object}
 695          @since 3.6.0
 696          **/
 697          //headerConfig: {},
 698  
 699          /**
 700          An instance of this class is used to render the contents of the
 701          `<tfoot>` (if appropriate).
 702  
 703          The instance of this View will be assigned to the instance's `foot`
 704          property.
 705  
 706          It is not strictly necessary that the class function assigned here be
 707          a View subclass.  It must however have a `render()` method.
 708  
 709          @attribute footerView
 710          @type {Function|Object}
 711          @since 3.6.0
 712          **/
 713          footerView: {
 714              validator: '_validateView'
 715          },
 716  
 717          /**
 718          Configuration overrides used when instantiating the `footerView`
 719          instance.
 720  
 721          @attribute footerConfig
 722          @type {Object}
 723          @since 3.6.0
 724          **/
 725          //footerConfig: {},
 726  
 727          /**
 728          An instance of this class is used to render the contents of the table's
 729          `<tbody>`&mdash;the data cells in the table.
 730  
 731          The instance of this View will be assigned to the instance's `body`
 732          property.
 733  
 734          It is not strictly necessary that the class function assigned here be
 735          a View subclass.  It must however have a `render()` method.
 736  
 737          @attribute bodyView
 738          @type {Function|Object}
 739          @default Y.DataTable.BodyView
 740          @since 3.6.0
 741          **/
 742          bodyView: {
 743              value: Y.DataTable.BodyView,
 744              validator: '_validateView'
 745          }
 746  
 747          /**
 748          Configuration overrides used when instantiating the `bodyView`
 749          instance.
 750  
 751          @attribute bodyConfig
 752          @type {Object}
 753          @since 3.6.0
 754          **/
 755          //bodyConfig: {}
 756      }
 757  });
 758  
 759  
 760  
 761  
 762  }, '3.17.2', {"requires": ["datatable-core", "datatable-head", "datatable-body", "view", "classnamemanager"]});


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