-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent-script.js
More file actions
114 lines (93 loc) · 2.64 KB
/
Copy pathcontent-script.js
File metadata and controls
114 lines (93 loc) · 2.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
const REWRITE_HOSTS = new Set([
"twitter.com",
"www.twitter.com",
"fixupx.com",
"www.fixupx.com"
]);
const REPLACEMENT_HOST = "x.com";
const REWRITTEN_ATTRIBUTE = "data-really-fixupx-rewritten";
function rewriteUrl(rawUrl) {
let url;
try {
url = new URL(rawUrl, window.location.href);
} catch {
return rawUrl;
}
if (!REWRITE_HOSTS.has(url.hostname.toLowerCase())) {
return rawUrl;
}
url.hostname = REPLACEMENT_HOST;
return url.toString();
}
function rewriteText(text) {
return text
.replace(/\bhttps?:\/\/(?:www\.)?(?:x\.com|twitter\.com|fixupx\.com)\b/gi, (match) => {
const protocol = match.startsWith("https://") ? "https://" : "http://";
return `${protocol}${REPLACEMENT_HOST}`;
})
.replace(/\b(?:www\.)?(?:x\.com|twitter\.com|fixupx\.com)\b/gi, REPLACEMENT_HOST);
}
function rewriteElementAttributes(element) {
for (const attributeName of ["href", "data-expanded-url", "data-url"]) {
if (!element.hasAttribute(attributeName)) {
continue;
}
const originalValue = element.getAttribute(attributeName);
const rewrittenValue = rewriteUrl(originalValue);
if (rewrittenValue !== originalValue) {
element.setAttribute(attributeName, rewrittenValue);
element.setAttribute(REWRITTEN_ATTRIBUTE, "true");
}
}
}
function rewriteVisibleLinkText(element) {
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
while (walker.nextNode()) {
const textNode = walker.currentNode;
const rewrittenText = rewriteText(textNode.nodeValue);
if (rewrittenText !== textNode.nodeValue) {
textNode.nodeValue = rewrittenText;
}
}
}
function rewriteNode(root) {
if (root.nodeType !== Node.ELEMENT_NODE) {
return;
}
const element = root;
rewriteElementAttributes(element);
if (element.matches("a")) {
rewriteVisibleLinkText(element);
}
for (const child of element.querySelectorAll("a[href], [data-expanded-url], [data-url]")) {
rewriteElementAttributes(child);
if (child.matches("a")) {
rewriteVisibleLinkText(child);
}
}
}
function installObserver() {
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === "attributes") {
rewriteNode(mutation.target);
continue;
}
for (const node of mutation.addedNodes) {
rewriteNode(node);
}
}
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: [
"href",
"data-expanded-url",
"data-url"
]
});
}
rewriteNode(document.documentElement);
installObserver();