OLD | NEW |
| (Empty) |
1 /** | |
2 * @license | |
3 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
4 * This code may only be used under the BSD style license found at http://polyme
r.github.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/CON
TRIBUTORS.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/PA
TENTS.txt | |
9 */ | |
10 // @version 0.7.22 | |
11 if (typeof WeakMap === "undefined") { | |
12 (function() { | |
13 var defineProperty = Object.defineProperty; | |
14 var counter = Date.now() % 1e9; | |
15 var WeakMap = function() { | |
16 this.name = "__st" + (Math.random() * 1e9 >>> 0) + (counter++ + "__"); | |
17 }; | |
18 WeakMap.prototype = { | |
19 set: function(key, value) { | |
20 var entry = key[this.name]; | |
21 if (entry && entry[0] === key) entry[1] = value; else defineProperty(key
, this.name, { | |
22 value: [ key, value ], | |
23 writable: true | |
24 }); | |
25 return this; | |
26 }, | |
27 get: function(key) { | |
28 var entry; | |
29 return (entry = key[this.name]) && entry[0] === key ? entry[1] : undefin
ed; | |
30 }, | |
31 "delete": function(key) { | |
32 var entry = key[this.name]; | |
33 if (!entry || entry[0] !== key) return false; | |
34 entry[0] = entry[1] = undefined; | |
35 return true; | |
36 }, | |
37 has: function(key) { | |
38 var entry = key[this.name]; | |
39 if (!entry) return false; | |
40 return entry[0] === key; | |
41 } | |
42 }; | |
43 window.WeakMap = WeakMap; | |
44 })(); | |
45 } | |
46 | |
47 (function(global) { | |
48 if (global.JsMutationObserver) { | |
49 return; | |
50 } | |
51 var registrationsTable = new WeakMap(); | |
52 var setImmediate; | |
53 if (/Trident|Edge/.test(navigator.userAgent)) { | |
54 setImmediate = setTimeout; | |
55 } else if (window.setImmediate) { | |
56 setImmediate = window.setImmediate; | |
57 } else { | |
58 var setImmediateQueue = []; | |
59 var sentinel = String(Math.random()); | |
60 window.addEventListener("message", function(e) { | |
61 if (e.data === sentinel) { | |
62 var queue = setImmediateQueue; | |
63 setImmediateQueue = []; | |
64 queue.forEach(function(func) { | |
65 func(); | |
66 }); | |
67 } | |
68 }); | |
69 setImmediate = function(func) { | |
70 setImmediateQueue.push(func); | |
71 window.postMessage(sentinel, "*"); | |
72 }; | |
73 } | |
74 var isScheduled = false; | |
75 var scheduledObservers = []; | |
76 function scheduleCallback(observer) { | |
77 scheduledObservers.push(observer); | |
78 if (!isScheduled) { | |
79 isScheduled = true; | |
80 setImmediate(dispatchCallbacks); | |
81 } | |
82 } | |
83 function wrapIfNeeded(node) { | |
84 return window.ShadowDOMPolyfill && window.ShadowDOMPolyfill.wrapIfNeeded(nod
e) || node; | |
85 } | |
86 function dispatchCallbacks() { | |
87 isScheduled = false; | |
88 var observers = scheduledObservers; | |
89 scheduledObservers = []; | |
90 observers.sort(function(o1, o2) { | |
91 return o1.uid_ - o2.uid_; | |
92 }); | |
93 var anyNonEmpty = false; | |
94 observers.forEach(function(observer) { | |
95 var queue = observer.takeRecords(); | |
96 removeTransientObserversFor(observer); | |
97 if (queue.length) { | |
98 observer.callback_(queue, observer); | |
99 anyNonEmpty = true; | |
100 } | |
101 }); | |
102 if (anyNonEmpty) dispatchCallbacks(); | |
103 } | |
104 function removeTransientObserversFor(observer) { | |
105 observer.nodes_.forEach(function(node) { | |
106 var registrations = registrationsTable.get(node); | |
107 if (!registrations) return; | |
108 registrations.forEach(function(registration) { | |
109 if (registration.observer === observer) registration.removeTransientObse
rvers(); | |
110 }); | |
111 }); | |
112 } | |
113 function forEachAncestorAndObserverEnqueueRecord(target, callback) { | |
114 for (var node = target; node; node = node.parentNode) { | |
115 var registrations = registrationsTable.get(node); | |
116 if (registrations) { | |
117 for (var j = 0; j < registrations.length; j++) { | |
118 var registration = registrations[j]; | |
119 var options = registration.options; | |
120 if (node !== target && !options.subtree) continue; | |
121 var record = callback(options); | |
122 if (record) registration.enqueue(record); | |
123 } | |
124 } | |
125 } | |
126 } | |
127 var uidCounter = 0; | |
128 function JsMutationObserver(callback) { | |
129 this.callback_ = callback; | |
130 this.nodes_ = []; | |
131 this.records_ = []; | |
132 this.uid_ = ++uidCounter; | |
133 } | |
134 JsMutationObserver.prototype = { | |
135 observe: function(target, options) { | |
136 target = wrapIfNeeded(target); | |
137 if (!options.childList && !options.attributes && !options.characterData ||
options.attributeOldValue && !options.attributes || options.attributeFilter &&
options.attributeFilter.length && !options.attributes || options.characterDataOl
dValue && !options.characterData) { | |
138 throw new SyntaxError(); | |
139 } | |
140 var registrations = registrationsTable.get(target); | |
141 if (!registrations) registrationsTable.set(target, registrations = []); | |
142 var registration; | |
143 for (var i = 0; i < registrations.length; i++) { | |
144 if (registrations[i].observer === this) { | |
145 registration = registrations[i]; | |
146 registration.removeListeners(); | |
147 registration.options = options; | |
148 break; | |
149 } | |
150 } | |
151 if (!registration) { | |
152 registration = new Registration(this, target, options); | |
153 registrations.push(registration); | |
154 this.nodes_.push(target); | |
155 } | |
156 registration.addListeners(); | |
157 }, | |
158 disconnect: function() { | |
159 this.nodes_.forEach(function(node) { | |
160 var registrations = registrationsTable.get(node); | |
161 for (var i = 0; i < registrations.length; i++) { | |
162 var registration = registrations[i]; | |
163 if (registration.observer === this) { | |
164 registration.removeListeners(); | |
165 registrations.splice(i, 1); | |
166 break; | |
167 } | |
168 } | |
169 }, this); | |
170 this.records_ = []; | |
171 }, | |
172 takeRecords: function() { | |
173 var copyOfRecords = this.records_; | |
174 this.records_ = []; | |
175 return copyOfRecords; | |
176 } | |
177 }; | |
178 function MutationRecord(type, target) { | |
179 this.type = type; | |
180 this.target = target; | |
181 this.addedNodes = []; | |
182 this.removedNodes = []; | |
183 this.previousSibling = null; | |
184 this.nextSibling = null; | |
185 this.attributeName = null; | |
186 this.attributeNamespace = null; | |
187 this.oldValue = null; | |
188 } | |
189 function copyMutationRecord(original) { | |
190 var record = new MutationRecord(original.type, original.target); | |
191 record.addedNodes = original.addedNodes.slice(); | |
192 record.removedNodes = original.removedNodes.slice(); | |
193 record.previousSibling = original.previousSibling; | |
194 record.nextSibling = original.nextSibling; | |
195 record.attributeName = original.attributeName; | |
196 record.attributeNamespace = original.attributeNamespace; | |
197 record.oldValue = original.oldValue; | |
198 return record; | |
199 } | |
200 var currentRecord, recordWithOldValue; | |
201 function getRecord(type, target) { | |
202 return currentRecord = new MutationRecord(type, target); | |
203 } | |
204 function getRecordWithOldValue(oldValue) { | |
205 if (recordWithOldValue) return recordWithOldValue; | |
206 recordWithOldValue = copyMutationRecord(currentRecord); | |
207 recordWithOldValue.oldValue = oldValue; | |
208 return recordWithOldValue; | |
209 } | |
210 function clearRecords() { | |
211 currentRecord = recordWithOldValue = undefined; | |
212 } | |
213 function recordRepresentsCurrentMutation(record) { | |
214 return record === recordWithOldValue || record === currentRecord; | |
215 } | |
216 function selectRecord(lastRecord, newRecord) { | |
217 if (lastRecord === newRecord) return lastRecord; | |
218 if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) retur
n recordWithOldValue; | |
219 return null; | |
220 } | |
221 function Registration(observer, target, options) { | |
222 this.observer = observer; | |
223 this.target = target; | |
224 this.options = options; | |
225 this.transientObservedNodes = []; | |
226 } | |
227 Registration.prototype = { | |
228 enqueue: function(record) { | |
229 var records = this.observer.records_; | |
230 var length = records.length; | |
231 if (records.length > 0) { | |
232 var lastRecord = records[length - 1]; | |
233 var recordToReplaceLast = selectRecord(lastRecord, record); | |
234 if (recordToReplaceLast) { | |
235 records[length - 1] = recordToReplaceLast; | |
236 return; | |
237 } | |
238 } else { | |
239 scheduleCallback(this.observer); | |
240 } | |
241 records[length] = record; | |
242 }, | |
243 addListeners: function() { | |
244 this.addListeners_(this.target); | |
245 }, | |
246 addListeners_: function(node) { | |
247 var options = this.options; | |
248 if (options.attributes) node.addEventListener("DOMAttrModified", this, tru
e); | |
249 if (options.characterData) node.addEventListener("DOMCharacterDataModified
", this, true); | |
250 if (options.childList) node.addEventListener("DOMNodeInserted", this, true
); | |
251 if (options.childList || options.subtree) node.addEventListener("DOMNodeRe
moved", this, true); | |
252 }, | |
253 removeListeners: function() { | |
254 this.removeListeners_(this.target); | |
255 }, | |
256 removeListeners_: function(node) { | |
257 var options = this.options; | |
258 if (options.attributes) node.removeEventListener("DOMAttrModified", this,
true); | |
259 if (options.characterData) node.removeEventListener("DOMCharacterDataModif
ied", this, true); | |
260 if (options.childList) node.removeEventListener("DOMNodeInserted", this, t
rue); | |
261 if (options.childList || options.subtree) node.removeEventListener("DOMNod
eRemoved", this, true); | |
262 }, | |
263 addTransientObserver: function(node) { | |
264 if (node === this.target) return; | |
265 this.addListeners_(node); | |
266 this.transientObservedNodes.push(node); | |
267 var registrations = registrationsTable.get(node); | |
268 if (!registrations) registrationsTable.set(node, registrations = []); | |
269 registrations.push(this); | |
270 }, | |
271 removeTransientObservers: function() { | |
272 var transientObservedNodes = this.transientObservedNodes; | |
273 this.transientObservedNodes = []; | |
274 transientObservedNodes.forEach(function(node) { | |
275 this.removeListeners_(node); | |
276 var registrations = registrationsTable.get(node); | |
277 for (var i = 0; i < registrations.length; i++) { | |
278 if (registrations[i] === this) { | |
279 registrations.splice(i, 1); | |
280 break; | |
281 } | |
282 } | |
283 }, this); | |
284 }, | |
285 handleEvent: function(e) { | |
286 e.stopImmediatePropagation(); | |
287 switch (e.type) { | |
288 case "DOMAttrModified": | |
289 var name = e.attrName; | |
290 var namespace = e.relatedNode.namespaceURI; | |
291 var target = e.target; | |
292 var record = new getRecord("attributes", target); | |
293 record.attributeName = name; | |
294 record.attributeNamespace = namespace; | |
295 var oldValue = e.attrChange === MutationEvent.ADDITION ? null : e.prevVa
lue; | |
296 forEachAncestorAndObserverEnqueueRecord(target, function(options) { | |
297 if (!options.attributes) return; | |
298 if (options.attributeFilter && options.attributeFilter.length && optio
ns.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(names
pace) === -1) { | |
299 return; | |
300 } | |
301 if (options.attributeOldValue) return getRecordWithOldValue(oldValue); | |
302 return record; | |
303 }); | |
304 break; | |
305 | |
306 case "DOMCharacterDataModified": | |
307 var target = e.target; | |
308 var record = getRecord("characterData", target); | |
309 var oldValue = e.prevValue; | |
310 forEachAncestorAndObserverEnqueueRecord(target, function(options) { | |
311 if (!options.characterData) return; | |
312 if (options.characterDataOldValue) return getRecordWithOldValue(oldVal
ue); | |
313 return record; | |
314 }); | |
315 break; | |
316 | |
317 case "DOMNodeRemoved": | |
318 this.addTransientObserver(e.target); | |
319 | |
320 case "DOMNodeInserted": | |
321 var changedNode = e.target; | |
322 var addedNodes, removedNodes; | |
323 if (e.type === "DOMNodeInserted") { | |
324 addedNodes = [ changedNode ]; | |
325 removedNodes = []; | |
326 } else { | |
327 addedNodes = []; | |
328 removedNodes = [ changedNode ]; | |
329 } | |
330 var previousSibling = changedNode.previousSibling; | |
331 var nextSibling = changedNode.nextSibling; | |
332 var record = getRecord("childList", e.target.parentNode); | |
333 record.addedNodes = addedNodes; | |
334 record.removedNodes = removedNodes; | |
335 record.previousSibling = previousSibling; | |
336 record.nextSibling = nextSibling; | |
337 forEachAncestorAndObserverEnqueueRecord(e.relatedNode, function(options)
{ | |
338 if (!options.childList) return; | |
339 return record; | |
340 }); | |
341 } | |
342 clearRecords(); | |
343 } | |
344 }; | |
345 global.JsMutationObserver = JsMutationObserver; | |
346 if (!global.MutationObserver) { | |
347 global.MutationObserver = JsMutationObserver; | |
348 JsMutationObserver._isPolyfilled = true; | |
349 } | |
350 })(self); | |
OLD | NEW |