@@ -28,7 +28,7 @@ fileInput.onchange = updateFiles;
2828function updateFiles ( ) {
2929 if ( fileInput . files . length > 0 ) {
3030 const fileName = document . querySelector ( "#inputs_file_name" ) ;
31- fileName . innerHTML = "" ;
31+ fileName . replaceChildren ( ) ;
3232
3333 // Update the selectedFiles array
3434 const newFiles = Array . from ( fileInput . files ) ;
@@ -40,22 +40,40 @@ function updateFiles() {
4040 selectedFiles = selectedFiles . concat ( filteredNewFiles ) ;
4141
4242 for ( let file of selectedFiles ) {
43- const fileNameWithoutSpaces = file . name . replace ( / \s / g, '' ) ;
44- fileName . innerHTML += `
45- <span class="is-flex is-justify-content-space-between is-block" id="file-name-${ fileNameWithoutSpaces } ">
46- <span class="is-block">${ file . name } </span>
47- <a href="#" onclick="removeFile('${ fileNameWithoutSpaces } ')" class="model-button" id="file-delete-btn-${ fileNameWithoutSpaces } ">
48- <i class="fa-solid fa-trash-can"></i>
49- </a>
50- </span>
51- ` ;
52- document . getElementById ( "file-delete-btn-" + fileNameWithoutSpaces ) . addEventListener ( "click" , function ( event ) {
43+ const fileNameWithoutSpaces = file . name . replace ( / \s / g, "" ) ;
44+
45+ // Build the wrapper span
46+ const wrapper = document . createElement ( "span" ) ;
47+ wrapper . className = "is-flex is-justify-content-space-between is-block" ;
48+ wrapper . id = `file-name-${ fileNameWithoutSpaces } ` ;
49+
50+ // File name label - textContent is safe, no HTML injection possible
51+ const label = document . createElement ( "span" ) ;
52+ label . className = "is-block" ;
53+ label . textContent = file . name ;
54+
55+ // Delete button
56+ const deleteLink = document . createElement ( "a" ) ;
57+ deleteLink . href = "#" ;
58+ deleteLink . className = "model-button" ;
59+ deleteLink . id = `file-delete-btn-${ fileNameWithoutSpaces } ` ;
60+ deleteLink . addEventListener ( "click" , function ( event ) {
5361 disableEvent ( event ) ;
5462 removeFile ( fileNameWithoutSpaces ) ;
55- if ( selectedFiles . length == 0 ) {
56- fileName . innerHTML = "<i>No files selected</i>"
63+ if ( selectedFiles . length == 0 ) {
64+ const emptyNotice = document . createElement ( "i" ) ;
65+ emptyNotice . textContent = "No files selected" ;
66+ fileName . replaceChildren ( emptyNotice ) ;
5767 }
5868 } ) ;
69+
70+ const icon = document . createElement ( "i" ) ;
71+ icon . className = "fa-solid fa-trash-can" ;
72+
73+ deleteLink . appendChild ( icon ) ;
74+ wrapper . appendChild ( label ) ;
75+ wrapper . appendChild ( deleteLink ) ;
76+ fileName . appendChild ( wrapper ) ;
5977 }
6078 }
6179}
@@ -68,7 +86,7 @@ function disableEvent(event) {
6886
6987function removeFile ( fileName ) {
7088 selectedFiles = selectedFiles . filter ( file => {
71- const fileNameWithoutSpaces = file . name . replace ( / \s / g, '' ) ;
89+ const fileNameWithoutSpaces = file . name . replace ( / \s / g, "" ) ;
7290 return fileNameWithoutSpaces !== fileName ;
7391 } ) ;
7492
@@ -87,18 +105,10 @@ function removeFile(fileName) {
87105
88106function dropHandler ( event ) {
89107 disableEvent ( event ) ;
90- const droppedFiles = event . dataTransfer . files ;
91- const updatedFilesSet = new Set ( Array . from ( fileInput . files ) ) ;
92-
93- for ( let file of droppedFiles ) {
94- updatedFilesSet . add ( file ) ;
95- }
96-
97- // Convert the Set back to an array if needed
98- const updatedFiles = Array . from ( updatedFilesSet ) ;
99108
109+ // Merge existing files and dropped files, let updateFiles handle dedup
100110 const dataTransfer = new DataTransfer ( ) ;
101- for ( let file of updatedFiles ) {
111+ for ( const file of [ ... fileInput . files , ... event . dataTransfer . files ] ) {
102112 dataTransfer . items . add ( file ) ;
103113 }
104114
0 commit comments