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://polymer.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/CONTRIBUTORS.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/PATENTS.txt 9 */ 10// @version 0.7.24 11if (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] : undefined; 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(node) || 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.removeTransientObservers(); 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.characterDataOldValue && !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)) return 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, true); 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("DOMNodeRemoved", 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("DOMCharacterDataModified", this, true); 260 if (options.childList) node.removeEventListener("DOMNodeInserted", this, true); 261 if (options.childList || options.subtree) node.removeEventListener("DOMNodeRemoved", 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.prevValue; 296 forEachAncestorAndObserverEnqueueRecord(target, function(options) { 297 if (!options.attributes) return; 298 if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -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(oldValue); 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);