import Attributor from './attributor/attributor';
|
import { Blot, Formattable } from './blot/abstract/blot';
|
|
export interface BlotConstructor {
|
blotName: string;
|
new (node: Node, value?: any): Blot;
|
create(value?: any): Node;
|
}
|
|
export class ParchmentError extends Error {
|
message: string;
|
name: string;
|
stack!: string;
|
|
constructor(message: string) {
|
message = '[Parchment] ' + message;
|
super(message);
|
this.message = message;
|
this.name = (<any>this.constructor).name;
|
}
|
}
|
|
let attributes: { [key: string]: Attributor } = {};
|
let classes: { [key: string]: BlotConstructor } = {};
|
let tags: { [key: string]: BlotConstructor } = {};
|
let types: { [key: string]: Attributor | BlotConstructor } = {};
|
|
export const DATA_KEY = '__blot';
|
|
export enum Scope {
|
TYPE = (1 << 2) - 1, // 0011 Lower two bits
|
LEVEL = ((1 << 2) - 1) << 2, // 1100 Higher two bits
|
|
ATTRIBUTE = (1 << 0) | LEVEL, // 1101
|
BLOT = (1 << 1) | LEVEL, // 1110
|
INLINE = (1 << 2) | TYPE, // 0111
|
BLOCK = (1 << 3) | TYPE, // 1011
|
|
BLOCK_BLOT = BLOCK & BLOT, // 1010
|
INLINE_BLOT = INLINE & BLOT, // 0110
|
BLOCK_ATTRIBUTE = BLOCK & ATTRIBUTE, // 1001
|
INLINE_ATTRIBUTE = INLINE & ATTRIBUTE, // 0101
|
|
ANY = TYPE | LEVEL,
|
}
|
|
export function create(input: Node | string | Scope, value?: any): Blot {
|
let match = query(input);
|
if (match == null) {
|
throw new ParchmentError(`Unable to create ${input} blot`);
|
}
|
let BlotClass = <BlotConstructor>match;
|
let node =
|
// @ts-ignore
|
input instanceof Node || input['nodeType'] === Node.TEXT_NODE ? input : BlotClass.create(value);
|
return new BlotClass(<Node>node, value);
|
}
|
|
export function find(node: Node | null, bubble: boolean = false): Blot | null {
|
if (node == null) return null;
|
// @ts-ignore
|
if (node[DATA_KEY] != null) return node[DATA_KEY].blot;
|
if (bubble) return find(node.parentNode, bubble);
|
return null;
|
}
|
|
export function query(
|
query: string | Node | Scope,
|
scope: Scope = Scope.ANY,
|
): Attributor | BlotConstructor | null {
|
let match;
|
if (typeof query === 'string') {
|
match = types[query] || attributes[query];
|
// @ts-ignore
|
} else if (query instanceof Text || query['nodeType'] === Node.TEXT_NODE) {
|
match = types['text'];
|
} else if (typeof query === 'number') {
|
if (query & Scope.LEVEL & Scope.BLOCK) {
|
match = types['block'];
|
} else if (query & Scope.LEVEL & Scope.INLINE) {
|
match = types['inline'];
|
}
|
} else if (query instanceof HTMLElement) {
|
let names = (query.getAttribute('class') || '').split(/\s+/);
|
for (let i in names) {
|
match = classes[names[i]];
|
if (match) break;
|
}
|
match = match || tags[query.tagName];
|
}
|
if (match == null) return null;
|
// @ts-ignore
|
if (scope & Scope.LEVEL & match.scope && scope & Scope.TYPE & match.scope) return match;
|
return null;
|
}
|
|
export function register(...Definitions: any[]): any {
|
if (Definitions.length > 1) {
|
return Definitions.map(function(d) {
|
return register(d);
|
});
|
}
|
let Definition = Definitions[0];
|
if (typeof Definition.blotName !== 'string' && typeof Definition.attrName !== 'string') {
|
throw new ParchmentError('Invalid definition');
|
} else if (Definition.blotName === 'abstract') {
|
throw new ParchmentError('Cannot register abstract class');
|
}
|
types[Definition.blotName || Definition.attrName] = Definition;
|
if (typeof Definition.keyName === 'string') {
|
attributes[Definition.keyName] = Definition;
|
} else {
|
if (Definition.className != null) {
|
classes[Definition.className] = Definition;
|
}
|
if (Definition.tagName != null) {
|
if (Array.isArray(Definition.tagName)) {
|
Definition.tagName = Definition.tagName.map(function(tagName: string) {
|
return tagName.toUpperCase();
|
});
|
} else {
|
Definition.tagName = Definition.tagName.toUpperCase();
|
}
|
let tagNames = Array.isArray(Definition.tagName) ? Definition.tagName : [Definition.tagName];
|
tagNames.forEach(function(tag: string) {
|
if (tags[tag] == null || Definition.className == null) {
|
tags[tag] = Definition;
|
}
|
});
|
}
|
}
|
return Definition;
|
}
|