@@ -68,18 +68,18 @@ <h3>Add a {{ pretty_title }} {{ tab.title() }} from Google Drive</h3>
6868
6969 <!-- Link a FOLDER (import all allowed files) -->
7070 < form method ="post " class ="stack " style ="margin-bottom:1em; ">
71- < div class ="small "> Or link a Drive FOLDER (we’ll import all allowed files directly under it ).</ div >
71+ < div class ="small "> Or link a Drive FOLDER (we’ll import all allowed files, including subfolders ).</ div >
7272 < div >
7373 < input type ="text " name ="drive_folder_link " placeholder ="Drive FOLDER link or folder ID " style ="width:560px " required >
7474 < button type ="submit " name ="link_folder " value ="1 "> Link Folder</ button >
7575 </ div >
7676 </ form >
7777
78- <!-- Upload a ZIP and push to Drive -->
78+ <!-- Upload a ZIP and push to Drive (currently optional) -->
7979 < form method ="post " enctype ="multipart/form-data " class ="stack ">
8080 < div class ="small "> Or upload a .zip; allowed files inside will be uploaded to Drive automatically.</ div >
8181 < div >
82- < input type ="file " name ="zipfile " accept =".zip " required >
82+ < input type ="file " name ="zipfile " accept =".zip ">
8383 < button type ="submit " name ="zip_upload " value ="1 "> Upload ZIP to Drive</ button >
8484 </ div >
8585 </ form >
@@ -115,7 +115,7 @@ <h3>Add a {{ pretty_title }} {{ tab.title() }} from Google Drive</h3>
115115 {% if tab == 'dataset' %}
116116 < td >
117117 {% if admin %}
118- < form method ="post " style ="display:inline; ">
118+ < form method ="post " class =" row-edit " style ="display:inline; ">
119119 < input type ="hidden " name ="row_filename " value ="{{ filename }} ">
120120 < input type ="text " name ="row_source " value ="{{ source or '' }} " size ="18 ">
121121 {% else %}
@@ -131,7 +131,7 @@ <h3>Add a {{ pretty_title }} {{ tab.title() }} from Google Drive</h3>
131131 < button type ="submit " name ="edit_row " value ="1 " style ="margin-left:6px; "> Save</ button >
132132 </ form >
133133 {% else %}
134- < form method ="post " style ="display:inline; ">
134+ < form method ="post " class =" row-edit " style ="display:inline; ">
135135 < input type ="hidden " name ="row_filename " value ="{{ filename }} ">
136136 < input type ="text " name ="row_description " value ="{{ description or '' }} " size ="22 ">
137137 < button type ="submit " name ="edit_row " value ="1 " style ="margin-left:6px; "> Save</ button >
@@ -150,18 +150,18 @@ <h3>Add a {{ pretty_title }} {{ tab.title() }} from Google Drive</h3>
150150
151151 < td >
152152 {% if (storage or 'local') == 'drive' %}
153- {% if preview_url %}< a href ="{{ preview_url }} " target ="_blank "> View</ a > {% endif %}
154- {% if download_url %} | < a href ="{{ download_url }} " target ="_blank "> Download</ a > {% endif %}
153+ {% if preview_url %}< a href ="{{ preview_url }} " target ="_blank " rel =" noopener " > View</ a > {% endif %}
154+ {% if download_url %} | < a href ="{{ download_url }} " target ="_blank " rel =" noopener " > Download</ a > {% endif %}
155155 {% else %}
156156 {% if tab == 'dataset' and (filename.endswith('.csv') or filename.endswith('.npy')) %}
157157 {% set tname = table_map.get(filename) %}
158158 {% if tname %}
159- < a href ="{{ url_for('public_view', table=tname) }} " target ="_blank "> View</ a >
159+ < a href ="{{ url_for('public_view', table=tname) }} " target ="_blank " rel =" noopener " > View</ a >
160160 {% else %}
161161 < span class ="small "> No table yet</ span >
162162 {% endif %}
163163 {% elif tab == 'results' %}
164- < a href ="{{ url_for('view_result_file', property_name=property_name, tab=tab, filename=filename) }} " target ="_blank "> View</ a >
164+ < a href ="{{ url_for('view_result_file', property_name=property_name, tab=tab, filename=filename) }} " target ="_blank " rel =" noopener " > View</ a >
165165 {% endif %}
166166 | < a href ="{{ url_for('uploaded_file', filename=property_name ~ '/' ~ tab ~ '/' ~ filename) }} " download > Download</ a >
167167 {% endif %}
@@ -187,5 +187,37 @@ <h3>Add a {{ pretty_title }} {{ tab.title() }} from Google Drive</h3>
187187 < a class ="return-home " href ="{{ url_for('public_home') }} "> Return to Home</ a >
188188 < a class ="return-home " href ="{{ url_for('materials_portal') }} " style ="margin-left:1.5em; "> Back to Materials Database</ a >
189189 </ div >
190+
191+ {% if admin %}
192+ < script >
193+ // Intercept per-row Save to avoid page reload (preserves other unsaved edits)
194+ document . querySelectorAll ( 'form.row-edit' ) . forEach ( function ( form ) {
195+ form . addEventListener ( 'submit' , async function ( e ) {
196+ e . preventDefault ( ) ;
197+ const fd = new FormData ( form ) ;
198+ // Ensure the intent flag is present
199+ if ( ! fd . has ( 'edit_row' ) ) fd . append ( 'edit_row' , '1' ) ;
200+ const btn = form . querySelector ( 'button[type="submit"]' ) ;
201+ const old = btn . textContent ;
202+ btn . disabled = true ;
203+
204+ try {
205+ const resp = await fetch ( location . href , {
206+ method : 'POST' ,
207+ body : fd ,
208+ headers : { 'X-Requested-With' : 'XMLHttpRequest' }
209+ } ) ;
210+ let data = { } ;
211+ try { data = await resp . json ( ) ; } catch { /* ignore */ }
212+ btn . textContent = data . ok ? 'Saved ✓' : 'Saved' ;
213+ } catch ( err ) {
214+ btn . textContent = 'Error' ;
215+ }
216+
217+ setTimeout ( ( ) => { btn . disabled = false ; btn . textContent = old ; } , 1200 ) ;
218+ } ) ;
219+ } ) ;
220+ </ script >
221+ {% endif %}
190222</ body >
191223</ html >
0 commit comments