diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 7c042f77d43..87053c01609 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -614,5 +614,9 @@ "translations": { "message": "Translations", "description": "Translations" + }, + "searchFolder": { + "message": "Search folder", + "description": "Search folder" } } diff --git a/src/popup/app/config.js b/src/popup/app/config.js index bda90498c05..61446489b1c 100644 --- a/src/popup/app/config.js +++ b/src/popup/app/config.js @@ -88,6 +88,13 @@ controller: 'toolsController' }) + .state('viewFolder', { + url: '/view-folder?folderId', + templateUrl: 'app/vault/views/vaultViewFolder.html', + controller: 'vaultViewFolderController', + data: { authorize: true }, + params: { animation: null, returnScrollY: 0, returnSearchText: null, fromCurrent: false } + }) .state('viewSite', { url: '/view-site?siteId', templateUrl: 'app/vault/views/vaultViewSite.html', diff --git a/src/popup/app/vault/vaultController.js b/src/popup/app/vault/vaultController.js index c030cec3f66..a0c8c61f46f 100644 --- a/src/popup/app/vault/vaultController.js +++ b/src/popup/app/vault/vaultController.js @@ -115,7 +115,12 @@ }; $scope.viewFolder = function (folder) { - // TODO: vault folder page + $state.go('viewFolder', { + folderId: folder.id || '', + animation: 'in-slide-left', + returnScrollY: getScrollY(), + returnSearchText: $scope.searchText + }); }; $scope.clipboardError = function (e) { diff --git a/src/popup/app/vault/vaultViewFolderController.js b/src/popup/app/vault/vaultViewFolderController.js new file mode 100644 index 00000000000..0af3df22c74 --- /dev/null +++ b/src/popup/app/vault/vaultViewFolderController.js @@ -0,0 +1,127 @@ +angular + .module('bit.vault') + + .controller('vaultViewFolderController', function ($scope, siteService, folderService, $q, $state, $stateParams, toastr, + syncService, $analytics, i18nService) { + $scope.folder = { + id: $stateParams.folderId || null, + name: '(none)' + }; + $scope.i18n = i18nService; + $('#search').focus(); + + $scope.loaded = false; + $scope.vaultSites = []; + loadVault(); + + function loadVault() { + var decFolder = null; + var decSites = []; + var promises = []; + + if ($scope.folder.id) { + var folderDeferred = $q.defer(); + folderService.get($scope.folder.id, function (folder) { + $q.when(folder.decrypt()).then(function (model) { + decFolder = model; + folderDeferred.resolve(); + }); + }); + promises.push(folderDeferred.promise); + } + + var sitePromise = $q.when(siteService.getAllDecryptedForFolder($scope.folder.id)); + sitePromise.then(function (sites) { + decSites = sites; + }); + promises.push(sitePromise); + + $q.all(promises).then(function () { + $scope.loaded = true; + $scope.vaultSites = decSites; + if (decFolder) { + $scope.folder.name = decFolder.name; + } + setScrollY(); + }); + } + + $scope.searchText = null; + if ($stateParams.searchText) { + $scope.searchText = $stateParams.searchText; + } + + $scope.folderSort = function (item) { + if (!item.id) { + return ''; + } + + return item.name.toLowerCase(); + }; + + $scope.searchSites = function () { + if (!$scope.searchText || $scope.searchText.length < 2) { + return; + } + + return searchSite; + }; + + function searchSite(site) { + var searchTerm = $scope.searchText.toLowerCase(); + if (site.name && site.name.toLowerCase().indexOf(searchTerm) !== -1) { + return true; + } + if (site.username && site.username.toLowerCase().indexOf(searchTerm) !== -1) { + return true; + } + if (site.uri && site.uri.toLowerCase().indexOf(searchTerm) !== -1) { + return true; + } + + return false; + } + + $scope.addSite = function () { + $state.go('addSite', { + animation: 'in-slide-up', + returnScrollY: getScrollY(), + returnSearchText: $scope.searchText + }); + }; + + $scope.viewSite = function (site) { + $state.go('viewSite', { + siteId: site.id, + animation: 'in-slide-up', + returnScrollY: getScrollY(), + returnSearchText: $scope.searchText + }); + }; + + $scope.clipboardError = function (e) { + toastr.info(i18n.browserNotSupportClipboard); + }; + + $scope.clipboardSuccess = function (e, type) { + e.clearSelection(); + $analytics.eventTrack('Copied ' + (type === i18nService.username ? 'Username' : 'Password')); + toastr.info(type + i18nService.valueCopied); + }; + + $scope.$on('syncCompleted', function (event, successfully) { + setTimeout(loadVault, 500); + }); + + function getScrollY() { + var content = document.getElementsByClassName('content')[0]; + return content.scrollTop; + } + + function setScrollY() { + if ($stateParams.scrollY) { + var content = document.getElementsByClassName('content')[0]; + content.scrollTop = $stateParams.scrollY; + } + } + }); diff --git a/src/popup/app/vault/views/vault.html b/src/popup/app/vault/views/vault.html index a99a6abcd44..b84a5d02413 100644 --- a/src/popup/app/vault/views/vault.html +++ b/src/popup/app/vault/views/vault.html @@ -10,7 +10,7 @@
-
+
{{i18n.folders}}
diff --git a/src/popup/app/vault/views/vaultViewFolder.html b/src/popup/app/vault/views/vaultViewFolder.html new file mode 100644 index 00000000000..aa7d21d64be --- /dev/null +++ b/src/popup/app/vault/views/vaultViewFolder.html @@ -0,0 +1,49 @@ +
+ +
+ +
+ +
+
+
+ +
+
+

+ {{i18n.noSitesInList}} + +

+
+
+ +
+
diff --git a/src/popup/index.html b/src/popup/index.html index 6d733414653..6378dc49aab 100644 --- a/src/popup/index.html +++ b/src/popup/index.html @@ -61,6 +61,7 @@ + diff --git a/src/popup/less/components.less b/src/popup/less/components.less index d483e71f12a..a895cc40e82 100644 --- a/src/popup/less/components.less +++ b/src/popup/less/components.less @@ -103,6 +103,14 @@ color: lighten(@brand-primary, 30%); } } + + .left ~ .right ~ .search { + margin-left: 92px; + + input { + width: 77%; + } + } } .tabs { diff --git a/src/services/siteService.js b/src/services/siteService.js index f3e76ea5871..41e12d94325 100644 --- a/src/services/siteService.js +++ b/src/services/siteService.js @@ -115,6 +115,21 @@ function initSiteService() { return deferred.promise; }; + SiteService.prototype.getAllDecryptedForFolder = function (folderId) { + var self = this; + + return self.getAllDecrypted().then(function (sites) { + var sitesToReturn = []; + for (var i = 0; i < sites.length; i++) { + if (sites[i].folderId === folderId) { + sitesToReturn.push(sites[i]); + } + } + + return sitesToReturn; + }); + }; + SiteService.prototype.saveWithServer = function (site) { var deferred = Q.defer();