blob: d39f8146343633d1af4406fabad1400b03ce1474 [file] [log] [blame]
avm99963a2945b62020-11-27 00:32:02 +01001var mutationObserver, intersectionObserver, options, authuser;
avm99963cbea3142019-03-28 00:48:15 +01002
avm99963f5923962020-12-07 16:44:37 +01003function removeChildNodes(node) {
4 while (node.firstChild) {
5 node.removeChild(node.firstChild);
avm99963af7860e2019-06-04 03:33:26 +02006 }
avm99963f5923962020-12-07 16:44:37 +01007}
avm99963af7860e2019-06-04 03:33:26 +02008
avm99963f5923962020-12-07 16:44:37 +01009function createExtBadge() {
10 var badge = document.createElement('div');
11 badge.classList.add('TWPT-badge');
12 badge.setAttribute(
13 'title', chrome.i18n.getMessage('inject_extension_badge_helper', [
14 chrome.i18n.getMessage('appName')
15 ]));
16
17 var badgeI = document.createElement('i');
18 badgeI.classList.add('material-icon-i', 'material-icons-extended');
19 badgeI.textContent = 'repeat';
20
21 badge.append(badgeI);
22 return badge;
avm99963af7860e2019-06-04 03:33:26 +020023}
24
avm99963943b8492020-08-31 23:40:43 +020025function addProfileHistoryLink(node, type, query) {
26 var urlpart = encodeURIComponent('query=' + query);
avm99963a2945b62020-11-27 00:32:02 +010027 var authuserpart =
28 (authuser == '0' ? '' : '?authuser=' + encodeURIComponent(authuser));
avm99963943b8492020-08-31 23:40:43 +020029 var container = document.createElement('div');
30 container.style.margin = '3px 0';
31
32 var link = document.createElement('a');
33 link.setAttribute(
avm99963a2945b62020-11-27 00:32:02 +010034 'href',
35 'https://support.google.com/s/community/search/' + urlpart +
36 authuserpart);
avm99963943b8492020-08-31 23:40:43 +020037 link.innerText = chrome.i18n.getMessage('inject_previousposts_' + type);
38
39 container.appendChild(link);
avm9996306167752020-09-08 00:50:36 +020040 node.appendChild(container);
avm99963943b8492020-08-31 23:40:43 +020041}
42
avm999638e0c1002020-12-03 16:54:20 +010043function applyDragAndDropFix(node) {
44 console.debug('Adding link drag&drop fix to ', node);
45 node.addEventListener('drop', e => {
46 if (e.dataTransfer.types.includes('text/uri-list')) {
47 e.stopImmediatePropagation();
48 console.debug('Stopping link drop event propagation.');
49 }
50 }, true);
51}
52
avm99963f5923962020-12-07 16:44:37 +010053function nodeIsReadToggleBtn(node) {
54 return ('tagName' in node) && node.tagName == 'MATERIAL-BUTTON' &&
55 node.getAttribute('debugid') !== null &&
56 (node.getAttribute('debugid') == 'mark-read-button' ||
57 node.getAttribute('debugid') == 'mark-unread-button') &&
58 ('parentNode' in node) && node.parentNode !== null &&
59 ('parentNode' in node.parentNode) &&
60 node.parentNode.querySelector('[debugid="batchlock"]') === null &&
61 node.parentNode.parentNode !== null &&
62 ('tagName' in node.parentNode.parentNode) &&
63 node.parentNode.parentNode.tagName == 'EC-BULK-ACTIONS';
64}
65
66function addBatchLockBtn(readToggle) {
67 var clone = readToggle.cloneNode(true);
68 clone.setAttribute('debugid', 'batchlock');
69 clone.classList.add('TWPT-btn--with-badge');
70 clone.setAttribute('title', chrome.i18n.getMessage('inject_lockbtn'));
71 clone.querySelector('material-icon').setAttribute('icon', 'lock');
72 clone.querySelector('i.material-icon-i').textContent = 'lock';
73
74 var badge = createExtBadge();
75 clone.append(badge);
76
77 clone.addEventListener('click', function() {
78 var modal = document.querySelector('.pane[pane-id="default-1"]');
79
80 var dialog = document.createElement('material-dialog');
81 dialog.setAttribute('role', 'dialog');
82 dialog.setAttribute('aria-modal', 'true');
83 dialog.classList.add('TWPT-dialog');
84
85 var header = document.createElement('header');
86 header.setAttribute('role', 'presentation');
87 header.classList.add('TWPT-dialog-header');
88
89 var title = document.createElement('div');
90 title.classList.add('TWPT-dialog-header--title', 'title');
91 title.textContent = chrome.i18n.getMessage('inject_lockbtn');
92
93 header.append(title);
94
95 var main = document.createElement('main');
96 main.setAttribute('role', 'presentation');
97 main.classList.add('TWPT-dialog-main');
98
99 var p = document.createElement('p');
100 p.textContent = chrome.i18n.getMessage('inject_lockdialog_desc');
101
102 main.append(p);
103
104 dialog.append(header, main);
105
106 var footers = [['lock', 'unlock', 'cancel'], ['reload', 'close']];
107
108 for (var i = 0; i < footers.length; ++i) {
109 var footer = document.createElement('footer');
110 footer.setAttribute('role', 'presentation');
111 footer.classList.add('TWPT-dialog-footer');
112 footer.setAttribute('data-footer-id', i);
113
114 if (i > 0) footer.classList.add('is-hidden');
115
116 footers[i].forEach(action => {
117 var btn = document.createElement('material-button');
118 btn.setAttribute('role', 'button');
119 btn.classList.add('TWPT-dialog-footer-btn');
120 if (i == 1) btn.classList.add('is-disabled');
121
122 switch (action) {
123 case 'lock':
124 case 'unlock':
125 btn.addEventListener('click', _ => {
126 if (btn.classList.contains('is-disabled')) return;
127 var message = {
128 action,
129 prefix: 'TWPT-batchlock',
130 };
131 window.postMessage(message, '*');
132 });
133 break;
134
135 case 'cancel':
136 case 'close':
137 btn.addEventListener('click', _ => {
138 if (btn.classList.contains('is-disabled')) return;
139 modal.classList.remove('visible');
140 modal.style.display = 'none';
141 removeChildNodes(modal);
142 });
143 break;
144
145 case 'reload':
146 btn.addEventListener('click', _ => {
147 if (btn.classList.contains('is-disabled')) return;
148 window.location.reload()
149 });
150 break;
151 }
152
153 var content = document.createElement('div');
154 content.classList.add('content', 'TWPT-dialog-footer-btn--content');
155 content.textContent =
156 chrome.i18n.getMessage('inject_lockdialog_btn_' + action);
157
158 btn.append(content);
159 footer.append(btn);
160 });
161
162 var clear = document.createElement('div');
163 clear.style.clear = 'both';
164
165 footer.append(clear);
166 dialog.append(footer);
167 }
168
169 removeChildNodes(modal);
170 modal.append(dialog);
171 modal.classList.add('visible', 'modal');
172 modal.style.display = 'flex';
173 });
174 readToggle.parentNode.insertBefore(
175 clone, (readToggle.nextSibling || readToggle));
176}
177
avm99963847ee632019-03-27 00:57:44 +0100178function mutationCallback(mutationList, observer) {
179 mutationList.forEach((mutation) => {
avm99963b69eb3d2020-08-20 02:03:44 +0200180 if (mutation.type == 'childList') {
181 mutation.addedNodes.forEach(function(node) {
182 if (typeof node.classList !== 'undefined') {
183 if (options.thread && node.classList.contains('load-more-bar')) {
184 intersectionObserver.observe(
185 node.querySelector('.load-more-button'));
avm99963d0757252019-03-30 20:13:00 +0100186 }
187
avm99963b69eb3d2020-08-20 02:03:44 +0200188 if (options.threadall && node.classList.contains('load-more-bar')) {
189 intersectionObserver.observe(
190 node.querySelector('.load-all-button'));
avm999636d9c5fe2019-06-04 00:35:53 +0200191 }
192
avm99963b69eb3d2020-08-20 02:03:44 +0200193 if (options.history && ('parentNode' in node) &&
194 node.parentNode !== null && ('tagName' in node.parentNode) &&
195 node.parentNode.tagName == 'EC-USER') {
196 var nameElement = node.querySelector('.name span');
avm99963d0757252019-03-30 20:13:00 +0100197 if (nameElement !== null) {
avm99963943b8492020-08-31 23:40:43 +0200198 var forumId =
199 location.href.split('/forum/')[1].split('/')[0] || '0';
200
avm9996314116b02020-11-02 14:04:14 +0100201 var name = escapeUsername(nameElement.textContent);
avm99963943b8492020-08-31 23:40:43 +0200202 var query1 = encodeURIComponent(
avm99963ad65e752020-09-01 00:13:59 +0200203 '(creator:"' + name + '" | replier:"' + name +
204 '") forum:' + forumId);
avm99963943b8492020-08-31 23:40:43 +0200205 var query2 = encodeURIComponent(
avm99963ad65e752020-09-01 00:13:59 +0200206 '(creator:"' + name + '" | replier:"' + name +
207 '") forum:any');
avm9996306167752020-09-08 00:50:36 +0200208
209 var container = document.createElement('div');
210 container.classList.add('TWPT-previous-posts');
211
avm99963f5923962020-12-07 16:44:37 +0100212 var badge = createExtBadge();
avm9996306167752020-09-08 00:50:36 +0200213 container.appendChild(badge);
214
215 var linkContainer = document.createElement('div');
216 linkContainer.classList.add('TWPT-previous-posts--links');
217
218 addProfileHistoryLink(linkContainer, 'forum', query1);
219 addProfileHistoryLink(linkContainer, 'all', query2);
220
221 container.appendChild(linkContainer);
222
223 node.querySelector('.main-card-content').appendChild(container);
avm99963d0757252019-03-30 20:13:00 +0100224 }
225 }
avm999638e0c1002020-12-03 16:54:20 +0100226
227 // We target both tags because in different contexts different
228 // elements containing the text editor get added to the DOM structure.
229 // Sometimes it's a EC-MOVABLE-DIALOG which already contains the
230 // EC-RICH-TEXT-EDITOR, and sometimes it's the EC-RICH-TEXT-EDITOR
231 // directly.
232 if (options.ccdragndropfix && ('tagName' in node) &&
233 (node.tagName == 'EC-MOVABLE-DIALOG' ||
234 node.tagName == 'EC-RICH-TEXT-EDITOR')) {
235 applyDragAndDropFix(node);
236 }
avm99963f5923962020-12-07 16:44:37 +0100237
238 if (options.batchlock && nodeIsReadToggleBtn(node)) {
239 addBatchLockBtn(node);
240 }
avm99963d0757252019-03-30 20:13:00 +0100241 }
avm99963847ee632019-03-27 00:57:44 +0100242 });
243 }
244 });
245}
246
avm99963adf90862020-04-12 13:27:45 +0200247function intersectionCallback(entries, observer) {
avm99963847ee632019-03-27 00:57:44 +0100248 entries.forEach(entry => {
249 if (entry.isIntersecting) {
250 entry.target.click();
251 }
252 });
253};
254
255var observerOptions = {
256 childList: true,
avm99963b69eb3d2020-08-20 02:03:44 +0200257 subtree: true,
avm99963847ee632019-03-27 00:57:44 +0100258}
259
avm99963129fb502020-08-28 05:18:53 +0200260var intersectionOptions = {
261 root: document.querySelector('.scrollable-content'),
262 rootMargin: '0px',
263 threshold: 1.0,
264};
avm99963847ee632019-03-27 00:57:44 +0100265
avm99963129fb502020-08-28 05:18:53 +0200266chrome.storage.sync.get(null, function(items) {
267 options = items;
avm99963cbea3142019-03-28 00:48:15 +0100268
avm99963a2945b62020-11-27 00:32:02 +0100269 var startup =
270 JSON.parse(document.querySelector('html').getAttribute('data-startup'));
271 authuser = startup[2][1] || '0';
272
avm99963129fb502020-08-28 05:18:53 +0200273 mutationObserver = new MutationObserver(mutationCallback);
avm99963e4cac402020-12-03 16:10:58 +0100274 mutationObserver.observe(document.body, observerOptions);
avm99963cbea3142019-03-28 00:48:15 +0100275
avm99963129fb502020-08-28 05:18:53 +0200276 intersectionObserver =
277 new IntersectionObserver(intersectionCallback, intersectionOptions);
avm99963122dc9b2019-03-30 18:44:18 +0100278
avm99963129fb502020-08-28 05:18:53 +0200279 if (options.fixedtoolbar) {
280 injectStyles(
avm999630bc113a2020-09-07 13:02:11 +0200281 'ec-bulk-actions{position: sticky; top: 0; background: var(--TWPT-primary-background, #fff); z-index: 96;}');
avm99963129fb502020-08-28 05:18:53 +0200282 }
avm99963ae6a26d2020-04-12 14:03:51 +0200283
avm99963129fb502020-08-28 05:18:53 +0200284 if (options.increasecontrast) {
avm999630bc113a2020-09-07 13:02:11 +0200285 injectStyles(
avm99963a2a06442020-11-25 21:11:10 +0100286 '.thread-summary.read:not(.checked){background: var(--TWPT-thread-read-background, #ecedee)!important;}');
avm99963129fb502020-08-28 05:18:53 +0200287 }
avm999630f9503f2020-07-27 13:56:52 +0200288
avm99963129fb502020-08-28 05:18:53 +0200289 if (options.stickysidebarheaders) {
290 injectStyles(
avm999630bc113a2020-09-07 13:02:11 +0200291 'material-drawer .main-header{background: var(--TWPT-drawer-background, #fff)!important; position: sticky; top: 0; z-index: 1;}');
292 }
293
294 if (options.ccdarktheme && options.ccdarktheme_mode == 'switch') {
avm999630bc113a2020-09-07 13:02:11 +0200295 var darkThemeSwitch = document.createElement('material-button');
avm99963f5923962020-12-07 16:44:37 +0100296 darkThemeSwitch.classList.add('TWPT-dark-theme', 'TWPT-btn--with-badge');
avm999630bc113a2020-09-07 13:02:11 +0200297 darkThemeSwitch.setAttribute('button', '');
298 darkThemeSwitch.setAttribute(
299 'title', chrome.i18n.getMessage('inject_ccdarktheme_helper'));
300
301 darkThemeSwitch.addEventListener('click', e => {
302 chrome.storage.sync.get(null, currentOptions => {
303 currentOptions.ccdarktheme_switch_status =
304 !options.ccdarktheme_switch_status;
305 chrome.storage.sync.set(currentOptions, _ => {
306 location.reload();
307 });
308 });
309 });
310
311 var switchContent = document.createElement('div');
312 switchContent.classList.add('content');
313
314 var icon = document.createElement('material-icon');
315
316 var i = document.createElement('i');
317 i.classList.add('material-icon-i', 'material-icons-extended');
318 i.textContent = 'brightness_4';
319
320 icon.appendChild(i);
321 switchContent.appendChild(icon);
322 darkThemeSwitch.appendChild(switchContent);
323
avm99963f5923962020-12-07 16:44:37 +0100324 var badgeContent = createExtBadge();
avm9996306167752020-09-08 00:50:36 +0200325
avm9996306167752020-09-08 00:50:36 +0200326 darkThemeSwitch.appendChild(badgeContent);
327
avm999630bc113a2020-09-07 13:02:11 +0200328 var rightControl = document.querySelector('header .right-control');
329 rightControl.style.width =
330 (parseInt(window.getComputedStyle(rightControl).width) + 58) + 'px';
331 rightControl.insertAdjacentElement('afterbegin', darkThemeSwitch);
avm99963129fb502020-08-28 05:18:53 +0200332 }
avm99963129942f2020-09-08 02:07:18 +0200333
334 if (options.ccforcehidedrawer) {
335 var drawer = document.querySelector('material-drawer');
336 if (drawer !== null && drawer.classList.contains('mat-drawer-expanded')) {
337 document.querySelector('.material-drawer-button').click();
338 }
339 }
avm99963f5923962020-12-07 16:44:37 +0100340
341 if (options.batchlock) {
342 injectScript(chrome.runtime.getURL('injections/batchlock_inject.js'));
343 }
avm99963129fb502020-08-28 05:18:53 +0200344});