@@ -3,14 +3,19 @@ import '@github/text-expander-element';
33import $ from 'jquery' ;
44import { attachTribute } from '../tribute.ts' ;
55import { hideElem , showElem , autosize , isElemVisible } from '../../utils/dom.ts' ;
6- import { initEasyMDEPaste , initTextareaEvents } from './EditorUpload.ts' ;
6+ import {
7+ EventUploadStateChanged ,
8+ initEasyMDEPaste ,
9+ initTextareaEvents ,
10+ triggerUploadStateChanged ,
11+ } from './EditorUpload.ts' ;
712import { handleGlobalEnterQuickSubmit } from './QuickSubmit.ts' ;
813import { renderPreviewPanelContent } from '../repo-editor.ts' ;
914import { easyMDEToolbarActions } from './EasyMDEToolbarActions.ts' ;
1015import { initTextExpander } from './TextExpander.ts' ;
1116import { showErrorToast } from '../../modules/toast.ts' ;
1217import { POST } from '../../modules/fetch.ts' ;
13- import { initTextareaMarkdown } from './EditorMarkdown.ts' ;
18+ import { EventEditorContentChanged , initTextareaMarkdown , triggerEditorContentChanged } from './EditorMarkdown.ts' ;
1419import { DropzoneCustomEventReloadFiles , initDropzone } from '../dropzone.ts' ;
1520
1621let elementIdCounter = 0 ;
@@ -37,7 +42,34 @@ export function validateTextareaNonEmpty(textarea) {
3742 return true ;
3843}
3944
40- class ComboMarkdownEditor {
45+ export class ComboMarkdownEditor {
46+ static EventEditorContentChanged = EventEditorContentChanged ;
47+ static EventUploadStateChanged = EventUploadStateChanged ;
48+
49+ public container : HTMLElement ;
50+
51+ // TODO: use correct types to replace these "any" types
52+ options : any ;
53+
54+ tabEditor : HTMLElement ;
55+ tabPreviewer : HTMLElement ;
56+
57+ easyMDE : any ;
58+ easyMDEToolbarActions : any ;
59+ easyMDEToolbarDefault : any ;
60+
61+ textarea : HTMLTextAreaElement & { _giteaComboMarkdownEditor : any } ;
62+ textareaMarkdownToolbar : HTMLElement ;
63+ textareaAutosize : any ;
64+
65+ dropzone : HTMLElement ;
66+ attachedDropzoneInst : any ;
67+
68+ previewUrl : string ;
69+ previewContext : string ;
70+ previewMode : string ;
71+ previewWiki : boolean ;
72+
4173 constructor ( container , options = { } ) {
4274 container . _giteaComboMarkdownEditor = this ;
4375 this . options = options ;
@@ -63,14 +95,13 @@ class ComboMarkdownEditor {
6395
6496 setupContainer ( ) {
6597 initTextExpander ( this . container . querySelector ( 'text-expander' ) ) ;
66- this . container . addEventListener ( 'ce-editor-content-changed' , ( e ) => this . options ?. onContentChanged ?.( this , e ) ) ;
6798 }
6899
69100 setupTextarea ( ) {
70101 this . textarea = this . container . querySelector ( '.markdown-text-editor' ) ;
71102 this . textarea . _giteaComboMarkdownEditor = this ;
72103 this . textarea . id = `_combo_markdown_editor_${ String ( elementIdCounter ++ ) } ` ;
73- this . textarea . addEventListener ( 'input' , ( e ) => this . options ?. onContentChanged ?. ( this , e ) ) ;
104+ this . textarea . addEventListener ( 'input' , ( ) => triggerEditorContentChanged ( this . container ) ) ;
74105 this . applyEditorHeights ( this . textarea , this . options . editorHeights ) ;
75106
76107 if ( this . textarea . getAttribute ( 'data-disable-autosize' ) !== 'true' ) {
@@ -115,15 +146,21 @@ class ComboMarkdownEditor {
115146
116147 async setupDropzone ( ) {
117148 const dropzoneParentContainer = this . container . getAttribute ( 'data-dropzone-parent-container' ) ;
118- if ( dropzoneParentContainer ) {
119- this . dropzone = this . container . closest ( this . container . getAttribute ( 'data-dropzone-parent-container' ) ) ?. querySelector ( '.dropzone' ) ;
120- if ( this . dropzone ) this . attachedDropzoneInst = await initDropzone ( this . dropzone ) ;
121- }
149+ if ( ! dropzoneParentContainer ) return ;
150+ this . dropzone = this . container . closest ( this . container . getAttribute ( 'data-dropzone-parent-container' ) ) ?. querySelector ( '.dropzone' ) ;
151+ if ( ! this . dropzone ) return ;
152+
153+ this . attachedDropzoneInst = await initDropzone ( this . dropzone ) ;
154+ // dropzone events
155+ // * "processing" means a file is being uploaded
156+ // * "queuecomplete" means all files have been uploaded
157+ this . attachedDropzoneInst . on ( 'processing' , ( ) => triggerUploadStateChanged ( this . container ) ) ;
158+ this . attachedDropzoneInst . on ( 'queuecomplete' , ( ) => triggerUploadStateChanged ( this . container ) ) ;
122159 }
123160
124161 dropzoneGetFiles ( ) {
125162 if ( ! this . dropzone ) return null ;
126- return Array . from ( this . dropzone . querySelectorAll ( '.files [name=files]' ) , ( el ) => el . value ) ;
163+ return Array . from ( this . dropzone . querySelectorAll < HTMLInputElement > ( '.files [name=files]' ) , ( el ) => el . value ) ;
127164 }
128165
129166 dropzoneReloadFiles ( ) {
@@ -137,8 +174,13 @@ class ComboMarkdownEditor {
137174 this . attachedDropzoneInst . emit ( DropzoneCustomEventReloadFiles ) ;
138175 }
139176
177+ isUploading ( ) {
178+ if ( ! this . dropzone ) return false ;
179+ return this . attachedDropzoneInst . getQueuedFiles ( ) . length || this . attachedDropzoneInst . getUploadingFiles ( ) . length ;
180+ }
181+
140182 setupTab ( ) {
141- const tabs = this . container . querySelectorAll ( '.tabular.menu > .item' ) ;
183+ const tabs = this . container . querySelectorAll < HTMLElement > ( '.tabular.menu > .item' ) ;
142184
143185 // Fomantic Tab requires the "data-tab" to be globally unique.
144186 // So here it uses our defined "data-tab-for" and "data-tab-panel" to generate the "data-tab" attribute for Fomantic.
@@ -170,7 +212,7 @@ class ComboMarkdownEditor {
170212 formData . append ( 'mode' , this . previewMode ) ;
171213 formData . append ( 'context' , this . previewContext ) ;
172214 formData . append ( 'text' , this . value ( ) ) ;
173- formData . append ( 'wiki' , this . previewWiki ) ;
215+ formData . append ( 'wiki' , String ( this . previewWiki ) ) ;
174216 const response = await POST ( this . previewUrl , { data : formData } ) ;
175217 const data = await response . text ( ) ;
176218 renderPreviewPanelContent ( $ ( panelPreviewer ) , data ) ;
@@ -237,24 +279,24 @@ class ComboMarkdownEditor {
237279 easyMDEOpt . toolbar = this . parseEasyMDEToolbar ( EasyMDE , easyMDEOpt . toolbar ?? this . easyMDEToolbarDefault ) ;
238280
239281 this . easyMDE = new EasyMDE ( easyMDEOpt ) ;
240- this . easyMDE . codemirror . on ( 'change' , ( ... args ) => { this . options ?. onContentChanged ?. ( this , ... args ) } ) ;
282+ this . easyMDE . codemirror . on ( 'change' , ( ) => triggerEditorContentChanged ( this . container ) ) ;
241283 this . easyMDE . codemirror . setOption ( 'extraKeys' , {
242284 'Cmd-Enter' : ( cm ) => handleGlobalEnterQuickSubmit ( cm . getTextArea ( ) ) ,
243285 'Ctrl-Enter' : ( cm ) => handleGlobalEnterQuickSubmit ( cm . getTextArea ( ) ) ,
244286 Enter : ( cm ) => {
245- const tributeContainer = document . querySelector ( '.tribute-container' ) ;
287+ const tributeContainer = document . querySelector < HTMLElement > ( '.tribute-container' ) ;
246288 if ( ! tributeContainer || tributeContainer . style . display === 'none' ) {
247289 cm . execCommand ( 'newlineAndIndent' ) ;
248290 }
249291 } ,
250292 Up : ( cm ) => {
251- const tributeContainer = document . querySelector ( '.tribute-container' ) ;
293+ const tributeContainer = document . querySelector < HTMLElement > ( '.tribute-container' ) ;
252294 if ( ! tributeContainer || tributeContainer . style . display === 'none' ) {
253295 return cm . execCommand ( 'goLineUp' ) ;
254296 }
255297 } ,
256298 Down : ( cm ) => {
257- const tributeContainer = document . querySelector ( '.tribute-container' ) ;
299+ const tributeContainer = document . querySelector < HTMLElement > ( '.tribute-container' ) ;
258300 if ( ! tributeContainer || tributeContainer . style . display === 'none' ) {
259301 return cm . execCommand ( 'goLineDown' ) ;
260302 }
@@ -314,13 +356,7 @@ export function getComboMarkdownEditor(el) {
314356 return el ?. _giteaComboMarkdownEditor ;
315357}
316358
317- export async function initComboMarkdownEditor ( container , options = { } ) {
318- if ( container instanceof $ ) {
319- if ( container . length !== 1 ) {
320- throw new Error ( 'initComboMarkdownEditor: container must be a single element' ) ;
321- }
322- container = container [ 0 ] ;
323- }
359+ export async function initComboMarkdownEditor ( container : HTMLElement , options = { } ) {
324360 if ( ! container ) {
325361 throw new Error ( 'initComboMarkdownEditor: container is null' ) ;
326362 }
0 commit comments