diff --git a/client/src/views/admin/field-manager/fields/options-with-style.js b/client/src/views/admin/field-manager/fields/options-with-style.js
index 8f64f5e6d2..dde3f8cc93 100644
--- a/client/src/views/admin/field-manager/fields/options-with-style.js
+++ b/client/src/views/admin/field-manager/fields/options-with-style.js
@@ -30,6 +30,8 @@ import OptionsView from 'views/admin/field-manager/fields/options';
export default class extends OptionsView {
+ noDragHandle = true
+
setup() {
super.setup();
diff --git a/client/src/views/fields/array.js b/client/src/views/fields/array.js
index e2dfbbd3f6..7815144159 100644
--- a/client/src/views/fields/array.js
+++ b/client/src/views/fields/array.js
@@ -121,6 +121,13 @@ class ArrayFieldView extends BaseFieldView {
*/
translatedOptions = null
+ /**
+ * @protected
+ * @type {boolean}
+ * @since 9.2.0
+ */
+ noDragHandle = false
+
// noinspection JSCheckFunctionSignatures
/** @inheritDoc */
@@ -434,6 +441,7 @@ class ArrayFieldView extends BaseFieldView {
distance: 5,
cancel: 'input,textarea,button,select,option,a[role="button"]',
cursor: 'grabbing',
+ handle: !this.noDragHandle ? '.drag-handle' : undefined,
});
}
@@ -658,7 +666,7 @@ class ArrayFieldView extends BaseFieldView {
value;
const div = document.createElement('div');
- div.classList.add('list-group-item');
+ div.className = 'list-group-item';
div.dataset.value = value;
div.style.cursor = 'default';
@@ -672,7 +680,7 @@ class ArrayFieldView extends BaseFieldView {
a.append(
(() => {
const span = document.createElement('span');
- span.classList.add('fas', 'fa-times');
+ span.className = 'fas fa-times'
return span;
})(),
@@ -682,6 +690,20 @@ class ArrayFieldView extends BaseFieldView {
}
div.append(
+ (() => {
+ const span = document.createElement('span');
+ span.className = 'drag-handle';
+ span.append(
+ (() => {
+ const span = document.createElement('span');
+ span.className = 'fas fa-grip fa-sm';
+
+ return span;
+ })(),
+ );
+
+ return span;
+ })(),
(() => {
const span = document.createElement('span');
span.classList.add('text');
diff --git a/client/src/views/preferences/fields/dashboard-tab-list.js b/client/src/views/preferences/fields/dashboard-tab-list.js
index a5ba0c8533..1f26cdac5d 100644
--- a/client/src/views/preferences/fields/dashboard-tab-list.js
+++ b/client/src/views/preferences/fields/dashboard-tab-list.js
@@ -55,10 +55,26 @@ export default class extends ArrayFieldView {
return $('
')
.addClass('list-group-item link-with-role form-inline')
.attr('data-value', value)
+ .append(
+ (() => {
+ const span = document.createElement('span');
+ span.className = 'drag-handle pull-left';
+ span.append(
+ (() => {
+ const span = document.createElement('span');
+ span.className = 'fas fa-grip fa-sm';
+
+ return span;
+ })(),
+ );
+
+ return span;
+ })(),
+ )
.append(
$('
')
.addClass('pull-left')
- .css('width', '92%')
+ .css('width', 'calc(100% - var(--36px))')
.css('display', 'inline-block')
.append(
$('
')
@@ -67,12 +83,12 @@ export default class extends ArrayFieldView {
.attr('data-value', value)
.addClass('role form-control input-sm')
.attr('value', translatedValue)
- .css('width', '65%')
+ .css('width', 'calc(100% - var(--4px))')
)
)
.append(
$('
')
- .css('width', '8%')
+ .css('width', 'var(--18px)')
.css('display', 'inline-block')
.css('vertical-align', 'top')
.append(
@@ -87,9 +103,6 @@ export default class extends ArrayFieldView {
)
)
)
- .append(
- $('
').css('clear', 'both')
- )
.get(0).outerHTML;
}
diff --git a/client/src/views/settings/fields/tab-list.js b/client/src/views/settings/fields/tab-list.js
index 76479bd53e..8b68f32387 100644
--- a/client/src/views/settings/fields/tab-list.js
+++ b/client/src/views/settings/fields/tab-list.js
@@ -46,11 +46,9 @@ class TabListFieldView extends ArrayFieldView {
}
});
- this.events['click [data-action="editGroup"]'] = e => {
- const id = $(e.currentTarget).parent().data('value').toString();
-
- this.editGroup(id);
- };
+ this.addActionHandler('editGroup', (e, target) => {
+ this.editGroup(target.dataset.value);
+ })
}
generateItemId() {
@@ -132,39 +130,110 @@ class TabListFieldView extends ArrayFieldView {
return super.getItemHtml(value);
}
+ /**
+ *
+ * @param {{id: string, text?: string|null, type: string}} item
+ * @return {string | jQuery}
+ */
getGroupItemHtml(item) {
- const label = item.text || '';
+ const labelElement = document.createElement('span');
+ labelElement.textContent = item.text ?? '';
- const $label = $('
').text(label);
-
- let $icon = null;
+ let icon;
if (item.type === 'group') {
- $icon = $('')
- .addClass('far fa-list-alt')
- .addClass('text-muted')
+ icon = document.createElement('span');
+ icon.className = 'far fa-list-alt text-muted';
}
if (item.type === 'url') {
- $icon = $('')
- .addClass('fas fa-link fa-sm')
- .addClass('text-muted')
+ icon = document.createElement('span');
+ icon.className = 'fas fa-link fa-sm text-muted';
}
if (item.type === 'divider') {
- $label.addClass('text-soft')
- .addClass('text-italic');
+ labelElement.classList.add('text-soft', 'text-italic');
}
- const $item = $('').append($label);
+ const itemElement = document.createElement('span');
+ itemElement.append(labelElement);
+ itemElement.className = 'text';
- if ($icon) {
- $item.prepend(
- $icon,
- ' '
- )
+ if (icon) {
+ icon.style.marginRight = 'var(--4px)';
+
+ itemElement.prepend(icon);
}
+ const div = document.createElement('div');
+ div.className = 'list-group-item';
+ div.dataset.value = item.id;
+ div.style.cursor = 'default';
+
+ div.append(
+ (() => {
+ const span = document.createElement('span');
+ span.className = 'drag-handle';
+ span.append(
+ (() => {
+ const span = document.createElement('span');
+ span.className = 'fas fa-grip fa-sm';
+
+ return span;
+ })(),
+ );
+
+ return span;
+ })(),
+ (() => {
+ const span = document.createElement('span');
+ span.className = 'item-button'
+ span.append(
+ (() => {
+ const a = document.createElement('a');
+ a.role = 'button';
+ a.tabIndex = 0;
+ a.dataset.value = item.id;
+ a.dataset.action = 'editGroup';
+ a.append(
+ (() => {
+ const span = document.createElement('span');
+ span.className = 'fas fa-pencil-alt fa-sm';
+
+ return span;
+ })(),
+ );
+
+ return a;
+ })(),
+ )
+
+ return span;
+ })(),
+ itemElement,
+ (() => {
+ const a = document.createElement('a');
+ a.role = 'button';
+ a.tabIndex = 0;
+ a.classList.add('pull-right');
+ a.dataset.value = item.id;
+ a.dataset.action = 'removeValue';
+ a.append(
+ (() => {
+ const span = document.createElement('span');
+ span.className = 'fas fa-times'
+
+ return span;
+ })(),
+ );
+
+ return a;
+ })(),
+ );
+
+ return div.outerHTML;
+
+
return $('')
.addClass('list-group-item')
.attr('data-value', item.id)
diff --git a/frontend/less/espo/custom.less b/frontend/less/espo/custom.less
index 9bbe02aec1..2e294621c9 100644
--- a/frontend/less/espo/custom.less
+++ b/frontend/less/espo/custom.less
@@ -827,6 +827,43 @@ input.global-search-input {
width: calc(100% - var(--18px));
display: inline-block;
}
+
+ > span.drag-handle {
+ display: inline-block;
+ width: var(--18px);
+ color: var(--text-muted-color);
+ cursor: grab;
+ vertical-align: top;
+ }
+
+ > span.item-button {
+ display: inline-block;
+ width: var(--18px);
+ vertical-align: top;
+ }
+
+ &:has(> .item-button) {
+ > span.text {
+ width: calc(100% - var(--36px));
+ }
+ }
+
+ &:has(> .drag-handle) {
+ > span.text {
+ width: calc(100% - var(--36px));
+ }
+ }
+
+ &:has(> .item-button):has(> .drag-handle) {
+ > span.text {
+ width: calc(100% - var(--36px) - var(--18px));
+ }
+ }
+
+ > a[role="button"] {
+ margin-top: var(--1px);
+ margin-left: var(--2px);
+ }
}
.link-group-item-with-columns {
@@ -947,11 +984,6 @@ input.global-search-input {
margin-left: var(--2px);
}
-.field .link-container .list-group-item a[role="button"] {
- margin-top: var(--1px);
- margin-left: var(--2px);
-}
-
.field .link-container > .list-group-item.link-with-role > a[role="button"],
.field .link-container > .list-group-item.link-with-role > div > a[role="button"] {
margin-top: var(--7px);