@@ -287,6 +287,10 @@ <h3>Edit Settings</h3>
287287 < button id ="editDelete " class ="btn btn-danger w-100 mb-2 " onclick ="handleDelete() " disabled > Delete</ button >
288288 < button id ="editClear " class ="btn btn-secondary w-100 " onclick ="ClearEditFields() " disabled > Clear</ button >
289289 </ div >
290+ < div class ="d-flex gap-1 ">
291+ < button id ="editMoveUp " class ="btn btn-outline-secondary flex-fill " onclick ="handleMoveUp() " title ="Move Up " disabled > < i class ="fas fa-arrow-up "> </ i > </ button >
292+ < button id ="editMoveDown " class ="btn btn-outline-secondary flex-fill " onclick ="handleMoveDown() " title ="Move Down " disabled > < i class ="fas fa-arrow-down "> </ i > </ button >
293+ </ div >
290294 < div >
291295 < button id ="saveEditButton " class ="btn btn-success " onclick ="saveEditSettings() " disabled > Save</ button >
292296 </ div >
@@ -357,6 +361,7 @@ <h2 class="text-center">Websites Preview</h2>
357361 let settings = { } ,
358362 currentEditTab = 'engine' ,
359363 selectedItem = null ,
364+ pendingReorder = false ,
360365 pendingChanges = { add : [ ] , upd : [ ] , del : [ ] } ;
361366
362367 // [DEBUG]: reference variables for debugging
@@ -406,7 +411,9 @@ <h2 class="text-center">Websites Preview</h2>
406411 editList = document . getElementById ( 'editList' ) ,
407412 editAction = document . getElementById ( 'editAction' ) ,
408413 editDelete = document . getElementById ( 'editDelete' ) ,
409- editClear = document . getElementById ( 'editClear' ) ;
414+ editClear = document . getElementById ( 'editClear' ) ,
415+ editMoveUp = document . getElementById ( 'editMoveUp' ) ,
416+ editMoveDown = document . getElementById ( 'editMoveDown' ) ;
410417
411418 // Create simple select options
412419 function populateOptions ( elem , items , selected = null ) {
@@ -801,6 +808,7 @@ <h2 class="text-center">Websites Preview</h2>
801808 }
802809
803810 function handleItemSelect ( ) {
811+ if ( pendingReorder ) { updateMoveButtons ( ) ; return ; } // reorder in progress — update boundary buttons, ignore CRUD
804812 editName . value = selectedItem = editList . value ;
805813 editDelete . disabled = editClear . disabled = false ;
806814 editAction . textContent = 'Update' ;
@@ -809,6 +817,7 @@ <h2 class="text-center">Websites Preview</h2>
809817 editValue . value = pendingChanges . add . find ( i => i . name === selectedItem ) ?. value ||
810818 pendingChanges . upd . find ( i => i . name === selectedItem ) ?. value ||
811819 '' ;
820+ updateMoveButtons ( ) ;
812821 }
813822
814823 function handleAction ( ) { // handles Add/Update actions only
@@ -868,12 +877,22 @@ <h2 class="text-center">Websites Preview</h2>
868877 function __postActionReset ( ) { // common reset tasks after Add/Update/Delete
869878 ClearEditFields ( ) ;
870879 saveEditBtn . disabled = ! ( pendingChanges . add . length || pendingChanges . upd . length || pendingChanges . del . length ) ;
880+ updateMoveButtons ( ) ; // move buttons only enabled when no CRUD changes pending
881+ }
882+
883+ function __postMoveReset ( ) { // common reset tasks after Move Up/Down
884+ pendingReorder = true ;
885+ saveEditBtn . disabled = false ;
886+ updateMoveButtons ( ) ;
887+ lockCRUD ( ) ;
871888 }
872889
873890 function resetEditForm ( ) {
891+ unlockCRUD ( ) ;
874892 ClearEditFields ( ) ;
875893 saveEditBtn . disabled = true ;
876894 pendingChanges = { add : [ ] , upd : [ ] , del : [ ] } ; // clear pending changes (for current tab)
895+ pendingReorder = false ;
877896 }
878897
879898 function ClearEditFields ( ) {
@@ -887,32 +906,65 @@ <h2 class="text-center">Websites Preview</h2>
887906 editList . value = '' ;
888907 editDelete . disabled = true ;
889908 editAction . textContent = 'Add' ;
909+ editMoveUp . disabled = editMoveDown . disabled = true ;
910+ }
911+
912+ function updateMoveButtons ( ) { // enable based on selection; CRUD and reorder are mutually exclusive
913+ const idx = editList . selectedIndex ,
914+ noSelection = ! selectedItem || idx === - 1 ;
915+ editMoveUp . disabled = noSelection || idx === 0 ;
916+ editMoveDown . disabled = noSelection || idx === editList . options . length - 1 ;
917+ }
918+
919+ function lockCRUD ( ) { // disable all CRUD controls while a reorder is pending
920+ editAction . disabled = editDelete . disabled = editClear . disabled = true ;
921+ editName . disabled = editValue . disabled = true ;
922+ }
923+
924+ function unlockCRUD ( ) { // re-enable inputs after reorder is cleared (resetEditForm handles button states)
925+ editName . disabled = editValue . disabled = false ;
890926 }
891927
892- function saveEditSettings ( ) { // save all pending changes
928+ function handleMoveUp ( ) {
929+ const idx = editList . selectedIndex ;
930+ if ( idx <= 0 ) return ;
931+ editList . insertBefore ( editList . options [ idx ] , editList . options [ idx - 1 ] ) ;
932+ editList . selectedIndex = idx - 1 ;
933+ __postMoveReset ( ) ;
934+ }
935+
936+ function handleMoveDown ( ) {
937+ const idx = editList . selectedIndex ;
938+ if ( idx === - 1 || idx >= editList . options . length - 1 ) return ;
939+ editList . insertBefore ( editList . options [ idx + 1 ] , editList . options [ idx ] ) ;
940+ editList . selectedIndex = idx + 1 ;
941+ __postMoveReset ( ) ;
942+ }
943+
944+ function dispatchSave ( endpoint , payloadKey , payloadVal , label , deletedKeys ) { // handles the actual fetch — no branching, pure execution
893945 const formData = new FormData ( ) ;
894946 formData . append ( 'type' , currentEditTab ) ;
895- formData . append ( 'changes' , JSON . stringify ( pendingChanges ) ) ;
896- fetch ( '/update_settings' , {
897- method : 'POST' ,
898- body : formData ,
899- headers : { 'Cache-Control' : 'no-cache, no-store, must-revalidate' } // prevent caching sensitive data
900- } )
947+ formData . append ( payloadKey , JSON . stringify ( payloadVal ) ) ;
948+ fetch ( endpoint , { method : 'POST' , body : formData , headers : { 'Cache-Control' : 'no-cache, no-store, must-revalidate' } } )
901949 . then ( response => response . json ( ) )
902950 . then ( data => {
903951 if ( data . error ) { alert ( data . error ) ; return ; }
904- if ( currentEditTab !== 'proxy' ) { // handle localStorage cleanup for deleted items
952+ if ( deletedKeys . length ) { // handle localStorage cleanup for deleted items
905953 const key = currentEditTab === 'api' ? 'apiKey' : 'searchEngine' , value = localStorage . getItem ( key ) ;
906- if ( value && pendingChanges . del . includes ( value ) ) localStorage . removeItem ( key ) ;
954+ if ( value && deletedKeys . includes ( value ) ) localStorage . removeItem ( key ) ;
907955 }
908956 loadSettingsOptions ( ) ; // reload settings options for the main modal
909957 // closeEditSettingsModal(); // [NOTE]: not needed, user can continue editing & close manually
910- alert ( 'Changes saved successfully!' ) ; // [NOTE]: can be replaced with a non-intrusive toast notification (like floating timeout msg in top middle)
958+ alert ( ` ${ label } saved successfully!` ) ; // [NOTE]: can be replaced with a non-intrusive toast notification
911959 } )
912- . catch ( error => {
913- console . error ( 'Error saving changes:' , error ) ;
914- alert ( 'Failed to save changes. Please try again.' ) ;
915- } ) ;
960+ . catch ( error => { console . error ( 'Error saving settings:' , error ) ; alert ( 'Failed to save. Please try again.' ) ; } ) ;
961+ }
962+
963+ function saveEditSettings ( ) { // decides what to save, delegates execution to dispatchSave
964+ pendingReorder
965+ ? dispatchSave ( '/reorder_settings' , 'order' , Array . from ( editList . options , o => o . value ) , 'Order' , [ ] )
966+ : dispatchSave ( '/update_settings' , 'changes' , pendingChanges , 'Changes' ,
967+ currentEditTab !== 'proxy' ? [ ...pendingChanges . del ] : [ ] ) ; // snapshot del before resetEditForm clears it
916968 resetEditForm ( ) ;
917969 }
918970
0 commit comments