@@ -5,10 +5,9 @@ import {attachTribute} from '../tribute.js';
5
5
import { hideElem , showElem , autosize } from '../../utils/dom.js' ;
6
6
import { initEasyMDEImagePaste , initTextareaImagePaste } from './ImagePaste.js' ;
7
7
import { handleGlobalEnterQuickSubmit } from './QuickSubmit.js' ;
8
- import { emojiString } from '../emoji.js' ;
9
8
import { renderPreviewPanelContent } from '../repo-editor.js' ;
10
- import { matchEmoji , matchMention } from '../../utils/match.js' ;
11
9
import { svg } from '../../svg.js' ;
10
+ import { initTributeExpander } from './TributeExpander.js' ;
12
11
13
12
let elementIdCounter = 0 ;
14
13
@@ -43,14 +42,12 @@ class ComboMarkdownEditor {
43
42
44
43
async init ( ) {
45
44
this . prepareEasyMDEToolbarActions ( ) ;
45
+ this . setupContainer ( ) ;
46
46
this . setupTab ( ) ;
47
47
this . setupDropzone ( ) ;
48
48
this . setupTextarea ( ) ;
49
- this . setupExpander ( ) ;
50
49
51
- if ( this . userPreferredEditor === 'easymde' ) {
52
- await this . switchToEasyMDE ( ) ;
53
- }
50
+ await this . switchToUserPreference ( ) ;
54
51
}
55
52
56
53
applyEditorHeights ( el , heights ) {
@@ -60,6 +57,11 @@ class ComboMarkdownEditor {
60
57
if ( heights . maxHeight ) el . style . maxHeight = heights . maxHeight ;
61
58
}
62
59
60
+ setupContainer ( ) {
61
+ initTributeExpander ( this . container . querySelector ( 'text-expander' ) ) ;
62
+ this . container . addEventListener ( 'ce-editor-content-changed' , ( e ) => this . options ?. onContentChanged ?. ( this , e ) ) ;
63
+ }
64
+
63
65
setupTextarea ( ) {
64
66
this . textarea = this . container . querySelector ( '.markdown-text-editor' ) ;
65
67
this . textarea . _giteaComboMarkdownEditor = this ;
@@ -103,64 +105,6 @@ class ComboMarkdownEditor {
103
105
}
104
106
}
105
107
106
- setupExpander ( ) {
107
- const expander = this . container . querySelector ( 'text-expander' ) ;
108
- expander ?. addEventListener ( 'text-expander-change' , ( { detail : { key, provide, text} } ) => {
109
- if ( key === ':' ) {
110
- const matches = matchEmoji ( text ) ;
111
- if ( ! matches . length ) return provide ( { matched : false } ) ;
112
-
113
- const ul = document . createElement ( 'ul' ) ;
114
- ul . classList . add ( 'suggestions' ) ;
115
- for ( const name of matches ) {
116
- const emoji = emojiString ( name ) ;
117
- const li = document . createElement ( 'li' ) ;
118
- li . setAttribute ( 'role' , 'option' ) ;
119
- li . setAttribute ( 'data-value' , emoji ) ;
120
- li . textContent = `${ emoji } ${ name } ` ;
121
- ul . append ( li ) ;
122
- }
123
-
124
- provide ( { matched : true , fragment : ul } ) ;
125
- } else if ( key === '@' ) {
126
- const matches = matchMention ( text ) ;
127
- if ( ! matches . length ) return provide ( { matched : false } ) ;
128
-
129
- const ul = document . createElement ( 'ul' ) ;
130
- ul . classList . add ( 'suggestions' ) ;
131
- for ( const { value, name, fullname, avatar} of matches ) {
132
- const li = document . createElement ( 'li' ) ;
133
- li . setAttribute ( 'role' , 'option' ) ;
134
- li . setAttribute ( 'data-value' , `${ key } ${ value } ` ) ;
135
-
136
- const img = document . createElement ( 'img' ) ;
137
- img . src = avatar ;
138
- li . append ( img ) ;
139
-
140
- const nameSpan = document . createElement ( 'span' ) ;
141
- nameSpan . textContent = name ;
142
- li . append ( nameSpan ) ;
143
-
144
- if ( fullname && fullname . toLowerCase ( ) !== name ) {
145
- const fullnameSpan = document . createElement ( 'span' ) ;
146
- fullnameSpan . classList . add ( 'fullname' ) ;
147
- fullnameSpan . textContent = fullname ;
148
- li . append ( fullnameSpan ) ;
149
- }
150
-
151
- ul . append ( li ) ;
152
- }
153
-
154
- provide ( { matched : true , fragment : ul } ) ;
155
- }
156
- } ) ;
157
- expander ?. addEventListener ( 'text-expander-value' , ( { detail} ) => {
158
- if ( detail ?. item ) {
159
- detail . value = detail . item . getAttribute ( 'data-value' ) ;
160
- }
161
- } ) ;
162
- }
163
-
164
108
setupDropzone ( ) {
165
109
const dropzoneParentContainer = this . container . getAttribute ( 'data-dropzone-parent-container' ) ;
166
110
if ( dropzoneParentContainer ) {
@@ -270,7 +214,16 @@ class ComboMarkdownEditor {
270
214
return processed ;
271
215
}
272
216
217
+ async switchToUserPreference ( ) {
218
+ if ( this . userPreferredEditor === 'easymde' ) {
219
+ await this . switchToEasyMDE ( ) ;
220
+ } else {
221
+ this . switchToTextarea ( ) ;
222
+ }
223
+ }
224
+
273
225
switchToTextarea ( ) {
226
+ if ( ! this . easyMDE ) return ;
274
227
showElem ( this . textareaMarkdownToolbar ) ;
275
228
if ( this . easyMDE ) {
276
229
this . easyMDE . toTextArea ( ) ;
@@ -279,6 +232,8 @@ class ComboMarkdownEditor {
279
232
}
280
233
281
234
async switchToEasyMDE ( ) {
235
+ if ( this . easyMDE ) return ;
236
+
282
237
// EasyMDE's CSS should be loaded via webpack config, otherwise our own styles can not overwrite the default styles.
283
238
const { default : EasyMDE } = await import ( /* webpackChunkName: "easymde" */ 'easymde' ) ;
284
239
const easyMDEOpt = {
0 commit comments