Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1110)

Side by Side Diff: appengine/config_service/ui/bower_components/polymer/lib/elements/array-selector.html

Issue 2923973003: Added base template for config ui. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 <!--
2 @license
3 Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.g ithub.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI BUTORS.txt
7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN TS.txt
9 -->
10
11 <link rel="import" href="../../polymer-element.html">
12 <link rel="import" href="../utils/mixin.html">
13 <link rel="import" href="../utils/array-splice.html">
14
15 <script>
16 (function() {
17 'use strict';
18
19 /**
20 * Element mixin for recording dynamic associations between item paths in a
21 * master `items` array and a `selected` array such that path changes to the
22 * master array (at the host) element or elsewhere via data-binding) are
23 * correctly propagated to items in the selected array and vice-versa.
24 *
25 * The `items` property accepts an array of user data, and via the
26 * `select(item)` and `deselect(item)` API, updates the `selected` property
27 * which may be bound to other parts of the application, and any changes to
28 * sub-fields of `selected` item(s) will be kept in sync with items in the
29 * `items` array. When `multi` is false, `selected` is a property
30 * representing the last selected item. When `multi` is true, `selected`
31 * is an array of multiply selected items.
32 *
33 * @polymerMixin
34 * @memberof Polymer
35 */
36 let ArraySelectorMixin = Polymer.dedupingMixin(superClass => {
37
38 /**
39 * @polymerMixinClass
40 * @implements {Polymer_ArraySelectorMixin}
41 */
42 class ArraySelectorMixin extends superClass {
43
44 static get properties() {
45
46 return {
47
48 /**
49 * An array containing items from which selection will be made.
50 */
51 items: {
52 type: Array,
53 },
54
55 /**
56 * When `true`, multiple items may be selected at once (in this case,
57 * `selected` is an array of currently selected items). When `false`,
58 * only one item may be selected at a time.
59 */
60 multi: {
61 type: Boolean,
62 value: false,
63 },
64
65 /**
66 * When `multi` is true, this is an array that contains any selected.
67 * When `multi` is false, this is the currently selected item, or `nul l`
68 * if no item is selected.
69 */
70 selected: {
71 type: Object,
72 notify: true
73 },
74
75 /**
76 * When `multi` is false, this is the currently selected item, or `nul l`
77 * if no item is selected.
78 */
79 selectedItem: {
80 type: Object,
81 notify: true
82 },
83
84 /**
85 * When `true`, calling `select` on an item that is already selected
86 * will deselect the item.
87 */
88 toggle: {
89 type: Boolean,
90 value: false
91 }
92
93 }
94 }
95
96 static get observers() {
97 return ['__updateSelection(multi, items.*)']
98 }
99
100 constructor() {
101 super();
102 this.__lastItems = null;
103 this.__lastMulti = null;
104 this.__selectedMap = null;
105 }
106
107 __updateSelection(multi, itemsInfo) {
108 let path = itemsInfo.path;
109 if (path == 'items') {
110 // Case 1 - items array changed, so diff against previous array and
111 // deselect any removed items and adjust selected indices
112 let newItems = itemsInfo.base || [];
113 let lastItems = this.__lastItems;
114 let lastMulti = this.__lastMulti;
115 if (multi !== lastMulti) {
116 this.clearSelection();
117 }
118 if (lastItems) {
119 let splices = Polymer.ArraySplice.calculateSplices(newItems, lastIte ms);
120 this.__applySplices(splices);
121 }
122 this.__lastItems = newItems;
123 this.__lastMulti = multi;
124 } else if (itemsInfo.path == 'items.splices') {
125 // Case 2 - got specific splice information describing the array mutat ion:
126 // deselect any removed items and adjust selected indices
127 this.__applySplices(itemsInfo.value.indexSplices);
128 } else {
129 // Case 3 - an array element was changed, so deselect the previous
130 // item for that index if it was previously selected
131 let part = path.slice('items.'.length);
132 let idx = parseInt(part, 10);
133 if ((part.indexOf('.') < 0) && part == idx) {
134 this.__deselectChangedIdx(idx);
135 }
136 }
137 }
138
139 __applySplices(splices) {
140 let selected = this.__selectedMap;
141 // Adjust selected indices and mark removals
142 for (let i=0; i<splices.length; i++) {
143 let s = splices[i];
144 selected.forEach((idx, item) => {
145 if (idx < s.index) {
146 // no change
147 } else if (idx >= s.index + s.removed.length) {
148 // adjust index
149 selected.set(item, idx + s.addedCount - s.removed.length);
150 } else {
151 // remove index
152 selected.set(item, -1);
153 }
154 });
155 for (let j=0; j<s.addedCount; j++) {
156 let idx = s.index + j;
157 if (selected.has(this.items[idx])) {
158 selected.set(this.items[idx], idx);
159 }
160 }
161 }
162 // Update linked paths
163 this.__updateLinks();
164 // Remove selected items that were removed from the items array
165 let sidx = 0;
166 selected.forEach((idx, item) => {
167 if (idx < 0) {
168 if (this.multi) {
169 this.splice('selected', sidx, 1);
170 } else {
171 this.selected = this.selectedItem = null;
172 }
173 selected.delete(item);
174 } else {
175 sidx++;
176 }
177 });
178 }
179
180 __updateLinks() {
181 this.__dataLinkedPaths = {};
182 if (this.multi) {
183 let sidx = 0;
184 this.__selectedMap.forEach(idx => {
185 if (idx >= 0) {
186 this.linkPaths('items.' + idx, 'selected.' + sidx++);
187 }
188 });
189 } else {
190 this.__selectedMap.forEach(idx => {
191 this.linkPaths('selected', 'items.' + idx);
192 this.linkPaths('selectedItem', 'items.' + idx);
193 });
194 }
195 }
196
197 /**
198 * Clears the selection state.
199 *
200 */
201 clearSelection() {
202 // Unbind previous selection
203 this.__dataLinkedPaths = {};
204 // The selected map stores 3 pieces of information:
205 // key: items array object
206 // value: items array index
207 // order: selected array index
208 this.__selectedMap = new Map();
209 // Initialize selection
210 this.selected = this.multi ? [] : null
211 this.selectedItem = null;
212 }
213
214 /**
215 * Returns whether the item is currently selected.
216 *
217 * @param {*} item Item from `items` array to test
218 * @return {boolean} Whether the item is selected
219 */
220 isSelected(item) {
221 return this.__selectedMap.has(item);
222 }
223
224 /**
225 * Returns whether the item is currently selected.
226 *
227 * @param {*} idx Index from `items` array to test
228 * @return {boolean} Whether the item is selected
229 */
230 isIndexSelected(idx) {
231 return this.isSelected(this.items[idx]);
232 }
233
234 __deselectChangedIdx(idx) {
235 let sidx = this.__selectedIndexForItemIndex(idx);
236 if (sidx >= 0) {
237 let i = 0;
238 this.__selectedMap.forEach((idx, item) => {
239 if (sidx == i++) {
240 this.deselect(item);
241 }
242 });
243 }
244 }
245
246 __selectedIndexForItemIndex(idx) {
247 let selected = this.__dataLinkedPaths['items.' + idx];
248 if (selected) {
249 return parseInt(selected.slice('selected.'.length), 10);
250 }
251 }
252
253 /**
254 * Deselects the given item if it is already selected.
255 *
256 * @param {*} item Item from `items` array to deselect
257 */
258 deselect(item) {
259 let idx = this.__selectedMap.get(item);
260 if (idx >= 0) {
261 this.__selectedMap.delete(item);
262 let sidx;
263 if (this.multi) {
264 sidx = this.__selectedIndexForItemIndex(idx);
265 }
266 this.__updateLinks();
267 if (this.multi) {
268 this.splice('selected', sidx, 1);
269 } else {
270 this.selected = this.selectedItem = null;
271 }
272 }
273 }
274
275 /**
276 * Deselects the given index if it is already selected.
277 *
278 * @param {number} idx Index from `items` array to deselect
279 */
280 deselectIndex(idx) {
281 this.deselect(this.items[idx]);
282 }
283
284 /**
285 * Selects the given item. When `toggle` is true, this will automatically
286 * deselect the item if already selected.
287 *
288 * @param {*} item Item from `items` array to select
289 */
290 select(item) {
291 this.selectIndex(this.items.indexOf(item));
292 }
293
294 /**
295 * Selects the given index. When `toggle` is true, this will automaticall y
296 * deselect the item if already selected.
297 *
298 * @param {number} idx Index from `items` array to select
299 */
300 selectIndex(idx) {
301 let item = this.items[idx];
302 if (!this.isSelected(item)) {
303 if (!this.multi) {
304 this.__selectedMap.clear();
305 }
306 this.__selectedMap.set(item, idx);
307 this.__updateLinks();
308 if (this.multi) {
309 this.push('selected', item);
310 } else {
311 this.selected = this.selectedItem = item;
312 }
313 } else if (this.toggle) {
314 this.deselectIndex(idx);
315 }
316 }
317
318 }
319
320 return ArraySelectorMixin;
321
322 });
323
324 // export mixin
325 Polymer.ArraySelectorMixin = ArraySelectorMixin;
326
327 /**
328 * @constructor
329 * @extends {Polymer.Element}
330 * @implements {Polymer_ArraySelectorMixin}
331 */
332 let baseArraySelector = ArraySelectorMixin(Polymer.Element);
333
334 /**
335 * Element implementing the `Polymer.ArraySelector` mixin, which records
336 * dynamic associations between item paths in a master `items` array and a
337 * `selected` array such that path changes to the master array (at the host)
338 * element or elsewhere via data-binding) are correctly propagated to items
339 * in the selected array and vice-versa.
340 *
341 * The `items` property accepts an array of user data, and via the
342 * `select(item)` and `deselect(item)` API, updates the `selected` property
343 * which may be bound to other parts of the application, and any changes to
344 * sub-fields of `selected` item(s) will be kept in sync with items in the
345 * `items` array. When `multi` is false, `selected` is a property
346 * representing the last selected item. When `multi` is true, `selected`
347 * is an array of multiply selected items.
348 *
349 * Example:
350 *
351 * ```html
352 * <dom-module id="employee-list">
353 *
354 * <template>
355 *
356 * <div> Employee list: </div>
357 * <template is="dom-repeat" id="employeeList" items="{{employees}}">
358 * <div>First name: <span>{{item.first}}</span></div>
359 * <div>Last name: <span>{{item.last}}</span></div>
360 * <button on-click="toggleSelection">Select</button>
361 * </template>
362 *
363 * <array-selector id="selector" items="{{employees}}" selected="{{selecte d}}" multi toggle></array-selector>
364 *
365 * <div> Selected employees: </div>
366 * <template is="dom-repeat" items="{{selected}}">
367 * <div>First name: <span>{{item.first}}</span></div>
368 * <div>Last name: <span>{{item.last}}</span></div>
369 * </template>
370 *
371 * </template>
372 *
373 * </dom-module>
374 * ```
375 *
376 * ```js
377 * Polymer({
378 * is: 'employee-list',
379 * ready() {
380 * this.employees = [
381 * {first: 'Bob', last: 'Smith'},
382 * {first: 'Sally', last: 'Johnson'},
383 * ...
384 * ];
385 * },
386 * toggleSelection(e) {
387 * let item = this.$.employeeList.itemForElement(e.target);
388 * this.$.selector.select(item);
389 * }
390 * });
391 * ```
392 *
393 * @polymerElement
394 * @extends Polymer.Element
395 * @mixes Polymer.ArraySelectorMixin
396 * @memberof Polymer
397 * @summary Custom element that links paths between an input `items` array and
398 * an output `selected` item or array based on calls to its selection API.
399 */
400 class ArraySelector extends baseArraySelector {
401 // Not needed to find template; can be removed once the analyzer
402 // can find the tag name from customElements.define call
403 static get is() { return 'array-selector' }
404 }
405 customElements.define(ArraySelector.is, ArraySelector);
406 Polymer.ArraySelector = ArraySelector;
407
408 })();
409
410 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698