array drag handle

This commit is contained in:
Yuri Kuznetsov
2025-08-01 11:18:30 +03:00
parent 6e487345ec
commit c2261feeec
5 changed files with 174 additions and 36 deletions
@@ -30,6 +30,8 @@ import OptionsView from 'views/admin/field-manager/fields/options';
export default class extends OptionsView { export default class extends OptionsView {
noDragHandle = true
setup() { setup() {
super.setup(); super.setup();
+24 -2
View File
@@ -121,6 +121,13 @@ class ArrayFieldView extends BaseFieldView {
*/ */
translatedOptions = null translatedOptions = null
/**
* @protected
* @type {boolean}
* @since 9.2.0
*/
noDragHandle = false
// noinspection JSCheckFunctionSignatures // noinspection JSCheckFunctionSignatures
/** @inheritDoc */ /** @inheritDoc */
@@ -434,6 +441,7 @@ class ArrayFieldView extends BaseFieldView {
distance: 5, distance: 5,
cancel: 'input,textarea,button,select,option,a[role="button"]', cancel: 'input,textarea,button,select,option,a[role="button"]',
cursor: 'grabbing', cursor: 'grabbing',
handle: !this.noDragHandle ? '.drag-handle' : undefined,
}); });
} }
@@ -658,7 +666,7 @@ class ArrayFieldView extends BaseFieldView {
value; value;
const div = document.createElement('div'); const div = document.createElement('div');
div.classList.add('list-group-item'); div.className = 'list-group-item';
div.dataset.value = value; div.dataset.value = value;
div.style.cursor = 'default'; div.style.cursor = 'default';
@@ -672,7 +680,7 @@ class ArrayFieldView extends BaseFieldView {
a.append( a.append(
(() => { (() => {
const span = document.createElement('span'); const span = document.createElement('span');
span.classList.add('fas', 'fa-times'); span.className = 'fas fa-times'
return span; return span;
})(), })(),
@@ -682,6 +690,20 @@ class ArrayFieldView extends BaseFieldView {
} }
div.append( 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'); const span = document.createElement('span');
span.classList.add('text'); span.classList.add('text');
@@ -55,10 +55,26 @@ export default class extends ArrayFieldView {
return $('<div>') return $('<div>')
.addClass('list-group-item link-with-role form-inline') .addClass('list-group-item link-with-role form-inline')
.attr('data-value', value) .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( .append(
$('<div>') $('<div>')
.addClass('pull-left') .addClass('pull-left')
.css('width', '92%') .css('width', 'calc(100% - var(--36px))')
.css('display', 'inline-block') .css('display', 'inline-block')
.append( .append(
$('<input>') $('<input>')
@@ -67,12 +83,12 @@ export default class extends ArrayFieldView {
.attr('data-value', value) .attr('data-value', value)
.addClass('role form-control input-sm') .addClass('role form-control input-sm')
.attr('value', translatedValue) .attr('value', translatedValue)
.css('width', '65%') .css('width', 'calc(100% - var(--4px))')
) )
) )
.append( .append(
$('<div>') $('<div>')
.css('width', '8%') .css('width', 'var(--18px)')
.css('display', 'inline-block') .css('display', 'inline-block')
.css('vertical-align', 'top') .css('vertical-align', 'top')
.append( .append(
@@ -87,9 +103,6 @@ export default class extends ArrayFieldView {
) )
) )
) )
.append(
$('<br>').css('clear', 'both')
)
.get(0).outerHTML; .get(0).outerHTML;
} }
+92 -23
View File
@@ -46,11 +46,9 @@ class TabListFieldView extends ArrayFieldView {
} }
}); });
this.events['click [data-action="editGroup"]'] = e => { this.addActionHandler('editGroup', (e, target) => {
const id = $(e.currentTarget).parent().data('value').toString(); this.editGroup(target.dataset.value);
})
this.editGroup(id);
};
} }
generateItemId() { generateItemId() {
@@ -132,39 +130,110 @@ class TabListFieldView extends ArrayFieldView {
return super.getItemHtml(value); return super.getItemHtml(value);
} }
/**
*
* @param {{id: string, text?: string|null, type: string}} item
* @return {string | jQuery}
*/
getGroupItemHtml(item) { getGroupItemHtml(item) {
const label = item.text || ''; const labelElement = document.createElement('span');
labelElement.textContent = item.text ?? '';
const $label = $('<span>').text(label); let icon;
let $icon = null;
if (item.type === 'group') { if (item.type === 'group') {
$icon = $('<span>') icon = document.createElement('span');
.addClass('far fa-list-alt') icon.className = 'far fa-list-alt text-muted';
.addClass('text-muted')
} }
if (item.type === 'url') { if (item.type === 'url') {
$icon = $('<span>') icon = document.createElement('span');
.addClass('fas fa-link fa-sm') icon.className = 'fas fa-link fa-sm text-muted';
.addClass('text-muted')
} }
if (item.type === 'divider') { if (item.type === 'divider') {
$label.addClass('text-soft') labelElement.classList.add('text-soft', 'text-italic');
.addClass('text-italic');
} }
const $item = $('<span>').append($label); const itemElement = document.createElement('span');
itemElement.append(labelElement);
itemElement.className = 'text';
if ($icon) { if (icon) {
$item.prepend( icon.style.marginRight = 'var(--4px)';
$icon,
' ' 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 $('<div>') return $('<div>')
.addClass('list-group-item') .addClass('list-group-item')
.attr('data-value', item.id) .attr('data-value', item.id)
+37 -5
View File
@@ -827,6 +827,43 @@ input.global-search-input {
width: calc(100% - var(--18px)); width: calc(100% - var(--18px));
display: inline-block; 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 { .link-group-item-with-columns {
@@ -947,11 +984,6 @@ input.global-search-input {
margin-left: var(--2px); 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 > a[role="button"],
.field .link-container > .list-group-item.link-with-role > div > a[role="button"] { .field .link-container > .list-group-item.link-with-role > div > a[role="button"] {
margin-top: var(--7px); margin-top: var(--7px);