/** * Main Popup Page * Belongs to LocalCDN (since 2020-02-26) * (Origin: Decentraleyes) * * @author Thomas Rientjes * @since 2016-08-09 * * @author nobody * @since 2020-02-26 * * @license MPL 2.0 * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; /** * Popup */ var popup = {}; const PopupLinks = { 'statistics': Links.STATISTICS, 'translation': Links.WEBLATE, 'logging': Links.LOGGING, 'faq-html-filter': Links.FAQ_HTML_FILTER, 'donate': Links.DONATE, }; /** * Private Methods */ popup._renderContents = function () { helpers.insertI18nContentIntoDocument(document); helpers.insertI18nTitlesIntoDocument(document); if (!helpers.insertI18nContentIntoDocument(document)) { popup._renderLocaleNotice(); } popup._renderNonContextualContents(); popup._determineTargetTab() .then(popup._determineDomainAllowlistStatus) .then(popup._determineStatusManipulateDOM) .then(popup._determineResourceInjections) .then(popup._determineNegateHtmlFilterOption) .then(popup._renderContextualContents); if (BrowserType.CHROMIUM) { document.getElementById('div-manipulateDOM').hidden = true; } }; popup._renderNonContextualContents = function () { let versionLabelElement, nameLabelElement, counterElement, testingUtilityLinkElement, optionsButtonElement, donationButtonElement, infoButtonLabel; versionLabelElement = document.getElementById('version-label'); nameLabelElement = document.getElementById('name-label'); counterElement = document.getElementById('injection-counter'); testingUtilityLinkElement = document.getElementById('testing-utility-link'); optionsButtonElement = document.getElementById('options-button'); donationButtonElement = document.getElementById('donate-button'); infoButtonLabel = document.getElementById('manipulateDOM-indicator'); versionLabelElement.innerText = popup._version; nameLabelElement.innerText = popup._name; counterElement.innerText = helpers.formatNumber(popup._amountInjected); testingUtilityLinkElement.addEventListener('mouseup', popup._onTestingUtilityLinkClicked); optionsButtonElement.addEventListener('mouseup', popup._onOptionsButtonClicked); donationButtonElement.addEventListener('mouseup', popup._onButtonClicked); infoButtonLabel.addEventListener('mouseup', popup._onButtonClicked); if (popup._statisticsStatus) { document.getElementById('statistics-button').style.display = 'block'; document.getElementById('statistics-button').addEventListener('mouseup', popup._onButtonClicked); } if (popup._loggingStatus) { document.getElementById('logging-button').style.display = 'block'; document.getElementById('logging-button').addEventListener('mouseup', popup._onButtonClicked); } if (!popup.hideDonationButton) { document.getElementById('donate-button').style.display = 'flex'; } }; popup._renderContextualContents = function () { if (popup._domain !== null) { popup._renderDomainAllowlistPanel(); document.getElementById('testing-utility-link').style.display = 'block'; } if (Object.keys(popup._resourceInjections).length > 0) { popup._renderInjectionPanel(popup._resourceInjections); } }; popup._renderDomainAllowlistPanel = function () { let websiteContextElement, protectionToggleElement, domainIndicatorElement, manipulateDOMToggleElement, manipulateDOMToggleStyle; websiteContextElement = document.getElementById('website-context'); protectionToggleElement = document.getElementById('protection-toggle-switch'); domainIndicatorElement = document.getElementById('domain-indicator'); protectionToggleElement.setAttribute('dir', popup._scriptDirection); domainIndicatorElement.innerText = popup._domain; manipulateDOMToggleElement = document.getElementById('manipulateDOM-toggle-switch'); manipulateDOMToggleStyle = document.getElementById('toggle-switch-manipulateDOM'); if (popup._domainIsAllowlisted === true) { manipulateDOMToggleElement.disabled = true; protectionToggleElement.checked = false; manipulateDOMToggleStyle.setAttribute('class', 'slider-disabled'); protectionToggleElement.addEventListener('click', popup._enableProtection); } else { manipulateDOMToggleElement.disabled = false; manipulateDOMToggleStyle.setAttribute('class', 'slider'); protectionToggleElement.checked = true; protectionToggleElement.addEventListener('click', popup._disableProtection); if (popup.negateHtmlFilterList && !popup._domainManipulateDOM) { manipulateDOMToggleElement.checked = true; manipulateDOMToggleElement.addEventListener('click', popup._enableManipulateDOM); } else if (!popup.negateHtmlFilterList && !popup._domainManipulateDOM) { manipulateDOMToggleElement.checked = false; manipulateDOMToggleElement.addEventListener('click', popup._enableManipulateDOM); } else if (popup.negateHtmlFilterList && popup._domainManipulateDOM) { manipulateDOMToggleElement.checked = false; manipulateDOMToggleElement.addEventListener('click', popup._disableManipulateDOM); } else if (!popup.negateHtmlFilterList && popup._domainManipulateDOM) { manipulateDOMToggleElement.checked = true; manipulateDOMToggleElement.addEventListener('click', popup._disableManipulateDOM); } } websiteContextElement.setAttribute('class', 'panel'); }; popup._renderInjectionPanel = function (groupedInjections) { let websiteContextElement, injectionOverviewElement; websiteContextElement = document.getElementById('website-context'); injectionOverviewElement = popup._createInjectionOverviewElement(groupedInjections); injectionOverviewElement.setAttribute('class', 'panel-overflow'); websiteContextElement.append(injectionOverviewElement); }; popup._enableProtection = function () { let message = { 'topic': 'allowlist:remove-domain', 'value': popup._domain, }; chrome.runtime.sendMessage(message, function () { popup._onToggled(); }); }; popup._disableProtection = function () { let message = { 'topic': 'allowlist:add-domain', 'value': popup._domain, }; chrome.runtime.sendMessage(message, function () { popup._onToggled(); }); }; popup._enableManipulateDOM = function () { let message = { 'topic': 'manipulateDOM:add-domain', 'value': popup._domain, }; chrome.runtime.sendMessage(message, function () { popup._onToggled(); }); }; popup._disableManipulateDOM = function () { let message = { 'topic': 'manipulateDOM:remove-domain', 'value': popup._domain, }; chrome.runtime.sendMessage(message, function () { popup._onToggled(); }); }; popup._determineDomainAllowlistStatus = function () { return new Promise((resolve) => { let message = { 'topic': 'domain:fetch-is-allowlisted', 'value': popup._domain, }; if (popup._domain === null) { return; } chrome.runtime.sendMessage(message, function (response) { popup._domainIsAllowlisted = response.value; resolve(); }); }); }; popup._determineStatusManipulateDOM = function () { return new Promise((resolve) => { let message = { 'topic': 'domain:fetch-is-manipulateDOM', 'value': popup._domain, }; chrome.runtime.sendMessage(message, function (response) { popup._domainManipulateDOM = response.value; resolve(); }); }); }; popup._determineResourceInjections = function () { return new Promise((resolve) => { let message = { 'topic': 'tab:fetch-injections', 'value': popup._targetTab.id, }; chrome.runtime.sendMessage(message, function (response) { let groupedInjections = popup._groupResourceInjections(response.value); popup._resourceInjections = groupedInjections; resolve(); }); }); }; popup._determineTargetTab = function () { return new Promise((resolve) => { helpers.determineActiveTab().then((activeTab) => { popup._targetTab = activeTab; popup._domain = helpers.extractDomainFromUrl(activeTab.url, true); resolve(); }); }); }; popup._getData = function () { return new Promise((resolve) => { let message = { 'topic': 'popup:get-data' }; chrome.runtime.sendMessage(message, function (items) { popup._amountInjected = items.data.amountInjected; popup._statisticsStatus = items.data.internalStatistics; popup.negateHtmlFilterList = items.data.negateHtmlFilterList; popup._loggingStatus = items.data.loggingStatus; popup.hideDonationButton = items.data.hideDonationButton; resolve(); }); }); }; popup._groupResourceInjections = function (injections) { let groupedInjections = {}; for (let index in injections) { let {source} = injections[index]; groupedInjections[source] = groupedInjections[source] || []; groupedInjections[source].push(injections[index]); } return groupedInjections; }; popup._createInjectionOverviewElement = function (groupedInjections) { let injectionOverviewElement = document.createElement('ul'); injectionOverviewElement.setAttribute('class', 'list'); for (let source in groupedInjections) { let injectionGroupHeaderElement, injectionGroupElement, cdn; cdn = groupedInjections[source]; injectionGroupHeaderElement = popup._createInjectionGroupHeaderElement(source, cdn); injectionGroupElement = popup._createInjectionGroupElement(source, cdn); injectionOverviewElement.appendChild(injectionGroupHeaderElement); injectionOverviewElement.appendChild(injectionGroupElement); } return injectionOverviewElement; }; popup._createInjectionGroupHeaderElement = function (source, cdn) { let injectionGroupHeaderElement, badgeElement, badgeTextNode, cdnNameTextNode; injectionGroupHeaderElement = document.createElement('li'); injectionGroupHeaderElement.setAttribute('class', 'list-item'); badgeElement = document.createElement('span'); badgeElement.setAttribute('class', 'badge'); badgeTextNode = document.createTextNode(cdn.length); badgeElement.appendChild(badgeTextNode); cdnNameTextNode = document.createTextNode(helpers.determineCdnName(source)); injectionGroupHeaderElement.appendChild(badgeElement); injectionGroupHeaderElement.appendChild(cdnNameTextNode); return injectionGroupHeaderElement; }; popup._createInjectionGroupElement = function (source, cdn) { let injectionGroupElement, bundle, filtered; // Filter duplicates bundle = []; for (let injection of cdn) { bundle.push(injection); } filtered = popup._filterDuplicates(bundle, 'bundle'); injectionGroupElement = document.createElement('ul'); injectionGroupElement.setAttribute('class', 'sublist'); for (let injection of filtered) { let injectionElement = popup._createInjectionElement(injection); injectionGroupElement.appendChild(injectionElement); } return injectionGroupElement; }; popup._createInjectionElement = function (injection) { let injectionElement, filename, name, nameTextNode, noteElement, noteTextNode; injectionElement = document.createElement('li'); injectionElement.setAttribute('class', 'sublist-item'); filename = helpers.extractFilenameFromPath(injection.path); // If bundle empty, use filename if (injection.bundle === '') { name = targets.determineResourceName(filename); } else { name = `${injection.bundle}`; } nameTextNode = document.createTextNode(`- ${name}`); injectionElement.appendChild(nameTextNode); if (injection.versionRequested !== null) { noteElement = document.createElement('span'); noteElement.setAttribute('class', 'side-note'); let versionNode; if (injection.versionRequested === undefined || injection.versionDelivered === undefined) { versionNode = ''; } else if (injection.versionRequested === injection.versionDelivered) { versionNode = ` v${injection.versionRequested}`; } else if (injection.versionRequested === 'beta') { versionNode = ` ${injection.versionRequested}`; } else if (injection.versionRequested !== 'latest') { versionNode = ` (v${injection.versionRequested} ยป v${injection.versionDelivered})`; } else if (injection.versionRequested === 'latest') { versionNode = ` v${injection.versionDelivered}`; } else { versionNode = ''; } noteTextNode = document.createTextNode(versionNode); noteElement.appendChild(noteTextNode); injectionElement.appendChild(noteElement); } return injectionElement; }; popup._filterDuplicates = function (array, key) { /** * Function to remove duplicates from an array, depending on 'key'. * Ignore empty values of the 'key' * */ let filtered = array .map((e) => e[key]) .map(function (value, index, newArray) { return value !== '' ? newArray.indexOf(value) === index && index : index; }) .filter((e) => array[e]) .map((e) => array[e]); return filtered; }; popup._renderLocaleNotice = function () { let localeNoticeElement, nameTextNode; localeNoticeElement = document.getElementById('popup-incomplete-translation'); localeNoticeElement.setAttribute('class', 'notice notice-default'); localeNoticeElement.addEventListener('mouseup', popup._onButtonClicked); nameTextNode = document.createTextNode('Translation is incomplete. You want to help on Weblate?'); localeNoticeElement.appendChild(nameTextNode); }; /** * Event Handlers */ popup._onDocumentLoaded = function () { let manifest, language; manifest = chrome.runtime.getManifest(); language = navigator.language; popup._name = manifest.name; popup._version = manifest.version; popup._scriptDirection = helpers.determineScriptDirection(language); popup._getData().then(popup._renderContents); }; popup._onTestingUtilityLinkClicked = function (event) { if (event.button === 0 || event.button === 1) { chrome.tabs.create({ 'url': Links.LOCALCDN_TEST_WEBSITE, 'active': event.button === 0, }, function (tab) { popup._injectDomain(tab.id); }); } if (event.button === 0) { window.close(); } }; popup._injectDomain = function (tabId) { let message = { 'topic': 'tab:inject', 'value': tabId, 'url': popup._targetTab.url }; chrome.runtime.sendMessage(message); }; popup._onOptionsButtonClicked = function () { chrome.runtime.openOptionsPage(); return window.close(); }; popup._onToggled = function () { let bypassCache = typeof browser === 'undefined'; chrome.tabs.reload(popup._targetTab.id, {bypassCache}); setTimeout(function () { popup._close(); }, 200); }; popup._close = function () { chrome.runtime.getPlatformInfo(function (information) { if (information.os === chrome.runtime.PlatformOs.ANDROID) { chrome.tabs.getCurrent(function (activeTab) { if (activeTab) { chrome.tabs.remove(activeTab.id); } else { window.close(); } }); } else { window.close(); } }); }; popup._onButtonClicked = function ({target}) { let data = target.getAttribute('data-link'); if (event.button === 0 || event.button === 1) { chrome.tabs.create({ 'url': PopupLinks[data], 'active': event.button === 0, }); } if (event.button === 0) { window.close(); } }; /** * Initializations */ popup.negateHtmlFilterList = false; popup._statisticsStatus = false; popup._loggingStatus = false; document.addEventListener('DOMContentLoaded', popup._onDocumentLoaded);