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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: appengine/config_service/ui/bower_components/polymer/lib/elements/array-selector.html
diff --git a/appengine/config_service/ui/bower_components/polymer/lib/elements/array-selector.html b/appengine/config_service/ui/bower_components/polymer/lib/elements/array-selector.html
new file mode 100644
index 0000000000000000000000000000000000000000..85603aaed64aaf6dd06538e591803a4e7909a6a4
--- /dev/null
+++ b/appengine/config_service/ui/bower_components/polymer/lib/elements/array-selector.html
@@ -0,0 +1,410 @@
+<!--
+@license
+Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../../polymer-element.html">
+<link rel="import" href="../utils/mixin.html">
+<link rel="import" href="../utils/array-splice.html">
+
+<script>
+(function() {
+ 'use strict';
+
+ /**
+ * Element mixin for recording dynamic associations between item paths in a
+ * master `items` array and a `selected` array such that path changes to the
+ * master array (at the host) element or elsewhere via data-binding) are
+ * correctly propagated to items in the selected array and vice-versa.
+ *
+ * The `items` property accepts an array of user data, and via the
+ * `select(item)` and `deselect(item)` API, updates the `selected` property
+ * which may be bound to other parts of the application, and any changes to
+ * sub-fields of `selected` item(s) will be kept in sync with items in the
+ * `items` array. When `multi` is false, `selected` is a property
+ * representing the last selected item. When `multi` is true, `selected`
+ * is an array of multiply selected items.
+ *
+ * @polymerMixin
+ * @memberof Polymer
+ */
+ let ArraySelectorMixin = Polymer.dedupingMixin(superClass => {
+
+ /**
+ * @polymerMixinClass
+ * @implements {Polymer_ArraySelectorMixin}
+ */
+ class ArraySelectorMixin extends superClass {
+
+ static get properties() {
+
+ return {
+
+ /**
+ * An array containing items from which selection will be made.
+ */
+ items: {
+ type: Array,
+ },
+
+ /**
+ * When `true`, multiple items may be selected at once (in this case,
+ * `selected` is an array of currently selected items). When `false`,
+ * only one item may be selected at a time.
+ */
+ multi: {
+ type: Boolean,
+ value: false,
+ },
+
+ /**
+ * When `multi` is true, this is an array that contains any selected.
+ * When `multi` is false, this is the currently selected item, or `null`
+ * if no item is selected.
+ */
+ selected: {
+ type: Object,
+ notify: true
+ },
+
+ /**
+ * When `multi` is false, this is the currently selected item, or `null`
+ * if no item is selected.
+ */
+ selectedItem: {
+ type: Object,
+ notify: true
+ },
+
+ /**
+ * When `true`, calling `select` on an item that is already selected
+ * will deselect the item.
+ */
+ toggle: {
+ type: Boolean,
+ value: false
+ }
+
+ }
+ }
+
+ static get observers() {
+ return ['__updateSelection(multi, items.*)']
+ }
+
+ constructor() {
+ super();
+ this.__lastItems = null;
+ this.__lastMulti = null;
+ this.__selectedMap = null;
+ }
+
+ __updateSelection(multi, itemsInfo) {
+ let path = itemsInfo.path;
+ if (path == 'items') {
+ // Case 1 - items array changed, so diff against previous array and
+ // deselect any removed items and adjust selected indices
+ let newItems = itemsInfo.base || [];
+ let lastItems = this.__lastItems;
+ let lastMulti = this.__lastMulti;
+ if (multi !== lastMulti) {
+ this.clearSelection();
+ }
+ if (lastItems) {
+ let splices = Polymer.ArraySplice.calculateSplices(newItems, lastItems);
+ this.__applySplices(splices);
+ }
+ this.__lastItems = newItems;
+ this.__lastMulti = multi;
+ } else if (itemsInfo.path == 'items.splices') {
+ // Case 2 - got specific splice information describing the array mutation:
+ // deselect any removed items and adjust selected indices
+ this.__applySplices(itemsInfo.value.indexSplices);
+ } else {
+ // Case 3 - an array element was changed, so deselect the previous
+ // item for that index if it was previously selected
+ let part = path.slice('items.'.length);
+ let idx = parseInt(part, 10);
+ if ((part.indexOf('.') < 0) && part == idx) {
+ this.__deselectChangedIdx(idx);
+ }
+ }
+ }
+
+ __applySplices(splices) {
+ let selected = this.__selectedMap;
+ // Adjust selected indices and mark removals
+ for (let i=0; i<splices.length; i++) {
+ let s = splices[i];
+ selected.forEach((idx, item) => {
+ if (idx < s.index) {
+ // no change
+ } else if (idx >= s.index + s.removed.length) {
+ // adjust index
+ selected.set(item, idx + s.addedCount - s.removed.length);
+ } else {
+ // remove index
+ selected.set(item, -1);
+ }
+ });
+ for (let j=0; j<s.addedCount; j++) {
+ let idx = s.index + j;
+ if (selected.has(this.items[idx])) {
+ selected.set(this.items[idx], idx);
+ }
+ }
+ }
+ // Update linked paths
+ this.__updateLinks();
+ // Remove selected items that were removed from the items array
+ let sidx = 0;
+ selected.forEach((idx, item) => {
+ if (idx < 0) {
+ if (this.multi) {
+ this.splice('selected', sidx, 1);
+ } else {
+ this.selected = this.selectedItem = null;
+ }
+ selected.delete(item);
+ } else {
+ sidx++;
+ }
+ });
+ }
+
+ __updateLinks() {
+ this.__dataLinkedPaths = {};
+ if (this.multi) {
+ let sidx = 0;
+ this.__selectedMap.forEach(idx => {
+ if (idx >= 0) {
+ this.linkPaths('items.' + idx, 'selected.' + sidx++);
+ }
+ });
+ } else {
+ this.__selectedMap.forEach(idx => {
+ this.linkPaths('selected', 'items.' + idx);
+ this.linkPaths('selectedItem', 'items.' + idx);
+ });
+ }
+ }
+
+ /**
+ * Clears the selection state.
+ *
+ */
+ clearSelection() {
+ // Unbind previous selection
+ this.__dataLinkedPaths = {};
+ // The selected map stores 3 pieces of information:
+ // key: items array object
+ // value: items array index
+ // order: selected array index
+ this.__selectedMap = new Map();
+ // Initialize selection
+ this.selected = this.multi ? [] : null
+ this.selectedItem = null;
+ }
+
+ /**
+ * Returns whether the item is currently selected.
+ *
+ * @param {*} item Item from `items` array to test
+ * @return {boolean} Whether the item is selected
+ */
+ isSelected(item) {
+ return this.__selectedMap.has(item);
+ }
+
+ /**
+ * Returns whether the item is currently selected.
+ *
+ * @param {*} idx Index from `items` array to test
+ * @return {boolean} Whether the item is selected
+ */
+ isIndexSelected(idx) {
+ return this.isSelected(this.items[idx]);
+ }
+
+ __deselectChangedIdx(idx) {
+ let sidx = this.__selectedIndexForItemIndex(idx);
+ if (sidx >= 0) {
+ let i = 0;
+ this.__selectedMap.forEach((idx, item) => {
+ if (sidx == i++) {
+ this.deselect(item);
+ }
+ });
+ }
+ }
+
+ __selectedIndexForItemIndex(idx) {
+ let selected = this.__dataLinkedPaths['items.' + idx];
+ if (selected) {
+ return parseInt(selected.slice('selected.'.length), 10);
+ }
+ }
+
+ /**
+ * Deselects the given item if it is already selected.
+ *
+ * @param {*} item Item from `items` array to deselect
+ */
+ deselect(item) {
+ let idx = this.__selectedMap.get(item);
+ if (idx >= 0) {
+ this.__selectedMap.delete(item);
+ let sidx;
+ if (this.multi) {
+ sidx = this.__selectedIndexForItemIndex(idx);
+ }
+ this.__updateLinks();
+ if (this.multi) {
+ this.splice('selected', sidx, 1);
+ } else {
+ this.selected = this.selectedItem = null;
+ }
+ }
+ }
+
+ /**
+ * Deselects the given index if it is already selected.
+ *
+ * @param {number} idx Index from `items` array to deselect
+ */
+ deselectIndex(idx) {
+ this.deselect(this.items[idx]);
+ }
+
+ /**
+ * Selects the given item. When `toggle` is true, this will automatically
+ * deselect the item if already selected.
+ *
+ * @param {*} item Item from `items` array to select
+ */
+ select(item) {
+ this.selectIndex(this.items.indexOf(item));
+ }
+
+ /**
+ * Selects the given index. When `toggle` is true, this will automatically
+ * deselect the item if already selected.
+ *
+ * @param {number} idx Index from `items` array to select
+ */
+ selectIndex(idx) {
+ let item = this.items[idx];
+ if (!this.isSelected(item)) {
+ if (!this.multi) {
+ this.__selectedMap.clear();
+ }
+ this.__selectedMap.set(item, idx);
+ this.__updateLinks();
+ if (this.multi) {
+ this.push('selected', item);
+ } else {
+ this.selected = this.selectedItem = item;
+ }
+ } else if (this.toggle) {
+ this.deselectIndex(idx);
+ }
+ }
+
+ }
+
+ return ArraySelectorMixin;
+
+ });
+
+ // export mixin
+ Polymer.ArraySelectorMixin = ArraySelectorMixin;
+
+ /**
+ * @constructor
+ * @extends {Polymer.Element}
+ * @implements {Polymer_ArraySelectorMixin}
+ */
+ let baseArraySelector = ArraySelectorMixin(Polymer.Element);
+
+ /**
+ * Element implementing the `Polymer.ArraySelector` mixin, which records
+ * dynamic associations between item paths in a master `items` array and a
+ * `selected` array such that path changes to the master array (at the host)
+ * element or elsewhere via data-binding) are correctly propagated to items
+ * in the selected array and vice-versa.
+ *
+ * The `items` property accepts an array of user data, and via the
+ * `select(item)` and `deselect(item)` API, updates the `selected` property
+ * which may be bound to other parts of the application, and any changes to
+ * sub-fields of `selected` item(s) will be kept in sync with items in the
+ * `items` array. When `multi` is false, `selected` is a property
+ * representing the last selected item. When `multi` is true, `selected`
+ * is an array of multiply selected items.
+ *
+ * Example:
+ *
+ * ```html
+ * <dom-module id="employee-list">
+ *
+ * <template>
+ *
+ * <div> Employee list: </div>
+ * <template is="dom-repeat" id="employeeList" items="{{employees}}">
+ * <div>First name: <span>{{item.first}}</span></div>
+ * <div>Last name: <span>{{item.last}}</span></div>
+ * <button on-click="toggleSelection">Select</button>
+ * </template>
+ *
+ * <array-selector id="selector" items="{{employees}}" selected="{{selected}}" multi toggle></array-selector>
+ *
+ * <div> Selected employees: </div>
+ * <template is="dom-repeat" items="{{selected}}">
+ * <div>First name: <span>{{item.first}}</span></div>
+ * <div>Last name: <span>{{item.last}}</span></div>
+ * </template>
+ *
+ * </template>
+ *
+ * </dom-module>
+ * ```
+ *
+ * ```js
+ * Polymer({
+ * is: 'employee-list',
+ * ready() {
+ * this.employees = [
+ * {first: 'Bob', last: 'Smith'},
+ * {first: 'Sally', last: 'Johnson'},
+ * ...
+ * ];
+ * },
+ * toggleSelection(e) {
+ * let item = this.$.employeeList.itemForElement(e.target);
+ * this.$.selector.select(item);
+ * }
+ * });
+ * ```
+ *
+ * @polymerElement
+ * @extends Polymer.Element
+ * @mixes Polymer.ArraySelectorMixin
+ * @memberof Polymer
+ * @summary Custom element that links paths between an input `items` array and
+ * an output `selected` item or array based on calls to its selection API.
+ */
+ class ArraySelector extends baseArraySelector {
+ // Not needed to find template; can be removed once the analyzer
+ // can find the tag name from customElements.define call
+ static get is() { return 'array-selector' }
+ }
+ customElements.define(ArraySelector.is, ArraySelector);
+ Polymer.ArraySelector = ArraySelector;
+
+})();
+
+</script>

Powered by Google App Engine
This is Rietveld 408576698