UNPKG

shadow-dom-element

Version:

shadow-dom-element is a declarative custom element/web component to render local and remote template

89 lines (82 loc) 3.17 kB
const attr = (el, name)=>el.getAttribute(name)|| el.sde?.getAttribute(name); const TAG = 'shadow-dom-element'; export default class ShadowDomElement extends HTMLElement { promise; constructor() { super(); const tag = attr(this,'tag') , tagName = this.tagName.toLowerCase(); if( tag && tagName !== tag ) { const sde = this; this.templates = [...this.getElementsByTagName( 'template' )]; this.templates.map( t=>t.remove() ); customElements.define( tag, class ShadowDomElementDCE extends ShadowDomElement{ async slotsInit() { this.sde = sde; await sde.promise; return super.slotsInit(); } } ); if( this.childElementCount ) { const html = this.outerHTML.replace('<'+tagName, '<'+tag); this.innerHTML=''; this.insertAdjacentHTML('afterend',html); } }else { this.templates = []; this.promise = this.slotsInit(); } } async fetch( url ){ return ( await fetch( url ) ).text() } applyTemplate( t ) { const s = this.shadowRoot; s.appendChild( t.content.cloneNode( true ) ); this.postTemplateCallback( s ); return this; } postTemplateCallback(s) { s.querySelectorAll('slot[attribute]').forEach( a => { let f = attr(a,'for') , s = f ? a.getRootNode().querySelector('#'+f) : a.parentElement; s.setAttribute( attr( a, 'attribute' ) , a.assignedElements().map( l=>attr( l, 'href') || attr( l, 'src') || l.innerText).join('')) }); } async slotsInit() { const getText = async url => this.fetch( url ); const onAttr = async( att, cb ) => { await ( async a => ( a ? cb( a ) : 0 ) )( attr(this, att ) ); }; const embeddedTemplates = [ ...this.getElementsByTagName( 'template' ) , ...( this.sde ? this.sde.templates : [] ) ]; await onAttr( 'srcset', id => ( this.innerHTML = `${ document.getElementById( id )?.innerHTML }` ) ); await onAttr( 'src', async url => ( this.innerHTML = await getText( url ) ) ); this.attachShadow( { mode: 'open' } ); const applyTemplate = t => this.applyTemplate( t ); // @ts-ignore embeddedTemplates.forEach( applyTemplate ); await onAttr( 'for', id => applyTemplate( document.getElementById( id ) ) ); await onAttr( 'code', async url => { const d = document.createElement( 'div' ); d.innerHTML = await getText( url ); const t = document.createElement( 'template' ); d.childNodes.forEach( n => t.content.append( n ) ); this.templates.push(t); applyTemplate( t ); } ); return this; } } window.customElements.define(TAG, ShadowDomElement);