22 Commits

Author SHA1 Message Date
s2
75e6a73f7f v0.0.8 2017-12-13 10:31:28 +01:00
s2
bd501edba3 ignore hosts option 2017-12-13 10:30:18 +01:00
s2
52e7e13957 v0.0.7 2017-12-13 09:04:28 +01:00
s2
e3fc267821 fix favicon size 2017-12-13 09:04:14 +01:00
s2
2c81a30231 v0.0.6 2017-12-13 08:24:16 +01:00
s2
352131be4f ws 2017-12-13 08:23:50 +01:00
s2
65aadb4624 don't clutter the page with favicons 2017-12-13 08:22:37 +01:00
s2
ebeeab9ed5 v0.0.5 2017-12-12 22:31:55 +01:00
s2
1f8fb529d6 fix icons 2017-12-12 22:28:29 +01:00
s2
56c58896b8 reformat 2017-12-12 15:00:45 +01:00
s2
ac83798388 v0.0.4 2017-12-12 14:24:25 +01:00
s2
ad4af7871a add options 2017-12-12 14:22:32 +01:00
s2
01aa8eba44 make indicator larger 2017-12-12 09:36:51 +01:00
s2
594e53b38f screenshot 2017-12-12 09:20:19 +01:00
s2
b393e4f859 v0.0.3 2017-12-12 09:01:00 +01:00
s2
ffa5b59615 handle no favicon 2017-12-12 09:00:41 +01:00
s2
e73e806dca readme 2017-12-12 08:34:23 +01:00
s2
0a00b1c1f1 v0.0.2 2017-12-12 08:28:08 +01:00
s2
41d70eb3f0 handle other tab events 2017-12-12 08:27:40 +01:00
s2
724bec321b fix updateAllColorsOnAllTabs 2017-12-12 08:21:31 +01:00
s2
90f7108eee icons 2017-12-12 08:21:31 +01:00
s2
c56454a097 just text 2017-12-12 08:21:25 +01:00
10 changed files with 176 additions and 44 deletions

View File

