@surface/custom-element
Version:
Provides support of directives and data binding on custom elements.
57 lines (56 loc) • 2.44 kB
JavaScript
import { CancellationTokenSource, hasValue } from "@surface/core";
import Observer, { Metadata } from "@surface/observer";
export default class AsyncObserver extends Observer {
constructor(root, path, scheduler) {
super(root, path);
this.cancellationTokenSource = new CancellationTokenSource();
this.scheduler = scheduler;
}
static observePath(root, path, observer) {
if (root instanceof HTMLElement && (root.contentEditable == "true" || root.nodeName == "INPUT")) {
const [key, ...keys] = path;
const metadata = Metadata.from(root);
this.observeComputed(root, key, metadata, observer);
let subject = metadata.subjects.get(key);
if (!subject) {
const action = (event) => {
event.stopImmediatePropagation();
for (const [observer] of Metadata.from(root).subjects.get(key)) {
observer.notify();
}
};
root.addEventListener("input", action);
this.observeProperty(root, key);
metadata.subjects.set(key, subject = new Map());
}
subject.set(observer, keys);
const property = root[key];
if (keys.length > 0 && hasValue(property)) {
this.observePath(property, keys, observer);
}
}
else {
super.observePath(root, path, observer);
}
}
static observe(root, path, scheduler) {
if (scheduler) {
const key = path.join("\u{fffff}");
const metadata = Metadata.from(root);
let observer = metadata.observers.get(key);
if (!observer) {
this.observePath(root, path, observer = new AsyncObserver(root, path, scheduler));
metadata.observers.set(key, observer);
metadata.disposables.push({ dispose: () => this.unobservePath(root, path, observer) });
}
return observer;
}
return super.observe(root, path);
}
notify() {
const task = () => super.notify();
this.cancellationTokenSource.cancel();
this.cancellationTokenSource = new CancellationTokenSource();
void this.scheduler.enqueue(task, "high", this.cancellationTokenSource.token);
}
}