Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Side by Side Diff: chrome/browser/resources/shared/js/cr/ui/array_data_model.js

Issue 7063007: Revert 86065 - Move sorting logic from table to list. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview This is a data model representin 6 * @fileoverview This is a data model representin
7 */ 7 */
8 8
9 cr.define('cr.ui', function() { 9 cr.define('cr.ui', function() {
10 const EventTarget = cr.EventTarget; 10 const EventTarget = cr.EventTarget;
11 const Event = cr.Event; 11 const Event = cr.Event;
12 12
13 /** 13 /**
14 * A data model that wraps a simple array and supports sorting by storing 14 * A data model that wraps a simple array.
15 * initial indexes of elements for each position in sorted array.
16 * @param {!Array} array The underlying array. 15 * @param {!Array} array The underlying array.
17 * @constructor 16 * @constructor
18 * @extends {EventTarget} 17 * @extends {EventTarget}
19 */ 18 */
20 function ArrayDataModel(array) { 19 function ArrayDataModel(array) {
21 this.array_ = array; 20 this.array_ = array;
22 this.indexes_ = [];
23 for (var i = 0; i < array.length; i++) {
24 this.indexes_.push(i);
25 }
26 } 21 }
27 22
28 ArrayDataModel.prototype = { 23 ArrayDataModel.prototype = {
29 __proto__: EventTarget.prototype, 24 __proto__: EventTarget.prototype,
30 25
31 /** 26 /**
32 * The length of the data model. 27 * The length of the data model.
33 * @type {number} 28 * @type {number}
34 */ 29 */
35 get length() { 30 get length() {
36 return this.array_.length; 31 return this.array_.length;
37 }, 32 },
38 33
39 /** 34 /**
40 * Returns the item at the given index. 35 * Returns the item at the given index.
41 * This implementation returns the item at the given index in the sorted
42 * array.
43 * @param {number} index The index of the element to get. 36 * @param {number} index The index of the element to get.
44 * @return {*} The element at the given index. 37 * @return {*} The element at the given index.
45 */ 38 */
46 item: function(index) { 39 item: function(index) {
47 if (index >= 0 && index < this.length) 40 return this.array_[index];
48 return this.array_[this.indexes_[index]];
49 return undefined;
50 }, 41 },
51 42
52 /** 43 /**
53 * Returns compare function set for given field.
54 * @param {string} field The field to get compare function for.
55 * @return {function(*, *): number} Compare function set for given field.
56 */
57 compareFunction: function(field) {
58 return this.compareFunctions_[field];
59 },
60
61 /**
62 * Sets compare function for given field.
63 * @param {string} field The field to set compare function.
64 * @param {function(*, *): number} Compare function to set for given field.
65 */
66 setCompareFunction: function(field, compareFunction) {
67 this.compareFunctions_[field] = compareFunction;
68 },
69
70 /**
71 * Returns current sort status.
72 * @return {!Object} Current sort status.
73 */
74 get sortStatus() {
75 if (this.sortStatus_) {
76 return this.createSortStatus(
77 this.sortStatus_.field, this.sortStatus_.direction);
78 } else {
79 return this.createSortStatus(null, null);
80 }
81 },
82
83
84
85 /**
86 * Returns the first matching item. 44 * Returns the first matching item.
87 * @param {*} item The item to find. 45 * @param {*} item The item to find.
88 * @param {number=} opt_fromIndex If provided, then the searching start at 46 * @param {number=} opt_fromIndex If provided, then the searching start at
89 * the {@code opt_fromIndex}. 47 * the {@code opt_fromIndex}.
90 * @return {number} The index of the first found element or -1 if not found. 48 * @return {number} The index of the first found element or -1 if not found.
91 */ 49 */
92 indexOf: function(item, opt_fromIndex) { 50 indexOf: function(item, opt_fromIndex) {
93 return this.array_.indexOf(item, opt_fromIndex); 51 return this.array_.indexOf(item, opt_fromIndex);
94 }, 52 },
95 53
96 /** 54 /**
97 * Returns an array of elements in a selected range. 55 * Returns an array of elements in a selected range.
98 * @param {number=} opt_from The starting index of the selected range. 56 * @param {number=} opt_from The starting index of the selected range.
99 * @param {number=} opt_to The ending index of selected range. 57 * @param {number=} opt_to The ending index of selected range.
100 * @return {Array} An array of elements in the selected range. 58 * @return {Array} An array of elements in the selected range.
101 */ 59 */
102 slice: function(opt_from, opt_to) { 60 slice: function(opt_from, opt_to) {
103 return this.array_.slice.apply(this.array_, arguments); 61 return this.array_.slice.apply(this.array_, arguments);
104 }, 62 },
105 63
106 /** 64 /**
107 * This removes and adds items to the model. 65 * This removes and adds items to the model.
66 *
108 * This dispatches a splice event. 67 * This dispatches a splice event.
109 * This implementation runs sort after splice and creates permutation for 68 *
110 * the whole change.
111 * @param {number} index The index of the item to update. 69 * @param {number} index The index of the item to update.
112 * @param {number} deleteCount The number of items to remove. 70 * @param {number} deleteCount The number of items to remove.
113 * @param {...*} The items to add. 71 * @param {...*} The items to add.
114 * @return {!Array} An array with the removed items. 72 * @return {!Array} An array with the removed items.
115 */ 73 */
116 splice: function(index, deleteCount, var_args) { 74 splice: function(index, deleteCount, var_args) {
117 var addCount = arguments.length - 2;
118 var newIndexes = [];
119 var deletePermutation = [];
120 var deleted = 0;
121 for (var i = 0; i < this.indexes_.length; i++) {
122 var oldIndex = this.indexes_[i];
123 if (oldIndex < index) {
124 newIndexes.push(oldIndex);
125 deletePermutation.push(i - deleted);
126 } else if (oldIndex >= index + deleteCount) {
127 newIndexes.push(oldIndex - deleteCount + addCount);
128 deletePermutation.push(i - deleted);
129 } else {
130 deletePermutation.push(-1);
131 deleted++;
132 }
133 }
134 for (var i = 0; i < addCount; i++) {
135 newIndexes.push(index + i);
136 }
137 this.indexes_ = newIndexes;
138
139 var arr = this.array_; 75 var arr = this.array_;
140 76
141 // TODO(arv): Maybe unify splice and change events? 77 // TODO(arv): Maybe unify splice and change events?
142 var spliceEvent = new Event('splice'); 78 var e = new Event('splice');
143 spliceEvent.index = index; 79 e.index = index;
144 spliceEvent.removed = arr.slice(index, index + deleteCount); 80 e.removed = arr.slice(index, index + deleteCount);
145 spliceEvent.added = Array.prototype.slice.call(arguments, 2); 81 e.added = Array.prototype.slice.call(arguments, 2);
146 82
147 var rv = arr.splice.apply(arr, arguments); 83 var rv = arr.splice.apply(arr, arguments);
148 84
149 // if sortStatus.field is null, this restores original order. 85 this.dispatchEvent(e);
150 var sortPermutation = this.doSort_(this.sortStatus.field,
151 this.sortStatus.direction);
152 if (sortPermutation) {
153 var splicePermutation = deletePermutation.map(function(element) {
154 return element != -1 ? sortPermutation[element] : -1;
155 });
156 this.dispatchPermutedEvent_(splicePermutation);
157 } else {
158 this.dispatchPermutedEvent_(deletePermutation);
159 }
160 86
161 this.dispatchEvent(spliceEvent);
162 return rv; 87 return rv;
163 }, 88 },
164 89
165 /** 90 /**
166 * Appends items to the end of the model. 91 * Appends items to the end of the model.
167 * 92 *
168 * This dispatches a splice event. 93 * This dispatches a splice event.
169 * 94 *
170 * @param {...*} The items to append. 95 * @param {...*} The items to append.
171 * @return {number} The new length of the model. 96 * @return {number} The new length of the model.
172 */ 97 */
173 push: function(var_args) { 98 push: function(var_args) {
174 var args = Array.prototype.slice.call(arguments); 99 var args = Array.prototype.slice.call(arguments);
175 args.unshift(this.length, 0); 100 args.unshift(this.length, 0);
176 this.splice.apply(this, args); 101 this.splice.apply(this, args);
177 return this.length; 102 return this.length;
178 }, 103 },
179 104
180 /** 105 /**
181 * Use this to update a given item in the array. This does not remove and 106 * Use this to update a given item in the array. This does not remove and
182 * reinsert a new item. 107 * reinsert a new item.
108 *
183 * This dispatches a change event. 109 * This dispatches a change event.
184 * This runs sort after updating. 110 *
185 * @param {number} index The index of the item to update. 111 * @param {number} index The index of the item to update.
186 */ 112 */
187 updateIndex: function(index) { 113 updateIndex: function(index) {
188 if (index < 0 || index >= this.length) 114 if (index < 0 || index >= this.length)
189 throw Error('Invalid index, ' + index); 115 throw Error('Invalid index, ' + index);
190 116
191 // TODO(arv): Maybe unify splice and change events? 117 // TODO(arv): Maybe unify splice and change events?
192 var e = new Event('change'); 118 var e = new Event('change');
193 e.index = index; 119 e.index = index;
194 this.dispatchEvent(e); 120 this.dispatchEvent(e);
195
196 if (this.sortStatus.field) {
197 var sortPermutation = this.doSort_(this.sortStatus.field,
198 this.sortStatus.direction);
199 if (sortPermutation)
200 this.dispatchPermutedEvent_(sortPermutation);
201 }
202 },
203
204 /**
205 * Creates sort status with given field and direction.
206 * @param {string} field Sort field.
207 * @param {string} direction Sort direction.
208 * @return {!Object} Created sort status.
209 */
210 createSortStatus: function(field, direction) {
211 return {
212 field: field,
213 direction: direction
214 };
215 },
216
217 /**
218 * Called before a sort happens so that you may fetch additional data
219 * required for the sort.
220 *
221 * @param {string} field Sort field.
222 * @param {function()} callback The function to invoke when preparation
223 * is complete.
224 */
225 prepareSort: function(field, callback) {
226 callback();
227 },
228
229 /**
230 * Sorts data model according to given field and direction and dispathes
231 * sorted event.
232 * @param {string} field Sort field.
233 * @param {string} direction Sort direction.
234 */
235 sort: function(field, direction) {
236 var self = this;
237
238 this.prepareSort(field, function() {
239 var sortPermutation = self.doSort_(field, direction);
240 if (sortPermutation)
241 self.dispatchPermutedEvent_(sortPermutation);
242 self.dispatchSortEvent_();
243 });
244 },
245
246 /**
247 * Sorts data model according to given field and direction.
248 * @param {string} field Sort field.
249 * @param {string} direction Sort direction.
250 */
251 doSort_: function(field, direction) {
252 var compareFunction = this.sortFunction_(field, direction);
253 var positions = [];
254 for (var i = 0; i < this.length; i++) {
255 positions[this.indexes_[i]] = i;
256 }
257 this.indexes_.sort(compareFunction);
258 this.sortStatus_ = this.createSortStatus(field, direction);
259 var sortPermutation = [];
260 var changed = false;
261 for (var i = 0; i < this.length; i++) {
262 if (positions[this.indexes_[i]] != i)
263 changed = true;
264 sortPermutation[positions[this.indexes_[i]]] = i;
265 }
266 if (changed)
267 return sortPermutation;
268 return null;
269 },
270
271 dispatchSortEvent_: function() {
272 var e = new Event('sorted');
273 this.dispatchEvent(e);
274 },
275
276 dispatchPermutedEvent_: function(permutation) {
277 var e = new Event('permuted');
278 e.permutation = permutation;
279 this.dispatchEvent(e);
280 },
281
282 /**
283 * Creates compare function for the field.
284 * Returns the function set as sortFunction for given field
285 * or default compare function
286 * @param {string} field Sort field.
287 * @param {function(*, *): number} Compare function.
288 */
289 createCompareFunction_: function(field) {
290 var compareFunction =
291 this.compareFunctions_ ? this.compareFunctions_[field] : null;
292 var defaultValuesCompareFunction = this.defaultValuesCompareFunction;
293 if (compareFunction) {
294 return compareFunction;
295 } else {
296 return function(a, b) {
297 return defaultValuesCompareFunction.call(null, a[field], b[field]);
298 }
299 }
300 return compareFunction;
301 },
302
303 /**
304 * Creates compare function for given field and direction.
305 * @param {string} field Sort field.
306 * @param {string} direction Sort direction.
307 * @param {function(*, *): number} Compare function.
308 */
309 sortFunction_: function(field, direction) {
310 var compareFunction = null;
311 if (field !== null)
312 compareFunction = this.createCompareFunction_(field);
313 var dirMultiplier = direction == 'desc' ? -1 : 1;
314
315 return function(index1, index2) {
316 var item1 = this.array_[index1];
317 var item2 = this.array_[index2];
318
319 var compareResult = 0;
320 if (typeof(compareFunction) === 'function')
321 compareResult = compareFunction.call(null, item1, item2);
322 if (compareResult != 0)
323 return dirMultiplier * compareResult;
324 return dirMultiplier * this.defaultValuesCompareFunction(index1,
325 index2);
326 }.bind(this);
327 },
328
329 /**
330 * Default compare function.
331 */
332 defaultValuesCompareFunction: function(a, b) {
333 // We could insert i18n comparisons here.
334 if (a < b)
335 return -1;
336 if (a > b)
337 return 1;
338 return 0;
339 } 121 }
340 }; 122 };
341 123
342 return { 124 return {
343 ArrayDataModel: ArrayDataModel 125 ArrayDataModel: ArrayDataModel
344 }; 126 };
345 }); 127 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/file_manager/main.html ('k') | chrome/browser/resources/shared/js/cr/ui/list.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698