image-exporter 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +133 -81
  2. package/dist/capture/capture-element.d.ts +8 -0
  3. package/dist/capture/capture-element.d.ts.map +1 -0
  4. package/dist/capture/determine-total-elements.d.ts +9 -0
  5. package/dist/capture/determine-total-elements.d.ts.map +1 -0
  6. package/dist/capture/download-images.d.ts +10 -0
  7. package/dist/capture/download-images.d.ts.map +1 -0
  8. package/dist/capture/get-image-options.d.ts +15 -0
  9. package/dist/capture/get-image-options.d.ts.map +1 -0
  10. package/dist/capture/handle-filenames.d.ts +11 -0
  11. package/dist/capture/handle-filenames.d.ts.map +1 -0
  12. package/dist/capture/index.d.ts +10 -0
  13. package/dist/capture/index.d.ts.map +1 -0
  14. package/dist/capture/remove-hidden-elements.d.ts +2 -0
  15. package/dist/capture/remove-hidden-elements.d.ts.map +1 -0
  16. package/dist/config.d.ts +4 -0
  17. package/dist/config.d.ts.map +1 -0
  18. package/dist/cors-proxy/cleanup.d.ts +7 -0
  19. package/dist/cors-proxy/cleanup.d.ts.map +1 -0
  20. package/dist/cors-proxy/index.d.ts +7 -0
  21. package/dist/cors-proxy/index.d.ts.map +1 -0
  22. package/dist/cors-proxy/is-valid-url.d.ts +7 -0
  23. package/dist/cors-proxy/is-valid-url.d.ts.map +1 -0
  24. package/dist/cors-proxy/proxy-css.d.ts +9 -0
  25. package/dist/cors-proxy/proxy-css.d.ts.map +1 -0
  26. package/dist/cors-proxy/proxy-images.d.ts +9 -0
  27. package/dist/cors-proxy/proxy-images.d.ts.map +1 -0
  28. package/dist/cors-proxy/run.d.ts +9 -0
  29. package/dist/cors-proxy/run.d.ts.map +1 -0
  30. package/dist/index.browser.js +40 -0
  31. package/dist/index.browser.js.map +84 -0
  32. package/dist/index.cjs +14878 -0
  33. package/dist/index.cjs.map +84 -0
  34. package/dist/index.d.ts +5 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +14869 -0
  37. package/dist/index.js.map +83 -0
  38. package/dist/logger.d.ts +26 -0
  39. package/dist/logger.d.ts.map +1 -0
  40. package/package.json +19 -14
  41. package/.gitattributes +0 -2
  42. package/.prettierrc +0 -5
  43. package/bun.lockb +0 -0
  44. package/dist/image-exporter.es.js +0 -4508
  45. package/dist/image-exporter.umd.js +0 -4514
  46. package/src/capture/capture-element.ts +0 -79
  47. package/src/capture/determine-total-elements.ts +0 -40
  48. package/src/capture/download-images.ts +0 -69
  49. package/src/capture/get-image-options.ts +0 -207
  50. package/src/capture/handle-filenames.ts +0 -54
  51. package/src/capture/index.ts +0 -102
  52. package/src/capture/remove-hidden-elements.ts +0 -19
  53. package/src/config.ts +0 -19
  54. package/src/cors-proxy/cleanup.ts +0 -43
  55. package/src/cors-proxy/index.ts +0 -7
  56. package/src/cors-proxy/is-valid-url.ts +0 -22
  57. package/src/cors-proxy/proxy-css.ts +0 -48
  58. package/src/cors-proxy/proxy-images.ts +0 -34
  59. package/src/cors-proxy/run.ts +0 -26
  60. package/src/index.ts +0 -14
  61. package/src/logger.ts +0 -71
  62. package/src/types.d.ts +0 -51
  63. package/vite.config.js +0 -35
