User:Beao/CropToolHotKeys.js
Jump to navigation
Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
Documentation for this user script can be added at User:Beao/CropToolHotKeys. |
// ==UserScript==
// @name CropToolHotKeys
// @namespace https://croptool.toolforge.org/
// @match https://croptool.toolforge.org/?title=*
// @description CropToolHotKeys (https://commons.wikimedia.org/wiki/User:Beao/CropToolHotKeys.js)
// @version 0.2
// @icon https://wikitech.wikimedia.org/favicon.ico
// @grant none
// ==/UserScript==
// A userscript to add hotkeys to CropTool
// https://croptool.toolforge.org/
// Confirmed to work in Firefox with Tampermonkey 2023-10-02
(function () {
"use strict";
angular.element(function () {
const q = (x) => document.querySelector(x);
document.addEventListener(
"keydown",
function (e) {
if (e.key.toLowerCase() === "x") {
q(".crop-tool-hotkeys").classList.toggle("crop-tool-hotkeys-hidden");
localStorage.setItem(
"crop-tool-hotkeys-hidden",
q(".crop-tool-hotkeys").classList.contains("crop-tool-hotkeys-hidden")
);
}
if (e.key === "Enter") {
if (q("[ladda=ladda]")?.getBoundingClientRect().width > 0) {
q("[ladda=ladda]").click();
} else if (q("[ladda=ladda2]")?.getBoundingClientRect().width > 0) {
q("[ladda=ladda2]").click();
}
}
if (e.key === "Backspace") {
if (q("[ng-click='back()']")) {
q("[ng-click='back()']").click();
}
}
keydown(e.key.toLowerCase(), e.shiftKey);
},
false
);
const keydown = (key, big) => {
const isCropping = q("[ladda=ladda]")?.getBoundingClientRect().width > 0;
if (!isCropping) return;
if (key === "e") {
q("[ng-click='locateBorder()']").click();
return;
}
if (key === "w") {
if (q("#crop-tool-image-viewer")) {
if (q("#crop-tool-image-viewer").style.backgroundColor === "black") {
q("#crop-tool-image-viewer").style.backgroundColor = "white";
} else {
q("#crop-tool-image-viewer").outerHTML = "";
}
} else {
const img = q(".cropper-canvas img");
const viewer = document.createElement("div");
viewer.id = "crop-tool-image-viewer";
viewer.style.position = "fixed";
viewer.style.top = "0";
viewer.style.left = "0";
viewer.style.width = "100%";
viewer.style.height = "100%";
viewer.style.backgroundColor = "black";
viewer.style.zIndex = "10000";
viewer.style.display = "flex";
viewer.style.justifyContent = "center";
viewer.style.alignItems = "center";
viewer.style.padding = "10px";
viewer.style.cursor = "pointer";
viewer.addEventListener("click", () => viewer.outerHTML = "");
const img2 = img.cloneNode();
img2.style.maxWidth = "100%";
img2.style.maxHeight = "100%";
viewer.appendChild(img2);
document.body.appendChild(viewer);
}
return;
}
const x = q("[ng-model='crop_dim.x']");
const y = q("[ng-model='crop_dim.y']");
const w = q("[ng-model='crop_dim.w']");
const h = q("[ng-model='crop_dim.h']");
const _x = parseInt(x.value, 10);
const _y = parseInt(y.value, 10);
const _w = parseInt(w.value, 10);
const _h = parseInt(h.value, 10);
if (!x || !y || !w || !h) return;
if (!q("[translate-value-width]")?.attributes["translate-value-width"]) {
return;
}
const maxW = parseInt(
q("[translate-value-width]").attributes["translate-value-width"].value,
10
);
const maxH = parseInt(
q("[translate-value-height]").attributes["translate-value-height"]
.value,
10
);
const step = big
? Math.max(Math.floor(maxW / 100), Math.floor(maxH / 100), 10)
: 1;
const c = (dim, delta) => {
dim.value = parseInt(dim.value, 10) + delta;
};
if (key === "r") {
x.value = 0;
y.value = 0;
w.value = maxW;
h.value = maxH;
}
const memRound = (x) => Math.round(x * 10000) / 10000;
if (key === "n") {
localStorage.setItem("crop-tool-hotkeys-x", memRound(_x / maxW));
localStorage.setItem("crop-tool-hotkeys-y", memRound(_y / maxH));
localStorage.setItem("crop-tool-hotkeys-w", memRound(_w / maxW));
localStorage.setItem("crop-tool-hotkeys-h", memRound(_h / maxH));
}
if (key === "m") {
const memoryX = parseFloat(localStorage.getItem("crop-tool-hotkeys-x") || "0");
const memoryY = parseFloat(localStorage.getItem("crop-tool-hotkeys-y") || "0");
const memoryW = parseFloat(localStorage.getItem("crop-tool-hotkeys-w") || "1");
const memoryH = parseFloat(localStorage.getItem("crop-tool-hotkeys-h") || "1");
x.value = Math.round(memoryX * maxW);
y.value = Math.round(memoryY * maxH);
w.value = Math.round(memoryW * maxW);
h.value = Math.round(memoryH * maxH);
}
if (key === "a" && _x >= step) {
c(x, -step);
c(w, step);
}
if (key === "s" && _y >= step) {
c(y, -step);
c(h, step);
}
if (key === "d" && _h >= step) {
c(y, step);
c(h, -step);
}
if (key === "f" && _w >= step) {
c(x, step);
c(w, -step);
}
if (key === "h" && _w >= step) c(w, -step);
if (key === "j" && _h >= step) c(h, -step);
if (key === "k" && _h + _y + step <= maxH) c(h, step);
if (key === "l" && _w + _x + step <= maxW) c(w, step);
if (key === "g") {
if (_w > 2 * step) {
c(x, step);
c(w, -2 * step);
}
if (_h > 2 * step) {
c(y, step);
c(h, -2 * step);
}
}
if (key === "t") {
if (_w + _x + 2 * step <= maxW) {
c(x, -step);
c(w, 2 * step);
}
if (_h + _y + 2 * step <= maxH) {
c(y, -step);
c(h, 2 * step);
}
}
x.dispatchEvent(new Event("input", { bubbles: true }));
y.dispatchEvent(new Event("input", { bubbles: true }));
w.dispatchEvent(new Event("input", { bubbles: true }));
h.dispatchEvent(new Event("input", { bubbles: true }));
};
const instructionsStyle = document.createElement("style");
instructionsStyle.innerHTML = `
.crop-tool-hotkeys {
position: fixed;
bottom: 0;
right: 0;
background: black;
color: white;
padding: 5px;
font-size: 10px;
z-index: 100000;
font-family: monospace;
line-height: 1.2;
gap: 5px;
opacity: 0.9;
transition: opacity 0.2s;
cursor: default;
}
.crop-tool-hotkeys-hidden {
opacity: 0.4;
cursor: pointer;
}
.crop-tool-hotkeys-hidden:hover {
opacity: 0.9;
}
.crop-tool-hotkeys-hidden p {
margin: 0;
}
.crop-tool-hotkeys-hidden section {
display: none;
}
`;
document.body.appendChild(instructionsStyle);
const instructions = document.createElement("div");
instructions.classList.add("crop-tool-hotkeys");
if (localStorage.getItem("crop-tool-hotkeys-hidden") === "true") {
instructions.classList.add("crop-tool-hotkeys-hidden");
}
instructions.innerHTML = `
<p><b>CropToolHotKeys</b></p>
<section>
<p><kbd>Enter</kbd> to crop or upload</p>
<p><kbd>Backspace</kbd> to go back</p>
<p><kbd>a</kbd> <kbd>s</kbd> <kbd>d</kbd> <kbd>f</kbd> to move upper left corner</p>
<p><kbd>h</kbd> <kbd>j</kbd> <kbd>k</kbd> <kbd>l</kbd> to move lower right corner</p>
<p><kbd>g</kbd> to shrink crop</p>
<p><kbd>t</kbd> to grow crop</p>
<p><kbd>shift</kbd> + <kbd>a/s/d/f/h/j/k/l/g/t</kbd> to move faster</p>
<p><kbd>r</kbd> to reset crop to full image</p>
<p><kbd>e</kbd> to auto-detect border</p>
<p><kbd>w</kbd> to toggle image viewer with black or white background</p>
<p><kbd>n</kbd> to save current crop percentage to memory</p>
<p><kbd>m</kbd> to load saved crop percentage</p>
<p><kbd>x</kbd> or click here to toggle this help</p>
</section>
`.replace(/\n\s*/g, "\n");
instructions.addEventListener("click", () => {
instructions.classList.toggle("crop-tool-hotkeys-hidden");
localStorage.setItem(
"crop-tool-hotkeys-hidden",
instructions.classList.contains("crop-tool-hotkeys-hidden")
);
});
document.body.appendChild(instructions);
});
})();