Index: chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/js/cr/ui/list_selection_controller.js |
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/js/cr/ui/list_selection_controller.js b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/js/cr/ui/list_selection_controller.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..35101d1e715e5f83a4d76f1d5dd6a39582e45a85 |
--- /dev/null |
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/domui/js/cr/ui/list_selection_controller.js |
@@ -0,0 +1,289 @@ |
+// Copyright (c) 2010 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() { |
+ /** |
+ * Creates a selection controller that is to be used with lists. This is |
+ * implemented for vertical lists but changing the behavior for horizontal |
+ * lists or icon views is a matter of overriding {@code getIndexBefore}, |
+ * {@code getIndexAfter}, {@code getIndexAbove} as well as |
+ * {@code getIndexBelow}. |
+ * |
+ * @param {cr.ui.ListSelectionModel} selectionModel The selection model to |
+ * interact with. |
+ * |
+ * @constructor |
+ * @extends {!cr.EventTarget} |
+ */ |
+ function ListSelectionController(selectionModel) { |
+ this.selectionModel_ = selectionModel; |
+ } |
+ |
+ ListSelectionController.prototype = { |
+ |
+ /** |
+ * The selection model we are interacting with. |
+ * @type {cr.ui.ListSelectionModel} |
+ */ |
+ get selectionModel() { |
+ return this.selectionModel_; |
+ }, |
+ |
+ /** |
+ * Returns the index below (y axis) the given element. |
+ * @param {number} index The index to get the index below. |
+ * @return {number} The index below or -1 if not found. |
+ */ |
+ getIndexBelow: function(index) { |
+ if (index == this.getLastIndex()) |
+ return -1; |
+ return index + 1; |
+ }, |
+ |
+ /** |
+ * Returns the index above (y axis) the given element. |
+ * @param {number} index The index to get the index above. |
+ * @return {number} The index below or -1 if not found. |
+ */ |
+ getIndexAbove: function(index) { |
+ return index - 1; |
+ }, |
+ |
+ /** |
+ * Returns the index before (x axis) the given element. This returns -1 |
+ * by default but override this for icon view and horizontal selection |
+ * models. |
+ * |
+ * @param {number} index The index to get the index before. |
+ * @return {number} The index before or -1 if not found. |
+ */ |
+ getIndexBefore: function(index) { |
+ return -1; |
+ }, |
+ |
+ /** |
+ * Returns the index after (x axis) the given element. This returns -1 |
+ * by default but override this for icon view and horizontal selection |
+ * models. |
+ * |
+ * @param {number} index The index to get the index after. |
+ * @return {number} The index after or -1 if not found. |
+ */ |
+ getIndexAfter: function(index) { |
+ return -1; |
+ }, |
+ |
+ /** |
+ * Returns the next list index. This is the next logical and should not |
+ * depend on any kind of layout of the list. |
+ * @param {number} index The index to get the next index for. |
+ * @return {number} The next index or -1 if not found. |
+ */ |
+ getNextIndex: function(index) { |
+ if (index == this.getLastIndex()) |
+ return -1; |
+ return index + 1; |
+ }, |
+ |
+ /** |
+ * Returns the prevous list index. This is the previous logical and should |
+ * not depend on any kind of layout of the list. |
+ * @param {number} index The index to get the previous index for. |
+ * @return {number} The previous index or -1 if not found. |
+ */ |
+ getPreviousIndex: function(index) { |
+ return index - 1; |
+ }, |
+ |
+ /** |
+ * @return {number} The first index. |
+ */ |
+ getFirstIndex: function() { |
+ return 0; |
+ }, |
+ |
+ /** |
+ * @return {number} The last index. |
+ */ |
+ getLastIndex: function() { |
+ return this.selectionModel.length - 1; |
+ }, |
+ |
+ /** |
+ * Called by the view when the user does a mousedown or mouseup on the list. |
+ * @param {!Event} e The browser mousedown event. |
+ * @param {number} index The index that was under the mouse pointer, -1 if |
+ * none. |
+ */ |
+ handleMouseDownUp: function(e, index) { |
+ var sm = this.selectionModel; |
+ var anchorIndex = sm.anchorIndex; |
+ var isDown = e.type == 'mousedown'; |
+ |
+ sm.beginChange(); |
+ |
+ if (index == -1) { |
+ // On Mac we always clear the selection if the user clicks a blank area. |
+ // On Windows, we only clear the selection if neither Shift nor Ctrl are |
+ // pressed. |
+ if (cr.isMac) { |
+ sm.leadIndex = sm.anchorIndex = -1; |
+ if (sm.multiple) |
+ sm.unselectAll(); |
+ } else if (!isDown && !e.shiftKey && !e.ctrlKey) |
+ // Keep anchor and lead indexes. Note that this is intentionally |
+ // different than on the Mac. |
+ if (sm.multiple) |
+ sm.unselectAll(); |
+ } else { |
+ if (sm.multiple && (cr.isMac ? e.metaKey : |
+ (e.ctrlKey && !e.shiftKey))) { |
+ // Selection is handled at mouseUp on windows/linux, mouseDown on mac. |
+ if (cr.isMac? isDown : !isDown) { |
+ // Toggle the current one and make it anchor index. |
+ sm.setIndexSelected(index, !sm.getIndexSelected(index)); |
+ sm.leadIndex = index; |
+ sm.anchorIndex = index; |
+ } |
+ } else if (e.shiftKey && anchorIndex != -1 && anchorIndex != index) { |
+ // Shift is done in mousedown. |
+ if (isDown) { |
+ sm.unselectAll(); |
+ sm.leadIndex = index; |
+ if (sm.multiple) |
+ sm.selectRange(anchorIndex, index); |
+ else |
+ sm.setIndexSelected(index, true); |
+ } |
+ } else { |
+ // Right click for a context menu needs to not clear the selection. |
+ var isRightClick = e.button == 2; |
+ |
+ // If the index is selected this is handled in mouseup. |
+ var indexSelected = sm.getIndexSelected(index); |
+ if ((indexSelected && !isDown || !indexSelected && isDown) && |
+ !(indexSelected && isRightClick)) { |
+ sm.unselectAll(); |
+ sm.setIndexSelected(index, true); |
+ sm.leadIndex = index; |
+ sm.anchorIndex = index; |
+ } |
+ } |
+ } |
+ |
+ sm.endChange(); |
+ }, |
+ |
+ /** |
+ * Called by the view when it receives a keydown event. |
+ * @param {Event} e The keydown event. |
+ */ |
+ handleKeyDown: function(e) { |
+ const SPACE_KEY_CODE = 32; |
+ var tagName = e.target.tagName; |
+ // If focus is in an input field of some kind, only handle navigation keys |
+ // that aren't likely to conflict with input interaction (e.g., text |
+ // editing, or changing the value of a checkbox or select). |
+ if (tagName == 'INPUT') { |
+ var inputType = e.target.type; |
+ // Just protect space (for toggling) for checkbox and radio. |
+ if (inputType == 'checkbox' || inputType == 'radio') { |
+ if (e.keyCode == SPACE_KEY_CODE) |
+ return; |
+ // Protect all but the most basic navigation commands in anything else. |
+ } else if (e.keyIdentifier != 'Up' && e.keyIdentifier != 'Down') { |
+ return; |
+ } |
+ } |
+ // Similarly, don't interfere with select element handling. |
+ if (tagName == 'SELECT') |
+ return; |
+ |
+ var sm = this.selectionModel; |
+ var newIndex = -1; |
+ var leadIndex = sm.leadIndex; |
+ var prevent = true; |
+ |
+ // Ctrl/Meta+A |
+ if (sm.multiple && e.keyCode == 65 && |
+ (cr.isMac && e.metaKey || !cr.isMac && e.ctrlKey)) { |
+ sm.selectAll(); |
+ e.preventDefault(); |
+ return; |
+ } |
+ |
+ // Space |
+ if (e.keyCode == SPACE_KEY_CODE) { |
+ if (leadIndex != -1) { |
+ var selected = sm.getIndexSelected(leadIndex); |
+ if (e.ctrlKey || !selected) { |
+ sm.setIndexSelected(leadIndex, !selected || !sm.multiple); |
+ return; |
+ } |
+ } |
+ } |
+ |
+ switch (e.keyIdentifier) { |
+ case 'Home': |
+ newIndex = this.getFirstIndex(); |
+ break; |
+ case 'End': |
+ newIndex = this.getLastIndex(); |
+ break; |
+ case 'Up': |
+ newIndex = leadIndex == -1 ? |
+ this.getLastIndex() : this.getIndexAbove(leadIndex); |
+ break; |
+ case 'Down': |
+ newIndex = leadIndex == -1 ? |
+ this.getFirstIndex() : this.getIndexBelow(leadIndex); |
+ break; |
+ case 'Left': |
+ newIndex = leadIndex == -1 ? |
+ this.getLastIndex() : this.getIndexBefore(leadIndex); |
+ break; |
+ case 'Right': |
+ newIndex = leadIndex == -1 ? |
+ this.getFirstIndex() : this.getIndexAfter(leadIndex); |
+ break; |
+ default: |
+ prevent = false; |
+ } |
+ |
+ if (newIndex != -1) { |
+ sm.beginChange(); |
+ |
+ sm.leadIndex = newIndex; |
+ if (e.shiftKey) { |
+ var anchorIndex = sm.anchorIndex; |
+ if (sm.multiple) |
+ sm.unselectAll(); |
+ if (anchorIndex == -1) { |
+ sm.setIndexSelected(newIndex, true); |
+ sm.anchorIndex = newIndex; |
+ } else { |
+ sm.selectRange(anchorIndex, newIndex); |
+ } |
+ } else if (e.ctrlKey && !cr.isMac) { |
+ // Setting the lead index is done above. |
+ // Mac does not allow you to change the lead. |
+ } else { |
+ if (sm.multiple) |
+ sm.unselectAll(); |
+ sm.setIndexSelected(newIndex, true); |
+ sm.anchorIndex = newIndex; |
+ } |
+ |
+ sm.endChange(); |
+ |
+ if (prevent) |
+ e.preventDefault(); |
+ } |
+ } |
+ }; |
+ |
+ return { |
+ ListSelectionController: ListSelectionController |
+ }; |
+}); |