// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * @fileoverview This implements a table header. */ cr.define('cr.ui.table', function() { /** @const */ var TableSplitter = cr.ui.TableSplitter; /** * Creates a new table header. * @param {Object=} opt_propertyBag Optional properties. * @constructor * @extends {HTMLDivElement} */ var TableHeader = cr.ui.define('div'); TableHeader.prototype = { __proto__: HTMLDivElement.prototype, table_: null, /** * Initializes the element. */ decorate: function() { this.className = 'table-header'; this.headerInner_ = this.ownerDocument.createElement('div'); this.headerInner_.className = 'table-header-inner'; this.appendChild(this.headerInner_); }, /** * Updates table header width. Header width depends on list having a * vertical scrollbar. */ updateWidth: function() { // Header should not span over the vertical scrollbar of the list. var list = this.table_.querySelector('list'); this.headerInner_.style.width = list.clientWidth + 'px'; }, /** * Resizes columns. */ resize: function() { var cm = this.table_.columnModel; var headerCells = this.querySelectorAll('.table-header-cell'); if (headerCells.length != cm.size) { this.redraw(); return; } this.headerInner_.textContent = ''; for (var i = 0; i < cm.size; i++) { headerCells[i].style.width = cm.getWidth(i) + '%'; this.headerInner_.appendChild(headerCells[i]); } this.appendSplitters_(); }, batchCount_: 0, startBatchUpdates: function() { this.batchCount_++; }, endBatchUpdates: function() { this.batchCount_--; if (this.batchCount_ == 0) this.redraw(); }, /** * Redraws table header. */ redraw: function() { if (this.batchCount_ != 0) return; var cm = this.table_.columnModel; var dm = this.table_.dataModel; this.updateWidth(); this.headerInner_.textContent = ''; if (!cm || ! dm) { return; } for (var i = 0; i < cm.size; i++) { var cell = this.ownerDocument.createElement('div'); cell.style.width = cm.getWidth(i) + '%'; cell.className = 'table-header-cell'; if (dm.isSortable(cm.getId(i))) cell.addEventListener('click', this.createSortFunction_(i).bind(this)); cell.appendChild(this.createHeaderLabel_(i)); this.headerInner_.appendChild(cell); } this.appendSplitters_(); }, /** * Appends column splitters to the table header. */ appendSplitters_: function() { var cm = this.table_.columnModel; var leftPercent = 0; for (var i = 0; i < cm.size - 1; i++) { leftPercent += cm.getWidth(i); // splitter should use CSS for background image. var splitter = new TableSplitter({table: this.table_}); splitter.columnIndex = i; var rtl = this.ownerDocument.defaultView.getComputedStyle(this). direction == 'rtl'; splitter.style.left = rtl ? 100 - leftPercent + '%' : leftPercent + '%'; this.headerInner_.appendChild(splitter); } }, /** * Renders column header. Appends text label and sort arrow if needed. * @param {number} index Column index. */ createHeaderLabel_: function(index) { var cm = this.table_.columnModel; var dm = this.table_.dataModel; var labelDiv = this.ownerDocument.createElement('div'); labelDiv.className = 'table-header-label'; if (cm.isEndAlign(index)) labelDiv.style.textAlign = 'end'; var span = this.ownerDocument.createElement('span'); span.appendChild(cm.renderHeader(index, this.table_)); span.style.padding = '0'; if (dm) { if (dm.sortStatus.field == cm.getId(index)) { if (dm.sortStatus.direction == 'desc') span.className = 'table-header-sort-image-desc'; else span.className = 'table-header-sort-image-asc'; } } labelDiv.appendChild(span); return labelDiv; }, /** * Creates sort function for given column. * @param {number} index The index of the column to sort by. */ createSortFunction_: function(index) { return function() { this.table_.sort(index); }.bind(this); }, }; /** * The table associated with the header. * @type {cr.ui.Table} */ cr.defineProperty(TableHeader, 'table'); return { TableHeader: TableHeader }; });