]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/defaults/form-definitions.ts
6c0a54f2333024acff0aede76846f85d4e99d762
[bookstack] / resources / js / wysiwyg / ui / defaults / form-definitions.ts
1 import {EditorFormDefinition, EditorFormTabs, EditorSelectFormFieldDefinition} from "../framework/forms";
2 import {EditorUiContext} from "../framework/core";
3 import {$createLinkNode} from "@lexical/link";
4 import {$createTextNode, $getSelection, LexicalNode} from "lexical";
5 import {$createImageNode} from "../../nodes/image";
6 import {setEditorContentFromHtml} from "../../actions";
7 import {$createMediaNodeFromHtml, $createMediaNodeFromSrc, $isMediaNode, MediaNode} from "../../nodes/media";
8 import {$getNodeFromSelection} from "../../helpers";
9 import {$insertNodeToNearestRoot} from "@lexical/utils";
10
11
12 export const link: EditorFormDefinition = {
13     submitText: 'Apply',
14     async action(formData, context: EditorUiContext) {
15         context.editor.update(() => {
16
17             const selection = $getSelection();
18
19             const linkNode = $createLinkNode(formData.get('url')?.toString() || '', {
20                 title: formData.get('title')?.toString() || '',
21                 target: formData.get('target')?.toString() || '',
22             });
23             linkNode.append($createTextNode(formData.get('text')?.toString() || ''));
24
25             selection?.insertNodes([linkNode]);
26         });
27         return true;
28     },
29     fields: [
30         {
31             label: 'URL',
32             name: 'url',
33             type: 'text',
34         },
35         {
36             label: 'Text to display',
37             name: 'text',
38             type: 'text',
39         },
40         {
41             label: 'Title',
42             name: 'title',
43             type: 'text',
44         },
45         {
46             label: 'Open link in...',
47             name: 'target',
48             type: 'select',
49             valuesByLabel: {
50                 'Current window': '',
51                 'New window': '_blank',
52             }
53         } as EditorSelectFormFieldDefinition,
54     ],
55 };
56
57 export const image: EditorFormDefinition = {
58     submitText: 'Apply',
59     async action(formData, context: EditorUiContext) {
60         context.editor.update(() => {
61             const selection = $getSelection();
62             const imageNode = $createImageNode(formData.get('src')?.toString() || '', {
63                 alt: formData.get('alt')?.toString() || '',
64                 height: Number(formData.get('height')?.toString() || '0'),
65                 width: Number(formData.get('width')?.toString() || '0'),
66             });
67             selection?.insertNodes([imageNode]);
68         });
69         return true;
70     },
71     fields: [
72         {
73             label: 'Source',
74             name: 'src',
75             type: 'text',
76         },
77         {
78             label: 'Alternative description',
79             name: 'alt',
80             type: 'text',
81         },
82         {
83             label: 'Width',
84             name: 'width',
85             type: 'text',
86         },
87         {
88             label: 'Height',
89             name: 'height',
90             type: 'text',
91         },
92     ],
93 };
94
95 export const media: EditorFormDefinition = {
96     submitText: 'Save',
97     async action(formData, context: EditorUiContext) {
98         const selectedNode: MediaNode|null = await (new Promise((res, rej) => {
99             context.editor.getEditorState().read(() => {
100                 const node = $getNodeFromSelection($getSelection(), $isMediaNode);
101                 res(node as MediaNode|null);
102             });
103         }));
104
105         const embedCode = (formData.get('embed') || '').toString().trim();
106         if (embedCode) {
107             context.editor.update(() => {
108                 const node = $createMediaNodeFromHtml(embedCode);
109                 if (selectedNode && node) {
110                     selectedNode.replace(node)
111                 } else if (node) {
112                     $insertNodeToNearestRoot(node);
113                 }
114             });
115
116             return true;
117         }
118
119         context.editor.update(() => {
120             const src = (formData.get('src') || '').toString().trim();
121             const height = (formData.get('height') || '').toString().trim();
122             const width = (formData.get('width') || '').toString().trim();
123
124             const updateNode = selectedNode || $createMediaNodeFromSrc(src);
125             updateNode.setSrc(src);
126             updateNode.setWidthAndHeight(width, height);
127             if (!selectedNode) {
128                 $insertNodeToNearestRoot(updateNode);
129             }
130         });
131
132         return true;
133     },
134     fields: [
135         {
136             build() {
137                 return new EditorFormTabs([
138                     {
139                         label: 'General',
140                         contents: [
141                             {
142                                 label: 'Source',
143                                 name: 'src',
144                                 type: 'text',
145                             },
146                             {
147                                 label: 'Width',
148                                 name: 'width',
149                                 type: 'text',
150                             },
151                             {
152                                 label: 'Height',
153                                 name: 'height',
154                                 type: 'text',
155                             },
156                         ],
157                     },
158                     {
159                         label: 'Embed',
160                         contents: [
161                             {
162                                 label: 'Paste your embed code below:',
163                                 name: 'embed',
164                                 type: 'textarea',
165                             },
166                         ],
167                     }
168                 ])
169             }
170         },
171     ],
172 };
173
174 export const source: EditorFormDefinition = {
175     submitText: 'Save',
176     async action(formData, context: EditorUiContext) {
177         setEditorContentFromHtml(context.editor, formData.get('source')?.toString() || '');
178         return true;
179     },
180     fields: [
181         {
182             label: 'Source',
183             name: 'source',
184             type: 'textarea',
185         },
186     ],
187 };