11// src/controller.ts
22import { Controller } from "@hotwired/stimulus" ;
33var controller_default = class extends Controller {
4+ constructor ( ) {
5+ super ( ...arguments ) ;
6+ this . files = /* @__PURE__ */ new Map ( ) ;
7+ }
48 initialize ( ) {
59 this . clear = this . clear . bind ( this ) ;
610 this . onInputChange = this . onInputChange . bind ( this ) ;
@@ -9,72 +13,125 @@ var controller_default = class extends Controller {
913 }
1014 connect ( ) {
1115 this . clear ( ) ;
12- this . previewClearButtonTarget . addEventListener ( "click" , this . clear ) ;
1316 this . inputTarget . addEventListener ( "change" , this . onInputChange ) ;
1417 this . element . addEventListener ( "dragenter" , this . onDragEnter ) ;
1518 this . element . addEventListener ( "dragleave" , this . onDragLeave ) ;
1619 this . dispatchEvent ( "connect" ) ;
1720 }
1821 disconnect ( ) {
19- this . previewClearButtonTarget . removeEventListener ( "click" , this . clear ) ;
2022 this . inputTarget . removeEventListener ( "change" , this . onInputChange ) ;
2123 this . element . removeEventListener ( "dragenter" , this . onDragEnter ) ;
2224 this . element . removeEventListener ( "dragleave" , this . onDragLeave ) ;
2325 }
24- clear ( ) {
25- this . inputTarget . value = "" ;
26- this . inputTarget . style . display = "block" ;
27- this . placeholderTarget . style . display = "block" ;
28- this . previewTarget . style . display = "none" ;
29- this . previewImageTarget . style . display = "none" ;
30- this . previewImageTarget . style . backgroundImage = "none" ;
31- this . previewFilenameTarget . textContent = "" ;
26+ clear ( event ) {
27+ if ( event ?. params ) {
28+ const filename = event . params . filename ;
29+ if ( filename && this . files . has ( filename ) ) {
30+ this . files . delete ( filename ) ;
31+ this . updateFileInput ( ) ;
32+ this . renderPreview ( ) ;
33+ }
34+ }
35+ if ( ! this . inputTarget || ! this . inputTarget . files || this . inputTarget ?. files ?. length === 0 ) {
36+ this . placeholderTarget . style . display = "block" ;
37+ if ( ! this . isMultiple ) {
38+ this . inputTarget . style . display = "block" ;
39+ }
40+ }
3241 this . dispatchEvent ( "clear" ) ;
3342 }
34- onInputChange ( event ) {
35- const file = event . target . files [ 0 ] ;
36- if ( typeof file === "undefined" ) {
43+ onInputChange ( ) {
44+ const files = this . inputTarget . files ;
45+ if ( ! files || files . length <= 0 ) {
3746 return ;
3847 }
39- this . inputTarget . style . display = "none" ;
40- this . placeholderTarget . style . display = "none" ;
41- this . previewFilenameTarget . textContent = file . name ;
42- this . previewTarget . style . display = "flex" ;
43- this . previewImageTarget . style . display = "none" ;
44- if ( file . type && file . type . indexOf ( "image" ) !== - 1 ) {
45- this . _populateImagePreview ( file ) ;
48+ if ( ! this . isMultiple && this . files . size > 0 ) {
49+ this . inputTarget . style . display = "none" ;
4650 }
47- this . dispatchEvent ( "change" , file ) ;
51+ const selectedFiles = this . isMultiple ? Array . from ( files ) : Array . from ( files ) . slice ( 0 , 1 ) ;
52+ this . addFiles ( selectedFiles ) ;
53+ this . updateFileInput ( ) ;
54+ this . renderPreview ( ) ;
55+ this . dispatchEvent ( "change" , files ) ;
4856 }
49- _populateImagePreview ( file ) {
50- if ( typeof FileReader === "undefined" ) {
51- return ;
57+ renderPreview ( ) {
58+ this . clearPreviewContainer ( ) ;
59+ for ( const file of this . files . values ( ) ) {
60+ const preview = this . buildPreview ( file ) ;
61+ if ( preview ) {
62+ this . previewContainerTarget . appendChild ( preview ) ;
63+ }
64+ }
65+ if ( this . previewTargets . length > 1 ) {
66+ this . placeholderTarget . style . display = "none" ;
67+ if ( ! this . isMultiple ) {
68+ this . inputTarget . style . display = "none" ;
69+ } else {
70+ this . inputTarget . style . display = "block" ;
71+ }
72+ }
73+ }
74+ clearPreviewContainer ( ) {
75+ const previews = this . previewTargets ;
76+ previews . slice ( 1 ) . forEach ( ( el ) => el . remove ( ) ) ;
77+ }
78+ buildPreview ( file , element ) {
79+ if ( ! element ) {
80+ element = this . previewContainerTarget . firstElementChild ?. cloneNode ( true ) ;
81+ }
82+ element . style . display = "flex" ;
83+ const fileName = element . querySelector ( ".dropzone-preview-filename" ) ;
84+ if ( fileName ) {
85+ fileName . textContent = file . name ;
86+ }
87+ const button = element . querySelector ( ".dropzone-preview-button" ) ;
88+ if ( button ) {
89+ button . setAttribute ( "data-symfony--ux-dropzone--dropzone-filename-param" , file . name ) ;
90+ }
91+ this . _populateImagePreview ( element , file ) ;
92+ return element ;
93+ }
94+ _populateImagePreview ( element , file ) {
95+ const image = element . querySelector ( ".dropzone-preview-image" ) ;
96+ if ( image && this . isImage ( file ) && typeof FileReader !== "undefined" ) {
97+ const reader = new FileReader ( ) ;
98+ reader . addEventListener ( "load" , ( event ) => {
99+ image . querySelector ( ".dropzone-preview-image" ) ?. remove ( ) ;
100+ image . style . backgroundImage = `url('${ event . target . result } ')` ;
101+ image . style . display = "block" ;
102+ } ) ;
103+ reader . readAsDataURL ( file ) ;
52104 }
53- const reader = new FileReader ( ) ;
54- reader . addEventListener ( "load" , ( event ) => {
55- this . previewImageTarget . style . display = "block" ;
56- this . previewImageTarget . style . backgroundImage = `url("${ event . target . result } ")` ;
57- } ) ;
58- reader . readAsDataURL ( file ) ;
59105 }
60106 onDragEnter ( ) {
61107 this . inputTarget . style . display = "block" ;
62- this . placeholderTarget . style . display = "block" ;
63- this . previewTarget . style . display = "none" ;
64108 }
65109 onDragLeave ( event ) {
66110 event . preventDefault ( ) ;
67- if ( ! this . element . contains ( event . relatedTarget ) ) {
68- this . inputTarget . style . display = "none" ;
69- this . placeholderTarget . style . display = "none" ;
70- this . previewTarget . style . display = "block" ;
111+ }
112+ updateFileInput ( ) {
113+ const dataTransfer = new DataTransfer ( ) ;
114+ for ( const file of this . files . values ( ) ) {
115+ dataTransfer . items . add ( file ) ;
116+ }
117+ this . inputTarget . files = dataTransfer . files ;
118+ }
119+ addFiles ( files ) {
120+ for ( const file of files ) {
121+ this . files . set ( file . name , file ) ;
71122 }
72123 }
124+ isImage ( file ) {
125+ return typeof file . type !== "undefined" && file . type . indexOf ( "image" ) !== - 1 ;
126+ }
127+ get isMultiple ( ) {
128+ return this . inputTarget . multiple ;
129+ }
73130 dispatchEvent ( name , payload = { } ) {
74131 this . dispatch ( name , { detail : payload , prefix : "dropzone" } ) ;
75132 }
76133} ;
77- controller_default . targets = [ "input" , "placeholder" , "preview" , "previewClearButton" , "previewFilename" , "previewImage" ] ;
134+ controller_default . targets = [ "input" , "placeholder" , "preview" , "previewClearButton" , "previewFilename" , "previewImage" , "previewContainer" ] ;
78135export {
79136 controller_default as default
80137} ;
0 commit comments