schema-basic.ts (5350B)
1 import {Schema, NodeSpec, MarkSpec, DOMOutputSpec} from "prosemirror-model" 2 3 const pDOM: DOMOutputSpec = ["p", 0], blockquoteDOM: DOMOutputSpec = ["blockquote", 0], 4 hrDOM: DOMOutputSpec = ["hr"], preDOM: DOMOutputSpec = ["pre", ["code", 0]], 5 brDOM: DOMOutputSpec = ["br"] 6 7 /// [Specs](#model.NodeSpec) for the nodes defined in this schema. 8 export const nodes = { 9 /// NodeSpec The top level document node. 10 doc: { 11 content: "block+" 12 } as NodeSpec, 13 14 /// A plain paragraph textblock. Represented in the DOM 15 /// as a `<p>` element. 16 paragraph: { 17 content: "inline*", 18 group: "block", 19 parseDOM: [{tag: "p"}], 20 toDOM() { return pDOM } 21 } as NodeSpec, 22 23 /// A blockquote (`<blockquote>`) wrapping one or more blocks. 24 blockquote: { 25 content: "block+", 26 group: "block", 27 defining: true, 28 parseDOM: [{tag: "blockquote"}], 29 toDOM() { return blockquoteDOM } 30 } as NodeSpec, 31 32 /// A horizontal rule (`<hr>`). 33 horizontal_rule: { 34 group: "block", 35 parseDOM: [{tag: "hr"}], 36 toDOM() { return hrDOM } 37 } as NodeSpec, 38 39 /// A heading textblock, with a `level` attribute that 40 /// should hold the number 1 to 6. Parsed and serialized as `<h1>` to 41 /// `<h6>` elements. 42 heading: { 43 attrs: {level: {default: 1, validate: "number"}}, 44 content: "inline*", 45 group: "block", 46 defining: true, 47 parseDOM: [{tag: "h1", attrs: {level: 1}}, 48 {tag: "h2", attrs: {level: 2}}, 49 {tag: "h3", attrs: {level: 3}}, 50 {tag: "h4", attrs: {level: 4}}, 51 {tag: "h5", attrs: {level: 5}}, 52 {tag: "h6", attrs: {level: 6}}], 53 toDOM(node) { return ["h" + node.attrs.level, 0] } 54 } as NodeSpec, 55 56 /// A code listing. Disallows marks or non-text inline 57 /// nodes by default. Represented as a `<pre>` element with a 58 /// `<code>` element inside of it. 59 code_block: { 60 content: "text*", 61 marks: "", 62 group: "block", 63 code: true, 64 defining: true, 65 parseDOM: [{tag: "pre", preserveWhitespace: "full"}], 66 toDOM() { return preDOM } 67 } as NodeSpec, 68 69 /// The text node. 70 text: { 71 group: "inline" 72 } as NodeSpec, 73 74 /// An inline image (`<img>`) node. Supports `src`, 75 /// `alt`, and `href` attributes. The latter two default to the empty 76 /// string. 77 image: { 78 inline: true, 79 attrs: { 80 src: {validate: "string"}, 81 alt: {default: null, validate: "string|null"}, 82 title: {default: null, validate: "string|null"} 83 }, 84 group: "inline", 85 draggable: true, 86 parseDOM: [{tag: "img[src]", getAttrs(dom: HTMLElement) { 87 return { 88 src: dom.getAttribute("src"), 89 title: dom.getAttribute("title"), 90 alt: dom.getAttribute("alt") 91 } 92 }}], 93 toDOM(node) { let {src, alt, title} = node.attrs; return ["img", {src, alt, title}] } 94 } as NodeSpec, 95 96 /// A hard line break, represented in the DOM as `<br>`. 97 hard_break: { 98 inline: true, 99 group: "inline", 100 selectable: false, 101 parseDOM: [{tag: "br"}], 102 toDOM() { return brDOM } 103 } as NodeSpec 104 } 105 106 const emDOM: DOMOutputSpec = ["em", 0], strongDOM: DOMOutputSpec = ["strong", 0], codeDOM: DOMOutputSpec = ["code", 0] 107 108 /// [Specs](#model.MarkSpec) for the marks in the schema. 109 export const marks = { 110 /// A link. Has `href` and `title` attributes. `title` 111 /// defaults to the empty string. Rendered and parsed as an `<a>` 112 /// element. 113 link: { 114 attrs: { 115 href: {validate: "string"}, 116 title: {default: null, validate: "string|null"} 117 }, 118 inclusive: false, 119 parseDOM: [{tag: "a[href]", getAttrs(dom: HTMLElement) { 120 return {href: dom.getAttribute("href"), title: dom.getAttribute("title")} 121 }}], 122 toDOM(node) { let {href, title} = node.attrs; return ["a", {href, title}, 0] } 123 } as MarkSpec, 124 125 /// An emphasis mark. Rendered as an `<em>` element. Has parse rules 126 /// that also match `<i>` and `font-style: italic`. 127 em: { 128 parseDOM: [ 129 {tag: "i"}, {tag: "em"}, 130 {style: "font-style=italic"}, 131 {style: "font-style=normal", clearMark: m => m.type.name == "em"} 132 ], 133 toDOM() { return emDOM } 134 } as MarkSpec, 135 136 /// A strong mark. Rendered as `<strong>`, parse rules also match 137 /// `<b>` and `font-weight: bold`. 138 strong: { 139 parseDOM: [ 140 {tag: "strong"}, 141 // This works around a Google Docs misbehavior where 142 // pasted content will be inexplicably wrapped in `<b>` 143 // tags with a font-weight normal. 144 {tag: "b", getAttrs: (node: HTMLElement) => node.style.fontWeight != "normal" && null}, 145 {style: "font-weight=400", clearMark: m => m.type.name == "strong"}, 146 {style: "font-weight", getAttrs: (value: string) => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null}, 147 ], 148 toDOM() { return strongDOM } 149 } as MarkSpec, 150 151 /// Code font mark. Represented as a `<code>` element. 152 code: { 153 code: true, 154 parseDOM: [{tag: "code"}], 155 toDOM() { return codeDOM } 156 } as MarkSpec 157 } 158 159 /// This schema roughly corresponds to the document schema used by 160 /// [CommonMark](http://commonmark.org/), minus the list elements, 161 /// which are defined in the [`prosemirror-schema-list`](#schema-list) 162 /// module. 163 /// 164 /// To reuse elements from this schema, extend or read from its 165 /// `spec.nodes` and `spec.marks` [properties](#model.Schema.spec). 166 export const schema = new Schema({nodes, marks})