diff options
Diffstat (limited to 'chromium/chrome/browser/resources/file_manager/foreground/js/file_table.js')
-rw-r--r-- | chromium/chrome/browser/resources/file_manager/foreground/js/file_table.js | 1036 |
1 files changed, 0 insertions, 1036 deletions
diff --git a/chromium/chrome/browser/resources/file_manager/foreground/js/file_table.js b/chromium/chrome/browser/resources/file_manager/foreground/js/file_table.js deleted file mode 100644 index 3280de32953..00000000000 --- a/chromium/chrome/browser/resources/file_manager/foreground/js/file_table.js +++ /dev/null @@ -1,1036 +0,0 @@ -// 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. - -'use strict'; - -/** - * Namespace for utility functions. - */ -var filelist = {}; - -/** - * Custom column model for advanced auto-resizing. - * - * @param {Array.<cr.ui.table.TableColumn>} tableColumns Table columns. - * @extends {cr.ui.table.TableColumnModel} - * @constructor - */ -function FileTableColumnModel(tableColumns) { - cr.ui.table.TableColumnModel.call(this, tableColumns); -} - -/** - * The columns whose index is less than the constant are resizable. - * @const - * @type {number} - * @private - */ -FileTableColumnModel.RESIZABLE_LENGTH_ = 4; - -/** - * Inherits from cr.ui.TableColumnModel. - */ -FileTableColumnModel.prototype.__proto__ = - cr.ui.table.TableColumnModel.prototype; - -/** - * Minimum width of column. - * @const - * @type {number} - * @private - */ -FileTableColumnModel.MIN_WIDTH_ = 10; - -/** - * Sets column width so that the column dividers move to the specified position. - * This function also check the width of each column and keep the width larger - * than MIN_WIDTH_. - * - * @private - * @param {Array.<number>} newPos Positions of each column dividers. - */ -FileTableColumnModel.prototype.applyColumnPositions_ = function(newPos) { - // Check the minimum width and adjust the positions. - for (var i = 0; i < newPos.length - 2; i++) { - if (newPos[i + 1] - newPos[i] < FileTableColumnModel.MIN_WIDTH_) { - newPos[i + 1] = newPos[i] + FileTableColumnModel.MIN_WIDTH_; - } - } - for (var i = newPos.length - 1; i >= 2; i--) { - if (newPos[i] - newPos[i - 1] < FileTableColumnModel.MIN_WIDTH_) { - newPos[i - 1] = newPos[i] - FileTableColumnModel.MIN_WIDTH_; - } - } - // Set the new width of columns - for (var i = 0; i < FileTableColumnModel.RESIZABLE_LENGTH_; i++) { - this.columns_[i].width = newPos[i + 1] - newPos[i]; - } -}; - -/** - * Normalizes widths to make their sum 100% if possible. Uses the proportional - * approach with some additional constraints. - * - * @param {number} contentWidth Target width. - * @override - */ -FileTableColumnModel.prototype.normalizeWidths = function(contentWidth) { - var totalWidth = 0; - var fixedWidth = 0; - // Some columns have fixed width. - for (var i = 0; i < this.columns_.length; i++) { - if (i < FileTableColumnModel.RESIZABLE_LENGTH_) - totalWidth += this.columns_[i].width; - else - fixedWidth += this.columns_[i].width; - } - var newTotalWidth = Math.max(contentWidth - fixedWidth, 0); - var positions = [0]; - var sum = 0; - for (var i = 0; i < FileTableColumnModel.RESIZABLE_LENGTH_; i++) { - var column = this.columns_[i]; - sum += column.width; - // Faster alternative to Math.floor for non-negative numbers. - positions[i + 1] = ~~(newTotalWidth * sum / totalWidth); - } - this.applyColumnPositions_(positions); -}; - -/** - * Handles to the start of column resizing by splitters. - */ -FileTableColumnModel.prototype.handleSplitterDragStart = function() { - this.columnPos_ = [0]; - for (var i = 0; i < this.columns_.length; i++) { - this.columnPos_[i + 1] = this.columns_[i].width + this.columnPos_[i]; - } -}; - -/** - * Handles to the end of column resizing by splitters. - */ -FileTableColumnModel.prototype.handleSplitterDragEnd = function() { - this.columnPos_ = null; -}; - -/** - * Sets the width of column with keeping the total width of table. - * @param {number} columnIndex Index of column that is resized. - * @param {number} columnWidth New width of the column. - */ -FileTableColumnModel.prototype.setWidthAndKeepTotal = function( - columnIndex, columnWidth) { - // Skip to resize 'selection' column - if (columnIndex < 0 || - columnIndex >= FileTableColumnModel.RESIZABLE_LENGTH_ || - !this.columnPos_) { - return; - } - - // Calculate new positions of column splitters. - var newPosStart = - this.columnPos_[columnIndex] + Math.max(columnWidth, - FileTableColumnModel.MIN_WIDTH_); - var newPos = []; - var posEnd = this.columnPos_[FileTableColumnModel.RESIZABLE_LENGTH_]; - for (var i = 0; i < columnIndex + 1; i++) { - newPos[i] = this.columnPos_[i]; - } - for (var i = columnIndex + 1; - i < FileTableColumnModel.RESIZABLE_LENGTH_; - i++) { - var posStart = this.columnPos_[columnIndex + 1]; - newPos[i] = (posEnd - newPosStart) * - (this.columnPos_[i] - posStart) / - (posEnd - posStart) + - newPosStart; - // Faster alternative to Math.floor for non-negative numbers. - newPos[i] = ~~newPos[i]; - } - newPos[columnIndex] = this.columnPos_[columnIndex]; - newPos[FileTableColumnModel.RESIZABLE_LENGTH_] = posEnd; - this.applyColumnPositions_(newPos); - - // Notifiy about resizing - cr.dispatchSimpleEvent(this, 'resize'); -}; - -/** - * Custom splitter that resizes column with retaining the sum of all the column - * width. - */ -var FileTableSplitter = cr.ui.define('div'); - -/** - * Inherits from cr.ui.TableSplitter. - */ -FileTableSplitter.prototype.__proto__ = cr.ui.TableSplitter.prototype; - -/** - * Handles the drag start event. - */ -FileTableSplitter.prototype.handleSplitterDragStart = function() { - cr.ui.TableSplitter.prototype.handleSplitterDragStart.call(this); - this.table_.columnModel.handleSplitterDragStart(); -}; - -/** - * Handles the drag move event. - * @param {number} deltaX Horizontal mouse move offset. - */ -FileTableSplitter.prototype.handleSplitterDragMove = function(deltaX) { - this.table_.columnModel.setWidthAndKeepTotal(this.columnIndex, - this.columnWidth_ + deltaX, - true); -}; - -/** - * Handles the drag end event. - */ -FileTableSplitter.prototype.handleSplitterDragEnd = function() { - cr.ui.TableSplitter.prototype.handleSplitterDragEnd.call(this); - this.table_.columnModel.handleSplitterDragEnd(); -}; - -/** - * File list Table View. - * @constructor - */ -function FileTable() { - throw new Error('Designed to decorate elements'); -} - -/** - * Inherits from cr.ui.Table. - */ -FileTable.prototype.__proto__ = cr.ui.Table.prototype; - -/** - * Decorates the element. - * @param {HTMLElement} self Table to decorate. - * @param {MetadataCache} metadataCache To retrieve metadata. - * @param {boolean} fullPage True if it's full page File Manager, - * False if a file open/save dialog. - */ -FileTable.decorate = function(self, metadataCache, fullPage) { - cr.ui.Table.decorate(self); - self.__proto__ = FileTable.prototype; - self.metadataCache_ = metadataCache; - self.collator_ = Intl.Collator([], {numeric: true, sensitivity: 'base'}); - - var columns = [ - new cr.ui.table.TableColumn('name', str('NAME_COLUMN_LABEL'), - fullPage ? 386 : 324), - new cr.ui.table.TableColumn('size', str('SIZE_COLUMN_LABEL'), - 110, true), - new cr.ui.table.TableColumn('type', str('TYPE_COLUMN_LABEL'), - fullPage ? 110 : 110), - new cr.ui.table.TableColumn('modificationTime', - str('DATE_COLUMN_LABEL'), - fullPage ? 150 : 210) - ]; - - columns[0].renderFunction = self.renderName_.bind(self); - columns[1].renderFunction = self.renderSize_.bind(self); - columns[1].defaultOrder = 'desc'; - columns[2].renderFunction = self.renderType_.bind(self); - columns[3].renderFunction = self.renderDate_.bind(self); - columns[3].defaultOrder = 'desc'; - - var tableColumnModelClass; - tableColumnModelClass = FileTableColumnModel; - if (self.showCheckboxes) { - columns.push(new cr.ui.table.TableColumn('selection', - '', - 50, true)); - columns[4].renderFunction = self.renderSelection_.bind(self); - columns[4].headerRenderFunction = - self.renderSelectionColumnHeader_.bind(self); - columns[4].fixed = true; - } - - var columnModel = Object.create(tableColumnModelClass.prototype, { - /** - * The number of columns. - * @type {number} - */ - size: { - /** - * @this {FileTableColumnModel} - * @return {number} Number of columns. - */ - get: function() { - return this.totalSize; - } - }, - - /** - * The number of columns. - * @type {number} - */ - totalSize: { - /** - * @this {FileTableColumnModel} - * @return {number} Number of columns. - */ - get: function() { - return columns.length; - } - }, - - /** - * Obtains a column by the specified horizontal position. - */ - getHitColumn: { - /** - * @this {FileTableColumnModel} - * @param {number} x Horizontal position. - * @return {object} The object that contains column index, column width, - * and hitPosition where the horizontal position is hit in the column. - */ - value: function(x) { - for (var i = 0; x >= this.columns_[i].width; i++) { - x -= this.columns_[i].width; - } - if (i >= this.columns_.length) - return null; - return {index: i, hitPosition: x, width: this.columns_[i].width}; - } - } - }); - - tableColumnModelClass.call(columnModel, columns); - self.columnModel = columnModel; - self.setDateTimeFormat(true); - self.setRenderFunction(self.renderTableRow_.bind(self, - self.getRenderFunction())); - - self.scrollBar_ = MainPanelScrollBar(); - self.scrollBar_.initialize(self, self.list); - // Keep focus on the file list when clicking on the header. - self.header.addEventListener('mousedown', function(e) { - self.list.focus(); - e.preventDefault(); - }); - - var handleSelectionChange = function() { - var selectAll = self.querySelector('#select-all-checkbox'); - if (selectAll) - self.updateSelectAllCheckboxState_(selectAll); - }; - - self.relayoutAggregation_ = - new AsyncUtil.Aggregation(self.relayoutImmediately_.bind(self)); - - Object.defineProperty(self.list_, 'selectionModel', { - /** - * @this {cr.ui.List} - * @return {cr.ui.ListSelectionModel} The current selection model. - */ - get: function() { - return this.selectionModel_; - }, - /** - * @this {cr.ui.List} - */ - set: function(value) { - var sm = this.selectionModel; - if (sm) - sm.removeEventListener('change', handleSelectionChange); - - util.callInheritedSetter(this, 'selectionModel', value); - sm = value; - - if (sm) - sm.addEventListener('change', handleSelectionChange); - handleSelectionChange(); - } - }); - - // Override header#redraw to use FileTableSplitter. - self.header_.redraw = function() { - this.__proto__.redraw.call(this); - // Extend table splitters - var splitters = this.querySelectorAll('.table-header-splitter'); - for (var i = 0; i < splitters.length; i++) { - if (splitters[i] instanceof FileTableSplitter) - continue; - FileTableSplitter.decorate(splitters[i]); - } - }; - - // Save the last selection. This is used by shouldStartDragSelection. - self.list.addEventListener('mousedown', function(e) { - this.lastSelection_ = this.selectionModel.selectedIndexes; - }.bind(self), true); - self.list.shouldStartDragSelection = - self.shouldStartDragSelection_.bind(self); - - /** - * Obtains the index list of elements that are hit by the point or the - * rectangle. - * - * @param {number} x X coordinate value. - * @param {number} y Y coordinate value. - * @param {=number} opt_width Width of the coordinate. - * @param {=number} opt_height Height of the coordinate. - * @return {Array.<number>} Index list of hit elements. - */ - self.list.getHitElements = function(x, y, opt_width, opt_height) { - var currentSelection = []; - var bottom = y + (opt_height || 0); - for (var i = 0; i < this.selectionModel_.length; i++) { - var itemMetrics = this.getHeightsForIndex_(i); - if (itemMetrics.top < bottom && itemMetrics.top + itemMetrics.height >= y) - currentSelection.push(i); - } - return currentSelection; - }; -}; - -/** - * Sets date and time format. - * @param {boolean} use12hourClock True if 12 hours clock, False if 24 hours. - */ -FileTable.prototype.setDateTimeFormat = function(use12hourClock) { - this.timeFormatter_ = Intl.DateTimeFormat( - [] /* default locale */, - {hour: 'numeric', minute: 'numeric', - hour12: use12hourClock}); - this.dateFormatter_ = Intl.DateTimeFormat( - [] /* default locale */, - {year: 'numeric', month: 'short', day: 'numeric', - hour: 'numeric', minute: 'numeric', - hour12: use12hourClock}); -}; - -/** - * Obtains if the drag selection should be start or not by referring the mouse - * event. - * @param {MouseEvent} event Drag start event. - * @return {boolean} True if the mouse is hit to the background of the list. - * @private - */ -FileTable.prototype.shouldStartDragSelection_ = function(event) { - // If the shift key is pressed, it should starts drag selection. - if (event.shiftKey) - return true; - - // If the position values are negative, it points the out of list. - // It should start the drag selection. - var pos = DragSelector.getScrolledPosition(this.list, event); - if (!pos) - return false; - if (pos.x < 0 || pos.y < 0) - return true; - - // If the item index is out of range, it should start the drag selection. - var itemHeight = this.list.measureItem().height; - // Faster alternative to Math.floor for non-negative numbers. - var itemIndex = ~~(pos.y / itemHeight); - if (itemIndex >= this.list.dataModel.length) - return true; - - // If the pointed item is already selected, it should not start the drag - // selection. - if (this.lastSelection_.indexOf(itemIndex) != -1) - return false; - - // If the horizontal value is not hit to column, it should start the drag - // selection. - var hitColumn = this.columnModel.getHitColumn(pos.x); - if (!hitColumn) - return true; - - // Check if the point is on the column contents or not. - var item = this.list.getListItemByIndex(itemIndex); - switch (this.columnModel.columns_[hitColumn.index].id) { - case 'name': - var spanElement = item.querySelector('.filename-label span'); - var spanRect = spanElement.getBoundingClientRect(); - // The this.list.cachedBounds_ object is set by - // DragSelector.getScrolledPosition. - if (!this.list.cachedBounds) - return true; - var textRight = - spanRect.left - this.list.cachedBounds.left + spanRect.width; - return textRight <= hitColumn.hitPosition; - default: - return true; - } -}; - -/** - * Update check and disable states of the 'Select all' checkbox. - * @param {HTMLInputElement} checkbox The checkbox. If not passed, using - * the default one. - * @private - */ -FileTable.prototype.updateSelectAllCheckboxState_ = function(checkbox) { - // TODO(serya): introduce this.selectionModel.selectedCount. - checkbox.checked = this.dataModel.length > 0 && - this.dataModel.length == this.selectionModel.selectedIndexes.length; - checkbox.disabled = this.dataModel.length == 0; -}; - -/** - * Prepares the data model to be sorted by columns. - * @param {cr.ui.ArrayDataModel} dataModel Data model to prepare. - */ -FileTable.prototype.setupCompareFunctions = function(dataModel) { - dataModel.setCompareFunction('name', - this.compareName_.bind(this)); - dataModel.setCompareFunction('modificationTime', - this.compareMtime_.bind(this)); - dataModel.setCompareFunction('size', - this.compareSize_.bind(this)); - dataModel.setCompareFunction('type', - this.compareType_.bind(this)); -}; - -/** - * Render the Name column of the detail table. - * - * Invoked by cr.ui.Table when a file needs to be rendered. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderName_ = function(entry, columnId, table) { - var label = this.ownerDocument.createElement('div'); - label.appendChild(this.renderIconType_(entry, columnId, table)); - label.entry = entry; - label.className = 'detail-name'; - label.appendChild(filelist.renderFileNameLabel(this.ownerDocument, entry)); - return label; -}; - -/** - * Render the Selection column of the detail table. - * - * Invoked by cr.ui.Table when a file needs to be rendered. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderSelection_ = function(entry, columnId, table) { - var label = this.ownerDocument.createElement('div'); - label.className = 'selection-label'; - if (this.selectionModel.multiple) { - var checkBox = this.ownerDocument.createElement('input'); - filelist.decorateSelectionCheckbox(checkBox, entry, this.list); - label.appendChild(checkBox); - } - return label; -}; - -/** - * Render the Size column of the detail table. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderSize_ = function(entry, columnId, table) { - var div = this.ownerDocument.createElement('div'); - div.className = 'size'; - this.updateSize_( - div, entry, this.metadataCache_.getCached(entry, 'filesystem')); - - return div; -}; - -/** - * Sets up or updates the size cell. - * - * @param {HTMLDivElement} div The table cell. - * @param {Entry} entry The corresponding entry. - * @param {Object} filesystemProps Metadata. - * @private - */ -FileTable.prototype.updateSize_ = function(div, entry, filesystemProps) { - if (!filesystemProps) { - div.textContent = '...'; - } else if (filesystemProps.size == -1) { - div.textContent = '--'; - } else if (filesystemProps.size == 0 && - FileType.isHosted(entry)) { - div.textContent = '--'; - } else { - div.textContent = util.bytesToString(filesystemProps.size); - } -}; - -/** - * Render the Type column of the detail table. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderType_ = function(entry, columnId, table) { - var div = this.ownerDocument.createElement('div'); - div.className = 'type'; - div.textContent = FileType.getTypeString(entry); - return div; -}; - -/** - * Render the Date column of the detail table. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderDate_ = function(entry, columnId, table) { - var div = this.ownerDocument.createElement('div'); - div.className = 'date'; - - this.updateDate_(div, - this.metadataCache_.getCached(entry, 'filesystem')); - return div; -}; - -/** - * Sets up or updates the date cell. - * - * @param {HTMLDivElement} div The table cell. - * @param {Object} filesystemProps Metadata. - * @private - */ -FileTable.prototype.updateDate_ = function(div, filesystemProps) { - if (!filesystemProps) { - div.textContent = '...'; - return; - } - - var modTime = filesystemProps.modificationTime; - var today = new Date(); - today.setHours(0); - today.setMinutes(0); - today.setSeconds(0); - today.setMilliseconds(0); - - /** - * Number of milliseconds in a day. - */ - var MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; - - if (modTime >= today && - modTime < today.getTime() + MILLISECONDS_IN_DAY) { - div.textContent = strf('TIME_TODAY', this.timeFormatter_.format(modTime)); - } else if (modTime >= today - MILLISECONDS_IN_DAY && modTime < today) { - div.textContent = strf('TIME_YESTERDAY', - this.timeFormatter_.format(modTime)); - } else { - div.textContent = - this.dateFormatter_.format(filesystemProps.modificationTime); - } -}; - -/** - * Updates the file metadata in the table item. - * - * @param {Element} item Table item. - * @param {Entry} entry File entry. - */ -FileTable.prototype.updateFileMetadata = function(item, entry) { - var props = this.metadataCache_.getCached(entry, 'filesystem'); - this.updateDate_(item.querySelector('.date'), props); - this.updateSize_(item.querySelector('.size'), entry, props); -}; - -/** - * Updates list items 'in place' on metadata change. - * @param {string} type Type of metadata change. - * @param {Object.<sting, Object>} propsMap Map from entry URLs to metadata - * properties. - */ -FileTable.prototype.updateListItemsMetadata = function(type, propsMap) { - var forEachCell = function(selector, callback) { - var cells = this.querySelectorAll(selector); - for (var i = 0; i < cells.length; i++) { - var cell = cells[i]; - var listItem = this.list_.getListItemAncestor(cell); - var entry = this.dataModel.item(listItem.listIndex); - if (entry) { - var props = propsMap[entry.toURL()]; - if (props) - callback.call(this, cell, entry, props, listItem); - } - } - }.bind(this); - if (type == 'filesystem') { - forEachCell('.table-row-cell > .date', function(item, entry, props) { - this.updateDate_(item, props); - }); - forEachCell('.table-row-cell > .size', function(item, entry, props) { - this.updateSize_(item, entry, props); - }); - } else if (type == 'drive') { - // The cell name does not matter as the entire list item is needed. - forEachCell('.table-row-cell > .date', - function(item, entry, props, listItem) { - filelist.updateListItemDriveProps(listItem, props); - }); - } -}; - -/** - * Compare by mtime first, then by name. - * @param {Entry} a First entry. - * @param {Entry} b Second entry. - * @return {number} Compare result. - * @private - */ -FileTable.prototype.compareName_ = function(a, b) { - return this.collator_.compare(a.name, b.name); -}; - -/** - * Compare by mtime first, then by name. - * @param {Entry} a First entry. - * @param {Entry} b Second entry. - * @return {number} Compare result. - * @private - */ -FileTable.prototype.compareMtime_ = function(a, b) { - var aCachedFilesystem = this.metadataCache_.getCached(a, 'filesystem'); - var aTime = aCachedFilesystem ? aCachedFilesystem.modificationTime : 0; - - var bCachedFilesystem = this.metadataCache_.getCached(b, 'filesystem'); - var bTime = bCachedFilesystem ? bCachedFilesystem.modificationTime : 0; - - if (aTime > bTime) - return 1; - - if (aTime < bTime) - return -1; - - return this.collator_.compare(a.name, b.name); -}; - -/** - * Compare by size first, then by name. - * @param {Entry} a First entry. - * @param {Entry} b Second entry. - * @return {number} Compare result. - * @private - */ -FileTable.prototype.compareSize_ = function(a, b) { - var aCachedFilesystem = this.metadataCache_.getCached(a, 'filesystem'); - var aSize = aCachedFilesystem ? aCachedFilesystem.size : 0; - - var bCachedFilesystem = this.metadataCache_.getCached(b, 'filesystem'); - var bSize = bCachedFilesystem ? bCachedFilesystem.size : 0; - - if (aSize != bSize) return aSize - bSize; - return this.collator_.compare(a.name, b.name); -}; - -/** - * Compare by type first, then by subtype and then by name. - * @param {Entry} a First entry. - * @param {Entry} b Second entry. - * @return {number} Compare result. - * @private - */ -FileTable.prototype.compareType_ = function(a, b) { - // Directories precede files. - if (a.isDirectory != b.isDirectory) - return Number(b.isDirectory) - Number(a.isDirectory); - - var aType = FileType.getTypeString(a); - var bType = FileType.getTypeString(b); - - var result = this.collator_.compare(aType, bType); - if (result != 0) - return result; - - return this.collator_.compare(a.name, b.name); -}; - -/** - * Renders table row. - * @param {function(Entry, cr.ui.Table)} baseRenderFunction Base renderer. - * @param {Entry} entry Corresponding entry. - * @return {HTMLLiElement} Created element. - * @private - */ -FileTable.prototype.renderTableRow_ = function(baseRenderFunction, entry) { - var item = baseRenderFunction(entry, this); - filelist.decorateListItem(item, entry, this.metadataCache_); - return item; -}; - -/** - * Renders the name column header. - * @param {string} name Localized column name. - * @return {HTMLLiElement} Created element. - * @private - */ -FileTable.prototype.renderNameColumnHeader_ = function(name) { - if (!this.selectionModel.multiple) - return this.ownerDocument.createTextNode(name); - - var input = this.ownerDocument.createElement('input'); - input.setAttribute('type', 'checkbox'); - input.setAttribute('tabindex', -1); - input.id = 'select-all-checkbox'; - input.className = 'common'; - - this.updateSelectAllCheckboxState_(input); - - input.addEventListener('click', function(event) { - if (input.checked) - this.selectionModel.selectAll(); - else - this.selectionModel.unselectAll(); - event.stopPropagation(); - }.bind(this)); - - var fragment = this.ownerDocument.createDocumentFragment(); - fragment.appendChild(input); - fragment.appendChild(this.ownerDocument.createTextNode(name)); - return fragment; -}; - -/** - * Renders the selection column header. - * @param {string} name Localized column name. - * @return {HTMLLiElement} Created element. - * @private - */ -FileTable.prototype.renderSelectionColumnHeader_ = function(name) { - if (!this.selectionModel.multiple) - return this.ownerDocument.createTextNode(''); - - var input = this.ownerDocument.createElement('input'); - input.setAttribute('type', 'checkbox'); - input.setAttribute('tabindex', -1); - input.id = 'select-all-checkbox'; - input.className = 'common'; - - this.updateSelectAllCheckboxState_(input); - - input.addEventListener('click', function(event) { - if (input.checked) - this.selectionModel.selectAll(); - else - this.selectionModel.unselectAll(); - event.stopPropagation(); - }.bind(this)); - - var fragment = this.ownerDocument.createDocumentFragment(); - fragment.appendChild(input); - return fragment; -}; - -/** - * Render the type column of the detail table. - * - * Invoked by cr.ui.Table when a file needs to be rendered. - * - * @param {Entry} entry The Entry object to render. - * @param {string} columnId The id of the column to be rendered. - * @param {cr.ui.Table} table The table doing the rendering. - * @return {HTMLDivElement} Created element. - * @private - */ -FileTable.prototype.renderIconType_ = function(entry, columnId, table) { - var icon = this.ownerDocument.createElement('div'); - icon.className = 'detail-icon'; - icon.setAttribute('file-type-icon', FileType.getIcon(entry)); - return icon; -}; - -/** - * Sets the margin height for the transparent preview panel at the bottom. - * @param {number} margin Margin to be set in px. - */ -FileTable.prototype.setBottomMarginForPanel = function(margin) { - this.list_.style.paddingBottom = margin + 'px'; - this.scrollBar_.setBottomMarginForPanel(margin); -}; - -/** - * Redraws the UI. Skips multiple consecutive calls. - */ -FileTable.prototype.relayout = function() { - this.relayoutAggregation_.run(); -}; - -/** - * Redraws the UI immediately. - * @private - */ -FileTable.prototype.relayoutImmediately_ = function() { - if (this.clientWidth > 0) - this.normalizeColumns(); - this.redraw(); - cr.dispatchSimpleEvent(this.list, 'relayout'); -}; - -/** - * Decorates (and wire up) a checkbox to be used in either a detail or a - * thumbnail list item. - * @param {HTMLInputElement} input Element to decorate. - */ -filelist.decorateCheckbox = function(input) { - var stopEventPropagation = function(event) { - if (!event.shiftKey) - event.stopPropagation(); - }; - input.setAttribute('type', 'checkbox'); - input.setAttribute('tabindex', -1); - input.classList.add('common'); - input.addEventListener('mousedown', stopEventPropagation); - input.addEventListener('mouseup', stopEventPropagation); - - input.addEventListener( - 'click', - /** - * @this {HTMLInputElement} - */ - function(event) { - // Revert default action and swallow the event - // if this is a multiple click or Shift is pressed. - if (event.detail > 1 || event.shiftKey) { - this.checked = !this.checked; - stopEventPropagation(event); - } - }); -}; - -/** - * Decorates selection checkbox. - * @param {HTMLInputElement} input Element to decorate. - * @param {Entry} entry Corresponding entry. - * @param {cr.ui.List} list Owner list. - */ -filelist.decorateSelectionCheckbox = function(input, entry, list) { - filelist.decorateCheckbox(input); - input.classList.add('file-checkbox'); - input.addEventListener('click', function(e) { - var sm = list.selectionModel; - var listIndex = list.getListItemAncestor(this).listIndex; - sm.setIndexSelected(listIndex, this.checked); - sm.leadIndex = listIndex; - if (sm.anchorIndex == -1) - sm.anchorIndex = listIndex; - - }); - // Since we do not want to open the item when tap on checkbox, we need to - // stop propagation of TAP event dispatched by checkbox ideally. But all - // touch events from touch_handler are dispatched to the list control. So we - // have to stop propagation of native touchstart event to prevent list - // control from generating TAP event here. The synthetic click event will - // select the touched checkbox/item. - input.addEventListener('touchstart', - function(e) { e.stopPropagation() }); - - var index = list.dataModel.indexOf(entry); - // Our DOM nodes get discarded as soon as we're scrolled out of view, - // so we have to make sure the check state is correct when we're brought - // back to life. - input.checked = list.selectionModel.getIndexSelected(index); -}; - -/** - * Common item decoration for table's and grid's items. - * @param {ListItem} li List item. - * @param {Entry} entry The entry. - * @param {MetadataCache} metadataCache Cache to retrieve metadada. - */ -filelist.decorateListItem = function(li, entry, metadataCache) { - li.classList.add(entry.isDirectory ? 'directory' : 'file'); - if (FileType.isOnDrive(entry)) { - // The metadata may not yet be ready. In that case, the list item will be - // updated when the metadata is ready via updateListItemsMetadata. - var driveProps = metadataCache.getCached(entry, 'drive'); - if (driveProps) - filelist.updateListItemDriveProps(li, driveProps); - } - - // Overriding the default role 'list' to 'listbox' for better - // accessibility on ChromeOS. - li.setAttribute('role', 'option'); - - Object.defineProperty(li, 'selected', { - /** - * @this {ListItem} - * @return {boolean} True if the list item is selected. - */ - get: function() { - return this.hasAttribute('selected'); - }, - - /** - * @this {ListItem} - */ - set: function(v) { - if (v) - this.setAttribute('selected', ''); - else - this.removeAttribute('selected'); - var checkBox = this.querySelector('input.file-checkbox'); - if (checkBox) - checkBox.checked = !!v; - } - }); -}; - -/** - * Render filename label for grid and list view. - * @param {HTMLDocument} doc Owner document. - * @param {Entry} entry The Entry object to render. - * @return {HTMLDivElement} The label. - */ -filelist.renderFileNameLabel = function(doc, entry) { - // Filename need to be in a '.filename-label' container for correct - // work of inplace renaming. - var box = doc.createElement('div'); - box.className = 'filename-label'; - var fileName = doc.createElement('span'); - fileName.textContent = entry.name; - box.appendChild(fileName); - - return box; -}; - -/** - * Updates grid item or table row for the driveProps. - * @param {cr.ui.ListItem} li List item. - * @param {Object} driveProps Metadata. - */ -filelist.updateListItemDriveProps = function(li, driveProps) { - if (li.classList.contains('file')) { - if (driveProps.availableOffline) - li.classList.remove('dim-offline'); - else - li.classList.add('dim-offline'); - // TODO(mtomasz): Consider adding some vidual indication for files which - // are not cached on LTE. Currently we show them as normal files. - // crbug.com/246611. - } - - if (driveProps.customIconUrl) { - var iconDiv = li.querySelector('.detail-icon'); - if (!iconDiv) - return; - iconDiv.style.backgroundImage = 'url(' + driveProps.customIconUrl + ')'; - } -}; |