2024-07-17 19:49:13 +00:00
|
|
|
const blank = document.createElement("img");
|
2023-09-13 20:03:36 +00:00
|
|
|
|
2023-08-14 23:42:02 +00:00
|
|
|
class DraggableContainer extends HTMLElement {
|
|
|
|
constructor () {
|
|
|
|
super();
|
|
|
|
this.attachShadow({ mode: "open" });
|
|
|
|
this.shadowRoot.innerHTML = `
|
2024-07-17 19:49:13 +00:00
|
|
|
<style>
|
|
|
|
draggable-item.ghost::part(wrapper) {
|
|
|
|
border: 1px dashed var(--main-text-color);
|
|
|
|
border-radius: 5px;
|
|
|
|
margin: -1px;
|
|
|
|
}
|
2024-07-24 19:32:40 +00:00
|
|
|
draggable-item::part(wrapper) {
|
|
|
|
cursor: grab;
|
|
|
|
}
|
2024-07-17 19:49:13 +00:00
|
|
|
</style>
|
2023-08-14 23:42:02 +00:00
|
|
|
<label id="title"></label>
|
2024-07-17 19:49:13 +00:00
|
|
|
<div id="wrapper" style="padding-bottom: 1em;"></div>
|
2023-08-14 23:42:02 +00:00
|
|
|
`;
|
|
|
|
this.content = this.shadowRoot.querySelector("#wrapper");
|
|
|
|
this.titleElem = this.shadowRoot.querySelector("#title");
|
2024-07-17 19:49:13 +00:00
|
|
|
|
|
|
|
window.Sortable.create(this.content, {
|
|
|
|
group: "boot",
|
|
|
|
ghostClass: "ghost",
|
|
|
|
setData: function (dataTransfer, dragEl) {
|
|
|
|
dataTransfer.setDragImage(blank, 0, 0);
|
|
|
|
}
|
|
|
|
});
|
2023-08-14 23:42:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
get title () {
|
|
|
|
return this.titleElem.innerText;
|
|
|
|
}
|
|
|
|
|
|
|
|
set title (title) {
|
|
|
|
this.titleElem.innerText = title;
|
|
|
|
}
|
|
|
|
|
|
|
|
append (newNode) {
|
2024-07-17 19:49:13 +00:00
|
|
|
this.content.appendChild(newNode, this.bottom);
|
2023-08-14 23:42:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
insertBefore (newNode, referenceNode) {
|
|
|
|
this.content.insertBefore(newNode, referenceNode);
|
|
|
|
}
|
2023-08-16 23:14:42 +00:00
|
|
|
|
2023-09-07 21:42:19 +00:00
|
|
|
querySelector (query) {
|
|
|
|
return this.content.querySelector(query);
|
2023-08-22 21:23:14 +00:00
|
|
|
}
|
|
|
|
|
2023-09-07 21:42:19 +00:00
|
|
|
removeChild (node) {
|
|
|
|
if (node && this.content.contains(node)) {
|
2023-08-16 23:14:42 +00:00
|
|
|
this.content.removeChild(node);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2023-08-19 03:32:52 +00:00
|
|
|
|
|
|
|
set value (value) {}
|
|
|
|
|
|
|
|
get value () {
|
|
|
|
const value = [];
|
|
|
|
this.content.childNodes.forEach((element) => {
|
|
|
|
if (element.value) {
|
|
|
|
value.push(element.value);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return value;
|
|
|
|
}
|
2023-08-14 23:42:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class DraggableItem extends HTMLElement {
|
2023-09-13 20:03:36 +00:00
|
|
|
uuid = null;
|
2023-08-14 23:42:02 +00:00
|
|
|
constructor () {
|
|
|
|
super();
|
|
|
|
this.attachShadow({ mode: "open" });
|
2023-08-16 23:14:42 +00:00
|
|
|
// for whatever reason, only grid layout seems to respect the parent's content bounds
|
2023-08-14 23:42:02 +00:00
|
|
|
this.shadowRoot.innerHTML = `
|
|
|
|
<style>
|
2024-07-24 19:32:40 +00:00
|
|
|
img, svg {
|
2023-08-16 23:14:42 +00:00
|
|
|
height: 1em;
|
|
|
|
width: 1em;
|
2023-08-14 23:42:02 +00:00
|
|
|
}
|
2024-07-17 19:49:13 +00:00
|
|
|
* {
|
|
|
|
-webkit-box-sizing: border-box;
|
|
|
|
-moz-box-sizing: border-box;
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
2023-08-14 23:42:02 +00:00
|
|
|
</style>
|
2024-07-17 19:49:13 +00:00
|
|
|
<div id="wrapper" part="wrapper"></div>
|
2023-08-14 23:42:02 +00:00
|
|
|
`;
|
|
|
|
this.content = this.shadowRoot.querySelector("#wrapper");
|
|
|
|
}
|
|
|
|
|
|
|
|
get innerHTML () {
|
|
|
|
return this.content.innerHTML;
|
|
|
|
}
|
|
|
|
|
|
|
|
set innerHTML (innerHTML) {
|
|
|
|
this.content.innerHTML = innerHTML;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
customElements.define("draggable-container", DraggableContainer);
|
|
|
|
customElements.define("draggable-item", DraggableItem);
|