| Index: chrome/tools/test/reference_build/chrome_linux/resources/bookmark_manager/js/cr/ui/listselectionmodel.js
|
| ===================================================================
|
| --- chrome/tools/test/reference_build/chrome_linux/resources/bookmark_manager/js/cr/ui/listselectionmodel.js (revision 0)
|
| +++ chrome/tools/test/reference_build/chrome_linux/resources/bookmark_manager/js/cr/ui/listselectionmodel.js (revision 0)
|
| @@ -0,0 +1,442 @@
|
| +// 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() {
|
| + const Event = cr.Event;
|
| + const EventTarget = cr.EventTarget;
|
| +
|
| + /**
|
| + * Creates a new selection model 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 getItemBefore},
|
| + * {@code getItemAfter}, {@code getItemAbove} as well as {@code getItemBelow}.
|
| + *
|
| + * @constructor
|
| + * @extends {!cr.EventTarget}
|
| + */
|
| + function ListSelectionModel(list) {
|
| + this.list = list;
|
| + this.selectedItems_ = {};
|
| + }
|
| +
|
| + ListSelectionModel.prototype = {
|
| + __proto__: EventTarget.prototype,
|
| +
|
| + /**
|
| + * Returns the item below (y axis) the given element.
|
| + * @param {*} item The item to get the item below.
|
| + * @return {*} The item below or null if not found.
|
| + */
|
| + getItemBelow: function(item) {
|
| + return item.nextElementSibling;
|
| + },
|
| +
|
| + /**
|
| + * Returns the item above (y axis) the given element.
|
| + * @param {*} item The item to get the item above.
|
| + * @return {*} The item below or null if not found.
|
| + */
|
| + getItemAbove: function(item) {
|
| + return item.previousElementSibling;
|
| + },
|
| +
|
| + /**
|
| + * Returns the item before (x axis) the given element. This returns null
|
| + * by default but override this for icon view and horizontal selection
|
| + * models.
|
| + *
|
| + * @param {*} item The item to get the item before.
|
| + * @return {*} The item before or null if not found.
|
| + */
|
| + getItemBefore: function(item) {
|
| + return null;
|
| + },
|
| +
|
| + /**
|
| + * Returns the item after (x axis) the given element. This returns null
|
| + * by default but override this for icon view and horizontal selection
|
| + * models.
|
| + *
|
| + * @param {*} item The item to get the item after.
|
| + * @return {*} The item after or null if not found.
|
| + */
|
| + getItemAfter: function(item) {
|
| + return null;
|
| + },
|
| +
|
| + /**
|
| + * Returns the next list item. This is the next logical and should not
|
| + * depend on any kind of layout of the list.
|
| + * @param {*} item The item to get the next item for.
|
| + * @return {*} The next item or null if not found.
|
| + */
|
| + getNextItem: function(item) {
|
| + return item.nextElementSibling;
|
| + },
|
| +
|
| + /**
|
| + * Returns the prevous list item. This is the previous logical and should
|
| + * not depend on any kind of layout of the list.
|
| + * @param {*} item The item to get the previous item for.
|
| + * @return {*} The previous item or null if not found.
|
| + */
|
| + getPreviousItem: function(item) {
|
| + return item.previousElementSibling;
|
| + },
|
| +
|
| + /**
|
| + * @return {*} The first item.
|
| + */
|
| + getFirstItem: function() {
|
| + return this.list.firstElementChild;
|
| + },
|
| +
|
| + /**
|
| + * @return {*} The last item.
|
| + */
|
| + getLastItem: function() {
|
| + return this.list.lastElementChild;
|
| + },
|
| +
|
| + /**
|
| + * Called by the view when the user does a mousedown or mouseup on the list.
|
| + * @param {!Event} e The browser mousedown event.
|
| + * @param {*} item The item that was under the mouse pointer, null if none.
|
| + */
|
| + handleMouseDownUp: function(e, item) {
|
| + var anchorItem = this.anchorItem;
|
| +
|
| + this.beginChange_();
|
| +
|
| + if (!item && !e.ctrlKey && !e.shiftKey && !e.metaKey) {
|
| + this.clear();
|
| + } else {
|
| + var isDown = e.type == 'mousedown';
|
| + if (!cr.isMac && e.ctrlKey) {
|
| + // Handle ctrlKey on mouseup
|
| + if (!isDown) {
|
| + // toggle the current one and make it anchor item
|
| + this.setItemSelected(item, !this.getItemSelected(item));
|
| + this.leadItem = item;
|
| + this.anchorItem = item;
|
| + }
|
| + } else if (e.shiftKey && anchorItem && anchorItem != item) {
|
| + // Shift is done in mousedown
|
| + if (isDown) {
|
| + this.clearAllSelected_();
|
| + this.leadItem = item;
|
| + this.selectRange(anchorItem, item);
|
| + }
|
| + } else {
|
| + // Right click for a context menu need to not clear the selection.
|
| + var isRightClick = e.button == 2;
|
| +
|
| + // If the item is selected this is handled in mouseup.
|
| + var itemSelected = this.getItemSelected(item);
|
| + if ((itemSelected && !isDown || !itemSelected && isDown) &&
|
| + !(itemSelected && isRightClick)) {
|
| + this.clearAllSelected_();
|
| + this.setItemSelected(item, true);
|
| + this.leadItem = item;
|
| + this.anchorItem = item;
|
| + }
|
| + }
|
| + }
|
| +
|
| + this.endChange_();
|
| + },
|
| +
|
| + /**
|
| + * Called by the view when it recieves a keydown event.
|
| + * @param {Event} e The keydown event.
|
| + */
|
| + handleKeyDown: function(e) {
|
| + var newItem = null;
|
| + var leadItem = this.leadItem;
|
| + var prevent = true;
|
| +
|
| + // Ctrl/Meta+A
|
| + if (e.keyCode == 65 &&
|
| + (cr.isMac && e.metaKey || !cr.isMac && e.ctrlKey)) {
|
| + this.selectAll();
|
| + e.preventDefault();
|
| + return;
|
| + }
|
| +
|
| + // Space
|
| + if (e.keyCode == 32) {
|
| + if (leadItem != null) {
|
| + var selected = this.getItemSelected(leadItem);
|
| + if (e.ctrlKey || !selected) {
|
| + this.beginChange_();
|
| + this.setItemSelected(leadItem, !selected);
|
| + this.endChange_();
|
| + return;
|
| + }
|
| + }
|
| + }
|
| +
|
| + switch (e.keyIdentifier) {
|
| + case 'Home':
|
| + newItem = this.getFirstItem();
|
| + break;
|
| + case 'End':
|
| + newItem = this.getLastItem();
|
| + break;
|
| + case 'Up':
|
| + newItem = !leadItem ?
|
| + this.getLastItem() : this.getItemAbove(leadItem);
|
| + break;
|
| + case 'Down':
|
| + newItem = !leadItem ?
|
| + this.getFirstItem() : this.getItemBelow(leadItem);
|
| + break;
|
| + case 'Left':
|
| + newItem = !leadItem ?
|
| + this.getLastItem() : this.getItemBefore(leadItem);
|
| + break;
|
| + case 'Right':
|
| + newItem = !leadItem ?
|
| + this.getFirstItem() : this.getItemAfter(leadItem);
|
| + break;
|
| + default:
|
| + prevent = false;
|
| + }
|
| +
|
| + if (newItem) {
|
| + this.beginChange_();
|
| +
|
| + this.leadItem = newItem;
|
| + if (e.shiftKey) {
|
| + var anchorItem = this.anchorItem;
|
| + this.clearAllSelected_();
|
| + if (!anchorItem) {
|
| + this.setItemSelected(newItem, true);
|
| + this.anchorItem = newItem;
|
| + } else {
|
| + this.selectRange(anchorItem, newItem);
|
| + }
|
| + } else if (e.ctrlKey && !cr.isMac) {
|
| + // Setting the lead item is done above
|
| + // Mac does not allow you to change the lead.
|
| + } else {
|
| + this.clearAllSelected_();
|
| + this.setItemSelected(newItem, true);
|
| + this.anchorItem = newItem;
|
| + }
|
| +
|
| + this.endChange_();
|
| +
|
| + if (prevent)
|
| + e.preventDefault();
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * @type {!Array} The selected items.
|
| + */
|
| + get selectedItems() {
|
| + return Object.keys(this.selectedItems_).map(function(uid) {
|
| + return this.selectedItems_[uid];
|
| + }, this);
|
| + },
|
| + set selectedItems(selectedItems) {
|
| + this.beginChange_();
|
| + this.clearAllSelected_();
|
| + for (var i = 0; i < selectedItems.length; i++) {
|
| + this.setItemSelected(selectedItems[i], true);
|
| + }
|
| + this.leadItem = this.anchorItem = selectedItems[0] || null;
|
| + this.endChange_();
|
| + },
|
| +
|
| + /**
|
| + * Convenience getter which returns the first selected item.
|
| + * @type {*}
|
| + */
|
| + get selectedItem() {
|
| + for (var uid in this.selectedItems_) {
|
| + return this.selectedItems_[uid];
|
| + }
|
| + return null;
|
| + },
|
| + set selectedItem(selectedItem) {
|
| + this.beginChange_();
|
| + this.clearAllSelected_();
|
| + if (selectedItem) {
|
| + this.selectedItems = [selectedItem];
|
| + } else {
|
| + this.leadItem = this.anchorItem = null;
|
| + }
|
| + this.endChange_();
|
| + },
|
| +
|
| + /**
|
| + * Selects a range of items, starting with {@code start} and ends with
|
| + * {@code end}.
|
| + * @param {*} start The first item to select.
|
| + * @param {*} end The last item to select.
|
| + */
|
| + selectRange: function(start, end) {
|
| + // Swap if starts comes after end.
|
| + if (start.compareDocumentPosition(end) & Node.DOCUMENT_POSITION_PRECEDING) {
|
| + var tmp = start;
|
| + start = end;
|
| + end = tmp;
|
| + }
|
| +
|
| + this.beginChange_();
|
| +
|
| + for (var item = start; item != end; item = this.getNextItem(item)) {
|
| + this.setItemSelected(item, true);
|
| + }
|
| + this.setItemSelected(end, true);
|
| +
|
| + this.endChange_();
|
| + },
|
| +
|
| + /**
|
| + * Selects all items.
|
| + */
|
| + selectAll: function() {
|
| + this.selectRange(this.getFirstItem(), this.getLastItem());
|
| + },
|
| +
|
| + /**
|
| + * Clears the selection
|
| + */
|
| + clear: function() {
|
| + this.beginChange_();
|
| + this.clearAllSelected_();
|
| + this.endChange_();
|
| + },
|
| +
|
| + /**
|
| + * Clears the selection and updates the view.
|
| + * @private
|
| + */
|
| + clearAllSelected_: function() {
|
| + for (var uid in this.selectedItems_) {
|
| + this.setItemSelected(this.selectedItems_[uid], false);
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Sets the selecte state for an item.
|
| + * @param {*} item The item to set the selected state for.
|
| + * @param {boolean} b Whether to select the item or not.
|
| + */
|
| + setItemSelected: function(item, b) {
|
| + var uid = this.list.itemToUid(item);
|
| + var oldSelected = uid in this.selectedItems_;
|
| + if (oldSelected == b)
|
| + return;
|
| +
|
| + if (b)
|
| + this.selectedItems_[uid] = item;
|
| + else
|
| + delete this.selectedItems_[uid];
|
| +
|
| + this.beginChange_();
|
| +
|
| + // Changing back?
|
| + if (uid in this.changedUids_ && this.changedUids_[uid] == !b) {
|
| + delete this.changedUids_[uid];
|
| + } else {
|
| + this.changedUids_[uid] = b;
|
| + }
|
| +
|
| + // End change dispatches an event which in turn may update the view.
|
| + this.endChange_();
|
| + },
|
| +
|
| + /**
|
| + * Whether a given item is selected or not.
|
| + * @param {*} item The item to check.
|
| + * @return {boolean} Whether an item is selected.
|
| + */
|
| + getItemSelected: function(item) {
|
| + var uid = this.list.itemToUid(item);
|
| + return uid in this.selectedItems_;
|
| + },
|
| +
|
| + /**
|
| + * This is used to begin batching changes. Call {@code endChange_} when you
|
| + * are done making changes.
|
| + * @private
|
| + */
|
| + beginChange_: function() {
|
| + if (!this.changeCount_) {
|
| + this.changeCount_ = 0;
|
| + this.changedUids_ = {};
|
| + }
|
| + this.changeCount_++;
|
| + },
|
| +
|
| + /**
|
| + * Call this after changes are done and it will dispatch a change event if
|
| + * any changes were actually done.
|
| + * @private
|
| + */
|
| + endChange_: function() {
|
| + this.changeCount_--;
|
| + if (!this.changeCount_) {
|
| + var uids = Object.keys(this.changedUids_);
|
| + if (uids.length) {
|
| + var e = new Event('change');
|
| + e.changes = uids.map(function(uid) {
|
| + return {
|
| + uid: uid,
|
| + selected: this.changedUids_[uid]
|
| + };
|
| + }, this);
|
| + this.dispatchEvent(e);
|
| + }
|
| + delete this.changedUids_;
|
| + delete this.changeCount_;
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Called when an item is removed from the lisst.
|
| + * @param {cr.ui.ListItem} item The list item that was removed.
|
| + */
|
| + remove: function(item) {
|
| + if (item == this.leadItem)
|
| + this.leadItem = this.getNextItem(item) || this.getPreviousItem(item);
|
| + if (item == this.anchorItem)
|
| + this.anchorItem = this.getNextItem(item) || this.getPreviousItem(item);
|
| +
|
| + // Deselect when removing items.
|
| + if (this.getItemSelected(item))
|
| + this.setItemSelected(item, false);
|
| + },
|
| +
|
| + /**
|
| + * Called when an item was added to the list.
|
| + * @param {cr.ui.ListItem} item The list item to add.
|
| + */
|
| + add: function(item) {
|
| + // We could (should?) check if the item is selected here and update the
|
| + // selection model.
|
| + }
|
| + };
|
| +
|
| + /**
|
| + * The anchorItem is used with multiple selection.
|
| + * @type {*}
|
| + */
|
| + cr.defineProperty(ListSelectionModel, 'anchorItem', cr.PropertyKind.JS, null);
|
| +
|
| + /**
|
| + * The leadItem is used with multiple selection and it is the item that the
|
| + * user is moving uysing the arrow keys.
|
| + * @type {*}
|
| + */
|
| + cr.defineProperty(ListSelectionModel, 'leadItem', cr.PropertyKind.JS, null);
|
| +
|
| + return {
|
| + ListSelectionModel: ListSelectionModel
|
| + };
|
| +});
|
|
|
| Property changes on: chrome/tools/test/reference_build/chrome_linux/resources/bookmark_manager/js/cr/ui/listselectionmodel.js
|
| ___________________________________________________________________
|
| Name: svn:eol-style
|
| + LF
|
|
|
|
|