created gallery.mjs
This commit is contained in:
parent
0ccd3d7fcd
commit
c8801c6938
|
@ -0,0 +1,423 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name gallery.mjs
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Module for creating galleries with re-ordering
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* import gallery from "https://codepen.io/mirzaev-sexy/pen/RNPdYvv.js";
|
||||||
|
*
|
||||||
|
* // Initializing the instance
|
||||||
|
* const instance = new gallery(
|
||||||
|
* document.getElementById("wrap"),
|
||||||
|
* document.getElementById("images"),
|
||||||
|
* document.getElementById("gallery"),
|
||||||
|
* true
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* {@link https://git.svoboda.works/mirzaev/gallery.mjs}
|
||||||
|
* {@link https://codepen.io/mirzaev-sexy/pen/RNPdYvv}
|
||||||
|
*
|
||||||
|
* @todo 1. Instead of `ascend()`` create `remember()` and `restore()` methods
|
||||||
|
*
|
||||||
|
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
|
||||||
|
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||||
|
*/
|
||||||
|
export default class gallery {
|
||||||
|
/**
|
||||||
|
* @name Wrap
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Wrap for the gallery
|
||||||
|
*
|
||||||
|
* @type {HTMLElement}
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
#wrap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Input
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Input for importing images
|
||||||
|
*
|
||||||
|
* @type {HTMLInputElement}
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
#input;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Gallery
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Wrap for images <img> elements (`flex-flow: row wrap`)
|
||||||
|
*
|
||||||
|
* @type {HTMLElement}
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
#gallery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Identifiers
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Identifiers registry of loaded images (array proxy)
|
||||||
|
*
|
||||||
|
* @see https://stackoverflow.com/a/76599646 by Alexander Nenashev
|
||||||
|
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
|
||||||
|
*
|
||||||
|
* @type {Proxy}
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
#identifiers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Identifiers (get)
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Identifiers registry of loaded images (array proxy)
|
||||||
|
*
|
||||||
|
* @see https://stackoverflow.com/a/76599646 by Alexander Nenashev
|
||||||
|
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
|
||||||
|
*
|
||||||
|
* @return {array}
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
get identifiers() {
|
||||||
|
return this.#identifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Update
|
||||||
|
*
|
||||||
|
* @type {Promise|null}
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
#update;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Prefixes
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Prefixes for identifiers
|
||||||
|
*
|
||||||
|
* @type {object}
|
||||||
|
*/
|
||||||
|
prefixes = {
|
||||||
|
wrap: "",
|
||||||
|
image: "image_"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Dragged
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Buffer of currently dragged wrap identifier
|
||||||
|
*
|
||||||
|
* @type {string|number}
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
#dragged;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Events
|
||||||
|
*
|
||||||
|
* @type {Map}
|
||||||
|
*
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
#events = new Map([
|
||||||
|
[
|
||||||
|
"dragstart",
|
||||||
|
(event) => {
|
||||||
|
// Disabling default actions
|
||||||
|
this.#dragged = event.target.getAttribute("id");
|
||||||
|
|
||||||
|
// Allowing moving
|
||||||
|
event.dataTransfer.effectAllowed = "move";
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"dragover",
|
||||||
|
(event) => {
|
||||||
|
// Disabling default actions
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// Allowing moving
|
||||||
|
event.dataTransfer.dropEffect = "move";
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"dragenter",
|
||||||
|
(event) => {
|
||||||
|
// Searching for the wrap
|
||||||
|
const wrap = event.target.closest("div.image");
|
||||||
|
|
||||||
|
if (wrap?.getAttribute("id") !== this.#dragged) {
|
||||||
|
// Wrap is not currently draggable wrap
|
||||||
|
|
||||||
|
// Writing class about targeting
|
||||||
|
wrap?.classList.add("target");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"dragleave",
|
||||||
|
(event) => {
|
||||||
|
// Searching for the closest parent wrap
|
||||||
|
const wrap = event.target.closest("div.image");
|
||||||
|
|
||||||
|
if (wrap instanceof HTMLElement) {
|
||||||
|
// Found the wrap
|
||||||
|
|
||||||
|
// Deleting class about targeting
|
||||||
|
wrap.classList.remove("target");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"dragend",
|
||||||
|
(event) => {
|
||||||
|
// Searching for the closest parent wrap
|
||||||
|
const wrap = event.target.closest("div.image");
|
||||||
|
|
||||||
|
if (wrap instanceof HTMLElement) {
|
||||||
|
// Found the wrap
|
||||||
|
|
||||||
|
// Deleting class about targeting
|
||||||
|
wrap.target.classList.remove("target");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"drop",
|
||||||
|
(event) => {
|
||||||
|
// Searching for the closest parent wrap
|
||||||
|
const wrap = event.target.closest("div.image");
|
||||||
|
|
||||||
|
if (
|
||||||
|
wrap instanceof HTMLElement &&
|
||||||
|
wrap.getAttribute("id") &&
|
||||||
|
wrap.getAttribute("id") !== this.#dragged
|
||||||
|
) {
|
||||||
|
// Found the wrap and has it identifier and it not currently draggable wrap
|
||||||
|
|
||||||
|
// Deleting class about targeting from every wrap
|
||||||
|
this.#gallery
|
||||||
|
.querySelector("div.image.target")
|
||||||
|
?.classList.remove("target");
|
||||||
|
|
||||||
|
// Initializing indexes of wraps in the identifiers registry
|
||||||
|
const from = this.#identifiers.indexOf(this.#dragged);
|
||||||
|
const to = this.#identifiers.indexOf(wrap.getAttribute("id"));
|
||||||
|
|
||||||
|
// Swapping wraps
|
||||||
|
[this.#identifiers[from], this.#identifiers[to]] = [
|
||||||
|
this.#identifiers[to],
|
||||||
|
this.#identifiers[from]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Constructor
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Initialize the instance
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} wrap The wrap element
|
||||||
|
* @param {HTMLInputElement} input The input <input> element
|
||||||
|
* @param {HTMLElement} gallery The gallery element
|
||||||
|
* @param {boolean} [inject=false] Write the instance into the wrap element?
|
||||||
|
**/
|
||||||
|
constructor(wrap, input, gallery, inject = false) {
|
||||||
|
if (wrap instanceof HTMLElement) {
|
||||||
|
// Initialized the wrap element
|
||||||
|
|
||||||
|
// Writing the wrap
|
||||||
|
this.#wrap = wrap;
|
||||||
|
|
||||||
|
// Writing the instance into the wrap element
|
||||||
|
if (inject) this.#wrap.gallery = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input instanceof HTMLInputElement) {
|
||||||
|
// Initialized the input <input> element
|
||||||
|
|
||||||
|
// Writing the input
|
||||||
|
this.#input = input;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gallery instanceof HTMLElement) {
|
||||||
|
// Initialized the gallery element
|
||||||
|
|
||||||
|
// Writing the gallery
|
||||||
|
this.#gallery = gallery;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializing the identifiers registry proxy
|
||||||
|
this.proxy();
|
||||||
|
|
||||||
|
// Synchronizing the identifiers registry with images in the gallery element
|
||||||
|
this.#identifiers.push(
|
||||||
|
...[...this.#gallery.querySelectorAll("div.image")].map((image) =>
|
||||||
|
image.getAttribute("id")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Proxy
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Initialize the identifiers registry proxy
|
||||||
|
*/
|
||||||
|
proxy() {
|
||||||
|
// Initializing the identifiers registry
|
||||||
|
this.#identifiers = new Proxy([], {
|
||||||
|
set: (target, property, value) => {
|
||||||
|
// Postponing the update with a microtask
|
||||||
|
this.#update ??= Promise.resolve().then(() => {
|
||||||
|
// Deinitializing the update promise
|
||||||
|
this.#update = null;
|
||||||
|
|
||||||
|
// Generating the order row (can be deleted without any problems)
|
||||||
|
document.getElementById("order").textContent =
|
||||||
|
"Order: " + target.join(", ");
|
||||||
|
|
||||||
|
// Re-ordering wraps <div> elements by the identifiers registry
|
||||||
|
target.forEach((identifier) => {
|
||||||
|
this.#gallery.appendChild(document.getElementById(identifier));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Regenerating the identifiers registry and return (success)
|
||||||
|
return Reflect.set(target, property, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Ascending
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Sort images in ascending order
|
||||||
|
*/
|
||||||
|
ascending() {
|
||||||
|
this.#identifiers.sort((a, b) => a - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Start
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Start handling moving of images
|
||||||
|
*/
|
||||||
|
start() {
|
||||||
|
// Initializing events listeners
|
||||||
|
for (const [event, handler] of this.#events)
|
||||||
|
this.#gallery.addEventListener(event, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Stop
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Stop handling moving of images
|
||||||
|
*/
|
||||||
|
stop() {
|
||||||
|
// Deinitializing events listeners
|
||||||
|
for (const [event, handler] of this.#events)
|
||||||
|
this.#gallery.removeEventListener(event, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Import
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* Creating images <img> elements by loaded images
|
||||||
|
*
|
||||||
|
* @param {FileList} files Loaded images
|
||||||
|
*/
|
||||||
|
import(files) {
|
||||||
|
// Stopping events handlers
|
||||||
|
this.stop();
|
||||||
|
|
||||||
|
// Initializing the identifiers registry proxy
|
||||||
|
this.proxy();
|
||||||
|
|
||||||
|
// Deleting deprecated images from the gallery
|
||||||
|
this.#gallery.innerHTML = "";
|
||||||
|
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
// Iterating over imported images
|
||||||
|
|
||||||
|
// Creating the wrap <div> element
|
||||||
|
const wrap = document.createElement("div");
|
||||||
|
wrap.classList.add("image");
|
||||||
|
wrap.setAttribute("id", this.prefixes.wrap + i);
|
||||||
|
wrap.setAttribute("draggable", true);
|
||||||
|
|
||||||
|
// Creating the button <button> element
|
||||||
|
const button = document.createElement("button");
|
||||||
|
button.classList.add("delete");
|
||||||
|
button.addEventListener("click", (event) => {
|
||||||
|
// Deleting the identifier
|
||||||
|
|
||||||
|
// Initializing index of the wrap
|
||||||
|
const index = this.#identifiers.indexOf(this.prefixes.wrap + i);
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
// Initialized index of the wrap
|
||||||
|
|
||||||
|
// Deleting identifier of the wrap from the identifiers registry
|
||||||
|
this.#identifiers.splice(index, 1);
|
||||||
|
|
||||||
|
// Deleting the wrap
|
||||||
|
wrap.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Creating the trash icon <i> element
|
||||||
|
const trash = document.createElement("i");
|
||||||
|
trash.classList.add("icon", "trash");
|
||||||
|
|
||||||
|
// Creating the image <img> element
|
||||||
|
const image = document.createElement("img");
|
||||||
|
image.setAttribute("id", this.prefixes.image + i);
|
||||||
|
image.setAttribute("draggable", false);
|
||||||
|
image.setAttribute("src", URL.createObjectURL(files[i]));
|
||||||
|
|
||||||
|
// Writing into the gallery
|
||||||
|
button.appendChild(trash);
|
||||||
|
wrap.appendChild(image);
|
||||||
|
wrap.appendChild(button);
|
||||||
|
this.#gallery.appendChild(wrap);
|
||||||
|
|
||||||
|
// Writing into the identifiers registry
|
||||||
|
this.#identifiers.push(wrap.getAttribute("id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starting events handlers
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue