Switchable Tab Groups like Firefox Panorama Alpha!
-
I created very usefull, but also bugged mod. Some things are not complete.
But I'm lazy/without motivation/depressed, so I do not know whether I will continue to develop this mod. If you could help to code even very simple things, that would be great.
I'm not good in English, so don't ask me complicated questions.Warning!!!:
- Bugs included
- Your saved sessions can be deleted/overwritten!!!
- Your current unpinned tabs can be closed forever (no tabs in Trash)!
- Your computer can explode
- Tabs in your current group are saved only if you select option in menu or you switch to other group!
- You are warned!!!
How switching of groups works (short):
- select unpinned tabs
- move tabs to temporary window
- because of bug-fix move tabs to another temporary window
- (if exist) try delete session where are saved tabs from current group
- save tabs in temporary window to session
- remove temporary window (probably you won't even see window)
- load tabs from session for next group
JS code Alpha 1:
var switchGroupBtn,currentGroup; var tgsDisabled=false; vivaldiWindowIdTimer=setInterval(function() { if(typeof vivaldiWindowId !== 'undefined') { clearInterval(vivaldiWindowIdTimer); console.log("vivaldiWindowId: ",vivaldiWindowId); chrome.windows.get(vivaldiWindowId, {windowTypes:["normal"]}, function (e){ if(typeof e==="undefined") return; //if(JSON.parse(e.extData).windowType!=="normal") return; //console.log(e,e.extData,!(/"windowType":"normal"/.test(e.extData))); if( !(/"windowType":"normal"/.test(e.extData)) ) return; if(e.incognito===true) return; saveCurrentGroupInfo(); chrome.windows.getAll((e)=>console.log("win ",e)); switchGroupBtnTimer=setInterval(function() { if(document.querySelector("#main>.toolbar")) { clearInterval(switchGroupBtnTimer); switchGroupBtn0=document.createElement("button"); switchGroupBtn0.className="button-toolbar browserAction-button dragging-current"; switchGroupBtn0.style.position="relative"; switchGroupBtn0.tabIndex=-1; switchGroupBtn0.title="Tab groups-sessions"; switchGroupBtn=document.createElement("span"); switchGroupBtn.className="button-badge"; switchGroupBtn.title="Tab groups-sessions"; chrome.storage.local.get({currentGroup: "..."},function(e) { currentGroup=switchGroupBtn.innerHTML=e.currentGroup; }); document.querySelector("#main>.toolbar").appendChild(switchGroupBtn0); switchGroupBtn0.appendChild(switchGroupBtn); switchGroupBtn0.addEventListener("click",(ev)=>tgsClick(ev)); switchGroupBtn0.addEventListener("auxclick",(ev)=>tgsClick(ev)); //switchGroupBtn.addEventListener("contextmenu",(e)=>tgsPopup(e)); switchGroupBtn0.addEventListener("contextmenu",(ev)=>tgsContextMenu(ev)); } },200); chrome.windows.onRemoved.addListener(function (a,b){ console.log("onRemoved window",a); saveCurrentGroupInfo(); },{ windowTypes: [ "normal" ] }); }); } },200); function testDuration(a,b=performance.now()){return Math.round(b-a)+" ms";} function tgsContextMenu(ev){ console.log(ev); ev.preventDefault(); chrome.storage.local.get({tgsGroups:[]},function(e){ console.log(e); var tgsGroups=e.tgsGroups; var tgsGroupsMenus=tgsGroups.map(function(a,b) {return {name:a,id:b*10+10,items:[{name:"Delete",id:b*10+17},{name:"Open",id:b*10+10}]}}); vivaldi.showMenu.create({ mode:"context", //left:Math.round(switchGroupBtn.getBoundingClientRect().x),top:20+Math.round(switchGroupBtn.getBoundingClientRect().y), left:ev.clientX,top:ev.clientY, items:tgsGroupsMenus.concat([ {name:"---",id:-1}, {name:"&New group...",id:1}, {name:"&Save current group",id:2}, {name:"Save current tabs &as...",id:3} ])}, function(e){ console.log(e); if(e.id==1) newGroupDialog(); if(e.id==2) saveCurrentGroup(); else if(e.id%10===0) switchGroup(tgsGroups[e.id/10-1]); else if((e.id-7)%10===0 && e.shift==true) { chrome.storage.local.get({tgsGroups:[]},function(f){ var deleteGroup=tgsGroups[(e.id-7)/10-1]; if(f.tgsGroups.indexOf(deleteGroup)!==-1) { f.tgsGroups.splice(f.tgsGroups.indexOf(deleteGroup),1); chrome.storage.local.set({tgsGroups:f.tgsGroups}); vivaldi.sessionsPrivate.delete(deleteGroup,function(){}); if(currentGroup==deleteGroup) { currentGroup=switchGroupBtn.innerHTML="..."; saveCurrentGroupInfo(); } } }); } } ); }); } function newGroupDialog(){ document.querySelector("#main>.inner").insertAdjacentHTML("afterbegin", '<div id="modal-bg" class="slide"><span tabindex="0" class="focus_modal"></span><div><div class="save-session"><header class="dialog-header"><h1 class="dialog-title">New tab group</h1></header><form><div class="dialog-content session-dialog"><div><input type="text" maxlength=150 placeholder="Name of group" spellcheck="false"></div><!--<label class="dialog-checkbox"><input type="checkbox" value="on"><span>Add current tabs</span></label>--></div><div id="new-group-error"></div><footer class="dialog-footer"><input type="submit" class="primary" value="Save"><input type="button" value="Another non functioning button ;)"></footer></form></div></div><span tabindex="0" class="focus_modal"></span></div>'); var modalBg=document.getElementById("modal-bg"); modalBg.addEventListener("click",function(ev){if(ev.target===modalBg) modalBg.parentNode.removeChild(modalBg);}); var groupNameInput=modalBg.querySelector('input[type="text"]'); var groupSubmitInput=modalBg.querySelector('input[type="submit"]'); var groupError=modalBg.querySelector('#new-group-error'); groupNameInput.addEventListener("input",function(ev){ if(groupNameInput.value===""){ groupSubmitInput.disabled=true; groupError.innerHTML=""; } else if(!isValidSessionName(groupNameInput.value)){ groupSubmitInput.disabled=true; groupError.innerHTML='<div class="error-validation"><input type="text" value="Bad characters in input." readonly=""></div>'; } else{ groupSubmitInput.disabled=false; groupError.innerHTML=''; } }); groupSubmitInput.addEventListener("click",function(ev){ var groupName = groupNameInput.value; chrome.storage.local.get({tgsGroups:[]},function(e){ var tgsGroups=e.tgsGroups; var tgsGroupsLowerCase=tgsGroups.map(function(a){return a.toLowerCase()}); if(!tgsGroupsLowerCase.includes(groupName.toLowerCase())) { vivaldi.sessionsPrivate.saveOpenTabs(groupName,{saveOnlyWindowId: -1},function(e){ if(e===0) { vivaldi.sessionsPrivate.delete(groupName,function(){}); tgsGroups.push(groupName); chrome.storage.local.set({tgsGroups:tgsGroups}); } }); } }); }); } function tgsClick(ev){ if(ev.button===0 && ev.ctrlKey==false) tgsPopup(); if(ev.button==1 || ev.button===0 && ev.ctrlKey==true) switchGroup(); } function tgsPopup(e){ if(document.getElementById("tgs_popup")) return; //e.preventDefault(); document.querySelector("#main>.inner").insertAdjacentHTML("afterbegin", '<span id=tgs_popup tabindex=-1 class="extensionaction" style="background:yellow;position: fixed;height: 379px;width: 161px;right:0;margin-top:11px;topp: 74px;visibility: visible;"><div class="popup top"><div id=tgs_popup_content style=position:absolute></div></div></span>'); tgs_popup=document.getElementById("tgs_popup"); tgs_popup_content=document.getElementById("tgs_popup_content"); tgs_popup.focus(); tgs_popup.addEventListener("focusout",function(){ setTimeout(function(){ if(/*document.activeElement !== this*/ document.activeElement.closest("#tgs_popup")===null) tgs_popup.parentNode.removeChild(tgs_popup); },50); }); tgs_popup_content.innerHTML="<h1>Groooooups!!</h1>Useless popup<input>"; chrome.storage.local.get({tgsGroups:[]},function(e){ console.log(e); }); } function isValidSessionName(e) { var t = /^[^\\\/:\*\?"<>\|]+$/, n = /^\./, a = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return t.test(e) && !n.test(e) && !a.test(e) } //very old function function switchGroupVeryOldFunction(){ var nextGroup,tabsToRemove; var lastGroup=currentGroup; if(tgsDisabled) return; tgsDisabled=true; var t0 = performance.now(); console.log("prepnutie skupiny začalo", testDuration(t0)); if(currentGroup=="1") nextGroup="2"; else if(currentGroup=="2") nextGroup="1"; else nextGroup="1"; //záloha vivaldi.sessionsPrivate.saveOpenTabs("tempBackup",{saveOnlyWindowId: vivaldiWindowId},function(e) { if(e!==0) return console.log("chyba pri vytváraní zálohy: "+e); console.log("záloha vytvorená", testDuration(t0)); //console.log(t1-t0); chrome.tabs.query({windowId:vivaldiWindowId,pinned:false},function(e){ tabsToRemove=e.map(function(a) {return a.id;}); console.log("vybratie kariet na odstránenie", testDuration(t0)); currentGroup=switchGroupBtn.innerHTML="..."; vivaldi.sessionsPrivate.delete(lastGroup,function(e) { if(e===0||e==3)//skupina zmazaná/neexistuje { console.log("stará skupina zmazaná", testDuration(t0)); vivaldi.sessionsPrivate.saveOpenTabs(lastGroup,{saveOnlyWindowId: vivaldiWindowId},function(e) { if(e===0)//skupina vytvorená { console.log("súčasná skupina uložená", testDuration(t0)); vivaldi.sessionsPrivate.open(nextGroup,{openInNewWindow:false},function(e) { if(e===0||e==3)//nová skupina načítaná { console.log("nová skupina načítaná /nové karty vytvorené", testDuration(t0)); chrome.tabs.remove(tabsToRemove,function() { currentGroup=switchGroupBtn.innerHTML=nextGroup; saveCurrentGroupInfo(); console.log("prepnutie skupiny dokončené", testDuration(t0)); setTimeout(function(){tgsDisabled=false;},900); }); } else console.log("chyba pri načítaní skupiny: "+e); }); vivaldi.sessionsPrivate.delete("tempBackup",function(e){}); } }); } }); }); }); } function switchGroup(nextGroup){ var nextGroup,tabsToRemove; var lastGroup=currentGroup; if(typeof nextGroup === 'undefined') if(currentGroup=="1") nextGroup="2"; else if(currentGroup=="2") nextGroup="1"; else nextGroup="1"; if(nextGroup===currentGroup) return; if(tgsDisabled) return; tgsDisabled=true; var t0 = performance.now(); console.log("prepnutie skupiny začalo", testDuration(t0)); //záloha vivaldi.sessionsPrivate.saveOpenTabs("tempBackup",{saveOnlyWindowId: vivaldiWindowId},function(e) { if(e!==0) return console.log("chyba pri vytváraní zálohy: "+e); console.log("záloha vytvorená", testDuration(t0)); //console.log(t1-t0); chrome.tabs.query({windowId:vivaldiWindowId,pinned:false},function(e){ tabsToRemove=e.map(function(a) {return a.id;}); if(tabsToRemove.length>120) return console.log("Too many tabs..."); console.log("vybratie kariet na odstránenie", testDuration(t0)); currentGroup=switchGroupBtn.innerHTML="..."; if(tabsToRemove.length===0) vivaldi.sessionsPrivate.delete(lastGroup,function(e) { if(e===0||e==3)//skupina zmazaná/neexistuje { console.log("stará skupina zmazaná", testDuration(t0)); vivaldi.sessionsPrivate.delete("tempBackup",function(e){}); } }); else chrome.windows.create({top:500,width:1,height:1,left:1300},function(win){ console.log("okno vytvorené", testDuration(t0)); chrome.tabs.move(tabsToRemove, {windowId:win.id,index:-1}, function (e){ console.log("karty presunuté", testDuration(t0)); chrome.tabs.update(tabsToRemove[0],{active:true},function(){ chrome.windows.create({top:500,width:1,height:1,left:1300},function(win){ console.log("okno vytvorené", testDuration(t0)); chrome.tabs.move(tabsToRemove, {windowId:win.id,index:-1}, function (e){ console.log("karty presunuté", testDuration(t0)); vivaldi.sessionsPrivate.delete(lastGroup,function(e) { if(e===0||e==3)//skupina zmazaná/neexistuje { console.log("stará skupina zmazaná", testDuration(t0)); vivaldi.sessionsPrivate.saveOpenTabs(lastGroup,{saveOnlyWindowId: win.id},function(e) { if(e===0)//skupina uložená { console.log("súčasná skupina uložená", testDuration(t0)); setTimeout(function(){ chrome.windows.remove(win.id,function(){console.log("okno zavreté", testDuration(t0));}); },00); vivaldi.sessionsPrivate.delete("tempBackup",function(e){}); } }); } }); }); }); }); }); }); vivaldi.sessionsPrivate.open(nextGroup,{openInNewWindow:false},function(e) { if(e===0||e==3)//nová skupina načítaná { console.log("nová skupina načítaná /nové karty vytvorené", testDuration(t0)); //chrome.tabs.remove(tabsToRemove,function() { currentGroup=switchGroupBtn.innerHTML=nextGroup; saveCurrentGroupInfo(); console.log("prepnutie skupiny dokončené", testDuration(t0)); setTimeout(function(){tgsDisabled=false;},900); }//); } else console.log("chyba pri načítaní skupiny: "+e); }); }); }); } function saveCurrentGroup(){ var tabsToSave; var t0 = performance.now(); console.log("ukladanie skupiny začalo", testDuration(t0)); chrome.tabs.query({windowId:vivaldiWindowId,pinned:false},function(e){ tabsToSave=e.map(function(a) {return a.id;}); if(tabsToSave.length>120) return console.log("Too many tabs..."); console.log("vybratie kariet na uloženie", testDuration(t0)); if(tabsToSave.length===0) vivaldi.sessionsPrivate.delete(currentGroup,function(e) { if(e===0||e==3)//skupina zmazaná/neexistuje console.log("stará skupina zmazaná", testDuration(t0)); }); else chrome.windows.create({top:500,width:1,height:1,left:1300},function(win){ console.log("okno vytvorené", testDuration(t0)); chrome.tabs.move(tabsToSave, {windowId:win.id,index:-1}, function (e){ console.log("karty presunuté", testDuration(t0)); vivaldi.sessionsPrivate.delete(currentGroup,function(e) { if(e===0||e==3)//skupina zmazaná/neexistuje { console.log("stará skupina zmazaná", testDuration(t0)); vivaldi.sessionsPrivate.saveOpenTabs(currentGroup,{saveOnlyWindowId: win.id},function(e) { if(e===0)//skupina uložená { console.log("súčasná skupina uložená", testDuration(t0)); chrome.tabs.move(tabsToSave, {windowId:vivaldiWindowId,index:-1}, function (e){ console.log("karty presunuté späť", testDuration(t0)); }); } }); } }); }); }); }); } function saveCurrentGroupInfo(){ chrome.windows.getAll({windowTypes: [ "normal" ]}, function (wins){ var wins2 = wins.filter(function(w){ //return (JSON.parse(w.extData).windowType==="normal"&&w.incognito===false); return ((/"windowType":"normal"/.test(w.extData))&&w.incognito===false); }); if(wins2.length===1) chrome.storage.local.set({currentGroup: currentGroup},function(){}); else chrome.storage.local.set({currentGroup: "..."},function(){}); }); } chrome.tabs.onCreated.addListener(function (tab){ console.log("onCreated tab: "); //for old function /*if(tab.pinned==true) chrome.tabs.update(tab.id,{pinned:false},function(tab){ setTimeout(function(){ chrome.tabs.remove(tab.id) },85*10); });*/ }); chrome.tabs.onReplaced.addListener(function (a,b){console.log("onReplaced tab");}); chrome.tabs.onUpdated.addListener(function (a,b,c){console.log("onUpdated tab ");}); chrome.tabs.onMoved.addListener(function (a,b){console.log("onMoved tab");}); chrome.tabs.onDetached.addListener(function (a,b){console.log("onDetached tab");}); /*chrome.tabs.onAttached.addListener(function (a,b){console.log("onAttached tab");});*/ chrome.tabs.onRemoved.addListener(function (a,b){console.log("onRemoved tab");});
-
Is this an interface for switching session?
-
Yes.
-