cordis/client/webapp/elements/require/q-module.ts

223 lines
7.2 KiB
TypeScript
Raw Normal View History

2021-10-30 17:26:41 +00:00
// Fake jQuery because jQuery is for faggots
let document: Document | null = null;
export class SelectorError extends Error {
constructor(...args: any[]) {
super(...args);
this.name = 'SelectorError';
}
}
export const $ = function(queryString: string): HTMLElement {
if (document === null) {
throw new SelectorError('document not specified');
}
let element = document.querySelector<HTMLElement>(queryString);
if (element === null) {
throw new SelectorError(`unable to find [${queryString}] in document`);
}
return element;
}
export const $_ = function(queryString: string): HTMLElement | null {
try {
return $(queryString);
} catch (e) {
return null;
}
}
export const $$ = function(queryString: string): HTMLElement[] { // Because ElementList Objects are cancerous
if (document === null) {
throw new SelectorError('document not specified');
}
return Array.from(document.querySelectorAll(queryString));
}
export const $$$ = function(element: HTMLElement, queryString: string): HTMLElement {
let foundElement = element.querySelector<HTMLElement>(queryString);
if (foundElement === null) {
throw new SelectorError(`unable to find [${queryString}] in element`);
}
return foundElement;
}
export const $$$_ = function(element: HTMLElement, queryString: string): HTMLElement | null {
try {
return $$$(element, queryString);
} catch (e) {
return null;
}
}
2021-10-30 17:26:41 +00:00
export const $$$$ = function(element: HTMLElement, queryString: string): HTMLElement[] {
return Array.from(element.querySelectorAll(queryString));
}
// Set the document for all q.js functions to use
$.setDocument = function(doc: Document) {
document = doc;
}
// General javascript functions
/**
* @function $.zip
* @description Zip arrays together
* $.zip([2, 3, 4], [5, 6]) -> [ [2, 5], [3, 6], [4, undefined] ]
* $.zip([3, 4], [5, 6, 7]) -> [ [3, 5], [4, 6], [undefined, 7] ]
* @param {...any} arrays Lists to zip together
* @return The arrays zipped together
*/
$.zip = function(...arrays: any[]): any[] {
let n = 0;
let result: any[] = [];
for (let array of arrays) {
$.assert(Array.isArray(array), 'all parameters must be arrays');
for (let i = 0; i < array.length; ++i) {
if (i == result.length) {
result.push([]);
for (let j = 0; j < n; ++j) {
result[i].push(undefined);
}
}
result[i].push(array[i]);
}
}
return result;
}
/**
* @function $.previousElement
* @description gets the previous HTMLElement in the DOM. Useful to skip any text nodes
* @param element HTMLElement to get the previous element of
* @returns the previous HTMLElement in the DOM or null if there are no HTMLElements before the specified element.
*/
$.previousElement = function(element: HTMLElement): HTMLElement | null {
let current: ChildNode | HTMLElement = element;
while (current.previousSibling) {
if (current.previousSibling instanceof HTMLElement) {
return current.previousSibling;
}
current = current.previousSibling;
}
return null;
}
/**
* @function $.nextElement
* @description gets the next HTMLElement in the DOM. Useful to skip any text nodes
* @param element HTMLElement to get the next element of
* @returns the next HTMLElement in the DOM or null if there are no HTMLElements after the specified element.
*/
$.nextElement = function(element: HTMLElement): HTMLElement | null {
let current: ChildNode | HTMLElement = element;
while (current.nextSibling) {
if (current.nextSibling instanceof HTMLElement) {
return current.nextSibling;
}
current = current.nextSibling;
}
return null;
}
// From elipzer.com q.js, custom HTMLElement generation
/**
* @function $.assert
* @description Asserts that the value is true, throwing an error with specified
* message otherwise
* @param value The value of the assertion
* @param message The message to be put in the error message if the value is falsy
*/
$.assert = function(value: boolean, message: string): void {
if (!value) {
throw new Error(message);
}
}
/**
* @function $.addContent
* @description Adds to the internal content of an HTMLElement
* @param {HTMLElement} element The element to add content to
* @param content The content to be added to the element
*/
$.addContent = function(element: HTMLElement, content: any) {
content = Array.isArray(content) ? content : [ content ];
for (let e of content) {
element.appendChild($.create(e));
}
}
/**
* @function $.clearChildren
* @description removes all children from an element
* @param {HTMLElement} element The element to remove all children from
*/
$.clearChildren = function(element: HTMLElement): void {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
/**
* @function $.create
* Recursively creates an HTMLElement from the specified content
* @param obj An element initialization object { tag, id, class, content, ... }
* @var tag The HTML tag of the element (default: 'div')
* @var id The id of the elemnt
* @var class The class of the element (string or list of strings)
* @var content The internal content of the element. This is handled recursively.
* Can be a string, HTMLElement, obj, list of objs, or list of HTMLElements
* @var ... All other attributes will be applied using element.setAttribute(key, value)
*/
$.create = function(obj: HTMLElement | any | null): Node {
if (document === null) {
throw new Error('document not specified');
}
if (obj instanceof HTMLElement) {
return obj
} else if (typeof obj !== 'object') {
return document.createTextNode(obj.toString());
} else if (obj == null) {
return document.createTextNode('[null]');
}
$.assert(obj !== undefined, 'obj is undefined');
let element: HTMLElement;
if (obj.ns) {
element = document.createElementNS(obj.ns, obj.tag || 'div');
} else {
element = document.createElement(obj.tag || 'div');
}
if (obj.id) {
element.id = obj.id;
}
if (obj.class) {
if (Array.isArray(obj.class)) {
for (let c of obj.class) {
$.assert(typeof c === 'string', `Invalid obj.class[i] type: ${typeof c}`);
element.classList.add(c);
}
} else if (typeof obj.class === 'string') {
element.className = obj.class;
} else {
throw new Error(`Invalid obj.class type: ${obj.class}`);
}
}
for (let key in obj) {
if (key !== 'tag' && key !== 'id' && key != 'class' && key != 'content') {
if (obj.hasOwnProperty(key)) {
element.setAttribute(key.toString(), obj[key].toString());
}
}
}
if (obj.content !== undefined) {
$.addContent(element, obj.content);
}
return element;
}