@@ -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 ( ) {
@@ -139,11 +176,11 @@ class ComboMarkdownEditor {
139176
140177 isUploading ( ) {
141178 if ( ! this . dropzone ) return false ;
142- return this . attachedDropzoneInst . getUploadingFiles ( ) . length !== 0 ;
179+ return this . attachedDropzoneInst . getQueuedFiles ( ) . length || this . attachedDropzoneInst . getUploadingFiles ( ) . length ;
143180 }
144181
145182 setupTab ( ) {
146- const tabs = this . container . querySelectorAll ( '.tabular.menu > .item' ) ;
183+ const tabs = this . container . querySelectorAll < HTMLElement > ( '.tabular.menu > .item' ) ;
147184
148185 // Fomantic Tab requires the "data-tab" to be globally unique.
149186 // So here it uses our defined "data-tab-for" and "data-tab-panel" to generate the "data-tab" attribute for Fomantic.
@@ -175,7 +212,7 @@ class ComboMarkdownEditor {
175212 formData . append ( 'mode' , this . previewMode ) ;
176213 formData . append ( 'context' , this . previewContext ) ;
177214 formData . append ( 'text' , this . value ( ) ) ;
178- formData . append ( 'wiki' , this . previewWiki ) ;
215+ formData . append ( 'wiki' , String ( this . previewWiki ) ) ;
179216 const response = await POST ( this . previewUrl , { data : formData } ) ;
180217 const data = await response . text ( ) ;
181218 renderPreviewPanelContent ( $ ( panelPreviewer ) , data ) ;
@@ -242,24 +279,24 @@ class ComboMarkdownEditor {
242279 easyMDEOpt . toolbar = this . parseEasyMDEToolbar ( EasyMDE , easyMDEOpt . toolbar ?? this . easyMDEToolbarDefault ) ;
243280
244281 this . easyMDE = new EasyMDE ( easyMDEOpt ) ;
245- this . easyMDE . codemirror . on ( 'change' , ( ... args ) => { this . options ?. onContentChanged ?. ( this , ... args ) } ) ;
282+ this . easyMDE . codemirror . on ( 'change' , ( ) => triggerEditorContentChanged ( this . container ) ) ;
246283 this . easyMDE . codemirror . setOption ( 'extraKeys' , {
247284 'Cmd-Enter' : ( cm ) => handleGlobalEnterQuickSubmit ( cm . getTextArea ( ) ) ,
248285 'Ctrl-Enter' : ( cm ) => handleGlobalEnterQuickSubmit ( cm . getTextArea ( ) ) ,
249286 Enter : ( cm ) => {
250- const tributeContainer = document . querySelector ( '.tribute-container' ) ;
287+ const tributeContainer = document . querySelector < HTMLElement > ( '.tribute-container' ) ;
251288 if ( ! tributeContainer || tributeContainer . style . display === 'none' ) {
252289 cm . execCommand ( 'newlineAndIndent' ) ;
253290 }
254291 } ,
255292 Up : ( cm ) => {
256- const tributeContainer = document . querySelector ( '.tribute-container' ) ;
293+ const tributeContainer = document . querySelector < HTMLElement > ( '.tribute-container' ) ;
257294 if ( ! tributeContainer || tributeContainer . style . display === 'none' ) {
258295 return cm . execCommand ( 'goLineUp' ) ;
259296 }
260297 } ,
261298 Down : ( cm ) => {
262- const tributeContainer = document . querySelector ( '.tribute-container' ) ;
299+ const tributeContainer = document . querySelector < HTMLElement > ( '.tribute-container' ) ;
263300 if ( ! tributeContainer || tributeContainer . style . display === 'none' ) {
264301 return cm . execCommand ( 'goLineDown' ) ;
265302 }
@@ -319,13 +356,7 @@ export function getComboMarkdownEditor(el) {
319356 return el ?. _giteaComboMarkdownEditor ;
320357}
321358
322- export async function initComboMarkdownEditor ( container , options = { } ) {
323- if ( container instanceof $ ) {
324- if ( container . length !== 1 ) {
325- throw new Error ( 'initComboMarkdownEditor: container must be a single element' ) ;
326- }
327- container = container [ 0 ] ;
328- }
359+ export async function initComboMarkdownEditor ( container : HTMLElement , options = { } ) {
329360 if ( ! container ) {
330361 throw new Error ( 'initComboMarkdownEditor: container is null' ) ;
331362 }
0 commit comments