@webqit/oohtml
Version:
A suite of new DOM features that brings language support for modern UI development paradigms: a component-based architecture, data binding, and reactivity.
129 lines (114 loc) • 3.79 kB
JavaScript
/**
* @imports
*/
import DOMContexts from './DOMContexts.js';
import { env } from '../util.js';
export default class DOMContext {
/**
* To be implemented by subclasses
*/
static kind;
/**
* @createRequest
*/
static createRequest() { return { kind: this.kind }; }
/**
* @constructor
*/
constructor( detail = null ) {
Object.defineProperty( this, 'detail', { get: () => detail } );
Object.defineProperty( this, 'subscriptions', { value: new Set } );
}
/**
* @configs
*/
get configs() {
const { window: { webqit: { oohtml: { configs } } } } = env;
return configs;
}
/**
* @name
*/
get name() { return [ env.window.Document, env.window.ShadowRoot ].some( x => this.host instanceof x ) ? Infinity : this.host.getAttribute( this.configs.CONTEXT_API.attr.contextname ); }
/**
* @subscribed()
*/
subscribed( event ) {}
/**
* @handle()
*/
handle( event ) {}
/**
* @unsubscribed()
*/
unsubscribed( event ) {}
/**
* @matchEvent
*/
matchEvent( event ) {
return event.kind === this.constructor.kind
&& ( !event.targetContext || event.targetContext === this.name );
}
/**
* @handleEvent()
*/
handleEvent( event ) {
if ( this.disposed || typeof event.respondWith !== 'function' ) return;
if ( event.type === 'contextclaim' ) {
if ( !( event.detail instanceof DOMContext ) || event.target === this.host ) return;
const claims = new Set;
this.subscriptions.forEach( subscriptionEvent => {
if ( !event.target.contains( subscriptionEvent.target ) || !event.detail.matchEvent( subscriptionEvent ) ) return;
this.subscriptions.delete( subscriptionEvent );
this.unsubscribed( subscriptionEvent );
claims.add( subscriptionEvent );
} );
if ( claims.size ) { return event.respondWith( claims ); }
}
if ( event.type === 'contextrequest' ) {
if ( !this.matchEvent( event ) ) return;
if ( event.live ) {
this.subscriptions.add( event );
this.subscribed( event );
event.signal?.addEventListener( 'abort', () => {
this.subscriptions.delete( event );
this.unsubscribed( event );
} );
}
event.stopPropagation();
return this.handle( event );
}
}
/**
* @initialize()
*/
initialize( host ) {
this.host = host;
this.disposed = false;
host.addEventListener( 'contextrequest', this );
host.addEventListener( 'contextclaim', this );
const { value: claims } = DOMContexts.instance( host ).request( 'contextclaim', { kind: this.constructor.kind, detail: this } );
claims?.forEach( subscriptionEvent => {
this.subscriptions.add( subscriptionEvent );
this.subscribed( subscriptionEvent );
this.handle( subscriptionEvent );
} );
return this;
}
/**
* @dispose()
*/
dispose( host ) {
this.disposed = true;
host.removeEventListener( 'contextrequest', this );
host.removeEventListener( 'contextclaim', this );
this.subscriptions.forEach( subscriptionEvent => {
this.subscriptions.delete( subscriptionEvent );
this.unsubscribed( subscriptionEvent );
const { target } = subscriptionEvent;
subscriptionEvent.meta.answered = false;
target.dispatchEvent( subscriptionEvent );
} );
return this;
}
}