Home | History | Annotate | Download | only in table
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 /**
      6  * @fileoverview This implements a table header.
      7  */
      8 
      9 cr.define('cr.ui.table', function() {
     10   /** @const */ var TableSplitter = cr.ui.TableSplitter;
     11 
     12   /**
     13    * Creates a new table header.
     14    * @param {Object=} opt_propertyBag Optional properties.
     15    * @constructor
     16    * @extends {HTMLDivElement}
     17    */
     18   var TableHeader = cr.ui.define('div');
     19 
     20   TableHeader.prototype = {
     21     __proto__: HTMLDivElement.prototype,
     22 
     23     table_: null,
     24 
     25     /**
     26      * Initializes the element.
     27      */
     28     decorate: function() {
     29       this.className = 'table-header';
     30 
     31       this.headerInner_ = this.ownerDocument.createElement('div');
     32       this.headerInner_.className = 'table-header-inner';
     33       this.appendChild(this.headerInner_);
     34     },
     35 
     36     /**
     37      * Updates table header width. Header width depends on list having a
     38      * vertical scrollbar.
     39      */
     40     updateWidth: function() {
     41       // Header should not span over the vertical scrollbar of the list.
     42       var list = this.table_.querySelector('list');
     43       this.headerInner_.style.width = list.clientWidth + 'px';
     44     },
     45 
     46     /**
     47      * Resizes columns.
     48      */
     49     resize: function() {
     50       var cm = this.table_.columnModel;
     51 
     52       var headerCells = this.querySelectorAll('.table-header-cell');
     53       if (headerCells.length != cm.size) {
     54         this.redraw();
     55         return;
     56       }
     57       this.headerInner_.textContent = '';
     58       for (var i = 0; i < cm.size; i++) {
     59         headerCells[i].style.width = cm.getWidth(i) + '%';
     60         this.headerInner_.appendChild(headerCells[i]);
     61       }
     62       this.appendSplitters_();
     63     },
     64 
     65     batchCount_: 0,
     66 
     67     startBatchUpdates: function() {
     68       this.batchCount_++;
     69     },
     70 
     71     endBatchUpdates: function() {
     72       this.batchCount_--;
     73       if (this.batchCount_ == 0)
     74         this.redraw();
     75     },
     76 
     77     /**
     78      * Redraws table header.
     79      */
     80     redraw: function() {
     81       if (this.batchCount_ != 0)
     82         return;
     83 
     84       var cm = this.table_.columnModel;
     85       var dm = this.table_.dataModel;
     86 
     87       this.updateWidth();
     88       this.headerInner_.textContent = '';
     89 
     90       if (!cm || ! dm) {
     91         return;
     92       }
     93 
     94       for (var i = 0; i < cm.size; i++) {
     95         var cell = this.ownerDocument.createElement('div');
     96         cell.style.width = cm.getWidth(i) + '%';
     97         cell.className = 'table-header-cell';
     98         if (dm.isSortable(cm.getId(i)))
     99           cell.addEventListener('click',
    100                                 this.createSortFunction_(i).bind(this));
    101 
    102         cell.appendChild(this.createHeaderLabel_(i));
    103         this.headerInner_.appendChild(cell);
    104       }
    105       this.appendSplitters_();
    106     },
    107 
    108     /**
    109      * Appends column splitters to the table header.
    110      */
    111     appendSplitters_: function() {
    112       var cm = this.table_.columnModel;
    113 
    114       var leftPercent = 0;
    115       for (var i = 0; i < cm.size - 1; i++) {
    116         leftPercent += cm.getWidth(i);
    117 
    118         // splitter should use CSS for background image.
    119         var splitter = new TableSplitter({table: this.table_});
    120         splitter.columnIndex = i;
    121 
    122         var rtl = this.ownerDocument.defaultView.getComputedStyle(this).
    123             direction == 'rtl';
    124         splitter.style.left = rtl ? 100 - leftPercent + '%' : leftPercent + '%';
    125 
    126         this.headerInner_.appendChild(splitter);
    127       }
    128     },
    129 
    130     /**
    131      * Renders column header. Appends text label and sort arrow if needed.
    132      * @param {number} index Column index.
    133      */
    134     createHeaderLabel_: function(index) {
    135       var cm = this.table_.columnModel;
    136       var dm = this.table_.dataModel;
    137 
    138       var labelDiv = this.ownerDocument.createElement('div');
    139       labelDiv.className = 'table-header-label';
    140 
    141       if (cm.isEndAlign(index))
    142         labelDiv.style.textAlign = 'end';
    143       var span = this.ownerDocument.createElement('span');
    144       span.appendChild(cm.renderHeader(index, this.table_));
    145       span.style.padding = '0';
    146 
    147       if (dm) {
    148         if (dm.sortStatus.field == cm.getId(index)) {
    149           if (dm.sortStatus.direction == 'desc')
    150             span.className = 'table-header-sort-image-desc';
    151           else
    152             span.className = 'table-header-sort-image-asc';
    153         }
    154       }
    155       labelDiv.appendChild(span);
    156       return labelDiv;
    157     },
    158 
    159     /**
    160      * Creates sort function for given column.
    161      * @param {number} index The index of the column to sort by.
    162      */
    163     createSortFunction_: function(index) {
    164       return function() {
    165         this.table_.sort(index);
    166       }.bind(this);
    167     },
    168   };
    169 
    170   /**
    171    * The table associated with the header.
    172    * @type {cr.ui.Table}
    173    */
    174   cr.defineProperty(TableHeader, 'table');
    175 
    176   return {
    177     TableHeader: TableHeader
    178   };
    179 });
    180