Kleine fehler beseitigt
This commit is contained in:
1 parent
57e201b8fc
commit
115f0f5671
15 files changed
+220
-115
No files matched your search
@@ -24,11 +24,23 @@ function delProjectFromList(id){
|
||||
|
||||
// editProjectField: ändert ein Feld eines Projekts (z.B. Name oder Gruppe).
|
||||
// Parameter: `id` (Projekt-ID), `field` (Feldname), `val` (neuer Wert).
|
||||
// Keine Rückgabe.
|
||||
// Beim Wechsel der Gruppe wird das Projekt ans Ende der Zielgruppe angehängt
|
||||
// (neue `order` = höchste Order der Zielgruppe + 1), damit es nicht anhand
|
||||
// seiner alten `order` in der Liste landet. Keine Rückgabe.
|
||||
function editProjectField(id,field,val){
|
||||
if(guardWeekLocked()) return;
|
||||
const p = currentWeek().projects.find(x=>x.id===id);
|
||||
if(p){ p[field]=val; save(); renderProjects(); renderBoard(); }
|
||||
const w = currentWeek();
|
||||
const p = w.projects.find(x=>x.id===id);
|
||||
if(!p) return;
|
||||
if(field === 'group' && val && val !== p.group){
|
||||
p.group = val;
|
||||
const targetProjects = w.projects.filter(x => x.id !== id && x.group === val);
|
||||
const maxOrder = targetProjects.reduce((m,x)=>Math.max(m, x.order || 0), -1);
|
||||
p.order = maxOrder + 1;
|
||||
} else {
|
||||
p[field] = val;
|
||||
}
|
||||
save(); renderProjects(); renderBoard();
|
||||
}
|
||||
|
||||
// editProjectActiveLP: setzt bzw. hebt die amtierende Leistungsphase eines
|
||||
@@ -59,9 +71,9 @@ function renderProjects(){
|
||||
|
||||
sortGroups(Object.keys(groups)).forEach(g=>{
|
||||
html += `<div class="section-title">${esc(g)}</div>`;
|
||||
html += `<div class="projects-sortable" data-group="${g}">`;
|
||||
html += `<div class="projects-sortable" data-group="${g}" ondragover="handleDragOver(event)" ondrop="handleDrop(event)">`;
|
||||
groups[g].forEach(p=>{
|
||||
html += `<div class="person-list-item" draggable="true" data-project-id="${p.id}" ondragstart="handleDragStart(event)" ondragover="handleDragOver(event)" ondrop="handleDrop(event)" ondragend="handleDragEnd(event)">
|
||||
html += `<div class="person-list-item" draggable="true" data-project-id="${p.id}" ondragstart="handleDragStart(event)" ondragend="handleDragEnd(event)">
|
||||
<span class="drag-handle" style="cursor:grab;color:#999;margin-right:8px">⋮⋮</span>
|
||||
<input type="text" value="${esc(p.nr)}" onchange="editProjectField('${p.id}','nr',this.value)" style="width:100px" placeholder="Proj-Nr">
|
||||
<input type="text" value="${esc(p.name)}" onchange="editProjectField('${p.id}','name',this.value)" style="width:200px" placeholder="Bezeichnung">
|
||||
@@ -106,18 +118,31 @@ function handleDragOver(event){
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
}
|
||||
|
||||
// handleDrop: legt die gezogene Projekt-Zeile an der Position ab, die
|
||||
// `getDragAfterElement` relativ zur Mausposition ermittelt, und speichert
|
||||
// die neue Reihenfolge über `reorderProjects()`.
|
||||
// handleDrop: legt die gezogene Projekt-Zeile ab. Der Handler hängt am
|
||||
// Gruppen-Container (`.projects-sortable`), sodass das Ablegen über der
|
||||
// gesamten Gruppe inklusive leerer Flächen möglich ist. Beim Wechsel zwischen
|
||||
// Gruppen (z. B. "Kleine Projekte" → "Aktive Projekte") wird das Projekt ans
|
||||
// Ende der Zielgruppe angehängt; innerhalb derselben Gruppe wird die Position
|
||||
// per `getDragAfterElement` relativ zur Mausposition bestimmt. Danach speichert
|
||||
// `reorderProjects()` die neue Reihenfolge.
|
||||
function handleDrop(event){
|
||||
event.preventDefault();
|
||||
if(!draggedProject || draggedProject === event.currentTarget) return;
|
||||
const sortable = event.currentTarget.parentElement;
|
||||
const afterElement = getDragAfterElement(sortable, event.clientY);
|
||||
if(afterElement == null){
|
||||
sortable.appendChild(draggedProject);
|
||||
if(!draggedProject) return;
|
||||
const sortable = event.currentTarget;
|
||||
const sourceSortable = draggedProject.parentElement;
|
||||
const isSameGroup = sourceSortable &&
|
||||
sourceSortable.dataset && sortable.dataset &&
|
||||
sourceSortable.dataset.group === sortable.dataset.group;
|
||||
if(isSameGroup){
|
||||
const afterElement = getDragAfterElement(sortable, event.clientY);
|
||||
if(afterElement == null){
|
||||
sortable.appendChild(draggedProject);
|
||||
} else {
|
||||
sortable.insertBefore(draggedProject, afterElement);
|
||||
}
|
||||
} else {
|
||||
sortable.insertBefore(draggedProject, afterElement);
|
||||
// Gruppenwechsel: ans Ende der Zielgruppe anhängen
|
||||
sortable.appendChild(draggedProject);
|
||||
}
|
||||
reorderProjects();
|
||||
}
|
||||
@@ -131,11 +156,14 @@ function handleDragEnd(event){
|
||||
|
||||
// getDragAfterElement: ermittelt das Element in `container`, vor dem die
|
||||
// gezogene Zeile bei Mausposition `y` abgelegt werden soll (Suche nach dem
|
||||
// Element mit der kleinsten negativen Distanz zur Mitte). Rückgabe:
|
||||
// Ziel-Element oder undefined (→ ans Ende anfügen). Wird auch von
|
||||
// `js/people/people.js` für die Personen-Sortierung verwendet.
|
||||
function getDragAfterElement(container, y){
|
||||
const draggableElements = [...container.querySelectorAll('.person-list-item:not([style*="opacity"])')];
|
||||
// Element mit der kleinsten negativen Distanz zur Mitte). Parameter:
|
||||
// `selector` = CSS-Selektor der sortierbaren Elemente (standardmäßig die
|
||||
// Projekt-Zeilen, steht aber auch der Personen-Liste für `.person-card` zur
|
||||
// Verfügung). Rückgabe: Ziel-Element oder undefined (→ ans Ende anfügen).
|
||||
// Wird auch von `js/people/people.js` für die Personen-Sortierung verwendet.
|
||||
function getDragAfterElement(container, y, selector){
|
||||
const sel = selector || '.person-list-item:not([style*="opacity"])';
|
||||
const draggableElements = [...container.querySelectorAll(sel)];
|
||||
return draggableElements.reduce((closest, child) => {
|
||||
const box = child.getBoundingClientRect();
|
||||
const offset = y - box.top - box.height / 2;
|
||||
|
||||
Reference in new issue
Block a user