| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- 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;
- }
|