@rajaniraiyn/raj.js
Version:
A modern, fast, performant and lightweight jQuery alternative.
657 lines (568 loc) • 18 kB
text/typescript
/**!
Raj.js
© 2021 Rajaniraiyn
A modern alternative to jQuery.
*/
((_) => {
"use strict";
/**
* to handle jQuery "Sizzle" selector https://github.com/jquery/sizzle
*/
function raj(selector: keyof HTMLElementTagNameMap = undefined): Raj {
switch (selector) {
case undefined:
return;
default:
// @ts-ignore
selector = selector.trim();
function isSpecialSelector(selector: string): boolean {
switch (
selector.includes("#") &&
(selector.includes(".") || /[~!+:>\\\-()\[\]*]\w*/gm.test(selector))
) {
case true:
return true;
default:
// used for some special selectors
return /[~!+:>\\\-()\[\]*]\w*/gm.test(selector);
}
//if (selector.includes("#") && selector.includes(".")) return true;
}
switch (isSpecialSelector(selector)) {
case true:
return new Raj(document.querySelectorAll(selector), selector);
default:
switch (selector.startsWith("#")) {
case true:
return new Raj(
document.getElementById(selector.replace("#", "")),
selector
);
default:
switch (selector.startsWith(".")) {
case true:
return new Raj(
document.getElementsByClassName(
selector.replace(".", "")
),
selector
);
default:
return new Raj(
document.getElementsByTagName(selector),
selector
);
}
}
}
}
/*
if (selector === undefined) return;
// @ts-ignore
selector = selector.trim();
function isSpecialSelector(selector: string): boolean {
if (selector.includes("#") && selector.includes(".")) return true;
var specialChars = [
"~",
"!",
"+",
":",
">",
",",
"-",
"(",
")",
"[",
"]",
"*",
];
for (var i = 0, len = specialChars.length; i < len; i++) {
if (selector.includes(specialChars[i])) return true;
}
return false;
}
if (isSpecialSelector(selector)) {
return new Raj(document.querySelectorAll(selector), selector);
} else if (selector.startsWith("#")) {
return new Raj(
document.getElementById(selector.replace("#", "")),
selector
);
} else if (selector.startsWith(".")) {
return new Raj(
document.getElementsByClassName(selector.replace(".", "")),
selector
);
} else return new Raj(document.getElementsByTagName(selector), selector);
*/
}
raj["version"] = "1.0.0";
/**
* performance focused forEach loop
* using "reversed for loop"
*/
function forEach(array: any[], callback: Function): void {
for (var i = 0, len = array.length; i < len; i++) {
callback(array[i], i);
}
}
class Raj extends Array {
selector: keyof HTMLElementTagNameMap;
constructor(
elements: any = undefined,
selector: keyof HTMLElementTagNameMap
) {
switch (elements.length) {
case undefined:
elements = [elements];
break;
default:
elements = [...elements];
break;
}
//elements = elements.length === undefined ? [elements] : [...elements];
super(...elements);
this["context"] = window.document;
this.selector = selector;
return this;
}
/**
* hides the selected elements
*
*/
hide(): Raj {
forEach(this, (element: HTMLElement) => {
element[raj.expando] = { display: element.style.display };
element.style.setProperty("display", "none");
});
return this;
}
/**
* makes hidden selected elements visible
*
*/
show(): Raj {
forEach(this, (element: HTMLElement) => {
element.style.setProperty("display", element[raj.expando]["display"]);
});
return this;
}
eq(index: number): Raj {
return new Raj(
this[((index % this.length) + this.length) % this.length],
this.selector
);
}
/**
* selects first element among selected element
*
*/
first(): Raj {
return this.eq(0);
}
/**
* selects last element among selected element
*
*/
last(): Raj {
return this.eq(-1);
}
even(): Raj {
// @ts-ignore
return this.filter((_: HTMLElement, i: number) => {
return i % 2 !== 0;
});
}
odd(): Raj {
// @ts-ignore
return this.filter((_: HTMLElement, i: number) => {
return i % 2 === 0;
});
}
not(selector: keyof HTMLElementTagNameMap = undefined): Raj {
var not = raj(selector);
// @ts-ignore
return this.filter((element: HTMLElement) => {
return !not.includes(element);
});
}
/**
* Adds class name to all selected elements
*
*/
addClass(className: string): Raj {
forEach(this, (element: Element) => {
element.classList.add(className);
});
return this;
}
/**
* Removes a class if it presents in selected elements
*
*/
removeClass(className: string): Raj {
forEach(this, (element: Element) => {
element.classList.remove(className);
});
return this;
}
/**
* Toggles a class in all selected elements
*
*/
toggleClass(className: string): Raj {
forEach(this, (element: Element) => {
element.classList.toggle(className);
});
return this;
}
/**
* Adds a event listener to all selected elements
*
*/
on(
event: keyof HTMLElementEventMap,
callback: any,
options?: boolean | AddEventListenerOptions
) {
forEach(this, (element: HTMLElement) => {
element.addEventListener(event, callback, options);
});
}
off(event: keyof HTMLElementEventMap, selector: string, handler?: any) {
if (handler === undefined) {
forEach(this, (element: HTMLElement) => {
// remove all events
});
}
}
click(handler?: Function, ...args: boolean[] | AddEventListenerOptions[]) {
if (handler === undefined) {
forEach(this, (element: HTMLElement) => {
element.click();
});
}
this.on("click", handler, ...args);
}
/**
* Adds a HTML string after all selected elements
*
*/
after(...args: string[]): Raj {
var elementText: string = [...args].reverse().join("");
forEach(this, (element: HTMLElement) => {
element.insertAdjacentHTML("afterend", elementText);
});
return this;
}
/**
* Adds HTML string within all selected elements as a last child
*
*/
append(...args: string[]): Raj {
var elementText: string = [...args].join("");
forEach(this, (element: HTMLElement) => {
element.insertAdjacentHTML("beforeend", elementText);
});
return this;
}
/**
* Adds HTML string within all selected elements as a first child
*
*/
prepend(...args: string[]): Raj {
var elementText: string = [...args].reverse().join("");
forEach(this, (element: HTMLElement) => {
element.insertAdjacentHTML("afterbegin", elementText);
});
return this;
}
/**
* Adds HTML string before all selected elements
*
*/
before(...args: string[]): Raj {
var elementText: string = [...args].join("");
forEach(this, (element: HTMLElement) => {
element.insertAdjacentHTML("beforebegin", elementText);
});
return this;
}
/**
* Handles the attributes of a DOM element i.e. first among the selected elements
*
* Acts as both getter and setter & can also take multiple attributes at once
* as a key value Object
*
*/
attr(attribute: string | object, value?: string | Function): string {
switch (value) {
case undefined:
switch (typeof attribute) {
case "object":
var values: string[] = Object.values(attribute);
forEach(Object.keys(attribute), (key: string, i: number) => {
this[0].setAttribute(key, values[i]);
});
break;
default:
return this[0].getAttribute(attribute);
}
default:
switch (typeof value) {
case "function":
forEach(this, (element: HTMLElement, i: number) => {
// @ts-ignore
value(i, element.getAttribute(attribute));
});
break;
default:
return this[0].setAttribute(attribute, value);
}
}
// if (value === undefined) {
// if (typeof attribute === "object") {
// var values: string[] = Object.values(attribute);
// forEach(Object.keys(attribute), (key: string, i: number) => {
// this[0].setAttribute(key, values[i]);
// });
// }
// return this[0].getAttribute(attribute);
// } else if (typeof value === "function") {
// forEach(this, (element: HTMLElement, i: number) => {
// // @ts-ignore
// value(i, element.getAttribute(attribute));
// });
// }
// return this[0].setAttribute(attribute, value);
}
/**
* Handles the styles of a DOM element i.e. first among the selected elements
*
* Acts as both getter and setter & can also take multiple attributes at once
* as a key value Object
*
*/
css(property: string | object, value?: string | Function): string {
switch (value) {
case undefined:
switch (typeof property) {
case "object":
var values: string[] = Object.values(property);
forEach(Object.keys(property), (key: string, i: number) => {
this[0].style.setProperty(key, values[i]);
});
break;
default:
return getComputedStyle(this[0])[property];
}
default:
switch (typeof value) {
case "function":
forEach(this, (element: HTMLElement, i: number) => {
// @ts-ignore
value(i, getComputedStyle(element)[property]);
});
break;
default:
return this[0].style.setProperty(property, value);
}
}
// if (value === undefined) {
// if (typeof property === "object") {
// var values: string[] = Object.values(property);
// forEach(Object.keys(property), (key: string, i: number) => {
// this[0].style.setProperty(key, values[i]);
// });
// }
// //@ts-ignore
// return getComputedStyle(this[0])[property];
// } else if (typeof value === "function") {
// forEach(this, (element: HTMLElement, i: number) => {
// // @ts-ignore
// value(i, getComputedStyle(element)[property]);
// });
// }
// return this[0].style.setProperty(property, value);
}
/**
* Cleans everything inside all selected elements i.e. excluding the element itself
*
*/
empty(): Raj {
forEach(this, (element: HTMLElement, i: number) => {
element.innerHTML = null;
});
return this;
}
/**
* Checks wether a class is present in the first element of selected
*
*/
hasClass(className: string): boolean {
return this[0].classList.contains(className);
}
/**
* Returns the height of the first element of selected
*
*/
height(): number {
return parseFloat(getComputedStyle(this[0])["height"]);
}
outerHeight(includeMargin?: boolean): number {
if (includeMargin) {
return (
this.height() +
parseInt(this.css("margin-top")) +
parseInt(this.css("margin-bottom"))
);
}
return this[0].offsetHeight;
}
/**
* Returns the width of the first element of selected
*
*/
width(): number {
return parseFloat(getComputedStyle(this[0])["width"]);
}
outerWidth(includeMargin?: boolean): number {
if (includeMargin) {
return (
this.width() +
parseInt(this.css("margin-left")) +
parseInt(this.css("margin-right"))
);
}
return this[0].offsetWidth;
}
/**
* Stores some data for the first element of selected
*
*/
data(name: string | object, value?: string): string | void {
return raj.data(this[0], name, value);
}
each(callback: Function): void {
raj.each(this, callback);
}
}
raj.expando = "raj" + Date.now();
document[raj.expando] = {};
raj.extend = (target: object, ...args: object[]) => {
switch ([...args][0]) {
case undefined:
return Object.assign(raj, target);
default:
return Object.assign(target, ...args);
}
// if ([...args][0] === undefined) {
// return Object.assign(raj, target);
// }
// return Object.assign(target, ...args);
};
raj.noConflict = (removeAll?: boolean) => {
switch (removeAll) {
case true:
window["$"] = window["jQuery"] = window["raj"] = undefined;
break;
case false:
window["$"] = undefined;
}
//if (removeAll) window["raj"] = window["jQuery"] = window["$"] = undefined;
//else window["$"] = undefined;
return raj;
};
raj.data = (
element: HTMLElement,
name: string | object,
value?: string
): string => {
switch (value) {
case undefined:
switch (raj.cache[element[raj.expando]]) {
case undefined:
raj.cache[element[raj.expando]] = {};
break;
}
switch (typeof name) {
case "string":
return raj.cache[element[raj.expando]][name];
case "object":
console.log(raj.cache[element[raj.expando]]);
element[raj.expando] = ++raj.cache.latest;
if (Object.keys(raj.cache[element[raj.expando]]).length === 0)
//@ts-ignore
return (raj.cache[element[raj.expando]] = name);
return Object.assign(raj.cache[element[raj.expando]], name);
// var values = Object.values(name);
// forEach(Object.keys(name), (key: string, i: number) => {
// raj.cache[element[raj.expando]][key] = values[i];
// });
default:
break;
}
break;
default:
element[raj.expando] = ++raj.cache.latest;
switch (raj.cache[element[raj.expando]]) {
case undefined:
raj.cache[element[raj.expando]] = {};
break;
}
return (raj.cache[element[raj.expando]][name] = value);
}
// if (value !== undefined) {
// element[raj.expando] = ++raj.cache.latest;
// if (raj.cache[element[raj.expando]] === undefined)
// raj.cache[element[raj.expando]] = {};
// return (raj.cache[element[raj.expando]][name] = value);
// }
// if (typeof name === "string") {
// if (raj.cache[element[raj.expando]] === undefined)
// raj.cache[element[raj.expando]] = {};
// return raj.cache[element[raj.expando]][name];
// } else if (typeof name === "object") {
// element[raj.expando] = ++raj.cache.latest;
// if (raj.cache[element[raj.expando]] === undefined)
// raj.cache[element[raj.expando]] = {};
// var values = Object.values(name);
// forEach(Object.keys(name), (key: string, i: number) => {
// raj.cache[element[raj.expando]][key] = values[i];
// });
// }
};
raj.removeData = (element: HTMLElement, name: string | object) => {
switch (name) {
case undefined:
raj.cache[element[raj.expando]] = undefined;
break;
}
// if (name === undefined) {
// raj.cache[element[raj.expando]] = undefined;
// }
raj.cache[element[raj.expando]][name] = undefined;
};
raj.when = async (...deferreds: any[]) => {
// @ts-ignore
return Object.assign(...deferreds);
};
raj.cache = { latest: 0 };
raj.now = Date.now;
raj.parseJSON = JSON.parse;
raj.inArray = (item: any, array: any[]): number => {
return array.indexOf(item);
};
raj.isArray = (arr: any[]): boolean => {
return Array.isArray(arr);
};
raj.isFunction = (fun: Function): boolean => {
return typeof fun === "function";
};
raj.each = (array: any[], callback: Function): void => {
forEach(array, (element: HTMLElement, index: number) => {
callback(index, element);
});
};
window["raj"] = window["jQuery"] = window["$"] = raj;
})();