diff --git a/background.js b/background.js
index 21be04f97..6f0b05587 100644
--- a/background.js
+++ b/background.js
@@ -4,6 +4,8 @@ chrome.commands.onCommand.addListener(async function (command) {
await saveSelection();
} else if (command == "saveWholePage") {
await saveWholePage();
+ } else if (command == "saveTabs") {
+ await saveTabs();
} else if (command == "saveScreenshot") {
const activeTab = await getActiveTab();
@@ -100,6 +102,14 @@ async function getActiveTab() {
return tabs[0];
}
+async function getWindowTabs() {
+ const tabs = await browser.tabs.query({
+ currentWindow: true
+ });
+
+ return tabs;
+}
+
async function sendMessageToActiveTab(message) {
const activeTab = await getActiveTab();
@@ -115,11 +125,12 @@ async function sendMessageToActiveTab(message) {
}
}
-function toast(message, noteId = null) {
+function toast(message, noteId = null, tabIds = null) {
sendMessageToActiveTab({
name: 'toast',
message: message,
- noteId: noteId
+ noteId: noteId,
+ tabIds: tabIds
});
}
@@ -260,6 +271,50 @@ async function saveLinkWithNote(title, content) {
return true;
}
+async function getTabsPayload(tabs) {
+ let content = '
';
+ tabs.forEach(tab => {
+ content += `- ${tab.title}
`
+ });
+ content += '
';
+
+ const domainsCount = tabs.map(tab => tab.url)
+ .reduce((acc, url) => {
+ const hostname = new URL(url).hostname
+ return acc.set(hostname, (acc.get(hostname) || 0) + 1)
+ }, new Map());
+
+ let topDomains = [...domainsCount]
+ .sort((a, b) => {return b[1]-a[1]})
+ .slice(0,3)
+ .map(domain=>domain[0])
+ .join(', ')
+
+ if (tabs.length > 3) { topDomains += '...' }
+
+ return {
+ title: `${tabs.length} browser tabs: ${topDomains}`,
+ content: content,
+ clipType: 'tabs'
+ };
+}
+
+async function saveTabs() {
+ const tabs = await getWindowTabs();
+
+ const payload = await getTabsPayload(tabs);
+
+ const resp = await triliumServerFacade.callService('POST', 'notes', payload);
+
+ if (!resp) {
+ return;
+ }
+
+ const tabIds = tabs.map(tab=>{return tab.id});
+
+ toast(`${tabs.length} links have been saved to Trilium.`, resp.noteId, tabIds);
+}
+
browser.contextMenus.onClicked.addListener(async function(info, tab) {
if (info.menuItemId === 'trilium-save-selection') {
await saveSelection();
@@ -326,6 +381,9 @@ browser.runtime.onMessage.addListener(async request => {
}
}
}
+ else if (request.name === 'closeTabs') {
+ return await browser.tabs.remove(request.tabIds)
+ }
else if (request.name === 'load-script') {
return await browser.tabs.executeScript({file: request.file});
}
@@ -340,6 +398,9 @@ browser.runtime.onMessage.addListener(async request => {
else if (request.name === 'save-link-with-note') {
return await saveLinkWithNote(request.title, request.content);
}
+ else if (request.name === 'save-tabs') {
+ return await saveTabs();
+ }
else if (request.name === 'trigger-trilium-search') {
triliumServerFacade.triggerSearchForTrilium();
}
diff --git a/content.js b/content.js
index 3cc1c7bbf..c84f8b8ce 100644
--- a/content.js
+++ b/content.js
@@ -191,6 +191,18 @@ function getImages(container) {
return images;
}
+function createLink(clickAction, text, color = "lightskyblue") {
+ const link = document.createElement('a');
+ link.href = "javascript:";
+ link.style.color = color;
+ link.appendChild(document.createTextNode(text));
+ link.addEventListener("click", () => {
+ browser.runtime.sendMessage(null, clickAction)
+ });
+
+ return link
+}
+
async function prepareMessageResponse(message) {
console.info('Message: ' + message.name);
@@ -198,21 +210,23 @@ async function prepareMessageResponse(message) {
let messageText;
if (message.noteId) {
- messageText = document.createElement('span');
+ messageText = document.createElement('p');
+ messageText.setAttribute("style", "padding: 0; margin: 0")
messageText.appendChild(document.createTextNode(message.message + " "));
+ messageText.appendChild(createLink(
+ {name: 'openNoteInTrilium', noteId: message.noteId},
+ "Open in Trilium."
+ ));
- const link = document.createElement('a');
- link.href = "javascript:";
- link.style.color = "lightskyblue";
- link.appendChild(document.createTextNode("Open in Trilium."));
- link.addEventListener("click", () => {
- browser.runtime.sendMessage(null, {
- name: 'openNoteInTrilium',
- noteId: message.noteId
- })
- });
-
- messageText.appendChild(link);
+ // only after saving tabs
+ if (message.tabIds) {
+ messageText.appendChild(document.createElement("br"));
+ messageText.appendChild(createLink(
+ {name: 'closeTabs', tabIds: message.tabIds},
+ "Close saved tabs.",
+ "tomato"
+ ));
+ }
}
else {
messageText = message.message;
diff --git a/popup/popup.html b/popup/popup.html
index 51dbcb2cf..8b280defc 100644
--- a/popup/popup.html
+++ b/popup/popup.html
@@ -21,6 +21,7 @@
+
diff --git a/popup/popup.js b/popup/popup.js
index 5a11a79d6..b95620d7a 100644
--- a/popup/popup.js
+++ b/popup/popup.js
@@ -12,6 +12,7 @@ async function sendMessage(message) {
const $showOptionsButton = $("#show-options-button");
const $clipScreenShotButton = $("#clip-screenshot-button");
const $saveWholePageButton = $("#save-whole-page-button");
+const $saveTabsButton = $("#save-tabs-button");
$showOptionsButton.on("click", () => browser.runtime.openOptionsPage());
@@ -19,6 +20,8 @@ $clipScreenShotButton.on("click", () => sendMessage({name: 'save-screenshot'}));
$saveWholePageButton.on("click", () => sendMessage({name: 'save-whole-page'}));
+$saveTabsButton.on("click", () => sendMessage({name: 'save-tabs'}));
+
const $saveLinkWithNoteWrapper = $("#save-link-with-note-wrapper");
const $textNote = $("#save-link-with-note-textarea");