ui-editor.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  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, singlefile, window, document, prompt */
  24. singlefile.extension.ui.bg.editor = (() => {
  25. const editorElement = document.querySelector(".editor");
  26. const highlightYellowButton = document.querySelector(".highlight-yellow-button");
  27. const highlightPinkButton = document.querySelector(".highlight-pink-button");
  28. const highlightBlueButton = document.querySelector(".highlight-blue-button");
  29. const highlightGreenButton = document.querySelector(".highlight-green-button");
  30. const highlightButtons = Array.from(document.querySelectorAll(".highlight-button"));
  31. const toggleNotesButton = document.querySelector(".toggle-notes-button");
  32. const toggleHighlightsButton = document.querySelector(".toggle-highlights-button");
  33. const removeHighlightButton = document.querySelector(".remove-highlight-button");
  34. const addYellowNoteButton = document.querySelector(".add-note-yellow-button");
  35. const addPinkNoteButton = document.querySelector(".add-note-pink-button");
  36. const addBlueNoteButton = document.querySelector(".add-note-blue-button");
  37. const addGreenNoteButton = document.querySelector(".add-note-green-button");
  38. const editPageButton = document.querySelector(".edit-page-button");
  39. const formatPageButton = document.querySelector(".format-page-button");
  40. const cutPageButton = document.querySelector(".cut-page-button");
  41. const undoCutPageButton = document.querySelector(".undo-cut-page-button");
  42. const undoAllCutPageButton = document.querySelector(".undo-all-cut-page-button");
  43. const savePageButton = document.querySelector(".save-page-button");
  44. let tabData, tabDataContents = [];
  45. addYellowNoteButton.title = browser.i18n.getMessage("editorAddYellowNote");
  46. addPinkNoteButton.title = browser.i18n.getMessage("editorAddPinkNote");
  47. addBlueNoteButton.title = browser.i18n.getMessage("editorAddBlueNote");
  48. addGreenNoteButton.title = browser.i18n.getMessage("editorAddGreenNote");
  49. highlightYellowButton.title = browser.i18n.getMessage("editorHighlightYellow");
  50. highlightPinkButton.title = browser.i18n.getMessage("editorHighlightPink");
  51. highlightBlueButton.title = browser.i18n.getMessage("editorHighlightBlue");
  52. highlightGreenButton.title = browser.i18n.getMessage("editorHighlightGreen");
  53. toggleNotesButton.title = browser.i18n.getMessage("editorToggleNotes");
  54. toggleHighlightsButton.title = browser.i18n.getMessage("editorToggleHighlights");
  55. removeHighlightButton.title = browser.i18n.getMessage("editorRemoveHighlight");
  56. editPageButton.title = browser.i18n.getMessage("editorEditPage");
  57. formatPageButton.title = browser.i18n.getMessage("editorFormatPage");
  58. cutPageButton.title = browser.i18n.getMessage("editorCutPage");
  59. undoCutPageButton.title = browser.i18n.getMessage("editorUndoCutPage");
  60. undoAllCutPageButton.title = browser.i18n.getMessage("editorUndoAllCutPage");
  61. savePageButton.title = browser.i18n.getMessage("editorSavePage");
  62. addYellowNoteButton.onclick = () => editorElement.contentWindow.postMessage(JSON.stringify({ method: "addNote", color: "note-yellow" }), "*");
  63. addPinkNoteButton.onclick = () => editorElement.contentWindow.postMessage(JSON.stringify({ method: "addNote", color: "note-pink" }), "*");
  64. addBlueNoteButton.onclick = () => editorElement.contentWindow.postMessage(JSON.stringify({ method: "addNote", color: "note-blue" }), "*");
  65. addGreenNoteButton.onclick = () => editorElement.contentWindow.postMessage(JSON.stringify({ method: "addNote", color: "note-green" }), "*");
  66. highlightYellowButton.onclick = () => {
  67. if (highlightYellowButton.classList.contains("highlight-disabled")) {
  68. highlightButtons.forEach(highlightButton => highlightButton.classList.add("highlight-disabled"));
  69. highlightYellowButton.classList.remove("highlight-disabled");
  70. editorElement.contentWindow.postMessage(JSON.stringify({ method: "enableHighlight", color: "single-file-highlight-yellow" }), "*");
  71. } else {
  72. highlightYellowButton.classList.add("highlight-disabled");
  73. editorElement.contentWindow.postMessage(JSON.stringify({ method: "disableHighlight" }), "*");
  74. }
  75. };
  76. highlightPinkButton.onclick = () => {
  77. if (highlightPinkButton.classList.contains("highlight-disabled")) {
  78. highlightButtons.forEach(highlightButton => highlightButton.classList.add("highlight-disabled"));
  79. highlightPinkButton.classList.remove("highlight-disabled");
  80. editorElement.contentWindow.postMessage(JSON.stringify({ method: "enableHighlight", color: "single-file-highlight-pink" }), "*");
  81. } else {
  82. highlightPinkButton.classList.add("highlight-disabled");
  83. editorElement.contentWindow.postMessage(JSON.stringify({ method: "disableHighlight" }), "*");
  84. }
  85. };
  86. highlightBlueButton.onclick = () => {
  87. if (highlightBlueButton.classList.contains("highlight-disabled")) {
  88. highlightButtons.forEach(highlightButton => highlightButton.classList.add("highlight-disabled"));
  89. highlightBlueButton.classList.remove("highlight-disabled");
  90. editorElement.contentWindow.postMessage(JSON.stringify({ method: "enableHighlight", color: "single-file-highlight-blue" }), "*");
  91. } else {
  92. highlightBlueButton.classList.add("highlight-disabled");
  93. editorElement.contentWindow.postMessage(JSON.stringify({ method: "disableHighlight" }), "*");
  94. }
  95. };
  96. highlightGreenButton.onclick = () => {
  97. if (highlightGreenButton.classList.contains("highlight-disabled")) {
  98. highlightButtons.forEach(highlightButton => highlightButton.classList.add("highlight-disabled"));
  99. highlightGreenButton.classList.remove("highlight-disabled");
  100. editorElement.contentWindow.postMessage(JSON.stringify({ method: "enableHighlight", color: "single-file-highlight-green" }), "*");
  101. } else {
  102. highlightGreenButton.classList.add("highlight-disabled");
  103. editorElement.contentWindow.postMessage(JSON.stringify({ method: "disableHighlight" }), "*");
  104. }
  105. };
  106. toggleNotesButton.onclick = () => {
  107. if (toggleNotesButton.getAttribute("src") == "/extension/ui/resources/button_note_visible.png") {
  108. toggleNotesButton.src = "/extension/ui/resources/button_note_hidden.png";
  109. editorElement.contentWindow.postMessage(JSON.stringify({ method: "hideNotes" }), "*");
  110. } else {
  111. toggleNotesButton.src = "/extension/ui/resources/button_note_visible.png";
  112. editorElement.contentWindow.postMessage(JSON.stringify({ method: "displayNotes" }), "*");
  113. }
  114. };
  115. toggleHighlightsButton.onclick = () => {
  116. if (toggleHighlightsButton.getAttribute("src") == "/extension/ui/resources/button_highlighter_visible.png") {
  117. toggleHighlightsButton.src = "/extension/ui/resources/button_highlighter_hidden.png";
  118. editorElement.contentWindow.postMessage(JSON.stringify({ method: "hideHighlights" }), "*");
  119. } else {
  120. toggleHighlightsButton.src = "/extension/ui/resources/button_highlighter_visible.png";
  121. editorElement.contentWindow.postMessage(JSON.stringify({ method: "displayHighlights" }), "*");
  122. }
  123. };
  124. removeHighlightButton.onclick = () => {
  125. if (removeHighlightButton.classList.contains("remove-highlight-disabled")) {
  126. removeHighlightButton.classList.remove("remove-highlight-disabled");
  127. editorElement.contentWindow.postMessage(JSON.stringify({ method: "enableRemoveHighlights" }), "*");
  128. } else {
  129. removeHighlightButton.classList.add("remove-highlight-disabled");
  130. editorElement.contentWindow.postMessage(JSON.stringify({ method: "disableRemoveHighlights" }), "*");
  131. }
  132. };
  133. editPageButton.onclick = () => {
  134. if (editPageButton.classList.contains("edit-disabled")) {
  135. editPageButton.classList.remove("edit-disabled");
  136. editorElement.contentWindow.postMessage(JSON.stringify({ method: "enableEditPage" }), "*");
  137. } else {
  138. editPageButton.classList.add("edit-disabled");
  139. editorElement.contentWindow.postMessage(JSON.stringify({ method: "disableEditPage" }), "*");
  140. }
  141. };
  142. formatPageButton.onclick = () => {
  143. if (formatPageButton.classList.contains("format-disabled")) {
  144. formatPageButton.classList.remove("format-disabled");
  145. updatedResources = {};
  146. editorElement.contentWindow.postMessage(JSON.stringify({ method: tabData.options.applySystemTheme ? "formatPage" : "formatPageNoTheme" }), "*");
  147. }
  148. };
  149. cutPageButton.onclick = () => {
  150. if (cutPageButton.classList.contains("cut-disabled")) {
  151. cutPageButton.classList.remove("cut-disabled");
  152. editorElement.contentWindow.postMessage(JSON.stringify({ method: "enableCutPage" }), "*");
  153. } else {
  154. cutPageButton.classList.add("cut-disabled");
  155. editorElement.contentWindow.postMessage(JSON.stringify({ method: "disableCutPage" }), "*");
  156. }
  157. };
  158. undoCutPageButton.onclick = () => {
  159. editorElement.contentWindow.postMessage(JSON.stringify({ method: "undoCutPage" }), "*");
  160. };
  161. undoAllCutPageButton.onclick = () => {
  162. editorElement.contentWindow.postMessage(JSON.stringify({ method: "undoAllCutPage" }), "*");
  163. };
  164. savePageButton.onclick = () => {
  165. savePage();
  166. };
  167. let updatedResources = {};
  168. window.onmessage = event => {
  169. const message = JSON.parse(event.data);
  170. if (message.method == "setMetadata") {
  171. document.title = "[SingleFile] " + message.title;
  172. if (message.icon) {
  173. const linkElement = document.createElement("link");
  174. linkElement.rel = "icon";
  175. linkElement.href = message.icon;
  176. document.head.appendChild(linkElement);
  177. }
  178. }
  179. if (message.method == "setContent") {
  180. const pageData = {
  181. content: message.content,
  182. filename: tabData.filename
  183. };
  184. tabData.options.openEditor = false;
  185. singlefile.extension.core.content.download.downloadPage(pageData, tabData.options);
  186. }
  187. if (message.method == "disableFormatPage") {
  188. formatPageButton.remove();
  189. }
  190. if (message.method == "onUpdate") {
  191. tabData.docSaved = message.saved;
  192. }
  193. };
  194. window.onload = () => {
  195. browser.runtime.sendMessage({ method: "editor.getTabData" });
  196. browser.runtime.onMessage.addListener(message => {
  197. if (message.method == "devtools.resourceCommitted") {
  198. updatedResources[message.url] = { content: message.content, type: message.type, encoding: message.encoding };
  199. return Promise.resolve({});
  200. }
  201. if (message.method == "content.save") {
  202. tabData.options = message.options;
  203. savePage();
  204. browser.runtime.sendMessage({ method: "ui.processInit" });
  205. return Promise.resolve({});
  206. }
  207. if (message.method == "common.promptValueRequest") {
  208. browser.runtime.sendMessage({ method: "tabs.promptValueResponse", value: prompt(message.promptMessage) });
  209. return Promise.resolve({});
  210. }
  211. if (message.method == "editor.setTabData") {
  212. if (message.truncated) {
  213. tabDataContents.push(message.content);
  214. } else {
  215. tabDataContents = [message.content];
  216. }
  217. if (!message.truncated || message.finished) {
  218. tabData = JSON.parse(tabDataContents.join(""));
  219. tabData.docSaved = true;
  220. tabDataContents = [];
  221. editorElement.contentWindow.postMessage(JSON.stringify({ method: "init", content: tabData.content }), "*");
  222. delete tabData.content;
  223. }
  224. return Promise.resolve({});
  225. }
  226. });
  227. };
  228. window.onbeforeunload = event => {
  229. if (tabData.options.warnUnsavedPage && !tabData.docSaved) {
  230. event.preventDefault();
  231. event.returnValue = "";
  232. }
  233. };
  234. function savePage() {
  235. editorElement.contentWindow.postMessage(JSON.stringify({ method: "getContent", compressHTML: tabData.options.compressHTML, updatedResources }), "*");
  236. }
  237. return {};
  238. })();