diff --git a/src/popup/app/app.js b/src/popup/app/app.js index 4e23deda23..230be7915c 100644 --- a/src/popup/app/app.js +++ b/src/popup/app/app.js @@ -24,6 +24,7 @@ import ComponentsModule from './components/components.module'; import ToolsModule from './tools/tools.module'; import ServicesModule from './services/services.module'; import LockModule from './lock/lock.module'; +import CurrentModule from './current/current.module'; // Model imports import { Attachment } from '../../models/domain/attachment'; @@ -83,7 +84,7 @@ angular 'bit.global', 'bit.accounts', - 'bit.current', + CurrentModule, 'bit.vault', 'bit.settings', ToolsModule, @@ -107,8 +108,6 @@ require('./accounts/accountsLoginTwoFactorController.js'); require('./accounts/accountsTwoFactorMethodsController.js'); require('./accounts/accountsHintController.js'); require('./accounts/accountsRegisterController.js'); -require('./current/currentModule.js'); -require('./current/currentController.js'); require('./vault/vaultModule.js'); require('./vault/vaultController.js'); require('./vault/vaultViewFolderController.js'); diff --git a/src/popup/app/components/cipher-items.component.ts b/src/popup/app/components/cipher-items.component.ts index 35cd979030..fcace63579 100644 --- a/src/popup/app/components/cipher-items.component.ts +++ b/src/popup/app/components/cipher-items.component.ts @@ -9,11 +9,11 @@ class CipherItemsController implements ng.IController { } view(cipher: any) { - return this.onView()(cipher); + return this.onView({cipher}); } select(cipher: any) { - return this.onSelected()(cipher); + return this.onSelected({cipher}); } } diff --git a/src/popup/app/config.js b/src/popup/app/config.js index d679a3b1e2..b2aa814780 100644 --- a/src/popup/app/config.js +++ b/src/popup/app/config.js @@ -110,8 +110,7 @@ angular }) .state('tabs.current', { url: '/current', - template: require('./current/views/current.html'), - controller: 'currentController' + component: 'current' }) .state('tabs.vault', { url: '/vault', diff --git a/src/popup/app/current/current.component.html b/src/popup/app/current/current.component.html new file mode 100644 index 0000000000..de652cc253 --- /dev/null +++ b/src/popup/app/current/current.component.html @@ -0,0 +1,55 @@ + +
+
+
+
+ {{$ctrl.i18n.typeLogins}} +
+
+ + +
+

{{$ctrl.i18n.autoFillInfo}}

