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 );
|
|
|
|
}
|
|
|
|
}
|