html-images-alt-minifier.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * Copyright 2010-2019 Gildas Lormeau
  3. * contact : gildas.lormeau <at> gmail.com
  4. *
  5. * This file is part of SingleFile.
  6. *
  7. * The code in this file is free software: you can redistribute it and/or
  8. * modify it under the terms of the GNU Affero General Public License
  9. * (GNU AGPL) as published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * The code in this file 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 GNU Affero
  15. * General Public License for more details.
  16. *
  17. * As additional permission under GNU AGPL version 3 section 7, you may
  18. * distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
  19. * AGPL normally required by section 4, provided you include this license
  20. * notice and a URL through which recipients can access the Corresponding
  21. * Source.
  22. */
  23. this.imagesAltMinifier = this.imagesAltMinifier || (() => {
  24. const EMPTY_IMAGE = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
  25. let srcsetParser;
  26. return {
  27. getInstance(...args) {
  28. [srcsetParser] = args;
  29. return {
  30. process(doc) {
  31. doc.querySelectorAll("picture").forEach(pictureElement => {
  32. const imgElement = pictureElement.querySelector("img");
  33. if (imgElement) {
  34. let srcData = getImgSrcData(imgElement);
  35. let { src, srcset } = srcData;
  36. if (!src) {
  37. const sources = Array.from(pictureElement.querySelectorAll("source")).reverse();
  38. const data = getSourceSrcData(Array.from(sources));
  39. src = data.src;
  40. if (!srcset) {
  41. srcset = data.srcset;
  42. }
  43. }
  44. setSrc({ src, srcset }, imgElement, pictureElement);
  45. }
  46. });
  47. doc.querySelectorAll(":not(picture) > img[srcset]").forEach(imgElement => setSrc(getImgSrcData(imgElement), imgElement));
  48. }
  49. };
  50. }
  51. };
  52. function getImgSrcData(imgElement) {
  53. let src = imgElement.getAttribute("src");
  54. if (src == EMPTY_IMAGE) {
  55. src = null;
  56. }
  57. let srcset = getSourceSrc(imgElement.getAttribute("srcset"));
  58. if (srcset == EMPTY_IMAGE) {
  59. srcset = null;
  60. }
  61. return { src, srcset };
  62. }
  63. function getSourceSrcData(sources) {
  64. let source = sources.find(source => source.src);
  65. let src = source && source.src;
  66. let srcset = source && source.srcset;
  67. if (!src) {
  68. source = sources.find(source => getSourceSrc(source.src));
  69. src = source && source.src;
  70. if (src == EMPTY_IMAGE) {
  71. src = null;
  72. }
  73. }
  74. if (!srcset) {
  75. source = sources.find(source => getSourceSrc(source.srcset));
  76. srcset = source && source.srcset;
  77. if (srcset == EMPTY_IMAGE) {
  78. srcset = null;
  79. }
  80. }
  81. return { src, srcset };
  82. }
  83. function setSrc(srcData, imgElement, pictureElement) {
  84. if (srcData.src) {
  85. imgElement.setAttribute("src", srcData.src);
  86. imgElement.setAttribute("srcset", "");
  87. imgElement.setAttribute("sizes", "");
  88. } else {
  89. imgElement.setAttribute("src", EMPTY_IMAGE);
  90. if (srcData.srcset) {
  91. imgElement.setAttribute("srcset", srcData.srcset);
  92. } else {
  93. imgElement.setAttribute("srcset", "");
  94. imgElement.setAttribute("sizes", "");
  95. }
  96. }
  97. if (pictureElement) {
  98. pictureElement.querySelectorAll("source").forEach(sourceElement => sourceElement.remove());
  99. }
  100. }
  101. function getSourceSrc(sourceSrcSet) {
  102. if (sourceSrcSet) {
  103. const srcset = srcsetParser.process(sourceSrcSet);
  104. return (srcset.find(srcset => srcset.url)).url;
  105. }
  106. }
  107. })();