diff --git a/CHANGELOG.md b/CHANGELOG.md index a3ef306..0d73f22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ CHANGELOG ============================= +* 5.1.0 + * Added browser polyfill in preparation for Firefox compatibility * 5.0.2 * Added light/dark mode style to settings * Slight style improvements for settings diff --git a/html/menu_ui.html b/html/menu_ui.html index b91cda1..1edde86 100644 --- a/html/menu_ui.html +++ b/html/menu_ui.html @@ -161,5 +161,6 @@

Credits

- + + \ No newline at end of file diff --git a/js/D3.js b/js/D3.js index 5acf66e..a90df44 100644 --- a/js/D3.js +++ b/js/D3.js @@ -6,7 +6,7 @@ async function getCurrentTab() { active: true, currentWindow: true }; - let [tab] = await chrome.tabs.query(queryOptions); + let [tab] = await browser.tabs.query(queryOptions); return tab; } @@ -22,7 +22,7 @@ var D3 = { * * @var String */ - version: "5.0.0", + version: "5.1.0", /** * Tabs that already had the content worker script injected @@ -65,7 +65,7 @@ var D3 = { lastMessage: '', checkInstall: function (callback) { - chrome.storage.sync.get(null, function (items) { + browser.storage.sync.get(null).then((items) => { console.log("Check Install: Start"); update = {}; if (!items["messageType"]) { @@ -89,7 +89,7 @@ var D3 = { update["version"] = D3.version; } - chrome.storage.sync.set(update, function () { + browser.storage.sync.set(update).then(() => { console.log("Installed decoder version " + D3.version); }); }); @@ -104,13 +104,13 @@ var D3 = { // Inject the content scripts once at the start if (!(tabId in D3.injected_tabs)) { - await chrome.scripting.insertCSS({ + await browser.scripting.insertCSS({ target: { tabId: tabId }, files: ["styles/content.css"] }); - await chrome.scripting.executeScript({ + await browser.scripting.executeScript({ target: { tabId: tabId }, @@ -125,7 +125,7 @@ var D3 = { console.log(['d3coder:: FUNCTION:' + title, text]); }; - chrome.scripting.executeScript({ + browser.scripting.executeScript({ target: { tabId: tabId }, @@ -139,7 +139,7 @@ var D3 = { alert(title + '\n\n' + text); }; - chrome.scripting.executeScript({ + browser.scripting.executeScript({ target: { tabId: tabId }, @@ -153,7 +153,7 @@ var D3 = { D3content.createDiv(title, text); }; - chrome.scripting.executeScript({ + browser.scripting.executeScript({ target: { tabId: tabId }, @@ -168,7 +168,7 @@ var D3 = { D3content.replaceText(text); }; - chrome.scripting.executeScript({ + browser.scripting.executeScript({ target: { tabId: tabId }, @@ -193,7 +193,7 @@ var D3 = { } getCurrentTab().then(function (tab) { - chrome.scripting.executeScript({ + browser.scripting.executeScript({ target: { tabId: tab.id }, @@ -232,14 +232,12 @@ var D3 = { }; function clearMenu() { - console.log(D3.menuIds); for (id in D3.menuIds) { if (id && D3.menuIds[id] != null) { - chrome.contextMenus.remove(D3.menuIds[id]); + browser.contextMenus.remove(D3.menuIds[id]); } D3.menuIds[id] = null; } - console.log(D3.menuIds); } function createMenu(items, name) { @@ -253,20 +251,19 @@ var D3 = { "id": "d3coder-selection-" + function_list[name][1] }; try { - D3.menuIds[name] = chrome.contextMenus.create(menu); + D3.menuIds[name] = browser.contextMenus.create(menu); } catch (e) { - console.log(e); + console.log(["Error creating menu", e]); } } else if (items.checkboxes[name] == false) { if (D3.menuIds[name]) { - // console.log("Menu: Removing " + D3.menuIds[name]); - chrome.contextMenus.remove(D3.menuIds[name]); + browser.contextMenus.remove(D3.menuIds[name]); D3.menuIds[name] = null; } } } - chrome.storage.sync.get(null, function (items) { + browser.storage.sync.get(null).then((items) => { clearMenu(); for (itemName in items.checkboxes) { @@ -282,7 +279,7 @@ var D3 = { } try { - D3.menuIds["options"] = chrome.contextMenus.create(menu); + D3.menuIds["options"] = browser.contextMenus.create(menu); } catch (e) { console.log(e); } @@ -293,6 +290,6 @@ var D3 = { translate: function (name) { let e_msg = "Could not translate " + name; - return chrome.i18n.getMessage(name) || e_msg; + return browser.i18n.getMessage(name) || e_msg; } }; \ No newline at end of file diff --git a/js/browser-polyfill.min.js b/js/browser-polyfill.min.js new file mode 100644 index 0000000..5bd0343 --- /dev/null +++ b/js/browser-polyfill.min.js @@ -0,0 +1,8 @@ +(function(a,b){if("function"==typeof define&&define.amd)define("webextension-polyfill",["module"],b);else if("undefined"!=typeof exports)b(module);else{var c={exports:{}};b(c),a.browser=c.exports}})("undefined"==typeof globalThis?"undefined"==typeof self?this:self:globalThis,function(a){"use strict";if(!globalThis.chrome?.runtime?.id)throw new Error("This script should only be loaded in a browser extension.");if("undefined"==typeof globalThis.browser||Object.getPrototypeOf(globalThis.browser)!==Object.prototype){a.exports=(a=>{const b={alarms:{clear:{minArgs:0,maxArgs:1},clearAll:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getAll:{minArgs:0,maxArgs:0}},bookmarks:{create:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},getChildren:{minArgs:1,maxArgs:1},getRecent:{minArgs:1,maxArgs:1},getSubTree:{minArgs:1,maxArgs:1},getTree:{minArgs:0,maxArgs:0},move:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeTree:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}},browserAction:{disable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},enable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},getBadgeBackgroundColor:{minArgs:1,maxArgs:1},getBadgeText:{minArgs:1,maxArgs:1},getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},openPopup:{minArgs:0,maxArgs:0},setBadgeBackgroundColor:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setBadgeText:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},browsingData:{remove:{minArgs:2,maxArgs:2},removeCache:{minArgs:1,maxArgs:1},removeCookies:{minArgs:1,maxArgs:1},removeDownloads:{minArgs:1,maxArgs:1},removeFormData:{minArgs:1,maxArgs:1},removeHistory:{minArgs:1,maxArgs:1},removeLocalStorage:{minArgs:1,maxArgs:1},removePasswords:{minArgs:1,maxArgs:1},removePluginData:{minArgs:1,maxArgs:1},settings:{minArgs:0,maxArgs:0}},commands:{getAll:{minArgs:0,maxArgs:0}},contextMenus:{remove:{minArgs:1,maxArgs:1},removeAll:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},cookies:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:1,maxArgs:1},getAllCookieStores:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},devtools:{inspectedWindow:{eval:{minArgs:1,maxArgs:2,singleCallbackArg:!1}},panels:{create:{minArgs:3,maxArgs:3,singleCallbackArg:!0},elements:{createSidebarPane:{minArgs:1,maxArgs:1}}}},downloads:{cancel:{minArgs:1,maxArgs:1},download:{minArgs:1,maxArgs:1},erase:{minArgs:1,maxArgs:1},getFileIcon:{minArgs:1,maxArgs:2},open:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},pause:{minArgs:1,maxArgs:1},removeFile:{minArgs:1,maxArgs:1},resume:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},extension:{isAllowedFileSchemeAccess:{minArgs:0,maxArgs:0},isAllowedIncognitoAccess:{minArgs:0,maxArgs:0}},history:{addUrl:{minArgs:1,maxArgs:1},deleteAll:{minArgs:0,maxArgs:0},deleteRange:{minArgs:1,maxArgs:1},deleteUrl:{minArgs:1,maxArgs:1},getVisits:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1}},i18n:{detectLanguage:{minArgs:1,maxArgs:1},getAcceptLanguages:{minArgs:0,maxArgs:0}},identity:{launchWebAuthFlow:{minArgs:1,maxArgs:1}},idle:{queryState:{minArgs:1,maxArgs:1}},management:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},getSelf:{minArgs:0,maxArgs:0},setEnabled:{minArgs:2,maxArgs:2},uninstallSelf:{minArgs:0,maxArgs:1}},notifications:{clear:{minArgs:1,maxArgs:1},create:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:0},getPermissionLevel:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},pageAction:{getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},hide:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},permissions:{contains:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},request:{minArgs:1,maxArgs:1}},runtime:{getBackgroundPage:{minArgs:0,maxArgs:0},getPlatformInfo:{minArgs:0,maxArgs:0},openOptionsPage:{minArgs:0,maxArgs:0},requestUpdateCheck:{minArgs:0,maxArgs:0},sendMessage:{minArgs:1,maxArgs:3},sendNativeMessage:{minArgs:2,maxArgs:2},setUninstallURL:{minArgs:1,maxArgs:1}},sessions:{getDevices:{minArgs:0,maxArgs:1},getRecentlyClosed:{minArgs:0,maxArgs:1},restore:{minArgs:0,maxArgs:1}},storage:{local:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},managed:{get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1}},sync:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}}},tabs:{captureVisibleTab:{minArgs:0,maxArgs:2},create:{minArgs:1,maxArgs:1},detectLanguage:{minArgs:0,maxArgs:1},discard:{minArgs:0,maxArgs:1},duplicate:{minArgs:1,maxArgs:1},executeScript:{minArgs:1,maxArgs:2},get:{minArgs:1,maxArgs:1},getCurrent:{minArgs:0,maxArgs:0},getZoom:{minArgs:0,maxArgs:1},getZoomSettings:{minArgs:0,maxArgs:1},goBack:{minArgs:0,maxArgs:1},goForward:{minArgs:0,maxArgs:1},highlight:{minArgs:1,maxArgs:1},insertCSS:{minArgs:1,maxArgs:2},move:{minArgs:2,maxArgs:2},query:{minArgs:1,maxArgs:1},reload:{minArgs:0,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeCSS:{minArgs:1,maxArgs:2},sendMessage:{minArgs:2,maxArgs:3},setZoom:{minArgs:1,maxArgs:2},setZoomSettings:{minArgs:1,maxArgs:2},update:{minArgs:1,maxArgs:2}},topSites:{get:{minArgs:0,maxArgs:0}},webNavigation:{getAllFrames:{minArgs:1,maxArgs:1},getFrame:{minArgs:1,maxArgs:1}},webRequest:{handlerBehaviorChanged:{minArgs:0,maxArgs:0}},windows:{create:{minArgs:0,maxArgs:1},get:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:1},getCurrent:{minArgs:0,maxArgs:1},getLastFocused:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}}};if(0===Object.keys(b).length)throw new Error("api-metadata.json has not been included in browser-polyfill");class c extends WeakMap{constructor(a,b=void 0){super(b),this.createItem=a}get(a){return this.has(a)||this.set(a,this.createItem(a)),super.get(a)}}const d=a=>a&&"object"==typeof a&&"function"==typeof a.then,e=(b,c)=>(...d)=>{a.runtime.lastError?b.reject(new Error(a.runtime.lastError.message)):c.singleCallbackArg||1>=d.length&&!1!==c.singleCallbackArg?b.resolve(d[0]):b.resolve(d)},f=a=>1==a?"argument":"arguments",g=(a,b)=>function(c,...d){if(d.lengthb.maxArgs)throw new Error(`Expected at most ${b.maxArgs} ${f(b.maxArgs)} for ${a}(), got ${d.length}`);return new Promise((f,g)=>{if(b.fallbackToNoCallback)try{c[a](...d,e({resolve:f,reject:g},b))}catch(e){console.warn(`${a} API method doesn't seem to support the callback parameter, `+"falling back to call it without a callback: ",e),c[a](...d),b.fallbackToNoCallback=!1,b.noCallback=!0,f()}else b.noCallback?(c[a](...d),f()):c[a](...d,e({resolve:f,reject:g},b))})},h=(a,b,c)=>new Proxy(b,{apply(b,d,e){return c.call(d,a,...e)}});let i=Function.call.bind(Object.prototype.hasOwnProperty);const j=(a,b={},c={})=>{let d=Object.create(null),e=Object.create(a);return new Proxy(e,{has(b,c){return c in a||c in d},get(e,f){if(f in d)return d[f];if(!(f in a))return;let k=a[f];if("function"==typeof k){if("function"==typeof b[f])k=h(a,a[f],b[f]);else if(i(c,f)){let b=g(f,c[f]);k=h(a,a[f],b)}else k=k.bind(a);}else if("object"==typeof k&&null!==k&&(i(b,f)||i(c,f)))k=j(k,b[f],c[f]);else if(i(c,"*"))k=j(k,b[f],c["*"]);else return Object.defineProperty(d,f,{configurable:!0,enumerable:!0,get(){return a[f]},set(b){a[f]=b}}),k;return d[f]=k,k},set(b,c,e){return c in d?d[c]=e:a[c]=e,!0},defineProperty(a,b,c){return Reflect.defineProperty(d,b,c)},deleteProperty(a,b){return Reflect.deleteProperty(d,b)}})},k=a=>({addListener(b,c,...d){b.addListener(a.get(c),...d)},hasListener(b,c){return b.hasListener(a.get(c))},removeListener(b,c){b.removeListener(a.get(c))}}),l=new c(a=>"function"==typeof a?function(b){const c=j(b,{},{getContent:{minArgs:0,maxArgs:0}});a(c)}:a),m=new c(a=>"function"==typeof a?function(b,c,e){let f,g,h=!1,i=new Promise(a=>{f=function(b){h=!0,a(b)}});try{g=a(b,c,f)}catch(a){g=Promise.reject(a)}const j=!0!==g&&d(g);if(!0!==g&&!j&&!h)return!1;const k=a=>{a.then(a=>{e(a)},a=>{let b;b=a&&(a instanceof Error||"string"==typeof a.message)?a.message:"An unexpected error occurred",e({__mozWebExtensionPolyfillReject__:!0,message:b})}).catch(a=>{console.error("Failed to send onMessage rejected reply",a)})};return j?k(g):k(i),!0}:a),n=({reject:b,resolve:c},d)=>{a.runtime.lastError?a.runtime.lastError.message==="The message port closed before a response was received."?c():b(new Error(a.runtime.lastError.message)):d&&d.__mozWebExtensionPolyfillReject__?b(new Error(d.message)):c(d)},o=(a,b,c,...d)=>{if(d.lengthb.maxArgs)throw new Error(`Expected at most ${b.maxArgs} ${f(b.maxArgs)} for ${a}(), got ${d.length}`);return new Promise((a,b)=>{const e=n.bind(null,{resolve:a,reject:b});d.push(e),c.sendMessage(...d)})},p={devtools:{network:{onRequestFinished:k(l)}},runtime:{onMessage:k(m),onMessageExternal:k(m),sendMessage:o.bind(null,"sendMessage",{minArgs:1,maxArgs:3})},tabs:{sendMessage:o.bind(null,"sendMessage",{minArgs:2,maxArgs:3})}},q={clear:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}};return b.privacy={network:{"*":q},services:{"*":q},websites:{"*":q}},j(a,p,b)})(chrome)}else a.exports=globalThis.browser}); +//# sourceMappingURL=browser-polyfill.min.js.map + +// webextension-polyfill v.0.10.0 (https://github.com/mozilla/webextension-polyfill) + +/* 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/. */ \ No newline at end of file diff --git a/js/menu_ui.js b/js/menu_ui.js index 84d78a5..a540ea6 100644 --- a/js/menu_ui.js +++ b/js/menu_ui.js @@ -9,7 +9,7 @@ let localizeHtmlPage = function(){ let valStrH = obj.innerHTML.toString(); let valNewH = valStrH.replace(/__MSG_(\w+)__/g, function(match, v1) { - return v1 ? chrome.i18n.getMessage(v1) : ""; + return v1 ? browser.i18n.getMessage(v1) : ""; }); if(valNewH != valStrH) @@ -25,7 +25,7 @@ var D3menu = { * * @var String */ - version: "4.0.0", + version: "5.1.0", /** * list all functions. Needed to upgrade from older versions @@ -60,7 +60,7 @@ var D3menu = { function upgrade() { var clipboardSave, checkboxes = {}, version = D3menu.version; - chrome.storage.sync.get({version: false}, function(items) { + browser.storage.sync.get({version: false}).then((items) => { if (items.version) { console.log("Upgrade: D3coder version " + version + " found."); return; @@ -79,16 +79,16 @@ function save_options() { checkboxes[option.id] = document.getElementById(option.id).checked == true ? true : false; } - chrome.storage.sync.set( + browser.storage.sync.set( { checkboxes: checkboxes, messageType: messageType, clipboardSave: clipboardSave, version: D3menu.version - }, function() { + }).then(() => { console.log("Save: Options saved to storage"); var status = document.getElementById('status'); - status.textContent = chrome.i18n.getMessage('options_saved'); + status.textContent = browser.i18n.getMessage('options_saved'); status.style.display = "block"; status.style.opacity = 1; setTimeout(function() { @@ -99,15 +99,15 @@ function save_options() { } // Restores select box and checkbox state using the preferences -// stored in chrome.storage. +// stored in browser.storage / chrome.storage. function restore_options() { console.log("Restore: Starting restore"); - chrome.storage.sync.get({ + browser.storage.sync.get({ checkboxes: [], messageType: 'message', clipboardSave: false, version: 0 - }, function(items) { + }).then((items) => { console.log("Restore: Loaded these items:"); console.log("Restore: Checkboxes", items.checkboxes); console.log("Restore: Message Type", items.messageType); diff --git a/js/serviceworker.js b/js/serviceworker.js index f15f386..80b2f2e 100644 --- a/js/serviceworker.js +++ b/js/serviceworker.js @@ -4,29 +4,32 @@ console.log("Successfully loaded D3 lib"); importScripts("/js/D3.js"); console.log("Successfully loaded D3 main"); -chrome.runtime.onInstalled.addListener(() => { +importScripts("/js/browser-polyfill.min.js"); +console.log("Successfully loaded browser-polyfill"); + +browser.runtime.onInstalled.addListener(() => { D3.checkInstall(D3.createContextMenu()); }); -chrome.storage.onChanged.addListener((changes, namespace) => { +browser.storage.onChanged.addListener((changes, namespace) => { D3.createContextMenu(); }); -chrome.runtime.onMessage.addListener( +browser.runtime.onMessage.addListener( (request, sender, sendResponse) => { console.log([request, sender, sendResponse]); if (request.command == "doCopy") { var responseStatus = D3.copyToClipboard(D3.lastMessage); - sendResponse({status: [chrome.i18n.getMessage("message_copied_to_clipboard"), responseStatus] }); + sendResponse({status: [browser.i18n.getMessage("message_copied_to_clipboard"), responseStatus] }); } else if (request.command == "setContextMenuTitle") { - chrome.contextMenus.update(contextMenuId, {title: request.message}); + browser.contextMenus.update(contextMenuId, {title: request.message}); } else { sendResponse({}); } }); -chrome.contextMenus.onClicked.addListener( +browser.contextMenus.onClicked.addListener( (info, tab) => { menuId = info.menuItemId; @@ -37,10 +40,10 @@ chrome.contextMenus.onClicked.addListener( // Menu item for the extension's settings page if (menuId === 'd3coder-settings') { - chrome.runtime.openOptionsPage(); + browser.runtime.openOptionsPage(); // Menu for selected/editable text } else if (fn_selection === true && fn_normalized in D3lib) { - chrome.storage.sync.get(null, (items) => { + browser.storage.sync.get(null).then((items) => { D3.createPopup( D3.translate(`function_${fn_normalized}`), D3lib[fn_normalized](info.selectionText), diff --git a/manifest.json b/manifest.json index 2865ffa..556b673 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "__MSG_extName__", - "version": "5.0.2", + "version": "5.1.0", "description": "__MSG_extDescription__", "options_ui": { "page": "html/menu_ui.html",