registry.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import Attributor from './attributor/attributor';
  2. import { Blot, Formattable } from './blot/abstract/blot';
  3. export interface BlotConstructor {
  4. blotName: string;
  5. new (node: Node, value?: any): Blot;
  6. create(value?: any): Node;
  7. }
  8. export class ParchmentError extends Error {
  9. message: string;
  10. name: string;
  11. stack!: string;
  12. constructor(message: string) {
  13. message = '[Parchment] ' + message;
  14. super(message);
  15. this.message = message;
  16. this.name = (<any>this.constructor).name;
  17. }
  18. }
  19. let attributes: { [key: string]: Attributor } = {};
  20. let classes: { [key: string]: BlotConstructor } = {};
  21. let tags: { [key: string]: BlotConstructor } = {};
  22. let types: { [key: string]: Attributor | BlotConstructor } = {};
  23. export const DATA_KEY = '__blot';
  24. export enum Scope {
  25. TYPE = (1 << 2) - 1, // 0011 Lower two bits
  26. LEVEL = ((1 << 2) - 1) << 2, // 1100 Higher two bits
  27. ATTRIBUTE = (1 << 0) | LEVEL, // 1101
  28. BLOT = (1 << 1) | LEVEL, // 1110
  29. INLINE = (1 << 2) | TYPE, // 0111
  30. BLOCK = (1 << 3) | TYPE, // 1011
  31. BLOCK_BLOT = BLOCK & BLOT, // 1010
  32. INLINE_BLOT = INLINE & BLOT, // 0110
  33. BLOCK_ATTRIBUTE = BLOCK & ATTRIBUTE, // 1001
  34. INLINE_ATTRIBUTE = INLINE & ATTRIBUTE, // 0101
  35. ANY = TYPE | LEVEL,
  36. }
  37. export function create(input: Node | string | Scope, value?: any): Blot {
  38. let match = query(input);
  39. if (match == null) {
  40. throw new ParchmentError(`Unable to create ${input} blot`);
  41. }
  42. let BlotClass = <BlotConstructor>match;
  43. let node =
  44. // @ts-ignore
  45. input instanceof Node || input['nodeType'] === Node.TEXT_NODE ? input : BlotClass.create(value);
  46. return new BlotClass(<Node>node, value);
  47. }
  48. export function find(node: Node | null, bubble: boolean = false): Blot | null {
  49. if (node == null) return null;
  50. // @ts-ignore
  51. if (node[DATA_KEY] != null) return node[DATA_KEY].blot;
  52. if (bubble) return find(node.parentNode, bubble);
  53. return null;
  54. }
  55. export function query(
  56. query: string | Node | Scope,
  57. scope: Scope = Scope.ANY,
  58. ): Attributor | BlotConstructor | null {
  59. let match;
  60. if (typeof query === 'string') {
  61. match = types[query] || attributes[query];
  62. // @ts-ignore
  63. } else if (query instanceof Text || query['nodeType'] === Node.TEXT_NODE) {
  64. match = types['text'];
  65. } else if (typeof query === 'number') {
  66. if (query & Scope.LEVEL & Scope.BLOCK) {
  67. match = types['block'];
  68. } else if (query & Scope.LEVEL & Scope.INLINE) {
  69. match = types['inline'];
  70. }
  71. } else if (query instanceof HTMLElement) {
  72. let names = (query.getAttribute('class') || '').split(/\s+/);
  73. for (let i in names) {
  74. match = classes[names[i]];
  75. if (match) break;
  76. }
  77. match = match || tags[query.tagName];
  78. }
  79. if (match == null) return null;
  80. // @ts-ignore
  81. if (scope & Scope.LEVEL & match.scope && scope & Scope.TYPE & match.scope) return match;
  82. return null;
  83. }
  84. export function register(...Definitions: any[]): any {
  85. if (Definitions.length > 1) {
  86. return Definitions.map(function(d) {
  87. return register(d);
  88. });
  89. }
  90. let Definition = Definitions[0];
  91. if (typeof Definition.blotName !== 'string' && typeof Definition.attrName !== 'string') {
  92. throw new ParchmentError('Invalid definition');
  93. } else if (Definition.blotName === 'abstract') {
  94. throw new ParchmentError('Cannot register abstract class');
  95. }
  96. types[Definition.blotName || Definition.attrName] = Definition;
  97. if (typeof Definition.keyName === 'string') {
  98. attributes[Definition.keyName] = Definition;
  99. } else {
  100. if (Definition.className != null) {
  101. classes[Definition.className] = Definition;
  102. }
  103. if (Definition.tagName != null) {
  104. if (Array.isArray(Definition.tagName)) {
  105. Definition.tagName = Definition.tagName.map(function(tagName: string) {
  106. return tagName.toUpperCase();
  107. });
  108. } else {
  109. Definition.tagName = Definition.tagName.toUpperCase();
  110. }
  111. let tagNames = Array.isArray(Definition.tagName) ? Definition.tagName : [Definition.tagName];
  112. tagNames.forEach(function(tag: string) {
  113. if (tags[tag] == null || Definition.className == null) {
  114. tags[tag] = Definition;
  115. }
  116. });
  117. }
  118. }
  119. return Definition;
  120. }