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