Wait For Elements

given a selector waits for elements to be inserted into the DOM and executes a callback for each match

当前为 2016-09-15 提交的版本,查看 最新版本

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

  1. /**
  2. * @param obj - {
  3. * sel: 'a', // the selector you want to wait for (optional)
  4. * context: document.body, // scope of search for selector or mutations (optional, default document.body)
  5. * stop: true, // stop waiting after first result (optional, default false)
  6. * mode: 'M', // M to use mutation observer, S to use setInterval (optional, default M)
  7. * onchange: func, // if using mode 'M' this function will be called whenever mutation handler triggers
  8. * onmatch: func, // if selector is specified function will be called for each match with element as parameter
  9. * config: { attributes: true } // if using mode 'M' this object will override settings passed to mutation observer
  10. * }
  11. */
  12. function waitForElems(obj) {
  13. var tick;
  14. var id = 'fke' + Math.floor(Math.random() * 12345);
  15. var type = window.MutationObserver ? (obj.mode || 'M') : 'S';
  16. var lastMutation = Date.now();
  17. var lastCall = Date.now();
  18. var context = obj.context || document.body;
  19. var sel = obj.sel;
  20. var onChange = obj.onchange;
  21. var queuedCall;
  22.  
  23. function throttle(func) {
  24. var now = Date.now();
  25. clearTimeout(queuedCall);
  26. // less than 100ms since last mutation
  27. if (now - lastMutation < 100) {
  28. // 500ms or more since last query
  29. if (now - lastCall >= 500) {
  30. func();
  31. } else {
  32. queuedCall = setTimeout(func, 100);
  33. }
  34. } else {
  35. func();
  36. }
  37. lastMutation = now;
  38. }
  39.  
  40. function findElem(sel) {
  41. lastCall = Date.now();
  42. var found = [].filter.call(context.querySelectorAll(sel), function(elem) {
  43. return elem.dataset[id] !== 'y';
  44. });
  45. if (found.length > 0) {
  46. if (obj.stop) {
  47. type === 'M' ? tick.disconnect() : clearInterval(tick);
  48. }
  49. found.forEach(function(elem) {
  50. elem.dataset[id] = 'y';
  51. obj.onmatch(elem);
  52. });
  53. }
  54. }
  55. if (type === 'M') {
  56. tick = new MutationObserver(function() {
  57. if (sel) throttle.call(null, findElem.bind(null, sel));
  58. if (onChange) onChange.apply(this, arguments);
  59. })
  60. tick.observe(context, obj.config || {
  61. subtree: true,
  62. childList: true
  63. });
  64. } else {
  65. tick = setInterval(findElem.bind(null, sel), 300);
  66. }
  67. if (sel) findElem(sel);
  68. return {
  69. type: type,
  70. stop: function() {
  71. if (type === 'M') {
  72. tick.disconnect();
  73. } else {
  74. clearInterval(tick);
  75. }
  76. }
  77. };
  78. }
  79. /**
  80. * @param regex - should match the site you're waiting for
  81. * @param action - the callback that will be executed when a matching url is visited
  82. * @param stopLooking - if true the function will stop waiting for another url match after the first match
  83. */
  84. function waitForUrl(regex, action, stopLooking) {
  85. function checkUrl(urlTest) {
  86. var url = window.location.href;
  87. if (url !== lastUrl && urlTest(url)) {
  88. if (stopLooking) {
  89. clearInterval(tick);
  90. }
  91. lastUrl = url;
  92. action();
  93. }
  94. lastUrl = url;
  95. }
  96. var urlTest = (typeof regex === 'function' ? regex : regex.test.bind(regex)),
  97. tick = setInterval(checkUrl.bind(null, urlTest), 300),
  98. lastUrl;
  99. checkUrl(urlTest);
  100. return tick;
  101. }