TreeTabsMigration/background.js

598 lines
26 KiB
JavaScript

// BACKGROUND VARIABLES
let b = {
debug: [],
bg_running: false,
schedule_save: 0,
windows: {},
tabs: {},
tt_ids: {},
EmptyTabs: [],
newTabUrl: browserId == "F" ? "about:newtab" : "chrome://startpage/",
safe_mode: false
};
// BACKGROUND FUNCTIONS
function pushlog(log) {
b.debug.push(log);
if (b.debug.length > 100) b.debug.splice(0, 1);
console.log(log);
b.schedule_save++;
}
function ReplaceParents(oldTabId, newTabId) {
for (let tabId in b.tabs) {
if (b.tabs[tabId].parent == oldTabId) b.tabs[tabId].parent = newTabId;
}
}
async function DiscardTab(tabId) {
let DiscardTimeout = 0;
let Discard = setInterval(function() {
chrome.tabs.get(tabId, function(tab) {
if ((tab.favIconUrl != undefined && tab.favIconUrl != "" && tab.title != undefined && tab.title != "") || tab.status == "complete" || tab.audible) {
chrome.tabs.discard(tab.id);
clearInterval(Discard);
}
if (DiscardTimeout > 300) clearInterval(Discard);
});
DiscardTimeout++;
}, 2000);
}
async function DiscardWindow(windowId) {
let DiscardTimeout = 0;
let DiscardedTabs = 0;
let Discard = setInterval(function() {
chrome.windows.get(windowId, { populate: true }, function(w) {
for (let i = 0; i < w.tabs.length; i++) {
if (w.tabs[i].discarded == false && w.tabs[i].active == false) {
if ((w.tabs[i].favIconUrl != undefined && w.tabs[i].favIconUrl != "" && w.tabs[i].title != undefined && w.tabs[i].title != "") || w.tabs[i].status == "complete" || tab.audible) {
chrome.tabs.discard(w.tabs[i].id);
DiscardedTabs++;
}
}
}
if (DiscardedTabs == w.tabs.length) clearInterval(Discard);
});
if (DiscardTimeout > 300) clearInterval(Discard);
DiscardTimeout++;
}, 5000);
}
function GetTabGroupId(tabId, windowId) {
let groupId = "tab_list";
if (tabId == undefined || windowId == undefined || b.windows[windowId] == undefined || b.tabs[tabId] == undefined) return groupId;
let parent = b.tabs[tabId].parent;
while (parent) {
if (isNaN(parent) == false && b.tabs[parent]) {
parent = b.tabs[parent].parent;
} else {
if (parent.match("tab_list|g_|f_") == null && b.tabs[parent]) {
parent = b.tabs[parent].parent;
} else {
if (parent.match("f_") != null && b.windows[windowId].folders[parent]) {
parent = b.windows[windowId].folders[parent].parent;
} else {
if (parent.match("pin_list|tab_list|g_") != null) {
groupId = parent;
parent = false;
} else {
parent = false;
}
}
}
}
}
return groupId;
}
function GetTabParents(tabId, windowId) {
let Parents = [];
if (tabId == undefined) return Parents;
if (b.tabs[tabId] == undefined) return Parents;
let parent = b.tabs[tabId].parent;
let escape = 9999;
while (escape > 0 && (b.tabs[parent] != undefined || b.windows[windowId].folders[parent])) {
if (b.tabs[parent]) {
Parents.push(parent);
parent = b.tabs[parent].parent;
} else {
if (b.windows[windowId].folders[parent]) {
Parents.push(parent);
parent = b.windows[windowId].folders[parent].parent;
}
}
escape--;
}
return Parents;
}
function GetChildren(TTObj, parentId) { // TTObj is b.tabs or b.windows[winId].folders
let Children = [];
for (let Id in TTObj) {
if (TTObj[Id].parent == parentId) Children.push(Id);
}
return Children;
}
function ShiftChildrenIndexes(TabsIdsArray, OpenerIndex, folderIdsArray, windowId) {
for (let tabId of TabsIdsArray) { // shift indexes of siblings tabs
if (b.tabs[tabId].index > OpenerIndex) b.tabs[tabId].index += 1;
}
for (let folderId of folderIdsArray) { // shift indexes of siblings folders
if (b.windows[windowId].folders[folderId].index > OpenerIndex) b.windows[windowId].folders[folderId].index += 1;
}
}
function UnshiftChildrenIndexes(TabsIdsArray, ClosedIndex, folderIdsArray, windowId) {
for (let tabId of TabsIdsArray) { // shift indexes of siblings tabs
if (b.tabs[tabId].index > ClosedIndex) b.tabs[tabId].index -= 1;
}
for (let folderId of folderIdsArray) { // shift indexes of siblings folders
if (b.windows[windowId].folders[folderId].index > ClosedIndex) b.windows[windowId].folders[folderId].index -= 1;
}
}
function AppendTabToGroupOnRegexMatch(tabId, windowId, url) {
let TabGroupId = GetTabGroupId(tabId, windowId);
for (let i = 0; i < opt.tab_group_regexes.length; i++) {
let regexPair = opt.tab_group_regexes[i];
if (url.match(regexPair[0])) {
let groupId = FindGroupIdByName(regexPair[1], b.windows[windowId].groups);
let groupName = regexPair[1];
if (groupId === null) { // no group
let newGroupID = "";
while (newGroupID == "") {
newGroupID = "g_" + GenerateRandomID();
for (let wId in b.windows) {
for (let gId in b.windows[wId].groups) {
if (gId == newGroupID) newGroupID = "";
}
}
}
groupId = newGroupID;
b.windows[windowId].groups[groupId] = { id: groupId, index: 999, active_tab: 0, prev_active_tab: 0, name: groupName, font: "" };
chrome.runtime.sendMessage({ command: "append_group", groupId: groupId, group_name: groupName, font_color: "", windowId: windowId });
}
if (TabGroupId != groupId && groupId != null) {
b.tabs[tabId].parent = groupId;
setTimeout(function() {
chrome.runtime.sendMessage({ command: "append_tab_to_group", tabId: tabId, groupId: groupId, windowId: windowId });
}, 100);
}
break;
}
}
return b.tabs[tabId].parent;
}
function FindGroupIdByName(name, groups) {
for (let groupId in groups) {
if (!groups.hasOwnProperty(groupId)) continue;
if (groups[groupId].name === name) return groupId;
}
return null;
}
// LISTENERS
function StartBackgroundListeners() {
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message.command == "is_bg_ready") {
sendResponse(b.bg_running);
return;
}
if (message.command == "is_bg_safe_mode") {
sendResponse(b.safe_mode);
return;
}
if (message.command == "reload") {
window.location.reload();
return;
}
if (message.command == "reload_options") {
opt = Object.assign({}, message.opt);
return;
}
if (message.command == "get_windows") {
sendResponse(b.windows);
return;
}
if (message.command == "get_folders") {
if (b.windows[message.windowId]) {
sendResponse(b.windows[message.windowId].folders);
}
return;
}
if (message.command == "save_folders") {
if (b.windows[message.windowId]) {
b.windows[message.windowId].folders = Object.assign({}, message.folders);
b.schedule_save++;
}
return;
}
if (message.command == "get_groups") {
if (b.windows[message.windowId]) {
sendResponse(b.windows[message.windowId].groups);
}
return;
}
if (message.command == "save_groups") {
if (b.windows[message.windowId]) {
b.windows[message.windowId].groups = Object.assign({}, message.groups);
b.schedule_save++;
}
return;
}
if (message.command == "set_active_group") {
if (b.windows[message.windowId]) {
b.windows[message.windowId].active_group = message.active_group;
b.schedule_save++;
}
return;
}
if (message.command == "get_active_group") {
if (b.windows[message.windowId]) {
sendResponse(b.windows[message.windowId].active_group);
}
return;
}
if (message.command == "set_search_filter") {
if (b.windows[message.windowId]) {
b.windows[message.windowId].search_filter = message.search_filter;
b.schedule_save++;
}
return;
}
if (message.command == "get_search_filter") {
if (b.windows[message.windowId]) {
sendResponse(b.windows[message.windowId].search_filter);
}
return;
}
if (message.command == "set_active_shelf") {
if (b.windows[message.windowId]) {
b.windows[message.windowId].active_shelf = message.active_shelf;
b.schedule_save++;
}
return;
}
if (message.command == "get_active_shelf") {
if (b.windows[message.windowId]) {
sendResponse(b.windows[message.windowId].active_shelf);
}
return;
}
if (message.command == "set_group_bar") {
if (b.windows[message.windowId]) {
b.windows[message.windowId].group_bar = message.group_bar;
b.schedule_save++;
}
return;
}
if (message.command == "get_group_bar") {
if (b.windows[message.windowId]) {
sendResponse(b.windows[message.windowId].group_bar);
}
return;
}
if (message.command == "get_browser_tabs") {
sendResponse(b.tabs);
return;
}
if (message.command == "update_tab") {
if (b.tabs[message.tabId]) {
if (message.tab.index) {
b.tabs[message.tabId].index = message.tab.index;
}
if (message.tab.expand) {
b.tabs[message.tabId].expand = message.tab.expand;
}
if (message.tab.parent) {
b.tabs[message.tabId].parent = message.tab.parent;
}
b.schedule_save++;
}
return;
}
if (message.command == "update_all_tabs") {
for (let pin of message.pins) {
if (b.tabs[pin.id]) {
b.tabs[pin.id].parent = "pin_list";
b.tabs[pin.id].expand = "";
b.tabs[pin.id].index = pin.index;
}
}
for (let tab of message.tabs) {
if (b.tabs[tab.id]) {
b.tabs[tab.id].parent = tab.parent;
b.tabs[tab.id].expand = tab.expand;
b.tabs[tab.id].index = tab.index;
}
}
b.schedule_save++;
return;
}
if (message.command == "all_tabs_exist") {
let yes = true;
for (let Win in message.windows) {
for (let Tab in message.windows[Win].tabs) {
if (b.tabs[message.windows[Win].tabs[Tab].id] == undefined) {
yes = false;
}
}
}
sendResponse(yes);
return;
}
if (message.command == "does_tabs_match") {
let match = true;
for (let Win in message.windows) {
for (let Tab in message.windows[Win].tabs) {
if (b.tabs[message.windows[Win].tabs[Tab].id] != undefined) {
if (message.windows[Win].tabs[Tab].parent !== b.tabs[message.windows[Win].tabs[Tab].id].parent) {
match = false;
}
}
}
}
sendResponse(match);
return;
}
if (message.command == "discard_tab") {
DiscardTab(message.tabId);
return;
}
if (message.command == "discard_window") {
DiscardWindow(message.windowId);
return;
}
if (message.command == "remove_tab_from_empty_tabs") {
setTimeout(function() {
if (b.EmptyTabs.indexOf(message.tabId) != -1) {
b.EmptyTabs.splice(b.EmptyTabs.indexOf(message.tabId), 1);
}
}, 100);
return;
}
if (message.command == "debug") {
pushlog(message.log);
return;
}
});
// WebChromeClient.onConsoleMessage(ConsoleMessage consoleMessage)
}
// NEW TAB
function OnMessageTabCreated(NewTab, activeTabId) {
let ParentId;
let AfterId;
let append;
if (b.windows[NewTab.windowId] && NewTab.active) {
b.windows[NewTab.windowId].groups[b.windows[NewTab.windowId].active_group].active_tab = NewTab.id;
}
if (NewTab.url == b.newTabUrl) {
b.EmptyTabs.push(NewTab.id);
}
if (NewTab.pinned) {
let PinTabs = GetChildren(b.tabs, "pin_list");
b.tabs[NewTab.id].parent = "pin_list";
if (opt.append_pinned_tab == "after") {
if (NewTab.openerTabId && b.tabs[NewTab.openerTabId]) { // has opener tab case
ShiftChildrenIndexes(PinTabs, b.tabs[NewTab.openerTabId].index, [], NewTab.windowId);
b.tabs[NewTab.id].index = NewTab.index;
AfterId = NewTab.openerTabId;
} else {
if (b.tabs[activeTabId]) { // after active case
ShiftChildrenIndexes(PinTabs, b.tabs[activeTabId].index, [], NewTab.windowId);
AfterId = activeTabId;
}
}
}
if (opt.append_pinned_tab == "first") { // as first
ShiftChildrenIndexes(PinTabs, -1, [], NewTab.windowId);
b.tabs[NewTab.id].index = 0;
append = false;
}
if (opt.append_pinned_tab == "last") { // as last
b.tabs[NewTab.id].index = PinTabs.length;
append = true;
}
} else {
if (opt.append_orphan_tab == "as_child" && opt.orphaned_tabs_to_ungrouped == false) {
NewTab.openerTabId = activeTabId;
}
if (NewTab.openerTabId) { // child case
let OpenerSiblingTabs = GetChildren(b.tabs, b.tabs[NewTab.openerTabId].parent);
let OpenerSiblingFolders = GetChildren(b.windows[NewTab.windowId].folders, b.tabs[NewTab.openerTabId].parent);
if (opt.append_child_tab == "after") { // place tabs flat without automatic tree
b.tabs[NewTab.id].parent = b.tabs[NewTab.openerTabId].parent;
ShiftChildrenIndexes(OpenerSiblingTabs, b.tabs[NewTab.openerTabId].index, OpenerSiblingFolders, NewTab.windowId);
b.tabs[NewTab.id].index = b.tabs[NewTab.openerTabId].index + 1;
AfterId = NewTab.openerTabId;
} else {
if (opt.max_tree_depth == 0) { // place tabs flat if limit is set to 0
b.tabs[NewTab.id].parent = b.tabs[NewTab.openerTabId].parent;
if (opt.append_child_tab_after_limit == "after") { // max tree depth, place tab after parent
ShiftChildrenIndexes(OpenerSiblingTabs, b.tabs[NewTab.openerTabId].index, OpenerSiblingFolders, NewTab.windowId);
b.tabs[NewTab.id].index = b.tabs[NewTab.openerTabId].index + 1;
AfterId = NewTab.openerTabId;
}
if (opt.append_child_tab_after_limit == "top" && opt.append_child_tab != "after") { // max tree depth, place tab on top (above parent)
ShiftChildrenIndexes(OpenerSiblingTabs, -1, OpenerSiblingFolders, NewTab.windowId);
b.tabs[NewTab.id].index = 0;
ParentId = b.tabs[NewTab.id].parent;
append = false;
}
if (opt.append_child_tab_after_limit == "bottom" && opt.append_child_tab != "after") { // max tree depth, place tab on bottom (below parent)
b.tabs[NewTab.id].index = OpenerSiblingTabs.length + OpenerSiblingFolders.length;
ParentId = b.tabs[NewTab.id].parent;
append = true;
}
} else {
let Parents = GetTabParents(NewTab.openerTabId, NewTab.windowId);
let OpenerChildren = GetChildren(b.tabs, NewTab.openerTabId);
if (opt.max_tree_depth < 0 || (opt.max_tree_depth > 0 && Parents.length < opt.max_tree_depth)) { // append to tree on top and bottom
b.tabs[NewTab.id].parent = NewTab.openerTabId;
if (opt.append_child_tab == "top") { // place child tab at the top (reverse hierarchy)
ShiftChildrenIndexes(OpenerSiblingTabs, -1, OpenerSiblingFolders, NewTab.windowId);
b.tabs[NewTab.id].index = 0;
ParentId = b.tabs[NewTab.id].parent;
}
if (opt.append_child_tab == "bottom") { // place child tab at the bottom
b.tabs[NewTab.id].index = OpenerSiblingTabs.length + OpenerSiblingFolders.length;
ParentId = b.tabs[NewTab.id].parent;
append = true;
}
} else {
if (opt.max_tree_depth > 0 && Parents.length >= opt.max_tree_depth) { // if reached depth limit of the tree
b.tabs[NewTab.id].parent = b.tabs[NewTab.openerTabId].parent;
if (opt.append_child_tab_after_limit == "after") { // tab will append after opener
ShiftChildrenIndexes(OpenerSiblingTabs, b.tabs[NewTab.openerTabId].index, OpenerSiblingFolders, NewTab.windowId);
b.tabs[NewTab.id].index = b.tabs[NewTab.openerTabId].index + 1;
AfterId = NewTab.openerTabId;
}
if (opt.append_child_tab_after_limit == "top") { // tab will append on top
ShiftChildrenIndexes(OpenerSiblingTabs, -1, OpenerSiblingFolders, NewTab.windowId);
b.tabs[NewTab.id].index = 0;
ParentId = b.tabs[NewTab.id].parent;
}
if (opt.append_child_tab_after_limit == "bottom") { // tab will append on bottom
b.tabs[NewTab.id].index = OpenerSiblingTabs.length + OpenerSiblingFolders.length;
ParentId = b.tabs[NewTab.id].parent;
append = true;
}
}
}
}
}
} else { // ORPHAN TAB
if (opt.orphaned_tabs_to_ungrouped == true) { // if set to append orphan tabs to ungrouped group
let TabListTabs = GetChildren(b.tabs, "tab_list");
let TabListFolders = GetChildren(b.windows[NewTab.windowId].folders, "tab_list");
b.tabs[NewTab.id].index = TabListTabs.length + TabListFolders.length;
ParentId = "tab_list";
append = true;
} else {
if (opt.append_orphan_tab == "after_active" || opt.append_orphan_tab == "active_parent_top" || opt.append_orphan_tab == "active_parent_bottom") {
if (b.windows[NewTab.windowId] && b.windows[NewTab.windowId].activeTabId) {
if (b.tabs[activeTabId]) {
let ActiveTabSiblings = GetChildren(b.tabs, b.tabs[activeTabId].parent);
let ActiveTabSiblingFolders = GetChildren(b.windows[NewTab.windowId].folders, b.tabs[activeTabId].parent);
b.tabs[NewTab.id].parent = b.tabs[activeTabId].parent;
if (opt.append_orphan_tab == "after_active") {
ShiftChildrenIndexes(ActiveTabSiblings, b.tabs[activeTabId].index, ActiveTabSiblingFolders, NewTab.windowId);
b.tabs[NewTab.id].index = b.tabs[activeTabId].index + 1;
AfterId = activeTabId;
}
if (opt.append_orphan_tab == "active_parent_top") {
ShiftChildrenIndexes(ActiveTabSiblings, -1, ActiveTabSiblingFolders, NewTab.windowId);
b.tabs[NewTab.id].index = 0;
ParentId = b.tabs[NewTab.id].parent;
}
if (opt.append_orphan_tab == "active_parent_bottom") {
b.tabs[NewTab.id].index = ActiveTabSiblings.length + ActiveTabSiblingFolders.length;
ParentId = b.tabs[NewTab.id].parent;
append = true;
}
} else { // FAIL, no active tab!
let ActiveGroupTabs = GetChildren(b.tabs, b.windows[NewTab.windowId].active_group);
let ActiveGroupFolders = GetChildren(b.windows[NewTab.windowId].folders, b.windows[NewTab.windowId].active_group);
b.tabs[NewTab.id].parent = b.windows[NewTab.windowId].active_group;
b.tabs[NewTab.id].index = ActiveGroupTabs.length + ActiveGroupFolders.length;
ParentId = b.windows[NewTab.windowId].active_group;
}
} else {
b.tabs[NewTab.id].parent = "tab_list";
b.tabs[NewTab.id].index = NewTab.index;
ParentId = "tab_list";
}
}
if (opt.append_orphan_tab == "top") {
let ActiveGroupTabs = GetChildren(b.tabs, b.windows[NewTab.windowId].active_group);
let ActiveGroupFolders = GetChildren(b.windows[NewTab.windowId].folders, b.tabs[activeTabId].parent);
b.tabs[NewTab.id].parent = b.windows[NewTab.windowId].active_group;
ShiftChildrenIndexes(ActiveGroupTabs, -1, ActiveGroupFolders, NewTab.windowId);
b.tabs[NewTab.id].index = 0;
ParentId = b.windows[NewTab.windowId].active_group;
}
if (opt.append_orphan_tab == "bottom") {
let ActiveGroupTabs = GetChildren(b.tabs, b.windows[NewTab.windowId].active_group);
let ActiveGroupFolders = b.tabs[activeTabId] ? GetChildren(b.windows[NewTab.windowId].folders, b.tabs[activeTabId].parent) : [];
b.tabs[NewTab.id].parent = b.windows[NewTab.windowId].active_group;
b.tabs[NewTab.id].index = ActiveGroupTabs.length + ActiveGroupFolders.length;
ParentId = b.windows[NewTab.windowId].active_group;
append = true;
}
}
}
if (opt.move_tabs_on_url_change === "all_new" && NewTab.pinned == false) {
setTimeout(function() {
chrome.tabs.get(NewTab.id, function(CheckTabsUrl) {
AppendTabToGroupOnRegexMatch(CheckTabsUrl.id, CheckTabsUrl.windowId, CheckTabsUrl.url);
});
}, 100);
}
}
setTimeout(function() {
b.schedule_save++;
}, 500);
chrome.runtime.sendMessage({ command: "tab_created", windowId: NewTab.windowId, tabId: NewTab.id, tab: NewTab, ParentId: ParentId, InsertAfterId: AfterId, Append: append });
}
function SafeModeCheck() {
setInterval(function() {
if (b.safe_mode) {
if (browserId == "F") {
chrome.windows.getAll({ windowTypes: ["normal"], populate: true }, function(w) {
for (win of w) {
Promise.resolve(browser.sessions.getWindowValue(win.id, "TTdata")).then(function(WindowData) {
if (WindowData != undefined) {
chrome.runtime.sendMessage({command: "reload_sidebar"});
window.location.reload();
}
});
}
});
}
}
}, 2000);
}
// START BACKGROUND SCRIPT
document.addEventListener("DOMContentLoaded", function() {
StartBackgroundListeners();
if (browserId == "F") {
QuantumStart();
}
if (browserId == "O") {
OperaStart();
}
if (browserId == "V") {
VivaldiStart();
}
});