Created
June 15, 2024 23:50
This class extends dom Elements with some jQuery functions and other helpers.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This class extends dom Elements with some jQuery functions and other helpers. | |
*/ | |
declare global { | |
interface String { | |
toHtmlElement(): DocumentFragment; | |
} | |
interface Element { | |
//jQuery helpers | |
offset(): { left: number; top: number }; | |
find(selectors: string): HTMLElement | null; | |
findAll(selectors: string): NodeListOf<Element>; | |
parent(): HTMLElement | null; | |
width(): number; | |
height(): number; | |
text(text: string): Element; | |
text(): string | null; | |
data(key: string): string | null; | |
data(key: string, value: string): Element; | |
is(selector: string): boolean; | |
on(type: string, listener: (this: Element, ev: Event) => any): Element; | |
on(type: string, selector: string, listener: (this: Element, ev: Event) => any): Element; | |
hasClass(className: string): boolean; | |
addClass(className: string): Element; | |
removeClass(className: string): Element; | |
toggleClass(className: string, state?: boolean): Element; | |
html(html: string): Element; | |
html(): string; | |
css(key: string): string; | |
css(key: string, value: string | number): Element; | |
css(properties: { [key: string]: string | number }): Element; | |
toggle(state?: boolean): Element; | |
removeData(key: string): Element; | |
val(): string; | |
val(value: string | number): Element; | |
attr(attribute: string): string; | |
attr(attribute: string, value: string | boolean | number | null): Element; | |
prop(attribute: string): string; | |
prop(attribute: string, value: string | boolean | number): Element; | |
index(): number; | |
appendHtml(html: string): void; | |
clone(): Element; | |
} | |
interface Document { | |
on(type: string, listener: (this: Document, ev: Event) => any): Document; | |
on(type: string, selector: string, listener: (this: Document, ev: Event) => any): Document; | |
scrollTop(): number; | |
scrollLeft(): number; | |
} | |
} | |
export function initDomHelpers(): void { | |
Document.prototype.scrollTop = function (): number { | |
//https://stackoverflow.com/questions/50431891/how-can-i-detect-the-scrolltop-of-an-element-using-vanilla-javascript | |
return document.documentElement.scrollTop; | |
}; | |
Document.prototype.scrollLeft = function (): number { | |
return document.documentElement.scrollLeft; | |
}; | |
Element.prototype.val = function (parameter1?: any): any { | |
if (parameter1 !== undefined && this instanceof HTMLInputElement) { | |
this.value = parameter1; | |
return this; | |
} | |
if (this instanceof HTMLInputElement) return this.value; | |
return ''; | |
}; | |
Element.prototype.offset = function () { | |
let rect = this.getBoundingClientRect(); | |
return { | |
top: rect.top + window.scrollY, | |
left: rect.left + window.scrollX | |
}; | |
}; | |
Element.prototype.find = function (selectors: string) { | |
return this.querySelector(selectors); | |
}; | |
Element.prototype.findAll = function (selectors: string) { | |
return this.querySelectorAll(selectors); | |
}; | |
Element.prototype.parent = function () { | |
return this.parentElement; | |
}; | |
Element.prototype.width = function (): number { | |
return parseFloat(getComputedStyle(this).width); | |
}; | |
Element.prototype.height = function (): number { | |
return parseFloat(getComputedStyle(this).height); | |
}; | |
Element.prototype.hasClass = function (className: string): boolean { | |
return this.classList.contains(className); | |
}; | |
Element.prototype.appendHtml = function (parameter1: string) { | |
this.appendChild(document.createRange().createContextualFragment(parameter1)); | |
}; | |
Element.prototype.text = function (prameter1?: any): any { | |
if (prameter1 && typeof prameter1 == 'string') { | |
this.textContent = prameter1; | |
return this; | |
} else { | |
return this.textContent; | |
} | |
}; | |
Element.prototype.html = function (parameter1: any): any { | |
if (parameter1 && typeof parameter1 == 'string') { | |
this.innerHTML = parameter1; | |
return this; | |
}else{ | |
return this.innerHTML; | |
} | |
}; | |
Element.prototype.index = function (): number { | |
let parent = this.parentNode; | |
if (parent === null) return -1; | |
let children = parent.childNodes; | |
let num = 0; | |
for (let i = 0; i < children.length; i++) { | |
if (children[i] == this) return num; | |
if (children[i].nodeType == 1) num++; | |
} | |
return -1; | |
}; | |
Element.prototype.is = function (selector: string): boolean { | |
return this.matches(selector); | |
}; | |
Element.prototype.data = function (parameter1: any, parameter2?: any): any { | |
return this.attr('data-' + parameter1, parameter2); | |
}; | |
Element.prototype.attr = function (parameter1: any, parameter2?: any): any { | |
if ( | |
parameter1 && | |
typeof parameter1 == 'string' && | |
((parameter2 && (typeof parameter2 == 'string' || typeof parameter2 == 'number')) || | |
parameter2 === '' || | |
parameter2 === null) | |
) { | |
if (parameter2 === null || parameter2 === '' || parameter2 === false) { | |
this.removeAttribute(parameter1); | |
} else { | |
if (parameter2 === true) parameter2 = ''; | |
this.setAttribute(parameter1, parameter2); | |
} | |
return this; | |
} else if (parameter1) { | |
return this.getAttribute(parameter1); | |
} | |
}; | |
Element.prototype.prop = function (parameter1: any, parameter2?: any): any { | |
if ( | |
parameter1 && | |
typeof parameter1 == 'string' && | |
((parameter2 && (typeof parameter2 == 'string' || typeof parameter2 == 'number')) || | |
parameter2 === '' || | |
parameter2 === null) | |
) { | |
if (parameter2 === null || parameter2 === '' || parameter2 === false) { | |
//@ts-ignore | |
this[parameter1] = null; | |
this.removeAttribute(parameter1); | |
} else { | |
if (parameter2 === true) parameter2 = ''; | |
//@ts-ignore | |
this[parameter1] = parameter2; | |
} | |
return this; | |
} else if (parameter1) { | |
//@ts-ignore | |
return this[parameter1]; | |
} | |
}; | |
Element.prototype.removeData = function (key: string): Element { | |
this.removeAttribute(key); | |
return this; | |
}; | |
Element.prototype.clone = function (): Element { | |
return this.cloneNode(true) as Element; | |
}; | |
Element.prototype.addClass = function (className: string): Element { | |
className.split(' ').forEach((classNamePart) => { | |
this.classList.add(classNamePart); | |
}); | |
return this; | |
}; | |
Element.prototype.removeClass = function (className: string): Element { | |
className.split(' ').forEach((classNamePart) => { | |
this.classList.remove(classNamePart); | |
}); | |
return this; | |
}; | |
Element.prototype.toggleClass = function (className: string, state?: boolean): Element { | |
this.classList.toggle(className, state); | |
return this; | |
}; | |
Element.prototype.on = function (parameter1: any, parameter2: any, parameter3?: any): any { | |
let _this = this; | |
if ( | |
parameter1 && | |
typeof parameter1 == 'string' && | |
parameter2 && | |
typeof parameter2 == 'string' && | |
parameter3 | |
) { | |
parameter1.split(',').forEach(function (eventName: string) { | |
_this.addEventListener(eventName, function (this: HTMLElement, e: Event) { | |
if (!(e.target instanceof Element)) return; | |
let originalTarget = e.target.closest(parameter2); | |
if (originalTarget === null) return; | |
parameter3.call(originalTarget, e); | |
}); | |
}); | |
} else if (parameter1 && typeof parameter1 == 'string' && parameter2) { | |
parameter1.split(',').forEach(function (eventName: string) { | |
_this.addEventListener(eventName, parameter2); | |
}); | |
} | |
return _this; | |
}; | |
Document.prototype.on = function (parameter1: any, parameter2: any, parameter3?: any): any { | |
let _this = this; | |
if ( | |
parameter1 && | |
typeof parameter1 == 'string' && | |
parameter2 && | |
typeof parameter2 == 'string' && | |
parameter3 && | |
parameter3 instanceof Function | |
) { | |
this.addEventListener(parameter1, function (this: Document, e: Event) { | |
if (e.target instanceof Element && e.target.matches(parameter2)) { | |
parameter3.call(_this, e); | |
} | |
}); | |
} else if ( | |
parameter1 && | |
typeof parameter1 == 'string' && | |
parameter2 && | |
parameter2 instanceof Function | |
) { | |
parameter1.split(' ').forEach(function (eventName: string) { | |
_this.addEventListener(eventName, parameter2); | |
}); | |
} | |
return _this; | |
}; | |
Element.prototype.toggle = function (state?: boolean): any { | |
if (this instanceof HTMLElement) { | |
if (state === undefined) { | |
state = this.style.display === 'none'; | |
} | |
this.style.display = state ? '' : 'none'; | |
} | |
return this; | |
}; | |
Element.prototype.css = function (parameter1?: any, parameter2?: any): any { | |
if (this instanceof HTMLElement) { | |
if ( | |
parameter1 && | |
typeof parameter1 == 'string' && | |
parameter2 && | |
(typeof parameter2 === 'string' || typeof parameter2 === 'number') | |
) { | |
parameter1 = parameter1 | |
.replace(/\.?([A-Z])/g, function (x, y) { | |
return '-' + y.toLowerCase(); | |
}) | |
.replace(/^-(?!-)/, ''); | |
// @ts-ignore | |
this.style.setProperty(parameter1, parameter2); | |
return this; | |
} else if (typeof parameter1 == 'object' && !parameter2) { | |
for (let [key, value] of Object.entries(parameter1)) { | |
if (typeof key == 'string' && (typeof value === 'string' || typeof value === 'number')) | |
this.css(key, value); | |
} | |
return this; | |
} else if (typeof parameter1 == 'string' && !parameter2) { | |
// @ts-ignore | |
return this.style[parameter1]; | |
} | |
} | |
}; | |
String.prototype.toHtmlElement = function (this: string): DocumentFragment { | |
return document.createRange().createContextualFragment(this); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment