library-ts/browser/dom/ElementAttribute.ts

436 lines
9.4 KiB
TypeScript
Raw Permalink Normal View History

2025-03-08 08:16:54 +00:00
import { HTMLNodeTreeWalker } from "../graphs/HTMLNodeTreeWalker";
import { DOMEditor } from "./DOMEditor";
import { DOMNameSpaces } from "./DOMNameSpaces";
export class ElementAttribute
{
static readonly nameAttribute = new ElementAttribute( "name", false );
static readonly style = new ElementAttribute( "style", false );
static readonly class = new ElementAttribute( "class", false );
static readonly id = new ElementAttribute( "id", false );
static readonly href = new ElementAttribute( "href", false );
static readonly download = new ElementAttribute( "download", false );
static readonly target = new ElementAttribute( "target", false );
static readonly type = new ElementAttribute( "type", false );
static readonly lang = new ElementAttribute( "lang", false );
static readonly src = new ElementAttribute( "src", false );
static readonly value = new ElementAttribute( "value", false );
static readonly svgClass = new ElementAttribute( "class", false, "" );
static readonly xlinkHref = new ElementAttribute( "xlink:href", false, DOMNameSpaces.XLink );
static readonly contentEditable = new ElementAttribute( "contenteditable", false );
static readonly allowfullscreen = new ElementAttribute( "allowfullscreen", false );
static readonly controls = new ElementAttribute( "controls", false );
static readonly preload = new ElementAttribute( "preload", false );
2025-09-06 11:33:04 +00:00
static readonly playsinline = new ElementAttribute( "playsinline", false );
2025-03-08 08:16:54 +00:00
static readonly selected = new ElementAttribute( "selected", false );
static readonly data_lang = new ElementAttribute( "lang" );
static readonly title = new ElementAttribute( "title", false );
static readonly width = new ElementAttribute( "width", false );
static readonly height = new ElementAttribute( "height", false );
static readonly frameborder = new ElementAttribute( "frameborder", false );
static readonly allow = new ElementAttribute( "allow", false );
static readonly autoplay = new ElementAttribute( "autoplay", false );
static readonly muted = new ElementAttribute( "muted", false );
static readonly loop = new ElementAttribute( "loop", false );
static readonly readonly = new ElementAttribute( "readonly", false );
static readonly dataType = new ElementAttribute( "type" );
static readonly dataName = new ElementAttribute( "name" );
static readonly hidden = new ElementAttribute( "hidden", false );
static readonly rootHref = new ElementAttribute( "root-href" );
private _name:string;
get name(){ return this._name; }
get fullName()
{
return this._useDataPrefix ? ( "data-" + this._name ) : this._name;
}
private _useDataPrefix = true;
private _useNameSpace = false;
get usesNameSpace(){ return this._useNameSpace; }
private _nameSpace:string = null;
get nameSpace(){ return this._nameSpace;}
constructor( name:string, useDataPrefix:boolean = true, nameSpace:string = null )
{
if ( this._name && this._name.startsWith( "data-" ) && useDataPrefix )
{
console.warn(
`The name of the attribute starts with a 'data-' prefix AND the 'useDataPrefix' at the same time!` );
}
this._name = name;
this._useDataPrefix = useDataPrefix;
if ( nameSpace )
{
this._useNameSpace = true;
this._nameSpace = nameSpace === "" ? null : nameSpace;
}
}
forAll( target:Element|Document, callback:(element:Element)=>any)
{
let elements = target.querySelectorAll( this.selector );
for ( let i = 0; i < elements.length; i++ )
{
callback( elements[ i ] );
}
}
toString()
{
return this.fullName;
}
queryDoc()
{
return document.querySelector( this.selector );
}
querySelfOrParent( element:Element )
{
if ( this.in( element ) )
{
return element;
}
return this.queryParent( element );
}
queryParent( element:Element )
{
let parent = element.parentElement;
while ( parent )
{
if ( this.in( parent ) )
{
return parent;
}
parent = parent.parentElement;
}
return null;
}
queryParentValue( element:Element )
{
let parent = this.queryParent( element );
return this.from( parent );
}
queryWithValue( element:Element|Document, value:string )
{
return element.querySelector( this.selectorEquals( value ) );
}
queryDocWithValue( value:string )
{
return this.queryWithValue( document, value );
}
hasParentWithValue( element:Element, value:string )
{
return this.queryParentValue( element ) === value;
}
query<T=Element>( element:Element|Document )
{
return element.querySelector( this.selector ) as any as T;
}
isQueriedChecked( element:Element )
{
let queried = this.query<HTMLInputElement>( element );
if ( ! queried )
{
return false;
}
return queried.checked;
}
matches( element:Element, regex:RegExp )
{
if ( ! this.in( element ) )
{
return false;
}
return regex.exec( this.from( element ) ) !== null;
}
queryDocAll()
{
return DOMEditor.nodeListToArray( document.querySelectorAll( this.selector ) );
}
forEachInDoc( callback:(element:Element)=>void )
{
this.queryDocAll().forEach( callback );
}
queryAll( t:Element|Document )
{
if ( ! this._needsWalker( this.selector ) )
{
return this._queryAllQuerySelector( t );
}
return this._queryAllWalker( t );
}
_needsWalker( selector:string )
{
if ( "[xlink:href]" == selector )
{
return true;
}
return false;
}
_queryAllQuerySelector( element:Element|Document )
{
return DOMEditor.nodeListToArray( element.querySelectorAll( this.selector ) );
}
_queryAllWalker( t:Element|Document )
{
let list:Element[] = [];
let walker = new HTMLNodeTreeWalker();
let end = walker.iterationEndOf( t );
let it:Node = t;
while ( it !== end )
{
if ( Node.ELEMENT_NODE != it.nodeType )
{
it = walker.nextNode( it );
continue;
}
let element = it as Element;
if ( this.in( element ) )
{
list.push( element );
}
it = walker.nextNode( it );
}
return list;
}
queryValueInDoc( element:Element )
{
return this.queryValueIn( element, document );
}
queryValueIn( element:Element, source:Document|Element = undefined )
{
source = source || element;
let selector = this.from( element );
return source.querySelector( selector );
}
get selector()
{
return `[${this.fullName}]`;
}
selectorContaining( fragment:string )
{
return `[${this.fullName}*="${fragment}"]`;
}
selectorContainingWord( word:string )
{
return `[${this.fullName}|="${word}"]`;
}
selectorStartsWith( word:string )
{
return `[${this.fullName}^="${word}"]`;
}
selectorEquals( word:string )
{
let selector = `[${this.fullName}="${word}"]`;
return selector;
}
is( element:Element, value:string|RegExp )
{
if ( ! this.in( element ) )
{
return false;
}
let stringValue = this.from( element );
if ( typeof value === "string" )
{
return value === stringValue;
}
return value.test( stringValue );
}
in( element:Element )
{
if ( ! element.attributes )
{
return false;
}
if ( this._useNameSpace )
{
return element.hasAttributeNS( this._nameSpace, this.fullName );
}
return element.hasAttribute( this.fullName );
}
inAll( elements:Element[] )
{
if ( elements.length === 0 )
{
return false;
}
for ( let e of elements )
{
if ( ! this.in( e ) )
{
return false;
}
}
return true;
}
from( element:Element, alternative:string = null )
{
if ( ! element )
{
console.log( "Element is null", this );
return null;
}
if ( this._useNameSpace )
{
return element.getAttributeNS( this._nameSpace, this.fullName );
}
return element.getAttribute( this.fullName ) || alternative;
}
toggleRemove( element:Element, value:boolean )
{
if ( value )
{
this.to( element, "" );
}
else
{
this.removeFrom( element );
}
}
to( element:Element, value:string|number|boolean = "")
{
value = value + "";
if ( ! element )
{
console.log( "Element is null", this );
}
if ( this._useNameSpace )
{
element.setAttributeNS( this._nameSpace, this.fullName, value );
return;
}
element.setAttribute( this.fullName, value );
}
replaceIn( element:Element, matcher:RegExp, replacement:string )
{
let value = this.from( element );
value = value.replace( matcher, replacement );
this.to( element, value )
}
removeFrom( element:Element )
{
if ( this._useNameSpace )
{
element.removeAttributeNS( this._nameSpace, this.fullName );
return;
}
element.removeAttribute( this.fullName );
}
copy( source:Element, target:Element )
{
this.to( target, this.from( source ) );
}
2025-09-06 11:33:04 +00:00
asNumberFrom( element:Element, alternative:number = null )
{
if ( ! this.in( element ) )
{
return alternative;
}
let value = this.from( element );
if ( ! value )
{
return alternative;
}
let numberValue = parseFloat( value );
if ( isNaN( numberValue ) )
{
return alternative;
}
return numberValue;
}
2025-03-08 08:16:54 +00:00
}