image-exporter 0.0.1

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 (46) hide show
  1. package/.gitattributes +2 -0
  2. package/.prettierrc +5 -0
  3. package/LICENSE.md +201 -0
  4. package/README.md +3 -0
  5. package/dist/image-exporter.es.js +3807 -0
  6. package/dist/image-exporter.umd.js +3813 -0
  7. package/example/example.css +122 -0
  8. package/example/example.html +152 -0
  9. package/example/github.jpg +0 -0
  10. package/example/poll-h.svg +1 -0
  11. package/package.json +50 -0
  12. package/src/capture-images.ts +129 -0
  13. package/src/clean-up.ts +50 -0
  14. package/src/cors-proxy/index.ts +22 -0
  15. package/src/cors-proxy/proxy-css.ts +52 -0
  16. package/src/cors-proxy/proxy-images.ts +90 -0
  17. package/src/default-options.ts +58 -0
  18. package/src/download-images.ts +52 -0
  19. package/src/get-capture-element.test.html +21 -0
  20. package/src/get-capture-element.test.ts +36 -0
  21. package/src/get-capture-element.ts +175 -0
  22. package/src/get-options/get-input-options.test.html +217 -0
  23. package/src/get-options/get-input-options.test.ts +109 -0
  24. package/src/get-options/get-input-options.ts +40 -0
  25. package/src/get-options/get-item-options.ts +46 -0
  26. package/src/get-options/get-wrapper-options.test.html +33 -0
  27. package/src/get-options/get-wrapper-options.test.ts +109 -0
  28. package/src/get-options/get-wrapper-options.ts +84 -0
  29. package/src/get-options/index.ts +28 -0
  30. package/src/image-exporter.ts +108 -0
  31. package/src/index.ts +8 -0
  32. package/src/types/image.ts +2 -0
  33. package/src/types/index.ts +2 -0
  34. package/src/types/options.ts +69 -0
  35. package/src/utils/convert-to-slug.ts +15 -0
  36. package/src/utils/get-attribute-values.ts +68 -0
  37. package/src/utils/get-date-MMDDYY.ts +11 -0
  38. package/src/utils/ignore-items.ts +11 -0
  39. package/src/utils/index.ts +18 -0
  40. package/src/utils/is-valid-url.ts +20 -0
  41. package/src/utils/is-visible.ts +12 -0
  42. package/src/utils/parse-labels.ts +55 -0
  43. package/src/utils/push-to-window.ts +3 -0
  44. package/tests/index.html +88 -0
  45. package/tests/input-tests.html +169 -0
  46. package/vite.config.js +39 -0
