[Typecript] Convert current (#372)
* Convert current controller to component. * Remove unessesary $ctrl.loaded checks. * Fix bindings for callbacks. * Re-format html. * Add UtilService interface to current component. * Set sucessfully to boolean, change setTimeout to $timeout.
This commit is contained in:
parent
0c8dc0c3ec
commit
c6c8042ecf
|
@ -24,6 +24,7 @@ import ComponentsModule from './components/components.module';
|
||||||
import ToolsModule from './tools/tools.module';
|
import ToolsModule from './tools/tools.module';
|
||||||
import ServicesModule from './services/services.module';
|
import ServicesModule from './services/services.module';
|
||||||
import LockModule from './lock/lock.module';
|
import LockModule from './lock/lock.module';
|
||||||
|
import CurrentModule from './current/current.module';
|
||||||
|
|
||||||
// Model imports
|
// Model imports
|
||||||
import { Attachment } from '../../models/domain/attachment';
|
import { Attachment } from '../../models/domain/attachment';
|
||||||
|
@ -83,7 +84,7 @@ angular
|
||||||
|
|
||||||
'bit.global',
|
'bit.global',
|
||||||
'bit.accounts',
|
'bit.accounts',
|
||||||
'bit.current',
|
CurrentModule,
|
||||||
'bit.vault',
|
'bit.vault',
|
||||||
'bit.settings',
|
'bit.settings',
|
||||||
ToolsModule,
|
ToolsModule,
|
||||||
|
@ -107,8 +108,6 @@ require('./accounts/accountsLoginTwoFactorController.js');
|
||||||
require('./accounts/accountsTwoFactorMethodsController.js');
|
require('./accounts/accountsTwoFactorMethodsController.js');
|
||||||
require('./accounts/accountsHintController.js');
|
require('./accounts/accountsHintController.js');
|
||||||
require('./accounts/accountsRegisterController.js');
|
require('./accounts/accountsRegisterController.js');
|
||||||
require('./current/currentModule.js');
|
|
||||||
require('./current/currentController.js');
|
|
||||||
require('./vault/vaultModule.js');
|
require('./vault/vaultModule.js');
|
||||||
require('./vault/vaultController.js');
|
require('./vault/vaultController.js');
|
||||||
require('./vault/vaultViewFolderController.js');
|
require('./vault/vaultViewFolderController.js');
|
||||||
|
|
|
@ -9,11 +9,11 @@ class CipherItemsController implements ng.IController {
|
||||||
}
|
}
|
||||||
|
|
||||||
view(cipher: any) {
|
view(cipher: any) {
|
||||||
return this.onView()(cipher);
|
return this.onView({cipher});
|
||||||
}
|
}
|
||||||
|
|
||||||
select(cipher: any) {
|
select(cipher: any) {
|
||||||
return this.onSelected()(cipher);
|
return this.onSelected({cipher});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,8 +110,7 @@ angular
|
||||||
})
|
})
|
||||||
.state('tabs.current', {
|
.state('tabs.current', {
|
||||||
url: '/current',
|
url: '/current',
|
||||||
template: require('./current/views/current.html'),
|
component: 'current'
|
||||||
controller: 'currentController'
|
|
||||||
})
|
})
|
||||||
.state('tabs.vault', {
|
.state('tabs.vault', {
|
||||||
url: '/vault',
|
url: '/vault',
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
<div class="header header-search">
|
||||||
|
<div class="left" ng-if="!$ctrl.inSidebar">
|
||||||
|
<pop-out></pop-out>
|
||||||
|
</div>
|
||||||
|
<div class="left" ng-if="$ctrl.inSidebar">
|
||||||
|
<a href="" ng-click="$ctrl.refresh()"><i class="fa fa-refresh fa-lg"></i></a>
|
||||||
|
</div>
|
||||||
|
<div class="search" ng-style="{'visibility': $ctrl.disableSearch ? 'hidden' : 'visible'}">
|
||||||
|
<input type="search" placeholder="{{$ctrl.i18n.searchVault}}" id="search" ng-model="searchText" ng-change="$ctrl.searchVault()" />
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<a href="" ng-click="$ctrl.addCipher()"><i class="fa fa-plus fa-lg"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content content-tabs">
|
||||||
|
<div class="list" ng-if="$ctrl.loaded">
|
||||||
|
<div class="list-section">
|
||||||
|
<div class="list-section-header">
|
||||||
|
{{$ctrl.i18n.typeLogins}}
|
||||||
|
</div>
|
||||||
|
<div class="list-section-items" ng-class="{'list-no-selection': !$ctrl.loginCiphers.length}">
|
||||||
|
<cipher-items
|
||||||
|
ng-if="$ctrl.loginCiphers.length"
|
||||||
|
ciphers="$ctrl.loginCiphers"
|
||||||
|
on-view="$ctrl.viewCipher(cipher)"
|
||||||
|
on-selected="$ctrl.fillCipher(cipher)"
|
||||||
|
selection-title="$ctrl.i18n.autoFill">
|
||||||
|
</cipher-items>
|
||||||
|
<div class="list-section-item" ng-if="!$ctrl.loginCiphers.length">
|
||||||
|
<p>{{$ctrl.i18n.autoFillInfo}}</p>
|
||||||
|
<button ng-click="$ctrl.addCipher()" class="btn btn-link btn-block">{{$ctrl.i18n.addLogin}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="list-section" ng-class="{'list-no-selection': !$ctrl.otherCiphers.length}">
|
||||||
|
<div class="list-section-header">
|
||||||
|
{{$ctrl.i18n.other}}
|
||||||
|
</div>
|
||||||
|
<div class="list-section-items">
|
||||||
|
<div class="list-section-item" ng-if="!$ctrl.otherCiphers.length">{{$ctrl.i18n.noItemsInList}}</div>
|
||||||
|
<cipher-items
|
||||||
|
ng-if="$ctrl.otherCiphers.length"
|
||||||
|
ciphers="$ctrl.otherCiphers"
|
||||||
|
on-view="$ctrl.viewCipher(cipher)"
|
||||||
|
on-selected="$ctrl.fillCipher(cipher)"
|
||||||
|
selection-title="$ctrl.i18n.autoFill">
|
||||||
|
</cipher-items>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page-loading" ng-if="!$ctrl.loaded">
|
||||||
|
<i class="fa fa-lg fa-spinner fa-spin"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -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,
|
||||||
|
};
|
|
@ -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;
|
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,2 +0,0 @@
|
||||||
angular
|
|
||||||
.module('bit.current', ['toastr', 'ngclipboard']);
|
|
|
@ -1,45 +0,0 @@
|
||||||
<div class="header header-search">
|
|
||||||
<div class="left" ng-if="!inSidebar">
|
|
||||||
<pop-out></pop-out>
|
|
||||||
</div>
|
|
||||||
<div class="left" ng-if="inSidebar">
|
|
||||||
<a href="" ng-click="refresh()"><i class="fa fa-refresh fa-lg"></i></a>
|
|
||||||
</div>
|
|
||||||
<div class="search" ng-style="{'visibility': disableSearch ? 'hidden' : 'visible'}">
|
|
||||||
<input type="search" placeholder="{{i18n.searchVault}}" id="search" ng-model="searchText" ng-change="searchVault()" />
|
|
||||||
<i class="fa fa-search"></i>
|
|
||||||
</div>
|
|
||||||
<div class="right">
|
|
||||||
<a href="" ng-click="addCipher()"><i class="fa fa-plus fa-lg"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="content content-tabs">
|
|
||||||
<div class="list" ng-if="loaded">
|
|
||||||
<div class="list-section">
|
|
||||||
<div class="list-section-header">
|
|
||||||
{{i18n.typeLogins}}
|
|
||||||
</div>
|
|
||||||
<div class="list-section-items" ng-class="{'list-no-selection': !loginCiphers.length}">
|
|
||||||
<div class="list-section-item" ng-if="loaded && !loginCiphers.length">
|
|
||||||
<p>{{i18n.autoFillInfo}}</p>
|
|
||||||
<button ng-click="addCipher()" class="btn btn-link btn-block">{{i18n.addLogin}}</button>
|
|
||||||
</div>
|
|
||||||
<cipher-items ng-if="loginCiphers.length" ciphers="loginCiphers" on-view="viewCipher"
|
|
||||||
on-selected="fillCipher" selection-title="i18n.autoFill"></cipher-items>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="list-section" ng-class="{'list-no-selection': !otherCiphers.length}">
|
|
||||||
<div class="list-section-header">
|
|
||||||
{{i18n.other}}
|
|
||||||
</div>
|
|
||||||
<div class="list-section-items">
|
|
||||||
<div class="list-section-item" ng-if="loaded && !otherCiphers.length">{{i18n.noItemsInList}}</div>
|
|
||||||
<cipher-items ng-if="otherCiphers.length" ciphers="otherCiphers" on-view="viewCipher"
|
|
||||||
on-selected="fillCipher" selection-title="i18n.autoFill"></cipher-items>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="page-loading" ng-if="!loaded">
|
|
||||||
<i class="fa fa-lg fa-spinner fa-spin"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
Loading…
Reference in New Issue