@surface/custom-element
Version:
Provides support of directives and data binding on custom elements.
66 lines (65 loc) • 3.13 kB
JavaScript
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;
}
}
}