OLD | NEW |
| (Empty) |
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_.className = | |
50 'raw-button close-button custom-appearance'; | |
51 this.closeButtonElement_.addEventListener('mousedown', | |
52 this.handleMouseDownUpOnClose_); | |
53 this.closeButtonElement_.addEventListener('mouseup', | |
54 this.handleMouseDownUpOnClose_); | |
55 this.closeButtonElement_.addEventListener('focus', | |
56 this.handleFocus_.bind(this)); | |
57 this.appendChild(this.closeButtonElement_); | |
58 }, | |
59 | |
60 /** | |
61 * Returns the element subclasses should add content to. | |
62 * @return {HTMLElement} The element subclasses should popuplate. | |
63 */ | |
64 get contentElement() { | |
65 return this.contentElement_; | |
66 }, | |
67 | |
68 /* Gets/sets the deletable property. An item that is not deletable doesn't | |
69 * show the delete button (although space is still reserved for it). | |
70 */ | |
71 get deletable() { | |
72 return this.deletable_; | |
73 }, | |
74 set deletable(value) { | |
75 this.deletable_ = value; | |
76 this.closeButtonElement_.disabled = !value; | |
77 }, | |
78 | |
79 /** | |
80 * Called when a focusable child element receives focus. Selects this item | |
81 * in the list selection model. | |
82 * @private | |
83 */ | |
84 handleFocus_: function() { | |
85 var list = this.parentNode; | |
86 var index = list.getIndexOfListItem(this); | |
87 list.selectionModel.selectedIndex = index; | |
88 list.selectionModel.anchorIndex = index; | |
89 }, | |
90 | |
91 /** | |
92 * Don't let the list have a crack at the event. We don't want clicking the | |
93 * close button to change the selection of the list. | |
94 * @param {Event} e The mouse down/up event object. | |
95 * @private | |
96 */ | |
97 handleMouseDownUpOnClose_: function(e) { | |
98 if (!e.target.disabled) | |
99 e.stopPropagation(); | |
100 }, | |
101 }; | |
102 | |
103 var DeletableItemList = cr.ui.define('list'); | |
104 | |
105 DeletableItemList.prototype = { | |
106 __proto__: List.prototype, | |
107 | |
108 /** @inheritDoc */ | |
109 decorate: function() { | |
110 List.prototype.decorate.call(this); | |
111 this.addEventListener('click', this.handleClick_); | |
112 this.addEventListener('keydown', this.handleKeyDown_); | |
113 }, | |
114 | |
115 /** | |
116 * Callback for onclick events. | |
117 * @param {Event} e The click event object. | |
118 * @private | |
119 */ | |
120 handleClick_: function(e) { | |
121 if (this.disabled) | |
122 return; | |
123 | |
124 var target = e.target; | |
125 if (target.classList.contains('close-button')) { | |
126 var listItem = this.getListItemAncestor(target); | |
127 var selected = this.selectionModel.selectedIndexes; | |
128 | |
129 // Check if the list item that contains the close button being clicked | |
130 // is not in the list of selected items. Only delete this item in that | |
131 // case. | |
132 var idx = this.getIndexOfListItem(listItem); | |
133 if (selected.indexOf(idx) == -1) { | |
134 this.deleteItemAtIndex(idx); | |
135 } else { | |
136 this.deleteSelectedItems_(); | |
137 } | |
138 } | |
139 }, | |
140 | |
141 /** | |
142 * Callback for keydown events. | |
143 * @param {Event} e The keydown event object. | |
144 * @private | |
145 */ | |
146 handleKeyDown_: function(e) { | |
147 // Map delete (and backspace on Mac) to item deletion (unless focus is | |
148 // in an input field, where it's intended for text editing). | |
149 if ((e.keyCode == 46 || (e.keyCode == 8 && cr.isMac)) && | |
150 e.target.tagName != 'INPUT') { | |
151 this.deleteSelectedItems_(); | |
152 // Prevent the browser from going back. | |
153 e.preventDefault(); | |
154 } | |
155 }, | |
156 | |
157 /** | |
158 * Deletes all the currently selected items that are deletable. | |
159 * @private | |
160 */ | |
161 deleteSelectedItems_: function() { | |
162 var selected = this.selectionModel.selectedIndexes; | |
163 // Reverse through the list of selected indexes to maintain the | |
164 // correct index values after deletion. | |
165 for (var j = selected.length - 1; j >= 0; j--) { | |
166 var index = selected[j]; | |
167 if (this.getListItemByIndex(index).deletable) | |
168 this.deleteItemAtIndex(index); | |
169 } | |
170 }, | |
171 | |
172 /** | |
173 * Called when an item should be deleted; subclasses are responsible for | |
174 * implementing. | |
175 * @param {number} index The index of the item that is being deleted. | |
176 */ | |
177 deleteItemAtIndex: function(index) { | |
178 }, | |
179 }; | |
180 | |
181 return { | |
182 DeletableItemList: DeletableItemList, | |
183 DeletableItem: DeletableItem, | |
184 }; | |
185 }); | |
OLD | NEW |