1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 cr.define('options', function() { 6 const List = cr.ui.List; 7 const ListItem = cr.ui.ListItem; 8 9 /** 10 * Creates a deletable list item, which has a button that will trigger a call 11 * to deleteItemAtIndex(index) in the list. 12 */ 13 var DeletableItem = cr.ui.define('li'); 14 15 DeletableItem.prototype = { 16 __proto__: ListItem.prototype, 17 18 /** 19 * The element subclasses should populate with content. 20 * @type {HTMLElement} 21 * @private 22 */ 23 contentElement_: null, 24 25 /** 26 * The close button element. 27 * @type {HTMLElement} 28 * @private 29 */ 30 closeButtonElement_: null, 31 32 /** 33 * Whether or not this item can be deleted. 34 * @type {boolean} 35 * @private 36 */ 37 deletable_: true, 38 39 /** @inheritDoc */ 40 decorate: function() { 41 ListItem.prototype.decorate.call(this); 42 43 this.classList.add('deletable-item'); 44 45 this.contentElement_ = this.ownerDocument.createElement('div'); 46 this.appendChild(this.contentElement_); 47 48 this.closeButtonElement_ = this.ownerDocument.createElement('button'); 49 this.closeButtonElement_.classList.add('raw-button'); 50 this.closeButtonElement_.classList.add('close-button'); 51 this.closeButtonElement_.addEventListener('mousedown', 52 this.handleMouseDownUpOnClose_); 53 this.closeButtonElement_.addEventListener('mouseup', 54 this.handleMouseDownUpOnClose_); 55 this.appendChild(this.closeButtonElement_); 56 }, 57 58 /** 59 * Returns the element subclasses should add content to. 60 * @return {HTMLElement} The element subclasses should popuplate. 61 */ 62 get contentElement() { 63 return this.contentElement_; 64 }, 65 66 /* Gets/sets the deletable property. An item that is not deletable doesn't 67 * show the delete button (although space is still reserved for it). 68 */ 69 get deletable() { 70 return this.deletable_; 71 }, 72 set deletable(value) { 73 this.deletable_ = value; 74 this.closeButtonElement_.disabled = !value; 75 }, 76 77 /** 78 * Don't let the list have a crack at the event. We don't want clicking the 79 * close button to change the selection of the list. 80 * @param {Event} e The mouse down/up event object. 81 * @private 82 */ 83 handleMouseDownUpOnClose_: function(e) { 84 if (!e.target.disabled) 85 e.stopPropagation(); 86 }, 87 }; 88 89 var DeletableItemList = cr.ui.define('list'); 90 91 DeletableItemList.prototype = { 92 __proto__: List.prototype, 93 94 /** @inheritDoc */ 95 decorate: function() { 96 List.prototype.decorate.call(this); 97 this.addEventListener('click', this.handleClick_); 98 this.addEventListener('keydown', this.handleKeyDown_); 99 }, 100 101 /** 102 * Callback for onclick events. 103 * @param {Event} e The click event object. 104 * @private 105 */ 106 handleClick_: function(e) { 107 if (this.disabled) 108 return; 109 110 var target = e.target; 111 if (target.classList.contains('close-button')) { 112 var listItem = this.getListItemAncestor(target); 113 var selected = this.selectionModel.selectedIndexes; 114 115 // Check if the list item that contains the close button being clicked 116 // is not in the list of selected items. Only delete this item in that 117 // case. 118 var idx = this.getIndexOfListItem(listItem); 119 if (selected.indexOf(idx) == -1) { 120 this.deleteItemAtIndex(idx); 121 } else { 122 this.deleteSelectedItems_(); 123 } 124 } 125 }, 126 127 /** 128 * Callback for keydown events. 129 * @param {Event} e The keydown event object. 130 * @private 131 */ 132 handleKeyDown_: function(e) { 133 // Map delete (and backspace on Mac) to item deletion (unless focus is 134 // in an input field, where it's intended for text editing). 135 if ((e.keyCode == 46 || (e.keyCode == 8 && cr.isMac)) && 136 e.target.tagName != 'INPUT') { 137 this.deleteSelectedItems_(); 138 // Prevent the browser from going back. 139 e.preventDefault(); 140 } 141 }, 142 143 /** 144 * Deletes all the currently selected items that are deletable. 145 * @private 146 */ 147 deleteSelectedItems_: function() { 148 var selected = this.selectionModel.selectedIndexes; 149 // Reverse through the list of selected indexes to maintain the 150 // correct index values after deletion. 151 for (var j = selected.length - 1; j >= 0; j--) { 152 var index = selected[j]; 153 if (this.getListItemByIndex(index).deletable) 154 this.deleteItemAtIndex(index); 155 } 156 }, 157 158 /** 159 * Called when an item should be deleted; subclasses are responsible for 160 * implementing. 161 * @param {number} index The index of the item that is being deleted. 162 */ 163 deleteItemAtIndex: function(index) { 164 }, 165 }; 166 167 return { 168 DeletableItemList: DeletableItemList, 169 DeletableItem: DeletableItem, 170 }; 171 }); 172