const kTST_ID = 'treestyletab@piro.sakura.ne.jp'; const MY_EXTENSION_NAME = 'tab-groupcolor'; var changeIcon = function(color, currentIcon, options) { var canvas = document.createElement('canvas'); canvas.width = 16; canvas.height = 16; var ctx = canvas.getContext('2d'); var img = new Image(); 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() { ctx.drawImage(img, 0, 0); ctx.fillStyle = color; if (options.globals.orientation === 'vertical') { ctx.fillRect(0, 0, options.globals.width, 16); } else { ctx.fillRect(0, 0, 16, options.globals.width); } var link = document.createElement('link'); link.type = 'image/x-icon'; link.rel = 'shortcut icon'; link.href = canvas.toDataURL("image/x-icon"); document.getElementsByTagName('head')[0].appendChild(link); } }; var generateRandomColor = function(seed) { var selectColor = function (colorNum, colors) { if (colors < 1) { colors = 1; // defaults to one color - avoid divide by zero } return "hsl(" + (colorNum * (360 / colors) % 360) + ",100%,50%)"; } return selectColor(seed, 8); }; var registerToTST = async function() { try { var success = await browser.runtime.sendMessage(kTST_ID, { type: 'register-self', // The name of your addon (string, optional) name: MY_EXTENSION_NAME }); updateAllColorsOnAllTabs(); } catch (e) { // TST is not available } }; //returns the index of the tabs array object that contains the tab with the passed id var getTabParent = (tabs, id, currentTopLevelTabPos) => { for (let i = 0; i < tabs.length; i++) { //on a root node because there is no opener if (typeof(tabs[i].openerTabId) === 'undefined' || tabs[i].openerTabId === tabs[i].id) { currentTopLevelTabPos = i; } if (tabs[i].id === id) { //get original favicon for this tab let orginalFavIconUrl = tabs[i].favIconUrl; //let orginalFavIconUrl = await browser.sessions.getTabValue(id, 'orginalFavIconUrl'); // if (!orginalFavIconUrl) { // orginalFavIconUrl = tabs[i].favIconUrl; // await browser.sessions.setTabValue(id, 'orginalFavIconUrl', orginalFavIconUrl); // } return { parentIndex: currentTopLevelTabPos, faviconUrl: orginalFavIconUrl }; } else { if (tabs[i].children && tabs[i].children.length > 0) { let ret = getTabParent(tabs[i].children, id, currentTopLevelTabPos); if (ret) { return ret; } } } } }; var updateAllColorsOnAllTabs = async () => { let allWindows = await browser.windows.getAll(); allWindows.forEach(async w => { var tstTabs = await browser.runtime.sendMessage(kTST_ID, { type: 'get-tree', window: w.id }); var changeTabs = (tabs) => { for (let i = 0; i < tabs.length; i++) { if (tabs[i].status === 'complete') { let t = getTabParent(tstTabs, tabs[i].id); loadOptions().then((options) => { 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) { changeTabs(tabs[i].children); } } }; changeTabs(tstTabs); }); } //events //register to tst browser.runtime.onMessageExternal.addListener((aMessage, aSender) => { if (aSender.id === kTST_ID) { switch (aMessage.type) { case 'ready': registerToTST(); // passive registration for secondary (or after) startup break; } } }); //when something happens with a tab let tabEvents = ['onUpdated', 'onAttached', 'onDetached', 'onMoved', 'onRemoved'] tabEvents.forEach((ev) => { browser.tabs[ev].addListener(async (tabId, changeInfo, tab) => { updateAllColorsOnAllTabs(); }); }); //when the options are updated browser.storage.onChanged.addListener((changes) => { updateAllColorsOnAllTabs(); }); registerToTST(); // aggressive registration on initial installation