diff --git a/jslib b/jslib
index 593870e9365..f39bdc4269c 160000
--- a/jslib
+++ b/jslib
@@ -1 +1 @@
-Subproject commit 593870e9365d68e924955f1ec192a70216b63621
+Subproject commit f39bdc4269c1105211ac901b7d2d51978375b222
diff --git a/package-lock.json b/package-lock.json
index 0de21c284be..b0805a2b66b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -413,6 +413,15 @@
"tslib": "^1.9.0"
}
},
+ "@angular/cdk": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-7.2.1.tgz",
+ "integrity": "sha512-oU1Pjq3JkDtkXquLxWK84A2jOCeYRf352dVGbQCxWoSOQ5KBtMAd42huGidPiOSHN6/f7xZwL3n4fq3fVIut8A==",
+ "requires": {
+ "parse5": "^5.0.0",
+ "tslib": "^1.7.1"
+ }
+ },
"@angular/common": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/@angular/common/-/common-7.2.1.tgz",
@@ -9278,6 +9287,12 @@
"integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
"dev": true
},
+ "parse5": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
+ "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==",
+ "optional": true
+ },
"pascalcase": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
diff --git a/package.json b/package.json
index 6891e513645..6c21dbb4cf7 100644
--- a/package.json
+++ b/package.json
@@ -232,6 +232,7 @@
},
"dependencies": {
"@angular/animations": "7.2.1",
+ "@angular/cdk": "7.2.1",
"@angular/common": "7.2.1",
"@angular/compiler": "7.2.1",
"@angular/core": "7.2.1",
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index e6c21cc6779..4f1ba7dbdba 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -9,6 +9,7 @@ import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { AppRoutingModule } from './app-routing.module';
import { ServicesModule } from './services.module';
+import { DragDropModule } from '@angular/cdk/drag-drop';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
@@ -138,6 +139,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
}),
ToasterModule.forRoot(),
InfiniteScrollModule,
+ DragDropModule,
],
declarations: [
AddEditComponent,
diff --git a/src/app/vault/add-edit.component.html b/src/app/vault/add-edit.component.html
index ecb6cac1e4c..92acab02f94 100644
--- a/src/app/vault/add-edit.component.html
+++ b/src/app/vault/add-edit.component.html
@@ -261,36 +261,42 @@
{{'customFields' | i18n}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{'newCustomField' | i18n}}
diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json
index 515401b6f62..074c202d7d2 100644
--- a/src/locales/en/messages.json
+++ b/src/locales/en/messages.json
@@ -297,6 +297,9 @@
"value": {
"message": "Value"
},
+ "dragToSort": {
+ "message": "Drag to sort"
+ },
"cfTypeText": {
"message": "Text"
},
diff --git a/src/scss/box.scss b/src/scss/box.scss
index a1648af622c..dfddb09695f 100644
--- a/src/scss/box.scss
+++ b/src/scss/box.scss
@@ -1,6 +1,7 @@
@import "variables.scss";
.box {
+ position: relative;
width: 100%;
.box-header {
@@ -34,300 +35,6 @@
padding: 10px 15px;
}
- .box-content-row {
- display: block;
- padding: 10px 15px;
- position: relative;
- z-index: 1;
-
- &:before {
- content: "";
- position: absolute;
- right: 0;
- bottom: 0;
- height: 1px;
- width: calc(100% - 10px);
- border-bottom: 1px solid #000000;
-
- @include themify($themes) {
- border-bottom-color: themed('boxBorderColor');
- }
- }
-
- &:first-child, &:last-child {
- border-radius: $border-radius;
-
- .progress {
- border-bottom-left-radius: $border-radius;
- border-bottom-right-radius: $border-radius;
- }
- }
-
- &:last-child {
- &:before {
- border: none;
- height: 0;
- }
- }
-
- &:after {
- content: "";
- display: table;
- clear: both;
- }
-
- &:hover, &:focus, &.active {
- @include themify($themes) {
- background-color: themed('boxBackgroundHoverColor');
- }
- }
-
- &.pre {
- white-space: pre;
- overflow-x: auto;
- }
-
- &.pre-line {
- white-space: pre-line;
- overflow-x: auto;
- }
-
- .row-label, label {
- font-size: $font-size-small;
- display: block;
- width: 100%;
- margin-bottom: 5px;
-
- @include themify($themes) {
- color: themed('mutedColor');
- }
-
- .sub-label {
- margin-left: 10px;
- }
- }
-
- .text, .detail {
- display: block;
-
- @include themify($themes) {
- color: themed('textColor');
- }
- }
-
- .detail {
- font-size: $font-size-small;
-
- @include themify($themes) {
- color: themed('mutedColor');
- }
- }
-
- .img-right {
- float: right;
- margin-left: 10px;
- }
-
- .row-main {
- flex-grow: 1;
- }
-
- &.box-content-row-flex, .box-content-row-flex, &.box-content-row-checkbox, &.box-content-row-input,
- &.box-content-row-slider, &.box-content-row-multi {
- display: flex;
- align-items: center;
- word-break: break-word;
- }
-
- &.box-content-row-multi {
- width: 100%;
-
- input:not([type="checkbox"]) {
- width: 100%;
- }
-
- input + label.sr-only + select {
- margin-top: 5px;
- }
-
- > a {
- padding: 8px 8px 8px 4px;
- margin: 0;
-
- @include themify($themes) {
- color: themed('dangerColor');
- }
- }
- }
-
- &.box-content-row-checkbox, &.box-content-row-input, &.box-content-row-slider {
- label, .row-label {
- font-size: $font-size-base;
- display: inline;
- width: initial;
- margin-bottom: 0;
-
- @include themify($themes) {
- color: themed('textColor');
- }
- }
-
- > span {
- @include themify($themes) {
- color: themed('mutedColor');
- }
- }
-
- > input {
- margin: 0 0 0 auto;
- padding: 0;
- }
-
- > * {
- margin-right: 15px;
-
- &:last-child {
- margin-right: 0;
- }
- }
- }
-
- &.box-content-row-input {
- label {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- input {
- text-align: right;
- width: 45px !important;
- }
- }
-
- &.box-content-row-slider {
- input[type="range"] {
- height: 10px;
- width: 110px !important;
- }
-
- input[type="number"] {
- text-align: right;
- width: 45px !important;
- }
-
- label {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- }
-
- input:not([type="checkbox"]), textarea {
- border: none;
- width: 100%;
- background-color: transparent;
-
- &::-webkit-input-placeholder {
- @include themify($themes) {
- color: themed('inputPlaceholderColor');
- }
- }
-
- &:focus {
- outline: none;
- }
- }
-
- select {
- width: 100%;
- border: 1px solid #000000;
- border-radius: $border-radius;
-
- @include themify($themes) {
- border-color: themed('inputBorderColor');
- }
- }
-
- .action-buttons {
- display: flex;
- margin-left: 5px;
-
- .row-btn {
- cursor: pointer;
- padding: 10px 8px;
- background: none;
- border: none;
-
- @include themify($themes) {
- color: themed('boxRowButtonColor');
- }
-
- &:hover, &:focus {
- @include themify($themes) {
- color: themed('boxRowButtonHoverColor');
- }
- }
-
- &.disabled {
- @include themify($themes) {
- color: themed('disabledIconColor');
- }
-
- &:hover {
- @include themify($themes) {
- color: themed('disabledIconColor');
- }
- }
- }
-
- &:last-child {
- padding-right: 2px !important;
- }
- }
-
- &.no-pad .row-btn {
- padding-top: 0;
- padding-bottom: 0;
- }
- }
-
- select.field-type {
- margin: 5px 0 0 25px;
- width: calc(100% - 25px);
- }
-
- .row-sub-icon {
- @include themify($themes) {
- color: themed('disabledIconColor');
- }
- }
-
- .row-sub-label {
- margin: 0 15px;
- white-space: nowrap;
-
- @include themify($themes) {
- color: themed('mutedColor');
- }
- }
-
- .progress {
- display: flex;
- height: 5px;
- overflow: hidden;
- margin: 5px -15px -10px;
-
- .progress-bar {
- display: flex;
- flex-direction: column;
- justify-content: center;
- white-space: nowrap;
- background-color: $brand-primary;
- }
- }
- }
-
&.condensed .box-content-row, .box-content-row.condensed {
padding-top: 5px;
padding-bottom: 5px;
@@ -349,3 +56,318 @@
}
}
}
+
+.box-content-row {
+ display: block;
+ padding: 10px 15px;
+ position: relative;
+ z-index: 1;
+
+ &:before {
+ content: "";
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ height: 1px;
+ width: calc(100% - 10px);
+ border-bottom: 1px solid #000000;
+
+ @include themify($themes) {
+ border-bottom-color: themed('boxBorderColor');
+ }
+ }
+
+ &:first-child, &:last-child {
+ border-radius: $border-radius;
+
+ .progress {
+ border-bottom-left-radius: $border-radius;
+ border-bottom-right-radius: $border-radius;
+ }
+ }
+
+ &:last-child {
+ &:before {
+ border: none;
+ height: 0;
+ }
+ }
+
+ &:after {
+ content: "";
+ display: table;
+ clear: both;
+ }
+
+ &:hover, &:focus, &.active {
+ @include themify($themes) {
+ background-color: themed('boxBackgroundHoverColor');
+ }
+ }
+
+ &.pre {
+ white-space: pre;
+ overflow-x: auto;
+ }
+
+ &.pre-line {
+ white-space: pre-line;
+ overflow-x: auto;
+ }
+
+ .row-label, label {
+ font-size: $font-size-small;
+ display: block;
+ width: 100%;
+ margin-bottom: 5px;
+
+ @include themify($themes) {
+ color: themed('mutedColor');
+ }
+
+ .sub-label {
+ margin-left: 10px;
+ }
+ }
+
+ .text, .detail {
+ display: block;
+
+ @include themify($themes) {
+ color: themed('textColor');
+ }
+ }
+
+ .detail {
+ font-size: $font-size-small;
+
+ @include themify($themes) {
+ color: themed('mutedColor');
+ }
+ }
+
+ .img-right {
+ float: right;
+ margin-left: 10px;
+ }
+
+ .row-main {
+ flex-grow: 1;
+ }
+
+ &.box-content-row-flex, .box-content-row-flex, &.box-content-row-checkbox, &.box-content-row-input,
+ &.box-content-row-slider, &.box-content-row-multi {
+ display: flex;
+ align-items: center;
+ word-break: break-word;
+ }
+
+ &.box-content-row-multi {
+ width: 100%;
+
+ input:not([type="checkbox"]) {
+ width: 100%;
+ }
+
+ input + label.sr-only + select {
+ margin-top: 5px;
+ }
+
+ > a {
+ padding: 8px 8px 8px 4px;
+ margin: 0;
+
+ @include themify($themes) {
+ color: themed('dangerColor');
+ }
+ }
+ }
+
+ &.box-content-row-checkbox, &.box-content-row-input, &.box-content-row-slider {
+ label, .row-label {
+ font-size: $font-size-base;
+ display: inline;
+ width: initial;
+ margin-bottom: 0;
+
+ @include themify($themes) {
+ color: themed('textColor');
+ }
+ }
+
+ > span {
+ @include themify($themes) {
+ color: themed('mutedColor');
+ }
+ }
+
+ > input {
+ margin: 0 0 0 auto;
+ padding: 0;
+ }
+
+ > * {
+ margin-right: 15px;
+
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+
+ &.box-content-row-input {
+ label {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ input {
+ text-align: right;
+ width: 45px !important;
+ }
+ }
+
+ &.box-content-row-slider {
+ input[type="range"] {
+ height: 10px;
+ width: 110px !important;
+ }
+
+ input[type="number"] {
+ text-align: right;
+ width: 45px !important;
+ }
+
+ label {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ }
+
+ input:not([type="checkbox"]), textarea {
+ border: none;
+ width: 100%;
+ background-color: transparent;
+
+ &::-webkit-input-placeholder {
+ @include themify($themes) {
+ color: themed('inputPlaceholderColor');
+ }
+ }
+
+ &:focus {
+ outline: none;
+ }
+ }
+
+ select {
+ width: 100%;
+ border: 1px solid #000000;
+ border-radius: $border-radius;
+
+ @include themify($themes) {
+ border-color: themed('inputBorderColor');
+ }
+ }
+
+ .action-buttons {
+ display: flex;
+ margin-left: 5px;
+
+ .row-btn {
+ cursor: pointer;
+ padding: 10px 8px;
+ background: none;
+ border: none;
+
+ @include themify($themes) {
+ color: themed('boxRowButtonColor');
+ }
+
+ &:hover, &:focus {
+ @include themify($themes) {
+ color: themed('boxRowButtonHoverColor');
+ }
+ }
+
+ &.disabled {
+ @include themify($themes) {
+ color: themed('disabledIconColor');
+ }
+
+ &:hover {
+ @include themify($themes) {
+ color: themed('disabledIconColor');
+ }
+ }
+ }
+
+ &:last-child {
+ padding-right: 2px !important;
+ }
+ }
+
+ &.no-pad .row-btn {
+ padding-top: 0;
+ padding-bottom: 0;
+ }
+ }
+
+ select.field-type {
+ margin: 5px 0 0 25px;
+ width: calc(100% - 25px);
+ }
+
+ .row-sub-icon {
+ @include themify($themes) {
+ color: themed('disabledIconColor');
+ }
+ }
+
+ .row-sub-label {
+ margin: 0 15px;
+ white-space: nowrap;
+
+ @include themify($themes) {
+ color: themed('mutedColor');
+ }
+ }
+
+ .progress {
+ display: flex;
+ height: 5px;
+ overflow: hidden;
+ margin: 5px -15px -10px;
+
+ .progress-bar {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ white-space: nowrap;
+ background-color: $brand-primary;
+ }
+ }
+}
+
+.box-drag-handle {
+ cursor: move;
+ margin-left: 5px;
+ user-select: none;
+
+ @include themify($themes) {
+ color: themed('mutedColor');
+ }
+}
+
+.cdk-drag-preview {
+ position: relative;
+ display: flex;
+ align-items: center;
+ opacity: .8;
+
+ @include themify($themes) {
+ background-color: themed('boxBackgroundColor');
+ }
+}