123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- import ParchmentError from '../../error.js';
- import Registry from '../../registry.js';
- import Scope from '../../scope.js';
- import type {
- Blot,
- BlotConstructor,
- Formattable,
- Parent,
- Root,
- } from './blot.js';
- class ShadowBlot implements Blot {
- public static blotName = 'abstract';
- public static className: string;
- public static requiredContainer: BlotConstructor;
- public static scope: Scope;
- public static tagName: string | string[];
- public static create(rawValue?: unknown): Node {
- if (this.tagName == null) {
- throw new ParchmentError('Blot definition missing tagName');
- }
- let node: HTMLElement;
- let value: string | number | undefined;
- if (Array.isArray(this.tagName)) {
- if (typeof rawValue === 'string') {
- value = rawValue.toUpperCase();
- if (parseInt(value, 10).toString() === value) {
- value = parseInt(value, 10);
- }
- } else if (typeof rawValue === 'number') {
- value = rawValue;
- }
- if (typeof value === 'number') {
- node = document.createElement(this.tagName[value - 1]);
- } else if (value && this.tagName.indexOf(value) > -1) {
- node = document.createElement(value);
- } else {
- node = document.createElement(this.tagName[0]);
- }
- } else {
- node = document.createElement(this.tagName);
- }
- if (this.className) {
- node.classList.add(this.className);
- }
- return node;
- }
- public prev: Blot | null;
- public next: Blot | null;
- // @ts-expect-error Fix me later
- public parent: Parent;
- // Hack for accessing inherited static methods
- get statics(): any {
- return this.constructor;
- }
- constructor(
- public scroll: Root,
- public domNode: Node,
- ) {
- Registry.blots.set(domNode, this);
- this.prev = null;
- this.next = null;
- }
- public attach(): void {
- // Nothing to do
- }
- public clone(): Blot {
- const domNode = this.domNode.cloneNode(false);
- return this.scroll.create(domNode);
- }
- public detach(): void {
- if (this.parent != null) {
- this.parent.removeChild(this);
- }
- Registry.blots.delete(this.domNode);
- }
- public deleteAt(index: number, length: number): void {
- const blot = this.isolate(index, length);
- blot.remove();
- }
- public formatAt(
- index: number,
- length: number,
- name: string,
- value: any,
- ): void {
- const blot = this.isolate(index, length);
- if (this.scroll.query(name, Scope.BLOT) != null && value) {
- blot.wrap(name, value);
- } else if (this.scroll.query(name, Scope.ATTRIBUTE) != null) {
- const parent = this.scroll.create(this.statics.scope) as Parent &
- Formattable;
- blot.wrap(parent);
- parent.format(name, value);
- }
- }
- public insertAt(index: number, value: string, def?: any): void {
- const blot =
- def == null
- ? this.scroll.create('text', value)
- : this.scroll.create(value, def);
- const ref = this.split(index);
- this.parent.insertBefore(blot, ref || undefined);
- }
- public isolate(index: number, length: number): Blot {
- const target = this.split(index);
- if (target == null) {
- throw new Error('Attempt to isolate at end');
- }
- target.split(length);
- return target;
- }
- public length(): number {
- return 1;
- }
- public offset(root: Blot = this.parent): number {
- if (this.parent == null || this === root) {
- return 0;
- }
- return this.parent.children.offset(this) + this.parent.offset(root);
- }
- public optimize(_context?: { [key: string]: any }): void {
- if (
- this.statics.requiredContainer &&
- !(this.parent instanceof this.statics.requiredContainer)
- ) {
- this.wrap(this.statics.requiredContainer.blotName);
- }
- }
- public remove(): void {
- if (this.domNode.parentNode != null) {
- this.domNode.parentNode.removeChild(this.domNode);
- }
- this.detach();
- }
- public replaceWith(name: string | Blot, value?: any): Blot {
- const replacement =
- typeof name === 'string' ? this.scroll.create(name, value) : name;
- if (this.parent != null) {
- this.parent.insertBefore(replacement, this.next || undefined);
- this.remove();
- }
- return replacement;
- }
- public split(index: number, _force?: boolean): Blot | null {
- return index === 0 ? this : this.next;
- }
- public update(
- _mutations: MutationRecord[],
- _context: { [key: string]: any },
- ): void {
- // Nothing to do by default
- }
- public wrap(name: string | Parent, value?: any): Parent {
- const wrapper =
- typeof name === 'string'
- ? (this.scroll.create(name, value) as Parent)
- : name;
- if (this.parent != null) {
- this.parent.insertBefore(wrapper, this.next || undefined);
- }
- if (typeof wrapper.appendChild !== 'function') {
- throw new ParchmentError(`Cannot wrap ${name}`);
- }
- wrapper.appendChild(this);
- return wrapper;
- }
- }
- export default ShadowBlot;
|