| Index: chrome/browser/resources/shared/js/cr/ui/array_data_model.js
|
| ===================================================================
|
| --- chrome/browser/resources/shared/js/cr/ui/array_data_model.js (revision 177292)
|
| +++ chrome/browser/resources/shared/js/cr/ui/array_data_model.js (working copy)
|
| @@ -1,413 +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.
|
| -
|
| -/**
|
| - * @fileoverview This is a data model representin
|
| - */
|
| -
|
| -cr.define('cr.ui', function() {
|
| - /** @const */ var EventTarget = cr.EventTarget;
|
| - /** @const */ var Event = cr.Event;
|
| -
|
| - /**
|
| - * 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_ = [];
|
| - this.compareFunctions_ = {};
|
| -
|
| - for (var i = 0; i < array.length; i++) {
|
| - this.indexes_.push(i);
|
| - }
|
| - }
|
| -
|
| - ArrayDataModel.prototype = {
|
| - __proto__: EventTarget.prototype,
|
| -
|
| - /**
|
| - * The length of the data model.
|
| - * @type {number}
|
| - */
|
| - get length() {
|
| - return this.array_.length;
|
| - },
|
| -
|
| - /**
|
| - * 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.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) {
|
| - if (!this.compareFunctions_) {
|
| - this.compareFunctions_ = {};
|
| - }
|
| - this.compareFunctions_[field] = compareFunction;
|
| - },
|
| -
|
| - /**
|
| - * Returns true if the field has a compare function.
|
| - * @param {string} field The field to check.
|
| - * @return {boolean} True if the field is sortable.
|
| - */
|
| - isSortable: function(field) {
|
| - return this.compareFunctions_ && field in this.compareFunctions_;
|
| - },
|
| -
|
| - /**
|
| - * 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);
|
| - }
|
| - },
|
| -
|
| - /**
|
| - * Returns the first matching item.
|
| - * @param {*} item The item to find.
|
| - * @param {number=} opt_fromIndex If provided, then the searching start at
|
| - * the {@code opt_fromIndex}.
|
| - * @return {number} The index of the first found element or -1 if not found.
|
| - */
|
| - indexOf: function(item, opt_fromIndex) {
|
| - for (var i = opt_fromIndex || 0; i < this.indexes_.length; i++) {
|
| - if (item === this.item(i))
|
| - return i;
|
| - }
|
| - return -1;
|
| - },
|
| -
|
| - /**
|
| - * Returns an array of elements in a selected range.
|
| - * @param {number=} opt_from The starting index of the selected range.
|
| - * @param {number=} opt_to The ending index of selected range.
|
| - * @return {Array} An array of elements in the selected range.
|
| - */
|
| - slice: function(opt_from, opt_to) {
|
| - var arr = this.array_;
|
| - return this.indexes_.slice(opt_from, opt_to).map(
|
| - function(index) { return arr[index] });
|
| - },
|
| -
|
| - /**
|
| - * 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 deletedItems = [];
|
| - var newArray = [];
|
| - index = Math.min(index, this.indexes_.length);
|
| - deleteCount = Math.min(deleteCount, this.indexes_.length - index);
|
| - // Copy items before the insertion point.
|
| - for (var i = 0; i < index; i++) {
|
| - newIndexes.push(newArray.length);
|
| - deletePermutation.push(i);
|
| - newArray.push(this.array_[this.indexes_[i]]);
|
| - }
|
| - // Delete items.
|
| - for (; i < index + deleteCount; i++) {
|
| - deletePermutation.push(-1);
|
| - deletedItems.push(this.array_[this.indexes_[i]]);
|
| - }
|
| - // Insert new items instead deleted ones.
|
| - for (var j = 0; j < addCount; j++) {
|
| - newIndexes.push(newArray.length);
|
| - newArray.push(arguments[j + 2]);
|
| - }
|
| - // Copy items after the insertion point.
|
| - for (; i < this.indexes_.length; i++) {
|
| - newIndexes.push(newArray.length);
|
| - deletePermutation.push(i - deleteCount + addCount);
|
| - newArray.push(this.array_[this.indexes_[i]]);
|
| - }
|
| -
|
| - this.indexes_ = newIndexes;
|
| -
|
| - this.array_ = newArray;
|
| -
|
| - // TODO(arv): Maybe unify splice and change events?
|
| - var spliceEvent = new Event('splice');
|
| - spliceEvent.removed = deletedItems;
|
| - spliceEvent.added = Array.prototype.slice.call(arguments, 2);
|
| -
|
| - var status = this.sortStatus;
|
| - // 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);
|
| - spliceEvent.index = sortPermutation[index];
|
| - } else {
|
| - this.dispatchPermutedEvent_(deletePermutation);
|
| - spliceEvent.index = index;
|
| - }
|
| -
|
| - this.dispatchEvent(spliceEvent);
|
| -
|
| - // If real sorting is needed, we should first call prepareSort (data may
|
| - // change), and then sort again.
|
| - // Still need to finish the sorting above (including events), so
|
| - // list will not go to inconsistent state.
|
| - if (status.field)
|
| - this.delayedSort_(status.field, status.direction);
|
| -
|
| - return deletedItems;
|
| - },
|
| -
|
| - /**
|
| - * Appends items to the end of the model.
|
| - *
|
| - * This dispatches a splice event.
|
| - *
|
| - * @param {...*} The items to append.
|
| - * @return {number} The new length of the model.
|
| - */
|
| - push: function(var_args) {
|
| - var args = Array.prototype.slice.call(arguments);
|
| - args.unshift(this.length, 0);
|
| - this.splice.apply(this, args);
|
| - return this.length;
|
| - },
|
| -
|
| - /**
|
| - * 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) {
|
| - if (index < 0 || index >= this.length)
|
| - throw Error('Invalid index, ' + index);
|
| -
|
| - // TODO(arv): Maybe unify splice and change events?
|
| - var e = new Event('change');
|
| - e.index = index;
|
| - this.dispatchEvent(e);
|
| -
|
| - if (this.sortStatus.field) {
|
| - var status = this.sortStatus;
|
| - var sortPermutation = this.doSort_(this.sortStatus.field,
|
| - this.sortStatus.direction);
|
| - if (sortPermutation)
|
| - this.dispatchPermutedEvent_(sortPermutation);
|
| - // We should first call prepareSort (data may change), and then sort.
|
| - // Still need to finish the sorting above (including events), so
|
| - // list will not go to inconsistent state.
|
| - this.delayedSort_(status.field, status.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 with delay. If no need to delay, use sort() instead.
|
| - * @param {string} field Sort field.
|
| - * @param {string} direction Sort direction.
|
| - * @private
|
| - */
|
| - delayedSort_: function(field, direction) {
|
| - var self = this;
|
| - setTimeout(function() {
|
| - // If the sort status has been changed, sorting has already done
|
| - // on the change event.
|
| - if (field == self.sortStatus.field &&
|
| - direction == self.sortStatus.direction) {
|
| - self.sort(field, direction);
|
| - }
|
| - }, 0);
|
| - },
|
| -
|
| - /**
|
| - * 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.
|
| - * @private
|
| - */
|
| - 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;
|
| - }
|
| - var sorted = this.indexes_.every(function(element, index, array) {
|
| - return index == 0 || compareFunction(element, array[index - 1]) >= 0;
|
| - });
|
| - if (!sorted)
|
| - 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.
|
| - * @private
|
| - */
|
| - 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.
|
| - * @private
|
| - */
|
| - 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;
|
| - }
|
| - };
|
| -
|
| - return {
|
| - ArrayDataModel: ArrayDataModel
|
| - };
|
| -});
|
|
|