+ +
+
+
+
+
+ {{$ctrl.i18n.other}} +
+
+
{{$ctrl.i18n.noItemsInList}}
+ + +
+
+
+
+ +
+
diff --git a/src/popup/app/current/current.component.ts b/src/popup/app/current/current.component.ts new file mode 100644 index 0000000000..ec0756811f --- /dev/null +++ b/src/popup/app/current/current.component.ts @@ -0,0 +1,161 @@ +import { UtilsService } from '../../../services/abstractions/utils.service'; +import * as template from './current.component.html'; + +class CurrentController { + i18n: any; + pageDetails: any = []; + loaded: boolean = false; + otherCiphers: any = []; + loginCiphers: any = []; + url: any; + domain: any; + canAutofill: boolean = false; + searchText: string = null; + inSidebar: boolean = false; + disableSearch: boolean = false; + + constructor($scope: any, private cipherService: any, private utilsService: UtilsService, private toastr: any, + private $window: any, private $state: any, private $timeout: any, private autofillService: any, + private $analytics: any, private i18nService: any, private constantsService: any, + private $filter: any) { + + this.i18n = i18nService; + this.inSidebar = utilsService.inSidebar($window); + this.disableSearch = utilsService.isEdge(); + + document.getElementById('search').focus(); + + $scope.$on('syncCompleted', (event: any, successfully: boolean) => { + if (this.loaded) { + $timeout(this.loadVault.bind(this), 500); + } + }); + + $scope.$on('collectPageDetailsResponse', (event: any, details: any) => { + this.pageDetails.push(details); + }); + } + + $onInit() { + this.loadVault(); + } + + refresh() { + this.loadVault(); + } + + addCipher() { + this.$state.go('addCipher', { + animation: 'in-slide-up', + name: this.domain, + uri: this.url, + from: 'current', + }); + } + + viewCipher(cipher: any) { + this.$state.go('viewCipher', { + cipherId: cipher.id, + animation: 'in-slide-up', + from: 'current', + }); + } + + fillCipher(cipher: any) { + if (!this.canAutofill) { + this.$analytics.eventTrack('Autofilled Error'); + this.toastr.error(this.i18nService.autofillError); + } + + this.autofillService + .doAutoFill({ + cipher, + pageDetails: this.pageDetails, + fromBackground: false, + }) + .then((totpCode: string) => { + this.$analytics.eventTrack('Autofilled'); + if (totpCode && this.utilsService.isFirefox()) { + this.utilsService.copyToClipboard(totpCode, document); + } + if (this.utilsService.inPopup(this.$window)) { + this.$window.close(); + } + }) + .catch(() => { + this.$analytics.eventTrack('Autofilled Error'); + this.toastr.error(this.i18nService.autofillError); + }); + } + + searchVault() { + this.$state.go('tabs.vault', { + searchText: this.searchText, + }); + } + + private loadVault() { + chrome.tabs.query({ active: true, currentWindow: true }, (tabs: any) => { + if (tabs.length > 0) { + this.url = tabs[0].url; + } else { + this.$timeout(() => { + this.loaded = true; + }); + return; + } + + this.domain = this.utilsService.getDomain(this.url); + + chrome.tabs.sendMessage(tabs[0].id, { + command: 'collectPageDetails', + tab: tabs[0], + sender: 'currentController', + }, () => { + this.canAutofill = true; + }); + + const otherTypes = [ + this.constantsService.cipherType.card, + this.constantsService.cipherType.identity, + ]; + + this.cipherService.getAllDecryptedForDomain(this.domain, otherTypes).then((ciphers: any) => { + const loginCiphers: any = []; + const otherCiphers: any = []; + + for (const cipher of ciphers) { + if (cipher.type === this.constantsService.cipherType.login) { + loginCiphers.push(cipher); + } else { + otherCiphers.push(cipher); + } + } + + this.$timeout(() => { + this.loginCiphers = this.$filter('orderBy')( + loginCiphers, + [this.sortUriMatch, this.sortLastUsed, 'name', 'subTitle'], + ); + this.otherCiphers = this.$filter('orderBy')(otherCiphers, [this.sortLastUsed, 'name', 'subTitle']); + this.loaded = true; + }); + }); + }); + } + + private sortUriMatch(cipher: any) { + // exact matches should sort earlier. + return this.url && this.url.startsWith(cipher.uri) ? 0 : 1; + } + + private sortLastUsed(cipher: any) { + return cipher.localData && cipher.localData.lastUsedDate ? -1 * cipher.localData.lastUsedDate : 0; + } +} + +export const CurrentComponent = { + bindings: {}, + controller: CurrentController, + template, +}; diff --git a/src/popup/app/current/current.module.ts b/src/popup/app/current/current.module.ts new file mode 100644 index 0000000000..a3bbd942a4 --- /dev/null +++ b/src/popup/app/current/current.module.ts @@ -0,0 +1,9 @@ +import * as angular from 'angular'; +import { CurrentComponent } from './current.component'; + +export default angular + .module('bit.current', ['toastr', 'ngclipboard']) + + .component('current', CurrentComponent) + + .name; diff --git a/src/popup/app/current/currentController.js b/src/popup/app/current/currentController.js deleted file mode 100644 index 1d448b4053..0000000000 --- a/src/popup/app/current/currentController.js +++ /dev/null @@ -1,139 +0,0 @@ -angular - .module('bit.current') - - .controller('currentController', function ($scope, cipherService, utilsService, toastr, $window, $state, $timeout, - autofillService, $analytics, i18nService, totpService, tokenService, constantsService, $filter) { - $scope.i18n = i18nService; - - var pageDetails = [], - url = null, - domain = null, - canAutofill = false; - - $scope.loginCiphers = []; - $scope.otherCiphers = []; - $scope.loaded = false; - $scope.searchText = null; - $scope.inSidebar = utilsService.inSidebar($window); - $scope.disableSearch = utilsService.isEdge(); - document.getElementById('search').focus(); - - $scope.$on('$viewContentLoaded', function () { - $timeout(loadVault, 100); - }); - - function loadVault() { - chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { - if (tabs.length > 0) { - url = tabs[0].url; - } - else { - $timeout(function () { - $scope.loaded = true; - }); - return; - } - - domain = utilsService.getDomain(url); - - chrome.tabs.sendMessage(tabs[0].id, { - command: 'collectPageDetails', - tab: tabs[0], - sender: 'currentController' - }, function () { - canAutofill = true; - }); - - var otherTypes = [constantsService.cipherType.card, constantsService.cipherType.identity]; - cipherService.getAllDecryptedForDomain(domain, otherTypes).then(function (ciphers) { - var loginCiphers = [], - otherCiphers = []; - - for (var i = 0; i < ciphers.length; i++) { - if (ciphers[i].type === constantsService.cipherType.login) { - loginCiphers.push(ciphers[i]); - } - else { - otherCiphers.push(ciphers[i]); - } - } - - $timeout(function () { - $scope.loginCiphers = $filter('orderBy')(loginCiphers, [sortUriMatch, sortLastUsed, 'name', 'subTitle']); - $scope.otherCiphers = $filter('orderBy')(otherCiphers, [sortLastUsed, 'name', 'subTitle']); - $scope.loaded = true; - }); - }); - }); - } - - $scope.addCipher = function () { - $state.go('addCipher', { - animation: 'in-slide-up', - name: domain, - uri: url, - from: 'current' - }); - }; - - $scope.fillCipher = function (cipher) { - if (!canAutofill) { - $analytics.eventTrack('Autofilled Error'); - toastr.error(i18nService.autofillError); - } - - autofillService.doAutoFill({ - cipher: cipher, - pageDetails: pageDetails, - fromBackground: false - }).then(function (totpCode) { - $analytics.eventTrack('Autofilled'); - if (totpCode && utilsService.isFirefox()) { - utilsService.copyToClipboard(totpCode, document); - } - if (utilsService.inPopup($window)) { - $window.close(); - } - }, function () { - $analytics.eventTrack('Autofilled Error'); - toastr.error(i18nService.autofillError); - }); - }; - - $scope.viewCipher = function (cipher) { - $state.go('viewCipher', { - cipherId: cipher.id, - animation: 'in-slide-up', - from: 'current' - }); - }; - - function sortUriMatch(cipher) { - // exact matches should sort earlier. - return url && url.startsWith(cipher.uri) ? 0 : 1; - } - - function sortLastUsed(cipher) { - return cipher.localData && cipher.localData.lastUsedDate ? -1 * cipher.localData.lastUsedDate : 0; - } - - $scope.searchVault = function () { - $state.go('tabs.vault', { - searchText: $scope.searchText - }); - }; - - $scope.refresh = function () { - loadVault(); - }; - - $scope.$on('syncCompleted', function (event, successfully) { - if ($scope.loaded) { - setTimeout(loadVault, 500); - } - }); - - $scope.$on('collectPageDetailsResponse', function (event, details) { - pageDetails.push(details); - }); - }); diff --git a/src/popup/app/current/currentModule.js b/src/popup/app/current/currentModule.js deleted file mode 100644 index 3334a742ac..0000000000 --- a/src/popup/app/current/currentModule.js +++ /dev/null @@ -1,2 +0,0 @@ -angular - .module('bit.current', ['toastr', 'ngclipboard']); diff --git a/src/popup/app/current/views/current.html b/src/popup/app/current/views/current.html deleted file mode 100644 index 8c39fcde23..0000000000 --- a/src/popup/app/current/views/current.html +++ /dev/null @@ -1,45 +0,0 @@ - -
-
-
-
- {{i18n.typeLogins}} -
-
-
-

{{i18n.autoFillInfo}}

- -
- -
-
-
-
- {{i18n.other}} -
-
-
{{i18n.noItemsInList}}
- -
-
-
-
- -
-