UNPKG

flyonui

Version:

The easiest, free and open-source Tailwind CSS component library with semantic classes.

211 lines (158 loc) 6.17 kB
/* * HSCopyMarkup * @version: 3.2.2 * @author: Preline Labs Ltd. * @license: Licensed under MIT and Preline UI Fair Use License (https://preline.co/docs/license.html) * Copyright 2024 Preline Labs Ltd. */ import { dispatch } from '../../utils' import { ICopyMarkup, ICopyMarkupOptions } from './interfaces' import HSBasePlugin from '../base-plugin' import { ICollectionItem } from '../../interfaces' class HSCopyMarkup extends HSBasePlugin<ICopyMarkupOptions> implements ICopyMarkup { private readonly targetSelector: string | null private readonly wrapperSelector: string | null private readonly limit: number | null private target: HTMLElement | null private wrapper: HTMLElement | null private items: HTMLElement[] | null private count = 0 private onElementClickListener: () => void private onDeleteItemButtonClickListener: () => void constructor(el: HTMLElement, options?: ICopyMarkupOptions) { super(el, options) const data = el.getAttribute('data-copy-markup') const dataOptions: ICopyMarkupOptions = data ? JSON.parse(data) : {} const concatOptions = { ...dataOptions, ...options } this.targetSelector = concatOptions?.targetSelector || null this.wrapperSelector = concatOptions?.wrapperSelector || null this.limit = concatOptions?.limit || null this.items = [] if (this.targetSelector) this.init() } private elementClick() { this.copy() } private deleteItemButtonClick(item: HTMLElement) { this.delete(item) } private init() { this.createCollection(window.$hsCopyMarkupCollection, this) this.onElementClickListener = () => this.elementClick() this.setTarget() this.setWrapper() this.addPredefinedItems() this.el.addEventListener('click', this.onElementClickListener) } private copy() { if (this.limit && this.items.length >= this.limit) return false if (this.el.hasAttribute('disabled')) this.el.setAttribute('disabled', '') const copiedElement = this.target.cloneNode(true) as HTMLElement const newId = `${this.target.id}-${this.count++}` copiedElement.setAttribute('id', newId) this.addToItems(copiedElement) if (this.limit && this.items.length >= this.limit) { this.el.setAttribute('disabled', 'disabled') } this.fireEvent('copy', copiedElement) dispatch('copy.copyMarkup', copiedElement, copiedElement) } private addPredefinedItems() { Array.from(this.wrapper.children) .filter((el: HTMLElement) => !el.classList.contains('[--ignore-for-count]')) .forEach((el: HTMLElement) => { this.addToItems(el) }) if (this.limit && this.items.length >= this.limit) { this.el.setAttribute('disabled', 'disabled') } } // Updated in FlyonUI private setTarget() { const target: HTMLElement = typeof this.targetSelector === 'string' ? (document.querySelector(this.targetSelector).cloneNode(true) as HTMLElement) : ((this.targetSelector as HTMLElement).cloneNode(true) as HTMLElement) this.target = target } private setWrapper() { this.wrapper = typeof this.wrapperSelector === 'string' ? document.querySelector(this.wrapperSelector) : this.wrapperSelector } private addToItems(item: HTMLElement) { const deleteItemButton = item.querySelector('[data-copy-markup-delete-item]') if (this.wrapper) this.wrapper.append(item) else this.el.before(item) if (deleteItemButton) { this.onDeleteItemButtonClickListener = () => this.deleteItemButtonClick(item) deleteItemButton.addEventListener('click', this.onDeleteItemButtonClickListener) } this.items.push(item) } // Public methods // Updated in FlyonUI public delete(target: HTMLElement) { if (target) { const index = this.items.indexOf(target) if (index !== -1) this.items.splice(index, 1) target.remove() this.fireEvent('delete', target) dispatch('delete.copyMarkup', target, target) if (this.limit && this.items.length < this.limit) { this.el.removeAttribute('disabled') } } } public destroy() { const deleteItemButtons = this.wrapper.querySelectorAll('[data-copy-markup-delete-item]') this.el.removeEventListener('click', this.onElementClickListener) if (deleteItemButtons.length) { deleteItemButtons.forEach(el => el.removeEventListener('click', this.onDeleteItemButtonClickListener)) } this.el.removeAttribute('disabled') this.target = null this.wrapper = null this.items = null window.$hsCopyMarkupCollection = window.$hsCopyMarkupCollection.filter(({ element }) => element.el !== this.el) } // Static method static getInstance(target: HTMLElement | string, isInstance?: boolean) { const elInCollection = window.$hsCopyMarkupCollection.find( el => el.element.el === (typeof target === 'string' ? document.querySelector(target) : target) ) return elInCollection ? (isInstance ? elInCollection : elInCollection.element) : null } static autoInit() { if (!window.$hsCopyMarkupCollection) window.$hsCopyMarkupCollection = [] if (window.$hsCopyMarkupCollection) { window.$hsCopyMarkupCollection = window.$hsCopyMarkupCollection.filter(({ element }) => document.contains(element.el) ) } document.querySelectorAll('[data-copy-markup]:not(.--prevent-on-load-init)').forEach((el: HTMLElement) => { if (!window.$hsCopyMarkupCollection.find(elC => (elC?.element?.el as HTMLElement) === el)) { const data = el.getAttribute('data-copy-markup') const options: ICopyMarkupOptions = data ? JSON.parse(data) : {} new HSCopyMarkup(el, options) } }) } } declare global { interface Window { HSCopyMarkup: Function $hsCopyMarkupCollection: ICollectionItem<HSCopyMarkup>[] } } window.addEventListener('load', () => { HSCopyMarkup.autoInit() // Uncomment for debug // console.log('Copy markup collection:', window.$hsCopyMarkupCollection); }) if (typeof window !== 'undefined') { window.HSCopyMarkup = HSCopyMarkup } export default HSCopyMarkup