diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 6eb4a57..951c361 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -6,12 +6,24 @@ "message": "Stops Chrome from suspending tabs, and reloading them when you switch to them." }, "manifest_title": { - "message": "Automatic tab discarding currently disabled\nDisable/uninstall this extension to enable it" + "message": "Click to open popup." }, "cm_review": { "message": "Rate this extension in store" }, "cm_support": { "message": "Send feedback (suggestions, issues)" + }, + "cm_help": { + "message": "Help" + }, + "version": { + "message": "Version" + }, + "help": { + "message": "Select the tabs you want to disable discarding for." + }, + "select_all": { + "message": "Select all" } } diff --git a/_locales/es/messages.json b/_locales/es/messages.json index 854b465..02fae97 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -6,12 +6,24 @@ "message": "Evita que Chrome suspenda pestañas y se actualicen cuando vuelves a ellas." }, "manifest_title": { - "message": "La suspensión de pestañas está deshabilitada\nDesactiva/desinstala esta extensión para activarla" + "message": "Haga clic para abrir la ventana emergente." }, "cm_review": { "message": "Calificar esta extensión en la tienda" }, "cm_support": { "message": "Enviar comentarios (sugerencias, problemas)" + }, + "cm_help": { + "message": "Ayudar" + }, + "version": { + "message": "Versión" + }, + "help": { + "message": "Seleccione las pestañas para las que desea deshabilitar el descarte." + }, + "select_all": { + "message": "Seleccionar todo" } } diff --git a/background.js b/background.js index 32a9c2f..5d10aad 100644 --- a/background.js +++ b/background.js @@ -1,39 +1,65 @@ -chrome.tabs.onCreated.addListener(function(tab) { - chrome.tabs.update(tab.id, {autoDiscardable: false}); +chrome.tabs.onCreated.addListener(function (tab) { + chrome.tabs.update(tab.id, { autoDiscardable: false }); }); -chrome.tabs.onReplaced.addListener(function(tabId) { - chrome.tabs.update(tabId, {autoDiscardable: false}); +chrome.tabs.onReplaced.addListener(function (tabId) { + chrome.tabs.update(tabId, { autoDiscardable: false }); }); -chrome.runtime.onInstalled.addListener(function(details) { - chrome.tabs.query({}, function(tabs) { - tabs.forEach(function(tab) { - chrome.tabs.update(tab.id, {autoDiscardable: false}); +chrome.runtime.onInstalled.addListener(function (details) { + chrome.tabs.query({}, function (tabs) { + tabs.forEach(function (tab) { + chrome.tabs.update(tab.id, { autoDiscardable: false }); }); }); }); - chrome.runtime.setUninstallURL("https://chrome.google.com/webstore/detail/dnhngfnfolbmhgealdpolmhimnoliiok/support"); chrome.contextMenus.create({ id: "review", title: "🌟 " + chrome.i18n.getMessage("cm_review"), - contexts: ["browser_action"] + contexts: ["browser_action"], }); + chrome.contextMenus.create({ id: "support", title: "💬 " + chrome.i18n.getMessage("cm_support"), - contexts: ["browser_action"] + contexts: ["browser_action"], +}); + +chrome.contextMenus.create({ + id: "help", + title: "❓ " + chrome.i18n.getMessage("cm_help"), + contexts: ["browser_action"], }); -chrome.contextMenus.onClicked.addListener(function(info, tab) { - switch(info.menuItemId) { + +chrome.contextMenus.onClicked.addListener(function (info, tab) { + switch (info.menuItemId) { case "review": - chrome.tabs.create({url: "https://chrome.google.com/webstore/detail/dnhngfnfolbmhgealdpolmhimnoliiok/reviews"}); - break; + chrome.tabs.create({ url: "https://chrome.google.com/webstore/detail/dnhngfnfolbmhgealdpolmhimnoliiok/reviews" }); + break; case "support": - chrome.tabs.create({url: "https://chrome.google.com/webstore/detail/dnhngfnfolbmhgealdpolmhimnoliiok/support"}); - break; + chrome.tabs.create({ url: "https://chrome.google.com/webstore/detail/dnhngfnfolbmhgealdpolmhimnoliiok/support" }); + break; + case "help": + chrome.tabs.create({ url: "https://github.com/WorldLanguages/DoNotDiscard/issues" }); + break; + } +}); + +chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { + switch (request.request) { + case "getTabs": + chrome.tabs.query({}, function (tabs) { + sendResponse({ data: tabs }); + }); + break; + case "setDiscardable": + chrome.tabs.update(request.tab, { autoDiscardable: request.value }); + break; + default: + break; } + return true; }); diff --git a/manifest.json b/manifest.json index 561e59d..2f43b46 100644 --- a/manifest.json +++ b/manifest.json @@ -2,20 +2,21 @@ "manifest_version": 2, "name": "__MSG_manifest_name__", "description": "__MSG_manifest_description__", - "version": "1.0.4", + "version": "2.0.0", "background": { "scripts": ["background.js"], "persistent": false }, "browser_action": { "default_title": "__MSG_manifest_title__", - "default_icon":"icon.png" + "default_icon":"icon.png", + "default_popup": "popup/popup.html" }, "icons": { "16":"icon.png", "48":"icon.png", "128":"icon.png" }, - "permissions": ["contextMenus"], + "permissions": ["contextMenus", "tabs"], "default_locale": "en" } diff --git a/popup/check.svg b/popup/check.svg new file mode 100644 index 0000000..5e6c2db --- /dev/null +++ b/popup/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/popup/image-not-found.svg b/popup/image-not-found.svg new file mode 100644 index 0000000..aa04bd0 --- /dev/null +++ b/popup/image-not-found.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/popup/popup.css b/popup/popup.css new file mode 100644 index 0000000..96e3d0f --- /dev/null +++ b/popup/popup.css @@ -0,0 +1,153 @@ +body, +html { + height: 500px; + width: 300px; +} + +* { + user-select: none; +} + +#titlebar { + height: 40px; + width: 100%; + position: fixed; + background-color: rgba(0, 0, 0, 0.5); + top: 0; + left: 0; +} + +#titlebar > img { + height: 30px; + margin: 5px; +} + +#titlebar > p { + height: 30px; + line-height: 15px; + position: absolute; + width: -webkit-fill-available; + top: 0; + font-size: 15px; + left: 40px; + font-weight: bold; +} + +#version { + width: 100%; + text-align: center; + position: absolute; + top: 40px; + left: 0px; + line-height: 0px; + font-size: 10px; +} + +#help { + width: 100%; + text-align: center; + position: absolute; + top: 60px; + left: 0px; + line-height: 0px; + font-size: 10px; +} + +#tablist { + position: fixed; + width: 290px; + border: 1px solid black; + top: 80px; + left: 5px; + bottom: 5px; + right: 5px; + overflow: hidden; + border-radius: 4px; +} + +.tabitem:nth-child(even) { + background-color: rgba(0, 0, 0, 0.1); +} + +.tabitem { + position: absolute; + left: 0; + height: 20px; + width: 290px; + border-bottom: 1px solid rgba(0, 0, 0, 0.25); +} + +.tabitem > input { + position: absolute; + top: 0; + left: 0; + height: 15px; + width: 15px; +} + +input[type="checkbox"] { + margin: 2.5px; + border-radius: 4px; + padding: 0; + -webkit-appearance: none; + background-color: #fff; + background-size: 15px 15px; + background-position: center center; + border: 1px solid rgba(0, 0, 0, 0.5); + transition: box-shadow 0.25s ease-out; +} + +input[type="checkbox"]:checked { + background-color: #175ef8; + background-image: url(check.svg); +} + +input[type="checkbox"]:focus { + outline: none; + box-shadow: 0 0 0 2px #2670ff5d; +} + +.tabitem > img { + position: absolute; + height: 15px; + width: 15px; + margin: 2.5px; + left: 20px; +} + +.tabitem > p { + position: absolute; + top: -12px; + left: 45px; + height: 20px; + line-height: 20px; + text-overflow: ellipsis; + width: 240px; + overflow: hidden; + white-space: nowrap; +} + +#controls { + position: absolute; + top: 0; + width: 100%; + height: 30px; + background-color: rgba(0, 0, 0, 0.25); +} + +#controls > input { + height: 15px; + position: absolute; + top: 7.5px; + left: 0; + width: 15px; + margin-top: 0px; +} + +#alllabel { + height: 15px; + position: absolute; + top: 7.5px; + left: 20px; + margin-top: 0px; +} diff --git a/popup/popup.html b/popup/popup.html new file mode 100644 index 0000000..b02ebc1 --- /dev/null +++ b/popup/popup.html @@ -0,0 +1,22 @@ + + + + + + + +
+ +

+
+

+

+
+
+ + +
+
+ + + diff --git a/popup/popup.js b/popup/popup.js new file mode 100644 index 0000000..0ecf276 --- /dev/null +++ b/popup/popup.js @@ -0,0 +1,52 @@ +let tabs; +(async () => { + tabs = await new Promise(function (resolve, reject) { + try { + chrome.runtime.sendMessage({ request: "getTabs" }, function ({ data }) { + resolve(data); + }); + } catch { + reject(); + } + }); + tabs = tabs.filter(function (tab) { + return tab.url.search(/chrome:\/\/.*/) < 0; + }); + console.log(tabs); + let top = 30; + for (let tab of tabs) { + document.querySelector("#tablist").insertAdjacentHTML( + "beforeend", + `
+ + +

${tab.title}

+
` + ); + top += 20; + } + let checkboxes = Array.from(document.querySelectorAll(".tabitem > input")); + for (let checkbox of checkboxes) { + checkbox.addEventListener("change", function (e) { + chrome.runtime.sendMessage({ request: "setDiscardable", tab: Number(e.currentTarget.dataset.tab), value: !e.currentTarget.checked }, null); + document.querySelector("#all").checked = checkboxes.every(function (box) { + return box.checked; + }); + }); + } + document.querySelector("#all").checked = tabs.every(function (tab) { + return !tab.autoDiscardable; + }); + document.querySelector("#all").onclick = function () { + let checked = this.checked; + for (let box of checkboxes) { + box.checked = checked; + box.dispatchEvent(new Event("change")); + } + }; +})(); + +document.querySelector("#title").innerText = chrome.i18n.getMessage("manifest_name"); +document.querySelector("#version").innerText = chrome.i18n.getMessage("version") + " " + chrome.runtime.getManifest().version; +document.querySelector("#help").innerText = chrome.i18n.getMessage("help"); +document.querySelector("#alllabel").innerText = chrome.i18n.getMessage("select_all");