Release v1.1.3: playlist drag sorting, local SortableJS, and playlist UI updates

This commit is contained in:
2026-07-15 00:45:40 +01:00
parent b0649d838e
commit b7f1d800ef
9 changed files with 164 additions and 54 deletions
+31 -34
View File
@@ -230,7 +230,6 @@
var addSlideForm = document.getElementById('playlist-add-slide-form');
var addSlideButton = document.getElementById('playlist-add-slide-button');
var addSlideSelect = document.getElementById('playlist-add-slide-select');
var addDurationInput = document.getElementById('playlist-add-duration');
var addSlideEmpty = document.getElementById('playlist-add-slide-empty');
if (!tbody || !form) {
@@ -351,9 +350,6 @@
if (addSlideSelect) {
addSlideSelect.disabled = availableCount === 0;
}
if (addDurationInput) {
addDurationInput.disabled = availableCount === 0;
}
if (addSlideEmpty) {
addSlideEmpty.style.display = availableCount === 0 ? '' : 'none';
}
@@ -366,17 +362,9 @@
function updateRowOrder() {
var rows = getRows();
rows.forEach(function (row, index) {
var orderCell = row.querySelector('.playlist-order-cell');
var moveUp = row.querySelector('[data-playlist-move="up"]');
var moveDown = row.querySelector('[data-playlist-move="down"]');
if (orderCell) {
orderCell.textContent = String(index + 1);
}
if (moveUp) {
moveUp.disabled = index === 0;
}
if (moveDown) {
moveDown.disabled = index === rows.length - 1;
var orderNumber = row.querySelector('.playlist-order-number');
if (orderNumber) {
orderNumber.textContent = String(index + 1);
}
});
syncAddSlideOptions();
@@ -423,9 +411,13 @@
row.setAttribute('data-slide-id', String(values.slide_id));
row.setAttribute('data-canvas-signature', String(values.canvas_signature || ''));
row.innerHTML = '' +
'<td class="playlist-order-cell"></td>' +
'<td class="playlist-order-cell" data-label="Order">' +
'<div class="playlist-order-cell-inner">' +
'<button type="button" class="playlist-drag-handle" data-playlist-drag-handle aria-label="Drag to reorder" title="Drag to reorder"></button>' +
'<span class="playlist-order-number"></span>' +
'</div>' +
'</td>' +
'<td>' + values.title + '<input type="hidden" name="slide_id[]" value="' + values.slide_id + '" /></td>' +
'<td><input name="duration_seconds[]" type="number" min="1" value="' + values.duration_seconds + '" required /></td>' +
'<td>' +
'<div class="playlist-schedule-summary">' + values.summary + '</div>' +
'<input type="hidden" name="schedule_mode[]" value="' + values.schedule_mode + '" />' +
@@ -435,9 +427,8 @@
'<input type="hidden" name="schedule_end_time[]" value="' + values.schedule_end_time + '" />' +
'<input type="hidden" name="schedule_days_json[]" value="' + values.schedule_days_json + '" />' +
'</td>' +
'<td><input name="duration_seconds[]" type="number" min="1" value="' + values.duration_seconds + '" required /></td>' +
'<td><div class="actions playlist-item-actions">' +
'<button type="button" class="secondary" data-playlist-move="up">Up</button>' +
'<button type="button" class="secondary" data-playlist-move="down">Down</button>' +
'<button type="button" class="schedule-config-button" disabled>Schedule</button>' +
'<button type="button" class="danger" data-playlist-remove-row>Remove</button>' +
'</div></td>';
@@ -445,7 +436,6 @@
}
tbody.addEventListener('click', function (event) {
var moveButton = event.target.closest('[data-playlist-move]');
var removeButton = event.target.closest('[data-playlist-remove-row]');
var scheduleButton = event.target.closest('[data-schedule-config]');
var row = event.target.closest('tr[data-playlist-slide-row]');
@@ -454,18 +444,6 @@
return;
}
if (moveButton) {
event.preventDefault();
var direction = moveButton.getAttribute('data-playlist-move');
if (direction === 'up' && row.previousElementSibling && row.previousElementSibling.matches('[data-playlist-slide-row]')) {
tbody.insertBefore(row, row.previousElementSibling);
} else if (direction === 'down' && row.nextElementSibling && row.nextElementSibling.matches('[data-playlist-slide-row]')) {
tbody.insertBefore(row.nextElementSibling, row);
}
updateRowOrder();
return;
}
if (removeButton) {
event.preventDefault();
row.remove();
@@ -481,7 +459,26 @@
}
});
if (addSlideButton && addSlideSelect && addDurationInput) {
if (window.Sortable) {
Sortable.create(tbody, {
animation: 180,
handle: '[data-playlist-drag-handle]',
draggable: 'tr[data-playlist-slide-row]',
ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag',
forceFallback: true,
fallbackOnBody: true,
fallbackTolerance: 3,
swapThreshold: 0.65,
invertedSwapThreshold: 0.65,
onEnd: function () {
updateRowOrder();
}
});
}
if (addSlideButton && addSlideSelect) {
addSlideButton.addEventListener('click', function () {
var selectedOption = addSlideSelect.options[addSlideSelect.selectedIndex];
if (!selectedOption || selectedOption.disabled) {
@@ -496,7 +493,7 @@
slide_id: String(selectedOption.value),
canvas_signature: String(selectedOption.getAttribute('data-canvas-signature') || ''),
title: selectedOption.textContent || 'Slide',
duration_seconds: Math.max(1, Number(addDurationInput.value || 10)),
duration_seconds: 10,
schedule_mode: 'always',
schedule_start_datetime: '',
schedule_end_datetime: '',
File diff suppressed because one or more lines are too long