mirror of
https://github.com/wekan/wekan.git
synced 2026-11-07 11:02:33 -05:00
69 lines
3.0 KiB
JavaScript
69 lines
3.0 KiB
JavaScript
'use strict';
|
|
|
|
// Pure helpers for reordering boards on the All Boards page by drag-and-drop.
|
|
// Extracted so the decision logic is unit-testable in plain Node without Meteor
|
|
// (mirrors models/lib/cardSearch.js).
|
|
//
|
|
// #6439 (Custom (drag order) sort — drag shows 'not-allowed' cursor, drop does
|
|
// not reorder): the old jQuery-ui sortable that reordered boards in the "custom"
|
|
// mode was removed when the All Boards page moved to HTML5 drag-and-drop for
|
|
// workspace/space management, and no HTML5 reorder handler replaced it. Boards
|
|
// carry draggable="true", but with no drop target that accepts them the browser
|
|
// shows the forbidden cursor and nothing persists to profile.boardSortIndex.
|
|
//
|
|
// The wiring lives in client/components/boards/boardsList.js; the pieces below
|
|
// are the two decisions worth testing in isolation:
|
|
// 1. whether drag-reordering should be active for the current sort mode, and
|
|
// 2. the new per-user boardSortIndex mapping produced by a drop.
|
|
|
|
// Drag-reordering only makes sense in the manual "custom" order. In the sorted
|
|
// modes ('title-asc' / 'title-desc') the order is derived from the title, so a
|
|
// manual drop must be ignored (and the board grid must not offer a drop target).
|
|
function isDragReorderEnabled(sortBy) {
|
|
return sortBy === 'custom';
|
|
}
|
|
|
|
// Given the currently displayed board ids (in display order), move `draggedId`
|
|
// so it sits immediately before `targetId` (the board it was dropped on). Returns
|
|
// the new ordered array, or null when the drop is a no-op or the ids are unknown.
|
|
function computeReorderedIds(orderedIds, draggedId, targetId) {
|
|
if (!Array.isArray(orderedIds)) return null;
|
|
if (!draggedId || !targetId || draggedId === targetId) return null;
|
|
const from = orderedIds.indexOf(draggedId);
|
|
const to = orderedIds.indexOf(targetId);
|
|
if (from === -1 || to === -1) return null;
|
|
const result = orderedIds.slice();
|
|
result.splice(from, 1);
|
|
// Insert before the target's current position (after the dragged id has been
|
|
// removed), so the dragged board takes the target's slot and pushes it down.
|
|
const insertAt = result.indexOf(targetId);
|
|
result.splice(insertAt, 0, draggedId);
|
|
return result;
|
|
}
|
|
|
|
// Turn an ordered list of board ids into a { boardId: index } mapping suitable
|
|
// for profile.boardSortIndex. Sequential integers keep the order stable and
|
|
// avoid fractional drift on repeated reorders.
|
|
function computeSortIndexMapping(orderedIds) {
|
|
const mapping = {};
|
|
(orderedIds || []).forEach((id, i) => {
|
|
mapping[id] = i;
|
|
});
|
|
return mapping;
|
|
}
|
|
|
|
// Convenience: compute the persisted boardSortIndex mapping for a drop, or null
|
|
// when the drop changes nothing (so callers can skip the write).
|
|
function computeReorderedSortIndex(orderedIds, draggedId, targetId) {
|
|
const reordered = computeReorderedIds(orderedIds, draggedId, targetId);
|
|
if (!reordered) return null;
|
|
return computeSortIndexMapping(reordered);
|
|
}
|
|
|
|
module.exports = {
|
|
isDragReorderEnabled,
|
|
computeReorderedIds,
|
|
computeSortIndexMapping,
|
|
computeReorderedSortIndex,
|
|
};
|