mirror of
https://github.com/cupcakearmy/svelte-cloudinary.git
synced 2024-12-22 16:06:25 +00:00
110 lines
3.7 KiB
TypeScript
110 lines
3.7 KiB
TypeScript
import { Cloudinary, Configuration, Transformation } from 'cloudinary-core'
|
|
|
|
export type ElementOrString = HTMLElement | string
|
|
export type Size = { width: number; height: number }
|
|
export type BindType = ElementOrString | true
|
|
export type BindObject = BindType | { width?: BindType; height?: BindType }
|
|
|
|
export type InitParameters = { debug?: boolean }
|
|
export type ImageParameters = {
|
|
src: string
|
|
options?: Transformation | Transformation.Options
|
|
bind?: BindObject
|
|
lazy?: boolean | IntersectionObserverInit
|
|
step?: number
|
|
}
|
|
|
|
let cl: Cloudinary | null = null
|
|
let DEBUG: boolean = false
|
|
|
|
function log(...msg: any[]) {
|
|
if (DEBUG) console.debug(...msg)
|
|
}
|
|
|
|
export function initialize(cloudinary: Configuration.Options, options: InitParameters = {}) {
|
|
DEBUG = options.debug || false
|
|
cl = Cloudinary.new(cloudinary)
|
|
}
|
|
|
|
const defaults: Transformation | Transformation.Options = {
|
|
fetchFormat: 'auto',
|
|
quality: 'auto',
|
|
}
|
|
|
|
function calculateApproxRealSize(size: string, step: number): number {
|
|
const withRatio = (parseInt(size) * window.devicePixelRatio) | 0
|
|
const approx = withRatio - (withRatio % step) + step
|
|
log(`Size\t withRation=${withRatio} approx=${approx} step=${step}`)
|
|
return approx
|
|
}
|
|
|
|
function getSizeOfElement(el: HTMLElement, step: number): Size {
|
|
const styles = window.getComputedStyle(el)
|
|
log('GetSizeOfElement', el, `width=${styles.width} height=${styles.height}`)
|
|
return {
|
|
width: calculateApproxRealSize(styles.width, step),
|
|
height: calculateApproxRealSize(styles.height, step),
|
|
}
|
|
}
|
|
|
|
function getSizeOfElementOrSelector(node: ElementOrString, elOrString: ElementOrString, step: number): Size {
|
|
if (typeof elOrString === 'string') {
|
|
const search = typeof node === 'string' ? window.document.querySelector(node) : node
|
|
if (!search) throw new Error('Could not find element: ' + node)
|
|
const closest = search.closest<HTMLElement>(elOrString)
|
|
if (closest) return getSizeOfElement(closest, step)
|
|
else throw new Error('Could not find element: ' + elOrString)
|
|
} else {
|
|
return getSizeOfElement(elOrString, step)
|
|
}
|
|
}
|
|
|
|
export function image(node: HTMLImageElement, parameters: ImageParameters) {
|
|
if (!parameters || !parameters.src) throw new Error('No url provided for cloudinary')
|
|
|
|
let { src, options, bind, lazy, step } = parameters
|
|
log('Image Declared', parameters)
|
|
options = options ?? {}
|
|
step = step ?? 200
|
|
lazy = lazy ?? true
|
|
|
|
if (!cl) throw new Error('Cloudinary not initialized')
|
|
if (!src) throw new Error('Src must be set in use:image')
|
|
|
|
if (bind) {
|
|
if (bind === true) {
|
|
bind = node
|
|
}
|
|
if (!options.crop) options.crop = 'fill'
|
|
|
|
if (bind instanceof Element) Object.assign(options, getSizeOfElement(bind, step))
|
|
else if (typeof bind === 'string') {
|
|
Object.assign(options, getSizeOfElementOrSelector(node, bind, step))
|
|
} else if (typeof bind === 'object') {
|
|
if (bind.width) {
|
|
options.width = getSizeOfElementOrSelector(node, bind.width === true ? node : bind.width, step).width
|
|
}
|
|
if (bind.height) {
|
|
options.height = getSizeOfElementOrSelector(node, bind.height === true ? node : bind.height, step).height
|
|
}
|
|
}
|
|
}
|
|
|
|
const all: Transformation | Transformation.Options = { ...defaults, ...options }
|
|
const attrs: any = cl.imageTag(parameters.src, all).attributes()
|
|
log('Attributes', attrs)
|
|
const replace = () => (node.src = attrs.src)
|
|
|
|
if (lazy && typeof IntersectionObserver !== 'undefined') {
|
|
const options: IntersectionObserverInit = lazy === true ? { rootMargin: '25%', threshold: 0 } : lazy
|
|
new IntersectionObserver((entries, observer) => {
|
|
if (entries[0].isIntersecting) {
|
|
observer.disconnect()
|
|
replace()
|
|
}
|
|
}, options).observe(node)
|
|
} else {
|
|
replace()
|
|
}
|
|
}
|