UNPKG

@surface/custom-element

Version:

Provides support of directives and data binding on custom elements.

66 lines (65 loc) 3.13 kB
import { CancellationTokenSource, assert } from "@surface/core"; import { tryEvaluateExpression, tryObserveByObservable } from "../common.js"; import TemplateProcessor from "../processors/template-processor.js"; import { scheduler } from "../singletons.js"; import TemplateBlock from "./template-block.js"; export default class ChoiceDirective { constructor(templates, descriptor, context) { this.cancellationTokenSource = new CancellationTokenSource(); this.choices = []; this.subscriptions = []; this.templateBlock = new TemplateBlock(); this.currentDisposable = null; this.disposed = false; this.task = () => { for (const choice of this.choices) { if (tryEvaluateExpression(this.context.scope, choice.branche.expression, choice.branche.rawExpression, choice.branche.stackTrace)) { if (choice != this.currentChoice) { this.currentChoice = choice; this.currentDisposable?.dispose(); this.templateBlock.clear(); const content = choice.template.content.cloneNode(true); const context = { directives: this.context.directives, host: this.context.host, parentNode: this.context.parentNode, root: content, scope: { ...this.context.scope }, templateDescriptor: choice.branche.descriptor, }; const disposable = TemplateProcessor.process(context); this.templateBlock.setContent(content); this.currentDisposable = disposable; } return; } } this.currentDisposable?.dispose(); this.templateBlock.clear(); this.currentChoice = undefined; }; this.context = context; assert(templates[0].parentNode); const parent = templates[0].parentNode; this.templateBlock.insertAt(parent, templates[0]); const listener = () => void scheduler.enqueue(this.task, "normal", this.cancellationTokenSource.token); for (let index = 0; index < descriptor.branches.length; index++) { const branche = descriptor.branches[index]; const template = templates[index]; this.subscriptions.push(tryObserveByObservable(context.scope, branche, listener, true)); this.choices.push({ branche, template }); template.remove(); } listener(); } dispose() { if (!this.disposed) { this.cancellationTokenSource.cancel(); this.currentDisposable?.dispose(); this.subscriptions.forEach(x => x.unsubscribe()); this.templateBlock.clear(); this.templateBlock.dispose(); this.disposed = true; } } }