TreeTabsMigration/scripts/tabs.js

1087 lines
38 KiB
JavaScript

// Copyright (c) 2017 kroppy. All rights reserved.
// Use of this source code is governed by a Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0) license
// that can be found at https://creativecommons.org/licenses/by-nc-nd/4.0/
// ********** TABS FUNCTIONS ***************
async function UpdateData() {
if (opt.debug) {
log("f: UpdateData");
}
setInterval(function() {
if (tt.schedule_update_data > 1) {
tt.schedule_update_data = 1;
}
if (tt.schedule_update_data > 0) {
let PinInd = 0;
let pins_data = [];
document.querySelectorAll(".pin").forEach(function(pin){
pins_data.push({id: pin.id, index: PinInd});
PinInd++;
});
let tabs_data = [];
document.querySelectorAll(".tab").forEach(function(tab){
tabs_data.push({id: tab.id, parent: tab.parentNode.parentNode.id, index: Array.from(tab.parentNode.children).indexOf(tab), expand: (tab.classList.contains("c") ? "c" : (tab.classList.contains("o") ? "o" : ""))});
});
chrome.runtime.sendMessage({command: "update_all_tabs", pins: pins_data, tabs: tabs_data});
tt.schedule_update_data--;
}
}, 1000);
}
async function RearrangeBrowserTabs() {
setInterval(function() {
if (tt.schedule_rearrange_tabs > 0) {
tt.schedule_rearrange_tabs--;
if (opt.debug) {
log("f: RearrangeBrowserTabs");
}
chrome.tabs.query({currentWindow: true}, function(tabs) {
let ttTabIds = Array.prototype.map.call(document.querySelectorAll(".pin, .tab"), function(s){
return parseInt(s.id);
});
let tabIds = Array.prototype.map.call(tabs, function(t){
return t.id;
});
RearrangeBrowserTabsLoop(ttTabIds, tabIds, ttTabIds.length-1);
});
}
}, 1000);
}
async function RearrangeBrowserTabsLoop(ttTabIds, tabIds, tabIndex) {
if (opt.debug) {
log("f: RearrangeBrowserTabsLoop");
}
if (tabIndex >= 0 && tt.schedule_rearrange_tabs == 0){
if (ttTabIds[tabIndex] != tabIds[tabIndex]) {
chrome.tabs.move(ttTabIds[tabIndex], {index: tabIndex});
}
setTimeout(function() {
RearrangeBrowserTabsLoop(ttTabIds, tabIds, (tabIndex-1));
}, 0);
}
}
function RearrangeTreeTabs(bgtabs, show_finish_in_status) {
if (opt.debug) {
log("f: RearrangeTreeTabs");
}
ShowStatusBar({show: true, spinner: true, message: "Rearranging tabs and folders"});
document.querySelectorAll(".pin, .tab").forEach(function(tab){
if (bgtabs[tab.id]) {
let Sibling = tab.nextElementSibling;
while (Sibling) {
if (bgtabs[Sibling.id]) {
if (bgtabs[tab.id].index > bgtabs[Sibling.id].index ) {
InsterAfterNode(tab, Sibling);
}
}
Sibling = Sibling.nextElementSibling ? Sibling.nextElementSibling : false;
}
}
if (show_finish_in_status){
ShowStatusBar({show: true, spinner: false, message: "Rearranging: done.", hideTimeout: 1000});
}
});
}
function AppendTab(p) { // tab: chrome tab object, ParentId: int or string, InsertBeforeId: int or string, InsertAfterId: int or string, Append: bool, SkipSetEvents: bool, AdditionalClass: string, SkipSetActive: bool, Scroll: bool, addCounter: bool, SkipMediaIcon: bool
if (document.getElementById(p.tab.id) != null) {
GetFaviconAndTitle(p.tab.id, p.addCounter);
return;
}
let ClassList = p.tab.pinned ? "pin" : "tab";
if (p.tab.discarded) {
ClassList = ClassList + " discarded";
}
if (p.AdditionalClass) {
ClassList = ClassList +" "+ p.AdditionalClass;
}
let tb = document.createElement("div"); tb.className = ClassList; tb.id = p.tab.id; // TAB
let tbh = document.createElement("div"); tbh.className = (opt.always_show_close && !opt.never_show_close) ? "tab_header close_show" : "tab_header"; tbh.id = "tab_header"+p.tab.id; if (!p.SkipSetEvents) {tbh.draggable = true;} tb.appendChild(tbh); // HEADER
let tbe = document.createElement("div"); tbe.className = "expand"; tbe.id = "exp"+p.tab.id; tbh.appendChild(tbe); // EXPAND ARROW
let tbc = document.createElement("div"); tbc.className = "tab_counter"; tbc.id = "tab_counter"+p.tab.id; tbh.appendChild(tbc); // TABS COUNTER
let tbcn = document.createElement("div"); tbcn.className = "counter_number"; tbcn.id = "counter_number"+p.tab.id; tbc.appendChild(tbcn); // TABS COUNTER NUMBER
let tbt = document.createElement("div"); tbt.className = "tab_title"; tbt.id = "tab_title"+p.tab.id; tbh.appendChild(tbt); // TITLE
let cl = undefined;
if (!opt.never_show_close) {
cl = document.createElement("div"); cl.className = "close"; cl.id = "close"+p.tab.id; tbh.appendChild(cl); // CLOSE BUTTON
let ci = document.createElement("div"); ci.className = "close_img"; ci.id = "close_img"+p.tab.id; cl.appendChild(ci);
}
let mi = document.createElement("div"); mi.className = "tab_mediaicon"; mi.id = "tab_mediaicon"+p.tab.id; tbh.appendChild(mi);
let ct = document.createElement("div"); ct.className = "children_tabs"; ct.id = "ct"+p.tab.id; tb.appendChild(ct);
let di = document.createElement("div"); di.className = "drag_indicator"; di.id = "di"+p.tab.id; tb.appendChild(di); // DROP TARGET INDICATOR
if (!p.SkipSetEvents) {
ct.onclick = function(event) {
if (event.target == this && event.which == 1) {
DeselectFolders();
DeselectTabs();
}
}
ct.onmousedown = function(event) {
if (event.target == this) {
if (event.which == 2 && event.target == this) {
event.stopImmediatePropagation();
ActionClickGroup(this.parentNode, opt.midclick_group);
}
if (event.which == 3) {
ShowFGlobalMenu(event);
}
}
}
ct.ondblclick = function(event) {
if (event.target == this) {
ActionClickGroup(this.parentNode, opt.dbclick_group);
}
}
tbe.onmousedown = function(event) {
if (document.getElementById("main_menu").style.top != "-1000px") {
HideMenus();
}
if (event.which == 1 && !event.shiftKey && !event.ctrlKey) {
EventExpandBox(this.parentNode.parentNode);
}
}
tbe.onmouseenter = function(event) {
this.classList.add("hover");
}
tbe.onmouseleave = function(event) {
this.classList.remove("hover");
}
if (!opt.never_show_close && cl) {
cl.onmousedown = function(event) {
event.stopImmediatePropagation();
if (event.which != 3) {
CloseTabs([parseInt(this.parentNode.parentNode.id)]);
}
}
cl.onmouseenter = function(event) {
this.classList.add("close_hover");
}
cl.onmouseleave = function(event) {
this.classList.remove("close_hover");
}
}
tbh.onclick = function(event) {
event.stopImmediatePropagation();
if (document.getElementById("main_menu").style.top != "-1000px") {
HideMenus();
} else {
if (event.which == 1 && !event.shiftKey && !event.ctrlKey && event.target.classList.contains("tab_header")) {
DeselectTabs();
chrome.tabs.update(parseInt(this.parentNode.id), { active: true });
}
}
}
tbh.ondblclick = function(event) {
if (event.target.classList && event.target.classList.contains("tab_header")) {
ActionClickTab(this.parentNode, opt.dbclick_tab);
}
}
tbh.onmousedown = function(event) {
if (browserId == "V") {
chrome.windows.getCurrent({populate: false}, function(window) {
if (tt.CurrentWindowId != window.id && window.focused) {
location.reload();
}
});
}
event.stopImmediatePropagation();
if (event.which == 1) {
EventSelectTab(event, this.parentNode);
}
if (event.which == 2) {
event.preventDefault();
ActionClickTab(this.parentNode, opt.midclick_tab);
}
if (event.which == 3) {
ShowTabMenu(this.parentNode, event);
}
}
tbh.onmouseover = function(event) {
this.classList.add("tab_header_hover");
if (opt.never_show_close == false && opt.always_show_close == false) {
this.classList.add("close_show");
}
}
tbh.onmouseleave = function(event) {
this.classList.remove("tab_header_hover");
if (opt.never_show_close == false && opt.always_show_close == false) {
this.classList.remove("close_show");
}
}
tbh.ondragstart = function(event) { // DRAG START
TabStartDrag(this.parentNode, event);
}
tbh.ondragenter = function(event) {
this.classList.remove("tab_header_hover");
}
tbh.ondragleave = function(event) {
RemoveHighlight();
}
tbh.ondragover = function(event) {
TabDragOver(this, event);
if (opt.open_tree_on_hover && tt.DragOverId != this.id) {
if (this.parentNode.classList.contains("c") && this.parentNode.classList.contains("dragged_tree") == false) {
clearTimeout(tt.DragOverTimer);
tt.DragOverId = this.id;
let This = this;
tt.DragOverTimer = setTimeout(function() {
if (tt.DragOverId == This.id) {
This.parentNode.classList.add("o");
This.parentNode.classList.remove("c");
}
}, 1500);
}
}
}
mi.onmousedown = function(event) {
event.stopImmediatePropagation();
if (event.which == 1 && (this.parentNode.parentNode.classList.contains("audible") || this.parentNode.parentNode.classList.contains("muted")) ) {
chrome.tabs.get(parseInt(this.parentNode.parentNode.id), function(tab) {
if (tab) {
chrome.tabs.update(tab.id, {muted:!tab.mutedInfo.muted});
}
});
}
}
}
let parent;
if (p.tab.pinned) {
parent = document.getElementById("pin_list");
} else {
if (p.ParentId == false || p.ParentId == undefined || document.getElementById(p.ParentId) == null || document.querySelector(".pin[id='"+p.ParentId+"']") != null || p.ParentId == "pin_list") {
parent = document.getElementById("ct"+tt.active_group);
} else {
parent = document.getElementById("ct"+p.ParentId);
if (parent.children.length == 0) {
parent.parentNode.classList.add("o");
parent.parentNode.classList.remove("c");
}
}
}
if (p.Append && parent) {
parent.appendChild(tb);
}
if (!p.Append && parent) {
parent.prepend(tb);
}
if (p.InsertBeforeId) {
let Before = document.getElementById(p.InsertBeforeId);
if (Before != null) {
if ((p.tab.pinned && Before.classList.contains("pin")) || (p.tab.pinned == false && Before.classList.contains("tab"))) {
Before.parentNode.insertBefore(tb, Before);
}
}
}
if (p.InsertAfterId) {
let After = document.getElementById(p.InsertAfterId);
if (After != null) {
if ((p.tab.pinned && After.classList.contains("pin")) || (p.tab.pinned == false && After.classList.contains("tab"))) {
InsterAfterNode(tb, After);
}
}
}
GetFaviconAndTitle(p.tab.id, p.addCounter);
if (!p.SkipMediaIcon) {
RefreshMediaIcon(p.tab.id);
}
if (p.tab.active && !p.SkipSetActive) {
SetActiveTab(p.tab.id);
}
if (p.Scroll) {
ScrollToTab(p.tab.id);
}
return tb;
}
function RemoveTabFromList(tabId) {
if (opt.debug) {
log("f: RemoveTabFromList, tabId: "+tabId);
}
let tab = document.getElementById(tabId);
if (tab != null) {
tab.parentNode.removeChild(tab);
}
}
function SetTabClass(tabId, pin) {
let PinList = document.getElementById("pin_list");
let GroupList = document.getElementById("ct"+tt.active_group);
let Tab = document.getElementById(tabId);
if (Tab != null) {
if (pin) {
if (Tab.parentNode.id != "pin_list") {
document.getElementById("pin_list").appendChild(Tab);
}
Tab.classList.remove("tab");
Tab.classList.remove("o");
Tab.classList.remove("c");
Tab.classList.add("pin");
if (document.getElementById("ct"+tabId).childNodes.length > 0) { // flatten out children
let tabs = document.querySelectorAll("#ct"+tabId+" .pin, #ct"+tabId+" .tab");
for (let i = tabs.length-1; i >= 0; i--) {
tabs[i].classList.remove("tab");
tabs[i].classList.remove("o");
tabs[i].classList.remove("c");
tabs[i].classList.add("pin");
InsterAfterNode(tabs[i], Tab);
chrome.tabs.update(parseInt(tabs[i].id), {pinned: true});
}
}
chrome.tabs.update(parseInt(tabId), {pinned: true});
} else {
if (Tab.parentNode.id == "pin_list") { // if coming from pin_list
if (GroupList.childNodes.length > 0) {
GroupList.insertBefore(Tab, GroupList.childNodes[0]);
} else {
GroupList.appendChild(Tab);
}
}
Tab.classList.remove("pin");
Tab.classList.remove("attention");
Tab.classList.add("tab");
RefreshExpandStates();
chrome.tabs.update(parseInt(tabId), {pinned: false});
}
RefreshGUI();
}
}
function SetMultiTabsClass(TabsIds, pin) {
TabsIds.forEach(function(tabId){
SetTabClass(tabId, pin);
chrome.tabs.update(parseInt(tabId), {pinned: pin});
});
}
function SetActiveTab(tabId, switchToGroup) {
if (opt.debug) {
log("f: SetActiveTab, tabId: "+tabId);
}
let Tab = document.getElementById(tabId);
if (Tab != null) {
let TabGroup = GetParentsByClass(Tab, "group");
if (TabGroup.length) {
if (Tab.classList.contains("tab")) {
SetActiveTabInGroup(TabGroup[0].id, tabId);
}
if (switchToGroup) {
SetActiveGroup(TabGroup[0].id, false, false); // not going to scroll, because mostly it's going to change to a new active in group AFTER switch, so we are not going to scroll to previous active tab
}
}
document.querySelectorAll(".selected_folder").forEach(function(s){
s.classList.remove("selected_folder");
});
// document.querySelectorAll(".pin, #"+tt.active_group+" .tab"+(TabGroup.length ? ", #"+TabGroup[0].id+" .tab" : "")).forEach(function(s){
document.querySelectorAll(".pin, #"+tt.active_group+" .tab").forEach(function(s){
s.classList.remove("active_tab");
s.classList.remove("selected_tab");
s.classList.remove("selected_last");
s.classList.remove("selected_frozen");
s.classList.remove("selected_temporarly");
s.classList.remove("tab_header_hover");
});
RemoveHighlight();
Tab.classList.remove("attention");
Tab.classList.add("active_tab");
ScrollToTab(tabId);
}
}
function ScrollToTab(tabId) {
let Tab = document.getElementById(tabId);
if (Tab != null) {
if (Tab.classList.contains("pin")) {
if (Tab.getBoundingClientRect().left - document.getElementById("pin_list").getBoundingClientRect().left < 0) {
document.getElementById("pin_list").scrollLeft = document.getElementById("pin_list").scrollLeft + Tab.getBoundingClientRect().left - document.getElementById("pin_list").getBoundingClientRect().left - 2;
} else {
if (Tab.getBoundingClientRect().left - document.getElementById("pin_list").getBoundingClientRect().left > document.getElementById(tt.active_group).getBoundingClientRect().width - document.querySelector(".tab_header").getBoundingClientRect().width) {
document.getElementById("pin_list").scrollLeft = document.getElementById("pin_list").scrollLeft + Tab.getBoundingClientRect().left - document.getElementById("pin_list").getBoundingClientRect().left - document.getElementById("pin_list").getBoundingClientRect().width + document.querySelector(".tab_header").getBoundingClientRect().width + 2;
}
}
}
if (Tab.classList.contains("tab") && document.querySelector("#"+tt.active_group+" [id='"+tabId+"']") != null) {
let Parents = GetParentsByClass(Tab, "c");
if (Parents.length > 0) {
Parents.forEach(function(s){
s.classList.remove("c");
s.classList.add("o");
});
}
if (Tab.getBoundingClientRect().top - document.getElementById(tt.active_group).getBoundingClientRect().top < 0) {
document.getElementById(tt.active_group).scrollTop = document.getElementById(tt.active_group).scrollTop + Tab.getBoundingClientRect().top - document.getElementById(tt.active_group).getBoundingClientRect().top - 2;
} else {
if (Tab.getBoundingClientRect().top - document.getElementById(tt.active_group).getBoundingClientRect().top > document.getElementById(tt.active_group).getBoundingClientRect().height - document.querySelector(".tab_header").getBoundingClientRect().height) {
document.getElementById(tt.active_group).scrollTop = document.getElementById(tt.active_group).scrollTop + Tab.getBoundingClientRect().top - document.getElementById(tt.active_group).getBoundingClientRect().top - document.getElementById(tt.active_group).getBoundingClientRect().height + document.querySelector(".tab_header").getBoundingClientRect().height + 10;
}
}
}
}
}
function Detach(tabsIds, Folders) {
if (opt.debug) {
log("f: Detach");
}
chrome.windows.get(tt.CurrentWindowId, {populate : true}, function(window) {
if (window.tabs.length == 1 || tabsIds.length == 0) {
return;
}
if (tabsIds.length == window.tabs.length) {
if (opt.debug) {
log("You are trying to detach all tabs! Skipping!");
}
return;
}
let Indexes = [];
let Parents = [];
let Expands = [];
let NewTabs = [];
let Ind = 0;
tabsIds.forEach(function(tabId) {
let tab = document.getElementById(tabId);
Indexes.push(Array.from(tab.parentNode.children).indexOf(tab));
Parents.push(tab.parentNode.parentNode.id);
Expands.push( (tab.classList.contains("c") ? "c" : (tab.classList.contains("o") ? "o" : "")) );
});
chrome.windows.create({tabId: tabsIds[0], state:window.state}, function(new_window) {
tabsIds.splice(0, 1);
chrome.tabs.move(tabsIds, {windowId: new_window.id, index:-1}, function(MovedTabs) {
if (Folders && Object.keys(Folders).length > 0) {
for (let folder in Folders) {
RemoveFolder(Folders[folder].id);
}
}
});
});
});
}
function CloseTabs(tabsIds) {
if (opt.debug) {
log("f: CloseTabs, tabsIds are: "+JSON.stringify(tabsIds));
}
tabsIds.forEach(function(tabId) {
let Tab = document.getElementById(tabId);
if (Tab != null) {
Tab.classList.add("will_be_closed");
}
});
let activeTab = document.querySelector(".pin.active_tab, #"+tt.active_group+" .tab.active_tab");
if (activeTab != null && tabsIds.indexOf(parseInt(activeTab.id)) != -1) {
SwitchActiveTabBeforeClose(tt.active_group);
}
setTimeout(function() {
tabsIds.forEach(function(tabId) {
let tab = document.getElementById(tabId);
if (tab.classList.contains("pin") && opt.allow_pin_close) {
tab.parentNode.removeChild(tab);
chrome.tabs.update(tabId, {pinned: false});
// RefreshGUI();
}
if (tabId == tabsIds[tabsIds.length-1]) {
setTimeout(function() {
chrome.tabs.remove(tabsIds, null);
}, 10);
}
});
}, 200);
}
function DiscardTabs(tabsIds) {
let delay = 100;
let tabNode = document.getElementById(tabsIds[0]);
if (tabNode == null || tabNode.classList.contains("discarded") || tabNode.classList.contains("active_tab")) {
delay = 5;
} else {
chrome.tabs.discard(tabsIds[0]);
}
tabsIds.splice(0, 1);
if (tabsIds.length > 0) {
setTimeout(function() {
DiscardTabs(tabsIds);
}, delay);
}
}
function SwitchActiveTabBeforeClose(ActiveGroupId) {
if (opt.debug) {
log("f: SwitchActiveTabBeforeClose");
}
let activeGroup = document.getElementById(ActiveGroupId);
if (document.querySelectorAll("#"+ActiveGroupId+" .tab").length < 2 && document.querySelector(".pin.active_tab") == null) { // CHECK IF CLOSING LAST TAB IN ACTIVE GROUP
let pins = document.querySelectorAll(".pin");
if (pins.length > 0) { // IF THERE ARE ANY PINNED TABS, ACTIVATE IT
if (opt.debug) {
log("available pin, switching to: "+pins[pins.length-1].id);
}
chrome.tabs.update(parseInt(pins[pins.length-1].id), {active: true});
return;
} else { // NO OTHER CHOICE BUT TO SEEK IN ANOTHER GROUP
if (opt.after_closing_active_tab == "above" || opt.after_closing_active_tab == "above_seek_in_parent") {
if (activeGroup.previousSibling != null) {
if (document.querySelectorAll("#"+activeGroup.previousSibling.id+" .tab").length > 0) {
SetActiveGroup(activeGroup.previousSibling.id, true, true);
} else {
SwitchActiveTabBeforeClose(activeGroup.previousSibling.id);
return;
}
} else {
SetActiveGroup("tab_list", true, true);
}
} else {
if (activeGroup.nextSibling != null) {
if (document.querySelectorAll("#"+activeGroup.nextSibling.id+" .tab").length > 0) {
SetActiveGroup(activeGroup.nextSibling.id, true, true);
} else {
SwitchActiveTabBeforeClose(activeGroup.nextSibling.id);
return;
}
} else {
SetActiveGroup("tab_list", true, true);
}
}
}
} else {
if (opt.debug) {
log("available tabs in current group, switching option is: "+opt.after_closing_active_tab);
}
if (opt.after_closing_active_tab == "above" || opt.after_closing_active_tab == "above_seek_in_parent") {
ActivatePrevTab(true);
}
if (opt.after_closing_active_tab == "below" || opt.after_closing_active_tab == "below_seek_in_parent") {
ActivateNextTab(true);
}
// if (opt.after_closing_active_tab == "above_seek_in_parent") {
// ActivatePrevTabBeforeClose();
// }
// if (opt.after_closing_active_tab == "below_seek_in_parent") {
// ActivateNextTabBeforeClose();
// }
}
}
function ActivateNextTabBeforeClose() {
let activePin = document.querySelector(".pin.active_tab");
if (activePin != null) {
if (activePin.nextSibling != null) {
chrome.tabs.update(parseInt(activePin.nextSibling.id), { active: true });
} else {
if (activePin.previousSibling != null) {
chrome.tabs.update(parseInt(activePin.previousSibling.id), { active: true });
}
}
}
let will_be_closed = document.querySelectorAll("#"+tt.active_group+" .will_be_closed");
let activeTab = will_be_closed.length > 0 ? will_be_closed[will_be_closed.length-1] : document.querySelector("#"+tt.active_group+" .tab.active_tab");
if (activeTab != null && document.querySelectorAll("#"+tt.active_group+" .tab:not(.will_be_closed)").length > 1) {
if (opt.promote_children && activeTab.childNodes[1].firstChild != null) {
chrome.tabs.update(parseInt(activeTab.childNodes[1].firstChild.id), { active: true });
} else {
if (activeTab.nextSibling != null) {
chrome.tabs.update(parseInt(activeTab.nextSibling.id), { active: true });
} else {
if (activeTab.previousSibling != null) {
chrome.tabs.update(parseInt(activeTab.previousSibling.id), { active: true });
} else {
if (activeTab.parentNode.parentNode.classList.contains("tab")) {
chrome.tabs.update(parseInt(activeTab.parentNode.parentNode.id), { active: true });
} else {
ActivatePrevTab();
}
}
}
}
}
}
function ActivatePrevTabBeforeClose() {
let activePin = document.querySelector(".pin.active_tab");
if (activePin != null) {
if (activePin.previousSibling != null) {
chrome.tabs.update(parseInt(activePin.previousSibling.id), { active: true });
} else {
if (activePin.nextSibling != null) {
chrome.tabs.update(parseInt(activePin.nextSibling.id), { active: true });
}
}
}
let will_be_closed = document.querySelectorAll("#"+tt.active_group+" .will_be_closed");
let activeTab = will_be_closed.length > 0 ? will_be_closed[0] : document.querySelector("#"+tt.active_group+" .tab.active_tab");
if (activeTab != null && document.querySelectorAll("#"+tt.active_group+" .tab:not(.will_be_closed)").length > 1) {
if (opt.promote_children && activeTab.childNodes[1].firstChild != null) {
chrome.tabs.update(parseInt(activeTab.childNodes[1].firstChild.id), { active: true });
} else {
if (activeTab.previousSibling != null) {
chrome.tabs.update(parseInt(activeTab.previousSibling.id), { active: true });
} else {
if (activeTab.nextSibling != null) {
chrome.tabs.update(parseInt(activeTab.nextSibling.id), { active: true });
} else {
if (activeTab.parentNode.parentNode.classList.contains("tab")) {
chrome.tabs.update(parseInt(activeTab.parentNode.parentNode.id), { active: true });
} else {
ActivateNextTab();
}
}
}
}
}
}
function ActivateNextTab(allow_reverse) {
let activePin = document.querySelector(".pin.active_tab");
if (activePin != null) {
if (activePin.nextSibling != null) {
chrome.tabs.update(parseInt(activePin.nextSibling.id), { active: true });
} else {
if (activePin.previousSibling != null && allow_reverse) {
chrome.tabs.update(parseInt(activePin.previousSibling.id), { active: true });
}
}
}
let will_be_closed = document.querySelectorAll("#"+tt.active_group+" .will_be_closed");
let activeTab = will_be_closed.length > 0 ? will_be_closed[will_be_closed.length-1] : document.querySelector("#"+tt.active_group+" .tab.active_tab");
if (activeTab != null && document.querySelectorAll("#"+tt.active_group+" .tab").length > 1) {
let FirstChild = activeTab.childNodes[1].firstChild;
if (FirstChild != null) {
chrome.tabs.update(parseInt(FirstChild.id), { active: true });
} else {
if (activeTab.nextSibling != null) {
chrome.tabs.update(parseInt(activeTab.nextSibling.id), { active: true });
} else {
let Next = null;
while (Next == null && activeTab.parentNode != null && activeTab.parentNode.parentNode != null) {
if (activeTab.parentNode.parentNode.classList != undefined && activeTab.parentNode.parentNode.classList.contains("tab") && activeTab.parentNode.parentNode.nextSibling != null && activeTab.parentNode.parentNode.nextSibling.classList.contains("tab")) {
Next = activeTab.parentNode.parentNode.nextSibling;
}
activeTab = activeTab.parentNode.parentNode;
}
if (Next != null) {
chrome.tabs.update(parseInt(Next.id), { active: true });
} else {
if (allow_reverse) {
ActivatePrevTab();
}
}
}
}
}
}
function ActivatePrevTab(allow_reverse) {
let activePin = document.querySelector(".pin.active_tab");
if (activePin != null) {
if (activePin.previousSibling != null) {
chrome.tabs.update(parseInt(activePin.previousSibling.id), { active: true });
} else {
if (activePin.nextSibling != null && allow_reverse) {
chrome.tabs.update(parseInt(activePin.nextSibling.id), { active: true });
}
}
}
let will_be_closed = document.querySelectorAll("#"+tt.active_group+" .will_be_closed");
let activeTab = will_be_closed.length > 0 ? will_be_closed[0] : document.querySelector("#"+tt.active_group+" .tab.active_tab");
if (activeTab != null && document.querySelectorAll("#"+tt.active_group+" .tab").length > 1) {
let pSchildren = activeTab.previousSibling != null ? document.querySelectorAll("#ct"+activeTab.previousSibling.id+" .tab") : null;
if (activeTab.previousSibling != null && pSchildren.length > 0) {
chrome.tabs.update(parseInt(pSchildren[pSchildren.length-1].id), { active: true });
} else {
if (activeTab.previousSibling != null) {
chrome.tabs.update(parseInt(activeTab.previousSibling.id), { active: true });
} else {
if (activeTab.parentNode.parentNode.classList.contains("tab")) {
chrome.tabs.update(parseInt(activeTab.parentNode.parentNode.id), { active: true });
} else {
if (allow_reverse) {
ActivateNextTab();
}
}
}
}
}
}
function OpenNewTab(pin, parentId) {
if (pin) {
chrome.tabs.create({pinned: true}, function(tab) {
if (parentId) {
AppendTab({tab: tab, ParentId: "pin_list", InsertAfterId: parentId, Append: true, Scroll: true});
tt.schedule_update_data++;
}
});
} else {
chrome.tabs.create({}, function(tab) {
if (parentId) {
AppendTab({tab: tab, ParentId: parentId, Append: (opt.append_orphan_tab == "top" ? false : true), Scroll: true});
tt.schedule_update_data++;
}
if (opt.move_tabs_on_url_change == "from_empty") {
chrome.runtime.sendMessage({command: "remove_tab_from_empty_tabs", tabId: tab.id});
}
});
}
}
function DuplicateTab(SourceTabNode) {
chrome.tabs.duplicate(parseInt(SourceTabNode.id), function(tab) {
let DupRetry = setInterval(function() {
let DupTab = document.getElementById(tab.id);
if (DupTab != null) {
if (browserId == "F" && tab.pinned) {
DupTab.classList.remove("tab");
DupTab.classList.add("pin");
}
InsterAfterNode(DupTab, SourceTabNode);
RefreshExpandStates();
tt.schedule_update_data++;
RefreshCounters();
clearInterval(DupRetry);
}
}, 10);
setTimeout(function() {
if (DupRetry) {
clearInterval(DupRetry);
}
}, 500);
});
}
function DeselectTabs() {
document.querySelectorAll(".pin.selected_tab, #"+tt.active_group+" .selected_tab").forEach(function(s){
s.classList.remove("selected_tab");
s.classList.remove("selected_last");
});
}
// TAB EVENTS
function EventExpandBox(Node) {
if (Node.classList.contains("o")) {
Node.classList.remove("o");
Node.classList.add("c");
if (Node.classList.contains("tab")) {
chrome.runtime.sendMessage({ command: "update_tab", tabId: parseInt(Node.id), tab: { expand: "c" } });
}
if (Node.classList.contains("folder")) {
SaveFolders();
}
} else {
if (Node.classList.contains("c")) {
if (opt.collapse_other_trees) {
let thisTreeTabs = GetParentsByClass(Node.childNodes[0], "tab"); // start from tab's first child, instead of tab, important to include clicked tab as well
let thisTreeFolders = GetParentsByClass(Node.childNodes[0], "folder");
document.querySelectorAll("#"+tt.active_group+" .o.tab").forEach(function(s){
s.classList.remove("o");
s.classList.add("c");
chrome.runtime.sendMessage({ command: "update_tab", tabId: parseInt(s.id), tab: { expand: "c" } });
});
document.querySelectorAll("#"+tt.active_group+" .o.folder").forEach(function(s){
s.classList.remove("o");
s.classList.add("c");
});
thisTreeTabs.forEach(function(s){
s.classList.remove("c");
s.classList.add("o");
chrome.runtime.sendMessage({ command: "update_tab", tabId: parseInt(s.id), tab: { expand: "o" } });
});
thisTreeFolders.forEach(function(s){
s.classList.remove("c");
s.classList.add("o");
});
SaveFolders();
if (Node.classList.contains("tab")) {
ScrollToTab(Node.id);
}
} else {
Node.classList.remove("c");
Node.classList.add("o");
if (Node.classList.contains("tab")) {
chrome.runtime.sendMessage({ command: "update_tab", tabId: parseInt(Node.id), tab: { expand: "o" } });
}
if (Node.classList.contains("folder")) {
SaveFolders();
}
}
}
}
}
function EventSelectTab(event, TabNode) {
DeselectFolders();
if (event.shiftKey) { // SET SELECTION WITH SHIFT
let activeTab = document.querySelector("#"+tt.active_group+" .selected_tab.selected_last");
if (activeTab == null) {
activeTab = document.querySelector(".pin.active_tab, #"+tt.active_group+" .tab.active_tab");
}
if (activeTab != null && TabNode.parentNode.id == activeTab.parentNode.id) {
if (!event.ctrlKey) {
document.querySelectorAll(".pin.selected_tab, #"+tt.active_group+" .selected_tab").forEach(function(s){
s.classList.remove("selected_frozen");
s.classList.remove("selected_temporarly");
s.classList.remove("selected_tab");
s.classList.remove("selected_last");
});
}
let ChildrenArray = Array.from(TabNode.parentNode.children);
let activeTabIndex = ChildrenArray.indexOf(activeTab);
let thisTabIndex = ChildrenArray.indexOf(TabNode);
let fromIndex = thisTabIndex >= activeTabIndex ? activeTabIndex : thisTabIndex;
let toIndex = thisTabIndex >= activeTabIndex ? thisTabIndex : activeTabIndex;
for (let i = fromIndex; i <= toIndex; i++) {
activeTab.parentNode.childNodes[i].classList.add("selected_tab");
if (i == toIndex && event.ctrlKey) {
activeTab.parentNode.childNodes[i].classList.add("selected_last");
}
}
}
}
if (event.ctrlKey && !event.shiftKey) { // TOGGLE SELECTION WITH CTRL
TabNode.classList.toggle("selected_tab");
if (TabNode.classList.contains("selected_tab")) {
document.querySelectorAll(".selected_last").forEach(function(s){
s.classList.remove("selected_last");
});
TabNode.classList.add("selected_last");
} else {
TabNode.classList.remove("selected_last");
}
}
}
function ActionClickTab(TabNode, bgOption) {
if (bgOption == "new_tab") {
OpenNewTab(TabNode.classList.contains("pin"), TabNode.id);
}
if (bgOption == "expand_collapse") {
EventExpandBox(TabNode);
}
if (bgOption == "close_tab") {
if ((TabNode.classList.contains("pin") && opt.allow_pin_close) || TabNode.classList.contains("tab")) {
CloseTabs([parseInt(TabNode.id)]);
}
}
if (bgOption == "undo_close_tab") {
chrome.sessions.getRecentlyClosed( null, function(sessions) {
if (sessions.length > 0) {
chrome.sessions.restore(null, function(restored) {});
}
});
}
if (bgOption == "reload_tab") {
chrome.tabs.reload(parseInt(TabNode.id));
}
if (bgOption == "unload_tab") {
if (TabNode.classList.contains("active_tab")) {
SwitchActiveTabBeforeClose(tt.active_group);
setTimeout(function() {
DiscardTabs([parseInt(TabNode.id)]);
}, 500);
} else {
DiscardTabs([parseInt(TabNode.id)]);
}
}
if (bgOption == "activate_previous_active" && TabNode.classList.contains("active_tab")) {
chrome.tabs.update(parseInt(tt.groups[tt.active_group].prev_active_tab), {active: true});
}
}
function TabStartDrag(Node, event) {
event.stopPropagation();
event.dataTransfer.setDragImage(document.getElementById("DragImage"), 0, 0);
event.dataTransfer.setData("text", "");
event.dataTransfer.setData("SourceWindowId", tt.CurrentWindowId);
CleanUpDragClasses();
EmptyDragAndDrop();
tt.DragNodeClass = "tab";
let TabsIds = [];
let TabsIdsParents = [];
let TabsIdsSelected = [];
if (Node.classList.contains("selected_tab")) {
document.querySelectorAll(".group:not(#"+tt.active_group+") .selected_tab").forEach(function(s){
s.classList.add("selected_frozen");
s.classList.remove("selected_tab");
s.classList.remove("selected_last");
});
document.querySelectorAll("#pin_list .selected_tab, .group#"+tt.active_group+" .selected_tab").forEach(function(s){
TabsIdsSelected.push(parseInt(s.id));
});
} else {
FreezeSelected();
Node.classList.add("selected_temporarly");
Node.classList.add("selected_tab");
TabsIdsSelected.push(parseInt(Node.id));
event.dataTransfer.setData("DraggedTabNode", Node.id);
}
document.querySelectorAll("[id='"+Node.id+"'], [id='"+Node.id+"'] .tab").forEach(function(s){
s.classList.add("dragged_tree");
});
if (opt.max_tree_drag_drop || opt.max_tree_depth >= 0) {
document.querySelectorAll(".dragged_tree .tab").forEach(function(s){
let parents = GetParentsByClass(s.parentNode, "dragged_tree");
if (parents.length > tt.DragTreeDepth) {
tt.DragTreeDepth = parents.length;
}
});
} else {
tt.DragTreeDepth = -1;
}
// REST OF SELECTED TABS THAT WILL BE DRAGGED
document.querySelectorAll(".selected_tab, .selected_tab .tab").forEach(function(s){
s.classList.add("dragged_tree");
TabsIds.push(parseInt(s.id));
TabsIdsParents.push(s.parentNode.id);
});
let DraggedFolderParents = GetParentsByClass(Node, "folder");
DraggedFolderParents.forEach(function(s){
s.classList.add("dragged_parents");
});
let DraggedParents = GetParentsByClass(Node, "tab");
DraggedParents.forEach(function(s){
s.classList.add("dragged_parents");
});
DragAndDropData = {TabsIds: TabsIds, TabsIdsParents: TabsIdsParents, TabsIdsSelected: TabsIdsSelected};
event.dataTransfer.setData("Class", "tab");
event.dataTransfer.setData("TabsIds", JSON.stringify(TabsIds));
event.dataTransfer.setData("TabsIdsParents", JSON.stringify(TabsIdsParents));
event.dataTransfer.setData("TabsIdsSelected", JSON.stringify(TabsIdsSelected));
chrome.runtime.sendMessage({
command: "drag_drop",
DragNodeClass: "tab",
DragTreeDepth: tt.DragTreeDepth
});
if (opt.debug) {
log("f: TabStartDrag, Node: "+Node.id+", TabsIdsSelected: "+JSON.stringify(TabsIdsSelected)+", TabsIds: "+JSON.stringify(TabsIds)+", TabsIdsParents: "+JSON.stringify(TabsIdsParents) );
}
}
function TabDragOver(Node, event) {
if (tt.DragNodeClass == "tab" && Node.parentNode.classList.contains("dragged_tree") == false) {
if (Node.parentNode.classList.contains("pin")) {
if (Node.parentNode.classList.contains("before") == false && event.layerX < Node.clientWidth/2) {
RemoveHighlight();
Node.parentNode.classList.remove("after");
Node.parentNode.classList.add("before");
Node.parentNode.classList.add("highlighted_drop_target");
}
if (Node.parentNode.classList.contains("after") == false && event.layerX >= Node.clientWidth/2) {
RemoveHighlight();
Node.parentNode.classList.remove("before");
Node.parentNode.classList.add("after");
Node.parentNode.classList.add("highlighted_drop_target");
}
}
if (Node.parentNode.classList.contains("tab")) {
let PDepth = (GetParentsByClass(Node, "tab")).length + tt.DragTreeDepth;
let PIsGroup = Node.parentNode.parentNode.parentNode.classList.contains("group");
let PIsDraggedParents = Node.parentNode.classList.contains("dragged_parents");
if (Node.parentNode.classList.contains("before") == false && event.layerY < Node.clientHeight/3 && (PDepth <= opt.max_tree_depth+1 || opt.max_tree_depth < 0 || PIsGroup || PIsDraggedParents || opt.max_tree_drag_drop == false)) {
RemoveHighlight();
Node.parentNode.classList.remove("inside");
Node.parentNode.classList.remove("after");
Node.parentNode.classList.add("before");
Node.parentNode.classList.add("highlighted_drop_target");
}
if (Node.parentNode.classList.contains("inside") == false && event.layerY > Node.clientHeight/3 && event.layerY <= 2*(Node.clientHeight/3) && (PDepth <= opt.max_tree_depth || opt.max_tree_depth < 0 || PIsDraggedParents || opt.max_tree_drag_drop == false)) {
RemoveHighlight();
Node.parentNode.classList.remove("before");
Node.parentNode.classList.remove("after");
Node.parentNode.classList.add("inside");
Node.parentNode.classList.add("highlighted_drop_target");
}
if (Node.parentNode.classList.contains("after") == false && Node.parentNode.classList.contains("o") == false && event.layerY > 2*(Node.clientHeight/3) && (PDepth <= opt.max_tree_depth+1 || opt.max_tree_depth < 0 || PIsGroup || PIsDraggedParents || opt.max_tree_drag_drop == false)) {
RemoveHighlight();
Node.parentNode.classList.remove("inside");
Node.parentNode.classList.remove("before");
Node.parentNode.classList.add("after");
Node.parentNode.classList.add("highlighted_drop_target");
}
}
}
}