From 93827da5a4e0de8e2b622a98beee2f7599dde318 Mon Sep 17 00:00:00 2001 From: Pramjeet Ahlawat Date: Sat, 25 Mar 2017 23:58:39 +0530 Subject: [PATCH] delete and backspace can remove focused tab --- app.css | 5 +- app.js | 335 ++++++++++++++++++++++++++++++-------------------------- 2 files changed, 184 insertions(+), 156 deletions(-) diff --git a/app.css b/app.css index 54fc538..2a56175 100644 --- a/app.css +++ b/app.css @@ -237,6 +237,7 @@ html, body { overflow: hidden; padding: 6px 7px; background: #fafafa; + margin: 1px; } .tab.visible { @@ -251,8 +252,8 @@ html, body { } .tab.active { - border-color: #2e7fb9; - /* background: #eee; */ + /*border-color: #2e7fb9;*/ + background: rgba(46, 127, 185, 0.04); /* box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); */ color: #2e7fb9; } diff --git a/app.js b/app.js index f095505..5bb572b 100644 --- a/app.js +++ b/app.js @@ -3,45 +3,41 @@ */ document.addEventListener('DOMContentLoaded', function () { - var activeWindowId = window.initialWindowId; - var peekATabWindowId = null; - var closeOnFocusChange = true; + var activeWindowId = window.initialWindowId + var peekATabWindowId = null + var closeOnFocusChange = true - var activeTabElement = null; + var activeTabElement = null - var mouseBehavior = 'click'; //click, hover or single-click + var mouseBehavior = 'click' //click, hover or single-click - var tabsListEl = document.getElementById("tabs-list"); - var searchInput = document.getElementById("search-input"); + var tabsListEl = document.getElementById("tabs-list") + var searchInput = document.getElementById("search-input") - //keep search input focused - searchInput.focus(); - searchInput.addEventListener("blur", function () { - searchInput.focus(); - }); + // searchInput.focus() searchInput.addEventListener("input", function () { - populateTabs(); - }); + populateTabs() + }) //save width changes window.addEventListener('resize', function (event) { - var widthToStore = document.documentElement.clientWidth; + var widthToStore = document.documentElement.clientWidth if (widthToStore <= 300) { - widthToStore = 300; + widthToStore = 300 } chrome.storage.sync.set({ windowWidth: widthToStore - }); + }) - }); + }) function highlight(text, textToHighlight) { if (textToHighlight.length > 0) { return text.toLowerCase().replace(textToHighlight, "" + textToHighlight + "") } else { - return text; + return text } } @@ -49,293 +45,324 @@ document.addEventListener('DOMContentLoaded', function () { * removes the dom element and the corresponding tab from the browser * @param tabElement - DOM element from the list containing data-id attributes */ - function closeTab(tabElement) { - var tabId = tabElement.dataset.id; - chrome.tabs.remove(+tabId); - tabElement.remove(); + function removeTabElement(tabElement) { + var tabId = tabElement.dataset.id + + var tabEls = document.getElementsByClassName('tab') + if (tabElement == activeTabElement) { + for (var i = 0; i < tabEls.length; i++) { + if (tabId == tabEls[i].id) { + if (i == tabEls.length - 1) { + makePreviousTabActive() + } + else if (tabEls.length > 1) { + makeNextTabActive() + } + break + } + } + } + else{ + activeTabElement.focus() + } + + chrome.tabs.remove(+tabId) + tabElement.remove() + + //if only one tab was present before closing this tab, close peek-a-tab window too + if (tabEls.length == 1) { + window.close() + } } //get peek-a-tab window id and listener for focus change chrome.windows.getCurrent({}, function (peekATabWindow) { - peekATabWindowId = peekATabWindow.id; + peekATabWindowId = peekATabWindow.id chrome.windows.onFocusChanged.addListener(function (newWindowId) { if (closeOnFocusChange && newWindowId != peekATabWindow.id && newWindowId != chrome.windows.WINDOW_ID_NONE) { - window.close(); + window.close() } - }); - }); - + }) + }) + /** + * make the tab active in browser, and add class 'active' to the corresponding element in the list and focuses on it + * @param {*} tab + */ function changeActiveTab(tab) { + //if tab is in different window than change focus to that that window first if (tab.windowId != activeWindowId) { - closeOnFocusChange = false; - chrome.windows.update(tab.windowId, {focused: true}, function () { - chrome.windows.update(peekATabWindowId, {focused: true}, function () { - closeOnFocusChange = true; - }); - }); + closeOnFocusChange = false + chrome.windows.update(tab.windowId, { focused: true }, function () { + chrome.windows.update(peekATabWindowId, { focused: true }, function () { + closeOnFocusChange = true + }) + }) } - chrome.tabs.update(tab.id, {active: true}); - activeWindowId = tab.windowId; + chrome.tabs.update(tab.id, { active: true }) + activeWindowId = tab.windowId if (activeTabElement) { - activeTabElement.classList.remove("active"); + activeTabElement.classList.remove("active") } - activeTabElement = document.getElementById(tab.id); - activeTabElement.classList.add("active"); - scrollToShowActiveTab(); + activeTabElement = document.getElementById(tab.id) + + activeTabElement.classList.add("active") + if (document.activeElement != searchInput) { + activeTabElement.focus() + } } function changeActiveTabAndCloseWindow(tab) { - changeActiveTab(tab); - window.close(); + changeActiveTab(tab) + window.close() } function hoveredOnTab(tab) { if (mouseBehavior == "hover") { - changeActiveTab(tab); + changeActiveTab(tab) } } function clickedOnTab(tab) { if (mouseBehavior == "click") { - changeActiveTab(tab); + changeActiveTab(tab) } else if (mouseBehavior == "single-click") { - changeActiveTabAndCloseWindow(tab); + changeActiveTabAndCloseWindow(tab) } } function doubleClickedOnTab(tab) { - changeActiveTabAndCloseWindow(tab); + changeActiveTabAndCloseWindow(tab) } + function getActiveTabIndex() { - var tabIndex; + var tabIndex - var tabEls = document.getElementsByClassName('tab'); + var tabEls = document.getElementsByClassName('tab') for (tabIndex = 0; tabIndex < tabEls.length; tabIndex++) { if (activeTabElement.id == tabEls[tabIndex].id) - return tabIndex; + return tabIndex } } function makeTabIndexActive(tabIndex) { - var tabElement = document.getElementsByClassName('tab')[tabIndex]; - var tabId = tabElement.id; - + var tabElement = document.getElementsByClassName('tab')[tabIndex] + var tabId = tabElement.id chrome.tabs.get(+tabId, function (tab) { - changeActiveTab(tab); - }); + changeActiveTab(tab) + }) } function makeNextTabActive() { - - var tabIndex = getActiveTabIndex(); - var tabEls = document.getElementsByClassName('tab'); + var tabIndex = getActiveTabIndex() + var tabEls = document.getElementsByClassName('tab') if (tabIndex < (tabEls.length - 1)) { - makeTabIndexActive(tabIndex + 1); - scrollToShowActiveTab(); - return; + makeTabIndexActive(tabIndex + 1) + return } - - makeTabIndexActive(0); + makeTabIndexActive(0) } function makePreviousTabActive() { - var tabIndex = getActiveTabIndex(); - var tabEls = document.getElementsByClassName('tab'); - + var tabIndex = getActiveTabIndex() + var tabEls = document.getElementsByClassName('tab') if (tabIndex > 0) { - makeTabIndexActive(tabIndex - 1); - scrollToShowActiveTab(); - return; + makeTabIndexActive(tabIndex - 1) + return } - - makeTabIndexActive((tabEls.length - 1)); - } - - function scrollToShowActiveTab() { - - var tabIndex = getActiveTabIndex(); - - chrome.windows.getAll({populate: true, windowTypes: ['normal']}, function (windows) { - if ((tabsListEl.offsetHeight + tabsListEl.scrollTop) < (36 * (tabIndex + (windows.length + 1)))) { - tabsListEl.scrollTop = (36 * (tabIndex + (windows.length + 1))) - tabsListEl.offsetHeight; - } else if (tabsListEl.scrollTop > (36 * tabIndex)) { - tabsListEl.scrollTop = (36 * tabIndex); - } - }); + makeTabIndexActive((tabEls.length - 1)) } /** * get all tabs from all windows and populates the list */ function populateTabs() { - chrome.windows.getAll({populate: true, windowTypes: ['normal']}, function (windows) { + chrome.windows.getAll({ populate: true, windowTypes: ['normal'] }, function (windows) { //if no window present, close peek-a-tab if (windows.length == 0) { - window.close(); + window.close() } - tabsListEl.innerHTML = ""; + tabsListEl.innerHTML = "" for (var i = 0; i < windows.length; i++) { - var aWindow = windows[i]; - var windowTitle = document.createElement('li'); - windowTitle.classList.add("window-text"); - windowTitle.textContent = "Window " + (i + 1); + var aWindow = windows[i] + var windowTitle = document.createElement('li') + windowTitle.classList.add("window-text") + windowTitle.textContent = "Window " + (i + 1) - tabsListEl.appendChild(windowTitle); + tabsListEl.appendChild(windowTitle) for (var j = 0; j < aWindow.tabs.length; j++) { - var tab = aWindow.tabs[j]; + var tab = aWindow.tabs[j] if (searchInput.value.trim() != "" && tab.title.toLowerCase().indexOf(searchInput.value.trim().toLowerCase()) == -1 && tab.url.toLowerCase().indexOf(searchInput.value.trim().toLowerCase()) == -1) { - continue; + continue } - var tabEl = document.createElement("li"); - tabEl.classList.add("tab"); - tabEl.dataset.id = tab.id; - tabEl.id = tab.id; + var tabEl = document.createElement("li") + tabEl.classList.add("tab") + tabEl.dataset.id = tab.id + tabEl.tabIndex = 0 + tabEl.id = tab.id - var tabImgEl = document.createElement("img"); - tabImgEl.classList.add("icon"); - tabImgEl.src = tab.favIconUrl || ""; + var tabImgEl = document.createElement("img") + tabImgEl.classList.add("icon") + tabImgEl.src = tab.favIconUrl || "" - var tabTitleEl = document.createElement("p"); - tabTitleEl.classList.add("title"); - tabTitleEl.innerHTML = highlight(tab.title, searchInput.value); + var tabTitleEl = document.createElement("p") + tabTitleEl.classList.add("title") + tabTitleEl.innerHTML = highlight(tab.title, searchInput.value) - var tabCrossEl = document.createElement("img"); - tabCrossEl.title = "close"; - tabCrossEl.classList.add("close-icon"); - tabCrossEl.src = "images/close_icon.png"; + var tabCrossEl = document.createElement("img") + tabCrossEl.title = "close" + tabCrossEl.classList.add("close-icon") + tabCrossEl.src = "images/close_icon.png" tabCrossEl.addEventListener("click", (function (tabElement) { return function (e) { - e.stopPropagation(); - closeTab(tabElement); + e.stopPropagation() + removeTabElement(tabElement) } - })(tabEl)); + })(tabEl)) tabEl.addEventListener("mouseover", (function (tab, tabElement) { return function () { - hoveredOnTab(tab); + hoveredOnTab(tab) } - })(tab)); + })(tab)) tabEl.addEventListener("click", (function (tab, tabElement) { return function () { - clickedOnTab(tab); + clickedOnTab(tab) } - })(tab)); + })(tab)) tabEl.addEventListener("dblclick", (function (tab, tabElement) { return function () { - doubleClickedOnTab(tab); + doubleClickedOnTab(tab) } - })(tab)); + })(tab)) - tabEl.appendChild(tabImgEl); - tabEl.appendChild(tabTitleEl); - tabEl.appendChild(tabCrossEl); - tabsListEl.appendChild(tabEl); + tabEl.appendChild(tabImgEl) + tabEl.appendChild(tabTitleEl) + tabEl.appendChild(tabCrossEl) + tabsListEl.appendChild(tabEl) if (aWindow.id == activeWindowId && tab.active) { - changeActiveTab(tab); + changeActiveTab(tab) } } } }) } - - populateTabs(); - //key bindings document.onkeydown = function (e) { switch (e.keyCode) { - case 38: - makePreviousTabActive(); - break; - case 40: - makeNextTabActive(); - break; + case 38: //up arrow + e.preventDefault() + searchInput.blur() + makePreviousTabActive() + break + case 40: //down arrow + e.preventDefault() + searchInput.blur() + makeNextTabActive() + break case 13: //enter - window.close(); - break; + window.close() + break case 27: //esc - window.close(); - break; + window.close() + break + case 8: //backspace + case 46: //delete + if (document.activeElement != searchInput) {//search input is not focused + removeTabElement(activeTabElement) + } + break + default: + //if search input is not focused and space or any of alphanumeric keys is pressed + if (document.activeElement != searchInput) { + searchInput.focus() + // searchInput.value = searchInput.value + String.fromCharCode(e.keyCode) + } + populateTabs() } - }; + } - var mouseBehaviorImage = document.getElementById("mouse-behavior-image"); + var mouseBehaviorImage = document.getElementById("mouse-behavior-image") function changeMouseBehaviorImage() { - mouseBehaviorImage.src = "./images/cursor-pointer-" + mouseBehavior + ".png"; + mouseBehaviorImage.src = "./images/cursor-pointer-" + mouseBehavior + ".png" } function saveMouseBehavior() { chrome.storage.sync.set({ mouseBehavior: mouseBehavior - }); + }) } //show hint to change mouse behavior chrome.storage.sync.get(null, function (items) { if (typeof items.mouseBehavior == "undefined") { - saveMouseBehavior(); + saveMouseBehavior() } else { - mouseBehavior = items.mouseBehavior; + mouseBehavior = items.mouseBehavior } - changeMouseBehaviorImage(); - }); + changeMouseBehaviorImage() + }) - var mouseBehaviorOptionsContainer = document.getElementById("mouse-behavior-options-container"); + var mouseBehaviorOptionsContainer = document.getElementById("mouse-behavior-options-container") - var mouseBehaviorOptions = document.getElementsByClassName("mouse-behavior-option"); + var mouseBehaviorOptions = document.getElementsByClassName("mouse-behavior-option") for (var i = 0; i < mouseBehaviorOptions.length; i++) { mouseBehaviorOptions[i].addEventListener('click', (function (mouseBehaviorOption) { return function () { - mouseBehavior = mouseBehaviorOption.dataset.mouseBehavior; - changeMouseBehaviorImage(); - saveMouseBehavior(); + mouseBehavior = mouseBehaviorOption.dataset.mouseBehavior + changeMouseBehaviorImage() + saveMouseBehavior() } - })(mouseBehaviorOptions[i])); + })(mouseBehaviorOptions[i])) } mouseBehaviorImage.addEventListener("click", function (e) { - e.stopPropagation(); + e.stopPropagation() if (mouseBehaviorOptionsContainer.style.display != "block") { - mouseBehaviorOptionsContainer.style.display = "block"; + mouseBehaviorOptionsContainer.style.display = "block" } else { - mouseBehaviorOptionsContainer.style.display = "none"; + mouseBehaviorOptionsContainer.style.display = "none" } - }); + }) document.addEventListener("click", function () { if (mouseBehaviorOptionsContainer.style.display != "none") { - mouseBehaviorOptionsContainer.style.display = "none"; + mouseBehaviorOptionsContainer.style.display = "none" } }) -}); \ No newline at end of file + + + + populateTabs() +}) \ No newline at end of file