diff --git a/src/popup/app/tools/password-generator.component.ts b/src/popup/app/tools/password-generator.component.ts
new file mode 100644
index 0000000000..b6efd7ec5f
--- /dev/null
+++ b/src/popup/app/tools/password-generator.component.ts
@@ -0,0 +1,139 @@
+import * as angular from 'angular';
+import * as template from './password-generator.component.html';
+
+export class PasswordGeneratorController {
+ $transition$: any;
+ options: any;
+ showSelect: any;
+ password: string = '-';
+ editState: any;
+ addState: any;
+ i18n: any;
+
+ constructor(private $state: any, private passwordGenerationService: any,
+ private toastr: any, utilsService: any, private $analytics: any,
+ private i18nService: any) {
+ this.i18n = i18nService;
+
+ utilsService.initListSectionItemListeners($(document), angular);
+
+ passwordGenerationService.getOptions().then((options: any) => {
+ this.options = options;
+ this.regenerate(false);
+ $analytics.eventTrack('Generated Password');
+ passwordGenerationService.addHistory(this.password);
+ });
+
+ // Save password once the slider stop moving.
+ document.querySelector('#length').addEventListener('change', (e) => {
+ e.preventDefault();
+
+ $analytics.eventTrack('Generated Password');
+ this.saveOptions(this.options, false);
+ passwordGenerationService.addHistory(this.password);
+ });
+ }
+
+ $onInit() {
+ const params = this.$transition$.params('to');
+ this.addState = params.addState;
+ this.editState = params.editState;
+
+ this.showSelect = this.addState || this.editState;
+ }
+
+ sliderMoved() {
+ this.regenerate(false);
+ }
+
+ regenerate(trackEvent: any) {
+ this.password = this.passwordGenerationService.generatePassword(this.options);
+
+ if (trackEvent) {
+ this.$analytics.eventTrack('Regenerated Password');
+ this.passwordGenerationService.addHistory(this.password);
+ }
+ }
+
+ saveOptions(options: any, regenerate: boolean = true) {
+ if (!options.uppercase && !options.lowercase && !options.number && !options.special) {
+ options.lowercase = this.options.lowercase = true;
+ }
+ if (!options.minNumber) {
+ options.minNumber = this.options.minNumber = 0;
+ }
+ if (!options.minSpecial) {
+ options.minSpecial = this.options.minSpecial = 0;
+ }
+
+ this.passwordGenerationService.saveOptions(options);
+ if (regenerate) {
+ this.regenerate(false);
+ }
+ return true;
+ }
+
+ clipboardError(e: any, password: any) {
+ this.toastr.info(this.i18nService.browserNotSupportClipboard);
+ }
+
+ clipboardSuccess(e: any) {
+ this.$analytics.eventTrack('Copied Generated Password');
+ e.clearSelection();
+ this.toastr.info(this.i18nService.passwordCopied);
+ }
+
+ close() {
+ this.dismiss();
+ }
+
+ select() {
+ this.$analytics.eventTrack('Selected Generated Password');
+
+ if (this.addState) {
+ this.addState.cipher.login.password = this.password;
+ } else if (this.editState) {
+ this.editState.cipher.login.password = this.password;
+ }
+
+ this.dismiss();
+ }
+
+ goHistory() {
+ this.$state.go('^.passwordGeneratorHistory', {
+ animation: 'in-slide-left',
+ addState: this.addState,
+ editState: this.editState,
+ });
+ }
+
+ private dismiss() {
+ if (this.addState) {
+ this.$state.go('addCipher', {
+ animation: 'out-slide-down',
+ from: this.addState.from,
+ cipher: this.addState.cipher,
+ });
+ } else if (this.editState) {
+ this.$state.go('editCipher', {
+ animation: 'out-slide-down',
+ cipher: this.editState.cipher,
+ fromView: this.editState.fromView,
+ cipherId: this.editState.cipherId,
+ from: this.editState.from,
+ });
+ } else {
+ this.$state.go('tabs.tools', {
+ animation: 'out-slide-down',
+ });
+ }
+ }
+}
+
+export const PasswordGeneratorComponent = {
+ bindings: {
+ $transition$: '<',
+ },
+ controller: PasswordGeneratorController,
+ template,
+};
diff --git a/src/popup/app/tools/tools.module.ts b/src/popup/app/tools/tools.module.ts
index daedaac198..c01111438e 100644
--- a/src/popup/app/tools/tools.module.ts
+++ b/src/popup/app/tools/tools.module.ts
@@ -1,7 +1,11 @@
import * as angular from 'angular';
+import { PasswordGeneratorComponent } from './password-generator.component';
import { ToolsComponent } from './tools.component';
export default angular
.module('bit.tools', ['ngAnimate', 'ngclipboard', 'toastr', 'oitozero.ngSweetAlert'])
+
.component('tools', ToolsComponent)
+ .component('passwordGenerator', PasswordGeneratorComponent)
+
.name;
diff --git a/src/popup/app/tools/toolsPasswordGeneratorController.js b/src/popup/app/tools/toolsPasswordGeneratorController.js
deleted file mode 100644
index 19da18ea60..0000000000
--- a/src/popup/app/tools/toolsPasswordGeneratorController.js
+++ /dev/null
@@ -1,116 +0,0 @@
-angular
- .module('bit.tools')
-
- .controller('toolsPasswordGeneratorController', function ($scope, $state, $stateParams, passwordGenerationService,
- toastr, utilsService, $analytics, i18nService) {
- $scope.i18n = i18nService;
- var addState = $stateParams.addState,
- editState = $stateParams.editState;
-
- $scope.showSelect = $stateParams.addState || $stateParams.editState;
-
- utilsService.initListSectionItemListeners($(document), angular);
- $scope.password = '-';
-
- passwordGenerationService.getOptions().then(function (options) {
- $scope.options = options;
- $scope.regenerate(false);
- $analytics.eventTrack('Generated Password');
- passwordGenerationService.addHistory($scope.password);
- });
-
- $scope.sliderMoved = function () {
- $scope.regenerate(false);
- };
-
- $('#length').change(function (e) {
- e.preventDefault();
- $analytics.eventTrack('Generated Password');
- $scope.saveOptions($scope.options);
- passwordGenerationService.addHistory($scope.password);
- });
-
- $scope.regenerate = function (trackEvent) {
- $scope.password = passwordGenerationService.generatePassword($scope.options);
-
- if (trackEvent) {
- $analytics.eventTrack('Regenerated Password');
- passwordGenerationService.addHistory($scope.password);
- }
- };
-
- $scope.saveOptions = function (options) {
- if (!options.uppercase && !options.lowercase && !options.number && !options.special) {
- options.lowercase = $scope.options.lowercase = true;
- }
- if (!options.minNumber) {
- options.minNumber = $scope.options.minNumber = 0;
- }
- if (!options.minSpecial) {
- options.minSpecial = $scope.options.minSpecial = 0;
- }
-
- passwordGenerationService.saveOptions(options);
- $scope.regenerate(false);
- return true;
- };
-
- $scope.clipboardError = function (e, password) {
- toastr.info(i18n.browserNotSupportClipboard);
- };
-
- $scope.clipboardSuccess = function (e) {
- $analytics.eventTrack('Copied Generated Password');
- e.clearSelection();
- toastr.info(i18nService.passwordCopied);
- };
-
- $scope.close = function () {
- dismiss();
- };
-
- $scope.select = function () {
- $analytics.eventTrack('Selected Generated Password');
-
- if (addState) {
- addState.cipher.login.password = $scope.password;
- }
- else if (editState) {
- editState.cipher.login.password = $scope.password;
- }
-
- dismiss();
- };
-
- $scope.goHistory = function () {
- $state.go('^.passwordGeneratorHistory', {
- animation: 'in-slide-left',
- addState: $stateParams.addState,
- editState: $stateParams.editState
- });
- };
-
- function dismiss() {
- if (addState) {
- $state.go('addCipher', {
- animation: 'out-slide-down',
- from: addState.from,
- cipher: addState.cipher
- });
- }
- else if (editState) {
- $state.go('editCipher', {
- animation: 'out-slide-down',
- cipher: editState.cipher,
- fromView: editState.fromView,
- cipherId: editState.cipherId,
- from: editState.from
- });
- }
- else {
- $state.go('tabs.tools', {
- animation: 'out-slide-down'
- });
- }
- }
- });