UNPKG

@medyll/idae-be

Version:

A modern, lightweight, and extensible DOM manipulation library built with TypeScript. Designed for precise element targeting and manipulation using a callback-based approach. Features include advanced DOM traversal, event handling, style management, attri

355 lines (354 loc) 11.9 kB
import { AttrHandler } from './modules/attrs.js'; import { StylesHandler } from './modules/styles.js'; import { BeUtils } from './utils.js'; import { DataHandler } from './modules/data.js'; import { EventsHandler } from './modules/events.js'; import { ClassesHandler } from './modules/classes.js'; import { DomHandler } from './modules/dom.js'; import { PositionHandler } from './modules/position.js'; import { WalkHandler } from './modules/walk.js'; import { TextHandler } from './modules/text.js'; import { TimersHandler } from './modules/timers.js'; import { HttpHandler } from './modules/http.js'; export class Be { inputNode; isWhat; // timerOut = null; timerInterval = null; // styles styles; styleHandler; setStyle; getStyle; unsetStyle; // dataSet data; dataHandler; setData; getData; deleteData; getKey; // attributes attrs; attrHandler; setAttr; getAttr; deleteAttr; // position position; positionHandler; clonePosition; overlapPosition; snapTo; // dom dom; domHandler; update; append; prepend; insert; afterBegin; afterEnd; beforeBegin; beforeEnd; remove; replace; clear; normalize; wrap; unwrap; // text text; textHandler; appendText; prependText; updateText; replaceText; removeText; clearText; normalizeText; wrapText; // events events; eventHandler; on; off; fire; // classes classes; classesHandler; addClass; removeClass; toggleClass; replaceClass; // walk walk; walkHandler; up; next; without; previous; siblings; children; closest; lastChild; firstChild; find; findAll; // timers timers; timerHandler; timeout; interval; clearTimeout; clearInterval; // http http; httpHandler; updateHttp; insertHttp; constructor(input) { if (input instanceof Be) { return input; } this.inputNode = Be.getNode(input); this.isWhat = typeof this.inputNode === 'string' ? 'qy' : Array.isArray(this.inputNode) ? 'array' : 'element'; // styles this.styleHandler = new StylesHandler(this); this.styles = this.handle(this.styleHandler); this.attach(StylesHandler, 'Style'); // dataSet this.dataHandler = new DataHandler(this); this.data = this.handle(this.dataHandler); this.attach(DataHandler, 'Data'); // attributes this.attrHandler = new AttrHandler(this); this.attrs = this.handle(this.attrHandler); this.attach(AttrHandler, 'Attr'); // position this.positionHandler = new PositionHandler(this); this.position = this.handle(this.positionHandler); this.attach(PositionHandler); // text this.textHandler = new TextHandler(this); this.text = this.handle(this.textHandler); this.attach(TextHandler, 'Text'); // dom and handle this.domHandler = new DomHandler(this); this.dom = this.handle(this.domHandler); this.attach(DomHandler); // events this.eventHandler = new EventsHandler(this); this.events = this.handle(this.eventHandler); this.attach(EventsHandler); // classes this.classesHandler = new ClassesHandler(this); this.classes = this.handle(this.classesHandler); this.attach(ClassesHandler, 'Class'); // walk this.walkHandler = new WalkHandler(this); this.walk = this.handle(this.walkHandler); this.attach(WalkHandler); // timers this.timerHandler = new TimersHandler(this); this.timers = this.handle(this.timerHandler); this.attach(TimersHandler); // http this.httpHandler = new HttpHandler(this); this.http = this.handle(this.httpHandler); this.attach(HttpHandler, 'Http'); } /** * Normalizes the input to ensure `node` is always an HTMLElement or an array of HTMLElements. * @param input - The input to normalize (string, HTMLElement, or array of HTMLElements). * @returns A valid HTMLElement or an array of HTMLElements. */ static getNode(input) { if (typeof input === 'string') { // Si `input` est une chaîne, sélectionnez les éléments correspondants const elements = Array.from(document.querySelectorAll(input)); return elements.length === 1 ? elements[0] : elements; } else if (input instanceof HTMLElement) { // Si `input` est un seul élément DOM, retournez-le return input; } else if (Array.isArray(input)) { // Si `input` est un tableau, filtrez pour ne garder que les éléments DOM valides return input.filter((n) => n instanceof HTMLElement); } throw new Error('Invalid input: must be a string, HTMLElement, or an array of HTMLElements.'); } static elem(node) { return new Be(node); } static createBe(tagOrHtml, options) { const test = BeUtils.isHTML(tagOrHtml, { returnHTMLelement: true }); const testIsTag = test.isHtml && !tagOrHtml.includes(' ') && tagOrHtml.length < 15; let ret; if (test.isHtml && test.beElem) { ret = test.beElem; } else if (testIsTag) { const el = document.createElement(tagOrHtml); ret = be(el); } else { const el = document.createElement('div'); ret = be(el); } if (options?.style) ret.setStyle(options.style); if (options?.attributes) ret.setAttr(options.attributes); if (options?.className) ret.addClass(options.className); return ret; } /** * Creates a new `Be` element based on the provided string or HTMLElement. * If the input is an HTMLElement, it creates a new `Be` element and sets it as the child of the provided element. * If the input is a string, it checks if it is a valid HTML string and creates a new `Be` element based on it. * If the input is neither a string nor an HTMLElement, it creates a new `Be` element with the default tag. * * @param str - The string or HTMLElement to create the `Be` element from. * @param options - Additional options for creating the `Be` element. * @returns The created `Be` element. */ static toBe(str, options = {}) { const { tag = 'div' } = options; let beElem; if (str instanceof HTMLElement) { beElem = be(str); } else if (typeof str === 'string') { const trimmed = str.trim(); if (trimmed.startsWith('<') && trimmed.endsWith('>') && trimmed.includes('</')) { // Parse as HTML const parser = new DOMParser(); const doc = parser.parseFromString(trimmed, 'text/html'); const element = doc.body.firstElementChild || document.createElement(tag); beElem = createBe(tag); beElem.update(element.innerHTML); // Apply styles const styles = element.getAttribute('style'); if (styles) { const styleObj = Object.fromEntries(styles .split(';') .filter((style) => style.trim()) .map((style) => { const [key, value] = style.split(':').map((s) => s.trim()); return [key, value]; })); beElem.setStyle(styleObj); } // Apply other attributes Array.from(element.attributes).forEach((attr) => { if (attr.name !== 'style') { beElem.setAttr(attr.name, attr.value); } }); } else { // Create a Be element with the default tag and set text content beElem = be(document.createElement(tag)); beElem.update(str); } } else { // Handle non-string, non-HTMLElement input beElem = createBe(tag); } return beElem; } fetch(options) { return fetch(options.url, { method: options.method || 'GET', body: options.data ? JSON.stringify(options.data) : undefined, headers: options.headers || {} }).then((response) => response.json()); } /** * Iterates over nodes based on the type of `this.isWhat` and applies a callback function to each node. * * @param callback - A function to be executed for each node. Receives the current node as an argument. * @param firstChild - Optional. If `true`, stops further iteration after the first child is processed. * * The behavior of the method depends on the value of `this.isWhat`: * - `'element'`: Applies the callback to a single HTMLElement (`this.inputNode`). * - `'array'`: Iterates over an array of HTMLElements (`this.inputNode`) and applies the callback to each. * - `'qy'`: Selects elements using a query selector string (`this.inputNode`) and applies the callback to each. */ eachNode(callback, firstChild) { switch (this.isWhat) { case 'element': BeUtils.applyCallback(this.inputNode, callback); break; case 'array': this.inputNode.forEach((lo) => { BeUtils.applyCallback(lo, callback); if (firstChild) return; }); break; case 'qy': document.querySelectorAll(this.inputNode).forEach((el) => { callback(el); if (firstChild) return; }); break; } } get html() { return this.isWhat === 'element' ? this.inputNode.innerHTML : null; } get node() { switch (this.isWhat) { case 'element': return this.inputNode; case 'array': return Array.from(this.inputNode); case 'qy': return Array.from(document.querySelectorAll(this.inputNode)); } } attach(Handler, suffix = '') { const fromMethods = Handler.methods || []; fromMethods.forEach((method) => { const handler = new Handler(this); const methodName = suffix ? method + suffix : method; if (!(method in handler)) { console.error(`Method ${method} not found in ${Handler.name}`, handler); } else if (methodName in this) { if (!handler) { console.error(`Handler ${Handler.name} not found`, handler); } this[methodName] = (...args) => { return handler[method].apply(handler, args); }; } }); } handle(cl) { return cl.handle.bind(cl); } } /** set exports as root */ export const be = Be.elem; export const toBe = Be.toBe; export const beId = (id) => Be.elem(`#${id}`); export const createBe = Be.createBe; // be('.test').dom.update('content', () => {}); // should return be('.test').dom. // relies on dom.handle // should return be('.test') /* be('.test').dom({ update: { content: '<p>Updated</p>', callback: () => {} }, append: { content: '<p>Appended</p>', callback: () => {} } }); */