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

Side by Side Diff: appengine/config_service/ui/bower_components/polymer/lib/utils/flattened-nodes-observer.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 <link rel="import" href="../utils/boot.html">
11 <link rel="import" href="../utils/array-splice.html">
12 <link rel="import" href="../utils/async.html">
13 <script>
14 (function() {
15 'use strict';
16
17 function isSlot(node) {
18 return (node.localName === 'slot');
19 }
20
21 /**
22 * Class that listens for changes (additions or removals) to
23 * "flattened nodes" on a given `node`. The list of flattened nodes consists
24 * of a node's children and, for any children that are `<slot>` elements,
25 * the expanded flattened list of `assignedNodes`.
26 * For example, if the observed node has children `<a></a><slot></slot><b></b> `
27 * and the `<slot>` has one `<div>` assigned to it, then the flattened
28 * nodes list is `<a></a><div></div><b></b>`. If the `<slot>` has other
29 * `<slot>` elements assigned to it, these are flattened as well.
30 *
31 * The provided `callback` is called whenever any change to this list
32 * of flattened nodes occurs, where an addition or removal of a node is
33 * considered a change. The `callback` is called with one argument, an object
34 * containing an array of any `addedNodes` and `removedNodes`.
35 *
36 * Note: the callback is called asynchronous to any changes
37 * at a microtask checkpoint. This is because observation is performed using
38 * `MutationObserver` and the `<slot>` element's `slotchange` event which
39 * are asynchronous.
40 *
41 * @memberof Polymer
42 * @param {Node} target Node on which to listen for changes.
43 * @param {Function} callback Function called when there are additions
44 * or removals from the target's list of flattened nodes.
45 * @summary Class that listens for changes (additions or removals) to
46 * "flattened nodes" on a given `node`.
47 */
48 class FlattenedNodesObserver {
49
50 /**
51 * Returns the list of flattened nodes for the given `node`.
52 * This list consists of a node's children and, for any children
53 * that are `<slot>` elements, the expanded flattened list of `assignedNodes `.
54 * For example, if the observed node has children `<a></a><slot></slot><b></ b>`
55 * and the `<slot>` has one `<div>` assigned to it, then the flattened
56 * nodes list is `<a></a><div></div><b></b>`. If the `<slot>` has other
57 * `<slot>` elements assigned to it, these are flattened as well.
58 *
59 * @param {Node} node The node for which to return the list of flattened nod es.
60 * @return {Array} The list of flattened nodes for the given `node`.
61 */
62 static getFlattenedNodes(node) {
63 if (isSlot(node)) {
64 return node.assignedNodes({flatten: true});
65 } else {
66 return Array.from(node.childNodes).map(node => {
67 if (isSlot(node)) {
68 return node.assignedNodes({flatten: true});
69 } else {
70 return [node];
71 }
72 }).reduce((a, b) => a.concat(b), []);
73 }
74 }
75
76 constructor(target, callback) {
77 /** @type {MutationObserver} */
78 this._shadyChildrenObserver = null;
79 /** @type {MutationObserver} */
80 this._nativeChildrenObserver = null;
81 this._connected = false;
82 this._target = target;
83 this.callback = callback;
84 this._effectiveNodes = [];
85 this._observer = null;
86 this._scheduled = false;
87 this._boundSchedule = () => {
88 this._schedule();
89 }
90 this.connect();
91 this._schedule();
92 }
93
94 /**
95 * Activates an observer. This method is automatically called when
96 * a `FlattenedNodesObserver` is created. It should only be called to
97 * re-activate an observer that has been deactivated via the `disconnect` me thod.
98 */
99 connect() {
100 if (isSlot(this._target)) {
101 this._listenSlots([this._target]);
102 } else {
103 this._listenSlots(this._target.children);
104 if (window.ShadyDOM) {
105 this._shadyChildrenObserver =
106 ShadyDOM.observeChildren(this._target, (mutations) => {
107 this._processMutations(mutations);
108 });
109 } else {
110 this._nativeChildrenObserver =
111 new MutationObserver((mutations) => {
112 this._processMutations(mutations);
113 });
114 this._nativeChildrenObserver.observe(this._target, {childList: true});
115 }
116 }
117 this._connected = true;
118 }
119
120 /**
121 * Deactivates the flattened nodes observer. After calling this method
122 * the observer callback will not be called when changes to flattened nodes
123 * occur. The `connect` method may be subsequently called to reactivate
124 * the observer.
125 */
126 disconnect() {
127 if (isSlot(this._target)) {
128 this._unlistenSlots([this._target]);
129 } else {
130 this._unlistenSlots(this._target.children);
131 if (window.ShadyDOM && this._shadyChildrenObserver) {
132 ShadyDOM.unobserveChildren(this._shadyChildrenObserver);
133 this._shadyChildrenObserver = null;
134 } else if (this._nativeChildrenObserver) {
135 this._nativeChildrenObserver.disconnect();
136 this._nativeChildrenObserver = null;
137 }
138 }
139 this._connected = false;
140 }
141
142 _schedule() {
143 if (!this._scheduled) {
144 this._scheduled = true;
145 Polymer.Async.microTask.run(() => this.flush());
146 }
147 }
148
149 _processMutations(mutations) {
150 this._processSlotMutations(mutations);
151 this.flush();
152 }
153
154 _processSlotMutations(mutations) {
155 if (mutations) {
156 for (let i=0; i < mutations.length; i++) {
157 let mutation = mutations[i];
158 if (mutation.addedNodes) {
159 this._listenSlots(mutation.addedNodes);
160 }
161 if (mutation.removedNodes) {
162 this._unlistenSlots(mutation.removedNodes);
163 }
164 }
165 }
166 }
167
168 /**
169 * Flushes the observer causing any pending changes to be immediately
170 * delivered the observer callback. By default these changes are delivered
171 * asynchronously at the next microtask checkpoint.
172 *
173 * @return {boolean} Returns true if any pending changes caused the observer
174 * callback to run.
175 */
176 flush() {
177 if (!this._connected) {
178 return;
179 }
180 if (window.ShadyDOM) {
181 ShadyDOM.flush();
182 }
183 if (this._nativeChildrenObserver) {
184 this._processSlotMutations(this._nativeChildrenObserver.takeRecords());
185 } else if (this.shadyChildrenObserver) {
186 this._processSlotMutations(this._shadyChildrenObserver.takeRecords());
187 }
188 this._scheduled = false;
189 let info = {
190 target: this._target,
191 addedNodes: [],
192 removedNodes: []
193 };
194 let newNodes = this.constructor.getFlattenedNodes(this._target);
195 let splices = Polymer.ArraySplice.calculateSplices(newNodes,
196 this._effectiveNodes);
197 // process removals
198 for (let i=0, s; (i<splices.length) && (s=splices[i]); i++) {
199 for (let j=0, n; (j < s.removed.length) && (n=s.removed[j]); j++) {
200 info.removedNodes.push(n);
201 }
202 }
203 // process adds
204 for (let i=0, s; (i<splices.length) && (s=splices[i]); i++) {
205 for (let j=s.index; j < s.index + s.addedCount; j++) {
206 info.addedNodes.push(newNodes[j]);
207 }
208 }
209 // update cache
210 this._effectiveNodes = newNodes;
211 let didFlush = false;
212 if (info.addedNodes.length || info.removedNodes.length) {
213 didFlush = true;
214 this.callback.call(this._target, info);
215 }
216 return didFlush;
217 }
218
219 _listenSlots(nodeList) {
220 for (let i=0; i < nodeList.length; i++) {
221 let n = nodeList[i];
222 if (isSlot(n)) {
223 n.addEventListener('slotchange', this._boundSchedule);
224 }
225 }
226 }
227
228 _unlistenSlots(nodeList) {
229 for (let i=0; i < nodeList.length; i++) {
230 let n = nodeList[i];
231 if (isSlot(n)) {
232 n.removeEventListener('slotchange', this._boundSchedule);
233 }
234 }
235 }
236
237 }
238
239 Polymer.FlattenedNodesObserver = FlattenedNodesObserver;
240
241 })();
242 </script>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698