UNPKG

@surface/custom-element

Version:

Provides support of directives and data binding on custom elements.

57 lines (56 loc) 2.44 kB
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); } }