zhangjian
2023-06-05 0976d2d0f90cff460cedfdc8bd74e98c2c31a58c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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;
}