library-ts/browser/dom/RootPathResolver.ts

228 lines
5.8 KiB
TypeScript
Raw Permalink Normal View History

2025-03-25 06:42:27 +00:00
import { HTMLNodeTreeWalker } from "../graphs/HTMLNodeTreeWalker";
import { DOMNameSpaces } from "./DOMNameSpaces";
import { ElementAttribute } from "./ElementAttribute";
export class ResolvablePathAttribute
{
private _selector:string;
private _attribute:ElementAttribute
constructor( selector:string, attribute:string, namespace?:string )
{
this._selector = selector;
this._attribute = new ElementAttribute( attribute, false, namespace );
}
get combinedSelector()
{
let combined = `${this._selector}${this._attribute.selector}`;
return combined;
}
get useNodeNameMatcher()
{
return this._selector === "image";
}
getFrom( target:Element|Document )
{
if ( this.useNodeNameMatcher )
{
let matchedElements:Element[] = [];
let walker = new HTMLNodeTreeWalker();
let walkable = target;
if ( ( target as Document ).documentElement )
{
walkable = ( target as Document).documentElement;
}
walker.forAll( walkable,
n =>
{
if ( n.nodeName === this._selector )
{
matchedElements.push( n as Element );
}
}
);
return matchedElements;
}
let elements = target.querySelectorAll( this.combinedSelector );
return Array.prototype.slice.call( elements );
}
process( element:Element, rootToken:string, rootPath:string )
{
let value = this._attribute.from( element );
if ( value === null )
{
if ( this._selector === "image" )
{
console.log( "no value for image" );
this.lgGetAttribute( element, "href" );
this.lgGetAttribute( element, "xlink:href" );
}
return;
}
else if ( this._selector === "image" )
{
}
/*if ( ! value.startsWith( rootToken ) )
{
if ( this._selector === "image" )
{
let shortValue = value;
if ( value.length > 100 )
{
shortValue = value.substring( 0, 100 );
}
}
else if ( this._attribute.name === "style" )
{
value = value.replace( rootToken, rootPath )
}
return;
}*/
value = value.replace( rootToken, rootPath )
this._attribute.to( element, value );
}
lgGetAttribute( element:Element, attribute:string )
{
this.lg( `${attribute} >> ${element.getAttribute( attribute )} `);
this.lg( `${attribute} NS=null >> ${element.getAttributeNS( null, attribute )} `);
this.lg( `${attribute} NS="" >> ${element.getAttributeNS( "", attribute )} `);
this.lg( `${attribute} NS=XLink >> ${element.getAttributeNS( DOMNameSpaces.XLink, attribute )} `);
this.lg( `${attribute} NS=SVG >> ${element.getAttributeNS( DOMNameSpaces.SVG, attribute )} `);
}
lg( value:string )
{
let shortValue = value;
if ( value.length > 100 )
{
shortValue = value.substring( 0, 100 ) + "...";
}
console.log( shortValue );
}
}
export class RootPathResolver
{
static readonly customResolve = new ElementAttribute( "resolve-root-path" );
static readonly resolvables:ResolvablePathAttribute[] =
[
new ResolvablePathAttribute( "link", "href" ),
new ResolvablePathAttribute( "script", "src" ),
new ResolvablePathAttribute( "a", "href" ),
new ResolvablePathAttribute( "img", "src" ),
new ResolvablePathAttribute( "audio", "src" ),
new ResolvablePathAttribute( "source", "src" ),
new ResolvablePathAttribute( "video", "poster" ),
new ResolvablePathAttribute( "video", "src" ),
new ResolvablePathAttribute( "*", "style" ),
new ResolvablePathAttribute( "image", "xlink:href" ),
new ResolvablePathAttribute( "*", "data-load-audio-element" ),
new ResolvablePathAttribute( "meta", "content" ),
new ResolvablePathAttribute( "*", "data-root-href" ),
]
private static _rootToken = "::/";
static clearRootPath( rootPath:string )
{
return rootPath.replace( /^\:\:\//, "" );
}
static isRootPath( path:string )
{
return path.startsWith( RootPathResolver._rootToken );
}
static get rootToken()
{
return RootPathResolver._rootToken;
}
getRootPath( relativeFilePath:string )
{
let normalizedPath = relativeFilePath.replace( /\\/g, "/" );
if ( normalizedPath.startsWith( "/" ) )
{
normalizedPath = normalizedPath.substring( 1 );
}
let numParentDirectories = normalizedPath.split( "/" ).length - 1;
let rootPath = "";
for ( let i = 0; i < numParentDirectories; i++ )
{
rootPath += "../";
}
return rootPath;
}
process( target:Element|Document, relativeFilePath:string )
{
let rootPath = this.getRootPath( relativeFilePath );
RootPathResolver.resolvables.forEach(
( resolvable )=>
{
let elements = resolvable.getFrom( target );
elements.forEach(
( e:Element ) =>
resolvable.process( e, RootPathResolver.rootToken, rootPath )
);
}
)
RootPathResolver.customResolve.forAll(
target,
( e:Element ) =>
{
let attName = RootPathResolver.customResolve.from( e );
let att = new ElementAttribute( attName, false );
let path = att.from( e );
console.log( `Processing custom root path "${attName}" = "${path}"` );
if ( path === null )
{
console.log( "Root Path Resolve: No path found in ", attName);
return;
}
path = path.replace( RootPathResolver.rootToken, rootPath );
att.to( e, path );
}
)
}
}