UNPKG

preline

Version:

Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.

236 lines (181 loc) 5.99 kB
/* * HSCopyMarkup * @version: 3.1.0 * @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 "../copy-markup/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 onElementClickListener: () => void; private onDeleteItemButtonClickListener: () => void; constructor(el: HTMLElement, options?: ICopyMarkupOptions) { super(el, options); const data = el.getAttribute("data-hs-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; this.addToItems(copiedElement); if (this.limit && this.items.length >= this.limit) { this.el.setAttribute("disabled", "disabled"); } this.fireEvent("copy", copiedElement); dispatch("copy.hs.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"); } } 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); target.removeAttribute("id"); 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-hs-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 public delete(target: HTMLElement) { const index = this.items.indexOf(target); if (index !== -1) this.items.splice(index, 1); target.remove(); if (this.limit && this.items.length < this.limit) { this.el.removeAttribute("disabled"); } this.fireEvent("delete", target); dispatch("delete.hs.copyMarkup", target, target); } public destroy() { const deleteItemButtons = this.wrapper.querySelectorAll( "[data-hs-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-hs-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-hs-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;