content-lazy-loader.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. /*
  2. * Copyright 2018 Gildas Lormeau
  3. * contact : gildas.lormeau <at> gmail.com
  4. *
  5. * This file is part of SingleFile.
  6. *
  7. * SingleFile is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * SingleFile is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with SingleFile. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /* global browser, document, timeout, MutationObserver */
  21. this.lazyLoader = this.lazyLoader || (() => {
  22. const LAZY_LOADING_TIMEOUT = 1000;
  23. const IDLE_LAZY_LOADING_TIMEOUT = 3000;
  24. const MAX_LAZY_LOADING_TIMEOUT = 30000;
  25. return { process };
  26. function process() {
  27. return new Promise(resolve => {
  28. let timeoutId, maxTimeoutId, idleTimeoutId, srcAttributeChanged;
  29. const observer = new MutationObserver(mutations => {
  30. if (mutations.find(mutation => mutation.type == "attributes")) {
  31. srcAttributeChanged = true;
  32. timeoutId = deferLazyLoadEnd(timeoutId, maxTimeoutId, idleTimeoutId, observer, resolve);
  33. }
  34. });
  35. observer.observe(document, { attributeFilter: ["src", "srcset"], subtree: true, childList: true });
  36. const scriptBeforeElement = document.createElement("script");
  37. scriptBeforeElement.src = browser.runtime.getURL("lib/lazy/web-lazy-loader-before.js");
  38. document.body.appendChild(scriptBeforeElement);
  39. scriptBeforeElement.onload = () => scriptBeforeElement.remove();
  40. idleTimeoutId = timeout.set(() => {
  41. if (!srcAttributeChanged) {
  42. timeout.clear(timeoutId);
  43. lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, resolve);
  44. }
  45. }, IDLE_LAZY_LOADING_TIMEOUT);
  46. maxTimeoutId = timeout.set(() => {
  47. timeout.clear(timeoutId);
  48. lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, resolve);
  49. }, MAX_LAZY_LOADING_TIMEOUT);
  50. });
  51. }
  52. function deferLazyLoadEnd(timeoutId, maxTimeoutId, idleTimeoutId, observer, resolve) {
  53. timeout.clear(timeoutId);
  54. return timeout.set(() => lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, resolve), LAZY_LOADING_TIMEOUT);
  55. }
  56. function lazyLoadEnd(maxTimeoutId, idleTimeoutId, observer, resolve) {
  57. timeout.clear(maxTimeoutId);
  58. timeout.clear(idleTimeoutId);
  59. timeout.set(resolve, LAZY_LOADING_TIMEOUT);
  60. const scriptURL = browser.runtime.getURL("lib/lazy/web-lazy-loader-after.js");
  61. const scriptAfterElement = document.createElement("script");
  62. scriptAfterElement.src = scriptURL;
  63. document.body.appendChild(scriptAfterElement);
  64. scriptAfterElement.onload = () => scriptAfterElement.remove();
  65. observer.disconnect();
  66. }
  67. })();