Last active
March 30, 2022 13:05
-
-
Save addam/abceced29dd9d13e2a9e8e82f5752c01 to your computer and use it in GitHub Desktop.
html tool for manual sorting photos on local disk
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="list.js"></script> | |
<script> | |
// generate list.js from images in current directory: | |
// (echo 'imageList = ['; ls *.{jpg,jpeg,JPG,JPEG} | sed -E 's/(.*)/"\1",/p'; echo ']') > list.js | |
// generate list.js from images in subdirectories of the current one: | |
// (echo 'imageList = ['; ( for d in *; do ls "$d"/*.{jpg,jpeg,JPG,JPEG}; done) | sed -E 's/(.*)/"\1",/p'; echo ']') > list.js | |
var lastClicked; | |
function qsa(selector) { | |
return document.querySelectorAll(selector) | |
} | |
function cel(name, parameters={}) { | |
const element = document.createElement(name); | |
for (const param in parameters) { | |
element[param] = parameters[param]; | |
} | |
return element; | |
} | |
function clearClass(cls) { | |
for (it of qsa(`.${cls}`)) { | |
it.classList.remove(cls) | |
} | |
} | |
function imgOnclick(event) { | |
const img = event.target; | |
if (event.shiftKey) { | |
let it = lastClicked; | |
while (it != img) { | |
it = it.nextElementSibling; | |
it.classList.add("selected"); | |
} | |
} else if (event.ctrlKey) { | |
img.classList.toggle("selected"); | |
} else { | |
clearClass("selected") | |
img.classList.add("selected") | |
} | |
lastClicked = img; | |
} | |
function imgOnload(event) { | |
const img = event.target; | |
img.title = `${img.naturalWidth}×${img.naturalHeight}`; | |
} | |
function imgOndragover(ev) { | |
ev.preventDefault(); | |
clearClass("drop") | |
ev.target.classList.add("drop"); | |
} | |
function imgOndragstart(ev) { | |
if (!ev.target.classList.contains("selected")) { | |
clearClass("selected") | |
ev.target.classList.add("selected"); | |
} | |
ev.dataTransfer.setData("text", "imagesorter"); | |
for (const it of qsa(".selected")) { | |
it.classList.add("drag"); | |
} | |
} | |
function imgOndrop(ev) { | |
ev.preventDefault(); | |
if (ev.dataTransfer.getData("text") === "imagesorter") { | |
const img = ev.target; | |
for (const it of qsa(".drag")) { | |
img.parentNode.insertBefore(it, img); | |
} | |
} | |
clearClass("drag") | |
clearClass("drop") | |
} | |
function windowOnload() { | |
const body = document.body; | |
for (const src of imageList) { | |
body.appendChild(cel("img", {src, alt:src, onclick: imgOnclick, onload: imgOnload, draggable: true, ondragstart: imgOndragstart, ondrop: imgOndrop, ondragover: imgOndragover})) | |
} | |
} | |
function keyDown(event) { | |
if (!(event.ctrlKey || event.shiftKey || event.altKey || event.metaKey)) { | |
if (event.key == "Delete") { | |
if (Array.from(qsa(".selected")).every(it => it.classList.contains("delete"))) { | |
for (const it of qsa(".selected")) { | |
it.classList.remove("delete"); | |
} | |
} else { | |
for (const it of qsa(".selected")) { | |
it.classList.add("delete"); | |
} | |
} | |
} else { | |
return; | |
} | |
event.preventDefault() | |
} | |
} | |
function downloadOnclick(event) { | |
const a = event.target; | |
const data = Array.from(qsa("img:not(.delete)")).map(it => it.alt); | |
const code = `imageList = ${JSON.stringify(data, null, 2)}`; | |
a.href = `data:application/javascript,${encodeURI(code)}`; | |
} | |
window.onload = windowOnload; | |
document.onkeydown = keyDown; | |
</script> | |
<title>Image sorter</title> | |
<style> | |
body { | |
display: flex; | |
flex-wrap: wrap; | |
} | |
img { | |
max-height: 300px; | |
box-sizing: border-box; | |
} | |
.drag { | |
opacity: 20%; | |
} | |
.delete { | |
border: 3px solid red; | |
opacity: 70%; | |
} | |
.selected { | |
border: 5px solid paleturquoise; | |
} | |
.drop { | |
border-left: 5em solid paleturquoise; | |
} | |
</style> | |
</head> | |
<body> | |
<a download="list.js" href="#" onclick="return downloadOnclick(event)">download list.js</a><br> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment