diff options
author | vsevik@chromium.org <vsevik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-26 13:48:10 +0000 |
---|---|---|
committer | vsevik@chromium.org <vsevik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-26 13:48:10 +0000 |
commit | d3fe3b27838f4ec1787bec09437a075afcf0a131 (patch) | |
tree | 962de966ea6036430b4008f20864e789cb2069ed /chrome | |
parent | f117eb9ad41c134ff895f58d20f05bacab76344a (diff) | |
download | chromium_src-d3fe3b27838f4ec1787bec09437a075afcf0a131.zip chromium_src-d3fe3b27838f4ec1787bec09437a075afcf0a131.tar.gz chromium_src-d3fe3b27838f4ec1787bec09437a075afcf0a131.tar.bz2 |
Move sorting logic from table to list.
BUG=82868
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=86065
Review URL: http://codereview.chromium.org/7038024
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86814 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
12 files changed, 329 insertions, 582 deletions
diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js index 6ef815f..09d0dab 100644 --- a/chrome/browser/resources/file_manager/js/file_manager.js +++ b/chrome/browser/resources/file_manager/js/file_manager.js @@ -518,20 +518,18 @@ FileManager.prototype = { // Always sharing the data model between the detail/thumb views confuses // them. Instead we maintain this bogus data model, and hook it up to the // view that is not in use. - this.emptyDataModel_ = new cr.ui.table.TableDataModel([]); + this.emptyDataModel_ = new cr.ui.ArrayDataModel([]); - this.dataModel_ = new cr.ui.table.TableDataModel([]); + this.dataModel_ = new cr.ui.ArrayDataModel([]); this.dataModel_.sort('name'); - this.dataModel_.addEventListener('sorted', - this.onDataModelSorted_.bind(this)); this.dataModel_.prepareSort = this.prepareSort_.bind(this); if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE || this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FOLDER || this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { - this.selectionModelClass_ = cr.ui.table.TableSingleSelectionModel; + this.selectionModelClass_ = cr.ui.ListSingleSelectionModel; } else { - this.selectionModelClass_ = cr.ui.table.TableSelectionModel; + this.selectionModelClass_ = cr.ui.ListSelectionModel; } this.initTable_(); @@ -1426,16 +1424,6 @@ FileManager.prototype = { }; /** - * Invoked by the table dataModel after a sort completes. - * - * We use this hook to make sure selected files stay visible after a sort. - */ - FileManager.prototype.onDataModelSorted_ = function() { - var i = this.currentList_.selectionModel.leadIndex; - this.currentList_.scrollIntoView(i); - } - - /** * Update the selection summary UI when the selection summarization completes. */ FileManager.prototype.onSelectionSummarized_ = function() { @@ -1576,9 +1564,6 @@ FileManager.prototype = { function onReadSome(entries) { if (entries.length == 0) { - if (self.dataModel_.sortStatus.field != 'name') - self.dataModel_.updateIndex(0); - if (opt_callback) opt_callback(); return; @@ -1624,7 +1609,6 @@ FileManager.prototype = { var spliceArgs = [].slice.call(this.rootEntries_); spliceArgs.unshift(0, 0); // index, deleteCount self.dataModel_.splice.apply(self.dataModel_, spliceArgs); - self.dataModel_.updateIndex(0); if (opt_callback) opt_callback(); diff --git a/chrome/browser/resources/file_manager/main.html b/chrome/browser/resources/file_manager/main.html index 53013f3..8fdcae5 100644 --- a/chrome/browser/resources/file_manager/main.html +++ b/chrome/browser/resources/file_manager/main.html @@ -30,9 +30,6 @@ 'cr/ui/splitter.js', 'cr/ui/table/table_splitter.js', - 'cr/ui/table/table_selection_model.js', - 'cr/ui/table/table_single_selection_model.js', - 'cr/ui/table/table_data_model.js', 'cr/ui/table/table_column.js', 'cr/ui/table/table_column_model.js', diff --git a/chrome/browser/resources/options/autofill_options_list.js b/chrome/browser/resources/options/autofill_options_list.js index 3fadeab..86aaae8 100644 --- a/chrome/browser/resources/options/autofill_options_list.js +++ b/chrome/browser/resources/options/autofill_options_list.js @@ -174,6 +174,9 @@ cr.define('options.autofillOptions', function() { if (this.input.value && this.list.dataModel.indexOf(this.input.value) == -1) { + // It is important that updateIndex is done before validateAndSave. + // Otherwise we can not be sure about AddRow index. + this.list.dataModel.updateIndex(i); this.list.validateAndSave(i, 0, this.input.value); } else { this.input.value = ''; diff --git a/chrome/browser/resources/shared/js/cr/ui/array_data_model.js b/chrome/browser/resources/shared/js/cr/ui/array_data_model.js index 64da3be..bc26eb6 100644 --- a/chrome/browser/resources/shared/js/cr/ui/array_data_model.js +++ b/chrome/browser/resources/shared/js/cr/ui/array_data_model.js @@ -11,13 +11,18 @@ cr.define('cr.ui', function() { const Event = cr.Event; /** - * A data model that wraps a simple array. + * A data model that wraps a simple array and supports sorting by storing + * initial indexes of elements for each position in sorted array. * @param {!Array} array The underlying array. * @constructor * @extends {EventTarget} */ function ArrayDataModel(array) { this.array_ = array; + this.indexes_ = []; + for (var i = 0; i < array.length; i++) { + this.indexes_.push(i); + } } ArrayDataModel.prototype = { @@ -33,11 +38,46 @@ cr.define('cr.ui', function() { /** * Returns the item at the given index. + * This implementation returns the item at the given index in the sorted + * array. * @param {number} index The index of the element to get. * @return {*} The element at the given index. */ item: function(index) { - return this.array_[index]; + if (index >= 0 && index < this.length) + return this.array_[this.indexes_[index]]; + return undefined; + }, + + /** + * Returns compare function set for given field. + * @param {string} field The field to get compare function for. + * @return {function(*, *): number} Compare function set for given field. + */ + compareFunction: function(field) { + return this.compareFunctions_[field]; + }, + + /** + * Sets compare function for given field. + * @param {string} field The field to set compare function. + * @param {function(*, *): number} Compare function to set for given field. + */ + setCompareFunction: function(field, compareFunction) { + this.compareFunctions_[field] = compareFunction; + }, + + /** + * Returns current sort status. + * @return {!Object} Current sort status. + */ + get sortStatus() { + if (this.sortStatus_) { + return this.createSortStatus( + this.sortStatus_.field, this.sortStatus_.direction); + } else { + return this.createSortStatus(null, null); + } }, /** @@ -63,27 +103,60 @@ cr.define('cr.ui', function() { /** * This removes and adds items to the model. - * * This dispatches a splice event. - * + * This implementation runs sort after splice and creates permutation for + * the whole change. * @param {number} index The index of the item to update. * @param {number} deleteCount The number of items to remove. * @param {...*} The items to add. * @return {!Array} An array with the removed items. */ splice: function(index, deleteCount, var_args) { + var addCount = arguments.length - 2; + var newIndexes = []; + var deletePermutation = []; + var deleted = 0; + for (var i = 0; i < this.indexes_.length; i++) { + var oldIndex = this.indexes_[i]; + if (oldIndex < index) { + newIndexes.push(oldIndex); + deletePermutation.push(i - deleted); + } else if (oldIndex >= index + deleteCount) { + newIndexes.push(oldIndex - deleteCount + addCount); + deletePermutation.push(i - deleted); + } else { + deletePermutation.push(-1); + deleted++; + } + } + for (var i = 0; i < addCount; i++) { + newIndexes.push(index + i); + } + this.indexes_ = newIndexes; + var arr = this.array_; // TODO(arv): Maybe unify splice and change events? - var e = new Event('splice'); - e.index = index; - e.removed = arr.slice(index, index + deleteCount); - e.added = Array.prototype.slice.call(arguments, 2); + var spliceEvent = new Event('splice'); + spliceEvent.index = index; + spliceEvent.removed = arr.slice(index, index + deleteCount); + spliceEvent.added = Array.prototype.slice.call(arguments, 2); var rv = arr.splice.apply(arr, arguments); - this.dispatchEvent(e); + // if sortStatus.field is null, this restores original order. + var sortPermutation = this.doSort_(this.sortStatus.field, + this.sortStatus.direction); + if (sortPermutation) { + var splicePermutation = deletePermutation.map(function(element) { + return element != -1 ? sortPermutation[element] : -1; + }); + this.dispatchPermutedEvent_(splicePermutation); + } else { + this.dispatchPermutedEvent_(deletePermutation); + } + this.dispatchEvent(spliceEvent); return rv; }, @@ -105,9 +178,8 @@ cr.define('cr.ui', function() { /** * Use this to update a given item in the array. This does not remove and * reinsert a new item. - * * This dispatches a change event. - * + * This runs sort after updating. * @param {number} index The index of the item to update. */ updateIndex: function(index) { @@ -118,6 +190,151 @@ cr.define('cr.ui', function() { var e = new Event('change'); e.index = index; this.dispatchEvent(e); + + if (this.sortStatus.field) { + var sortPermutation = this.doSort_(this.sortStatus.field, + this.sortStatus.direction); + if (sortPermutation) + this.dispatchPermutedEvent_(sortPermutation); + } + }, + + /** + * Creates sort status with given field and direction. + * @param {string} field Sort field. + * @param {string} direction Sort direction. + * @return {!Object} Created sort status. + */ + createSortStatus: function(field, direction) { + return { + field: field, + direction: direction + }; + }, + + /** + * Called before a sort happens so that you may fetch additional data + * required for the sort. + * + * @param {string} field Sort field. + * @param {function()} callback The function to invoke when preparation + * is complete. + */ + prepareSort: function(field, callback) { + callback(); + }, + + /** + * Sorts data model according to given field and direction and dispathes + * sorted event. + * @param {string} field Sort field. + * @param {string} direction Sort direction. + */ + sort: function(field, direction) { + var self = this; + + this.prepareSort(field, function() { + var sortPermutation = self.doSort_(field, direction); + if (sortPermutation) + self.dispatchPermutedEvent_(sortPermutation); + self.dispatchSortEvent_(); + }); + }, + + /** + * Sorts data model according to given field and direction. + * @param {string} field Sort field. + * @param {string} direction Sort direction. + */ + doSort_: function(field, direction) { + var compareFunction = this.sortFunction_(field, direction); + var positions = []; + for (var i = 0; i < this.length; i++) { + positions[this.indexes_[i]] = i; + } + this.indexes_.sort(compareFunction); + this.sortStatus_ = this.createSortStatus(field, direction); + var sortPermutation = []; + var changed = false; + for (var i = 0; i < this.length; i++) { + if (positions[this.indexes_[i]] != i) + changed = true; + sortPermutation[positions[this.indexes_[i]]] = i; + } + if (changed) + return sortPermutation; + return null; + }, + + dispatchSortEvent_: function() { + var e = new Event('sorted'); + this.dispatchEvent(e); + }, + + dispatchPermutedEvent_: function(permutation) { + var e = new Event('permuted'); + e.permutation = permutation; + e.newLength = this.length; + this.dispatchEvent(e); + }, + + /** + * Creates compare function for the field. + * Returns the function set as sortFunction for given field + * or default compare function + * @param {string} field Sort field. + * @param {function(*, *): number} Compare function. + */ + createCompareFunction_: function(field) { + var compareFunction = + this.compareFunctions_ ? this.compareFunctions_[field] : null; + var defaultValuesCompareFunction = this.defaultValuesCompareFunction; + if (compareFunction) { + return compareFunction; + } else { + return function(a, b) { + return defaultValuesCompareFunction.call(null, a[field], b[field]); + } + } + return compareFunction; + }, + + /** + * Creates compare function for given field and direction. + * @param {string} field Sort field. + * @param {string} direction Sort direction. + * @param {function(*, *): number} Compare function. + */ + sortFunction_: function(field, direction) { + var compareFunction = null; + if (field !== null) + compareFunction = this.createCompareFunction_(field); + var dirMultiplier = direction == 'desc' ? -1 : 1; + + return function(index1, index2) { + var item1 = this.array_[index1]; + var item2 = this.array_[index2]; + + var compareResult = 0; + if (typeof(compareFunction) === 'function') + compareResult = compareFunction.call(null, item1, item2); + if (compareResult != 0) + return dirMultiplier * compareResult; + return dirMultiplier * this.defaultValuesCompareFunction(index1, + index2); + }.bind(this); + }, + + /** + * Default compare function. + */ + defaultValuesCompareFunction: function(a, b) { + // We could insert i18n comparisons here. + if (a < b) + return -1; + if (a > b) + return 1; + return 0; } }; diff --git a/chrome/browser/resources/shared/js/cr/ui/list.js b/chrome/browser/resources/shared/js/cr/ui/list.js index d8dc94c9..5878ccd 100644 --- a/chrome/browser/resources/shared/js/cr/ui/list.js +++ b/chrome/browser/resources/shared/js/cr/ui/list.js @@ -160,26 +160,23 @@ cr.define('cr.ui', function() { /** * The data model driving the list. - * @type {ListDataModel} + * @type {ArrayDataModel} */ set dataModel(dataModel) { if (this.dataModel_ != dataModel) { - if (!this.boundHandleDataModelSplice_) { - this.boundHandleDataModelSplice_ = - this.handleDataModelSplice_.bind(this); + if (!this.boundHandleDataModelPermuted_) { + this.boundHandleDataModelPermuted_ = + this.handleDataModelPermuted_.bind(this); this.boundHandleDataModelChange_ = this.handleDataModelChange_.bind(this); - this.boundHandleSorted_ = - this.handleSorted_.bind(this); } if (this.dataModel_) { - this.dataModel_.removeEventListener('splice', - this.boundHandleDataModelSplice_); + this.dataModel_.removeEventListener( + 'permuted', + this.boundHandleDataModelPermuted_); this.dataModel_.removeEventListener('change', this.boundHandleDataModelChange_); - this.dataModel_.removeEventListener('sorted', - this.boundHandleSorted_); } this.dataModel_ = dataModel; @@ -187,15 +184,14 @@ cr.define('cr.ui', function() { this.cachedItems_ = {}; this.selectionModel.clear(); if (dataModel) - this.selectionModel.adjust(0, 0, dataModel.length); + this.selectionModel.adjustLength(dataModel.length); if (this.dataModel_) { - this.dataModel_.addEventListener('splice', - this.boundHandleDataModelSplice_); + this.dataModel_.addEventListener( + 'permuted', + this.boundHandleDataModelPermuted_); this.dataModel_.addEventListener('change', this.boundHandleDataModelChange_); - this.dataModel_.addEventListener('sorted', - this.boundHandleSorted_); } this.redraw(); @@ -554,42 +550,48 @@ cr.define('cr.ui', function() { } }, - handleDataModelSplice_: function(e) { - this.selectionModel.adjust(e.index, e.removed.length, e.added.length); - // Remove the cache of everything above index. + /** + * This handles data model 'permuted' event. + * this event is dispatched as a part of sort or splice. + * We need to + * - adjust the cache. + * - adjust selection. + * - redraw. + * - scroll the list to show selection. + * It is important that the cache adjustment happens before selection model + * adjustments. + * @param {Event} e The 'permuted' event. + */ + handleDataModelPermuted_: function(e) { + var newCachedItems = {}; for (var index in this.cachedItems_) { - if (index >= e.index) + if (e.permutation[index] != -1) + newCachedItems[e.permutation[index]] = this.cachedItems_[index]; + else delete this.cachedItems_[index]; } - this.redraw(); - }, + this.cachedItems_ = newCachedItems; - handleDataModelChange_: function(e) { - if (e.index >= this.firstIndex_ && e.index < this.lastIndex_) { - this.cachedItems_ = null; - this.redraw(); - } - }, + this.startBatchUpdates(); - /** - * This handles data model 'sorted' event. - * After sorting we need to - * - adjust selection. - * - delete the cache. - * - redraw all the items. - * - scroll the list to show selection. - * @param {Event} e The 'sorted' event. - */ - handleSorted_: function(e) { var sm = this.selectionModel; - sm.adjustToReordering(e.sortPermutation); + sm.adjustLength(e.newLength); + sm.adjustToReordering(e.permutation); + + this.endBatchUpdates(); - this.cachedItems_ = null; - this.redraw(); if (sm.leadIndex != -1) this.scrollIndexIntoView(sm.leadIndex); }, + handleDataModelChange_: function(e) { + if (e.index >= this.firstIndex_ && e.index < this.lastIndex_) { + if (this.cachedItems_[e.index]) + delete this.cachedItems_[e.index]; + this.redraw(); + } + }, + /** * @param {number} index The index of the item. * @return {number} The top position of the item inside the list, not taking @@ -823,6 +825,7 @@ cr.define('cr.ui', function() { var listItem; var dataModel = this.dataModel; + window.l = this; for (var y = firstIndex; y < lastIndex; y++) { var dataItem = dataModel.item(y); listItem = cachedItems[y] || this.createItem(dataItem); @@ -931,6 +934,13 @@ cr.define('cr.ui', function() { }, /** + * Invalidates list by removing cached items. + */ + invalidate: function() { + this.cachedItems_ = {}; + }, + + /** * Redraws a single item. * @param {number} index The row index to redraw. */ diff --git a/chrome/browser/resources/shared/js/cr/ui/list_selection_model.js b/chrome/browser/resources/shared/js/cr/ui/list_selection_model.js index fc5710f..8c16d57 100644 --- a/chrome/browser/resources/shared/js/cr/ui/list_selection_model.js +++ b/chrome/browser/resources/shared/js/cr/ui/list_selection_model.js @@ -247,43 +247,25 @@ cr.define('cr.ui', function() { * @param {!Array.<number>} permutation The reordering permutation. */ adjustToReordering: function(permutation) { + var oldLeadIndex = this.leadIndex; + + var oldSelectedIndexes = this.selectedIndexes; + this.selectedIndexes = oldSelectedIndexes.map(function(oldIndex) { + return permutation[oldIndex]; + }).filter(function(index) { + return index != -1; + }); + + if (oldLeadIndex != -1) + this.leadIndex = permutation[oldLeadIndex]; }, /** - * Adjust the selection by adding or removing a certain numbers of items. - * This should be called by the owner of the selection model as items are - * added and removed from the underlying data model. - * @param {number} index The index of the first change. - * @param {number} itemsRemoved Number of items removed. - * @param {number} itemsAdded Number of items added. + * Adjusts selection model length. + * @param {number} length New selection model length. */ - adjust: function(index, itemsRemoved, itemsAdded) { - function getNewAdjustedIndex(i) { - if (i >= index && i < index + itemsRemoved) { - return index - } else if (i >= index) { - return i - itemsRemoved + itemsAdded; - } - return i; - } - - this.length_ += itemsAdded - itemsRemoved; - - var newMap = []; - for (var i in this.selectedIndexes_) { - i = Number(i); - if (i < index) { - newMap[i] = true; - } else if (i < index + itemsRemoved) { - // noop - } else { - newMap[i + itemsAdded - itemsRemoved] = true; - } - } - this.selectedIndexes_ = newMap; - - this.leadIndex = getNewAdjustedIndex(this.leadIndex); - this.anchorIndex = getNewAdjustedIndex(this.anchorIndex); + adjustLength: function(length) { + this.length_ = length; } }; diff --git a/chrome/browser/resources/shared/js/cr/ui/list_single_selection_model.js b/chrome/browser/resources/shared/js/cr/ui/list_single_selection_model.js index 119f0fb..2cf43a92 100644 --- a/chrome/browser/resources/shared/js/cr/ui/list_single_selection_model.js +++ b/chrome/browser/resources/shared/js/cr/ui/list_single_selection_model.js @@ -197,35 +197,21 @@ cr.define('cr.ui', function() { * @param {!Array.<number>} permutation The reordering permutation. */ adjustToReordering: function(permutation) { + if (this.leadIndex != -1) + this.leadIndex = permutation[this.leadIndex]; + + var oldSelectedIndex = this.selectedIndex; + if (oldSelectedIndex != -1) { + this.selectedIndex = permutation[oldSelectedIndex]; + } }, /** - * Adjust the selection by adding or removing a certain numbers of items. - * This should be called by the owner of the selection model as items are - * added and removed from the underlying data model. - * @param {number} index The index of the first change. - * @param {number} itemsRemoved Number of items removed. - * @param {number} itemsAdded Number of items added. + * Adjusts selection model length. + * @param {number} length New selection model length. */ - adjust: function(index, itemsRemoved, itemsAdded) { - function getNewAdjustedIndex(i) { - if (i >= index && i < index + itemsRemoved) { - return index; - } else if (i >= index) { - return i + itemsAdded - itemsRemoved; - } - return i; - } - - this.length_ += itemsAdded - itemsRemoved; - - var i = this.selectedIndex; - if (itemsRemoved > 0 && i >= index && i < index + itemsRemoved) - this.selectedIndex = -1; - else if (i >= index) - this.selectedIndex = i + itemsAdded - itemsRemoved; - - this.leadIndex = getNewAdjustedIndex(this.leadIndex); + adjustLength: function(length) { + this.length_ = length; } }; diff --git a/chrome/browser/resources/shared/js/cr/ui/table.js b/chrome/browser/resources/shared/js/cr/ui/table.js index c23a02a..bd67378 100644 --- a/chrome/browser/resources/shared/js/cr/ui/table.js +++ b/chrome/browser/resources/shared/js/cr/ui/table.js @@ -7,7 +7,7 @@ */ cr.define('cr.ui', function() { - const TableSelectionModel = cr.ui.table.TableSelectionModel; + const ListSelectionModel = cr.ui.ListSelectionModel; const ListSelectionController = cr.ui.ListSelectionController; const ArrayDataModel = cr.ui.ArrayDataModel; const TableColumnModel = cr.ui.table.TableColumnModel; @@ -30,25 +30,19 @@ cr.define('cr.ui', function() { /** * The table data model. * - * @type {cr.ui.table.TableDataModel} + * @type {cr.ui.ArrayDataModel} */ get dataModel() { return this.list_.dataModel; }, set dataModel(dataModel) { if (this.list_.dataModel != dataModel) { - this.list_.dataModel = dataModel; if (this.list_.dataModel) { - this.list_.dataModel.removeEventListener('splice', this.boundRedraw_); this.list_.dataModel.removeEventListener('sorted', this.boundHandleSorted_); } this.list_.dataModel = dataModel; - this.list_.dataModel.table = this; - - if (this.list_.dataModel) { - this.list_.dataModel.addEventListener('splice', this.boundRedraw_); this.list_.dataModel.addEventListener('sorted', this.boundHandleSorted_); } @@ -66,16 +60,13 @@ cr.define('cr.ui', function() { }, set columnModel(columnModel) { if (this.columnModel_ != columnModel) { - if (this.columnModel_) { - this.columnModel_.removeEventListener('change', this.boundRedraw_); + if (this.columnModel_) this.columnModel_.removeEventListener('resize', this.boundResize_); - } this.columnModel_ = columnModel; - if (this.columnModel_) { - this.columnModel_.addEventListener('change', this.boundRedraw_); + if (this.columnModel_) this.columnModel_.addEventListener('resize', this.boundResize_); - } + this.list_.invalidate(); this.redraw(); } }, @@ -84,7 +75,7 @@ cr.define('cr.ui', function() { * The table selection model. * * @type - * {cr.ui.table.TableSelectionModel|cr.ui.table.TableSingleSelectionModel} + * {cr.ui.ListSelectionModel|cr.ui.table.ListSingleSelectionModel} */ get selectionModel() { return this.list_.selectionModel; @@ -92,9 +83,8 @@ cr.define('cr.ui', function() { set selectionModel(selectionModel) { if (this.list_.selectionModel != selectionModel) { if (this.dataModel) - selectionModel.adjust(0, 0, this.dataModel.length); + selectionModel.adjustLength(this.dataModel.length); this.list_.selectionModel = selectionModel; - this.redraw(); } }, @@ -114,7 +104,7 @@ cr.define('cr.ui', function() { decorate: function() { this.list_ = this.ownerDocument.createElement('list'); TableList.decorate(this.list_); - this.list_.selectionModel = new TableSelectionModel(this); + this.list_.selectionModel = new ListSelectionModel(this); this.list_.table = this; this.header_ = this.ownerDocument.createElement('div'); @@ -127,7 +117,6 @@ cr.define('cr.ui', function() { this.ownerDocument.defaultView.addEventListener( 'resize', this.header_.updateWidth.bind(this.header_)); - this.boundRedraw_ = this.redraw.bind(this); this.boundResize_ = this.resize.bind(this); this.boundHandleSorted_ = this.handleSorted_.bind(this); @@ -139,6 +128,14 @@ cr.define('cr.ui', function() { }, /** + * Redraws the table. + */ + redraw: function(index) { + this.list_.redraw(); + this.header_.redraw(); + }, + + /** * Resize the table columns. */ resize: function() { @@ -166,36 +163,12 @@ cr.define('cr.ui', function() { }, /** - * Redraws the table. - * This forces the list to remove all cached items. - */ - redraw: function() { - this.list_.startBatchUpdates(); - if (this.list_.dataModel) { - for (var i = 0; i < this.list_.dataModel.length; i++) { - this.list_.redrawItem(i); - } - } - this.list_.endBatchUpdates(); - this.list_.redraw(); - this.header_.redraw(); - }, - - /** * This handles data model 'sorted' event. - * After sorting we need to - * - adjust selection - * - redraw all the items - * - scroll the list to show selection. + * After sorting we need to redraw header * @param {Event} e The 'sorted' event. */ handleSorted_: function(e) { - var sm = this.list_.selectionModel; - sm.adjustToReordering(e.sortPermutation); - - this.redraw(); - if (sm.leadIndex != -1) - this.list_.scrollIndexIntoView(sm.leadIndex) + this.header_.redraw(); }, /** diff --git a/chrome/browser/resources/shared/js/cr/ui/table/table_data_model.js b/chrome/browser/resources/shared/js/cr/ui/table/table_data_model.js deleted file mode 100644 index 311fd67..0000000 --- a/chrome/browser/resources/shared/js/cr/ui/table/table_data_model.js +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (c) 2011 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 is a table data model - */ -cr.define('cr.ui.table', function() { - const EventTarget = cr.EventTarget; - const Event = cr.Event; - const ArrayDataModel = cr.ui.ArrayDataModel; - - /** - * A table data model that supports sorting by storing initial indexes of - * elements for each position in sorted array. - * @param {!Array} items The underlying array. - * @constructor - * @extends {ArrayDataModel} - */ - function TableDataModel(items) { - ArrayDataModel.apply(this, arguments); - this.indexes_ = []; - for (var i = 0; i < items.length; i++) { - this.indexes_.push(i); - } - } - - TableDataModel.prototype = { - __proto__: ArrayDataModel.prototype, - - /** - * Returns the item at the given index. - * This implementation returns the item at the given index in the source - * array before sort. - * @param {number} index The index of the element to get. - * @return {*} The element at the given index. - */ - getItemByUnsortedIndex_: function(unsortedIndex) { - return ArrayDataModel.prototype.item.call(this, unsortedIndex); - }, - - /** - * Returns the item at the given index. - * This implementation returns the item at the given index in the sorted - * array. - * @param {number} index The index of the element to get. - * @return {*} The element at the given index. - */ - item: function(index) { - if (index >= 0 && index < this.length) - return this.getItemByUnsortedIndex_(this.indexes_[index]); - return undefined; - }, - - /** - * Returns compare function set for given field. - * @param {string} field The field to get compare function for. - * @return {Function(*, *): number} Compare function set for given field. - */ - compareFunction: function(field) { - return this.compareFunctions_[field]; - }, - - /** - * Sets compare function for given field. - * @param {string} field The field to set compare function. - * @param {Function(*, *): number} Compare function to set for given field. - */ - setCompareFunction: function(field, compareFunction) { - this.compareFunctions_[field] = compareFunction; - }, - - /** - * Returns current sort status. - * @return {!Object} Current sort status. - */ - get sortStatus() { - if (this.sortStatus_) { - return this.createSortStatus( - this.sortStatus_.field, this.sortStatus_.direction); - } else { - return this.createSortStatus(null, null); - } - }, - - /** - * This removes and adds items to the model. - * This dispatches a splice event. - * This implementation runs sort after splice and creates permutation for - * the whole change. - * @param {number} index The index of the item to update. - * @param {number} deleteCount The number of items to remove. - * @param {...*} The items to add. - * @return {!Array} An array with the removed items. - */ - splice: function(index, deleteCount, var_args) { - var addCount = arguments.length - 2; - var newIndexes = []; - var deletePermutation = []; - var deleted = 0; - for (var i = 0; i < this.indexes_.length; i++) { - var oldIndex = this.indexes_[i]; - if (oldIndex < index) { - newIndexes.push(oldIndex); - deletePermutation.push(i - deleted); - } else if (oldIndex >= index + deleteCount) { - newIndexes.push(oldIndex - deleteCount + addCount); - deletePermutation.push(i - deleted); - } else { - deletePermutation.push(-1); - deleted++; - } - } - for (var i = 0; i < addCount; i++) { - newIndexes.push(index + i); - } - this.indexes_ = newIndexes; - - var rv = ArrayDataModel.prototype.splice.apply(this, arguments); - - var splicePermutation; - if (this.sortStatus.field) { - var sortPermutation = this.doSort_(this.sortStatus.field, - this.sortStatus.direction); - splicePermutation = deletePermutation.map(function(element) { - return element != -1 ? sortPermutation[element] : -1; - }); - } else { - splicePermutation = deletePermutation; - } - this.dispatchSortEvent_(splicePermutation); - - return rv; - }, - - /** - * Use this to update a given item in the array. This does not remove and - * reinsert a new item. - * This dispatches a change event. - * This implementation runs sort after updating. - * @param {number} index The index of the item to update. - */ - updateIndex: function(index) { - ArrayDataModel.prototype.updateIndex.apply(this, arguments); - - if (this.sortStatus.field) - this.sort(this.sortStatus.field, this.sortStatus.direction); - }, - - /** - * Creates sort status with given field and direction. - * @param {string} field Sort field. - * @param {string} direction Sort direction. - * @return {!Object} Created sort status. - */ - createSortStatus: function(field, direction) { - return { - field: field, - direction: direction - }; - }, - - /** - * Called before a sort happens so that you may fetch additional data - * required for the sort. - * - * @param {string} field Sort field. - * @param {function()} callback The function to invoke when preparation - * is complete. - */ - prepareSort: function(field, callback) { - callback(); - }, - - /** - * Sorts data model according to given field and direction and dispathes - * sorted event. - * @param {string} field Sort field. - * @param {string} direction Sort direction. - */ - sort: function(field, direction) { - var self = this; - - this.prepareSort(field, function() { - var sortPermutation = self.doSort_(field, direction); - self.dispatchSortEvent_(sortPermutation); - }); - }, - - /** - * Sorts data model according to given field and direction. - * @param {string} field Sort field. - * @param {string} direction Sort direction. - */ - doSort_: function(field, direction) { - var compareFunction = this.sortFunction_(field, direction); - var positions = []; - for (var i = 0; i < this.length; i++) { - positions[this.indexes_[i]] = i; - } - this.indexes_.sort(compareFunction); - this.sortStatus_ = this.createSortStatus(field, direction); - var sortPermutation = []; - for (var i = 0; i < this.length; i++) { - sortPermutation[positions[this.indexes_[i]]] = i; - } - return sortPermutation; - }, - - dispatchSortEvent_: function(sortPermutation) { - var e = new Event('sorted'); - e.sortPermutation = sortPermutation; - this.dispatchEvent(e); - }, - - /** - * Creates compare function for the field. - * Returns the function set as sortFunction for given field - * or default compare function - * @param {string} field Sort field. - * @param {Function(*, *): number} Compare function. - */ - createCompareFunction_: function(field) { - var compareFunction = - this.compareFunctions_ ? this.compareFunctions_[field] : null; - var defaultValuesCompareFunction = this.defaultValuesCompareFunction; - if (compareFunction) { - return compareFunction; - } else { - return function(a, b) { - return defaultValuesCompareFunction.call(null, a[field], b[field]); - } - } - return compareFunction; - }, - - /** - * Creates compare function for given field and direction. - * @param {string} field Sort field. - * @param {string} direction Sort direction. - * @param {Function(*, *): number} Compare function. - */ - sortFunction_: function(field, direction) { - var compareFunction = this.createCompareFunction_(field); - var dirMultiplier = direction == 'desc' ? -1 : 1; - - return function(index1, index2) { - var item1 = this.getItemByUnsortedIndex_(index1); - var item2 = this.getItemByUnsortedIndex_(index2); - - var compareResult = compareFunction.call(null, item1, item2); - if (compareResult != 0) - return dirMultiplier * compareResult; - return dirMultiplier * this.defaultValuesCompareFunction(index1, - index2); - }.bind(this); - }, - - /** - * Default compare function. - */ - defaultValuesCompareFunction: function(a, b) { - // We could insert i18n comparisons here. - if (a < b) - return -1; - if (a > b) - return 1; - return 0; - } - }; - - return { - TableDataModel: TableDataModel - }; -}); diff --git a/chrome/browser/resources/shared/js/cr/ui/table/table_selection_model.js b/chrome/browser/resources/shared/js/cr/ui/table/table_selection_model.js deleted file mode 100644 index d4a197a..0000000 --- a/chrome/browser/resources/shared/js/cr/ui/table/table_selection_model.js +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2011 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 is a multiple selection model for table - */ -cr.define('cr.ui.table', function() { - const ListSelectionModel = cr.ui.ListSelectionModel; - - /** - * Creates a new selection model that is to be used with tables. - * This implementation supports multiple selection. - * Selected items are stored, not indexes, so selections are preserved - * after items reordering (e.g. because of sort). - * @param {number=} opt_length The number of items in the selection. - * @constructor - * @extends {!cr.EventTarget} - */ - function TableSelectionModel(opt_length) { - ListSelectionModel.apply(this, arguments); - } - - TableSelectionModel.prototype = { - __proto__: ListSelectionModel.prototype, - - - /** - * Adjusts the selection after reordering of items in the table. - * @param {!Array.<number>} permutation The reordering permutation. - */ - adjustToReordering: function(permutation) { - var oldLeadIndex = this.leadIndex; - - var oldSelectedIndexes = this.selectedIndexes; - this.selectedIndexes = oldSelectedIndexes.map(function(oldIndex) { - return permutation[oldIndex]; - }).filter(function(index) { - return index != -1; - }); - - if (oldLeadIndex != -1) - this.leadIndex = permutation[oldLeadIndex]; - }, - - /** - * Adjust the selection by adding or removing a certain numbers of items. - * This should be called by the owner of the selection model as items are - * added and removed from the underlying data model. - * This implementation updates selection model length only. The actual - * selected indexes changes are processed in adjustToReordering. - * @param {number} index The index of the first change. - * @param {number} itemsRemoved Number of items removed. - * @param {number} itemsAdded Number of items added. - */ - adjust: function(index, itemsRemoved, itemsAdded) { - ListSelectionModel.prototype.adjust.call( - this, this.length, itemsRemoved, itemsAdded); - } - }; - - return { - TableSelectionModel: TableSelectionModel - }; -}); diff --git a/chrome/browser/resources/shared/js/cr/ui/table/table_single_selection_model.js b/chrome/browser/resources/shared/js/cr/ui/table/table_single_selection_model.js deleted file mode 100644 index c1da65f..0000000 --- a/chrome/browser/resources/shared/js/cr/ui/table/table_single_selection_model.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2011 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 is a single selection model for table - */ -cr.define('cr.ui.table', function() { - const ListSingleSelectionModel = cr.ui.ListSingleSelectionModel; - - /** - * Creates a new selection model that is to be used with tables. - * This implementation supports single selection. - * Selected item is stored, not index, so selection is preserved - * after items reordering (e.g. because of sort). - * @param {number=} opt_length The number of items in the selection. - * @constructor - * @extends {!cr.EventTarget} - */ - function TableSingleSelectionModel(opt_length) { - ListSingleSelectionModel.apply(this, arguments); - } - - TableSingleSelectionModel.prototype = { - __proto__: ListSingleSelectionModel.prototype, - - - /** - * Adjusts the selection after reordering of items in the table. - * @param {!Array.<number>} permutation The reordering permutation. - */ - adjustToReordering: function(permutation) { - if (this.leadIndex != -1) - this.leadIndex = permutation[this.leadIndex]; - - var oldSelectedIndex = this.selectedIndex; - if (oldSelectedIndex != -1) { - this.selectedIndex = permutation[oldSelectedIndex]; - } - }, - - /** - * Adjust the selection by adding or removing a certain numbers of items. - * This should be called by the owner of the selection model as items are - * added and removed from the underlying data model. - * @param {number} index The index of the first change. - * @param {number} itemsRemoved Number of items removed. - * @param {number} itemsAdded Number of items added. - */ - adjust: function(index, itemsRemoved, itemsAdded) { - ListSingleSelectionModel.prototype.adjust.call( - this, this.length, itemsRemoved, itemsAdded); - } - }; - - return { - TableSingleSelectionModel: TableSingleSelectionModel - }; -}); diff --git a/chrome/browser/resources/shared_resources.grd b/chrome/browser/resources/shared_resources.grd index 525edf6..a66ece9 100644 --- a/chrome/browser/resources/shared_resources.grd +++ b/chrome/browser/resources/shared_resources.grd @@ -94,16 +94,10 @@ without changes to the corresponding grd file. paaaae --> file="shared/js/cr/ui/table/table_column.js" type="BINDATA" /> <include name="IDR_SHARED_JS_CR_UI_TABLE_COLUMN_MODEL" file="shared/js/cr/ui/table/table_column_model.js" type="BINDATA" /> - <include name="IDR_SHARED_JS_CR_UI_TABLE_DATA_MODEL" - file="shared/js/cr/ui/table/table_data_model.js" type="BINDATA" /> <include name="IDR_SHARED_JS_CR_UI_TABLE_HEADER" file="shared/js/cr/ui/table/table_header.js" type="BINDATA" /> <include name="IDR_SHARED_JS_CR_UI_TABLE_LIST" file="shared/js/cr/ui/table/table_list.js" type="BINDATA" /> - <include name="IDR_SHARED_JS_CR_UI_TABLE_SELECTION_MODEL" - file="shared/js/cr/ui/table/table_selection_model.js" type="BINDATA" /> - <include name="IDR_SHARED_JS_CR_UI_TABLE_SINGLE_SELECTION_MODEL" - file="shared/js/cr/ui/table/table_single_selection_model.js" type="BINDATA" /> <include name="IDR_SHARED_JS_CR_UI_TABLE_SPLITTER" file="shared/js/cr/ui/table/table_splitter.js" type="BINDATA" /> <include name="IDR_SHARED_JS_CR_UI_TABS" |