1
0
mirror of https://github.com/XFox111/TabsAsideExtension.git synced 2026-07-02 19:52:47 +03:00

Compare commits

...

4 Commits

Author SHA1 Message Date
Michael Gordeev 80c9dbe1a5 HOTFIX: Chinese language pack path typo fixed 2020-08-05 12:29:01 +03:00
Michael Gordeev c777f1a60a Minor 1.7 (#31)
- Complete UI/UX overhaul
- Updated default hotkeys (#27)
- Added option to disable deletion confirmation (#29)
- Added Chinese translation
- Fixed font artifacts on Windows

Co-authored-by: Dustin-Jiang <56217843+Dustin-Jiang@users.noreply.github.com>
Co-Authored-By: Michael Gordeev <michael@xfox111.net>
2020-08-05 12:07:11 +03:00
Michael Gordeev 1b7b419168 Patch 1.6.1
One tab remove button removes whole collection fixed (#25)
2020-07-18 21:39:15 +03:00
Michael Gordeev 39f7cd391a Minor 1.6 (#24)
- Added localization system (#23)
- Added Russian locale (#23)
- Feedback button link is now based on the extension download source (#20)
- Added badge counter to the extension icon
- Added keyboard shortcuts (#22)
- Added action items to the extension icon context menu (#22)
- Added ability to change primary extension icon action to save tabs instead of opening the pane (#22)
2020-07-15 16:54:50 +03:00
10 changed files with 730 additions and 147 deletions
+23 -12
View File
@@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<title>Tabs aside</title> <title loc="name">Tabs aside</title>
<link id="icon" rel="shortcut icon" type="image/png" href="icons/light/empty/16.png" /> <link id="icon" rel="shortcut icon" type="image/png" href="icons/light/empty/16.png" />
<link rel="stylesheet" type="text/css" href="css/style.css" /> <link rel="stylesheet" type="text/css" href="css/style.css" />
@@ -15,33 +15,44 @@
<aside class="tabsAside pane"> <aside class="tabsAside pane">
<header> <header>
<div> <div>
<h1>Tabs aside</h1> <h1 loc="name">Tabs aside</h1>
<button class="btn more" title="Options"></button> <button loc_alt="options" class="btn more" title="Options"></button>
<nav> <nav>
<p> <p>
<input type="checkbox" id="loadOnRestore"/> <input type="checkbox" id="loadOnRestore"/>
<label for="loadOnRestore">Load tabs on restore</label> <label loc="loadOnRestore" for="loadOnRestore">Load tabs on restore</label>
</p> </p>
<p>
<input type="checkbox" id="swapIconAction"/>
<label loc="swapIconAction" for="swapIconAction">Set tabs aside on extension icon click (Alt+P or right-click to open the pane)</label>
</p>
<p>
<input type="checkbox" id="showDeleteDialog"/>
<label loc="showDeleteDialog" for="showDeleteDialog">Show confirmation dialog before deleting an item</label>
</p>
<hr/>
<div> <div>
<button value="https://github.com/xfox111/ChromiumTabsAside">Visit GitHub page</button> <button loc="github" value="https://github.com/xfox111/ChromiumTabsAside">Visit GitHub page</button>
<button value="https://github.com/XFox111/ChromiumTabsAside/graphs/contributors">Project contributors</button> <button loc="contributors" value="https://github.com/XFox111/ChromiumTabsAside/graphs/contributors">Project contributors</button>
<button value="https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin">Leave feedback</button> <button loc="feedback" feedback-button>Leave feedback</button>
<button value="https://buymeacoffee.com/xfox111">Buy me a coffee!</button> <button loc="buyMeACoffee" value="https://buymeacoffee.com/xfox111">Buy me a coffee!</button>
</div> </div>
<hr/>
<p> <p>
<small>v1.0</small><br /> <small>v1.0</small><br />
Developed by Michael Gordeev (<a href="https://twitter.com/xfox111" <span loc="credits">Developed by Michael Gordeev</span> (<a href="https://twitter.com/xfox111"
target="_blank">@xfox111</a>) target="_blank">@xfox111</a>)
</p> </p>
</nav> </nav>
<button loc_alt="closePanel" class="btn remove" title="Close panel"></button>
</div> </div>
<a class="saveTabs"><span class="iconArrowRight"></span> Set current tabs aside</a> <a class="saveTabs"><span class="iconArrowRight"></span> <span loc="setAside">Set current tabs aside</span></a>
<hr />
</header> </header>
<section> <section>
<h2>You have no aside tabs</h2> <h2 loc="nothingSaved">You have no aside tabs</h2>
</section> </section>
</aside> </aside>
</div> </div>
+127
View File
@@ -0,0 +1,127 @@
{
"name":
{
"message": "Tabs aside",
"description": "Extension name. Displayed in the manifest and pane header"
},
"description":
{
"message": "Classic Microsoft Edge \"Tabs Aside\" feature for Chromium browsers",
"description": "Extension description"
},
"author":
{
"message": "Michael \"XFox\" Gordeev",
"description": "Author name"
},
"options":
{
"message": "Options",
"description": "Alternative text for options button in the pane"
},
"closePanel":
{
"message": "Close",
"description": "Alternative text for close panel button"
},
"loadOnRestore":
{
"message": "Load tabs on restore",
"description": "Label for option"
},
"showDeleteDialog":
{
"message": "Show confirmation dialog before deleting an item",
"description": "Label for option"
},
"swapIconAction":
{
"message": "Set tabs aside on extension icon click (%TOGGLE_SHORTCUT% or right-click to open the pane)",
"description": "Label for option"
},
"github":
{
"message": "Visit GitHub page",
"description": "Link title"
},
"contributors":
{
"message": "Project contributors",
"description": "Link title"
},
"feedback":
{
"message": "Leave feedback",
"description": "Link title"
},
"buyMeACoffee":
{
"message": "Buy me a coffee!",
"description": "Link title"
},
"credits":
{
"message": "Developed by Michael 'XFox' Gordeev",
"description": "Options menu credits"
},
"setAside":
{
"message": "Set current tabs aside",
"description": "Save collection action name. Used in the pane, extension context menu and manifest shortcuts"
},
"nothingSaved":
{
"message": "You have no aside tabs",
"description": "Placeholder for empty pane"
},
"removeTab":
{
"message": "Remove tab from collection",
"description": "Button hint on a tab card"
},
"restoreTabs":
{
"message": "Restore tabs",
"description": "Collection restore action link name"
},
"more":
{
"message": "More...",
"description": "Collections' more button title"
},
"restoreNoRemove":
{
"message": "Restore without removing",
"description": "Context action item name"
},
"removeCollection":
{
"message": "Remove collection",
"description": "Collection remove action name"
},
"removeCollectionConfirm":
{
"message": "Are you sure you want to delete this collection?",
"description": "Prompt dialog content on collection deletion"
},
"removeTabConfirm":
{
"message": "Are you sure you want to delete this tab?",
"description": "Prompt dialog content on one tab deletion"
},
"togglePaneContext":
{
"message": "Toggle tabs aside pane",
"description": "Context action name. Used in extension context menu and manifest shortcuts"
},
"noTabsToSave":
{
"message": "No tabs available to save",
"description": "Alert dialog message when there's no tabs to save"
},
"tabs":
{
"message": "items",
"description": "Collection tabs counter label (e.g. 8 items)"
}
}
+127
View File
@@ -0,0 +1,127 @@
{
"name":
{
"message": "Отложенные вкладки",
"description": "Extension name. Displayed in the manifest and pane header"
},
"description":
{
"message": "Функиця классического Microsoft Edge на браузерах Chromium",
"description": "Extension description"
},
"author":
{
"message": "Михаил \"XFox\" Гордеев",
"description": "Author name"
},
"options":
{
"message": "Настройки",
"description": "Alternative text for options button in the pane"
},
"closePanel":
{
"message": "Закрыть",
"description": "Alternative text for close panel button"
},
"loadOnRestore":
{
"message": "Загружать вкладки после открытия",
"description": "Label for option"
},
"showDeleteDialog":
{
"message": "Показывать окно подтверждения перед удалением элемента",
"description": "Label for option"
},
"swapIconAction":
{
"message": "Откладывать вкладки при нажатии на иконку расширения (%TOGGLE_SHORTCUT% или правая кнопка мыши для открытия панели)",
"description": "Label for option"
},
"github":
{
"message": "Страница GitHub",
"description": "Link title"
},
"contributors":
{
"message": "Свой вклад вложили",
"description": "Link title"
},
"feedback":
{
"message": "Оставить отзыв",
"description": "Link title"
},
"buyMeACoffee":
{
"message": "Купить мне кофе!",
"description": "Link title"
},
"credits":
{
"message": "Разработано: Михаил 'XFox' Гордеев",
"description": "Options menu credits"
},
"setAside":
{
"message": "Отложить открытые вкладки",
"description": "Save collection action name. Used in the pane, extension context menu and manifest shortcuts"
},
"nothingSaved":
{
"message": "У вас нет отложенных вкладок",
"description": "Placeholder for empty pane"
},
"removeTab":
{
"message": "Удалить вкладку из коллекции",
"description": "Button hint on a tab card"
},
"restoreTabs":
{
"message": "Восстановить вкладки",
"description": "Collection restore action link name"
},
"more":
{
"message": "Больше...",
"description": "Collections' more button title"
},
"restoreNoRemove":
{
"message": "Восстановить без удаления",
"description": "Context action item name"
},
"removeCollection":
{
"message": "Удалить коллекцию",
"description": "Collection remove action name"
},
"removeCollectionConfirm":
{
"message": "Вы уверены, что хотите удалить эту коллекцию?",
"description": "Prompt dialog content on collection deletion"
},
"removeTabConfirm":
{
"message": "Вы уверены, что хотите удалить эту вкладку из коллекции?",
"description": "Prompt dialog content on one tab deletion"
},
"togglePaneContext":
{
"message": "Открыть/закрыть панель",
"description": "Context action name. Used in extension context menu and manifest shortcuts"
},
"noTabsToSave":
{
"message": "Нет доступных для сохранения вкладок",
"description": "Alert dialog message when there's no tabs to save"
},
"tabs":
{
"message": "вкладок",
"description": "Collection tabs counter label (e.g. 8 items)"
}
}
+127
View File
@@ -0,0 +1,127 @@
{
"name":
{
"message": "搁置的标签页",
"description": "Extension name. Displayed in the manifest and pane header"
},
"description":
{
"message": "为Chromium浏览器提供旧版 Microsoft Edge 中的\"搁置标签页\" 功能",
"description": "Extension description"
},
"author":
{
"message": "Michael \"XFox\" Gordeev",
"description": "Author name"
},
"options":
{
"message": "设置",
"description": "Alternative text for options button in the pane"
},
"closePanel":
{
"message": "关闭",
"description": "Alternative text for close panel button"
},
"loadOnRestore":
{
"message": "在重新打开时加载页面",
"description": "Label for option"
},
"showDeleteDialog":
{
"message": "在删除项目之前显示确认对话框",
"description": "Label for option"
},
"swapIconAction":
{
"message": "点击拓展图标来搁置所有标签页 (按%TOGGLE_SHORTCUT%或右键来打开侧栏)",
"description": "Label for option"
},
"github":
{
"message": "查看GitHub页面",
"description": "Link title"
},
"contributors":
{
"message": "项目贡献者",
"description": "Link title"
},
"feedback":
{
"message": "给我们反馈",
"description": "Link title"
},
"buyMeACoffee":
{
"message": "给我买杯咖啡!",
"description": "Link title"
},
"credits":
{
"message": "由Michael 'XFox' Gordeev开发",
"description": "Options menu credits"
},
"setAside":
{
"message": "搁置当前的所有标签页",
"description": "Save collection action name. Used in the pane, extension context menu and manifest shortcuts"
},
"nothingSaved":
{
"message": "你目前没有搁置的标签页",
"description": "Placeholder for empty pane"
},
"removeTab":
{
"message": "从标签页集中移除标签页",
"description": "Button hint on a tab card"
},
"restoreTabs":
{
"message": "恢复标签页",
"description": "Collection restore action link name"
},
"more":
{
"message": "更多...",
"description": "Collections' more button title"
},
"restoreNoRemove":
{
"message": "恢复但不移除标签页",
"description": "Context action item name"
},
"removeCollection":
{
"message": "移除标签页集",
"description": "Collection remove action name"
},
"removeCollectionConfirm":
{
"message": "你确定要移除这个标签页集吗?",
"description": "Prompt dialog content on collection deletion"
},
"removeTabConfirm":
{
"message": "你确定要移除这个标签页吗?",
"description": "Prompt dialog content on one tab deletion"
},
"togglePaneContext":
{
"message": "打开或关闭侧栏",
"description": "Context action name. Used in extension context menu and manifest shortcuts"
},
"noTabsToSave":
{
"message": "没有可以搁置的标签页",
"description": "Alert dialog message when there's no tabs to save"
},
"tabs":
{
"message": "项",
"description": "Collection tabs counter label (e.g. 8 items)"
}
}
+73 -40
View File
@@ -18,7 +18,9 @@
right: 0px; right: 0px;
top: 0px; top: 0px;
bottom: 0px; bottom: 0px;
overflow: auto; overflow: hidden;
display: grid;
grid-template-rows: auto 1fr;
width: 100%; width: 100%;
min-width: 500px; min-width: 500px;
@@ -36,7 +38,7 @@
aside[embedded] aside[embedded]
{ {
width: 40% !important; width: 500px !important;
} }
.tabsAside.pane[opened] .tabsAside.pane[opened]
@@ -47,37 +49,32 @@
/* Pane header*/ /* Pane header*/
.tabsAside.pane > header .tabsAside.pane > header
{ {
margin: 20px 40px; z-index: 1;
padding: 14px 20px 16px 20px;
box-shadow: 0px 0px 5px rgba(0,0,0,.5);
background-color: white;
} }
.tabsAside.pane > header > div .tabsAside.pane > header > div
{ {
display: grid; display: grid;
grid-template-columns: 1fr auto; grid-template-columns: 1fr auto auto;
grid-column-gap: 10px;
margin-bottom: 29px;
} }
.tabsAside.pane > header > div > h1 .tabsAside.pane > header > div > h1
{ {
margin: 10px 0px; margin: 0px 5px;
font-weight: normal; font-weight: 500;
font-size: 21pt; font-size: 15pt;
}
.tabsAside.pane > header > div > button
{
margin: auto;
} }
.tabsAside.pane > header > div > nav .tabsAside.pane > header > div > nav
{ {
top: 70px; top: 45px;
right: 40px; right: 55px;
} }
.tabsAside.pane > header nav > div
{
box-shadow: 0px 4px 5px -2px rgba(100, 100, 100, .5);
}
.tabsAside.pane > header nav > p .tabsAside.pane > header nav > p
{ {
margin: 10px; margin: 10px;
@@ -88,25 +85,35 @@
text-decoration: none; text-decoration: none;
} }
.iconArrowRight .saveTabs
{ {
width: 13px; display: inline-grid;
height: 13px; grid-template-columns: 16px auto;
display: inline-block; grid-column-gap: 15px;
background-repeat: no-repeat;
background-size: 13px; font-weight: 600;
background-position: center;
background-image: url("chrome-extension://__MSG_@@extension_id__/icons/arrowRight.svg");
} }
.tabsAside.pane > header > hr .iconArrowRight
{ {
border: 1px solid #8a8a8a; width: 16px;
height: 16px;
display: inline-block;
background-repeat: no-repeat;
background-size: 16px;
background-position: center;
background-image: url("chrome-extension://__MSG_@@extension_id__/icons/arrowRight.svg");
margin: 2px;
} }
.tabsAside.pane section
{
overflow: auto;
}
.tabsAside.pane > section > h2 .tabsAside.pane > section > h2
{ {
margin: 0px 40px; margin: 20px;
font-weight: normal; font-weight: normal;
} }
@@ -116,11 +123,34 @@
transition: .2s; transition: .2s;
} }
.collectionSet
{
background-color: white;
margin: 10px;
border-radius: 5px;
border: 1px solid #eee;
}
.collectionSet:hover
{
box-shadow: 0px 0px 5px rgba(0, 0, 0, .25);
}
.collectionSet .header > *
{
visibility: hidden;
}
.collectionSet:hover .header > *
{
visibility: visible;
}
.collectionSet > .header .collectionSet > .header
{ {
margin: 0px 20px; margin: 10px 10px 0px 20px;
display: grid; display: grid;
grid-template-columns: auto 1fr auto auto auto; grid-template-columns: 1fr auto auto auto;
grid-column-gap: 10px; grid-column-gap: 10px;
align-items: center; align-items: center;
} }
@@ -128,11 +158,14 @@
.collectionSet > .header > small .collectionSet > .header > small
{ {
color: gray; color: gray;
visibility: visible !important;
} }
.collectionSet > .header > span .collectionSet > .header > h4
{ {
font-weight: 600; margin: 0px;
visibility: visible !important;
font-weight: 500;
} }
.collectionSet > .header > a .collectionSet > .header > a
@@ -149,8 +182,7 @@
/* Tabs collection */ /* Tabs collection */
.collectionSet > .set .collectionSet > .set
{ {
margin: 0px 0px 0px 20px; padding: 5px 10px;
padding: 10px 40px 10px 20px;
white-space: nowrap; white-space: nowrap;
overflow: auto; overflow: auto;
} }
@@ -179,14 +211,15 @@
display: inline-grid; display: inline-grid;
grid-template-rows: 1fr auto; grid-template-rows: 1fr auto;
box-shadow: 0px 0px 5px rgba(100, 100, 100, .5);
transition: .25s; transition: .25s;
cursor: pointer; cursor: pointer;
border: 1px solid #eee;
border-radius: 5px;
} }
.collectionSet > .set > div:hover .collectionSet > .set > div:hover
{ {
filter: brightness(120%); box-shadow: 0px 0px 5px rgba(100, 100, 100, .5);
box-shadow: 0px 0px 15px rgba(100, 100, 100, .5);
} }
.collectionSet > .set > div > div .collectionSet > .set > div > div
@@ -213,7 +246,7 @@
{ {
width: 20px; width: 20px;
height: 20px; height: 20px;
margin: 10px; margin: 8px;
background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_icon.png"); background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_icon.png");
background-size: 20px; background-size: 20px;
+17
View File
@@ -9,6 +9,16 @@
color: white; color: white;
} }
.tabsAside[darkmode] .pane header .iconArrowRight
{
filter: invert();
}
.tabsAside[darkmode] .pane header
{
background-color: #3b3b3b;
}
.tabsAside[darkmode] .saveTabs > div .tabsAside[darkmode] .saveTabs > div
{ {
filter: invert(); filter: invert();
@@ -50,11 +60,18 @@
background: dimgray; background: dimgray;
} }
.tabsAside[darkmode] .pane .collectionSet
{
background-color: #3b3b3b;
border-color: #444;
}
/* Tab style */ /* Tab style */
.tabsAside[darkmode] .pane .collectionSet > .set > div .tabsAside[darkmode] .pane .collectionSet > .set > div
{ {
background-color: #0c0c0c; background-color: #0c0c0c;
background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_thumbnail_dark.png"); background-image: url("chrome-extension://__MSG_@@extension_id__/images/tab_thumbnail_dark.png");
border-color: #444;
} }
.tabsAside[darkmode] .pane .collectionSet > .set > div > div .tabsAside[darkmode] .pane .collectionSet > .set > div > div
+23 -7
View File
@@ -17,7 +17,7 @@
.tabsAside .tabsAside
{ {
font-family: 'DefaultFont'; font-family: 'Segoe UI' ,'DefaultFont';
font-size: 14px; font-size: 14px;
user-select: none; user-select: none;
} }
@@ -41,15 +41,15 @@
/* Buttons style */ /* Buttons style */
.tabsAside button .tabsAside button
{ {
width: 32px; width: 28px;
height: 32px; height: 28px;
background-color: transparent; background-color: transparent;
border: none; border: none;
cursor: pointer; cursor: pointer;
} }
.tabsAside button:hover .tabsAside button:hover
{ {
background-color: #c6c6c6; background-color: #f2f2f2;
} }
.tabsAside button:active .tabsAside button:active
{ {
@@ -62,25 +62,41 @@
user-select: none; user-select: none;
position: absolute; position: absolute;
width: 250px; width: 290px;
box-shadow: 0px 0px 10px black; box-shadow: 0px 0px 10px rgba(0,0,0,.5);
background-color: white; background-color: white;
border-radius: 5px; border-radius: 5px;
z-index: 10; z-index: 10;
visibility: hidden; visibility: hidden;
padding: 4px 0px;
} }
.tabsAside nav hr
{
border: none;
height: 1px;
background-color: lightgray;
}
.tabsAside nav button .tabsAside nav button
{ {
text-align: start; text-align: start;
padding: 0px 10px; padding: 0px 10px;
width: 100%; width: 100%;
height: 32px;
font-family: 'Segoe UI' ,'DefaultFont';
} }
.tabsAside nav button:hover
{
background-color: #eeee;
}
.tabsAside button + nav:active, .tabsAside button + nav:active,
.tabsAside button:focus + nav .tabsAside button:focus + nav
{ {
@@ -91,7 +107,7 @@
.btn .btn
{ {
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 15px; background-size: 12px;
background-position: center; background-position: center;
} }
+116 -80
View File
@@ -62,6 +62,8 @@ function Initialize()
}); });
} }
UpdateLocale();
if (window.matchMedia("(prefers-color-scheme: dark)").matches) if (window.matchMedia("(prefers-color-scheme: dark)").matches)
{ {
pane.parentElement.setAttribute("darkmode", ""); pane.parentElement.setAttribute("darkmode", "");
@@ -69,10 +71,14 @@ function Initialize()
} }
document.querySelector(".tabsAside .saveTabs").onclick = SetTabsAside; document.querySelector(".tabsAside .saveTabs").onclick = SetTabsAside;
document.querySelector(".tabsAside header .btn.remove").addEventListener("click", () =>
chrome.runtime.sendMessage({ command: "togglePane" })
);
document.querySelector("nav > p > small").textContent = chrome.runtime.getManifest()["version"]; document.querySelector("nav > p > small").textContent = chrome.runtime.getManifest()["version"];
var loadOnRestoreCheckbox = document.querySelector("nav > p > input[type=checkbox]"); // Tabs dismiss option
var loadOnRestoreCheckbox = document.querySelector("#loadOnRestore");
chrome.storage.sync.get( chrome.storage.sync.get(
{ "loadOnRestore": false }, { "loadOnRestore": false },
values => loadOnRestoreCheckbox.checked = values.loadOnRestore values => loadOnRestoreCheckbox.checked = values.loadOnRestore
@@ -91,8 +97,59 @@ function Initialize()
}) })
); );
// Exntension browser icon action
var swapIconAction = document.querySelector("#swapIconAction");
chrome.storage.sync.get(
{ "setAsideOnClick": false },
values => swapIconAction.checked = values.setAsideOnClick
);
chrome.storage.onChanged.addListener((changes, namespace) =>
{
if (namespace == 'sync')
for (key in changes)
if (key === 'setAsideOnClick')
swapIconAction.checked = changes[key].newValue
});
swapIconAction.addEventListener("click", () =>
chrome.storage.sync.set(
{
"setAsideOnClick": swapIconAction.checked
})
);
// Deletion confirmation dialog
var showDeleteDialog = document.querySelector("#showDeleteDialog");
chrome.storage.sync.get(
{ "showDeleteDialog": true },
values => showDeleteDialog.checked = values.showDeleteDialog
);
chrome.storage.onChanged.addListener((changes, namespace) =>
{
if (namespace == 'sync')
for (key in changes)
if (key === 'showDeleteDialog')
showDeleteDialog.checked = changes[key].newValue
});
showDeleteDialog.addEventListener("click", () =>
chrome.storage.sync.set(
{
"showDeleteDialog": showDeleteDialog.checked
})
);
document.querySelectorAll(".tabsAside.pane > header nav button").forEach(i => document.querySelectorAll(".tabsAside.pane > header nav button").forEach(i =>
i.onclick = () => window.open(i.value, '_blank')); i.onclick = () =>
{
if (i.hasAttribute("feedback-button"))
{
if (chrome.runtime.getManifest()["update_url"] && chrome.runtime.getManifest()["update_url"].includes("edge.microsoft.com"))
window.open("https://microsoftedge.microsoft.com/addons/detail/tabs-aside/kmnblllmalkiapkfknnlpobmjjdnlhnd", "_blank")
else
window.open("https://chrome.google.com/webstore/detail/tabs-aside/mgmjbodjgijnebfgohlnjkegdpbdjgin", "_blank")
}
else
window.open(i.value, "_blank");
});
chrome.runtime.sendMessage({ command: "loadData" }, (collections) => chrome.runtime.sendMessage({ command: "loadData" }, (collections) =>
{ {
@@ -104,6 +161,15 @@ function Initialize()
setTimeout(() => pane.setAttribute("opened", ""), 100); setTimeout(() => pane.setAttribute("opened", ""), 100);
} }
function UpdateLocale()
{
document.querySelectorAll("*[loc]").forEach(i => i.textContent = chrome.i18n.getMessage(i.getAttribute("loc")));
document.querySelectorAll("*[loc_alt]").forEach(i => i.title = chrome.i18n.getMessage(i.getAttribute("loc_alt")));
var swapActionsLabel = document.querySelector("label[loc=swapIconAction]");
chrome.commands.getAll((commands) => swapActionsLabel.textContent = swapActionsLabel.textContent.replace("%TOGGLE_SHORTCUT%", commands[2].shortcut));
}
function AddCollection(collection) function AddCollection(collection)
{ {
var list = document.querySelector(".tabsAside section"); var list = document.querySelector(".tabsAside section");
@@ -119,7 +185,7 @@ function AddCollection(collection)
"<div>" + "<div>" +
"<div" + ((collection.icons[i] == 0 || collection.icons[i] == null) ? "" : " style='background-image: url(\"" + collection.icons[i] + "\")'") + "></div>" + "<div" + ((collection.icons[i] == 0 || collection.icons[i] == null) ? "" : " style='background-image: url(\"" + collection.icons[i] + "\")'") + "></div>" +
"<span>" + collection.titles[i] + "</span>" + "<span>" + collection.titles[i] + "</span>" +
"<button class='btn remove' title='Remove tab from collection'></button>" + "<button loc_alt='removeTab' class='btn remove' title='Remove tab from collection'></button>" +
"</div>" + "</div>" +
"</div>"; "</div>";
} }
@@ -127,20 +193,22 @@ function AddCollection(collection)
list.innerHTML += list.innerHTML +=
"<div class='collectionSet'>" + "<div class='collectionSet'>" +
"<div class='header'>" + "<div class='header'>" +
"<span>Tabs: " + collection.links.length + "</span>" + "<h4>" + new Date(collection.timestamp).toDateString() + "</h4>" +
"<small>" + GetAgo(collection.timestamp) + "</small>" + "<a loc='restoreTabs' class='restoreCollection'>Restore tabs</a>" +
"<a class='restoreCollection'>Restore tabs</a>" +
"<div>" + "<div>" +
"<button class='btn more' title='More...'></button>" + "<button loc_alt='more' class='btn more' title='More...'></button>" +
"<nav>" + "<nav>" +
"<button class='restoreCollection noDelete'>Restore without removing</button>" + "<button loc='restoreNoRemove' class='restoreCollection noDelete'>Restore without removing</button>" +
"</nav>" + "</nav>" +
"</div>" + "</div>" +
"<button class='btn remove' title='Remove collection'></button>" + "<button loc_alt='removeCollection' class='btn remove' title='Remove collection'></button>" +
"<small>" + collection.links.length + " " + chrome.i18n.getMessage("tabs") +"</small>" +
"</div>" + "</div>" +
"<div class='set' class='tabsList'>" + rawTabs + "</div>" + "<div class='set' class='tabsList'>" + rawTabs + "</div>" +
"</div>" "</div>";
UpdateLocale();
list.querySelectorAll(".restoreCollection").forEach(i => list.querySelectorAll(".restoreCollection").forEach(i =>
i.onclick = () => RestoreTabs(i.parentElement.parentElement)); i.onclick = () => RestoreTabs(i.parentElement.parentElement));
@@ -157,10 +225,10 @@ function AddCollection(collection)
} }
)); ));
document.querySelectorAll(".btn.remove").forEach(i => document.querySelectorAll(".header .btn.remove").forEach(i =>
i.onclick = () => RemoveTabs(i.parentElement.parentElement)); i.onclick = () => RemoveTabs(i.parentElement.parentElement));
document.querySelectorAll(".tabsList .btn.remove").forEach(i => document.querySelectorAll(".set .btn.remove").forEach(i =>
i.onclick = () => RemoveOneTab(i.parentElement.parentElement)); i.onclick = () => RemoveOneTab(i.parentElement.parentElement));
} }
@@ -187,79 +255,47 @@ function RestoreTabs(collectionData, removeCollection = true)
function RemoveTabs(collectionData) function RemoveTabs(collectionData)
{ {
if (!confirm("Are you sure you want to delete this collection?")) chrome.storage.sync.get({ "showDeleteDialog": true }, values =>
return; {
if (values.showDeleteDialog && !confirm(chrome.i18n.getMessage("removeCollectionConfirm")))
return;
chrome.runtime.sendMessage( chrome.runtime.sendMessage(
{ {
command: "deleteTabs", command: "deleteTabs",
collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1 collectionIndex: Array.prototype.slice.call(collectionData.parentElement.children).indexOf(collectionData) - 1
}, },
() => RemoveCollectionElement(collectionData) () => RemoveCollectionElement(collectionData)
); );
});
} }
function RemoveOneTab(tabData) function RemoveOneTab(tabData)
{ {
if (!confirm("Are you sure you want to delete this tab?")) chrome.storage.sync.get({ "showDeleteDialog": true }, values =>
return; {
if (values.showDeleteDialog && !confirm(chrome.i18n.getMessage("removeTabConfirm")))
return;
chrome.runtime.sendMessage( 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)
},
() =>
{
tabData.parentElement.previousElementSibling.children[0].textContent = "Tabs: " + (tabData.parentElement.children.length - 1);
if (tabData.parentElement.children.length < 2)
{ {
RemoveElement(tabData.parentElement.parentElement); command: "removeTab",
if (document.querySelector("tabsAside.pane > section").children.length < 2) collectionIndex: Array.prototype.slice.call(tabData.parentElement.parentElement.parentElement.children).indexOf(tabData.parentElement.parentElement) - 1,
setTimeout(() => document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"), 250); tabIndex: Array.prototype.slice.call(tabData.parentElement.children).indexOf(tabData)
} },
else () =>
RemoveElement(tabData); {
}); tabData.parentElement.previousElementSibling.children[0].textContent = chrome.i18n.getMessage("tabs") + ": " + (tabData.parentElement.children.length - 1);
} if (tabData.parentElement.children.length < 2)
{
function GetAgo(timestamp) RemoveElement(tabData.parentElement.parentElement);
{ if (document.querySelector("tabsAside.pane > section").children.length < 2)
var minutes = (Date.now() - timestamp) / 60000; setTimeout(() => document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"), 250);
}
if (minutes < 1) else
return "Just now"; RemoveElement(tabData);
});
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) function RemoveElement(el)
@@ -270,7 +306,7 @@ function RemoveElement(el)
function RemoveCollectionElement(el) function RemoveCollectionElement(el)
{ {
RemoveElement(el); if (el.parentElement.children.length < 3)
if (el.parentElement.children.length < 2)
setTimeout(() => document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"), 250); setTimeout(() => document.querySelector(".tabsAside.pane > section > h2").removeAttribute("hidden"), 250);
RemoveElement(el);
} }
+66 -2
View File
@@ -1,4 +1,4 @@
chrome.browserAction.onClicked.addListener((tab) => function TogglePane(tab)
{ {
if (tab.url.startsWith("http") if (tab.url.startsWith("http")
&& !tab.url.includes("chrome.google.com") && !tab.url.includes("chrome.google.com")
@@ -38,10 +38,59 @@ chrome.browserAction.onClicked.addListener((tab) =>
}); });
})); }));
} }
}
function ProcessCommand(command)
{
switch(command)
{
case "set-aside":
SaveCollection();
break;
case "toggle-pane":
chrome.tabs.query(
{
active: true,
currentWindow: true
},
(tabs) => TogglePane(tabs[0])
)
break;
}
}
chrome.browserAction.onClicked.addListener((tab) =>
{
chrome.storage.sync.get({ "setAsideOnClick": false }, values =>
{
if (values.setAsideOnClick)
SaveCollection();
else
TogglePane(tab);
});
}); });
// Adding context menu options
chrome.contextMenus.create(
{
id: "toggle-pane",
contexts: ['all'],
title: chrome.i18n.getMessage("togglePaneContext")
}
);
chrome.contextMenus.create(
{
id: "set-aside",
contexts: ['all'],
title: chrome.i18n.getMessage("setAside")
}
);
var collections = JSON.parse(localStorage.getItem("sets")) || []; var collections = JSON.parse(localStorage.getItem("sets")) || [];
chrome.commands.onCommand.addListener(ProcessCommand);
chrome.contextMenus.onClicked.addListener((info) => ProcessCommand(info.menuItemId));
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => chrome.runtime.onMessage.addListener((message, sender, sendResponse) =>
{ {
switch (message.command) switch (message.command)
@@ -67,6 +116,15 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) =>
RemoveTab(message.collectionIndex, message.tabIndex); RemoveTab(message.collectionIndex, message.tabIndex);
sendResponse(); sendResponse();
break; break;
case "togglePane":
chrome.tabs.query(
{
active: true,
currentWindow: true
},
(tabs) => TogglePane(tabs[0])
)
break;
} }
}); });
@@ -88,6 +146,12 @@ function UpdateTheme()
"16": basePath + "16.png" "16": basePath + "16.png"
} }
}); });
// Updating badge counter
if (collections.length < 1)
chrome.browserAction.setBadgeText({ });
else
chrome.browserAction.setBadgeText({ text: collections.length.toString() });
} }
UpdateTheme(); UpdateTheme();
@@ -104,7 +168,7 @@ function SaveCollection()
if (tabs.length < 1) if (tabs.length < 1)
{ {
alert("No tabs available to save"); alert(chrome.i18n.getMessage("noTabsToSave"));
return; return;
} }
+31 -6
View File
@@ -1,15 +1,18 @@
{ {
"name": "Tabs Aside", "name": "__MSG_name__",
"version": "1.5", "version": "1.7",
"manifest_version": 2, "manifest_version": 2,
"description": "Classic Microsoft Edge \"Tabs Aside\" feature for Chromium browsers", "description": "__MSG_description__",
"author": "Michael \"XFox\" Gordeev", "author": "__MSG_author__",
"default_locale": "en",
"permissions": "permissions":
[ [
"tabs", "tabs",
"unlimitedStorage", "unlimitedStorage",
"storage", "storage",
"<all_urls>" "<all_urls>",
"contextMenus"
], ],
"icons": "icons":
@@ -26,5 +29,27 @@
{ {
"scripts": [ "js/background.js" ], "scripts": [ "js/background.js" ],
"persistent": false "persistent": false
},
"commands":
{
"set-aside":
{
"description": "__MSG_setAside__",
"suggested_key":
{
"default": "Alt+Left",
"mac": "MacCtrl+T"
}
},
"toggle-pane":
{
"description": "__MSG_togglePaneContext__",
"suggested_key":
{
"default": "Alt+P",
"mac": "Command+Shift+P"
}
}
} }
} }