86 lines
2.4 KiB
JavaScript
86 lines
2.4 KiB
JavaScript
function createPlanToday({ identity, save, start, limit = 5 }) {
|
|
let openState = false;
|
|
let draftIds = [];
|
|
let itemsById = new Map();
|
|
|
|
function cleanItems(items) {
|
|
const unique = new Map();
|
|
for (const item of items || []) {
|
|
const id = identity?.(item);
|
|
if (id && !unique.has(id)) unique.set(id, item);
|
|
}
|
|
return unique;
|
|
}
|
|
|
|
function open(selectedItems, candidates) {
|
|
itemsById = cleanItems([...(selectedItems || []), ...(candidates || [])]);
|
|
draftIds = [];
|
|
for (const item of selectedItems || []) {
|
|
const id = identity?.(item);
|
|
if (id && itemsById.has(id) && !draftIds.includes(id) && draftIds.length < limit) draftIds.push(id);
|
|
}
|
|
openState = true;
|
|
return snapshot();
|
|
}
|
|
|
|
function toggle(item) {
|
|
if (!openState) return 'closed';
|
|
const id = identity?.(item);
|
|
if (!id) return 'unavailable';
|
|
itemsById.set(id, item);
|
|
const index = draftIds.indexOf(id);
|
|
if (index >= 0) {
|
|
draftIds.splice(index, 1);
|
|
return 'removed';
|
|
}
|
|
if (draftIds.length >= limit) return 'full';
|
|
draftIds.push(id);
|
|
return 'added';
|
|
}
|
|
|
|
function move(id, direction) {
|
|
const index = draftIds.indexOf(id);
|
|
const target = direction === 'up' ? index - 1 : direction === 'down' ? index + 1 : -1;
|
|
if (!openState || index < 0 || target < 0 || target >= draftIds.length) return false;
|
|
[draftIds[index], draftIds[target]] = [draftIds[target], draftIds[index]];
|
|
return true;
|
|
}
|
|
|
|
function close() {
|
|
openState = false;
|
|
draftIds = [];
|
|
itemsById = new Map();
|
|
}
|
|
|
|
function cancel() {
|
|
close();
|
|
return true;
|
|
}
|
|
|
|
function commit({ start: startAfterSave = false } = {}) {
|
|
if (!openState) return 'closed';
|
|
const ids = [...draftIds];
|
|
if (save?.(ids) === false) return 'unavailable';
|
|
const first = ids.length ? itemsById.get(ids[0]) : null;
|
|
close();
|
|
if (startAfterSave && first) start?.(first);
|
|
return 'saved';
|
|
}
|
|
|
|
function snapshot() {
|
|
return { open: openState, ids: [...draftIds], count: draftIds.length, limit };
|
|
}
|
|
|
|
function item(id) {
|
|
return itemsById.get(id) || null;
|
|
}
|
|
|
|
function candidates() {
|
|
return [...itemsById.entries()].filter(([id]) => !draftIds.includes(id)).map(([, value]) => value);
|
|
}
|
|
|
|
return { open, toggle, move, cancel, commit, snapshot, item, candidates };
|
|
}
|
|
|
|
if (typeof module !== 'undefined' && module.exports) module.exports = createPlanToday;
|