Implement basic desktop drag and drop

This commit is contained in:
Adrian Gruntkowski 2024-11-11 20:30:03 +01:00
parent ec2952c172
commit 1330f230c4
3 changed files with 60 additions and 4 deletions

View file

@ -23,6 +23,7 @@
href="/img/favicon-16x16.png"
/>
<link rel="manifest" href="/site.webmanifest" />
<script src="/js/jenot.js" defer></script>
</head>
<body>
@ -36,8 +37,8 @@
<div class="note">
<task-list>
<ul>
<li><task-list-item checked>one</task-list-item></li>
<li><task-list-item>two</task-list-item></li>
<li draggable="true"><task-list-item checked>one</task-list-item></li>
<li draggable="true"><task-list-item>two</task-list-item></li>
</ul>
</task-list>
</div>
@ -49,7 +50,5 @@
<editable-area></editable-area>
<div class="remove"><button>X</button></div>
</template>
<script src="/js/jenot.js"></script>
</body>
</html>

View file

@ -151,9 +151,24 @@ class TaskListItem extends HTMLElement {
}
});
// drag and drop events
this.parentNode.addEventListener("dragstart", (e) => {
this.parentNode.classList.add("dragging");
});
this.parentNode.addEventListener("dragend", () => {
this.parentNode.classList.remove("dragging");
});
this.#updateChecked();
}
disconnectedCallback() {
this.textContent = this.contentElement.value;
this.setAttribute("checked", this.checkboxElement.checked);
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === "checked") {
this.#updateChecked();
@ -195,11 +210,14 @@ class TaskList extends HTMLElement {
}
connectedCallback() {
this.listElement = this.querySelector("ul");
this.addEventListener("removeTaskWithButton", (e) => {
const tasksCount = this.querySelectorAll("task-list-item").length;
if (tasksCount === 1) {
const newLI = document.createElement("li");
newLI.setAttribute("draggable", "true");
const newItem = document.createElement("task-list-item");
newLI.appendChild(newItem);
this.querySelector("ul").appendChild(newLI);
@ -228,6 +246,7 @@ class TaskList extends HTMLElement {
const currentLI = e.target.parentNode;
const newLI = document.createElement("li");
newLI.setAttribute("draggable", "true");
const newItem = document.createElement("task-list-item");
newItem.textContent = text;
newLI.appendChild(newItem);
@ -254,6 +273,40 @@ class TaskList extends HTMLElement {
prevItem.focusEnd();
}
});
// drag and drop
this.listElement.addEventListener("dragover", (e) => {
e.preventDefault();
const afterElement = this.#getDragAfterElement(e.clientY);
const draggable = document.querySelector(".dragging");
if (afterElement == null) {
this.listElement.appendChild(draggable);
} else {
this.listElement.insertBefore(draggable, afterElement);
}
});
}
#getDragAfterElement(y) {
const draggableElements = [
...this.listElement.querySelectorAll("li:not(.dragging)"),
];
return draggableElements.reduce(
(closest, containerChild) => {
const box = containerChild.getBoundingClientRect();
const offset = y - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: containerChild };
} else {
return closest;
}
},
{ offset: Number.NEGATIVE_INFINITY },
).element;
}
}

View file

@ -128,6 +128,10 @@ task-list-item .checkbox input {
height: 1.1em;
}
.dragging {
opacity: 0.5;
}
/* Styles */
* {