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