25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

nwmatcher-cache.js 5.4 KiB

3 yıl önce
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Copyright (C) 2007-2018 Diego Perini
  3. * All rights reserved.
  4. *
  5. * Caching/memoization module for NWMatcher
  6. *
  7. * Added capabilities:
  8. *
  9. * - Mutation Events are feature tested and used safely
  10. * - handle caching different document types HTML/XML/SVG
  11. * - store result sets for different selectors / contexts
  12. * - simultaneously control mutation on multiple documents
  13. *
  14. */
  15. (function(global) {
  16. // export the public API for CommonJS implementations,
  17. // for headless JS engines or for standard web browsers
  18. var Dom =
  19. // as CommonJS/NodeJS module
  20. typeof exports == 'object' ? exports :
  21. // create or extend NW namespace
  22. ((global.NW || (global.NW = { })) &&
  23. (global.NW.Dom || (global.NW.Dom = { }))),
  24. Contexts = { },
  25. Results = { },
  26. isEnabled = false,
  27. isExpired = true,
  28. isPaused = false,
  29. context = global.document,
  30. root = context.documentElement,
  31. // timing pauses
  32. now = 0,
  33. // last time cache initialization was called
  34. lastCalled = 0,
  35. // minimum time allowed between calls to the cache initialization
  36. minCacheRest = 15, //ms
  37. mutationTest =
  38. function(type, callback) {
  39. var isSupported = false,
  40. root = document.documentElement,
  41. div = document.createElement('div'),
  42. handler = function() { isSupported = true; };
  43. root.insertBefore(div, root.firstChild);
  44. div.addEventListener(type, handler, true);
  45. if (callback && callback.call) callback(div);
  46. div.removeEventListener(type, handler, true);
  47. root.removeChild(div);
  48. return isSupported;
  49. },
  50. // check for Mutation Events, DOMAttrModified should be
  51. // enough to ensure DOMNodeInserted/DOMNodeRemoved exist
  52. HACKED_MUTATION_EVENTS = false,
  53. NATIVE_MUTATION_EVENTS = root.addEventListener ?
  54. mutationTest('DOMAttrModified', function(e) { e.setAttribute('id', 'nw'); }) : false,
  55. loadResults =
  56. function(selector, from, doc, root) {
  57. if (isEnabled && !isPaused) {
  58. if (!isExpired) {
  59. if (Results[selector] && Contexts[selector] === from) {
  60. return Results[selector];
  61. }
  62. } else {
  63. // pause caching while we are getting
  64. // hammered by dom mutations (jdalton)
  65. now = (new Date).getTime();
  66. if ((now - lastCalled) < minCacheRest) {
  67. isPaused = isExpired = true;
  68. setTimeout(function() { isPaused = false; }, minCacheRest);
  69. } else setCache(true, doc);
  70. lastCalled = now;
  71. }
  72. }
  73. return undefined;
  74. },
  75. saveResults =
  76. function(selector, from, doc, data) {
  77. Contexts[selector] = from;
  78. Results[selector] = data;
  79. return;
  80. },
  81. /*-------------------------------- CACHING ---------------------------------*/
  82. // invoked by mutation events to expire cached parts
  83. mutationWrapper =
  84. function(event) {
  85. var d = event.target.ownerDocument || event.target;
  86. stopMutation(d);
  87. expireCache(d);
  88. },
  89. // append mutation events
  90. startMutation =
  91. function(d) {
  92. if (!d.isCaching && d.addEventListener) {
  93. // FireFox/Opera/Safari/KHTML have support for Mutation Events
  94. d.addEventListener('DOMAttrModified', mutationWrapper, true);
  95. d.addEventListener('DOMNodeInserted', mutationWrapper, true);
  96. d.addEventListener('DOMNodeRemoved', mutationWrapper, true);
  97. d.isCaching = true;
  98. }
  99. },
  100. // remove mutation events
  101. stopMutation =
  102. function(d) {
  103. if (d.isCaching && d.removeEventListener) {
  104. d.removeEventListener('DOMAttrModified', mutationWrapper, true);
  105. d.removeEventListener('DOMNodeInserted', mutationWrapper, true);
  106. d.removeEventListener('DOMNodeRemoved', mutationWrapper, true);
  107. d.isCaching = false;
  108. }
  109. },
  110. // enable/disable context caching system
  111. // @d optional document context (iframe, xml document)
  112. // script loading context will be used as default context
  113. setCache =
  114. function(enable, d) {
  115. if (!!enable) {
  116. isExpired = false;
  117. startMutation(d);
  118. } else {
  119. isExpired = true;
  120. stopMutation(d);
  121. }
  122. isEnabled = !!enable;
  123. },
  124. // expire complete cache
  125. // can be invoked by Mutation Events or
  126. // programmatically by other code/scripts
  127. // document context is mandatory no checks
  128. expireCache =
  129. function(d) {
  130. isExpired = true;
  131. Contexts = { };
  132. Results = { };
  133. };
  134. if (!NATIVE_MUTATION_EVENTS && root.addEventListener && Element && Element.prototype) {
  135. if (mutationTest('DOMNodeInserted', function(e) { e.appendChild(document.createElement('div')); }) &&
  136. mutationTest('DOMNodeRemoved', function(e) { e.removeChild(e.appendChild(document.createElement('div'))); })) {
  137. HACKED_MUTATION_EVENTS = true;
  138. Element.prototype._setAttribute = Element.prototype.setAttribute;
  139. Element.prototype.setAttribute =
  140. function(name, val) {
  141. this._setAttribute(name, val);
  142. mutationWrapper({
  143. target: this,
  144. type: 'DOMAttrModified',
  145. attrName: name,
  146. attrValue: val });
  147. };
  148. }
  149. }
  150. isEnabled = NATIVE_MUTATION_EVENTS || HACKED_MUTATION_EVENTS;
  151. /*------------------------------- PUBLIC API -------------------------------*/
  152. // save results into cache
  153. Dom.saveResults = saveResults;
  154. // load results from cache
  155. Dom.loadResults = loadResults;
  156. // expire DOM tree cache
  157. Dom.expireCache = expireCache;
  158. // enable/disable cache
  159. Dom.setCache = setCache;
  160. })(this);