@@ -83,31 +83,13 @@ export class Application implements IApplication {
8383
8484 private initWindowEvents ( ) {
8585 window . onbeforeunload = this . handleWindowUnload ;
86- this . mainWindow ?. addEventListener (
87- "dragstart" ,
88- ( ev ) => {
89- ev . preventDefault ( ) ;
90- } ,
91- false ,
92- ) ;
93- this . mainWindow ?. addEventListener (
94- "dragover" ,
95- ( ev ) => {
96- ev . stopPropagation ( ) ;
97- ev . preventDefault ( ) ;
98- ev . dataTransfer ! . dropEffect = "copy" ;
99- } ,
100- false ,
101- ) ;
102- this . mainWindow ?. addEventListener (
103- "drop" ,
104- ( ev ) => {
105- ev . stopPropagation ( ) ;
106- ev . preventDefault ( ) ;
107- this . importFiles ( ev . dataTransfer ?. files ) ;
108- } ,
109- false ,
110- ) ;
86+ this . mainWindow ?. addEventListener ( "dragstart" , this . handleDragStart , false ) ;
87+ // Use capture to intercept file-drop before nested widgets call stopPropagation().
88+ this . mainWindow ?. addEventListener ( "dragover" , this . handleDragOver , true ) ;
89+ this . mainWindow ?. addEventListener ( "drop" , this . handleDrop , true ) ;
90+ // Fallback: catch drag/drop anywhere in page, also in capture phase.
91+ window . addEventListener ( "dragover" , this . handleDragOver , true ) ;
92+ window . addEventListener ( "drop" , this . handleDrop , true ) ;
11193 }
11294
11395 private readonly handleWindowUnload = ( event : BeforeUnloadEvent ) => {
@@ -119,6 +101,25 @@ export class Application implements IApplication {
119101 }
120102 } ;
121103
104+ private readonly handleDragStart = ( ev : DragEvent ) => {
105+ ev . preventDefault ( ) ;
106+ } ;
107+
108+ private readonly handleDragOver = ( ev : DragEvent ) => {
109+ ev . stopPropagation ( ) ;
110+ ev . preventDefault ( ) ;
111+ if ( ev . dataTransfer ) {
112+ ev . dataTransfer . dropEffect = "copy" ;
113+ }
114+ } ;
115+
116+ private readonly handleDrop = ( ev : DragEvent ) => {
117+ ev . stopPropagation ( ) ;
118+ ev . preventDefault ( ) ;
119+ const files = this . extractDroppedFiles ( ev . dataTransfer ) ;
120+ this . importFiles ( files ) ;
121+ } ;
122+
122123 async importFiles ( files : File [ ] | FileList | undefined ) {
123124 if ( ! files || files . length === 0 ) {
124125 return ;
@@ -162,9 +163,10 @@ export class Application implements IApplication {
162163 const imports : File [ ] = [ ] ;
163164 const plugins : File [ ] = [ ] ;
164165 for ( const element of files ) {
165- if ( element . name . endsWith ( DOCUMENT_FILE_EXTENSION ) ) {
166+ const fileName = element . name . toLowerCase ( ) ;
167+ if ( fileName . endsWith ( DOCUMENT_FILE_EXTENSION ) ) {
166168 opens . push ( element ) ;
167- } else if ( element . name . endsWith ( PLUGIN_FILE_EXTENSION ) ) {
169+ } else if ( fileName . endsWith ( PLUGIN_FILE_EXTENSION ) ) {
168170 plugins . push ( element ) ;
169171 } else {
170172 imports . push ( element ) ;
@@ -173,6 +175,17 @@ export class Application implements IApplication {
173175 return { opens, imports, plugins } ;
174176 }
175177
178+ private extractDroppedFiles ( dataTransfer : DataTransfer | null ) : File [ ] {
179+ if ( ! dataTransfer ) return [ ] ;
180+ const fromFileList = Array . from ( dataTransfer . files ?? [ ] ) ;
181+ if ( fromFileList . length > 0 ) return fromFileList ;
182+ const fromItems = Array . from ( dataTransfer . items ?? [ ] )
183+ . filter ( ( item ) => item . kind === "file" )
184+ . map ( ( item ) => item . getAsFile ( ) )
185+ . filter ( ( file ) : file is File => file !== null ) ;
186+ return fromItems ;
187+ }
188+
176189 async openDocument ( id : string ) : Promise < IDocument | undefined > {
177190 const document = await Document . open ( this , id ) ;
178191 await this . createActiveView ( document ) ;
0 commit comments