This commit is contained in:
brantje 2017-05-06 19:54:37 +02:00
Родитель 0ddca1061c ff0b4fdec0
Коммит c6517950d8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 5FF1D117F918687F
36 изменённых файлов: 7426 добавлений и 10238 удалений

Просмотреть файл

@ -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"
@ -247,6 +271,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"
@ -263,10 +307,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"
@ -287,6 +347,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"
@ -300,7 +372,7 @@
"description": "One time password"
},
"settings": {
"message": "settings",
"message": "Settings",
"description": "Settings"
},
"search": {

Просмотреть файл

@ -150,13 +150,13 @@ input[type="password"], input[type="text"] {
left: 10px;
top: 6px;
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 +165,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 {

96
css/material.css Normal file
Просмотреть файл

@ -0,0 +1,96 @@
body, html {
min-width: 450px; }
.server_settings md-input-container {
margin-bottom: 0; }
.pointer {
cursor: pointer; }
.password-list {
min-height: 250px; }
.md-content {
height: 100%;
max-height: auto; }
.addFab {
position: fixed;
right: 10px;
bottom: 10px; }
.menu {
padding: 0; }
.menu ul {
padding: 0;
margin: 0;
width: 100%; }
.menu ul li {
list-style-type: none;
width: 100%; }
.menu ul li md-icon {
margin-right: 16px;
min-width: 40px;
width: 40px; }
.menu ul li a {
color: #000;
position: relative;
cursor: pointer;
user-select: none;
display: block;
height: 48px;
line-height: 48px;
padding: 0;
padding-left: 16px;
padding-right: 56px;
text-decoration: none;
clear: both;
font-weight: 500;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
-webkit-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out; }
.menu ul li a:hover {
background-color: #e0e0e0; }
.password-list {
padding: 0; }
/*/*/
.radial-progress {
display: inline-block;
position: relative;
width: 12px;
height: 12px;
background-color: #d6dadc;
border-radius: 50%; }
.radial-progress .circle .mask, .radial-progress .circle .fill {
width: 12px;
height: 12px;
position: absolute;
border-radius: 50%;
-webkit-transition: -webkit-transform 0.5s;
-moz-transition: -moz-transform 0.5s;
transition: transform 0.5s;
-webkit-backface-visibility: hidden;
backface-visibility: hidden; }
.radial-progress .circle .mask {
clip: rect(0px, 12px, 12px, 6px); }
.radial-progress .circle .mask .fill {
clip: rect(0px, 6px, 12px, 0px);
background-color: #0277bd; }
.ng-hide {
display: none; }
.unlock-container {
height: 350px; }
.unlock-container .unlock {
padding: 20px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); }
.unlock-container .unlock md-input-container {
margin-top: 0;
margin-bottom: 0; }

7
css/vendor/angular-material.min.css поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

587
css/vendor/bootstrap-theme.css поставляемый
Просмотреть файл

@ -1,587 +0,0 @@
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
.btn-default,
.btn-primary,
.btn-success,
.btn-info,
.btn-warning,
.btn-danger {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
}
.btn-default:active,
.btn-primary:active,
.btn-success:active,
.btn-info:active,
.btn-warning:active,
.btn-danger:active,
.btn-default.active,
.btn-primary.active,
.btn-success.active,
.btn-info.active,
.btn-warning.active,
.btn-danger.active {
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
.btn-default.disabled,
.btn-primary.disabled,
.btn-success.disabled,
.btn-info.disabled,
.btn-warning.disabled,
.btn-danger.disabled,
.btn-default[disabled],
.btn-primary[disabled],
.btn-success[disabled],
.btn-info[disabled],
.btn-warning[disabled],
.btn-danger[disabled],
fieldset[disabled] .btn-default,
fieldset[disabled] .btn-primary,
fieldset[disabled] .btn-success,
fieldset[disabled] .btn-info,
fieldset[disabled] .btn-warning,
fieldset[disabled] .btn-danger {
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-default .badge,
.btn-primary .badge,
.btn-success .badge,
.btn-info .badge,
.btn-warning .badge,
.btn-danger .badge {
text-shadow: none;
}
.btn:active,
.btn.active {
background-image: none;
}
.btn-default {
text-shadow: 0 1px 0 #fff;
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #dbdbdb;
border-color: #ccc;
}
.btn-default:hover,
.btn-default:focus {
background-color: #e0e0e0;
background-position: 0 -15px;
}
.btn-default:active,
.btn-default.active {
background-color: #e0e0e0;
border-color: #dbdbdb;
}
.btn-default.disabled,
.btn-default[disabled],
fieldset[disabled] .btn-default,
.btn-default.disabled:hover,
.btn-default[disabled]:hover,
fieldset[disabled] .btn-default:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
fieldset[disabled] .btn-default:focus,
.btn-default.disabled.focus,
.btn-default[disabled].focus,
fieldset[disabled] .btn-default.focus,
.btn-default.disabled:active,
.btn-default[disabled]:active,
fieldset[disabled] .btn-default:active,
.btn-default.disabled.active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default.active {
background-color: #e0e0e0;
background-image: none;
}
.btn-primary {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #245580;
}
.btn-primary:hover,
.btn-primary:focus {
background-color: #265a88;
background-position: 0 -15px;
}
.btn-primary:active,
.btn-primary.active {
background-color: #265a88;
border-color: #245580;
}
.btn-primary.disabled,
.btn-primary[disabled],
fieldset[disabled] .btn-primary,
.btn-primary.disabled:hover,
.btn-primary[disabled]:hover,
fieldset[disabled] .btn-primary:hover,
.btn-primary.disabled:focus,
.btn-primary[disabled]:focus,
fieldset[disabled] .btn-primary:focus,
.btn-primary.disabled.focus,
.btn-primary[disabled].focus,
fieldset[disabled] .btn-primary.focus,
.btn-primary.disabled:active,
.btn-primary[disabled]:active,
fieldset[disabled] .btn-primary:active,
.btn-primary.disabled.active,
.btn-primary[disabled].active,
fieldset[disabled] .btn-primary.active {
background-color: #265a88;
background-image: none;
}
.btn-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #3e8f3e;
}
.btn-success:hover,
.btn-success:focus {
background-color: #419641;
background-position: 0 -15px;
}
.btn-success:active,
.btn-success.active {
background-color: #419641;
border-color: #3e8f3e;
}
.btn-success.disabled,
.btn-success[disabled],
fieldset[disabled] .btn-success,
.btn-success.disabled:hover,
.btn-success[disabled]:hover,
fieldset[disabled] .btn-success:hover,
.btn-success.disabled:focus,
.btn-success[disabled]:focus,
fieldset[disabled] .btn-success:focus,
.btn-success.disabled.focus,
.btn-success[disabled].focus,
fieldset[disabled] .btn-success.focus,
.btn-success.disabled:active,
.btn-success[disabled]:active,
fieldset[disabled] .btn-success:active,
.btn-success.disabled.active,
.btn-success[disabled].active,
fieldset[disabled] .btn-success.active {
background-color: #419641;
background-image: none;
}
.btn-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #28a4c9;
}
.btn-info:hover,
.btn-info:focus {
background-color: #2aabd2;
background-position: 0 -15px;
}
.btn-info:active,
.btn-info.active {
background-color: #2aabd2;
border-color: #28a4c9;
}
.btn-info.disabled,
.btn-info[disabled],
fieldset[disabled] .btn-info,
.btn-info.disabled:hover,
.btn-info[disabled]:hover,
fieldset[disabled] .btn-info:hover,
.btn-info.disabled:focus,
.btn-info[disabled]:focus,
fieldset[disabled] .btn-info:focus,
.btn-info.disabled.focus,
.btn-info[disabled].focus,
fieldset[disabled] .btn-info.focus,
.btn-info.disabled:active,
.btn-info[disabled]:active,
fieldset[disabled] .btn-info:active,
.btn-info.disabled.active,
.btn-info[disabled].active,
fieldset[disabled] .btn-info.active {
background-color: #2aabd2;
background-image: none;
}
.btn-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #e38d13;
}
.btn-warning:hover,
.btn-warning:focus {
background-color: #eb9316;
background-position: 0 -15px;
}
.btn-warning:active,
.btn-warning.active {
background-color: #eb9316;
border-color: #e38d13;
}
.btn-warning.disabled,
.btn-warning[disabled],
fieldset[disabled] .btn-warning,
.btn-warning.disabled:hover,
.btn-warning[disabled]:hover,
fieldset[disabled] .btn-warning:hover,
.btn-warning.disabled:focus,
.btn-warning[disabled]:focus,
fieldset[disabled] .btn-warning:focus,
.btn-warning.disabled.focus,
.btn-warning[disabled].focus,
fieldset[disabled] .btn-warning.focus,
.btn-warning.disabled:active,
.btn-warning[disabled]:active,
fieldset[disabled] .btn-warning:active,
.btn-warning.disabled.active,
.btn-warning[disabled].active,
fieldset[disabled] .btn-warning.active {
background-color: #eb9316;
background-image: none;
}
.btn-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #b92c28;
}
.btn-danger:hover,
.btn-danger:focus {
background-color: #c12e2a;
background-position: 0 -15px;
}
.btn-danger:active,
.btn-danger.active {
background-color: #c12e2a;
border-color: #b92c28;
}
.btn-danger.disabled,
.btn-danger[disabled],
fieldset[disabled] .btn-danger,
.btn-danger.disabled:hover,
.btn-danger[disabled]:hover,
fieldset[disabled] .btn-danger:hover,
.btn-danger.disabled:focus,
.btn-danger[disabled]:focus,
fieldset[disabled] .btn-danger:focus,
.btn-danger.disabled.focus,
.btn-danger[disabled].focus,
fieldset[disabled] .btn-danger.focus,
.btn-danger.disabled:active,
.btn-danger[disabled]:active,
fieldset[disabled] .btn-danger:active,
.btn-danger.disabled.active,
.btn-danger[disabled].active,
fieldset[disabled] .btn-danger.active {
background-color: #c12e2a;
background-image: none;
}
.thumbnail,
.img-thumbnail {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background-color: #e8e8e8;
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
background-color: #2e6da4;
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
}
.navbar-default {
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
}
.navbar-default .navbar-nav > .open > a,
.navbar-default .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
}
.navbar-brand,
.navbar-nav > li > a {
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
}
.navbar-inverse {
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
}
.navbar-inverse .navbar-nav > .open > a,
.navbar-inverse .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
}
.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
}
.navbar-static-top,
.navbar-fixed-top,
.navbar-fixed-bottom {
border-radius: 0;
}
@media (max-width: 767px) {
.navbar .navbar-nav .open .dropdown-menu > .active > a,
.navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
.navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
color: #fff;
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
}
}
.alert {
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
}
.alert-success {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
background-repeat: repeat-x;
border-color: #b2dba1;
}
.alert-info {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
background-repeat: repeat-x;
border-color: #9acfea;
}
.alert-warning {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
background-repeat: repeat-x;
border-color: #f5e79e;
}
.alert-danger {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
background-repeat: repeat-x;
border-color: #dca7a7;
}
.progress {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-striped {
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
}
.list-group {
border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
text-shadow: 0 -1px 0 #286090;
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
background-repeat: repeat-x;
border-color: #2b669a;
}
.list-group-item.active .badge,
.list-group-item.active:hover .badge,
.list-group-item.active:focus .badge {
text-shadow: none;
}
.panel {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
}
.panel-default > .panel-heading {
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.panel-primary > .panel-heading {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
background-repeat: repeat-x;
}
.panel-success > .panel-heading {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
background-repeat: repeat-x;
}
.panel-info > .panel-heading {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
background-repeat: repeat-x;
}
.panel-warning > .panel-heading {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
background-repeat: repeat-x;
}
.panel-danger > .panel-heading {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
background-repeat: repeat-x;
}
.well {
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
border-color: #dcdcdc;
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
}
/*# sourceMappingURL=bootstrap-theme.css.map */

6757
css/vendor/bootstrap.css поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

507
css/vendor/material-steppers.css поставляемый Normal file
Просмотреть файл

@ -0,0 +1,507 @@
md-stepper {
display: block;
}
md-steppers-header,
md-steppers-mobile-header,
md-step-actions {
-webkit-flex: 0 0 auto;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
box-sizing: border-box;
}
.md-steppers-header-region {
z-index: 1;
}
@media (max-width: 599px) {
md-stepper {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
}
md-stepper > div {
min-width: 0px;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
}
.md-steppers-content {
min-height: 0px;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
md-step.md-active {
min-height: 0px;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
md-step.md-active .md-stepper {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
min-height: 0px;
}
md-steppers-scope {
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
}
md-step-body {
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
}
}
.md-steppers {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-flow: column;
-ms-flex-flow: column;
flex-flow: column;
}
.md-steppers:not(.md-steppers-linear) .md-stepper-indicator:not(.md-active):not(.md-completed):hover,
.md-steppers:not(.md-steppers-linear) .md-stepper-indicator.md-editable.md-completed:hover {
cursor: pointer;
}
.md-steppers:not(.md-steppers-linear) .md-stepper-indicator:not(.md-active):not(.md-completed):hover,
.md-steppers:not(.md-steppers-linear) .md-stepper-indicator.md-editable.md-completed:hover,
.md-steppers:not(.md-steppers-linear) .md-stepper-indicator:not(.md-active):not(.md-completed):hover .md-stepper-indicator-wrapper,
.md-steppers:not(.md-steppers-linear) .md-stepper-indicator.md-editable.md-completed:hover .md-stepper-indicator-wrapper {
background-color: #F6F6F6;
}
.md-steppers-header {
margin: 0;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-flow: row nowrap;
-ms-flex-flow: row nowrap;
flex-flow: row nowrap;
border-radius: 0;
-webkit-align-items: flex-start;
-ms-flex-align: start;
align-items: flex-start;
}
.md-steppers-horizontal .md-stepper-indicator {
min-height: 72px;
}
.md-steppers-horizontal .md-stepper-indicator:first-child .md-stepper-indicator-wrapper {
padding-left: 16px;
}
.md-steppers-horizontal .md-stepper-indicator:after {
width: 999em;
height: 1px;
margin-top: -1px;
position: absolute;
top: 50%;
left: 0;
z-index: 1;
background-color: #E8E8E8;
content: " ";
}
.md-stepper-indicator {
margin: 0;
padding: 0 16px;
position: relative;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex: 1 0 auto;
-ms-flex: 1 0 auto;
flex: 1 0 auto;
-webkit-align-content: flex-start;
-ms-flex-line-pack: start;
align-content: flex-start;
-webkit-align-items: flex-start;
-ms-flex-align: start;
align-items: flex-start;
overflow: hidden;
cursor: default;
background: none;
border: none;
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.md-stepper-indicator:focus {
outline: none;
}
.md-stepper-indicator.md-completed .md-stepper-number,
.md-stepper-indicator.md-active .md-stepper-number {
background-color: #2196F3;
}
.md-stepper-indicator.md-completed .md-stepper-title,
.md-stepper-indicator.md-active .md-stepper-title {
color: rgba(0, 0, 0, 0.87);
}
.md-stepper-indicator.md-active .md-stepper-title,
.md-stepper-indicator.md-editable .md-stepper-title {
font-weight: 500;
}
.md-stepper-indicator.md-error .md-stepper-title {
color: #f44336;
}
.md-stepper-indicator:first-child {
padding-left: 0;
}
.md-stepper-indicator:last-child {
padding-right: 0;
-webkit-justify-content: flex-end;
-ms-flex-pack: end;
justify-content: flex-end;
}
.md-stepper-indicator:last-child .md-stepper-indicator-wrapper {
padding-right: 24px;
}
.md-stepper-indicator .md-ripple-container {
z-index: 3;
}
.md-stepper-indicator-wrapper {
padding: 0 8px 0 0;
position: relative;
z-index: 2;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-align-content: center;
-ms-flex-line-pack: center;
align-content: center;
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.md-stepper-number {
width: 24px;
height: 24px;
margin: 0 8px;
border-radius: 24px;
background-color: #BDBDBD;
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
color: #fff;
font-size: 12px;
line-height: 24px;
text-align: center;
}
.md-stepper-number.ng-hide {
transition: none;
}
.md-error .md-stepper-error-indicator {
margin: 0 8px;
background-color: #fff;
}
.md-error .md-stepper-error-indicator md-icon {
color: #f44336;
}
.md-error .md-stepper-error-message {
color: #f44336;
font-weight: 400;
}
.md-stepper-icon {
width: 18px;
height: 18px;
position: relative;
top: -1px;
color: #fff;
font-size: 18px;
font-weight: 700;
}
.md-stepper-icon.md-stepper-icon-edit {
width: 14px;
height: 14px;
font-size: 14px;
font-weight: 400;
}
.md-stepper-title {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-flow: column nowrap;
-ms-flex-flow: column nowrap;
flex-flow: column nowrap;
position: relative;
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
font-size: 14px;
line-height: 24px;
}
.md-steppers-content {
position: relative;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
}
.md-stepper {
box-sizing: border-box;
}
.md-stepper.md-active {
position: relative;
pointer-events: auto;
}
.md-steppers-actions {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.md-stepper-optional .md-stepper-title {
text-align: left;
white-space: nowrap;
}
.md-stepper-optional .md-stepper-title small:not(.md-stepper-error-message) {
color: rgba(0, 0, 0, 0.54);
}
.md-stepper-optional .md-stepper-title small {
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
font-size: 12px;
line-height: 1em;
}
.md-steppers-linear .md-stepper-indicator {
cursor: default;
}
.md-steppers-linear .md-stepper-indicator.md-editable.md-completed:hover {
cursor: pointer;
}
.md-steppers-linear .md-stepper-indicator.md-editable.md-completed:hover,
.md-steppers-linear .md-stepper-indicator.md-editable.md-completed:hover .md-stepper-indicator-wrapper {
background-color: #F6F6F6;
}
.md-steppers-linear .md-stepper-indicator.md-editable.md-completed:hover .md-stepper-number:before,
.md-steppers-linear .md-stepper-indicator.md-editable.md-completed:hover .md-stepper-number:after {
background-color: #F6F6F6;
}
.md-steppers-linear .md-stepper-title {
color: rgba(0, 0, 0, 0.26);
}
.md-steppers-linear .md-stepper-title small:not(.md-stepper-error-message) {
color: rgba(0, 0, 0, 0.26);
}
.md-steppers-alternative:not(.md-steppers-linear) .md-stepper-indicator:not(.md-active):not(.md-completed):hover .md-stepper-indicator-wrapper {
background: none;
}
.md-steppers-alternative:not(.md-steppers-linear) .md-stepper-indicator:not(.md-active):not(.md-completed):hover .md-stepper-number:before,
.md-steppers-alternative:not(.md-steppers-linear) .md-stepper-indicator:not(.md-active):not(.md-completed):hover .md-stepper-number:after {
background-color: #F6F6F6;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-indicator {
min-height: 104px;
padding: 24px 16px;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-indicator .md-stepper-indicator-wrapper {
padding: 0;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-indicator:first-child {
padding-left: 24px;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-indicator:first-child:after {
left: 50%;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-indicator:last-child {
padding-right: 24px;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-indicator:last-child:after {
right: 50%;
left: auto;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-indicator:after {
margin-top: 0;
top: 36px;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-indicator-wrapper {
padding: 0 16px;
min-height: 50px;
-webkit-flex-flow: column nowrap;
-ms-flex-flow: column nowrap;
flex-flow: column nowrap;
background: none;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-number,
.md-steppers-alternative .md-steppers-horizontal .md-stepper-error-indicator {
position: relative;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-number:before,
.md-steppers-alternative .md-steppers-horizontal .md-stepper-error-indicator:before,
.md-steppers-alternative .md-steppers-horizontal .md-stepper-number:after,
.md-steppers-alternative .md-steppers-horizontal .md-stepper-error-indicator:after {
width: 8px;
position: absolute;
top: 0;
bottom: 0;
background-color: #fff;
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
content: " ";
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-number:before,
.md-steppers-alternative .md-steppers-horizontal .md-stepper-error-indicator:before {
left: -8px;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-number:after,
.md-steppers-alternative .md-steppers-horizontal .md-stepper-error-indicator:after {
right: -8px;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-title {
margin-top: 16px;
line-height: 18px;
text-align: center;
}
.md-steppers-alternative .md-steppers-horizontal .md-stepper-title small {
text-align: center;
}
.md-steppers:not(.md-steppers-vertical) .md-steppers-header.md-steppers-vertical {
display: none;
}
.md-steppers-vertical .md-stepper {
padding: 8px 24px;
}
.md-steppers-vertical .md-steppers-scope {
margin-left: 20px;
border-left: 1px solid #E8E8E8;
padding-left: 20px;
}
.md-steppers-vertical .md-steppers-header.md-steppers-horizontal {
display: none;
}
.md-steppers-mobile-header,
.md-stepper-feedback-message {
display: none;
}
@media (max-width: 599px) {
.md-steppers-mobile-step-text:not(.md-steppers-vertical) .md-stepper {
padding: 0;
}
.md-steppers-mobile-step-text:not(.md-steppers-vertical) .md-steppers-mobile-header {
display: block;
}
.md-steppers-mobile-step-text:not(.md-steppers-vertical) .md-stepper-feedback-message {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.md-steppers-mobile-step-text:not(.md-steppers-vertical) .md-steppers-header.md-steppers-horizontal {
display: none;
}
.md-steppers-mobile-step-text:not(.md-steppers-vertical) md-step-actions {
background: #f6f6f6 !important;
color: #202020 !important;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
box-sizing: border-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-content: stretch;
-ms-flex-line-pack: stretch;
align-content: stretch;
-webkit-align-items: stretch;
-ms-flex-align: stretch;
align-items: stretch;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 3px 0px, rgba(0, 0, 0, 0.137255) 0px 1px 1px 0px, rgba(0, 0, 0, 0.117647) 0px 2px 1px -1px;
}
}
.md-steppers-header-region {
position: relative;
}
.md-stepper-feedback-message {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
background-color: #fff;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
padding-left: 10px;
z-index: 2;
box-sizing: border-box;
}
.md-steppers {
position: relative;
}
md-step-body {
position: relative;
overflow: auto;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.md-step-body-loading {
display: none;
}
.md-steppers-has-feedback .md-stepper-feedback-message {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.md-steppers-has-feedback .md-steppers-overlay {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
z-index: 10;
}
.md-steppers-has-feedback .md-step-body-overlay {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
z-index: 11;
opacity: 0.75;
background-color: white;
}
.md-steppers-has-feedback .md-step-body-loading {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
z-index: 12;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
box-sizing: border-box;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-align-content: center;
-ms-flex-line-pack: center;
align-content: center;
max-width: 100%;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}

Просмотреть файл

@ -1,56 +1,134 @@
<!doctype html>
<html ng-app="passmanExtension" ng-csp>
<head>
<meta charset="UTF-8" />
<title>Passman rules</title>
<script src="/js/vendor/jquery/jquery.js"></script>
<script src="/js/vendor/bootstrap/bootstrap.js"></script>
<script src="/js/vendor/angular/framework.js"></script>
<head>
<meta charset="UTF-8"/>
<title>Passman rules</title>
<script src="/js/vendor/jquery/jquery.js"></script>
<script src="/js/vendor/angular/framework.js"></script>
<script src="/js/lib/promise.js"></script>
<script src="/js/lib/API/base.js"></script>
<script src="/js/lib/API/storage.js"></script>
<script src="/js/lib/API/runtime.js"></script>
<script src="/js/lib/API/tabs.js"></script>
<script src="/js/lib/API/cookies.js"></script>
<script src="/js/lib/API/extension.js"></script>
<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/vendor/sjcl/sjcl.js"></script>
<script src="/js/vendor/angular-resource/angular-resource.js"></script>
<script src="/js/lib/promise.js"></script>
<script src="/js/lib/API/base.js"></script>
<script src="/js/lib/API/storage.js"></script>
<script src="/js/lib/API/runtime.js"></script>
<script src="/js/lib/API/tabs.js"></script>
<script src="/js/lib/API/cookies.js"></script>
<script src="/js/lib/API/extension.js"></script>
<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>
<script src="/js/vendor/angular-route/angular-route.js"></script>
<script src="/js/vendor/angular-sanitize/angular-sanitize.js"></script>
<script src="/js/vendor/angular-translate/angular-translate.js"></script>
<script src="/js/vendor/angular-steps/angular-steps.js"></script>
<script src="/js/vendor/sha/sha.js"></script>
<script src="/js/vendor/angular-route/angular-route.js"></script>
<script src="/js/vendor/angular-aria/angular-aria.js"></script>
<script src="/js/vendor/angular-messages/angular-messages.js"></script>
<script src="/js/vendor/angular-animate/angular-animate.js"></script>
<script src="/js/vendor/angular-sanitize/angular-sanitize.js"></script>
<script src="/js/vendor/angular-translate/angular-translate.js"></script>
<script src="/js/vendor/angular-material/angular-material.min.js"></script>
<script src="/js/vendor/sha/sha.js"></script>
<script src="/js/vendor/material-steppers/material-steppers.js"></script>
<script src="/js/lib/api.js"></script>
<script src="/js/ui/popup/app.js"></script>
<script src="/js/ui/popup/factories/storage.js"></script>
<script src="/js/ui/popup/factories/debounce.js"></script>
<script src="/js/ui/popup/controllers/main.js"></script>
<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/directives/otp.js"></script>
<script src="/js/ui/popup/directives/ngenter.js"></script>
<script src="/js/ui/popup/filters/translate.js"></script>
<script src="/js/lib/api.js"></script>
<link href="/css/vendor/bootstrap.css" media="all" rel="stylesheet" />
<link href="/css/vendor/bootstrap-theme.css" media="all" rel="stylesheet" />
<link href="/css/vendor/font-awesome.css" media="all" rel="stylesheet" />
<link href="/css/main.css" media="all" rel="stylesheet" />
</head>
<body>
<div id="mainPopup" ng-view>
<script src="/js/ui/popup/app.js"></script>
<script src="/js/ui/popup/factories/storage.js"></script>
<script src="/js/ui/popup/factories/debounce.js"></script>
<script src="/js/ui/popup/controllers/main.js"></script>
<script src="/js/ui/popup/controllers/list.js"></script>
<script src="/js/ui/popup/controllers/edit.js"></script>
<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/directives/otp.js"></script>
<script src="/js/ui/popup/directives/copyText.js"></script>
<script src="/js/ui/popup/directives/ngenter.js"></script>
<script src="/js/ui/popup/filters/translate.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="/css/vendor/font-awesome.css" media="all" rel="stylesheet"/>
<link href="/css/vendor/angular-material.min.css" media="all" rel="stylesheet"/>
<link href="/css/vendor/material-steppers.css" media="all" rel="stylesheet"/>
<link href="/css/material.css" media="all" rel="stylesheet"/>
<!--<link href="/css/main.css" media="all" rel="stylesheet" /> -->
</head>
<body ng-controller="MainCtrl">
<section layout="column" flex="">
<md-toolbar class="md-hue-2" ng-if="toolbarShown">
<div class="md-toolbar-tools">
<md-button class="md-icon-button" aria-label="menu" ng-click="toggleLeft()">
<md-icon>menu</md-icon>
</md-button>
<h2>
<span>Passman</span>
</h2>
<span flex></span>
<md-button class="md-icon-button" aria-label="Lock" ng-click="lockExtension()">
<md-tooltip md-direction="bottom">{{'lock_extension' | translate}}</md-tooltip>
<md-icon>lock</md-icon>
</md-button>
</div>
</body>
</md-toolbar>
<md-sidenav class="md-sidenav-left" md-component-id="left" md-is-locked-open="$mdMedia('gt-md')" ng-if="toolbarShown"
md-disable-backdrop="" md-whiteframe="4">
<md-toolbar class="md-hue-2">
<div class="md-toolbar-tools">
<h2>
<span>Menu</span>
</h2>
<span flex></span>
<md-button class="md-icon-button" aria-label="Close" ng-click="toggleLeft()">
<md-icon>close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-content class="menu" layout-padding="">
<ul>
<li>
<a ng-click="goto_list()">
<md-icon>list</md-icon>
{{'list' | translate}}
</a>
</li>
<li>
<a ng-click="goto_search()">
<md-icon>search</md-icon>
{{'search' | translate}}
</a>
</li>
<li>
<a ng-click="goto_settings()">
<md-icon>settings</md-icon>
{{'settings' | translate}}
</a>
</li>
<li>
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6YS8F97PETVU2" target="_blank">
<md-icon>payment</md-icon>
Donate
</a>
</li>
</ul>
</md-content>
</md-sidenav>
<md-content layout="column" class="container" layout-fill>
<div ng-view></div>
</md-content>
</section>
</body>
</html>

Просмотреть файл

@ -0,0 +1,121 @@
<md-content layout="column" class="container" layout-fill>
<md-tabs md-dynamic-height md-border-bottom>
<md-tab label="General">
<md-content class="md-padding" ng-init="pwFieldShown = false;">
<md-input-container class="md-block" flex-gt-sm>
<label>{{'label' | translate}}</label>
<input ng-model="credential.label" required>
<copy-text text="credential.label"></copy-text>
</md-input-container>
<md-input-container class="md-block">
<label>{{'username' | translate}}</label>
<input ng-model="credential.username"/>
<copy-text text="credential.username"></copy-text>
</md-input-container>
<md-input-container class="md-block">
<label>{{'email' | translate}}</label>
<input ng-model="credential.email"/>
<copy-text text="credential.email"></copy-text>
</md-input-container>
<md-input-container class="md-block" ng-if="!pwFieldShown">
<label>{{'password' | translate}}</label>
<input type="password" ng-model="credential.password" style="width: 325px;" >
<md-icon class="pointer" ng-click="generatePassword()" style="left: initial; right: 35px;">refresh</md-icon>
<md-icon class="pointer" style="left: initial; right: 70px;" ng-click="togglePwField()">remove_red_eye</md-icon>
<copy-text text="credential.password"></copy-text>
</md-input-container>
<md-input-container class="md-block" ng-if="pwFieldShown">
<label>{{'password' | translate}}</label>
<input type="text" ng-model="credential.password" style="width: 325px;" >
<md-icon class="pointer" ng-click="generatePassword()" style="left: initial; right: 35px;">refresh</md-icon>
<md-icon class="pointer" style="left: initial; right: 70px;" ng-click="togglePwField()">remove_red_eye</md-icon>
<copy-text text="credential.password"></copy-text>
</md-input-container>
<md-input-container class="md-block">
<label>{{'password_repeat' | translate}}</label>
<input type="password" ng-model="credential.password_repeat">
</md-input-container>
<md-input-container class="md-block" style="margin-bottom: -5px;">
<label>{{'url' | translate}}</label>
<input ng-model="credential.url"/>
<copy-text text="credential.url"></copy-text>
</md-input-container>
</md-content>
</md-tab>
<md-tab label="Custom fields">
<md-content class="md-padding" style="overflow-x: hidden;">
<div layout="row" layout-align="space-around" ng-repeat="custom_field in credential.custom_fields" ng-if="custom_field.field_type !== 'file'">
<md-input-container flex="40">
<label>Label</label>
<input required ng-model="custom_field.label">
</md-input-container>
<md-input-container flex="40" ng-if="!custom_field.secret">
<label>Value</label>
<input required ng-model="custom_field.value">
</md-input-container>
<md-input-container flex="40" ng-if="custom_field.secret">
<label>Value</label>
<input type="password" ng-model="custom_field.value">
</md-input-container>
<md-input-container flex="10">
<md-button class="md-secondary md-icon-button" ng-click="deleteCustomField(custom_field)"
aria-label="call">
<md-tooltip md-direction="left">{{'delete' | translate}}</md-tooltip>
<md-icon>delete</md-icon>
</md-button>
</md-input-container>
</div>
<div layout="row">
Add custom field
</div>
<div layout="row" layout-align="space-around">
<md-input-container flex="25">
<label>Label</label>
<input ng-model="new_custom_field.label">
</md-input-container>
<md-input-container flex="25" ng-if="new_custom_field.field_type === 'text'">
<label>Value</label>
<input ng-model="new_custom_field.value">
</md-input-container>
<md-input-container flex="25" ng-if="new_custom_field.field_type === 'password'">
<label>Value</label>
<input type="password" ng-model="new_custom_field.value">
</md-input-container>
<md-input-container flex="25">
<label>Type</label>
<md-select name="type" ng-model="new_custom_field.field_type">
<md-option value="text">Text</md-option>
<md-option value="password">Password</md-option>
</md-select>
</md-input-container>
<md-input-container flex="10">
<md-button class="md-secondary md-icon-button" ng-click="addCustomField(new_custom_field)">
<md-icon>add_box</md-icon>
<md-tooltip md-direction="left">{{'add' | translate}}</md-tooltip>
</md-button>
</md-input-container>
</div>
</md-content>
</md-tab>
</md-tabs>
<div layout="row" layout-sm="column" layout-align="space-around">
<md-button class="md-raised md-primary" ng-click="saveCredential()" ng-disabled="saving"></span>{{'save' |
translate}}
</md-button>
<md-button class="md-raised md-hue-1" ng-click="cancel()">{{'cancel' | translate}}</md-button>
</div>
</md-content>

Просмотреть файл

@ -1,32 +1,39 @@
<div class="col-xs-12 nopadding pwcontainer">
<div ng-show="found_credentials.length === 0">
{{ 'no_credentials_found_for_site' | translate}}
</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>
<md-list class="password-list" flex>
<md-list-item class="md-3-line" ng-repeat="credential in found_credentials">
<!--<img ng-src="{{item.face}}?{{$index}}" class="md-avatar" alt="{{item.who}}"/>-->
<div class="md-list-item-text" layout="column">
<h3>{{credential.label}}</h3>
<h4>{{credential.username}}</h4>
<p ng-if="credential.otp.secret">OTP: <span otp-generator secret="credential.otp.secret"></span></p>
</div>
<div class="col-xs-5 OTP" ng-if="credential.otp.secret">
{{'one_time_password' | translate}}: <div otp-generator secret="credential.otp.secret"></div>
<md-button class="md-secondary md-icon-button" ng-click="edit(credential)" aria-label="call">
<md-tooltip md-direction="left">{{'edit' | translate}}</md-tooltip>
<md-icon>edit</md-icon>
</md-button>
</md-list-item>
<md-list-item ng-if="found_credentials.length === 0">
<div class="md-list-item-text" layout="column">
<h3>{{ 'no_credentials_found_for_site' | translate}}</h3>
</div>
</div>
</div>
<div class="footer">
<div style="position: absolute; left: 50%; margin-top: -7px; width: 110px;">
<div style="position: relative; left: -50%; margin-top: 1.3em;">
<small>{{'credentials_in_db' | translate:credential_amount}}</small>
</div>
</div>
<div class="bottomBtn" ng-click="goto_settings()" title="{{'settings' | translate}}"><i class="fa fa-gears"></i></div>
<div class="bottomBtn" ng-click="goto_search()" title="{{'search' | translate}}"><i class="fa fa-search"></i></div>
<div class="bottomBtn" ng-click="refresh()" title="{{'refresh_credential_list' | translate}}"><i class="fa fa-refresh" ng-class="{'fa-spin': refreshing_credentials}"></i></div>
<div class="bottomBtn pull-right"> <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6YS8F97PETVU2" target="_blank"
title="{{'donate_button_title' | translate}}"
rel="nofollow noopener noreferrer"
><i class="fa fa-paypal"></i> </a>
</div>
<div class="bottomBtn pull-right" ng-click="lockExtension()" title="{{'lock_extension' | translate}}"><i class="fa fa-lock"></i></div>
<!-- <a class="btn btn-success pull-right"
>Donate</a> -->
</div>
</md-list-item>
</md-list>
<!--<div class="footer">-->
<!--<div style="position: absolute; left: 50%; margin-top: -7px; width: 110px;">-->
<!--<div style="position: relative; left: -50%; margin-top: 1.3em;">-->
<!--<small>{{'credentials_in_db' | translate:credential_amount}}</small>-->
<!--</div>-->
<!--</div>-->
<!--&lt;!&ndash;-->
<!--<div class="bottomBtn" ng-click="goto_settings()" title="{{'settings' | translate}}"><i class="fa fa-gears"></i></div>-->
<!--<div class="bottomBtn" ng-click="goto_search()" title="{{'search' | translate}}"><i class="fa fa-search"></i></div>-->
<!--<div class="bottomBtn" ng-click="refresh()" title="{{'refresh_credential_list' | translate}}"><i class="fa fa-refresh" ng-class="{'fa-spin': refreshing_credentials}"></i></div>-->
<!--<div class="bottomBtn pull-right"> <a -->
<!--title="{{'donate_button_title' | translate}}"-->
<!--rel="nofollow noopener noreferrer"-->
<!--&gt;<i class="fa fa-paypal"></i> </a>-->
<!--</div>-->
<!--<div class="bottomBtn pull-right" ng-click="lockExtension()" title="{{'lock_extension' | translate}}"><i class="fa fa-lock"></i></div>-->
<!--&lt;!&ndash; <a class="btn btn-success pull-right"-->
<!--&gt;Donate</a> &ndash;&gt;-->
<!--</div>-->

Просмотреть файл

@ -1,15 +1,43 @@
<div class="content unlock" style="max-height: 160px; overflow: auto">
<div>
<i class="fa fa-lock fa-5x"></i>
<div>{{'extension_locked'| translate}}:</div>
<input class="form-control" type="password" ng-enter="apply_settings()" ng-model="master_password" />
<label><input type="checkbox" ng-model="master_password_remember">Remember master password</label>
</div>
<div layout="row" layout-align="center center" class="unlock-container">
<div class="unlock">
<div style="width: 100%; text-align: center; margin-bottom: 15px;">
<img src="/icons/Passman_Color_Horizontal.png" height="40"/>
</div>
<div>
<span >{{'extension_locked'| translate}}</span>
</div>
<div>
<md-input-container style="width: 100%;">
<input class="form-control" aria-label="password" type="password" ng-enter="apply_settings()" ng-model="master_password" style="width: 100%;"/>
</md-input-container>
<div class="clearfix"></div>
</div>
<div ng-show="inValidPassword" class="error">
{{'invalid_master_password' | translate}}
{{'invalid_master_password' | translate}}
</div>
<button class="btn btn-default stepNext" ng-click="apply_settings()" ng-disabled="saving"><i ng-show="saving" ng-class="{'fa-spinner fa-spin': saving}" class="fa"></i><i ng-show="!saving" class="fa fa-unlock"></i> {{'unlock' | translate}}</button>
</div>
<div layout="row" layout-sm="column" layout-align="space-around">
<md-button class="md-raised md-primary" ng-click="apply_settings()" ng-disabled="saving"></span>
<i ng-show="saving"
ng-class="{'fa-spinner fa-spin': saving}"
class="fa"></i><i
ng-show="!saving" class="fa fa-unlock"></i>
{{'unlock' | translate}}
</md-button>
</div>
<br />
<div layout="row" layout-sm="column" layout-align="space-around">
<md-input-container>
<md-checkbox class="md-primary" md-no-ink aria-label=" {{'remember_master_password'| translate}}" ng-model="master_password_remember">
{{'remember_master_password'| translate}}
</md-checkbox>
</md-input-container>
</div>
</div>
</div>

Просмотреть файл

@ -1,38 +1,25 @@
<div class="col-xs-12 nopadding pwcontainer">
<div class="searchContainer">
<input type="text" ng-model="searchText" placeholder="{{'search_for' | translate }}..." class="form-control" ng-enter="search()"/>
</div>
<div ng-show="found_credentials.length === 0">
{{'no_credentials_found' | translate}}
</div>
<div class="credential" ng-repeat="credential in found_credentials">
<div class="col-xs-7 nopadding">{{credential.label}}<br/>
<small>{{credential.username}}</small>
<small>{{credential.email}}</small>
<div layout-padding>
<md-input-container class="md-block">
<label>{{'search_for' | translate }}</label>
<input ng-model="searchText" ng-enter="search()">
</md-input-container>
<md-list class="password-list" ng-show="found_credentials.length > 0">
<md-list-item class="md-3-line" ng-repeat="credential in found_credentials">
<!--<img ng-src="{{item.face}}?{{$index}}" class="md-avatar" alt="{{item.who}}"/>-->
<div class="md-list-item-text" layout="column">
<h3>{{credential.label}}</h3>
<h4>{{credential.username}}</h4>
<p ng-if="credential.otp.secret">OTP: <span otp-generator secret="credential.otp.secret"></span></p>
</div>
<md-button class="md-secondary md-icon-button" ng-click="edit(credential)" aria-label="call">
<md-tooltip md-direction="left">{{'edit' | translate}}</md-tooltip>
<md-icon>edit</md-icon>
</md-button>
</md-list-item>
</md-list>
<md-list-item ng-if="found_credentials.length === 0">
<div class="md-list-item-text" layout="column">
<h3>{{ 'no_credentials_found' | translate}}</h3>
</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>
</div>
</div>
<div class="footer">
<div style="position: absolute; left: 50%; margin-top: -7px; width: 110px;">
<div style="position: relative; left: -50%; margin-top: 1.3em;">
<small>{{'credentials_in_db' | translate:credential_amount}}</small>
</div>
</div>
<div class="bottomBtn" ng-click="goto_settings()" title="{{'settings' | translate}}"><i class="fa fa-gears"></i></div>
<div class="bottomBtn" ng-click="goto_search()" title="{{'search' | translate}}"><i class="fa fa-search"></i></div>
<div class="bottomBtn" ng-click="refresh()" title="{{'refresh_credential_list' | translate}}"><i class="fa fa-refresh" ng-class="{'fa-spin': refreshing_credentials}"></i></div>
<div class="bottomBtn pull-right"> <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6YS8F97PETVU2" target="_blank"
title="{{'donate_button_title' | translate}}"
rel="nofollow noopener noreferrer"
><i class="fa fa-paypal"></i> </a>
</div>
<div class="bottomBtn pull-right" ng-click="lockExtension()" title="{{'lock_extension' | translate}}"><i class="fa fa-lock"></i></div>
<!-- <a class="btn btn-success pull-right"
>Donate</a> -->
</md-list-item>
</div>

Просмотреть файл

@ -1,10 +1,80 @@
<h4 align="center">{{'please_enter_nextcloud_credentials' | translate}}:</h4>
<div class="alerts alert alert-warning" ng-if="errors.length > 0">
<li ng-repeat="error in errors">{{error}}</li>
</div>
<div style="max-height: 350px; overflow-y: auto;">
<table class="table">
<h4 align="center">{{'please_enter_nextcloud_credentials' | translate}}:</h4>
<md-content layout-padding>
<div layout-gt-sm="row">
<md-input-container class="md-block" flex-gt-sm>
<label>{{'server_url' | translate}}</label>
<input ng-model="settings.nextcloud_host" required ng-debounce="1000">
</md-input-container>
<md-input-container class="md-block">
<label>{{'username' | translate}}</label>
<input ng-model="settings.nextcloud_username" required ng-debounce="1000">
</md-input-container>
<md-input-container class="md-block">
<label>{{'password' | translate}}</label>
<input type="password" ng-model="settings.nextcloud_password" required ng-debounce="1000">
</md-input-container>
<md-input-container class="md-block" ng-if="vaults">
<label>{{'select_default_vault' | translate}}</label>
<md-select ng-model="settings.default_vault.guid">
<md-option ng-repeat="vault in vaults" value="{{vault.guid}}"
ng-selected="settings.default_vault.vault_id === vault.vault_id">
{{vault.name}}
</md-option>
</md-select>
</md-input-container>
<md-input-container class="md-block" ng-show="settings.default_vault != ''">
<label>{{'vault_password' | translate}}</label>
<input type="password" ng-model="settings.vault_password" required>
</md-input-container>
<md-input-container class="md-block">
<label>{{'refresh_timer' | translate}}</label>
<input type="text" ng-model="settings.refreshTime" required>
</md-input-container>
<md-input-container class="md-block">
<md-switch class="md-primary" name="special" ng-model="settings.ignoreProtocol">
{{'ignore_protocol' | translate}}
</md-switch>
</md-input-container>
<md-input-container class="md-block">
<md-switch class="md-primary" name="special" ng-model="settings.ignoreSubdomain">
{{'ignore_subdomain' | translate}}
</md-switch>
</md-input-container>
<md-input-container class="md-block">
<md-switch class="md-primary" name="special" ng-model="settings.ignorePort">
{{'ignore_port' | translate}}
</md-switch>
</md-input-container>
<md-input-container class="md-block">
<md-switch class="md-primary" name="special" ng-model="settings.disableAutoFill">
{{'disable_autofill' | translate}}
</md-switch>
</md-input-container>
<md-input-container class="md-block">
<md-switch class="md-primary" name="special" ng-model="settings.disablePasswordPicker">
{{'disable_password_picker' | translate}}
</md-switch>
</md-input-container>
<md-input-container class="md-block">
<md-switch class="md-primary" name="special" ng-model="settings.debug">
{{'enable_debug' | translate}}
</md-switch>
</md-input-container>
<div layout="row" layout-sm="column" layout-align="space-around">
<md-button class="md-raised md-primary" ng-click="saveSettings()" ng-disabled="saving"></span>{{'save' |
translate}}
</md-button>
<md-button class="md-raised" ng-click="cancel()">{{'cancel' | translate}}</md-button>
</div>
</div>
</md-content>
<!-- <table class="table">
<tr>
<td><small>{{'server_url' | translate}}:</small></td>
<td><input type="url" class="form-control input-sm" id="host" ng-model="settings.nextcloud_host" required ng-debounce="1000">
@ -74,8 +144,8 @@
<button class="btn btn-warning" ng-click="cancel()">{{'cancel' | translate}}</button>
</td>
</tr>
</table>
<div class="version">
{{extension}}
</div>
</table> -->
<div class="version">
{{extension}}
</div>

Просмотреть файл

@ -1,52 +1,102 @@
<div class="alerts alert alert-warning" ng-if="errors.length > 0">
<li ng-repeat="error in errors">{{error}}</li>
</div>
<steps on-finish="finished()" class="setup">
<step class="step1" name="welcome">
<h2>{{'welcome_to_passman' | translate}}</h2>
{{'intro_text' | translate}}
<button class="btn btn-default stepNext" ng-click="next()">{{'begin' | translate}}</button>
</step>
<step class="step2" name="server">
<h2>{{'nextcloud_settings' | translate}}</h2>
<label>{{'server_url' | translate}}</label>
<input type="text" ng-model="settings.nextcloud_host"/>
<label>{{'username' | translate}}</label>
<input type="text" ng-model="settings.nextcloud_username"/>
<label>{{'password' | translate}}</label>
<input type="password" ng-model="settings.nextcloud_password" />
<div layout-padding style="height: 520px; width: 500px;">
<md-stepper id="setup-stepper" md-linear="false" md-vertical="true">
<md-step md-label="{{'welcome_to_passman' | translate}}">
<md-step-body>
<p>{{'intro_text' | translate}}</p>
</md-step-body>
<md-step-actions>
<md-button class="md-primary md-raised" ng-click="nextStep();">
<i ng-show="saving" ng-class="{'fa-spinner fa-spin': saving}" class="fa"></i>
Continue
</md-button>
</md-step-actions>
</md-step>
<md-step md-label="{{ 'server_settings' | translate}}" class="server_settings">
<md-step-body style="overflow: hidden;">
<md-input-container>
<label>{{'server_url' | translate}}</label>
<input ng-model="settings.nextcloud_host" required>
</md-input-container>
<md-input-container>
<label>{{'username' | translate}}</label>
<input ng-model="settings.nextcloud_username" required>
</md-input-container>
<button step-previous class="btn btn-default">{{'prev' | translate}}</button>
<md-input-container>
<label>{{'password' | translate}}</label>
<input type="password" ng-model="settings.nextcloud_password" required>
</md-input-container>
</md-step-body>
<md-step-actions>
<md-button class="md-primary md-raised" ng-click="nextStep('server');">
<i ng-show="saving" ng-class="{'fa-spinner fa-spin': saving}" class="fa"></i>
{{ 'continue' | translate}}
</md-button>
<md-button class="md-primary" ng-click="previousStep();">{{ 'back' | translate}}</md-button>
</md-step-actions>
</md-step>
<md-step md-label="{{'vault_settings' | translate}}">
<md-step-body style="overflow: hidden;">
<md-input-container class="md-block" ng-if="vaults">
<label>{{'select_default_vault' | translate}}</label>
<md-select ng-model="settings.default_vault.guid">
<md-option ng-repeat="vault in vaults" value="{{vault.guid}}"
ng-selected="settings.default_vault.vault_id === vault.vault_id">
{{vault.name}}
</md-option>
</md-select>
</md-input-container>
<md-input-container class="md-block">
<label>{{'vault_password' | translate}}</label>
<input type="password" ng-model="settings.vault_password" required>
</md-input-container>
</md-step-body>
<md-step-actions>
<md-button class="md-primary md-raised" ng-click="nextStep('vault');">
<i ng-show="saving" ng-class="{'fa-spinner fa-spin': saving}" class="fa"></i>
{{ 'continue' | translate}}
</md-button>
<md-button class="md-primary" ng-click="previousStep();">{{ 'back' | translate}}</md-button>
</md-step-actions>
</md-step>
<md-step md-label="{{ 'master_password' | translate}}">
<md-step-body>
<p>
{{'enter_master_password_desc' | translate}}
</p>
<md-input-container class="md-block">
<input type="password" ng-model="settings.master_password" aria-label="Master password" />
</md-input-container>
<md-input-container>
<md-checkbox class="md-primary" md-no-ink aria-label=" {{'remember_master_password'| translate}}" ng-model="settings.master_password_remember">
{{'remember_master_password'| translate}}
</md-checkbox>
</md-input-container>
</md-step-body>
<md-step-actions>
<md-button class="md-primary md-raised" ng-click="nextStep('master');">
<i ng-show="saving" ng-class="{'fa-spinner fa-spin': saving}" class="fa"></i>
{{ 'continue' | translate}}
</md-button>
<md-button class="md-primary" ng-click="previousStep();">{{ 'back' | translate}}</md-button>
</md-step-actions>
</md-step>
<button class="btn btn-default stepNext" ng-click="next()" ng-disabled="saving"><i ng-show="saving" ng-class="{'fa-spinner fa-spin': saving}" class="fa"></i> {{'next' | translate}}</button>
</step>
<step class="step3" name="vault">
<h2>{{'default_vault' | translate}}</h2>
<label>{{'default_vault_desc' | translate}}</label>
<select id="defaultVault" class="form-control input-sm" ng-model="settings.default_vault" required ng-options="vault.name for vault in vaults track by vault.guid">
</select>
<label>{{'vault_password' | translate}}</label>
<input type="password" ng-change="" ng-model="settings.vault_password" />
<button step-previous class="btn btn-default">{{'prev' | translate}}</button>
<button class="btn btn-default stepNext" ng-click="next()" ng-disabled="saving"><i ng-show="saving" ng-class="{'fa-spinner fa-spin': saving}" class="fa"></i> {{'next' | translate}}</button>
</step>
<step class="step4" name="master">
<h2>{{'enter_master_password' | translate}}</h2>
<div>{{'enter_master_password_desc' | translate}}</div>
<br />
<input type="password" ng-model="settings.master_password" />
<br />
<label><input type="checkbox" ng-model="settings.master_password_remember">{{'remember_master_password' | translate}}</label>
<button step-previous class="btn btn-default">{{'prev' | translate}}</button>
<button class="btn btn-default stepNext" ng-click="next()" ng-disabled="saving"><i ng-show="saving" ng-class="{'fa-spinner fa-spin': saving}" class="fa"></i> {{'next' | translate}}</button>
</step>
<step class="step5" name="last">
<h1>{{'done' | translate}}!</h1>
<div>{{'done_donate' | translate}}</div>
<button step-finish class="btn btn-default" ng-disabled="saving"><i ng-show="saving" ng-class="{'fa-spinner fa-spin': saving}" class="fa"></i> {{'finish' | translate}}</button>
</step>
</steps>
<md-step md-label="{{'done' | translate}}">
<md-step-body>
<p>
{{'done_donate' | translate}}
</p>
</md-step-body>
<md-step-actions>
<md-button class="md-primary md-raised" ng-click="finished();">{{'finish' | translate}}</md-button>
<md-button class="md-primary" ng-click="previousStep();">{{ 'back' | translate}}</md-button>
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6YS8F97PETVU2" target="_blank"><md-button class="md-primary md-raised">{{'donate' | translate}}</md-button></a>
</md-step-actions>
</md-step>
<!-- Other steps if needed ... -->
</md-stepper>
</div>

Двоичные данные
icons/Passman_Color_Horizontal.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 15 KiB

Просмотреть файл

@ -6,7 +6,6 @@ var background = (function () {
var _window = {};
API.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(function (msg) {
@ -90,7 +89,7 @@ var background = (function () {
_self.settings = _settings;
if(!_self.settings.hasOwnProperty('ignored_sites')){
if (!_self.settings.hasOwnProperty('ignored_sites')) {
_self.settings.ignored_sites = [];
}
@ -139,7 +138,7 @@ var background = (function () {
PAPI.username = settings.nextcloud_username;
PAPI.password = settings.nextcloud_password;
if(!settings.hasOwnProperty('ignored_sites')){
if (!settings.hasOwnProperty('ignored_sites')) {
settings.ignored_sites = [];
}
@ -147,7 +146,6 @@ var background = (function () {
_self.settings = settings;
storage.set('settings', settings).then(function () {
getSettings();
});
@ -192,6 +190,17 @@ var background = (function () {
_self.getCredentials = getCredentials;
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 getCredentialsByUrl(_url, sender) {
if (!master_password) {
return [];
@ -259,11 +268,14 @@ var background = (function () {
//console.log('Fecthing mined data for tab id', sender.tab.id)
var senderUrl = sender.tab.url;
var site = processURL(senderUrl, _self.settings.ignoreProtocol, _self.settings.ignoreSubdomain, _self.settings.ignorePath, _self.settings.ignorePort);
if(!_self.settings.hasOwnProperty('ignored_sites')){
return mined_data[sender.tab.id];
}
var matches = _self.settings.ignored_sites.filter(function (item) {
return typeof item === 'string' && site.indexOf(item) > -1;
});
if(matches.length !== 0){
if (matches.length !== 0) {
return null;
}
return mined_data[sender.tab.id];
@ -411,7 +423,31 @@ var background = (function () {
});
}
self.injectCreateCredential = injectCreateCredential;
_self.injectCreateCredential = injectCreateCredential;
function saveCredential(credential) {
if (!credential.credential_id) {
PAPI.createCredential(credential, _self.settings.vault_password, function (createdCredential) {
local_credentials.push(createdCredential);
});
} else {
var credential_index;
for (var i = 0; i < local_credentials.length; i++) {
if (local_credentials[i].guid === credential.guid) {
credential_index = i;
break;
}
}
PAPI.updateCredential(credential, _self.settings.vault_password, function (updatedCredential) {
if (credential_index) {
local_credentials[credential_index] = updatedCredential;
}
});
}
}
_self.saveCredential = saveCredential;
function isVaultKeySet() {
return (_self.settings.vault_password !== null);
@ -429,14 +465,17 @@ var background = (function () {
_self.isAutoFillEnabled = isAutoFillEnabled;
var doorhangerData = null;
function setDoorhangerData(data) {
doorhangerData = data;
}
_self.setDoorhangerData = setDoorhangerData;
function getDoorhangerData() {
return doorhangerData;
}
_self.getDoorhangerData = getDoorhangerData;
API.runtime.onMessage.addListener(function (msg, sender, sendResponse) {

Просмотреть файл

@ -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);

Просмотреть файл

@ -37,13 +37,14 @@
'ngRoute',
'ngSanitize',
'pascalprecht.translate',
'angular-steps'
'ngMaterial',
'mdSteppers'
])
.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
controller: 'ListCtrl'
})
.when('/search', {
templateUrl: 'views/search.html',
@ -53,6 +54,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'
@ -79,6 +84,9 @@
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension|moz-extension):/);
// Angular before v1.2 uses $compileProvider.urlSanitizationWhitelist(...)
}
]);
]).config(function($mdThemingProvider) {
$mdThemingProvider.theme('default')
.primaryPalette('blue');
});
}());

Просмотреть файл

@ -0,0 +1,172 @@
/* 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', '$mdToast','$timeout', function ($scope, $routeParams, $mdToast, $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;
};
function generate_pass(inputId) {
}
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 = '#!/';
};
}]);
}());

Просмотреть файл

@ -0,0 +1,98 @@
/* 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('ListCtrl', ['$scope', 'Settings', '$location', '$rootScope', function ($scope, Settings, $window, $rootScope) {
$scope.app = 'passman';
var port = API.runtime.connect(null, {
name: "PassmanCommunication"
});
var messageParser = function (message) {
var e = message.split(':');
switch (e[0]) {
case "credential_amount":
$scope.credential_amount = e[1];
$scope.refreshing_credentials = false;
}
$scope.$apply();
};
/**
* Connect to the background service
*/
var initApp = function () {
port.onMessage.addListener(messageParser);
API.runtime.sendMessage(API.runtime.id, {method: "getMasterPasswordSet"}).then(function (isPasswordSet) {
getActiveTab();
$scope.refreshing_credentials = true;
setTimeout(function () {
port.postMessage("credential_amount");
}, 500);
});
};
$scope.refreshing_credentials = false;
$scope.refresh = function () {
$scope.refreshing_credentials = true;
API.runtime.sendMessage(API.runtime.id, {method: "getCredentials"}).then(function () {
setTimeout(function () {
port.postMessage("credential_amount");
}, 2000);
});
};
var getActiveTab = function (cb) {
API.tabs.query({currentWindow: true, active: true}).then(function (tab) {
API.runtime.sendMessage(API.runtime.id, {
method: "getCredentialsByUrl",
args: [tab[0].url]
}).then(function (_logins) {
//var url = backgroundPage.processURL(tab.url, $rootScope.app_settings.ignoreProtocol, $rootScope.app_settings.ignoreSubdomain, $rootScope.app_settings.ignorePath);
$scope.found_credentials = _logins;
$scope.$apply();
});
});
};
initApp();
$scope.edit = function (credential) {
window.location = '#!/edit/' + credential.guid;
};
}]);
}());

Просмотреть файл

@ -33,100 +33,56 @@
* Controller of the passmanApp
*/
angular.module('passmanExtension')
.controller('MainCtrl', ['$scope', 'Settings', '$location', '$rootScope', function ($scope, Settings, $window, $rootScope) {
$scope.app = 'passman';
var port = API.runtime.connect(null, {
name: "PassmanCommunication"
.controller('MainCtrl', ['$scope', '$mdSidenav', '$rootScope', function ($scope, $mdSidenav, $rootScope) {
function buildToggler(navID) {
return function() {
// Component lookup should always be available since we are not using `ng-if`
$mdSidenav(navID)
.toggle();
};
}
$scope.toolbarShown = true;
$rootScope.$on('lockExtension', function () {
$scope.lockExtension();
});
var messageParser = function (message) {
var e = message.split(':');
$rootScope.$on('unlocked', function () {
$scope.toolbarShown = true;
});
switch (e[0]) {
case "credential_amount":
$scope.credential_amount = e[1];
$scope.refreshing_credentials = false;
}
$scope.$apply();
};
/**
* Connect to the background service
*/
var initApp = function () {
port.onMessage.addListener(messageParser);
API.runtime.sendMessage(API.runtime.id, {method: "getMasterPasswordSet"}).then(function (isPasswordSet) {
function redirectToPrompt() {
window.location = '#!/locked';
return;
}
//First check attributes
if (!isPasswordSet) {
redirectToPrompt();
return;
}
getActiveTab();
$scope.refreshing_credentials = true;
setTimeout(function () {
port.postMessage("credential_amount");
}, 500);
});
};
$scope.refreshing_credentials = false;
$scope.refresh = function () {
$scope.refreshing_credentials = true;
API.runtime.sendMessage(API.runtime.id, {method: "getCredentials"}).then(function () {
setTimeout(function () {
port.postMessage("credential_amount");
}, 2000);
});
};
var getActiveTab = function (cb) {
API.tabs.query({currentWindow: true, active: true}).then(function (tab) {
API.runtime.sendMessage(API.runtime.id, {
method: "getCredentialsByUrl",
args: [tab[0].url]
}).then(function (_logins) {
//var url = backgroundPage.processURL(tab.url, $rootScope.app_settings.ignoreProtocol, $rootScope.app_settings.ignoreSubdomain, $rootScope.app_settings.ignorePath);
$scope.found_credentials = _logins;
$scope.$apply();
});
});
};
$scope.toggleLeft = buildToggler('left');
$scope.lockExtension = function () {
$scope.toolbarShown = false;
API.runtime.sendMessage(API.runtime.id, {method: "setMasterPassword", args: {password: null}}).then(function () {
window.location = '#!/locked';
});
};
API.runtime.sendMessage(API.runtime.id, {'method': 'getRuntimeSettings'}).then(function (settings) {
$rootScope.app_settings = settings;
if (!settings || Object.keys(settings).length === 0) {
window.location = '#!/setup';
} else if (settings.hasOwnProperty('isInstalled')) {
window.location = '#!/locked';
} else {
initApp();
}
});
$scope.goto_list = function () {
window.location = '#!/';
$mdSidenav('left').close();
};
$scope.goto_settings = function () {
window.location = '#!/settings';
$mdSidenav('left').close();
};
$scope.goto_search = function () {
window.location = '#!/search';
$mdSidenav('left').close();
};
API.runtime.sendMessage(API.runtime.id, {'method': 'getRuntimeSettings'}).then(function (settings) {
$rootScope.app_settings = settings;
if (!settings || Object.keys(settings).length === 0) {
window.location = '#!/setup';
} else if (settings.hasOwnProperty('isInstalled')) {
$scope.lockExtension();
}
});
}]);
}());

Просмотреть файл

@ -38,6 +38,7 @@
API.runtime.sendMessage(API.runtime.id, {method: "getMasterPasswordSet"}).then(function(isSet) {
$scope.masterPwSet = isSet;
$rootScope.$broadcast('lockExtension');
$scope.$apply();
});
API.runtime.sendMessage(API.runtime.id, {method: "getSettings"});
@ -51,6 +52,7 @@
API.runtime.sendMessage(API.runtime.id, {method: "setMasterPassword", args: {password: $scope.master_password, savePassword: $scope.master_password_remember} }).then(function () {
setTimeout(function () {
window.location = '#!/';
$rootScope.$emit('unlocked');
$scope.saving = false;
$scope.saving = false;
},1500);

Просмотреть файл

@ -54,11 +54,8 @@
port.onMessage.addListener(messageParser);
port.postMessage("credential_amount");
$scope.lockExtension = function () {
API.runtime.sendMessage(API.runtime.id, {method: "setMasterPassword", args: {password: null}}).then(function () {
window.location = '#!/locked';
});
$scope.edit = function (credential) {
window.location = '#!/edit/' + credential.guid;
};
$scope.found_credentials = false;
@ -71,15 +68,6 @@
};
$scope.goto_settings = function () {
window.location = '#!/settings';
};
$scope.goto_search = function () {
window.location = '#!/search';
};
}]);
}());

Просмотреть файл

@ -102,6 +102,14 @@
$scope.saveSettings = function () {
$scope.errors = [];
var settings = angular.copy($scope.settings);
for (var i =0; i < $scope.vaults.length; i++){
var vault = $scope.vaults[i];
if(vault.guid === settings.default_vault.guid){
settings.default_vault = angular.copy(vault);
break;
}
}
try {
/** global: PAPI */
PAPI.decryptString(settings.default_vault.challenge_password, settings.vault_password);

Просмотреть файл

@ -33,7 +33,8 @@
* Controller of the passmanApp
*/
angular.module('passmanExtension')
.controller('SetupCtrl', ['$scope', '$timeout', '$location', '$rootScope', 'StepsService', function ($scope, $timeout, $location, $rootScope, StepsService) {
.controller('SetupCtrl', ['$scope', '$timeout', '$location', '$rootScope', '$mdStepper', '$mdToast',
function ($scope, $timeout, $location, $rootScope, $mdStepper, $mdToast) {
$scope.settings = {
nextcloud_host: '',
nextcloud_username: '',
@ -54,20 +55,54 @@
};
$scope.vaults = [];
$scope.gogo = function (to) {
StepsService.steps().goTo(to);
$scope.nextStep = function (stepName) {
var steppers = $mdStepper('setup-stepper');
$scope.saving = true;
$scope.errors = [];
$timeout(function () {
var step = stepName;
var check = $scope.check[step];
if (typeof check === "function") {
check(function (result) {
$scope.saving = false;
if (result) {
$scope.errors = [];
$scope.$apply();
steppers.next();
}
$timeout(function () {
$scope.errors = [];
$scope.$apply();
}, 5000);
});
}
else {
$scope.saving = false;
steppers.next();
}
}, 10);
};
$scope.previousStep = function () {
var steppers = $mdStepper('setup-stepper');
steppers.back();
};
$scope.check = {
server: function (callback) {
if(!$scope.settings.nextcloud_host){
$mdToast.showSimple(API.i18n.getMessage('invalid_host'));
callback(false);
return;
}
PAPI.host = $scope.settings.nextcloud_host;
PAPI.username = $scope.settings.nextcloud_username;
PAPI.password = $scope.settings.nextcloud_password;
PAPI.getVaults(function (vaults) {
if (vaults.hasOwnProperty('error')) {
var errors = API.i18n.getMessage('invalid_response_from_server', [vaults.result.status, vaults.result.statusText]);
$scope.errors.push(errors);
$mdToast.showSimple(API.i18n.getMessage('invalid_response_from_server', [vaults.result.status, vaults.result.statusText]));
callback(false);
}
else {
@ -78,12 +113,19 @@
});
},
vault: function (callback) {
for (var i = 0; i < $scope.vaults.length; i++) {
var vault = $scope.vaults[i];
if (vault.guid === $scope.settings.default_vault.guid) {
$scope.settings.default_vault = angular.copy(vault);
break;
}
}
try {
PAPI.decryptString($scope.settings.default_vault.challenge_password, $scope.settings.vault_password);
callback(true);
}
catch (e) {
$scope.errors.push(API.i18n.getMessage('invalid_vault_password'));
$mdToast.showSimple(API.i18n.getMessage('invalid_vault_password'));
callback(false);
}
},
@ -91,38 +133,13 @@
if ($scope.settings.master_password.trim() !== '') {
callback(true);
} else {
$scope.errors.push(API.i18n.getMessage('empty_master_key'));
$mdToast.showSimple(API.i18n.getMessage('empty_master_key'));
callback(false);
}
}
};
$scope.saving = false;
$scope.next = function () {
$scope.saving = true;
$scope.errors = [];
$timeout(function () {
var step = StepsService.getCurrent().name;
var check = $scope.check[step];
if (typeof check === "function") {
check(function (result) {
$scope.saving = false;
if (result) {
$scope.errors = [];
$scope.$apply();
StepsService.steps().next();
}
$timeout(function () {
$scope.errors = [];
$scope.$apply();
}, 5000);
});
}
else {
$scope.saving = false;
StepsService.steps().next();
}
}, 10);
};
$scope.finished = function () {
var settings = angular.copy($scope.settings);

Просмотреть файл

@ -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: '<md-icon class="pointer" ng-click="copyText()">content_copy</md-icon>',
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);
};
}
};
}
]);
}());

Просмотреть файл

@ -68,10 +68,12 @@
return str;
}
var strCopy = API.i18n.getMessage('copy');
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">{{otp}} <i class="fa fa-copy" ng-click="copyOTP(otp)"><md-tooltip md-direction="top">'+ strCopy +'</md-tooltip></i></md-button> </span>',
template: '<span class="otp_generator"><span class="code">{{otp}}</span> <i class="fa fa-copy" ng-click="copyOTP(otp)"><md-tooltip md-direction="top">'+ strCopy +'</md-tooltip></i></md-button> <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: '='
@ -127,6 +129,16 @@
$timeout.cancel(scope.timer);
}
);
scope.copyOTP = function (otp) {
var txtToCopy = document.createElement('input');
txtToCopy.value = otp;
document.body.appendChild(txtToCopy);
txtToCopy.select();
document.execCommand('copy');
txtToCopy.parentNode.removeChild(txtToCopy);
};
}
};
}

4154
js/vendor/angular-animate/angular-animate.js поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

402
js/vendor/angular-aria/angular-aria.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,402 @@
/**
* @license AngularJS v1.6.1
* (c) 2010-2016 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular) {'use strict';
/**
* @ngdoc module
* @name ngAria
* @description
*
* The `ngAria` module provides support for common
* [<abbr title="Accessible Rich Internet Applications">ARIA</abbr>](http://www.w3.org/TR/wai-aria/)
* attributes that convey state or semantic information about the application for users
* of assistive technologies, such as screen readers.
*
* <div doc-module-components="ngAria"></div>
*
* ## Usage
*
* For ngAria to do its magic, simply include the module `ngAria` as a dependency. The following
* directives are supported:
* `ngModel`, `ngChecked`, `ngReadonly`, `ngRequired`, `ngValue`, `ngDisabled`, `ngShow`, `ngHide`, `ngClick`,
* `ngDblClick`, and `ngMessages`.
*
* Below is a more detailed breakdown of the attributes handled by ngAria:
*
* | Directive | Supported Attributes |
* |---------------------------------------------|-----------------------------------------------------------------------------------------------------|
* | {@link ng.directive:ngModel ngModel} | aria-checked, aria-valuemin, aria-valuemax, aria-valuenow, aria-invalid, aria-required, input roles |
* | {@link ng.directive:ngDisabled ngDisabled} | aria-disabled |
* | {@link ng.directive:ngRequired ngRequired} | aria-required |
* | {@link ng.directive:ngChecked ngChecked} | aria-checked |
* | {@link ng.directive:ngReadonly ngReadonly} | aria-readonly |
* | {@link ng.directive:ngValue ngValue} | aria-checked |
* | {@link ng.directive:ngShow ngShow} | aria-hidden |
* | {@link ng.directive:ngHide ngHide} | aria-hidden |
* | {@link ng.directive:ngDblclick ngDblclick} | tabindex |
* | {@link module:ngMessages ngMessages} | aria-live |
* | {@link ng.directive:ngClick ngClick} | tabindex, keydown event, button role |
*
* Find out more information about each directive by reading the
* {@link guide/accessibility ngAria Developer Guide}.
*
* ## Example
* Using ngDisabled with ngAria:
* ```html
* <md-checkbox ng-disabled="disabled">
* ```
* Becomes:
* ```html
* <md-checkbox ng-disabled="disabled" aria-disabled="true">
* ```
*
* ## Disabling Attributes
* It's possible to disable individual attributes added by ngAria with the
* {@link ngAria.$ariaProvider#config config} method. For more details, see the
* {@link guide/accessibility Developer Guide}.
*/
var ngAriaModule = angular.module('ngAria', ['ng']).
provider('$aria', $AriaProvider);
/**
* Internal Utilities
*/
var nodeBlackList = ['BUTTON', 'A', 'INPUT', 'TEXTAREA', 'SELECT', 'DETAILS', 'SUMMARY'];
var isNodeOneOf = function(elem, nodeTypeArray) {
if (nodeTypeArray.indexOf(elem[0].nodeName) !== -1) {
return true;
}
};
/**
* @ngdoc provider
* @name $ariaProvider
* @this
*
* @description
*
* Used for configuring the ARIA attributes injected and managed by ngAria.
*
* ```js
* angular.module('myApp', ['ngAria'], function config($ariaProvider) {
* $ariaProvider.config({
* ariaValue: true,
* tabindex: false
* });
* });
*```
*
* ## Dependencies
* Requires the {@link ngAria} module to be installed.
*
*/
function $AriaProvider() {
var config = {
ariaHidden: true,
ariaChecked: true,
ariaReadonly: true,
ariaDisabled: true,
ariaRequired: true,
ariaInvalid: true,
ariaValue: true,
tabindex: true,
bindKeydown: true,
bindRoleForClick: true
};
/**
* @ngdoc method
* @name $ariaProvider#config
*
* @param {object} config object to enable/disable specific ARIA attributes
*
* - **ariaHidden** `{boolean}` Enables/disables aria-hidden tags
* - **ariaChecked** `{boolean}` Enables/disables aria-checked tags
* - **ariaReadonly** `{boolean}` Enables/disables aria-readonly tags
* - **ariaDisabled** `{boolean}` Enables/disables aria-disabled tags
* - **ariaRequired** `{boolean}` Enables/disables aria-required tags
* - **ariaInvalid** `{boolean}` Enables/disables aria-invalid tags
* - **ariaValue** `{boolean}` Enables/disables aria-valuemin, aria-valuemax and
* aria-valuenow tags
* - **tabindex** `{boolean}` Enables/disables tabindex tags
* - **bindKeydown** `{boolean}` Enables/disables keyboard event binding on non-interactive
* elements (such as `div` or `li`) using ng-click, making them more accessible to users of
* assistive technologies
* - **bindRoleForClick** `{boolean}` Adds role=button to non-interactive elements (such as
* `div` or `li`) using ng-click, making them more accessible to users of assistive
* technologies
*
* @description
* Enables/disables various ARIA attributes
*/
this.config = function(newConfig) {
config = angular.extend(config, newConfig);
};
function watchExpr(attrName, ariaAttr, nodeBlackList, negate) {
return function(scope, elem, attr) {
var ariaCamelName = attr.$normalize(ariaAttr);
if (config[ariaCamelName] && !isNodeOneOf(elem, nodeBlackList) && !attr[ariaCamelName]) {
scope.$watch(attr[attrName], function(boolVal) {
// ensure boolean value
boolVal = negate ? !boolVal : !!boolVal;
elem.attr(ariaAttr, boolVal);
});
}
};
}
/**
* @ngdoc service
* @name $aria
*
* @description
* @priority 200
*
* The $aria service contains helper methods for applying common
* [ARIA](http://www.w3.org/TR/wai-aria/) attributes to HTML directives.
*
* ngAria injects common accessibility attributes that tell assistive technologies when HTML
* elements are enabled, selected, hidden, and more. To see how this is performed with ngAria,
* let's review a code snippet from ngAria itself:
*
*```js
* ngAriaModule.directive('ngDisabled', ['$aria', function($aria) {
* return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nodeBlackList, false);
* }])
*```
* Shown above, the ngAria module creates a directive with the same signature as the
* traditional `ng-disabled` directive. But this ngAria version is dedicated to
* solely managing accessibility attributes on custom elements. The internal `$aria` service is
* used to watch the boolean attribute `ngDisabled`. If it has not been explicitly set by the
* developer, `aria-disabled` is injected as an attribute with its value synchronized to the
* value in `ngDisabled`.
*
* Because ngAria hooks into the `ng-disabled` directive, developers do not have to do
* anything to enable this feature. The `aria-disabled` attribute is automatically managed
* simply as a silent side-effect of using `ng-disabled` with the ngAria module.
*
* The full list of directives that interface with ngAria:
* * **ngModel**
* * **ngChecked**
* * **ngReadonly**
* * **ngRequired**
* * **ngDisabled**
* * **ngValue**
* * **ngShow**
* * **ngHide**
* * **ngClick**
* * **ngDblclick**
* * **ngMessages**
*
* Read the {@link guide/accessibility ngAria Developer Guide} for a thorough explanation of each
* directive.
*
*
* ## Dependencies
* Requires the {@link ngAria} module to be installed.
*/
this.$get = function() {
return {
config: function(key) {
return config[key];
},
$$watchExpr: watchExpr
};
};
}
ngAriaModule.directive('ngShow', ['$aria', function($aria) {
return $aria.$$watchExpr('ngShow', 'aria-hidden', [], true);
}])
.directive('ngHide', ['$aria', function($aria) {
return $aria.$$watchExpr('ngHide', 'aria-hidden', [], false);
}])
.directive('ngValue', ['$aria', function($aria) {
return $aria.$$watchExpr('ngValue', 'aria-checked', nodeBlackList, false);
}])
.directive('ngChecked', ['$aria', function($aria) {
return $aria.$$watchExpr('ngChecked', 'aria-checked', nodeBlackList, false);
}])
.directive('ngReadonly', ['$aria', function($aria) {
return $aria.$$watchExpr('ngReadonly', 'aria-readonly', nodeBlackList, false);
}])
.directive('ngRequired', ['$aria', function($aria) {
return $aria.$$watchExpr('ngRequired', 'aria-required', nodeBlackList, false);
}])
.directive('ngModel', ['$aria', function($aria) {
function shouldAttachAttr(attr, normalizedAttr, elem, allowBlacklistEls) {
return $aria.config(normalizedAttr) && !elem.attr(attr) && (allowBlacklistEls || !isNodeOneOf(elem, nodeBlackList));
}
function shouldAttachRole(role, elem) {
// if element does not have role attribute
// AND element type is equal to role (if custom element has a type equaling shape) <-- remove?
// AND element is not in nodeBlackList
return !elem.attr('role') && (elem.attr('type') === role) && !isNodeOneOf(elem, nodeBlackList);
}
function getShape(attr, elem) {
var type = attr.type,
role = attr.role;
return ((type || role) === 'checkbox' || role === 'menuitemcheckbox') ? 'checkbox' :
((type || role) === 'radio' || role === 'menuitemradio') ? 'radio' :
(type === 'range' || role === 'progressbar' || role === 'slider') ? 'range' : '';
}
return {
restrict: 'A',
require: 'ngModel',
priority: 200, //Make sure watches are fired after any other directives that affect the ngModel value
compile: function(elem, attr) {
var shape = getShape(attr, elem);
return {
post: function(scope, elem, attr, ngModel) {
var needsTabIndex = shouldAttachAttr('tabindex', 'tabindex', elem, false);
function ngAriaWatchModelValue() {
return ngModel.$modelValue;
}
function getRadioReaction(newVal) {
// Strict comparison would cause a BC
// eslint-disable-next-line eqeqeq
var boolVal = (attr.value == ngModel.$viewValue);
elem.attr('aria-checked', boolVal);
}
function getCheckboxReaction() {
elem.attr('aria-checked', !ngModel.$isEmpty(ngModel.$viewValue));
}
switch (shape) {
case 'radio':
case 'checkbox':
if (shouldAttachRole(shape, elem)) {
elem.attr('role', shape);
}
if (shouldAttachAttr('aria-checked', 'ariaChecked', elem, false)) {
scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
getRadioReaction : getCheckboxReaction);
}
if (needsTabIndex) {
elem.attr('tabindex', 0);
}
break;
case 'range':
if (shouldAttachRole(shape, elem)) {
elem.attr('role', 'slider');
}
if ($aria.config('ariaValue')) {
var needsAriaValuemin = !elem.attr('aria-valuemin') &&
(attr.hasOwnProperty('min') || attr.hasOwnProperty('ngMin'));
var needsAriaValuemax = !elem.attr('aria-valuemax') &&
(attr.hasOwnProperty('max') || attr.hasOwnProperty('ngMax'));
var needsAriaValuenow = !elem.attr('aria-valuenow');
if (needsAriaValuemin) {
attr.$observe('min', function ngAriaValueMinReaction(newVal) {
elem.attr('aria-valuemin', newVal);
});
}
if (needsAriaValuemax) {
attr.$observe('max', function ngAriaValueMinReaction(newVal) {
elem.attr('aria-valuemax', newVal);
});
}
if (needsAriaValuenow) {
scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) {
elem.attr('aria-valuenow', newVal);
});
}
}
if (needsTabIndex) {
elem.attr('tabindex', 0);
}
break;
}
if (!attr.hasOwnProperty('ngRequired') && ngModel.$validators.required
&& shouldAttachAttr('aria-required', 'ariaRequired', elem, false)) {
// ngModel.$error.required is undefined on custom controls
attr.$observe('required', function() {
elem.attr('aria-required', !!attr['required']);
});
}
if (shouldAttachAttr('aria-invalid', 'ariaInvalid', elem, true)) {
scope.$watch(function ngAriaInvalidWatch() {
return ngModel.$invalid;
}, function ngAriaInvalidReaction(newVal) {
elem.attr('aria-invalid', !!newVal);
});
}
}
};
}
};
}])
.directive('ngDisabled', ['$aria', function($aria) {
return $aria.$$watchExpr('ngDisabled', 'aria-disabled', nodeBlackList, false);
}])
.directive('ngMessages', function() {
return {
restrict: 'A',
require: '?ngMessages',
link: function(scope, elem, attr, ngMessages) {
if (!elem.attr('aria-live')) {
elem.attr('aria-live', 'assertive');
}
}
};
})
.directive('ngClick',['$aria', '$parse', function($aria, $parse) {
return {
restrict: 'A',
compile: function(elem, attr) {
var fn = $parse(attr.ngClick, /* interceptorFn */ null, /* expensiveChecks */ true);
return function(scope, elem, attr) {
if (!isNodeOneOf(elem, nodeBlackList)) {
if ($aria.config('bindRoleForClick') && !elem.attr('role')) {
elem.attr('role', 'button');
}
if ($aria.config('tabindex') && !elem.attr('tabindex')) {
elem.attr('tabindex', 0);
}
if ($aria.config('bindKeydown') && !attr.ngKeydown && !attr.ngKeypress && !attr.ngKeyup) {
elem.on('keydown', function(event) {
var keyCode = event.which || event.keyCode;
if (keyCode === 32 || keyCode === 13) {
scope.$apply(callback);
}
function callback() {
fn(scope, { $event: event });
}
});
}
}
};
}
};
}])
.directive('ngDblclick', ['$aria', function($aria) {
return function(scope, elem, attr) {
if ($aria.config('tabindex') && !elem.attr('tabindex') && !isNodeOneOf(elem, nodeBlackList)) {
elem.attr('tabindex', 0);
}
};
}]);
})(window, window.angular);

17
js/vendor/angular-material/angular-material.min.js поставляемый Normal file

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

739
js/vendor/angular-messages/angular-messages.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,739 @@
/**
* @license AngularJS v1.6.1
* (c) 2010-2016 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular) {'use strict';
var forEach;
var isArray;
var isString;
var jqLite;
/**
* @ngdoc module
* @name ngMessages
* @description
*
* The `ngMessages` module provides enhanced support for displaying messages within templates
* (typically within forms or when rendering message objects that return key/value data).
* Instead of relying on JavaScript code and/or complex ng-if statements within your form template to
* show and hide error messages specific to the state of an input field, the `ngMessages` and
* `ngMessage` directives are designed to handle the complexity, inheritance and priority
* sequencing based on the order of how the messages are defined in the template.
*
* Currently, the ngMessages module only contains the code for the `ngMessages`, `ngMessagesInclude`
* `ngMessage` and `ngMessageExp` directives.
*
* # Usage
* The `ngMessages` directive allows keys in a key/value collection to be associated with a child element
* (or 'message') that will show or hide based on the truthiness of that key's value in the collection. A common use
* case for `ngMessages` is to display error messages for inputs using the `$error` object exposed by the
* {@link ngModel ngModel} directive.
*
* The child elements of the `ngMessages` directive are matched to the collection keys by a `ngMessage` or
* `ngMessageExp` directive. The value of these attributes must match a key in the collection that is provided by
* the `ngMessages` directive.
*
* Consider the following example, which illustrates a typical use case of `ngMessages`. Within the form `myForm` we
* have a text input named `myField` which is bound to the scope variable `field` using the {@link ngModel ngModel}
* directive.
*
* The `myField` field is a required input of type `email` with a maximum length of 15 characters.
*
* ```html
* <form name="myForm">
* <label>
* Enter text:
* <input type="email" ng-model="field" name="myField" required maxlength="15" />
* </label>
* <div ng-messages="myForm.myField.$error" role="alert">
* <div ng-message="required">Please enter a value for this field.</div>
* <div ng-message="email">This field must be a valid email address.</div>
* <div ng-message="maxlength">This field can be at most 15 characters long.</div>
* </div>
* </form>
* ```
*
* In order to show error messages corresponding to `myField` we first create an element with an `ngMessages` attribute
* set to the `$error` object owned by the `myField` input in our `myForm` form.
*
* Within this element we then create separate elements for each of the possible errors that `myField` could have.
* The `ngMessage` attribute is used to declare which element(s) will appear for which error - for example,
* setting `ng-message="required"` specifies that this particular element should be displayed when there
* is no value present for the required field `myField` (because the key `required` will be `true` in the object
* `myForm.myField.$error`).
*
* ### Message order
*
* By default, `ngMessages` will only display one message for a particular key/value collection at any time. If more
* than one message (or error) key is currently true, then which message is shown is determined by the order of messages
* in the HTML template code (messages declared first are prioritised). This mechanism means the developer does not have
* to prioritize messages using custom JavaScript code.
*
* Given the following error object for our example (which informs us that the field `myField` currently has both the
* `required` and `email` errors):
*
* ```javascript
* <!-- keep in mind that ngModel automatically sets these error flags -->
* myField.$error = { required : true, email: true, maxlength: false };
* ```
* The `required` message will be displayed to the user since it appears before the `email` message in the DOM.
* Once the user types a single character, the `required` message will disappear (since the field now has a value)
* but the `email` message will be visible because it is still applicable.
*
* ### Displaying multiple messages at the same time
*
* While `ngMessages` will by default only display one error element at a time, the `ng-messages-multiple` attribute can
* be applied to the `ngMessages` container element to cause it to display all applicable error messages at once:
*
* ```html
* <!-- attribute-style usage -->
* <div ng-messages="myForm.myField.$error" ng-messages-multiple>...</div>
*
* <!-- element-style usage -->
* <ng-messages for="myForm.myField.$error" multiple>...</ng-messages>
* ```
*
* ## Reusing and Overriding Messages
* In addition to prioritization, ngMessages also allows for including messages from a remote or an inline
* template. This allows for generic collection of messages to be reused across multiple parts of an
* application.
*
* ```html
* <script type="text/ng-template" id="error-messages">
* <div ng-message="required">This field is required</div>
* <div ng-message="minlength">This field is too short</div>
* </script>
*
* <div ng-messages="myForm.myField.$error" role="alert">
* <div ng-messages-include="error-messages"></div>
* </div>
* ```
*
* However, including generic messages may not be useful enough to match all input fields, therefore,
* `ngMessages` provides the ability to override messages defined in the remote template by redefining
* them within the directive container.
*
* ```html
* <!-- a generic template of error messages known as "my-custom-messages" -->
* <script type="text/ng-template" id="my-custom-messages">
* <div ng-message="required">This field is required</div>
* <div ng-message="minlength">This field is too short</div>
* </script>
*
* <form name="myForm">
* <label>
* Email address
* <input type="email"
* id="email"
* name="myEmail"
* ng-model="email"
* minlength="5"
* required />
* </label>
* <!-- any ng-message elements that appear BEFORE the ng-messages-include will
* override the messages present in the ng-messages-include template -->
* <div ng-messages="myForm.myEmail.$error" role="alert">
* <!-- this required message has overridden the template message -->
* <div ng-message="required">You did not enter your email address</div>
*
* <!-- this is a brand new message and will appear last in the prioritization -->
* <div ng-message="email">Your email address is invalid</div>
*
* <!-- and here are the generic error messages -->
* <div ng-messages-include="my-custom-messages"></div>
* </div>
* </form>
* ```
*
* In the example HTML code above the message that is set on required will override the corresponding
* required message defined within the remote template. Therefore, with particular input fields (such
* email addresses, date fields, autocomplete inputs, etc...), specialized error messages can be applied
* while more generic messages can be used to handle other, more general input errors.
*
* ## Dynamic Messaging
* ngMessages also supports using expressions to dynamically change key values. Using arrays and
* repeaters to list messages is also supported. This means that the code below will be able to
* fully adapt itself and display the appropriate message when any of the expression data changes:
*
* ```html
* <form name="myForm">
* <label>
* Email address
* <input type="email"
* name="myEmail"
* ng-model="email"
* minlength="5"
* required />
* </label>
* <div ng-messages="myForm.myEmail.$error" role="alert">
* <div ng-message="required">You did not enter your email address</div>
* <div ng-repeat="errorMessage in errorMessages">
* <!-- use ng-message-exp for a message whose key is given by an expression -->
* <div ng-message-exp="errorMessage.type">{{ errorMessage.text }}</div>
* </div>
* </div>
* </form>
* ```
*
* The `errorMessage.type` expression can be a string value or it can be an array so
* that multiple errors can be associated with a single error message:
*
* ```html
* <label>
* Email address
* <input type="email"
* ng-model="data.email"
* name="myEmail"
* ng-minlength="5"
* ng-maxlength="100"
* required />
* </label>
* <div ng-messages="myForm.myEmail.$error" role="alert">
* <div ng-message-exp="'required'">You did not enter your email address</div>
* <div ng-message-exp="['minlength', 'maxlength']">
* Your email must be between 5 and 100 characters long
* </div>
* </div>
* ```
*
* Feel free to use other structural directives such as ng-if and ng-switch to further control
* what messages are active and when. Be careful, if you place ng-message on the same element
* as these structural directives, Angular may not be able to determine if a message is active
* or not. Therefore it is best to place the ng-message on a child element of the structural
* directive.
*
* ```html
* <div ng-messages="myForm.myEmail.$error" role="alert">
* <div ng-if="showRequiredError">
* <div ng-message="required">Please enter something</div>
* </div>
* </div>
* ```
*
* ## Animations
* If the `ngAnimate` module is active within the application then the `ngMessages`, `ngMessage` and
* `ngMessageExp` directives will trigger animations whenever any messages are added and removed from
* the DOM by the `ngMessages` directive.
*
* Whenever the `ngMessages` directive contains one or more visible messages then the `.ng-active` CSS
* class will be added to the element. The `.ng-inactive` CSS class will be applied when there are no
* messages present. Therefore, CSS transitions and keyframes as well as JavaScript animations can
* hook into the animations whenever these classes are added/removed.
*
* Let's say that our HTML code for our messages container looks like so:
*
* ```html
* <div ng-messages="myMessages" class="my-messages" role="alert">
* <div ng-message="alert" class="some-message">...</div>
* <div ng-message="fail" class="some-message">...</div>
* </div>
* ```
*
* Then the CSS animation code for the message container looks like so:
*
* ```css
* .my-messages {
* transition:1s linear all;
* }
* .my-messages.ng-active {
* // messages are visible
* }
* .my-messages.ng-inactive {
* // messages are hidden
* }
* ```
*
* Whenever an inner message is attached (becomes visible) or removed (becomes hidden) then the enter
* and leave animation is triggered for each particular element bound to the `ngMessage` directive.
*
* Therefore, the CSS code for the inner messages looks like so:
*
* ```css
* .some-message {
* transition:1s linear all;
* }
*
* .some-message.ng-enter {}
* .some-message.ng-enter.ng-enter-active {}
*
* .some-message.ng-leave {}
* .some-message.ng-leave.ng-leave-active {}
* ```
*
* {@link ngAnimate Click here} to learn how to use JavaScript animations or to learn more about ngAnimate.
*/
angular.module('ngMessages', [], function initAngularHelpers() {
// Access helpers from angular core.
// Do it inside a `config` block to ensure `window.angular` is available.
forEach = angular.forEach;
isArray = angular.isArray;
isString = angular.isString;
jqLite = angular.element;
})
/**
* @ngdoc directive
* @module ngMessages
* @name ngMessages
* @restrict AE
*
* @description
* `ngMessages` is a directive that is designed to show and hide messages based on the state
* of a key/value object that it listens on. The directive itself complements error message
* reporting with the `ngModel` $error object (which stores a key/value state of validation errors).
*
* `ngMessages` manages the state of internal messages within its container element. The internal
* messages use the `ngMessage` directive and will be inserted/removed from the page depending
* on if they're present within the key/value object. By default, only one message will be displayed
* at a time and this depends on the prioritization of the messages within the template. (This can
* be changed by using the `ng-messages-multiple` or `multiple` attribute on the directive container.)
*
* A remote template can also be used to promote message reusability and messages can also be
* overridden.
*
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
*
* @usage
* ```html
* <!-- using attribute directives -->
* <ANY ng-messages="expression" role="alert">
* <ANY ng-message="stringValue">...</ANY>
* <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
* <ANY ng-message-exp="expressionValue">...</ANY>
* </ANY>
*
* <!-- or by using element directives -->
* <ng-messages for="expression" role="alert">
* <ng-message when="stringValue">...</ng-message>
* <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
* <ng-message when-exp="expressionValue">...</ng-message>
* </ng-messages>
* ```
*
* @param {string} ngMessages an angular expression evaluating to a key/value object
* (this is typically the $error object on an ngModel instance).
* @param {string=} ngMessagesMultiple|multiple when set, all messages will be displayed with true
*
* @example
* <example name="ngMessages-directive" module="ngMessagesExample"
* deps="angular-messages.js"
* animations="true" fixBase="true">
* <file name="index.html">
* <form name="myForm">
* <label>
* Enter your name:
* <input type="text"
* name="myName"
* ng-model="name"
* ng-minlength="5"
* ng-maxlength="20"
* required />
* </label>
* <pre>myForm.myName.$error = {{ myForm.myName.$error | json }}</pre>
*
* <div ng-messages="myForm.myName.$error" style="color:maroon" role="alert">
* <div ng-message="required">You did not enter a field</div>
* <div ng-message="minlength">Your field is too short</div>
* <div ng-message="maxlength">Your field is too long</div>
* </div>
* </form>
* </file>
* <file name="script.js">
* angular.module('ngMessagesExample', ['ngMessages']);
* </file>
* </example>
*/
.directive('ngMessages', ['$animate', function($animate) {
var ACTIVE_CLASS = 'ng-active';
var INACTIVE_CLASS = 'ng-inactive';
return {
require: 'ngMessages',
restrict: 'AE',
controller: ['$element', '$scope', '$attrs', function NgMessagesCtrl($element, $scope, $attrs) {
var ctrl = this;
var latestKey = 0;
var nextAttachId = 0;
this.getAttachId = function getAttachId() { return nextAttachId++; };
var messages = this.messages = {};
var renderLater, cachedCollection;
this.render = function(collection) {
collection = collection || {};
renderLater = false;
cachedCollection = collection;
// this is true if the attribute is empty or if the attribute value is truthy
var multiple = isAttrTruthy($scope, $attrs.ngMessagesMultiple) ||
isAttrTruthy($scope, $attrs.multiple);
var unmatchedMessages = [];
var matchedKeys = {};
var messageItem = ctrl.head;
var messageFound = false;
var totalMessages = 0;
// we use != instead of !== to allow for both undefined and null values
while (messageItem != null) {
totalMessages++;
var messageCtrl = messageItem.message;
var messageUsed = false;
if (!messageFound) {
forEach(collection, function(value, key) {
if (!messageUsed && truthy(value) && messageCtrl.test(key)) {
// this is to prevent the same error name from showing up twice
if (matchedKeys[key]) return;
matchedKeys[key] = true;
messageUsed = true;
messageCtrl.attach();
}
});
}
if (messageUsed) {
// unless we want to display multiple messages then we should
// set a flag here to avoid displaying the next message in the list
messageFound = !multiple;
} else {
unmatchedMessages.push(messageCtrl);
}
messageItem = messageItem.next;
}
forEach(unmatchedMessages, function(messageCtrl) {
messageCtrl.detach();
});
if (unmatchedMessages.length !== totalMessages) {
$animate.setClass($element, ACTIVE_CLASS, INACTIVE_CLASS);
} else {
$animate.setClass($element, INACTIVE_CLASS, ACTIVE_CLASS);
}
};
$scope.$watchCollection($attrs.ngMessages || $attrs['for'], ctrl.render);
// If the element is destroyed, proactively destroy all the currently visible messages
$element.on('$destroy', function() {
forEach(messages, function(item) {
item.message.detach();
});
});
this.reRender = function() {
if (!renderLater) {
renderLater = true;
$scope.$evalAsync(function() {
if (renderLater && cachedCollection) {
ctrl.render(cachedCollection);
}
});
}
};
this.register = function(comment, messageCtrl) {
var nextKey = latestKey.toString();
messages[nextKey] = {
message: messageCtrl
};
insertMessageNode($element[0], comment, nextKey);
comment.$$ngMessageNode = nextKey;
latestKey++;
ctrl.reRender();
};
this.deregister = function(comment) {
var key = comment.$$ngMessageNode;
delete comment.$$ngMessageNode;
removeMessageNode($element[0], comment, key);
delete messages[key];
ctrl.reRender();
};
function findPreviousMessage(parent, comment) {
var prevNode = comment;
var parentLookup = [];
while (prevNode && prevNode !== parent) {
var prevKey = prevNode.$$ngMessageNode;
if (prevKey && prevKey.length) {
return messages[prevKey];
}
// dive deeper into the DOM and examine its children for any ngMessage
// comments that may be in an element that appears deeper in the list
if (prevNode.childNodes.length && parentLookup.indexOf(prevNode) === -1) {
parentLookup.push(prevNode);
prevNode = prevNode.childNodes[prevNode.childNodes.length - 1];
} else if (prevNode.previousSibling) {
prevNode = prevNode.previousSibling;
} else {
prevNode = prevNode.parentNode;
parentLookup.push(prevNode);
}
}
}
function insertMessageNode(parent, comment, key) {
var messageNode = messages[key];
if (!ctrl.head) {
ctrl.head = messageNode;
} else {
var match = findPreviousMessage(parent, comment);
if (match) {
messageNode.next = match.next;
match.next = messageNode;
} else {
messageNode.next = ctrl.head;
ctrl.head = messageNode;
}
}
}
function removeMessageNode(parent, comment, key) {
var messageNode = messages[key];
var match = findPreviousMessage(parent, comment);
if (match) {
match.next = messageNode.next;
} else {
ctrl.head = messageNode.next;
}
}
}]
};
function isAttrTruthy(scope, attr) {
return (isString(attr) && attr.length === 0) || //empty attribute
truthy(scope.$eval(attr));
}
function truthy(val) {
return isString(val) ? val.length : !!val;
}
}])
/**
* @ngdoc directive
* @name ngMessagesInclude
* @restrict AE
* @scope
*
* @description
* `ngMessagesInclude` is a directive with the purpose to import existing ngMessage template
* code from a remote template and place the downloaded template code into the exact spot
* that the ngMessagesInclude directive is placed within the ngMessages container. This allows
* for a series of pre-defined messages to be reused and also allows for the developer to
* determine what messages are overridden due to the placement of the ngMessagesInclude directive.
*
* @usage
* ```html
* <!-- using attribute directives -->
* <ANY ng-messages="expression" role="alert">
* <ANY ng-messages-include="remoteTplString">...</ANY>
* </ANY>
*
* <!-- or by using element directives -->
* <ng-messages for="expression" role="alert">
* <ng-messages-include src="expressionValue1">...</ng-messages-include>
* </ng-messages>
* ```
*
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
*
* @param {string} ngMessagesInclude|src a string value corresponding to the remote template.
*/
.directive('ngMessagesInclude',
['$templateRequest', '$document', '$compile', function($templateRequest, $document, $compile) {
return {
restrict: 'AE',
require: '^^ngMessages', // we only require this for validation sake
link: function($scope, element, attrs) {
var src = attrs.ngMessagesInclude || attrs.src;
$templateRequest(src).then(function(html) {
if ($scope.$$destroyed) return;
if (isString(html) && !html.trim()) {
// Empty template - nothing to compile
replaceElementWithMarker(element, src);
} else {
// Non-empty template - compile and link
$compile(html)($scope, function(contents) {
element.after(contents);
replaceElementWithMarker(element, src);
});
}
});
}
};
// Helpers
function replaceElementWithMarker(element, src) {
// A comment marker is placed for debugging purposes
var comment = $compile.$$createComment ?
$compile.$$createComment('ngMessagesInclude', src) :
$document[0].createComment(' ngMessagesInclude: ' + src + ' ');
var marker = jqLite(comment);
element.after(marker);
// Don't pollute the DOM anymore by keeping an empty directive element
element.remove();
}
}])
/**
* @ngdoc directive
* @name ngMessage
* @restrict AE
* @scope
*
* @description
* `ngMessage` is a directive with the purpose to show and hide a particular message.
* For `ngMessage` to operate, a parent `ngMessages` directive on a parent DOM element
* must be situated since it determines which messages are visible based on the state
* of the provided key/value map that `ngMessages` listens on.
*
* More information about using `ngMessage` can be found in the
* {@link module:ngMessages `ngMessages` module documentation}.
*
* @usage
* ```html
* <!-- using attribute directives -->
* <ANY ng-messages="expression" role="alert">
* <ANY ng-message="stringValue">...</ANY>
* <ANY ng-message="stringValue1, stringValue2, ...">...</ANY>
* </ANY>
*
* <!-- or by using element directives -->
* <ng-messages for="expression" role="alert">
* <ng-message when="stringValue">...</ng-message>
* <ng-message when="stringValue1, stringValue2, ...">...</ng-message>
* </ng-messages>
* ```
*
* @param {expression} ngMessage|when a string value corresponding to the message key.
*/
.directive('ngMessage', ngMessageDirectiveFactory())
/**
* @ngdoc directive
* @name ngMessageExp
* @restrict AE
* @priority 1
* @scope
*
* @description
* `ngMessageExp` is the same as {@link directive:ngMessage `ngMessage`}, but instead of a static
* value, it accepts an expression to be evaluated for the message key.
*
* @usage
* ```html
* <!-- using attribute directives -->
* <ANY ng-messages="expression">
* <ANY ng-message-exp="expressionValue">...</ANY>
* </ANY>
*
* <!-- or by using element directives -->
* <ng-messages for="expression">
* <ng-message when-exp="expressionValue">...</ng-message>
* </ng-messages>
* ```
*
* {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
*
* @param {expression} ngMessageExp|whenExp an expression value corresponding to the message key.
*/
.directive('ngMessageExp', ngMessageDirectiveFactory());
function ngMessageDirectiveFactory() {
return ['$animate', function($animate) {
return {
restrict: 'AE',
transclude: 'element',
priority: 1, // must run before ngBind, otherwise the text is set on the comment
terminal: true,
require: '^^ngMessages',
link: function(scope, element, attrs, ngMessagesCtrl, $transclude) {
var commentNode = element[0];
var records;
var staticExp = attrs.ngMessage || attrs.when;
var dynamicExp = attrs.ngMessageExp || attrs.whenExp;
var assignRecords = function(items) {
records = items
? (isArray(items)
? items
: items.split(/[\s,]+/))
: null;
ngMessagesCtrl.reRender();
};
if (dynamicExp) {
assignRecords(scope.$eval(dynamicExp));
scope.$watchCollection(dynamicExp, assignRecords);
} else {
assignRecords(staticExp);
}
var currentElement, messageCtrl;
ngMessagesCtrl.register(commentNode, messageCtrl = {
test: function(name) {
return contains(records, name);
},
attach: function() {
if (!currentElement) {
$transclude(function(elm, newScope) {
$animate.enter(elm, null, element);
currentElement = elm;
// Each time we attach this node to a message we get a new id that we can match
// when we are destroying the node later.
var $$attachId = currentElement.$$attachId = ngMessagesCtrl.getAttachId();
// in the event that the element or a parent element is destroyed
// by another structural directive then it's time
// to deregister the message from the controller
currentElement.on('$destroy', function() {
if (currentElement && currentElement.$$attachId === $$attachId) {
ngMessagesCtrl.deregister(commentNode);
messageCtrl.detach();
}
newScope.$destroy();
});
});
}
},
detach: function() {
if (currentElement) {
var elm = currentElement;
currentElement = null;
$animate.leave(elm);
}
}
});
}
};
}];
function contains(collection, key) {
if (collection) {
return isArray(collection)
? collection.indexOf(key) >= 0
: collection.hasOwnProperty(key);
}
}
}
})(window, window.angular);

193
js/vendor/angular-steps/angular-steps.js поставляемый
Просмотреть файл

@ -1,193 +0,0 @@
(function () {
angular.module('templates-angular-steps', ['step.html', 'steps.html']);
angular.module('step.html', []).run(function ($templateCache) {
$templateCache.put('step.html', '<div ng-show=\"selected\" class=\"step ng-hide\" ng-transclude></div>');
});
angular.module('steps.html', []).run(function ($templateCache) {
$templateCache.put('steps.html',
'<div class=\"angular-steps\">\n' +
' <div class=\"steps\" ng-transclude></div>\n' +
'</div>');
});
angular.module('angular-steps', ['templates-angular-steps']);
angular.module('angular-steps').directive('step', function () {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
name: '@'
},
require: '^steps',
templateUrl: function (element, attributes) {
return attributes.template || 'step.html';
},
link: function ($scope, $element, $attrs, steps) {
steps.addStep($scope);
}
};
});
angular.module('angular-steps').directive('steps', function () {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
currentStep: '=',
onFinish: '&',
name: '@'
},
templateUrl: function (element, attributes) {
return attributes.template || 'steps.html';
},
controller: function ($scope, $element, StepsService) {
StepsService.addSteps($scope.name || StepsService.defaultName, this);
$scope.$on('$destroy', function () {
StepsService.removeSteps($scope.name || StepsService.defaultName);
});
this.steps = $scope.steps = [];
$scope.$watch('currentStep', function (step) {
if (!step) return;
var stepName = $scope.selectedStep.name;
if ($scope.selectedStep && stepName !== $scope.currentStep) {
var found = $scope.steps.filter(function (elm) {
return elm.name === $scope.currentStep;
})[0];
$scope.goTo(found);
}
});
this.addStep = function (step) {
$scope.steps.push(step);
if ($scope.steps.length === 1) {
$scope.goTo($scope.steps[0]);
}
};
$scope.goTo = function (step) {
unselectAll();
$scope.selectedStep = step;
if ($scope.currentStep !== void 0) {
$scope.currentStep = step.name;
}
step.selected = true;
};
function unselectAll() {
$scope.steps.forEach(function (step) {
step.selected = false;
});
$scope.selectedStep = null;
}
this.next = function () {
var index = $scope.steps.indexOf($scope.selectedStep);
if (index === $scope.steps.length - 1) {
this.finish();
} else {
$scope.goTo($scope.steps[index + 1]);
}
};
this.previous = function () {
var index = $scope.steps.indexOf($scope.selectedStep);
if (index === 0) {
throw new Error('Already at step 0');
} else {
$scope.goTo($scope.steps[index - 1]);
}
};
this.goTo = function (step) {
var stepTo;
if (isNaN(step)) {
stepTo = $scope.steps.filter(function (elm) {
return elm.name === step;
})[0];
} else {
stepTo = $scope.steps[step];
}
$scope.goTo(stepTo);
};
this.getCurrent = function() {
var index = $scope.steps.indexOf($scope.selectedStep);
return $scope.steps[index];
};
this.finish = function () {
if ($scope.onFinish) {
$scope.onFinish();
}
};
this.cancel = function () {
$scope.goTo($scope.steps[0]);
};
}
};
});
function stepsButtonDirective(action) {
angular.module('angular-steps')
.directive(action, function () {
return {
restrict: 'A',
replace: false,
require: '^steps',
link: function ($scope, $element, $attrs, steps) {
$element.on('click', function (e) {
e.preventDefault();
$element.addClass(action);
$scope.$apply(function () {
$scope.$eval($attrs[action]);
steps[action.replace('step', '').toLowerCase()]();
});
});
}
};
});
}
stepsButtonDirective('stepNext');
stepsButtonDirective('stepPrevious');
stepsButtonDirective('stepFinish');
stepsButtonDirective('stepCancel');
angular.module('angular-steps').factory('StepsService', function () {
var service = {};
var instances = {};
service.defaultName = 'default';
service.addSteps = function (name, steps) {
instances[name] = steps;
};
service.removeSteps = function (name) {
delete instances[name];
};
service.steps = function (name) {
return instances[name || service.defaultName];
};
service.getCurrent = function() {
return instances[service.defaultName].getCurrent();
};
return service;
});
})();

2377
js/vendor/bootstrap/bootstrap.js поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

250
js/vendor/material-steppers/material-steppers.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,250 @@
var StepperCtrl = (function () {
function StepperCtrl($mdComponentRegistry, $attrs, $log) {
this.$mdComponentRegistry = $mdComponentRegistry;
this.$attrs = $attrs;
this.$log = $log;
this.labelStep = 'Step';
this.labelOf = 'of';
/* End of bindings */
this.steps = [];
this.currentStep = 0;
}
StepperCtrl.prototype.$onInit = function () {
if (this.$attrs.mdMobileStepText === '') {
this.mobileStepText = true;
}
if (this.$attrs.mdLinear === '') {
this.linear = true;
}
if (this.$attrs.mdAlternative === '') {
this.alternative = true;
}
};
StepperCtrl.prototype.$postLink = function () {
if (!this.$attrs.id) {
this.$log.warn('You must set an id attribute to your stepper');
}
this.registeredStepper = this.$mdComponentRegistry.register(this, this.$attrs.id);
};
StepperCtrl.prototype.$onDestroy = function () {
this.registeredStepper && this.registeredStepper();
};
/**
* Register component step to this stepper.
*
* @param {StepCtrl} step The step to add.
* @returns number - The step number.
*/
StepperCtrl.prototype.$addStep = function (step) {
return this.steps.push(step) - 1;
};
/**
* Complete the current step and move one to the next.
* Using this method on editable steps (in linear stepper)
* it will search by the next step without "completed" state to move.
* When invoked it dispatch the event onstepcomplete to the step element.
*
* @returns boolean - True if move and false if not move (e.g. On the last step)
*/
StepperCtrl.prototype.next = function () {
if (this.currentStep < this.steps.length) {
this.clearError();
this.currentStep++;
this.clearFeedback();
return true;
}
return false;
};
/**
* Move to the previous step without change the state of current step.
* Using this method in linear stepper it will check if previous step is editable to move.
*
* @returns boolean - True if move and false if not move (e.g. On the first step)
*/
StepperCtrl.prototype.back = function () {
if (this.currentStep > 0) {
this.clearError();
this.currentStep--;
this.clearFeedback();
return true;
}
return false;
};
/**
* Move to the next step without change the state of current step.
* This method works only in optional steps.
*
* @returns boolean - True if move and false if not move (e.g. On non-optional step)
*/
StepperCtrl.prototype.skip = function () {
var step = this.steps[this.currentStep];
if (step.optional) {
this.currentStep++;
this.clearFeedback();
return true;
}
return false;
};
/**
* Defines the current step state to "error" and shows the message parameter on
* title message element.When invoked it dispatch the event onsteperror to the step element.
*
* @param {string} message The error message
*/
StepperCtrl.prototype.error = function (message) {
var step = this.steps[this.currentStep];
step.hasError = true;
step.message = message;
this.clearFeedback();
};
/**
* Defines the current step state to "normal" and removes the message parameter on
* title message element.
*/
StepperCtrl.prototype.clearError = function () {
var step = this.steps[this.currentStep];
step.hasError = false;
};
/**
* Move "active" to specified step id parameter.
* The id used as reference is the integer number shown on the label of each step (e.g. 2).
*
* @param {number} stepNumber (description)
* @returns boolean - True if move and false if not move (e.g. On id not found)
*/
StepperCtrl.prototype.goto = function (stepNumber) {
if (stepNumber < this.steps.length) {
this.currentStep = stepNumber;
this.clearFeedback();
return true;
}
return false;
};
/**
* Shows a feedback message and a loading indicador.
*
* @param {string} [message] The feedbackMessage
*/
StepperCtrl.prototype.showFeedback = function (message) {
this.hasFeedback = true;
this.feedbackMessage = message;
};
/**
* Removes the feedback.
*/
StepperCtrl.prototype.clearFeedback = function () {
this.hasFeedback = false;
};
StepperCtrl.prototype.isCompleted = function (stepNumber) {
return this.linear && stepNumber < this.currentStep;
};
;
StepperCtrl.prototype.isActiveStep = function (step) {
return this.steps.indexOf(step) === this.currentStep;
};
StepperCtrl.$inject = [
'$mdComponentRegistry',
'$attrs',
'$log'
];
return StepperCtrl;
}());
var StepperServiceFactory = ['$mdComponentRegistry',
function ($mdComponentRegistry) {
return function (handle) {
var instance = $mdComponentRegistry.get(handle);
if (!instance) {
$mdComponentRegistry.notFoundError(handle);
}
return instance;
};
}];
var StepCtrl = (function () {
/**
*
*/
function StepCtrl($element, $compile, $scope) {
this.$element = $element;
this.$compile = $compile;
this.$scope = $scope;
}
StepCtrl.prototype.$postLink = function () {
this.stepNumber = this.$stepper.$addStep(this);
};
StepCtrl.prototype.isActive = function () {
var state = this.$stepper.isActiveStep(this);
return state;
};
StepCtrl.$inject = [
'$element',
'$compile',
'$scope'
];
return StepCtrl;
}());
angular.module('mdSteppers', ['ngMaterial'])
.factory('$mdStepper', StepperServiceFactory)
.directive('mdStepper', function () {
return {
transclude: true,
scope: {
linear: '<?mdLinear',
alternative: '<?mdAlternative',
vertical: '<?mdVertical',
mobileStepText: '<?mdMobileStepText',
labelStep: '@?mdLabelStep',
labelOf: '@?mdLabelOf'
},
bindToController: true,
controller: StepperCtrl,
controllerAs: 'stepper',
templateUrl: 'mdSteppers/mdStepper.tpl.html'
};
})
.directive('mdStep', ['$compile', function ($compile) {
return {
require: '^^mdStepper',
transclude: true,
scope: {
label: '@mdLabel',
optional: '@?mdOptional'
},
bindToController: true,
controller: StepCtrl,
controllerAs: '$ctrl',
link: function (scope, iElement, iAttrs, stepperCtrl) {
function addOverlay() {
var hasOverlay = !!iElement.find('.md-step-body-overlay')[0];
if (!hasOverlay) {
var overlay = angular.element("<div class=\"md-step-body-overlay\"></div>\n <div class=\"md-step-body-loading\">\n <md-progress-circular md-mode=\"indeterminate\"></md-progress-circular>\n </div>");
$compile(overlay)(scope);
iElement.find('.md-steppers-scope').append(overlay);
}
}
scope.$ctrl.$stepper = stepperCtrl;
scope.$watch(function () {
return scope.$ctrl.isActive();
}, function (isActive) {
if (isActive) {
iElement.addClass('md-active');
addOverlay();
}
else {
iElement.removeClass('md-active');
}
});
},
templateUrl: 'mdSteppers/mdStep.tpl.html'
};
}])
.config(['$mdIconProvider', function ($mdIconProvider) {
$mdIconProvider.icon('steppers-check', 'mdSteppers/ic_check_24px.svg');
$mdIconProvider.icon('steppers-warning', 'mdSteppers/ic_warning_24px.svg');
}])
.run(["$templateCache", function ($templateCache) {
$templateCache.put("mdSteppers/ic_check_24px.svg", "<svg height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M0 0h24v24H0z\" fill=\"none\"/>\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n</svg>");
$templateCache.put("mdSteppers/ic_warning_24px.svg", "<svg height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M0 0h24v24H0z\" fill=\"none\"/>\r\n <path d=\"M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z\"/>\r\n</svg>");
}]);
angular.module("mdSteppers").run(["$templateCache", function($templateCache) {$templateCache.put("mdSteppers/mdStep.tpl.html","<div class=\"md-stepper\" ng-class=\"{ \'md-active\': $ctrl.isActive() }\">\r\n <md-steppers-header class=\"md-steppers-header md-steppers-vertical\">\r\n <button class=\"md-stepper-indicator\" ng-class=\"{\r\n \'md-active\': $ctrl.stepNumber === $ctrl.$stepper.currentStep,\r\n \'md-completed\': $ctrl.$stepper.isCompleted($ctrl.stepNumber),\r\n \'md-error\': $ctrl.hasError,\r\n \'md-stepper-optional\': $ctrl.optional || $ctrl.hasError\r\n }\" ng-click=\"$ctrl.$stepper.goto($ctrl.stepNumber)\" ng-disabled=\"$ctrl.$stepper.linear || $ctrl.stepNumber === $ctrl.$stepper.currentStep\">\r\n <div class=\"md-stepper-indicator-wrapper\">\r\n <div class=\"md-stepper-number\" ng-hide=\"$ctrl.hasError\">\r\n <span ng-if=\"!$ctrl.$stepper.isCompleted($ctrl.stepNumber)\">{{ ::$ctrl.stepNumber+1 }}</span>\r\n <md-icon md-svg-icon=\"steppers-check\" class=\"md-stepper-icon\" ng-if=\"$ctrl.$stepper.isCompleted($ctrl.stepNumber)\"></md-icon>\r\n </div>\r\n <div class=\"md-stepper-error-indicator\" ng-show=\"$ctrl.hasError\">\r\n <md-icon md-svg-icon=\"steppers-warning\"></md-icon>\r\n </div>\r\n\r\n <div class=\"md-stepper-title\">\r\n <span>{{ $ctrl.label }}</span>\r\n <small ng-if=\"$ctrl.optional && !$ctrl.hasError\">{{ $ctrl.optional }}</small>\r\n <small class=\"md-stepper-error-message\" ng-show=\"$ctrl.hasError\">\r\n {{ $ctrl.message }}\r\n </small>\r\n </div>\r\n </div>\r\n </button>\r\n <div class=\"md-stepper-feedback-message\" ng-show=\"stepper.hasFeedback\">\r\n {{stepper.feedbackMessage}}\r\n </div>\r\n </md-steppers-header>\r\n <md-steppers-scope layout=\"column\" class=\"md-steppers-scope\" ng-if=\"$ctrl.isActive()\" ng-transclude></md-steppers-scope>\r\n</div>");
$templateCache.put("mdSteppers/mdStepper.tpl.html","<div flex class=\"md-steppers\" ng-class=\"{ \r\n \'md-steppers-linear\': stepper.linear, \r\n \'md-steppers-alternative\': stepper.alternative,\r\n \'md-steppers-vertical\': stepper.vertical,\r\n \'md-steppers-mobile-step-text\': stepper.mobileStepText,\r\n \'md-steppers-has-feedback\': stepper.hasFeedback\r\n }\">\r\n <div class=\"md-steppers-header-region\">\r\n <md-steppers-header class=\"md-steppers-header md-steppers-horizontal md-whiteframe-1dp\">\r\n <button class=\"md-stepper-indicator\" ng-repeat=\"(stepNumber, $step) in stepper.steps track by $index\" ng-class=\"{\r\n \'md-active\': stepNumber === stepper.currentStep,\r\n \'md-completed\': stepper.isCompleted(stepNumber),\r\n \'md-error\': $step.hasError,\r\n \'md-stepper-optional\': $step.optional || $step.hasError\r\n }\" ng-click=\"stepper.goto(stepNumber)\" ng-disabled=\"stepper.linear || stepNumber === stepper.currentStep\">\r\n <div class=\"md-stepper-indicator-wrapper\">\r\n <div class=\"md-stepper-number\" ng-hide=\"$step.hasError\">\r\n <span ng-if=\"!stepper.isCompleted(stepNumber)\">{{ ::stepNumber+1 }}</span>\r\n <md-icon md-svg-icon=\"steppers-check\" class=\"md-stepper-icon\" ng-if=\"stepper.isCompleted(stepNumber)\"></md-icon>\r\n </div>\r\n\r\n <div class=\"md-stepper-error-indicator\" ng-show=\"$step.hasError\">\r\n <md-icon md-svg-icon=\"steppers-warning\"></md-icon>\r\n </div>\r\n <div class=\"md-stepper-title\">\r\n <span>{{ $step.label }}</span>\r\n <small ng-if=\"$step.optional && !$step.hasError\">{{ $step.optional }}</small>\r\n <small class=\"md-stepper-error-message\" ng-show=\"$step.hasError\">\r\n {{ $step.message }}\r\n </small>\r\n </div>\r\n </div>\r\n </button>\r\n \r\n </md-steppers-header>\r\n <md-steppers-mobile-header class=\"md-steppers-mobile-header\">\r\n <md-toolbar flex=\"none\" class=\"md-whiteframe-1dp\" style=\"background: #f6f6f6 !important; color: #202020 !important;\">\r\n <div class=\"md-toolbar-tools\">\r\n <h3>\r\n <span>{{stepper.labelStep}} {{stepper.currentStep+1}} {{stepper.labelOf}} {{stepper.steps.length}}</span>\r\n </h3>\r\n </div>\r\n </md-toolbar>\r\n </md-steppers-mobile-header>\r\n <div class=\"md-stepper-feedback-message\" ng-show=\"stepper.hasFeedback\">\r\n {{stepper.feedbackMessage}}\r\n </div>\r\n </div>\r\n <md-steppers-content class=\"md-steppers-content\" ng-transclude></md-steppers-content>\r\n <div class=\"md-steppers-overlay\"></div>\r\n</div>");}]);

Просмотреть файл

@ -187,7 +187,7 @@ input[type="password"], input[type="text"] {
.radial-progress {
$circle-size : 25px;
$circle-size : 10px;
$circle-background : #d6dadc;
$circle-color : #97a71d;
$transition-length : 0.5s;
@ -210,7 +210,7 @@ input[type="password"], input[type="text"] {
@include transition(transform $transition-length);
@include backface-visibility(hidden);
}
.mask {
clip: rect(0px, $circle-size, $circle-size, $circle-size/2);

124
style/material.scss Normal file
Просмотреть файл

@ -0,0 +1,124 @@
@import "bourbon/bourbon";
$height: auto;
body,html {
min-width: 450px;
}
.server_settings{
md-input-container{
margin-bottom: 0;
}
}
.pointer{
cursor: pointer;
}
.password-list{
min-height: 250px;
}
.md-content {
height: 100%;
max-height: $height;
}
.addFab{
position: fixed;
right: 10px;
bottom: 10px;
}
.menu {
padding: 0;
ul {
padding: 0;
margin: 0;
width: 100%;
li {
list-style-type: none;
width: 100%;
md-icon {
margin-right: 16px;
min-width: 40px;
width: 40px;
}
a {
color: #000;
position: relative;
cursor: pointer;
user-select: none;
display: block;
height: 48px;
line-height: 48px;
padding: 0;
padding-left: 16px;
padding-right: 56px;
text-decoration: none;
clear: both;
font-weight: 500;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
-webkit-transition: all 0.2s ease-in-out;
-o-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
}
a:hover {
background-color: #e0e0e0;
}
}
}
}
.password-list {
padding: 0;
}
/*/*/
.radial-progress {
$circle-size : 12px;
$circle-background : #d6dadc;
$circle-color : rgb(2,119,189);
$transition-length : 0.5s;
display: inline-block;
position: relative;
width: $circle-size;
height: $circle-size;
background-color: $circle-background;
border-radius: 50%;
.circle {
.mask, .fill {
width: $circle-size;
height: $circle-size;
position: absolute;
border-radius: 50%;
@include transition(transform $transition-length);
@include backface-visibility(hidden);
}
.mask {
clip: rect(0px, $circle-size, $circle-size, $circle-size/2);
.fill {
clip: rect(0px, $circle-size/2, $circle-size, 0px);
background-color: $circle-color;
}
}
}
}
.ng-hide{
display: none;
}
.unlock-container {
height: 350px;
.unlock {
padding: 20px;
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
md-input-container {
margin-top: 0;
margin-bottom: 0;
}
}
}