setMutationHandler

MutationObserver wrapper to wait for the specified CSS selector

当前为 2017-02-11 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/12228/174471/setMutationHandler.js

  1. /* EXAMPLE:
  2.  
  3. setMutationHandler(document, '.container p.some-child', function(nodes) {
  4. // single node:
  5. nodes[0].remove();
  6.  
  7. // or multiple nodes:
  8. nodes.forEach(node => node.style.display = 'none');
  9.  
  10. // disconnect the observer, this is useful for one-time jobs
  11. return false;
  12. });
  13.  
  14. // the observation target parameter may be omitted so "document" will be used by default:
  15. // setMutationHandler('#some-id', function(nodes) { ....... });
  16.  
  17. // process existing elements and set a mutation handler for the future ones
  18. processExistingAndSetMutationHandler('a', processLinks);
  19. */
  20.  
  21. // ==UserScript==
  22. // @name setMutationHandler
  23. // @description MutationObserver wrapper to wait for the specified CSS selector
  24. // @namespace wOxxOm.scripts
  25. // @author wOxxOm
  26. // @grant none
  27. // @version 3.0.0
  28. // ==/UserScript==
  29.  
  30. function setMutationHandler(baseNode, selector, cb, options) {
  31. if (typeof baseNode == 'string') {
  32. options = cb;
  33. cb = selector;
  34. selector = baseNode;
  35. baseNode = document;
  36. }
  37.  
  38. var ob;
  39.  
  40. if (/^#[\w\d-]+$/.test(selector)) {
  41. selector = selector.substr(1);
  42. ob = new MutationObserver(MOhandlerForId);
  43. } else {
  44. ob = new MutationObserver(MOhandler);
  45. }
  46.  
  47. ob.observe(baseNode || document, options || {subtree:true, childList:true});
  48. return ob;
  49.  
  50. function MOhandler(mutations, observer) {
  51. if (mutations.length > 100 && !document.querySelector(selector))
  52. return;
  53. var found = [];
  54. for (var i=0, m; (m = mutations[i++]); ) {
  55. switch (m.type) {
  56. case 'childList':
  57. var nodes = m.addedNodes, nl = nodes.length;
  58. var textNodesOnly = true;
  59. for (var j=0; j < nl; j++) {
  60. var n = nodes[j];
  61. textNodesOnly &= n.nodeType == 3; // TEXT_NODE
  62. if (n.nodeType != 1) // ELEMENT_NODE
  63. continue;
  64. if (n.matches(selector))
  65. found.push(n);
  66. else if (n.querySelector(selector)) {
  67. n = n.querySelectorAll(selector);
  68. if (n.length < 1000)
  69. found.push.apply(found, n);
  70. else
  71. found = found.concat(found.slice.call(n));
  72. }
  73. }
  74. if (textNodesOnly && m.target.matches(selector))
  75. found.push(m.target);
  76. break;
  77. case 'attributes':
  78. if (m.target.matches(selector))
  79. found.push(m.target);
  80. break;
  81. case 'characterData':
  82. if (m.target.parentNode && m.target.parentNode.matches(selector))
  83. found.push(m.target.parentNode);
  84. break;
  85. }
  86. }
  87. if (!found.length)
  88. return;
  89. if (cb.call(ob, found) === false)
  90. ob.disconnect();
  91. }
  92.  
  93. function MOhandlerForId(mutations, observer) {
  94. var el = document.getElementById(selector);
  95. if (!el || !baseNode.contains(el))
  96. return;
  97. if (cb.call(ob, [el]) === false)
  98. ob.disconnect();
  99. }
  100. }
  101.  
  102. function processExistingAndSetMutationHandler(baseNode, selector, cb, options) {
  103. if (typeof baseNode == 'string') {
  104. options = cb;
  105. cb = selector;
  106. selector = baseNode;
  107. baseNode = document;
  108. }
  109. baseNode = baseNode || document;
  110. if (baseNode.querySelector(selector))
  111. cb.call(null, Array.prototype.slice.call(baseNode.querySelectorAll(selector)));
  112. setMutationHandler(baseNode, selector, cb, options);
  113. }