[gnome-browser-extension/wip/refactor: 7/7] Format code




commit 9ecca91282ca9ca0aa618d5b7181e03273ee7ecb
Author: Yuri Konotopov <ykonotopov gnome org>
Date:   Thu Aug 4 22:40:52 2022 +0400

    Format code
    
    1. Use spaces instead of tabs
    2. Use open curly bracket on same line
    3. Use space after operator before parenthesis

 extension/content-script-start.js          |  53 +-
 extension/css/options.css                  | 143 ++---
 extension/extension.js                     | 320 ++++++-----
 extension/include/compat-common.js         | 160 +++---
 extension/include/compat-content-script.js |  68 ++-
 extension/include/constants.js             |  96 ++--
 extension/include/gsc.js                   | 260 +++++----
 extension/include/i18n.js                  |  43 +-
 extension/include/notifications.js         | 396 +++++++-------
 extension/include/sweettooth-api.js        | 397 +++++++-------
 extension/include/sync.js                  | 832 ++++++++++++++---------------
 extension/include/toolbar.js               |  90 ++--
 extension/include/update.js                | 360 ++++++-------
 extension/options.html                     | 229 ++++----
 extension/options.js                       | 703 +++++++++++-------------
 15 files changed, 1981 insertions(+), 2169 deletions(-)
---
diff --git a/extension/content-script-start.js b/extension/content-script-start.js
index 2772662..dfa820d 100644
--- a/extension/content-script-start.js
+++ b/extension/content-script-start.js
@@ -6,51 +6,48 @@
  */
 
 var gs_require_inject = function () {
-       GS_CHROME_ID            = "${GS_CHROME_ID}";
-       GS_CHROME_VERSION       = "${GS_CHROME_VERSION}";
+    GS_CHROME_ID        = "${GS_CHROME_ID}";
+    GS_CHROME_VERSION   = "${GS_CHROME_VERSION}";
 };
 
 var siteMessages = {};
-if(EXTERNAL_MESSAGES)
-{
-       for(var key in EXTERNAL_MESSAGES)
-       {
-               siteMessages[EXTERNAL_MESSAGES[key]] = chrome.i18n.getMessage(EXTERNAL_MESSAGES[key]);
-       }
+if (EXTERNAL_MESSAGES) {
+    for (var key in EXTERNAL_MESSAGES) {
+        siteMessages[EXTERNAL_MESSAGES[key]] = chrome.i18n.getMessage(EXTERNAL_MESSAGES[key]);
+    }
 }
 
 var s = document.createElement('script');
 
 s.type = "text/javascript";
 s.textContent = '(' +
-       gs_require_inject.toString()
-               .replace("${GS_CHROME_ID}", GS_CHROME_ID)
-               .replace("${GS_CHROME_VERSION}", chrome.runtime.getManifest().version)
-       + ")(); GSC = {i18n: JSON.parse('" + JSON.stringify(siteMessages).replace(/'/g, "\\'") + "')};";
-(document.head||document.documentElement).appendChild(s);
+    gs_require_inject.toString()
+        .replace("${GS_CHROME_ID}", GS_CHROME_ID)
+        .replace("${GS_CHROME_VERSION}", chrome.runtime.getManifest().version)
+    + ")(); GSC = {i18n: JSON.parse('" + JSON.stringify(siteMessages).replace(/'/g, "\\'") + "')};";
+(document.head || document.documentElement).appendChild(s);
 s.parentNode.removeChild(s);
 
 chrome.runtime.onMessage.addListener(
-       function (request, sender, sendResponse) {
-               if(
-                       sender.id && sender.id === GS_CHROME_ID &&
-                       request && request.signal &&
-                       [SIGNAL_EXTENSION_CHANGED, SIGNAL_SHELL_APPEARED, 
SIGNAL_SHELL_SETTING_CHANGED].indexOf(request.signal) !== -1)
-               {
-                       window.postMessage(
-                               {
-                                       type: "gs-chrome",
-                                       request: request
-                               }, "*"
-                       );
-               }
-       }
+    function (request, sender, sendResponse) {
+        if (
+            sender.id && sender.id === GS_CHROME_ID &&
+            request && request.signal &&
+            [SIGNAL_EXTENSION_CHANGED, SIGNAL_SHELL_APPEARED, 
SIGNAL_SHELL_SETTING_CHANGED].indexOf(request.signal) !== -1) {
+            window.postMessage(
+                {
+                    type: "gs-chrome",
+                    request: request
+                }, "*"
+            );
+        }
+    }
 );
 
 s = document.createElement('script');
 
 s.src = chrome.extension.getURL('include/sweettooth-api.js');
-s.onload = function() {
+s.onload = function () {
     this.parentNode.removeChild(this);
 };
 (document.head || document.documentElement).appendChild(s);
diff --git a/extension/css/options.css b/extension/css/options.css
index 3c7ba6e..456bb04 100644
--- a/extension/css/options.css
+++ b/extension/css/options.css
@@ -1,125 +1,144 @@
 body {
-       font-family: Cantarell, Arial, sans-serif;
-       padding: 10px;
-       min-width: 550px;
+    font-family: Cantarell, Arial, sans-serif;
+    padding: 10px;
+    min-width: 550px;
+}
+
+#update_check_period {
+    width: 5em;
 }
 
-#update_check_period { width: 5em; }
 #status {
-       visibility: hidden;
-       opacity: 0;
-       color: green;
-       text-align: center;
+    visibility: hidden;
+    opacity: 0;
+    color: green;
+    text-align: center;
 }
 
 #error {
-       visibility: hidden;
-       opacity: 0;
-       color: red;
-       text-align: center;
+    visibility: hidden;
+    opacity: 0;
+    color: red;
+    text-align: center;
 }
 
 .show {
-       visibility: visible !important;
-       opacity: 1 !important;
-       transition: visibility 0.25s, opacity 0.25s ease-in-out;
+    visibility: visible !important;
+    opacity: 1 !important;
+    transition: visibility 0.25s, opacity 0.25s ease-in-out;
 }
 
 .hide {
-       display: none;
+    display: none;
 }
 
-.buttons { text-align: center; margin-top: 1em; }
-.notice { font-size: 90%; font-weight: normal; margin-top: 0.5em; white-space: nowrap; }
-.update-notice { display: none; }
-.wrapped { white-space: normal; }
+.buttons {
+    text-align: center;
+    margin-top: 1em;
+}
+
+.notice {
+    font-size: 90%;
+    font-weight: normal;
+    margin-top: 0.5em;
+    white-space: nowrap;
+}
+
+.update-notice {
+    display: none;
+}
+
+.wrapped {
+    white-space: normal;
+}
 
 fieldset {
-       border: 0;
-       margin: 0;
-       padding: 0;
-       width: 100%;
+    border: 0;
+    margin: 0;
+    padding: 0;
+    width: 100%;
 }
 
 dl {
-       padding: 0.2em 0;
-       clear: both;
+    padding: 0.2em 0;
+    clear: both;
 }
 
 dt {
-       display: block;
-       float: left;
-       width: 50%;
-       text-align: left;
-       font-weight: bold;
+    display: block;
+    float: left;
+    width: 50%;
+    text-align: left;
+    font-weight: bold;
 }
 
 dd {
-       margin-left: 51%;
-       vertical-align: top;
-       margin-bottom: 3px;
+    margin-left: 51%;
+    vertical-align: top;
+    margin-bottom: 3px;
 }
 
 ul.tabs {
-       float: right;
+    float: right;
 }
 
 ul.tabs li {
-       list-style: none;
+    list-style: none;
 }
 
-ul.tabs li, ul.tabs li a {
-       display: inline-block;
+ul.tabs li,
+ul.tabs li a {
+    display: inline-block;
 }
 
 ul.tabs li a.active {
-       color: inherit;
-       cursor: default;
-       text-decoration: none;
+    color: inherit;
+    cursor: default;
+    text-decoration: none;
 }
 
 ul.tabs li:not(:last-child) {
-       border-right: 1px solid #000;
-       margin-right: 5px;
-       padding-right: 5px;
+    border-right: 1px solid #000;
+    margin-right: 5px;
+    padding-right: 5px;
 }
 
 div.tabs-pane {
-       clear: both;
+    clear: both;
 }
 
 #synchronization table {
-       width: 100%;
-       border-collapse: collapse;
-       vertical-align: middle;
+    width: 100%;
+    border-collapse: collapse;
+    vertical-align: middle;
 }
 
 #synchronization table th {
-       border-bottom: 1px solid #000;
+    border-bottom: 1px solid #000;
 }
 
-#synchronization table tbody td.ok, #synchronization table td.fail {
-       text-align: center;
-       font-size: 150%;
+#synchronization table tbody td.ok,
+#synchronization table td.fail {
+    text-align: center;
+    font-size: 150%;
 }
 
 #synchronization table tbody td.ok:after {
-       content: '\2713';
-       color: green;
+    content: '\2713';
+    color: green;
 }
 
 #synchronization table td.fail:after {
-       content: '\2717';
-       color: red;
+    content: '\2717';
+    color: red;
 }
 
 dialog#syncChoice button {
-       display: block;
-       width: 90%;
-       margin: 0.3em auto;
+    display: block;
+    width: 90%;
+    margin: 0.3em auto;
 }
 
-div#translation_credits div
-{
-       white-space: pre-line;
+div#translation_credits div {
+    white-space: pre-line;
 }
diff --git a/extension/extension.js b/extension/extension.js
index 0b752db..f1032dd 100644
--- a/extension/extension.js
+++ b/extension/extension.js
@@ -1,196 +1,178 @@
 // SPDX-License-Identifer: GPL-3.0-or-later
 
-chrome.runtime.onInstalled.addListener(function(details) {
-       var version = chrome.runtime.getManifest().version;
-
-       if(details.reason == chrome.runtime.OnInstalledReason.UPDATE && details.previousVersion != version)
-       {
-               chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (options) {
-                       if(options.showReleaseNotes)
-                       {
-                               chrome.tabs.create({
-                                       url: 
'https://wiki.gnome.org/Projects/GnomeShellIntegrationForChrome/ReleaseNotes/' + version,
-                                       active: true
-                               });
-                       }
-               });
-       }
+chrome.runtime.onInstalled.addListener(function (details) {
+    var version = chrome.runtime.getManifest().version;
+
+    if (details.reason == chrome.runtime.OnInstalledReason.UPDATE && details.previousVersion != version) {
+        chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (options) {
+            if (options.showReleaseNotes) {
+                chrome.tabs.create({
+                    url: 'https://wiki.gnome.org/Projects/GnomeShellIntegrationForChrome/ReleaseNotes/' + 
version,
+                    active: true
+                });
+            }
+        });
+    }
 });
 
 chrome.runtime.onMessageExternal.addListener(function (request, sender, sendResponse) {
-       if (
-               EXTENSIONS_WEBSITE.reduce(
-                       (accumulator, url) => accumulator + sender.url.startsWith(url),
-                       0)
-       )
-       {
-               if (request && request.execute)
-               {
-                       if (request.uuid && !GSC.isUUID(request.uuid))
-                       {
-                               return;
-                       }
-
-                       switch (request.execute)
-                       {
-                               case 'initialize':
-                               case 'listExtensions':
-                                       GSC.sendNativeRequest({execute: request.execute}, sendResponse);
-                                       return true;
-
-                               case 'launchExtensionPrefs':
-                                       GSC.sendNativeRequest({execute: request.execute, uuid: request.uuid});
-                                       break;
-
-                               case 'getExtensionErrors':
-                               case 'getExtensionInfo':
-                               case 'installExtension':
-                               case 'uninstallExtension':
-                                       GSC.sendNativeRequest({execute: request.execute, uuid: request.uuid}, 
sendResponse);
-                                       return true;
-
-                               case 'enableExtension':
-                                       GSC.sendNativeRequest({
-                                                       execute: request.execute,
-                                                       uuid: request.uuid,
-                                                       enable: request.enable
-                                               },
-                                               sendResponse
-                                       );
-                                       return true;
-
-                               case 'setUserExtensionsDisabled':
-                               case 'setVersionValidationDisabled':
-                                       GSC.sendNativeRequest({execute: request.execute, disable: 
request.disable ? true : false}, sendResponse);
-                                       return true;
-                       }
-               }
-       }
+    if (
+        EXTENSIONS_WEBSITE.reduce(
+            (accumulator, url) => accumulator + sender.url.startsWith(url),
+            0)
+    ) {
+        if (request && request.execute) {
+            if (request.uuid && !GSC.isUUID(request.uuid)) {
+                return;
+            }
+
+            switch (request.execute) {
+                case 'initialize':
+                case 'listExtensions':
+                    GSC.sendNativeRequest({ execute: request.execute }, sendResponse);
+                    return true;
+
+                case 'launchExtensionPrefs':
+                    GSC.sendNativeRequest({ execute: request.execute, uuid: request.uuid });
+                    break;
+
+                case 'getExtensionErrors':
+                case 'getExtensionInfo':
+                case 'installExtension':
+                case 'uninstallExtension':
+                    GSC.sendNativeRequest({ execute: request.execute, uuid: request.uuid }, sendResponse);
+                    return true;
+
+                case 'enableExtension':
+                    GSC.sendNativeRequest({
+                        execute: request.execute,
+                        uuid: request.uuid,
+                        enable: request.enable
+                    },
+                        sendResponse
+                    );
+                    return true;
+
+                case 'setUserExtensionsDisabled':
+                case 'setVersionValidationDisabled':
+                    GSC.sendNativeRequest({ execute: request.execute, disable: request.disable ? true : 
false }, sendResponse);
+                    return true;
+            }
+        }
+    }
 });
 
 EXTENSIONS_WEBSITE.forEach(url => {
-       chrome.browserAction.onClicked.addListener(function () {
-               chrome.tabs.create({
-                       url: url,
-                       active: true
-               });
-       });
+    chrome.browserAction.onClicked.addListener(function () {
+        chrome.tabs.create({
+            url: url,
+            active: true
+        });
+    });
 });
 
 var disabledExtensionTimeout = null;
-var lastPortMessage = {message: null, date: 0};
+var lastPortMessage = { message: null, date: 0 };
 var port = chrome.runtime.connectNative(NATIVE_HOST);
 /*
  * Native host messaging events handler.
  */
 port.onMessage.addListener(function (message) {
-       if (message && message.signal)
-       {
-               if([SIGNAL_EXTENSION_CHANGED, SIGNAL_SHELL_APPEARED, 
SIGNAL_SHELL_SETTING_CHANGED].indexOf(message.signal) !== -1)
-               {
-                       /*
-                        * Skip duplicate events. This is happens eg when extension is installed.
-                        */
-                       if (
-                                       message.signal != SIGNAL_SHELL_SETTING_CHANGED &&
-                                       (new Date().getTime()) - lastPortMessage.date < 1000 && 
GSC.isSignalsEqual(message, lastPortMessage.message)
-                       )
-                       {
-                               lastPortMessage.date = new Date().getTime();
-                               return;
-                       }
-
-                       /*
-                        * Send events to opened extensions.gnome.org tabs
-                        */
-                       EXTENSIONS_WEBSITE.forEach(url => {
-                               chrome.tabs.query({
-                                       url: url + '*'
-                               },
-                               function (tabs) {
-                                       for (k in tabs)
-                                       {
-                                               chrome.tabs.sendMessage(tabs[k].id, message);
-                                       }
-                               });
-                       });
-
-                       /*
-                        * Route message to Options page.
-                        */
-                       chrome.runtime.sendMessage(GS_CHROME_ID, message);
-                       if (message.signal === SIGNAL_EXTENSION_CHANGED)
-                       {
-                               /*
-                                * GNOME Shell sends 2 events when extension is uninstalled:
-                                * "disabled" event and then "uninstalled" event.
-                                * Let's delay any "disabled" event and drop it if
-                                * "uninstalled" event received within 1,5 secs.
-                                */
-                               if (message.parameters[EXTENSION_CHANGED_STATE] === EXTENSION_STATE.DISABLED)
-                               {
-                                       disabledExtensionTimeout = setTimeout(function () {
-                                               disabledExtensionTimeout = null;
-                                               GSC.sync.onExtensionChanged(message);
-                                       }, 1500);
-                               }
-                               else if (
-                                       disabledExtensionTimeout &&
-                                       message.parameters[EXTENSION_CHANGED_STATE] === 
EXTENSION_STATE.UNINSTALLED &&
-                                       lastPortMessage.message.signal === SIGNAL_EXTENSION_CHANGED &&
-                                       lastPortMessage.message.parameters[EXTENSION_CHANGED_UUID] === 
message.parameters[EXTENSION_CHANGED_UUID] &&
-                                       lastPortMessage.message.parameters[EXTENSION_CHANGED_STATE] === 
EXTENSION_STATE.DISABLED
-                               )
-                               {
-                                       clearTimeout(disabledExtensionTimeout);
-                                       disabledExtensionTimeout = null;
-                                       GSC.sync.onExtensionChanged(message);
-                               }
-                               else
-                               {
-                                       GSC.sync.onExtensionChanged(message);
-                               }
-                       }
-
-                       lastPortMessage = {
-                               message: message,
-                               date: new Date().getTime()
-                       };
-               }
-               else if([SIGNAL_NOTIFICATION_ACTION, SIGNAL_NOTIFICATION_CLICKED].indexOf(message.signal) != 
-1)
-               {
-                       window.postMessage(message, "*");
-               }
-       }
+    if (message && message.signal) {
+        if ([SIGNAL_EXTENSION_CHANGED, SIGNAL_SHELL_APPEARED, 
SIGNAL_SHELL_SETTING_CHANGED].indexOf(message.signal) !== -1) {
+            /*
+             * Skip duplicate events. This is happens eg when extension is installed.
+             */
+            if (
+                message.signal != SIGNAL_SHELL_SETTING_CHANGED &&
+                (new Date().getTime()) - lastPortMessage.date < 1000 && GSC.isSignalsEqual(message, 
lastPortMessage.message)
+            ) {
+                lastPortMessage.date = new Date().getTime();
+                return;
+            }
+
+            /*
+             * Send events to opened extensions.gnome.org tabs
+             */
+            EXTENSIONS_WEBSITE.forEach(url => {
+                chrome.tabs.query({
+                    url: url + '*'
+                },
+                    function (tabs) {
+                        for (k in tabs) {
+                            chrome.tabs.sendMessage(tabs[k].id, message);
+                        }
+                    });
+            });
+
+            /*
+             * Route message to Options page.
+             */
+            chrome.runtime.sendMessage(GS_CHROME_ID, message);
+            if (message.signal === SIGNAL_EXTENSION_CHANGED) {
+                /*
+                 * GNOME Shell sends 2 events when extension is uninstalled:
+                 * "disabled" event and then "uninstalled" event.
+                 * Let's delay any "disabled" event and drop it if
+                 * "uninstalled" event received within 1,5 secs.
+                 */
+                if (message.parameters[EXTENSION_CHANGED_STATE] === EXTENSION_STATE.DISABLED) {
+                    disabledExtensionTimeout = setTimeout(function () {
+                        disabledExtensionTimeout = null;
+                        GSC.sync.onExtensionChanged(message);
+                    }, 1500);
+                }
+                else if (
+                    disabledExtensionTimeout &&
+                    message.parameters[EXTENSION_CHANGED_STATE] === EXTENSION_STATE.UNINSTALLED &&
+                    lastPortMessage.message.signal === SIGNAL_EXTENSION_CHANGED &&
+                    lastPortMessage.message.parameters[EXTENSION_CHANGED_UUID] === 
message.parameters[EXTENSION_CHANGED_UUID] &&
+                    lastPortMessage.message.parameters[EXTENSION_CHANGED_STATE] === EXTENSION_STATE.DISABLED
+                ) {
+                    clearTimeout(disabledExtensionTimeout);
+                    disabledExtensionTimeout = null;
+                    GSC.sync.onExtensionChanged(message);
+                }
+                else {
+                    GSC.sync.onExtensionChanged(message);
+                }
+            }
+
+            lastPortMessage = {
+                message: message,
+                date: new Date().getTime()
+            };
+        }
+        else if ([SIGNAL_NOTIFICATION_ACTION, SIGNAL_NOTIFICATION_CLICKED].indexOf(message.signal) != -1) {
+            window.postMessage(message, "*");
+        }
+    }
 });
 /*
  * Subscribe to GNOME Shell signals
  */
