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.

    0_1515628670510_tgs.png

    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):

    1. select unpinned tabs
    2. move tabs to temporary window
    3. because of bug-fix move tabs to another temporary window
    4. (if exist) try delete session where are saved tabs from current group
    5. save tabs in temporary window to session
    6. remove temporary window (probably you won't even see window)
    7. 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.


 

Looks like your connection to Vivaldi Forum was lost, please wait while we try to reconnect.