| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586 | var MutationObserver = window.MutationObserver  || window.WebKitMutationObserver  || window.MozMutationObserver;/* * Copyright 2012 The Polymer Authors. All rights reserved. * Use of this source code is goverened by a BSD-style * license that can be found in the LICENSE file. */var WeakMap = window.WeakMap;if (typeof WeakMap === 'undefined') {  var defineProperty = Object.defineProperty;  var counter = Date.now() % 1e9;  WeakMap = function() {    this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');  };  WeakMap.prototype = {    set: function(key, value) {      var entry = key[this.name];      if (entry && entry[0] === key)        entry[1] = value;      else        defineProperty(key, this.name, {value: [key, value], writable: true});      return this;    },    get: function(key) {      var entry;      return (entry = key[this.name]) && entry[0] === key ?          entry[1] : undefined;    },    'delete': function(key) {      var entry = key[this.name];      if (!entry) return false;      var hasValue = entry[0] === key;      entry[0] = entry[1] = undefined;      return hasValue;    },    has: function(key) {      var entry = key[this.name];      if (!entry) return false;      return entry[0] === key;    }  };}var registrationsTable = new WeakMap();// We use setImmediate or postMessage for our future callback.var setImmediate = window.msSetImmediate;// Use post message to emulate setImmediate.if (!setImmediate) {  var setImmediateQueue = [];  var sentinel = String(Math.random());  window.addEventListener('message', function(e) {    if (e.data === sentinel) {      var queue = setImmediateQueue;      setImmediateQueue = [];      queue.forEach(function(func) {        func();      });    }  });  setImmediate = function(func) {    setImmediateQueue.push(func);    window.postMessage(sentinel, '*');  };}// This is used to ensure that we never schedule 2 callas to setImmediatevar isScheduled = false;// Keep track of observers that needs to be notified next time.var scheduledObservers = [];/** * Schedules |dispatchCallback| to be called in the future. * @param {MutationObserver} observer */function scheduleCallback(observer) {  scheduledObservers.push(observer);  if (!isScheduled) {    isScheduled = true;    setImmediate(dispatchCallbacks);  }}function wrapIfNeeded(node) {  return window.ShadowDOMPolyfill &&      window.ShadowDOMPolyfill.wrapIfNeeded(node) ||      node;}function dispatchCallbacks() {  // http://dom.spec.whatwg.org/#mutation-observers  isScheduled = false; // Used to allow a new setImmediate call above.  var observers = scheduledObservers;  scheduledObservers = [];  // Sort observers based on their creation UID (incremental).  observers.sort(function(o1, o2) {    return o1.uid_ - o2.uid_;  });  var anyNonEmpty = false;  observers.forEach(function(observer) {    // 2.1, 2.2    var queue = observer.takeRecords();    // 2.3. Remove all transient registered observers whose observer is mo.    removeTransientObserversFor(observer);    // 2.4    if (queue.length) {      observer.callback_(queue, observer);      anyNonEmpty = true;    }  });  // 3.  if (anyNonEmpty)    dispatchCallbacks();}function removeTransientObserversFor(observer) {  observer.nodes_.forEach(function(node) {    var registrations = registrationsTable.get(node);    if (!registrations)      return;    registrations.forEach(function(registration) {      if (registration.observer === observer)        registration.removeTransientObservers();    });  });}/** * This function is used for the "For each registered observer observer (with * observer's options as options) in target's list of registered observers, * run these substeps:" and the "For each ancestor ancestor of target, and for * each registered observer observer (with options options) in ancestor's list * of registered observers, run these substeps:" part of the algorithms. The * |options.subtree| is checked to ensure that the callback is called * correctly. * * @param {Node} target * @param {function(MutationObserverInit):MutationRecord} callback */function forEachAncestorAndObserverEnqueueRecord(target, callback) {  for (var node = target; node; node = node.parentNode) {    var registrations = registrationsTable.get(node);    if (registrations) {      for (var j = 0; j < registrations.length; j++) {        var registration = registrations[j];        var options = registration.options;        // Only target ignores subtree.        if (node !== target && !options.subtree)          continue;        var record = callback(options);        if (record)          registration.enqueue(record);      }    }  }}var uidCounter = 0;/** * The class that maps to the DOM MutationObserver interface. * @param {Function} callback. * @constructor */function JsMutationObserver(callback) {  this.callback_ = callback;  this.nodes_ = [];  this.records_ = [];  this.uid_ = ++uidCounter;}JsMutationObserver.prototype = {  observe: function(target, options) {    target = wrapIfNeeded(target);    // 1.1    if (!options.childList && !options.attributes && !options.characterData ||        // 1.2        options.attributeOldValue && !options.attributes ||        // 1.3        options.attributeFilter && options.attributeFilter.length &&            !options.attributes ||        // 1.4        options.characterDataOldValue && !options.characterData) {      throw new SyntaxError();    }    var registrations = registrationsTable.get(target);    if (!registrations)      registrationsTable.set(target, registrations = []);    // 2    // If target's list of registered observers already includes a registered    // observer associated with the context object, replace that registered    // observer's options with options.    var registration;    for (var i = 0; i < registrations.length; i++) {      if (registrations[i].observer === this) {        registration = registrations[i];        registration.removeListeners();        registration.options = options;        break;      }    }    // 3.    // Otherwise, add a new registered observer to target's list of registered    // observers with the context object as the observer and options as the    // options, and add target to context object's list of nodes on which it    // is registered.    if (!registration) {      registration = new Registration(this, target, options);      registrations.push(registration);      this.nodes_.push(target);    }    registration.addListeners();  },  disconnect: function() {    this.nodes_.forEach(function(node) {      var registrations = registrationsTable.get(node);      for (var i = 0; i < registrations.length; i++) {        var registration = registrations[i];        if (registration.observer === this) {          registration.removeListeners();          registrations.splice(i, 1);          // Each node can only have one registered observer associated with          // this observer.          break;        }      }    }, this);    this.records_ = [];  },  takeRecords: function() {    var copyOfRecords = this.records_;    this.records_ = [];    return copyOfRecords;  }};/** * @param {string} type * @param {Node} target * @constructor */function MutationRecord(type, target) {  this.type = type;  this.target = target;  this.addedNodes = [];  this.removedNodes = [];  this.previousSibling = null;  this.nextSibling = null;  this.attributeName = null;  this.attributeNamespace = null;  this.oldValue = null;}function copyMutationRecord(original) {  var record = new MutationRecord(original.type, original.target);  record.addedNodes = original.addedNodes.slice();  record.removedNodes = original.removedNodes.slice();  record.previousSibling = original.previousSibling;  record.nextSibling = original.nextSibling;  record.attributeName = original.attributeName;  record.attributeNamespace = original.attributeNamespace;  record.oldValue = original.oldValue;  return record;};// We keep track of the two (possibly one) records used in a single mutation.var currentRecord, recordWithOldValue;/** * Creates a record without |oldValue| and caches it as |currentRecord| for * later use. * @param {string} oldValue * @return {MutationRecord} */function getRecord(type, target) {  return currentRecord = new MutationRecord(type, target);}/** * Gets or creates a record with |oldValue| based in the |currentRecord| * @param {string} oldValue * @return {MutationRecord} */function getRecordWithOldValue(oldValue) {  if (recordWithOldValue)    return recordWithOldValue;  recordWithOldValue = copyMutationRecord(currentRecord);  recordWithOldValue.oldValue = oldValue;  return recordWithOldValue;}function clearRecords() {  currentRecord = recordWithOldValue = undefined;}/** * @param {MutationRecord} record * @return {boolean} Whether the record represents a record from the current * mutation event. */function recordRepresentsCurrentMutation(record) {  return record === recordWithOldValue || record === currentRecord;}/** * Selects which record, if any, to replace the last record in the queue. * This returns |null| if no record should be replaced. * * @param {MutationRecord} lastRecord * @param {MutationRecord} newRecord * @param {MutationRecord} */function selectRecord(lastRecord, newRecord) {  if (lastRecord === newRecord)    return lastRecord;  // Check if the the record we are adding represents the same record. If  // so, we keep the one with the oldValue in it.  if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord))    return recordWithOldValue;  return null;}/** * Class used to represent a registered observer. * @param {MutationObserver} observer * @param {Node} target * @param {MutationObserverInit} options * @constructor */function Registration(observer, target, options) {  this.observer = observer;  this.target = target;  this.options = options;  this.transientObservedNodes = [];}Registration.prototype = {  enqueue: function(record) {    var records = this.observer.records_;    var length = records.length;    // There are cases where we replace the last record with the new record.    // For example if the record represents the same mutation we need to use    // the one with the oldValue. If we get same record (this can happen as we    // walk up the tree) we ignore the new record.    if (records.length > 0) {      var lastRecord = records[length - 1];      var recordToReplaceLast = selectRecord(lastRecord, record);      if (recordToReplaceLast) {        records[length - 1] = recordToReplaceLast;        return;      }    } else {      scheduleCallback(this.observer);    }    records[length] = record;  },  addListeners: function() {    this.addListeners_(this.target);  },  addListeners_: function(node) {    var options = this.options;    if (options.attributes)      node.addEventListener('DOMAttrModified', this, true);    if (options.characterData)      node.addEventListener('DOMCharacterDataModified', this, true);    if (options.childList)      node.addEventListener('DOMNodeInserted', this, true);    if (options.childList || options.subtree)      node.addEventListener('DOMNodeRemoved', this, true);  },  removeListeners: function() {    this.removeListeners_(this.target);  },  removeListeners_: function(node) {    var options = this.options;    if (options.attributes)      node.removeEventListener('DOMAttrModified', this, true);    if (options.characterData)      node.removeEventListener('DOMCharacterDataModified', this, true);    if (options.childList)      node.removeEventListener('DOMNodeInserted', this, true);    if (options.childList || options.subtree)      node.removeEventListener('DOMNodeRemoved', this, true);  },  /**   * Adds a transient observer on node. The transient observer gets removed   * next time we deliver the change records.   * @param {Node} node   */  addTransientObserver: function(node) {    // Don't add transient observers on the target itself. We already have all    // the required listeners set up on the target.    if (node === this.target)      return;    this.addListeners_(node);    this.transientObservedNodes.push(node);    var registrations = registrationsTable.get(node);    if (!registrations)      registrationsTable.set(node, registrations = []);    // We know that registrations does not contain this because we already    // checked if node === this.target.    registrations.push(this);  },  removeTransientObservers: function() {    var transientObservedNodes = this.transientObservedNodes;    this.transientObservedNodes = [];    transientObservedNodes.forEach(function(node) {      // Transient observers are never added to the target.      this.removeListeners_(node);      var registrations = registrationsTable.get(node);      for (var i = 0; i < registrations.length; i++) {        if (registrations[i] === this) {          registrations.splice(i, 1);          // Each node can only have one registered observer associated with          // this observer.          break;        }      }    }, this);  },  handleEvent: function(e) {    // Stop propagation since we are managing the propagation manually.    // This means that other mutation events on the page will not work    // correctly but that is by design.    e.stopImmediatePropagation();    switch (e.type) {      case 'DOMAttrModified':        // http://dom.spec.whatwg.org/#concept-mo-queue-attributes        var name = e.attrName;        var namespace = e.relatedNode.namespaceURI;        var target = e.target;        // 1.        var record = new getRecord('attributes', target);        record.attributeName = name;        record.attributeNamespace = namespace;        // 2.        var oldValue = null;        if (!(typeof MutationEvent !== 'undefined' && e.attrChange === MutationEvent.ADDITION))          oldValue = e.prevValue;        forEachAncestorAndObserverEnqueueRecord(target, function(options) {          // 3.1, 4.2          if (!options.attributes)            return;          // 3.2, 4.3          if (options.attributeFilter && options.attributeFilter.length &&              options.attributeFilter.indexOf(name) === -1 &&              options.attributeFilter.indexOf(namespace) === -1) {            return;          }          // 3.3, 4.4          if (options.attributeOldValue)            return getRecordWithOldValue(oldValue);          // 3.4, 4.5          return record;        });        break;      case 'DOMCharacterDataModified':        // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata        var target = e.target;        // 1.        var record = getRecord('characterData', target);        // 2.        var oldValue = e.prevValue;        forEachAncestorAndObserverEnqueueRecord(target, function(options) {          // 3.1, 4.2          if (!options.characterData)            return;          // 3.2, 4.3          if (options.characterDataOldValue)            return getRecordWithOldValue(oldValue);          // 3.3, 4.4          return record;        });        break;      case 'DOMNodeRemoved':        this.addTransientObserver(e.target);        // Fall through.      case 'DOMNodeInserted':        // http://dom.spec.whatwg.org/#concept-mo-queue-childlist        var target = e.relatedNode;        var changedNode = e.target;        var addedNodes, removedNodes;        if (e.type === 'DOMNodeInserted') {          addedNodes = [changedNode];          removedNodes = [];        } else {          addedNodes = [];          removedNodes = [changedNode];        }        var previousSibling = changedNode.previousSibling;        var nextSibling = changedNode.nextSibling;        // 1.        var record = getRecord('childList', target);        record.addedNodes = addedNodes;        record.removedNodes = removedNodes;        record.previousSibling = previousSibling;        record.nextSibling = nextSibling;        forEachAncestorAndObserverEnqueueRecord(target, function(options) {          // 2.1, 3.2          if (!options.childList)            return;          // 2.2, 3.3          return record;        });    }    clearRecords();  }};if (!MutationObserver) {  MutationObserver = JsMutationObserver;}module.exports = MutationObserver;
 |