-port.postMessage({execute: 'subscribeSignals'});
+port.postMessage({ execute: 'subscribeSignals' });
 
 window.addEventListener("message", function (event) {
-               // We only accept messages from ourselves
-               if (event.source == window && event.data && event.data.execute)
-               {
-                       switch (event.data.execute)
-                       {
-                               case 'createNotification':
-                                       port.postMessage(event.data);
-                                       break;
-                               case 'removeNotification':
-                                       port.postMessage(event.data);
-                                       break;
-                       }
-               }
-       }
+    // We only accept messages from ourselves
+    if (event.source == window && event.data && event.data.execute) {
+        switch (event.data.execute) {
+            case 'createNotification':
+                port.postMessage(event.data);
+                break;
+            case 'removeNotification':
+                port.postMessage(event.data);
+                break;
+        }
+    }
+}
 );
 
-chrome.runtime.getPlatformInfo(function(info) {
-       if (PLATFORMS_WHITELIST.indexOf(info.os) !== -1)
-       {
-               GSC.update.init();
-               GSC.sync.init();
-       }
+chrome.runtime.getPlatformInfo(function (info) {
+    if (PLATFORMS_WHITELIST.indexOf(info.os) !== -1) {
+        GSC.update.init();
+        GSC.sync.init();
+    }
 });
 
 GSC.toolbar.init();
diff --git a/extension/include/compat-common.js b/extension/include/compat-common.js
index a0d17a5..0ad3cd3 100644
--- a/extension/include/compat-common.js
+++ b/extension/include/compat-common.js
@@ -6,106 +6,98 @@ $ = (...args) => document.querySelector(...args);
 $$ = (...args) => document.querySelectorAll(...args);
 
 function empty(element) {
-       while(element.firstChild) element.removeChild(element.firstChild);
+    while (element.firstChild) element.removeChild(element.firstChild);
 }
 
 function isEmptyObject(object) {
-       for (const k in object) return false;
-       return true;
+    for (const k in object) return false;
+    return true;
 }
 
 function showWithDelay(element, delay, message) {
-       if (message) {
-               element.innerHtml = message;
-       }
+    if (message) {
+        element.innerHtml = message;
+    }
 
-       element.classList.remove('hide');
-       element.classList.add('show');
-       setTimeout(() => {
-               element.classList.remove('show');
-               setTimeout(() => {
-                       element.classList.add('hide');
-               }, 250);
-       }, delay);
+    element.classList.remove('hide');
+    element.classList.add('show');
+    setTimeout(() => {
+        element.classList.remove('show');
+        setTimeout(() => {
+            element.classList.add('hide');
+        }, 250);
+    }, delay);
 }
 
-COMPAT.PERMISSIONS_CONTAINS            = true;
-COMPAT.PERMISSIONS_EVENTS              = true;
-COMPAT.SYNC_STORAGE                            = true;
-COMPAT.NOTIFICATIONS_BUTTONS   = (!COMPAT.IS_FIREFOX || false);
+COMPAT.PERMISSIONS_CONTAINS     = true;
+COMPAT.PERMISSIONS_EVENTS       = true;
+COMPAT.SYNC_STORAGE             = true;
+COMPAT.NOTIFICATIONS_BUTTONS    = (!COMPAT.IS_FIREFOX || false);
 
-if(COMPAT.IS_FIREFOX)
-{
-       chrome.runtime.onMessageExternal = {
-               addListener: chrome.runtime.onMessage.addListener
-       };
+if (COMPAT.IS_FIREFOX) {
+    chrome.runtime.onMessageExternal = {
+        addListener: chrome.runtime.onMessage.addListener
+    };
 }
 
-if(typeof(chrome.permissions) === 'undefined')
-{
-       chrome.permissions = {
-               contains: function(permissions, callback) {
-                       callback(false);
-               }
-       };
-       COMPAT.PERMISSIONS_CONTAINS = false;
+if (typeof (chrome.permissions) === 'undefined') {
+    chrome.permissions = {
+        contains: function (permissions, callback) {
+            callback(false);
+        }
+    };
+    COMPAT.PERMISSIONS_CONTAINS = false;
 }
 
-if(typeof(chrome.permissions.onAdded) === 'undefined' || typeof(chrome.permissions.onRemoved) === 
'undefined')
-{
-       chrome.permissions.onAdded = {
-               addListener: function(callback) {
-                       chrome.runtime.onMessage.addListener(
-                               function (request, sender, sendResponse) {
-                                       if (sender.id && sender.id === GS_CHROME_ID && request)
-                                       {
-                                               if (request === MESSAGE_IDLE_PERMISSION_ADDED)
-                                               {
-                                                       callback({
-                                                               permissions: ['idle']
-                                                       });
-                                               }
-                                       }
-                               }
-                       );
-               },
-               removeListener: function(callback) {
-                       chrome.runtime.onMessage.removeListener(callback);
-               },
-               hasListener: function(callback) {
-                       return chrome.runtime.onMessage.hasListener(callback);
-               }
-       }
+if (typeof (chrome.permissions.onAdded) === 'undefined' || typeof (chrome.permissions.onRemoved) === 
'undefined') {
+    chrome.permissions.onAdded = {
+        addListener: function (callback) {
+            chrome.runtime.onMessage.addListener(
+                function (request, sender, sendResponse) {
+                    if (sender.id && sender.id === GS_CHROME_ID && request) {
+                        if (request === MESSAGE_IDLE_PERMISSION_ADDED) {
+                            callback({
+                                permissions: ['idle']
+                            });
+                        }
+                    }
+                }
+            );
+        },
+        removeListener: function (callback) {
+            chrome.runtime.onMessage.removeListener(callback);
+        },
+        hasListener: function (callback) {
+            return chrome.runtime.onMessage.hasListener(callback);
+        }
+    }
 
-       chrome.permissions.onRemoved = {
-               addListener: function(callback) {
-                       chrome.runtime.onMessage.addListener(
-                               function (request, sender, sendResponse) {
-                                       if (sender.id && sender.id === GS_CHROME_ID && request)
-                                       {
-                                               if (request === MESSAGE_IDLE_PERMISSION_REMOVED)
-                                               {
-                                                       callback({
-                                                               permissions: ['idle']
-                                                       });
-                                               }
-                                       }
-                               }
-                       );
-               },
-               removeListener: function(callback) {
-                       chrome.runtime.onMessage.removeListener(callback);
-               },
-               hasListener: function(callback) {
-                       return chrome.runtime.onMessage.hasListener(callback);
-               }
-       }
+    chrome.permissions.onRemoved = {
+        addListener: function (callback) {
+            chrome.runtime.onMessage.addListener(
+                function (request, sender, sendResponse) {
+                    if (sender.id && sender.id === GS_CHROME_ID && request) {
+                        if (request === MESSAGE_IDLE_PERMISSION_REMOVED) {
+                            callback({
+                                permissions: ['idle']
+                            });
+                        }
+                    }
+                }
+            );
+        },
+        removeListener: function (callback) {
+            chrome.runtime.onMessage.removeListener(callback);
+        },
+        hasListener: function (callback) {
+            return chrome.runtime.onMessage.hasListener(callback);
+        }
+    }
 
-       COMPAT.PERMISSIONS_EVENTS = false;
+    COMPAT.PERMISSIONS_EVENTS = false;
 }
 
-if(typeof(chrome.storage.sync) === 'undefined')
-{
-       chrome.storage.sync = chrome.storage.local;
-       COMPAT.SYNC_STORAGE = false;
+if (typeof (chrome.storage.sync) === 'undefined') {
+    chrome.storage.sync = chrome.storage.local;
+    COMPAT.SYNC_STORAGE = false;
 }
diff --git a/extension/include/compat-content-script.js b/extension/include/compat-content-script.js
index f6870d2..448f55f 100644
--- a/extension/include/compat-content-script.js
+++ b/extension/include/compat-content-script.js
@@ -1,42 +1,38 @@
 // SPDX-License-Identifer: GPL-3.0-or-later
 
-if(!window.chrome)
-{
-       (function() {
-               // Define the API subset provided to the webpage
-               var externalMessaging = {
-                       runtime: {
-                               sendMessage: function (extensionId, message, options, responseCallback) {
-                                       if(extensionId !== chrome.runtime.id)
-                                       {
-                                               console.error('Wrong extension id provided.')
-                                               return;
-                                       }
+if (!window.chrome) {
+    (function () {
+        // Define the API subset provided to the webpage
+        var externalMessaging = {
+            runtime: {
+                sendMessage: function (extensionId, message, options, responseCallback) {
+                    if (extensionId !== chrome.runtime.id) {
+                        console.error('Wrong extension id provided.')
+                        return;
+                    }
 
-                                       if(typeof(options) === 'function')
-                                       {
-                                               responseCallback = options;
-                                               options = undefined;
-                                       }
+                    if (typeof (options) === 'function') {
+                        responseCallback = options;
+                        options = undefined;
+                    }
 
-                                       chrome.runtime.sendMessage(extensionId, message, options)
-                                               .then(result => {
-                                                       if(typeof(responseCallback) == 'function')
-                                                       {
-                                                               responseCallback(cloneInto(result, window));
-                                                       }
-                                               })
-                                               .catch(err => {
-                                                       console.error("firefox-external-messaging: 
runtime.sendMessage error", err);
-                                               });
-                               }
-                       }
-               };
+                    chrome.runtime.sendMessage(extensionId, message, options)
+                        .then(result => {
+                            if (typeof (responseCallback) == 'function') {
+                                responseCallback(cloneInto(result, window));
+                            }
+                        })
+                        .catch(err => {
+                            console.error("firefox-external-messaging: runtime.sendMessage error", err);
+                        });
+                }
+            }
+        };
 
-               // Inject the API in the webpage wrapped by this content script
-               // (exposed as `chrome.runtime.sendMessage({anyProp: "anyValue"}).then(reply => ..., err => 
...)`)
-               window.wrappedJSObject.chrome = cloneInto(externalMessaging, window, {
-                       cloneFunctions: true,
-               });
-       })();
+        // Inject the API in the webpage wrapped by this content script
+        // (exposed as `chrome.runtime.sendMessage({anyProp: "anyValue"}).then(reply => ..., err => ...)`)
+        window.wrappedJSObject.chrome = cloneInto(externalMessaging, window, {
+            cloneFunctions: true,
+        });
+    })();
 }
diff --git a/extension/include/constants.js b/extension/include/constants.js
index 87adf55..976a63b 100644
--- a/extension/include/constants.js
+++ b/extension/include/constants.js
@@ -1,73 +1,73 @@
 // SPDX-License-Identifer: GPL-3.0-or-later
 
-GS_CHROME_ID                           = chrome.runtime.id;
-PLATFORMS_WHITELIST                    = ["freebsd", "linux", "openbsd"];
+GS_CHROME_ID = chrome.runtime.id;
+PLATFORMS_WHITELIST = ["freebsd", "linux", "openbsd"];
 
 COMPAT = {
-       IS_FIREFOX:      CSS.supports("-moz-appearance: none"),
+    IS_FIREFOX: CSS.supports("-moz-appearance: none"),
 };
 
-NOTIFICATION_SYNC_FAILED               = 'gs-chrome-sync-fail';
-NOTIFICATION_UPDATE_AVAILABLE          = 'gs-chrome-update';
-ALARM_UPDATE_CHECK                     = 'gs-chrome-update-check';
+NOTIFICATION_SYNC_FAILED        = 'gs-chrome-sync-fail';
+NOTIFICATION_UPDATE_AVAILABLE   = 'gs-chrome-update';
+ALARM_UPDATE_CHECK              = 'gs-chrome-update-check';
 
-MESSAGE_NEXT_UPDATE_CHANGED            = 'gs-next-update-changed';
-MESSAGE_SYNC_FROM_REMOTE               = 'gs-sync-from-remote';
-MESSAGE_IDLE_PERMISSION_ADDED  = 'gs-idle-added';
-MESSAGE_IDLE_PERMISSION_REMOVED        = 'gs-idle-removed';
+MESSAGE_NEXT_UPDATE_CHANGED     = 'gs-next-update-changed';
+MESSAGE_SYNC_FROM_REMOTE        = 'gs-sync-from-remote';
+MESSAGE_IDLE_PERMISSION_ADDED   = 'gs-idle-added';
+MESSAGE_IDLE_PERMISSION_REMOVED = 'gs-idle-removed';
 
-SIGNAL_EXTENSION_CHANGED               = 'ExtensionStatusChanged';
-SIGNAL_NOTIFICATION_ACTION             = 'NotificationAction';
-SIGNAL_NOTIFICATION_CLICKED            = 'NotificationClicked';
-SIGNAL_SHELL_SETTING_CHANGED   = 'ShellSettingsChanged';
-SIGNAL_SHELL_APPEARED                  = 'org.gnome.Shell';
+SIGNAL_EXTENSION_CHANGED        = 'ExtensionStatusChanged';
+SIGNAL_NOTIFICATION_ACTION      = 'NotificationAction';
+SIGNAL_NOTIFICATION_CLICKED     = 'NotificationClicked';
+SIGNAL_SHELL_SETTING_CHANGED    = 'ShellSettingsChanged';
+SIGNAL_SHELL_APPEARED           = 'org.gnome.Shell';
 
-EXTENSION_CHANGED_UUID                 = 0;
-EXTENSION_CHANGED_STATE                        = 1;
-EXTENSION_CHANGED_ERROR                        = 2;
+EXTENSION_CHANGED_UUID          = 0;
+EXTENSION_CHANGED_STATE         = 1;
+EXTENSION_CHANGED_ERROR         = 2;
 
-NATIVE_HOST                            = 'org.gnome.chrome_gnome_shell';
+NATIVE_HOST = 'org.gnome.chrome_gnome_shell';
 
-EXTENSIONS_WEBSITE                     = [
-       'https://extensions.gnome.org/',
+EXTENSIONS_WEBSITE = [
+    'https://extensions.gnome.org/',
 ];
-UPDATE_URL                             = EXTENSIONS_WEBSITE + 'update-info/';
+UPDATE_URL = EXTENSIONS_WEBSITE + 'update-info/';
 
-DEFAULT_SYNC_OPTIONS                   = {
-       showReleaseNotes:       true,
-       updateCheck:            true,
-       updateCheckEnabledOnly: true,
-       updateCheckPeriod:      6
+DEFAULT_SYNC_OPTIONS = {
+    showReleaseNotes: true,
+    updateCheck: true,
+    updateCheckEnabledOnly: true,
+    updateCheckPeriod: 6
 };
 
-DEFAULT_LOCAL_OPTIONS                  = {
-       syncExtensions:         false,
-       useLightIcon:           false
+DEFAULT_LOCAL_OPTIONS = {
+    syncExtensions: false,
+    useLightIcon: false
 };
 
-EXTERNAL_MESSAGES                      = [
-       "error_connector_response",
-       "no_gnome_shell",
-       "no_host_connector",
-       "warning_apis_missing"
+EXTERNAL_MESSAGES = [
+    "error_connector_response",
+    "no_gnome_shell",
+    "no_host_connector",
+    "warning_apis_missing"
 ];
 
 // gnome-shell/js/ui/extensionSystem.js
-EXTENSION_STATE                        = {
-       ENABLED:        1,
-       DISABLED:       2,
-       ERROR:          3,
-       OUT_OF_DATE:    4,
-       DOWNLOADING:    5,
-       INITIALIZED:    6,
+EXTENSION_STATE = {
+    ENABLED:        1,
+    DISABLED:       2,
+    ERROR:          3,
+    OUT_OF_DATE:    4,
+    DOWNLOADING:    5,
+    INITIALIZED:    6,
 
-       // Used as an error state for operations on unknown extensions,
-       // should never be in a real extensionMeta object.
-       UNINSTALLED:    99
+    // Used as an error state for operations on unknown extensions,
+    // should never be in a real extensionMeta object.
+    UNINSTALLED:    99
 };
 
 // gnome-shell/js/misc/extensionUtils.js
-EXTENSION_TYPE                 = {
-    SYSTEM:            1,
-    PER_USER:  2
+EXTENSION_TYPE = {
+    SYSTEM:     1,
+    PER_USER:   2
 };
diff --git a/extension/include/gsc.js b/extension/include/gsc.js
index 7f52885..8e00907 100644
--- a/extension/include/gsc.js
+++ b/extension/include/gsc.js
@@ -1,140 +1,126 @@
 // SPDX-License-Identifer: GPL-3.0-or-later
 
-GSC = (function() {
-       var ready = new Promise(function(resolve, reject) {
-               chrome.runtime.getPlatformInfo(function(info) {
-                       if (PLATFORMS_WHITELIST.indexOf(info.os) === -1)
-                       {
-                               reject();
-                       }
-                       else
-                       {
-                               resolve();
-                       }
-               });
-       });
-       ready.catch(function() {});
-
-       var onInitialize = new Promise((resolve, reject) => {
-               sendNativeRequest({ execute: "initialize" }, (response) => {
-                       if(response && response.success)
-                       {
-                               resolve(response);
-                       }
-                       else
-                       {
-                               reject(response);
-                       }
-               });
-       });
-
-       function sendNativeRequest(request, sendResponse) {
-               ready.then(function () {
-                       if (sendResponse)
-                       {
-                               chrome.runtime.sendNativeMessage(
-                                       NATIVE_HOST,
-                                       request,
-                                       function (response) {
-                                               if (response)
-                                               {
-                                                       sendResponse(response);
-                                               }
-                                               else
-                                               {
-                                                       var message = m('no_host_connector');
-                                                       if (
-                                                               chrome.runtime.lastError &&
-                                                               chrome.runtime.lastError.message &&
-                                                               
chrome.runtime.lastError.message.indexOf("host not found") === -1 && // Chrome
-                                                               
chrome.runtime.lastError.message.indexOf("disconnected port") === -1 // Firefox
-                                                       )
-                                                       {
-                                                               // Some error occured. Show to user
-                                                               message = chrome.runtime.lastError.message;
-                                                       }
-
-                                                       sendResponse({
-                                                               success: false,
-                                                               message: message
-                                                       });
-                                               }
-                                       }
-                               );
-                       }
-                       else
-                       {
-                               chrome.runtime.sendNativeMessage(NATIVE_HOST, request);
-                       }
-               }, function () {
-                       if (sendResponse)
-                       {
-                               sendResponse({
-                                       success: false,
-                                       message: m('platform_not_supported')
-                               });
-                       }
-               });
-       }
-
-       function isSupported(feature, response) {
-               return response.properties &&
-                               response.properties.supports && response.properties.supports.indexOf(feature) 
!== -1;
-       }
-
-       return {
-               // https://wiki.gnome.org/Projects/GnomeShell/Extensions/UUIDGuidelines
-               isUUID: function(uuid) {
-                       return uuid && uuid.match('^[-a-zA-Z0-9@._]+$');
-               },
-
-               sendNativeRequest: sendNativeRequest,
-
-               isSignalsEqual: function(newSignal, oldSignal) {
-                       if(!oldSignal || !newSignal)
-                               return false;
-
-                       if(!newSignal.signal || !oldSignal.signal || newSignal.signal !== oldSignal.signal)
-                               return false;
-
-                       if(newSignal.parameters)
-                       {
-                               if(!oldSignal.parameters)
-                                       return false;
-
-                               if(newSignal.parameters.length !== oldSignal.parameters.length)
-                                       return false;
-
-                               for(var i = 0; i < newSignal.parameters.length; i++)
-                               {
-                                       if(newSignal.parameters[i] !== oldSignal.parameters[i])
-                                       {
-                                               return false;
-                                       }
-                               }
-                       }
-                       else if (oldSignal.parameters)
-                       {
-                               return false;
-                       }
-
-                       return true;
-               },
-
-               onInitialize: function() {
-                       return onInitialize;
-               },
-
-               nativeNotificationsSupported: function (response) {
-                       return isSupported('notifications', response);
-               },
-
-               nativeUpdateCheckSupported: function (response) {
-                       return isSupported('update-check', response);
-               },
-
-               nativeUpdateCheckEnabledOnlySupported: function (response) {
-                       return isSupported('update-enabled', response);
-               }
-       };
+GSC = (function () {
+    var ready = new Promise(function (resolve, reject) {
+        chrome.runtime.getPlatformInfo(function (info) {
+            if (PLATFORMS_WHITELIST.indexOf(info.os) === -1) {
+                reject();
+            }
+            else {
+                resolve();
+            }
+        });
+    });
+    ready.catch(function () { });
+
+    var onInitialize = new Promise((resolve, reject) => {
+        sendNativeRequest({ execute: "initialize" }, (response) => {
+            if (response && response.success) {
+                resolve(response);
+            }
+            else {
+                reject(response);
+            }
+        });
+    });
+
+    function sendNativeRequest(request, sendResponse) {
+        ready.then(function () {
+            if (sendResponse) {
+                chrome.runtime.sendNativeMessage(
+                    NATIVE_HOST,
+                    request,
+                    function (response) {
+                        if (response) {
+                            sendResponse(response);
+                        }
+                        else {
+                            var message = m('no_host_connector');
+                            if (
+                                chrome.runtime.lastError &&
+                                chrome.runtime.lastError.message &&
+                                chrome.runtime.lastError.message.indexOf("host not found") === -1 && // 
Chrome
+                                chrome.runtime.lastError.message.indexOf("disconnected port") === -1 // 
Firefox
+                            ) {
+                                // Some error occured. Show to user
+                                message = chrome.runtime.lastError.message;
+                            }
+
+                            sendResponse({
+                                success: false,
+                                message: message
+                            });
+                        }
+                    }
+                );
+            }
+            else {
+                chrome.runtime.sendNativeMessage(NATIVE_HOST, request);
+            }
+        }, function () {
+            if (sendResponse) {
+                sendResponse({
+                    success: false,
+                    message: m('platform_not_supported')
+                });
+            }
+        });
+    }
+
+    function isSupported(feature, response) {
+        return response.properties &&
+            response.properties.supports && response.properties.supports.indexOf(feature) !== -1;
+    }
+
+    return {
+        // https://wiki.gnome.org/Projects/GnomeShell/Extensions/UUIDGuidelines
+        isUUID: function (uuid) {
+            return uuid && uuid.match('^[-a-zA-Z0-9@._]+$');
+        },
+
+        sendNativeRequest: sendNativeRequest,
+
+        isSignalsEqual: function (newSignal, oldSignal) {
+            if (!oldSignal || !newSignal)
+                return false;
+
+            if (!newSignal.signal || !oldSignal.signal || newSignal.signal !== oldSignal.signal)
+                return false;
+
+            if (newSignal.parameters) {
+                if (!oldSignal.parameters)
+                    return false;
+
+                if (newSignal.parameters.length !== oldSignal.parameters.length)
+                    return false;
+
+                for (var i = 0; i < newSignal.parameters.length; i++) {
+                    if (newSignal.parameters[i] !== oldSignal.parameters[i]) {
+                        return false;
+                    }
+                }
+            }
+            else if (oldSignal.parameters) {
+                return false;
+            }
+
+            return true;
+        },
+
+        onInitialize: function () {
+            return onInitialize;
+        },
+
+        nativeNotificationsSupported: function (response) {
+            return isSupported('notifications', response);
+        },
+
+        nativeUpdateCheckSupported: function (response) {
+            return isSupported('update-check', response);
+        },
+
+        nativeUpdateCheckEnabledOnlySupported: function (response) {
+            return isSupported('update-enabled', response);
+        }
+    };
 })();
diff --git a/extension/include/i18n.js b/extension/include/i18n.js
index ba9ac4a..b32fbd3 100644
--- a/extension/include/i18n.js
+++ b/extension/include/i18n.js
@@ -2,31 +2,26 @@
 
 m = chrome.i18n.getMessage;
 i18n = (() => {
-       $$('[data-i18n]').forEach((element) => {
-               let data = element.dataset.i18n.split(',').map((value) => {
-                       value = value.trim();
+    $$('[data-i18n]').forEach((element) => {
+        let data = element.dataset.i18n.split(',').map((value) => {
+            value = value.trim();
 
-                       if(value.startsWith('__MSG_'))
-                       {
-                               return value.replace(/__MSG_(\w+)__/g, function(match, key)
-                               {
-                                       return key ? m(key) : "";
-                               });
-                       }
+            if (value.startsWith('__MSG_')) {
+                return value.replace(/__MSG_(\w+)__/g, function (match, key) {
+                    return key ? m(key) : "";
+                });
+            }
 
-                       return value;
-               });
+            return value;
+        });
 
-               if(data)
-               {
-                       if(element.dataset.i18nHtml)
-                       {
-                               element.innerHtml = m(data[0], data.slice(1));
-                       }
-                       else
-                       {
-                               element.innerText = m(data[0], data.slice(1));
-                       }
-               }
-       });
+        if (data) {
+            if (element.dataset.i18nHtml) {
+                element.innerHtml = m(data[0], data.slice(1));
+            }
+            else {
+                element.innerText = m(data[0], data.slice(1));
+            }
+        }
+    });
 });
diff --git a/extension/include/notifications.js b/extension/include/notifications.js
index d2631cc..05fb445 100644
--- a/extension/include/notifications.js
+++ b/extension/include/notifications.js
@@ -1,210 +1,192 @@
 // SPDX-License-Identifer: GPL-3.0-or-later
 
-GSC.notifications = (function() {
-       var DEFAULT_NOTIFICATION_OPTIONS = {
-               type: chrome.notifications.TemplateType.BASIC,
-               iconUrl: 'icons/GnomeLogo-128.png',
-               title: m('gs_chrome'),
-               buttons: [
-                       {title: m('close')}
-               ],
-               priority: 2,
-               isClickable: true,
-               requireInteraction: true
-       };
-
-       function remove_list(options) {
-               if(options.items)
-               {
-                       var items = [];
-                       for (k in options.items)
-                       {
-                               if (options.items.hasOwnProperty(k))
-                               {
-                                       items.push(options.items[k].title + ' ' + options.items[k].message);
-                               }
-                       }
-
-                       if(options.message && items)
-                       {
-                               options.message += "\n";
-                       }
-
-                       options.message += items.join("\n");
-
-                       options.type = chrome.notifications.TemplateType.BASIC;
-                       delete options.items;
-               }
-
-               return options;
-       }
-
-       /*
-               @Deprecated: remove browser notifications in version 9
-        */
-       var browser = (function() {
-               function init() {
-                       chrome.runtime.onStartup.addListener(function() {
-                               // Do nothing. We just need this callback to restore notifications
-                       });
-
-                       chrome.notifications.onClosed.addListener(function (notificationId, byUser) {
-                               if (!byUser)
-                               {
-                                       update(notificationId);
-                               }
-                               else
-                               {
-                                       remove(notificationId);
-                               }
-                       });
-
-                       chrome.notifications.onClicked.addListener(function (notificationId) {
-                               GSC.notifications.remove(notificationId);
-                       });
-
-                       restore();
-               }
-
-               function create(name, options) {
-                       chrome.storage.local.get({
-                               notifications: {}
-                       }, function (items) {
-                               var notifications = items.notifications;
-
-                               notifications[name] = {...DEFAULT_NOTIFICATION_OPTIONS, ...options};
-
-                               _create(name, notifications[name], function (notificationId) {
-                                       chrome.storage.local.set({
-                                               notifications: notifications
-                                       });
-                               });
-                       });
-               }
-
-               function _create(name, options, callback)
-               {
-                       if(!COMPAT.NOTIFICATIONS_BUTTONS && options.buttons)
-                       {
-                               delete options.buttons;
-                       }
-
-                       if (callback)
-                       {
-                               chrome.notifications.create(name, options, callback);
-                       }
-                       else
-                       {
-                               chrome.notifications.create(name, options);
-                       }
-               }
-
-               function update(notificationId) {
-                       chrome.storage.local.get({
-                               notifications: {}
-                       }, function (items) {
-                               var notifications = items.notifications;
-
-                               if (notifications[notificationId])
-                               {
-                                       _create(notificationId, notifications[notificationId]);
-                               }
-                       });
-               }
-
-               function remove(notificationId) {
-                       chrome.storage.local.get({
-                               notifications: {}
-                       }, function (items) {
-                               var notifications = items.notifications;
-
-                               if (notifications[notificationId])
-                               {
-                                       delete notifications[notificationId];
-                                       chrome.storage.local.set({
-                                               notifications: notifications
-                                       });
-                               }
-
-                               chrome.notifications.clear(notificationId);
-                       });
-               }
-
-               function restore() {
-                       chrome.storage.local.get({
-                               notifications: {}
-                       }, function (items) {
-                               var notifications = items.notifications;
-
-                               for (notificationId in notifications)
-                               {
-                                       update(notificationId);
-                               }
-                       });
-               }
-
-               return {
-                       create: create,
-                       remove: remove,
-                       init: init
-               };
-       })();
-
-       var native = (function() {
-               function create(name, options) {
-                       options = remove_list(options);
-
-                       window.postMessage({
-                               execute: 'createNotification',
-                               name: name,
-                               options: {...DEFAULT_NOTIFICATION_OPTIONS, ...options}
-                       }, "*");
-               }
-
-               function remove(notificationId) {
-                       chrome.runtime.sendMessage({
-                               execute: 'removeNotification',
-                               name: notificationId
-                       });
-               }
-
-               return {
-                       create: create,
-                       remove: remove
-               };
-       })();
-
-       GSC.onInitialize().then(response => {
-               if (!GSC.nativeNotificationsSupported(response))
-               {
-                       browser.init();
-               }
-       });
-
-       return {
-               create: function() {
-                       GSC.onInitialize().then(response => {
-                               if(GSC.nativeNotificationsSupported(response))
-                               {
-                                       native.create.apply(this, arguments);
-                               }
-                               else
-                               {
-                                       browser.create.apply(this, arguments);
-                               }
-                       });
-               },
-               remove: function() {
-                       GSC.onInitialize().then(response => {
-                               if(GSC.nativeNotificationsSupported(response))
-                               {
-                                       native.remove.apply(this, arguments);
-                               }
-                               else
-                               {
-                                       browser.remove.apply(this, arguments);
-                               }
-                       });
-               }
-       };
+GSC.notifications = (function () {
+    var DEFAULT_NOTIFICATION_OPTIONS = {
+        type: chrome.notifications.TemplateType.BASIC,
+        iconUrl: 'icons/GnomeLogo-128.png',
+        title: m('gs_chrome'),
+        buttons: [
+            { title: m('close') }
+        ],
+        priority: 2,
+        isClickable: true,
+        requireInteraction: true
+    };
+
+    function remove_list(options) {
+        if (options.items) {
+            var items = [];
+            for (k in options.items) {
+                if (options.items.hasOwnProperty(k)) {
+                    items.push(options.items[k].title + ' ' + options.items[k].message);
+                }
+            }
+
+            if (options.message && items) {
+                options.message += "\n";
+            }
+
+            options.message += items.join("\n");
+
+            options.type = chrome.notifications.TemplateType.BASIC;
+            delete options.items;
+        }
+
+        return options;
+    }
+
+    /*
+        @Deprecated: remove browser notifications in version 9
+     */
+    var browser = (function () {
+        function init() {
+            chrome.runtime.onStartup.addListener(function () {
+                // Do nothing. We just need this callback to restore notifications
+            });
+
+            chrome.notifications.onClosed.addListener(function (notificationId, byUser) {
+                if (!byUser) {
+                    update(notificationId);
+                }
+                else {
+                    remove(notificationId);
+                }
+            });
+
+            chrome.notifications.onClicked.addListener(function (notificationId) {
+                GSC.notifications.remove(notificationId);
+            });
+
+            restore();
+        }
+
+        function create(name, options) {
+            chrome.storage.local.get({
+                notifications: {}
+            }, function (items) {
+                var notifications = items.notifications;
+
+                notifications[name] = { ...DEFAULT_NOTIFICATION_OPTIONS, ...options };
+
+                _create(name, notifications[name], function (notificationId) {
+                    chrome.storage.local.set({
+                        notifications: notifications
+                    });
+                });
+            });
+        }
+
+        function _create(name, options, callback) {
+            if (!COMPAT.NOTIFICATIONS_BUTTONS && options.buttons) {
+                delete options.buttons;
+            }
+
+            if (callback) {
+                chrome.notifications.create(name, options, callback);
+            }
+            else {
+                chrome.notifications.create(name, options);
+            }
+        }
+
+        function update(notificationId) {
+            chrome.storage.local.get({
+                notifications: {}
+            }, function (items) {
+                var notifications = items.notifications;
+
+                if (notifications[notificationId]) {
+                    _create(notificationId, notifications[notificationId]);
+                }
+            });
+        }
+
+        function remove(notificationId) {
+            chrome.storage.local.get({
+                notifications: {}
+            }, function (items) {
+                var notifications = items.notifications;
+
+                if (notifications[notificationId]) {
+                    delete notifications[notificationId];
+                    chrome.storage.local.set({
+                        notifications: notifications
+                    });
+                }
+
+                chrome.notifications.clear(notificationId);
+            });
+        }
+
+        function restore() {
+            chrome.storage.local.get({
+                notifications: {}
+            }, function (items) {
+                var notifications = items.notifications;
+
+                for (notificationId in notifications) {
+                    update(notificationId);
+                }
+            });
+        }
+
+        return {
+            create: create,
+            remove: remove,
+            init: init
+        };
+    })();
+
+    var native = (function () {
+        function create(name, options) {
+            options = remove_list(options);
+
+            window.postMessage({
+                execute: 'createNotification',
+                name: name,
+                options: { ...DEFAULT_NOTIFICATION_OPTIONS, ...options }
+            }, "*");
+        }
+
+        function remove(notificationId) {
+            chrome.runtime.sendMessage({
+                execute: 'removeNotification',
+                name: notificationId
+            });
+        }
+
+        return {
+            create: create,
+            remove: remove
+        };
+    })();
+
+    GSC.onInitialize().then(response => {
+        if (!GSC.nativeNotificationsSupported(response)) {
+            browser.init();
+        }
+    });
+
+    return {
+        create: function () {
+            GSC.onInitialize().then(response => {
+                if (GSC.nativeNotificationsSupported(response)) {
+                    native.create.apply(this, arguments);
+                }
+                else {
+                    browser.create.apply(this, arguments);
+                }
+            });
+        },
+        remove: function () {
+            GSC.onInitialize().then(response => {
+                if (GSC.nativeNotificationsSupported(response)) {
+                    native.remove.apply(this, arguments);
+                }
+                else {
+                    browser.remove.apply(this, arguments);
+                }
+            });
+        }
+    };
 })();
diff --git a/extension/include/sweettooth-api.js b/extension/include/sweettooth-api.js
index 1929d00..b7c197e 100644
--- a/extension/include/sweettooth-api.js
+++ b/extension/include/sweettooth-api.js
@@ -3,220 +3,197 @@
 "use strict";
 
 GSC.getMessage = function (key) {
-       if (GSC && GSC.i18n && GSC.i18n[key])
-       {
-               var message = GSC.i18n[key];
+    if (GSC && GSC.i18n && GSC.i18n[key]) {
+        var message = GSC.i18n[key];
 
-               for (var i = 1; i < arguments.length; i++)
-               {
-                       message = message.replace('$' + i, arguments[i]);
-               }
+        for (var i = 1; i < arguments.length; i++) {
+            message = message.replace('$' + i, arguments[i]);
+        }
 
-               return message;
-       }
+        return message;
+    }
 
-       return key;
+    return key;
 };
 
 window.SweetTooth = function () {
-       var apiObject = {
-               apiVersion: 5,
-               shellVersion: '-1',
-               versionValidationEnabled: true,
-               userExtensionsDisabled: false,
-
-               getChromeExtensionId: function () {
-                       return GS_CHROME_ID;
-               },
-
-               getExtensionErrors: function (uuid) {
-                       return sendResolveExtensionMessage("getExtensionErrors", "extensionErrors", {uuid: 
uuid});
-               },
-
-               getExtensionInfo: function (uuid) {
-                       return sendResolveExtensionMessage("getExtensionInfo", "extensionInfo", {uuid: uuid});
-               },
-
-               installExtension: function (uuid) {
-                       return sendResolveExtensionMessage("installExtension", "status", {uuid: uuid});
-               },
-
-               launchExtensionPrefs: function (uuid) {
-                       sendExtensionMessage("launchExtensionPrefs", null, {uuid: uuid});
-               },
-
-               listExtensions: function () {
-                       return sendResolveExtensionMessage("listExtensions", "extensions");
-               },
-
-               setExtensionEnabled: function (uuid, enable) {
-                       return sendResolveExtensionMessage("enableExtension", "success", {uuid: uuid, enable: 
enable});
-               },
-
-               uninstallExtension: function (uuid) {
-                       return sendResolveExtensionMessage("uninstallExtension", "status", {uuid: uuid});
-               },
-
-               setUserExtensionsDisabled: function (disable) {
-                       return sendResolveExtensionMessage("setUserExtensionsDisabled", "success", {disable: 
disable})
-                               .then(success => {
-                                       if(success)
-                                       {
-                                               apiObject.userExtensionsDisabled = disable;
-                                       }
-
-                                       return success;
-                               });
-               },
-
-               setVersionValidationDisabled: function (disable) {
-                       return sendResolveExtensionMessage("setVersionValidationDisabled", "success", 
{disable: disable})
-                               .then(success => {
-                                       if(success)
-                                       {
-                                               apiObject.versionValidationEnabled = !disable;
-                                       }
-
-                                       return success;
-                               });
-               },
-
-               initialize: function () {
-                       if (SweetTooth.shellVersion !== '-1')
-                       {
-                               return Promise.resolve(apiObject);
-                       }
-
-                       var ready = new Promise(function(resolve, reject) {
-                               sendExtensionMessage("initialize", response => {
-                                       if (response && response.success && response.properties && 
response.properties.shellVersion)
-                                       {
-                                               resolve(response.properties);
-                                       }
-                                       else
-                                       {
-                                               var message = response && response.message ? 
GSC.getMessage(response.message) : GSC.getMessage('error_connector_response');
-                                               reject(message);
-                                       }
-                               });
-                       });
-
-                       ready.then(function (response) {
-                               apiObject.shellVersion = response.shellVersion;
-                               apiObject.versionValidationEnabled = response.versionValidationEnabled;
-                               apiObject.userExtensionsDisabled = response.userExtensionsDisabled;
-
-                               let REQUIRED_APIS = [
-                                       "notifications",
-                                       "v6"
-                               ];
-
-                               if(response.supports)
-                               {
-                                       for(let api of response.supports)
-                                       {
-                                               let api_index;
-                                               if((api_index = REQUIRED_APIS.indexOf(api)) != -1)
-                                               {
-                                                       REQUIRED_APIS.splice(api_index, 1);
-                                               }
-
-                                               if(api === 'v6')
-                                               {
-                                                       apiObject.apiVersion = 6;
-                                               }
-                                       }
-                               }
-
-                               if (REQUIRED_APIS.length > 0)
-                               {
-                                       require(['messages'], function (messages) {
-                                               messages.addWarning(GSC.getMessage('warning_apis_missing', 
REQUIRED_APIS.join(", ")));
-                                       });
-                               }
-                       }, function (message) {
-                               apiObject.apiVersion = null;
-
-                               require(['messages'], function (messages) {
-                                       messages.addError(message ? message : 
GSC.getMessage('no_host_connector'));
-                               })
-                       });
-
-                       return ready;
-               }
-       };
-
-       window.addEventListener("message", function (event) {
-               // We only accept messages from ourselves
-               if (event.source != window)
-               {
-                       return;
-               }
-
-               if (event.data.type)
-               {
-                       if (event.data.type == "gs-chrome")
-                       {
-                               if (event.data.request.signal == 'ExtensionStatusChanged' && 
apiObject.onchange)
-                               {
-                                       apiObject.onchange(
-                                               event.data.request.parameters[0],
-                                               event.data.request.parameters[1],
-                                               event.data.request.parameters[2]
-                                       );
-                               }
-                               else if (event.data.request.signal == 'org.gnome.Shell' && 
apiObject.onshellrestart)
-                               {
-                                       apiObject.onshellrestart();
-                               }
-                               else if (event.data.request.signal == 'ShellSettingsChanged' && 
apiObject.onShellSettingChanged)
-                               {
-                                       if(event.data.request.key === 'disable-user-extensions')
-                                       {
-                                               apiObject.userExtensionsDisabled = event.data.request.value;
-                                       }
-                                       else if(event.data.request.key === 
'disable-extension-version-validation')
-                                       {
-                                               apiObject.versionValidationEnabled = 
!event.data.request.value;
-                                       }
-
-                                       apiObject.onShellSettingChanged(event.data.request.key, 
event.data.request.value);
-                               }
-                       }
-               }
-       }, false);
-
-       function sendResolveExtensionMessage(method, resolveProperty, parameters) {
-               return new Promise(function (resolve, reject) {
-                       sendExtensionMessage(method, function (response) {
-                                       if (response && response.success)
-                                       {
-                                               resolve(response[resolveProperty]);
-                                       }
-                                       else
-                                       {
-                                               var message = response && response.message ? response.message 
: GSC.getMessage('error_connector_response');
-                                               reject(message);
-                                       }
-                               },
-                               parameters
-                       );
-               });
-       }
-
-       function sendExtensionMessage(method, callback, parameters) {
-               var request = {execute: method};
-               if (parameters)
-               {
-                       request = Object.assign(parameters, request);
-               }
-
-               chrome.runtime.sendMessage(
-                       apiObject.getChromeExtensionId(),
-                       request,
-                       callback
-               );
-       }
-
-       return apiObject;
+    var apiObject = {
+        apiVersion: 5,
+        shellVersion: '-1',
+        versionValidationEnabled: true,
+        userExtensionsDisabled: false,
+
+        getChromeExtensionId: function () {
+            return GS_CHROME_ID;
+        },
+
+        getExtensionErrors: function (uuid) {
+            return sendResolveExtensionMessage("getExtensionErrors", "extensionErrors", { uuid: uuid });
+        },
+
+        getExtensionInfo: function (uuid) {
+            return sendResolveExtensionMessage("getExtensionInfo", "extensionInfo", { uuid: uuid });
+        },
+
+        installExtension: function (uuid) {
+            return sendResolveExtensionMessage("installExtension", "status", { uuid: uuid });
+        },
+
+        launchExtensionPrefs: function (uuid) {
+            sendExtensionMessage("launchExtensionPrefs", null, { uuid: uuid });
+        },
+
+        listExtensions: function () {
+            return sendResolveExtensionMessage("listExtensions", "extensions");
+        },
+
+        setExtensionEnabled: function (uuid, enable) {
+            return sendResolveExtensionMessage("enableExtension", "success", { uuid: uuid, enable: enable });
+        },
+
+        uninstallExtension: function (uuid) {
+            return sendResolveExtensionMessage("uninstallExtension", "status", { uuid: uuid });
+        },
+
+        setUserExtensionsDisabled: function (disable) {
+            return sendResolveExtensionMessage("setUserExtensionsDisabled", "success", { disable: disable })
+                .then(success => {
+                    if (success) {
+                        apiObject.userExtensionsDisabled = disable;
+                    }
+
+                    return success;
+                });
+        },
+
+        setVersionValidationDisabled: function (disable) {
+            return sendResolveExtensionMessage("setVersionValidationDisabled", "success", { disable: disable 
})
+                .then(success => {
+                    if (success) {
+                        apiObject.versionValidationEnabled = !disable;
+                    }
+
+                    return success;
+                });
+        },
+
+        initialize: function () {
+            if (SweetTooth.shellVersion !== '-1') {
+                return Promise.resolve(apiObject);
+            }
+
+            var ready = new Promise(function (resolve, reject) {
+                sendExtensionMessage("initialize", response => {
+                    if (response && response.success && response.properties && 
response.properties.shellVersion) {
+                        resolve(response.properties);
+                    }
+                    else {
+                        var message = response && response.message ? GSC.getMessage(response.message) : 
GSC.getMessage('error_connector_response');
+                        reject(message);
+                    }
+                });
+            });
+
+            ready.then(function (response) {
+                apiObject.shellVersion = response.shellVersion;
+                apiObject.versionValidationEnabled = response.versionValidationEnabled;
+                apiObject.userExtensionsDisabled = response.userExtensionsDisabled;
+
+                let REQUIRED_APIS = [
+                    "notifications",
+                    "v6"
+                ];
+
+                if (response.supports) {
+                    for (let api of response.supports) {
+                        let api_index;
+                        if ((api_index = REQUIRED_APIS.indexOf(api)) != -1) {
+                            REQUIRED_APIS.splice(api_index, 1);
+                        }
+
+                        if (api === 'v6') {
+                            apiObject.apiVersion = 6;
+                        }
+                    }
+                }
+
+                if (REQUIRED_APIS.length > 0) {
+                    require(['messages'], function (messages) {
+                        messages.addWarning(GSC.getMessage('warning_apis_missing', REQUIRED_APIS.join(", 
")));
+                    });
+                }
+            }, function (message) {
+                apiObject.apiVersion = null;
+
+                require(['messages'], function (messages) {
+                    messages.addError(message ? message : GSC.getMessage('no_host_connector'));
+                })
+            });
+
+            return ready;
+        }
+    };
+
+    window.addEventListener("message", function (event) {
+        // We only accept messages from ourselves
+        if (event.source != window) {
+            return;
+        }
+
+        if (event.data.type) {
+            if (event.data.type == "gs-chrome") {
+                if (event.data.request.signal == 'ExtensionStatusChanged' && apiObject.onchange) {
+                    apiObject.onchange(
+                        event.data.request.parameters[0],
+                        event.data.request.parameters[1],
+                        event.data.request.parameters[2]
+                    );
+                }
+                else if (event.data.request.signal == 'org.gnome.Shell' && apiObject.onshellrestart) {
+                    apiObject.onshellrestart();
+                }
+                else if (event.data.request.signal == 'ShellSettingsChanged' && 
apiObject.onShellSettingChanged) {
+                    if (event.data.request.key === 'disable-user-extensions') {
+                        apiObject.userExtensionsDisabled = event.data.request.value;
+                    }
+                    else if (event.data.request.key === 'disable-extension-version-validation') {
+                        apiObject.versionValidationEnabled = !event.data.request.value;
+                    }
+
+                    apiObject.onShellSettingChanged(event.data.request.key, event.data.request.value);
+                }
+            }
+        }
+    }, false);
+
+    function sendResolveExtensionMessage(method, resolveProperty, parameters) {
+        return new Promise(function (resolve, reject) {
+            sendExtensionMessage(method, function (response) {
+                if (response && response.success) {
+                    resolve(response[resolveProperty]);
+                }
+                else {
+                    var message = response && response.message ? response.message : 
GSC.getMessage('error_connector_response');
+                    reject(message);
+                }
+            },
+                parameters
+            );
+        });
+    }
+
+    function sendExtensionMessage(method, callback, parameters) {
+        var request = { execute: method };
+        if (parameters) {
+            request = Object.assign(parameters, request);
+        }
+
+        chrome.runtime.sendMessage(
+            apiObject.getChromeExtensionId(),
+            request,
+            callback
+        );
+    }
+
+    return apiObject;
 }();
diff --git a/extension/include/sync.js b/extension/include/sync.js
index 37ff0f5..dc390f9 100644
--- a/extension/include/sync.js
+++ b/extension/include/sync.js
@@ -3,445 +3,395 @@
 /*
  * Main object that handles extensions synchronization with remote storage.
  */
-GSC.sync = (function($) {
-       var enabled = true;
-       var extensionChangedTimeout = false;
-       var extensionChangedQueue = {};
-
-       const SYNC_QUEUE_TIMEOUT = 7000;
-
-       /*
-        * Initialization rutines.
-        */
-       function init() {
-               if(!COMPAT.SYNC_STORAGE)
-               {
-                       enabled = false;
-                       return;
-               }
-
-               function onIdleStateChanged(state) {
-                       if (state === 'locked')
-                       {
-                               enabled = false;
-
-                               // Remove all disabled extensions from queue
-                               for (const [extensionId, extension] of Object.entries(extensionChangedQueue)) 
{
-                                       if(extension.state == EXTENSION_STATE.DISABLED)
-                                       {
-                                               delete extensionChangedQueue[extensionId];
-                                       }
-                               };
-                       }
-                       else if (state === 'active')
-                       {
-                               enabled = true;
-                       }
-               }
-
-               chrome.permissions.contains({
-                       permissions: ["idle"]
-               }, function (result) {
-                       if(result)
-                       {
-                               chrome.idle.onStateChanged.addListener(onIdleStateChanged);
-                       }
-                       else
-                       {
-                               enabled = false;
-                       }
-               });
-
-               chrome.permissions.onAdded.addListener(function(permissions) {
-                       if(permissions.permissions && permissions.permissions.indexOf('idle') !== -1)
-                       {
-                               enabled = true;
-                               chrome.idle.onStateChanged.addListener(onIdleStateChanged);
-                       }
-               });
-
-               chrome.permissions.onRemoved.addListener(function(permissions) {
-                       if(permissions.permissions && permissions.permissions.indexOf('idle') !== -1)
-                       {
-                               enabled = false;
-                               chrome.idle.onStateChanged.removeListener(onIdleStateChanged);
-                       }
-               });
-
-               function onNotificationAction(notificationId, buttonIndex) {
-                       if (notificationId !== NOTIFICATION_SYNC_FAILED)
-                       {
-                               return;
-                       }
-
-                       GSC.notifications.remove(notificationId);
-               }
-
-               onSyncFromRemote();
-               chrome.storage.onChanged.addListener(function(changes, areaName) {
-                       if(areaName === 'sync' && changes.extensions)
-                       {
-                               onSyncFromRemote(changes.extensions.newValue);
-                       }
-               });
-
-               chrome.runtime.onMessage.addListener(
-                       function (request, sender, sendResponse) {
-                               if (sender.id && sender.id === GS_CHROME_ID && request)
-                               {
-                                       if (request === MESSAGE_SYNC_FROM_REMOTE)
-                                       {
-                                               onSyncFromRemote();
-                                       }
-                               }
-                       }
-               );
-
-               GSC.onInitialize().then(response => {
-                       /*
-                               @Deprecated: remove browser notifications in version 9
-                        */
-                       if (!GSC.nativeNotificationsSupported(response))
-                       {
-                               chrome.notifications.onButtonClicked.addListener(onNotificationAction);
-                       }
-                       else
-                       {
-                               chrome.runtime.onMessage.addListener(
-                                       function (request, sender, sendResponse) {
-                                               if(
-                                                       sender.id && sender.id === GS_CHROME_ID &&
-                                                       request && request.signal)
-                                               {
-                                                       if(request.signal == SIGNAL_NOTIFICATION_ACTION)
-                                                       {
-                                                               onNotificationAction(request.name, 
request.button_id);
-                                                       }
-                                               }
-                                       }
-                               );
-                       }
-               });
-       }
-
-       /*
-        * Returns array of all local and remote extensions with structure:
-        * [
-        *      $extension_uuid: {
-        *              uuid:           extension uuid,
-        *              name:           extension name,
-        *              remoteState:    extension state in remote storage,
-        *              localState:     extension state in current GNOME Shell,
-        *              remote:         true if extensions is in remote storage,
-        *              local:          true if extension installed localy
-        *      },
-        *      ...
-        * ]
-        */
-       function getExtensions(remoteExtensions) {
-               return new Promise((resolve, reject) => {
-                       GSC.sendNativeRequest({
-                               execute: 'listExtensions'
-                       }, function(response) {
-                               if(response && response.success)
-                               {
-                                       if(remoteExtensions)
-                                       {
-                                               resolve(mergeExtensions(remoteExtensions, 
response.extensions));
-                                       }
-                                       else
-                                       {
-                                               chrome.storage.sync.get({
-                                                       extensions: {}
-                                               }, function(options) {
-                                                       if(chrome.runtime.lastError)
-                                                       {
-                                                               reject(chrome.runtime.lastError.message);
-                                                       }
-                                                       else
-                                                       {
-                                                               resolve(mergeExtensions(options.extensions, 
response.extensions));
-                                                       }
-                                               });
-                                       }
-                               }
-                               else
-                               {
-                                       var message = response && response.message ? response.message : 
m('error_connector_response');
-                                       reject(message);
-                               }
-                       });
-               });
-       }
-
-       /*
-        * Returns merged list of extensions list in remote storage and
-        * locally installed extensions.
-        * 
-        * Both parameters should be in form:
-        * {
-        *      $extension_uuid: {
-        *              uuid:   ,
-        *              name:   ,
-        *              state:  
-        *      },
-        *      ...
-        * }
-        */
-       function mergeExtensions(remoteExtensions, localExtensions)
-       {
-               var extensions = {};
-
-               for (const [key, extension] of Object.entries(remoteExtensions)) {
-                       if(extension.uuid && extension.name && extension.state)
-                       {
-                               extensions[extension.uuid] = {
-                                       uuid:           extension.uuid,
-                                       name:           extension.name,
-                                       remoteState:    extension.state,
-                                       remote:         true,
-                                       local:          false
-                               };
-                       }
-               };
-
-               for (const [key, extension] of Object.entries(localExtensions)) {
-                       if(extensions[extension.uuid])
-                       {
-                               extensions[extension.uuid].name = extension.name;
-                               extensions[extension.uuid].localState = extension.state;
-                               extensions[extension.uuid].local = true;
-                       }
-                       else
-                       {
-                               extensions[extension.uuid] = {
-                                       uuid:           extension.uuid,
-                                       name:           extension.name,
-                                       remoteState:    EXTENSION_STATE.UNINSTALLED,
-                                       localState:     extension.state,
-                                       remote:         false,
-                                       local:          true
-                               };
-                       }
-               };
-
-               return extensions;
-       }
-
-       /*
-        * Synchronize local changed extensions to remote list.
-        */
-       function localExtensionsChanged() {
-               extensionChangedTimeout = false;
-
-               if (!isEmptyObject(extensionChangedQueue))
-               {
-                       GSC.sendNativeRequest({
-                               execute: 'listExtensions'
-                       }, function (response) {
-                               if (response && response.success && response.extensions)
-                               {
-                                       chrome.storage.sync.get({
-                                               extensions: {}
-                                       }, function (options) {
-                                               for (const [extensionId, extension] of 
Object.entries(extensionChangedQueue)) {
-                                                       if ([EXTENSION_STATE.ENABLED, 
EXTENSION_STATE.DISABLED, EXTENSION_STATE.UNINSTALLED].includes(extension.state))
-                                                       {
-                                                               // Extension can be uninstalled already
-                                                               if (response.extensions[extensionId] && 
!isEmptyObject(response.extensions[extensionId]))
-                                                               {
-                                                                       extension = 
response.extensions[extensionId];
-                                                               }
-
-                                                               if (extension.state === 
EXTENSION_STATE.UNINSTALLED && options.extensions[extension.uuid])
-                                                               {
-                                                                       delete 
options.extensions[extension.uuid];
-                                                               }
-                                                               else
-                                                               {
-                                                                       options.extensions[extension.uuid] = {
-                                                                               uuid: extension.uuid,
-                                                                               name: extension.name,
-                                                                               state: extension.state
-                                                                       };
-                                                               }
-                                                       }
-                                               };
-
-                                               chrome.storage.sync.set({
-                                                       extensions: options.extensions
-                                               });
-
-                                               extensionChangedQueue = {};
-                                       });
-                               }
-                               else
-                               {
-                                       createSyncFailedNotification();
-                               }
-                       });
-               }
-       }
-
-       /*
-        * Synchronize remote changes with local GNOME Shell.
-        * 
-        * @param remoteExtensions - (optional) remote extensions list
-        */
-       function remoteExtensionsChanged(remoteExtensions) {
-               getExtensions(remoteExtensions).then((extensions) => {
-                       var enableExtensions = [];
-                       for ([uuid, extension] of Object.entries(extensions)) {
-                               if(extension.remote)
-                               {
-                                       if(!extension.local)
-                                       {
-                                               GSC.sendNativeRequest({
-                                                       execute: "installExtension",
-                                                       uuid: extension.uuid
-                                               }, onInstallUninstall);
-                                       }
-                                       else if (extension.remoteState !== extension.localState)
-                                       {
-                                               if(extension.remoteState === EXTENSION_STATE.ENABLED)
-                                               {
-                                                       enableExtensions.push({
-                                                               uuid: extension.uuid,
-                                                               enable: true
-                                                       });
-                                               }
-                                               else
-                                               {
-                                                       enableExtensions.push({
-                                                               uuid: extension.uuid,
-                                                               enable: false
-                                                       });
-                                               }
-                                       }
-                               }
-                               else if(extension.local)
-                               {
-                                       GSC.sendNativeRequest({
-                                               execute: "uninstallExtension",
-                                               uuid: extension.uuid
-                                       }, onInstallUninstall);
-                               }
-                       };
-
-                       if(enableExtensions.length > 0)
-                       {
-                               GSC.sendNativeRequest({
-                                       execute: "enableExtension",
-                                       extensions: enableExtensions
-                               });
-                       }
-               }).catch((message) => {
-                       createSyncFailedNotification(message);
-               });
-       }
-
-       /*
-        * Callback called when extension is installed or uninstalled as part
-        * of synchronization process.
-        */
-       function onInstallUninstall(response) {
-               if(response)
-               {
-                       if(!response.success)
-                       {
-                               createSyncFailedNotification(response.message);
-                       }
-               }
-               else
-               {
-                       createSyncFailedNotification();
-               }
-       }
-
-       /*
-        * Wrapper for localExtensionChanged that checks if synchronization is
-        * enabled.
-        */
-       function onExtensionChanged(request)
-       {
-               if(!COMPAT.SYNC_STORAGE || !enabled)
-               {
-                       return;
-               }
-
-               runIfSyncEnabled(() => {
-                       if (extensionChangedTimeout)
-                       {
-                               clearTimeout(extensionChangedTimeout);
-                       }
-
-                       extensionChangedQueue[request.parameters[EXTENSION_CHANGED_UUID]] = {
-                               uuid: request.parameters[EXTENSION_CHANGED_UUID],
-                               state: request.parameters[EXTENSION_CHANGED_STATE],
-                               error: request.parameters[EXTENSION_CHANGED_ERROR]
-                       };
-
-                       extensionChangedTimeout = setTimeout(function () {
-                               localExtensionsChanged();
-                       }, SYNC_QUEUE_TIMEOUT);
-               });
-       }
-
-       /*
-        * Wrapper for remoteExtensionsChanged that checks if synchronization is
-        * enabled.
-        */
-       function onSyncFromRemote(remoteExtensions)
-       {
-               if(!COMPAT.SYNC_STORAGE)
-               {
-                       return;
-               }
-
-               runIfSyncEnabled(function() {
-                       remoteExtensionsChanged(remoteExtensions);
-               });
-       }
-
-       /*
-        * Runs callback function if synchronyzation is enabled.
-        * 
-        * @param callback - callback function
-        */
-       function runIfSyncEnabled(callback) {
-               chrome.storage.local.get({
-                       syncExtensions: false
-               }, function (options) {
-                       if (options.syncExtensions)
-                       {
-                               chrome.permissions.contains({
-                                       permissions: ["idle"]
-                               }, function (result) {
-                                       if (result)
-                                       {
-                                               callback();
-                                       }
-                               });
-
-                       }
-               });
-       }
-
-       /*
-        * Create notification when synchronization failed.
-        */
-       function createSyncFailedNotification(cause) {
-               GSC.notifications.create(NOTIFICATION_SYNC_FAILED, {
-                       message: m('synchronization_failed', cause ? cause : m('unknown_error'))
-               });
-       }
-
-       /*
-        * Public methods.
-        */
-       return {
-               init: init,
-               getExtensions: getExtensions,
-               onExtensionChanged: onExtensionChanged
-       };
+GSC.sync = (function ($) {
+    var enabled = true;
+    var extensionChangedTimeout = false;
+    var extensionChangedQueue = {};
+
+    const SYNC_QUEUE_TIMEOUT = 7000;
+
+    /*
+     * Initialization rutines.
+     */
+    function init() {
+        if (!COMPAT.SYNC_STORAGE) {
+            enabled = false;
+            return;
+        }
+
+        function onIdleStateChanged(state) {
+            if (state === 'locked') {
+                enabled = false;
+
+                // Remove all disabled extensions from queue
+                for (const [extensionId, extension] of Object.entries(extensionChangedQueue)) {
+                    if (extension.state == EXTENSION_STATE.DISABLED) {
+                        delete extensionChangedQueue[extensionId];
+                    }
+                };
+            }
+            else if (state === 'active') {
+                enabled = true;
+            }
+        }
+
+        chrome.permissions.contains({
+            permissions: ["idle"]
+        }, function (result) {
+            if (result) {
+                chrome.idle.onStateChanged.addListener(onIdleStateChanged);
+            }
+            else {
+                enabled = false;
+            }
+        });
+
+        chrome.permissions.onAdded.addListener(function (permissions) {
+            if (permissions.permissions && permissions.permissions.indexOf('idle') !== -1) {
+                enabled = true;
+                chrome.idle.onStateChanged.addListener(onIdleStateChanged);
+            }
+        });
+
+        chrome.permissions.onRemoved.addListener(function (permissions) {
+            if (permissions.permissions && permissions.permissions.indexOf('idle') !== -1) {
+                enabled = false;
+                chrome.idle.onStateChanged.removeListener(onIdleStateChanged);
+            }
+        });
+
+        function onNotificationAction(notificationId, buttonIndex) {
+            if (notificationId !== NOTIFICATION_SYNC_FAILED) {
+                return;
+            }
+
+            GSC.notifications.remove(notificationId);
+        }
+
+        onSyncFromRemote();
+        chrome.storage.onChanged.addListener(function (changes, areaName) {
+            if (areaName === 'sync' && changes.extensions) {
+                onSyncFromRemote(changes.extensions.newValue);
+            }
+        });
+
+        chrome.runtime.onMessage.addListener(
+            function (request, sender, sendResponse) {
+                if (sender.id && sender.id === GS_CHROME_ID && request) {
+                    if (request === MESSAGE_SYNC_FROM_REMOTE) {
+                        onSyncFromRemote();
+                    }
+                }
+            }
+        );
+
+        GSC.onInitialize().then(response => {
+            /*
+                @Deprecated: remove browser notifications in version 9
+             */
+            if (!GSC.nativeNotificationsSupported(response)) {
+                chrome.notifications.onButtonClicked.addListener(onNotificationAction);
+            }
+            else {
+                chrome.runtime.onMessage.addListener(
+                    function (request, sender, sendResponse) {
+                        if (
+                            sender.id && sender.id === GS_CHROME_ID &&
+                            request && request.signal) {
+                            if (request.signal == SIGNAL_NOTIFICATION_ACTION) {
+                                onNotificationAction(request.name, request.button_id);
+                            }
+                        }
+                    }
+                );
+            }
+        });
+    }
+
+    /*
+     * Returns array of all local and remote extensions with structure:
+     * [
+     * $extension_uuid: {
+     *         uuid:           extension uuid,
+     *         name:           extension name,
+     *         remoteState:    extension state in remote storage,
+     *         localState:     extension state in current GNOME Shell,
+     *         remote:         true if extensions is in remote storage,
+     *         local:          true if extension installed localy
+     * },
+     * ...
+     * ]
+     */
+    function getExtensions(remoteExtensions) {
+        return new Promise((resolve, reject) => {
+            GSC.sendNativeRequest({
+                execute: 'listExtensions'
+            }, function (response) {
+                if (response && response.success) {
+                    if (remoteExtensions) {
+                        resolve(mergeExtensions(remoteExtensions, response.extensions));
+                    }
+                    else {
+                        chrome.storage.sync.get({
+                            extensions: {}
+                        }, function (options) {
+                            if (chrome.runtime.lastError) {
+                                reject(chrome.runtime.lastError.message);
+                            }
+                            else {
+                                resolve(mergeExtensions(options.extensions, response.extensions));
+                            }
+                        });
+                    }
+                }
+                else {
+                    var message = response && response.message ? response.message : 
m('error_connector_response');
+                    reject(message);
+                }
+            });
+        });
+    }
+
+    /*
+     * Returns merged list of extensions list in remote storage and
+     * locally installed extensions.
+     *
+     * Both parameters should be in form:
+     * {
+     * $extension_uuid: {
+     *         uuid:   ,
+     *         name:   ,
+     *         state:
+     * },
+     * ...
+     * }
+     */
+    function mergeExtensions(remoteExtensions, localExtensions) {
+        var extensions = {};
+
+        for (const [key, extension] of Object.entries(remoteExtensions)) {
+            if (extension.uuid && extension.name && extension.state) {
+                extensions[extension.uuid] = {
+                    uuid: extension.uuid,
+                    name: extension.name,
+                    remoteState: extension.state,
+                    remote: true,
+                    local: false
+                };
+            }
+        };
+
+        for (const [key, extension] of Object.entries(localExtensions)) {
+            if (extensions[extension.uuid]) {
+                extensions[extension.uuid].name = extension.name;
+                extensions[extension.uuid].localState = extension.state;
+                extensions[extension.uuid].local = true;
+            }
+            else {
+                extensions[extension.uuid] = {
+                    uuid: extension.uuid,
+                    name: extension.name,
+                    remoteState: EXTENSION_STATE.UNINSTALLED,
+                    localState: extension.state,
+                    remote: false,
+                    local: true
+                };
+            }
+        };
+
+        return extensions;
+    }
+
+    /*
+     * Synchronize local changed extensions to remote list.
+     */
+    function localExtensionsChanged() {
+        extensionChangedTimeout = false;
+
+        if (!isEmptyObject(extensionChangedQueue)) {
+            GSC.sendNativeRequest({
+                execute: 'listExtensions'
+            }, function (response) {
+                if (response && response.success && response.extensions) {
+                    chrome.storage.sync.get({
+                        extensions: {}
+                    }, function (options) {
+                        for (const [extensionId, extension] of Object.entries(extensionChangedQueue)) {
+                            if ([EXTENSION_STATE.ENABLED, EXTENSION_STATE.DISABLED, 
EXTENSION_STATE.UNINSTALLED].includes(extension.state)) {
+                                // Extension can be uninstalled already
+                                if (response.extensions[extensionId] && 
!isEmptyObject(response.extensions[extensionId])) {
+                                    extension = response.extensions[extensionId];
+                                }
+
+                                if (extension.state === EXTENSION_STATE.UNINSTALLED && 
options.extensions[extension.uuid]) {
+                                    delete options.extensions[extension.uuid];
+                                }
+                                else {
+                                    options.extensions[extension.uuid] = {
+                                        uuid: extension.uuid,
+                                        name: extension.name,
+                                        state: extension.state
+                                    };
+                                }
+                            }
+                        };
+
+                        chrome.storage.sync.set({
+                            extensions: options.extensions
+                        });
+
+                        extensionChangedQueue = {};
+                    });
+                }
+                else {
+                    createSyncFailedNotification();
+                }
+            });
+        }
+    }
+
+    /*
+     * Synchronize remote changes with local GNOME Shell.
+     *
+     * @param remoteExtensions - (optional) remote extensions list
+     */
+    function remoteExtensionsChanged(remoteExtensions) {
+        getExtensions(remoteExtensions).then((extensions) => {
+            var enableExtensions = [];
+            for ([uuid, extension] of Object.entries(extensions)) {
+                if (extension.remote) {
+                    if (!extension.local) {
+                        GSC.sendNativeRequest({
+                            execute: "installExtension",
+                            uuid: extension.uuid
+                        }, onInstallUninstall);
+                    }
+                    else if (extension.remoteState !== extension.localState) {
+                        if (extension.remoteState === EXTENSION_STATE.ENABLED) {
+                            enableExtensions.push({
+                                uuid: extension.uuid,
+                                enable: true
+                            });
+                        }
+                        else {
+                            enableExtensions.push({
+                                uuid: extension.uuid,
+                                enable: false
+                            });
+                        }
+                    }
+                }
+                else if (extension.local) {
+                    GSC.sendNativeRequest({
+                        execute: "uninstallExtension",
+                        uuid: extension.uuid
+                    }, onInstallUninstall);
+                }
+            };
+
+            if (enableExtensions.length > 0) {
+                GSC.sendNativeRequest({
+                    execute: "enableExtension",
+                    extensions: enableExtensions
+                });
+            }
+        }).catch((message) => {
+            createSyncFailedNotification(message);
+        });
+    }
+
+    /*
+     * Callback called when extension is installed or uninstalled as part
+     * of synchronization process.
+     */
+    function onInstallUninstall(response) {
+        if (response) {
+            if (!response.success) {
+                createSyncFailedNotification(response.message);
+            }
+        }
+        else {
+            createSyncFailedNotification();
+        }
+    }
+
+    /*
+     * Wrapper for localExtensionChanged that checks if synchronization is
+     * enabled.
+     */
+    function onExtensionChanged(request) {
+        if (!COMPAT.SYNC_STORAGE || !enabled) {
+            return;
+        }
+
+        runIfSyncEnabled(() => {
+            if (extensionChangedTimeout) {
+                clearTimeout(extensionChangedTimeout);
+            }
+
+            extensionChangedQueue[request.parameters[EXTENSION_CHANGED_UUID]] = {
+                uuid: request.parameters[EXTENSION_CHANGED_UUID],
+                state: request.parameters[EXTENSION_CHANGED_STATE],
+                error: request.parameters[EXTENSION_CHANGED_ERROR]
+            };
+
+            extensionChangedTimeout = setTimeout(function () {
+                localExtensionsChanged();
+            }, SYNC_QUEUE_TIMEOUT);
+        });
+    }
+
+    /*
+     * Wrapper for remoteExtensionsChanged that checks if synchronization is
+     * enabled.
+     */
+    function onSyncFromRemote(remoteExtensions) {
+        if (!COMPAT.SYNC_STORAGE) {
+            return;
+        }
+
+        runIfSyncEnabled(function () {
+            remoteExtensionsChanged(remoteExtensions);
+        });
+    }
+
+    /*
+     * Runs callback function if synchronyzation is enabled.
+     *
+     * @param callback - callback function
+     */
+    function runIfSyncEnabled(callback) {
+        chrome.storage.local.get({
+            syncExtensions: false
+        }, function (options) {
+            if (options.syncExtensions) {
+                chrome.permissions.contains({
+                    permissions: ["idle"]
+                }, function (result) {
+                    if (result) {
+                        callback();
+                    }
+                });
+
+            }
+        });
+    }
+
+    /*
+     * Create notification when synchronization failed.
+     */
+    function createSyncFailedNotification(cause) {
+        GSC.notifications.create(NOTIFICATION_SYNC_FAILED, {
+            message: m('synchronization_failed', cause ? cause : m('unknown_error'))
+        });
+    }
+
+    /*
+     * Public methods.
+     */
+    return {
+        init: init,
+        getExtensions: getExtensions,
+        onExtensionChanged: onExtensionChanged
+    };
 })();
diff --git a/extension/include/toolbar.js b/extension/include/toolbar.js
index d918b43..24a7fda 100644
--- a/extension/include/toolbar.js
+++ b/extension/include/toolbar.js
@@ -3,55 +3,51 @@
 /*
  * Main object that handles toolbar icon.
  */
-GSC.toolbar = (function() {
-       /*
-        * Initialization rutines.
-        */
-       function init() {
-               chrome.storage.local.get(DEFAULT_LOCAL_OPTIONS, function (options) {
-                       if (options.useLightIcon)
-                       {
-                               setLightIcon();
-                       }
-               });
+GSC.toolbar = (function () {
+    /*
+     * Initialization rutines.
+     */
+    function init() {
+        chrome.storage.local.get(DEFAULT_LOCAL_OPTIONS, function (options) {
+            if (options.useLightIcon) {
+                setLightIcon();
+            }
+        });
 
-               chrome.storage.onChanged.addListener(function(changes, areaName) {
-                       if(areaName === 'local' && changes.useLightIcon)
-                       {
-                               if(changes.useLightIcon.newValue)
-                               {
-                                       setLightIcon();
-                               }
-                               else
-                               {
-                                       setDarkicon();
-                               }
-                       }
-               });
-       }
+        chrome.storage.onChanged.addListener(function (changes, areaName) {
+            if (areaName === 'local' && changes.useLightIcon) {
+                if (changes.useLightIcon.newValue) {
+                    setLightIcon();
+                }
+                else {
+                    setDarkicon();
+                }
+            }
+        });
+    }
 
-       function setLightIcon() {
-               chrome.browserAction.setIcon({
-                       path: {
-                               "16": "icons/GnomeLogo-light-16.png",
-                               "32": "icons/GnomeLogo-light-32.png"
-                       }
-               });
-       }
+    function setLightIcon() {
+        chrome.browserAction.setIcon({
+            path: {
+                "16": "icons/GnomeLogo-light-16.png",
+                "32": "icons/GnomeLogo-light-32.png"
+            }
+        });
+    }
 
-       function setDarkicon() {
-               chrome.browserAction.setIcon({
-                       path: {
-                               "16": "icons/GnomeLogo-16.png",
-                           "32": "icons/GnomeLogo-32.png"
-                       }
-               });
-       }
+    function setDarkicon() {
+        chrome.browserAction.setIcon({
+            path: {
+                "16": "icons/GnomeLogo-16.png",
+                "32": "icons/GnomeLogo-32.png"
+            }
+        });
+    }
 
-       /*
-        * Public methods.
-        */
-       return {
-               init: init
-       };
+    /*
+     * Public methods.
+     */
+    return {
+        init: init
+    };
 })();
diff --git a/extension/include/update.js b/extension/include/update.js
index db1a948..53050ff 100644
--- a/extension/include/update.js
+++ b/extension/include/update.js
@@ -1,196 +1,170 @@
 // SPDX-License-Identifer: GPL-3.0-or-later
 
-GSC.update = (function() {
-       function schedule(updateCheckPeriod, skipCheck) {
-               if(!skipCheck)
-               {
-                       check();
-               }
-
-               chrome.alarms.create(
-                       ALARM_UPDATE_CHECK,
-                       {
-                               delayInMinutes: updateCheckPeriod * 60,
-                               periodInMinutes: updateCheckPeriod * 60
-                       }
-               );
-
-               chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_NEXT_UPDATE_CHANGED);
-       }
-
-       function check() {
-               GSC.onInitialize().then(response => {
-                       if (response.success)
-                       {
-                               if(GSC.nativeUpdateCheckSupported(response))
-                               {
-                                       chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (options) {
-                                               GSC.sendNativeRequest(
-                                                       {
-                                                               execute: 'checkUpdate',
-                                                               url: UPDATE_URL,
-                                                               enabledOnly: options.updateCheckEnabledOnly
-                                                       }, function (response) {
-                                                       if (response.success)
-                                                       {
-                                                               onSweetToothResponse(response.upgrade, 
response.extensions);
-                                                       }
-                                                       else if(console)
-                                                       {
-                                                               console.error(response.message ? 
response.message : m('native_request_failed', 'checkUpdate'));
-                                                       }
-                                               });
-                                       });
-                               }
-                               else
-                               {
-                                       chrome.storage.sync.set({
-                                               updateCheck: false
-                                       });
-                               }
-                       }
-                       else if(console)
-                       {
-                               console.error(response.message ? response.message : 
m('native_request_failed', 'initialize'));
-                       }
-               });
-       }
-
-       function onSweetToothResponse(data, installedExtensions) {
-               var toUpgrade = [];
-               for (uuid in data)
-               {
-                       if (installedExtensions[uuid] && ['upgrade', 'downgrade'].includes(data[uuid]))
-                       {
-                               toUpgrade.push({
-                                       title: installedExtensions[uuid].name,
-                                       message: m('extension_status_' + data[uuid])
-                               });
-                       }
-               }
-
-               if (toUpgrade.length > 0)
-               {
-                       GSC.notifications.create(NOTIFICATION_UPDATE_AVAILABLE, {
-                               type: chrome.notifications.TemplateType.LIST,
-                               title: m('update_available'),
-                               message: '',
-                               items: toUpgrade
-                       });
-               }
-
-               chrome.storage.local.set({
-                       lastUpdateCheck: new Date().toLocaleString()
-               });
-       }
-
-       function init() {
-               function onNotificationAction(notificationId, buttonIndex) {
-                       if (NOTIFICATION_UPDATE_AVAILABLE == notificationId)
-                               return;
-
-                       GSC.notifications.remove(notificationId);
-               }
-
-               function onNotificationClicked(notificationId) {
-                       if (notificationId === NOTIFICATION_UPDATE_AVAILABLE)
-                       {
-                               chrome.tabs.create({
-                                       url: EXTENSIONS_WEBSITE + 'local/',
-                                       active: true
-                               });
-                       }
-               }
-
-               chrome.alarms.onAlarm.addListener(function (alarm) {
-                       if (alarm.name === ALARM_UPDATE_CHECK)
-                       {
-                               check();
-
-                               chrome.alarms.get(ALARM_UPDATE_CHECK, function (alarm) {
-                                       if (alarm && alarm.periodInMinutes && ((alarm.scheduledTime - 
Date.now()) / 1000 / 60 < alarm.periodInMinutes * 0.9))
-                                       {
-                                               schedule(alarm.periodInMinutes / 60, true);
-                                       }
-                                       else
-                                       {
-                                               chrome.runtime.sendMessage(GS_CHROME_ID, 
MESSAGE_NEXT_UPDATE_CHANGED);
-                                       }
-                               });
-                       }
-               });
-
-               GSC.onInitialize().then(response => {
-                       /*
-                               @Deprecated: remove browser notifications in version 9
-                        */
-                       if (!GSC.nativeNotificationsSupported(response))
-                       {
-                               chrome.notifications.onClicked.addListener(function (notificationId) {
-                                       onNotificationClicked(notificationId);
-                               });
-
-                               chrome.notifications.onButtonClicked.addListener(onNotificationAction);
-                       }
-                       else
-                       {
-                               window.addEventListener("message", function (event) {
-                                       if (event.source == window && event.data && event.data.signal)
-                                       {
-                                               if(event.data.signal == SIGNAL_NOTIFICATION_ACTION)
-                                               {
-                                                       onNotificationAction(event.data.name, 
event.data.button_id);
-                                               }
-                                               else if(event.data.signal == SIGNAL_NOTIFICATION_CLICKED)
-                                               {
-                                                       onNotificationClicked(event.data.name);
-                                               }
-                                       }
-                               });
-                       }
-               });
-
-               chrome.storage.onChanged.addListener(function (changes, areaName) {
-                       if (changes.updateCheck)
-                       {
-                               if (!changes.updateCheck.newValue)
-                               {
-                                       chrome.alarms.clear(ALARM_UPDATE_CHECK);
-                               }
-                               else
-                               {
-                                       chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (options) {
-                                               schedule(options.updateCheckPeriod);
-                                       });
-                               }
-                       }
-                       else if (changes.updateCheckPeriod)
-                       {
-                               chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (options) {
-                                       if (options.updateCheck)
-                                       {
-                                               schedule(options.updateCheckPeriod);
-                                       }
-                               });
-                       }
-               });
-
-               chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (options) {
-                       if (options.updateCheck)
-                       {
-                               chrome.alarms.get(ALARM_UPDATE_CHECK, function (alarm) {
-                                       if (!alarm || !alarm.periodInMinutes || alarm.periodInMinutes !== 
options.updateCheckPeriod * 60)
-                                       {
-                                               schedule(options.updateCheckPeriod);
-                                       }
-                               });
-                       }
-               });
-       }
-
-       return {
-               init: init,
-               check: check,
-               schedule: schedule
-       };
+GSC.update = (function () {
+    function schedule(updateCheckPeriod, skipCheck) {
+        if (!skipCheck) {
+            check();
+        }
+
+        chrome.alarms.create(
+            ALARM_UPDATE_CHECK,
+            {
+                delayInMinutes: updateCheckPeriod * 60,
+                periodInMinutes: updateCheckPeriod * 60
+            }
+        );
+
+        chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_NEXT_UPDATE_CHANGED);
+    }
+
+    function check() {
+        GSC.onInitialize().then(response => {
+            if (response.success) {
+                if (GSC.nativeUpdateCheckSupported(response)) {
+                    chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (options) {
+                        GSC.sendNativeRequest(
+                            {
+                                execute: 'checkUpdate',
+                                url: UPDATE_URL,
+                                enabledOnly: options.updateCheckEnabledOnly
+                            }, function (response) {
+                                if (response.success) {
+                                    onSweetToothResponse(response.upgrade, response.extensions);
+                                }
+                                else if (console) {
+                                    console.error(response.message ? response.message : 
m('native_request_failed', 'checkUpdate'));
+                                }
+                            });
+                    });
+                }
+                else {
+                    chrome.storage.sync.set({
+                        updateCheck: false
+                    });
+                }
+            }
+            else if (console) {
+                console.error(response.message ? response.message : m('native_request_failed', 
'initialize'));
+            }
+        });
+    }
+
+    function onSweetToothResponse(data, installedExtensions) {
+        var toUpgrade = [];
+        for (uuid in data) {
+            if (installedExtensions[uuid] && ['upgrade', 'downgrade'].includes(data[uuid])) {
+                toUpgrade.push({
+                    title: installedExtensions[uuid].name,
+                    message: m('extension_status_' + data[uuid])
+                });
+            }
+        }
+
+        if (toUpgrade.length > 0) {
+            GSC.notifications.create(NOTIFICATION_UPDATE_AVAILABLE, {
+                type: chrome.notifications.TemplateType.LIST,
+                title: m('update_available'),
+                message: '',
+                items: toUpgrade
+            });
+        }
+
+        chrome.storage.local.set({
+            lastUpdateCheck: new Date().toLocaleString()
+        });
+    }
+
+    function init() {
+        function onNotificationAction(notificationId, buttonIndex) {
+            if (NOTIFICATION_UPDATE_AVAILABLE == notificationId)
+                return;
+
+            GSC.notifications.remove(notificationId);
+        }
+
+        function onNotificationClicked(notificationId) {
+            if (notificationId === NOTIFICATION_UPDATE_AVAILABLE) {
+                chrome.tabs.create({
+                    url: EXTENSIONS_WEBSITE + 'local/',
+                    active: true
+                });
+            }
+        }
+
+        chrome.alarms.onAlarm.addListener(function (alarm) {
+            if (alarm.name === ALARM_UPDATE_CHECK) {
+                check();
+
+                chrome.alarms.get(ALARM_UPDATE_CHECK, function (alarm) {
+                    if (alarm && alarm.periodInMinutes && ((alarm.scheduledTime - Date.now()) / 1000 / 60 < 
alarm.periodInMinutes * 0.9)) {
+                        schedule(alarm.periodInMinutes / 60, true);
+                    }
+                    else {
+                        chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_NEXT_UPDATE_CHANGED);
+                    }
+                });
+            }
+        });
+
+        GSC.onInitialize().then(response => {
+            /*
+                @Deprecated: remove browser notifications in version 9
+             */
+            if (!GSC.nativeNotificationsSupported(response)) {
+                chrome.notifications.onClicked.addListener(function (notificationId) {
+                    onNotificationClicked(notificationId);
+                });
+
+                chrome.notifications.onButtonClicked.addListener(onNotificationAction);
+            }
+            else {
+                window.addEventListener("message", function (event) {
+                    if (event.source == window && event.data && event.data.signal) {
+                        if (event.data.signal == SIGNAL_NOTIFICATION_ACTION) {
+                            onNotificationAction(event.data.name, event.data.button_id);
+                        }
+                        else if (event.data.signal == SIGNAL_NOTIFICATION_CLICKED) {
+                            onNotificationClicked(event.data.name);
+                        }
+                    }
+                });
+            }
+        });
+
+        chrome.storage.onChanged.addListener(function (changes, areaName) {
+            if (changes.updateCheck) {
+                if (!changes.updateCheck.newValue) {
+                    chrome.alarms.clear(ALARM_UPDATE_CHECK);
+                }
+                else {
+                    chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (options) {
+                        schedule(options.updateCheckPeriod);
+                    });
+                }
+            }
+            else if (changes.updateCheckPeriod) {
+                chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (options) {
+                    if (options.updateCheck) {
+                        schedule(options.updateCheckPeriod);
+                    }
+                });
+            }
+        });
+
+        chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (options) {
+            if (options.updateCheck) {
+                chrome.alarms.get(ALARM_UPDATE_CHECK, function (alarm) {
+                    if (!alarm || !alarm.periodInMinutes || alarm.periodInMinutes !== 
options.updateCheckPeriod * 60) {
+                        schedule(options.updateCheckPeriod);
+                    }
+                });
+            }
+        });
+    }
+
+    return {
+        init: init,
+        check: check,
+        schedule: schedule
+    };
 })();
diff --git a/extension/options.html b/extension/options.html
index c8f809a..61e3337 100644
--- a/extension/options.html
+++ b/extension/options.html
@@ -1,113 +1,132 @@
 <!DOCTYPE html>
 <html>
-       <head>
-               <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-               <title data-i18n="options_title, __MSG_gs_chrome__"></title>
-               <link href="css/options.css" rel="stylesheet" type="text/css" />
-               <script type="text/javascript" src="include/i18n.js"></script>
-               <script type="text/javascript" src="include/constants.js"></script>
-               <script type="text/javascript" src="include/compat-common.js"></script>
-               <script type="text/javascript" src="include/gsc.js"></script>
-               <script type="text/javascript" src="include/sync.js"></script>
-       </head>
-       <body>
-               <ul data-tabs class="tabs">
-                       <li><a href="#options" data-tabs-active data-i18n='options_link' 
data-tab='tab'></a></li>
-                       <li><a href="#synchronization" data-i18n='synchronization' data-tab='tab'></a></li>
-                       <li class='translation_credits_container'><a href="#translation_credits" 
data-i18n='translation_credits_title' data-tab='tab'></a></li>
-               </ul>
-               <div>
-                       <div id="options" class="tabs-pane active" data-tabs-pane='tabs-pane'>
-                               <div id="status" class="hide" data-i18n="options_saved"></div>
-                               <div id="error" class="hide"></div>
 
-                               <fieldset>
-                                       <dl>
-                                               <dt>
-                                                       <span data-i18n="options_update_check"></span>:<br 
class="update-notice"/>
-                                                       <span class="notice wrapped update-notice" 
data-i18n="options_update_check_notice"></span>
-                                               </dt>
-                                               <dd>
-                                                       <label for='update_check_yes' 
data-i18n="yes"></label> <input type='radio' id='update_check_yes' name='update_check' disabled='disabled' />
-                                                       <label for='update_check_no' data-i18n="no"></label> 
<input type='radio' id='update_check_no' name='update_check' disabled='disabled' />
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title data-i18n="options_title, __MSG_gs_chrome__"></title>
+    <link href="css/options.css" rel="stylesheet" type="text/css" />
+    <script type="text/javascript" src="include/i18n.js"></script>
+    <script type="text/javascript" src="include/constants.js"></script>
+    <script type="text/javascript" src="include/compat-common.js"></script>
+    <script type="text/javascript" src="include/gsc.js"></script>
+    <script type="text/javascript" src="include/sync.js"></script>
+</head>
 
-                                                       <div class='notice'><span 
data-i18n="options_last_check"></span>: <span id="last_update_check" data-i18n="never"></span></div>
-                                               </dd>
-                                       </dl>
-                                       <dl>
-                                               <dt>
-                                                       <span 
data-i18n="options_update_check_enabled"></span>:<br class="update-notice"/>
-                                                       <span class="notice wrapped update-notice" 
data-i18n="options_update_check_enabled_notice"></span>
-                                               </dt>
-                                               <dd>
-                                                       <label for='update_check_enabled_yes' 
data-i18n="yes"></label> <input type='radio' id='update_check_enabled_yes' name='update_check_enabled' 
disabled='disabled' />
-                                                       <label for='update_check_enabled_no' 
data-i18n="no"></label> <input type='radio' id='update_check_enabled_no' name='update_check_enabled' 
disabled='disabled' />
-                                               </dd>
-                                       </dl>
-                                       <dl>
-                                               <dt><label for='update_check_period' 
data-i18n="options_check_period"></label>:</dt>
-                                               <dd>
-                                                       <input id='update_check_period' type='number' min="3" 
disabled='disabled' /> <span data-i18n="hours"></span>
+<body>
+    <ul data-tabs class="tabs">
+        <li><a href="#options" data-tabs-active data-i18n='options_link' data-tab='tab'></a></li>
+        <li><a href="#synchronization" data-i18n='synchronization' data-tab='tab'></a></li>
+        <li class='translation_credits_container'><a href="#translation_credits" 
data-i18n='translation_credits_title'
+                data-tab='tab'></a></li>
+    </ul>
+    <div>
+        <div id="options" class="tabs-pane active" data-tabs-pane='tabs-pane'>
+            <div id="status" class="hide" data-i18n="options_saved"></div>
+            <div id="error" class="hide"></div>
 
-                                                       <div class='notice'><span 
data-i18n="options_next_check"></span>: <span id="next_update_check" data-i18n="never"></span></div>
-                                               </dd>
-                                       </dl>
-                                       <dl>
-                                               <dt>
-                                                       <label for='synchronize_extensions_yes' 
data-i18n="options_synchronize_extensions"></label>:<br />
-                                                       <span class="notice wrapped" 
data-i18n="options_synchronize_extensions_notice"></span>
-                                               </dt>
-                                               <dd>
-                                                       <label for='synchronize_extensions_yes' 
data-i18n="yes"></label> <input type='radio' id='synchronize_extensions_yes' name='synchronize_extensions' />
-                                                       <label for='synchronize_extensions_no' 
data-i18n="no"></label> <input type='radio' id='synchronize_extensions_no' name='synchronize_extensions' />
-                                               </dd>
-                                       </dl>
-                                       <dl>
-                                               <dt><span data-i18n="options_use_light_icon"></span>:</dt>
-                                               <dd>
-                                                       <label for='use_light_icon_yes' 
data-i18n="yes"></label> <input type='radio' id='use_light_icon_yes' name='use_light_icon' />
-                                                       <label for='use_light_icon_no' 
data-i18n="no"></label> <input type='radio' id='use_light_icon_no' name='use_light_icon' />
-                                               </dd>
-                                       </dl>
-                                       <dl>
-                                               <dt><span data-i18n="options_show_release_notes"></span>:</dt>
-                                               <dd>
-                                                       <label for='show_release_notes_yes' 
data-i18n="yes"></label> <input type='radio' id='show_release_notes_yes' name='show_release_notes' />
-                                                       <label for='show_release_notes_no' 
data-i18n="no"></label> <input type='radio' id='show_release_notes_no' name='show_release_notes' />
-                                               </dd>
-                                       </dl>
-                               </fieldset>
+            <fieldset>
+                <dl>
+                    <dt>
+                        <span data-i18n="options_update_check"></span>:<br class="update-notice" />
+                        <span class="notice wrapped update-notice" 
data-i18n="options_update_check_notice"></span>
+                    </dt>
+                    <dd>
+                        <label for='update_check_yes' data-i18n="yes"></label> <input type='radio' 
id='update_check_yes'
+                            name='update_check' disabled='disabled' />
+                        <label for='update_check_no' data-i18n="no"></label> <input type='radio' 
id='update_check_no'
+                            name='update_check' disabled='disabled' />
 
-                               <div class='buttons'>
-                                       <button id="save" data-i18n="save"></button>
-                               </div>
-                       </div>
-                       <div id="synchronization" class="tabs-pane" data-tabs-pane='tabs-pane'>
-                               <table>
-                                       <thead>
-                                               <tr>
-                                                       <th data-i18n="extension_name"></th>
-                                                       <th data-i18n="extension_installed"></th>
-                                                       <th data-i18n="extension_enabled"></th>
-                                                       <th data-i18n="extension_synchronized"></th>
-                                               </tr>
-                                       </thead>
-                                       <tbody></tbody>
-                               </table>
-                       </div>
-                       <div id="translation_credits" class="tabs-pane translation_credits_container" 
data-tabs-pane='tabs-pane'>
-                               <div data-i18n='translation_credits' data-i18n-html='true'></div>
-                       </div>
-               </div>
+                        <div class='notice'><span data-i18n="options_last_check"></span>: <span 
id="last_update_check"
+                                data-i18n="never"></span></div>
+                    </dd>
+                </dl>
+                <dl>
+                    <dt>
+                        <span data-i18n="options_update_check_enabled"></span>:<br class="update-notice" />
+                        <span class="notice wrapped update-notice"
+                            data-i18n="options_update_check_enabled_notice"></span>
+                    </dt>
+                    <dd>
+                        <label for='update_check_enabled_yes' data-i18n="yes"></label> <input type='radio'
+                            id='update_check_enabled_yes' name='update_check_enabled' disabled='disabled' />
+                        <label for='update_check_enabled_no' data-i18n="no"></label> <input type='radio'
+                            id='update_check_enabled_no' name='update_check_enabled' disabled='disabled' />
+                    </dd>
+                </dl>
+                <dl>
+                    <dt><label for='update_check_period' data-i18n="options_check_period"></label>:</dt>
+                    <dd>
+                        <input id='update_check_period' type='number' min="3" disabled='disabled' /> <span
+                            data-i18n="hours"></span>
+
+                        <div class='notice'><span data-i18n="options_next_check"></span>: <span 
id="next_update_check"
+                                data-i18n="never"></span></div>
+                    </dd>
+                </dl>
+                <dl>
+                    <dt>
+                        <label for='synchronize_extensions_yes'
+                            data-i18n="options_synchronize_extensions"></label>:<br />
+                        <span class="notice wrapped" 
data-i18n="options_synchronize_extensions_notice"></span>
+                    </dt>
+                    <dd>
+                        <label for='synchronize_extensions_yes' data-i18n="yes"></label> <input type='radio'
+                            id='synchronize_extensions_yes' name='synchronize_extensions' />
+                        <label for='synchronize_extensions_no' data-i18n="no"></label> <input type='radio'
+                            id='synchronize_extensions_no' name='synchronize_extensions' />
+                    </dd>
+                </dl>
+                <dl>
+                    <dt><span data-i18n="options_use_light_icon"></span>:</dt>
+                    <dd>
+                        <label for='use_light_icon_yes' data-i18n="yes"></label> <input type='radio'
+                            id='use_light_icon_yes' name='use_light_icon' />
+                        <label for='use_light_icon_no' data-i18n="no"></label> <input type='radio'
+                            id='use_light_icon_no' name='use_light_icon' />
+                    </dd>
+                </dl>
+                <dl>
+                    <dt><span data-i18n="options_show_release_notes"></span>:</dt>
+                    <dd>
+                        <label for='show_release_notes_yes' data-i18n="yes"></label> <input type='radio'
+                            id='show_release_notes_yes' name='show_release_notes' />
+                        <label for='show_release_notes_no' data-i18n="no"></label> <input type='radio'
+                            id='show_release_notes_no' name='show_release_notes' />
+                    </dd>
+                </dl>
+            </fieldset>
+
+            <div class='buttons'>
+                <button id="save" data-i18n="save"></button>
+            </div>
+        </div>
+        <div id="synchronization" class="tabs-pane" data-tabs-pane='tabs-pane'>
+            <table>
+                <thead>
+                    <tr>
+                        <th data-i18n="extension_name"></th>
+                        <th data-i18n="extension_installed"></th>
+                        <th data-i18n="extension_enabled"></th>
+                        <th data-i18n="extension_synchronized"></th>
+                    </tr>
+                </thead>
+                <tbody></tbody>
+            </table>
+        </div>
+        <div id="translation_credits" class="tabs-pane translation_credits_container" 
data-tabs-pane='tabs-pane'>
+            <div data-i18n='translation_credits' data-i18n-html='true'></div>
+        </div>
+    </div>
+
+    <dialog id='syncChoice'>
+        <h2 data-i18n='synchronization_storage_exists'></h2>
+        <form method="dialog">
+            <button type='submit' value='local' data-i18n='synchronization_use_local'></button>
+            <button type='submit' value='remote' data-i18n='synchronization_use_remote'></button>
+            <button type='submit' value='cancel' data-i18n='synchronization_cancel'></button>
+        </form>
+    </dialog>
+    <script type="text/javascript" src="options.js"></script>
+</body>
 
-               <dialog id='syncChoice'>
-                       <h2 data-i18n='synchronization_storage_exists'></h2>
-                       <form method="dialog">
-                               <button type='submit' value='local' 
data-i18n='synchronization_use_local'></button>
-                               <button type='submit' value='remote' 
data-i18n='synchronization_use_remote'></button>
-                               <button type='submit' value='cancel' 
data-i18n='synchronization_cancel'></button>
-                       </form>
-               </dialog>
-               <script type="text/javascript" src="options.js"></script>
-       </body>
 </html>
diff --git a/extension/options.js b/extension/options.js
index f0f67f2..5aa392e 100644
--- a/extension/options.js
+++ b/extension/options.js
@@ -1,369 +1,325 @@
 // SPDX-License-Identifer: GPL-3.0-or-later
 
-function init_tabs()
-{
-       let tabLinks = $("[data-tabs]").querySelectorAll('a');
-       let updateTabs = (active = null) => {
-               tabLinks.forEach((link) => {
-                       let tab = $(link.getAttribute("href"));
-
-                       if((!active && link.hasAttribute('data-tabs-active')) || link == active) {
-                               tab.classList.remove('hide');
-                       }
-                       else {
-                               tab.classList.add('hide');
-                       }
-               });
-       };
-
-       tabLinks.forEach((link) => {
-               link.addEventListener('click', (event) => {
-                       updateTabs(event.target);
-               });
-       });
-
-       updateTabs();
+function init_tabs() {
+    let tabLinks = $("[data-tabs]").querySelectorAll('a');
+    let updateTabs = (active = null) => {
+        tabLinks.forEach((link) => {
+            let tab = $(link.getAttribute("href"));
+
+            if ((!active && link.hasAttribute('data-tabs-active')) || link == active) {
+                tab.classList.remove('hide');
+            }
+            else {
+                tab.classList.add('hide');
+            }
+        });
+    };
+
+    tabLinks.forEach((link) => {
+        link.addEventListener('click', (event) => {
+            updateTabs(event.target);
+        });
+    });
+
+    updateTabs();
 }
 
-function save_options()
-{
-       var showReleaseNotes = $('#show_release_notes_yes').checked;
-       var syncExtensions = $('#synchronize_extensions_yes').checked;
-       var updateCheck = $('#update_check_yes').checked;
-       var updateCheckEnabledOnly = $('#update_check_enabled_yes').checked;
-       var updateCheckPeriod = $('#update_check_period').value;
-       var useLightIcon = $('#use_light_icon_yes').checked;
-       updateCheckPeriod = Math.max(3, updateCheckPeriod);
-
-       chrome.storage.sync.set({
-               showReleaseNotes:       showReleaseNotes,
-               updateCheck:            updateCheck,
-               updateCheckEnabledOnly: updateCheckEnabledOnly,
-               updateCheckPeriod:      updateCheckPeriod
-       }, function () {
-               chrome.storage.local.set({
-                       syncExtensions: syncExtensions,
-                       useLightIcon:   useLightIcon
-               }, function() {
-                       if(syncExtensions)
-                       {
-                               syncType = document.getElementById('syncChoice').returnValue;
-                               if(!syncType || syncType === 'local')
-                               {
-                                       GSC.sync.getExtensions().then((extensions) => {
-                                               var localExtensions = {};
-                                               for (const [uuid, extension] of Object.entries(extensions)) {
-                                                       if(extension.local && extension.localState != 
EXTENSION_STATE.UNINSTALLED)
-                                                       {
-                                                               localExtensions[extension.uuid] = {
-                                                                       uuid:   extension.uuid,
-                                                                       name:   extension.name,
-                                                                       state:  extension.localState
-                                                               };
-                                                       }
-                                               };
-
-                                               chrome.storage.sync.set({
-                                                       extensions: localExtensions
-                                               }, function() {
-                                                       showSuccessStatus();
-                                               });
-                                       }).catch((message) => {
-                                               showWithDelay($('#error'), 15000, message);
-                                       });
-                               }
-                               else if(syncType === 'remote')
-                               {
-                                       chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_SYNC_FROM_REMOTE);
-                                       showSuccessStatus();
-                               }
-                       }
-                       else
-                       {
-                               showSuccessStatus();
-                       }
-               });
-       });
+function save_options() {
+    var showReleaseNotes = $('#show_release_notes_yes').checked;
+    var syncExtensions = $('#synchronize_extensions_yes').checked;
+    var updateCheck = $('#update_check_yes').checked;
+    var updateCheckEnabledOnly = $('#update_check_enabled_yes').checked;
+    var updateCheckPeriod = $('#update_check_period').value;
+    var useLightIcon = $('#use_light_icon_yes').checked;
+    updateCheckPeriod = Math.max(3, updateCheckPeriod);
+
+    chrome.storage.sync.set({
+        showReleaseNotes: showReleaseNotes,
+        updateCheck: updateCheck,
+        updateCheckEnabledOnly: updateCheckEnabledOnly,
+        updateCheckPeriod: updateCheckPeriod
+    }, function () {
+        chrome.storage.local.set({
+            syncExtensions: syncExtensions,
+            useLightIcon: useLightIcon
+        }, function () {
+            if (syncExtensions) {
+                syncType = document.getElementById('syncChoice').returnValue;
+                if (!syncType || syncType === 'local') {
+                    GSC.sync.getExtensions().then((extensions) => {
+                        var localExtensions = {};
+                        for (const [uuid, extension] of Object.entries(extensions)) {
+                            if (extension.local && extension.localState != EXTENSION_STATE.UNINSTALLED) {
+                                localExtensions[extension.uuid] = {
+                                    uuid: extension.uuid,
+                                    name: extension.name,
+                                    state: extension.localState
+                                };
+                            }
+                        };
+
+                        chrome.storage.sync.set({
+                            extensions: localExtensions
+                        }, function () {
+                            showSuccessStatus();
+                        });
+                    }).catch((message) => {
+                        showWithDelay($('#error'), 15000, message);
+                    });
+                }
+                else if (syncType === 'remote') {
+                    chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_SYNC_FROM_REMOTE);
+                    showSuccessStatus();
+                }
+            }
+            else {
+                showSuccessStatus();
+            }
+        });
+    });
 }
 
-function showSuccessStatus()
-{
-       // Update status to let user know options were saved.
-       showWithDelay($('#status'), 750);
+function showSuccessStatus() {
+    // Update status to let user know options were saved.
+    showWithDelay($('#status'), 750);
 }
 
-function restore_options()
-{
-       init_tabs();
-
-       chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (items) {
-               function toggle_notice(show, id) {
-                       let notice = $('#' + id)
-                               .closest('dl')
-                               .querySelector('dt br, dt span.notice');
-
-                       if (show)
-                       {
-                               notice.style.display = 'block';
-                       }
-                       else
-                       {
-                               notice.style.display = 'none';
-                       }
-               }
-
-               function toggle_update_notice(show) {
-                       toggle_notice(show, "update_check_yes");
-               }
-
-               function toggle_update_enable_notice(show) {
-                       toggle_notice(show, "update_check_enabled_yes");
-               }
-
-               function disable_update_check() {
-                       if (items.updateCheck)
-                       {
-                               items.updateCheck = false;
-
-                               chrome.storage.sync.set({
-                                       updateCheck: items.updateCheck
-                               });
-                       }
-
-                       toggle_update_notice(true);
-               }
-
-               function disable_update_enabled_only() {
-                       if (items.updateCheckEnabledOnly)
-                       {
-                               items.updateCheckEnabledOnly = false;
-
-                               chrome.storage.sync.set({
-                                       updateCheckEnabledOnly: items.updateCheckEnabledOnly
-                               });
-                       }
-
-                       toggle_update_enable_notice(true);
-               }
-
-               GSC.onInitialize().then(function (response) {
-                       if (!GSC.nativeUpdateCheckSupported(response))
-                       {
-                               disable_update_check();
-                       }
-                       else
-                       {
-                               $$("input[name='update_check'], #update_check_period").forEach((input) => 
input.disabled = false);
-                               $('#update_check_period').value = items.updateCheckPeriod;
-                               toggle_update_notice(false);
-                               retrieveUpdateTimes();
-                       }
-
-                       if (!GSC.nativeUpdateCheckEnabledOnlySupported(response))
-                       {
-                               disable_update_enabled_only();
-                       }
-                       else
-                       {
-                               $("input[name='update_check_enabled']").disabled = false;
-                               toggle_update_enable_notice(false);
-                       }
-
-                       setCheckUpdate(items.updateCheck);
-                       setCheckUpdateEnabledOnly(items.updateCheckEnabledOnly);
-               }, function(response) {
-                       disable_update_check();
-               });
-
-               setReleaseNotes(items.showReleaseNotes);
-       });
-
-       if(COMPAT.SYNC_STORAGE)
-       {
-               updateSynchronizationStatus();
-       }
-       else
-       {
-               $('a[data-i18n="synchronization"]').parentNode.remove();
-               $('#synchronize_extensions_yes').closest('dl').style.display = 'none';
-       }
-
-       chrome.storage.local.get(DEFAULT_LOCAL_OPTIONS, function (items) {
-               if(items.syncExtensions)
-               {
-                       chrome.permissions.contains({
-                               permissions: ["idle"]
-                       }, function (result) {
-                               setSyncExtensions(result);
-                       });
-               }
-               else if(COMPAT.SYNC_STORAGE)
-               {
-                       setSyncExtensions(false);
-               }
-
-               setLightIcon(items.useLightIcon);
-       });
+function restore_options() {
+    init_tabs();
+
+    chrome.storage.sync.get(DEFAULT_SYNC_OPTIONS, function (items) {
+        function toggle_notice(show, id) {
+            let notice = $('#' + id)
+                .closest('dl')
+                .querySelector('dt br, dt span.notice');
+
+            if (show) {
+                notice.style.display = 'block';
+            }
+            else {
+                notice.style.display = 'none';
+            }
+        }
+
+        function toggle_update_notice(show) {
+            toggle_notice(show, "update_check_yes");
+        }
+
+        function toggle_update_enable_notice(show) {
+            toggle_notice(show, "update_check_enabled_yes");
+        }
+
+        function disable_update_check() {
+            if (items.updateCheck) {
+                items.updateCheck = false;
+
+                chrome.storage.sync.set({
+                    updateCheck: items.updateCheck
+                });
+            }
+
+            toggle_update_notice(true);
+        }
+
+        function disable_update_enabled_only() {
+            if (items.updateCheckEnabledOnly) {
+                items.updateCheckEnabledOnly = false;
+
+                chrome.storage.sync.set({
+                    updateCheckEnabledOnly: items.updateCheckEnabledOnly
+                });
+            }
+
+            toggle_update_enable_notice(true);
+        }
+
+        GSC.onInitialize().then(function (response) {
+            if (!GSC.nativeUpdateCheckSupported(response)) {
+                disable_update_check();
+            }
+            else {
+                $$("input[name='update_check'], #update_check_period").forEach((input) => input.disabled = 
false);
+                $('#update_check_period').value = items.updateCheckPeriod;
+                toggle_update_notice(false);
+                retrieveUpdateTimes();
+            }
+
+            if (!GSC.nativeUpdateCheckEnabledOnlySupported(response)) {
+                disable_update_enabled_only();
+            }
+            else {
+                $("input[name='update_check_enabled']").disabled = false;
+                toggle_update_enable_notice(false);
+            }
+
+            setCheckUpdate(items.updateCheck);
+            setCheckUpdateEnabledOnly(items.updateCheckEnabledOnly);
+        }, function (response) {
+            disable_update_check();
+        });
+
+        setReleaseNotes(items.showReleaseNotes);
+    });
+
+    if (COMPAT.SYNC_STORAGE) {
+        updateSynchronizationStatus();
+    }
+    else {
+        $('a[data-i18n="synchronization"]').parentNode.remove();
+        $('#synchronize_extensions_yes').closest('dl').style.display = 'none';
+    }
+
+    chrome.storage.local.get(DEFAULT_LOCAL_OPTIONS, function (items) {
+        if (items.syncExtensions) {
+            chrome.permissions.contains({
+                permissions: ["idle"]
+            }, function (result) {
+                setSyncExtensions(result);
+            });
+        }
+        else if (COMPAT.SYNC_STORAGE) {
+            setSyncExtensions(false);
+        }
+
+        setLightIcon(items.useLightIcon);
+    });
 }
 
-function retrieveUpdateTimes()
-{
-       chrome.storage.local.get({
-               lastUpdateCheck: null
-       }, function (items) {
-               if(items.lastUpdateCheck)
-               {
-                       $('#last_update_check').innerText = items.lastUpdateCheck;
-               }
-               else
-               {
-                       $('#last_update_check').innerText = m('never');
-               }
-       });
-
-       retrieveNextUpdateTime();
+function retrieveUpdateTimes() {
+    chrome.storage.local.get({
+        lastUpdateCheck: null
+    }, function (items) {
+        if (items.lastUpdateCheck) {
+            $('#last_update_check').innerText = items.lastUpdateCheck;
+        }
+        else {
+            $('#last_update_check').innerText = m('never');
+        }
+    });
+
+    retrieveNextUpdateTime();
 }
 
-function retrieveNextUpdateTime()
-{
-       chrome.alarms.get(ALARM_UPDATE_CHECK, function (alarm) {
-               if (alarm)
-               {
-                       $('#next_update_check').innerText = new Date(alarm.scheduledTime).toLocaleString();
-               }
-               else
-               {
-                       $('#next_update_check').innerText = m('never');
-               }
-       });
+function retrieveNextUpdateTime() {
+    chrome.alarms.get(ALARM_UPDATE_CHECK, function (alarm) {
+        if (alarm) {
+            $('#next_update_check').innerText = new Date(alarm.scheduledTime).toLocaleString();
+        }
+        else {
+            $('#next_update_check').innerText = m('never');
+        }
+    });
 }
 
-function setCheckUpdate(result)
-{
-       if(result)
-               $('#update_check_yes').checked = true;
-       else
-               $('#update_check_no').checked = true;
+function setCheckUpdate(result) {
+    if (result)
+        $('#update_check_yes').checked = true;
+    else
+        $('#update_check_no').checked = true;
 }
 
-function setCheckUpdateEnabledOnly(result)
-{
-       if(result)
-               $('#update_check_enabled_yes').checked = true;
-       else
-               $('#update_check_enabled_no').checked = true;
+function setCheckUpdateEnabledOnly(result) {
+    if (result)
+        $('#update_check_enabled_yes').checked = true;
+    else
+        $('#update_check_enabled_no').checked = true;
 }
 
-function setLightIcon(result)
-{
-       if(result)
-               $('#use_light_icon_yes').checked = true;
-       else
-               $('#use_light_icon_no').checked = true;
+function setLightIcon(result) {
+    if (result)
+        $('#use_light_icon_yes').checked = true;
+    else
+        $('#use_light_icon_no').checked = true;
 }
 
-function setReleaseNotes(result)
-{
-       if(result)
-               $('#show_release_notes_yes').checked = true;
-       else
-               $('#show_release_notes_no').checked = true;
+function setReleaseNotes(result) {
+    if (result)
+        $('#show_release_notes_yes').checked = true;
+    else
+        $('#show_release_notes_no').checked = true;
 }
 
-function setSyncExtensions(result)
-{
-       if(result)
-               $('#synchronize_extensions_yes').checked = true;
-       else
-               $('#synchronize_extensions_no').checked = true;
+function setSyncExtensions(result) {
+    if (result)
+        $('#synchronize_extensions_yes').checked = true;
+    else
+        $('#synchronize_extensions_no').checked = true;
 }
 
-function handleSynchronize()
-{
-       if($('#synchronize_extensions_yes').checked)
-       {
-               chrome.permissions.request({
-                       permissions: ["idle"]
-               }, function(granted) {
-                       if(granted)
-                       {
-                               if(!COMPAT.PERMISSIONS_EVENTS)
-                               {
-                                       chrome.runtime.sendMessage(GS_CHROME_ID, 
MESSAGE_IDLE_PERMISSION_ADDED);
-                               }
-
-                               chrome.storage.sync.get({
-                                       extensions: {}
-                               }, function (options) {
-                                       if(!isEmptyObject(options.extensions))
-                                       {
-                                               document.getElementById('syncChoice').showModal();
-                                       }
-                               });
-                       }
-                       else
-                       {
-                               if(!COMPAT.PERMISSIONS_EVENTS)
-                               {
-                                       chrome.runtime.sendMessage(GS_CHROME_ID, 
MESSAGE_IDLE_PERMISSION_REMOVED);
-                               }
-
-                               setSyncExtensions(false);
-                       }
-               });
-       }
-       else
-       {
-               chrome.permissions.remove({
-                       permissions: ["idle"]
-               }, function(removed) {
-                       if(removed && !COMPAT.PERMISSIONS_EVENTS)
-                       {
-                               chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_IDLE_PERMISSION_REMOVED);
-                       }
-
-                       setSyncExtensions(!removed);
-               });
-       }
+function handleSynchronize() {
+    if ($('#synchronize_extensions_yes').checked) {
+        chrome.permissions.request({
+            permissions: ["idle"]
+        }, function (granted) {
+            if (granted) {
+                if (!COMPAT.PERMISSIONS_EVENTS) {
+                    chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_IDLE_PERMISSION_ADDED);
+                }
+
+                chrome.storage.sync.get({
+                    extensions: {}
+                }, function (options) {
+                    if (!isEmptyObject(options.extensions)) {
+                        document.getElementById('syncChoice').showModal();
+                    }
+                });
+            }
+            else {
+                if (!COMPAT.PERMISSIONS_EVENTS) {
+                    chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_IDLE_PERMISSION_REMOVED);
+                }
+
+                setSyncExtensions(false);
+            }
+        });
+    }
+    else {
+        chrome.permissions.remove({
+            permissions: ["idle"]
+        }, function (removed) {
+            if (removed && !COMPAT.PERMISSIONS_EVENTS) {
+                chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_IDLE_PERMISSION_REMOVED);
+            }
+
+            setSyncExtensions(!removed);
+        });
+    }
 }
 
-function updateSynchronizationStatus()
-{
-       GSC.sync.getExtensions().then((extensions) => {
-               var keys = Object.keys(extensions).sort(function (a, b) {
-                       var nameA = extensions[a].name.toLowerCase();
-                       var nameB = extensions[b].name.toLowerCase();
-
-                       if (nameA < nameB)
-                       {
-                               return -1;
-                       }
-
-                       if (nameA > nameB)
-                       {
-                               return 1;
-                       }
-
-                       return 0;
-               });
-
-               empty($('#synchronization table tbody'));
-               for (const [key, uuid] of Object.entries(keys)) {
-                       var extension = extensions[uuid];
-
-                       $('#synchronization table tbody').insertAdjacentHTML(
-                               'beforeEnd',
-                               `<tr>
+function updateSynchronizationStatus() {
+    GSC.sync.getExtensions().then((extensions) => {
+        var keys = Object.keys(extensions).sort(function (a, b) {
+            var nameA = extensions[a].name.toLowerCase();
+            var nameB = extensions[b].name.toLowerCase();
+
+            if (nameA < nameB) {
+                return -1;
+            }
+
+            if (nameA > nameB) {
+                return 1;
+            }
+
+            return 0;
+        });
+
+        empty($('#synchronization table tbody'));
+        for (const [key, uuid] of Object.entries(keys)) {
+            var extension = extensions[uuid];
+
+            $('#synchronization table tbody').insertAdjacentHTML(
+                'beforeEnd',
+                `<tr>
                                        <td>${extension.name}</td>
                                        <td class='${extension.local && 'ok' || 'fail'}'></td>
                                        <td class='${extension.localState == EXTENSION_STATE.ENABLED && 'ok' 
|| 'fail'}'></td>
                                        <td class='${extension.remote && 'ok' || 'fail'}'></td>
                                </tr>`
-                       );
-               };
-       }).catch((message) => {
-               showWithDelay($('#error'), 15000, message);
-       });
+            );
+        };
+    }).catch((message) => {
+        showWithDelay($('#error'), 15000, message);
+    });
 }
 
 i18n();
@@ -372,58 +328,49 @@ document.addEventListener('DOMContentLoaded', restore_options);
 document.getElementById('save').addEventListener('click', save_options);
 
 document.getElementsByName('synchronize_extensions').forEach((control) => {
-       control.addEventListener('change', handleSynchronize);
+    control.addEventListener('change', handleSynchronize);
 });
 
 
-document.getElementById('syncChoice').addEventListener('close', function() {
-       if(document.getElementById('syncChoice').returnValue === 'cancel')
-       {
-               chrome.permissions.remove({
-                       permissions: ["idle"]
-               }, function(removed) {
-                       if(removed && !COMPAT.PERMISSIONS_EVENTS)
-                       {
-                               chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_IDLE_PERMISSION_REMOVED);
-                       }
-
-                       setSyncExtensions(!removed);
-               });
-       }
+document.getElementById('syncChoice').addEventListener('close', function () {
+    if (document.getElementById('syncChoice').returnValue === 'cancel') {
+        chrome.permissions.remove({
+            permissions: ["idle"]
+        }, function (removed) {
+            if (removed && !COMPAT.PERMISSIONS_EVENTS) {
+                chrome.runtime.sendMessage(GS_CHROME_ID, MESSAGE_IDLE_PERMISSION_REMOVED);
+            }
+
+            setSyncExtensions(!removed);
+        });
+    }
 });
 
-if(!$('#translation_credits div').firstChild)
-{
-       $('.translation_credits_container').remove();
+if (!$('#translation_credits div').firstChild) {
+    $('.translation_credits_container').remove();
 }
 
 chrome.storage.onChanged.addListener(function (changes, areaName) {
-       if (areaName === 'local')
-       {
-               if(changes.lastUpdateCheck && changes.lastUpdateCheck.newValue)
-               {
-                       $('#last_update_check').innerText = changes.lastUpdateCheck.newValue;
-               }
-       }
-
-       if (areaName === 'sync' && changes.extensions)
-       {
-               updateSynchronizationStatus();
-       }
+    if (areaName === 'local') {
+        if (changes.lastUpdateCheck && changes.lastUpdateCheck.newValue) {
+            $('#last_update_check').innerText = changes.lastUpdateCheck.newValue;
+        }
+    }
+
+    if (areaName === 'sync' && changes.extensions) {
+        updateSynchronizationStatus();
+    }
 });
 
 chrome.runtime.onMessage.addListener(
-       function (request, sender, sendResponse) {
-               if(sender.id && sender.id === GS_CHROME_ID && request)
-               {
-                       if(request === MESSAGE_NEXT_UPDATE_CHANGED)
-                       {
-                               retrieveNextUpdateTime();
-                       }
-                       else if(request.signal && request.signal === SIGNAL_EXTENSION_CHANGED)
-                       {
-                               updateSynchronizationStatus();
-                       }
-               }
-       }
+    function (request, sender, sendResponse) {
+        if (sender.id && sender.id === GS_CHROME_ID && request) {
+            if (request === MESSAGE_NEXT_UPDATE_CHANGED) {
+                retrieveNextUpdateTime();
+            }
+            else if (request.signal && request.signal === SIGNAL_EXTENSION_CHANGED) {
+                updateSynchronizationStatus();
+            }
+        }
+    }
 );


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]