UNPKG

@apicart/js-utils

Version:

A small set of useful utilities for easier development

186 lines (150 loc) 4.21 kB
import { Loops, Objects } from '.'; class Dom { public addClass(element: Element, classes: string|string[]): Dom { if (typeof classes === 'string') { classes = classes.split(' '); } Loops.forEach(classes, (newClass: string) => { if (!element.classList.contains(newClass)) { element.className += ' ' + newClass; } }); element.className = element.className.trim(); return this; } public findParent(element: Element, selector: string): Element|null { let parent = null; /* eslint-disable-next-line no-cond-assign */ while (element = element.parentElement) { if (this.matches(element, selector)) { parent = element; break; } } return parent; } public matches(element: any, selector: string): boolean { const elementPrototype = Element.prototype; if (elementPrototype.matches) { return element.matches(selector); } else if (elementPrototype.msMatchesSelector) { return element.msMatchesSelector(selector); } return false; } /* eslint-disable @typescript-eslint/no-this-alias, max-nested-callbacks */ public on(eventTypes: string|string[], selectors: string|string[], callback: Function): this { const self = this; if (typeof eventTypes === 'string') { eventTypes = eventTypes.split(' '); } if (typeof selectors === 'string') { selectors = selectors.split(','); } Loops.forEach(selectors, (selector: string): void => { Loops.forEach(eventTypes, (eventType: string): void => { ((selector, eventType): void => { document.addEventListener(eventType, function (event): void { let target = event.target as any; if (target === this) { return; } if (!self.matches(target, selector)) { target = self.findParent(target, selector); } if (target && target !== this) { event.preventDefault(); const newEvent = { currentTarget: target, originalEvent: event }; Loops.forEach([ 'altKey', 'bubbles', 'button', 'buttons', 'cancelable', 'char', 'charCode', 'clientX', 'clientY', 'ctrlKey', 'data', 'detail', 'eventPhase', 'key', 'keyCode', 'metaKey', 'offsetX', 'offsetY', 'originalTarget', 'pageX', 'pageY', 'preventDefault', 'relatedTarget', 'screenX', 'screenY', 'shiftKey', 'stopImmediatePropagation', 'stopPropagation', 'target', 'toElement', 'type', 'view', 'which' ], (keyToCopy: any) => { if (!Objects.keyExists(event, keyToCopy)) { return; } const isFunction = event[keyToCopy] instanceof Function; if (isFunction) { newEvent[keyToCopy] = function (): any { return event[keyToCopy](); }; } else { Object.defineProperty(newEvent, keyToCopy, { get: function () { return event[keyToCopy]; } }); } }); callback.call(target, newEvent); } }); })(selector, eventType); }); }); return this; } /* eslint-enable @typescript-eslint/no-this-alias, max-nested-callbacks */ public removeClass(element: Element, classes: string): Dom { element.className = element.className .replace(new RegExp(classes.trim().replace(' ', '|'), 'g'), '') .trim() .replace(/\s+/, ' '); return this; } public toggleClass(element: Element, classes: string): Dom { const classesForCheck = classes.split(' '); let classesToRemove = ''; let classesToAdd = ''; Loops.forEach(classesForCheck, (value: string) => { if (element.classList.contains(value)) { classesToRemove += ' ' + value; } else { classesToAdd += ' ' + value; } }); this.removeClass(element, classesToRemove); this.addClass(element, classesToAdd); return this; } public trigger(element: any[], event: string): this { if (element instanceof Element) { element = [element]; } Loops.forEach(element, (elementItem: Element): void => { elementItem.dispatchEvent( new Event(event, { bubbles: true, cancelable: true // view: window }) ); }); return this; } } export default new Dom();