aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--index.html2
-rw-r--r--index.js151
-rw-r--r--styles.css10
3 files changed, 124 insertions, 39 deletions
diff --git a/index.html b/index.html
index e62ed72..9cec0e8 100644
--- a/index.html
+++ b/index.html
@@ -51,7 +51,7 @@
</div>
<section class='images'></section>
</div>
- <p class='hint'>Hint: you can paste an image into this page to have it show up in the image list.</p>
+ <p class='hint'>Hint: drag an image left/right within the same row to reorder it quickly. You can also paste an image into this page to add it to the image list.</p>
</div>
</section>
<div class="top-container">
diff --git a/index.js b/index.js
index c5d07a2..cf1591b 100644
--- a/index.js
+++ b/index.js
@@ -33,6 +33,8 @@ let headers_orig_min_width;
let untiered_images;
let tierlist_div;
let dragged_image;
+let dragged_item;
+let drop_placeholder;
function reset_row(row) {
row.querySelectorAll('span.item').forEach((item) => {
@@ -205,9 +207,17 @@ function create_img_with_src(src) {
img.draggable = true;
img.addEventListener("dragstart", (evt) => {
- evt.dataTransfer.setData("text/plain", null);
+ evt.dataTransfer.setData("text/plain", '');
+ evt.dataTransfer.effectAllowed = 'move';
dragged_image = evt.target;
+ dragged_item = wrap_image_in_item(dragged_image);
dragged_image.classList.add("dragged");
+
+ drop_placeholder = document.createElement('span');
+ drop_placeholder.classList.add('item', 'drop-placeholder');
+ let rect = dragged_item.getBoundingClientRect();
+ drop_placeholder.style.width = `${Math.max(30, Math.ceil(rect.width))}px`;
+ drop_placeholder.style.height = `${Math.max(30, Math.ceil(rect.height))}px`;
});
img.addEventListener("mouseenter", (evt) => {
@@ -217,11 +227,16 @@ function create_img_with_src(src) {
}
});
- img.addEventListener("dragend", (evt) => {
+ img.addEventListener("dragend", () => {
if (dragged_image) {
dragged_image.classList.remove("dragged");
}
+ if (drop_placeholder && drop_placeholder.parentNode) {
+ drop_placeholder.parentNode.removeChild(drop_placeholder);
+ }
dragged_image = null;
+ dragged_item = null;
+ drop_placeholder = null;
});
return img;
@@ -375,68 +390,116 @@ function load_tierlist(serialized_tierlist) {
unsaved_changes = false;
}
-function end_drag(evt) {
+function end_drag() {
if (dragged_image) {
dragged_image.classList.remove("dragged");
}
+ if (drop_placeholder && drop_placeholder.parentNode) {
+ drop_placeholder.parentNode.removeChild(drop_placeholder);
+ }
dragged_image = null;
+ dragged_item = null;
+ drop_placeholder = null;
}
window.addEventListener('mouseup', end_drag);
window.addEventListener('dragend', end_drag);
+function wrap_image_in_item(img) {
+ let parent = img.parentNode;
+ if (parent && parent.tagName.toUpperCase() === 'SPAN' && parent.classList.contains('item')) {
+ return parent;
+ }
+
+ let wrapper = document.createElement('span');
+ wrapper.classList.add('item');
+ parent.insertBefore(wrapper, img);
+ wrapper.appendChild(img);
+ return wrapper;
+}
+
+function get_drop_container(elem) {
+ let items_container = elem.querySelector('.items');
+ return items_container || elem;
+}
+
+function get_drop_reference(container, x, y) {
+ let children = Array.from(container.children).filter((child) => {
+ if (child === dragged_item || child === drop_placeholder) return false;
+ if (child.classList && child.classList.contains('item')) return true;
+ return child.tagName && child.tagName.toUpperCase() === 'IMG';
+ });
+
+ for (let child of children) {
+ let rect = child.getBoundingClientRect();
+ if (y < rect.top) {
+ return child;
+ }
+ if (y <= rect.bottom && x < rect.left + rect.width / 2) {
+ return child;
+ }
+ }
+
+ return null;
+}
+
function make_accept_drop(elem) {
elem.classList.add('droppable');
elem.addEventListener('dragenter', (evt) => {
evt.preventDefault();
- evt.target.classList.add('drag-entered');
+ elem.classList.add('drag-entered');
});
elem.addEventListener('dragleave', (evt) => {
- evt.target.classList.remove('drag-entered');
+ if (elem.contains(evt.relatedTarget)) {
+ return;
+ }
+ elem.classList.remove('drag-entered');
});
elem.addEventListener('dragover', (evt) => {
evt.preventDefault();
+ if (!dragged_item || !drop_placeholder) {
+ return;
+ }
+
+ let items_container = get_drop_container(elem);
+ let reference = get_drop_reference(items_container, evt.clientX, evt.clientY);
+ if (reference) {
+ items_container.insertBefore(drop_placeholder, reference);
+ } else {
+ items_container.appendChild(drop_placeholder);
+ }
});
elem.addEventListener('drop', (evt) => {
evt.preventDefault();
- evt.target.classList.remove('drag-entered');
-
- if (!dragged_image) {
+ elem.classList.remove('drag-entered');
+ if (!dragged_item) {
return;
}
- let dragged_image_parent = dragged_image.parentNode;
- if (dragged_image_parent.tagName.toUpperCase() === 'SPAN' &&
- dragged_image_parent.classList.contains('item')) {
- let containing_tr = dragged_image_parent.parentNode;
- containing_tr.removeChild(dragged_image_parent);
+ let items_container = get_drop_container(elem);
+ if (drop_placeholder && drop_placeholder.parentNode === items_container) {
+ items_container.insertBefore(dragged_item, drop_placeholder);
+ drop_placeholder.parentNode.removeChild(drop_placeholder);
} else {
- dragged_image_parent.removeChild(dragged_image);
+ let reference = get_drop_reference(items_container, evt.clientX, evt.clientY);
+ if (reference) {
+ items_container.insertBefore(dragged_item, reference);
+ } else {
+ items_container.appendChild(dragged_item);
+ }
}
- let td = document.createElement('span');
- td.classList.add('item');
- td.appendChild(dragged_image);
- let items_container = elem.querySelector('.items');
-
- if (!items_container) {
- items_container = elem;
+ if (dragged_image) {
+ dragged_image.classList.remove("dragged");
}
- items_container.appendChild(td);
-
- dragged_image.draggable = true;
- dragged_image.classList.remove("dragged");
-
- dragged_image.addEventListener("dragstart", (e) => {
- e.dataTransfer.setData("text/plain", null);
- dragged_image.classList.add("dragged");
- });
-
+ dragged_image = null;
+ dragged_item = null;
+ drop_placeholder = null;
unsaved_changes = true;
});
}
@@ -597,15 +660,27 @@ function bind_trash_events() {
trash.addEventListener('drop', (evt) => {
evt.preventDefault();
evt.target.src = 'img/trash.svg';
- if (dragged_image) {
- let dragged_image_parent = dragged_image.parentNode;
- if (dragged_image_parent.tagName.toUpperCase() === 'SPAN' &&
- dragged_image_parent.classList.contains('item')) {
- let containing_tr = dragged_image_parent.parentNode;
- containing_tr.removeChild(dragged_image_parent);
- }
+ if (!dragged_item && !dragged_image) {
+ return;
+ }
+
+ if (drop_placeholder && drop_placeholder.parentNode) {
+ drop_placeholder.parentNode.removeChild(drop_placeholder);
+ }
+
+ if (dragged_item) {
+ dragged_item.remove();
+ } else if (dragged_image) {
dragged_image.remove();
}
+
+ if (dragged_image) {
+ dragged_image.classList.remove('dragged');
+ }
+ dragged_image = null;
+ dragged_item = null;
+ drop_placeholder = null;
+ unsaved_changes = true;
});
}
diff --git a/styles.css b/styles.css
index 994c882..821c0df 100644
--- a/styles.css
+++ b/styles.css
@@ -108,6 +108,16 @@ span.items {
span.item {
pointer-events: auto;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+span.item.drop-placeholder {
+ pointer-events: none;
+ border: 2px dashed #aaa;
+ background-color: rgba(255, 255, 255, 0.15);
+ box-sizing: border-box;
}
.images {
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage