diff --git a/Makefile b/Makefile
index 2bd591f..ad9ac9c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-old-reddit-redirect.zip: *.json *.js img/* *.md *.txt
- zip -r old-reddit-redirect.zip * -x .git/* -x img/screenshot.png -x .gitignore -x Makefile
+bitbucket-fork-redirect.zip: *.json *.js img/* *.md *.txt
+ zip -r bitbucket-fork-redirect.zip * -x .git/* -x img/screenshot.png -x .gitignore -x Makefile
clean:
rm *.zip
diff --git a/background.js b/background.js
index abb306e..5c2efac 100644
--- a/background.js
+++ b/background.js
@@ -1,36 +1,14 @@
-const oldReddit = "https://old.reddit.com";
-const excludedPaths = [
- "/poll",
- "/rpan",
- "/settings",
- "/topics",
- "/community-points",
-];
+chrome.webRequest.onBeforeRequest.addListener(details => {
+ const url = new URL(details.url)
-chrome.webRequest.onBeforeRequest.addListener(
- function (details) {
- const url = new URL(details.url);
+ if (url.hostname !== "git.add123.com") return
+ if (!url.pathname.endsWith("plugins/servlet/search")) return
+ if (details.url.includes("fork:") || details.url.includes("fork%3A")) return
- if (url.hostname === "old.reddit.com") return;
-
- for (const path of excludedPaths) {
- if (url.pathname.indexOf(path) === 0) return;
- }
-
- if (url.pathname.indexOf("/gallery") === 0) {
- return { redirectUrl: oldReddit + '/comments' + url.pathname.slice("/gallery".length) };
- }
-
- return { redirectUrl: oldReddit + url.pathname + url.search + url.hash };
+ return { redirectUrl: `${details.url}%20fork%3Afalse` }
},
{
- urls: [
- "*://reddit.com/*",
- "*://www.reddit.com/*",
- "*://np.reddit.com/*",
- "*://amp.reddit.com/*",
- "*://i.reddit.com/*",
- ],
+ urls: [ "https://git.add123.com/*" ],
types: [
"main_frame",
"sub_frame",
@@ -43,4 +21,4 @@ chrome.webRequest.onBeforeRequest.addListener(
],
},
["blocking"]
-);
+)
diff --git a/backtick-comments.js b/backtick-comments.js
new file mode 100644
index 0000000..2c66728
--- /dev/null
+++ b/backtick-comments.js
@@ -0,0 +1,107 @@
+const jsKeywords = new Set([
+ "abstract", "arguments", "await*", "boolean", "break", "byte", "case",
+ "catch", "char", "class*", "const", "continue", "debugger", "default",
+ "delete", "do", "double", "else", "enum*", "eval", "export*", "extends*",
+ "false", "final", "finally", "float", "for", "function", "goto", "if",
+ "implements", "import*", "in", "instanceof", "int", "interface", "let*",
+ "long", "native", "new", "null", "package", "private", "protected", "public",
+ "return", "short", "static", "super*", "switch", "synchronized", "this",
+ "throw", "throws", "transient", "true", "try", "typeof", "var", "void",
+ "volatile", "while", "with", "yield"
+])
+
+const csKeywords = new Set([
+ "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char",
+ "checked", "class", "const", "continue", "decimal", "default", "delegate",
+ "do", "double", "else", "enum", "event", "explicit", "extern", "false",
+ "finally", "fixed", "float", "for", "foreach", "goto", "if", "implicit",
+ "in", "int", "interface", "internal", "is", "lock", "long", "namespace",
+ "new", "null", "object", "operator", "out", "override", "params", "private",
+ "protected", "public", "readonly", "ref", "return", "sbyte", "sealed",
+ "short", "sizeof", "stackalloc", "static", "string", "struct", "switch",
+ "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked",
+ "unsafe", "ushort", "using", "virtual", "void", "volatile", "while",
+])
+
+const javaKeywords = new Set([
+ "abstract", "continue", "for", "new", "switch", "assert", "default",
+ "goto", "package", "synchronized", "boolean", "do", "if", "private",
+ "this", "break", "double", "implements", "protected", "throw", "byte",
+ "else", "import", "public", "throws", "case", "enum", "instanceof",
+ "return", "transient", "catch", "extends", "int", "short", "try", "char",
+ "final", "interface", "static", "void", "class", "finally", "long",
+ "strictfp", "volatile", "const", "float", "native", "super", "while",
+])
+
+const keywordMap = {
+ js: jsKeywords,
+ mjs: jsKeywords,
+ java: javaKeywords,
+ cs: csKeywords,
+ none: new Set()
+}
+
+
+const bookendedWith = (text, bookend) => text.startsWith(bookend) && text.endsWith(bookend)
+
+const getClass = (text, keywords) => {
+ if (keywords.has(text)) {
+ return 'hl-keyword'
+ }
+
+ if (bookendedWith(text, '"')) {
+ return 'hl-string'
+ }
+
+ return 'hl-variable'
+}
+
+const getKeywords = () => keywordMap[getFileName().replace(/.*\./g, '')] || keywordMap.none
+
+const commentSpan = innerText => {
+ const span = document.createElement('span')
+ span.innerText = innerText
+ span.classList.add('hl-comment')
+ return span
+}
+
+const colorCodeInComment = (codeStart = '`', codeEnd) => {
+ codeEnd ??= codeStart
+ const processed = new Set()
+ const keywords = getKeywords()
+ getClassNameElementsArray('hl-comment').forEach(element => {
+ if (!element.innerText?.startsWith(codeStart) || processed.has(element)) {
+ return
+ }
+ const codeStartElement = commentSpan(codeStart)
+ element.replaceWith(codeStartElement, element)
+ element.innerText = element.innerText.replace(codeStart, '')
+ while (element) {
+ if (!element.classList.contains('hl-comment')) {
+ break
+ }
+ processed.add(element)
+ element.classList.remove('hl-comment')
+ const text = element.innerText.replaceAll(codeStart, '').replaceAll(codeEnd, '')
+ element.classList.add(getClass(text, keywords))
+ const codeEndIndex = element.innerText.indexOf(codeEnd)
+ if (codeEndIndex > -1) {
+ const codeEndElement = commentSpan(element.innerText.substring(codeEndIndex))
+ element.innerText = element.innerText.substring(0, codeEndIndex)
+ element.replaceWith(element, codeEndElement)
+ break
+ }
+ element = element.nextElementSibling
+ }
+ })
+}
+
+const commentCodeFix = () => {
+ colorCodeInComment('`', '`')
+ colorCodeInComment('', '
')
+ colorCodeInComment('
', '') + colorCodeInComment('', '') +} + + +addFix(commentCodeFix) diff --git a/csharp-quotes.js b/csharp-quotes.js new file mode 100644 index 0000000..506dbe2 --- /dev/null +++ b/csharp-quotes.js @@ -0,0 +1,17 @@ +const fixCSharpStrings = () => { + const hasCSharpFileName = getFileName().endsWith('.cs') + if (!hasCSharpFileName) { + return + } + getClassNameElementsArray('hl-string') + .filter(e => e.innerText.includes('@"') || e.innerText.includes('@$""')) + .forEach(e => { + const s = e.innerHTML + const firstQuote = s.indexOf('"') + 1 + const spanned = s.substring(firstQuote, s.length - 1).replaceAll('""', '""') + e.innerHTML = s.substring(0, firstQuote) + spanned + '"' + }) +} + + +addFix(fixCSharpStrings) diff --git a/img/icon128.png b/img/icon128.png index e999360..a4e1bfa 100644 Binary files a/img/icon128.png and b/img/icon128.png differ diff --git a/img/icon48.png b/img/icon48.png index b1452a8..7c7baeb 100644 Binary files a/img/icon48.png and b/img/icon48.png differ diff --git a/manifest.json b/manifest.json index 75273ea..a4a37f4 100644 --- a/manifest.json +++ b/manifest.json @@ -1,27 +1,41 @@ { - "name": "Old Reddit Redirect", - "description": "Ensure Reddit always loads the old design", - "version": "1.6.1", + "name": "ADD Git NoFork", + "description": "Ensure searches don't include forks", + "version": "1.0.2", "manifest_version": 2, - "background": { "scripts": ["background.js"] }, + "browser_specific_settings": { + "gecko": { + "id": "svaillancourt@add123.com" + } + }, + "background": { + "scripts": ["background.js"] + }, "icons": { "48": "img/icon48.png", "128": "img/icon128.png" }, "content_scripts": [ { - "matches": ["*://old.reddit.com/*"], + "matches": ["*://git.add123.com/*"], "css": ["styles.css"], "run_at": "document_start" + }, + { + "matches": ["*://git.add123.com/*"], + "js": [ + "utils.js", + "csharp-quotes.js", + "backtick-comments.js", + "var-highlighter.js" + ], + "run_at": "document_start" } ], "permissions": [ + "activeTab", "webRequest", "webRequestBlocking", - "*://reddit.com/*", - "*://www.reddit.com/*", - "*://np.reddit.com/*", - "*://amp.reddit.com/*", - "*://i.reddit.com/*" + "*://git.add123.com/*" ] } diff --git a/utils.js b/utils.js new file mode 100644 index 0000000..37315db --- /dev/null +++ b/utils.js @@ -0,0 +1,13 @@ +const NEW_PAGE_DELAY = 1000 +const CURRENT_PAGE_DELAY = 300 + +const getClassNameElementsArray = className => + Object.values(document.getElementsByClassName(className)) + +// Runs on "complete" load and when https://urlurl.url#this-hash-value changes +const addFix = fixFunc => { + window.addEventListener('load', () => setTimeout(fixFunc, NEW_PAGE_DELAY)) + addEventListener('hashchange', () => setTimeout(fixFunc, CURRENT_PAGE_DELAY)) +} + +const getFileName = () => getClassNameElementsArray('file-breadcrumbs-segment-highlighted').map(e => e.innerText)[0] diff --git a/var-highlighter.js b/var-highlighter.js new file mode 100644 index 0000000..e5138e6 --- /dev/null +++ b/var-highlighter.js @@ -0,0 +1,89 @@ +const getVarElements = () => [ + ...getClassNameElementsArray('hl-variable'), + ...getClassNameElementsArray('hl-def'), + ...getClassNameElementsArray('hl-type') +] + +let currentSelected + +const selectVar = varName => { + if (!varName) { + return + } + // Clear existing colors + getClassNameElementsArray(selectedClass) + .forEach(e => e.classList.remove(selectedClass)) + + // Color vars with matching text + getVarElements() + .filter(e => e.innerText === varName) + .forEach(e => e.classList.add(selectedClass)) + + currentSelected = varName +} + +const selectedClass = 'sages-selected-variable' + +const getTagMatching = (name, matcher) => { + const elements = Object.values(document.getElementsByTagName(name)).filter(matcher) + return elements.length ? elements[0] : null +} + +const addVariableClickers = skipExpandos => { + const getSearchButton = () => getTagMatching( + 'button', e => e.dataset?.testid === 'search-action-button') + + const getSearchBox = () => getTagMatching('input', e => e.name === 'changes-search-input') + + if (!skipExpandos) { + getClassNameElementsArray('expand-context-button').forEach(e => { + const currentOnClick = e.onclick + e.onclick = (...args) => { + currentOnClick && currentOnClick(...args) + setTimeout(() => { + selectVar(currentSelected) + addVariableClickers(true) + }, CURRENT_PAGE_DELAY) + } + }) + } + + getVarElements() + .forEach(e => { + e.onclick = () => selectVar(e.innerText) + e.ondblclick = () => { + let searchBox = getSearchBox() + + if (!searchBox) { + getSearchButton()?.click() + searchBox = getSearchBox() + } + + searchBox.value = e.innerText + searchBox.dispatchEvent(new window.Event('change', { bubbles: true })) + } + }) + +} + + +addFix(() => { + const styleSheet = document.createElement('style') + styleSheet.innerText = ` + .${selectedClass} { + background: rgb(255, 253, 170) !important; + border-radius: 3px; + padding: 2px !important; + margin: -2px !important; + /* + padding-left: 2px !important; + padding-right: 2px !important; + margin-left: -2px !important; + margin-right: -2px !important; + */ + }` + + document.head.appendChild(styleSheet) + addVariableClickers() + selectVar(currentSelected) +})