Extension to return old Twitter layout from 2015.
1let r = document.createElement('a');
2let hrefUrl = new URL(location.href);
3let searchParams = new URLSearchParams(hrefUrl.search);
4searchParams.delete('newtwitter')
5hrefUrl.search = searchParams.toString();
6r.href = hrefUrl.toString();
7setInterval(() => {
8 let hrefUrl = new URL(location.href);
9 let searchParams = new URLSearchParams(hrefUrl.search);
10 searchParams.delete('newtwitter')
11 hrefUrl.search = searchParams.toString();
12 r.href = hrefUrl.toString();
13
14 let realPath = location.pathname.split('?')[0].split('#')[0];
15 if (realPath.endsWith("/")) {
16 realPath = realPath.slice(0, -1);
17 }
18 if(
19 /^\/[A-z-0-9-_]{1,15}\/status\/\d{5,32}\/analytics$/.test(realPath) ||
20 (realPath.startsWith('/i/') && realPath !== "/i/bookmarks" && !realPath.startsWith('/i/lists/')) ||
21 realPath === '/explore' ||
22 realPath === '/login' ||
23 realPath === '/register' ||
24 realPath === '/logout' ||
25 realPath === '/messages' ||
26 realPath.endsWith('/tos') ||
27 realPath.endsWith('/privacy') ||
28 realPath.startsWith('/account/') ||
29 realPath.endsWith('/lists') ||
30 realPath.endsWith('/topics') ||
31 realPath.startsWith('/settings/')
32 ) {
33 r.hidden = true;
34 } else {
35 r.hidden = false;
36 }
37
38 if(!location.search.includes('newtwitter=true')) {
39 let url = new URL(location.href);
40 url.searchParams.set('newtwitter', 'true');
41 history.replaceState(null, null, url.href);
42 }
43}, 500);
44r.textContent = 'Open this page in OldTwitter';
45r.style.cssText = 'position: fixed; top: 0; right: 10px; padding: 0.5em; background: #fff; color: #000; font-family: Arial, sans-serif;border-radius:3px;';
46document.body.appendChild(r);
47
48setTimeout(() => {
49 let realPath = location.pathname.split('?')[0].split('#')[0];
50 if (realPath.endsWith("/")) {
51 realPath = realPath.slice(0, -1);
52 }
53 if(realPath === '/i/flow/login') {
54 let i = setInterval(() => {
55 let head = document.getElementById('modal-header');
56 if(head) {
57 clearInterval(i);
58 let span = document.createElement('span');
59 span.innerHTML = `OldTwitter relies on internal APIs that only work when you're logged in.<br>Please log in on this page to see old Twitter layout.`;
60 span.style.cssText = `display: block;margin: 0.5em 0px;color: #fbfeff;font-family: TwitterChirp;background: rgb(0 161 255 / 10%);padding: 8px;border-radius: 5px;`;
61 head.after(span);
62 }
63 }, 500);
64 }
65}, 1000);
66
67(() => {
68 let keysHeld = {};
69 function processHotkeys() {
70 if (keysHeld['Alt'] && keysHeld['Control'] && keysHeld['KeyO']) {
71 let url = new URL(location.href);
72 url.searchParams.delete('newtwitter');
73 location.replace(url.href);
74 }
75 }
76 window.addEventListener('keydown', (ev) => {
77 let key = ev.code;
78 if(key === 'AltLeft' || key === 'AltRight') key = 'Alt';
79 if(key === 'ControlLeft' || key === 'ControlRight') key = 'Control';
80 if(key === 'ShiftLeft' || key === 'ShiftRight') key = 'Shift';
81 keysHeld[key] = true;
82
83 processHotkeys();
84 });
85
86 window.addEventListener('keyup', (ev) => {
87 let key = ev.code;
88 if(key === 'AltLeft' || key === 'AltRight') key = 'Alt';
89 if(key === 'ControlLeft' || key === 'ControlRight') key = 'Control';
90 if(key === 'ShiftLeft' || key === 'ShiftRight') key = 'Shift';
91 keysHeld[key] = true;
92 processHotkeys();
93 keysHeld[key] = false;
94 });
95})();
96
97function modifyLink(a) {
98 if(a.href && !a.href.includes('newtwitter=true')) {
99 let url = new URL(a.href);
100 url.searchParams.set('newtwitter', 'true');
101 a.href = url.href;
102 }
103}
104
105const linkObserver = new MutationObserver((mutations) => {
106 mutations.forEach((mutation) => {
107 if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
108 mutation.addedNodes.forEach((node) => {
109 if (node.nodeType === Node.ELEMENT_NODE) {
110 if(node.tagName === 'A') {
111 modifyLink(node);
112 }
113 node.querySelectorAll('a').forEach(modifyLink);
114 }
115 });
116 }
117 });
118});
119
120// Start observing the page for changes
121linkObserver.observe(document.documentElement, { childList: true, subtree: true });