@@ -2,6 +2,8 @@
## What it does ## What it does
**Please install [Tree Style Tab](https://addons.mozilla.org/firefox/addon/tree-style-tab/) before installing this extension, because this extension depends on it!**
This addon would like to color tabs based on the parent tab that opened the tab. This addon would like to color tabs based on the parent tab that opened the tab.
So say I am at work searching for a solution to a javascript problem on stackoverflow, so I open a bunch of tabs with possible solutions. Then I get distracted, and I start looking for honey badger images on google images, I open a bunch of tabs with honey badger images. So say I am at work searching for a solution to a javascript problem on stackoverflow, so I open a bunch of tabs with possible solutions. Then I get distracted, and I start looking for honey badger images on google images, I open a bunch of tabs with honey badger images.
Now all my tabs are mixed up with javascript snippets and honey badgers. Now all my tabs are mixed up with javascript snippets and honey badgers.
@@ -12,4 +14,7 @@ At the moment this is not possible because of Firefox bug [1320585](https://bugz
So this extension **tries** to get the favicon of the newly opened tab, and changes the color of the favicon to match that of the parent. So this extension **tries** to get the favicon of the newly opened tab, and changes the color of the favicon to match that of the parent.
**Please install [Tree Style Tab](https://addons.mozilla.org/firefox/addon/tree-style-tab/) before installing this extension, because this extension depends on it!** But it will not work
- on pages that don't allow content scripts (amo for example)
- on pages that dynamically change the favicon
- a lot of other cases

119
src/bg.js
View File

@@ -1,40 +1,45 @@
const kTST_ID = 'treestyletab@piro.sakura.ne.jp'; const kTST_ID = 'treestyletab@piro.sakura.ne.jp';
const MY_EXTENSION_NAME = 'tab-groupcolor'; const MY_EXTENSION_NAME = 'tab-groupcolor';
let tabIcons = {};
var changeIcon = function(color) { var changeIcon = function(color, currentIcon, options) {
var getFavicon = function(){
var favicon = undefined;
var nodeList = document.getElementsByTagName("link");
for (var i = 0; i < nodeList.length; i++)
{
if ((nodeList[i].getAttribute("rel") == "icon") || (nodeList[i].getAttribute("rel") == "shortcut icon")) {
favicon = nodeList[i].getAttribute("href");
}
}
return favicon;
};
var canvas = document.createElement('canvas'); var canvas = document.createElement('canvas');
canvas.width = 16;
canvas.height = 16;
var ctx = canvas.getContext('2d'); var ctx = canvas.getContext('2d');
var img = new Image(); var img = new Image();
img.src = getFavicon();
if (currentIcon && typeof(currentIcon) !== 'undefined' && currentIcon !== null && currentIcon !== 'undefined') {
img.src = currentIcon;
} else {
img.src = 'data:image/x-icon;base64,AAABAAEAEBACAAEAAQCwAAAAFgAAACgAAAAQAAAAIAAAAAEAAQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA';
}
img.onload = function() { img.onload = function() {
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
ctx.drawImage(img, 0, 0); ctx.drawImage(img, 0, 0);
ctx.fillStyle = color; ctx.fillStyle = color;
ctx.fillRect(0, 0, 2, 16); if (options.globals.orientation === 'vertical') {
ctx.fillRect(0, 0, (options.globals.width / 16) * canvas.width, canvas.height);
} else {
ctx.fillRect(0, 0, canvas.width, (options.globals.width / 16) * canvas.height);
}
var link = document.createElement('link'); var link = document.createElement('link');
link.type = 'image/x-icon'; link.type = 'image/x-icon';
link.rel = 'shortcut icon'; link.rel = 'shortcut icon';
link.href = canvas.toDataURL("image/x-icon"); link.href = canvas.toDataURL("image/x-icon");
link.id = 'tab-groupcolor' + '-favicon';
var oldicon = document.getElementById('tab-groupcolor' + '-favicon');
if (oldicon) {
oldicon.outerHTML = '';
delete oldicon;
}
document.getElementsByTagName('head')[0].appendChild(link); document.getElementsByTagName('head')[0].appendChild(link);
} }
}; };
var generateRandomColor = function(seed) { var generateRandomColor = function(seed) {
var selectColor = function (colorNum, colors){ var selectColor = function (colorNum, colors) {
if (colors < 1) { if (colors < 1) {
colors = 1; // defaults to one color - avoid divide by zero colors = 1; // defaults to one color - avoid divide by zero
} }
@@ -63,12 +68,23 @@ var getTabParent = (tabs, id, currentTopLevelTabPos) => {
for (let i = 0; i < tabs.length; i++) { for (let i = 0; i < tabs.length; i++) {
//on a root node because there is no opener //on a root node because there is no opener
if (typeof(tabs[i].openerTabId) === 'undefined' || tabs[i].openerTabId === tabs[i].id) { if (!tabs[i].openerTabId || typeof(tabs[i].openerTabId) === 'undefined' || tabs[i].openerTabId === tabs[i].id) {
currentTopLevelTabPos = i; currentTopLevelTabPos = i;
} }
if (tabs[i].id === id) { if (tabs[i].id === id) {
return currentTopLevelTabPos;
//get original favicon for this tab
let orginalFavIconUrl = tabIcons[id];
if (!orginalFavIconUrl) {
orginalFavIconUrl = tabs[i].favIconUrl;
tabIcons[id] = orginalFavIconUrl;
}
return {
parentIndex: currentTopLevelTabPos,
faviconUrl: orginalFavIconUrl
};
} else { } else {
if (tabs[i].children && tabs[i].children.length > 0) { if (tabs[i].children && tabs[i].children.length > 0) {
let ret = getTabParent(tabs[i].children, id, currentTopLevelTabPos); let ret = getTabParent(tabs[i].children, id, currentTopLevelTabPos);
@@ -85,16 +101,36 @@ var updateAllColorsOnAllTabs = async () => {
allWindows.forEach(async w => { allWindows.forEach(async w => {
var tstTabs = await browser.runtime.sendMessage(kTST_ID, { var tstTabs = await browser.runtime.sendMessage(kTST_ID, {
type: 'get-tree', type: 'get-tree',
window: w.id window: w.id
}); });
for (let i = 0; i < tstTabs.length; i++) { var changeTabs = async (tabs) => {
if (tstTabs[i].status === 'complete') {
browser.tabs.executeScript(tstTabs[i].id, { for (let i = 0; i < tabs.length; i++) {
code: '(' + changeIcon.toString() + ')("' + generateRandomColor(getTabParent(tstTabs, tstTabs[i].id)) + '")'
}); if (tabs[i].status === 'complete') {
let t = getTabParent(tstTabs, tabs[i].id);
let options = await loadOptions();
let tabHost = new URL(tabs[i].url).host;
if (tabHost) {
tabHost = tabHost.toLowerCase();
}
if (!(options.ignore && options.ignore.split('\n').includes(tabHost))) {
browser.tabs.executeScript(tabs[i].id, {
code: '(' + changeIcon.toString() + ')' +
'("' + generateRandomColor(t.parentIndex) + '", "' + t.faviconUrl + '", ' + JSON.stringify(options) + ')'
});
}
}
if (tabs[i].children && tabs[i].children.length > 0) {
await changeTabs(tabs[i].children);
}
} }
} };
await changeTabs(tstTabs);
}); });
} }
@@ -111,18 +147,25 @@ browser.runtime.onMessageExternal.addListener((aMessage, aSender) => {
} }
}); });
//when a tab is created //when something happens with a tab
browser.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { let tabEvents = ['onAttached', 'onDetached', 'onMoved', 'onRemoved']
var tstTab = await browser.runtime.sendMessage(kTST_ID, { tabEvents.forEach((ev) => {
type: 'get-tree', browser.tabs[ev].addListener((tabId, changeInfo, tab) => {
window: tab.windowId updateAllColorsOnAllTabs();
}); });
if (tab.status === 'complete') {
browser.tabs.executeScript(tab.id, {
code: '(' + changeIcon.toString() + ')("' + generateRandomColor(getTabParent(tstTab, tab.id)) + '")'
});
}
}); });
//when a tab reloads
browser.webNavigation.onCompleted.addListener((details) => {
delete tabIcons[details.tabId];
updateAllColorsOnAllTabs();
});
//when the options are updated
browser.storage.onChanged.addListener((changes) => {
updateAllColorsOnAllTabs();
});
registerToTST(); // aggressive registration on initial installation registerToTST(); // aggressive registration on initial installation

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 435 KiB

After

Width:  |  Height:  |  Size: 432 KiB

View File

@@ -1,8 +1,8 @@
{ {
"description": "color tabs based on their parent.", "description": "Color tabs based on their parent.",
"manifest_version": 2, "manifest_version": 2,
"name": "tab-groupcolor", "name": "Color Tab Group",
"version": "0.0.1", "version": "0.0.8",
"homepage_url": "https://git.e.tern.al/s2/tab-groupcolor", "homepage_url": "https://git.e.tern.al/s2/tab-groupcolor",
"icons": { "icons": {
"48": "img/icon-48.png" "48": "img/icon-48.png"
@@ -14,9 +14,15 @@
} }
}, },
"background": { "background": {
"scripts": ["bg.js"] "scripts": ["bg.js", "utils.js"]
}, },
"permissions": [ "permissions": [
"storage",
"webNavigation",
"<all_urls>" "<all_urls>"
] ],
"options_ui": {
"browser_style": true,
"page": "options/options.html"
}
} }

44
src/options/options.html Normal file
View File

@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<section id="options-section" class="panel">
<div class="panel-section panel-section-header">
<span class="text-section-header">Indicator options</span>
</div>
<div class="panel-section panel-section-formElements">
<div class="panel-formElements-item browser-style">
<label for="indicator-width">Width:</label>
<input type="number" id="indicator-width" max="16" min="1">
</div>
<div class="panel-formElements-item browser-style">
<label for="indicator-orientation">Orientation:</label>
<select id="indicator-orientation">
<option value="vertical">Vertical</option>
<option value="horizontal">Horizontal</option>
</select>
</div>
<div class="panel-formElements-item browser-style">
<label for="ignore">Ignore hosts (one per line - ex.: google.com):</label>
</div>
<div class="panel-formElements-item browser-style">
<textarea id="ignore"></textarea>
</div>
</div>
</section>
<script src="../utils.js"></script>
<script src="options.js"></script>
</body>
</html>

26
src/options/options.js Normal file
View File

@@ -0,0 +1,26 @@
function persistOptions() {
var globals = {}; //global addon options
globals = {
width: document.querySelector('#indicator-width').value,
orientation: document.querySelector('#indicator-orientation').value
};
return browser.storage.local.set({
globals: globals
});
}
document.addEventListener('DOMContentLoaded', () => {
loadOptions().then((options) => {
document.querySelector('#indicator-width').value = options.globals.width;
document.querySelector('#indicator-orientation').value = options.globals.orientation;
});
});
var list = document.querySelectorAll('select,input,textarea');
for (var i = 0; i < list.length; i++) {
list[i].addEventListener('change', (ev) => {
persistOptions();
});
}

BIN
src/screenshots/firefox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

8
src/utils.js Normal file
View File

@@ -0,0 +1,8 @@
function loadOptions() {
return browser.storage.local.get({
globals: {
width: 3,
orientation: 'vertical'
}
});
}