« get me outta code hell

Popup UI - interactive-bgm - Browser extension that adds background music based on the site you're browsing
about summary refs log tree commit diff
path: root/extension
diff options
context:
space:
mode:
authorFlorrie <towerofnix@gmail.com>2019-03-22 21:03:44 -0300
committerFlorrie <towerofnix@gmail.com>2019-03-22 21:03:44 -0300
commit951499dba4ea173ba4c1f08b956e5d558999da45 (patch)
tree7adae99d03bf9025063637c6fe7f8ea9eb80e759 /extension
parent3878c62bb16991ba2dab0bf069b0a67ad53d9106 (diff)
Popup UI
Diffstat (limited to 'extension')
-rw-r--r--extension/background.js24
-rw-r--r--extension/manifest.json4
-rw-r--r--extension/popup/index.html23
-rw-r--r--extension/popup/main.js162
-rw-r--r--extension/popup/style.css110
5 files changed, 307 insertions, 16 deletions
diff --git a/extension/background.js b/extension/background.js
index 020a2be..9b7db26 100644
--- a/extension/background.js
+++ b/extension/background.js
@@ -26,18 +26,14 @@ port.onDisconnect.addListener(() => {
 });
 
 browser.runtime.onMessage.addListener(({hostname}) => {
-    const map = {
-        'scratch.mit.edu': ['mantis'],
-        'stackoverflow.com': ['bass', 'main'],
-        'www.youtube.com': []
-    };
-
-    const mode = map[hostname];
-
-    if (mode) {
-        console.log('BGM:', mode);
-        port.postMessage(mode.map(track => ({track, volume: 100})));
-    } else {
-        console.log('No BGM found for ' + location.hostname);
-    }
+    browser.storage.sync.get('siteSettings').then(({siteSettings}) => {
+        const mode = siteSettings[hostname];
+
+        if (mode) {
+            console.log('BGM:', mode);
+            port.postMessage(mode.map(track => ({track, volume: 100})));
+        } else {
+            console.log('No BGM found for ' + hostname);
+        }
+    });
 });
