improve draggable item style
This commit is contained in:
parent
ea8d2e5b8c
commit
bab1ab8830
@ -1,3 +1,26 @@
|
|||||||
|
// Map valid UUIDs used by draggable-item elements in order to better validate data transfers to ignore random data transfers.
|
||||||
|
const draggableItemUUIDs = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate a data transfer object through its data types. Valid draggable-item events have one type of the format `application/json/${uuid}`.
|
||||||
|
* The function takes the entire type list from event.dataTransfer.types and returns true if the dataTransfer object is likely to be valid.
|
||||||
|
* @param {*} formatList from event.dataTransfer.types
|
||||||
|
* @returns {Boolean} true if dataTransfer is valid (from a draggable-item source on this page), false otherwise
|
||||||
|
*/
|
||||||
|
function getDragSource (typesList) {
|
||||||
|
if (typesList.length !== 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const typeString = typesList[0];
|
||||||
|
const type = typeString.split("/");
|
||||||
|
if (type.length === 3 && type[0] === "application" && type[1] === "json" && draggableItemUUIDs[type[2]]) {
|
||||||
|
return { type: typeString, uuid: type[2], element: draggableItemUUIDs[type[2]] };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class DraggableContainer extends HTMLElement {
|
class DraggableContainer extends HTMLElement {
|
||||||
constructor () {
|
constructor () {
|
||||||
super();
|
super();
|
||||||
@ -22,10 +45,14 @@ class DraggableContainer extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
append (newNode) {
|
append (newNode) {
|
||||||
|
newNode.uuid = window.crypto.randomUUID();
|
||||||
|
draggableItemUUIDs[newNode.uuid] = newNode;
|
||||||
this.content.insertBefore(newNode, this.bottom);
|
this.content.insertBefore(newNode, this.bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
insertBefore (newNode, referenceNode) {
|
insertBefore (newNode, referenceNode) {
|
||||||
|
newNode.uuid = window.crypto.randomUUID();
|
||||||
|
draggableItemUUIDs[newNode.uuid] = newNode;
|
||||||
this.content.insertBefore(newNode, referenceNode);
|
this.content.insertBefore(newNode, referenceNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,6 +62,7 @@ class DraggableContainer extends HTMLElement {
|
|||||||
|
|
||||||
removeChild (node) {
|
removeChild (node) {
|
||||||
if (node && this.content.contains(node)) {
|
if (node && this.content.contains(node)) {
|
||||||
|
draggableItemUUIDs[node.uuid] = null;
|
||||||
this.content.removeChild(node);
|
this.content.removeChild(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -57,20 +85,25 @@ class DraggableContainer extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DraggableItem extends HTMLElement {
|
class DraggableItem extends HTMLElement {
|
||||||
|
uuid = null;
|
||||||
constructor () {
|
constructor () {
|
||||||
super();
|
super();
|
||||||
this.attachShadow({ mode: "open" });
|
this.attachShadow({ mode: "open" });
|
||||||
// for whatever reason, only grid layout seems to respect the parent's content bounds
|
// for whatever reason, only grid layout seems to respect the parent's content bounds
|
||||||
this.shadowRoot.innerHTML = `
|
this.shadowRoot.innerHTML = `
|
||||||
<style>
|
<style>
|
||||||
#drag {
|
#drag-over {
|
||||||
cursor: move;
|
height: 1.5em;
|
||||||
|
border: 1px dotted var(--main-text-color);
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: rgba(0,0,0,0.25);
|
||||||
}
|
}
|
||||||
img {
|
img {
|
||||||
height: 1em;
|
height: 1em;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<div id="drag-over" style="display: none;"></div>
|
||||||
<div id="wrapper">
|
<div id="wrapper">
|
||||||
<div style="min-height: 1.5em;"></div>
|
<div style="min-height: 1.5em;"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -80,8 +113,14 @@ class DraggableItem extends HTMLElement {
|
|||||||
this.addEventListener("dragstart", (event) => {
|
this.addEventListener("dragstart", (event) => {
|
||||||
this.content.style.opacity = "0.5";
|
this.content.style.opacity = "0.5";
|
||||||
const data = { id: this.id, data: this.data, content: this.content.innerHTML, value: this.value };
|
const data = { id: this.id, data: this.data, content: this.content.innerHTML, value: this.value };
|
||||||
event.dataTransfer.setData("application/json", JSON.stringify(data));
|
event.dataTransfer.setData(`application/json/${this.uuid}`, JSON.stringify(data));
|
||||||
event.dataTransfer.effectAllowed = "move";
|
event.dataTransfer.effectAllowed = "move";
|
||||||
|
const blank = document.createElement("img");
|
||||||
|
event.dataTransfer.setDragImage(blank, 0, 0);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.content.style.visibility = "hidden";
|
||||||
|
this.content.style.height = "0";
|
||||||
|
}, 0);
|
||||||
});
|
});
|
||||||
this.addEventListener("dragend", (event) => {
|
this.addEventListener("dragend", (event) => {
|
||||||
if (event.dataTransfer.dropEffect === "move") {
|
if (event.dataTransfer.dropEffect === "move") {
|
||||||
@ -92,13 +131,14 @@ class DraggableItem extends HTMLElement {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.addEventListener("dragenter", (event) => {
|
this.addEventListener("dragenter", (event) => {
|
||||||
if (event.target.dropTarget) {
|
const sourceElement = getDragSource(event.dataTransfer.types);
|
||||||
event.target.dragOver = true;
|
if (event.target.dropTarget && sourceElement) {
|
||||||
|
event.target.dragOver = sourceElement.element.innerHTML;
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
this.addEventListener("dragleave", (event) => {
|
this.addEventListener("dragleave", (event) => {
|
||||||
if (event.target.dragOver) {
|
if (event.target.dragOver && getDragSource(event.dataTransfer.types)) {
|
||||||
event.target.dragOver = false;
|
event.target.dragOver = false;
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -110,8 +150,9 @@ class DraggableItem extends HTMLElement {
|
|||||||
if (event.target.dragOver) {
|
if (event.target.dragOver) {
|
||||||
event.target.dragOver = false;
|
event.target.dragOver = false;
|
||||||
}
|
}
|
||||||
if (event.target.dropTarget) {
|
const sourceElement = getDragSource(event.dataTransfer.types);
|
||||||
const transfer = JSON.parse(event.dataTransfer.getData("application/json"));
|
if (event.target.dropTarget && sourceElement) {
|
||||||
|
const transfer = JSON.parse(event.dataTransfer.getData(sourceElement.type));
|
||||||
const item = document.createElement("draggable-item");
|
const item = document.createElement("draggable-item");
|
||||||
item.data = transfer.data;
|
item.data = transfer.data;
|
||||||
item.innerHTML = transfer.content;
|
item.innerHTML = transfer.content;
|
||||||
@ -119,6 +160,7 @@ class DraggableItem extends HTMLElement {
|
|||||||
item.dropTarget = true;
|
item.dropTarget = true;
|
||||||
item.id = transfer.id;
|
item.id = transfer.id;
|
||||||
item.value = transfer.data.value;
|
item.value = transfer.data.value;
|
||||||
|
item.uuid = sourceElement.uuid;
|
||||||
event.target.parentElement.insertBefore(item, event.target);
|
event.target.parentElement.insertBefore(item, event.target);
|
||||||
}
|
}
|
||||||
this.content.attributeStyleMap.clear();
|
this.content.attributeStyleMap.clear();
|
||||||
@ -154,13 +196,13 @@ class DraggableItem extends HTMLElement {
|
|||||||
set dragOver (dragOver) {
|
set dragOver (dragOver) {
|
||||||
if (dragOver) {
|
if (dragOver) {
|
||||||
this.classList.add("drag-over");
|
this.classList.add("drag-over");
|
||||||
// temp hover over effect
|
this.shadowRoot.querySelector("#drag-over").style.display = "block";
|
||||||
this.content.style.borderTop = "1px dotted";
|
this.shadowRoot.querySelector("#drag-over").innerHTML = dragOver;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.classList.remove("drag-over");
|
this.classList.remove("drag-over");
|
||||||
// temp hover over effect
|
this.shadowRoot.querySelector("#drag-over").style.display = "none";
|
||||||
this.content.style.borderTop = "";
|
this.shadowRoot.querySelector("#drag-over").innerHTML = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user