diff --git a/.eslintrc.js b/.eslintrc.js index ccc033b..cd14b64 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -18,5 +18,7 @@ module.exports = { eqeqeq: ['error', 'always', { null: 'ignore' }], curly: ['error', 'multi-line'], 'no-var': 'error', + 'no-func-assign': 'off', + 'no-inner-declarations': 'off', }, }; diff --git a/extension/script.js b/extension/script.js index 72451a5..484d378 100644 --- a/extension/script.js +++ b/extension/script.js @@ -124,13 +124,13 @@ function isElementVisible(element) { function ensureTALinks() { let channelContainerNodes = getChannelContainers(); + for (let channelContainer of channelContainerNodes) { - channelContainer = adjustOwner(channelContainer); if (channelContainer.hasTA) continue; + channelContainer = adjustOwner(channelContainer); + let channelButton = buildChannelButton(channelContainer); + channelContainer.appendChild(channelButton); channelContainer.hasTA = true; - buildChannelButton(channelContainer).then(channelButton => { - channelContainer.appendChild(channelButton); - }); } let titleContainerNodes = getTitleContainers(); @@ -143,6 +143,7 @@ function ensureTALinks() { titleContainer.hasTA = true; } } +ensureTALinks = throttled(ensureTALinks, 700); // fix positioning of #owner div to fit new button function adjustOwner(channelContainer) { @@ -150,25 +151,45 @@ function adjustOwner(channelContainer) { } function buildChannelButton(channelContainer) { - return new Promise(resolve => { - let buttonDiv; - let channelSubButton; - let spacer; - let channelDownloadButton; + let channelHandle = getChannelHandle(channelContainer); + channelContainer.taDerivedHandle = channelHandle; - // Delayed execution for interface to refresh - setTimeout(() => { - const channelHandle = getChannelHandle(channelContainer); - buttonDiv = buildChannelButtonDiv(); - channelSubButton = buildChannelSubButton(channelHandle); - spacer = buildSpacer(); - channelDownloadButton = buildChannelDownloadButton(); - buttonDiv.appendChild(channelSubButton); - buttonDiv.appendChild(spacer); - buttonDiv.appendChild(channelDownloadButton); - resolve(buttonDiv); - }, 2000); - }); + let buttonDiv = buildChannelButtonDiv(); + + let channelSubButton = buildChannelSubButton(channelHandle); + buttonDiv.appendChild(channelSubButton); + channelContainer.taSubButton = channelSubButton; + + let spacer = buildSpacer(); + buttonDiv.appendChild(spacer); + + let channelDownloadButton = buildChannelDownloadButton(); + buttonDiv.appendChild(channelDownloadButton); + channelContainer.taDownloadButton = channelDownloadButton; + + if (!channelContainer.taObserver) { + function updateButtonsIfNecessary() { + let newHandle = getChannelHandle(channelContainer); + if (channelContainer.taDerivedHandle === newHandle) return; + console.log(`updating handle from ${channelContainer.taDerivedHandle} to ${newHandle}`); + channelContainer.taDerivedHandle = newHandle; + let channelSubButton = buildChannelSubButton(newHandle); + channelContainer.taSubButton.replaceWith(channelSubButton); + channelContainer.taSubButton = channelSubButton; + + let channelDownloadButton = buildChannelDownloadButton(); + channelContainer.taDownloadButton.replaceWith(channelDownloadButton); + channelContainer.taDownloadButton = channelDownloadButton; + } + channelContainer.taObserver = new MutationObserver(throttled(updateButtonsIfNecessary, 100)); + channelContainer.taObserver.observe(channelContainer, { + attributes: true, + childList: true, + subtree: true, + }); + } + + return buttonDiv; } function getChannelHandle(channelContainer) { @@ -236,10 +257,10 @@ function checkChannelSubscribed(channelSubButton) { console.log('Unknown state'); } } - function handleError() { + function handleError(e) { buttonError(channelSubButton); channelSubButton.innerText = 'Error'; - console.log('error'); + console.error('error', e); } let channelHandle = channelSubButton.dataset.id; @@ -395,10 +416,11 @@ function checkVideoExists(taButton) { } taButton.isChecked = true; } - function handleError() { + function handleError(e) { buttonError(taButton); let videoId = taButton.dataset.id; console.log(`error: failed to get info from TA for video ${videoId}`); + console.error(e); } let videoId = taButton.dataset.id; @@ -455,9 +477,8 @@ function sendUrl(url, action, button) { } } - function handleError(error) { - console.log('error'); - console.log(JSON.stringify(error)); + function handleError(e) { + console.log('error', e); buttonError(button); } @@ -490,15 +511,20 @@ function cleanButtons() { } let oldHref = document.location.href; -let throttleBlock; -const throttle = (callback, time) => { - if (throttleBlock) return; - throttleBlock = true; - setTimeout(() => { - callback(); - throttleBlock = false; - }, time); -}; + +function throttled(callback, time) { + let throttleBlock = false; + let lastArgs; + return (...args) => { + lastArgs = args; + if (throttleBlock) return; + throttleBlock = true; + setTimeout(() => { + throttleBlock = false; + callback(...lastArgs); + }, time); + }; +} let observer = new MutationObserver(list => { const currentHref = document.location.href; @@ -507,7 +533,7 @@ let observer = new MutationObserver(list => { oldHref = currentHref; } if (list.some(i => i.type === 'childList' && i.addedNodes.length > 0)) { - throttle(ensureTALinks, 700); + ensureTALinks(); } });