@@ -1,79 +0,0 @@
1
- import { Image, ParsedImageOptions } from "../types";
2
- import { handleFileNames } from "./handle-filenames";
3
- import * as modernScreenshot from "modern-screenshot";
4
-
5
- /**
6
- * captureElement
7
- *
8
- * Captures an image from an HTML element and returns it.
9
- */
10
- export async function captureElement(
11
- element: HTMLElement,
12
- imageOptions: ParsedImageOptions,
13
- filenames: string[]
14
- ): Promise<Image> {
15
- try {
16
- let dataURL = "";
17
- // Final settings for capturing images.
18
- let htmlToImageOptions: modernScreenshot.Options = {
19
- // Ensure quality is a number
20
- quality: imageOptions.quality,
21
- // Ensure scale is a number
22
- scale: imageOptions.scale,
23
- // Ignores elements with data-ignore-capture attribute
24
- filter: filter,
25
- };
26
-
27
- // If element has no background and is a JPG, default to white background
28
- const styles = getComputedStyle(element);
29
- const backgroundColor = styles.backgroundColor;
30
- const backgroundImage = styles.backgroundImage;
31
- let cleanUpBackground = false;
32
- if (
33
- backgroundColor === "rgba(0, 0, 0, 0)" &&
34
- backgroundImage === "none" &&
35
- imageOptions.format === "jpg"
36
- ) {
37
- element.style.backgroundColor = "#FFFFFF";
38
- cleanUpBackground = true;
39
- }
40
-
41
- // Captures image based on format
42
- switch (imageOptions.format) {
43
- case "jpg":
44
- dataURL = await modernScreenshot.domToJpeg(element, htmlToImageOptions);
45
- break;
46
- case "png":
47
- dataURL = await modernScreenshot.domToPng(element, htmlToImageOptions);
48
- break;
49
- case "svg":
50
- dataURL = await modernScreenshot.domToSvg(element, htmlToImageOptions);
51
- break;
52
- case "webp":
53
- dataURL = await modernScreenshot.domToWebp(element, htmlToImageOptions);
54
- break;
55
- }
56
-
57
- if (cleanUpBackground) {
58
- element.style.backgroundColor = "";
59
- element.style.backgroundImage = "";
60
- }
61
-
62
- return {
63
- dataURL,
64
- fileName: handleFileNames(imageOptions, filenames),
65
- };
66
- } catch (error) {
67
- console.error("ImageExporter: Error in captureImage", error);
68
- return { dataURL: "", fileName: "" };
69
- }
70
- }
71
-
72
- const filter = (node: Node) => {
73
- // Check if the node is an HTMLElement
74
- if (node instanceof HTMLElement) {
75
- return !node.hasAttribute("data-ignore-capture");
76
- }
77
- // If not an HTMLElement, return true to include the node
78
- return true;
79
- };
@@ -1,40 +0,0 @@
1
- /**
2
- * determineTotalElements
3
- *
4
- * Just used for progress logging to show progress of all element captures.
5
- *
6
- * This emcompasses multi-scale captures unlike elements.length.
7
- */
8
- export async function determineTotalElements(
9
- elements: HTMLElement[] | NodeListOf<HTMLElement>
10
- ): Promise<number> {
11
- try {
12
- let totalElements = 0;
13
-
14
- for (const element of elements) {
15
- const scaleAsString = element.dataset.scale;
16
- if (!scaleAsString) continue;
17
-
18
- if (scaleAsString.includes(",")) {
19
- const scales = scaleAsString
20
- .trim()
21
- .split(",")
22
- .map((scale) => parseFloat(scale));
23
-
24
- if (scales.some((scale) => isNaN(scale))) continue;
25
- totalElements += scales.length;
26
- } else {
27
- const scaleAsNumber = parseFloat(scaleAsString.trim());
28
- if (isNaN(scaleAsNumber)) {
29
- continue;
30
- } else {
31
- totalElements++;
32
- }
33
- }
34
- }
35
-
36
- return totalElements;
37
- } catch (error) {
38
- return 1;
39
- }
40
- }
@@ -1,69 +0,0 @@
1
- import { Config, Image, Label } from "../types";
2
- import download from "downloadjs";
3
- import JSZip from "jszip";
4
-
5
- /**
6
- * downloadImages
7
- *
8
- * If one image is provided, it will be downloaded as a file.
9
- *
10
- * If multiple images are provided, they will be zipped and downloaded as a file.
11
- */
12
- export async function downloadImages(images: Image[], config: Config) {
13
- if (images.length === 1) {
14
- const image = images[0];
15
-
16
- await download(image.dataURL, image.fileName);
17
- } else if (images.length > 1) {
18
- const imagesBlob = await zipUpImages(images);
19
- if (imagesBlob) await download(imagesBlob, parseLabel(config));
20
- }
21
- }
22
-
23
- /**
24
- * zipUpImages
25
- *
26
- * Zips up the images and returns the zip file as a Blob.
27
- */
28
- async function zipUpImages(images: Image[]): Promise<Blob | undefined> {
29
- const zip = new JSZip();
30
-
31
- try {
32
- // Loop through each image tuple and add to the zip
33
- images.forEach((image) => {
34
- // Extract the content from the data URL
35
- const content = image.dataURL.split(",")[1]; // Assumes base64 encoding
36
- zip.file(image.fileName, content, { base64: true });
37
- });
38
- } catch (error) {
39
- console.error("Image Exporter - Error adding images to ZIP:", error);
40
- return;
41
- }
42
-
43
- try {
44
- // Generate the ZIP file
45
- const imagesBlob = await zip.generateAsync({ type: "blob" });
46
- return imagesBlob;
47
- } catch (error) {
48
- console.error("Image Exporter - Error generating ZIP:", error);
49
- return;
50
- }
51
- }
52
-
53
- /**
54
- * parseLabel
55
- *
56
- * Parses the zip label from the config and returns a valid label.
57
- */
58
- function parseLabel(config: Config): Label {
59
- try {
60
- // Replace spaces with dashes
61
- let label = config.zipLabel;
62
- label = label.replace(/\s+/g, "-");
63
- // Allowed characters: a-z, A-Z, 0-9, -, _
64
- return label.replace(/[^a-zA-Z0-9-_]/g, "");
65
- } catch (error) {
66
- console.error(error);
67
- return "images";
68
- }
69
- }
@@ -1,207 +0,0 @@
1
- import {
2
- Quality,
3
- Label,
4
- Config,
5
- Format,
6
- ImageOptions,
7
- Scale,
8
- IncludeScaleInLabel,
9
- } from "../types";
10
-
11
- /**
12
- * Retrieves the image options for the given element or configuration.
13
- *
14
- * Data attributes:
15
- * - data-label: string
16
- * - data-format: "jpg" | "png" | "svg"
17
- * - data-scale: number | number[]
18
- * - data-quality: number
19
- * - data-include-scale-in-label: boolean
20
- *
21
- * @returns {Promise<ImageOptions>} - The parsed image options.
22
- */
23
- export async function getImageOptions(
24
- element: HTMLElement,
25
- config: Config
26
- ): Promise<ImageOptions> {
27
- return {
28
- label: parseLabel(),
29
- format: parseFormat(),
30
- scale: parseScale(),
31
- quality: parseQuality(),
32
- includeScaleInLabel: parseIncludeScaleInLabel(),
33
- };
34
- /**
35
- * # Helper functions
36
- *
37
- * Format:
38
- *
39
- * 1. Attempt to get value from dataset
40
- * 2. If found, process to correct data type and return it
41
- * 3. If not found, return value from config
42
- *
43
- * If dataset value is invalid, returns default value.
44
- */
45
-
46
- /**
47
- * Parses the label property from the element's dataset.
48
- * If the property is not present, it returns the default value from the config.
49
- * If the property is present, it removes any characters that are not a-z, A-Z, 0-9, -, or _ and returns the cleaned up label.
50
- * If an error occurs, it returns the default value from the config.
51
- */
52
- function parseLabel(): Label {
53
- try {
54
- const label = element.dataset.label || config.defaultImageLabel;
55
-
56
- if (label === "") return config.defaultImageLabel;
57
-
58
- // Check if the label ends with '@#x'
59
- const endsWithSpecial = /@\d+x$/.test(label);
60
- let cleanedLabel = label;
61
-
62
- // Allowed characters: a-z, A-Z, 0-9, -, _
63
- // Remove all other characters using regex, except '@Nx' at the end
64
- const regex = /[^a-zA-Z0-9-_]/g;
65
- if (endsWithSpecial) {
66
- const match = label.match(/@\d+x$/);
67
- if (!match) return config.defaultImageLabel;
68
- cleanedLabel = label.slice(0, -match[0].length).replace(regex, "") + match[0];
69
- } else {
70
- cleanedLabel = label.replace(regex, "");
71
- }
72
-
73
- return cleanedLabel;
74
- } catch (error) {
75
- console.error(error);
76
- return config.defaultImageLabel;
77
- }
78
- }
79
-
80
- /**
81
- * Parses the format property from the element's dataset.
82
- * If the property is not present, it returns the default value from the config.
83
- * If the property is present, it checks if it's a valid format (jpg, png, or svg) and returns it.
84
- * If the value is not valid, it throws an error and returns the default value from the config.
85
- */
86
- function parseFormat(): Format {
87
- try {
88
- let format = element.dataset.format || config.format;
89
- format = format.trim().toLowerCase();
90
- if (format === "jpg" || format === "png" || format === "svg" || format === "webp") {
91
- return format;
92
- } else {
93
- throw new Error(
94
- `ImageExporter: provided format is not valid.
95
- Provided: ${format}
96
- Element: ${element}
97
- Accepted values: jpg, png, svg,
98
- Defaulting to: ${config.format}`
99
- );
100
- }
101
- } catch (error) {
102
- console.error(error);
103
- return config.format;
104
- }
105
- }
106
-
107
- /**
108
- * Parses the scale property from the element's dataset.
109
- * If the property is not present, it returns the default value from the config.
110
- * If the property is present, it checks if it's a valid number or a comma-separated list of numbers and returns it.
111
- * If the value is not valid, it throws an error and returns the default value from the config.
112
- */
113
- function parseScale(): Scale {
114
- try {
115
- const scaleAsString = element.dataset.scale;
116
- if (!scaleAsString) return config.scale;
117
- if (scaleAsString.includes(",")) {
118
- const scales = scaleAsString
119
- .trim()
120
- .split(",")
121
- .map((scale) => parseFloat(scale));
122
- if (scales.some((scale) => isNaN(scale))) {
123
- throw new Error(
124
- `ImageExporter: provided scale is not valid.
125
- Provided: ${scaleAsString}
126
- Element: ${element}
127
- Accepted values: number or csv numbers e.g. (1,2)
128
- Defaulting to ${config.scale}`
129
- );
130
- }
131
- return scales;
132
- } else {
133
- const scaleAsNumber = parseFloat(scaleAsString.trim());
134
- if (isNaN(scaleAsNumber)) {
135
- throw new Error(
136
- `ImageExporter: provided scale is not valid.
137
- Provided: ${scaleAsString}
138
- Element: ${element}
139
- Accepted values: number or csv numbers e.g. (1,2)
140
- Defaulting to: ${config.scale}`
141
- );
142
- }
143
- return scaleAsNumber;
144
- }
145
- } catch (error) {
146
- console.error(error);
147
- return config.scale;
148
- }
149
- }
150
-
151
- /**
152
- * Parses the quality property from the element's dataset.
153
- * If the property is not present, it returns the default value from the config.
154
- * If the property is present, it checks if it's a valid number and returns it.
155
- * If the value is not valid, it throws an error and returns the default value from the config.
156
- */
157
- function parseQuality(): Quality {
158
- try {
159
- const qualityAsString = element.dataset.quality;
160
- if (!qualityAsString) return config.quality;
161
- const qualityAsNumber = parseFloat(qualityAsString.trim());
162
- if (isNaN(qualityAsNumber)) {
163
- throw new Error(
164
- `ImageExporter: provided quality is not valid.
165
- Provided: ${qualityAsString}
166
- Element: ${element}
167
- Accepted values: number
168
- Defaulting to: ${config.quality}`
169
- );
170
- }
171
- return qualityAsNumber;
172
- } catch (error) {
173
- console.error(error);
174
- return config.quality;
175
- }
176
- }
177
-
178
- /**
179
- * Parses the includeScaleInLabel property from the element's dataset.
180
- * If the property is not present, it returns the default value from the config.
181
- * If the property is present, it checks if it's a valid value (true or false) and returns it.
182
- * If the value is not valid, it throws an error and returns the default value from the config.
183
- */
184
- function parseIncludeScaleInLabel(): IncludeScaleInLabel {
185
- try {
186
- let includeScaleInLabel = element.dataset.includeScaleInLabel;
187
- if (!includeScaleInLabel) return config.includeScaleInLabel;
188
-
189
- includeScaleInLabel = includeScaleInLabel.trim();
190
-
191
- if (includeScaleInLabel === "true" || includeScaleInLabel === "false") {
192
- return includeScaleInLabel === "true";
193
- } else {
194
- throw new Error(
195
- `ImageExporter: provided includeScaleInLabel is not valid.
196
- Provided: ${includeScaleInLabel}
197
- Element: ${element}
198
- Accepted values: true or false
199
- Defaulting to: ${config.includeScaleInLabel}`
200
- );
201
- }
202
- } catch (error) {
203
- console.error(error);
204
- return config.includeScaleInLabel;
205
- }
206
- }
207
- }
@@ -1,54 +0,0 @@
1
- import { ImageOptions, Label } from "../types";
2
-
3
- /**
4
- * Handles the generation of unique filenames based on a proposed filename and an array of existing filenames.
5
- *
6
- * If the proposed filename is unique, it is added to the filenames array and returned as-is.
7
- * If the proposed filename is not unique, the function will check if it already ends with a "-n" pattern.
8
- * If it does, the function will increment the number until a unique filename is found.
9
- * If it doesn't, the function will start with "-2" and increment the number until a unique filename is found.
10
- */
11
- export function handleFileNames(imageOptions: ImageOptions, filenames: string[]): Label {
12
- // Finish altering filenames before checking for uniqueness
13
- let proposedFilename = imageOptions.label;
14
- // Add scale to filename if includeScaleInLabel is true
15
- if (imageOptions.includeScaleInLabel) proposedFilename += `_@${imageOptions.scale}x`;
16
- // Add format to filename last
17
- const extension = `.${imageOptions.format}`;
18
- proposedFilename += extension;
19
-
20
- // If filename is unique, add it to array and return as-is
21
- if (!filenames.includes(proposedFilename)) {
22
- filenames.push(proposedFilename);
23
- return proposedFilename;
24
- }
25
-
26
- // Check if filename already ends with -n pattern
27
- const numberPattern = /-(\d+)$/;
28
- const match = proposedFilename.match(numberPattern);
29
-
30
- if (match) {
31
- // File ends with -n, increment the number until we find a unique name
32
- const baseFilename = proposedFilename.replace(numberPattern, "");
33
- let counter = parseInt(match[1], 10);
34
-
35
- while (filenames.includes(`${baseFilename}-${counter}${extension}`)) {
36
- counter++;
37
- }
38
-
39
- const newFilename = `${baseFilename}-${counter}${extension}`;
40
- filenames.push(newFilename);
41
- return newFilename;
42
- } else {
43
- // File doesn't end with -n, start with -2 and increment if needed
44
- const baseFilename = proposedFilename.replace(extension, "");
45
- let counter = 2;
46
- while (filenames.includes(`${baseFilename}-${counter}${extension}`)) {
47
- counter++;
48
- }
49
-
50
- const newFilename = `${baseFilename}-${counter}${extension}`;
51
- filenames.push(newFilename);
52
- return newFilename;
53
- }
54
- }
@@ -1,102 +0,0 @@
1
- import { captureElement } from "./capture-element";
2
- import { downloadImages } from "./download-images";
3
- import { corsProxy } from "../cors-proxy";
4
- import { Config, Image, ParsedImageOptions } from "../types";
5
- import { getImageOptions } from "./get-image-options";
6
- import { defaultConfig } from "../config";
7
- import { removeHiddenElements } from "./remove-hidden-elements";
8
- import { log } from "../logger";
9
- import { determineTotalElements } from "./determine-total-elements";
10
-
11
- export let windowLogging = true;
12
- export let loggingLevel = "none";
13
-
14
- /**
15
- * capture
16
- *
17
- * Captures images from HTML elements and returns them or downloads them.
18
- */
19
- export async function capture(
20
- elements: HTMLElement[] | NodeListOf<HTMLElement> | HTMLElement,
21
- userConfig: Partial<Config> = defaultConfig
22
- ): Promise<Image[] | null> {
23
- log.group.open("image-exporter");
24
- try {
25
- /* --------------------------------- Config --------------------------------- */
26
- const config = { ...defaultConfig, ...userConfig };
27
- windowLogging = config.enableWindowLogging;
28
- loggingLevel = config.loggingLevel;
29
- log.verbose("config", config);
30
-
31
- /** If the user provided a single element, convert it to an array */
32
- if (elements instanceof HTMLElement) elements = [elements];
33
- const originalLength = elements.length;
34
- elements = removeHiddenElements(elements);
35
-
36
- const totalElements = await determineTotalElements(elements);
37
-
38
- if (originalLength !== elements.length)
39
- log.verbose(
40
- "Skipping capture of hidden elements: ",
41
- originalLength - elements.length
42
- );
43
- log.verbose("Element to capture", elements.length);
44
-
45
- /* ------------------------------- CORS proxy ------------------------------- */
46
- if (userConfig.corsProxyBaseUrl) await corsProxy.run(config, elements);
47
-
48
- /* --------------------------------- Capture -------------------------------- */
49
- let images: Image[] = [];
50
- let filenames: string[] = [];
51
- let imageNumber = 1;
52
-
53
- for (const element of elements) {
54
- const imageOptions = await getImageOptions(element, config);
55
- log.verbose("Image options", imageOptions);
56
-
57
- if (imageOptions.scale instanceof Array) {
58
- /* --------------------------- Multi-scale capture -------------------------- */
59
- log.verbose("Multi-scale capture");
60
-
61
- imageOptions.includeScaleInLabel = true;
62
-
63
- for (const scale of imageOptions.scale) {
64
- log.progress(imageNumber++, totalElements);
65
- const image = await captureElement(
66
- element,
67
- { ...imageOptions, scale: scale } as ParsedImageOptions,
68
- filenames
69
- );
70
-
71
- images.push(image);
72
- }
73
- } else if (typeof imageOptions.scale === "number") {
74
- log.progress(imageNumber++, totalElements);
75
- /* -------------------------- Single scale capture -------------------------- */
76
- log.verbose("Single-scale capture");
77
-
78
- const image = await captureElement(
79
- element,
80
- imageOptions as ParsedImageOptions,
81
- filenames
82
- );
83
-
84
- images.push(image);
85
- }
86
- }
87
-
88
- /* -------------------------------- Download -------------------------------- */
89
- if (userConfig.downloadImages) await downloadImages(images, config);
90
-
91
- /* --------------------------- Clean up CORS proxy -------------------------- */
92
- if (userConfig.corsProxyBaseUrl) await corsProxy.cleanUp();
93
-
94
- /** Return images optionally */
95
- return images;
96
- } catch (error) {
97
- log.error(error);
98
- return null;
99
- } finally {
100
- log.group.close();
101
- }
102
- }
@@ -1,19 +0,0 @@
1
- export function removeHiddenElements(
2
- elements: HTMLElement[] | NodeListOf<HTMLElement>
3
- ): HTMLElement[] {
4
- elements = Array.from(elements);
5
- return elements.filter((element) => isVisible(element));
6
- }
7
-
8
- function isVisible(element: HTMLElement): boolean {
9
- const computedStyle = window.getComputedStyle(element);
10
-
11
- return (
12
- element.offsetParent !== null &&
13
- element.style.display !== "none" &&
14
- computedStyle.visibility === "visible" &&
15
- computedStyle.opacity !== "0" &&
16
- computedStyle.width !== "0" &&
17
- computedStyle.height !== "0"
18
- );
19
- }
package/src/config.ts DELETED
@@ -1,19 +0,0 @@
1
- import { Config, ImageOptions } from "./types";
2
-
3
- export const defaultImageOptions: ImageOptions = {
4
- label: "image",
5
- format: "jpg",
6
- scale: 1,
7
- quality: 1,
8
- includeScaleInLabel: false,
9
- };
10
-
11
- export const defaultConfig: Config = {
12
- ...defaultImageOptions,
13
- downloadImages: true,
14
- defaultImageLabel: "image",
15
- zipLabel: "images",
16
- corsProxyBaseUrl: "",
17
- enableWindowLogging: true,
18
- loggingLevel: "none",
19
- };
@@ -1,43 +0,0 @@
1
- import { log } from "../logger";
2
- /**
3
- * cleanUpCorsProxy
4
- *
5
- * Restores the CSS and images to their original state.
6
- */
7
- export async function cleanUpCorsProxy() {
8
- await restoreCSS();
9
- await restoreImages();
10
- }
11
-
12
- async function restoreCSS() {
13
- const styleElements = document.querySelectorAll("style[original-link-element]");
14
-
15
- for (let styleElement of styleElements) {
16
- const originalLinkElementHTML = decodeURIComponent(
17
- styleElement.getAttribute("original-link-element")!
18
- );
19
-
20
- // Create a temporary container to parse the HTML string
21
- const tempContainer = document.createElement("div");
22
- tempContainer.innerHTML = originalLinkElementHTML;
23
-
24
- // Insert the parsed HTML before the style element
25
- styleElement.parentNode!.insertBefore(tempContainer.firstChild!, styleElement);
26
-
27
- styleElement.remove();
28
- log.verbose("Restored: ", originalLinkElementHTML);
29
- }
30
- }
31
-
32
- async function restoreImages() {
33
- const imageElements = document.querySelectorAll(
34
- "img[original-src]"
35
- ) as NodeListOf<HTMLImageElement>;
36
-
37
- for (let imageElement of imageElements) {
38
- const originalSrc = imageElement.getAttribute("original-src")!;
39
- imageElement.src = originalSrc;
40
- imageElement.removeAttribute("original-src");
41
- log.verbose("Restored: ", originalSrc);
42
- }
43
- }
@@ -1,7 +0,0 @@
1
- import { runCorsProxy } from "./run";
2
- import { cleanUpCorsProxy } from "./cleanup";
3
-
4
- export const corsProxy = {
5
- run: runCorsProxy,
6
- cleanUp: cleanUpCorsProxy,
7
- };
@@ -1,22 +0,0 @@
1
- /**
2
- * isValidUrl
3
- *
4
- * Checks if a string is a valid external URL.
5
- */
6
- export function isValidUrl(string: string): boolean {
7
- try {
8
- const url = new URL(string);
9
-
10
- if (url.protocol === "data:") {
11
- return false;
12
- }
13
-
14
- if (url.protocol !== "http:" && url.protocol !== "https:") {
15
- return false;
16
- }
17
-
18
- return true;
19
- } catch (_) {
20
- return false;
21
- }
22
- }