single-file.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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. /* global window */
  24. this.singlefile.lib.SingleFile = this.singlefile.lib.SingleFile || (() => {
  25. const singlefile = this.singlefile;
  26. const crypto = window.crypto;
  27. const fetch = window.fetch;
  28. const Blob = window.Blob;
  29. const FileReader = window.FileReader;
  30. const TextDecoder = window.TextDecoder;
  31. const TextEncoder = window.TextEncoder;
  32. const modules = {
  33. helper: singlefile.lib.helper,
  34. srcsetParser: singlefile.lib.vendor.srcsetParser,
  35. cssMinifier: singlefile.lib.vendor.cssMinifier,
  36. htmlMinifier: singlefile.lib.modules.htmlMinifier,
  37. serializer: singlefile.lib.modules.serializer,
  38. fontsMinifier: singlefile.lib.modules.fontsMinifier,
  39. fontsAltMinifier: singlefile.lib.modules.fontsAltMinifier,
  40. cssRulesMinifier: singlefile.lib.modules.cssRulesMinifier,
  41. matchedRules: singlefile.lib.modules.matchedRules,
  42. mediasAltMinifier: singlefile.lib.modules.mediasAltMinifier,
  43. imagesAltMinifier: singlefile.lib.modules.imagesAltMinifier
  44. };
  45. const util = {
  46. getResourceContent,
  47. digestText
  48. };
  49. const SingleFile = singlefile.lib.core.getClass(singlefile.lib.util.getInstance(modules, util), singlefile.lib.vendor.cssTree);
  50. const fetchResource = (singlefile.lib.fetch.content.resources && singlefile.lib.fetch.content.resources.fetch) || fetch;
  51. return {
  52. getClass: () => SingleFile
  53. };
  54. async function getResourceContent(resourceURL) {
  55. const resourceContent = await fetchResource(resourceURL);
  56. const buffer = await resourceContent.arrayBuffer();
  57. return {
  58. getUrl() {
  59. return resourceContent.url || resourceURL;
  60. },
  61. getContentType() {
  62. return resourceContent.headers && resourceContent.headers.get("content-type");
  63. },
  64. getStatusCode() {
  65. return resourceContent.status;
  66. },
  67. getSize() {
  68. return buffer.byteLength;
  69. },
  70. getText(charset) {
  71. return new TextDecoder(charset).decode(buffer);
  72. },
  73. async getDataUri(contentType) {
  74. const reader = new FileReader();
  75. reader.readAsDataURL(new Blob([buffer], { type: contentType || this.getContentType() }));
  76. return new Promise((resolve, reject) => {
  77. reader.addEventListener("load", () => resolve(reader.result), false);
  78. reader.addEventListener("error", reject, false);
  79. });
  80. }
  81. };
  82. }
  83. async function digestText(algo, text) {
  84. const hash = await crypto.subtle.digest(algo, new TextEncoder("utf-8").encode(text));
  85. return hex(hash);
  86. }
  87. // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest
  88. function hex(buffer) {
  89. const hexCodes = [];
  90. const view = new DataView(buffer);
  91. for (let i = 0; i < view.byteLength; i += 4) {
  92. const value = view.getUint32(i);
  93. const stringValue = value.toString(16);
  94. const padding = "00000000";
  95. const paddedValue = (padding + stringValue).slice(-padding.length);
  96. hexCodes.push(paddedValue);
  97. }
  98. return hexCodes.join("");
  99. }
  100. })();