mirror of
https://github.com/chylex/Userscripts.git
synced 2025-08-19 12:25:00 +02:00
Compare commits
1 Commits
bcaebeca36
...
vim-bindin
Author | SHA1 | Date | |
---|---|---|---|
390626f99f
|
@@ -1,20 +0,0 @@
|
|||||||
// ==UserScript==
|
|
||||||
// @name Patreon - Click Anywhere to Close Image Dialog
|
|
||||||
// @description Close modal image dialog by clicking anywhere on the page.
|
|
||||||
// @version 1
|
|
||||||
// @license MPL-2.0
|
|
||||||
// @namespace https://chylex.com
|
|
||||||
// @homepageURL https://github.com/chylex/Userscripts
|
|
||||||
// @supportURL https://github.com/chylex/Userscripts/issues
|
|
||||||
// @include https://www.patreon.com/*
|
|
||||||
// @run-at document-idle
|
|
||||||
// @grant none
|
|
||||||
// ==/UserScript==
|
|
||||||
|
|
||||||
document.body.addEventListener("click", e => {
|
|
||||||
if (e.target.tagName === "IMG" && e.target.getAttribute("data-tag") === "lightboxImage") {
|
|
||||||
document.querySelector("[data-tag='close']")?.click();
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
});
|
|
20
README.md
20
README.md
@@ -44,15 +44,6 @@ Before you [report an issue](https://github.com/chylex/Userscripts/issues/new) (
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th width="110px" rowspan="1">Patreon</th>
|
|
||||||
<td width="325px"><a href="#click-anywhere-to-close-image-dialog">Click Anywhere to Close Image Dialog</a></td>
|
|
||||||
<td>Script</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -140,17 +131,6 @@ Adds a button to load all pages in the [Crashes](https://openeye.openmods.info/c
|
|||||||
\-
|
\-
|
||||||
\[ [Source code](https://github.com/chylex/Userscripts/blob/master/OpenEye/LoadAllPages.user.js) \]
|
\[ [Source code](https://github.com/chylex/Userscripts/blob/master/OpenEye/LoadAllPages.user.js) \]
|
||||||
|
|
||||||
---
|
|
||||||
### Patreon
|
|
||||||
|
|
||||||
#### Click Anywhere to Close Image Dialog
|
|
||||||
Close modal image dialog by clicking anywhere on the page.
|
|
||||||
\[ [Automatically updated](https://github.com/chylex/Userscripts/raw/master/Patreon/ClickAnywhereToCloseImageDialog.user.js) \]
|
|
||||||
\-
|
|
||||||
\[ [Manually updated](https://github.com/chylex/Userscripts/raw/6b2f3698dc7082a57afa82470422f5c3418f1938/Patreon/ClickAnywhereToCloseImageDialog.user.js) \]
|
|
||||||
\-
|
|
||||||
\[ [Source code](https://github.com/chylex/Userscripts/blob/master/Patreon/ClickAnywhereToCloseImageDialog.user.js) \]
|
|
||||||
|
|
||||||
---
|
---
|
||||||
### Reddit
|
### Reddit
|
||||||
|
|
||||||
|
279
Vim/VimBindings.user.js
Normal file
279
Vim/VimBindings.user.js
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
// ==UserScript==
|
||||||
|
// @name Vim Bindings
|
||||||
|
// @description Reformats the Vim index help page and adds custom notes to each binding.
|
||||||
|
// @author chylex
|
||||||
|
// @version 1
|
||||||
|
// @license MIT
|
||||||
|
// @namespace https://chylex.com
|
||||||
|
// @homepageURL https://github.com/chylex/Userscripts
|
||||||
|
// @supportURL https://github.com/chylex/Userscripts/issues
|
||||||
|
// @include https://vimhelp.org/index.txt.html
|
||||||
|
// @run-at document-end
|
||||||
|
// @grant none
|
||||||
|
// ==/UserScript==
|
||||||
|
|
||||||
|
const settings = loadSettings();
|
||||||
|
|
||||||
|
function loadSettings() {
|
||||||
|
try {
|
||||||
|
const json = localStorage.getItem("vim_binding_settings");
|
||||||
|
return json === null ? {} : JSON.parse(json);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Could not load binding settings", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveSettings() {
|
||||||
|
localStorage.setItem("vim_binding_settings", JSON.stringify(settings));
|
||||||
|
}
|
||||||
|
|
||||||
|
appendElement(document.head, "style").textContent = `
|
||||||
|
#vh-content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#vh-content pre {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.h {
|
||||||
|
border-bottom: 2px dashed var(--aqua);
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.h td, tr:has(+ tr.subsection) td {
|
||||||
|
padding-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.h + tr td, tr.subsection + tr td {
|
||||||
|
padding-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 2px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:first-child {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:last-child {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.subsection td {
|
||||||
|
padding-top: 12px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-top: 1px dashed var(--aqua);
|
||||||
|
border-bottom: 1px dashed var(--aqua);
|
||||||
|
}
|
||||||
|
|
||||||
|
tr[data-binding-value="used"],
|
||||||
|
tr[data-binding-value="changed"],
|
||||||
|
tr[data-binding-value="rebound"],
|
||||||
|
tr[data-binding-value="not-used"] {
|
||||||
|
opacity: 0.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.missing {
|
||||||
|
opacity: 0.35;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
border: 0;
|
||||||
|
padding: 3px 5px;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
select, select option {
|
||||||
|
font-family: monospace;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
let headingIndex = 0;
|
||||||
|
|
||||||
|
/** @var {Object<string, HTMLSelectElement[]>} */
|
||||||
|
const selectsByBinding = {};
|
||||||
|
|
||||||
|
for (const headingEle of document.querySelectorAll("span[class='h']:has(+ span[class='h'])")) {
|
||||||
|
const delimiterEle = headingEle.nextElementSibling;
|
||||||
|
|
||||||
|
const columnNames = headingEle.textContent.split(/(?<!^)(?:\t+\s*|(?<=note ))(?!$)/).map(name => name.trim());
|
||||||
|
|
||||||
|
const tableEle = document.createElement("table");
|
||||||
|
addHeadingRow(tableEle, columnNames);
|
||||||
|
|
||||||
|
let currentNode = delimiterEle.nextSibling;
|
||||||
|
let html = "";
|
||||||
|
|
||||||
|
while (currentNode !== null && !isTagWithClass(currentNode, "SPAN", "h")) {
|
||||||
|
html += currentNode.nodeType === Node.ELEMENT_NODE ? currentNode.outerHTML : currentNode.textContent;
|
||||||
|
|
||||||
|
const nextNode = currentNode.nextSibling;
|
||||||
|
currentNode.remove();
|
||||||
|
currentNode = nextNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const line of html.split(/\n(?=<a|\t{1,3}[^\t]|\n)/)) {
|
||||||
|
addContentRow(tableEle, line, columnNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
headingEle.insertAdjacentElement("beforebegin", tableEle);
|
||||||
|
headingEle.remove();
|
||||||
|
delimiterEle.remove();
|
||||||
|
|
||||||
|
++headingIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isColumnRightAligned(columnName) {
|
||||||
|
return columnName === "note";
|
||||||
|
}
|
||||||
|
|
||||||
|
function addHeadingRow(table, columnNames) {
|
||||||
|
const tr = appendElement(table, "tr");
|
||||||
|
tr.classList.add("h");
|
||||||
|
|
||||||
|
appendElement(tr, "td");
|
||||||
|
|
||||||
|
for (const columnName of columnNames) {
|
||||||
|
const td = appendElement(tr, "td");
|
||||||
|
td.innerText = columnName;
|
||||||
|
|
||||||
|
if (isColumnRightAligned(columnName)) {
|
||||||
|
td.style.textAlign = "right";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addContentRow(table, line, columnNames) {
|
||||||
|
if (line.includes("Meta characters (0x80 to 0xff, 128 to 255)")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.info(line);
|
||||||
|
|
||||||
|
const columnCount = columnNames.length;
|
||||||
|
const matches = line.match(/^(?:(<a .+?<\/a>)\s+|\t{2})(.*?)(?:(?:\t+?\s*| {2}\t*|(?<=] )|(?<=<span class="s">{.+?}<\/span> (?!(?:<a .+?class="s">.+?<\/a> )?<span class="s">{.+?}<\/span>)))(?:(\d+(?:,\d+)*)\s+)?(.*))?$/s);
|
||||||
|
|
||||||
|
if (matches === null) {
|
||||||
|
addSubsectionRow(table, line, columnCount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var {HTMLTableRowElement} */
|
||||||
|
const tr = appendElement(table, "tr");
|
||||||
|
|
||||||
|
/** @var {HTMLTableCellElement[]} */
|
||||||
|
const tds = [ appendElement(tr, "td") ];
|
||||||
|
|
||||||
|
for (let matchIndex = 1; matchIndex < matches.length; matchIndex++) {
|
||||||
|
let td = tds[tds.length - 1];
|
||||||
|
|
||||||
|
if (matchIndex <= columnCount) {
|
||||||
|
tds.push(td = appendElement(tr, "td"));
|
||||||
|
|
||||||
|
if (isColumnRightAligned(columnNames[matchIndex - 1])) {
|
||||||
|
td.style.textAlign = "right";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (td.innerHTML.length > 0) {
|
||||||
|
td.innerHTML += " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = matches[matchIndex];
|
||||||
|
if (match !== undefined) {
|
||||||
|
td.innerHTML += match
|
||||||
|
.replaceAll("\t", "")
|
||||||
|
.replace(/\n\s*/g, " ")
|
||||||
|
.replace("<MiddleMouse>", "<MiddleMouse>")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bindingElements = tds[1].getElementsByClassName("l");
|
||||||
|
|
||||||
|
if (bindingElements.length === 1) {
|
||||||
|
const binding = bindingElements[0].innerText;
|
||||||
|
const select = appendElement(tds[0], "select");
|
||||||
|
|
||||||
|
addOption(select, "TBD", "");
|
||||||
|
addOption(select, "Used", "used");
|
||||||
|
addOption(select, "Changed", "changed");
|
||||||
|
addOption(select, "Rebound", "rebound");
|
||||||
|
addOption(select, "Interested", "interested");
|
||||||
|
addOption(select, "Not Used", "not-used");
|
||||||
|
|
||||||
|
const loadedValue = settings[binding];
|
||||||
|
select.value = loadedValue ?? "";
|
||||||
|
tr.setAttribute("data-binding-value", loadedValue);
|
||||||
|
|
||||||
|
select.addEventListener("change", _ => {
|
||||||
|
const newValue = select.value;
|
||||||
|
|
||||||
|
for (const otherSelect of selectsByBinding[binding]) {
|
||||||
|
if (otherSelect !== select) {
|
||||||
|
otherSelect.value = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
otherSelect.closest("tr").setAttribute("data-binding-value", newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newValue) {
|
||||||
|
delete settings[binding];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
settings[binding] = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSettings();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!(binding in selectsByBinding)) {
|
||||||
|
selectsByBinding[binding] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
selectsByBinding[binding].push(select);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tr.classList.add("missing");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSubsectionRow(table, line, columnCount) {
|
||||||
|
const text = line.trim();
|
||||||
|
if (text.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var {HTMLTableRowElement} */
|
||||||
|
const tr = appendElement(table, "tr");
|
||||||
|
tr.classList.add("subsection");
|
||||||
|
|
||||||
|
/** @var {HTMLTableCellElement} */
|
||||||
|
const td = appendElement(tr, "td");
|
||||||
|
td.innerHTML = text;
|
||||||
|
td.colSpan = columnCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTagWithClass(node, tagName, className) {
|
||||||
|
return node.nodeType === Node.ELEMENT_NODE && node.tagName === tagName && node.classList.contains(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendElement(target, tagName) {
|
||||||
|
const ele = document.createElement(tagName);
|
||||||
|
target.appendChild(ele);
|
||||||
|
return ele;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addOption(select, name, value) {
|
||||||
|
const option = appendElement(select, "option");
|
||||||
|
option.innerText = name;
|
||||||
|
option.value = value;
|
||||||
|
}
|
Reference in New Issue
Block a user