/* src/background.js * Originally created 3/10/2017 by DaAwesomeP * This is the background task file of the extension * https://github.com/DaAwesomeP/tab-counter * * Copyright 2017-present DaAwesomeP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { debounce } from 'underscore' const updateIcon = async function updateIcon () { // Get settings let settings = await browser.storage.local.get() // Get tab counter setting let counterPreference = settings.counter || 0 // Stop tab badge update if badge disabled if (counterPreference === 3) return // Get current tab to update badge in let currentTab = (await browser.tabs.query({ currentWindow: true, active: true }))[0] // Get tabs in current window, tabs in all windows, and the number of windows let currentWindow = (await browser.tabs.query({ currentWindow: true })).length.toString() let allTabs = (await browser.tabs.query({})).length.toString() let allWindows = (await browser.windows.getAll({ populate: false, windowTypes: ['normal'] })).length.toString() if (typeof currentTab !== 'undefined') { let text if (counterPreference === 0) text = currentWindow // Badge shows current window else if (counterPreference === 1) text = allTabs // Badge shows total of all windows else if (counterPreference === 2) text = `${currentWindow}/${allTabs}` // Badge shows both (Firefox limits to about 4 characters based on width) else if (counterPreference === 4) text = allWindows // Badge shows total of all windows // Update the badge browser.browserAction.setBadgeText({ text: text, tabId: currentTab.id }) // Update the tooltip browser.browserAction.setTitle({ title: `Tab Counter\nTabs in this window: ${currentWindow}\nTabs in all windows: ${allTabs}\nNumber of windows: ${allWindows}`, tabId: currentTab.id }) } } // Prevent from firing too frequently or flooding at a window or restore const lazyUpdateIcon = debounce(updateIcon, 250) // Prioritize active leading edge of every 1 second on tab switch (fluid update for new tabs) const lazyActivateUpdateIcon = debounce(updateIcon, 1000, { leading: true }) // Will be error if tab has been removed, so wait 150ms; // onActivated fires slightly before onRemoved, // but tab is gone during onActivated. // Must be a function to avoid event parameter errors const update = function update () { setTimeout(lazyUpdateIcon, 150) } // Init badge for when addon starts and not yet loaded tabs browser.browserAction.setBadgeText({ text: 'wait' }) browser.browserAction.setBadgeBackgroundColor({ color: '#000000' }) // Handler for when current tab changes const tabOnActivatedHandler = function tabOnActivatedHandler () { // Run normal update for most events update() // Prioritize active (fluid update for new tabs) lazyActivateUpdateIcon() } // Load and apply icon and badge color settings const checkSettings = async function checkSettings (settingsUpdate) { // Get settings object let settings = await browser.storage.local.get() // Get the browser name and version let browserInfo if (browser.runtime.hasOwnProperty('getBrowserInfo')) browserInfo = await browser.runtime.getBrowserInfo() else { browserInfo = { // polyfill doesn't seem to support this method, but we're only concerned with FF at the moment version: '0', vendor: '', name: '' } } const browserVersionSplit = browserInfo.version.split('.').map((n) => parseInt(n)) // Set base defaults if new insall if (!settings.hasOwnProperty('version')) { settings = { version: '0.0.0', icon: 'tabcounter.plain.min.svg', counter: 0, badgeColor: '#999999' } } // Perform settings upgrade if (settings.version !== browser.runtime.getManifest().version) { let versionSplit = settings.version.split('.').map((n) => parseInt(n)) // Upgrade // since v0.3.0, icons now adapt to theme so reset icon setting if (versionSplit[0] === 0 && versionSplit[1] < 3) settings.icon = 'tabcounter.plain.min.svg' // disable the "both" counter option in version v0.3.0 due to the four-character badge limit (renders the feature uselss) if (versionSplit[0] === 0 && versionSplit[1] < 3) { if (settings.hasOwnProperty('counter')) { if (settings.counter === 2) settings.counter = 0 } } // add badgeTextColor support if at least v0.4.0 and FF 63 if (versionSplit[0] === 0 && versionSplit[1] < 4 && browserInfo.vendor === 'Mozilla' && browserInfo.name === 'Firefox' && browserVersionSplit[0] >= 63) { settings.badgeTextColorAuto = true settings.badgeTextColor = '#000000' } } browser.storage.local.set(Object.assign(settings, { version: browser.runtime.getManifest().version })) // Apply badge color or use default if (settings.hasOwnProperty('badgeColor')) browser.browserAction.setBadgeBackgroundColor({ color: settings.badgeColor }) else browser.browserAction.setBadgeBackgroundColor({ color: '#000000' }) // Apply badge text color or use default if not set or not supported if (settings.hasOwnProperty('badgeTextColor')) { if (settings.badgeTextColorAuto !== true) browser.browserAction.setBadgeTextColor({ color: settings.badgeTextColor }) else browser.browserAction.setBadgeTextColor({ color: null }) } // Apply icon selection or use default if (settings.hasOwnProperty('icon')) browser.browserAction.setIcon({ path: `icons/${settings.icon}` }) else browser.browserAction.setIcon({ path: 'icons/tabcounter.plain.min.svg' }) // Get counter preference let counterPreference if (!settings.hasOwnProperty('counter')) counterPreference = 0 else counterPreference = settings.counter // Either add badge update events or don't if not set to if (counterPreference !== 3) { // Watch for tab and window events five seconds after browser startup setTimeout(() => { browser.tabs.onActivated.addListener(tabOnActivatedHandler) browser.tabs.onAttached.addListener(update) browser.tabs.onCreated.addListener(update) browser.tabs.onDetached.addListener(update) browser.tabs.onMoved.addListener(update) browser.tabs.onReplaced.addListener(update) browser.tabs.onRemoved.addListener(update) browser.tabs.onUpdated.addListener(update) browser.windows.onCreated.addListener(update) browser.windows.onRemoved.addListener(update) browser.windows.onFocusChanged.addListener(update) }, settingsUpdate ? 1 : 5000) // add listeners immeadietly if not browser startup } else { // remove the listeners that were added browser.tabs.onActivated.removeListener(tabOnActivatedHandler) browser.tabs.onAttached.removeListener(update) browser.tabs.onCreated.removeListener(update) browser.tabs.onDetached.removeListener(update) browser.tabs.onMoved.removeListener(update) browser.tabs.onReplaced.removeListener(update) browser.tabs.onRemoved.removeListener(update) browser.tabs.onUpdated.removeListener(update) browser.windows.onCreated.removeListener(update) browser.windows.onRemoved.removeListener(update) browser.windows.onFocusChanged.removeListener(update) // hide the "wait" badge if set not to show a badge browser.browserAction.setBadgeText({ text: '' }) browser.browserAction.setTitle({ title: 'Tab Counter' }) // check each tab that was overriden with a counter badge let allTabs = await browser.tabs.query({}) allTabs.forEach((tab) => { browser.browserAction.setBadgeText({ text: '', tabId: tab.id }) browser.browserAction.setTitle({ title: 'Tab Counter', tabId: tab.id }) }) } } // Load settings and update badge at app start const applyAll = async function applyAll (settingsUpdate) { await checkSettings(settingsUpdate) // Icon and badge color await update() // Badge text options } applyAll() // Listen for settings changes and update color, icon, and badge text instantly // Bug: this listener run nonstop // browser.storage.onChanged.addListener(applyAll) // Listen for internal addon messages const messageHandler = async function messageHandler (request, sender, sendResponse) { // Check for a settings update if (request.hasOwnProperty('updateSettings')) if (request.updateSettings) applyAll(true) } browser.runtime.onMessage.addListener(messageHandler)