Skip to content

Commit 9e9a4e7

Browse files
committed
EasyMDE actions
1 parent 9bf3292 commit 9e9a4e7

File tree

3 files changed

+160
-170
lines changed

3 files changed

+160
-170
lines changed

web_src/js/features/comp/ComboMarkdownEditor.js

Lines changed: 13 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {emojiString} from '../emoji.js';
99
import {renderPreviewPanelContent} from '../repo-editor.js';
1010
import {matchEmoji, matchMention} from '../../utils/match.js';
1111
import {svg} from '../../svg.js';
12+
import {easyMDEToolbarActions} from './EasyMDEToolbarActions.js';
1213

1314
let elementIdCounter = 0;
1415

@@ -42,6 +43,7 @@ class ComboMarkdownEditor {
4243
}
4344

4445
async init() {
46+
this.prepareEasyMDEToolbarActions();
4547
this.setupTab();
4648
this.setupDropzone();
4749
this.setupTextarea();
@@ -203,177 +205,22 @@ class ComboMarkdownEditor {
203205
});
204206
}
205207

206-
prepareEasyMDEToolbarActions(EasyMDE, isWiki) {
208+
prepareEasyMDEToolbarActions() {
207209
this.easyMDEToolbarDefault = [
208-
{
209-
name: 'heading-1',
210-
action: EasyMDE.toggleHeading1,
211-
icon: svg('octicon-heading'),
212-
title: 'Heading',
213-
},
214-
{
215-
name: 'heading-2',
216-
action: EasyMDE.toggleHeading2,
217-
icon: svg('octicon-heading'),
218-
title: 'Heading',
219-
},
220-
{
221-
name: 'heading-3',
222-
action: EasyMDE.toggleHeading3,
223-
icon: svg('octicon-heading'),
224-
title: 'Heading',
225-
},
226-
'|',
227-
{
228-
name: 'bold',
229-
action: EasyMDE.toggleBold,
230-
icon: svg('octicon-bold'),
231-
title: 'Bold',
232-
},
233-
{
234-
name: 'italic',
235-
action: EasyMDE.toggleItalic,
236-
icon: svg('octicon-italic'),
237-
title: 'Italic',
238-
},
239-
{
240-
name: 'strikethrough',
241-
action: EasyMDE.toggleStrikethrough,
242-
icon: svg('octicon-strikethrough'),
243-
title: 'Strikethrough',
244-
},
245-
'|',
246-
{
247-
name: 'quote',
248-
action: EasyMDE.toggleBlockquote,
249-
icon: svg('octicon-quote'),
250-
title: 'Quote',
251-
},
252-
isWiki && 'gitea-code-inline',
253-
{
254-
name: 'code',
255-
action: EasyMDE.toggleCodeBlock,
256-
icon: svg('octicon-code'),
257-
title: 'Code',
258-
},
259-
{
260-
name: 'link',
261-
action: EasyMDE.drawLink,
262-
icon: svg('octicon-link'),
263-
title: 'Link',
264-
},
265-
'|',
266-
{
267-
name: 'unordered-list',
268-
action: EasyMDE.toggleUnorderedList,
269-
icon: svg('octicon-list-unordered'),
270-
title: 'Unordered List',
271-
},
272-
{
273-
name: 'ordered-list',
274-
action: EasyMDE.toggleOrderedList,
275-
icon: svg('octicon-list-ordered'),
276-
title: 'Ordered List',
277-
},
278-
'|',
279-
'gitea-checkbox-empty',
280-
'gitea-checkbox-checked',
281-
'|',
282-
{
283-
name: 'image',
284-
action: EasyMDE.drawImage,
285-
icon: svg('octicon-image'),
286-
title: 'Image',
287-
},
288-
{
289-
name: 'table',
290-
action: EasyMDE.drawTable,
291-
icon: svg('octicon-table'),
292-
title: 'Table',
293-
},
294-
{
295-
name: 'horizontal-rule',
296-
action: EasyMDE.drawHorizontalRule,
297-
icon: svg('octicon-horizontal-rule'),
298-
title: 'Horizontal Rule',
299-
},
300-
isWiki && '|',
301-
isWiki && {
302-
name: 'preview',
303-
action: EasyMDE.togglePreview,
304-
icon: svg('octicon-eye'),
305-
title: 'Preview',
306-
},
307-
isWiki && {
308-
name: 'fullscreen',
309-
action: EasyMDE.toggleFullScreen,
310-
icon: svg('octicon-screen-full'),
311-
title: 'Fullscreen',
312-
},
313-
isWiki && {
314-
name: 'side-by-side',
315-
action: EasyMDE.toggleSideBySide,
316-
icon: svg('octicon-columns'),
317-
title: 'Side by Side',
318-
},
319-
'|',
210+
'bold', 'italic', 'strikethrough', '|', 'heading-1', 'heading-2', 'heading-3', '|',
211+
'code', 'quote', '|', 'gitea-checkbox-empty', 'gitea-checkbox-checked', '|',
212+
'unordered-list', 'ordered-list', '|', 'link', 'image', 'table', 'horizontal-rule', '|',
320213
'gitea-switch-to-textarea',
321-
].filter(Boolean);
322-
323-
this.easyMDEToolbarActions = {
324-
'gitea-checkbox-empty': {
325-
action(e) {
326-
const cm = e.codemirror;
327-
cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`);
328-
cm.focus();
329-
},
330-
icon: svg('gitea-empty-checkbox'),
331-
title: 'Add Checkbox (empty)',
332-
},
333-
'gitea-checkbox-checked': {
334-
action(e) {
335-
const cm = e.codemirror;
336-
cm.replaceSelection(`\n- [x] ${cm.getSelection()}`);
337-
cm.focus();
338-
},
339-
icon: svg('octicon-checkbox'),
340-
title: 'Add Checkbox (checked)',
341-
},
342-
'gitea-switch-to-textarea': {
343-
action: () => {
344-
this.userPreferredEditor = 'textarea';
345-
this.switchToTextarea();
346-
},
347-
icon: svg('octicon-arrow-switch'),
348-
title: 'Revert to simple textarea',
349-
},
350-
'gitea-code-inline': {
351-
action(e) {
352-
const cm = e.codemirror;
353-
const selection = cm.getSelection();
354-
cm.replaceSelection(`\`${selection}\``);
355-
if (!selection) {
356-
const cursorPos = cm.getCursor();
357-
cm.setCursor(cursorPos.line, cursorPos.ch - 1);
358-
}
359-
cm.focus();
360-
},
361-
icon: svg('octicon-chevron-right'),
362-
title: 'Add Inline Code',
363-
}
364-
};
214+
];
365215
}
366216

