nodes.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { nodes } from 'prosemirror-schema-basic';
  2. import type { Node, NodeSpec } from 'prosemirror-model';
  3. import { listItem as _listItem } from 'prosemirror-schema-list';
  4. type Attr = Record<string, number | string>;
  5. const orderedList: NodeSpec = {
  6. attrs: {
  7. order: {
  8. default: 1,
  9. },
  10. listStyleType: {
  11. default: '',
  12. },
  13. fontsize: {
  14. default: '',
  15. },
  16. color: {
  17. default: '',
  18. },
  19. },
  20. content: 'list_item+',
  21. group: 'block',
  22. parseDOM: [
  23. {
  24. tag: 'ol',
  25. getAttrs: (dom) => {
  26. const order =
  27. ((dom as HTMLElement).hasAttribute('start')
  28. ? (dom as HTMLElement).getAttribute('start')
  29. : 1) || 1;
  30. const attr: Attr = { order: +order };
  31. const { listStyleType, fontSize, color } = (dom as HTMLElement).style;
  32. if (listStyleType) attr['listStyleType'] = listStyleType;
  33. if (fontSize) attr['fontsize'] = fontSize;
  34. if (color) attr['color'] = color;
  35. return attr;
  36. },
  37. },
  38. ],
  39. toDOM: (node: Node) => {
  40. const { order, listStyleType, fontsize, color } = node.attrs;
  41. let style = '';
  42. if (listStyleType) style += `list-style-type: ${listStyleType};`;
  43. if (fontsize) style += `font-size: ${fontsize};`;
  44. if (color) style += `color: ${color};`;
  45. const attr: Attr = { style };
  46. if (order !== 1) attr['start'] = order;
  47. return ['ol', attr, 0];
  48. },
  49. };
  50. const bulletList: NodeSpec = {
  51. attrs: {
  52. listStyleType: {
  53. default: '',
  54. },
  55. fontsize: {
  56. default: '',
  57. },
  58. color: {
  59. default: '',
  60. },
  61. },
  62. content: 'list_item+',
  63. group: 'block',
  64. parseDOM: [
  65. {
  66. tag: 'ul',
  67. getAttrs: (dom) => {
  68. const attr: Attr = {};
  69. const { listStyleType, fontSize, color } = (dom as HTMLElement).style;
  70. if (listStyleType) attr['listStyleType'] = listStyleType;
  71. if (fontSize) attr['fontsize'] = fontSize;
  72. if (color) attr['color'] = color;
  73. return attr;
  74. },
  75. },
  76. ],
  77. toDOM: (node: Node) => {
  78. const { listStyleType, fontsize, color } = node.attrs;
  79. let style = '';
  80. if (listStyleType) style += `list-style-type: ${listStyleType};`;
  81. if (fontsize) style += `font-size: ${fontsize};`;
  82. if (color) style += `color: ${color};`;
  83. return ['ul', { style }, 0];
  84. },
  85. };
  86. const listItem: NodeSpec = {
  87. ..._listItem,
  88. content: 'paragraph block*',
  89. group: 'block',
  90. };
  91. const paragraph: NodeSpec = {
  92. attrs: {
  93. align: {
  94. default: '',
  95. },
  96. indent: {
  97. default: 0,
  98. },
  99. textIndent: {
  100. default: 0,
  101. },
  102. },
  103. content: 'inline*',
  104. group: 'block',
  105. parseDOM: [
  106. {
  107. tag: 'p',
  108. getAttrs: (dom) => {
  109. const { textAlign, textIndent } = (dom as HTMLElement).style;
  110. let align = (dom as HTMLElement).getAttribute('align') || textAlign || '';
  111. align = /(left|right|center|justify)/.test(align) ? align : '';
  112. let textIndentLevel = 0;
  113. if (textIndent) {
  114. if (/em/.test(textIndent)) {
  115. textIndentLevel = parseInt(textIndent);
  116. } else if (/px/.test(textIndent)) {
  117. textIndentLevel = Math.floor(parseInt(textIndent) / 16);
  118. if (!textIndentLevel) textIndentLevel = 1;
  119. }
  120. }
  121. const indent = +((dom as HTMLElement).getAttribute('data-indent') || 0);
  122. return { align, indent, textIndent: textIndentLevel };
  123. },
  124. },
  125. {
  126. tag: 'img',
  127. ignore: true,
  128. },
  129. {
  130. tag: 'pre',
  131. skip: true,
  132. },
  133. ],
  134. toDOM: (node: Node) => {
  135. const { align, indent, textIndent } = node.attrs;
  136. let style = '';
  137. if (align && align !== 'left') style += `text-align: ${align};`;
  138. if (textIndent) style += `text-indent: ${textIndent}em;`;
  139. const attr: Attr = { style };
  140. if (indent) attr['data-indent'] = indent;
  141. return ['p', attr, 0];
  142. },
  143. };
  144. const { doc, blockquote, text } = nodes;
  145. const schemaNodes = {
  146. doc,
  147. paragraph,
  148. blockquote,
  149. text,
  150. ordered_list: orderedList,
  151. bullet_list: bulletList,
  152. list_item: listItem,
  153. };
  154. export default schemaNodes;