diff --git a/extension/manifest.json b/extension/manifest.json
index 27cafda..d949ee5 100644
--- a/extension/manifest.json
+++ b/extension/manifest.json
@@ -7,7 +7,9 @@
 
     "permissions": [
         "activeTab",
-        "nativeMessaging"
+        "nativeMessaging",
+        "storage",
+        "tabs"
     ],
 
     "applications": {
diff --git a/extension/popup/index.html b/extension/popup/index.html
index e6cf5e5..9ddbec4 100644
--- a/extension/popup/index.html
+++ b/extension/popup/index.html
@@ -1 +1,22 @@
-<p>Nice.</p>
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>Interactive BGM</title>
+        <link rel="stylesheet" href="style.css">
+    </head>
+    <body>
+        <div class="screen visible" id="loading-screen">
+            <p>Loading...</p>
+        </div>
+        <div class="screen" id="main-screen">
+            <h1 id="hostname"></h1>
+            <h2>Tracks</h2>
+            <ul id="track-list"></ul>
+        </div>
+        <div class="screen" id="invalid-host-screen">
+            <p>Sorry, this page doesn't appear to have a hostname. We can't configure music here.</p>
+        </div>
+        <script src="main.js"></script>
+    </body>
+</html>
diff --git a/extension/popup/main.js b/extension/popup/main.js
new file mode 100644
index 0000000..ad1475a
--- /dev/null
+++ b/extension/popup/main.js
@@ -0,0 +1,162 @@
+function changeScreen(id) {
+    for (const screen of document.getElementsByClassName('screen')) {
+        if (screen.id === id) {
+            screen.classList.add('visible');
+        } else {
+            screen.classList.remove('visible');
+        }
+    }
+}
+
+function loadTrackList(opts) {
+    const {hostname, siteSettings} = opts;
+    const site = siteSettings[hostname] || [];
+    return browser.storage.sync.get('tracks').then(({tracks = []}) => {
+        const ul = document.getElementById('track-list');
+        while (ul.firstChild) {
+            ul.removeChild(ul.firstChild);
+        }
+
+        tracks.sort();
+
+        for (const track of tracks) {
+            const li = document.createElement('li');
+            ul.appendChild(li);
+
+            li.classList.add('track');
+
+            const label = document.createElement('label');
+            li.appendChild(label);
+
+            const checkbox = document.createElement('input');
+            label.appendChild(checkbox);
+
+            checkbox.type = 'checkbox';
+            checkbox.checked = site.includes(track);
+            checkbox.title = `Toggles whether the track "${track}" will play when this site is opened.`
+
+            checkbox.addEventListener('click', () => {
+                if (checkbox.checked) {
+                    if (!site.includes(track)) {
+                        site.push(track);
+                    }
+                } else {
+                    if (site.includes(track)) {
+                        site.splice(site.indexOf(track), 1);
+                    }
+                }
+
+                if (!siteSettings[hostname]) {
+                    siteSettings[hostname] = site;
+                }
+
+                disableButton.style.display = 'inline-block';
+
+                browser.storage.sync.set({siteSettings})
+                    .then(() => browser.runtime.sendMessage({hostname}));
+            });
+
+            label.appendChild(document.createTextNode(' ' + track));
+
+            const deleteButton = document.createElement('button');
+            li.appendChild(deleteButton);
+
+            deleteButton.appendChild(document.createTextNode('Delete...'));
+            deleteButton.title = `Deletes the track from all sites. You will be confirmed first.`;
+
+            deleteButton.addEventListener('click', () => {
+                if (confirm(`This will delete "${track}" from ALL sites - this cannot be undone. Are you sure?`)) {
+                    changeScreen('loading-screen');
+                    browser.storage.sync.set({tracks: tracks.filter(t => t !== track)})
+                        .then(() => loadTrackList(opts))
+                        .then(() => changeScreen('main-screen'));
+                }
+            });
+        }
+
+        const actionLi = document.createElement('li');
+        ul.appendChild(actionLi);
+
+        actionLi.classList.add('action');
+
+        const addButton = document.createElement('button');
+        actionLi.appendChild(addButton);
+
+        addButton.appendChild(document.createTextNode('Create Track'));
+        addButton.title = `Creates a new track, which will be an option present in all sites.`;
+
+        let newTrackInput = null;
+        addButton.addEventListener('click', () => {
+            if (newTrackInput) {
+                newTrackInput.focus();
+                return;
+            }
+
+            const li = document.createElement('li');
+            li.classList.add('track');
+            ul.insertBefore(li, actionLi);
+
+            newTrackInput = document.createElement('input');
+            li.appendChild(newTrackInput);
+
+            const saveButton = document.createElement('button');
+            li.appendChild(saveButton);
+
+            saveButton.appendChild(document.createTextNode('Save'));
+
+            saveButton.addEventListener('click', () => {
+                while (li.firstChild) {
+                    li.removeChild(li.firstChild);
+                }
+                li.appendChild(document.createTextNode('Saving...'));
+
+                const name = newTrackInput.value.trim();
+                if (name.length) {
+                    changeScreen('loading-screen');
+                    browser.storage.sync.set({tracks: tracks.concat([name])})
+                        .then(() => loadTrackList(opts))
+                        .then(() => changeScreen('main-screen'));
+                }
+            });
+
+            newTrackInput.focus();
+        });
+
+        const disableButton = document.createElement('button');
+        actionLi.appendChild(disableButton);
+
+        disableButton.appendChild(document.createTextNode('Disable Site'));
+        disableButton.title = `Removes the entry for this site altogether. It won't change BGM when you open it again.`;
+
+        disableButton.addEventListener('click', () => {
+            changeScreen('loading-screen');
+            delete siteSettings[hostname];
+            browser.storage.sync.set({siteSettings})
+                .then(() => loadTrackList(opts))
+                .then(() => changeScreen('main-screen'));
+        });
+
+        if (!(hostname in siteSettings)) {
+            disableButton.style.display = 'none';
+        }
+    });
+}
+
+Promise.all([
+    browser.tabs.query({active: true, currentWindow: true})
+        .then(([tab]) => {
+            const url = new URL(tab.url);
+            document.getElementById('hostname').appendChild(document.createTextNode(url.hostname));
+            return url.hostname;
+        }),
+    browser.storage.sync.get('siteSettings')
+        .then(({siteSettings = {}}) => siteSettings)
+])
+    .then(([hostname, siteSettings]) => {
+        if (hostname) {
+            return loadTrackList({hostname, siteSettings})
+                .then(() => changeScreen('main-screen'));
+        } else {
+            changeScreen('invalid-host-screen');
+        }
+    });
diff --git a/extension/popup/style.css b/extension/popup/style.css
new file mode 100644
index 0000000..147a94e
--- /dev/null
+++ b/extension/popup/style.css
@@ -0,0 +1,110 @@
+body, html {
+    width: 100%;
+    height: 100%;
+    padding: 0;
+    margin: 0;
+    min-width: 300px;
+    max-width: 400px;
+}
+
+body {
+    background-color: #EEEEEE;
+    color: black;
+    font-family: Helvetica, Arial, sans-serif;
+}
+
+label {
+    font-weight: 800;
+}
+
+input[type=checkbox] {
+    width: 13px;
+    height: 13px;
+    padding: 0;
+    margin: 0;
+    position: relative;
+    top: 1px;
+}
+
+input, button {
+    margin-right: 4px;
+    margin-left: 4px;
+}
+
+ul {
+    margin: 4px 0;
+}
+
+li {
+    padding: 3px;
+}
+
+li:nth-child(even) {
+    background-color: white;
+}
+
+li:nth-child(odd) {
+    background-color: #DDDDDD;
+}
+
+h1 {
+    margin: 2px 0;
+    font-size: 1.2em;
+    text-align: center;
+}
+
+h2 {
+    font-size: 0.9em;
+    margin: 2px 0;
+    text-align: center;
+    overflow: hidden;
+}
+
+h2:before, h2:after {
+    background-color: black;
+    content: '';
+    display: inline-block;
+    height: 1px;
+    position: relative;
+    vertical-align: middle;
+    width: 50%;
+}
+
+h2:before {
+    right: 0.5em;
+    margin-left: -50%;
+}
+
+h2:after {
+    left: 0.5em;
+    margin-right: -50%;
+}
+
+.screen {
+    width: 100%;
+    height: 100%;
+    padding: 5px;
+    box-sizing: border-box;
+}
+
+.screen:not(.visible) {
+    display: none;
+}
+
+#loading-screen p, #invalid-host-screen {
+    text-align: center;
+    font-style: oblique;
+}
+
+#track-list {
+    list-style: none;
+    padding-left: 0;
+}
+
+#track-list li.track button {
+    float: right;
+}
+
+#track-list li.action {
+    text-align: center;
+}