@@ -0,0 +1,40 @@
1
+ import * as types from "../types";
2
+ import { pushToWindow } from "../utils/push-to-window";
3
+ import { optionSafetyCheck } from "./get-wrapper-options";
4
+
5
+ // Helper function to handle common logic
6
+ async function handleOptions(optionsType: any, key: string) {
7
+ const selector = optionsType[key].inputSelector;
8
+
9
+ const inputElement = document.querySelector(`[${selector}]`) as HTMLInputElement;
10
+ if (!inputElement) return;
11
+
12
+ if (inputElement.getAttribute("type") === "checkbox") {
13
+ optionsType[key].value = inputElement.checked;
14
+ return;
15
+ }
16
+
17
+ if (inputElement.value) {
18
+ const safeValue = optionSafetyCheck(key, inputElement.value);
19
+ if (safeValue === null) return;
20
+
21
+ optionsType[key].value = safeValue;
22
+ }
23
+ }
24
+
25
+ export function getInputOptions(options: types.Options): types.Options {
26
+ try {
27
+ // Use the helper function for both 'image' and 'zip' options
28
+ Promise.all(
29
+ Object.keys(options.image).map((key) => handleOptions(options.image, key))
30
+ );
31
+ Promise.all(Object.keys(options.zip).map((key) => handleOptions(options.zip, key)));
32
+
33
+ if (options.debug) pushToWindow("getInputOptionsDebug", options);
34
+
35
+ return options;
36
+ } catch (e) {
37
+ console.error("ImageExporter: Error in getUserOptions", e);
38
+ return options;
39
+ }
40
+ }
@@ -0,0 +1,46 @@
1
+ import * as types from "../types";
2
+ import { parseImageLabel } from "../utils";
3
+
4
+ /**
5
+ * Extracts and customizes settings for a specific element based on its attributes and additional criteria.
6
+ *
7
+ * This function creates a copy of the provided options object and then customizes it for an individual
8
+ * element. It checks for specific attributes on the element (defined in the 'attributesToCheck' parameter)
9
+ * and, if present, overwrites the corresponding properties in the options object with the attribute values.
10
+ * Additionally, it sets a 'slug' property based on the content of a specific child element or generates a
11
+ * unique name based on the index.
12
+ *
13
+ * @param {HTMLElement} element - The HTML element for which the settings are being determined.
14
+ * @param {Object} options - The base options object that provides default settings.
15
+ * @param {number} index - An index value, typically representing the element's position in a collection.
16
+ * @param {Object} attributesToCheck - An object mapping option keys to attribute names to be checked on the element.
17
+ * @returns {Object} An object containing the customized settings for the element.
18
+ *
19
+ */
20
+ export function getItemOptions(
21
+ element: HTMLElement,
22
+ options: types.Options,
23
+ index: number
24
+ ): types.ItemOptions {
25
+ let itemOptions: types.ItemOptions = {
26
+ ...options,
27
+ id: index,
28
+ userSlug: "",
29
+ slug: "",
30
+ fileName: "",
31
+ };
32
+
33
+ Object.keys(options.image).forEach((key) => {
34
+ const attributeValue = element.getAttribute(options.image[key].attributeSelector);
35
+ if (attributeValue !== null) {
36
+ console.log("Capture item option:", key, "=", attributeValue);
37
+ itemOptions.image[key].value = attributeValue;
38
+ }
39
+ });
40
+
41
+ itemOptions.id = index;
42
+ itemOptions.userSlug = element.querySelector(options.selectors.slug)?.textContent || "";
43
+ itemOptions.slug = parseImageLabel(itemOptions);
44
+
45
+ return itemOptions;
46
+ }
@@ -0,0 +1,33 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Tests</title>
7
+ </head>
8
+ <body>
9
+ <div
10
+ ie="wrapper"
11
+ ie-scale="2"
12
+ ie-quality="0.55"
13
+ ie-format="png"
14
+ ie-img-label-date="false"
15
+ ie-img-label-scale="false"
16
+ ie-zip-label="yay"
17
+ ie-zip-label-date="false"
18
+ ie-zip-label-scale="false"
19
+ ></div>
20
+ <div
21
+ test="wrapper"
22
+ test-scale="3"
23
+ test-quality="0.65"
24
+ test-format="png"
25
+ test-img-label-date="false"
26
+ test-img-label-scale="false"
27
+ test-zip-label="test"
28
+ test-zip-label-date="false"
29
+ test-zip-label-scale="false"
30
+ ></div>
31
+ <script src="../../dist/image-exporter.umd.js"></script>
32
+ </body>
33
+ </html>
@@ -0,0 +1,109 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
+ import puppeteer from "puppeteer";
3
+ import path from "path";
4
+ import * as types from "../types";
5
+ import { defaultOptions } from "../default-options";
6
+
7
+ describe("get-wrapper-options", () => {
8
+ let browser;
9
+ let page;
10
+
11
+ beforeAll(async () => {
12
+ // Setup for puppeteer with Vitest
13
+ browser = await puppeteer.launch();
14
+ page = await browser.newPage();
15
+ await page.goto(`file://${path.join(__dirname, "get-wrapper-options.test.html")}`);
16
+ });
17
+
18
+ afterAll(async () => {
19
+ // Teardown for puppeteer with Vitest
20
+ await browser.close();
21
+ });
22
+
23
+ it("standard attributes", async () => {
24
+ const result = await page.evaluate(() => {
25
+ const js = `const options = { downloadImages: false, debug: true };
26
+ const imageExporter = new ImageExporter(options);
27
+ const images = imageExporter.captureAll();`;
28
+ //insert at the end of the body
29
+ const script = document.createElement("script");
30
+ script.text = js;
31
+ document.body.appendChild(script);
32
+
33
+ return (window as any).getWrapperOptionsDebug;
34
+ });
35
+
36
+ // Assertions can then be made based on the result object
37
+ expect(result.image.scale.value).toBe(2);
38
+ expect(result.image.quality.value).toBe(0.55);
39
+ expect(result.image.format.value).toBe("png");
40
+ expect(result.image.dateInLabel.value).toBe(false);
41
+ expect(result.image.scaleInLabel.value).toBe(false);
42
+ expect(result.zip.label.value).toBe("yay");
43
+ expect(result.zip.dateInLabel.value).toBe(false);
44
+ expect(result.zip.scaleInLabel.value).toBe(false);
45
+ });
46
+
47
+ it("custom attributes", async () => {
48
+ await page.reload();
49
+ const result = await page.evaluate(() => {
50
+ const js = `const options = {
51
+ downloadImages: false,
52
+ selectors: {
53
+ wrapper: "[test='wrapper']",
54
+ capture: "[test='capture']",
55
+ trigger: "[test='trigger']",
56
+ slug: "[test='slug']",
57
+ ignore: "[test='ignore']",
58
+ },
59
+ image: {
60
+ scale: {
61
+ attributeSelector: "test-scale",
62
+ },
63
+ quality: {
64
+ attributeSelector: "test-quality",
65
+ },
66
+ format: {
67
+ attributeSelector: "test-format",
68
+ },
69
+ dateInLabel: {
70
+ attributeSelector: "test-img-label-date",
71
+ },
72
+ scaleInLabel: {
73
+ attributeSelector: "test-img-label-scale",
74
+ },
75
+ },
76
+ zip: {
77
+ label: {
78
+ attributeSelector: "test-zip-label",
79
+ },
80
+ dateInLabel: {
81
+ attributeSelector: "test-zip-label-date",
82
+ },
83
+ scaleInLabel: {
84
+ attributeSelector: "test-zip-label-scale",
85
+ },
86
+ },
87
+ debug: true,
88
+ };
89
+ const imageExporter = new ImageExporter(options);
90
+ const images = imageExporter.captureAll();`;
91
+ //insert at the end of the body
92
+ const script = document.createElement("script");
93
+ script.text = js;
94
+ document.body.appendChild(script);
95
+
96
+ return (window as any).getWrapperOptionsDebug;
97
+ });
98
+
99
+ // Assertions can then be made based on the result object
100
+ expect(result.image.scale.value).toBe(3);
101
+ expect(result.image.quality.value).toBe(0.65);
102
+ expect(result.image.format.value).toBe("png");
103
+ expect(result.image.dateInLabel.value).toBe(false);
104
+ expect(result.image.scaleInLabel.value).toBe(false);
105
+ expect(result.zip.label.value).toBe("test");
106
+ expect(result.zip.dateInLabel.value).toBe(false);
107
+ expect(result.zip.scaleInLabel.value).toBe(false);
108
+ });
109
+ });
@@ -0,0 +1,84 @@
1
+ import * as types from "../types";
2
+ import { pushToWindow } from "../utils/push-to-window";
3
+
4
+ /**
5
+ * Retrieves and updates the options based on the attributes of the wrapper element.
6
+ *
7
+ * This function queries the DOM for the wrapper element specified in the options.
8
+ * If the wrapper element is found, it iterates over the image settings and updates
9
+ * them with the values provided in the wrapper element's attributes.
10
+ *
11
+ * @param {types.Options} options - The initial settings object, which may contain default settings.
12
+ * @returns {types.Options} The updated settings object with values from the wrapper element.
13
+ */
14
+ export function getWrapperOptions(options: types.Options): types.Options {
15
+ try {
16
+ const wrapper = document.querySelector(options.selectors.wrapper) as HTMLElement;
17
+
18
+ if (!wrapper) {
19
+ new Error("Wrapper element not found");
20
+ return options;
21
+ }
22
+
23
+ // For each image setting, see if value is provided in the wrapper element
24
+ // If so, update that setting with the new value
25
+ Object.keys(options.image).forEach((key) => {
26
+ const attrValue = wrapper.getAttribute(options.image[key].attributeSelector);
27
+ if (attrValue !== null) {
28
+ const safeValue = optionSafetyCheck(key, attrValue);
29
+ if (safeValue === null) return;
30
+ options.image[key].value = safeValue;
31
+ }
32
+ });
33
+
34
+ Object.keys(options.zip).forEach((key) => {
35
+ const attrValue = wrapper.getAttribute(options.zip[key].attributeSelector);
36
+ if (attrValue !== null) {
37
+ const safeValue = optionSafetyCheck(key, attrValue);
38
+ if (safeValue === null) return;
39
+ options.zip[key].value = safeValue;
40
+ }
41
+ });
42
+
43
+ if (options.debug) pushToWindow("getWrapperOptionsDebug", options);
44
+
45
+ return options;
46
+ } catch (e) {
47
+ console.error("ImageExporter: Error in getWrapperOptions", e);
48
+ return options;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Validates and converts the provided value based on the key.
54
+ */
55
+ export function optionSafetyCheck(key: string, value: any): any {
56
+ // Handle checkbox inputs
57
+ if (value === "on") return true;
58
+ if (value === "off") return false;
59
+
60
+ // Handle number inputs
61
+ if (key === "scale" || key === "quality") {
62
+ if (typeof value === "number") return value;
63
+ value = value.trim();
64
+ value = parseFloat(value);
65
+ if (isNaN(value)) return null;
66
+
67
+ return value;
68
+ }
69
+ // Handle boolean inputs
70
+ if (key === "dateInLabel" || key === "scaleInLabel") {
71
+ if (typeof value === "boolean") return value;
72
+ value = value.trim();
73
+
74
+ return value === "true";
75
+ }
76
+ // Handle image format
77
+ if (key === "format") {
78
+ value = value.trim();
79
+ if (value === "jpg" || value === "png") return value;
80
+
81
+ return null;
82
+ }
83
+ return value;
84
+ }
@@ -0,0 +1,28 @@
1
+ import { getWrapperOptions } from "./get-wrapper-options";
2
+ import { getInputOptions } from "./get-input-options";
3
+ import { getItemOptions } from "./get-item-options";
4
+ import * as types from "../types";
5
+
6
+ /**
7
+ * Asynchronously determines and finalizes settings by aggregating them from multiple sources.
8
+ *
9
+ * This function works through a sequence of steps to build a comprehensive settings object. Initially,
10
+ * it displays a loading message. It then sequentially updates the settings based on the attributes of a
11
+ * wrapper element and user inputs, respectively. Each step potentially overwrites the settings from the
12
+ * previous steps, allowing for a layered approach to setting configuration.
13
+ *
14
+ * @param {Object} options - The initial settings object, which may contain default settings.
15
+ * @returns {Promise<Object>} A promise that resolves to the fully determined settings object.
16
+ *
17
+ */
18
+ function determineOptions(options: types.Options): types.Options {
19
+ // If settings exist on the wrapper, overwrite the default options
20
+ options = getWrapperOptions(options);
21
+
22
+ // If settings exist via user input, overwrite the default/wrapper options
23
+ options = getInputOptions(options);
24
+
25
+ return options;
26
+ }
27
+
28
+ export { getItemOptions, determineOptions };
@@ -0,0 +1,108 @@
1
+ import * as types from "./types";
2
+ import { determineOptions, getItemOptions } from "./get-options";
3
+ import { findMultiScaleElements, getCaptureElements } from "./get-capture-element";
4
+ import { captureImage, captureImages } from "./capture-images";
5
+ import { downloadImages } from "./download-images";
6
+ import { runCorsProxy } from "./cors-proxy";
7
+ import { ignoreFilter } from "./utils/ignore-items";
8
+ import { defaultOptions } from "./default-options";
9
+ import { cleanUp } from "./clean-up";
10
+
11
+ // TODO: ignored nodes not working
12
+
13
+ export class ImageExporter {
14
+ options: types.Options;
15
+
16
+ constructor(userOptions = {}) {
17
+ this.options = { ...defaultOptions, ...userOptions };
18
+ }
19
+
20
+ /**
21
+ * Captures images from all elements specified in the options.
22
+ * If downloadImages is set to true, the images will be downloaded.
23
+ *
24
+ * @returns {types.Image[]} An array of captured images.
25
+ */
26
+ async captureAll(): Promise<types.Image[]> {
27
+ console.log(this.options);
28
+ this.options = determineOptions(this.options);
29
+
30
+ const captureElements = getCaptureElements(this.options);
31
+
32
+ const images = await captureImages(this.options, captureElements);
33
+
34
+ if (this.options.downloadImages) downloadImages(images, this.options);
35
+
36
+ cleanUp(this.options, captureElements);
37
+
38
+ return images;
39
+ }
40
+
41
+ /**
42
+ * Captures an image from a single element.
43
+ * If downloadImages is set to true, the image will be downloaded.
44
+ *
45
+ * If multiscale elements are found,
46
+ * the element will be cloned and captured at each scale.
47
+ */
48
+ async captureElement(element: HTMLElement): Promise<types.Image | types.Image[]> {
49
+ this.options = determineOptions(this.options);
50
+
51
+ await runCorsProxy(this.options);
52
+
53
+ const ignoredNodes = ignoreFilter(this.options);
54
+
55
+ const multiScale = findMultiScaleElements(this.options);
56
+
57
+ if (multiScale) {
58
+ const elements = Array.from(
59
+ document.querySelectorAll(
60
+ "[ie-clone], [ie-clone-source]"
61
+ ) as NodeListOf<HTMLElement>
62
+ );
63
+ const images = await captureImages(this.options, elements);
64
+
65
+ if (this.options.downloadImages) downloadImages(images, this.options);
66
+
67
+ cleanUp(this.options, elements);
68
+
69
+ return images;
70
+ }
71
+
72
+ const image = await captureImage(
73
+ element,
74
+ getItemOptions(element, this.options, 1),
75
+ ignoredNodes
76
+ );
77
+
78
+ if (this.options.downloadImages) downloadImages([image], this.options);
79
+
80
+ cleanUp(this.options, [element]);
81
+
82
+ return image;
83
+ }
84
+
85
+ /**
86
+ * Adds a click event listener to the trigger element.
87
+ * If no element is provided, the captureAll method will be run on click.
88
+ * If an element is provided, provided element will be captured on click.
89
+ */
90
+ addTrigger(triggerSelector: string, element: HTMLElement | null = null) {
91
+ const triggerElement = document.querySelector(triggerSelector);
92
+ if (!triggerElement) throw new Error("Trigger element not found");
93
+
94
+ if (!element) {
95
+ // add event listener to trigger element. on click, run captureAll
96
+ triggerElement.addEventListener("click", () => {
97
+ this.captureAll();
98
+ });
99
+ console.log("Listener added to trigger element");
100
+ } else {
101
+ // add event listener to trigger element. on click, run captureElement
102
+ triggerElement.addEventListener("click", () => {
103
+ this.captureElement(element);
104
+ });
105
+ console.log("Listener added to trigger element");
106
+ }
107
+ }
108
+ }
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { ImageExporter } from "./image-exporter";
2
+
3
+ // Pushes imageExporter to window object so it can be called in Webflow
4
+ if (typeof window !== "undefined") {
5
+ (window as any).ImageExporter = ImageExporter;
6
+ }
7
+
8
+ export { ImageExporter };
@@ -0,0 +1,2 @@
1
+ // First is dataURL, second is fileName
2
+ export type Image = [string, string];
@@ -0,0 +1,2 @@
1
+ export * from "./options";
2
+ export * from "./image";
@@ -0,0 +1,69 @@
1
+ export interface Options {
2
+ corsProxyBaseUrl: string;
3
+ downloadImages: boolean;
4
+ selectors: Selectors;
5
+ image: ImageOptions;
6
+ zip: ZipOptions;
7
+ debug: boolean;
8
+ }
9
+
10
+ export interface Selectors {
11
+ wrapper: string;
12
+ capture: string;
13
+ trigger: string;
14
+ slug: string;
15
+ ignore: string;
16
+ }
17
+
18
+ export interface ImageOptions {
19
+ scale: NumberSetting;
20
+ quality: NumberSetting;
21
+ format: ImageSetting;
22
+ dateInLabel: BooleanSetting;
23
+ scaleInLabel: BooleanSetting;
24
+ }
25
+
26
+ export interface ZipOptions {
27
+ label: {
28
+ value: string;
29
+ attributeSelector: string;
30
+ inputSelector: string;
31
+ };
32
+ dateInLabel: {
33
+ value: boolean;
34
+ attributeSelector: string;
35
+ inputSelector: string;
36
+ };
37
+ scaleInLabel: {
38
+ value: boolean;
39
+ attributeSelector: string;
40
+ inputSelector: string;
41
+ };
42
+ }
43
+
44
+ export interface ItemOptions extends Options {
45
+ // Options +
46
+ id: number;
47
+ userSlug: string;
48
+ slug: string;
49
+ fileName: string;
50
+ }
51
+
52
+ export interface Setting {
53
+ attributeSelector: string;
54
+ inputSelector: string;
55
+ value: string | number | boolean | "jpg" | "png";
56
+ }
57
+
58
+ export interface StringSetting extends Setting {
59
+ value: string;
60
+ }
61
+ export interface NumberSetting extends Setting {
62
+ value: number;
63
+ }
64
+ export interface BooleanSetting extends Setting {
65
+ value: boolean;
66
+ }
67
+ export interface ImageSetting extends Setting {
68
+ value: "jpg" | "png";
69
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Converts a given string to a URL-friendly slug.
3
+ *
4
+ * @param input - The string to be converted to a slug.
5
+ * @returns The input string transformed into a slug format.
6
+ */
7
+ export function convertToSlug(input: string) {
8
+ if (!input) {
9
+ return null;
10
+ }
11
+ input = input.toLowerCase();
12
+ input = input.replace(/[^a-z0-9_@ -]/g, "");
13
+ input = input.replace(/\s+/g, "-");
14
+ return input;
15
+ }
@@ -0,0 +1,68 @@
1
+ import * as types from "../types";
2
+
3
+ /**
4
+ * Option determination order:
5
+ * 1. User input
6
+ * 2. Item attribute
7
+ * 3. Wrapper attribute
8
+ * 4. Default
9
+ *
10
+ * Meaning wrapper overwrites default, item overwrites wrapper, and user input overwrites all.
11
+ */
12
+
13
+ /**
14
+ * Checks if the user provided a value via attribute on an input element.
15
+ * If the user provided a value, it returns the value. Otherwise, it returns null.
16
+ */
17
+ export function getUserInputValue(imageSetting: types.Setting): string | null {
18
+ try {
19
+ const inputElement = document.querySelector(
20
+ imageSetting.attributeSelector
21
+ ) as HTMLInputElement | null;
22
+
23
+ if (inputElement) {
24
+ return inputElement.value;
25
+ } else return null;
26
+ } catch (e) {
27
+ console.error("ImageExporter: Error in getUserInputValue", e);
28
+ return null;
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Checks if the user provided a value via attribute on the wrapper element.
34
+ * If the user provided a value, it returns the value. Otherwise, it returns null.
35
+ */
36
+ export function getWrapperValue(
37
+ options: types.Options,
38
+ attribute: string,
39
+ wrapperSelector: string
40
+ ): string | null {
41
+ try {
42
+ console.log("📣 - wrapperSelector:", wrapperSelector);
43
+ const wrapperElement = document.querySelector(wrapperSelector);
44
+ console.log(wrapperElement ? wrapperElement.getAttribute(attribute) : null);
45
+ return wrapperElement ? wrapperElement.getAttribute(attribute) : null;
46
+ } catch (e) {
47
+ console.error("ImageExporter: Error in getWrapperValue", e);
48
+ return null;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Checks if the user provided a value via attribute on an item element.
54
+ * If the user provided a value, it returns the value. Otherwise, it returns null.
55
+ */
56
+ export function getItemValue(options: types.Options, attribute, element): string | null {
57
+ try {
58
+ const itemValue = element.querySelector(attribute);
59
+ if (itemValue) {
60
+ return itemValue;
61
+ } else {
62
+ return null;
63
+ }
64
+ } catch (e) {
65
+ console.error("ImageExporter: Error in getItemValue", e);
66
+ return null;
67
+ }
68
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ *
3
+ * @returns {string} Current date formatted as MMDDYY
4
+ */
5
+ export function getDateMMDDYY() {
6
+ return (
7
+ String(new Date().getMonth() + 1).padStart(2, "0") +
8
+ String(new Date().getDate()).padStart(2, "0") +
9
+ new Date().getFullYear().toString().slice(-2)
10
+ );
11
+ }
@@ -0,0 +1,11 @@
1
+ import * as types from "../types";
2
+
3
+ // Return a function that checks if a node does not match the ignore selector
4
+ export function ignoreFilter(options: types.Options) {
5
+ return (node: HTMLElement) => {
6
+ if (!(node instanceof HTMLElement)) {
7
+ throw new Error("The provided node is not an HTMLElement");
8
+ }
9
+ return !node.matches(options.selectors.ignore);
10
+ };
11
+ }
@@ -0,0 +1,18 @@
1
+ import { getItemValue, getUserInputValue, getWrapperValue } from "./get-attribute-values";
2
+ import { convertToSlug } from "./convert-to-slug";
3
+ import { isVisible } from "./is-visible";
4
+ import { getDateMMDDYY } from "./get-date-MMDDYY";
5
+ import { parseImageLabel, parseZipLabel } from "./parse-labels";
6
+ import { isValidUrl } from "./is-valid-url";
7
+
8
+ export {
9
+ isValidUrl,
10
+ getItemValue,
11
+ getWrapperValue,
12
+ getUserInputValue as getUserValue,
13
+ isVisible,
14
+ convertToSlug,
15
+ getDateMMDDYY,
16
+ parseZipLabel,
17
+ parseImageLabel,
18
+ };
@@ -0,0 +1,20 @@
1
+ // Helper function to check if a URL is valid and not a data URL
2
+ export function isValidUrl(string: string): boolean {
3
+ try {
4
+ const url = new URL(string);
5
+
6
+ // Check if the URL is a data URL
7
+ if (url.protocol === "data:") {
8
+ return false;
9
+ }
10
+
11
+ // Optionally, check for HTTP and HTTPS protocols specifically
12
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
13
+ return false;
14
+ }
15
+
16
+ return true;
17
+ } catch (_) {
18
+ return false;
19
+ }
20
+ }