UNPKG

image-exporter

Version:

Easily download one or more DOM elements as images

208 lines (195 loc) 6.9 kB
import { Quality, Label, Config, Format, ImageOptions, Scale, IncludeScaleInLabel, } from "../types"; /** * Retrieves the image options for the given element or configuration. * * Data attributes: * - data-label: string * - data-format: "jpg" | "png" | "svg" * - data-scale: number | number[] * - data-quality: number * - data-include-scale-in-label: boolean * * @returns {Promise<ImageOptions>} - The parsed image options. */ export async function getImageOptions( element: HTMLElement, config: Config ): Promise<ImageOptions> { return { label: parseLabel(), format: parseFormat(), scale: parseScale(), quality: parseQuality(), includeScaleInLabel: parseIncludeScaleInLabel(), }; /** * # Helper functions * * Format: * * 1. Attempt to get value from dataset * 2. If found, process to correct data type and return it * 3. If not found, return value from config * * If dataset value is invalid, returns default value. */ /** * Parses the label property from the element's dataset. * If the property is not present, it returns the default value from the config. * 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. * If an error occurs, it returns the default value from the config. */ function parseLabel(): Label { try { const label = element.dataset.label || config.defaultImageLabel; if (label === "") return config.defaultImageLabel; // Check if the label ends with '@#x' const endsWithSpecial = /@\d+x$/.test(label); let cleanedLabel = label; // Allowed characters: a-z, A-Z, 0-9, -, _ // Remove all other characters using regex, except '@Nx' at the end const regex = /[^a-zA-Z0-9-_]/g; if (endsWithSpecial) { const match = label.match(/@\d+x$/); if (!match) return config.defaultImageLabel; cleanedLabel = label.slice(0, -match[0].length).replace(regex, "") + match[0]; } else { cleanedLabel = label.replace(regex, ""); } return cleanedLabel; } catch (error) { console.error(error); return config.defaultImageLabel; } } /** * Parses the format property from the element's dataset. * If the property is not present, it returns the default value from the config. * If the property is present, it checks if it's a valid format (jpg, png, or svg) and returns it. * If the value is not valid, it throws an error and returns the default value from the config. */ function parseFormat(): Format { try { let format = element.dataset.format || config.format; format = format.trim().toLowerCase(); if (format === "jpg" || format === "png" || format === "svg" || format === "webp") { return format; } else { throw new Error( `ImageExporter: provided format is not valid. Provided: ${format} Element: ${element} Accepted values: jpg, png, svg, Defaulting to: ${config.format}` ); } } catch (error) { console.error(error); return config.format; } } /** * Parses the scale property from the element's dataset. * If the property is not present, it returns the default value from the config. * If the property is present, it checks if it's a valid number or a comma-separated list of numbers and returns it. * If the value is not valid, it throws an error and returns the default value from the config. */ function parseScale(): Scale { try { const scaleAsString = element.dataset.scale; if (!scaleAsString) return config.scale; if (scaleAsString.includes(",")) { const scales = scaleAsString .trim() .split(",") .map((scale) => parseFloat(scale)); if (scales.some((scale) => isNaN(scale))) { throw new Error( `ImageExporter: provided scale is not valid. Provided: ${scaleAsString} Element: ${element} Accepted values: number or csv numbers e.g. (1,2) Defaulting to ${config.scale}` ); } return scales; } else { const scaleAsNumber = parseFloat(scaleAsString.trim()); if (isNaN(scaleAsNumber)) { throw new Error( `ImageExporter: provided scale is not valid. Provided: ${scaleAsString} Element: ${element} Accepted values: number or csv numbers e.g. (1,2) Defaulting to: ${config.scale}` ); } return scaleAsNumber; } } catch (error) { console.error(error); return config.scale; } } /** * Parses the quality property from the element's dataset. * If the property is not present, it returns the default value from the config. * If the property is present, it checks if it's a valid number and returns it. * If the value is not valid, it throws an error and returns the default value from the config. */ function parseQuality(): Quality { try { const qualityAsString = element.dataset.quality; if (!qualityAsString) return config.quality; const qualityAsNumber = parseFloat(qualityAsString.trim()); if (isNaN(qualityAsNumber)) { throw new Error( `ImageExporter: provided quality is not valid. Provided: ${qualityAsString} Element: ${element} Accepted values: number Defaulting to: ${config.quality}` ); } return qualityAsNumber; } catch (error) { console.error(error); return config.quality; } } /** * Parses the includeScaleInLabel property from the element's dataset. * If the property is not present, it returns the default value from the config. * If the property is present, it checks if it's a valid value (true or false) and returns it. * If the value is not valid, it throws an error and returns the default value from the config. */ function parseIncludeScaleInLabel(): IncludeScaleInLabel { try { let includeScaleInLabel = element.dataset.includeScaleInLabel; if (!includeScaleInLabel) return config.includeScaleInLabel; includeScaleInLabel = includeScaleInLabel.trim(); if (includeScaleInLabel === "true" || includeScaleInLabel === "false") { return includeScaleInLabel === "true"; } else { throw new Error( `ImageExporter: provided includeScaleInLabel is not valid. Provided: ${includeScaleInLabel} Element: ${element} Accepted values: true or false Defaulting to: ${config.includeScaleInLabel}` ); } } catch (error) { console.error(error); return config.includeScaleInLabel; } } }