import { nodes } from 'prosemirror-schema-basic' import type { Node, NodeSpec } from 'prosemirror-model' import { listItem as _listItem } from 'prosemirror-schema-list' interface Attr { [key: string]: number | string } const orderedList: NodeSpec = { attrs: { order: { default: 1, }, listStyleType: { default: '', }, fontsize: { default: '', }, color: { default: '', }, }, content: 'list_item+', group: 'block', parseDOM: [ { tag: 'ol', getAttrs: dom => { const order = ((dom as HTMLElement).hasAttribute('start') ? (dom as HTMLElement).getAttribute('start') : 1) || 1 const attr: Attr = { order: +order } const { listStyleType, fontSize, color } = (dom as HTMLElement).style if (listStyleType) attr['listStyleType'] = listStyleType if (fontSize) attr['fontsize'] = fontSize if (color) attr['color'] = color return attr } } ], toDOM: (node: Node) => { const { order, listStyleType, fontsize, color } = node.attrs let style = '' if (listStyleType) style += `list-style-type: ${listStyleType};` if (fontsize) style += `font-size: ${fontsize};` if (color) style += `color: ${color};` const attr: Attr = { style } if (order !== 1) attr['start'] = order return ['ol', attr, 0] }, } const bulletList: NodeSpec = { attrs: { listStyleType: { default: '', }, fontsize: { default: '', }, color: { default: '', }, }, content: 'list_item+', group: 'block', parseDOM: [ { tag: 'ul', getAttrs: dom => { const attr: Attr = {} const { listStyleType, fontSize, color } = (dom as HTMLElement).style if (listStyleType) attr['listStyleType'] = listStyleType if (fontSize) attr['fontsize'] = fontSize if (color) attr['color'] = color return attr } } ], toDOM: (node: Node) => { const { listStyleType, fontsize, color } = node.attrs let style = '' if (listStyleType) style += `list-style-type: ${listStyleType};` if (fontsize) style += `font-size: ${fontsize};` if (color) style += `color: ${color};` return ['ul', { style }, 0] }, } const listItem: NodeSpec = { ..._listItem, content: 'paragraph block*', group: 'block', } const paragraph: NodeSpec = { attrs: { align: { default: '', }, indent: { default: 0, }, textIndent: { default: 0, }, }, content: 'inline*', group: 'block', parseDOM: [ { tag: 'p', getAttrs: dom => { const { textAlign, textIndent } = (dom as HTMLElement).style let align = (dom as HTMLElement).getAttribute('align') || textAlign || '' align = /(left|right|center|justify)/.test(align) ? align : '' let textIndentLevel = 0 if (textIndent) { if (/em/.test(textIndent)) { textIndentLevel = parseInt(textIndent) } else if (/px/.test(textIndent)) { textIndentLevel = Math.floor(parseInt(textIndent) / 16) if (!textIndentLevel) textIndentLevel = 1 } } const indent = +((dom as HTMLElement).getAttribute('data-indent') || 0) return { align, indent, textIndent: textIndentLevel } } }, { tag: 'img', ignore: true, }, { tag: 'pre', skip: true, }, ], toDOM: (node: Node) => { const { align, indent, textIndent } = node.attrs let style = '' if (align && align !== 'left') style += `text-align: ${align};` if (textIndent) style += `text-indent: ${textIndent}em;` const attr: Attr = { style } if (indent) attr['data-indent'] = indent return ['p', attr, 0] }, } const { doc, blockquote, text, } = nodes export default { doc, paragraph, blockquote, text, 'ordered_list': orderedList, 'bullet_list': bulletList, 'list_item': listItem, }