diff --git a/src/popup/app/app.js b/src/popup/app/app.js index 4bb27571f6..b53c06ecd8 100644 --- a/src/popup/app/app.js +++ b/src/popup/app/app.js @@ -27,6 +27,7 @@ import ServicesModule from './services/services.module'; import LockModule from './lock/lock.module'; import CurrentModule from './current/current.module'; import GlobalModule from './global/global.module'; +import SettingsModule from './settings/settings.module'; // Model imports import { Attachment } from '../../models/domain/attachment'; @@ -88,7 +89,7 @@ angular 'bit.accounts', CurrentModule, 'bit.vault', - 'bit.settings', + SettingsModule, ToolsModule, LockModule ]); @@ -107,18 +108,6 @@ require('./vault/vaultAddCipherController.js'); require('./vault/vaultEditCipherController.js'); require('./vault/vaultViewCipherController.js'); require('./vault/vaultAttachmentsController.js'); -require('./settings/settingsModule.js'); -require('./settings/settingsController.js'); -require('./settings/settingsHelpController.js'); -require('./settings/settingsAboutController.js'); -require('./settings/settingsCreditsController.js'); -require('./settings/settingsFeaturesController.js'); -require('./settings/settingsSyncController.js'); -require('./settings/settingsFoldersController.js'); -require('./settings/settingsAddFolderController.js'); -require('./settings/settingsEditFolderController.js'); -require('./settings/settingsPremiumController.js'); -require('./settings/settingsEnvironmentController.js'); require('./tools/toolsPasswordGeneratorHistoryController.js'); // $$ngIsClass fix issue with "class constructors must be invoked with |new|" on Firefox ESR diff --git a/src/popup/app/config.js b/src/popup/app/config.js index c0c253f447..aa2cd10350 100644 --- a/src/popup/app/config.js +++ b/src/popup/app/config.js @@ -120,8 +120,7 @@ angular }) .state('tabs.settings', { url: '/settings', - template: require('./settings/views/settings.html'), - controller: 'settingsController' + component: 'settings', }) .state('tabs.tools', { url: '/tools', @@ -186,72 +185,62 @@ angular .state('about', { url: '/about', - template: require('./settings/views/settingsAbout.html'), - controller: 'settingsAboutController', + component: 'about', data: { authorize: true }, params: { animation: null } }) .state('credits', { url: '/credits', - template: require('./settings/views/settingsCredits.html'), - controller: 'settingsCreditsController', + component: 'credits', data: { authorize: true }, params: { animation: null } }) .state('features', { url: '/features', - template: require('./settings/views/settingsFeatures.html'), - controller: 'settingsFeaturesController', + component: 'features', data: { authorize: true }, params: { animation: null } }) .state('help', { url: '/help', - template: require('./settings/views/settingsHelp.html'), - controller: 'settingsHelpController', + component: 'help', data: { authorize: true }, params: { animation: null } }) .state('sync', { url: '/sync', - template: require('./settings/views/settingsSync.html'), - controller: 'settingsSyncController', + component: 'sync', data: { authorize: true }, params: { animation: null } }) .state('premium', { url: '/premium', - template: require('./settings/views/settingsPremium.html'), - controller: 'settingsPremiumController', + component: 'premium', data: { authorize: true }, params: { animation: null } }) .state('folders', { url: '/folders', - template: require('./settings/views/settingsFolders.html'), - controller: 'settingsFoldersController', + abstract: true, data: { authorize: true }, params: { animation: null } }) - .state('addFolder', { - url: '/addFolder', - template: require('./settings/views/settingsAddFolder.html'), - controller: 'settingsAddFolderController', - data: { authorize: true }, - params: { animation: null } + .state('folders.list', { + url: '', + component: 'folders', }) - .state('editFolder', { - url: '/editFolder?folderId', - template: require('./settings/views/settingsEditFolder.html'), - controller: 'settingsEditFolderController', - data: { authorize: true }, - params: { animation: null } + .state('folders.add', { + url: '/add', + component: 'addFolder', + }) + .state('folders.edit', { + url: '/{folderId}/edit', + component: 'editFolder', }) .state('environment', { url: '/environment', - template: require('./settings/views/settingsEnvironment.html'), - controller: 'settingsEnvironmentController', + component: 'environment', data: { authorize: false }, params: { animation: null } }) diff --git a/src/popup/app/settings/views/settingsAbout.html b/src/popup/app/settings/about.component.html similarity index 61% rename from src/popup/app/settings/views/settingsAbout.html rename to src/popup/app/settings/about.component.html index afa873417d..1de6951dc2 100644 --- a/src/popup/app/settings/views/settingsAbout.html +++ b/src/popup/app/settings/about.component.html @@ -1,20 +1,20 @@ 
- {{i18n.back}} + {{$ctrl.i18n.back}}
-
{{i18n.about}}
+
{{$ctrl.i18n.about}}
- bitwarden - {{i18n.version}} {{version}}
- © 8bit Solutions LLC 2015-{{year}} + bitwarden + {{$ctrl.i18n.version}} {{$ctrl.version}}
+ © 8bit Solutions LLC 2015-{{$ctrl.year}}
diff --git a/src/popup/app/settings/about.component.ts b/src/popup/app/settings/about.component.ts new file mode 100644 index 0000000000..1d94f70fa9 --- /dev/null +++ b/src/popup/app/settings/about.component.ts @@ -0,0 +1,19 @@ +import * as template from './about.component.html'; + +class AboutController { + version: string; + year: number; + i18n: any; + + constructor(i18nService: any) { + this.i18n = i18nService; + this.year = (new Date()).getFullYear(); + this.version = chrome.runtime.getManifest().version; + } +} + +export const AboutComponent = { + bindings: {}, + controller: AboutController, + template, +}; diff --git a/src/popup/app/settings/views/settingsCredits.html b/src/popup/app/settings/credits.component.html similarity index 81% rename from src/popup/app/settings/views/settingsCredits.html rename to src/popup/app/settings/credits.component.html index f75f5c6718..d5ab6f0bc1 100644 --- a/src/popup/app/settings/views/settingsCredits.html +++ b/src/popup/app/settings/credits.component.html @@ -1,14 +1,14 @@ 
-
{{i18n.thankYou}}
+
{{$ctrl.i18n.thankYou}}
- {{i18n.translations}} + {{$ctrl.i18n.translations}}
@@ -27,7 +27,7 @@
diff --git a/src/popup/app/settings/credits.component.ts b/src/popup/app/settings/credits.component.ts new file mode 100644 index 0000000000..90c83743a6 --- /dev/null +++ b/src/popup/app/settings/credits.component.ts @@ -0,0 +1,23 @@ +import * as template from './credits.component.html'; + +class CreditsController { + i18n: any; + + constructor(i18nService: any, private $analytics: any) { + this.i18n = i18nService; + } + + learnMore() { + this.$analytics.eventTrack('Contribute Learn More'); + + chrome.tabs.create({ + url: 'https://github.com/bitwarden/browser/blob/master/CONTRIBUTING.md', + }); + } +} + +export const CreditsComponent = { + bindings: {}, + controller: CreditsController, + template, +}; diff --git a/src/popup/app/settings/views/settingsEnvironment.html b/src/popup/app/settings/environment.component.html similarity index 68% rename from src/popup/app/settings/views/settingsEnvironment.html rename to src/popup/app/settings/environment.component.html index f6b5aea3c3..69d697edf2 100644 --- a/src/popup/app/settings/views/settingsEnvironment.html +++ b/src/popup/app/settings/environment.component.html @@ -1,54 +1,54 @@ -
+
- +
-
{{i18n.settings}}
+
{{$ctrl.i18n.settings}}
- {{i18n.selfHostedEnvironment}} + {{$ctrl.i18n.selfHostedEnvironment}}
- - {{$ctrl.i18n.baseUrl}} +
- {{i18n.customEnvironment}} + {{$ctrl.i18n.customEnvironment}}
- - + +
- - + +
- - + +
- - + +
diff --git a/src/popup/app/settings/environment.component.ts b/src/popup/app/settings/environment.component.ts new file mode 100644 index 0000000000..646a959d1c --- /dev/null +++ b/src/popup/app/settings/environment.component.ts @@ -0,0 +1,57 @@ +import * as angular from 'angular'; +import UtilsService from '../../../services/utils.service'; +import * as template from './environment.component.html'; + +class EnvironmentController { + iconsUrl: string; + identityUrl: string; + apiUrl: string; + webVaultUrl: string; + baseUrl: string; + i18n: any; + + constructor(private i18nService: any, private $analytics: any, utilsService: UtilsService, + private environmentService: any, private toastr: any, private $timeout: ng.ITimeoutService) { + this.i18n = i18nService; + + $timeout(() => { + utilsService.initListSectionItemListeners(document, angular); + }, 500); + + this.baseUrl = environmentService.baseUrl || ''; + this.webVaultUrl = environmentService.webVaultUrl || ''; + this.apiUrl = environmentService.apiUrl || ''; + this.identityUrl = environmentService.identityUrl || ''; + this.iconsUrl = environmentService.iconsUrl || ''; + } + + save() { + this.environmentService + .setUrls({ + base: this.baseUrl, + api: this.apiUrl, + identity: this.identityUrl, + webVault: this.webVaultUrl, + icons: this.iconsUrl, + }) + .then((resUrls: any) => { + this.$timeout(() => { + // re-set urls since service can change them, ex: prefixing https:// + this.baseUrl = resUrls.base; + this.apiUrl = resUrls.api; + this.identityUrl = resUrls.identity; + this.webVaultUrl = resUrls.webVault; + this.iconsUrl = resUrls.icons; + + this.$analytics.eventTrack('Set Environment URLs'); + this.toastr.success(this.i18nService.environmentSaved); + }); + }); + } +} + +export const EnvironmentComponent = { + bindings: {}, + controller: EnvironmentController, + template, +}; diff --git a/src/popup/app/settings/views/settingsFeatures.html b/src/popup/app/settings/features.component.html similarity index 56% rename from src/popup/app/settings/views/settingsFeatures.html rename to src/popup/app/settings/features.component.html index 5e5a8e1e7e..8b432dd7de 100644 --- a/src/popup/app/settings/views/settingsFeatures.html +++ b/src/popup/app/settings/features.component.html @@ -1,80 +1,81 @@ 
-
{{i18n.features}}
+
{{$ctrl.i18n.features}}
- - + +
- - + +
- - + +
- - + +
- - + +
- - + +
diff --git a/src/popup/app/settings/features.component.ts b/src/popup/app/settings/features.component.ts new file mode 100644 index 0000000000..697b12da91 --- /dev/null +++ b/src/popup/app/settings/features.component.ts @@ -0,0 +1,111 @@ +import * as angular from 'angular'; +import { UtilsService } from '../../../services/abstractions/utils.service'; +import StateService from '../services/state.service'; +import * as template from './features.component.html'; + +class FeaturesController { + disableFavicon = false; + enableAutoFillOnPageLoad = false; + disableAutoTotpCopy = false; + disableContextMenuItem = false; + disableAddLoginNotification = false; + disableGa = false; + i18n: any; + + constructor(private i18nService: any, private $analytics: any, private constantsService: any, + private utilsService: UtilsService, private totpService: any, private stateService: StateService, + private $timeout: ng.ITimeoutService) { + this.i18n = i18nService; + + $timeout(() => { + utilsService.initListSectionItemListeners(document, angular); + }, 500); + + this.loadSettings(); + } + + async loadSettings() { + this.enableAutoFillOnPageLoad = await this.utilsService + .getObjFromStorage(this.constantsService.enableAutoFillOnPageLoadKey); + + const disableGa = await this.utilsService.getObjFromStorage(this.constantsService.disableGaKey); + this.disableGa = disableGa || (this.utilsService.isFirefox() && disableGa === undefined); + + this.disableAddLoginNotification = await this.utilsService + .getObjFromStorage(this.constantsService.disableAddLoginNotificationKey); + + this.disableContextMenuItem = await this.utilsService + .getObjFromStorage(this.constantsService.disableContextMenuItemKey); + + this.disableAutoTotpCopy = !await this.totpService.isAutoCopyEnabled(); + + this.disableFavicon = await this.utilsService + .getObjFromStorage(this.constantsService.disableFaviconKey); + } + + callAnalytics(name: string, enabled: boolean) { + const status = enabled ? 'Enabled' : 'Disabled'; + this.$analytics.eventTrack(`${status} ${name}`); + } + + updateGa() { + this.utilsService.saveObjToStorage( + this.constantsService.disableGaKey, + this.disableGa, + ); + this.callAnalytics('Analytics', !this.disableGa); + } + + updateAddLoginNotification() { + this.utilsService.saveObjToStorage( + this.constantsService.disableAddLoginNotificationKey, + this.disableAddLoginNotification, + ); + this.callAnalytics('Add Login Notification', !this.disableAddLoginNotification); + } + + updateDisableContextMenuItem() { + this.utilsService + .saveObjToStorage( + this.constantsService.disableContextMenuItemKey, + this.disableContextMenuItem, + ) + .then(() => { + chrome.runtime.sendMessage({ + command: 'bgUpdateContextMenu', + }); + }); + this.callAnalytics('Context Menu Item', !this.disableContextMenuItem); + } + + updateAutoTotpCopy() { + this.utilsService.saveObjToStorage( + this.constantsService.disableAutoTotpCopyKey, + this.disableAutoTotpCopy, + ); + this.callAnalytics('Auto Copy TOTP', !this.disableAutoTotpCopy); + } + + updateAutoFillOnPageLoad() { + this.utilsService.saveObjToStorage( + this.constantsService.enableAutoFillOnPageLoadKey, + this.enableAutoFillOnPageLoad, + ); + this.callAnalytics('Auto-fill Page Load', this.enableAutoFillOnPageLoad); + } + + updateDisableFavicon() { + this.utilsService.saveObjToStorage( + this.constantsService.disableFaviconKey, + this.disableFavicon, + ); + this.stateService.saveState('faviconEnabled', !this.disableFavicon); + this.callAnalytics('Favicon', !this.disableFavicon); + } +} + +export const FeaturesComponent = { + bindings: {}, + controller: FeaturesController, + template, +}; diff --git a/src/popup/app/settings/views/settingsAddFolder.html b/src/popup/app/settings/folders/add-folder.component.html similarity index 60% rename from src/popup/app/settings/views/settingsAddFolder.html rename to src/popup/app/settings/folders/add-folder.component.html index 6189ad40b6..7793b9f5e2 100644 --- a/src/popup/app/settings/views/settingsAddFolder.html +++ b/src/popup/app/settings/folders/add-folder.component.html @@ -1,21 +1,21 @@ - +
- +
-
{{i18n.addFolder}}
+
{{$ctrl.i18n.addFolder}}
- - + +
diff --git a/src/popup/app/settings/folders/add-folder.component.ts b/src/popup/app/settings/folders/add-folder.component.ts new file mode 100644 index 0000000000..bdee42980d --- /dev/null +++ b/src/popup/app/settings/folders/add-folder.component.ts @@ -0,0 +1,47 @@ +import * as angular from 'angular'; +import { Folder } from '../../../../models/domain/folder'; +import { UtilsService } from '../../../../services/abstractions/utils.service'; +import * as template from './add-folder.component.html'; + +class AddFolderController { + savePromise: any; + folder: {}; + i18n: any; + + constructor(private folderService: any, private $state: any, private toastr: any, utilsService: UtilsService, + private $analytics: any, private i18nService: any, $timeout: any) { + $timeout(() => { + utilsService.initListSectionItemListeners(document, angular); + document.getElementById('name').focus(); + }, 500); + + this.i18n = i18nService; + this.folder = {}; + this.savePromise = null; + } + + save(model: any) { + if (!model.name) { + this.toastr.error(this.i18nService.nameRequired, this.i18nService.errorsOccurred); + return; + } + + this.savePromise = this.folderService + .encrypt(model) + .then((folderModel: any) => { + const folder = new Folder(folderModel, true); + return this.folderService.saveWithServer(folder); + }) + .then((folder: any) => { + this.$analytics.eventTrack('Added Folder'); + this.toastr.success(this.i18nService.addedFolder); + this.$state.go('^.list', { animation: 'out-slide-down' }); + }); + } +} + +export const AddFolderComponent = { + bindings: {}, + controller: AddFolderController, + template, +}; diff --git a/src/popup/app/settings/views/settingsEditFolder.html b/src/popup/app/settings/folders/edit-folder.component.html similarity index 61% rename from src/popup/app/settings/views/settingsEditFolder.html rename to src/popup/app/settings/folders/edit-folder.component.html index 440723e223..1d856ae1cc 100644 --- a/src/popup/app/settings/views/settingsEditFolder.html +++ b/src/popup/app/settings/folders/edit-folder.component.html @@ -1,28 +1,28 @@ - +
- +
-
{{i18n.editFolder}}
+
{{$ctrl.i18n.editFolder}}
- - + +
diff --git a/src/popup/app/settings/folders/edit-folder.component.ts b/src/popup/app/settings/folders/edit-folder.component.ts new file mode 100644 index 0000000000..4563775cc6 --- /dev/null +++ b/src/popup/app/settings/folders/edit-folder.component.ts @@ -0,0 +1,86 @@ +import * as angular from 'angular'; +import { Folder } from '../../../../models/domain/folder'; +import UtilsService from '../../../../services/utils.service'; +import * as template from './edit-folder.component.html'; + +class EditFolderController { + $transition$: any; + folderId: any; + savePromise: any = null; + i18n: any; + folder: Folder; + + constructor($scope: any, $stateParams: any, private folderService: any, private toastr: any, private $state: any, + private SweetAlert: any, utilsService: UtilsService, private $analytics: any, private i18nService: any, + $timeout: any) { + this.i18n = i18nService; + + $timeout(() => { + utilsService.initListSectionItemListeners(document, angular); + document.getElementById('name').focus(); + }, 500); + + $scope.folder = {}; + } + + $onInit() { + this.folderId = this.$transition$.params('to').folderId; + + this.folderService + .get(this.folderId) + .then((folder: any) => { + return folder.decrypt(); + }).then((model: Folder) => { + this.folder = model; + }); + } + + save(model: any) { + if (!model.name) { + this.toastr.error(this.i18nService.nameRequired, this.i18nService.errorsOccurred); + return; + } + + this.savePromise = this.folderService + .encrypt(model) + .then((folderModel: any) => { + const folder = new Folder(folderModel, true); + return this.folderService.saveWithServer(folder); + }) + .then((folder: any) => { + this.$analytics.eventTrack('Edited Folder'); + this.toastr.success(this.i18nService.editedFolder); + this.$state.go('^.list', { animation: 'out-slide-down' }); + }); + } + + delete() { + this.SweetAlert.swal({ + title: this.i18nService.deleteFolder, + text: this.i18nService.deleteFolderConfirmation, + showCancelButton: true, + confirmButtonText: this.i18nService.yes, + cancelButtonText: this.i18nService.no, + }, (confirmed: boolean) => { + if (confirmed) { + this.folderService + .deleteWithServer(this.folderId) + .then(() => { + this.$analytics.eventTrack('Deleted Folder'); + this.toastr.success(this.i18nService.deletedFolder); + this.$state.go('^.list', { + animation: 'out-slide-down', + }); + }); + } + }); + } +} + +export const EditFolderComponent = { + bindings: { + $transition$: '<', + }, + controller: EditFolderController, + template, +}; diff --git a/src/popup/app/settings/folders/folders.component.html b/src/popup/app/settings/folders/folders.component.html new file mode 100644 index 0000000000..def7e41ce6 --- /dev/null +++ b/src/popup/app/settings/folders/folders.component.html @@ -0,0 +1,31 @@ +
+ +
+ +
+
{{$ctrl.i18n.folders}}
+
+
+ +
+

+ {{$ctrl.i18n.noFolders}} + {{$ctrl.i18n.addFolder}} +

+
+
+ +
+
diff --git a/src/popup/app/settings/folders/folders.component.ts b/src/popup/app/settings/folders/folders.component.ts new file mode 100644 index 0000000000..04d3f617c3 --- /dev/null +++ b/src/popup/app/settings/folders/folders.component.ts @@ -0,0 +1,42 @@ +import { Folder } from '../../../../models/domain/folder'; +import * as template from './folders.component.html'; + +class FoldersController { + folders: Folder[] = []; + i18n: any; + loaded = false; + + constructor(private folderService: any, private $state: any, i18nService: any) { + this.i18n = i18nService; + + this.load(); + } + + load() { + this.folderService + .getAllDecrypted() + .then((folders: any) => { + if (folders.length > 0 && folders[0].id === null) { + // remove the "none" folder + this.folders = folders.slice(1); + } else { + this.folders = folders; + } + + this.loaded = true; + }); + } + + editFolder(folder: any) { + this.$state.go('^.edit', { + folderId: folder.id, + animation: 'in-slide-up', + }); + } +} + +export const FoldersComponent = { + bindings: {}, + controller: FoldersController, + template, +}; diff --git a/src/popup/app/settings/views/settingsHelp.html b/src/popup/app/settings/help.component.html similarity index 59% rename from src/popup/app/settings/views/settingsHelp.html rename to src/popup/app/settings/help.component.html index 75fcb89364..b61c3c9934 100644 --- a/src/popup/app/settings/views/settingsHelp.html +++ b/src/popup/app/settings/help.component.html @@ -1,53 +1,53 @@ 
-
{{i18n.helpFeedback}}
+
{{$ctrl.i18n.helpFeedback}}
diff --git a/src/popup/app/settings/help.component.ts b/src/popup/app/settings/help.component.ts new file mode 100644 index 0000000000..36ae275b5f --- /dev/null +++ b/src/popup/app/settings/help.component.ts @@ -0,0 +1,35 @@ +import * as template from './help.component.html'; + +class HelpController { + i18n: any; + + constructor(i18nService: any, private $analytics: any) { + this.i18n = i18nService; + } + + email() { + this.$analytics.eventTrack('Selected Help Email'); + chrome.tabs.create({ url: 'mailto:hello@bitwarden.com' }); + } + + website() { + this.$analytics.eventTrack('Selected Help Website'); + chrome.tabs.create({ url: 'https://bitwarden.com/contact/' }); + } + + tutorial() { + this.$analytics.eventTrack('Selected Help Tutorial'); + chrome.tabs.create({ url: 'https://bitwarden.com/browser-start/' }); + } + + bug() { + this.$analytics.eventTrack('Selected Help Bug Report'); + chrome.tabs.create({ url: 'https://github.com/bitwarden/browser' }); + } +} + +export const HelpComponent = { + bindings: {}, + controller: HelpController, + template, +}; diff --git a/src/popup/app/settings/views/settingsPremium.html b/src/popup/app/settings/premium.component.html similarity index 52% rename from src/popup/app/settings/views/settingsPremium.html rename to src/popup/app/settings/premium.component.html index 647f23a525..05c8b7af2b 100644 --- a/src/popup/app/settings/views/settingsPremium.html +++ b/src/popup/app/settings/premium.component.html @@ -1,52 +1,52 @@ 
-
{{i18n.premiumMembership}}
+
{{$ctrl.i18n.premiumMembership}}
-
-

{{i18n.premiumNotCurrentMember}}

-

{{i18n.premiumSignUpAndGet}}

+
+

{{$ctrl.i18n.premiumNotCurrentMember}}

+

{{$ctrl.i18n.premiumSignUpAndGet}}

  • - {{i18n.ppremiumSignUpStorage}} + {{$ctrl.i18n.ppremiumSignUpStorage}}
  • - {{i18n.ppremiumSignUpTwoStep}} + {{$ctrl.i18n.ppremiumSignUpTwoStep}}
  • - {{i18n.ppremiumSignUpTotp}} + {{$ctrl.i18n.ppremiumSignUpTotp}}
  • - {{i18n.ppremiumSignUpSupport}} + {{$ctrl.i18n.ppremiumSignUpSupport}}
  • - {{i18n.ppremiumSignUpFuture}} + {{$ctrl.i18n.ppremiumSignUpFuture}}
-

{{i18n.premiumPrice.replace('%price%', price)}}

+

{{$ctrl.i18n.premiumPrice.replace('%price%', $ctrl.price)}}

-

{{i18n.premiumCurrentMember}}

-

{{i18n.premiumCurrentMemberThanks}}

+

{{$ctrl.i18n.premiumCurrentMember}}

+

{{$ctrl.i18n.premiumCurrentMemberThanks}}

diff --git a/src/popup/app/settings/premium.component.ts b/src/popup/app/settings/premium.component.ts new file mode 100644 index 0000000000..8d71daad9c --- /dev/null +++ b/src/popup/app/settings/premium.component.ts @@ -0,0 +1,62 @@ +import * as template from './premium.component.html'; + +class PremiumController { + isPremium: boolean; + i18n: any; + price = '$10'; + + constructor(private i18nService: any, private tokenService: any, private apiService: any, private toastr: any, + private SweetAlert: any, private $analytics: any, private $timeout: any) { + this.i18n = i18nService; + this.isPremium = tokenService.getPremium(); + } + + refresh() { + this.apiService + .refreshIdentityToken() + .then(() => { + this.toastr.success(this.i18nService.refreshComplete); + this.$timeout(() => { + this.isPremium = this.tokenService.getPremium(); + }); + }, (err: any) => { + this.toastr.error(this.i18nService.errorsOccurred); + }); + } + + purchase() { + this.SweetAlert.swal({ + title: this.i18nService.premiumPurchase, + text: this.i18nService.premiumPurchaseAlert, + showCancelButton: true, + confirmButtonText: this.i18nService.yes, + cancelButtonText: this.i18nService.cancel, + }, (confirmed: boolean) => { + this.$analytics.eventTrack('Clicked Purchase Premium'); + if (confirmed) { + chrome.tabs.create({ url: 'https://vault.bitwarden.com/#/?premium=purchase' }); + } + }); + } + + manage() { + this.SweetAlert.swal({ + title: this.i18nService.premiumManage, + text: this.i18nService.premiumManageAlert, + showCancelButton: true, + confirmButtonText: this.i18nService.yes, + cancelButtonText: this.i18nService.cancel, + }, (confirmed: boolean) => { + this.$analytics.eventTrack('Clicked Manage Membership'); + if (confirmed) { + chrome.tabs.create({ url: 'https://vault.bitwarden.com/#/?premium=manage' }); + } + }); + } +} + +export const PremiumComponent = { + bindings: {}, + controller: PremiumController, + template, +}; diff --git a/src/popup/app/settings/views/settings.html b/src/popup/app/settings/settings.component.html similarity index 52% rename from src/popup/app/settings/views/settings.html rename to src/popup/app/settings/settings.component.html index 4071ddce9f..6d7f3af0eb 100644 --- a/src/popup/app/settings/views/settings.html +++ b/src/popup/app/settings/settings.component.html @@ -1,100 +1,100 @@ 
-
{{i18n.settings}}
+
{{$ctrl.i18n.settings}}
- {{i18n.security}} + {{$ctrl.i18n.security}}
- - + + + + + + + + + +
- - {{i18n.lockNow}} + + {{$ctrl.i18n.lockNow}} - - {{i18n.twoStepLogin}} + + {{$ctrl.i18n.twoStepLogin}}
diff --git a/src/popup/app/settings/settings.component.ts b/src/popup/app/settings/settings.component.ts new file mode 100644 index 0000000000..1e9a67012f --- /dev/null +++ b/src/popup/app/settings/settings.component.ts @@ -0,0 +1,161 @@ +import * as angular from 'angular'; +import { BrowserType } from '../../../enums/browserType.enum'; +import { CryptoService } from '../../../services/abstractions/crypto.service'; +import { UtilsService } from '../../../services/abstractions/utils.service'; +import ConstantsService from '../../../services/constants.service'; + +import * as template from './settings.component.html'; + +const RateUrls = { + [BrowserType.Chrome]: + 'https://chrome.google.com/webstore/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews', + [BrowserType.Firefox]: + 'https://addons.mozilla.org/en-US/firefox/addon/bitwarden-password-manager/#reviews', + [BrowserType.Opera]: + 'https://addons.opera.com/en/extensions/details/bitwarden-free-password-manager/#feedback-container', + [BrowserType.Edge]: + 'https://www.microsoft.com/store/p/bitwarden-free-password-manager/9p6kxl0svnnl', +}; + +class SettingsController { + lockOption = ''; + i18n: any; + showOnLocked: boolean; + + constructor(private $state: any, private SweetAlert: any, private utilsService: UtilsService, + private $analytics: any, private i18nService: any, private constantsService: ConstantsService, + private cryptoService: CryptoService, private lockService: any, private $timeout: ng.ITimeoutService) { + this.i18n = i18nService; + + $timeout(() => { + utilsService.initListSectionItemListeners(document, angular); + }, 500); + + this.showOnLocked = !utilsService.isFirefox() && !utilsService.isEdge(); + + chrome.storage.local.get(constantsService.lockOptionKey, (obj: any) => { + if (obj && (obj[constantsService.lockOptionKey] || obj[constantsService.lockOptionKey] === 0)) { + let option = obj[constantsService.lockOptionKey].toString(); + if (option === '-2' && !this.showOnLocked) { + option = '-1'; + } + this.lockOption = option; + } else { + this.lockOption = ''; + } + }); + } + + changeLockOption() { + const obj: any = {}; + obj[this.constantsService.lockOptionKey] = null; + if (this.lockOption && this.lockOption !== '') { + obj[this.constantsService.lockOptionKey] = parseInt(this.lockOption, 10); + } + + chrome.storage.local.set(obj, () => { + this.cryptoService.getKeyHash().then((keyHash) => { + if (keyHash) { + this.cryptoService.toggleKey(); + } else { + this.SweetAlert.swal({ + title: this.i18nService.loggingOut, + text: this.i18nService.loggingOutConfirmation, + showCancelButton: true, + confirmButtonText: this.i18nService.yes, + cancelButtonText: this.i18nService.cancel, + }, (confirmed: boolean) => { + if (confirmed) { + this.cryptoService.toggleKey(); + chrome.runtime.sendMessage({ command: 'logout' }); + } + }); + } + }); + }); + } + + lock() { + this.$analytics.eventTrack('Lock Now'); + this.lockService + .lock() + .then(() => { + return this.$state.go('lock', { + animation: 'in-slide-down', + }); + }); + } + + logOut() { + this.SweetAlert.swal({ + title: this.i18nService.logOut, + text: this.i18nService.logOutConfirmation, + showCancelButton: true, + confirmButtonText: this.i18nService.yes, + cancelButtonText: this.i18nService.cancel, + }, (confirmed: boolean) => { + if (confirmed) { + chrome.runtime.sendMessage({ command: 'logout' }); + } + }); + } + + changePassword() { + this.SweetAlert.swal({ + title: this.i18nService.changeMasterPassword, + text: this.i18nService.changeMasterPasswordConfirmation, + showCancelButton: true, + confirmButtonText: this.i18nService.yes, + cancelButtonText: this.i18nService.cancel, + }, (confirmed: boolean) => { + this.$analytics.eventTrack('Clicked Change Password'); + if (confirmed) { + chrome.tabs.create({ url: 'https://help.bitwarden.com/article/change-your-master-password/' }); + } + }); + } + + changeEmail() { + this.SweetAlert.swal({ + title: this.i18nService.changeEmail, + text: this.i18nService.changeEmailConfirmation, + showCancelButton: true, + confirmButtonText: this.i18nService.yes, + cancelButtonText: this.i18nService.cancel, + }, (confirmed: boolean) => { + this.$analytics.eventTrack('Clicked Change Email'); + if (confirmed) { + chrome.tabs.create({ url: 'https://help.bitwarden.com/article/change-your-email/' }); + } + }); + } + + twoStep() { + this.SweetAlert.swal({ + title: this.i18nService.twoStepLogin, + text: this.i18nService.twoStepLoginConfirmation, + showCancelButton: true, + confirmButtonText: this.i18nService.yes, + cancelButtonText: this.i18nService.cancel, + }, (confirmed: boolean) => { + this.$analytics.eventTrack('Clicked Two-step Login'); + if (confirmed) { + chrome.tabs.create({ url: 'https://help.bitwarden.com/article/setup-two-step-login/' }); + } + }); + } + + rate() { + this.$analytics.eventTrack('Rate Extension'); + + chrome.tabs.create({ + url: RateUrls[this.utilsService.getBrowser()], + }); + } +} + +export const SettingsComponent = { + bindings: {}, + controller: SettingsController, + template, +}; diff --git a/src/popup/app/settings/settings.module.ts b/src/popup/app/settings/settings.module.ts new file mode 100644 index 0000000000..c075c57d4b --- /dev/null +++ b/src/popup/app/settings/settings.module.ts @@ -0,0 +1,29 @@ +import * as angular from 'angular'; +import { AboutComponent } from './about.component'; +import { CreditsComponent } from './credits.component'; +import { EnvironmentComponent } from './environment.component'; +import { FeaturesComponent } from './features.component'; +import { AddFolderComponent } from './folders/add-folder.component'; +import { EditFolderComponent } from './folders/edit-folder.component'; +import { FoldersComponent } from './folders/folders.component'; +import { HelpComponent } from './help.component'; +import { PremiumComponent } from './premium.component'; +import { SettingsComponent } from './settings.component'; +import { SyncComponent } from './sync.component'; + +export default angular + .module('bit.settings', ['oitozero.ngSweetAlert', 'toastr']) + + .component('settings', SettingsComponent) + .component('environment', EnvironmentComponent) + .component('features', FeaturesComponent) + .component('about', AboutComponent) + .component('credits', CreditsComponent) + .component('help', HelpComponent) + .component('folders', FoldersComponent) + .component('addFolder', AddFolderComponent) + .component('editFolder', EditFolderComponent) + .component('premium', PremiumComponent) + .component('sync', SyncComponent) + + .name; diff --git a/src/popup/app/settings/settingsAboutController.js b/src/popup/app/settings/settingsAboutController.js deleted file mode 100644 index 76f1577c2a..0000000000 --- a/src/popup/app/settings/settingsAboutController.js +++ /dev/null @@ -1,8 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsAboutController', function ($scope, i18nService) { - $scope.i18n = i18nService; - $scope.year = (new Date()).getFullYear(); - $scope.version = chrome.runtime.getManifest().version; - }); diff --git a/src/popup/app/settings/settingsAddFolderController.js b/src/popup/app/settings/settingsAddFolderController.js deleted file mode 100644 index 5a8c317794..0000000000 --- a/src/popup/app/settings/settingsAddFolderController.js +++ /dev/null @@ -1,29 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsAddFolderController', function ($scope, $q, folderService, $state, toastr, utilsService, - $analytics, i18nService, $timeout) { - $timeout(function () { - utilsService.initListSectionItemListeners(document, angular); - document.getElementById('name').focus(); - }, 500); - - $scope.i18n = i18nService; - $scope.folder = {}; - $scope.savePromise = null; - $scope.save = function (model) { - if (!model.name) { - toastr.error(i18nService.nameRequired, i18nService.errorsOccurred); - return; - } - - $scope.savePromise = $q.when(folderService.encrypt(model)).then(function (folderModel) { - var folder = new Folder(folderModel, true); - return $q.when(folderService.saveWithServer(folder)).then(function (folder) { - $analytics.eventTrack('Added Folder'); - toastr.success(i18nService.addedFolder); - $state.go('folders', { animation: 'out-slide-down' }); - }); - }); - }; - }); diff --git a/src/popup/app/settings/settingsController.js b/src/popup/app/settings/settingsController.js deleted file mode 100644 index e6934a54cc..0000000000 --- a/src/popup/app/settings/settingsController.js +++ /dev/null @@ -1,158 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsController', function ($scope, $state, SweetAlert, utilsService, $analytics, - i18nService, constantsService, cryptoService, lockService, $timeout) { - $timeout(function () { - utilsService.initListSectionItemListeners(document, angular); - }, 500); - - $scope.showOnLocked = !utilsService.isFirefox() && !utilsService.isEdge(); - $scope.lockOption = ''; - $scope.i18n = i18nService; - - chrome.storage.local.get(constantsService.lockOptionKey, function (obj) { - if (obj && (obj[constantsService.lockOptionKey] || obj[constantsService.lockOptionKey] === 0)) { - var option = obj[constantsService.lockOptionKey].toString(); - if (option === '-2' && !$scope.showOnLocked) { - option = '-1'; - } - $scope.lockOption = option; - } - else { - $scope.lockOption = ''; - } - - $scope.$apply(); - }); - - $scope.changeLockOption = function () { - var obj = {}; - obj[constantsService.lockOptionKey] = null; - if ($scope.lockOption && $scope.lockOption !== '') { - obj[constantsService.lockOptionKey] = parseInt($scope.lockOption); - } - - chrome.storage.local.set(obj, function () { - cryptoService.getKeyHash().then(function (keyHash) { - if (keyHash) { - cryptoService.toggleKey(); - } - else { - SweetAlert.swal({ - title: i18nService.loggingOut, - text: i18nService.loggingOutConfirmation, - showCancelButton: true, - confirmButtonText: i18nService.yes, - cancelButtonText: i18nService.cancel - }, function (confirmed) { - if (confirmed) { - cryptoService.toggleKey(); - chrome.runtime.sendMessage({ command: 'logout' }); - } - }); - } - }); - }); - }; - - $scope.lock = function () { - $analytics.eventTrack('Lock Now'); - lockService.lock().then(function () { - return $state.go('lock', { - animation: 'in-slide-down' - }); - }); - }; - - $scope.logOut = function () { - SweetAlert.swal({ - title: i18nService.logOut, - text: i18nService.logOutConfirmation, - showCancelButton: true, - confirmButtonText: i18nService.yes, - cancelButtonText: i18nService.cancel - }, function (confirmed) { - if (confirmed) { - chrome.runtime.sendMessage({ command: 'logout' }); - } - }); - }; - - $scope.changePassword = function () { - SweetAlert.swal({ - title: i18nService.changeMasterPassword, - text: i18nService.changeMasterPasswordConfirmation, - showCancelButton: true, - confirmButtonText: i18nService.yes, - cancelButtonText: i18nService.cancel - }, function (confirmed) { - $analytics.eventTrack('Clicked Change Password'); - if (confirmed) { - chrome.tabs.create({ url: 'https://help.bitwarden.com/article/change-your-master-password/' }); - } - }); - }; - - $scope.changeEmail = function () { - SweetAlert.swal({ - title: i18nService.changeEmail, - text: i18nService.changeEmailConfirmation, - showCancelButton: true, - confirmButtonText: i18nService.yes, - cancelButtonText: i18nService.cancel - }, function (confirmed) { - $analytics.eventTrack('Clicked Change Email'); - if (confirmed) { - chrome.tabs.create({ url: 'https://help.bitwarden.com/article/change-your-email/' }); - } - }); - }; - - $scope.twoStep = function () { - SweetAlert.swal({ - title: i18nService.twoStepLogin, - text: i18nService.twoStepLoginConfirmation, - showCancelButton: true, - confirmButtonText: i18nService.yes, - cancelButtonText: i18nService.cancel - }, function (confirmed) { - $analytics.eventTrack('Clicked Two-step Login'); - if (confirmed) { - chrome.tabs.create({ url: 'https://help.bitwarden.com/article/setup-two-step-login/' }); - } - }); - }; - - $scope.rate = function () { - $analytics.eventTrack('Rate Extension'); - - switch (utilsService.getBrowserString()) { - case 'chrome': - chrome.tabs.create({ - url: 'https://chrome.google.com/webstore/detail/bitwarden-free-password-m/' + - 'nngceckbapebfimnlniiiahkandclblb/reviews' - }); - break; - case 'firefox': - chrome.tabs.create({ - url: 'https://addons.mozilla.org/en-US/firefox/addon/' + - 'bitwarden-password-manager/#reviews' - }); - break; - case 'edge': - chrome.tabs.create({ - url: 'https://www.microsoft.com/store/p/bitwarden-free-password-manager/9p6kxl0svnnl' - }); - break; - case 'opera': - chrome.tabs.create({ - url: 'https://addons.opera.com/en/extensions/details/' + - 'bitwarden-free-password-manager/#feedback-container' - }); - break; - default: - return; - } - }; - }); diff --git a/src/popup/app/settings/settingsCreditsController.js b/src/popup/app/settings/settingsCreditsController.js deleted file mode 100644 index 1f7dabe95a..0000000000 --- a/src/popup/app/settings/settingsCreditsController.js +++ /dev/null @@ -1,14 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsCreditsController', function ($scope, i18nService, $analytics) { - $scope.i18n = i18nService; - - $scope.learnMore = function () { - $analytics.eventTrack('Contribute Learn More'); - - chrome.tabs.create({ - url: 'https://github.com/bitwarden/browser/blob/master/CONTRIBUTING.md' - }); - }; - }); diff --git a/src/popup/app/settings/settingsEditFolderController.js b/src/popup/app/settings/settingsEditFolderController.js deleted file mode 100644 index 9b2fb5418d..0000000000 --- a/src/popup/app/settings/settingsEditFolderController.js +++ /dev/null @@ -1,57 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsEditFolderController', function ($scope, $stateParams, folderService, toastr, $state, SweetAlert, - utilsService, $analytics, i18nService, $timeout) { - $timeout(function () { - utilsService.initListSectionItemListeners(document, angular); - document.getElementById('name').focus(); - }, 500); - - $scope.i18n = i18nService; - $scope.folder = {}; - var folderId = $stateParams.folderId; - - folderService.get(folderId).then(function (folder) { - return folder.decrypt(); - }).then(function (model) { - $scope.folder = model; - }); - - $scope.savePromise = null; - $scope.save = function (model) { - if (!model.name) { - toastr.error(i18nService.nameRequired, i18nService.errorsOccurred); - return; - } - - $scope.savePromise = folderService.encrypt(model).then(function (folderModel) { - var folder = new Folder(folderModel, true); - return folderService.saveWithServer(folder).then(function (folder) { - $analytics.eventTrack('Edited Folder'); - toastr.success(i18nService.editedFolder); - $state.go('folders', { animation: 'out-slide-down' }); - }); - }); - }; - - $scope.delete = function () { - SweetAlert.swal({ - title: i18nService.deleteFolder, - text: i18nService.deleteFolderConfirmation, - showCancelButton: true, - confirmButtonText: i18nService.yes, - cancelButtonText: i18nService.no - }, function (confirmed) { - if (confirmed) { - folderService.deleteWithServer(folderId).then(function () { - $analytics.eventTrack('Deleted Folder'); - toastr.success(i18nService.deletedFolder); - $state.go('folders', { - animation: 'out-slide-down' - }); - }); - } - }); - }; - }); diff --git a/src/popup/app/settings/settingsEnvironmentController.js b/src/popup/app/settings/settingsEnvironmentController.js deleted file mode 100644 index 78b70c9bce..0000000000 --- a/src/popup/app/settings/settingsEnvironmentController.js +++ /dev/null @@ -1,38 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsEnvironmentController', function ($scope, i18nService, $analytics, utilsService, - environmentService, toastr, $timeout) { - $timeout(function () { - utilsService.initListSectionItemListeners(document, angular); - }, 500); - - $scope.i18n = i18nService; - $scope.baseUrl = environmentService.baseUrl || ''; - $scope.webVaultUrl = environmentService.webVaultUrl || ''; - $scope.apiUrl = environmentService.apiUrl || ''; - $scope.identityUrl = environmentService.identityUrl || ''; - $scope.iconsUrl = environmentService.iconsUrl || ''; - - $scope.save = function () { - environmentService.setUrls({ - base: $scope.baseUrl, - api: $scope.apiUrl, - identity: $scope.identityUrl, - webVault: $scope.webVaultUrl, - icons: $scope.iconsUrl - }).then(function (resUrls) { - $timeout(function () { - // re-set urls since service can change them, ex: prefixing https:// - $scope.baseUrl = resUrls.base; - $scope.apiUrl = resUrls.api; - $scope.identityUrl = resUrls.identity; - $scope.webVaultUrl = resUrls.webVault; - $scope.iconsUrl = resUrls.icons; - - $analytics.eventTrack('Set Environment URLs'); - toastr.success(i18nService.environmentSaved); - }); - }); - }; - }); diff --git a/src/popup/app/settings/settingsFeaturesController.js b/src/popup/app/settings/settingsFeaturesController.js deleted file mode 100644 index 5371f55f11..0000000000 --- a/src/popup/app/settings/settingsFeaturesController.js +++ /dev/null @@ -1,214 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsFeaturesController', function ($scope, i18nService, $analytics, constantsService, utilsService, - totpService, stateService, $timeout) { - $timeout(function () { - utilsService.initListSectionItemListeners(document, angular); - }, 500); - - $scope.i18n = i18nService; - $scope.disableGa = false; - $scope.disableAddLoginNotification = false; - $scope.disableContextMenuItem = false; - $scope.disableAutoTotpCopy = false; - $scope.enableAutoFillOnPageLoad = false; - $scope.disableFavicon = false; - - chrome.storage.local.get(constantsService.enableAutoFillOnPageLoadKey, function (obj) { - $timeout(function () { - $scope.enableAutoFillOnPageLoad = obj && obj[constantsService.enableAutoFillOnPageLoadKey] === true; - }); - }); - - chrome.storage.local.get(constantsService.disableGaKey, function (obj) { - $timeout(function () { - // Default for Firefox is disabled. - if ((utilsService.isFirefox() && obj[constantsService.disableGaKey] === undefined) || - obj[constantsService.disableGaKey]) { - $scope.disableGa = true; - } - else { - $scope.disableGa = false; - } - }); - }); - - chrome.storage.local.get(constantsService.disableAddLoginNotificationKey, function (obj) { - $timeout(function () { - if (obj && obj[constantsService.disableAddLoginNotificationKey]) { - $scope.disableAddLoginNotification = true; - } - else { - $scope.disableAddLoginNotification = false; - } - }); - }); - - chrome.storage.local.get(constantsService.disableContextMenuItemKey, function (obj) { - $timeout(function () { - if (obj && obj[constantsService.disableContextMenuItemKey]) { - $scope.disableContextMenuItem = true; - } - else { - $scope.disableContextMenuItem = false; - } - }); - }); - - totpService.isAutoCopyEnabled().then(function (enabled) { - $timeout(function () { - $scope.disableAutoTotpCopy = !enabled; - }); - }); - - chrome.storage.local.get(constantsService.disableFaviconKey, function (obj) { - $timeout(function () { - $scope.disableFavicon = obj && obj[constantsService.disableFaviconKey] === true; - }); - }); - - $scope.updateGa = function () { - chrome.storage.local.get(constantsService.disableGaKey, function (obj) { - // Default for Firefox is disabled. - if ((utilsService.isFirefox() && obj[constantsService.disableGaKey] === undefined) || - obj[constantsService.disableGaKey]) { - // enable - obj[constantsService.disableGaKey] = false; - } - else { - // disable - $analytics.eventTrack('Disabled Analytics'); - obj[constantsService.disableGaKey] = true; - } - - chrome.storage.local.set(obj, function () { - $timeout(function () { - $scope.disableGa = obj[constantsService.disableGaKey]; - }); - if (!obj[constantsService.disableGaKey]) { - $analytics.eventTrack('Enabled Analytics'); - } - }); - }); - }; - - $scope.updateAddLoginNotification = function () { - chrome.storage.local.get(constantsService.disableAddLoginNotificationKey, function (obj) { - if (obj[constantsService.disableAddLoginNotificationKey]) { - // enable - obj[constantsService.disableAddLoginNotificationKey] = false; - } - else { - // disable - $analytics.eventTrack('Disabled Add Login Notification'); - obj[constantsService.disableAddLoginNotificationKey] = true; - } - - chrome.storage.local.set(obj, function () { - $timeout(function () { - $scope.disableAddLoginNotification = obj[constantsService.disableAddLoginNotificationKey]; - }); - if (!obj[constantsService.disableAddLoginNotificationKey]) { - $analytics.eventTrack('Enabled Add Login Notification'); - } - }); - }); - }; - - $scope.updateDisableContextMenuItem = function () { - chrome.storage.local.get(constantsService.disableContextMenuItemKey, function (obj) { - if (obj[constantsService.disableContextMenuItemKey]) { - // enable - obj[constantsService.disableContextMenuItemKey] = false; - } - else { - // disable - $analytics.eventTrack('Disabled Context Menu Item'); - obj[constantsService.disableContextMenuItemKey] = true; - } - - chrome.storage.local.set(obj, function () { - $timeout(function () { - $scope.disableContextMenuItem = obj[constantsService.disableContextMenuItemKey]; - }); - if (!obj[constantsService.disableContextMenuItemKey]) { - $analytics.eventTrack('Enabled Context Menu Item'); - } - chrome.runtime.sendMessage({ - command: 'bgUpdateContextMenu' - }); - }); - }); - }; - - $scope.updateAutoTotpCopy = function () { - chrome.storage.local.get(constantsService.disableAutoTotpCopyKey, function (obj) { - if (obj[constantsService.disableAutoTotpCopyKey]) { - // enable - obj[constantsService.disableAutoTotpCopyKey] = false; - } - else { - // disable - $analytics.eventTrack('Disabled Auto Copy TOTP'); - obj[constantsService.disableAutoTotpCopyKey] = true; - } - - chrome.storage.local.set(obj, function () { - $timeout(function () { - $scope.disableAutoTotpCopy = obj[constantsService.disableAutoTotpCopyKey]; - }); - if (!obj[constantsService.disableAutoTotpCopyKey]) { - $analytics.eventTrack('Enabled Auto Copy TOTP'); - } - }); - }); - }; - - $scope.updateAutoFillOnPageLoad = function () { - chrome.storage.local.get(constantsService.enableAutoFillOnPageLoadKey, function (obj) { - if (obj[constantsService.enableAutoFillOnPageLoadKey]) { - // disable - obj[constantsService.enableAutoFillOnPageLoadKey] = false; - } - else { - // enable - $analytics.eventTrack('Enable Auto-fill Page Load'); - obj[constantsService.enableAutoFillOnPageLoadKey] = true; - } - - chrome.storage.local.set(obj, function () { - $timeout(function () { - $scope.enableAutoFillOnPageLoad = obj[constantsService.enableAutoFillOnPageLoadKey]; - }); - if (!obj[constantsService.enableAutoFillOnPageLoadKey]) { - $analytics.eventTrack('Disable Auto-fill Page Load'); - } - }); - }); - }; - - $scope.updateDisableFavicon = function () { - chrome.storage.local.get(constantsService.disableFaviconKey, function (obj) { - if (obj[constantsService.disableFaviconKey]) { - // enable - obj[constantsService.disableFaviconKey] = false; - } - else { - // disable - $analytics.eventTrack('Disabled Favicon'); - obj[constantsService.disableFaviconKey] = true; - } - - chrome.storage.local.set(obj, function () { - $timeout(function () { - $scope.disableFavicon = obj[constantsService.disableFaviconKey]; - stateService.saveState('faviconEnabled', !$scope.disableFavicon); - }); - if (!obj[constantsService.disableFaviconKey]) { - $analytics.eventTrack('Enabled Favicon'); - } - }); - }); - }; - }); diff --git a/src/popup/app/settings/settingsFoldersController.js b/src/popup/app/settings/settingsFoldersController.js deleted file mode 100644 index 86543999f1..0000000000 --- a/src/popup/app/settings/settingsFoldersController.js +++ /dev/null @@ -1,29 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsFoldersController', function ($scope, folderService, $q, $state, i18nService) { - $scope.i18n = i18nService; - $scope.loaded = false; - - load(); - function load() { - folderService.getAllDecrypted().then(function (folders) { - if (folders.length > 0 && folders[0].id === null) { - // remove the "none" folder - $scope.folders = folders.slice(1); - } - else { - $scope.folders = folders; - } - - $scope.loaded = true; - }); - } - - $scope.editFolder = function (folder) { - $state.go('editFolder', { - folderId: folder.id, - animation: 'in-slide-up' - }); - }; - }); diff --git a/src/popup/app/settings/settingsHelpController.js b/src/popup/app/settings/settingsHelpController.js deleted file mode 100644 index a1ca86eb3f..0000000000 --- a/src/popup/app/settings/settingsHelpController.js +++ /dev/null @@ -1,25 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsHelpController', function ($scope, $analytics, i18nService) { - $scope.i18n = i18nService; - $scope.email = function () { - $analytics.eventTrack('Selected Help Email'); - chrome.tabs.create({ url: 'mailto:hello@bitwarden.com' }); - }; - - $scope.website = function () { - $analytics.eventTrack('Selected Help Website'); - chrome.tabs.create({ url: 'https://bitwarden.com/contact/' }); - }; - - $scope.tutorial = function () { - $analytics.eventTrack('Selected Help Tutorial'); - chrome.tabs.create({ url: 'https://bitwarden.com/browser-start/' }); - }; - - $scope.bug = function () { - $analytics.eventTrack('Selected Help Bug Report'); - chrome.tabs.create({ url: 'https://github.com/bitwarden/browser' }); - }; - }); diff --git a/src/popup/app/settings/settingsModule.js b/src/popup/app/settings/settingsModule.js deleted file mode 100644 index 8e435ebb33..0000000000 --- a/src/popup/app/settings/settingsModule.js +++ /dev/null @@ -1,2 +0,0 @@ -angular - .module('bit.settings', ['oitozero.ngSweetAlert', 'toastr']); diff --git a/src/popup/app/settings/settingsPremiumController.js b/src/popup/app/settings/settingsPremiumController.js deleted file mode 100644 index da5fabb63f..0000000000 --- a/src/popup/app/settings/settingsPremiumController.js +++ /dev/null @@ -1,50 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsPremiumController', function ($scope, i18nService, tokenService, apiService, toastr, SweetAlert, - $analytics, $timeout) { - $scope.i18n = i18nService; - $scope.isPremium = tokenService.getPremium(); - $scope.price = '$10'; - - $scope.refresh = function () { - apiService.refreshIdentityToken().then(function () { - toastr.success(i18nService.refreshComplete); - $timeout(function () { - $scope.isPremium = tokenService.getPremium(); - }); - }, function (err) { - toastr.error(i18nService.errorsOccurred); - }); - }; - - $scope.purchase = function () { - SweetAlert.swal({ - title: i18nService.premiumPurchase, - text: i18nService.premiumPurchaseAlert, - showCancelButton: true, - confirmButtonText: i18nService.yes, - cancelButtonText: i18nService.cancel - }, function (confirmed) { - $analytics.eventTrack('Clicked Purchase Premium'); - if (confirmed) { - chrome.tabs.create({ url: 'https://vault.bitwarden.com/#/?premium=purchase' }); - } - }); - }; - - $scope.manage = function () { - SweetAlert.swal({ - title: i18nService.premiumManage, - text: i18nService.premiumManageAlert, - showCancelButton: true, - confirmButtonText: i18nService.yes, - cancelButtonText: i18nService.cancel - }, function (confirmed) { - $analytics.eventTrack('Clicked Manage Membership'); - if (confirmed) { - chrome.tabs.create({ url: 'https://vault.bitwarden.com/#/?premium=manage' }); - } - }); - }; - }); diff --git a/src/popup/app/settings/settingsSyncController.js b/src/popup/app/settings/settingsSyncController.js deleted file mode 100644 index b9dea2b680..0000000000 --- a/src/popup/app/settings/settingsSyncController.js +++ /dev/null @@ -1,35 +0,0 @@ -angular - .module('bit.settings') - - .controller('settingsSyncController', function ($scope, syncService, toastr, $analytics, i18nService) { - $scope.i18n = i18nService; - $scope.lastSync = '--'; - $scope.loading = false; - setLastSync(); - - $scope.sync = function () { - $scope.loading = true; - syncService.fullSync(true).then(function (success) { - $scope.loading = false; - if (success) { - setLastSync(); - $analytics.eventTrack('Synced Full'); - toastr.success(i18nService.syncingComplete); - } - else { - toastr.error(i18nService.syncingFailed); - } - }); - }; - - function setLastSync() { - syncService.getLastSync().then(function (lastSync) { - if (lastSync) { - $scope.lastSync = lastSync.toLocaleDateString() + ' ' + lastSync.toLocaleTimeString(); - } - else { - $scope.lastSync = i18nService.never; - } - }); - } - }); diff --git a/src/popup/app/settings/views/settingsSync.html b/src/popup/app/settings/sync.component.html similarity index 51% rename from src/popup/app/settings/views/settingsSync.html rename to src/popup/app/settings/sync.component.html index c44cc796bd..bb8a135f8d 100644 --- a/src/popup/app/settings/views/settingsSync.html +++ b/src/popup/app/settings/sync.component.html @@ -1,17 +1,17 @@ 
-
{{i18n.sync}}
+
{{$ctrl.i18n.sync}}

- - {{i18n.syncVaultNow}} + + {{$ctrl.i18n.syncVaultNow}} - {{i18n.lastSync}} {{lastSync}} - + {{$ctrl.i18n.lastSync}} {{$ctrl.lastSync}} +

diff --git a/src/popup/app/settings/sync.component.ts b/src/popup/app/settings/sync.component.ts new file mode 100644 index 0000000000..47d5d8938a --- /dev/null +++ b/src/popup/app/settings/sync.component.ts @@ -0,0 +1,47 @@ +import * as template from './sync.component.html'; + +class SyncController { + i18n: any; + lastSync = '--'; + loading = false; + + constructor(private syncService: any, private toastr: any, private $analytics: any, private i18nService: any) { + this.i18n = i18nService; + + this.setLastSync(); + } + + sync() { + this.loading = true; + this.syncService + .fullSync(true) + .then((success: boolean) => { + this.loading = false; + if (success) { + this.setLastSync(); + this.$analytics.eventTrack('Synced Full'); + this.toastr.success(this.i18nService.syncingComplete); + } else { + this.toastr.error(this.i18nService.syncingFailed); + } + }); + } + + setLastSync() { + this.syncService + .getLastSync() + .then((lastSync: any) => { + if (lastSync) { + this.lastSync = lastSync.toLocaleDateString() + ' ' + lastSync.toLocaleTimeString(); + } else { + this.lastSync = this.i18nService.never; + } + }); + } +} + +export const SyncComponent = { + bindings: {}, + controller: SyncController, + template, +}; diff --git a/src/popup/app/settings/views/settingsFolders.html b/src/popup/app/settings/views/settingsFolders.html deleted file mode 100644 index e06ada0b9a..0000000000 --- a/src/popup/app/settings/views/settingsFolders.html +++ /dev/null @@ -1,31 +0,0 @@ -
- -
- -
-
{{i18n.folders}}
-
-
- -
-

- {{i18n.noFolders}} - {{i18n.addFolder}} -

-
-
- -
-