index.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var gLite = require('@antv/g-lite');
  4. var MutationRecord = /*#__PURE__*/function () {
  5. MutationRecord.copy = function copy(original) {
  6. var record = new MutationRecord(original.type, original.target);
  7. record.addedNodes = original.addedNodes.slice();
  8. record.removedNodes = original.removedNodes.slice();
  9. record.previousSibling = original.previousSibling;
  10. record.nextSibling = original.nextSibling;
  11. record.attributeName = original.attributeName;
  12. record.attributeNamespace = original.attributeNamespace;
  13. record.oldValue = original.oldValue;
  14. return record;
  15. };
  16. function MutationRecord(type, target) {
  17. this.type = void 0;
  18. this.target = void 0;
  19. this.addedNodes = [];
  20. this.attributeName = null;
  21. this.attributeNamespace = null;
  22. this.nextSibling = null;
  23. this.oldValue = null;
  24. this.previousSibling = null;
  25. this.removedNodes = [];
  26. this.type = type;
  27. this.target = target;
  28. }
  29. return MutationRecord;
  30. }();
  31. var uidCounter = 0;
  32. var registrationsTable = new WeakMap();
  33. var Registration = /*#__PURE__*/function () {
  34. function Registration(observer, target, options) {
  35. this.observer = void 0;
  36. this.target = void 0;
  37. this.options = void 0;
  38. this.transientObservedNodes = [];
  39. this.observer = observer;
  40. this.target = target;
  41. this.options = options;
  42. }
  43. var _proto = Registration.prototype;
  44. _proto.enqueue = function enqueue(record) {
  45. var records = this.observer.records;
  46. var length = records.length;
  47. // There are cases where we replace the last record with the new record.
  48. // For example if the record represents the same mutation we need to use
  49. // the one with the oldValue. If we get same record (this can happen as we
  50. // walk up the tree) we ignore the new record.
  51. if (records.length > 0) {
  52. var lastRecord = records[length - 1];
  53. var recordToReplaceLast = selectRecord(lastRecord, record);
  54. if (recordToReplaceLast) {
  55. records[length - 1] = recordToReplaceLast;
  56. return;
  57. }
  58. } else {
  59. scheduleCallback(this.observer);
  60. }
  61. records[length] = record;
  62. };
  63. _proto.addListeners = function addListeners() {
  64. this.addListeners_(this.target);
  65. };
  66. _proto.addListeners_ = function addListeners_(node) {
  67. var options = this.options;
  68. if (options.attributes) node.addEventListener(gLite.ElementEvent.ATTR_MODIFIED, this, true);
  69. // if (options.characterData) node.addEventListener('DOMCharacterDataModified', this, true);
  70. if (options.childList) node.addEventListener(gLite.ElementEvent.INSERTED, this, true);
  71. if (options.childList || options.subtree) node.addEventListener(gLite.ElementEvent.REMOVED, this, true);
  72. };
  73. _proto.removeListeners = function removeListeners() {
  74. this.removeListeners_(this.target);
  75. };
  76. _proto.removeListeners_ = function removeListeners_(node) {
  77. var options = this.options;
  78. if (options.attributes) node.removeEventListener(gLite.ElementEvent.ATTR_MODIFIED, this, true);
  79. // if (options.characterData) node.removeEventListener('DOMCharacterDataModified', this, true);
  80. if (options.childList) node.removeEventListener(gLite.ElementEvent.INSERTED, this, true);
  81. if (options.childList || options.subtree) node.removeEventListener(gLite.ElementEvent.REMOVED, this, true);
  82. }
  83. /**
  84. * Adds a transient observer on node. The transient observer gets removed
  85. * next time we deliver the change records.
  86. */
  87. // addTransientObserver(node: IElement) {
  88. // // Don't add transient observers on the target itself. We already have all
  89. // // the required listeners set up on the target.
  90. // if (node === this.target) return;
  91. // this.addListeners_(node);
  92. // this.transientObservedNodes.push(node);
  93. // let registrations = registrationsTable.get(node);
  94. // if (!registrations) registrationsTable.set(node, (registrations = []));
  95. // // We know that registrations does not contain this because we already
  96. // // checked if node === this.target.
  97. // registrations.push(this);
  98. // }
  99. ;
  100. _proto.removeTransientObservers = function removeTransientObservers() {
  101. var transientObservedNodes = this.transientObservedNodes;
  102. this.transientObservedNodes = [];
  103. transientObservedNodes.forEach(function (node) {
  104. // Transient observers are never added to the target.
  105. this.removeListeners_(node);
  106. var registrations = registrationsTable.get(node);
  107. for (var i = 0; i < registrations.length; i++) {
  108. if (registrations[i] === this) {
  109. registrations.splice(i, 1);
  110. // Each node can only have one registered observer associated with
  111. // this observer.
  112. break;
  113. }
  114. }
  115. }, this);
  116. };
  117. _proto.handleEvent = function handleEvent(e) {
  118. // Stop propagation since we are managing the propagation manually.
  119. // This means that other mutation events on the page will not work
  120. // correctly but that is by design.
  121. e.stopImmediatePropagation();
  122. var record;
  123. var target;
  124. switch (e.type) {
  125. case gLite.ElementEvent.ATTR_MODIFIED:
  126. // http://dom.spec.whatwg.org/#concept-mo-queue-attributes
  127. var name = e.attrName;
  128. // @ts-ignore
  129. var namespace = e.relatedNode.namespaceURI;
  130. target = e.target;
  131. // 1.
  132. record = getRecord('attributes', target);
  133. record.attributeName = name;
  134. record.attributeNamespace = namespace;
  135. // 2.
  136. var oldValue = e.attrChange === gLite.MutationEvent.ADDITION ? null : e.prevValue;
  137. forEachAncestorAndObserverEnqueueRecord(target, function (options) {
  138. // 3.1, 4.2
  139. if (!options.attributes) return;
  140. // 3.2, 4.3
  141. if (options.attributeFilter && options.attributeFilter.length && options.attributeFilter.indexOf(name) === -1 && options.attributeFilter.indexOf(namespace) === -1) {
  142. return;
  143. }
  144. // 3.3, 4.4
  145. if (options.attributeOldValue) return getRecordWithOldValue(oldValue);
  146. // 3.4, 4.5
  147. return record;
  148. });
  149. break;
  150. // case 'DOMCharacterDataModified':
  151. // // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata
  152. // var target = e.target;
  153. // // 1.
  154. // var record = getRecord('characterData', target);
  155. // // 2.
  156. // var oldValue = e.prevValue;
  157. // forEachAncestorAndObserverEnqueueRecord(target, function(options) {
  158. // // 3.1, 4.2
  159. // if (!options.characterData)
  160. // return;
  161. // // 3.2, 4.3
  162. // if (options.characterDataOldValue)
  163. // return getRecordWithOldValue(oldValue);
  164. // // 3.3, 4.4
  165. // return record;
  166. // });
  167. // break;
  168. case gLite.ElementEvent.REMOVED:
  169. // this.addTransientObserver(e.target as IElement);
  170. // Fall through.
  171. case gLite.ElementEvent.INSERTED:
  172. // http://dom.spec.whatwg.org/#concept-mo-queue-childlist
  173. target = e.relatedNode;
  174. var changedNode = e.target;
  175. var addedNodes;
  176. var removedNodes;
  177. if (e.type === gLite.ElementEvent.INSERTED) {
  178. addedNodes = [changedNode];
  179. removedNodes = [];
  180. } else {
  181. addedNodes = [];
  182. removedNodes = [changedNode];
  183. }
  184. var previousSibling = changedNode.previousSibling;
  185. var nextSibling = changedNode.nextSibling;
  186. // 1.
  187. record = getRecord('childList', target);
  188. record.addedNodes = addedNodes;
  189. record.removedNodes = removedNodes;
  190. record.previousSibling = previousSibling;
  191. record.nextSibling = nextSibling;
  192. forEachAncestorAndObserverEnqueueRecord(target, function (options) {
  193. // 2.1, 3.2
  194. if (!options.childList) return;
  195. // 2.2, 3.3
  196. return record;
  197. });
  198. }
  199. clearRecords();
  200. };
  201. return Registration;
  202. }();
  203. /**
  204. * @see https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
  205. * @see https://github.com/googlearchive/MutationObservers/blob/master/MutationObserver.js
  206. */
  207. var MutationObserver = /*#__PURE__*/function () {
  208. function MutationObserver(callback) {
  209. this.callback = void 0;
  210. this.nodes = [];
  211. this.records = [];
  212. this.uid = uidCounter++;
  213. this.callback = callback;
  214. }
  215. var _proto2 = MutationObserver.prototype;
  216. _proto2.observe = function observe(target, options) {
  217. // 1.1
  218. if (!options.childList && !options.attributes && !options.characterData ||
  219. // 1.2
  220. options.attributeOldValue && !options.attributes ||
  221. // 1.3
  222. options.attributeFilter && options.attributeFilter.length && !options.attributes ||
  223. // 1.4
  224. options.characterDataOldValue && !options.characterData) {
  225. throw new SyntaxError();
  226. }
  227. var registrations = registrationsTable.get(target);
  228. if (!registrations) registrationsTable.set(target, registrations = []);
  229. // 2
  230. // If target's list of registered observers already includes a registered
  231. // observer associated with the context object, replace that registered
  232. // observer's options with options.
  233. var registration;
  234. for (var i = 0; i < registrations.length; i++) {
  235. if (registrations[i].observer === this) {
  236. registration = registrations[i];
  237. registration.removeListeners();
  238. registration.options = options;
  239. break;
  240. }
  241. }
  242. // 3.
  243. // Otherwise, add a new registered observer to target's list of registered
  244. // observers with the context object as the observer and options as the
  245. // options, and add target to context object's list of nodes on which it
  246. // is registered.
  247. if (!registration) {
  248. registration = new Registration(this, target, options);
  249. registrations.push(registration);
  250. this.nodes.push(target);
  251. }
  252. registration.addListeners();
  253. };
  254. _proto2.disconnect = function disconnect() {
  255. var _this = this;
  256. this.nodes.forEach(function (node) {
  257. var registrations = registrationsTable.get(node);
  258. for (var i = 0; i < registrations.length; i++) {
  259. var registration = registrations[i];
  260. if (registration.observer === _this) {
  261. registration.removeListeners();
  262. registrations.splice(i, 1);
  263. // Each node can only have one registered observer associated with
  264. // this observer.
  265. break;
  266. }
  267. }
  268. }, this);
  269. this.records = [];
  270. };
  271. _proto2.takeRecords = function takeRecords() {
  272. var copyOfRecords = this.records;
  273. this.records = [];
  274. return copyOfRecords;
  275. };
  276. return MutationObserver;
  277. }();
  278. // We keep track of the two (possibly one) records used in a single mutation.
  279. var currentRecord;
  280. var recordWithOldValue;
  281. /**
  282. * Creates a record without |oldValue| and caches it as |currentRecord| for
  283. * later use.
  284. */
  285. function getRecord(type, target) {
  286. return currentRecord = new MutationRecord(type, target);
  287. }
  288. /**
  289. * Gets or creates a record with |oldValue| based in the |currentRecord|
  290. */
  291. function getRecordWithOldValue(oldValue) {
  292. if (recordWithOldValue) return recordWithOldValue;
  293. recordWithOldValue = MutationRecord.copy(currentRecord);
  294. recordWithOldValue.oldValue = oldValue;
  295. return recordWithOldValue;
  296. }
  297. function clearRecords() {
  298. currentRecord = recordWithOldValue = undefined;
  299. }
  300. /**
  301. * Whether the record represents a record from the current
  302. * mutation event.
  303. */
  304. function recordRepresentsCurrentMutation(record) {
  305. return record === recordWithOldValue || record === currentRecord;
  306. }
  307. /**
  308. * Selects which record, if any, to replace the last record in the queue.
  309. * This returns |null| if no record should be replaced.
  310. */
  311. function selectRecord(lastRecord, newRecord) {
  312. if (lastRecord === newRecord) return lastRecord;
  313. // Check if the the record we are adding represents the same record. If
  314. // so, we keep the one with the oldValue in it.
  315. if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord)) return recordWithOldValue;
  316. return null;
  317. }
  318. function removeTransientObserversFor(observer) {
  319. observer.nodes.forEach(function (node) {
  320. var registrations = registrationsTable.get(node);
  321. if (!registrations) return;
  322. registrations.forEach(function (registration) {
  323. if (registration.observer === observer) registration.removeTransientObservers();
  324. });
  325. });
  326. }
  327. /**
  328. * This function is used for the "For each registered observer observer (with
  329. * observer's options as options) in target's list of registered observers,
  330. * run these substeps:" and the "For each ancestor ancestor of target, and for
  331. * each registered observer observer (with options options) in ancestor's list
  332. * of registered observers, run these substeps:" part of the algorithms. The
  333. * |options.subtree| is checked to ensure that the callback is called
  334. * correctly.
  335. *
  336. * @param {Node} target
  337. * @param {function(MutationObserverInit):MutationRecord} callback
  338. */
  339. function forEachAncestorAndObserverEnqueueRecord(target, callback) {
  340. for (var node = target; node; node = node.parentNode) {
  341. var registrations = registrationsTable.get(node);
  342. if (registrations) {
  343. for (var j = 0; j < registrations.length; j++) {
  344. var registration = registrations[j];
  345. var options = registration.options;
  346. // Only target ignores subtree.
  347. if (node !== target && !options.subtree) continue;
  348. var record = callback(options);
  349. if (record) registration.enqueue(record);
  350. }
  351. }
  352. }
  353. }
  354. // This is used to ensure that we never schedule 2 callas to setImmediate
  355. var isScheduled = false;
  356. // Keep track of observers that needs to be notified next time.
  357. var scheduledObservers = [];
  358. /**
  359. * Schedules |dispatchCallback| to be called in the future.
  360. */
  361. function scheduleCallback(observer) {
  362. scheduledObservers.push(observer);
  363. if (!isScheduled) {
  364. isScheduled = true;
  365. // setImmediate(dispatchCallbacks);
  366. if (typeof gLite.runtime.globalThis !== 'undefined') {
  367. gLite.runtime.globalThis.setTimeout(dispatchCallbacks);
  368. } else {
  369. dispatchCallbacks();
  370. }
  371. }
  372. }
  373. function dispatchCallbacks() {
  374. // http://dom.spec.whatwg.org/#mutation-observers
  375. isScheduled = false; // Used to allow a new setImmediate call above.
  376. var observers = scheduledObservers;
  377. scheduledObservers = [];
  378. // Sort observers based on their creation UID (incremental).
  379. observers.sort(function (o1, o2) {
  380. return o1.uid - o2.uid;
  381. });
  382. var anyNonEmpty = false;
  383. observers.forEach(function (observer) {
  384. // 2.1, 2.2
  385. var queue = observer.takeRecords();
  386. // 2.3. Remove all transient registered observers whose observer is mo.
  387. removeTransientObserversFor(observer);
  388. // 2.4
  389. if (queue.length) {
  390. // @ts-ignore
  391. observer.callback(queue, observer);
  392. anyNonEmpty = true;
  393. }
  394. });
  395. // 3.
  396. if (anyNonEmpty) dispatchCallbacks();
  397. }
  398. exports.MutationObserver = MutationObserver;
  399. exports.MutationRecord = MutationRecord;
  400. exports.Registration = Registration;