diff --git a/background.js b/background.js index 709d54f..ed142c7 100644 --- a/background.js +++ b/background.js @@ -12,6 +12,27 @@ import * as rwhMenus from './modules/menus.mjs'; import * as rwhCompose from './modules/compose.mjs'; import * as rwhTabs from './modules/tabs.mjs'; import * as rwhSettings from './modules/settings.mjs'; +import * as rwhAccounts from './modules/accounts.mjs'; + +messenger.runtime.onInstalled.addListener(async function(details) { + // About 'details' argument + // Refer here: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onInstalled + rwhLogger.debug(details); + let accounts = await rwhAccounts.all(); + rwhSettings.setAccountDefaults(accounts); +}); + +messenger.accounts.onCreated.addListener(async function(id, account){ + rwhLogger.debug('onCreated', id, account); + if (account.type === 'imap' || account.type === 'pop3') { + rwhSettings.setDefault(`${id}.enabled`, true); + } +}); + +messenger.accounts.onDeleted.addListener(async function(id){ + rwhLogger.debug('onDeleted', id); + rwhSettings.remove(`${id}.enabled`); +}); async function init() { await rwhSettings.setDefaults(); diff --git a/images/mail-accounts.svg b/images/mail-accounts.svg new file mode 100644 index 0000000..ad36601 --- /dev/null +++ b/images/mail-accounts.svg @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/manifest.json b/manifest.json index af6daa6..52c7221 100644 --- a/manifest.json +++ b/manifest.json @@ -23,7 +23,8 @@ "notifications", "menus", "compose", - "messagesRead" + "messagesRead", + "accountsRead" ], "background": { "page": "background.html" diff --git a/modules/accounts.mjs b/modules/accounts.mjs new file mode 100644 index 0000000..4eefc52 --- /dev/null +++ b/modules/accounts.mjs @@ -0,0 +1,36 @@ +/* + * Copyright (c) Jeevanandam M. (jeeva@myjeeva.com) + * + * 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 + * https://github.com/jeevatkm/ReplyWithHeaderMozilla/blob/master/LICENSE + */ + +// RWH Account Module + +export async function findIdByIdentityId(identityId) { + let accounts = await messenger.accounts.list(); + for (let account of accounts) { + for (let identity of account.identities) { + if (identity.id === identityId) { + return identity.accountId; + } + } + } + return null; +} + +export async function all() { + let accounts = await messenger.accounts.list(); + let res = []; + for (let account of accounts) { + if (account.type === 'none') { continue }; + res.push({ + 'id': account.id, + 'name': account.name, + 'type': account.type + }); + } + return res; +} diff --git a/modules/compose.mjs b/modules/compose.mjs index ff21c6a..ac910fd 100644 --- a/modules/compose.mjs +++ b/modules/compose.mjs @@ -12,6 +12,8 @@ import { rwhLogger} from './logger.mjs'; import * as rwhSettings from './settings.mjs'; import * as rwhI18n from './headers-i18n.mjs'; +import * as rwhAccounts from './accounts.mjs'; +import * as rwhUtils from './utils.mjs'; const positionBeforeBegin = 'beforebegin'; const positionAfterBegin = 'afterbegin'; @@ -24,6 +26,13 @@ export async function process(tab) { let composeDetails = await messenger.compose.getComposeDetails(tab.id); rwhLogger.debug(composeDetails); + let accountId = await rwhAccounts.findIdByIdentityId(composeDetails.identityId); + let isAccountEnabled = await rwhSettings.isAccountEnabled(accountId); + rwhLogger.debug('AccountId', accountId, 'isAccountEnabled', isAccountEnabled); + if (!isAccountEnabled) { + return; + } + let fullMsg = await messenger.messages.getFull(composeDetails.relatedMessageId); rwhLogger.debug(fullMsg); @@ -152,7 +161,7 @@ class ReplyWithHeader { let rwhHeaderString = await this._createHtmlHeaders(headers); rwhLogger.debug(rwhHeaderString); - let rwhHeaderHtmlElement = this._createElementFromString(rwhHeaderString); + let rwhHeaderHtmlElement = rwhUtils.createElementFromString(rwhHeaderString); div.insertAdjacentElement(positionAfterBegin, rwhHeaderHtmlElement); targetNode.replaceWith(div); @@ -403,12 +412,6 @@ class ReplyWithHeader { return new DOMParser().parseFromString(s, 'text/html') } - _createElementFromString(htmlString) { - var div = document.createElement('div'); - div.innerHTML = htmlString.trim(); - return div.firstElementChild; - } - _cleanNodesUpToClassName(node, cssClassName) { while (node.firstChild) { if (node.firstChild?.className?.includes(cssClassName)) { diff --git a/modules/settings.mjs b/modules/settings.mjs index e3b0f7a..02ad4b5 100755 --- a/modules/settings.mjs +++ b/modules/settings.mjs @@ -94,12 +94,29 @@ export async function getInt(key) { return parseInt(v) } +export async function setDefault(key, value) { + let ev = await get(key); + if (ev === null) { + set(key, value); + } +} + export async function setDefaults() { for (let [name, value] of Object.entries(rwhDefaultSettings)) { await setDefault(name, value); } } +export async function setAccountDefaults(accounts) { + for (let account of accounts) { + await setDefault(`${account.id}.enabled`, true); + } +} + +export async function isAccountEnabled(accountId) { + return await get(`${accountId}.enabled`, true); +} + export async function getHeaderLabelSeqStyle() { return await getInt(keyHeaderLabelSeqStyle); } @@ -143,15 +160,3 @@ export async function isCleanBlockQuoteColor() { export async function isCleanQuoteCharGreaterThan() { return await get(keyCleanQuoteCharGreaterThan, rwhDefaultSettings[keyCleanQuoteCharGreaterThan]); } - - -// -// Unexported methods -// - -async function setDefault(key, value) { - let ev = await get(key); - if (ev === null) { - set(key, value); - } -} diff --git a/modules/utils.mjs b/modules/utils.mjs index 3273d6c..56fc0e8 100644 --- a/modules/utils.mjs +++ b/modules/utils.mjs @@ -2,14 +2,14 @@ * Copyright (c) Jeevanandam M. (jeeva@myjeeva.com) * * This Source Code Form is subject to the terms of the Mozilla Public - * License, v2.0. If a copy of the MPL was not distributed with this + * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at * https://github.com/jeevatkm/ReplyWithHeaderMozilla/blob/master/LICENSE */ // RWH Utilities Module -function isObjectEmpty(objectName) { +export function isObjectEmpty(objectName) { for (let prop in objectName) { if (objectName.hasOwnProperty(prop)) { return false; @@ -18,4 +18,8 @@ function isObjectEmpty(objectName) { return true; } -export { isObjectEmpty }; \ No newline at end of file +export function createElementFromString(htmlString) { + var div = document.createElement('div'); + div.innerHTML = htmlString.trim(); + return div.firstElementChild; +} diff --git a/options/options.css b/options/options.css index 6f4c52f..be54d54 100644 --- a/options/options.css +++ b/options/options.css @@ -132,4 +132,48 @@ button { #hboxRwhBtn button { cursor: pointer; -} \ No newline at end of file +} + +/* multiselect dropdown - start */ +.multiselect { + width: 150px; +} + +.selectBox { + position: relative; +} + +.selectBox select { + width: 100%; +} + +.overSelect { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; +} + +#multiselectCheckboxes { + display: none; + position: absolute; + width: 200px; + background-color: white; + border-radius: 7px; + margin-top: -26px; + padding: 6px; + line-height: 1.7em; + border: 1px solid var(--color-gray-40); + box-shadow:0 0 10px var(--color-gray-40); +} + +#multiselectCheckboxes label { + display: block; +} + +#multiselectCheckboxes label:hover { + background: var(--color-gray-20); + border-radius: 4px; +} +/* multiselect dropdown - end */ \ No newline at end of file diff --git a/options/options.html b/options/options.html index 58fb87d..2913c1e 100644 --- a/options/options.html +++ b/options/options.html @@ -20,10 +20,18 @@ -
+
+ +
+
+ +
+
+
+
- -
diff --git a/options/options.js b/options/options.js index 01a60ed..a77b5e8 100644 --- a/options/options.js +++ b/options/options.js @@ -11,6 +11,8 @@ import { rwhLogger } from '../modules/logger.mjs'; import * as rwhNotifications from '../modules/notifications.mjs'; import * as rwhSettings from '../modules/settings.mjs'; import * as rwhI18n from '../modules/headers-i18n.mjs'; +import * as rwhAccounts from '../modules/accounts.mjs'; +import * as rwhUtils from '../modules/utils.mjs'; // UI function to hide/show out option tabs. function tabListClickHandler(elem) { @@ -58,6 +60,16 @@ async function populateLocale(prefElement) { } } +async function populateAccounts() { + let multiselectCheckboxes = document.getElementById('multiselectCheckboxes'); + let accounts = await rwhAccounts.all(); + + for (let account of accounts) { + let e = rwhUtils.createElementFromString(``); + multiselectCheckboxes.appendChild(e); + } +} + async function loadPref(prefElement) { let type = prefElement.dataset.type || prefElement.getAttribute('type') || prefElement.tagName; let name = prefElement.dataset.preference; @@ -132,6 +144,8 @@ async function savePref(prefElement) { // // } // } +let multiselectExpanded = false; + async function init() { const elementEventMap = { tabList: { type: 'click', callback: tabListClickHandler }, @@ -146,6 +160,30 @@ async function init() { document.getElementById(elementId).addEventListener(eventData.type, eventData.callback); } + // Account multi select + let multiselectAccount = document.getElementById('multiselectAccount'); + multiselectAccount.addEventListener('click', function(e) { + const multiselectCheckboxes = document.getElementById('multiselectCheckboxes'); + if (!multiselectExpanded) { + multiselectCheckboxes.style.display = 'block'; + multiselectExpanded = true; + } else { + multiselectCheckboxes.style.display = 'none'; + multiselectExpanded = false; + } + e.stopPropagation(); + }, true); + + document.addEventListener('click', function(e){ + if (multiselectExpanded) { + let multiselectCheckboxes = document.getElementById('multiselectCheckboxes'); + multiselectCheckboxes.style.display = 'none'; + multiselectExpanded = false; + } + }, false); + + await populateAccounts(); + // Load preferences and attach onchange listeners for auto save. let prefElements = document.querySelectorAll('*[data-preference]'); for (let prefElement of prefElements) {