diff sidebar/js/tab-collection-manager.js @ 0:d13d59494613

Initial revision
author Guido Berhoerster <guido+set-aside@berhoerster.name>
date Sat, 17 Nov 2018 10:44:16 +0100
parents
children b0827360b8e4
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sidebar/js/tab-collection-manager.js	Sat Nov 17 10:44:16 2018 +0100
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2018 Guido Berhoerster <guido+set-aside@berhoerster.name>
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+'use strict';
+
+var tabManager;
+
+class TabManager {
+    constructor() {
+        this.tabCollectionTemplate =
+                document.querySelector('#tab-collection-template');
+        this.tabItemTemplate = document.querySelector('#tab-item-template');
+        this.tabCollectionsElement = document.querySelector('#tab-collections');
+        this.port = browser.runtime.connect({name: 'tab-collection-manager'});
+        this.port.onMessage.addListener(this.onMessage.bind(this));
+        this.port.onDisconnect.addListener(this.onMessage.bind(this));
+        this.port.postMessage({type: 'getTabCollections'});
+        this.isInitialized = false;
+    }
+
+    initTabCollections(tabCollections) {
+        if (this.isInitialized) {
+            return;
+        }
+
+        for (let tabCollection of tabCollections.values()) {
+            this.prependTabCollection(tabCollection);
+        }
+        this.sortTabCollections();
+
+        document.querySelector('#message').textContent =
+                browser.i18n.getMessage('emptySidebarMessage');
+
+        document.body.addEventListener('click', this);
+
+        this.isInitialized = true;
+    }
+
+    createTabCollectionNode(tabCollection) {
+        let tabCollectionNode =
+                document.importNode(this.tabCollectionTemplate.content, true);
+
+        tabCollectionNode.querySelector('.tab-collection')
+                .dataset.tabCollectionUuid = tabCollection.uuid;
+
+        tabCollectionNode.querySelector('.tab-collection-title').textContent =
+                browser.i18n.getMessage('collectionTitle',
+                tabCollection.tabs.size);
+
+        let tabCollectionCtimeElement =
+                tabCollectionNode.querySelector('.tab-collection-ctime');
+        tabCollectionCtimeElement.dateTime = tabCollection.date.toISOString();
+        tabCollectionCtimeElement.textContent =
+                tabCollection.date.toLocaleString();
+
+        let tabCollectionRestoreElement =
+                tabCollectionNode.querySelector('.restore-tab-collection');
+        tabCollectionRestoreElement.title =
+                tabCollectionRestoreElement.textContent =
+                browser.i18n.getMessage('restoreTabsButtonTitle');
+        tabCollectionNode.querySelector('.remove-tab-collection').title =
+                browser.i18n.getMessage('removeTabsButtonTitle');
+
+        let tabListElement =
+                tabCollectionNode.querySelector('.tab-collection-tabs');
+        for (let tab of tabCollection.tabs.values()) {
+            let tabItemNode = document.importNode(this.tabItemTemplate.content,
+                    true);
+
+            tabItemNode.querySelector('.tab-item').dataset.tabUuid = tab.uuid;
+
+            let tabLinkElement = tabItemNode.querySelector('.tab-link');
+            tabLinkElement.href = tab.url;
+            tabLinkElement.title = tab.title;
+
+            if (tab.thumbnailUrl !== null) {
+                tabItemNode.querySelector('.tab-thumbnail').src =
+                        tab.thumbnailUrl;
+            }
+
+            if (tab.favIconUrl !== null) {
+                tabItemNode.querySelector('.tab-favicon').src = tab.favIconUrl;
+            }
+
+            tabItemNode.querySelector('.tab-title').textContent = tab.title;
+
+            tabItemNode.querySelector('.remove-tab').title =
+                    browser.i18n.getMessage('removeTabTitle');
+
+            tabListElement.append(tabItemNode);
+        }
+
+        return tabCollectionNode;
+    }
+
+    prependTabCollection(tabCollection) {
+        console.log('prepending tab collection', tabCollection,
+                'to tab collections');
+        this.tabCollectionsElement
+                .prepend(this.createTabCollectionNode(tabCollection));
+    }
+
+    replaceTabCollection(tabCollection) {
+        console.log('replacing tab collection', tabCollection);
+        this.tabCollectionsElement.querySelector(`[data-tab-collection-uuid=` +
+                `"${tabCollection.uuid}"]`)
+                .replaceWith(this.createTabCollectionNode(tabCollection));
+    }
+
+    removeTabCollection(tabCollectionUuid) {
+        console.log('removing tab collection %s', tabCollectionUuid);
+        this.tabCollectionsElement
+                .querySelector(`[data-tab-collection-uuid=` +
+                `"${tabCollectionUuid}"]`)
+                .remove();
+
+        if (this.tabCollectionsElement.childElementCount === 0) {
+            // remove any text nodes so that the :empty CSS selectora applies
+            while (this.tabCollectionsElement.firstChild !== null) {
+                this.tabCollectionsElement
+                        .removeChild(this.tabCollectionsElement.firstChild);
+            }
+        }
+    }
+
+    sortTabCollections() {
+        Array.from(this.tabCollectionsElement.children)
+                .map(element =>
+                [element.querySelector('.tab-collection-ctime').dateTime,
+                element])
+                .sort((a, b) => a[0] < b[0] ? 1 : a[0] > b[0] ? -1 : 0)
+                .forEach(([, element]) =>
+                this.tabCollectionsElement.append(element));
+    }
+
+    onMessage(message, port) {
+        console.log('received message', message, 'on port', port);
+        switch (message.type) {
+            case 'tabCollections':
+                this.initTabCollections(message.tabCollections);
+                break;
+            case 'tabCollectionCreated':
+                this.prependTabCollection(message.tabCollection);
+                break;
+            case 'tabCollectionRemoved':
+                this.removeTabCollection(message.tabCollectionUuid);
+                break;
+            case 'tabCollectionChanged':
+                this.replaceTabCollection(message.tabCollection);
+                break;
+        }
+        this.sortTabCollections();
+    }
+
+    handleEvent(ev) {
+        console.log('DOM event', ev);
+        if (ev.type === 'click') {
+            ev.preventDefault();
+            if (ev.target.classList.contains('restore-tab-collection')) {
+                // restore tab collection
+                let tabCollectionUuid = ev.target.closest('.tab-collection')
+                        .dataset.tabCollectionUuid;
+                this.port.postMessage({
+                    type: 'restoreTabCollection',
+                    tabCollectionUuid,
+                    windowId: browser.windows.WINDOW_ID_CURRENT
+                });
+            } else if (ev.target.classList.contains('remove-tab-collection')) {
+                // remove tab collection
+                let tabCollectionUuid = ev.target.closest('.tab-collection')
+                        .dataset.tabCollectionUuid;
+                this.port.postMessage({
+                    type: 'removeTabCollection',
+                    tabCollectionUuid
+                });
+            } else if (ev.target.classList.contains('remove-tab')) {
+                // remove tab from collection
+                let tabItemElement = ev.target.closest('.tab-item');
+                let tabCollectionUuid =
+                        tabItemElement.closest('.tab-collection')
+                        .dataset.tabCollectionUuid;
+                let tabUuid = tabItemElement.dataset.tabUuid;
+                this.port.postMessage({
+                    type: 'removeTab',
+                    tabCollectionUuid,
+                    tabUuid
+                });
+            } else {
+                let tabItemElement = ev.target.closest('.tab-item');
+                if (tabItemElement !== null) {
+                    // restore tab from collection
+                    let tabCollectionUuid =
+                            tabItemElement.closest('.tab-collection')
+                            .dataset.tabCollectionUuid;
+                    let tabUuid = tabItemElement.dataset.tabUuid;
+                    this.port.postMessage({
+                        type: 'restoreTab',
+                        tabCollectionUuid,
+                        tabUuid,
+                        windowId: browser.windows.WINDOW_ID_CURRENT
+                    });
+                }
+            }
+        }
+    }
+}
+
+browser.windows.getCurrent().then(currentWindow => {
+    // disable the sidebar for incognito windows
+    if (currentWindow.incognito) {
+        document.querySelector('#message').textContent =
+                browser.i18n.getMessage('incognitoModeMessage');
+        return;
+    }
+
+    tabManager = new TabManager();
+});