woocommerce/plugins/woocommerce-blocks/assets/js/interactivity/vdom.js

70 lines
1.8 KiB
JavaScript

import { h } from 'preact';
import { directivePrefix as p } from './constants';
const ignoreAttr = `${ p }ignore`;
const islandAttr = `${ p }island`;
const directiveParser = new RegExp( `${ p }([^:]+):?(.*)$` );
export const hydratedIslands = new WeakSet();
// Recursive function that transfoms a DOM tree into vDOM.
export function toVdom( node ) {
const props = {};
const { attributes, childNodes } = node;
const directives = {};
let hasDirectives = false;
let ignore = false;
let island = false;
if ( node.nodeType === 3 ) return node.data;
if ( node.nodeType === 4 ) {
node.replaceWith( new Text( node.nodeValue ) );
return node.nodeValue;
}
for ( let i = 0; i < attributes.length; i++ ) {
const n = attributes[ i ].name;
if ( n[ p.length ] && n.slice( 0, p.length ) === p ) {
if ( n === ignoreAttr ) {
ignore = true;
} else if ( n === islandAttr ) {
island = true;
} else {
hasDirectives = true;
let val = attributes[ i ].value;
try {
val = JSON.parse( val );
} catch ( e ) {}
const [ , prefix, suffix ] = directiveParser.exec( n );
directives[ prefix ] = directives[ prefix ] || {};
directives[ prefix ][ suffix || 'default' ] = val;
}
} else if ( n === 'ref' ) {
continue;
} else {
props[ n ] = attributes[ i ].value;
}
}
if ( ignore && ! island )
return h( node.localName, {
dangerouslySetInnerHTML: { __html: node.innerHTML },
} );
if ( island ) hydratedIslands.add( node );
if ( hasDirectives ) props.directives = directives;
const children = [];
for ( let i = 0; i < childNodes.length; i++ ) {
const child = childNodes[ i ];
if ( child.nodeType === 8 || child.nodeType === 7 ) {
child.remove();
i--;
} else {
children.push( toVdom( child ) );
}
}
return h( node.localName, props, children );
}