ui-batch-save-urls.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * Copyright 2010-2020 Gildas Lormeau
  3. * contact : gildas.lormeau <at> gmail.com
  4. *
  5. * This file is part of SingleFile.
  6. *
  7. * The code in this file is free software: you can redistribute it and/or
  8. * modify it under the terms of the GNU Affero General Public License
  9. * (GNU AGPL) as published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * The code in this file is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
  15. * General Public License for more details.
  16. *
  17. * As additional permission under GNU AGPL version 3 section 7, you may
  18. * distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
  19. * AGPL normally required by section 4, provided you include this license
  20. * notice and a URL through which recipients can access the Corresponding
  21. * Source.
  22. */
  23. /* global browser, window, document, location */
  24. const URLLabel = document.getElementById("URLLabel");
  25. const addUrlsLabel = document.getElementById("addUrlsLabel");
  26. const filterButton = document.getElementById("filterButton");
  27. const filterPanel = document.getElementById("filterPanel");
  28. const filterInput = document.getElementById("filterInput");
  29. const urlsTable = document.getElementById("urlsTable");
  30. const removeAllButton = document.getElementById("removeAllButton");
  31. const addUrlForm = document.getElementById("addUrlForm");
  32. const addUrlInput = document.getElementById("addUrlInput");
  33. const addUrlButton = document.getElementById("addUrlButton");
  34. const addUrlsButton = document.getElementById("addUrlsButton");
  35. const addUrlsInput = document.getElementById("addUrlsInput");
  36. const addUrlsCancelButton = document.getElementById("addUrlsCancelButton");
  37. const addUrlsOKButton = document.getElementById("addUrlsOKButton");
  38. const saveUrlsButton = document.getElementById("saveUrlsButton");
  39. document.title = browser.i18n.getMessage("batchSaveUrlsTitle");
  40. const noPendingsText = browser.i18n.getMessage("batchSaveUrlsNoURLs");
  41. addUrlButton.textContent = browser.i18n.getMessage("batchSaveUrlsAddUrlButton");
  42. addUrlsButton.textContent = browser.i18n.getMessage("batchSaveUrlsAddUrlsButton");
  43. removeAllButton.textContent = browser.i18n.getMessage("batchSaveUrlsRemoveAllButton");
  44. saveUrlsButton.textContent = browser.i18n.getMessage("batchSaveUrlsSavePagesButton");
  45. addUrlsCancelButton.textContent = browser.i18n.getMessage("pendingsAddUrlsCancelButton");
  46. addUrlsOKButton.textContent = browser.i18n.getMessage("pendingsAddUrlsOKButton");
  47. addUrlsLabel.textContent = browser.i18n.getMessage("pendingsAddUrls");
  48. URLLabel.textContent = browser.i18n.getMessage("batchSaveUrlsURLTitle");
  49. addUrlForm.onsubmit = () => {
  50. const value = addUrlInput.value.trim();
  51. if (value.length && !urls.includes(value) && (value.startsWith("http://") || value.startsWith("https://") || value.startsWith("file://"))) {
  52. urls.push(value);
  53. addUrlInput.value = "";
  54. refresh();
  55. }
  56. return false;
  57. };
  58. removeAllButton.onclick = async () => {
  59. const displayedUrls = getDisplayedUrls();
  60. urls = urls.filter(url => !displayedUrls.includes(url));
  61. await refresh();
  62. };
  63. addUrlsButton.onclick = displayAddUrlsPopup;
  64. if (location.href.endsWith("#side-panel")) {
  65. document.documentElement.classList.add("side-panel");
  66. }
  67. saveUrlsButton.onclick = async () => {
  68. const displayedUrls = getDisplayedUrls();
  69. if (displayedUrls.length) {
  70. await browser.runtime.sendMessage({ method: "downloads.saveUrls", urls: displayedUrls });
  71. urls = urls.filter(url => !displayedUrls.includes(url));
  72. refresh();
  73. }
  74. };
  75. let previousState;
  76. let urls = [];
  77. filterButton.onclick = () => {
  78. filterPanel.hidden = !filterPanel.hidden;
  79. if (!filterPanel.hidden) {
  80. filterButton.classList.add("filter-displayed");
  81. filterInput.focus();
  82. } else {
  83. filterButton.classList.remove("filter-displayed");
  84. }
  85. refresh(true);
  86. };
  87. filterButton.onkeyup = event => {
  88. if (event.key == "Enter") {
  89. filterButton.onclick();
  90. }
  91. };
  92. filterInput.oninput = () => {
  93. refresh();
  94. };
  95. filterInput.onkeyup = event => {
  96. if (event.key == "Escape") {
  97. filterPanel.hidden = true;
  98. filterButton.classList.remove("filter-displayed");
  99. filterButton.focus();
  100. refresh(true);
  101. }
  102. };
  103. browser.runtime.onMessage.addListener(message => {
  104. if (message.method == "newUrls.addURLs") {
  105. urls = message.urls;
  106. refresh();
  107. }
  108. });
  109. refresh();
  110. function resetTable() {
  111. urlsTable.innerHTML = "";
  112. }
  113. function updateTable(urls) {
  114. if (urls.length) {
  115. urls.forEach((url, indexUrl) => {
  116. const row = document.createElement("div");
  117. const cellURL = document.createElement("span");
  118. const cellCancel = document.createElement("span");
  119. const buttonCancel = document.createElement("button");
  120. row.className = "urls-row";
  121. cellURL.textContent = url;
  122. cellURL.className = "result-url-title";
  123. buttonCancel.textContent = "×";
  124. buttonCancel.onclick = () => cancel(indexUrl);
  125. cellCancel.appendChild(buttonCancel);
  126. cellCancel.className = "result-cancel";
  127. row.appendChild(cellURL);
  128. row.appendChild(cellCancel);
  129. urlsTable.appendChild(row);
  130. });
  131. }
  132. }
  133. async function cancel(index) {
  134. urls.splice(index, 1);
  135. await refresh();
  136. }
  137. async function displayAddUrlsPopup() {
  138. document.getElementById("formAddUrls").style.setProperty("display", "flex");
  139. document.querySelector("#formAddUrls .popup-content").style.setProperty("align-self", "center");
  140. addUrlsInput.value = "";
  141. addUrlsInput.focus();
  142. document.body.style.setProperty("overflow-y", "hidden");
  143. const newUrls = await new Promise(resolve => {
  144. addUrlsOKButton.onclick = event => hideAndResolve(event, addUrlsInput.value);
  145. addUrlsCancelButton.onclick = event => hideAndResolve(event);
  146. window.onkeyup = event => {
  147. if (event.key == "Escape") {
  148. hideAndResolve(event);
  149. }
  150. };
  151. function hideAndResolve(event, value = "") {
  152. event.preventDefault();
  153. document.getElementById("formAddUrls").style.setProperty("display", "none");
  154. document.body.style.setProperty("overflow-y", "");
  155. resolve(value.split("\n").map(url => url.trim()).filter(url => url));
  156. }
  157. });
  158. urls = Array.from(new Set(urls.concat(newUrls)));
  159. refresh();
  160. }
  161. async function refresh(force) {
  162. const displayedUrls = getDisplayedUrls();
  163. const currentState = JSON.stringify(displayedUrls);
  164. if (previousState != currentState || force) {
  165. previousState = currentState;
  166. resetTable();
  167. updateTable(displayedUrls);
  168. if (!displayedUrls.length) {
  169. const row = document.createElement("div");
  170. row.className = "urls-row";
  171. const cell = document.createElement("span");
  172. cell.className = "no-result";
  173. if (filterPanel.hidden) {
  174. cell.textContent = noPendingsText;
  175. }
  176. row.appendChild(cell);
  177. urlsTable.appendChild(row);
  178. }
  179. }
  180. }
  181. function getDisplayedUrls() {
  182. let displayedUrls = urls;
  183. if (!filterPanel.hidden) {
  184. displayedUrls = urls.filter(url => url.includes(filterInput.value));
  185. }
  186. return displayedUrls;
  187. }