22 Commits

Author SHA1 Message Date
s2
21dd898d44 v0.0.10 2017-12-13 11:19:35 +01:00
s2
757adc4722 need to test more 2017-12-13 11:19:20 +01:00
s2
26e7b44b36 v0.0.9 2017-12-13 11:15:59 +01:00
s2
675900d0c8 move screenshots folder 2017-12-13 11:15:37 +01:00
s2
34d0f821a0 actually persist hosts option 2017-12-13 11:15:06 +01:00
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
7 changed files with 155 additions and 21 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

BIN
screenshots/firefox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

View File

@@ -1,22 +1,39 @@
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, currentIcon) { var changeIcon = function(color, currentIcon, options) {
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 = currentIcon;
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);
} }
}; };
@@ -51,14 +68,22 @@ 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) {
//get original favicon for this tab
let orginalFavIconUrl = tabIcons[id];
if (!orginalFavIconUrl) {
orginalFavIconUrl = tabs[i].favIconUrl;
tabIcons[id] = orginalFavIconUrl;
}
return { return {
parentIndex: currentTopLevelTabPos, parentIndex: currentTopLevelTabPos,
faviconUrl: tabs[i].favIconUrl faviconUrl: orginalFavIconUrl
}; };
} else { } else {
if (tabs[i].children && tabs[i].children.length > 0) { if (tabs[i].children && tabs[i].children.length > 0) {
@@ -76,28 +101,35 @@ 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
}); });
var changeTabs = (tabs) => { var changeTabs = async (tabs) => {
for (let i = 0; i < tabs.length; i++) { for (let i = 0; i < tabs.length; i++) {
if (tabs[i].status === 'complete') { if (tabs[i].status === 'complete') {
let t = getTabParent(tstTabs, tabs[i].id); let t = getTabParent(tstTabs, tabs[i].id);
browser.tabs.executeScript(tabs[i].id, { let options = await loadOptions();
code: '(' + changeIcon.toString() + ')' + let tabHost = new URL(tabs[i].url).host;
'("' + generateRandomColor(t.parentIndex) + '", "' + t.faviconUrl + '")' if (tabHost) {
}); tabHost = tabHost.toLowerCase();
}
if (!(options.globals.ignore && options.globals.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) { if (tabs[i].children && tabs[i].children.length > 0) {
changeTabs(tabs[i].children); await changeTabs(tabs[i].children);
} }
} }
}; };
changeTabs(tstTabs); await changeTabs(tstTabs);
}); });
@@ -116,12 +148,24 @@ browser.runtime.onMessageExternal.addListener((aMessage, aSender) => {
}); });
//when something happens with a tab //when something happens with a tab
let tabEvents = ['onUpdated', 'onAttached', 'onDetached', 'onMoved', 'onRemoved'] let tabEvents = ['onAttached', 'onDetached', 'onMoved', 'onRemoved']
tabEvents.forEach((ev) => { tabEvents.forEach((ev) => {
browser.tabs[ev].addListener(async (tabId, changeInfo, tab) => { browser.tabs[ev].addListener((tabId, changeInfo, tab) => {
updateAllColorsOnAllTabs(); updateAllColorsOnAllTabs();
}); });
}); });
//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

View File

@@ -2,7 +2,7 @@
"description": "Color tabs based on their parent.", "description": "Color tabs based on their parent.",
"manifest_version": 2, "manifest_version": 2,
"name": "Color Tab Group", "name": "Color Tab Group",
"version": "0.0.2", "version": "0.0.10",
"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>

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

@@ -0,0 +1,27 @@
function persistOptions() {
var globals = {}; //global addon options
globals = {
width: document.querySelector('#indicator-width').value,
orientation: document.querySelector('#indicator-orientation').value,
ignore: document.querySelector('#ignore').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();
});
}

8
src/utils.js Normal file
View File

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