Index: chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/js/cr/ui/list_selection_model.js |
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/js/cr/ui/list_selection_model.js b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/js/cr/ui/list_selection_model.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8c16d577f5f2f9d5105df1511ebdbad9fabec353 |
--- /dev/null |
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/js/cr/ui/list_selection_model.js |
@@ -0,0 +1,275 @@ |
+// 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. |
+ |
+cr.define('cr.ui', function() { |
+ const Event = cr.Event; |
+ const EventTarget = cr.EventTarget; |
+ |
+ /** |
+ * Creates a new selection model that is to be used with lists. |
+ * |
+ * @param {number=} opt_length The number items in the selection. |
+ * |
+ * @constructor |
+ * @extends {!cr.EventTarget} |
+ */ |
+ function ListSelectionModel(opt_length) { |
+ this.length_ = opt_length || 0; |
+ // Even though selectedIndexes_ is really a map we use an array here to get |
+ // iteration in the order of the indexes. |
+ this.selectedIndexes_ = []; |
+ } |
+ |
+ ListSelectionModel.prototype = { |
+ __proto__: EventTarget.prototype, |
+ |
+ /** |
+ * The number of items in the model. |
+ * @type {number} |
+ */ |
+ get length() { |
+ return this.length_; |
+ }, |
+ |
+ /** |
+ * @type {!Array} The selected indexes. |
+ */ |
+ get selectedIndexes() { |
+ return Object.keys(this.selectedIndexes_).map(Number); |
+ }, |
+ set selectedIndexes(selectedIndexes) { |
+ this.beginChange(); |
+ this.unselectAll(); |
+ for (var i = 0; i < selectedIndexes.length; i++) { |
+ this.setIndexSelected(selectedIndexes[i], true); |
+ } |
+ if (selectedIndexes.length) { |
+ this.leadIndex = this.anchorIndex = selectedIndexes[0]; |
+ } else { |
+ this.leadIndex = this.anchorIndex = -1; |
+ } |
+ this.endChange(); |
+ }, |
+ |
+ /** |
+ * Convenience getter which returns the first selected index. |
+ * @type {number} |
+ */ |
+ get selectedIndex() { |
+ for (var i in this.selectedIndexes_) { |
+ return Number(i); |
+ } |
+ return -1; |
+ }, |
+ set selectedIndex(selectedIndex) { |
+ this.beginChange(); |
+ this.unselectAll(); |
+ if (selectedIndex != -1) { |
+ this.selectedIndexes = [selectedIndex]; |
+ } else { |
+ this.leadIndex = this.anchorIndex = -1; |
+ } |
+ this.endChange(); |
+ }, |
+ |
+ /** |
+ * Selects a range of indexes, starting with {@code start} and ends with |
+ * {@code end}. |
+ * @param {number} start The first index to select. |
+ * @param {number} end The last index to select. |
+ */ |
+ selectRange: function(start, end) { |
+ // Swap if starts comes after end. |
+ if (start > end) { |
+ var tmp = start; |
+ start = end; |
+ end = tmp; |
+ } |
+ |
+ this.beginChange(); |
+ |
+ for (var index = start; index != end; index++) { |
+ this.setIndexSelected(index, true); |
+ } |
+ this.setIndexSelected(end, true); |
+ |
+ this.endChange(); |
+ }, |
+ |
+ /** |
+ * Selects all indexes. |
+ */ |
+ selectAll: function() { |
+ this.selectRange(0, this.length - 1); |
+ }, |
+ |
+ /** |
+ * Clears the selection |
+ */ |
+ clear: function() { |
+ this.beginChange(); |
+ this.length_ = 0; |
+ this.anchorIndex = this.leadIndex = -1; |
+ this.unselectAll(); |
+ this.endChange(); |
+ }, |
+ |
+ /** |
+ * Unselects all selected items. |
+ */ |
+ unselectAll: function() { |
+ this.beginChange(); |
+ for (var i in this.selectedIndexes_) { |
+ this.setIndexSelected(i, false); |
+ } |
+ this.endChange(); |
+ }, |
+ |
+ /** |
+ * Sets the selected state for an index. |
+ * @param {number} index The index to set the selected state for. |
+ * @param {boolean} b Whether to select the index or not. |
+ */ |
+ setIndexSelected: function(index, b) { |
+ var oldSelected = index in this.selectedIndexes_; |
+ if (oldSelected == b) |
+ return; |
+ |
+ if (b) |
+ this.selectedIndexes_[index] = true; |
+ else |
+ delete this.selectedIndexes_[index]; |
+ |
+ this.beginChange(); |
+ |
+ // Changing back? |
+ if (index in this.changedIndexes_ && this.changedIndexes_[index] == !b) { |
+ delete this.changedIndexes_[index]; |
+ } else { |
+ this.changedIndexes_[index] = b; |
+ } |
+ |
+ // End change dispatches an event which in turn may update the view. |
+ this.endChange(); |
+ }, |
+ |
+ /** |
+ * Whether a given index is selected or not. |
+ * @param {number} index The index to check. |
+ * @return {boolean} Whether an index is selected. |
+ */ |
+ getIndexSelected: function(index) { |
+ return index in this.selectedIndexes_; |
+ }, |
+ |
+ /** |
+ * This is used to begin batching changes. Call {@code endChange} when you |
+ * are done making changes. |
+ */ |
+ beginChange: function() { |
+ if (!this.changeCount_) { |
+ this.changeCount_ = 0; |
+ this.changedIndexes_ = {}; |
+ } |
+ this.changeCount_++; |
+ }, |
+ |
+ /** |
+ * Call this after changes are done and it will dispatch a change event if |
+ * any changes were actually done. |
+ */ |
+ endChange: function() { |
+ this.changeCount_--; |
+ if (!this.changeCount_) { |
+ var indexes = Object.keys(this.changedIndexes_); |
+ if (indexes.length) { |
+ var e = new Event('change'); |
+ e.changes = indexes.map(function(index) { |
+ return { |
+ index: index, |
+ selected: this.changedIndexes_[index] |
+ }; |
+ }, this); |
+ this.dispatchEvent(e); |
+ } |
+ this.changedIndexes_ = {}; |
+ } |
+ }, |
+ |
+ leadIndex_: -1, |
+ |
+ /** |
+ * The leadIndex is used with multiple selection and it is the index that |
+ * the user is moving using the arrow keys. |
+ * @type {number} |
+ */ |
+ get leadIndex() { |
+ return this.leadIndex_; |
+ }, |
+ set leadIndex(leadIndex) { |
+ var li = Math.max(-1, Math.min(this.length_ - 1, leadIndex)); |
+ if (li != this.leadIndex_) { |
+ var oldLeadIndex = this.leadIndex_; |
+ this.leadIndex_ = li; |
+ cr.dispatchPropertyChange(this, 'leadIndex', li, oldLeadIndex); |
+ } |
+ }, |
+ |
+ anchorIndex_: -1, |
+ |
+ /** |
+ * The anchorIndex is used with multiple selection. |
+ * @type {number} |
+ */ |
+ get anchorIndex() { |
+ return this.anchorIndex_; |
+ }, |
+ set anchorIndex(anchorIndex) { |
+ var ai = Math.max(-1, Math.min(this.length_ - 1, anchorIndex)); |
+ if (ai != this.anchorIndex_) { |
+ var oldAnchorIndex = this.anchorIndex_; |
+ this.anchorIndex_ = ai; |
+ cr.dispatchPropertyChange(this, 'anchorIndex', ai, oldAnchorIndex); |
+ } |
+ }, |
+ |
+ /** |
+ * Whether the selection model supports multiple selected items. |
+ * @type {boolean} |
+ */ |
+ get multiple() { |
+ return true; |
+ }, |
+ |
+ /** |
+ * 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]; |
+ }, |
+ |
+ /** |
+ * Adjusts selection model length. |
+ * @param {number} length New selection model length. |
+ */ |
+ adjustLength: function(length) { |
+ this.length_ = length; |
+ } |
+ }; |
+ |
+ return { |
+ ListSelectionModel: ListSelectionModel |
+ }; |
+}); |