File: /home/dmstechonline/whatsapp.dmstech.online/node_modules/parchment/src/blot/scroll.ts
import { Blot } from './abstract/blot';
import ContainerBlot from './abstract/container';
import LinkedList from '../collection/linked-list';
import * as Registry from '../registry';
const OBSERVER_CONFIG = {
attributes: true,
characterData: true,
characterDataOldValue: true,
childList: true,
subtree: true,
};
const MAX_OPTIMIZE_ITERATIONS = 100;
class ScrollBlot extends ContainerBlot {
static blotName = 'scroll';
static defaultChild = 'block';
static scope = Registry.Scope.BLOCK_BLOT;
static tagName = 'DIV';
observer: MutationObserver;
constructor(node: HTMLDivElement) {
super(node);
this.scroll = this;
this.observer = new MutationObserver((mutations: MutationRecord[]) => {
this.update(mutations);
});
this.observer.observe(this.domNode, OBSERVER_CONFIG);
this.attach();
}
detach() {
super.detach();
this.observer.disconnect();
}
deleteAt(index: number, length: number): void {
this.update();
if (index === 0 && length === this.length()) {
this.children.forEach(function(child) {
child.remove();
});
} else {
super.deleteAt(index, length);
}
}
formatAt(index: number, length: number, name: string, value: any): void {
this.update();
super.formatAt(index, length, name, value);
}
insertAt(index: number, value: string, def?: any): void {
this.update();
super.insertAt(index, value, def);
}
optimize(context: { [key: string]: any }): void;
optimize(mutations: MutationRecord[], context: { [key: string]: any }): void;
optimize(mutations: any = [], context: any = {}): void {
super.optimize(context);
// We must modify mutations directly, cannot make copy and then modify
let records = [].slice.call(this.observer.takeRecords());
// Array.push currently seems to be implemented by a non-tail recursive function
// so we cannot just mutations.push.apply(mutations, this.observer.takeRecords());
while (records.length > 0) mutations.push(records.pop());
// TODO use WeakMap
let mark = (blot: Blot | null, markParent: boolean = true) => {
if (blot == null || blot === this) return;
if (blot.domNode.parentNode == null) return;
// @ts-ignore
if (blot.domNode[Registry.DATA_KEY].mutations == null) {
// @ts-ignore
blot.domNode[Registry.DATA_KEY].mutations = [];
}
if (markParent) mark(blot.parent);
};
let optimize = function(blot: Blot) {
// Post-order traversal
if (
// @ts-ignore
blot.domNode[Registry.DATA_KEY] == null ||
// @ts-ignore
blot.domNode[Registry.DATA_KEY].mutations == null
) {
return;
}
if (blot instanceof ContainerBlot) {
blot.children.forEach(optimize);
}
blot.optimize(context);
};
let remaining = mutations;
for (let i = 0; remaining.length > 0; i += 1) {
if (i >= MAX_OPTIMIZE_ITERATIONS) {
throw new Error('[Parchment] Maximum optimize iterations reached');
}
remaining.forEach(function(mutation: MutationRecord) {
let blot = Registry.find(mutation.target, true);
if (blot == null) return;
if (blot.domNode === mutation.target) {
if (mutation.type === 'childList') {
mark(Registry.find(mutation.previousSibling, false));
[].forEach.call(mutation.addedNodes, function(node: Node) {
let child = Registry.find(node, false);
mark(child, false);
if (child instanceof ContainerBlot) {
child.children.forEach(function(grandChild: Blot) {
mark(grandChild, false);
});
}
});
} else if (mutation.type === 'attributes') {
mark(blot.prev);
}
}
mark(blot);
});
this.children.forEach(optimize);
remaining = [].slice.call(this.observer.takeRecords());
records = remaining.slice();
while (records.length > 0) mutations.push(records.pop());
}
}
update(mutations?: MutationRecord[], context: { [key: string]: any } = {}): void {
mutations = mutations || this.observer.takeRecords();
// TODO use WeakMap
mutations
.map(function(mutation: MutationRecord) {
let blot = Registry.find(mutation.target, true);
if (blot == null) return null;
// @ts-ignore
if (blot.domNode[Registry.DATA_KEY].mutations == null) {
// @ts-ignore
blot.domNode[Registry.DATA_KEY].mutations = [mutation];
return blot;
} else {
// @ts-ignore
blot.domNode[Registry.DATA_KEY].mutations.push(mutation);
return null;
}
})
.forEach((blot: Blot | null) => {
if (
blot == null ||
blot === this ||
//@ts-ignore
blot.domNode[Registry.DATA_KEY] == null
)
return;
// @ts-ignore
blot.update(blot.domNode[Registry.DATA_KEY].mutations || [], context);
});
// @ts-ignore
if (this.domNode[Registry.DATA_KEY].mutations != null) {
// @ts-ignore
super.update(this.domNode[Registry.DATA_KEY].mutations, context);
}
this.optimize(mutations, context);
}
}
export default ScrollBlot;