library-ts/browser/dom/DOMEditor.ts

202 lines
4.7 KiB
TypeScript
Raw Normal View History

2025-09-06 11:33:04 +00:00
import { HTMLNodeTreeWalker } from "../graphs/HTMLNodeTreeWalker";
import { TreeWalker } from "../graphs/TreeWalker";
2025-03-08 08:16:54 +00:00
export class DOMEditor
{
static nodeListToArray( list:NodeList )
{
return Array.prototype.slice.call( list );
}
static prefixData( source:string )
{
let singleReplaceRegex = /\[\s*-/g;
source = source.replace(singleReplaceRegex, "[data-");
let autoDataExtensionRegex = /\[(?!data-|([a-zA-Z0-9]+s*(\=|\~|\||\^|\$|\*|\])))/g;
return source.replace( autoDataExtensionRegex, "[data-" );
}
static copyAttribute( destination:Element, source:Element, sourceAttribute:string)
{
sourceAttribute = DOMEditor.prefixData( sourceAttribute );
let value = source.getAttribute (sourceAttribute );
destination.setAttribute( sourceAttribute, value );
}
static copyAllAttributesThroughRawHTML( source:Element, destination:Element )
{
let attributes:[string,string][] = [];
for ( let i = 0; i < destination.attributes.length; i++ )
{
let attribute = destination.attributes[ i ];
let attributeName = attribute.nodeName;
let attributeValue = attribute.nodeValue;
attributes.push( [ attributeName, attributeValue ] );
}
for ( let i = 0; i < source.attributes.length; i++ )
{
let attribute = source.attributes[ i ];
let attributeName = attribute.nodeName;
let attributeValue = attribute.nodeValue;
let index = attributes.findIndex( a => a[ 0 ] === attributeName );
if ( index === -1 )
{
attributes.push( [ attributeName, attributeValue ] );
}
else
{
attributes[ index ][ 1 ] = attributeValue;
}
}
let innerHTML = destination.innerHTML;
let attributesString = "";
for ( let i = 0; i < attributes.length; i++ )
{
if ( i !== 0 ){ attributesString += " "; }
let attribute = attributes[ i ];
attributesString += `${attribute[ 0 ]}="${attribute[ 1 ]}"`;
}
let tag = destination.nodeName.toLowerCase();
let html = `<${tag} ${attributesString}>${innerHTML}</${tag}>`;
console.log( "Copied html:", html );
destination.outerHTML = html;
return destination;
}
static copyAllAttributes( source:Element, destination:Element )
{
for ( let i = 0; i < source.attributes.length; i++ )
{
let attribute = source.attributes[ i ];
let attributeName = attribute.nodeName;
let attributeValue = attribute.nodeValue;
destination.setAttribute( attributeName, attributeValue );
}
}
static cloneChildren( element:Element ):Node[]
{
let clones:Node[] = [];
for ( let i = 0; i < element.childNodes.length; i++ )
{
clones.push( element.childNodes[ i ].cloneNode( true ) );
}
return clones;
}
2025-09-06 11:33:04 +00:00
static reverseChildren( element:Element )
{
Array.from( element.childNodes ).reverse().forEach( node => {
element.appendChild( node );
});
}
static getChildrenWidth( parent:Element, callback:( e:Element )=>boolean )
{
HTMLNodeTreeWalker.$.forAll
}
static swapNodes( parent:Element, node1:Node, node2:Node )
{
if ( node1 === node2 )
{
return;
}
let next1 = node1.nextSibling;
let next2 = node2.nextSibling;
if ( next1 === node2 )
{
parent.insertBefore( node2, node1 );
}
else if ( next2 === node1 )
{
parent.insertBefore( node1, node2 );
}
else
{
parent.insertBefore( node1, next2 );
parent.insertBefore( node2, next1 );
}
}
2025-03-08 08:16:54 +00:00
static _cssCreationRegex:RegExp;
static get cssCreationRegex()
{
if ( DOMEditor._cssCreationRegex)
{
return DOMEditor._cssCreationRegex;
}
let cssCreationRules = [
//"Attribute",
/\[\s*(?:\w|-)+\s*(?:(?:\~|\||\^|\$|\*)?=)\s*(?:(?:"(?:\\"|.)*?")|(?:'(?:\\'|.)*?')|(?:(?:\w|-)+))\s*\]/,
//"ID",
/#(?:\w|-)+/,
//"Class",
/\.(?:\w|-)+/,
//"Empty Attribute",
/\[\s*(?:\w|-)+\s*]/,
//"Element",
/(?:\w|-)+/
];
let regexString = "";
for (let i = 0; i < cssCreationRules.length; i++)
{
if (i !== 0)
{
regexString += "|";
}
regexString += "(" + cssCreationRules[i].source + ")";
}
DOMEditor._cssCreationRegex = new RegExp(regexString, "g");
return DOMEditor._cssCreationRegex;
}
static stringToDocument( html:string ):Document
{
let parser = new DOMParser();
let doc = parser.parseFromString( html, "text/html" );
return doc;
}
static remove( node:Node )
{
if ( ! node )
{
return;
}
if ( ! node.parentNode )
{
return;
}
node.parentNode.removeChild( node );
}
}