import angular from 'angular' ; import { OnDestroy , OnInit , ViewParent } from 'angular-ts-decorators' ; import autobind from 'autobind-decorator' ; import { detect } from 'detect-browser' ; import { AlertType } from '../../../shared/alert/alert.enum' ; import { AlertService } from '../../../shared/alert/alert.service' ; import { Backup } from '../../../shared/backup-restore/backup-restore.interface' ; import { BackupRestoreService } from '../../../shared/backup-restore/backup-restore.service' ; import { BookmarkService } from '../../../shared/bookmark/bookmark.interface' ; import { BookmarkHelperService } from '../../../shared/bookmark/bookmark-helper/bookmark-helper.service' ; import { SyncVersionNotSupportedError } from '../../../shared/errors/errors' ; import { MessageCommand , PlatformType } from '../../../shared/global-shared.enum' ; import { PlatformService } from '../../../shared/global-shared.interface' ; import { LogService } from '../../../shared/log/log.service' ; import { StoreKey } from '../../../shared/store/store.enum' ; import { StoreService } from '../../../shared/store/store.service' ; import { SyncType } from '../../../shared/sync/sync.enum' ; import { UtilityService } from '../../../shared/utility/utility.service' ; import { WorkingContext } from '../../../shared/working/working.enum' ; import { WorkingService } from '../../../shared/working/working.service' ; import { AppEventType } from '../../app.enum' ; import { AppHelperService } from '../../shared/app-helper/app-helper.service' ; import { AppSettingsComponent } from '../app-settings.component' ; export abstract class BackupRestoreSettingsComponent implements OnInit , OnDestroy { Strings = require ( '../../../../../res/strings/en.json' ) ; $filter : ng . FilterFactory ; $q : ng . IQService ; $timeout : ng . ITimeoutService ; alertSvc : AlertService ; appHelperSvc : AppHelperService ; backupRestoreSvc : BackupRestoreService ; bookmarkHelperSvc : BookmarkHelperService ; bookmarkSvc : BookmarkService ; logSvc : LogService ; platformSvc : PlatformService ; storeSvc : StoreService ; utilitySvc : UtilityService ; workingSvc : WorkingService ; @ ViewParent ( '^appSettings' ) appSettingsCtrl : AppSettingsComponent ; backupCompletedMessage : string ; backupFileName : string ; dataToRestore : string ; displayAutoBackUpForm = false ; displayAutoBackUpConfirmation = false ; displayRestoreConfirmation = false ; displayRestoreForm = false ; displayResetConfirmation = false ; restoreCompletedMessage : string ; restoreForm : ng . IFormController ; resetCompleted = false ; resetConfirmationMessage : string ; resetUnavailable = false ; savingBackup = false ; syncEnabled = false ; useTextarea = false ; validatingRestoreData = false ; static $inject = [ '$filter' , '$q' , '$timeout' , 'AlertService' , 'AppHelperService' , 'BackupRestoreService' , 'BookmarkHelperService' , 'BookmarkService' , 'LogService' , 'PlatformService' , 'StoreService' , 'UtilityService' , 'WorkingService' ] ; constructor ( $filter , $q , $timeout , AlertSvc , AppHelperSvc , BackupRestoreSvc , BookmarkHelperSvc , BookmarkSvc , LogSvc , PlatformSvc , StoreSvc , UtilitySvc , WorkingSvc ) { this . $filter = $filter ; this . $q = $q ; this . $timeout = $timeout ; this . alertSvc = AlertSvc ; this . appHelperSvc = AppHelperSvc ; this . backupRestoreSvc = BackupRestoreSvc ; this . bookmarkHelperSvc = BookmarkHelperSvc ; this . bookmarkSvc = BookmarkSvc ; this . logSvc = LogSvc ; this . platformSvc = PlatformSvc ; this . storeSvc = StoreSvc ; this . utilitySvc = UtilitySvc ; this . workingSvc = WorkingSvc ; } @ autobind backupFileChanged ( ) { const fileInput = document . getElementById ( 'backupFile' ) as HTMLInputElement ; if ( fileInput . files . length > 0 ) { const [ file ] = fileInput . files ; this . backupFileName = file . name ; const reader = new FileReader ( ) ; reader . onload = ( ( data ) => { return ( ) => { this . $timeout ( ( ) => { this . dataToRestore = reader . result as string ; this . resetRestoreFormValidity ( ) ; this . validatingRestoreData = true ; this . $timeout ( ( ) => { if ( this . validateBackupData ( ) ) { this . appHelperSvc . focusOnElement ( '#restoreForm .btn-restore' ) ; } this . validatingRestoreData = false ; } ) ; } ) ; } ; } ) ( file ) ; reader . readAsText ( file ) ; } } @ autobind confirmRestore ( ) { if ( ! this . dataToRestore ) { this . alertSvc . setCurrentAlert ( { message : this . platformSvc . getI18nString ( this . Strings . Error . NoDataToRestore . Message ) , title : this . platformSvc . getI18nString ( this . Strings . Error . NoDataToRestore . Title ) , type : AlertType . Error } ) ; return ; } this . displayRestoreConfirmation = false ; this . displayRestoreForm = true ; this . workingSvc . show ( WorkingContext . Restoring ) ; this . backupRestoreSvc . restoreBackupData ( JSON . parse ( this . dataToRestore ) ) . then ( this . restoreBookmarksSuccess ) . catch ( ( err ) => { if ( err instanceof SyncVersionNotSupportedError ) { this . alertSvc . setCurrentAlert ( { message : this . platformSvc . getI18nString ( this . Strings . Error . SyncVersionNotSupported . Restore . Message ) , title : this . platformSvc . getI18nString ( this . Strings . Error . SyncVersionNotSupported . Title ) , type : AlertType . Error } ) ; return ; } throw err ; } ) . finally ( this . workingSvc . hide ) ; } @ autobind confirmReset ( ) { this . workingSvc . show ( WorkingContext . Resetting ) ; this . $q . all ( [ this . storeSvc . get < any > ( StoreKey . InstallBackup ) , this . platformSvc . disableSync ( ) ] ) . then ( ( response ) => { const [ installBackupData ] = response ; const installBackup = JSON . parse ( installBackupData ) ; const installBackupDate = new Date ( installBackup . date ) ; const bookmarksToRestore = installBackup . bookmarks ; this . logSvc . logInfo ( `Resetting to installation state from ${ installBackupDate . toISOString ( ) }` ) ; return this . platformSvc . queueSync ( { bookmarks : bookmarksToRestore , type : SyncType . Local } , MessageCommand . RestoreBookmarks ) ; } ) . then ( ( ) => { this . displayResetConfirmation = false ; this . resetCompleted = true ; this . appHelperSvc . focusOnElement ( '.reset-completed .focused' ) ; this . utilitySvc . broadcastEvent ( AppEventType . SyncDisabled ) ; } ) ; } @ autobind displayRestorePanel ( ) { this . backupFileName = null ; this . restoreCompletedMessage = null ; this . displayRestoreConfirmation = false ; this . dataToRestore = '' ; this . displayRestoreForm = true ; ( document . querySelector ( '#backupFile' ) as HTMLInputElement ) . value = null ; this . restoreForm . dataToRestore . $setValidity ( 'InvalidData' , true ) ; if ( this . platformSvc . platformName === PlatformType . Firefox ) { this . $timeout ( ( ) => { ( document . querySelector ( '#restoreForm textarea' ) as HTMLTextAreaElement ) . select ( ) ; } ) ; } else { this . appHelperSvc . focusOnElement ( '#restoreForm .focused' ) ; } } @ autobind displayResetPanel ( ) { this . storeSvc . get < any > ( StoreKey . InstallBackup ) . then ( ( installBackup ) => { if ( angular . isUndefined ( installBackup ) ) { this . resetUnavailable = true ; this . appHelperSvc . focusOnElement ( '.reset-completed .focused' ) ; return ; } const installBackupObj = JSON . parse ( installBackup ) ; if ( installBackupObj ?. date && installBackupObj ?. bookmarks ) { const date = new Date ( installBackupObj . date ) ; const confirmationMessage = this . platformSvc . getI18nString ( this . Strings . View . Settings . BackupRestore . Reset . Confirm ) ; this . resetConfirmationMessage = confirmationMessage . replace ( '{date}' , ( this . $filter ( 'date' ) as ng . IFilterDate ) ( date ) ) ; this . displayResetConfirmation = true ; } else { this . resetUnavailable = true ; } } ) ; } @ autobind downloadBackup ( ) { this . savingBackup = true ; this . backupRestoreSvc . saveBackupFile ( ) . then ( ( filename ) => { if ( ! filename ) { return ; } this . backupCompletedMessage = this . utilitySvc . isMobilePlatform ( this . platformSvc . platformName ) ? `${ this . platformSvc . getI18nString ( this . Strings . View . Settings . FileDownloaded ) }: ${ filename }` : undefined ; } ) . finally ( ( ) => { this . savingBackup = false ; this . appHelperSvc . focusOnElement ( '.file-downloaded .focused' ) ; } ) ; } @ autobind hideResetPanel ( ) { this . displayResetConfirmation = false ; this . resetCompleted = false ; this . resetConfirmationMessage = null ; this . resetUnavailable = false ; } @ autobind hideRestorePanel ( ) { this . displayRestoreForm = false ; this . restoreForm . $setPristine ( ) ; this . restoreForm . $setUntouched ( ) ; } ngOnDestroy ( ) { document . getElementById ( 'backupFile' ) . removeEventListener ( 'change' , this . backupFileChanged , false ) ; } ngOnInit ( ) { this . useTextarea = this . platformSvc . platformName === PlatformType . Firefox || ( this . platformSvc . platformName === PlatformType . Chromium && detect ( ) . os . toLowerCase ( ) === 'linux' ) ; if ( ! this . useTextarea ) { document . getElementById ( 'backupFile' ) . addEventListener ( 'change' , this . backupFileChanged , false ) ; } this . utilitySvc . isSyncEnabled ( ) . then ( ( syncEnabled ) => { this . syncEnabled = syncEnabled ; } ) ; } @ autobind resetRestoreFormValidity ( ) { this . restoreForm . dataToRestore . $setValidity ( 'InvalidData' , true ) ; } @ autobind restore ( ) { if ( ! this . validateBackupData ( ) ) { return ; } this . displayRestoreForm = false ; this . displayRestoreConfirmation = true ; this . appHelperSvc . focusOnElement ( '.btn-confirm-restore' ) ; } @ autobind restoreBookmarksSuccess ( ) { this . displayRestoreForm = false ; this . dataToRestore = undefined ; this . restoreCompletedMessage = this . platformSvc . getI18nString ( this . Strings . View . Settings . BackupRestore . Restore . Done ) ; this . appSettingsCtrl . refreshSyncDataUsage ( ) ; this . appHelperSvc . focusOnElement ( '.restore-completed .focused' ) ; } @ autobind selectBackupFile ( ) { ( document . querySelector ( '#backupFile' ) as HTMLInputElement ) . click ( ) ; } validateBackupData ( ) { if ( ! this . dataToRestore ) { return false ; } let validateData = false ; try { const restoreData = JSON . parse ( this . dataToRestore ) ; const bookmarks = restoreData . xBrowserSync ?. bookmarks ?? restoreData . xbrowsersync ?. data ?. bookmarks ; validateData = ! angular . isUndefined ( bookmarks ?? undefined ) ; } catch ( err ) { } this . restoreForm . dataToRestore . $setValidity ( 'InvalidData' , validateData ) ; return validateData ; } }