diff --git a/TabsAside.html b/TabsAside.html new file mode 100644 index 0000000..59f2927 --- /dev/null +++ b/TabsAside.html @@ -0,0 +1,87 @@ + + + + + Tabs aside + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/collections.html b/collections.html index df52f3d..ede2f66 100644 --- a/collections.html +++ b/collections.html @@ -1,56 +1,57 @@ -
-
-
-

Tabs aside

- - - -
-  Set current tabs aside -
-
- -
- - -
-
+
+
\ No newline at end of file diff --git a/css/style.css b/css/style.css index e2ff917..e2a1831 100644 --- a/css/style.css +++ b/css/style.css @@ -1,178 +1,222 @@ -.aside.pane +.tabsAside.background { - font-family: 'Segoe UI', 'Segoe MDL2 Assets'; - user-select: none; - position: fixed; - z-index: 999; - - right: 0px; - top: 0px; - width: 40%; - min-width: 500px; - min-height: 100%; - - background-color: #f7f7f7; - border: 1px solid rgba(100, 100, 100, .5); - box-sizing: border-box; - box-shadow: 6px 0px 12px black; - - transition: .2s; + z-index: 9999 !important; + background-color: rgba(255, 255, 255, .5) !important; + position: fixed !important; + top: 0 !important; + bottom: 0 !important; + right: 0 !important; + left: 0 !important; + transition: .2s !important; + opacity: 0; } - .aside.pane > .header +.tabsAside.pane +{ + font-family: 'Segoe UI', 'Segoe MDL2 Assets' !important; + user-select: none !important; + position: fixed !important; + + right: 0px !important; + top: 0px !important; + bottom: 0px !important; + overflow: auto !important; + + width: 40%; + min-width: 500px !important; + + background-color: #f7f7f7 !important; + border: 1px solid rgba(100, 100, 100, .5) !important; + border-width: 0px 0px 0px 1px !important; + box-sizing: border-box !important; + box-shadow: 6px 0px 12px black !important; + + font-size: small !important; + + transform: translateX(110%); /* Pane is hidden */ + transition: .2s !important; +} + + .tabsAside.pane[opened] { - margin: 20px 40px; + transform: translateX(0px) !important; } - .aside.pane > .header > .title + + /* Pane header*/ + .tabsAside.pane > header + { + margin: 20px 40px !important; + } + .tabsAside.pane > header > div { - display: grid; - grid-template-columns: 1fr auto; + display: grid !important; + grid-template-columns: 1fr auto !important; } - .aside.pane > .header > .title > h1 + .tabsAside.pane > header > div > h1 { - margin: 10px 0px; - font-weight: normal; - font-size: 21pt; + margin: 10px 0px !important; + font-weight: normal !important; + font-size: 21pt !important; } - .aside.pane > .header > .title > button + .tabsAside.pane > header > div > button { - margin: auto; + margin: auto !important; } - .aside.pane > .header > .title > nav + .tabsAside.pane > header > div > nav { - top: 70px; - right: 40px; + top: 70px !important; + right: 40px !important; } - .aside.pane > .header > .title > nav > div + .tabsAside.pane > header > div > nav > div { - box-shadow: 0px 4px 5px -2px rgba(100, 100, 100, .5); + box-shadow: 0px 4px 5px -2px rgba(100, 100, 100, .5) !important; } - .aside.pane > .header > .title > nav > p + .tabsAside.pane > header > div > nav > p { - margin: 10px; + margin: 10px !important; } - .aside.pane > .header > hr + .tabsAside.pane > header > hr { - border: 1px solid #8a8a8a; + border: 1px solid #8a8a8a !important; } - .aside.pane > #content > h2 + .tabsAside.pane > section > h2 { - margin: 0px 40px; - font-weight: normal; + margin: 0px 40px !important; + font-weight: normal !important; } - .aside.pane > #content > .set > .setHeader + /* Collection header */ + .tabsAside.pane > section > div { - margin: 0px 20px; - display: grid; - grid-template-columns: 1fr auto; + transition: .2s !important; } - .aside.pane > #content > .set > .setHeader small + .tabsAside.pane > section > div > div:first-child + { + margin: 0px 20px !important; + display: grid !important; + grid-template-columns: auto 1fr auto auto auto !important; + grid-column-gap: 10px !important; + align-items: center !important; + } + + .tabsAside.pane > section > div > div:first-child > small { - color: gray; + color: gray !important; + } + + .tabsAside.pane > section > div > div:first-child > span + { + font-weight: 600 !important; + } + + .tabsAside.pane > section > div > div:first-child > a + { + font-size: 11pt !important; } - .aside.pane > #content > .set > .setHeader span + .tabsAside.pane > section > div > div:first-child > div { - font-weight: 600; + display: none !important; /* TODO: Implement this menu */ } - .aside.pane > #content > .set > .setHeader a - { - font-size: 11pt; - font-weight: 500; - } - .aside.pane > #content > .set > .setHeader nav - { - width: 200px; - margin-top: 10px; - right: 50px; - } - - .aside.pane > #content > .set > .setHeader > div:first-child - { - margin: auto 0px; - } - - .aside.pane > #content > .set > .collection - { - padding: 10px 0px; - padding-left: 40px; - white-space: nowrap; - overflow: auto; - } - - .aside.pane > #content > .set > .collection > .item + .tabsAside.pane > section > div > div:first-child > div > nav { - width: 175px; - height: 148px; - margin: 5px; - - background-color: #c2c2c2; - background-image: url("../images/tab_thumbnail.png"); - - display: inline-grid; - grid-template-rows: 1fr auto; - - box-shadow: 0px 0px 5px rgba(100, 100, 100, .5); - transition: .25s; - cursor: pointer; + width: 200px !important; + margin-top: 10px !important; + right: 50px !important; } - .aside.pane > #content > .set > .collection > .item:hover + + /* Tabs collection */ + .tabsAside.pane > section > div > div:last-child + { + margin: 0px 0px 0px 20px !important; + padding: 10px 40px 10px 20px !important; + white-space: nowrap !important; + overflow: auto !important; + } + + .tabsAside.pane > section > div > div:last-child:hover::-webkit-scrollbar-thumb + { + visibility: visible !important; + } + + .tabsAside.pane > section > div > div:last-child > div + { + width: 175px !important; + height: 148px !important; + margin: 5px !important; + + background-color: #c2c2c2 !important; + background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_thumbnail.png"); + + display: inline-grid !important; + grid-template-rows: 1fr auto !important; + + box-shadow: 0px 0px 5px rgba(100, 100, 100, .5) !important; + transition: .25s !important; + cursor: pointer !important; + } + .tabsAside.pane > section > div > div:last-child > div:hover { - filter: brightness(120%); - box-shadow: 0px 0px 15px rgba(100, 100, 100, .5); + filter: brightness(120%) !important; + box-shadow: 0px 0px 15px rgba(100, 100, 100, .5) !important; } - .aside.pane > #content > .set > .collection > .item > .caption + .tabsAside.pane > section > div > div:last-child > div > div { - background-color: rgba(233, 233, 233, .75); - grid-row: 2; - display: grid; - grid-template-columns: auto 1fr auto; + background-color: rgba(233, 233, 233, .75) !important; + grid-row: 2 !important; + display: grid !important; + grid-template-columns: auto 1fr auto !important; } - .aside.pane > #content > .set > .collection > .item > .caption > button + .tabsAside.pane > section > div > div:last-child > div > div > button { - margin: auto; - margin-right: 5px; - visibility: hidden; + margin: auto !important; + margin-right: 5px !important; + display: none !important; } - .aside.pane > #content > .set > .collection > .item:hover > .caption > button + .tabsAside.pane > section > div > div:last-child > div:hover > div > button { - visibility: visible; + display: initial !important; } - .aside.pane > #content > .set > .collection > .item > .caption > div + .tabsAside.pane > section > div > div:last-child > div > div > div { - width: 20px; - height: 20px; - margin: 10px; + width: 20px !important; + height: 20px !important; + margin: 10px !important; - background-image: url("../images/tab_icon.png"); + background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_icon.png"); + background-size: 20px !important; } - .aside.pane > #content > .set > .collection > .item > .caption > span + .tabsAside.pane > section > div > div:last-child > div > div > span { - margin: auto 0px; + overflow: hidden !important; + margin: auto 0px !important; + margin-right: 10px !important; + } + .tabsAside.pane > section > div > div:last-child > div:hover > div > span + { + margin-right: 5px !important; } @media only screen and (max-width: 500px) { - .aside.pane + .tabsAside.pane { - right: initial; - width: 100%; - left: 0px; - min-width: initial; + width: initial !important; + left: 0px !important; + min-width: initial !important; } } \ No newline at end of file diff --git a/css/style.dark.css b/css/style.dark.css index 2350d46..11f541d 100644 --- a/css/style.dark.css +++ b/css/style.dark.css @@ -1,54 +1,59 @@ -.aside.pane +.tabsAside[darkmode].background +{ + background-color: rgba(0, 0, 0, .5) !important; +} + +.tabsAside[darkmode] .pane { - background-color: #333333; - color: white; + background-color: #333333 !important; + color: white !important; } -.aside button -{ - color: white; -} -.aside button:hover -{ - background-color: gray; -} -.aside button:active -{ - background-color: dimgray; -} - -.aside.pane > #content > .set > .setHeader small -{ - color: lightgray; -} - -.aside ::-webkit-scrollbar-thumb -{ - background: gray; - border-radius: 3px; -} - ::-webkit-scrollbar-thumb:hover + .tabsAside[darkmode] .pane button { - background: dimgray; + color: white !important; + } + .tabsAside[darkmode] .pane button:hover + { + background-color: gray !important; + } + .tabsAside[darkmode] .pane button:active + { + background-color: dimgray !important; } -.aside.pane > #content > .set > .collection > .item -{ - background-color: #0c0c0c; - background-image: url("../images/tab_thumbnail_dark.png"); -} + .tabsAside[darkmode] .pane > section > div > div:first-child > div:first-child > small + { + color: lightgray !important; + } -.aside.pane > #content > .set > .collection > .item > .caption -{ - background-color: rgba(50, 50, 50, .75); -} + .tabsAside[darkmode] .pane ::-webkit-scrollbar-thumb + { + background: gray !important; + border-radius: 3px !important; + } + .tabsAside[darkmode] .pane ::-webkit-scrollbar-thumb:hover + { + background: dimgray !important; + } -.aside nav -{ - background-color: #3f3f3f; -} + .tabsAside[darkmode] .pane > section > div > div:last-child > div + { + background-color: #0c0c0c !important; + background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_thumbnail_dark.png"); + } -.aside.pane > #content > .set > .collection > .item > .caption > div -{ - background-image: url("../images/tab_icon_dark.png"); -} \ No newline at end of file + .tabsAside[darkmode] .pane > section > div > div:last-child > div > div + { + background-color: rgba(50, 50, 50, .75) !important; + } + + .tabsAside[darkmode] .pane > section > div > div:last-child > div > div > div + { + background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_icon_dark.png"); + } + + .tabsAside[darkmode] .pane nav + { + background-color: #3f3f3f !important; + } \ No newline at end of file diff --git a/css/style.generic.css b/css/style.generic.css index 4057a94..0de65e8 100644 --- a/css/style.generic.css +++ b/css/style.generic.css @@ -1,123 +1,106 @@ -.aside ::-webkit-scrollbar +/* Custom scrollbar */ +.tabsAside ::-webkit-scrollbar { - height: 6px; + height: 6px !important; } -.aside ::-webkit-scrollbar-thumb +.tabsAside ::-webkit-scrollbar-thumb { - background: darkgray; - border-radius: 3px; + visibility: hidden !important; + background: darkgray !important; + border-radius: 3px !important; } - ::-webkit-scrollbar-thumb:hover + .tabsAside ::-webkit-scrollbar-thumb:hover { - background: gray; + background: gray !important; } -.aside a +.tabsAside::-webkit-scrollbar { - font-family: 'Segoe UI', 'Segoe MDL2 Assets'; - color: #0078d7; -} - .aside a:hover - { - text-decoration: underline; - cursor: pointer; - } - -.aside .slider -{ - position: relative; - display: inline-block; - - border-radius: 13px; - width: 50px; - height: 26px; - - background-color: #cccccc; - transition: .4s; + width: 6px !important; } - .aside .slider:before - { - position: absolute; - content: ""; - - height: 16px; - width: 16px; - left: 5px; - top: 5px; - border-radius: 50%; - - margin: auto; - - background-color: white; - transition: .3s; - } - - .aside input:checked + .slider, - .aside input:focus + .slider - { - background-color: #0078d7; - } - - .aside input:checked + .slider:before - { - transform: translateX(24px); - background-color: #3f3f3f; - } - -.aside nav +.tabsAside::-webkit-scrollbar-thumb { - font-family: 'Segoe UI'; - user-select: none; + background: gray !important; + border-radius: 3px !important; +} + .tabsAside::-webkit-scrollbar-thumb:hover + { + background: darkgray !important; + } - position: absolute; - width: 250px; +/* Links style */ +.tabsAside a +{ + font-family: 'Segoe UI', 'Segoe MDL2 Assets' !important; + color: #0078d7 !important; +} + .tabsAside a:hover + { + text-decoration: underline !important; + cursor: pointer !important; + } - box-shadow: 0px 0px 10px black; - background-color: white; - border-radius: 5px; + .tabsAside a:visited + { + color: #0078d7 !important; + } - z-index: 10; +/* Buttons style */ +.tabsAside button +{ + font-family: 'Segoe MDL2 Assets' !important; + width: 32px !important; + height: 32px !important; + background-color: transparent !important; + border: none !important; + cursor: pointer !important; +} + .tabsAside button:hover + { + background-color: #c6c6c6 !important; + } + .tabsAside button:active + { + background-color: gray !important; + } - visibility: hidden; +/* Context menus style */ +.tabsAside nav +{ + font-family: 'Segoe UI' !important; + user-select: none !important; + + position: absolute !important; + width: 250px !important; + + box-shadow: 0px 0px 10px black !important; + background-color: white !important; + border-radius: 5px !important; + + z-index: 10 !important; + + visibility: hidden !important; } - .aside nav button + .tabsAside nav button { - font-family: 'Segoe UI'; - cursor: pointer; - background-color: transparent; - border: none; + font-family: 'Segoe UI' !important; + cursor: pointer !important; + background-color: transparent !important; + border: none !important; - font-size: medium; - text-align: start; + font-size: medium !important; + text-align: start !important; - padding: 10px; - width: 100%; - height: initial; + padding: 10px !important; + width: 100% !important; + height: initial !important; } - .aside button + nav:active, - .aside button:focus + nav + .tabsAside button + nav:active, + .tabsAside button:focus + nav { - visibility: visible; - } - -.aside button -{ - font-family: 'Segoe MDL2 Assets'; - width: 32px; - height: 32px; - background-color: transparent; - border: none; - cursor: pointer; -} - .aside button:hover - { - background-color: #c6c6c6; - } - .aside button:active - { - background-color: gray; + visibility: visible !important; } \ No newline at end of file diff --git a/js/aside-script.js b/js/aside-script.js index 2c02062..370b616 100644 --- a/js/aside-script.js +++ b/js/aside-script.js @@ -1,40 +1,327 @@ -chrome.runtime.onMessage.addListener(function(sender, request, sendResponse) +if (document.location.protocol == "chrome-extension:") + InitializeStandalone(); +else { - var pane = document.querySelector("#aside-pane"); - if (pane.style.transform == "translateX(110%)") + setTimeout(function () { - pane.style.transform = "translateX(0%)"; - } - else - { - pane.style.transform = "translateX(110%)"; - } + var pane = document.querySelector(".tabsAside.pane"); - UpdateTheme(); - - sendResponse(); -}); + if (pane == null) + { + var xhr = new XMLHttpRequest(); + xhr.open('GET', chrome.extension.getURL("collections.html"), true); + xhr.onreadystatechange = function () + { + if (this.status !== 200 || document.querySelector("#aside-pane") != null) + return; -var xhr = new XMLHttpRequest(); -xhr.open('GET', chrome.extension.getURL("collections.html"), true); -xhr.onreadystatechange = function () + if (document.querySelector(".tabsAside.pane") == null) + { + document.body.innerHTML += this.responseText; + chrome.runtime.sendMessage({ command: "loadData" }, function (collections) + { + if (document.querySelector(".tabsAside.pane section div") == null) + collections.forEach(i => + { + AddCollection(i); + }); + }); + } + + setTimeout(function () + { + pane = document.querySelector(".tabsAside.pane"); + + if (window.matchMedia("(prefers-color-scheme: dark)").matches) + pane.parentElement.setAttribute("darkmode", ""); + + document.querySelector(".tabsAside .saveTabs").onclick = SetTabsAside; + + + document.querySelectorAll(".tabsAside.pane > header nav button").forEach(i => + { + i.onclick = function () { window.open(i.value, '_blank'); }; + }); + + document.querySelector(".tabsAside.background").addEventListener("click", function (event) + { + if (event.target == pane.parentElement) + { + pane.removeAttribute("opened"); + pane.parentElement.style.opacity = 0; + document.body.style.overflow = ""; + setTimeout(function () + { + pane.parentElement.remove(); + }, 300); + } + }); + + pane.setAttribute("opened", ""); + pane.parentElement.style.opacity = 1; + document.body.style.overflow = "hidden"; + }, 50); + }; + xhr.send(); + } + else + { + if (pane.hasAttribute("opened")) + { + pane.removeAttribute("opened"); + pane.parentElement.style.opacity = 0; + document.body.style.overflow = ""; + setTimeout(function () + { + if (!pane.hasAttribute("opened")) + pane.parentElement.remove(); + }, 300); + } + else + { + pane.setAttribute("opened", ""); + pane.parentElement.style.opacity = 1; + } + } + }, 50); +} + +function InitializeStandalone() { - if (this.status !== 200 || document.querySelector("#aside-pane") != null) - return; + pane = document.querySelector(".tabsAside.pane"); - document.body.innerHTML += this.responseText.split("%EXTENSION_PATH%").join(chrome.extension.getURL("")); -}; -xhr.send(); - -function UpdateTheme() -{ - var css = document.querySelector("#aside-pane #darkCSS") if (window.matchMedia("(prefers-color-scheme: dark)").matches) { - css.removeAttribute("disabled"); + pane.parentElement.setAttribute("darkmode", ""); + document.querySelector("#icon").href = "icons/dark/empty/16.png"; } - else + + document.querySelector(".tabsAside .saveTabs").onclick = SetTabsAside; + + document.querySelectorAll(".tabsAside.pane > header nav button").forEach(i => { - css.setAttribute("disabled", true); + i.onclick = function () { window.open(i.value, '_blank'); }; + }); + + chrome.runtime.sendMessage({ command: "loadData" }, function (collections) + { + if (document.querySelector(".tabsAside.pane section div") == null) + collections.forEach(i => + { + AddCollection(i); + }); + }); +} + +function AddCollection(collection) +{ + var list = document.querySelector(".tabsAside section"); + list.querySelector("h2").setAttribute("hidden", ""); + + var rawTabs = ""; + + for (var i = 0; i < collection.links.length; i++) + { + rawTabs += + "
" + + "" + + "
" + + "
" + + "" + collection.titles[i] + "" + + "" + + "
" + + "
"; } -} \ No newline at end of file + + list.innerHTML += "
" + + "
" + + "Tabs: " + collection.links.length + "" + + "" + GetAgo(collection.timestamp) + "" + + "Restore tabs" + + "
" + + "" + + "" + + "
" + + "" + + "
" + + + "
" + rawTabs + "
" + + "
" + + list.querySelectorAll("a").forEach(i => + { + i.onclick = function () { RestoreTabs(i.parentElement.parentElement) }; + }); + + list.querySelectorAll("div > div:last-child > div > span").forEach(i => + { + i.onclick = function () { window.open(i.getAttribute("value"), '_blank'); }; + }) + + document.querySelectorAll(".tabsAside.pane > section > div > div:first-child > button").forEach(i => + { + i.onclick = function () { RemoveTabs(i.parentElement.parentElement) }; + }); + + document.querySelectorAll(".tabsAside.pane > section > div > div:first-child > div > nav > button:first-child").forEach(i => + { + i.onclick = function () { AddToFavorites(i.parentElement.parentElement.parentElement.parentElement) }; + }); + document.querySelectorAll(".tabsAside.pane > section > div > div:first-child > div > nav > button:last-child").forEach(i => + { + i.onclick = function () { ShareTabs(i.parentElement.parentElement.parentElement.parentElement) }; + }); + + document.querySelectorAll(".tabsAside.pane > section > div > div:last-child > div > div > button").forEach(i => + { + i.onclick = function () { RemoveOneTab(i.parentElement.parentElement) }; + }); +} + +function SetTabsAside() +{ + chrome.runtime.sendMessage({ command: "saveTabs" }); +} + +function RestoreTabs(collectionData) +{ + chrome.runtime.sendMessage( + { + command: "restoreTabs", + collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1 + }, + function () + { + if (collectionData.parentElement.children.length < 3) + { + RemoveElement(collectionData); + setTimeout(function () + { + document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"); + }, 250); + } + else + RemoveElement(collectionData); + } + ); +} + +function RemoveTabs(collectionData) +{ + chrome.runtime.sendMessage( + { + command: "deleteTabs", + collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1 + }, + function () + { + if (collectionData.parentElement.children.length < 3) + { + RemoveElement(collectionData); + setTimeout(function () + { + document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"); + }, 250); + } + else + RemoveElement(collectionData); + } + ); +} + +function AddToFavorites(collectionData) +{ + chrome.runtime.sendMessage( + { + command: "toFavorites", + collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1 + }); +} + +function ShareTabs(collectionData) +{ + chrome.runtime.sendMessage( + { + command: "share", + collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1 + }); +} + +function RemoveOneTab(tabData) +{ + chrome.runtime.sendMessage( + { + command: "removeTab", + collectionIndex: Array.prototype.slice.call(tabData.parentElement.parentElement.parentElement.children).indexOf(tabData.parentElement.parentElement) - 1, + tabIndex: Array.prototype.slice.call(tabData.parentElement.children).indexOf(tabData) + }, + function () + { + tabData.parentElement.previousElementSibling.children[0].textContent = "Tabs: " + tabData.parentElement.children.length - 1; + if (tabData.parentElement.children.length < 2) + { + RemoveElement(tabData.parentElement.parentElement); + if (document.querySelector("tabsAside.pane > section").children.length < 2) + setTimeout(function () + { + document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"); + }, 250); + } + else + RemoveElement(tabData); + }); +} + +function GetAgo(timestamp) +{ + var minutes = (Date.now() - timestamp) / 60000; + + if (minutes < 1) + return "Just now"; + + else if (Math.floor(minutes) == 1) + return "1 minute ago"; + else if (minutes < 60) + return Math.floor(minutes) + " minutes ago"; + + else if (Math.floor(minutes / 60) == 1) + return "1 hour ago"; + else if (minutes < 24 * 60) + return Math.floor(minutes / 60) + " hours ago"; + + else if (Math.floor(minutes / 24 / 60) == 1) + return "1 day ago"; + else if (minutes < 7 * 24 * 60) + return Math.floor(minutes / 24 / 60) + " days ago"; + + else if (Math.floor(minutes / 7 / 24 / 60) == 1) + return "1 week ago"; + else if (minutes < 30 * 24 * 60) + return Math.floor(minutes / 7 / 24 / 60) + " weeks ago"; + + else if (Math.floor(minutes / 30 / 24 / 60) == 1) + return "1 month ago"; + else if (minutes < 365 * 24 * 60) + return Math.floor(minutes / 30 / 24 / 60) + " months ago"; + + else if (Math.floor(minutes / 24 / 60) == 365) + return "1 year ago"; + else + return Math.floor(minutes / 365 / 24 / 60) + "years ago"; +} + +function RemoveElement(el) +{ + el.style.opacity = 0; + setTimeout(function () + { + el.remove(); + }, 200); +} + +// TODO: Add more actions +// TODO: Make backup system +// TODO: Override websites' CSS \ No newline at end of file diff --git a/js/background.js b/js/background.js index bc22dac..6e50923 100644 --- a/js/background.js +++ b/js/background.js @@ -1,33 +1,130 @@ +chrome.browserAction.onClicked.addListener(function (tab) +{ + if (tab.url.startsWith("http")) + { + chrome.tabs.executeScript(tab.id, + { + file: "js/aside-script.js", + allFrames: true, + runAt: "document_idle" + }); + } + else if (tab.url.startsWith("chrome-extension") && tab.url.endsWith("TabsAside.html")) + chrome.tabs.remove(tab.id); + else + { + chrome.tabs.create({ + url: chrome.extension.getURL("TabsAside.html"), + active: true + }); + } +}); + +chrome.tabs.onActivated.addListener(function (activeInfo) +{ + chrome.tabs.query({ url: chrome.extension.getURL("TabsAside.html") }, function (result) + { + if (result.length) + setTimeout(function () + { + result.forEach(i => + { + if (activeInfo.tabId != i.id) + chrome.tabs.remove(i.id); + }); + }, 200); + }); +}); + function UpdateTheme() { if (window.matchMedia("(prefers-color-scheme: dark)").matches) { - chrome.browserAction.setIcon( - { - path: - { - "128": "icons/dark/empty/128.png", - "48": "icons/dark/empty/48.png", - "32": "icons/dark/empty/32.png", - "16": "icons/dark/empty/16.png" - } - }); + if (collections.length) + chrome.browserAction.setIcon( + { + path: + { + "128": "icons/dark/full/128.png", + "48": "icons/dark/full/48.png", + "32": "icons/dark/full/32.png", + "16": "icons/dark/full/16.png" + } + }); + else + chrome.browserAction.setIcon( + { + path: + { + "128": "icons/dark/empty/128.png", + "48": "icons/dark/empty/48.png", + "32": "icons/dark/empty/32.png", + "16": "icons/dark/empty/16.png" + } + }); } else { - chrome.browserAction.setIcon( - { - path: - { - "128": "icons/light/empty/128.png", - "48": "icons/light/empty/48.png", - "32": "icons/light/empty/32.png", - "16": "icons/light/empty/16.png" - } - }); + if (collections.length) + chrome.browserAction.setIcon( + { + path: + { + "128": "icons/light/full/128.png", + "48": "icons/light/full/48.png", + "32": "icons/light/full/32.png", + "16": "icons/light/full/16.png" + } + }); + else + chrome.browserAction.setIcon( + { + path: + { + "128": "icons/light/empty/128.png", + "48": "icons/light/empty/48.png", + "32": "icons/light/empty/32.png", + "16": "icons/light/empty/16.png" + } + }); } } +var collections = JSON.parse(localStorage.getItem("sets")); +if (collections == null) + collections = []; + +chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) +{ + switch (message.command) + { + case "loadData": + sendResponse(collections); + break; + case "saveTabs": + SaveCollection(); + break; + case "restoreTabs": + RestoreCollection(message.collectionIndex); + sendResponse(); + break; + case "deleteTabs": + DeleteCollection(message.collectionIndex); + sendResponse(); + break; + case "removeTab": + RemoveTab(message.collectionIndex, message.tabIndex); + sendResponse(); + break; + case "toFavorites": + AddTabsToFavorites(message.collectionIndex); + break; + case "share": + ShareTabs(message.collectionIndex); + break; + } +}); + UpdateTheme(); chrome.windows.onCreated.addListener(UpdateTheme); chrome.windows.onRemoved.addListener(UpdateTheme); @@ -45,6 +142,117 @@ chrome.tabs.onDetached.addListener(UpdateTheme); chrome.tabs.onAttached.addListener(UpdateTheme); chrome.tabs.onRemoved.addListener(UpdateTheme); chrome.tabs.onReplaced.addListener(UpdateTheme); -chrome.tabs.onZoomChange.addListener(UpdateTheme); -// TODO: Load saved tabs \ No newline at end of file +function SaveCollection() +{ + chrome.tabs.query({ currentWindow: true }, function (tabs) + { + tabs = tabs.filter(i => !i.url.startsWith("chrome-extension") && !i.url.endsWith("TabsAside.html")); + + var collection = + { + timestamp: Date.now(), + tabsCount: tabs.length, + titles: tabs.map(tab => tab.title ?? ""), + links: tabs.map(tab => tab.url ?? ""), + icons: tabs.map(tab => tab.favIconUrl ?? "")//, + //tumbnails: tabs.map(tab => chrome.tabs.captureVisibleTab) + }; + + var rawData; + if (localStorage.getItem("sets") === null) + rawData = [collection]; + else + { + rawData = JSON.parse(localStorage.getItem("sets")); + rawData.unshift(collection); + } + + localStorage.setItem("sets", JSON.stringify(rawData)); + + collections = JSON.parse(localStorage.getItem("sets")); + + chrome.tabs.create({}); + chrome.tabs.remove(tabs.map(tab => tab.id)); + }); + + UpdateTheme(); +} + +function DeleteCollection(collectionIndex) +{ + collections = collections.filter(i => i != collections[collectionIndex]); + localStorage.setItem("sets", JSON.stringify(collections)); + + UpdateTheme(); +} + +function RestoreCollection(collectionIndex) +{ + collections[collectionIndex].links.forEach(i => + { + chrome.tabs.create( + { + url: i, + active: false + }); + }); + + collections = collections.filter(i => i != collections[collectionIndex]); + localStorage.setItem("sets", JSON.stringify(collections)); + + UpdateTheme(); +} + +function AddTabsToFavorites(collectionIndex) +{ + alert("Adding to favorites"); + /*for (var i = 0; i < collections[collectionIndex].links.length; i++) + { + chrome.bookmarks.create( + { + title: collections[collectionIndex].titles[i], + url: collections[collectionIndex].links[i], + }); + }*/ +} + +function ShareTabs(collectionId) +{ + alert("Sharing"); +} + +function RemoveTab(collectionIndex, tabIndex) +{ + var set = collections[collectionIndex]; + if (--set.tabsCount < 1) + { + collections = collections.filter(i => i != set); + localStorage.setItem("sets", JSON.stringify(collections)); + + UpdateTheme(); + return; + } + + var titles = []; + var links = []; + var icons = []; + + for (var i = set.links.length - 1; i >= 0; i--) + { + if (i == tabIndex) + continue; + + titles.unshift(set.titles[i]); + links.unshift(set.links[i]); + icons.unshift(set.icons[i]); + } + + set.titles = titles; + set.links = links; + set.icons = icons; + + localStorage.setItem("sets", JSON.stringify(collections)); + + UpdateTheme(); +} \ No newline at end of file diff --git a/manifest.json b/manifest.json index b2e32af..e5bfb34 100644 --- a/manifest.json +++ b/manifest.json @@ -2,9 +2,15 @@ "name": "Tabs Aside", "version": "0.1", "manifest_version": 2, - "description": "Classic Microsoft Edge \"Tabs Aside\" feature", + "description": "Classic Microsoft Edge \"Tabs Aside\" feature for Chromium browers", "author": "Michael \"XFox\" Gordeev", - "permissions": [ "tabs" ], + "permissions": + [ + "tabs", + "unlimitedStorage", + "", + "bookmarks" + ], "icons": { @@ -13,27 +19,25 @@ "32": "icons/light/empty/32.png", "16": "icons/light/empty/16.png" }, + "browser_action": { "default_icon": "icons/light/empty/32.png" }, "web_accessible_resources": [ "*" ], - "browser_action": - { - "default_popup": "popup/popup.html" - }, "content_scripts": [ { "matches": [ "" ], - "js": [ "js/aside-script.js" ], "css": [ "css/style.css", - "css/style.generic.css" - ] + "css/style.generic.css", + "css/style.dark.css" + ], + "run_at": "document_start" } ], "background": { - "scripts": ["js/background.js"], + "scripts": [ "js/background.js" ], "persistent": true } } \ No newline at end of file diff --git a/popup/popup.html b/popup/popup.html deleted file mode 100644 index 9dadfd8..0000000 --- a/popup/popup.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/popup/trigger.js b/popup/trigger.js deleted file mode 100644 index ce46c81..0000000 --- a/popup/trigger.js +++ /dev/null @@ -1,11 +0,0 @@ -chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) -{ - chrome.tabs.sendMessage( - tabs[0].id, - { }, - function() - { - window.close(); - } - ); -}); \ No newline at end of file