setMutationHandler

MutationObserver wrapper to wait for the specified CSS selector

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

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

  1. /* EXAMPLE:
  2.  
  3. setMutationHandler('.container p.some-child', nodes => {
  4. nodes.forEach(node => node.style.display = 'none');
  5. return false; // disconnect the observer, this is useful for one-time jobs
  6. });
  7.  
  8. setMutationHandler({
  9. processExisting: true,
  10. selector: '.container p.some-child',
  11. handler: nodes => nodes.forEach(node => node.style.display = 'none')
  12. });
  13.  
  14. setMutationHandler({
  15. selector: '.container p.some-child',
  16. processExisting: false, // optional
  17. target: document, // optional
  18. childList: true, // optional
  19. subtree: true, // optional
  20. attributes: false, // optional
  21. attributeFilter: [], // optional
  22. attributeOldValue: false, // optional
  23. characterData: false, // optional
  24. characterDataOldValue: false, // optional
  25. handler: nodes => {
  26. nodes.forEach(node => node.style.display = 'none');
  27. return false; // disconnect the observer, this is useful for one-time jobs
  28. },
  29. });
  30. */
  31.  
  32. // ==UserScript==
  33. // @name setMutationHandler
  34. // @description MutationObserver wrapper to wait for the specified CSS selector
  35. // @namespace wOxxOm.scripts
  36. // @author wOxxOm
  37. // @grant none
  38. // @version 3.0.1
  39. // ==/UserScript==
  40.  
  41. function setMutationHandler(target, selector, handler, options) {
  42. // or setMutationHandler(selector, handler, options) {
  43. // or setMutationHandler(options) {
  44. if (typeof arguments[0] == 'string') {
  45. options = arguments[2] || {};
  46. handler = arguments[1];
  47. selector = arguments[0];
  48. target = document;
  49. } else if (arguments.length == 1 && target && typeof target.handler == 'function') {
  50. options = arguments[0];
  51. handler = options.handler;
  52. selector = options.selector;
  53. target = options.target || document;
  54. } else if (!(target instanceof Node)) {
  55. throw 'Bad params for setMutationHandler.\n' +
  56. 'A: [optional Node] target, [String] selector, [Function] handler, [optional Object] options\n' +
  57. 'B: [Object] options\n' +
  58. 'Options: target, selector, handler, processExisting, childList, attributes, characterData, subtree, attributeOldValue, characterDataOldValue, attributeFilter';
  59. }
  60. if (options.processExisting && target.querySelector(selector))
  61. handler.call(null, Array.prototype.slice.call(target.querySelectorAll(selector)));
  62. if (!options.attributes && !options.characterData && !options.childList && options.subtree === undefined)
  63. options.childList = options.subtree = true;
  64.  
  65. var cb;
  66. if (/^#[\w\d-]+$/.test(selector)) {
  67. selector = selector.substr(1);
  68. cb = MOhandlerForId;
  69. } else {
  70. cb = MOhandler;
  71. }
  72. var observer = new MutationObserver(cb);
  73. observer.observe(target, options || {subtree:true, childList:true});
  74. return observer;
  75.  
  76. function MOhandler(mutations) {
  77. if (mutations.length > 100 && !document.querySelector(selector))
  78. return;
  79. var found = [];
  80. for (var i=0, m; (m = mutations[i++]); ) {
  81. switch (m.type) {
  82. case 'childList':
  83. var nodes = m.addedNodes, nl = nodes.length;
  84. var textNodesOnly = true;
  85. for (var j=0; j < nl; j++) {
  86. var n = nodes[j];
  87. textNodesOnly &= n.nodeType == 3; // TEXT_NODE
  88. if (n.nodeType != 1) // ELEMENT_NODE
  89. continue;
  90. if (n.matches(selector))
  91. found.push(n);
  92. else if (n.querySelector(selector)) {
  93. n = n.querySelectorAll(selector);
  94. if (n.length < 1000)
  95. found.push.apply(found, n);
  96. else
  97. found = found.concat(found.slice.call(n));
  98. }
  99. }
  100. if (textNodesOnly && m.target.matches(selector))
  101. found.push(m.target);
  102. break;
  103. case 'attributes':
  104. if (m.target.matches(selector))
  105. found.push(m.target);
  106. break;
  107. case 'characterData':
  108. if (m.target.parentNode && m.target.parentNode.matches(selector))
  109. found.push(m.target.parentNode);
  110. break;
  111. }
  112. }
  113. if (!found.length)
  114. return;
  115. if (handler.call(observer, found) === false)
  116. observer.disconnect();
  117. }
  118.  
  119. function MOhandlerForId(mutations) {
  120. var el = document.getElementById(selector);
  121. if (el && target.contains(el))
  122. if (handler.call(observer, [el]) === false)
  123. observer.disconnect();
  124. }
  125. }