import { Schema } from 'prosemirror-model' const brDOM = ['br'] const calcYchangeDomAttrs = (attrs, domAttrs = {}) => { domAttrs = Object.assign({}, domAttrs) if (attrs.ychange !== null) { domAttrs.ychange_user = attrs.ychange.user domAttrs.ychange_state = attrs.ychange.state } return domAttrs } // :: Object // [Specs](#model.NodeSpec) for the nodes defined in this schema. export const nodes = { // :: NodeSpec The top level document node. doc: { content: 'block+' }, // :: NodeSpec A plain paragraph textblock. Represented in the DOM // as a `
` element. paragraph: { attrs: { ychange: { default: null } }, content: 'inline*', group: 'block', parseDOM: [{ tag: 'p' }], toDOM (node) { return ['p', calcYchangeDomAttrs(node.attrs), 0] } }, // :: NodeSpec A blockquote (`
`) wrapping one or more blocks. blockquote: { attrs: { ychange: { default: null } }, content: 'block+', group: 'block', defining: true, parseDOM: [{ tag: 'blockquote' }], toDOM (node) { return ['blockquote', calcYchangeDomAttrs(node.attrs), 0] } }, // :: NodeSpec A horizontal rule (`
`). horizontal_rule: { attrs: { ychange: { default: null } }, group: 'block', parseDOM: [{ tag: 'hr' }], toDOM (node) { return ['hr', calcYchangeDomAttrs(node.attrs)] } }, // :: NodeSpec A heading textblock, with a `level` attribute that // should hold the number 1 to 6. Parsed and serialized as `` to // `
` elements. heading: { attrs: { level: { default: 1 }, ychange: { default: null } }, content: 'inline*', group: 'block', defining: true, parseDOM: [{ tag: 'h1', attrs: { level: 1 } }, { tag: 'h2', attrs: { level: 2 } }, { tag: 'h3', attrs: { level: 3 } }, { tag: 'h4', attrs: { level: 4 } }, { tag: 'h5', attrs: { level: 5 } }, { tag: 'h6', attrs: { level: 6 } }], toDOM (node) { return ['h' + node.attrs.level, calcYchangeDomAttrs(node.attrs), 0] } }, // :: NodeSpec A code listing. Disallows marks or non-text inline // nodes by default. Represented as a `
` element with a // `` element inside of it. code_block: { attrs: { ychange: { default: null } }, content: 'text*', marks: '', group: 'block', code: true, defining: true, parseDOM: [{ tag: 'pre', preserveWhitespace: 'full' }], toDOM (node) { return ['pre', calcYchangeDomAttrs(node.attrs), ['code', 0]] } }, // :: NodeSpec The text node. text: { group: 'inline' }, // :: NodeSpec An inline image (`
`) node. Supports `src`, // `alt`, and `href` attributes. The latter two default to the empty // string. image: { inline: true, attrs: { ychange: { default: null }, src: {}, alt: { default: null }, title: { default: null } }, group: 'inline', draggable: true, parseDOM: [{ tag: 'img[src]', getAttrs (dom) { return { src: dom.getAttribute('src'), title: dom.getAttribute('title'), alt: dom.getAttribute('alt') } } }], toDOM (node) { const domAttrs = { src: node.attrs.src, title: node.attrs.title, alt: node.attrs.alt } return ['img', calcYchangeDomAttrs(node.attrs, domAttrs)] } }, // :: NodeSpec A hard line break, represented in the DOM as `
`. hard_break: { inline: true, group: 'inline', selectable: false, parseDOM: [{ tag: 'br' }], toDOM () { return brDOM } } } const emDOM = ['em', 0]; const strongDOM = ['strong', 0]; const codeDOM = ['code', 0] // :: Object [Specs](#model.MarkSpec) for the marks in the schema. export const marks = { // :: MarkSpec A link. Has `href` and `title` attributes. `title` // defaults to the empty string. Rendered and parsed as an `` // element. link: { attrs: { href: {}, title: { default: null } }, inclusive: false, parseDOM: [{ tag: 'a[href]', getAttrs (dom) { return { href: dom.getAttribute('href'), title: dom.getAttribute('title') } } }], toDOM (node) { return ['a', node.attrs, 0] } }, // :: MarkSpec An emphasis mark. Rendered as an `` element. // Has parse rules that also match `` and `font-style: italic`. em: { parseDOM: [{ tag: 'i' }, { tag: 'em' }, { style: 'font-style=italic' }], toDOM () { return emDOM } }, // :: MarkSpec A strong mark. Rendered as ``, parse rules // also match `` and `font-weight: bold`. strong: { parseDOM: [{ tag: 'strong' }, // This works around a Google Docs misbehavior where // pasted content will be inexplicably wrapped in `` // tags with a font-weight normal. { tag: 'b', getAttrs: node => node.style.fontWeight !== 'normal' && null }, { style: 'font-weight', getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null }], toDOM () { return strongDOM } }, // :: MarkSpec Code font mark. Represented as a `` element. code: { parseDOM: [{ tag: 'code' }], toDOM () { return codeDOM } }, ychange: { attrs: { user: { default: null }, state: { default: null } }, inclusive: false, parseDOM: [{ tag: 'ychange' }], toDOM (node) { return ['ychange', { ychange_user: node.attrs.user, ychange_state: node.attrs.state }, 0] } } } // :: Schema // This schema rougly corresponds to the document schema used by // [CommonMark](http://commonmark.org/), minus the list elements, // which are defined in the [`prosemirror-schema-list`](#schema-list) // module. // // To reuse elements from this schema, extend or read from its // `spec.nodes` and `spec.marks` [properties](#model.Schema.spec). export const schema = new Schema({ nodes, marks })