]> BookStack Code Mirror - bookstack/blob - resources/js/editor/markdown-serializer.js
Added image resizing via drag handles
[bookstack] / resources / js / editor / markdown-serializer.js
1 import {MarkdownSerializer, defaultMarkdownSerializer, MarkdownSerializerState} from "prosemirror-markdown";
2 import {docToHtml} from "./util";
3
4 const nodes = defaultMarkdownSerializer.nodes;
5 const marks = defaultMarkdownSerializer.marks;
6
7
8 nodes.callout = function (state, node) {
9     writeNodeAsHtml(state, node);
10 };
11
12 function isPlainURL(link, parent, index, side) {
13     if (link.attrs.title || !/^\w+:/.test(link.attrs.href)) {
14         return false
15     }
16     const content = parent.child(index + (side < 0 ? -1 : 0));
17     if (!content.isText || content.text != link.attrs.href || content.marks[content.marks.length - 1] != link) {
18         return false
19     }
20     if (index == (side < 0 ? 1 : parent.childCount - 1)) {
21         return true
22     }
23     const next = parent.child(index + (side < 0 ? -2 : 1));
24     return !link.isInSet(next.marks)
25 }
26
27 marks.link = {
28     open(state, mark, parent, index) {
29         const attrs = mark.attrs;
30         if (attrs.target) {
31             return `<a href="${attrs.target}" ${attrs.title ? `title="${attrs.title}"` : ''} target="${attrs.target}">`
32         }
33         return isPlainURL(mark, parent, index, 1) ? "<" : "["
34     },
35     close(state, mark, parent, index) {
36         if (mark.attrs.target) {
37             return `</a>`;
38         }
39         return isPlainURL(mark, parent, index, -1) ? ">"
40             : "](" + state.esc(mark.attrs.href) + (mark.attrs.title ? " " + state.quote(mark.attrs.title) : "") + ")"
41     }
42 };
43
44 marks.underline = {
45     open: '<span style="text-decoration: underline;">',
46     close: '</span>',
47 };
48
49 marks.strike = {
50     open: '<span style="text-decoration: line-through;">',
51     close: '</span>',
52 };
53
54 marks.superscript = {
55     open: '<sup>',
56     close: '</sup>',
57 };
58
59 marks.subscript = {
60     open: '<sub>',
61     close: '</sub>',
62 };
63
64 marks.text_color = {
65     open(state, mark, parent, index) {
66         return `<span style="color: ${mark.attrs.color};">`
67     },
68     close: '</span>',
69 };
70
71 marks.background_color = {
72     open(state, mark, parent, index) {
73         return `<span style="background-color: ${mark.attrs.color};">`
74     },
75     close: '</span>',
76 };
77
78 /**
79  * @param {MarkdownSerializerState} state
80  * @param node
81  */
82 function writeNodeAsHtml(state, node) {
83     const html = docToHtml({content: [node]});
84     state.write(html);
85     state.ensureNewLine();
86     state.write('\n');
87     state.closeBlock();
88 }
89
90 // Update serializers to just write out as HTML if we have an attribute
91 // or element that cannot be represented in commonmark without losing
92 // formatting or content.
93 for (const [nodeType, serializerFunction] of Object.entries(nodes)) {
94     nodes[nodeType] = function (state, node, parent, index) {
95         if (node.attrs.align || node.attrs.height || node.attrs.width) {
96             writeNodeAsHtml(state, node);
97         } else {
98             serializerFunction(state, node, parent, index);
99         }
100     }
101 }
102
103
104 const serializer = new MarkdownSerializer(nodes, marks);
105
106 export default serializer;