From 37a022fcfa77c7a5eb7ef7190338d4580c0176f6 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:53:18 -0500 Subject: [PATCH 01/17] Add greasyfork_better_page_titles.user.js --- README.md | 11 +++++ build/data_files/main_script_manifest.json | 11 +++++ greasyfork_better_page_titles.user.js | 50 ++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 greasyfork_better_page_titles.user.js diff --git a/README.md b/README.md index 608ab2c..968b388 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ To add a script: | [StackExchange Wide Mode](#SEWM) | [install][raw-SEWM] | N/A | :heavy_check_mark: | MIT | Jun 20, 2024 | Jun 20, 2024 | | [Better IzzyOnDroid App Titles](#BIAT) | [install][raw-BIAT] | N/A | :heavy_check_mark: | MIT | May 2, 2024 | May 22, 2025 | | [Better F-Droid App Titles](#BFAT) | [install][raw-BFAT] | N/A | :heavy_check_mark: | MIT | Aug 15, 2025 | Aug 15, 2025 | +| [Better Greasyfork Page Titles](#BGPT) | [install][raw-BGPT] | N/A | :heavy_check_mark: | MIT | Nov 15, 2025 | Nov 15, 2025 | --- @@ -485,6 +486,15 @@ Adds app description to page titles where possible. [[Install]][raw-BFAT] +--- + + +### Better Greasyfork Page Titles + +Include userscript descriptions in page titles on Greasy Fork (and Sleazy Fork) + +[[Install]][raw-BGPT] + --- ## Legacy Workaround Scripts @@ -622,6 +632,7 @@ Additionally, I do occasionally take requests for simple scripts, so feel free t [raw-SEWM]: /stackexchange_wide_mode.user.js?raw=1 [raw-BIAT]: /izzyondroid_description_in_title.user.js?raw=1 [raw-BFAT]: /fdroid_app_description_in_title.user.js?raw=1 +[raw-BGPT]: /greasyfork_better_page_titles.user.js?raw=1 [raw-DFSF]: /legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js?raw=1 diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 95058a6..544c90d 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -450,6 +450,17 @@ "updated": "Aug 15, 2025", "desc": "Adds app description to page titles where possible.", "version": "1.0.0" + }, + { + "name": "Better Greasyfork Page Titles", + "anchorString": "BGPT", + "path": "/greasyfork_better_page_titles.user.js", + "license": "MIT", + "autoUpdates": true, + "created": "Nov 15, 2025", + "updated": "Nov 15, 2025", + "desc": "Include userscript descriptions in page titles on Greasy Fork (and Sleazy Fork)", + "version": "1.0.0" } ] } \ No newline at end of file diff --git a/greasyfork_better_page_titles.user.js b/greasyfork_better_page_titles.user.js new file mode 100644 index 0000000..dd40b5d --- /dev/null +++ b/greasyfork_better_page_titles.user.js @@ -0,0 +1,50 @@ +// ==UserScript== +// @name Better Greasy Fork Page Titles +// @namespace https://github.com/StaticPH +// @match https://greasyfork.org/*/scripts/* +// @match https://sleazyfork.org/*/scripts/* +// @version 1.0.0 +// @createdAt 11/15/2025, 3:33:58 PM +// @author StaticPH +// @description Include userscript descriptions in page titles on Greasy Fork and Sleazy Fork +// @license MIT +// @updateURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/greasyfork_better_page_titles.user.js +// @downloadURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/greasyfork_better_page_titles.user.js +// @homepageURL https://github.com/StaticPH/UserScripts +// @supportURL https://github.com/StaticPH/UserScripts/issues +// @icon https://greasyfork.org/vite/assets/blacklogo16-DftkYuVe.png +// @grant none +// @noframes +// @run-at document-end +// ==/UserScript== + +(function(){ + "use strict"; + + // Get the description from the visible element, rather than from + // the meta tag in document.head; the latter changes based on + // which tab (Info/Code/History/Feedback/Stats) is active. + const descEle = document.getElementById('script-description'); + // Guard against a missing description element (which should never occur). + const descValue = descEle !== null ? descEle.textContent.trim() : 'No description'; + // Guard against the description element's text being only whitespace or an empty string. + const desc = descValue !== '' ? descValue : 'No description'; + + // Get the script title from the visible element, rather than from + // the existing document title; the latter changes based on + // which tab (Info/Code/History/Feedback/Stats) is active. + const scriptTitleEle = document.querySelector('#script-info > header > h2'); + // Fallback to actual page title only if necessary, which is less desirable because it makes extraKeyword seem out of place on all but the Info tab. + const scriptTitle = scriptTitleEle !== null ? scriptTitleEle.textContent.trim() : document.title; + + // For the purposes of searching through bookmarks and the like, + // ensure that the keyword "userscript" is always present in the title + const extraKeyword = scriptTitle.toLowerCase().includes('userscript') ? '' : ' userscript'; + + // If not viewing the first tab (Info), include the name of the tab in the updated title. + const tabLabelEle = document.querySelector('#script-links > .current:not(:first-of-type)'); + const tabLabel = tabLabelEle !== null ? ` (${tabLabelEle.textContent.trim().split(' ')[0]})` : ''; + + document.title = `${scriptTitle}${extraKeyword}${tabLabel} — ${desc}`; + +})(); From 873ef3ea5f6fc8845e53004acb7c9ebcdea9a373 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 11:50:57 -0500 Subject: [PATCH 02/17] Google Search Footer Privacy: Add additional location selector --- README.md | 2 +- build/data_files/main_script_manifest.json | 4 ++-- google_search_footer_privacy.user.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 968b388..d11dc52 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ To add a script: | [Wider Google Form Fields](#WGFF) | [install][raw-WGFF] | N/A | :heavy_check_mark: | MIT | Sep 30, 2021 | Aug 19, 2022 | | [Correct Google Form Correctness](#GFCC) | [install][raw-GFCC] | N/A | :heavy_check_mark: | MIT | Nov 9, 2021 | Nov 9, 2021 | | [Google Search Lean Query Updates](#GSLQU) | [install][raw-GSLQU] | N/A | :heavy_check_mark: | MIT | Jul 12, 2023 | Sep 28, 2024 | -| [Google Search Footer Privacy](#GSFP) | [install][raw-GSFP] | N/A | :heavy_check_mark: | MIT | Dec 30, 2023 | Dec 30, 2023 | +| [Google Search Footer Privacy](#GSFP) | [install][raw-GSFP] | N/A | :heavy_check_mark: | MIT | Dec 30, 2023 | Dec 16, 2025 | | [Roll20 Nonscrolling Number Fields](#RNNF) | [install][raw-RNNF] | N/A | :heavy_check_mark: | MIT | Jan 23, 2021 | Apr 5, 2021 | | [Bypass Blogspot's Blogger IFrame](#BBBI) | [install][raw-BBBI] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | May 1, 2022 | | [Foxaholic Fixes](#FoxF) | [install][raw-FoxF] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | Aug 27, 2021 | diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 544c90d..70662cb 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -227,9 +227,9 @@ "license": "MIT", "autoUpdates": true, "created": "Dec 30, 2023", - "updated": "Dec 30, 2023", + "updated": "Dec 16, 2025", "desc": "Hide the \"Location\" part of the footer on Google Search results, and don't show the email address of the current user.", - "version": "1.1.0" + "version": "1.1.1" }, { "name": "Roll20 Nonscrolling Number Fields", diff --git a/google_search_footer_privacy.user.js b/google_search_footer_privacy.user.js index 0eac588..2acd8fd 100644 --- a/google_search_footer_privacy.user.js +++ b/google_search_footer_privacy.user.js @@ -3,7 +3,7 @@ // @namespace https://github.com/StaticPH // @match *://google.com/search // @match *://*.google.com/search -// @version 1.1.0 +// @version 1.1.1 // @createdAt 12/30/2023, 6:16:41 PM // @author StaticPH // @description Hide the "Location" part of the footer on Google Search results, and don't show the email address of the current user. @@ -40,7 +40,7 @@ /* Hide email address of currently logged in user, if applicable */ /* #EOlPnc > :nth-last-child(2):not(:first-child) > :first-child:not(:last-child), */ /* Hide Location */ - #EOlPnc > .Srfpq, .dfB0uf { + #EOlPnc > .Srfpq, .dfB0uf, .HddGcc > .VYM29 { display: none !important; } From 4597b893d45e218d327ad5974917c004354b53aa Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 12:29:50 -0500 Subject: [PATCH 03/17] Improve README automation scripts abilities to change to the correct directory contexts for operation. --- build/run.sh | 18 ++++++++---------- build/update_script_manifest.py | 27 +++++++++++++-------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/build/run.sh b/build/run.sh index 1c18fac..4be6428 100644 --- a/build/run.sh +++ b/build/run.sh @@ -32,20 +32,18 @@ case "$1" in ;; esac +## POSIX way to determine the location of an executed shell script https://stackoverflow.com/a/29835459 +thisScriptLocation="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)" +## Ensure this script is run in the context of it's parent directory, which is within the git repository. +if [ "$PWD" != "$thisScriptLocation" ]; then + exec env -C "$thisScriptLocation" "./${0##*/}" "$@" +fi + repoRoot="$(git rev-parse --show-toplevel)" dataDir="${repoRoot}/build/data_files" templateDir="${repoRoot}/build/templates" -OLDPWD="${PWD}" -restorePWD(){ - cd "${OLDPWD}" >/dev/null 2>&1 || return -} -trap restorePWD EXIT - -# shellcheck disable=SC2164 -cd "${repoRoot}/build" >/dev/null 2>&1 - -TEST_READER=1 python3 "${repoRoot}/build/update_script_manifest.py" +WRITE_FILES=1 python3 "${repoRoot}/build/update_script_manifest.py" jq -rs 'reduce .[] as $item ({}; . * $item)' "${dataDir}/general_url_references.json" "${dataDir}/legacy_scripts.json" newdata.json | \ minijinja-cli --format json "${templateDir}/primary_template.md.j2" - > output.md diff --git a/build/update_script_manifest.py b/build/update_script_manifest.py index b9cf401..56c6602 100644 --- a/build/update_script_manifest.py +++ b/build/update_script_manifest.py @@ -272,27 +272,26 @@ def findScriptData(self) -> None: print(adjusted) # FIXME: Do something with this value other than just print it to stdout. self.dataFileContents['scripts'] = adjusted # TEMP - def writeTest(self) -> None: # TEMP - with open('newdata.json', 'w', encoding=defaultFileEncoding) as outputFile: + def writeNew(self, toFile: str='newdata.json') -> None: + with open(toFile, 'w', encoding=defaultFileEncoding) as outputFile: json.dump(self.dataFileContents, outputFile, indent="\t") - print('Go diff main_script_manifest.json and newdata.json') # TODO: ?Decide on some process to automatically assign an anchorString? if __name__ == '__main__': - from os import getenv from functools import partial - hasDebugVar: bool = bool(getenv('DEBUG')) + hasDebugVar: bool = bool(os.getenv('DEBUG')) if hasDebugVar: mayPrint = partial(print, file=sys.stderr) #noqa: F811, RUF100 - if bool(getenv('TEST_READER')): - updater = DataUpdater() - # TODO: utilize __file__ to make these paths relative to the script, rather than the working directory - updater.readJSONFile('./data_files/main_script_manifest.json') - here = os.getcwd() - os.chdir('..') - updater.findScriptData() - os.chdir(here) - updater.writeTest() + updater = DataUpdater() + # Get the parent directory of this script. + here = os.path.dirname(__file__) + + updater.readJSONFile(here + '/data_files/main_script_manifest.json') + os.chdir(here + '/..') + updater.findScriptData() + if bool(os.getenv('WRITE_FILES')): + updater.writeNew(here + '/newdata.json') + print('Go diff main_script_manifest.json and newdata.json') From 3a955204ef72f6c734c2b5930afc7899418adaf2 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:29:17 -0500 Subject: [PATCH 04/17] Fix README automation writing 2-part version strings in scripts as 3-part version strings in the manifest. --- build/update_script_manifest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/update_script_manifest.py b/build/update_script_manifest.py index 56c6602..672dc83 100644 --- a/build/update_script_manifest.py +++ b/build/update_script_manifest.py @@ -83,7 +83,7 @@ def __init__(self, value: str): self.minor: int = int(minor, 10) self.patch: int = int(patch, 10) or 0 self.originalValue: str = value - self.value: str = value + '.0' if patch == '' else value + self.value: str = f'{value}.{self.patch}' if value.count('.') < 2 else value def __str__(self) -> str: return self.value @@ -228,12 +228,12 @@ def getUpdatedScriptData(self, scriptFileMeta: Dict[str, Union[str, bool]], scri scriptItem['updated'] = scriptItem['created'] elif ('version' in scriptItem) and VersionString(scriptItem['version']) < scriptFileMeta['version']: # The file's version info was increased since the last time the data file was updated by this script; - # record the new "updated" date as the current date, and update the "version" to match the script's meta block + # record the new "updated" date as the current date scriptItem['updated'] = self._missingCreatedValue if self.__needsAttrForDataFile(scriptItem, 'license'): # Get license field from script file's metadata scriptItem['license'] = scriptFileMeta['license'] or self._missingLicenseValue - # Unconditionally update the version field + # Unconditionally update the "version" field to match the script's meta block scriptItem['version'] = str(VersionString(scriptFileMeta['version'])) or self._missingVersionValue # Unconditionally update the autoUpdates field scriptItem['autoUpdates'] = scriptFileMeta['autoUpdates'] or 'false' From c324f5c7acf5924992bdb1ab52dfcbbc543fad09 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:21:26 -0500 Subject: [PATCH 05/17] Add automation support for producing updated legacy_scripts manifest file. --- build/run.sh | 10 ++++++---- build/update_script_manifest.py | 19 +++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/build/run.sh b/build/run.sh index 4be6428..b98c442 100644 --- a/build/run.sh +++ b/build/run.sh @@ -7,10 +7,12 @@ usage(){ printf '%s\n' \ 'This script is used to generate updated versions of readme and manifest files.' \ 'To "register" a new userscript for inclusion in the readme, add a new' \ - 'object with both `path` and `anchorString` values to the `scripts` array' \ - 'in `main_script_manifest.json` before running this script.' \ + 'object with both `path` and `anchorString` values to the' \ '`scripts` array (or other such array where relevant)' \ + 'in `main_script_manifest.json` (and/or `legacy_scripts.json`)' \ + 'before running this script.' \ 'Updated manifest and readme files will be created in the `build` directory,' \ - 'and named `newdata.json` and `output.md`, respectively.' \ + 'and named `new_main_manifest.json`/`new_legacy_manifest.json`' \ + 'and `output.md`, respectively.' \ 'They can be manually copied over the originals.' return 0 } @@ -44,7 +46,7 @@ dataDir="${repoRoot}/build/data_files" templateDir="${repoRoot}/build/templates" WRITE_FILES=1 python3 "${repoRoot}/build/update_script_manifest.py" -jq -rs 'reduce .[] as $item ({}; . * $item)' "${dataDir}/general_url_references.json" "${dataDir}/legacy_scripts.json" newdata.json | \ +jq -rs 'reduce .[] as $item ({}; . * $item)' "${dataDir}/general_url_references.json" new_legacy_manifest.json new_main_manifest.json | \ minijinja-cli --format json "${templateDir}/primary_template.md.j2" - > output.md ################ diff --git a/build/update_script_manifest.py b/build/update_script_manifest.py index 672dc83..6ba36e7 100644 --- a/build/update_script_manifest.py +++ b/build/update_script_manifest.py @@ -239,14 +239,14 @@ def getUpdatedScriptData(self, scriptFileMeta: Dict[str, Union[str, bool]], scri scriptItem['autoUpdates'] = scriptFileMeta['autoUpdates'] or 'false' return self.sortScriptMeta(scriptItem) - def findScriptData(self) -> None: + def findScriptData(self, scriptArrayKey: str = 'scripts') -> None: # Must be called after either `readJSONFile`/`readJSONStr`/`readJSONDict` # FIXME: With the large blocks of data this function will eventually be producing and returning, # it would probably make sense to turn this into a Generator method, or at least make the # `for` loop into its own inner-function and make _that_ a Generator. adjusted: List[Dict[str, Union[str, bool]]] = [] - for scriptItem in self.dataFileContents['scripts']: + for scriptItem in self.dataFileContents[scriptArrayKey]: scriptItem: Dict[str, str] # Shut up linter wrongly complaining that scriptItem is a string. if 'path' not in scriptItem: # TODO: support automatic detection of version-controlled scripts not in a data file, @@ -270,9 +270,9 @@ def findScriptData(self) -> None: adjusted.append(self.getUpdatedScriptData(scriptFileMeta, scriptItem)) print(adjusted) # FIXME: Do something with this value other than just print it to stdout. - self.dataFileContents['scripts'] = adjusted # TEMP + self.dataFileContents[scriptArrayKey] = adjusted # TEMP - def writeNew(self, toFile: str='newdata.json') -> None: + def writeNew(self, toFile: str='new_main_manifest.json') -> None: with open(toFile, 'w', encoding=defaultFileEncoding) as outputFile: json.dump(self.dataFileContents, outputFile, indent="\t") @@ -293,5 +293,12 @@ def writeNew(self, toFile: str='newdata.json') -> None: os.chdir(here + '/..') updater.findScriptData() if bool(os.getenv('WRITE_FILES')): - updater.writeNew(here + '/newdata.json') - print('Go diff main_script_manifest.json and newdata.json') + updater.writeNew(here + '/new_main_manifest.json') + print('Go diff main_script_manifest.json and new_main_manifest.json') + + updater.readJSONFile(here + '/data_files/legacy_scripts.json') + os.chdir(here + '/..') + updater.findScriptData('legacy_scripts') + if bool(os.getenv('WRITE_FILES')): + updater.writeNew(here + '/new_legacy_manifest.json') + print('Go diff legacy_scripts.json and new_legacy_manifest.json') From 979636c2e9e85e36c321454c12135cb78f30f5e5 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:23:42 -0500 Subject: [PATCH 06/17] Add file containing instructions and todo list for readme generation. --- build/ABOUT.md | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 build/ABOUT.md diff --git a/build/ABOUT.md b/build/ABOUT.md new file mode 100644 index 0000000..e728bb3 --- /dev/null +++ b/build/ABOUT.md @@ -0,0 +1,88 @@ +This file contains instructions for using the readme automation in this directory, and also a todo list. + +# Instructions +## Prerequisites +The following tools must be available on the `PATH`: + * Python (minimum version: 3.7) + * [MiniJinja CLI](https://github.com/mitsuhiko/minijinja) + * [jq](https://github.com/stedolan/jq) + * Bash/Zsh/Ksh/other-sh-interpreter + * git + +# What the hell do I do with any of this? +Run `./run.sh --help` for instructions on what needs to be done manually +when adding a new userscript. + +Otherwise, run `./run.sh`, then manually compare: + * `./data_files/main_script_manifest.json` <-> `./new_main_manifest.json` + * `./data_files/legacy_scripts.json` <-> `./new_legacy_manifest.json` + * `../README.md` <-> `./output.md` +If satisfied, move/copy the right-hand files to the (version-controlled) +left-hand files. + +Then add the changes and commit. + +# TODO list +1. [X] The updater script, templates, and data files should reside under a directory named something like `build` or `deploy` + +2. [X] Clear fucking instructions on how to run this shit. + + 1. [X] How should the updater know which userscript files to check for updates? + Currently it only checks files specified in the data files. + 2. [X] I don't believe the script currently understands how to read from multiple separate data files; should it? + Script now reads and updates both the main and legacy script manifests separately. + Support has been added for alternate keys to access the list of scripts in a file, + as the legacy manifest uses 'legacy_scripts', while the main manifest uses 'scripts'. + + Running `./update_script_manifest.py` with Python3.7 or later and the + non-empty environment variable `WRITE_FILES` will produce updated + `new_main_manifest.json` and `new_legacy_manifest.json` from + `data_files/main_script_manifest.json` and `data_files/legacy_scripts.json`. + The updated readme can then be written to `output.md` by running: +```bash +jq -rs 'reduce .[] as $item ({}; . * $item)' 'data_files/general_url_references.json' new_legacy_manifest.json new_main_manifest.json | +minijinja-cli --format json templates/primary_template.md.j2 - > output.md +``` + +**For convenience, simply run `./run.sh`** + +3. [ ] Automatically display (?git-?)diff of data file after running updater script. + + 1. [-] Do I want to ultimately want to write back to the original data file, or should I write to a temporary file, then compare them, + and prompt for confirmation before overwriting the original? What if I want only part of the changes? + Currently all outputs go to temporary files that must be manually checked, copied (if good), and cleaned up. + +4. [X] If the metadata block of a script doesn't contain the non-standard `@createdAt` property, + and the script doesn't already have a `created` value in the data file, + + _EITHER_ + 1. Attempt to check the creation and modified date of the script file according to the file system. Keep the older of the two. + 2. Call out to git to determine when the script was first added to the repository. + 3. Set the earlier of the two as the `created` value in the data file. + + _OR_ + + set the `created` value in the data file to the current date. + + The first scenario seems preferable, but in the interest of speed and + convenience, the second option is employed. + +5. [ ] Support automatic detection of version-controlled scripts not yet in a data file, and automatically add them to the appropriate one. + This should also handle adding the `created` date if necessary. + +6. [ ] Decide on some process to automatically assign an `anchorString`. + Consider ditching custom anchor strings entirely in favor of just using the name of the script file, sans extension. + +7. [ ] Figure out what part of `getUpdatedScriptData` can be replaced with a call to `dict.update()`. + +8. [ ] Investigate converting some part of `findScriptData` into a generator. + +9. [ ] Vendor icons into a repo (Projects/third_party/asset_archive) (Projects/Userscripts/notes/icon_index.txt) + 1. [ ] Add some kind of disclaimer section mentioning that site names and logos are property of their original owners. + +10. [ ] Group scripts under collapsible `section`/`detail` tags according to the sites they affect. + 1. [ ] Support a *manually added* `group` property in the data files to denote a named group; scripts without (a non-empty, non-null value for) this property should be under an "ungrouped" group, and appear only after all other groups. + +11. [X] Temporary local branch in which to test repository layout with new automation files included. + +12. [X] Finish/fix date parsing and conversion for the non-standard `createdAt` property in script metadata, so that it can be stored *sensibly* in the manifest. From 9ba15b7c6a53aa802a5fc3bdc2e3d801625bc982 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:55:54 -0500 Subject: [PATCH 07/17] Add oxlint config --- .oxlintrc.json | 228 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 .oxlintrc.json diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..4d4c713 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,228 @@ +{ + "plugins": [ + "unicorn", + "typescript", + "oxc", + "jsdoc", + "promise" + ], + "categories": {}, + "rules": { + /* + "ruleName": "severity" + OR + "ruleName": ["severity", { "ruleOption": "value" (boolean and numeric values are unquoted) }] + */ + "block-scoped-var": "warn", + "for-direction": "warn", + "no-async-promise-executor": "warn", + "no-await-in-loop": "warn", + "no-caller": "warn", + "no-class-assign": "warn", + "no-compare-neg-zero": "warn", + "no-cond-assign": "warn", + "no-const-assign": "warn", + "no-constant-binary-expression": "warn", + "no-constant-condition": "warn", + "no-control-regex": "warn", + "no-debugger": "warn", + "no-delete-var": "warn", + "no-dupe-class-members": "warn", + "no-dupe-else-if": "warn", + "no-dupe-keys": "warn", + "no-duplicate-case": "warn", + "no-empty-character-class": "warn", + "no-empty-pattern": "warn", + "no-empty-static-block": "warn", + "no-eval": "warn", + "no-ex-assign": "warn", +// "no-extend-native": "warn", + "no-extra-bind": "warn", + "no-extra-boolean-cast": "warn", + "no-func-assign": "warn", + "no-global-assign": "warn", + "no-import-assign": "warn", + "no-invalid-regexp": "warn", + "no-irregular-whitespace": "warn", + "no-loss-of-precision": "warn", + "no-new": "warn", + "no-new-native-nonconstructor": "warn", + "no-nonoctal-decimal-escape": "warn", + "no-obj-calls": "warn", + "no-self-assign": "warn", + "no-setter-return": "warn", + "no-shadow-restricted-names": "warn", + "no-sparse-arrays": "warn", + "no-this-before-super": "warn", + "no-unassigned-vars": "warn", + "no-unexpected-multiline": "warn", + "no-unneeded-ternary": "warn", + "no-unsafe-finally": "warn", + "no-unsafe-negation": "warn", + "no-unsafe-optional-chaining": "warn", + "no-unused-expressions": "warn", + "no-unused-labels": "warn", + "no-unused-private-class-members": "warn", + "no-unused-vars": "warn", + "no-useless-backreference": "warn", + "no-useless-call": "warn", + "no-useless-catch": "warn", + "no-useless-concat": "warn", + "no-useless-constructor": "warn", + "no-useless-escape": "warn", + "no-useless-rename": "warn", + "no-with": "warn", + "preserve-caught-error": "warn", + "require-yield": "warn", + "use-isnan": "warn", + "valid-typeof": "warn", + "jsdoc/check-property-names": "warn", + "jsdoc/check-tag-names": "warn", + "jsdoc/implements-on-classes": "warn", + "jsdoc/no-defaults": "warn", + "jsdoc/require-property": "warn", + "jsdoc/require-property-description": "warn", + "jsdoc/require-property-name": "warn", + "jsdoc/require-property-type": "warn", + "jsdoc/require-yields": "warn", + "oxc/approx-constant": "warn", + "oxc/bad-array-method-on-arguments": "warn", + "oxc/bad-char-at-comparison": "warn", + "oxc/bad-comparison-sequence": "warn", + "oxc/bad-min-max-func": "warn", + "oxc/bad-object-literal-comparison": "warn", + "oxc/bad-replace-all-arg": "warn", + "oxc/const-comparisons": "warn", + "oxc/double-comparisons": "warn", + "oxc/erasing-op": "warn", + "oxc/misrefactored-assign-op": "warn", + "oxc/missing-throw": "warn", + "oxc/no-accumulating-spread": "warn", + "oxc/no-async-endpoint-handlers": "warn", + "oxc/number-arg-out-of-range": "warn", + "oxc/only-used-in-recursion": "warn", + "oxc/uninvoked-array-callback": "warn", + "promise/always-return": "warn", + "promise/no-callback-in-promise": "warn", + "promise/no-multiple-resolved": "warn", + "promise/no-new-statics": "warn", + "promise/no-promise-in-callback": "warn", + "promise/valid-params": "warn", + "typescript/await-thenable": "warn", + "typescript/no-array-delete": "warn", + "typescript/no-base-to-string": "warn", +// "typescript/no-confusing-non-null-assertion": "warn", + "typescript/no-duplicate-enum-values": "warn", + "typescript/no-duplicate-type-constituents": "warn", + "typescript/no-extra-non-null-assertion": "warn", +// "typescript/no-extraneous-class": "warn", + "typescript/no-floating-promises": "warn", + "typescript/no-for-in-array": "warn", + "typescript/no-implied-eval": "warn", + "typescript/no-meaningless-void-operator": "warn", + "typescript/no-misused-new": "warn", + "typescript/no-misused-spread": "warn", + "typescript/no-non-null-asserted-optional-chain": "warn", + "typescript/no-redundant-type-constituents": "warn", + "typescript/no-this-alias": "warn", +// "typescript/no-unnecessary-boolean-literal-compare": "warn", + "typescript/no-unnecessary-parameter-property-assignment": "warn", +// "typescript/no-unnecessary-template-expression": "warn", +// "typescript/no-unnecessary-type-arguments": "warn", +// "typescript/no-unnecessary-type-assertion": "warn", +// "typescript/no-unnecessary-type-constraint": "warn", + "typescript/no-unsafe-declaration-merging": "warn", +// "typescript/no-unsafe-enum-comparison": "warn", +// "typescript/no-unsafe-type-assertion": "warn", + "typescript/no-unsafe-unary-minus": "warn", + "typescript/no-useless-empty-export": "warn", + "typescript/no-wrapper-object-types": "warn", + "typescript/prefer-as-const": "warn", + "typescript/require-array-sort-compare": "warn", + "typescript/restrict-template-expressions": "warn", + "typescript/triple-slash-reference": "warn", + "typescript/unbound-method": "warn", + "unicorn/consistent-function-scoping": "warn", + "unicorn/no-accessor-recursion": "warn", + "unicorn/no-array-reverse": "warn", + "unicorn/no-array-sort": "warn", + "unicorn/no-await-in-promise-methods": "warn", + "unicorn/no-empty-file": "warn", + "unicorn/no-instanceof-builtins": "warn", + "unicorn/no-invalid-fetch-options": "warn", + "unicorn/no-invalid-remove-event-listener": "warn", + "unicorn/no-new-array": "warn", + "unicorn/no-single-promise-in-promise-methods": "warn", + "unicorn/no-thenable": "warn", + "unicorn/no-unnecessary-await": "warn", + "unicorn/no-useless-fallback-in-spread": "warn", + "unicorn/no-useless-length-check": "warn", + "unicorn/no-useless-spread": "warn", + "unicorn/prefer-add-event-listener": "warn", + "unicorn/prefer-array-find": "warn", + "unicorn/prefer-array-flat-map": "warn", + "unicorn/prefer-set-has": "warn", + "unicorn/prefer-set-size": "warn", + "unicorn/prefer-string-starts-ends-with": "warn", + "unicorn/require-module-specifiers": "warn", + "unicorn/require-post-message-target-origin": "warn" + }, + "settings": { + "jsx-a11y": { + "polymorphicPropName": null, + "components": {}, + "attributes": {} + }, + "next": { + "rootDir": [] + }, + "react": { + "formComponents": [], + "linkComponents": [] + }, + "jsdoc": { + "ignorePrivate": false, + "ignoreInternal": false, + "ignoreReplacesDocs": true, + "overrideReplacesDocs": true, + "augmentsExtendsReplacesDocs": false, + "implementsReplacesDocs": false, + "exemptDestructuredRootsFromChecks": false, + "tagNamePreference": {} + }, + "vitest": { + "typecheck": false + } + }, + "env": { + "builtin": true + }, + "globals": {}, + "ignorePatterns": [], + "extends": [ +// "localrules.json" + ], + "overrides": [ + // REFERENCE: https://eslint.org/docs/v8.x/use/configure/language-options + // REFERENCE: https://oxc.rs/docs/guide/usage/linter/config-file-reference + { // userscripts + "files": ["**/*.user.js"], + "rules": { + // Always allow console api in userscripts + "no-console": "off", + // Doesn't understand that immediately-executed-functions are only ever called once, and just whines... + "unicorn/consistent-function-scoping": "off", + }, + "env": { + "browser": true, + "greasemonkey": true, + "es2018": true, + "es2019": false + }, + "globals": { + "GM": "writable", + "unsafeWindow": "writable" + } + } + ] +} \ No newline at end of file From 37dd3e0bab8fa54b7b6ad6f37366da9c3999e608 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Wed, 28 Jan 2026 22:15:11 -0500 Subject: [PATCH 08/17] Update oxlint config --- .oxlintrc.json | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/.oxlintrc.json b/.oxlintrc.json index 4d4c713..4e049bb 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -4,7 +4,8 @@ "typescript", "oxc", "jsdoc", - "promise" + "promise", + "eslint" ], "categories": {}, "rules": { @@ -13,7 +14,9 @@ OR "ruleName": ["severity", { "ruleOption": "value" (boolean and numeric values are unquoted) }] */ + "accessor-pairs": "warn", "block-scoped-var": "warn", + "complexity": "warn", "for-direction": "warn", "no-async-promise-executor": "warn", "no-await-in-loop": "warn", @@ -39,17 +42,24 @@ // "no-extend-native": "warn", "no-extra-bind": "warn", "no-extra-boolean-cast": "warn", + "no-fallthrough": "warn", "no-func-assign": "warn", "no-global-assign": "warn", "no-import-assign": "warn", +// "no-implicit-coercion": "warn", "no-invalid-regexp": "warn", "no-irregular-whitespace": "warn", + "no-loop-func": "error", "no-loss-of-precision": "warn", "no-new": "warn", "no-new-native-nonconstructor": "warn", "no-nonoctal-decimal-escape": "warn", "no-obj-calls": "warn", + "no-promise-executor-return": "warn", + "no-regex-spaces": "warn", + "no-return-assign": "warn", "no-self-assign": "warn", + "no-sequences": [ "warn", { "allowInParentheses": false } ], "no-setter-return": "warn", "no-shadow-restricted-names": "warn", "no-sparse-arrays": "warn", @@ -67,6 +77,7 @@ "no-useless-backreference": "warn", "no-useless-call": "warn", "no-useless-catch": "warn", + "no-useless-computed-key": "warn", "no-useless-concat": "warn", "no-useless-constructor": "warn", "no-useless-escape": "warn", @@ -99,6 +110,7 @@ "oxc/missing-throw": "warn", "oxc/no-accumulating-spread": "warn", "oxc/no-async-endpoint-handlers": "warn", + "oxc/no-this-in-exported-function": "warn", "oxc/number-arg-out-of-range": "warn", "oxc/only-used-in-recursion": "warn", "oxc/uninvoked-array-callback": "warn", @@ -148,24 +160,40 @@ "unicorn/no-array-sort": "warn", "unicorn/no-await-in-promise-methods": "warn", "unicorn/no-empty-file": "warn", + "unicorn/no-immediate-mutation": "warn", "unicorn/no-instanceof-builtins": "warn", "unicorn/no-invalid-fetch-options": "warn", "unicorn/no-invalid-remove-event-listener": "warn", + "unicorn/no-negation-in-equality-check": "warn", "unicorn/no-new-array": "warn", "unicorn/no-single-promise-in-promise-methods": "warn", "unicorn/no-thenable": "warn", "unicorn/no-unnecessary-await": "warn", "unicorn/no-useless-fallback-in-spread": "warn", + "unicorn/no-unnecessary-array-flat-depth": "warn", + "unicorn/no-useless-collection-argument": "warn", + "unicorn/no-useless-error-capture-stack-trace": "warn", "unicorn/no-useless-length-check": "warn", "unicorn/no-useless-spread": "warn", "unicorn/prefer-add-event-listener": "warn", "unicorn/prefer-array-find": "warn", "unicorn/prefer-array-flat-map": "warn", + "unicorn/prefer-dom-node-append": "warn", + "unicorn/prefer-dom-node-dataset": "off", + "unicorn/prefer-dom-node-remove": "warn", + "unicorn/prefer-dom-node-text-content": "warn", + "unicorn/prefer-default-parameters": "warn", + "unicorn/prefer-keyboard-event-key": "warn", + "unicorn/prefer-logical-operator-over-ternary": "warn", + "unicorn/prefer-optional-catch-binding": "warn", + "unicorn/prefer-query-selector": "warn", + "unicorn/prefer-response-static-json": "warn", "unicorn/prefer-set-has": "warn", "unicorn/prefer-set-size": "warn", "unicorn/prefer-string-starts-ends-with": "warn", "unicorn/require-module-specifiers": "warn", - "unicorn/require-post-message-target-origin": "warn" + "unicorn/require-post-message-target-origin": "warn", + "unicorn/text-encoding-identifier-case": "warn" }, "settings": { "jsx-a11y": { @@ -212,6 +240,12 @@ "no-console": "off", // Doesn't understand that immediately-executed-functions are only ever called once, and just whines... "unicorn/consistent-function-scoping": "off", + // Portability + "unicorn/prefer-global-this": "warn", + // Too new + "typescript/prefer-nullish-coalescing": "off", + "typescript/prefer-optional-chain": "off", + "oxc/no-optional-chaining": [ "error", { "message": "es2018 target does not support optional chaining operator"} ] }, "env": { "browser": true, From aa92548905c4631b16befae8db65e941f095ef8c Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Wed, 28 Jan 2026 22:39:32 -0500 Subject: [PATCH 09/17] Trivial linting --- fix_youtube_player_bottom_gradient.user.js | 2 +- github_repo_network_tab.user.js | 9 ++++++--- greasyfork_better_page_titles.user.js | 2 +- izzyondroid_description_in_title.user.js | 2 +- .../stackexchange_legacy_comments_expander.user.js | 2 +- mitigate_target_blank_risk.user.js | 2 +- novelupdates_reading_list_upgrades.user.js | 5 ++++- scribblehub_reading_list_upgrades.user.js | 6 ++++-- ubuntu_packages_description_in_title.user.js | 1 + 9 files changed, 20 insertions(+), 11 deletions(-) diff --git a/fix_youtube_player_bottom_gradient.user.js b/fix_youtube_player_bottom_gradient.user.js index aa99c45..52111ec 100644 --- a/fix_youtube_player_bottom_gradient.user.js +++ b/fix_youtube_player_bottom_gradient.user.js @@ -26,7 +26,7 @@ // `); setTimeout(function wait(){ - const playerBottomGradient = document.getElementById('movie_player').querySelector('.ytp-gradient-bottom'); + const playerBottomGradient = document.querySelector('#movie_player .ytp-gradient-bottom'); if (playerBottomGradient){ console.log('Fixing bottom player gradient height'); playerBottomGradient.style.removeProperty('height'); diff --git a/github_repo_network_tab.user.js b/github_repo_network_tab.user.js index b4e93df..95b3e3b 100644 --- a/github_repo_network_tab.user.js +++ b/github_repo_network_tab.user.js @@ -91,11 +91,13 @@ // Wait until the page loads in enough to have the 'Pull Requests' tab in the repository header, so that it can be used as a point of reference for element insertion if (repoPullsTab.length !== 0){ repoPullsTab[0].insertAdjacentHTML('afterend', createBigNetworkTabHTML()); - document.getElementById('bigNetworkTab') && console.debug('Added big Network tab.'); + /* oxlint-disable no-unused-expressions */ + document.querySelector('#bigNetworkTab') && console.debug('Added big Network tab.'); if (repoPullsTab.length > 1){ repoPullsTab[1].insertAdjacentHTML('afterend', createSmallNetworkTabHTML()); - document.getElementById('smallNetworkTab') && console.debug('Added small Network tab.'); + /* oxlint-disable no-unused-expressions */ + document.querySelector('#smallNetworkTab') && console.debug('Added small Network tab.'); } // setTimeout(function foo(){ @@ -112,7 +114,8 @@ const pullsDropdownItem = document.querySelector('details-menu li[data-menu-item="i2pull-requests-tab"]'); if (pullsDropdownItem){ pullsDropdownItem.insertAdjacentHTML('afterend', createNetworkTabInDropdownHTML()); - document.getElementById('networkTabDropdown') && console.debug('Added Network tab item to dropdown.'); + /* oxlint-disable no-unused-expressions */ + document.querySelector('#networkTabDropdown') && console.debug('Added Network tab item to dropdown.'); } else if (dropdownRetries >= dropdownRetryLimit){ console.log(`Number of attempts at adding Network tab to dropdown have exceeded the limit of ${dropdownRetryLimit} attempts. Giving up.`); diff --git a/greasyfork_better_page_titles.user.js b/greasyfork_better_page_titles.user.js index dd40b5d..79345c8 100644 --- a/greasyfork_better_page_titles.user.js +++ b/greasyfork_better_page_titles.user.js @@ -24,7 +24,7 @@ // Get the description from the visible element, rather than from // the meta tag in document.head; the latter changes based on // which tab (Info/Code/History/Feedback/Stats) is active. - const descEle = document.getElementById('script-description'); + const descEle = document.querySelector('#script-description'); // Guard against a missing description element (which should never occur). const descValue = descEle !== null ? descEle.textContent.trim() : 'No description'; // Guard against the description element's text being only whitespace or an empty string. diff --git a/izzyondroid_description_in_title.user.js b/izzyondroid_description_in_title.user.js index 19ff31c..7b22e9b 100644 --- a/izzyondroid_description_in_title.user.js +++ b/izzyondroid_description_in_title.user.js @@ -23,7 +23,7 @@ const parts = document.title.split('- IzzyOnDroid'); const tail = parts.pop(); - let summary = document.getElementById('summary').textContent; + let summary = document.querySelector('#summary').textContent; summary = summary[0].toLocaleUpperCase() + summary.slice(1); parts.push('- ' + summary + ' | IzzyOnDroid' + tail); document.title = parts.join(''); diff --git a/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js b/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js index e86bdbf..f4aab5f 100644 --- a/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js +++ b/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js @@ -28,7 +28,7 @@ function replaceChildrenWithNodes(parentNode, ...newChildren){ while (parentNode.lastChild){ - parentNode.removeChild(parentNode.lastChild); + parentNode.lastChild.remove(); } if (newChildren !== undefined){ const replacements = (newChildren.length === 1 && Array.isArray(newChildren[0])) ? newChildren[0] : newChildren; diff --git a/mitigate_target_blank_risk.user.js b/mitigate_target_blank_risk.user.js index 2923f66..be0b920 100644 --- a/mitigate_target_blank_risk.user.js +++ b/mitigate_target_blank_risk.user.js @@ -47,7 +47,7 @@ let splitRel; function cleanse(){ // Unsure whether to prefer getElementByTagName('a')+if target=='_blank' OR querySeletorAll('a[target="_blank"]') - Array.from(document.getElementsByTagName('a')).forEach( (link) => { + Array.from(document.querySelectorAll('a')).forEach( (link) => { if (link.target == '_blank'){ if (allowedOrigins.includes(link.origin)){ console.log('Found link with allowed origin:"' + link.origin + '" and target="_blank". The link\'s "rel" attribute will not be modified.'); diff --git a/novelupdates_reading_list_upgrades.user.js b/novelupdates_reading_list_upgrades.user.js index 0841a1a..8332f24 100644 --- a/novelupdates_reading_list_upgrades.user.js +++ b/novelupdates_reading_list_upgrades.user.js @@ -120,6 +120,7 @@ // document.querySelectorAll('.bmhide > :not(.nu_editnotes):first-child') // get not caught up // document.querySelectorAll('.bmhide > span[class*="bm_hide_me"]:first-child') // alternative to get not caught up const caughtUpHelper = { + /* oxlint-disable unicorn/prefer-query-selector */ mainTbl: document.getElementById('myTable read'), hiddenTbl: (function(){ const tbl = document.createElement('table'); @@ -216,7 +217,9 @@ // Fuck tracking and analytics document.querySelectorAll('script').forEach(s => (s.textContent.includes('urchinTracker') || s.src.includes('analytic')) && s.remove()); - settings.improvePageTitle && improveTitle(); + if (settings.improvePageTitle){ + improveTitle(); + } caughtUpHelper.init(); })(); \ No newline at end of file diff --git a/scribblehub_reading_list_upgrades.user.js b/scribblehub_reading_list_upgrades.user.js index 40166d4..dcea3f4 100644 --- a/scribblehub_reading_list_upgrades.user.js +++ b/scribblehub_reading_list_upgrades.user.js @@ -132,7 +132,7 @@ } const caughtUpHelper = { - mainTbl: document.getElementsByClassName('rl_table')[0], + mainTbl: document.querySelector('.rl_table'), hiddenTbl: (function(){ const tbl = document.createElement('table'); tbl.id = 'hiddenTbl'; @@ -225,7 +225,9 @@ // Fuck tracking and analytics document.querySelectorAll('script').forEach(s => (s.textContent.includes('urchinTracker') || s.src.includes('analytic')) && s.remove()); - settings.improvePageTitle && improveTitle(); + if (settings.improvePageTitle){ + improveTitle(); + } if (settings.ctrlEnterSavesNotes){ document.addEventListener('keyup', saveNotesKeybindHandler); setTitleForFakeButton(document.querySelector('.rlnotes_btn.savenotes'), true, '', ' (Ctrl+Enter)'); diff --git a/ubuntu_packages_description_in_title.user.js b/ubuntu_packages_description_in_title.user.js index 5e1128b..eec846a 100644 --- a/ubuntu_packages_description_in_title.user.js +++ b/ubuntu_packages_description_in_title.user.js @@ -20,6 +20,7 @@ (function(){ 'use strict'; + /* oxlint-disable unicorn/no-array-reverse */ const [pkg, repo, sourceSegment, /*lang*/] = document.location.pathname.split('/').reverse(); setTimeout(function wait(){ From e1a4cb3a545d07fcaf628ccf5779d3c01b3f4bae Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Mon, 9 Feb 2026 11:05:55 -0500 Subject: [PATCH 10/17] Twitch Transparent Video Stats: Update CSS selectors and delay script injection time. Also coerce script versions in manifest file to three-segments. --- README.md | 4 +- build/data_files/main_script_manifest.json | 54 +++++++++++----------- twitch_transparent_video_stats.user.js | 7 +-- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index d11dc52..108f3bb 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ To add a script: | [Twitch Hide Content Disclosure](#THCD) | [install][raw-THCD] | N/A | :heavy_check_mark: | MIT | Jun 29, 2023 | Dec 12, 2024 | | [Twitch Hide Channel Leaderboard](#THCL) | [install][raw-THCL] | N/A | :heavy_check_mark: | MIT | Jun 19, 2020 | Dec 12, 2024 | | [Twitch Hide Overlay Ads](#THOA) | [install][raw-THOA] | N/A | :heavy_check_mark: | MIT | Dec 14, 2023 | Dec 12, 2024 | -| [Twitch Transparent Video Stats](#TTVS) | [install][raw-TTVS] | N/A | :heavy_check_mark: | MIT | May 19, 2021 | Dec 12, 2024 | +| [Twitch Transparent Video Stats](#TTVS) | [install][raw-TTVS] | N/A | :heavy_check_mark: | MIT | May 19, 2021 | Feb 9, 2026 | | [GitHub Repo Network Tab](#GRNT) | [install][raw-GRNT] | N/A | :heavy_check_mark: | MIT | Apr 6, 2020 | Feb 1, 2024 | | [Bigger GitHub Network Graph](#BGNG) | [install][raw-BGNG] | N/A | :heavy_check_mark: | MIT | Apr 12, 2020 | Oct 28, 2021 | | [GitHub Notification Page Tweaks](#GNPT) | [install][raw-GNPT] | N/A | :heavy_check_mark: | MIT | Oct 22, 2020 | Aug 3, 2021 | @@ -335,7 +335,7 @@ e.g. Setting `customAllowedOrigins` to `'http://wordpress.com https://stackexcha ### MSYS2 Package Description In Title -Include the package description on the tab title for a package's page on packages.msys2.org/packages +Include the package description on the tab title for a package's page on packages.msys2.org [[Install]][raw-MDIT] diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 70662cb..21b4abb 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -9,7 +9,7 @@ "created": "Apr 4, 2020", "updated": "Oct 27, 2020", "desc": "**This script should no longer be needed after Google's removal of overlay ads on April 6th, 2023.**
\n
\nYou know those little overlay advertisements that pop up on the bottom center of YouTube videos? If those really annoy you, this simple userscript (really just a userstyle wrapped into a userscript) will help by simply preventing them from rendering.
\nNote that this _does not_ affect other ads.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Fix YouTube Player Bottom Gradient", @@ -20,7 +20,7 @@ "created": "Feb 26, 2021", "updated": "Mar 30, 2021", "desc": "This \"fixes\" the excessively large bottom gradient area that sometimes appears on the YouTube video player when the mouse cursor is within the player frame.
\n**So far, I've only seen the phenomenon that led me to write this while using Vivaldi.**", - "version": "1.0" + "version": "1.0.0" }, { "name": "YouTube Channel Keyboard Protection", @@ -31,7 +31,7 @@ "created": "Nov 13, 2021", "updated": "May 1, 2022", "desc": "Prevents YouTube from hijacking the Up/Down arrow keys on channel pages, as it likes to do sometimes (Left and Right arrow keys are okay though, because those don't control page scrolling).", - "version": "1.1" + "version": "1.1.0" }, { "name": "Twitch Hide Content Disclosure", @@ -73,9 +73,9 @@ "license": "MIT", "autoUpdates": true, "created": "May 19, 2021", - "updated": "Dec 12, 2024", + "updated": "Feb 9, 2026", "desc": "Makes the video stats overlay on Twitch.tv video player partially transparent, so as to avoid obscuring the stream so much.", - "version": "1.1.1" + "version": "1.1.2" }, { "name": "GitHub Repo Network Tab", @@ -97,7 +97,7 @@ "created": "Apr 12, 2020", "updated": "Oct 28, 2021", "desc": "Makes the timeline on the Network page of GitHub repositories utilize more of that available whitespace on the sides.
\nStill can't seem to make it use all the space on the right side though...
\n
\nEssentially a subset of [Wide GitHub](https://github.com/xthexder/wide-github) which, of course, I only realized after I'd written this.
\nOh well, someone will probably find this useful.", - "version": "1.0" + "version": "1.0.0" }, { "name": "GitHub Notification Page Tweaks", @@ -108,7 +108,7 @@ "created": "Oct 22, 2020", "updated": "Aug 3, 2021", "desc": "Why does GitHub's beta notifications inbox use a \"More\" dropdown when there's more than enough space for the 2 elements within?
\nI don't know, and I dislike having to open a dropdown just to mark something as \"read\", so I did something about it.", - "version": "1.1" + "version": "1.1.0" }, { "name": "GitHub Sticky Editor Header", @@ -119,7 +119,7 @@ "created": "Nov 24, 2021", "updated": "Nov 24, 2021", "desc": "Makes the header of the (text) file editor on GitHub sticky.
\nWritten because I got sick and tired of having to move up and down the page to change to and from the preview while editing this README.", - "version": "1.0" + "version": "1.0.0" }, { "name": "GitLab Description In Title", @@ -130,7 +130,7 @@ "created": "May 22, 2021", "updated": "Aug 3, 2021", "desc": "Attempts to improve the page titles on GitLab by including the contents of the page's description, if one is provided.
\nThis also replaces instances of Unicode character 0x00B7, \"Middle Dot\", in the title, as I've found that particular character\nhas strangely led some editors to erroneously read and write the text in undesired encodings, such as GB2312, instead of UTF-8.", - "version": "1.1" + "version": "1.1.0" }, { "name": "Prettier Lib.rs Preformatted Code", @@ -141,7 +141,7 @@ "created": "Jul 5, 2020", "updated": "Mar 30, 2021", "desc": "Makes `
` blocks on lib.rs look more like they do on crates.io; lib.rs is so much faster thanks to reduced JS use, but it's not as pretty.",
-			"version": "1.0"
+			"version": "1.0.0"
 		},
 		{
 			"name": "Lib.rs Description In Title",
@@ -152,7 +152,7 @@
 			"created": "Apr 28, 2021",
 			"updated": "May 11, 2021",
 			"desc": "Replace the unhelpful part of the tab title on a lib.rs crate's page with the short description of the crate, if one is provided.
\nConvenient for bookmarking and tab-saving extensions, as pages are typically stored according to their titles.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Crates.io Description In Title", @@ -174,7 +174,7 @@ "created": "Jun 19, 2020", "updated": "Apr 5, 2021", "desc": "Do you hate that Gmail shows a toast notification that blocks functional regions of the UI after you do something to any email? Me too!
\nThis little change should help mitigate the problem by moving the toast notification to the bottom center of the screen.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Google Meet Ignore Hardware Disabled", @@ -185,7 +185,7 @@ "created": "Mar 3, 2023", "updated": "Mar 3, 2023", "desc": "A.K.A \"I know my hardware is disabled, Google\"
\nThanks Google, but I'm well aware that my browser hasn't given you permission to access my hardware; I don't need you showing a prompt that can't be closed with a keypress.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Wider Google Form Fields", @@ -196,7 +196,7 @@ "created": "Sep 30, 2021", "updated": "Aug 19, 2022", "desc": "Widens the input fields in google forms from 50% to 100% of the question element (minus padding).", - "version": "1.1" + "version": "1.1.0" }, { "name": "Correct Google Form Correctness", @@ -207,7 +207,7 @@ "created": "Nov 9, 2021", "updated": "Nov 9, 2021", "desc": "Make fields that have been manually marked as correct take on the same styling as fields that exactly matched the preset correct answer.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Google Search Lean Query Updates", @@ -240,7 +240,7 @@ "created": "Jan 23, 2021", "updated": "Apr 5, 2021", "desc": "This should disable changing the value of any numeric fields on Roll20 character sheets by scrolling.
\nTODO: Replace the use of setTimeout with a MutationObserver.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Bypass Blogspot's Blogger IFrame", @@ -251,7 +251,7 @@ "created": "Jun 2, 2021", "updated": "May 1, 2022", "desc": "Unhide the page body and hide obstructive injected iframes on some Blogspot pages, which use those methods for reasons like discouraging ad blocking.", - "version": "1.1" + "version": "1.1.0" }, { "name": "Foxaholic Fixes", @@ -262,7 +262,7 @@ "created": "Jun 2, 2021", "updated": "Aug 27, 2021", "desc": "Fix Foxaholic's deliberate breaking of context menus, keypresses, and text selection.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Mitigate Target \\_blank Risk", @@ -273,7 +273,7 @@ "created": "Aug 27, 2021", "updated": "Nov 23, 2021", "desc": "Appends `rel=\"noopener noreferrer\"` to every link (HTMLAnchorElement, not to be confused with HTMLLinkElement) that has `target=\"_blank\"`, preventing a possible security risk.
\nThis **_will_** break links to some sites, likely any links that would otherwise have opened in a new tab by default.
\nUsers may choose to ignore links from additional url origins, by setting the `customAllowedOrigins` key in the script's value storage to a list of origins, delimited by a single space character, `' '`.
\ne.g. Setting `customAllowedOrigins` to `'http://wordpress.com https://stackexchange.com https://novelupdates.com'` will prevent this script from modifying links to those origins.", - "version": "1.1" + "version": "1.1.0" }, { "name": "MSYS2 Package Description In Title", @@ -295,7 +295,7 @@ "created": "Apr 20, 2022", "updated": "Jun 18, 2022", "desc": "Modifies the format of the page title for some of CurseForge's Minecraft pages.", - "version": "1.1" + "version": "1.1.0" }, { "name": "Another \"Open In Steam\" Button", @@ -306,7 +306,7 @@ "created": "Nov 25, 2022", "updated": "Nov 25, 2022", "desc": "As the name should imply, this is my own version of a script which adds a new button on Steam's steampowered and steamcommunity sites to open the current page in the Steam app.
\nSome of the CSS used was borrowed from https://greasyfork.org/en/scripts/454372-open-steam-url after I spent well over an hour fiddling with my own CSS in the pre-dawn hours, and decided I wasn't going to manage much better.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Ubuntu Packages Description In Title", @@ -317,7 +317,7 @@ "created": "May 11, 2023", "updated": "May 11, 2023", "desc": "Try to provide a minimal, yet meaningful, page title that includes the package description on Ubuntu's package search/archive website.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Quietly Reject StackExchange Cookies", @@ -328,7 +328,7 @@ "created": "May 14, 2023", "updated": "May 14, 2023", "desc": "Hide the pesky cookie permission requests on StackExchange sites, which don't actually appear to set even \"necessary\" cookies until the user responds to the permission prompt.
\nAlso hides a few other little things that just don't warrant another tiny script.", - "version": "1.0" + "version": "1.0.0" }, { "name": "PyPI Description In Title", @@ -339,7 +339,7 @@ "created": "May 31, 2023", "updated": "Aug 15, 2024", "desc": "Rewrite the page title for a PyPI package to include a brief summary, when available.
\n
\nAlso doesn't use that centered dot character as a separator.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Simple URL Tracker Cleaner", @@ -361,7 +361,7 @@ "created": "Apr 8, 2022", "updated": "Jul 2, 2023", "desc": "Hide posts from arbitrary subreddits (unless specifically looking at them, of course).
\n
\nOnly works for old.reddit.com, not www.reddit.com, because not only does the latter use a DOM structure that makes it unsuitable for applying styles to entire post-elements by the CSS selector of the child element holding the subreddit, it _also_ commits the desktop (and frankly, even mobile) user-experience war-crime of infinite pagination (endless scrolling). **TLDR: Modern Reddit UI sucks, and supporting it would take more effort than I'm willing to put in to this for my own use.**", - "version": "1.1" + "version": "1.1.0" }, { "name": "ScribbleHub Reading List Upgrades", @@ -372,7 +372,7 @@ "created": "Oct 7, 2022", "updated": "Jan 19, 2024", "desc": "Allows hiding novels the user is caught up on from their reading lists, adds the current reading list name to the page title, and more planned.", - "version": "1.2" + "version": "1.2.0" }, { "name": "NovelUpdates Reading List Upgrades", @@ -383,7 +383,7 @@ "created": "Jul 8, 2022", "updated": "Nov 16, 2022", "desc": "Allows hiding novels the user is caught up on from their reading lists, adds the current reading list name to the page title, and more planned.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Softpedia Improvements", diff --git a/twitch_transparent_video_stats.user.js b/twitch_transparent_video_stats.user.js index 6090678..1ad2e4f 100644 --- a/twitch_transparent_video_stats.user.js +++ b/twitch_transparent_video_stats.user.js @@ -13,7 +13,7 @@ // @exclude-match https://www.twitch.tv/settings* // @exclude-match https://www.twitch.tv/turbo* // @exclude-match https://www.twitch.tv/annual-recap -// @version 1.1.1 +// @version 1.1.2 // @createdAt 5/19/2021 // @author StaticPH // @description Makes the video stats overlay 50% transparent @@ -25,7 +25,7 @@ // @icon https://brand.twitch.tv/assets/logos/svg/glitch/purple.svg // @grant GM.addStyle // @grant GM_addStyle -// @run-at document-start +// @run-at document-idle // ==/UserScript== (function(){ @@ -46,7 +46,8 @@ } GM.addStyle(` - div.video-player__overlay div.simplebar-scroll-content > div.simplebar-content > div { + div.video-player__overlay div.simplebar-scroll-content > div.simplebar-content > div, + [data-a-target="player-overlay-video-stats"] { opacity: 0.5; } `); From d72eac633a0736ff58c41746fcaca1ed5c538e3e Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Mon, 9 Feb 2026 11:10:01 -0500 Subject: [PATCH 11/17] MSYS2 Package Description In Title: Add support for Base Package pages --- README.md | 2 +- build/data_files/main_script_manifest.json | 6 +++--- msys2_package_description_in_title.user.js | 17 +++++++++++------ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 108f3bb..ae294cd 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ To add a script: | [Bypass Blogspot's Blogger IFrame](#BBBI) | [install][raw-BBBI] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | May 1, 2022 | | [Foxaholic Fixes](#FoxF) | [install][raw-FoxF] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | Aug 27, 2021 | | [Mitigate Target \_blank Risk](#MTBR) | [install][raw-MTBR] | N/A | :heavy_check_mark: | MIT | Aug 27, 2021 | Nov 23, 2021 | -| [MSYS2 Package Description In Title](#MDIT) | [install][raw-MDIT] | N/A | :heavy_check_mark: | MIT | Apr 28, 2021 | Sep 28, 2024 | +| [MSYS2 Package Description In Title](#MDIT) | [install][raw-MDIT] | N/A | :heavy_check_mark: | MIT | Apr 28, 2021 | Feb 9, 2026 | | [Minecraft CurseForge Title Tweaks](#MCTT) | [install][raw-MCTT] | N/A | :heavy_check_mark: | MIT | Apr 20, 2022 | Jun 18, 2022 | | [Another "Open In Steam" Button](#OISB) | [install][raw-OISB] | N/A | :heavy_check_mark: | MIT | Nov 25, 2022 | Nov 25, 2022 | | [Ubuntu Packages Description In Title](#UPDIT) | [install][raw-UPDIT] | N/A | :heavy_check_mark: | MIT | May 11, 2023 | May 11, 2023 | diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 21b4abb..af33274 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -282,9 +282,9 @@ "license": "MIT", "autoUpdates": true, "created": "Apr 28, 2021", - "updated": "Sep 28, 2024", - "desc": "Include the package description on the tab title for a package's page on packages.msys2.org/packages", - "version": "1.2.0" + "updated": "Feb 9, 2026", + "desc": "Include the package description on the tab title for a package's page on packages.msys2.org", + "version": "1.2.1" }, { "name": "Minecraft CurseForge Title Tweaks", diff --git a/msys2_package_description_in_title.user.js b/msys2_package_description_in_title.user.js index 2072e8e..28db64e 100644 --- a/msys2_package_description_in_title.user.js +++ b/msys2_package_description_in_title.user.js @@ -1,12 +1,13 @@ // ==UserScript== // @name MSYS Packages Description In Title // @namespace https://github.com/StaticPH +// @include http*://packages.msys2.org/base/* // @include http*://packages.msys2.org/package/* // @include http*://packages.msys2.org/packages/* -// @version 1.2.0 +// @version 1.2.1 // @createdAt 4/28/2021 // @author StaticPH -// @description Include the package description on the tab title for a package's page on packages.msys2.org/packages. +// @description Include the package description on the tab title for a package's page on packages.msys2.org. // @license MIT // @updateURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/msys2_package_description_in_title.user.js // @downloadURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/msys2_package_description_in_title.user.js @@ -22,12 +23,16 @@ setTimeout(function wait(){ const pkgName = document.querySelector('h4.card-title'); - const pkgDesc = document.querySelector('h6.card-subtitle, .card-body > dl > dd:nth-child(6)'); - - //TODO: Modify script to also indicate which pkg subpage is currently loaded (if it isnt the readme subpage) + let pkgDesc = null; + if (document.location.pathname.startsWith('/base/')){ + pkgDesc = document.querySelector('.card-body > dl > dd:nth-child(2)'); + } + else{ + pkgDesc = document.querySelector('h6.card-subtitle, .card-body > dl > dd:nth-child(6)'); + } if (pkgName && pkgDesc){ - document.title=`${pkgName.textContent.trim()} — ${pkgDesc.textContent.trim()}`; + document.title = `${pkgName.textContent.trim()} — ${pkgDesc.textContent.trim()}`; } else{ setTimeout(wait, 100); // Continue trying every 100ms until success From c5611ec46fdba3900444156474151c666bbdba22 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Fri, 27 Feb 2026 17:31:22 -0500 Subject: [PATCH 12/17] Github Repo Network Tab: Thanks for making it more annoying to find or work with meaningful elements using CSS selectors in a modern browser, GitHub. /s --- README.md | 2 +- build/data_files/main_script_manifest.json | 4 +- github_repo_network_tab.user.js | 95 +++++++++++++++++----- 3 files changed, 79 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index ae294cd..b8bc053 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ To add a script: | [Twitch Hide Channel Leaderboard](#THCL) | [install][raw-THCL] | N/A | :heavy_check_mark: | MIT | Jun 19, 2020 | Dec 12, 2024 | | [Twitch Hide Overlay Ads](#THOA) | [install][raw-THOA] | N/A | :heavy_check_mark: | MIT | Dec 14, 2023 | Dec 12, 2024 | | [Twitch Transparent Video Stats](#TTVS) | [install][raw-TTVS] | N/A | :heavy_check_mark: | MIT | May 19, 2021 | Feb 9, 2026 | -| [GitHub Repo Network Tab](#GRNT) | [install][raw-GRNT] | N/A | :heavy_check_mark: | MIT | Apr 6, 2020 | Feb 1, 2024 | +| [GitHub Repo Network Tab](#GRNT) | [install][raw-GRNT] | N/A | :heavy_check_mark: | MIT | Apr 6, 2020 | Feb 27, 2026 | | [Bigger GitHub Network Graph](#BGNG) | [install][raw-BGNG] | N/A | :heavy_check_mark: | MIT | Apr 12, 2020 | Oct 28, 2021 | | [GitHub Notification Page Tweaks](#GNPT) | [install][raw-GNPT] | N/A | :heavy_check_mark: | MIT | Oct 22, 2020 | Aug 3, 2021 | | [GitHub Sticky Editor Header](#GSEH) | [install][raw-GSEH] | N/A | :heavy_check_mark: | MIT | Nov 24, 2021 | Nov 24, 2021 | diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index af33274..5926c55 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -84,9 +84,9 @@ "license": "MIT", "autoUpdates": true, "created": "Apr 6, 2020", - "updated": "Feb 1, 2024", + "updated": "Feb 27, 2026", "desc": "Adds a navigation tab for faster access to the 'Network' page of a repository.
\n
\nKnown bugs:\n- Occasionally the tab fails to be added, with no clear explanation or pattern. If this occurs, simply reload the page.\n- When switching between repository tabs, the network tab sometimes disappears, and something about the way GitHub does page navigation within a repository doesn't cause this script to be re-injected. Short of constantly checking state on a sub-second timer, or using a mutation observer, I don't know how else to solve this.", - "version": "1.7.2" + "version": "1.8.0" }, { "name": "Bigger GitHub Network Graph", diff --git a/github_repo_network_tab.user.js b/github_repo_network_tab.user.js index 95b3e3b..0d8a5b3 100644 --- a/github_repo_network_tab.user.js +++ b/github_repo_network_tab.user.js @@ -25,7 +25,7 @@ // @exclude-match https://github.com/topics* // @exclude-match https://github.com/trending* // @exclude-match https://github.com/users/*/projects/* -// @version 1.7.2 +// @version 1.8.0 // @createdAt 4/06/2020 // @author StaticPH // @description Adds a navigation tab for faster access to the 'Network' page of a repository. @@ -48,16 +48,16 @@ return location.pathname.split('/', 3).slice(1).join('/'); })(); + const networkIconSvgHTML = ''; + /* Honestly, I feel like creating the HTML directly is less of a hassle than creating all the elements with JavaScript */ function createBigNetworkTabHTML(){ // Exclude analytical "data-ga-click" and "data-selected-links" attributes return '\n' + - ' \n' + + '\t' + networkIconSvgHTML + '\n' + ' \n' + ' Network\n' + - ' \n' + + ' \n' + '\n'; //TODO: Intelligently determine if the link element should have 'style="visibility:hidden;"' to start with? } @@ -81,6 +81,53 @@ '
  • '; } + function maybeFixHighlightedTab(){ + if (location.pathname.endsWith(here + '/network') || location.pathname.endsWith(here + '/network/')){ + let networkTab = document.querySelector('[data-tab-item="i2_1network-tab"]'); + let insightsTab = document.querySelector('[data-tab-item="i7insights-tab"]'); + + if (insightsTab /*&& insightsTab.hasAttribute('aria-current')*/){ + insightsTab.removeAttribute('aria-current'); + insightsTab.classList.remove('selected'); + } + if (networkTab){ + networkTab.setAttribute('aria-current', 'page'); + networkTab.classList.add('selected'); + } + } + } + + function doesNeedModernTabVariant(){ + // Thanks for making it more annoying to find or work with meaningful elements using CSS selectors, GitHub. /s + return document.querySelector('nav[class*="prc-components-UnderlineWrapper"]') !== null; + } + + function modernUIAddNetworkTab(){ + const prTabLink = document.querySelector(`li.prc-UnderlineNav-UnderlineNavItem-syRjR > a[href="/${here}/pulls"]`); + if (!prTabLink){ return false; } // Not ready yet... or GitHub changed shit again. + + const dataAttrs = 'data-turbo-frame="repo-content-turbo-frame" data-discover="true"'; + const isActiveTab = (location.pathname.endsWith('/network') || location.pathname.endsWith('/network/')); + const tabHTML = '
  • \n' + + `\n` + + ` ${networkIconSvgHTML}\n` + + // May want to skip adding actual text manually due to css attr magic setting value from data-content + ' Network\n' + + '\n' + + '
  • '; + prTabLink.parentElement.insertAdjacentHTML('afterend', tabHTML); + + const networkTab = document.querySelector('#bigNetworkTab'); + if (isActiveTab){ + const falseActiveTab = document.querySelector('li.prc-UnderlineNav-UnderlineNavItem-syRjR > a[aria-current]'); + if (falseActiveTab){ + falseActiveTab.removeAttribute('aria-current'); + } + networkTab.setAttribute('aria-current', 'page'); + } + return networkTab; + } + //TODO: Consider insertion at Nth element position, rather than relative to PR tab. setTimeout(function wait(){ /* Find the 'Pull Requests' tab; inserting the new Network tab immediately after it ensures consistent placement. */ @@ -120,29 +167,39 @@ else if (dropdownRetries >= dropdownRetryLimit){ console.log(`Number of attempts at adding Network tab to dropdown have exceeded the limit of ${dropdownRetryLimit} attempts. Giving up.`); } - else{ + else { console.log(`Waiting ${(dropdownRetries * 500) + 500}ms for page to load further before attempting insertion of dropdown-item.`); dropdownRetries++; setTimeout(waitmore, (dropdownRetries * 500) + 500); } }); - if (location.pathname.endsWith(here + '/network') || location.pathname.endsWith(here + '/network/')){ - let networkTab = document.querySelector('[data-tab-item="i2_1network-tab"]'); - let insightsTab = document.querySelector('[data-tab-item="i7insights-tab"]'); - - if (insightsTab /*&& insightsTab.hasAttribute('aria-current')*/){ - insightsTab.removeAttribute('aria-current'); - insightsTab.classList.remove('selected'); - } - if (networkTab){ - networkTab.classList.add('selected'); - } + maybeFixHighlightedTab(); + } + else if (doesNeedModernTabVariant()){ + if (modernUIAddNetworkTab()){ + console.log('Added Network tab to modern nagivation menu.'); + (async function(){ + return await setInterval(function babysit(){ + // Compensate for React's DOM fuckery often regenerating the navigation tabs (and who knows what else) shortly after document-idle; + // check back every 5 seconds. + if (!document.querySelector('#bigNetworkTab')){ + console.log('Compensating for React DOM fuckery regenerating the navigation tabs. Re-adding Network tab'); + if (modernUIAddNetworkTab()){ + console.log('Network tab re-added to modern navigation menu.'); + }; + } + }, 5000); + })(); + } + else { + console.log('Modern UI required; waiting 300ms for page to load further.'); + return setTimeout(wait, 300); } } - else{ + else { console.log('Waiting 300ms for page to load further.'); - setTimeout(wait, 300); + return setTimeout(wait, 300); } }); })(); From a41832113ef924b5a7e10f713ed2a82fa8a9ec58 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 28 Feb 2026 00:55:15 -0500 Subject: [PATCH 13/17] GitHub Issue Comments Legacy Workaround: Relax a selector. GitHub Collapsed Details Legacy Workaround: Unconditionally remove and add a CSS class instead of attempting to replace and falling back to adding. GitHub Lazy Release Assets Legacy Workaround: Made a selector more strict. --- build/data_files/legacy_scripts.json | 37 +++++++++++-------- ...ithub_collapsed_details_workaround.user.js | 13 ++++--- ...thub_lazy_release_asset_workaround.user.js | 4 +- ...hub_show_issue_comments_workaround.user.js | 7 ++-- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/build/data_files/legacy_scripts.json b/build/data_files/legacy_scripts.json index 32f83fb..b287537 100644 --- a/build/data_files/legacy_scripts.json +++ b/build/data_files/legacy_scripts.json @@ -5,70 +5,77 @@ "anchorString": "DFSF", "path": "/legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Jun 29, 2024", "updated": "Mar 23, 2025", - "desc": "Fix for Discourse forums breaking the ability to scroll on browsers that are too old or are blocking some script or other." + "desc": "Fix for Discourse forums breaking the ability to scroll on browsers that are too old or are blocking some script or other.", + "version": "1.0.4" }, { "name": "GitHub Line Hyperlink Workaround", "anchorString": "GLHW", "path": "/legacy_browser_workarounds/github_line_hyperlink_workaround.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Aug 10, 2022", "updated": "Nov 18, 2022", - "desc": "Add simple onclick handlers to the line numbers when viewing files on GitHub, as the normal behavior of linking directly to a clicked line number seems to have broken on legacy browsers as a result of some change to the implementation." + "desc": "Add simple onclick handlers to the line numbers when viewing files on GitHub, as the normal behavior of linking directly to a clicked line number seems to have broken on legacy browsers as a result of some change to the implementation.", + "version": "1.1.0" }, { "name": "GitHub Notifications Archive Workaround", "anchorString": "GNAW", "path": "/legacy_browser_workarounds/github_notifications_archive_workaround.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Jul 10, 2022", "updated": "Mar 12, 2023", - "desc": "Quick and simple redirect to work around strange behavior of being sent to github.com/notifications/beta/archive when marking notifications as done." + "desc": "Quick and simple redirect to work around strange behavior of being sent to github.com/notifications/beta/archive when marking notifications as done.", + "version": "1.1.0" }, { "name": "GitHub Collapsed Details Workaround", "anchorString": "GCDW", "path": "/legacy_browser_workarounds/github_collapsed_details_workaround.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Sep 30, 2022", "updated": "Jun 10, 2023", - "desc": "Add simple onclick handlers to the collapsed details of commits on GitHub, as the normal behavior of expanding the ellipses to the full commit message when clicked seems to have broken on legacy browsers as a result of some change to the implementation." + "desc": "Add simple onclick handlers to the collapsed details of commits on GitHub, as the normal behavior of expanding the ellipses to the full commit message when clicked seems to have broken on legacy browsers as a result of some change to the implementation.", + "version": "1.2.1" }, { "name": "GitHub Lazy Release Asset Workaround", "anchorString": "GLRAW", "path": "/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Oct 8, 2022", "updated": "Mar 12, 2023", - "desc": "Multiple fixes related to user-downloadable asset files on GitHub for users of legacy browsers.\n- Fetch asset list for releases, as the code that should already have been responsible for that is too modern, and is thus never even attempted on legacy browsers.\n- Fix the timestamps on the release page(s), most of which are within asset lists.\n- Slightly changes normal behavior by automatically showing __all__ assets for the first release on the page, whether that's two assets or fourty assets." + "desc": "Multiple fixes related to user-downloadable asset files on GitHub for users of legacy browsers.\n- Fetch asset list for releases, as the code that should already have been responsible for that is too modern, and is thus never even attempted on legacy browsers.\n- Fix the timestamps on the release page(s), most of which are within asset lists.\n- Slightly changes normal behavior by automatically showing __all__ assets for the first release on the page, whether that's two assets or fourty assets.", + "version": "1.1.1" }, { "name": "GitHub Show Issue Comments Workaround", "anchorString": "GSICW", "path": "/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Nov 10, 2025", "updated": "Nov 10, 2025", - "desc": "Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish." + "desc": "Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish.", + "version": "1.0.1" }, { "name": "StackExchange Legacy Comments Expander", "anchorString": "SELCE", "path": "/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Nov 6, 2022", "updated": "Nov 2, 2023", - "desc": "Replace 'Show X more comments' handler for StackExchange sites to better support older browsers; in particular, this enables showing all comments when using Chromium 72." + "desc": "Replace 'Show X more comments' handler for StackExchange sites to better support older browsers; in particular, this enables showing all comments when using Chromium 72.", + "version": "1.1.0" } ] -} +} \ No newline at end of file diff --git a/legacy_browser_workarounds/github_collapsed_details_workaround.user.js b/legacy_browser_workarounds/github_collapsed_details_workaround.user.js index ba3a2ff..4916e23 100644 --- a/legacy_browser_workarounds/github_collapsed_details_workaround.user.js +++ b/legacy_browser_workarounds/github_collapsed_details_workaround.user.js @@ -25,7 +25,7 @@ // @exclude-match https://github.com/topics* // @exclude-match https://github.com/trending* // @exclude-match https://github.com/users/*/projects/* -// @version 1.2 +// @version 1.2.1 // @createdAt 9/30/2022, 9:32:58 PM // @author StaticPH // @description Add simple onclick handlers to the collapsed details of commits on GitHub, as the normal behavior of expanding the ellipses to the full commit message when clicked seems to have broken on legacy browsers as a result of some change to the implementation. Also fixes some other instances of non-functioning collapsing elements. @@ -64,9 +64,12 @@ // let commitRow = evnt.target.closest('.Details').querySelector('p+*'); let commitRow = evnt.target.closest('.Details').querySelector('.Details-content--hidden, .Details-content--on') || evnt.target.closest('.Details').querySelector('.text-small').parentElement; commitRow.classList.toggle('Details-content--hidden'); - hasRefinedGithub && commitRow.closest('.rgh-dim-bot').classList.toggle('Details--on'); + if (hasRefinedGithub){ + commitRow.closest('.rgh-dim-bot').classList.toggle('Details--on'); + } } + /* oxlint-disable-next-line unicorn/prefer-add-event-listener */ document.querySelectorAll('.hidden-text-expander > button.ellipsis-expander.js-details-target').forEach(expander => expander.onclick = toggleShowDetails); if (urlRelativeToRepoDefault.startsWith('/wiki')){ @@ -110,9 +113,9 @@ evnt.target.parentElement.querySelector('[data-target="annotation-message.showLessButton"]').toggleAttribute('hidden'); } else { // Normally implies that classList contains 'annotation--expanded' - // replace 'annotation--expanded' with 'annotation--contracted' if the former exists, otherwise just add the latter; - // the second case is a fallback in case the class was previously just removed entirely, rather than replaced. - annotationBody.classList.replace('annotation--expanded', 'annotation--contracted') || annotationBody.classList.add('annotation--contracted'); + // Always attempt to remove the `annotation--expanded` class from annotationBody, and ensure it always has the `annotation--contracted` class. + annotationBody.classList.remove('annotation--expanded'); + annotationBody.classList.add('annotation--contracted'); evnt.target.toggleAttribute('hidden'); evnt.target.parentElement.querySelector('[data-target="annotation-message.showMoreButton"]').toggleAttribute('hidden'); } diff --git a/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js b/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js index e23c952..f9157e1 100644 --- a/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js +++ b/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Lazy Release Assets Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/releases* -// @version 1.1 +// @version 1.1.1 // @createdAt 10/8/2022, 4:40:25 PM // @author StaticPH // @description Fixes a number of things related to user-downloadable asset files on GitHub for users of legacy browsers. @@ -67,7 +67,7 @@ }); } - document.querySelectorAll('[data-view-component] include-fragment[loading="lazy"][src]:not([src=""])').forEach(async function(lazyPageFrag){ + document.querySelectorAll('[data-view-component] include-fragment[loading="lazy"][src]:not([src=""]):not([data-target="select-panel.includeFragment"])').forEach(async function(lazyPageFrag){ try{ await fetch(lazyPageFrag.getAttribute('src'), requestTemplate).then( resp => resp.text().then( diff --git a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js index adcbfee..867cd21 100644 --- a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js +++ b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Issue Comments Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/issues/* -// @version 1.0.0 +// @version 1.0.1 // @createdAt 11/10/2025, 6:17:25 PM // @author StaticPH // @description Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish. @@ -99,10 +99,9 @@ } function fixIssueTimeline(){ - const commentContainer = document.querySelector('div.react-comments-container > div.IssueViewer-module__commentsContainer--H8wxg'); + const commentContainer = document.querySelector('div.react-comments-container > div[class*="IssueViewer-module__commentsContainer"]'); const frag = document.createDocumentFragment(); - const substContainer = document.createElement('div'); - substContainer.className = 'IssueViewer-module__commentsContainer--H8wxg'; + const substContainer = commentContainer.cloneNode(); // fix borked styles substContainer.insertAdjacentHTML('beforeEnd', ``); From 4ea72155688fbcf25526e3423d18c3eb11177e76 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:29:07 -0500 Subject: [PATCH 14/17] GitHub Issue Comments Legacy Workaround: Slightly simplify the non-functional reactions button, and hardcode a tooltip. It's not like anyone but me will use this, and I know what to expect in the first place. --- ...hub_show_issue_comments_workaround.user.js | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js index 867cd21..d90aee4 100644 --- a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js +++ b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Issue Comments Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/issues/* -// @version 1.0.1 +// @version 1.0.2 // @createdAt 11/10/2025, 6:17:25 PM // @author StaticPH // @description Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish. @@ -20,7 +20,9 @@ (function(){ "use strict"; - const reactionToolbarHTML = `` + const reactionIconHTML = ''; + const reactionToolbarHTML = ``; + const fixedStyles = ` .dShPvE { display: flex; @@ -112,4 +114,18 @@ commentContainer.replaceWith(frag); } fixIssueTimeline(); + + /* + document.querySelectorAll('[aria-label="Reactions"]').forEach(function(ele){ + const btn = ele.querySelector('button[aria-labelledby=":rr:"]'); + if (!btn || btn.title){ return; } // No need to substitute a tooltip + if (btn.ariaDescribedBy === ':rq:-loading-announcement){ + btn.removeAttribute('aria-describedby'); + } + const oldLabelEle = ele.querySelector('[id=":rr:"]'); + if (!oldLabelEle){ return; } // No need to substitute a tooltip + btn.title = oldLabelEle.textContent; + oldLabelEle.remove(); // Will likely break the reaction menu popover, if I ever got around to fixing it in a way that resembles the modern standard behavior. + }); + */ // Hardcoded simplification, since the dummy reactions buttons are just constant raw HTML being applied by this script anyways. })(); From 4af43b64601cafa3e424c6b3f958445db59d1724 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:41:03 -0500 Subject: [PATCH 15/17] GitHub Issue Comments Legacy Workaround: Add tooltips for long descriptions to Issue labels. While not strictly within the scope of the script, it seemed like expanding upon this later might help cover some bases. --- ...hub_show_issue_comments_workaround.user.js | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js index d90aee4..c0ba037 100644 --- a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js +++ b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Issue Comments Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/issues/* -// @version 1.0.2 +// @version 1.1.0 // @createdAt 11/10/2025, 6:17:25 PM // @author StaticPH // @description Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish. @@ -113,7 +113,57 @@ frag.append(substContainer); commentContainer.replaceWith(frag); } + + function redoIssueLabelTooltips(){ + // Add tooltips for long descriptions to Issue labels. + /* + document.querySelectorAll('[aria-describedby*="-tooltip"]').forEach(function(ele){ + const tooltipIDSelector = ele.getAttribute('aria-describedby').split(' ').map(s => `[id="${s}"]`).join(','); + // Even if there may be multiple IDs, as the spec permits, take whatever is found first. + const descriptor = document.querySelector(tooltipIDSelector); + + if(!descriptor){ + console.warn(`ERROR: unable to find an element matching the selector "${tooltipIDSelector}"`); + return; + } + ele.title = descriptor.textContent.trim(); + descriptor.remove(); + ele.removeAttribute('aria-describedby'); + }); + */ + + // Has a similar overall effect, but less explicit DOM manipulation, I guess? + document.head.insertAdjacentHTML('beforeEnd', ` + `); + // The attribute `role="tooltip"` isn't already added by GitHub, even though aria-describedby is. + // Not sure what was expected to happen like that. + document.querySelectorAll('.sr-only[id*="-tooltip"]').forEach(e => e.setAttribute('role', 'tooltip')); + } + fixIssueTimeline(); + redoIssueLabelTooltips(); /* document.querySelectorAll('[aria-label="Reactions"]').forEach(function(ele){ From 1d4ed11505c00d34bec6005c877ab137368f4a50 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 28 Feb 2026 20:44:09 -0500 Subject: [PATCH 16/17] GitHub Issue Comments Legacy Workaround: Use friendly, localized, absolute timestamps because GitHub's relative-time-element isn't loading for some reason, which results in the custom element not showing any time. --- build/data_files/legacy_scripts.json | 4 ++-- ...hub_show_issue_comments_workaround.user.js | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/build/data_files/legacy_scripts.json b/build/data_files/legacy_scripts.json index b287537..dc30e2f 100644 --- a/build/data_files/legacy_scripts.json +++ b/build/data_files/legacy_scripts.json @@ -62,9 +62,9 @@ "license": "MIT", "autoUpdates": true, "created": "Nov 10, 2025", - "updated": "Nov 10, 2025", + "updated": "Mar 1, 2026", "desc": "Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish.", - "version": "1.0.1" + "version": "1.1.1" }, { "name": "StackExchange Legacy Comments Expander", diff --git a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js index c0ba037..535fc41 100644 --- a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js +++ b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Issue Comments Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/issues/* -// @version 1.1.0 +// @version 1.1.1 // @createdAt 11/10/2025, 6:17:25 PM // @author StaticPH // @description Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish. @@ -55,8 +55,19 @@ // Each *COMMENT* item in responseNodesData has the following properties (non-exhaustive): {author:{avatarUrl, id, login, name, profileUrl}, bodyHTML, bodyVersion, createdAt, databaseId, id, lastEditedAt, lastUserContentEdit:{editor:{id, login, url, __typename}, id}, reactionGroups, url} const responseNodesData = responses.map(e => e.node); + const friendlyTimeFormatter = new Intl.DateTimeFormat(navigator.language, { numberingSystem: 'ltn', calendar: 'gregory', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', hour12: true, minute: 'numeric', second: 'numeric' }); + + function buildTimeElement(timestamp){ + return `${ + // Until I come up with a way to make relative-time-element load + // (instead of being skipped due to earlier parsing errors), + // just use the absolute time in a friendly format + friendlyTimeFormatter.format(new Date(timestamp)) + }`; + } + function buildCommentNode(commentNode){ - return `\t
    + return `\t
    ${commentNode.author.login}
    @@ -65,14 +76,14 @@
    -

    ${commentNode.author.login} commented

    +

    ${commentNode.author.login} commented ${buildTimeElement(commentNode.createdAt)}

    @${commentNode.author.login}
    From 40bde333dea49f3bb32950891a3b38b25b834cec Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Wed, 11 Mar 2026 18:33:03 -0400 Subject: [PATCH 17/17] GitHub Lazy Release Assets Legacy Workaround: Convert all times to locale's absolute time, so that there's at least a time and a year on everything that needs it. StackExchange Legacy Comments Expander: Re-implement expanding comments on answers, because that's somehow different from comments on the question itself. Add an entry to the exclusions list for Github Repo Network Tab and GitHub Collapsed Details Legacy Workaround. --- github_repo_network_tab.user.js | 1 + ...ithub_collapsed_details_workaround.user.js | 1 + ...thub_lazy_release_asset_workaround.user.js | 29 +++-- ...kexchange_legacy_comments_expander.user.js | 116 +++++++++++++++++- 4 files changed, 133 insertions(+), 14 deletions(-) diff --git a/github_repo_network_tab.user.js b/github_repo_network_tab.user.js index 0d8a5b3..a230395 100644 --- a/github_repo_network_tab.user.js +++ b/github_repo_network_tab.user.js @@ -9,6 +9,7 @@ // @exclude-match https://github.com/enterprise* // @exclude-match https://github.com/explore* // @exclude-match https://github.com/features* +// @exclude-match https://github.com/github-copilot/* // @exclude-match https://github.com/login/* // @exclude-match https://github.com/marketplace* // @exclude-match https://github.com/new* diff --git a/legacy_browser_workarounds/github_collapsed_details_workaround.user.js b/legacy_browser_workarounds/github_collapsed_details_workaround.user.js index 4916e23..a71559e 100644 --- a/legacy_browser_workarounds/github_collapsed_details_workaround.user.js +++ b/legacy_browser_workarounds/github_collapsed_details_workaround.user.js @@ -9,6 +9,7 @@ // @exclude-match https://github.com/enterprise* // @exclude-match https://github.com/explore* // @exclude-match https://github.com/features* +// @exclude-match https://github.com/github-copilot/* // @exclude-match https://github.com/login/* // @exclude-match https://github.com/marketplace* // @exclude-match https://github.com/new* diff --git a/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js b/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js index f9157e1..738d91c 100644 --- a/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js +++ b/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Lazy Release Assets Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/releases* -// @version 1.1.1 +// @version 1.1.2 // @createdAt 10/8/2022, 4:40:25 PM // @author StaticPH // @description Fixes a number of things related to user-downloadable asset files on GitHub for users of legacy browsers. @@ -40,11 +40,12 @@ 'method': 'GET', 'mode': 'cors' }; - const timestampPreset = { month: 'short', year: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric' }; + const timestampPreset = new Intl.DateTimeFormat(navigator.language, { numberingSystem: 'ltn', calendar: 'gregory', year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', hour12: true, minute: 'numeric' }); async function localizeTimestamp(dateObj){ - return await dateObj.toLocaleString(navigator.language, timestampPreset); + return await timestampPreset.format(dateObj); } + /* // While on the topic of fixing things, fix all the timestamps on the page that don't seem to want to display. // Use the same format as GitHub would be, by utilizing the attributes of the local-time elements. async function fixDate(ele){ @@ -56,16 +57,20 @@ }); } document.querySelectorAll('section local-time:first-of-type').forEach(fixDate); + */ // Similar to fixDate, but tailored for relative-time rather than local-time // FIXME: the format for relative times should probably be different. Check and confirm. async function fixTime(ele){ - ele.textContent = await new Date(ele.getAttribute('datetime')).toLocaleString(navigator.language, { - month: ele.getAttribute('month') || undefined, - day: ele.getAttribute('day') || undefined, - year: ele.getAttribute('year') || undefined - }); + // ele.textContent = await new Date(ele.getAttribute('datetime')).toLocaleString(navigator.language, { + // month: ele.getAttribute('month') || undefined, + // day: ele.getAttribute('day') || undefined, + // year: ele.getAttribute('year') || undefined + // }); + //// Screw it, just use absolute time for the locale. + ele.textContent = await localizeTimestamp(new Date(ele.getAttribute('datetime'))); } + document.querySelectorAll('section relative-time:first-of-type').forEach(fixTime); document.querySelectorAll('[data-view-component] include-fragment[loading="lazy"][src]:not([src=""]):not([data-target="select-panel.includeFragment"])').forEach(async function(lazyPageFrag){ try{ @@ -73,8 +78,8 @@ resp => resp.text().then( async function(html){ await lazyPageFrag.replaceChildren(...parser.parseFromString(html, 'text/html').querySelectorAll('body > [data-view-component]')); - await lazyPageFrag.querySelectorAll('local-time').forEach(await fixDate); - await lazyPageFrag.querySelectorAll('relative-time').forEach(await fixTime); // FIXME: the format for relative times should probably be different. + // await lazyPageFrag.querySelectorAll('local-time').forEach(await fixDate); + await lazyPageFrag.querySelectorAll('relative-time').forEach(await fixTime); }, err => console.warn('There was a problem retrieving the response text', err) ), @@ -91,8 +96,8 @@ resp => resp.text().then( async function(html){ await deferredPageFrag.replaceChildren(...parser.parseFromString(html, 'text/html').querySelectorAll('body > [data-view-component]')); - await deferredPageFrag.querySelectorAll('local-time').forEach(await fixDate); - await deferredPageFrag.querySelectorAll('relative-time').forEach(await fixTime); // FIXME: the format for relative times should probably be different. + // await deferredPageFrag.querySelectorAll('local-time').forEach(await fixDate); + await deferredPageFrag.querySelectorAll('relative-time').forEach(await fixTime); }, err => console.warn('There was a problem retrieving the response text', err) ), diff --git a/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js b/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js index f4aab5f..5411852 100644 --- a/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js +++ b/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js @@ -8,7 +8,7 @@ // @match https://stackexchange.com/* // @match https://*.stackoverflow.com/* // @match https://*.stackexchange.com/* -// @version 1.1 +// @version 1.2.0 // @createdAt 11/6/2022, 1:17:14 AM // @author StaticPH // @description Replace 'Show X more comments' handler for StackExchange sites to better support older browsers; in particular, this enables showing all comments when using Chromium 72. @@ -20,7 +20,7 @@ // @icon https://cdn.sstatic.net/Sites/stackoverflow/Img/favicon.ico // @grant none // @noframes -// @run-at document-load +// @run-at document-idle // ==/UserScript== (function(){ @@ -44,6 +44,87 @@ return replaceChildrenWithNodes(parentEle, ...responseHtml.querySelectorAll('li')); } + function replaceCommentsListFromFetched(insertInto, data){ + const parser = new DOMParser(); + const responseHtml = parser.parseFromString(`
      ${data}
    `, 'text/html'); + return replaceChildrenWithNodes(insertInto, responseHtml.body.firstElementChild); + } + + const replySVG = ''; + const commentUpvoteSVG = ''; + const ellipsesSVG = ''; + + async function buildReplyTemplate(reply, postID){ + return await `
    +
    +
    +
    + + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    ${reply.htmlBody}
    + +
    +
    +
    +
    + + + + +
    +
    +
    +
    +
    +
    +
    +
    `; + } + function onExpandComments(evnt){ if (evnt.target.matches('.answer a.js-show-link, .question a.js-show-link')){ evnt.stopImmediatePropagation(); @@ -70,7 +151,38 @@ */ .then(data => replaceChildrenWithFetched(insertInto, data) && evnt.target.parentElement.remove(), insertInto.setAttribute('data-remaining-comments-count', '0')); } + else if (evnt.target.matches('.answer button.comments-link:not([data-so-test*="parent-answer"])')){ + evnt.stopImmediatePropagation(); + evnt.preventDefault(); + const answer = evnt.target.closest('.answer'); + const postID = answer.getAttribute('data-answerid') || answer.getAttribute('data-questionid'); + const followupScriptEle = answer.querySelector('script[type="application/json"]'); + const followupData = JSON.parse(followupScriptEle.textContent); + const insertInto = answer.querySelector(`#${followupData.containerElementId} [role="list"]`); + // for (reply of followupData.replies){ + // insertInto.insertAdjacentHTML('beforeEnd', buildReplyTemplate(reply, postID)); // Doesn't fix the order to be chronological, and that seems like a hassle. + //} + + fetch(`${document.location.origin}/posts/${postID}/comments`, { + 'headers': { + 'accept': 'text/html, */*; q=0.01', + }, + 'referrerPolicy': 'strict-origin-when-cross-origin', + 'body': null, + 'method': 'GET', + 'mode': 'cors', + 'credentials': 'include' + }).then(resp => resp.text()) + .then(data => requestAnimationFrame(function(){ + replaceCommentsListFromFetched(insertInto, data) && evnt.target.parentElement.remove(); + insertInto.setAttribute('data-remaining-comments-count', '0'); + })); + } } + + // Relevant if using buildReplyTemplate + // document.head.insertAdjacentHTML('beforeEnd', ''); + document.addEventListener('click', onExpandComments); })();