@@ -644,6 +644,57 @@ function initSettings() {
644644 } ;
645645 body . appendChild ( smoothScrollRow ) ;
646646
647+ // backup/restore button
648+ const backupRestoreRow = document . createElement ( "div" ) ;
649+ backupRestoreRow . className = "row" ;
650+ backupRestoreRow . innerHTML = `
651+ <button
652+ data-flow="bottom"
653+ data-tooltip="${ t ( {
654+ vi : "Lưu toàn bộ dữ liệu extension ra file" ,
655+ en : "Backup all extension data to file" ,
656+ } ) } ">
657+ <i class="fa-solid fa-download"></i>
658+ ${ t ( { vi : "Sao lưu" , en : "Backup" } ) }
659+ </button>
660+ <button
661+ data-flow="bottom"
662+ data-tooltip="${ t ( {
663+ vi : "Khôi phục dữ liệu extension từ file" ,
664+ en : "Restore all extension data from file" ,
665+ } ) } ">
666+ <i class="fa-solid fa-upload"></i>
667+ ${ t ( { vi : "Khôi phục" , en : "Restore" } ) }
668+ </button>
669+ ` ;
670+ const [ backupBtn , restoreBtn ] = Array . from (
671+ backupRestoreRow . querySelectorAll ( "button" )
672+ ) ;
673+ backupBtn . onclick = backup ;
674+ restoreBtn . onclick = restore ;
675+ body . appendChild ( backupRestoreRow ) ;
676+
677+ // reset row
678+ const resetRow = document . createElement ( "div" ) ;
679+ resetRow . classList . add ( "row" ) ;
680+ resetRow . innerHTML = `
681+ <button
682+ data-flow="bottom"
683+ data-tooltip="${ t ( {
684+ vi : "Xoá toàn bộ dữ liệu, đặt lại cài đặt gốc" ,
685+ en : "Delete all data, reset to default settings" ,
686+ } ) } ">
687+ <i class="fa-solid fa-rotate-left"></i>
688+ ${ t ( {
689+ vi : "Đặt lại dữ liệu" ,
690+ en : "Reset extension" ,
691+ } ) }
692+ </button>
693+ ` ;
694+ const resetBtn = resetRow . querySelector ( "button" ) ;
695+ resetBtn . onclick = reset ;
696+ body . appendChild ( resetRow ) ;
697+
647698 openModal (
648699 t ( {
649700 en : "Settings" ,
@@ -654,6 +705,99 @@ function initSettings() {
654705 } ;
655706}
656707
708+ async function backup ( ) {
709+ const data = {
710+ localStorage,
711+ chromeStorage : await chrome . storage . local . get ( ) ,
712+ time : new Date ( ) . getTime ( ) ,
713+ } ;
714+ const name = "useful-script-backup-" + new Date ( ) . toISOString ( ) + ".json" ;
715+ UfsGlobal . Utils . downloadData ( JSON . stringify ( data ) , name ) ;
716+ }
717+
718+ function restore ( ) {
719+ Swal . fire ( {
720+ title : t ( { en : "Restore data" , vi : "Khôi phục dữ liệu" } ) ,
721+ text : t ( { en : "Select backup file" , vi : "Chọn file đã sao lưu" } ) ,
722+ input : "file" ,
723+ inputAttributes : {
724+ accept : ".json" ,
725+ } ,
726+ showCancelButton : true ,
727+ confirmButtonText : t ( { en : "Restore" , vi : "Khôi phục" } ) ,
728+ showLoaderOnConfirm : true ,
729+ inputValidator : ( value ) => {
730+ if ( ! value )
731+ return t ( { en : "Please select a file" , vi : "Vui lòng chọn file" } ) ;
732+ } ,
733+ preConfirm : ( file ) => {
734+ return new Promise ( ( resolve ) => {
735+ const reader = new FileReader ( ) ;
736+ reader . onload = ( ) => {
737+ resolve ( reader . result ) ;
738+ } ;
739+ reader . readAsText ( file ) ;
740+ } ) ;
741+ } ,
742+ allowOutsideClick : ( ) => ! Swal . isLoading ( ) ,
743+ } ) . then ( async ( result ) => {
744+ if ( result . isConfirmed ) {
745+ try {
746+ const json = JSON . parse ( result . value ) ;
747+ const { localStorage : l , chromeStorage } = json ;
748+
749+ if ( l ) {
750+ Object . keys ( l ) . forEach ( ( key ) => {
751+ localStorage [ key ] = l [ key ] ;
752+ } ) ;
753+ }
754+
755+ if ( chromeStorage ) {
756+ for ( let key in chromeStorage ) {
757+ await chrome . storage . local . set ( { [ key ] : chromeStorage [ key ] } ) ;
758+ }
759+ }
760+
761+ Swal . fire ( {
762+ icon : "success" ,
763+ title : t ( { en : "Restore Success" , vi : "Khôi phục thành công" } ) ,
764+ text : t ( {
765+ en : "Imported data from" ,
766+ vi : "Đã nạp dữ liệu" ,
767+ } ) ,
768+ } ) ;
769+ } catch ( e ) {
770+ Swal . fire ( {
771+ icon : "error" ,
772+ title : t ( { en : "Error" , vi : "Lỗi" } ) ,
773+ text : e ?. message || e ,
774+ } ) ;
775+ }
776+ }
777+ } ) ;
778+ }
779+
780+ function reset ( ) {
781+ Swal . fire ( {
782+ icon : "warning" ,
783+ title : t ( { en : "Reset" , vi : "Đặt lại" } ) ,
784+ text : t ( {
785+ en : "All data will be deleted. Are you sure?" ,
786+ vi : "Tất cả dữ liệu sẽ bị xoá. Bạn có chắc không?" ,
787+ } ) ,
788+ showCancelButton : true ,
789+ confirmButtonText : t ( { en : "Delete all" , vi : "Xoá hết" } ) ,
790+ confirmButtonColor : "#d33" ,
791+ cancelButtonText : t ( { en : "Cancel" , vi : "Huỷ" } ) ,
792+ } ) . then ( ( result ) => {
793+ if ( result . isConfirmed ) {
794+ localStorage . clear ( ) ;
795+ chrome . storage . local . clear ( ) ;
796+ chrome . runtime . reload ( ) ;
797+ }
798+ } ) ;
799+ }
800+
657801function initSearch ( ) {
658802 searchInput . addEventListener ( "input" , ( event ) => {
659803 let keyword = event . target . value ;
0 commit comments