Added new page for viewing sites within a folder
This commit is contained in:
parent
b4d41c6808
commit
4476eb7389
|
@ -614,5 +614,9 @@
|
||||||
"translations": {
|
"translations": {
|
||||||
"message": "Translations",
|
"message": "Translations",
|
||||||
"description": "Translations"
|
"description": "Translations"
|
||||||
|
},
|
||||||
|
"searchFolder": {
|
||||||
|
"message": "Search folder",
|
||||||
|
"description": "Search folder"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,13 @@
|
||||||
controller: 'toolsController'
|
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', {
|
.state('viewSite', {
|
||||||
url: '/view-site?siteId',
|
url: '/view-site?siteId',
|
||||||
templateUrl: 'app/vault/views/vaultViewSite.html',
|
templateUrl: 'app/vault/views/vaultViewSite.html',
|
||||||
|
|
|
@ -115,7 +115,12 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.viewFolder = function (folder) {
|
$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) {
|
$scope.clipboardError = function (e) {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -10,7 +10,7 @@
|
||||||
<div class="content content-tabs">
|
<div class="content content-tabs">
|
||||||
<div ng-if="vaultSites.length && vaultSites.length >= 100 && vaultFolders.length && (!searchText || searchText.length < 2)">
|
<div ng-if="vaultSites.length && vaultSites.length >= 100 && vaultFolders.length && (!searchText || searchText.length < 2)">
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<div class="list-section">
|
<div class="list-section" style="padding-bottom: 0;">
|
||||||
<div class="list-section-header">
|
<div class="list-section-header">
|
||||||
{{i18n.folders}}
|
{{i18n.folders}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<div class="header">
|
||||||
|
<div class="left">
|
||||||
|
<a ui-sref="tabs.vault({animation: 'out-slide-right'})"><i class="fa fa-chevron-left"></i> {{i18n.myVault}}</a>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<a href="" ng-click="addSite()"><i class="fa fa-plus fa-lg"></i></a>
|
||||||
|
</div>
|
||||||
|
<div class="search">
|
||||||
|
<input type="search" placeholder="{{i18n.searchFolder}}" ng-model="searchText" id="search" />
|
||||||
|
<i class="fa fa-search"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div ng-if="vaultSites.length">
|
||||||
|
<div class="list">
|
||||||
|
<div class="list-section" style="padding-bottom: 0;">
|
||||||
|
<div class="list-section-header">
|
||||||
|
{{folder.name}}
|
||||||
|
</div>
|
||||||
|
<a href="javascript:void(0)" ng-click="viewSite(site)"
|
||||||
|
class="list-section-item condensed" title="{{i18n.edit}} {{site.name}}"
|
||||||
|
ng-repeat="site in vaultSites | filter: { folderId: folder.id }
|
||||||
|
| filter: searchSites() | orderBy: ['name', 'username']">
|
||||||
|
<span class="btn-list" ng-click="$event.stopPropagation()" title="{{i18n.copyPassword}}" ngclipboard
|
||||||
|
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.password)"
|
||||||
|
data-clipboard-text="{{site.password}}" ng-class="{'disabled': !site.password}">
|
||||||
|
<i class="fa fa-lg fa-key"></i>
|
||||||
|
</span>
|
||||||
|
<span class="btn-list" ng-click="$event.stopPropagation()" title="{{i18n.copyUsername}}" ngclipboard
|
||||||
|
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.username)"
|
||||||
|
data-clipboard-text="{{site.username}}" ng-class="{'disabled': !site.username}">
|
||||||
|
<i class="fa fa-lg fa-user"></i>
|
||||||
|
</span>
|
||||||
|
<span class="text">{{site.name}}</span>
|
||||||
|
<span class="detail">{{site.username}}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="centered-message" ng-if="loaded && !vaultSites.length">
|
||||||
|
<p>
|
||||||
|
{{i18n.noSitesInList}}
|
||||||
|
<button ng-click="addSite()" style="margin-top: 20px;" class="btn btn-link btn-block">{{i18n.addSite}}</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="page-loading" ng-if="!loaded">
|
||||||
|
<i class="fa fa-lg fa-spinner fa-spin"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -61,6 +61,7 @@
|
||||||
|
|
||||||
<script src="app/vault/vaultModule.js"></script>
|
<script src="app/vault/vaultModule.js"></script>
|
||||||
<script src="app/vault/vaultController.js"></script>
|
<script src="app/vault/vaultController.js"></script>
|
||||||
|
<script src="app/vault/vaultViewFolderController.js"></script>
|
||||||
<script src="app/vault/vaultAddSiteController.js"></script>
|
<script src="app/vault/vaultAddSiteController.js"></script>
|
||||||
<script src="app/vault/vaultEditSiteController.js"></script>
|
<script src="app/vault/vaultEditSiteController.js"></script>
|
||||||
<script src="app/vault/vaultViewSiteController.js"></script>
|
<script src="app/vault/vaultViewSiteController.js"></script>
|
||||||
|
|
|
@ -103,6 +103,14 @@
|
||||||
color: lighten(@brand-primary, 30%);
|
color: lighten(@brand-primary, 30%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.left ~ .right ~ .search {
|
||||||
|
margin-left: 92px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 77%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
|
|
|
@ -115,6 +115,21 @@ function initSiteService() {
|
||||||
return deferred.promise;
|
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) {
|
SiteService.prototype.saveWithServer = function (site) {
|
||||||
var deferred = Q.defer();
|
var deferred = Q.defer();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue