]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/defaults/form-definitions.ts
a2242c338739f8993939a755eb3964e13c399b1b
[bookstack] / resources / js / wysiwyg / ui / defaults / form-definitions.ts
1 import {EditorFormDefinition, 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             label: 'Source',
137             name: 'src',
138             type: 'text',
139         },
140         {
141             label: 'Width',
142             name: 'width',
143             type: 'text',
144         },
145         {
146             label: 'Height',
147             name: 'height',
148             type: 'text',
149         },
150         // TODO - Tabbed interface to separate this option
151         {
152             label: 'Paste your embed code below:',
153             name: 'embed',
154             type: 'textarea',
155         },
156     ],
157 };
158
159 export const source: EditorFormDefinition = {
160     submitText: 'Save',
161     async action(formData, context: EditorUiContext) {
162         setEditorContentFromHtml(context.editor, formData.get('source')?.toString() || '');
163         return true;
164     },
165     fields: [
166         {
167             label: 'Source',
168             name: 'source',
169             type: 'textarea',
170         },
171     ],
172 };