From 8fb4268524aa6d71ae38e6512bf7aa30b34fe6a1 Mon Sep 17 00:00:00 2001
From: argit2 <38925828+argit2@users.noreply.github.com>
Date: Wed, 17 Feb 2021 23:40:41 -0300
Subject: [PATCH 1/7] Update README.md
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index bda30e4..128ef2b 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
+Chrome fork of SessionSync
+
+
+
SessionSync [](https://addons.mozilla.org/en-US/firefox/addon/session-sync/)
===========
From 5d565f00b484d8407c3d40fed997239e99ab8500 Mon Sep 17 00:00:00 2001
From: argit2 <38925828+argit2@users.noreply.github.com>
Date: Thu, 18 Feb 2021 01:10:01 -0300
Subject: [PATCH 2/7] removed errors and fixed window size so extension is
usable for now
---
data/home/home.html | 1 +
data/lazy/lazy.html | 1 +
data/session-sync.css | 5 +++++
data/session-sync.html | 1 +
manifest.json | 1 +
5 files changed, 9 insertions(+)
diff --git a/data/home/home.html b/data/home/home.html
index 3ba3127..2151d51 100644
--- a/data/home/home.html
+++ b/data/home/home.html
@@ -6,6 +6,7 @@
Session Sync - Tutorial
+
diff --git a/data/lazy/lazy.html b/data/lazy/lazy.html
index 5ea1717..e00fd92 100644
--- a/data/lazy/lazy.html
+++ b/data/lazy/lazy.html
@@ -4,6 +4,7 @@
+
diff --git a/data/session-sync.css b/data/session-sync.css
index 8da35b1..ae5a745 100644
--- a/data/session-sync.css
+++ b/data/session-sync.css
@@ -6,6 +6,11 @@
* Action Button
*/
+html {
+ min-width: 800px;
+ min-height: 600px;
+ }
+
#session-sync .comp-button {
width: 100%;
color: #333;
diff --git a/data/session-sync.html b/data/session-sync.html
index 1dc4099..5acfab1 100644
--- a/data/session-sync.html
+++ b/data/session-sync.html
@@ -6,6 +6,7 @@
Session Sync
+
diff --git a/manifest.json b/manifest.json
index 1c36fbe..06b279d 100644
--- a/manifest.json
+++ b/manifest.json
@@ -21,6 +21,7 @@
},
"background": {
"scripts": [
+ "browser-polyfill.js",
"scripts/main.js",
"scripts/favicon-service.js",
"scripts/session-management.js",
From 92549c14622c1968fc9463a8dca016ef3fc13405 Mon Sep 17 00:00:00 2001
From: argit2 <38925828+argit2@users.noreply.github.com>
Date: Thu, 18 Feb 2021 04:47:22 -0300
Subject: [PATCH 3/7] fixed issues that prevented dragging and dropping into
folder
---
.../components/session-bookmark-events.js | 27 ++++++++++++++++++-
data/scripts/components/session-bookmark.js | 1 -
data/scripts/components/session-folder.js | 1 +
data/session-sync.css | 10 +++++++
4 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/data/scripts/components/session-bookmark-events.js b/data/scripts/components/session-bookmark-events.js
index f6dd6c6..96731a4 100644
--- a/data/scripts/components/session-bookmark-events.js
+++ b/data/scripts/components/session-bookmark-events.js
@@ -39,8 +39,26 @@ define(function(require, exports) {
}
}
+ // receives mouse event
+ function elementsAtMouse(e) {
+ let elements = document.elementsFromPoint(e.clientX,e.clientY);
+ return elements;
+ }
+
+ function elemAtMouseWhoseTypeIs(e, type) {
+ let elems = elementsAtMouse(e);
+ for (let ele of elems) {
+ if (ele.type === type) {
+ return ele;
+ }
+ }
+ return null;
+ }
+
function getTargetType(e) {
return getAttribute(e.target, 'type');
+ //return getAttribute(e.target, 'type') ||
+ // e.target.className // chrome;
}
function getSessionID(e) {
@@ -197,12 +215,19 @@ define(function(require, exports) {
var mouseUp = function _mouseUp(e)
{
+ // chrome fix to allow drag and drop of bookmarks to folders
+ let folderElem = elemAtMouseWhoseTypeIs(e, 'folder');
+ if (folderElem && folderElem != e.target) {
+ let newEvent = new MouseEvent(e.type, e);
+ folderElem.dispatchEvent(newEvent);
+ return;
+ }
+
switch(SyncModel.state.session)
{
// if restore session preview
case 'restore': {
var bookmarkID = getBookmarkID(e);
-
// Test if changing
if (bookmarkID != null)
{
diff --git a/data/scripts/components/session-bookmark.js b/data/scripts/components/session-bookmark.js
index 52e9b7d..a1407c6 100644
--- a/data/scripts/components/session-bookmark.js
+++ b/data/scripts/components/session-bookmark.js
@@ -31,7 +31,6 @@ define(function(require, exports) {
function SessionBookmark(bookmark)
{
var DomElem = HTMLCreator();
-
var box = DomElem('div', {class : 'bookmark'});
box.setAttribute('pinned', bookmark.pinned);
diff --git a/data/scripts/components/session-folder.js b/data/scripts/components/session-folder.js
index 53b2fbc..7507b2d 100644
--- a/data/scripts/components/session-folder.js
+++ b/data/scripts/components/session-folder.js
@@ -18,6 +18,7 @@ define(function(require, exports) {
{
var DomElem = HTMLCreator();
var folder = DomElem('div', {class: 'folder', type: bookmark.type});
+ folder.setAttribute('type', 'folder');
folder.setAttribute('sessionID', bookmark.id);
this.DOMRoot = folder;
diff --git a/data/session-sync.css b/data/session-sync.css
index ae5a745..b555614 100644
--- a/data/session-sync.css
+++ b/data/session-sync.css
@@ -6,17 +6,27 @@
* Action Button
*/
+
+
+/* chrome */
html {
min-width: 800px;
min-height: 600px;
}
+/* chrome */
+ * {
+ user-select: none;
+}
+
#session-sync .comp-button {
width: 100%;
color: #333;
display: flex;
}
+
+
#session-sync .comp-button .label {
flex: 1;
}
From d851332b1bb7cb8cd18b05e6f9961a5dd0076872 Mon Sep 17 00:00:00 2001
From: argit2 <38925828+argit2@users.noreply.github.com>
Date: Thu, 18 Feb 2021 04:52:03 -0300
Subject: [PATCH 4/7] Updated readme
---
README.md | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/README.md b/README.md
index 128ef2b..419dda2 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,20 @@
Chrome fork of SessionSync
+Basic features tested on Vivaldi browser as of February of 2021th.
+
+The extension might not work. It's advised to use this extension alongside another backup utility.
+
+# Instructions
+
+1) Download the extension files and extract them to a folder
+2) Go to Manage Extensions page
+3) Toggle developer mode on
+4) Click "Load unpacked"
+5) Select the folder the files are in
+6) Done.
+
+
+
SessionSync [](https://addons.mozilla.org/en-US/firefox/addon/session-sync/)
From 0c38e53c51e7dfcbd004d01750cb252f3822d7ad Mon Sep 17 00:00:00 2001
From: argit2 <38925828+argit2@users.noreply.github.com>
Date: Thu, 18 Feb 2021 04:57:44 -0300
Subject: [PATCH 5/7] updated readme
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 419dda2..985f3c8 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@ Chrome fork of SessionSync
Basic features tested on Vivaldi browser as of February of 2021th.
-The extension might not work. It's advised to use this extension alongside another backup utility.
+The extension might not work. It's advised to use this extension alongside another session backup extension.
# Instructions
From a6db9ba4ced3b1d0bf1b49094e23668b88c1d7fe Mon Sep 17 00:00:00 2001
From: argit2 <38925828+argit2@users.noreply.github.com>
Date: Thu, 18 Feb 2021 23:34:42 -0300
Subject: [PATCH 6/7] forgot some files
---
browser-polyfill.js | 1238 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1238 insertions(+)
create mode 100644 browser-polyfill.js
diff --git a/browser-polyfill.js b/browser-polyfill.js
new file mode 100644
index 0000000..f3cd531
--- /dev/null
+++ b/browser-polyfill.js
@@ -0,0 +1,1238 @@
+(function (global, factory) {
+ if (typeof define === "function" && define.amd) {
+ define("webextension-polyfill", ["module"], factory);
+ } else if (typeof exports !== "undefined") {
+ factory(module);
+ } else {
+ var mod = {
+ exports: {}
+ };
+ factory(mod);
+ global.browser = mod.exports;
+ }
+})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (module) {
+ /* webextension-polyfill - v0.7.0 - Tue Nov 10 2020 20:24:04 */
+
+ /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+
+ /* vim: set sts=2 sw=2 et tw=80: */
+
+ /* 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";
+
+ if (typeof browser === "undefined" || Object.getPrototypeOf(browser) !== Object.prototype) {
+ const CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE = "The message port closed before a response was received.";
+ const SEND_RESPONSE_DEPRECATION_WARNING = "Returning a Promise is the preferred way to send a reply from an onMessage/onMessageExternal listener, as the sendResponse will be removed from the specs (See https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage)"; // Wrapping the bulk of this polyfill in a one-time-use function is a minor
+ // optimization for Firefox. Since Spidermonkey does not fully parse the
+ // contents of a function until the first time it's called, and since it will
+ // never actually need to be called, this allows the polyfill to be included
+ // in Firefox nearly for free.
+
+ const wrapAPIs = extensionAPIs => {
+ // NOTE: apiMetadata is associated to the content of the api-metadata.json file
+ // at build time by replacing the following "include" with the content of the
+ // JSON file.
+ const apiMetadata = {
+ "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": true
+ },
+ "enable": {
+ "minArgs": 0,
+ "maxArgs": 1,
+ "fallbackToNoCallback": true
+ },
+ "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": true
+ },
+ "setBadgeText": {
+ "minArgs": 1,
+ "maxArgs": 1,
+ "fallbackToNoCallback": true
+ },
+ "setIcon": {
+ "minArgs": 1,
+ "maxArgs": 1
+ },
+ "setPopup": {
+ "minArgs": 1,
+ "maxArgs": 1,
+ "fallbackToNoCallback": true
+ },
+ "setTitle": {
+ "minArgs": 1,
+ "maxArgs": 1,
+ "fallbackToNoCallback": true
+ }
+ },
+ "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": false
+ }
+ },
+ "panels": {
+ "create": {
+ "minArgs": 3,
+ "maxArgs": 3,
+ "singleCallbackArg": true
+ },
+ "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": true
+ },
+ "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": true
+ }
+ },
+ "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": true
+ },
+ "setIcon": {
+ "minArgs": 1,
+ "maxArgs": 1
+ },
+ "setPopup": {
+ "minArgs": 1,
+ "maxArgs": 1,
+ "fallbackToNoCallback": true
+ },
+ "setTitle": {
+ "minArgs": 1,
+ "maxArgs": 1,
+ "fallbackToNoCallback": true
+ },
+ "show": {
+ "minArgs": 1,
+ "maxArgs": 1,
+ "fallbackToNoCallback": true
+ }
+ },
+ "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 (Object.keys(apiMetadata).length === 0) {
+ throw new Error("api-metadata.json has not been included in browser-polyfill");
+ }
+ /**
+ * A WeakMap subclass which creates and stores a value for any key which does
+ * not exist when accessed, but behaves exactly as an ordinary WeakMap
+ * otherwise.
+ *
+ * @param {function} createItem
+ * A function which will be called in order to create the value for any
+ * key which does not exist, the first time it is accessed. The
+ * function receives, as its only argument, the key being created.
+ */
+
+
+ class DefaultWeakMap extends WeakMap {
+ constructor(createItem, items = undefined) {
+ super(items);
+ this.createItem = createItem;
+ }
+
+ get(key) {
+ if (!this.has(key)) {
+ this.set(key, this.createItem(key));
+ }
+
+ return super.get(key);
+ }
+
+ }
+ /**
+ * Returns true if the given object is an object with a `then` method, and can
+ * therefore be assumed to behave as a Promise.
+ *
+ * @param {*} value The value to test.
+ * @returns {boolean} True if the value is thenable.
+ */
+
+
+ const isThenable = value => {
+ return value && typeof value === "object" && typeof value.then === "function";
+ };
+ /**
+ * Creates and returns a function which, when called, will resolve or reject
+ * the given promise based on how it is called:
+ *
+ * - If, when called, `chrome.runtime.lastError` contains a non-null object,
+ * the promise is rejected with that value.
+ * - If the function is called with exactly one argument, the promise is
+ * resolved to that value.
+ * - Otherwise, the promise is resolved to an array containing all of the
+ * function's arguments.
+ *
+ * @param {object} promise
+ * An object containing the resolution and rejection functions of a
+ * promise.
+ * @param {function} promise.resolve
+ * The promise's resolution function.
+ * @param {function} promise.rejection
+ * The promise's rejection function.
+ * @param {object} metadata
+ * Metadata about the wrapped method which has created the callback.
+ * @param {integer} metadata.maxResolvedArgs
+ * The maximum number of arguments which may be passed to the
+ * callback created by the wrapped async function.
+ *
+ * @returns {function}
+ * The generated callback function.
+ */
+
+
+ const makeCallback = (promise, metadata) => {
+ return (...callbackArgs) => {
+ if (extensionAPIs.runtime.lastError) {
+ promise.reject(extensionAPIs.runtime.lastError);
+ } else if (metadata.singleCallbackArg || callbackArgs.length <= 1 && metadata.singleCallbackArg !== false) {
+ promise.resolve(callbackArgs[0]);
+ } else {
+ promise.resolve(callbackArgs);
+ }
+ };
+ };
+
+ const pluralizeArguments = numArgs => numArgs == 1 ? "argument" : "arguments";
+ /**
+ * Creates a wrapper function for a method with the given name and metadata.
+ *
+ * @param {string} name
+ * The name of the method which is being wrapped.
+ * @param {object} metadata
+ * Metadata about the method being wrapped.
+ * @param {integer} metadata.minArgs
+ * The minimum number of arguments which must be passed to the
+ * function. If called with fewer than this number of arguments, the
+ * wrapper will raise an exception.
+ * @param {integer} metadata.maxArgs
+ * The maximum number of arguments which may be passed to the
+ * function. If called with more than this number of arguments, the
+ * wrapper will raise an exception.
+ * @param {integer} metadata.maxResolvedArgs
+ * The maximum number of arguments which may be passed to the
+ * callback created by the wrapped async function.
+ *
+ * @returns {function(object, ...*)}
+ * The generated wrapper function.
+ */
+
+
+ const wrapAsyncFunction = (name, metadata) => {
+ return function asyncFunctionWrapper(target, ...args) {
+ if (args.length < metadata.minArgs) {
+ throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`);
+ }
+
+ if (args.length > metadata.maxArgs) {
+ throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`);
+ }
+
+ return new Promise((resolve, reject) => {
+ if (metadata.fallbackToNoCallback) {
+ // This API method has currently no callback on Chrome, but it return a promise on Firefox,
+ // and so the polyfill will try to call it with a callback first, and it will fallback
+ // to not passing the callback if the first call fails.
+ try {
+ target[name](...args, makeCallback({
+ resolve,
+ reject
+ }, metadata));
+ } catch (cbError) {
+ console.warn(`${name} API method doesn't seem to support the callback parameter, ` + "falling back to call it without a callback: ", cbError);
+ target[name](...args); // Update the API method metadata, so that the next API calls will not try to
+ // use the unsupported callback anymore.
+
+ metadata.fallbackToNoCallback = false;
+ metadata.noCallback = true;
+ resolve();
+ }
+ } else if (metadata.noCallback) {
+ target[name](...args);
+ resolve();
+ } else {
+ target[name](...args, makeCallback({
+ resolve,
+ reject
+ }, metadata));
+ }
+ });
+ };
+ };
+ /**
+ * Wraps an existing method of the target object, so that calls to it are
+ * intercepted by the given wrapper function. The wrapper function receives,
+ * as its first argument, the original `target` object, followed by each of
+ * the arguments passed to the original method.
+ *
+ * @param {object} target
+ * The original target object that the wrapped method belongs to.
+ * @param {function} method
+ * The method being wrapped. This is used as the target of the Proxy
+ * object which is created to wrap the method.
+ * @param {function} wrapper
+ * The wrapper function which is called in place of a direct invocation
+ * of the wrapped method.
+ *
+ * @returns {Proxy}
+ * A Proxy object for the given method, which invokes the given wrapper
+ * method in its place.
+ */
+
+
+ const wrapMethod = (target, method, wrapper) => {
+ return new Proxy(method, {
+ apply(targetMethod, thisObj, args) {
+ return wrapper.call(thisObj, target, ...args);
+ }
+
+ });
+ };
+
+ let hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);
+ /**
+ * Wraps an object in a Proxy which intercepts and wraps certain methods
+ * based on the given `wrappers` and `metadata` objects.
+ *
+ * @param {object} target
+ * The target object to wrap.
+ *
+ * @param {object} [wrappers = {}]
+ * An object tree containing wrapper functions for special cases. Any
+ * function present in this object tree is called in place of the
+ * method in the same location in the `target` object tree. These
+ * wrapper methods are invoked as described in {@see wrapMethod}.
+ *
+ * @param {object} [metadata = {}]
+ * An object tree containing metadata used to automatically generate
+ * Promise-based wrapper functions for asynchronous. Any function in
+ * the `target` object tree which has a corresponding metadata object
+ * in the same location in the `metadata` tree is replaced with an
+ * automatically-generated wrapper function, as described in
+ * {@see wrapAsyncFunction}
+ *
+ * @returns {Proxy