367-
parseEasyMDEToolbar(actions) {
217+
parseEasyMDEToolbar(EasyMDE, actions) {
218+
this.easyMDEToolbarActions = this.easyMDEToolbarActions || easyMDEToolbarActions(EasyMDE, this);
368219
const processed = [];
369220
for (const action of actions) {
370-
if (typeof action === 'string' && action.startsWith('gitea-')) {
371-
const giteaAction = this.easyMDEToolbarActions[action];
372-
if (!giteaAction) throw new Error(`Unknown EasyMDE toolbar action ${action}`);
373-
processed.push(giteaAction);
374-
} else {
375-
processed.push(action);
376-
}
221+
const actionButton = this.easyMDEToolbarActions[action];
222+
if (!actionButton) throw new Error(`Unknown EasyMDE toolbar action ${action}`);
223+
processed.push(actionButton);
377224
}
378225
return processed;
379226
}
@@ -389,9 +236,6 @@ class ComboMarkdownEditor {
389236
async switchToEasyMDE() {
390237
// EasyMDE's CSS should be loaded via webpack config, otherwise our own styles can not overwrite the default styles.
391238
const {default: EasyMDE} = await import(/* webpackChunkName: "easymde" */'easymde');
392-
393-
this.prepareEasyMDEToolbarActions(EasyMDE, this.options.easyMDEOptions.isWiki);
394-
395239
const easyMDEOpt = {
396240
autoDownloadFontAwesome: false,
397241
element: this.textarea,
@@ -404,7 +248,7 @@ class ComboMarkdownEditor {
404248
nativeSpellcheck: true,
405249
...this.options.easyMDEOptions,
406250
};
407-
easyMDEOpt.toolbar = this.parseEasyMDEToolbar(easyMDEOpt.toolbar ?? this.easyMDEToolbarDefault);
251+
easyMDEOpt.toolbar = this.parseEasyMDEToolbar(EasyMDE, easyMDEOpt.toolbar ?? this.easyMDEToolbarDefault);
408252

409253
this.easyMDE = new EasyMDE(easyMDEOpt);
410254
this.easyMDE.codemirror.on('change', (...args) => {this.options?.onContentChanged?.(this, ...args)});
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import {svg} from '../../svg.js';
2+
3+
export function easyMDEToolbarActions(EasyMDE, editor) {
4+
const actions = {
5+
'|': '|',
6+
'heading-1': {
7+
action: EasyMDE.toggleHeading1,
8+
icon: svg('octicon-heading'),
9+
title: 'Heading',
10+
},
11+
'heading-2': {
12+
action: EasyMDE.toggleHeading2,
13+
icon: svg('octicon-heading'),
14+
title: 'Heading',
15+
},
16+
'heading-3': {
17+
action: EasyMDE.toggleHeading3,
18+
icon: svg('octicon-heading'),
19+
title: 'Heading',
20+
},
21+
'bold': {
22+
action: EasyMDE.toggleBold,
23+
icon: svg('octicon-bold'),
24+
title: 'Bold',
25+
},
26+
'italic': {
27+
action: EasyMDE.toggleItalic,
28+
icon: svg('octicon-italic'),
29+
title: 'Italic',
30+
},
31+
'strikethrough': {
32+
action: EasyMDE.toggleStrikethrough,
33+
icon: svg('octicon-strikethrough'),
34+
title: 'Strikethrough',
35+
},
36+
'quote': {
37+
action: EasyMDE.toggleBlockquote,
38+
icon: svg('octicon-quote'),
39+
title: 'Quote',
40+
},
41+
'code': {
42+
action: EasyMDE.toggleCodeBlock,
43+
icon: svg('octicon-code'),
44+
title: 'Code',
45+
},
46+
'link': {
47+
action: EasyMDE.drawLink,
48+
icon: svg('octicon-link'),
49+
title: 'Link',
50+
},
51+
'unordered-list': {
52+
action: EasyMDE.toggleUnorderedList,
53+
icon: svg('octicon-list-unordered'),
54+
title: 'Unordered List',
55+
},
56+
'ordered-list': {
57+
action: EasyMDE.toggleOrderedList,
58+
icon: svg('octicon-list-ordered'),
59+
title: 'Ordered List',
60+
},
61+
'image': {
62+
action: EasyMDE.drawImage,
63+
icon: svg('octicon-image'),
64+
title: 'Image',
65+
},
66+
'table': {
67+
action: EasyMDE.drawTable,
68+
icon: svg('octicon-table'),
69+
title: 'Table',
70+
},
71+
'horizontal-rule': {
72+
action: EasyMDE.drawHorizontalRule,
73+
icon: svg('octicon-horizontal-rule'),
74+
title: 'Horizontal Rule',
75+
},
76+
'preview': {
77+
action: EasyMDE.togglePreview,
78+
icon: svg('octicon-eye'),
79+
title: 'Preview',
80+
},
81+
'fullscreen': {
82+
action: EasyMDE.toggleFullScreen,
83+
icon: svg('octicon-screen-full'),
84+
title: 'Fullscreen',
85+
},
86+
'side-by-side': {
87+
action: EasyMDE.toggleSideBySide,
88+
icon: svg('octicon-columns'),
89+
title: 'Side by Side',
90+
},
91+
92+
// gitea's custom actions
93+
'gitea-checkbox-empty': {
94+
action(e) {
95+
const cm = e.codemirror;
96+
cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`);
97+
cm.focus();
98+
},
99+
icon: svg('gitea-empty-checkbox'),
100+
title: 'Add Checkbox (empty)',
101+
},
102+
'gitea-checkbox-checked': {
103+
action(e) {
104+
const cm = e.codemirror;
105+
cm.replaceSelection(`\n- [x] ${cm.getSelection()}`);
106+
cm.focus();
107+
},
108+
icon: svg('octicon-checkbox'),
109+
title: 'Add Checkbox (checked)',
110+
},
111+
'gitea-switch-to-textarea': {
112+
action: () => {
113+
editor.userPreferredEditor = 'textarea';
114+
editor.switchToTextarea();
115+
},
116+
icon: svg('octicon-arrow-switch'),
117+
title: 'Revert to simple textarea',
118+
},
119+
'gitea-code-inline': {
120+
action(e) {
121+
const cm = e.codemirror;
122+
const selection = cm.getSelection();
123+
cm.replaceSelection(`\`${selection}\``);
124+
if (!selection) {
125+
const cursorPos = cm.getCursor();
126+
cm.setCursor(cursorPos.line, cursorPos.ch - 1);
127+
}
128+
cm.focus();
129+
},
130+
icon: svg('octicon-chevron-right'),
131+
title: 'Add Inline Code',
132+
}
133+
};
134+
for (const action in actions) {
135+
if (action !== '|') {
136+
actions[action].name = action;
137+
}
138+
}
139+
return actions;
140+
}

web_src/js/features/repo-wiki.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,13 @@ async function initRepoWikiFormEditor() {
5353
previewWiki: true,
5454
easyMDEOptions: {
5555
previewRender: (_content, previewTarget) => previewTarget.innerHTML, // disable builtin preview render
56-
isWiki: true,
56+
toolbar: ['bold', 'italic', 'strikethrough', '|',
57+
'heading-1', 'heading-2', 'heading-3', '|',
58+
'gitea-code-inline', 'code', 'quote', '|', 'gitea-checkbox-empty', 'gitea-checkbox-checked', '|',
59+
'unordered-list', 'ordered-list', '|',
60+
'link', 'image', 'table', 'horizontal-rule', '|',
61+
'preview', 'fullscreen', 'side-by-side', '|', 'gitea-switch-to-textarea'
62+
],
5763
},
5864
});
5965

0 commit comments

Comments
 (0)