UNPKG

@twobirds/microcomponents

Version:

Micro Components Organization Class

1,635 lines (1,284 loc) 33.8 kB
import { MC, DC, HTMLMcElement, addListener, removeListener } from './MC.js'; import { LooseObject } from './helpers.js'; /* helpers */ const isObject = ( value: any ): boolean => { return value != null && typeof value === 'object'; } const words = ( classes: Array<string> ): Array<string> => { let classSet: Set<string> = new Set(); // read classes into set classes.forEach( c => { c = c.trim(); c.split(' ').forEach( e => { if ( e !== '' ){ classSet.add(e); } }); }); // now we have a sanitized array classes = Array.from( classSet ); return classes; } type inputTypes = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement; const getInputName = ( e: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement ): string => { let ret = e instanceof HTMLInputElement ? 'input' : e instanceof HTMLSelectElement ? 'select' : e instanceof HTMLTextAreaElement ? 'textarea' : '' ; return ret; } const getInputHandlers = ( e: HTMLElement | ShadowRoot ): LooseObject => { let //inputList = ( Array.from( e.querySelectorAll('*') ) as HTMLElement[] ).filter( i => isInputElement(i) ), inputList = $d('input,select,textarea', e).array, handlers: LooseObject = {}; inputList.forEach( (i) => { const name: string = ( i as inputTypes ).getAttribute('name') || 'undefined'; if ( name ){ let h: InputBase; switch ( getInputName( i as inputTypes ) ){ case 'input': //console.log( i, 'is HTMLInputElement'); h = new InputHandler( i as HTMLInputElement, e ); // e = element to search radios in = radioBase Object.defineProperty( handlers, name, { enumerable: true, configurable: true, get: (): any => { return h.val }, set: ( value: any ) => { h.val = value } }); break; case 'select': //console.log( i, 'is HTMLSelectElement'); h = new SelectHandler( i as HTMLSelectElement ); Object.defineProperty( handlers, name, { enumerable: true, configurable: true, get: (): any => { return h.val }, set: ( value: any ) => { h.val = value } }); break; case 'textarea': //console.log( i, 'is HTMLTextAreaElement'); h = new TextAreaHandler( i as HTMLTextAreaElement ); Object.defineProperty( handlers, name, { enumerable: true, configurable: true, get: (): any => { return h.val }, set: ( value: any ) => { h.val = value } }); break; default: console.warn('handler missing:', name, 'for', i); break; } } }); return handlers; } abstract class InputBase{ constructor( e: any ){ } abstract get val(): any; abstract set val( value: any ); } class InputHandler extends InputBase { #e: HTMLInputElement; #type: string; #radioBase: any; constructor( e: HTMLInputElement, radioBase?: HTMLElement | ShadowRoot ){ super( e ); this.#e = e; this.#type = e.type; this.#radioBase = radioBase; } get val(): any{ let that = this, type = that.#type, ret: any; switch (type){ case 'radio': const check = $d( `input[type="radio"][name="${ this.#e.getAttribute('name') }"]`, this.#radioBase ) .filter( e => e.checked ); if ( !check.length ) return ''; ret = check.array[0]; return ret.value; case 'checkbox': return that.#e.checked; default: return that.#e.value; break; } return ''; } set val( value: any ){ let that = this, type = that.#type, ret: any; switch (type){ case 'radio': const selection = `input[type="radio"][name="${ this.#e.getAttribute('name') }"]`, radios = $d( selection, this.#radioBase ); // console.log('set radios', selection, this.#radioBase, radios.array ); if ( !radios.length ) return; if ( value === '' ){ // uncheck all radios.forEach( r => { if (r.checked) r.checked = false } ); //console.log('unset all radios', radios.array ); return; } const setRadioElement = radios.filter( r => r.getAttribute('value') === value ); if ( !setRadioElement.length ) return; // console.log('set this radio', setRadioElement.array ); (setRadioElement.array[0] as HTMLInputElement).checked = true; // console.log('done', setRadioElement.array ); return; break; case 'checkbox': that.#e.checked = value; break; default: that.#e.value = value; break; } return; } } class SelectHandler extends InputBase { #e: HTMLSelectElement; #multi: boolean = false; constructor( e: HTMLSelectElement ){ super( e ); this.#e = e; this.#multi = e.type === 'select-multiple'; } get val(): string[] | string{ const that = this, ret: string[] = []; // get all options const options = $d( that.#e.querySelectorAll('option') ) .filter( o => o.selected ) .forEach( o => { if ( o.selected ) ret.push( o.value ) } ); if ( this.#multi ) return ret; return ret.length ? ret[0] : ''; } set val( value: string[] | string ){ const that = this; value = typeof value === 'string' ? [ value ] : value; //console.log('set values', value ); // set all options const options = $d( that.#e.querySelectorAll('option') ) .forEach( o => { if ( value.indexOf( o.value ) > -1 ) { o.setAttribute( 'selected', true ) o.selected = true; } else { o.removeAttribute( 'selected' ) o.selected = false; } }); /* if (pOption.selected) { if ( !pOption.disabled && (!pOption.parentNode.disabled || pOption.parentNode.nodeName !== 'optgroup') ) { var value = pOption.value; ret.push(value); } } */ return; } } class TextAreaHandler extends InputBase { #e: HTMLTextAreaElement constructor( e: HTMLTextAreaElement ){ super(e); this.#e = e; } get val(): string{ return this.#e.value; } set val( value: string ){ this.#e.value = value; return; } } /* selector classes */ class DomSelector{ #set: Set<HTMLElement> = new Set(); public get set(): Set<HTMLElement> { return this.#set; } public get array(): HTMLElement[] { return Array.from( this.#set ); } public set set( set: Set<HTMLElement> ) { this.#set = set; return; } public get length(): number { return this.#set.size; } constructor( selection?: selection, element: any = document.body ){ let that = this, undefinedTags: Set<any> = new Set(); // // console.log('DomSelector constructor', ...arguments); if ( !selection ) { return that; } /* autoloading disabled ! if ( selection instanceof Array ){ selection.forEach( (select) => { _getElementList( select, element ).forEach( (e) => { if ( e.localName?.indexOf('-') !== -1 || e.getAttribute?.('is') ) _loadRequirements( e ); that.#set.add( e ); }); }); } else { _getElementList( selection, element ).forEach( (e) => { if ( e.localName?.indexOf('-') !== -1 || e.getAttribute?.('is') ) _loadRequirements( e ); that.#set.add( e ); }); } */ } $t( nameSpace?: string ): TSelector { let result = new TbSelector() ; this.#set.forEach( (e: HTMLElement) => { if ( (e as HTMLMcElement)._mc ){ Object.values( (e as HTMLMcElement)._mc ).forEach( ( mc: MC | DC ) => { result.set.add( mc ); }); } }); if ( nameSpace ) { result.filter( mc => (mc as LooseObject).nameSpace === nameSpace ); } return result; } add( selection: selection, target?: HTMLElement ): DSelector { let that = this ; $d( selection, target ).forEach( element => { that.#set.add( element ); }); return that; } addClass( ...classes: string[] ): DSelector { // sanitize classes classes = words( classes ); // now set those classes this.forEach( element => { element.classList.add( ...classes ); }); return this; } after( selection: selection, target?: HTMLElement ): DSelector { let that = this, after = $d( selection, target ); ; if ( !after.length ) return that; after .first() .forEach( element => { that.array.reverse().forEach( (e: HTMLElement) => { e.after( element ); }); }); return that; } append( selection: selection, target?: HTMLElement ): DSelector { let that = this, addTo = that.array['0'], append = $d( selection, target ) ; if ( addTo ){ append.forEach( (e: HTMLElement) => { addTo.append( e ); }); } return that; } appendTo( selection: selection, target?: HTMLElement ): DSelector { let that = this, appendTo = $d( selection, target ).array['0'] ; if ( appendTo ){ that.forEach( (e: HTMLElement) => { appendTo.append( e ); }); } return that; } attr(): LooseObject; attr( obj: LooseObject ): DSelector; attr( name: string ): string | null; attr( first?: string | LooseObject, second?: string | object | null ): DSelector; attr( first?: unknown, second?: unknown ): DSelector | LooseObject | string | null { let that = this, attributes: LooseObject = {} ; // if no elements in set -> skip if ( !that.length ) return that; // if no arguments, return attributes of first in list as hash object if (!arguments.length) { Array.from( [ ...that.set ][0].attributes ).forEach( (attribute: LooseObject) => { attributes[attribute.name] = attribute.value; }); return attributes; } // if first is a string // if no value (second) is given -> return attribute value of first element in node selection // if value (second) is null -> remove attribute and return this // else set attribute values and return this if ( typeof first === 'string' ) { // return attributes if ( second === undefined ){ return [ ...that.set ][0].getAttribute( first ); } // remove attribute if ( second === null ){ [ ...that.set ].forEach( (e: HTMLElement) =>{ e.removeAttribute( first ); }); return that; } // if attribute value is an object -> convert to json string if ( typeof second === 'object' ){ second = JSON.stringify( second ); } // set attribute [ ...that.set ].forEach( (e: HTMLElement) =>{ e.setAttribute( first, second as string ); }); return that; } // if first is an object set attributes to all nodes if ( typeof first === 'object' ) { [ ...that.set ].forEach( (e: HTMLElement) =>{ Object.keys( first as LooseObject ).forEach( (key: string) => { $d(e).attr( key, ( first as LooseObject ).key ); }); }); return that; } return that; } before( selection: selection, target?: HTMLElement ): DSelector { let that = this, before = $d( selection, target ); ; if ( !before.length ) return that; before .first() .forEach( element => { that.forEach( (e: HTMLElement) => { e.before( element ); }); }); return that; } children( selection?: selection, rootNode?: HTMLElement ): DSelector{ let that: DomSelector = this, set: Set<HTMLElement> = new Set() ; that.#set.forEach( (e: HTMLElement) => { Array.from( e.children ).forEach( ( c ) => { set.add( c as HTMLElement ); }); }); that = $d( [ ...set] ); if ( selection ){ let compare = $d( selection, rootNode ); that.filter( ( e: HTMLElement ) => compare.has( e ) ); } return that; } descendants( selection?: selection, rootNode?: HTMLElement ): DSelector{ let that: DomSelector = this, set: Set<HTMLElement> = new Set() ; that.#set.forEach( (e: HTMLElement) => { e.querySelectorAll('*').forEach( ( h ) => { set.add( h as HTMLElement ); }); }); that = $d( [ ...set] ); if ( selection ){ let compare = $d( selection, rootNode ); that.filter( ( e: HTMLElement ) => compare.has( e ) ); } return that; } empty(): DSelector { return this.filter( (e: any)=>false ); } first( selection?: selection, rootNode?: HTMLElement ): DSelector{ let that: DomSelector = this, set: Set<HTMLElement> = new Set(), compare: any = false; ; // get compare selection if specified if ( selection ){ compare = $d( selection, rootNode ); } // get compare selection if specified that.#set.forEach( (e: HTMLElement) => { if ( e.parentNode ){ set.add( e.parentNode.children[0] as HTMLElement ); } }); // make result that = $d( [ ...set ] ); // compare if necessay if ( selection ){ that.filter( ( e: HTMLElement ) => compare.has( e ) ); } return that; } has( element: HTMLElement ): boolean{ return this.#set.has( element ); } hasClass( ...classes: string[] ): boolean { // sanitize classes classes = words( classes ); // now test those classes return this.every( e => { return Array.from( e.classList ).every( c => e.contains( c ) ); }); } html( html?: string ): string | DSelector{ let that = this; if ( html ){ that.forEach( (e: HTMLElement) => { !e.parentNode ? (()=>{ console.warn('Cannot access the .innerHTML of a HTMLElement that hasnt been inserted yet', e ); console.trace( e, this ); console.info( 'If you called this from inside a Web Component constructor, consider using the %c[connected] event callback!', 'color: blue;' ) })() : e.innerHTML = html; }); return that; } return that.array[0].innerHTML; } last( selection?: selection, rootNode?: HTMLElement ): DSelector{ let that: DomSelector = this, set: Set<HTMLElement> = new Set() ; that.#set.forEach( (e: HTMLElement) => { let siblings = e.parentNode?.children as HTMLCollection ; if ( siblings ) { set.add( Array.from(siblings).at(-1) as HTMLElement ); } }); that = $d( [ ...set] ); if ( selection ){ let compare = $d( selection, rootNode ); that.filter( ( e: HTMLElement ) => compare.has( e ) ); } return that; } /* load(): DSelector{ let that = this; if( !that.length ){ that.add( document.body ); } that.forEach( e => _loadRequirements( e ) ); return that; } */ next( selection?: selection, rootNode?: HTMLElement ): DSelector{ let that: DomSelector = this, set: Set<HTMLElement> = new Set() ; that.#set.forEach( (e: HTMLElement) => { let siblings = e.parentNode?.children as HTMLCollection ; if ( siblings ) { let arr = Array.from(siblings), pos = arr.indexOf(e) + 1 ; if ( pos < arr.length ){ set.add( arr.at(pos) as HTMLElement ); } } }); that = $d( [ ...set] ); if ( selection ){ let compare = $d( selection, rootNode ); that.filter( ( e: HTMLElement ) => compare.has( e ) ); } return that; } normalize(): DSelector { let that = this; that.#set.forEach( (e: HTMLElement) => { e.normalize() }); return that; } off( eventName: string, cb: Function ): DSelector{ let that = this, eventNames = eventName.indexOf(' ') > -1 ? eventName.split(' ') : [ eventName ] ; // remove handler that.array.forEach( (e: HTMLElement) => { eventNames.forEach(function ( n: string ) { removeListener( e, n, cb as EventListenerOrEventListenerObject ); }); }); return that; } on( eventName: string, cb: Function, capture: boolean = false, once: boolean = false ): Function{ let that = this, eventNames = eventName.indexOf(' ') > -1 ? eventName.split(' ').filter( (s) => s !== '' ) : [ eventName ] ; function wrapper(){ wrapper.cb.apply(that, Array.from(arguments) ); }; wrapper.cb = cb; // attach handler that.forEach( (e: HTMLElement) => { eventNames.forEach(function ( n: string ) { addListener( e, n, (wrapper as EventListenerOrEventListenerObject), capture, once ); }); }); return wrapper; } one( eventName: string, cb: Function, capture: boolean = false ): Function{ let that = this, eventNames = eventName.indexOf(' ') > -1 ? eventName.split(' ').filter( (s) => s !== '' ) : [ eventName ] ; function wrapper(){ wrapper.cb.apply(that, Array.from(arguments) ); }; wrapper.cb = cb; // attach handler that.forEach( (e: HTMLElement) => { eventNames.forEach(function ( n: string ) { addListener( e, n, (wrapper as EventListenerOrEventListenerObject), capture, true ); }); }); return wrapper; } parent( selection?: selection, rootNode?: HTMLElement ): DSelector { let that: DomSelector = this, set: Set<HTMLElement> = new Set() ; that.#set.forEach( (e: HTMLElement) => { if ( e.parentNode && (e.parentNode as HTMLElement).tagName !== 'HTML') { set.add( e.parentNode as HTMLElement ); } }); that = $d( [ ...set] ); if ( selection ){ let compare = $d( selection, rootNode ); that.filter( ( e: HTMLElement ) => compare.has( e ) ); } return that; } parents( selection?: selection, rootNode?: HTMLElement ): DSelector { let that: DomSelector = this, set: Set<HTMLElement> = new Set() ; that.#set.forEach( (e: HTMLElement) => { let current = e ; while ( current.parentNode && (current.parentNode as HTMLElement).tagName !== 'HTML' ){ current = current.parentNode as HTMLElement; set.add( current ); } }); that = $d( [ ...set] ); if ( selection ){ let compare = $d( selection, rootNode ); that.filter( ( e: HTMLElement ) => compare.has( e ) ); } return that; } prepend( selection: selection, target?: HTMLElement ): DSelector { let that = this, addTo = that.array['0'], prepend = $d( selection, target ) ; if ( addTo ){ prepend.forEach( (e: HTMLElement) => { addTo.prepend( e ); }); } return that; } prev( selection?: selection, rootNode?: HTMLElement ): DSelector{ let that: DomSelector = this, set: Set<HTMLElement> = new Set() ; that.#set.forEach( (e: HTMLElement) => { let siblings = e.parentNode?.children as HTMLCollection ; if ( siblings ) { let arr = Array.from(siblings), pos = arr.indexOf(e) - 1 ; if ( pos > -1 ){ set.add( arr.at(pos) as HTMLElement ); } } }); that = $d( [ ...set] ); if ( selection ){ let compare = $d( selection, rootNode ); that.filter( ( e: HTMLElement ) => compare.has( e ) ); } return that; } removeClass( ...classes: string[] ): DSelector { // sanitize classes classes = words( classes ); // now set those classes this.forEach( element => { element.classList.remove( ...classes ); }); return this; } text( text?: string ): string | DSelector{ let that = this; if ( text ){ that.forEach( (e: HTMLElement) => { !e.parentNode ? (()=>{ console.warn('Cannot access the .textContent of a HTMLElement that hasnt been inserted yet', e ); console.trace( e, this ); console.info( 'If you called this from inside a Web Component constructor, consider using the %c[connected] event callback!', 'color: blue;' ) })() : e.innerText = text; }); return that as DomSelector; } let t = that.array[0].innerText; return t ?? '' as string; } toggleClass( ...classes: string[] ): DSelector { // sanitize classes classes = words( classes ); // now set those classes this.forEach( element => { element.classList.toggle( ...classes ); }); return this; } trigger( eventName: string, data: any = {}, bubbles: boolean = false, cancelable: boolean = false, composed: boolean = false ): DSelector{ let that = this, ev: Event, options: LooseObject = { bubbles, cancelable, composed }, eventNames = eventName.indexOf(' ') > -1 ? eventName.split(' ') : [ eventName ] ; that.#set.forEach( (e: HTMLElement) => { eventNames.forEach(function ( n: string ) { // console.log() ev = new Event( n, options ); (ev as LooseObject ).data = data; e.dispatchEvent( ev ); }); }); return that; } // INFO: // val(): LooseObject; // no param: get all as LooseObject // val( p1: string ): Array<string> | number | string; // get from input name // val( p1: object ): DomSelector; // set from object // val( p1: string, p2: any ): DomSelector; // set from name and value val( p1?: any, p2?: any ): any { if ( !this.length ) return this; const that = this ; let result: any, handlers: LooseObject = getInputHandlers( that.array[0] ); // work with it if ( !p1 ){ // get all inputs as LooseObject result = Object.assign( {}, handlers ); // Object.keys( handlers ).forEach( ( key ) => result[key] = handlers.hasOwnProperty(key) ? handlers[key].val : undefined ); } else { if ( isObject(p1) ){ // set inputs from Object Object.assign( handlers, p1 ); // Object.keys( p1 ).forEach( ( key ) => !!handlers[key] ? handlers[key].val = p1[key] : false ); result = that; } else if ( typeof p1 === 'string' ){ if ( p2 === undefined ){ // get a single input result = handlers[p1]; } else { // set a single input handlers[p1] = p2; result = that; } } } return result; } values( values?: LooseObject ): LooseObject { const that = this, holder: LooseObject = {}; let data: LooseObject = {}; //console.log( '$d().values()', values ); if ( !that.length ) { console.warn('no dom selection to search inputs in'); return {}; } let handlers = getInputHandlers( that.array[0] ); //console.log( 'handlers', Object.keys(handlers), handlers['cb1'] ); // let values = that.val(); // console.log( 'values', values ); Object.keys( handlers ).forEach( (key: string) => { //console.log(key); data[key] = handlers[key]; }); // data = Object.assign( {}, that.val() ) //console.log( 'data', that.array[0], data, Object.keys( data ) ); if ( Object.keys( data ).length === 0 ) { console.warn('no inputs in this dom selection', that.array[0], data ); } //console.log( '$d val()', data ); if (values) { Object .keys( values ) .forEach( key => { if ( handlers.hasOwnProperty(key) ) { console.log( 'key found', key ); handlers[key] = values[key]; } }); // .forEach( key => handlers[key] = values[key] ) } return structuredClone( Object.assign( handlers ) ); } /* array method mapping */ at( index: number ): DSelector { return $d( this.array.at( index ) as HTMLElement ) as DomSelector; } concat( items: DSelector | any[] ): DSelector{ let that = this, arr = items instanceof DomSelector ? items.array : items as HTMLElement[] ; arr.forEach( (e: HTMLElement) => { that.#set.add( e ); }); return that; } entries(): IterableIterator<[number, any]> { return this.array.entries(); } every( predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any ): boolean { return this.array.every( predicate, thisArg ); } filter( predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any ): DSelector { this.#set = new Set( this.array.filter( predicate, thisArg ) ); return this; } forEach( predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any ): DSelector { this.array.forEach( predicate, thisArg ); return this; } includes( item: HTMLElement ): boolean{ return this.array.indexOf( item, 0 ) !== -1; } indexOf( item: HTMLElement, start?: number ): number{ return this.array.indexOf( item, start ); } map( predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any ): Array<any>{ return this.array.map( predicate, thisArg ); } pop(): HTMLElement { return this.array.pop() as HTMLElement; } push( ...items: HTMLElement[] ): DSelector { items.forEach( (item: HTMLElement) => { this.#set.add( item ); }); return this; } shift(): HTMLElement | undefined { let that = this, element = that.#set.size ? that.array[0] : undefined ; if ( element ){ that.#set.delete( element ); } return element; } slice( start: number, end?: number ): DSelector { return $d( this.array.slice( start, end ) ); } some( predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any ): boolean{ return this.array.some( predicate, thisArg ); } splice( start: number, deleteCount?: number | undefined ): DSelector; splice( start: number, deleteCount: number, ...items: HTMLElement[] ): DSelector { let that = this, arr = that.array ; arr.splice( start, deleteCount, ...items ); return $d( arr ); } } export interface DSelector extends DomSelector{}; class TbSelector{ #set: Set<any> = new Set(); public get set(): Set<any> { return this.#set; } public get array(): any[] { return Array.from( this.#set ); } public set set( set: Set<any> ) { this.#set = set; return; } public get length(): number { return this.#set.size; } public set length( value: number ){ //ignore } constructor( selection?: selection, element: HTMLElement = document.body ){ if ( !selection ) { return this; } $d( selection, element ).forEach( (e: HTMLMcElement) => { $t( e ).forEach( (t: any ) => { this.#set.add(t); }); }); } $d( selection?: selection, element: HTMLElement = document.body ): DSelector { let result = new DomSelector(), set: Set<HTMLElement> = new Set(), compare: boolean = !!selection || false, compareSelection: Set<HTMLElement> = new Set() ; if ( compare ){ compareSelection = $d( selection, element ).set; } this.#set.forEach( (e: any) => { if ( !compare || compareSelection.has( (e as any)._tg ) ) { set.add( (e as any)._tg ); } }); result.set = set; return result; } children( nameSpace?: string ): TSelector{ let that: TbSelector = this, set: Set<any> = new Set() ; that.#set.forEach( (e: any) => { e.children( nameSpace ).forEach( ( tb: any ) => { set.add( tb ); }); }); that.#set = set; return that; } descendants( nameSpace?: string ): TSelector{ let that: TbSelector = this, set: Set<any> = new Set() ; that.#set.forEach( (e: any) => { e.descendants( nameSpace ).forEach( ( tb: any ) => { set.add( tb ); }); }); that.#set = set; return that; } first( nameSpace?: string ): TSelector{ let that: TbSelector = this, set: Set<any> = new Set() ; that.#set.forEach( (e: any) => { e .parent() .children() .$d() .first() .$t() .forEach( (tb: any) => { set.add( tb ); }); }); that.#set = set; if ( nameSpace ){ that.filter( ( tb: any ) => (tb as any).nameSpace = nameSpace ); } return that; } has( element: any ): boolean{ return this.#set.has( element ); } last( nameSpace?: string ): TSelector{ let that: TbSelector = this, set: Set<any> = new Set() ; that.#set.forEach( (e: any) => { e .parent() .children() .$d() .last() .$t() .forEach( (tb: any) => { set.add( tb ); }); }); that.#set = set; if ( nameSpace ){ that.filter( ( e: any ) => ( e as LooseObject).nameSpace = nameSpace ); } return that; } next( nameSpace?: string ): TSelector{ let that: TbSelector = this, set: Set<any> = new Set() ; that.#set.forEach( (e: any) => { let elements: Set<HTMLElement> = new Set(), element: HTMLElement ; element = (e as any)._tg; while ( element.nextElementSibling !== null ){ element = element.nextElementSibling as HTMLElement; elements.add( element ); } $t([...elements]) .$d() .first() .$t() .forEach( (tb: any) => { set.add( tb ); }); }); that.#set = set; if ( nameSpace ){ that.filter( ( e: any ) => ( e as LooseObject).nameSpace = nameSpace ); } return that; } ns( nameSpace: string ): TSelector{ return this.filter( (tb: any) => (tb as any).nameSpace === nameSpace ); } off( name: string, cb: Function ): TSelector{ let that = this, eventNames = name.indexOf(' ') > -1 ? name.split(' ').filter( (s) => s !== '' ) : [ name ] ; // remove handlers that.$d().array.forEach( (e: HTMLElement) => { eventNames.forEach(function ( n: string ) { // console.log('Tb Selector remove event', `[TB]${n}`, e, cb ); removeListener( e, `[TB]${n}`, cb as EventListenerOrEventListenerObject ); }); }); return that; } on( name: string, cb: Function, once: boolean = false ): Function{ let that = this, eventNames = name.indexOf(' ') > -1 ? name.split(' ').filter( (s) => s !== '' ) : [ name ] ; function wrapper(){ wrapper.cb.apply(that, Array.from(arguments) ); }; wrapper.cb = cb; // attach handler that.forEach( ( tb: any) => { eventNames.forEach(function ( n: string ) { addListener( (tb as any)._tg, `[TB]${n}`, (wrapper as EventListenerOrEventListenerObject), false, once ); }); }); return wrapper; } one( name: string, cb: Function ): Function{ let that = this, eventNames = name.indexOf(' ') > -1 ? name.split(' ').filter( (s) => s !== '' ) : [ name ] ; function wrapper(){ wrapper.cb.apply(that, Array.from(arguments) ); }; wrapper.cb = cb; // attach handler that.forEach( ( tb: any) => { eventNames.forEach(function ( n: string ) { addListener( (tb as any)._tg, `[TB]${n}`, (wrapper as EventListenerOrEventListenerObject), false, true ); }); }); return wrapper; } parent( nameSpace?: string ): TSelector { let that: TbSelector = this, set: Set<any> = new Set() ; that.#set.forEach( (e: any) => { e.parent( nameSpace ).forEach( ( tb: any ) => { set.add( tb ); }); }); that.#set = set; return that; } parents( nameSpace?: string ): TSelector { let that: TbSelector = this, set: Set<any> = new Set() ; that.#set.forEach( (e: any) => { e.parents( nameSpace ).forEach( ( tb: any ) => { set.add( tb ); }); }); that.#set = set; return that; } prev( nameSpace?: string ): TSelector{ let that: TbSelector = this, set: Set<any> = new Set() ; that.#set.forEach( (e: any) => { let elements: Set<HTMLElement> = new Set(), element: HTMLElement ; element = (e as any)._tg; while ( element.previousElementSibling !== null ){ element = element.previousElementSibling as HTMLElement; elements.add( element ); } $t([...elements]) .$d() .last() .$t() .forEach( (tb: any) => { set.add( tb ); }); }); that.#set = set; if ( nameSpace ){ that.filter( ( e: any ) => ( e as LooseObject).nameSpace = nameSpace ); } return that; } trigger( ev: string, data: any = {}, bubble: string = 'l' ): TSelector{ let that = this ; that.forEach( ( tb: any ) => { tb.trigger( ev, data, bubble ); }); return that; } /* array method mapping */ at( index: number ): TSelector { return $t( this.array.at( index ) ) as TbSelector; } concat( items: TSelector ): TSelector { let that = this ; items.forEach( ( tb: any) => { that.#set.add( tb ); }); return that; } entries(): IterableIterator<[number, any]> { return this.array.entries(); } every( predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any ): boolean { return this.array.every( predicate, thisArg ); } filter( predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any ): TSelector { return $t( this.array.filter( predicate, thisArg ) ); } forEach( predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any ): TSelector { let that = this ; that.array.forEach( predicate, thisArg ); return that; } includes( item: any ): boolean{ return this.array.indexOf( item ) !== -1; } indexOf( item: any, start?: number ): number{ return this.array.indexOf( item, start ); } map( predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any ): Array<any>{ return this.array.map( predicate, thisArg ); } pop(): any { let that = this, arr = that.array, result = arr.pop() ; that.#set = new Set( arr ); return result as any; } push( item: any ): TSelector { let that = this ; that.#set.add( item ); return that; } shift(): any | undefined { let that = this, first = this.array.shift() as any ; that.#set.delete( first ); return first; } slice( start: number, end?: number ): TSelector { return $t( this.array.slice( start, end ) ); } some( predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any ): boolean{ return this.array.some( predicate, thisArg ); } splice( start: number, deleteCount?: number | undefined ): TSelector; splice( start: number, deleteCount: number, ...items: never[] ): TSelector { let that = this, arr = that.array, result = arr.splice( start, deleteCount, ...items ) ; return $t( result ); } } export interface TSelector extends TbSelector{}; export const $d = ( selection: selection, element: any = document ): DSelector => { let set = new Set<HTMLElement>() ; if ( selection instanceof Array ){ selection.forEach( value => { $d( value, element ).forEach( n => { set.add( n ); }); }); return new DomSelector( [...set] ); } else { return new DomSelector( selection, element ); } } export const $t = ( selection?: selection, element: any = document ): TSelector => { return $d( selection, element ).$t(); } export type singleSelector = string | ShadowRoot | HTMLElement | HTMLElement[] | HTMLCollection | NodeList | DSelector | MC | DC | TSelector | undefined; export type selection = singleSelector | singleSelector[];