function Groups_AppendGroupToList(groupId, group_name, font_color, SetEvents) { if (document.getElementById(groupId) == null) { let grp = DOM_New("div", document.getElementById("groups"), {id: groupId, className: "group"}, {display: "none"}); DOM_New("div", grp, {id: ("°" + groupId), className: "children"}); if (SetEvents) { grp.onclick = function(event) { if (event.which == 1 && event.target == this && event.clientX < (this.childNodes[0].getBoundingClientRect().width + this.getBoundingClientRect().left)) DOM_Deselect(); } grp.onmousedown = function(event) { event.stopImmediatePropagation(); if (event.which == 1 && event.target == this && event.clientX < (this.childNodes[0].getBoundingClientRect().width + this.getBoundingClientRect().left)) { Menu_HideMenus(); return false; } if (event.which == 2) { event.preventDefault(); Groups_ActionClickGroup(this, opt.midclick_group); } if (event.which == 3 && event.target.id == this.id) Menu_ShowFGlobalMenu(event); if (browserId == "V") { chrome.windows.getCurrent({populate: false}, function(window) { if (tt.CurrentWindowId != window.id && window.focused) location.reload(); }); } } grp.ondragover = function(event) { if (event.target.id == this.id && (tt.DraggingGroup || tt.DraggingPin || tt.DraggingTab || tt.DraggingFolder)) { DOM_RemoveHighlight(); this.classList.add("highlighted_drop_target"); } } grp.ondblclick = function(event) { if (event.target.id == this.id) Groups_ActionClickGroup(this, opt.dbclick_group); } if (opt.switch_with_scroll) DOM_BindTabsSwitchingToMouseWheel(groupId); } } if (document.getElementById("_" + groupId) == null) { let gbn = DOM_New("div", document.getElementById("group_list"), {id: ("_" + groupId), className: "group_button", draggable: (SetEvents ? true : false)}); DOM_New("span", gbn, {id: ("_gte" + groupId), className: "group_title", textContent: group_name}, {color: (font_color != "" ? ("#" + font_color) : (window.getComputedStyle(document.getElementById("body"), null).getPropertyValue("--group_list_default_font_color")))}); DOM_New("div", gbn, {id: ("di" + groupId), className: "drag_indicator"}); if (SetEvents) { gbn.onclick = function(event) { Groups_SetActiveGroup(this.id.substr(1), true, true); } gbn.onmousedown = function(event) { if (event.which == 3) Menu_ShowFGroupMenu(document.getElementById(this.id.substr(1)), event); } gbn.ondblclick = function(event) { if (event.which == 1 && this.id != "_tab_list") Groups_ShowGroupEditWindow((this.id).substr(1)); } gbn.ondragstart = function(event) { // DRAG START event.stopPropagation(); event.dataTransfer.setDragImage(document.getElementById("DragImage"), 0, 0); event.dataTransfer.setData("text", ""); event.dataTransfer.setData("SourceWindowId", tt.CurrentWindowId); DOM_CleanUpDragAndDrop(); tt.Dragging = true; tt.DraggingGroup = true; tt.DragTreeDepth = -1; let groupId = this.id.substr(1); let Group = Object.assign({}, tt.groups[groupId]); let Nodes = []; let query = document.querySelectorAll("#" + groupId + " .tab, #" + groupId + " .folder"); for (let s of query) { if (s.classList.contains("tab")) { tt.DraggingTab = true; Nodes.push({id: s.id, parent: s.parentNode.id, selected: false, temporary: false, NodeClass: "tab"}); } if (s.classList.contains("folder")) { tt.DraggingFolder = true; Nodes.push({id: s.id, parent: s.parentNode.id, selected: false, temporary: false, NodeClass: "folder", index: (tt.folders[s.id] ? tt.folders[s.id].index : 0), name: (tt.folders[s.id] ? tt.folders[s.id].name : labels.noname_group), expand: (tt.folders[s.id] ? tt.folders[s.id].expand : "")}); } } event.dataTransfer.setData("Group", JSON.stringify(Group)); event.dataTransfer.setData("Nodes", JSON.stringify(Nodes)); event.dataTransfer.setData("NodesTypes", JSON.stringify({DraggingGroup: tt.DraggingGroup, DraggingPin: tt.DraggingPin, DraggingTab: tt.DraggingTab, DraggingFolder: tt.DraggingFolder})); chrome.runtime.sendMessage({command: "drag_start", DragTreeDepth: tt.DragTreeDepth, DraggingGroup: tt.DraggingGroup, DraggingPin: tt.DraggingPin, DraggingTab: tt.DraggingTab, DraggingFolder: tt.DraggingFolder}); } gbn.ondragover = function(event) { if (this.classList.contains("inside") == false && tt.DraggingGroup == false && (tt.DraggingPin || tt.DraggingTab || tt.DraggingFolder)) { DOM_RemoveHighlight(); DOM_SetClasses(this, ["inside", "highlighted_drop_target"], ["before", "after"], []); } if (this.classList.contains("before") == false && event.layerY < this.clientHeight / 2 && tt.DraggingGroup) { DOM_RemoveHighlight(); DOM_SetClasses(this, ["before", "highlighted_drop_target"], ["inside", "after"], []); } if (this.classList.contains("after") == false && event.layerY > this.clientHeight / 2 && tt.DraggingGroup) { DOM_RemoveHighlight(); DOM_SetClasses(this, ["after", "highlighted_drop_target"], ["inside", "before"], []); } } gbn.ondragenter = function(event) { if (opt.open_tree_on_hover) { if (this.classList.contains("active") == false && (tt.DraggingGroup || tt.DraggingPin || tt.DraggingTab || tt.DraggingFolder)) { clearTimeout(tt.DragOverTimer); let This = this; tt.DragOverTimer = setTimeout(function() {Groups_SetActiveGroup(This.id.substr(1), false, false);}, 1500); } } } DOM_RefreshGUI(); } } } function Groups_AddNewGroup(Name, FontColor) { let newId = Groups_GenerateNewGroupID(); tt.groups[newId] = {id: newId, index: 0, active_tab: 0, prev_active_tab: 0, name: (Name ? Name : labels.noname_group), font: (FontColor ? FontColor : "")}; if (opt.debug) Utils_log("f: AddNewGroup, groupId: " + newId + ", Name: " + Name + ", FontColor: " + FontColor); Groups_AppendGroupToList(newId, tt.groups[newId].name, tt.groups[newId].font, true); Groups_UpdateBgGroupsOrder(); return newId; } function Groups_SaveGroups() { chrome.runtime.sendMessage({command: "save_groups", groups: tt.groups, windowId: tt.CurrentWindowId}); } function Groups_AppendGroups(groups) { Groups_AppendGroupToList("tab_list", labels.ungrouped_group, "", true); for (var group in groups) { Groups_AppendGroupToList(groups[group].id, groups[group].name, groups[group].font, true); if (document.querySelectorAll(".group").length == Object.keys(groups).length) { Groups_RearrangeGroupsButtons(); setTimeout(function() {Groups_RearrangeGroupsLists();}, 50); } } } function Groups_RearrangeGroupsButtons(first_loop) { let query = document.querySelectorAll(".group_button"); for (let s of query) { let groupId = (s.id).substr(1); if (tt.groups[groupId]) { if (s.parentNode.childNodes[tt.groups[groupId].index] != undefined) { let Ind = Array.from(s.parentNode.children).indexOf(s); if (Ind > tt.groups[groupId].index) { DOM_InsterBeforeNode(s, s.parentNode.childNodes[tt.groups[groupId].index]); } else { DOM_InsterAfterNode(s, s.parentNode.childNodes[tt.groups[groupId].index]); } let newInd = Array.from(s.parentNode.children).indexOf(s); if (newInd != tt.groups[groupId].index && first_loop) Groups_RearrangeGroupsButtons(false); } } } } function Groups_RearrangeGroupsLists() { if (opt.debug) Utils_log("f: RearrangeGroupsLists"); let activegroup = document.getElementById(tt.active_group); let scroll = activegroup.scrollTop; let groups = document.getElementById("groups"); let query = document.querySelectorAll(".group_button"); for (let s of query) { let group = document.getElementById((s.id).substr(1)); if (group != null) groups.appendChild(group); } activegroup.scrollTop = scroll; } function Groups_UpdateBgGroupsOrder() { let query = document.querySelectorAll(".group_button"); for (let s of query) { if (tt.groups[(s.id).substr(1)]) tt.groups[(s.id).substr(1)].index = Array.from(s.parentNode.children).indexOf(s); } Groups_SaveGroups(); } function Groups_GenerateNewGroupID() { let newID = ""; while (newID == "") { newID = "g_" + GenerateRandomID(); if (document.getElementById(newID) != null) newID = ""; } return newID; } function Groups_GroupRemove(groupId, close_tabs) { // remove group, delete tabs if close_tabs is true if (close_tabs) { let tabIds = Array.prototype.map.call(document.querySelectorAll("#" + groupId + " .tab"), function(s) {return parseInt(s.id);}); Tabs_CloseTabs(tabIds); let query = document.querySelectorAll("#" + groupId + " .folder"); for (let s of query) { Folders_RemoveFolder(s.id); } } else { let TabList = document.getElementById("°tab_list"); let GroupList = document.getElementById("°" + groupId); if (TabList != null && GroupList != null) { while (GroupList.firstChild) { TabList.appendChild(GroupList.firstChild); } } DOM_RefreshExpandStates(); DOM_RefreshCounters(); } if (groupId != "tab_list") { delete tt.groups[groupId]; let active_tab_is_pin = document.querySelector(".pin.active_tab"); if (groupId == tt.active_group && active_tab_is_pin == null) { if (document.getElementById("_" + groupId).previousSibling) { Groups_SetActiveGroup((document.getElementById("_" + groupId).previousSibling.id).substr(1), true, true); } else { if (document.getElementById("_" + groupId).nextSibling) { Groups_SetActiveGroup((document.getElementById("_" + groupId).nextSibling.id).substr(1), true, true); } else { Groups_SetActiveGroup("tab_list", true, true); } } } let group = document.getElementById(groupId); if (group != null) group.parentNode.removeChild(group); let groupButton = document.getElementById("_" + groupId); if (groupButton != null) groupButton.parentNode.removeChild(groupButton); } Groups_SaveGroups(); tt.schedule_update_data++; } function Groups_KeepOnlyOneActiveTabInGroup() { let active_tabs = document.querySelectorAll("#" + tt.active_group + " .active_tab"); if (active_tabs.length > 1) { chrome.tabs.query({currentWindow: true, active: true}, function(activeTab) { Tabs_SetActiveTab(activeTab[0].id, false); }); } } function Groups_SetActiveGroup(groupId, switch_to_active_in_group, scroll_to_active) { if (opt.debug) Utils_log("f: SetActiveGroup, groupId: " + groupId + ", switch_to_active_in_group: " + switch_to_active_in_group + ", scroll_to_active: " + scroll_to_active); let group = document.getElementById(groupId); if (group != null) { tt.active_group = groupId; let query = document.querySelectorAll(".group_button"); for (let s of query) { s.classList.remove("active_group"); } document.getElementById("_" + groupId).classList.add("active_group"); query = document.querySelectorAll(".group"); for (let s of query) { s.style.display = "none"; } group.style.display = ""; DOM_RefreshGUI(); DOM_HideRenameDialogs() let activeTab = document.querySelector("#" + groupId + " .active_tab"); if (activeTab != null) { if (switch_to_active_in_group) chrome.tabs.update(parseInt(activeTab.id), {active: true}); if (scroll_to_active && tt.tabs[activeTab.id]) tt.tabs[activeTab.id].ScrollToTab(); Groups_KeepOnlyOneActiveTabInGroup(); } if (groupId == "tab_list") { let query = document.querySelectorAll("#button_remove_group, #button_edit_group"); for (let s of query) { s.classList.add("disabled"); } } else { let query = document.querySelectorAll("#button_remove_group, #button_edit_group"); for (let s of query) { s.classList.remove("disabled"); } } chrome.runtime.sendMessage({command: "set_active_group", active_group: groupId, windowId: tt.CurrentWindowId}); DOM_RefreshExpandStates(); DOM_RefreshCounters(); if (browserId == "F" && opt.hide_other_groups_tabs_firefox) { let HideTabIds = Array.prototype.map.call(document.querySelectorAll(".group:not([id='" + groupId + "']) .tab"), function(s) { return parseInt(s.id); }); let ShowTabIds = Array.prototype.map.call(document.querySelectorAll("#" + groupId + " .tab"), function(s) { return parseInt(s.id); }); browser.tabs.hide(HideTabIds); browser.tabs.show(ShowTabIds); } } } function Groups_SetActiveTabInGroup(groupId, tabId) { if (document.querySelector("#" + groupId + " [id='" + tabId + "']") != null && tt.groups[groupId] != undefined) { if (groupId != tt.active_group) Groups_SetActiveGroup(groupId, false, true); if (tt.groups[groupId]) { tt.groups[groupId].prev_active_tab = tt.groups[groupId].active_tab; tt.groups[groupId].active_tab = parseInt(tabId); } Groups_SaveGroups(); } } function Groups_ShowGroupEditWindow(groupId) { // Edit group popup DOM_HideRenameDialogs(); if (tt.groups[groupId]) { let name = document.getElementById("group_edit_name"); name.value = tt.groups[groupId].name; let groupEditDialog = document.getElementById("group_edit"); groupEditDialog.setAttribute("groupId", groupId); DOM_SetStyle(groupEditDialog, {display: "block", left: "", top: document.getElementById("toolbar").getBoundingClientRect().height + document.getElementById("pin_list").getBoundingClientRect().height + 8 + "px"}); let DefaultGroupButtonFontColor = window.getComputedStyle(document.getElementById("body"), null).getPropertyValue("--group_list_default_font_color"); let GroupEditFont = document.getElementById("group_edit_font"); GroupEditFont.style.backgroundColor = (tt.groups[groupId].font == "" ? DefaultGroupButtonFontColor : "#" + tt.groups[groupId].font); setTimeout(function() {document.getElementById("group_edit_name").select();}, 5); } } function Groups_GroupEditConfirm() { // when pressed OK in group popup let groupId = document.getElementById("group_edit").getAttribute("groupId"); if (tt.groups[groupId]) { let GroupEditName = document.getElementById("group_edit_name"); tt.groups[groupId].name = GroupEditName.value; let GroupEditFont = document.getElementById("group_edit_font"); let DefaultGroupButtonFontColor = window.getComputedStyle(document.getElementById("body"), null).getPropertyValue("--group_list_default_font_color"); let ThisGroupButtonFontColor = Utils_RGBtoHex(GroupEditFont.style.backgroundColor); if ("#" + ThisGroupButtonFontColor != DefaultGroupButtonFontColor) { tt.groups[groupId].font = ThisGroupButtonFontColor; document.getElementById("_gte" + groupId).style.color = "#" + ThisGroupButtonFontColor; } DOM_HideRenameDialogs(); DOM_RefreshGUI(); Groups_SaveGroups(); } } function Groups_RestoreStateOfGroupsToolbar() { chrome.runtime.sendMessage({command: "get_group_bar", windowId: tt.CurrentWindowId}, function(response) { let toolbarGroups = document.getElementById("toolbar_groups"); if (response == true) { DOM_SetStyle(toolbarGroups, {display: "inline-block", width: "19px", borderRight: "1px solid var(--group_list_borders)"}); toolbarGroups.classList.remove("hidden"); } else { DOM_SetStyle(toolbarGroups, {display: "none", width: "0px", borderRight: "none"}); toolbarGroups.classList.add("hidden"); } }); } function Groups_GroupsToolbarToggle() { let toolbarGroups = document.getElementById("toolbar_groups"); toolbarGroups.classList.toggle("hidden"); if (toolbarGroups.classList.contains("hidden")) { DOM_SetStyle(toolbarGroups, {display: "none", width: "0px", borderRight: "none"}); chrome.runtime.sendMessage({command: "set_group_bar", group_bar: false, windowId: tt.CurrentWindowId}); } else { DOM_SetStyle(toolbarGroups, {display: "inline-block", width: "19px", borderRight: "1px solid var(--group_list_borders)"}); chrome.runtime.sendMessage({command: "set_group_bar", group_bar: true, windowId: tt.CurrentWindowId}); } DOM_RefreshGUI(); } function Groups_ActionClickGroup(Node, bgOption) { if (bgOption == "new_tab") { if (Node.id == "pin_list") Tabs_OpenNewTab(true, undefined, undefined); if (Node.classList.contains("tab")) Tabs_OpenNewTab(false, Node); if (Node.classList.contains("folder")) Tabs_OpenNewTab(false, undefined, Node.childNodes[1]); if (Node.classList.contains("group")) Tabs_OpenNewTab(false, undefined, Node.childNodes[0]); } if (bgOption == "activate_previous_active") { chrome.tabs.update(parseInt(tt.groups[tt.active_group].prev_active_tab), {active: true}); } if (bgOption == "undo_close_tab") { chrome.sessions.getRecentlyClosed(null, function(sessions) { if (sessions.length > 0) chrome.sessions.restore(null, function(restored) {}); }); } } function Groups_SetActiveTabInEachGroup() { // SET ACTIVE TAB FOR EACH GROUP chrome.tabs.query({currentWindow: true, active: true}, function(tabs) { if (tabs.length) { Tabs_SetActiveTab(tabs[0].id); chrome.runtime.sendMessage({command: "get_active_group", windowId: tt.CurrentWindowId}, function(response) { if (response) { Groups_SetActiveGroup(response, false, true); for (var group in tt.groups) { let ActiveInGroup = document.querySelector("#" + group + " [id='" + tt.groups[group].active_tab + "']"); if (ActiveInGroup != null) ActiveInGroup.classList.add("active_tab"); } if (tabs[0].pinned) { let ActiveTabinActiveGroup = document.querySelectorAll("#" + tt.active_group + " .active_tab"); if (ActiveTabinActiveGroup != null) { for (let s of ActiveTabinActiveGroup) { s.classList.remove("active_tab"); } } } } else { Groups_SetActiveGroup("tab_list", false, true); } }); } }); }