クリックでON・OFFできるチェックボックスUserScript_ver2
code:script.js
const writeText = (text) => {
const textArea = document.getElementById("text-input");
textArea.value = text;
textArea.dispatchEvent(
new InputEvent("input", { bubbles: true, cancelable: true })
);
}
const sleep = async (ms) => {
return new Promise(resolve => setTimeout(resolve, ms));
}
class KeydownEvent {
constructor() {
this.textArea = document.getElementById("text-input");
this.event = document.createEvent("UIEvent");
this.event.initEvent("keydown", true, true);
}
dispatch(
keyCode,
withShift = false,
withCtrl = false,
withAlt = false,
withCommand = false
) {
this.event.keyCode = keyCode;
this.event.shiftKey = withShift;
this.event.ctrlKey = withCtrl;
this.event.altKey = withAlt;
this.event.metaKey = withCommand;
this.textArea.dispatchEvent(this.event);
}
}
const isHeightViewable = (element) => {
const { top, bottom } = element.getBoundingClientRect();
return top >= 0 && bottom <= window.innerHeight;
}
const click = async (element, { button = 0, X, Y, shiftKey = false, ctrlKey = false, altKey = false, wait = 10 } = {}) => {
const mouseOptions = {
button: 0,
clientX: X,
clientY: Y,
bubbles: true,
cancelable: true,
shiftKey: shiftKey,
ctrlKey: ctrlKey,
altKey: altKey,
view: window,
};
element.dispatchEvent(new MouseEvent("mousedown", mouseOptions));
element.dispatchEvent(new MouseEvent("mouseup", mouseOptions));
element.dispatchEvent(new MouseEvent("click", mouseOptions));
await sleep(wait);
}
const goChar = async (lineId, pos) => {
const line = document.getElementById(lineId);
const charDOM = line.getElementsByClassName(c-${pos})0; if (!isHeightViewable(charDOM)) charDOM.scrollIntoView({ block: 'center' });
const rect = charDOM.getBoundingClientRect();
await click(charDOM, { X: rect.left, Y: rect.top + 1 });
}
const blur = () => {
const textarea = document.getElementById('text-input');
const reactKey = Object.keys(textarea).find((key) => key.startsWith("__reactFiber"));
const input = textareareactKey.return.return.stateNode; const cursor = input._stores.find((obj) => obj.hide);
cursor.hide();
}
const icons = {
check: {
path: "/iwsq/check.icon",
nextName: "uncheck"
},
uncheck: {
path: "/iwsq/uncheck.icon",
nextName: "check"
}
}
function getCursorLineString() {
return document.querySelector(".lines div.line.cursor-line")?.textContent;
}
const escapedIconPaths = Object.values(icons)
.map(({ path }) => (path)
.replaceAll(".", "\\.")
.replaceAll("[", "\\[")
.replaceAll("]", "\\]")
);
const startsWithIconsReg = new RegExp("^\\s*(" + escapedIconPaths.join("|") + ")");
scrapbox.PopupMenu.addButton({
title: "make todo",
onClick: (text) => {
return ${icons.uncheck.path} ${text};
}
});
$("#text-input").on("keydown", async (e) => {
if (e.key !== "Enter" || e.originalEvent.isComposing) return;
const currentLineString = getCursorLineString();
if (!startsWithIconsReg.test(currentLineString)) return;
await sleep(10);
writeText(icons.uncheck.path + " ");
});
$("#app-container").on("click", "img.icon", async (e) => {
e.preventDefault();
try {
const $icon = $(e.currentTarget);
const iconIndex = $icon.parent().siblings().attr("data-char-index")
const iconName = $icon.attr("title");
if (!icon) return;
const lineId = $icon.closest("div.line").first().attr("id");
await goChar(lineId, iconIndex);
blur();
} catch (error) {
console.error(error);
}
return false;
});