- section content type with structure service, reader context and grouped results/PDF/Excel - new questions append at the end (backend oncreate) and per-section add buttons - rich-text descriptions: Quill 2 (frontend), reduced TinyMCE (backend), server-side whitelist sanitizer - externalize inline assets, bundle Chart.js locally, harden debug access, validate range bounds Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
100 lines
3.5 KiB
JavaScript
100 lines
3.5 KiB
JavaScript
(function () {
|
|
function initSurveyQuestionSorting() {
|
|
if (typeof Sortable !== 'function') {
|
|
return;
|
|
}
|
|
|
|
var sortableList = document.querySelector('[data-survey-question-sortable]');
|
|
var orderForm = document.querySelector('[data-survey-question-order-shell]');
|
|
var orderInput = document.querySelector('[data-survey-question-order-input]');
|
|
|
|
if (!sortableList || !orderForm || !orderInput || sortableList._surveyQuestionSortable) {
|
|
return;
|
|
}
|
|
|
|
var getOrderedIds = function () {
|
|
return Array.from(sortableList.querySelectorAll('[data-survey-question-item]')).map(function (item) {
|
|
return item.getAttribute('data-question-id') || '';
|
|
}).filter(function (value) {
|
|
return value !== '';
|
|
});
|
|
};
|
|
|
|
var initialOrder = getOrderedIds().join(',');
|
|
|
|
var updateOrderField = function () {
|
|
orderInput.value = getOrderedIds().join(',');
|
|
};
|
|
|
|
var updateQuestionIndices = function () {
|
|
var position = 0;
|
|
|
|
sortableList.querySelectorAll('[data-survey-question-item]').forEach(function (item) {
|
|
// Themenbereiche verbrauchen keine Positionsnummer.
|
|
if (item.hasAttribute('data-survey-section-item')) {
|
|
return;
|
|
}
|
|
|
|
var indexNode = item.querySelector('.survey-accordion-index');
|
|
position += 1;
|
|
|
|
if (indexNode) {
|
|
indexNode.textContent = position + '.';
|
|
}
|
|
});
|
|
};
|
|
|
|
var updateSaveVisibility = function () {
|
|
var currentOrder = getOrderedIds().join(',');
|
|
var isDirty = currentOrder !== initialOrder;
|
|
|
|
orderForm.hidden = !isDirty;
|
|
orderForm.classList.toggle('is-visible', isDirty);
|
|
// Die "Frage hinzufügen"-Zeilen beziehen sich auf die gespeicherte
|
|
// Reihenfolge; nach dem Verschieben bis zum Speichern ausblenden.
|
|
sortableList.classList.toggle('is-order-dirty', isDirty);
|
|
updateOrderField();
|
|
};
|
|
|
|
sortableList.querySelectorAll('[data-survey-question-sort-handle]').forEach(function (handle) {
|
|
handle.addEventListener('click', function (event) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
});
|
|
});
|
|
|
|
updateQuestionIndices();
|
|
updateOrderField();
|
|
updateSaveVisibility();
|
|
|
|
sortableList._surveyQuestionSortable = Sortable.create(sortableList, {
|
|
animation: 180,
|
|
draggable: '[data-survey-question-item]',
|
|
handle: '[data-survey-question-sort-handle]',
|
|
ghostClass: 'sortable-ghost',
|
|
forceFallback: true,
|
|
fallbackTolerance: 3,
|
|
onStart: function (event) {
|
|
if (event.item) {
|
|
event.item.classList.add('is-reordering');
|
|
}
|
|
},
|
|
onEnd: function (event) {
|
|
if (event.item) {
|
|
event.item.classList.remove('is-reordering');
|
|
}
|
|
|
|
updateQuestionIndices();
|
|
updateSaveVisibility();
|
|
}
|
|
});
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', initSurveyQuestionSorting, { once: true });
|
|
} else {
|
|
initSurveyQuestionSorting();
|
|
}
|
|
|
|
window.addEventListener('load', initSurveyQuestionSorting, { once: true });
|
|
})(); |