Revert material design
This commit is contained in:
Родитель
8186c35d2e
Коммит
501116bf8d
|
@ -97,10 +97,34 @@
|
|||
"message": "Username",
|
||||
"description": "Username"
|
||||
},
|
||||
"email": {
|
||||
"message": "E-mail",
|
||||
"description": "E-mail"
|
||||
},
|
||||
"add": {
|
||||
"message": "Add",
|
||||
"description": "Add"
|
||||
},
|
||||
"credential_created": {
|
||||
"message": "Credential created",
|
||||
"description": "Credential created"
|
||||
},
|
||||
"url": {
|
||||
"message": "URL",
|
||||
"description": "URL"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Delete",
|
||||
"description": "Delete"
|
||||
},
|
||||
"password": {
|
||||
"message": "Password",
|
||||
"description": "Password"
|
||||
},
|
||||
"password_repeat": {
|
||||
"message": "Password (repeat)",
|
||||
"description": "Password"
|
||||
},
|
||||
"detected_new_login": {
|
||||
"message": "Detected new login",
|
||||
"description": "Detected new login"
|
||||
|
@ -251,6 +275,26 @@
|
|||
"message": "Done",
|
||||
"description": "Done"
|
||||
},
|
||||
"list": {
|
||||
"message": "List",
|
||||
"description": "List"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Edit",
|
||||
"description": "Edit"
|
||||
},
|
||||
"server_settings": {
|
||||
"message": "Server settings",
|
||||
"description": "Server Settings"
|
||||
},
|
||||
"vault_settings": {
|
||||
"message": "Vault settings",
|
||||
"description": "Vault settings"
|
||||
},
|
||||
"master_password": {
|
||||
"message": "Set Master password",
|
||||
"description": "Set a master password"
|
||||
},
|
||||
"finish": {
|
||||
"message": "Finish",
|
||||
"description": "Finish"
|
||||
|
@ -267,10 +311,26 @@
|
|||
"message": "Prev",
|
||||
"description": "Previous"
|
||||
},
|
||||
"back": {
|
||||
"message": "Back",
|
||||
"description": "Back"
|
||||
},
|
||||
"copy": {
|
||||
"message": "Copy",
|
||||
"description": "Copy"
|
||||
},
|
||||
"next": {
|
||||
"message": "Next",
|
||||
"description": "Next"
|
||||
},
|
||||
"continue": {
|
||||
"message": "Continue",
|
||||
"description": "Continue"
|
||||
},
|
||||
"donate": {
|
||||
"message": "Donate",
|
||||
"description": "Donate"
|
||||
},
|
||||
"nextcloud_settings": {
|
||||
"message": "Nextcloud / ownCloud server settings",
|
||||
"description": "Nextcloud / ownCloud server settings"
|
||||
|
@ -291,6 +351,18 @@
|
|||
"message": "Vault password",
|
||||
"description": "Vault password"
|
||||
},
|
||||
"label_required": {
|
||||
"message": "Please fill in a label",
|
||||
"description": "When comparing passwords"
|
||||
},
|
||||
"invalid_host": {
|
||||
"message": "Invalid server url",
|
||||
"description": "Invalid server url"
|
||||
},
|
||||
"no_password_match": {
|
||||
"message": "Passwords don't match",
|
||||
"description": "When comparing passwords"
|
||||
},
|
||||
"invalid_vault_password": {
|
||||
"message": "Invalid vault key!",
|
||||
"description": "Vault password"
|
||||
|
@ -304,7 +376,7 @@
|
|||
"description": "One time password"
|
||||
},
|
||||
"settings": {
|
||||
"message": "settings",
|
||||
"message": "Settings",
|
||||
"description": "Settings"
|
||||
},
|
||||
"search": {
|
||||
|
|
40
css/main.css
40
css/main.css
|
@ -19,6 +19,7 @@ body {
|
|||
overflow: auto;
|
||||
/*padding-right: 15px;*/ }
|
||||
#mainPopup .pwcontainer .credential {
|
||||
position: relative;
|
||||
border: 1px solid #fff;
|
||||
margin-bottom: 0.3em;
|
||||
float: left;
|
||||
|
@ -145,18 +146,21 @@ input[type="password"], input[type="text"] {
|
|||
.nopadding {
|
||||
padding: 0; }
|
||||
|
||||
.pad5 {
|
||||
padding: 5px; }
|
||||
|
||||
.radial-progress {
|
||||
display: inline-block;
|
||||
left: 10px;
|
||||
top: 6px;
|
||||
left: 5px;
|
||||
top: 2px;
|
||||
position: relative;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: #d6dadc;
|
||||
border-radius: 50%; }
|
||||
.radial-progress .circle .mask, .radial-progress .circle .fill {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
-webkit-transition: -webkit-transform 0.5s;
|
||||
|
@ -165,9 +169,9 @@ input[type="password"], input[type="text"] {
|
|||
-webkit-backface-visibility: hidden;
|
||||
backface-visibility: hidden; }
|
||||
.radial-progress .circle .mask {
|
||||
clip: rect(0px, 25px, 25px, 12.5px); }
|
||||
clip: rect(0px, 10px, 10px, 5px); }
|
||||
.radial-progress .circle .mask .fill {
|
||||
clip: rect(0px, 12.5px, 25px, 0px);
|
||||
clip: rect(0px, 5px, 10px, 0px);
|
||||
background-color: #97a71d; }
|
||||
|
||||
.ng-hide {
|
||||
|
@ -190,3 +194,23 @@ input[type="password"], input[type="text"] {
|
|||
cursor: pointer; }
|
||||
.ignored_sites li .fa:hover {
|
||||
color: #a94442; }
|
||||
|
||||
input {
|
||||
color: #000; }
|
||||
|
||||
.editCredential tr td {
|
||||
padding: 5px; }
|
||||
|
||||
.edit:before {
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
content: "\f0da";
|
||||
height: 100%;
|
||||
width: 20px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
border-left: 1px solid white;
|
||||
padding-left: 8px;
|
||||
padding-top: 5%;
|
||||
cursor: pointer; }
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<script src="/js/lib/API/i18n.js"></script>
|
||||
<script src="/js/lib/otp.js"></script>
|
||||
<script src="/js/lib/font-awesome.js"></script>
|
||||
<script src="/js/lib/passwordgen.js"></script>
|
||||
<script src="/js/vendor/sjcl/sjcl.js"></script>
|
||||
<script src="/js/vendor/angular-resource/angular-resource.js"></script>
|
||||
|
||||
|
@ -37,9 +38,11 @@
|
|||
<script src="/js/ui/popup/controllers/settings.js"></script>
|
||||
<script src="/js/ui/popup/controllers/password_prompt.js"></script>
|
||||
<script src="/js/ui/popup/controllers/search.js"></script>
|
||||
<script src="/js/ui/popup/controllers/setup.js"></script>
|
||||
<script src="/js/ui/popup/controllers/search.js"></script>
|
||||
<script src="/js/ui/popup/controllers/edit.js"></script>
|
||||
<script src="/js/ui/popup/directives/otp.js"></script>
|
||||
<script src="/js/ui/popup/directives/ngenter.js"></script>
|
||||
<script src="/js/ui/popup/directives/copyText.js"></script>
|
||||
<script src="/js/ui/popup/filters/translate.js"></script>
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<table class="editCredential table">
|
||||
<tr>
|
||||
<td>{{'label' | translate}}</td>
|
||||
<td>
|
||||
<input type="text" ng-model="credential.label" required>
|
||||
<copy-text text="credential.label"></copy-text>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{'username' | translate}}</td>
|
||||
<td>
|
||||
<input type="text" ng-model="credential.username"/>
|
||||
<copy-text text="credential.username"></copy-text>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{'email' | translate}}</td>
|
||||
<td>
|
||||
<input type="text" ng-model="credential.email"/>
|
||||
<copy-text text="credential.email"></copy-text>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{'password' | translate}}</td>
|
||||
<td>
|
||||
<input type="text" ng-model="credential.password" ng-if="pwFieldShown">
|
||||
<input type="password" ng-model="credential.password" ng-if="!pwFieldShown">
|
||||
<i class="fa fa-refresh pointer" ng-click="generatePassword()" style="left: initial; right: 35px;"></i>
|
||||
<i class="pointer fa" ng-class="{'fa-eye': !pwFieldShown, 'fa-eye-slash': pwFieldShown}" style="left: initial; right: 70px;" ng-click="togglePwField()"></i>
|
||||
<copy-text text="credential.password"></copy-text>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{'password_repeat' | translate}}</td>
|
||||
<td><input type="password" ng-model="credential.password_repeat"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{'url' | translate}}</td>
|
||||
<td>
|
||||
<input type="text" ng-model="credential.url"/>
|
||||
<copy-text text="credential.url"></copy-text>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="editCredential table">
|
||||
<tr ng-repeat="custom_field in credential.custom_fields" ng-if="custom_field.field_type !== 'file'">
|
||||
<td>
|
||||
<input required ng-model="custom_field.label" type="text">
|
||||
</td>
|
||||
<td>
|
||||
<input type="password" ng-model="custom_field.value" ng-if="custom_field.secret">
|
||||
<input type="text" ng-model="custom_field.value" ng-if="!custom_field.secret">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h4>Add custom field</h4>
|
||||
<div class="col-xs-3 pad5">
|
||||
<input class="form-control" type="text" ng-model="new_custom_field.label" placeholder="Label">
|
||||
</div>
|
||||
<div class="col-xs-3 pad5">
|
||||
<input class="form-control" type="password" ng-model="new_custom_field.value" ng-if="new_custom_field.field_type === 'password'">
|
||||
<input class="form-control" type="text" ng-model="new_custom_field.value" ng-if="new_custom_field.field_type === 'text'" placeholder="Value">
|
||||
</div>
|
||||
<div class="col-xs-3 pad5">
|
||||
<select class="form-control" name="type" ng-model="new_custom_field.field_type">
|
||||
<option value="text">Text</option>
|
||||
<option value="password">Password</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-3 pad5">
|
||||
<button class="btn btn-default" ng-click="addCustomField(new_custom_field)">
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<button class="btn btn-success" ng-click="saveCredential()" ng-disabled="saving">{{'save' |
|
||||
translate}}
|
||||
</button>
|
||||
<button class="btn btn-default" ng-click="cancel()">{{'cancel' | translate}}</button>
|
|
@ -4,11 +4,15 @@
|
|||
</div>
|
||||
<div ng-show="found_credentials.length > 0">{{'credentials_found_for_site' | translate:found_credentials.length.toString() }}</div>
|
||||
<div class="credential" ng-repeat="credential in found_credentials">
|
||||
<div class="col-xs-7 nopadding">{{credential.label}}<br/>
|
||||
<small>{{credential.username}}</small>
|
||||
<div class="col-xs-10 nopadding">{{credential.label}}<br/>
|
||||
<small>{{credential.username}}</small><br />
|
||||
<small ng-if="credential.otp.secret"> {{'one_time_password' | translate}}: <div otp-generator secret="credential.otp.secret"></div></small>
|
||||
</div>
|
||||
<div class="col-xs-5 OTP" ng-if="credential.otp.secret">
|
||||
{{'one_time_password' | translate}}: <div otp-generator secret="credential.otp.secret"></div>
|
||||
<div class="edit" ng-click="editCredential(credential)">
|
||||
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -62,6 +62,9 @@
|
|||
<tr>
|
||||
<td colspan=2><input type="checkbox" id="disableAutoFill" ng-model="settings.disableAutoFill"><small>{{'disable_autofill' | translate}}</small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan=2><input type="checkbox" id="disableBrowserAutoFill" ng-model="settings.disable_browser_autofill"><small>{{'disable_browser_autofill' | translate}}</small></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan=2><input type="checkbox" id="disablePasswordPicker" ng-model="settings.disablePasswordPicker"><small>{{'disable_password_picker' | translate}}</small></td>
|
||||
</tr>
|
||||
|
|
|
@ -65,7 +65,7 @@ $j(document).ready(function () {
|
|||
picker.css('left', left);
|
||||
picker.css('z-index', maxZ);
|
||||
picker.css('top', top);
|
||||
$j('body').append($j(picker));
|
||||
$j('body').prepend($j(picker));
|
||||
// picker.css('width', $j(form).width());
|
||||
$j('.passwordPickerIframe:not(:last)').remove();
|
||||
}
|
||||
|
|
|
@ -223,6 +223,17 @@ var background = (function () {
|
|||
_self.getCredentialsByUrl = getCredentialsByUrl;
|
||||
|
||||
|
||||
function getCredentialByGuid(guid) {
|
||||
for (var i = 0; i < local_credentials.length; i++) {
|
||||
var credential = local_credentials[i];
|
||||
if (credential.guid === guid) {
|
||||
return credential;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_self.getCredentialByGuid = getCredentialByGuid;
|
||||
|
||||
function getCredentialForHTTPAuth(req) {
|
||||
return getCredentialsByUrl(req.url)[0];
|
||||
}
|
||||
|
|
|
@ -108,8 +108,44 @@ window.PAPI = (function () {
|
|||
callback(credential);
|
||||
});
|
||||
},
|
||||
updateCredential: function (credential, _key, callback) {
|
||||
credential = this.encryptCredential(credential, _key);
|
||||
encryptSharedCredential: function (credential, sharedKey, origKey) {
|
||||
var _credential = credential;
|
||||
_credential.shared_key = this.encryptString(sharedKey, origKey);
|
||||
var encrypted_fields = _encryptedFields;
|
||||
for (var i = 0; i < encrypted_fields.length; i++) {
|
||||
var field = encrypted_fields[i];
|
||||
var fieldValue = credential[field];
|
||||
_credential[field] = this.encryptString(JSON.stringify(fieldValue), sharedKey);
|
||||
}
|
||||
return _credential;
|
||||
},
|
||||
|
||||
updateCredential: function (credential, key, callback) {
|
||||
var origKey = key;
|
||||
var _credential, _key;
|
||||
if (!credential.hasOwnProperty('acl') && credential.hasOwnProperty('shared_key')) {
|
||||
if (credential.shared_key) {
|
||||
_key = this.decryptString(credential.shared_key);
|
||||
}
|
||||
}
|
||||
|
||||
if (credential.hasOwnProperty('acl')) {
|
||||
_key = this.decryptString(credential.acl.shared_key);
|
||||
}
|
||||
|
||||
if (_key) {
|
||||
_credential = this.encryptSharedCredential(credential, _key, origKey);
|
||||
} else {
|
||||
_credential = credential;
|
||||
}
|
||||
delete _credential.shared_key;
|
||||
var regex = /(<([^>]+)>)/ig;
|
||||
if(_credential.description && _credential.description !== "") {
|
||||
_credential.description = _credential.description.replace(regex, "");
|
||||
}
|
||||
|
||||
|
||||
credential = this.encryptCredential(_credential, key);
|
||||
credential.expire_time = new Date(credential.expire_time).getTime() / 1000;
|
||||
api_request('/api/v2/credentials/' + credential.guid, 'PATCH', credential, function () {
|
||||
callback(credential);
|
||||
|
|
|
@ -53,6 +53,10 @@
|
|||
templateUrl: 'views/settings.html',
|
||||
controller: 'SettingsCtrl'
|
||||
})
|
||||
.when('/edit/:guid', {
|
||||
templateUrl: 'views/edit_credential.html',
|
||||
controller: 'EditCtrl'
|
||||
})
|
||||
.when('/locked', {
|
||||
templateUrl: 'views/password_prompt.html',
|
||||
controller: 'PasswordPromptCtrl'
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
/* global API */
|
||||
|
||||
/**
|
||||
* Nextcloud - passman
|
||||
*
|
||||
* @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
|
||||
* @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name passmanApp.controller:MainCtrl
|
||||
* @description
|
||||
* # MainCtrl
|
||||
* Controller of the passmanApp
|
||||
*/
|
||||
angular.module('passmanExtension')
|
||||
.controller('EditCtrl', ['$scope', '$routeParams', '$timeout', function ($scope, $routeParams, $timeout) {
|
||||
API.runtime.sendMessage(API.runtime.id, {
|
||||
method: "getCredentialByGuid",
|
||||
args: $routeParams.guid
|
||||
}).then(function (credential) {
|
||||
$scope.credential = credential;
|
||||
$scope.credential.password_repeat = angular.copy(credential.password);
|
||||
$scope.$apply();
|
||||
});
|
||||
|
||||
var storage = new API.Storage();
|
||||
|
||||
function genPwd(settings) {
|
||||
/* jshint ignore:start */
|
||||
var password = generatePassword(settings['length'],
|
||||
settings.useUppercase,
|
||||
settings.useLowercase,
|
||||
settings.useDigits,
|
||||
settings.useSpecialChars,
|
||||
settings.minimumDigitCount,
|
||||
settings.avoidAmbiguousCharacters,
|
||||
settings.requireEveryCharType);
|
||||
/* jshint ignore:end */
|
||||
return password;
|
||||
}
|
||||
|
||||
$scope.pw_settings = null;
|
||||
function getPasswordGenerationSettings(cb) {
|
||||
var default_settings = {
|
||||
'length': 12,
|
||||
'useUppercase': true,
|
||||
'useLowercase': true,
|
||||
'useDigits': true,
|
||||
'useSpecialChars': true,
|
||||
'minimumDigitCount': 3,
|
||||
'avoidAmbiguousCharacters': false,
|
||||
'requireEveryCharType': true
|
||||
};
|
||||
storage.get('password_generator_settings').then(function (_settings) {
|
||||
if (!_settings) {
|
||||
_settings = default_settings;
|
||||
}
|
||||
|
||||
$scope.pw_settings = _settings;
|
||||
}).error(function () {
|
||||
$scope.pw_settings = default_settings;
|
||||
});
|
||||
}
|
||||
|
||||
getPasswordGenerationSettings();
|
||||
|
||||
var custom_field = {
|
||||
label: '',
|
||||
value: '',
|
||||
field_type: 'text',
|
||||
secret: false
|
||||
};
|
||||
|
||||
$scope.new_custom_field = angular.copy(custom_field);
|
||||
|
||||
$scope.addCustomField = function (_field) {
|
||||
var field = angular.copy(_field);
|
||||
if (!field.label || !field.value) {
|
||||
return;
|
||||
}
|
||||
$scope.credential.custom_fields.push(field);
|
||||
$scope.new_custom_field = angular.copy(custom_field);
|
||||
};
|
||||
|
||||
$scope.deleteCustomField = function (field) {
|
||||
var idx = $scope.credential.custom_fields.indexOf(field);
|
||||
$scope.credential.custom_fields.splice(idx, 1);
|
||||
};
|
||||
|
||||
$scope.pwFieldShown = false;
|
||||
|
||||
$scope.togglePwField = function () {
|
||||
$scope.pwFieldShown = !$scope.pwFieldShown;
|
||||
};
|
||||
|
||||
var round = 0;
|
||||
$scope.generatePassword = function () {
|
||||
var new_password = genPwd($scope.pw_settings);
|
||||
$scope.credential.password = new_password;
|
||||
$scope.credential.password_repeat = new_password;
|
||||
$timeout(function () {
|
||||
if (round < 10) {
|
||||
$scope.generatePassword();
|
||||
round++;
|
||||
} else {
|
||||
round = 0;
|
||||
}
|
||||
}, 10);
|
||||
};
|
||||
|
||||
$scope.saveCredential = function () {
|
||||
if (!$scope.credential.label) {
|
||||
// $mdToast.showSimple(API.i18n.getMessage('label_required'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($scope.credential.password !== $scope.credential.password_repeat) {
|
||||
// $mdToast.showSimple(API.i18n.getMessage('no_password_match'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($scope.new_custom_field.label && $scope.new_custom_field.value) {
|
||||
$scope.credential.custom_fields.push(angular.copy($scope.new_custom_field));
|
||||
}
|
||||
delete $scope.credential.password_repeat;
|
||||
|
||||
API.runtime.sendMessage(API.runtime.id, {
|
||||
method: "saveCredential",
|
||||
args: $scope.credential
|
||||
}).then(function (credential) {
|
||||
if (!$scope.credential.credential_id) {
|
||||
// $mdToast.showSimple(API.i18n.getMessage('credential_created'));
|
||||
} else {
|
||||
// $mdToast.showSimple(API.i18n.getMessage('credential_updated'));
|
||||
}
|
||||
window.location = '#!/';
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.cancel = function () {
|
||||
window.location = '#!/';
|
||||
};
|
||||
|
||||
|
||||
}]);
|
||||
}());
|
|
@ -127,7 +127,9 @@
|
|||
window.location = '#!/search';
|
||||
};
|
||||
|
||||
|
||||
$scope.editCredential = function (credential) {
|
||||
window.location = '#!/edit/' + credential.guid;
|
||||
};
|
||||
}]);
|
||||
}());
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Nextcloud - passman
|
||||
*
|
||||
* @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com)
|
||||
* @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es)
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name passmanApp.directive:passwordGen
|
||||
* @description
|
||||
* # passwordGen
|
||||
*/
|
||||
angular.module('passmanExtension')
|
||||
.directive('copyText', ['$compile', '$timeout',
|
||||
function ($compile, $timeout) {
|
||||
var strCopy = API.i18n.getMessage('copy');
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope:{
|
||||
text: '='
|
||||
},
|
||||
template: '<i class="pointer fa fa-copy" ng-click="copyText()"></i>',
|
||||
replace: true,
|
||||
link: function (scope, el) {
|
||||
scope.copyText = function () {
|
||||
var txtToCopy = document.createElement('input');
|
||||
txtToCopy.value = scope.text;
|
||||
document.body.appendChild(txtToCopy);
|
||||
txtToCopy.select();
|
||||
document.execCommand('copy');
|
||||
txtToCopy.parentNode.removeChild(txtToCopy);
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
]);
|
||||
}());
|
|
@ -71,7 +71,7 @@
|
|||
return {
|
||||
restrict: 'A',
|
||||
// template: '<span class="otp_generator">{{otp}} <span ng-bind="timeleft"></span></span>',
|
||||
template: '<span class="otp_generator"><span class="code">{{otp}}</span> <div class="radial-progress"><div class="circle"><div class="mask full"><div class="fill"></div></div><div class="mask half"><div class="fill"></div><div class="fill fix"></div></div></div></div></span>',
|
||||
template: '<span class="otp_generator"><span class="code">{{otp}}</span> <copy-text text="otp"></copy-text> <div class="radial-progress"><div class="circle"><div class="mask full"><div class="fill"></div></div><div class="mask half"><div class="fill"></div><div class="fill fix"></div></div></div></div></span>',
|
||||
transclude: false,
|
||||
scope: {
|
||||
secret: '='
|
||||
|
|
|
@ -18,10 +18,12 @@ body {
|
|||
width: 400px;
|
||||
font-family: Helvetica, Ubuntu, Arial, sans-serif;
|
||||
.pwcontainer{
|
||||
|
||||
max-height: 195px;
|
||||
overflow: auto;
|
||||
/*padding-right: 15px;*/
|
||||
.credential {
|
||||
position: relative;
|
||||
border: 1px solid #fff;
|
||||
margin-bottom: 0.3em;
|
||||
float: left;
|
||||
|
@ -185,15 +187,18 @@ input[type="password"], input[type="text"] {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.pad5{
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.radial-progress {
|
||||
$circle-size : 25px;
|
||||
$circle-size : 10px;
|
||||
$circle-background : #d6dadc;
|
||||
$circle-color : #97a71d;
|
||||
$transition-length : 0.5s;
|
||||
display: inline-block;
|
||||
left: 10px;
|
||||
top: 6px;
|
||||
left: 5px;
|
||||
top: 2px;
|
||||
position: relative;
|
||||
width: $circle-size;
|
||||
height: $circle-size;
|
||||
|
@ -244,4 +249,28 @@ input[type="password"], input[type="text"] {
|
|||
color: #a94442;
|
||||
}
|
||||
}
|
||||
}
|
||||
input{
|
||||
color: #000;
|
||||
}
|
||||
.editCredential{
|
||||
tr{
|
||||
td{
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.edit:before {
|
||||
font: normal normal normal 14px/1 FontAwesome;
|
||||
content: "\f0da";
|
||||
height: 100%;
|
||||
width: 20px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
border-left: 1px solid white;
|
||||
padding-left: 8px;
|
||||
padding-top: 5%;
|
||||
cursor: pointer;
|
||||
}
|
Загрузка…
Ссылка в новой задаче