ui-options.js 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349
  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, localStorage, FileReader, location, fetch, TextDecoder, DOMParser, HTMLElement, MouseEvent */
  24. const HELP_ICON_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABIUlEQVQ4y+2TsarCMBSGvxTBRdqiUZAWOrhJB9EXcPKFfCvfQYfulUKHDqXg4CYUJSioYO4mSDX3ttzt3n87fMlHTpIjlsulxpDZbEYYhgghSNOUOI5Ny2mZYBAELBYLer0eAJ7ncTweKYri4x7LJJRS0u12n7XrukgpjSc0CpVSXK/XZ32/31FKNW85z3PW6zXT6RSAJEnIsqy5UGvNZrNhu90CcDqd+C6tT6J+v//2Th+PB2VZ1hN2Oh3G4zGTyQTbtl/YbrdjtVpxu91+Ljyfz0RRhG3bzOfzF+Y4TvNXvlwuaK2pE4tfzr/wzwsty0IIURlL0998KxRCMBqN8H2/wlzXJQxD2u12vVkeDoeUZUkURRU+GAw4HA7s9/sK+wK6CWHasQ/S/wAAAABJRU5ErkJggg==";
  25. const HELP_PAGE_PATH = "/src/ui/pages/help.html";
  26. let DEFAULT_PROFILE_NAME,
  27. DISABLED_PROFILE_NAME,
  28. CURRENT_PROFILE_NAME,
  29. BACKGROUND_SAVE_SUPPORTED,
  30. AUTO_SAVE_SUPPORTED,
  31. OPEN_SAVED_PAGE_SUPPORTED,
  32. AUTO_OPEN_EDITOR_SUPPORTED,
  33. INFOBAR_SUPPORTED,
  34. BOOKMARKS_API_SUPPORTED,
  35. IDENTITY_API_SUPPORTED,
  36. CLIPBOARD_API_SUPPORTED,
  37. NATIVE_API_API_SUPPORTED,
  38. WEB_BLOCKING_API_SUPPORTED;
  39. browser.runtime.sendMessage({ method: "config.getConstants" }).then(data => {
  40. ({
  41. DEFAULT_PROFILE_NAME,
  42. DISABLED_PROFILE_NAME,
  43. CURRENT_PROFILE_NAME,
  44. BACKGROUND_SAVE_SUPPORTED,
  45. AUTO_SAVE_SUPPORTED,
  46. OPEN_SAVED_PAGE_SUPPORTED,
  47. AUTO_OPEN_EDITOR_SUPPORTED,
  48. INFOBAR_SUPPORTED,
  49. BOOKMARKS_API_SUPPORTED,
  50. IDENTITY_API_SUPPORTED,
  51. CLIPBOARD_API_SUPPORTED,
  52. NATIVE_API_API_SUPPORTED,
  53. WEB_BLOCKING_API_SUPPORTED
  54. } = data);
  55. init();
  56. });
  57. const removeHiddenElementsLabel = document.getElementById("removeHiddenElementsLabel");
  58. const removeUnusedStylesLabel = document.getElementById("removeUnusedStylesLabel");
  59. const removeUnusedFontsLabel = document.getElementById("removeUnusedFontsLabel");
  60. const removeFramesLabel = document.getElementById("removeFramesLabel");
  61. const blockScriptsLabel = document.getElementById("blockScriptsLabel");
  62. const blockAudiosLabel = document.getElementById("blockAudiosLabel");
  63. const blockVideosLabel = document.getElementById("blockVideosLabel");
  64. const blockFontsLabel = document.getElementById("blockFontsLabel");
  65. const blockStylesheetsLabel = document.getElementById("blockStylesheetsLabel");
  66. const blockImagesLabel = document.getElementById("blockImagesLabel");
  67. const acceptHeaderDocumentLabel = document.getElementById("acceptHeaderDocumentLabel");
  68. const acceptHeaderScriptLabel = document.getElementById("acceptHeaderScriptLabel");
  69. const acceptHeaderAudioLabel = document.getElementById("acceptHeaderAudioLabel");
  70. const acceptHeaderVideoLabel = document.getElementById("acceptHeaderVideoLabel");
  71. const acceptHeaderFontLabel = document.getElementById("acceptHeaderFontLabel");
  72. const acceptHeaderStylesheetLabel = document.getElementById("acceptHeaderStylesheetLabel");
  73. const acceptHeaderImageLabel = document.getElementById("acceptHeaderImageLabel");
  74. const saveRawPageLabel = document.getElementById("saveRawPageLabel");
  75. const insertMetaCSPLabel = document.getElementById("insertMetaCSPLabel");
  76. const saveToClipboardLabel = document.getElementById("saveToClipboardLabel");
  77. const saveToFilesystemLabel = document.getElementById("saveToFilesystemLabel");
  78. const addProofLabel = document.getElementById("addProofLabel");
  79. const woleetKeyLabel = document.getElementById("woleetKeyLabel");
  80. const saveToGDriveLabel = document.getElementById("saveToGDriveLabel");
  81. const saveWithWebDAVLabel = document.getElementById("saveWithWebDAVLabel");
  82. const webDAVURLLabel = document.getElementById("webDAVURLLabel");
  83. const webDAVUserLabel = document.getElementById("webDAVUserLabel");
  84. const webDAVPasswordLabel = document.getElementById("webDAVPasswordLabel");
  85. const saveToGitHubLabel = document.getElementById("saveToGitHubLabel");
  86. const githubTokenLabel = document.getElementById("githubTokenLabel");
  87. const githubUserLabel = document.getElementById("githubUserLabel");
  88. const githubRepositoryLabel = document.getElementById("githubRepositoryLabel");
  89. const githubBranchLabel = document.getElementById("githubBranchLabel");
  90. const saveWithCompanionLabel = document.getElementById("saveWithCompanionLabel");
  91. const compressHTMLLabel = document.getElementById("compressHTMLLabel");
  92. const compressCSSLabel = document.getElementById("compressCSSLabel");
  93. const moveStylesInHeadLabel = document.getElementById("moveStylesInHeadLabel");
  94. const loadDeferredImagesLabel = document.getElementById("loadDeferredImagesLabel");
  95. const loadDeferredImagesMaxIdleTimeLabel = document.getElementById("loadDeferredImagesMaxIdleTimeLabel");
  96. const loadDeferredImagesKeepZoomLevelLabel = document.getElementById("loadDeferredImagesKeepZoomLevelLabel");
  97. const loadDeferredImagesDispatchScrollEventLabel = document.getElementById("loadDeferredImagesDispatchScrollEventLabel");
  98. const addMenuEntryLabel = document.getElementById("addMenuEntryLabel");
  99. const filenameTemplateLabel = document.getElementById("filenameTemplateLabel");
  100. const filenameMaxLengthLabel = document.getElementById("filenameMaxLengthLabel");
  101. const filenameMaxLengthBytesUnitLabel = document.getElementById("filenameMaxLengthBytesUnitLabel");
  102. const filenameMaxLengthCharsUnitLabel = document.getElementById("filenameMaxLengthCharsUnitLabel");
  103. const replaceEmojisInFilenameLabel = document.getElementById("replaceEmojisInFilenameLabel");
  104. const shadowEnabledLabel = document.getElementById("shadowEnabledLabel");
  105. const setMaxResourceSizeLabel = document.getElementById("setMaxResourceSizeLabel");
  106. const maxResourceSizeLabel = document.getElementById("maxResourceSizeLabel");
  107. const setMaxResourceDelayLabel = document.getElementById("setMaxResourceDelayLabel");
  108. const maxResourceDelayLabel = document.getElementById("maxResourceDelayLabel");
  109. const confirmFilenameLabel = document.getElementById("confirmFilenameLabel");
  110. const filenameConflictActionLabel = document.getElementById("filenameConflictActionLabel");
  111. const filenameConflictActionUniquifyLabel = document.getElementById("filenameConflictActionUniquifyLabel");
  112. const filenameConflictActionOverwriteLabel = document.getElementById("filenameConflictActionOverwriteLabel");
  113. const filenameConflictActionPromptLabel = document.getElementById("filenameConflictActionPromptLabel");
  114. const filenameConflictActionSkipLabel = document.getElementById("filenameConflictActionSkipLabel");
  115. const displayInfobarLabel = document.getElementById("displayInfobarLabel");
  116. const displayStatsLabel = document.getElementById("displayStatsLabel");
  117. const backgroundSaveLabel = document.getElementById("backgroundSaveLabel");
  118. const autoSaveDelayLabel = document.getElementById("autoSaveDelayLabel");
  119. const autoSaveLoadLabel = document.getElementById("autoSaveLoadLabel");
  120. const autoSaveUnloadLabel = document.getElementById("autoSaveUnloadLabel");
  121. const autoSaveLoadOrUnloadLabel = document.getElementById("autoSaveLoadOrUnloadLabel");
  122. const autoSaveDiscardLabel = document.getElementById("autoSaveDiscardLabel");
  123. const autoSaveRemoveLabel = document.getElementById("autoSaveRemoveLabel");
  124. const autoSaveRepeatLabel = document.getElementById("autoSaveRepeatLabel");
  125. const autoSaveRepeatDelayLabel = document.getElementById("autoSaveRepeatDelayLabel");
  126. const autoSaveExternalSaveLabel = document.getElementById("autoSaveExternalSaveLabel");
  127. const removeAlternativeFontsLabel = document.getElementById("removeAlternativeFontsLabel");
  128. const removeAlternativeImagesLabel = document.getElementById("removeAlternativeImagesLabel");
  129. const removeAlternativeMediasLabel = document.getElementById("removeAlternativeMediasLabel");
  130. const saveCreatedBookmarksLabel = document.getElementById("saveCreatedBookmarksLabel");
  131. const passReferrerOnErrorLabel = document.getElementById("passReferrerOnErrorLabel");
  132. const replaceBookmarkURLLabel = document.getElementById("replaceBookmarkURLLabel");
  133. const allowedBookmarkFoldersLabel = document.getElementById("allowedBookmarkFoldersLabel");
  134. const ignoredBookmarkFoldersLabel = document.getElementById("ignoredBookmarkFoldersLabel");
  135. const titleLabel = document.getElementById("titleLabel");
  136. const userInterfaceLabel = document.getElementById("userInterfaceLabel");
  137. const filenameLabel = document.getElementById("filenameLabel");
  138. const htmlContentLabel = document.getElementById("htmlContentLabel");
  139. const imagesLabel = document.getElementById("imagesLabel");
  140. const infobarLabel = document.getElementById("infobarLabel");
  141. const stylesheetsLabel = document.getElementById("stylesheetsLabel");
  142. const fontsLabel = document.getElementById("fontsLabel");
  143. const networkLabel = document.getElementById("networkLabel");
  144. const blockResourcesLabel = document.getElementById("blockResourcesLabel");
  145. const acceptHeadersLabel = document.getElementById("acceptHeadersLabel");
  146. const destinationLabel = document.getElementById("destinationLabel");
  147. const bookmarksLabel = document.getElementById("bookmarksLabel");
  148. const autoSaveLabel = document.getElementById("autoSaveLabel");
  149. const autoSettingsLabel = document.getElementById("autoSettingsLabel");
  150. const autoSettingsUrlLabel = document.getElementById("autoSettingsUrlLabel");
  151. const autoSettingsProfileLabel = document.getElementById("autoSettingsProfileLabel");
  152. const autoSettingsAutoSaveProfileLabel = document.getElementById("autoSettingsAutoSaveProfileLabel");
  153. const showAllProfilesLabel = document.getElementById("showAllProfilesLabel");
  154. const showAutoSaveProfileLabel = document.getElementById("showAutoSaveProfileLabel");
  155. const groupDuplicateImagesLabel = document.getElementById("groupDuplicateImagesLabel");
  156. const confirmInfobarLabel = document.getElementById("confirmInfobarLabel");
  157. const autoCloseLabel = document.getElementById("autoCloseLabel");
  158. const editorLabel = document.getElementById("editorLabel");
  159. const openEditorLabel = document.getElementById("openEditorLabel");
  160. const openSavedPageLabel = document.getElementById("openSavedPageLabel");
  161. const autoOpenEditorLabel = document.getElementById("autoOpenEditorLabel");
  162. const defaultEditorModeLabel = document.getElementById("defaultEditorModeLabel");
  163. const applySystemThemeLabel = document.getElementById("applySystemThemeLabel");
  164. const warnUnsavedPageLabel = document.getElementById("warnUnsavedPageLabel");
  165. const infobarTemplateLabel = document.getElementById("infobarTemplateLabel");
  166. const blockMixedContentLabel = document.getElementById("blockMixedContentLabel");
  167. const saveOriginalURLsLabel = document.getElementById("saveOriginalURLsLabel");
  168. const includeInfobarLabel = document.getElementById("includeInfobarLabel");
  169. const removeInfobarSavedDateLabel = document.getElementById("removeInfobarSavedDateLabel");
  170. const miscLabel = document.getElementById("miscLabel");
  171. const helpLabel = document.getElementById("helpLabel");
  172. const synchronizeLabel = document.getElementById("synchronizeLabel");
  173. const addProfileButton = document.getElementById("addProfileButton");
  174. const deleteProfileButton = document.getElementById("deleteProfileButton");
  175. const renameProfileButton = document.getElementById("renameProfileButton");
  176. const resetButton = document.getElementById("resetButton");
  177. const exportButton = document.getElementById("exportButton");
  178. const importButton = document.getElementById("importButton");
  179. const fileInput = document.getElementById("fileInput");
  180. const profileNamesInput = document.getElementById("profileNamesInput");
  181. const removeHiddenElementsInput = document.getElementById("removeHiddenElementsInput");
  182. const removeUnusedStylesInput = document.getElementById("removeUnusedStylesInput");
  183. const removeUnusedFontsInput = document.getElementById("removeUnusedFontsInput");
  184. const removeFramesInput = document.getElementById("removeFramesInput");
  185. const blockScriptsInput = document.getElementById("blockScriptsInput");
  186. const blockVideosInput = document.getElementById("blockVideosInput");
  187. const blockAudiosInput = document.getElementById("blockAudiosInput");
  188. const blockFontsInput = document.getElementById("blockFontsInput");
  189. const blockStylesheetsInput = document.getElementById("blockStylesheetsInput");
  190. const blockImagesInput = document.getElementById("blockImagesInput");
  191. const acceptHeaderDocumentInput = document.getElementById("acceptHeaderDocumentInput");
  192. const acceptHeaderScriptInput = document.getElementById("acceptHeaderScriptInput");
  193. const acceptHeaderAudioInput = document.getElementById("acceptHeaderAudioInput");
  194. const acceptHeaderVideoInput = document.getElementById("acceptHeaderVideoInput");
  195. const acceptHeaderFontInput = document.getElementById("acceptHeaderFontInput");
  196. const acceptHeaderStylesheetInput = document.getElementById("acceptHeaderStylesheetInput");
  197. const acceptHeaderImageInput = document.getElementById("acceptHeaderImageInput");
  198. const saveRawPageInput = document.getElementById("saveRawPageInput");
  199. const insertMetaCSPInput = document.getElementById("insertMetaCSPInput");
  200. const saveToClipboardInput = document.getElementById("saveToClipboardInput");
  201. const addProofInput = document.getElementById("addProofInput");
  202. const woleetKeyInput = document.getElementById("woleetKeyInput");
  203. const saveToGDriveInput = document.getElementById("saveToGDriveInput");
  204. const saveWithWebDAVInput = document.getElementById("saveWithWebDAVInput");
  205. const webDAVURLInput = document.getElementById("webDAVURLInput");
  206. const webDAVUserInput = document.getElementById("webDAVUserInput");
  207. const webDAVPasswordInput = document.getElementById("webDAVPasswordInput");
  208. const saveToGitHubInput = document.getElementById("saveToGitHubInput");
  209. const githubTokenInput = document.getElementById("githubTokenInput");
  210. const githubUserInput = document.getElementById("githubUserInput");
  211. const githubRepositoryInput = document.getElementById("githubRepositoryInput");
  212. const githubBranchInput = document.getElementById("githubBranchInput");
  213. const saveWithCompanionInput = document.getElementById("saveWithCompanionInput");
  214. const saveToFilesystemInput = document.getElementById("saveToFilesystemInput");
  215. const compressHTMLInput = document.getElementById("compressHTMLInput");
  216. const compressCSSInput = document.getElementById("compressCSSInput");
  217. const moveStylesInHeadInput = document.getElementById("moveStylesInHeadInput");
  218. const loadDeferredImagesInput = document.getElementById("loadDeferredImagesInput");
  219. const loadDeferredImagesMaxIdleTimeInput = document.getElementById("loadDeferredImagesMaxIdleTimeInput");
  220. const loadDeferredImagesKeepZoomLevelInput = document.getElementById("loadDeferredImagesKeepZoomLevelInput");
  221. const loadDeferredImagesDispatchScrollEventInput = document.getElementById("loadDeferredImagesDispatchScrollEventInput");
  222. const contextMenuEnabledInput = document.getElementById("contextMenuEnabledInput");
  223. const filenameTemplateInput = document.getElementById("filenameTemplateInput");
  224. const filenameMaxLengthInput = document.getElementById("filenameMaxLengthInput");
  225. const filenameMaxLengthUnitInput = document.getElementById("filenameMaxLengthUnitInput");
  226. const replaceEmojisInFilenameInput = document.getElementById("replaceEmojisInFilenameInput");
  227. const shadowEnabledInput = document.getElementById("shadowEnabledInput");
  228. const maxResourceSizeInput = document.getElementById("maxResourceSizeInput");
  229. const maxResourceSizeEnabledInput = document.getElementById("maxResourceSizeEnabledInput");
  230. const maxResourceDelayInput = document.getElementById("maxResourceDelayInput");
  231. const maxResourceDelayEnabledInput = document.getElementById("maxResourceDelayEnabledInput");
  232. const confirmFilenameInput = document.getElementById("confirmFilenameInput");
  233. const filenameConflictActionInput = document.getElementById("filenameConflictActionInput");
  234. const displayInfobarInput = document.getElementById("displayInfobarInput");
  235. const displayStatsInput = document.getElementById("displayStatsInput");
  236. const backgroundSaveInput = document.getElementById("backgroundSaveInput");
  237. const autoSaveDelayInput = document.getElementById("autoSaveDelayInput");
  238. const autoSaveLoadInput = document.getElementById("autoSaveLoadInput");
  239. const autoSaveUnloadInput = document.getElementById("autoSaveUnloadInput");
  240. const autoSaveDiscardInput = document.getElementById("autoSaveDiscardInput");
  241. const autoSaveRemoveInput = document.getElementById("autoSaveRemoveInput");
  242. const autoSaveLoadOrUnloadInput = document.getElementById("autoSaveLoadOrUnloadInput");
  243. const autoSaveRepeatInput = document.getElementById("autoSaveRepeatInput");
  244. const autoSaveRepeatDelayInput = document.getElementById("autoSaveRepeatDelayInput");
  245. const autoSaveExternalSaveInput = document.getElementById("autoSaveExternalSaveInput");
  246. const removeAlternativeFontsInput = document.getElementById("removeAlternativeFontsInput");
  247. const removeAlternativeImagesInput = document.getElementById("removeAlternativeImagesInput");
  248. const removeAlternativeMediasInput = document.getElementById("removeAlternativeMediasInput");
  249. const saveCreatedBookmarksInput = document.getElementById("saveCreatedBookmarksInput");
  250. const passReferrerOnErrorInput = document.getElementById("passReferrerOnErrorInput");
  251. const replaceBookmarkURLInput = document.getElementById("replaceBookmarkURLInput");
  252. const allowedBookmarkFoldersInput = document.getElementById("allowedBookmarkFoldersInput");
  253. const ignoredBookmarkFoldersInput = document.getElementById("ignoredBookmarkFoldersInput");
  254. const groupDuplicateImagesInput = document.getElementById("groupDuplicateImagesInput");
  255. const infobarTemplateInput = document.getElementById("infobarTemplateInput");
  256. const blockMixedContentInput = document.getElementById("blockMixedContentInput");
  257. const saveOriginalURLsInput = document.getElementById("saveOriginalURLsInput");
  258. const includeInfobarInput = document.getElementById("includeInfobarInput");
  259. const removeInfobarSavedDateInput = document.getElementById("removeInfobarSavedDateInput");
  260. const confirmInfobarInput = document.getElementById("confirmInfobarInput");
  261. const autoCloseInput = document.getElementById("autoCloseInput");
  262. const openEditorInput = document.getElementById("openEditorInput");
  263. const openSavedPageInput = document.getElementById("openSavedPageInput");
  264. const autoOpenEditorInput = document.getElementById("autoOpenEditorInput");
  265. const defaultEditorModeInput = document.getElementById("defaultEditorModeInput");
  266. const defaultEditorModeNormalLabel = document.getElementById("defaultEditorModeNormalLabel");
  267. const defaultEditorModeEditLabel = document.getElementById("defaultEditorModeEditLabel");
  268. const defaultEditorModeFormatLabel = document.getElementById("defaultEditorModeFormatLabel");
  269. const defaultEditorModeCutLabel = document.getElementById("defaultEditorModeCutLabel");
  270. const defaultEditorModeCutExternalLabel = document.getElementById("defaultEditorModeCutExternalLabel");
  271. const applySystemThemeInput = document.getElementById("applySystemThemeInput");
  272. const warnUnsavedPageInput = document.getElementById("warnUnsavedPageInput");
  273. const expandAllButton = document.getElementById("expandAllButton");
  274. const rulesDeleteAllButton = document.getElementById("rulesDeleteAllButton");
  275. const ruleUrlInput = document.getElementById("ruleUrlInput");
  276. const ruleProfileInput = document.getElementById("ruleProfileInput");
  277. const ruleAutoSaveProfileInput = document.getElementById("ruleAutoSaveProfileInput");
  278. const ruleEditProfileInput = document.getElementById("ruleEditProfileInput");
  279. const ruleEditAutoSaveProfileInput = document.getElementById("ruleEditAutoSaveProfileInput");
  280. const ruleAddButton = document.getElementById("ruleAddButton");
  281. const rulesElement = document.querySelector(".rules-table");
  282. const rulesContainerElement = document.querySelector(".rules-table-container");
  283. const ruleEditUrlInput = document.getElementById("ruleEditUrlInput");
  284. const ruleEditButton = document.getElementById("ruleEditButton");
  285. const createURLElement = rulesElement.querySelector(".rule-create");
  286. const showAllProfilesInput = document.getElementById("showAllProfilesInput");
  287. const showAutoSaveProfileInput = document.getElementById("showAutoSaveProfileInput");
  288. const synchronizeInput = document.getElementById("synchronizeInput");
  289. const resetAllButton = document.getElementById("resetAllButton");
  290. const resetCurrentButton = document.getElementById("resetCurrentButton");
  291. const resetCancelButton = document.getElementById("resetCancelButton");
  292. const confirmButton = document.getElementById("confirmButton");
  293. const cancelButton = document.getElementById("cancelButton");
  294. const promptInput = document.getElementById("promptInput");
  295. const promptCancelButton = document.getElementById("promptCancelButton");
  296. const promptConfirmButton = document.getElementById("promptConfirmButton");
  297. const manifest = browser.runtime.getManifest();
  298. const requestPermissionIdentity = manifest.optional_permissions && manifest.optional_permissions.includes("identity");
  299. let sidePanelDisplay;
  300. if (location.href.endsWith("#side-panel")) {
  301. sidePanelDisplay = true;
  302. document.querySelector(".options-title").remove();
  303. document.documentElement.classList.add("side-panel");
  304. }
  305. browser.runtime.onMessage.addListener(message => {
  306. if (message.method == "options.refresh" || (message.method == "options.refreshPanel" && sidePanelDisplay)) {
  307. refresh(message.profileName);
  308. }
  309. });
  310. let pendingSave = Promise.resolve();
  311. let autoSaveProfileChanged;
  312. ruleProfileInput.onchange = () => {
  313. if (!autoSaveProfileChanged && ruleProfileInput.value != CURRENT_PROFILE_NAME) {
  314. ruleAutoSaveProfileInput.value = ruleProfileInput.value;
  315. }
  316. };
  317. ruleAutoSaveProfileInput.onchange = () => {
  318. autoSaveProfileChanged = true;
  319. };
  320. rulesDeleteAllButton.addEventListener("click", async event => {
  321. if (await confirm(browser.i18n.getMessage("optionsDeleteDisplayedRulesConfirm"), event.clientY - 100)) {
  322. await browser.runtime.sendMessage({ method: "config.deleteRules", profileName: !showAllProfilesInput.checked && profileNamesInput.value });
  323. await refresh();
  324. await refreshExternalComponents();
  325. }
  326. }, false);
  327. createURLElement.onsubmit = async event => {
  328. event.preventDefault();
  329. try {
  330. await browser.runtime.sendMessage({ method: "config.addRule", url: ruleUrlInput.value, profileName: ruleProfileInput.value, autoSaveProfileName: ruleAutoSaveProfileInput.value });
  331. } catch (error) {
  332. // ignored
  333. }
  334. ruleUrlInput.value = "";
  335. ruleProfileInput.value = ruleAutoSaveProfileInput.value = DEFAULT_PROFILE_NAME;
  336. autoSaveProfileChanged = false;
  337. await refresh();
  338. await refreshExternalComponents();
  339. ruleUrlInput.focus();
  340. };
  341. ruleUrlInput.onclick = ruleUrlInput.onkeyup = ruleUrlInput.onchange = async () => {
  342. ruleAddButton.disabled = !ruleUrlInput.value;
  343. const rules = await browser.runtime.sendMessage({ method: "config.getRules" });
  344. if (rules.find(rule => rule.url == ruleUrlInput.value)) {
  345. ruleAddButton.disabled = true;
  346. }
  347. };
  348. ruleEditUrlInput.onclick = ruleEditUrlInput.onkeyup = ruleEditUrlInput.onchange = async () => {
  349. ruleEditButton.disabled = !ruleEditUrlInput.value;
  350. const rules = await browser.runtime.sendMessage({ method: "config.getRules" });
  351. if (rules.find(rule => rule.url == ruleEditUrlInput.value)) {
  352. ruleEditButton.disabled = true;
  353. }
  354. };
  355. if (getLocalStorageItem("optionShowAutoSaveProfile")) {
  356. showAutoSaveProfileInput.checked = true;
  357. rulesContainerElement.classList.remove("compact");
  358. }
  359. showAutoSaveProfileInput.addEventListener("click", () => {
  360. if (showAutoSaveProfileInput.checked) {
  361. setLocalStorageItem("optionShowAutoSaveProfile", 1);
  362. rulesContainerElement.classList.remove("compact");
  363. } else {
  364. removeLocalStorageItem("optionShowAutoSaveProfile");
  365. rulesContainerElement.classList.add("compact");
  366. }
  367. }, false);
  368. if (getLocalStorageItem("optionShowAllProfiles")) {
  369. showAllProfilesInput.checked = true;
  370. }
  371. showAllProfilesInput.addEventListener("click", () => {
  372. if (showAllProfilesInput.checked) {
  373. setLocalStorageItem("optionShowAllProfiles", 1);
  374. } else {
  375. removeLocalStorageItem("optionShowAllProfiles");
  376. }
  377. }, false);
  378. addProfileButton.addEventListener("click", async event => {
  379. const profileName = await prompt(browser.i18n.getMessage("profileAddPrompt"), event.clientY + 50);
  380. if (profileName) {
  381. try {
  382. await browser.runtime.sendMessage({ method: "config.createProfile", profileName, fromProfileName: profileNamesInput.value });
  383. } catch (error) {
  384. // ignored
  385. }
  386. if (sidePanelDisplay) {
  387. await refresh();
  388. } else {
  389. await refresh(profileName);
  390. }
  391. await refreshExternalComponents();
  392. }
  393. }, false);
  394. deleteProfileButton.addEventListener("click", async event => {
  395. if (await confirm(browser.i18n.getMessage("profileDeleteConfirm"), event.clientY + 50)) {
  396. try {
  397. await browser.runtime.sendMessage({ method: "config.deleteProfile", profileName: profileNamesInput.value });
  398. } catch (error) {
  399. // ignored
  400. }
  401. profileNamesInput.value = null;
  402. await refresh();
  403. await refreshExternalComponents();
  404. }
  405. }, false);
  406. renameProfileButton.addEventListener("click", async event => {
  407. const profileName = await prompt(browser.i18n.getMessage("profileRenamePrompt"), event.clientY + 50, profileNamesInput.value);
  408. if (profileName) {
  409. try {
  410. await browser.runtime.sendMessage({ method: "config.renameProfile", profileName: profileNamesInput.value, newProfileName: profileName });
  411. } catch (error) {
  412. // ignored
  413. }
  414. await refresh(profileName);
  415. await refreshExternalComponents();
  416. }
  417. }, false);
  418. resetButton.addEventListener("click", async event => {
  419. const choice = await reset(event.clientY - 250);
  420. if (choice) {
  421. if (choice == "all") {
  422. await browser.runtime.sendMessage({ method: "config.resetProfiles" });
  423. await refresh(DEFAULT_PROFILE_NAME);
  424. await refreshExternalComponents();
  425. }
  426. if (choice == "current") {
  427. await browser.runtime.sendMessage({ method: "config.resetProfile", profileName: profileNamesInput.value });
  428. await refresh();
  429. await refreshExternalComponents();
  430. }
  431. await update();
  432. }
  433. }, false);
  434. exportButton.addEventListener("click", async () => {
  435. const response = await browser.runtime.sendMessage({ method: "config.exportConfig" });
  436. if (response.filename && response.textContent) {
  437. const link = document.createElement("a");
  438. link.download = response.filename;
  439. link.href = "data:application/octet-stream," + response.textContent;
  440. link.target = "_blank";
  441. link.dispatchEvent(new MouseEvent("click"));
  442. }
  443. }, false);
  444. importButton.addEventListener("click", () => {
  445. fileInput.onchange = async () => {
  446. if (fileInput.files.length) {
  447. const reader = new FileReader();
  448. reader.readAsText(fileInput.files[0]);
  449. const serializedConfig = await new Promise((resolve, reject) => {
  450. reader.addEventListener("load", () => resolve(reader.result), false);
  451. reader.addEventListener("error", reject, false);
  452. });
  453. const config = JSON.parse(serializedConfig);
  454. await browser.runtime.sendMessage({ method: "config.importConfig", config });
  455. await refresh(DEFAULT_PROFILE_NAME);
  456. await refreshExternalComponents();
  457. fileInput.value = "";
  458. }
  459. };
  460. fileInput.click();
  461. }, false);
  462. autoSaveUnloadInput.addEventListener("click", async () => {
  463. if (!autoSaveLoadInput.checked && !autoSaveUnloadInput.checked) {
  464. autoSaveLoadOrUnloadInput.checked = true;
  465. }
  466. }, false);
  467. autoSaveLoadInput.addEventListener("click", async () => {
  468. if (!autoSaveLoadInput.checked && !autoSaveUnloadInput.checked) {
  469. autoSaveLoadOrUnloadInput.checked = true;
  470. }
  471. }, false);
  472. autoSaveLoadOrUnloadInput.addEventListener("click", async () => {
  473. if (autoSaveLoadOrUnloadInput.checked) {
  474. autoSaveUnloadInput.checked = autoSaveLoadInput.checked = false;
  475. } else {
  476. autoSaveUnloadInput.checked = false;
  477. }
  478. }, false);
  479. expandAllButton.addEventListener("click", () => {
  480. if (expandAllButton.className) {
  481. expandAllButton.className = "";
  482. } else {
  483. expandAllButton.className = "opened";
  484. }
  485. document.querySelectorAll("details").forEach(detailElement => detailElement.open = Boolean(expandAllButton.className));
  486. }, false);
  487. saveToFilesystemInput.addEventListener("click", () => disableDestinationPermissions(["clipboardWrite", "nativeMessaging"]), false);
  488. saveToClipboardInput.addEventListener("click", () => disableDestinationPermissions(["nativeMessaging"]), false);
  489. saveWithCompanionInput.addEventListener("click", () => disableDestinationPermissions(["clipboardWrite"]), false);
  490. saveToGDriveInput.addEventListener("click", () => disableDestinationPermissions(["clipboardWrite", "nativeMessaging"], false), false);
  491. saveWithWebDAVInput.addEventListener("click", () => disableDestinationPermissions(["clipboardWrite", "nativeMessaging"]), false);
  492. saveCreatedBookmarksInput.addEventListener("click", saveCreatedBookmarks, false);
  493. passReferrerOnErrorInput.addEventListener("click", passReferrerOnError, false);
  494. autoSaveExternalSaveInput.addEventListener("click", () => enableExternalSave(autoSaveExternalSaveInput), false);
  495. saveWithCompanionInput.addEventListener("click", () => enableExternalSave(saveWithCompanionInput), false);
  496. saveToClipboardInput.addEventListener("click", onClickSaveToClipboard, false);
  497. saveToGDriveInput.addEventListener("click", onClickSaveToGDrive, false);
  498. addProofInput.addEventListener("click", async event => {
  499. if (addProofInput.checked) {
  500. addProofInput.checked = false;
  501. if (await confirm(browser.i18n.getMessage("optionsAddProofConfirm"), event.clientY - 100)) {
  502. addProofInput.checked = true;
  503. woleetKeyInput.disabled = false;
  504. }
  505. await update();
  506. }
  507. });
  508. browser.runtime.sendMessage({ method: "config.isSync" }).then(data => synchronizeInput.checked = data.sync);
  509. synchronizeInput.addEventListener("click", async () => {
  510. if (synchronizeInput.checked) {
  511. await browser.runtime.sendMessage({ method: "config.enableSync" });
  512. await refresh(DEFAULT_PROFILE_NAME);
  513. } else {
  514. await browser.runtime.sendMessage({ method: "config.disableSync" });
  515. await refresh();
  516. }
  517. }, false);
  518. document.body.onchange = async event => {
  519. let target = event.target;
  520. if (target != ruleUrlInput &&
  521. target != ruleProfileInput &&
  522. target != ruleAutoSaveProfileInput &&
  523. target != ruleEditUrlInput &&
  524. target != ruleEditProfileInput &&
  525. target != ruleEditAutoSaveProfileInput &&
  526. target != showAutoSaveProfileInput &&
  527. target != saveCreatedBookmarksInput &&
  528. target != passReferrerOnErrorInput) {
  529. if (target != profileNamesInput && target != showAllProfilesInput) {
  530. await update();
  531. }
  532. if (target == profileNamesInput) {
  533. await refresh(profileNamesInput.value);
  534. if (sidePanelDisplay) {
  535. const tabsData = await browser.runtime.sendMessage({ method: "tabsData.get" });
  536. tabsData.profileName = profileNamesInput.value;
  537. await browser.runtime.sendMessage({ method: "tabsData.set", tabsData: tabsData });
  538. await browser.runtime.sendMessage({ method: "ui.refreshMenu" });
  539. }
  540. } else {
  541. if (target == contextMenuEnabledInput) {
  542. await browser.runtime.sendMessage({ method: "ui.refreshMenu" });
  543. }
  544. if (target == openEditorInput) {
  545. await browser.runtime.sendMessage({ method: "ui.refreshMenu" });
  546. }
  547. await refresh();
  548. }
  549. }
  550. };
  551. addProfileButton.title = browser.i18n.getMessage("profileAddButtonTooltip");
  552. deleteProfileButton.title = browser.i18n.getMessage("profileDeleteButtonTooltip");
  553. renameProfileButton.title = browser.i18n.getMessage("profileRenameButtonTooltip");
  554. removeHiddenElementsLabel.textContent = browser.i18n.getMessage("optionRemoveHiddenElements");
  555. removeUnusedStylesLabel.textContent = browser.i18n.getMessage("optionRemoveUnusedStyles");
  556. removeUnusedFontsLabel.textContent = browser.i18n.getMessage("optionRemoveUnusedFonts");
  557. removeFramesLabel.textContent = browser.i18n.getMessage("optionRemoveFrames");
  558. blockScriptsLabel.textContent = browser.i18n.getMessage("optionResourceScript");
  559. blockAudiosLabel.textContent = browser.i18n.getMessage("optionResourceAudio");
  560. blockVideosLabel.textContent = browser.i18n.getMessage("optionResourceVideo");
  561. blockFontsLabel.textContent = browser.i18n.getMessage("optionResourceFont");
  562. blockStylesheetsLabel.textContent = browser.i18n.getMessage("optionResourceStylesheet");
  563. blockImagesLabel.textContent = browser.i18n.getMessage("optionResourceImage");
  564. acceptHeaderDocumentLabel.textContent = browser.i18n.getMessage("optionResourceDocument");
  565. acceptHeaderScriptLabel.textContent = browser.i18n.getMessage("optionResourceScript");
  566. acceptHeaderAudioLabel.textContent = browser.i18n.getMessage("optionResourceAudio");
  567. acceptHeaderVideoLabel.textContent = browser.i18n.getMessage("optionResourceVideo");
  568. acceptHeaderFontLabel.textContent = browser.i18n.getMessage("optionResourceFont");
  569. acceptHeaderStylesheetLabel.textContent = browser.i18n.getMessage("optionResourceStylesheet");
  570. acceptHeaderImageLabel.textContent = browser.i18n.getMessage("optionResourceImage");
  571. saveRawPageLabel.textContent = browser.i18n.getMessage("optionSaveRawPage");
  572. insertMetaCSPLabel.textContent = browser.i18n.getMessage("optionInsertMetaCSP");
  573. saveToClipboardLabel.textContent = browser.i18n.getMessage("optionSaveToClipboard");
  574. saveToFilesystemLabel.textContent = browser.i18n.getMessage("optionSaveToFilesystem");
  575. addProofLabel.textContent = browser.i18n.getMessage("optionAddProof");
  576. woleetKeyLabel.textContent = browser.i18n.getMessage("optionWoleetKey");
  577. saveToGDriveLabel.textContent = browser.i18n.getMessage("optionSaveToGDrive");
  578. saveWithWebDAVLabel.textContent = browser.i18n.getMessage("optionSaveWithWebDAV");
  579. webDAVURLLabel.textContent = browser.i18n.getMessage("optionWebDAVURL");
  580. webDAVUserLabel.textContent = browser.i18n.getMessage("optionWebDAVUser");
  581. webDAVPasswordLabel.textContent = browser.i18n.getMessage("optionWebDAVPassword");
  582. saveToGitHubLabel.textContent = browser.i18n.getMessage("optionSaveToGitHub");
  583. githubTokenLabel.textContent = browser.i18n.getMessage("optionGitHubToken");
  584. githubUserLabel.textContent = browser.i18n.getMessage("optionGitHubUser");
  585. githubRepositoryLabel.textContent = browser.i18n.getMessage("optionGitHubRepository");
  586. githubBranchLabel.textContent = browser.i18n.getMessage("optionGitHubBranch");
  587. saveWithCompanionLabel.textContent = browser.i18n.getMessage("optionSaveWithCompanion");
  588. compressHTMLLabel.textContent = browser.i18n.getMessage("optionCompressHTML");
  589. compressCSSLabel.textContent = browser.i18n.getMessage("optionCompressCSS");
  590. moveStylesInHeadLabel.textContent = browser.i18n.getMessage("optionMoveStylesInHead");
  591. loadDeferredImagesLabel.textContent = browser.i18n.getMessage("optionLoadDeferredImages");
  592. loadDeferredImagesMaxIdleTimeLabel.textContent = browser.i18n.getMessage("optionLoadDeferredImagesMaxIdleTime");
  593. loadDeferredImagesKeepZoomLevelLabel.textContent = browser.i18n.getMessage("optionLoadDeferredImagesKeepZoomLevel");
  594. loadDeferredImagesDispatchScrollEventLabel.textContent = browser.i18n.getMessage("optionLoadDeferredImagesDispatchScrollEvent");
  595. addMenuEntryLabel.textContent = browser.i18n.getMessage("optionAddMenuEntry");
  596. filenameTemplateLabel.textContent = browser.i18n.getMessage("optionFilenameTemplate");
  597. filenameMaxLengthLabel.textContent = browser.i18n.getMessage("optionFilenameMaxLength");
  598. filenameMaxLengthBytesUnitLabel.textContent = browser.i18n.getMessage("optionFilenameMaxLengthBytesUnit");
  599. filenameMaxLengthCharsUnitLabel.textContent = browser.i18n.getMessage("optionFilenameMaxLengthCharsUnit");
  600. replaceEmojisInFilenameLabel.textContent = browser.i18n.getMessage("optionReplaceEmojisInFilename");
  601. shadowEnabledLabel.textContent = browser.i18n.getMessage("optionDisplayShadow");
  602. setMaxResourceSizeLabel.textContent = browser.i18n.getMessage("optionSetMaxResourceSize");
  603. maxResourceSizeLabel.textContent = browser.i18n.getMessage("optionMaxResourceSize");
  604. setMaxResourceDelayLabel.textContent = browser.i18n.getMessage("optionSetMaxResourceDelay");
  605. maxResourceDelayLabel.textContent = browser.i18n.getMessage("optionMaxResourceDelay");
  606. confirmFilenameLabel.textContent = browser.i18n.getMessage("optionConfirmFilename");
  607. filenameConflictActionLabel.textContent = browser.i18n.getMessage("optionFilenameConflictAction");
  608. filenameConflictActionUniquifyLabel.textContent = browser.i18n.getMessage("optionFilenameConflictActionUniquify");
  609. filenameConflictActionOverwriteLabel.textContent = browser.i18n.getMessage("optionFilenameConflictActionOverwrite");
  610. filenameConflictActionPromptLabel.textContent = browser.i18n.getMessage("optionFilenameConflictActionPrompt");
  611. filenameConflictActionSkipLabel.textContent = browser.i18n.getMessage("optionFilenameConflictActionSkip");
  612. displayInfobarLabel.textContent = browser.i18n.getMessage("optionDisplayInfobar");
  613. displayStatsLabel.textContent = browser.i18n.getMessage("optionDisplayStats");
  614. backgroundSaveLabel.textContent = browser.i18n.getMessage("optionBackgroundSave");
  615. autoSaveDelayLabel.textContent = browser.i18n.getMessage("optionAutoSaveDelay");
  616. autoSaveLoadLabel.textContent = browser.i18n.getMessage("optionAutoSaveLoad");
  617. autoSaveUnloadLabel.textContent = browser.i18n.getMessage("optionAutoSaveUnload");
  618. autoSaveLoadOrUnloadLabel.textContent = browser.i18n.getMessage("optionAutoSaveLoadOrUnload");
  619. autoSaveDiscardLabel.textContent = browser.i18n.getMessage("optionAutoSaveDiscard");
  620. autoSaveRemoveLabel.textContent = browser.i18n.getMessage("optionAutoSaveRemove");
  621. autoSaveRepeatLabel.textContent = browser.i18n.getMessage("optionAutoSaveRepeat");
  622. autoSaveRepeatDelayLabel.textContent = browser.i18n.getMessage("optionAutoSaveRepeatDelay");
  623. autoSaveExternalSaveLabel.textContent = browser.i18n.getMessage("optionAutoSaveExternalSave");
  624. removeAlternativeFontsLabel.textContent = browser.i18n.getMessage("optionRemoveAlternativeFonts");
  625. removeAlternativeImagesLabel.textContent = browser.i18n.getMessage("optionRemoveAlternativeImages");
  626. removeAlternativeMediasLabel.textContent = browser.i18n.getMessage("optionRemoveAlternativeMedias");
  627. saveCreatedBookmarksLabel.textContent = browser.i18n.getMessage("optionSaveCreatedBookmarks");
  628. passReferrerOnErrorLabel.textContent = browser.i18n.getMessage("optionPassReferrerOnError");
  629. replaceBookmarkURLLabel.textContent = browser.i18n.getMessage("optionReplaceBookmarkURL");
  630. allowedBookmarkFoldersLabel.textContent = browser.i18n.getMessage("optionAllowedBookmarkFolders");
  631. ignoredBookmarkFoldersLabel.textContent = browser.i18n.getMessage("optionIgnoredBookmarkFolders");
  632. groupDuplicateImagesLabel.textContent = browser.i18n.getMessage("optionGroupDuplicateImages");
  633. titleLabel.textContent = browser.i18n.getMessage("optionsTitle");
  634. userInterfaceLabel.textContent = browser.i18n.getMessage("optionsUserInterfaceSubTitle");
  635. filenameLabel.textContent = browser.i18n.getMessage("optionsFileNameSubTitle");
  636. htmlContentLabel.textContent = browser.i18n.getMessage("optionsHTMLContentSubTitle");
  637. infobarLabel.textContent = browser.i18n.getMessage("optionsInfobarSubTitle");
  638. imagesLabel.textContent = browser.i18n.getMessage("optionsImagesSubTitle");
  639. stylesheetsLabel.textContent = browser.i18n.getMessage("optionsStylesheetsSubTitle");
  640. fontsLabel.textContent = browser.i18n.getMessage("optionsFontsSubTitle");
  641. networkLabel.textContent = browser.i18n.getMessage("optionsNetworkSubTitle");
  642. blockResourcesLabel.textContent = browser.i18n.getMessage("optionsBlockedResources");
  643. acceptHeadersLabel.textContent = browser.i18n.getMessage("optionsAcceptHeaders");
  644. destinationLabel.textContent = browser.i18n.getMessage("optionsDestinationSubTitle");
  645. bookmarksLabel.textContent = browser.i18n.getMessage("optionsBookmarkSubTitle");
  646. autoSaveLabel.textContent = browser.i18n.getMessage("optionsAutoSaveSubTitle");
  647. miscLabel.textContent = browser.i18n.getMessage("optionsMiscSubTitle");
  648. helpLabel.textContent = browser.i18n.getMessage("optionsHelpLink");
  649. infobarTemplateLabel.textContent = browser.i18n.getMessage("optionInfobarTemplate");
  650. blockMixedContentLabel.textContent = browser.i18n.getMessage("optionBlockMixedContent");
  651. saveOriginalURLsLabel.textContent = browser.i18n.getMessage("optionSaveOriginalURLs");
  652. includeInfobarLabel.textContent = browser.i18n.getMessage("optionIncludeInfobar");
  653. removeInfobarSavedDateLabel.textContent = browser.i18n.getMessage("optionRemoveInfobarSavedDate");
  654. confirmInfobarLabel.textContent = browser.i18n.getMessage("optionConfirmInfobar");
  655. autoCloseLabel.textContent = browser.i18n.getMessage("optionAutoClose");
  656. editorLabel.textContent = browser.i18n.getMessage("optionsEditorSubTitle");
  657. openEditorLabel.textContent = browser.i18n.getMessage("optionOpenEditor");
  658. openSavedPageLabel.textContent = browser.i18n.getMessage("optionOpenSavedPage");
  659. autoOpenEditorLabel.textContent = browser.i18n.getMessage("optionAutoOpenEditor");
  660. defaultEditorModeLabel.textContent = browser.i18n.getMessage("optionDefaultEditorMode");
  661. defaultEditorModeNormalLabel.textContent = browser.i18n.getMessage("optionDefaultEditorModeNormal");
  662. defaultEditorModeEditLabel.textContent = browser.i18n.getMessage("optionDefaultEditorModeEdit");
  663. defaultEditorModeFormatLabel.textContent = browser.i18n.getMessage("optionDefaultEditorModeFormat");
  664. defaultEditorModeCutLabel.textContent = browser.i18n.getMessage("optionDefaultEditorModeCut");
  665. defaultEditorModeCutExternalLabel.textContent = browser.i18n.getMessage("optionDefaultEditorModeCutExternal");
  666. applySystemThemeLabel.textContent = browser.i18n.getMessage("optionApplySystemTheme");
  667. warnUnsavedPageLabel.textContent = browser.i18n.getMessage("optionWarnUnsavedPage");
  668. resetButton.textContent = browser.i18n.getMessage("optionsResetButton");
  669. exportButton.textContent = browser.i18n.getMessage("optionsExportButton");
  670. importButton.textContent = browser.i18n.getMessage("optionsImportButton");
  671. resetButton.title = browser.i18n.getMessage("optionsResetTooltip");
  672. autoSettingsLabel.textContent = browser.i18n.getMessage("optionsAutoSettingsSubTitle");
  673. autoSettingsUrlLabel.textContent = browser.i18n.getMessage("optionsAutoSettingsUrl");
  674. autoSettingsProfileLabel.textContent = browser.i18n.getMessage("optionsAutoSettingsProfile");
  675. autoSettingsAutoSaveProfileLabel.textContent = browser.i18n.getMessage("optionsAutoSettingsAutoSaveProfile");
  676. ruleAddButton.title = browser.i18n.getMessage("optionsAddRuleTooltip");
  677. ruleEditButton.title = browser.i18n.getMessage("optionsValidateChangesTooltip");
  678. rulesDeleteAllButton.title = browser.i18n.getMessage("optionsDeleteRulesTooltip");
  679. showAllProfilesLabel.textContent = browser.i18n.getMessage("optionsAutoSettingsShowAllProfiles");
  680. showAutoSaveProfileLabel.textContent = browser.i18n.getMessage("optionsAutoSettingsShowAutoSaveProfile");
  681. ruleUrlInput.placeholder = ruleEditUrlInput.placeholder = browser.i18n.getMessage("optionsAutoSettingsUrlPlaceholder");
  682. synchronizeLabel.textContent = browser.i18n.getMessage("optionSynchronize");
  683. resetAllButton.textContent = browser.i18n.getMessage("optionsResetAllButton");
  684. resetCurrentButton.textContent = browser.i18n.getMessage("optionsResetCurrentButton");
  685. resetCancelButton.textContent = promptCancelButton.textContent = cancelButton.textContent = browser.i18n.getMessage("optionsCancelButton");
  686. confirmButton.textContent = promptConfirmButton.textContent = browser.i18n.getMessage("optionsOKButton");
  687. document.getElementById("resetConfirmLabel").textContent = browser.i18n.getMessage("optionsResetConfirm");
  688. if (location.href.endsWith("#")) {
  689. document.querySelector(".new-window-link").remove();
  690. document.documentElement.classList.add("maximized");
  691. }
  692. let tabsData;
  693. browser.runtime.sendMessage({ method: "tabsData.get" }).then(allTabsData => {
  694. tabsData = allTabsData;
  695. return refresh(tabsData.profileName);
  696. });
  697. getHelpContents();
  698. function init() {
  699. if (!AUTO_SAVE_SUPPORTED) {
  700. document.getElementById("autoSaveSection").hidden = true;
  701. document.getElementById("showAutoSaveProfileOption").hidden = true;
  702. rulesContainerElement.classList.add("compact");
  703. }
  704. if (!BACKGROUND_SAVE_SUPPORTED) {
  705. document.getElementById("backgroundSaveOptions").hidden = true;
  706. document.getElementById("confirmFilenameOption").hidden = true;
  707. document.getElementById("filenameConflictAction").hidden = true;
  708. }
  709. if (!BOOKMARKS_API_SUPPORTED) {
  710. document.getElementById("bookmarksOptions").hidden = true;
  711. }
  712. if (!OPEN_SAVED_PAGE_SUPPORTED) {
  713. document.getElementById("openSavedPageOption").hidden = true;
  714. }
  715. if (!AUTO_OPEN_EDITOR_SUPPORTED) {
  716. document.getElementById("autoOpenEditorOption").hidden = true;
  717. }
  718. if (!INFOBAR_SUPPORTED) {
  719. document.getElementById("displayInfobarOption").hidden = true;
  720. }
  721. if (!IDENTITY_API_SUPPORTED) {
  722. document.getElementById("saveToGDriveOption").hidden = true;
  723. }
  724. if (!CLIPBOARD_API_SUPPORTED) {
  725. document.getElementById("saveToClipboardOption").hidden = true;
  726. }
  727. if (!NATIVE_API_API_SUPPORTED) {
  728. document.getElementById("saveWithCompanionOption").hidden = true;
  729. }
  730. if (!WEB_BLOCKING_API_SUPPORTED) {
  731. document.getElementById("passReferrerOnErrorOption").hidden = true;
  732. }
  733. }
  734. async function refresh(profileName) {
  735. const [profiles, rules, companionState] = await Promise.all([
  736. browser.runtime.sendMessage({ method: "config.getProfiles" }),
  737. browser.runtime.sendMessage({ method: "config.getRules" }),
  738. browser.runtime.sendMessage({ method: "companion.state" })]);
  739. const selectedProfileName = profileName || profileNamesInput.value || DEFAULT_PROFILE_NAME;
  740. Array.from(profileNamesInput.childNodes).forEach(node => node.remove());
  741. profileNamesInput.options.length = 0;
  742. ruleProfileInput.options.length = 0;
  743. ruleAutoSaveProfileInput.options.length = 0;
  744. ruleEditProfileInput.options.length = 0;
  745. ruleEditAutoSaveProfileInput.options.length = 0;
  746. let optionElement = document.createElement("option");
  747. optionElement.value = DEFAULT_PROFILE_NAME;
  748. optionElement.textContent = browser.i18n.getMessage("profileDefaultSettings");
  749. [CURRENT_PROFILE_NAME].concat(...Object.keys(profiles)).forEach(profileName => {
  750. const optionElement = document.createElement("option");
  751. optionElement.value = optionElement.textContent = profileName;
  752. if (profileName == DEFAULT_PROFILE_NAME) {
  753. optionElement.textContent = browser.i18n.getMessage("profileDefaultSettings");
  754. }
  755. if (profileName != CURRENT_PROFILE_NAME) {
  756. profileNamesInput.appendChild(optionElement);
  757. }
  758. ruleProfileInput.appendChild(optionElement.cloneNode(true));
  759. ruleAutoSaveProfileInput.appendChild(optionElement.cloneNode(true));
  760. ruleEditProfileInput.appendChild(optionElement.cloneNode(true));
  761. ruleEditAutoSaveProfileInput.appendChild(optionElement.cloneNode(true));
  762. });
  763. profileNamesInput.disabled = profileNamesInput.options.length == 1;
  764. optionElement = document.createElement("option");
  765. optionElement.value = DISABLED_PROFILE_NAME;
  766. optionElement.textContent = browser.i18n.getMessage("profileDisabled");
  767. ruleAutoSaveProfileInput.appendChild(optionElement);
  768. ruleEditAutoSaveProfileInput.appendChild(optionElement.cloneNode(true));
  769. const rulesDataElement = rulesElement.querySelector(".rules-data");
  770. Array.from(rulesDataElement.childNodes).forEach(node => (!node.className || !node.className.includes("rule-edit")) && node.remove());
  771. const editURLElement = rulesElement.querySelector(".rule-edit");
  772. createURLElement.hidden = false;
  773. editURLElement.hidden = true;
  774. ruleProfileInput.value = ruleAutoSaveProfileInput.value = selectedProfileName;
  775. let rulesDisplayed;
  776. rules.forEach(rule => {
  777. if (showAllProfilesInput.checked || selectedProfileName == rule.profile || selectedProfileName == rule.autoSaveProfile) {
  778. rulesDisplayed = true;
  779. const ruleElement = rulesElement.querySelector(".rule-view").cloneNode(true);
  780. const ruleUrlElement = ruleElement.querySelector(".rule-url");
  781. const ruleProfileElement = ruleElement.querySelector(".rule-profile");
  782. const ruleAutoSaveProfileElement = ruleElement.querySelector(".rule-autosave-profile");
  783. ruleUrlElement.textContent = ruleUrlElement.title = rule.url;
  784. ruleProfileElement.textContent = ruleProfileElement.title = getProfileText(rule.profile);
  785. ruleAutoSaveProfileElement.textContent = ruleAutoSaveProfileElement.title = getProfileText(rule.autoSaveProfile);
  786. ruleElement.hidden = false;
  787. ruleElement.className = "tr data";
  788. rulesDataElement.appendChild(ruleElement);
  789. const ruleDeleteButton = ruleElement.querySelector(".rule-delete-button");
  790. const ruleUpdateButton = ruleElement.querySelector(".rule-update-button");
  791. ruleDeleteButton.title = browser.i18n.getMessage("optionsDeleteRuleTooltip");
  792. ruleDeleteButton.addEventListener("click", async event => {
  793. if (await confirm(browser.i18n.getMessage("optionsDeleteRuleConfirm"), event.clientY - 100)) {
  794. await browser.runtime.sendMessage({ method: "config.deleteRule", url: rule.url });
  795. await refresh();
  796. await refreshExternalComponents();
  797. }
  798. }, false);
  799. ruleUpdateButton.title = browser.i18n.getMessage("optionsUpdateRuleTooltip");
  800. ruleUpdateButton.addEventListener("click", async () => {
  801. if (editURLElement.hidden) {
  802. createURLElement.hidden = true;
  803. editURLElement.hidden = false;
  804. rulesDataElement.replaceChild(editURLElement, ruleElement);
  805. ruleEditUrlInput.value = rule.url;
  806. ruleEditProfileInput.value = rule.profile;
  807. ruleEditAutoSaveProfileInput.value = rule.autoSaveProfile;
  808. ruleEditUrlInput.focus();
  809. editURLElement.onsubmit = async event => {
  810. event.preventDefault();
  811. rulesElement.appendChild(editURLElement);
  812. await browser.runtime.sendMessage({ method: "config.updateRule", url: rule.url, newUrl: ruleEditUrlInput.value, profileName: ruleEditProfileInput.value, autoSaveProfileName: ruleEditAutoSaveProfileInput.value });
  813. await refresh();
  814. await refreshExternalComponents();
  815. ruleUrlInput.focus();
  816. };
  817. }
  818. }, false);
  819. }
  820. });
  821. rulesDeleteAllButton.disabled = !rulesDisplayed;
  822. rulesElement.appendChild(createURLElement);
  823. profileNamesInput.value = selectedProfileName;
  824. renameProfileButton.disabled = deleteProfileButton.disabled = profileNamesInput.value == DEFAULT_PROFILE_NAME;
  825. const profileOptions = profiles[selectedProfileName];
  826. removeHiddenElementsInput.checked = profileOptions.removeHiddenElements;
  827. removeUnusedStylesInput.checked = profileOptions.removeUnusedStyles;
  828. removeUnusedFontsInput.checked = profileOptions.removeUnusedFonts;
  829. removeFramesInput.checked = profileOptions.removeFrames;
  830. blockScriptsInput.checked = profileOptions.blockScripts;
  831. blockVideosInput.checked = profileOptions.blockVideos;
  832. blockAudiosInput.checked = profileOptions.blockAudios;
  833. blockFontsInput.checked = profileOptions.blockFonts;
  834. blockStylesheetsInput.checked = profileOptions.blockStylesheets;
  835. blockImagesInput.checked = profileOptions.blockImages;
  836. acceptHeaderDocumentInput.value = profileOptions.acceptHeaders.document;
  837. acceptHeaderScriptInput.value = profileOptions.acceptHeaders.script;
  838. acceptHeaderAudioInput.value = profileOptions.acceptHeaders.audio;
  839. acceptHeaderVideoInput.value = profileOptions.acceptHeaders.video;
  840. acceptHeaderFontInput.value = profileOptions.acceptHeaders.font;
  841. acceptHeaderStylesheetInput.value = profileOptions.acceptHeaders.stylesheet;
  842. acceptHeaderImageInput.value = profileOptions.acceptHeaders.image;
  843. saveRawPageInput.checked = profileOptions.saveRawPage;
  844. insertMetaCSPInput.checked = profileOptions.insertMetaCSP;
  845. saveToClipboardInput.checked = profileOptions.saveToClipboard;
  846. addProofInput.checked = profileOptions.addProof;
  847. woleetKeyInput.value = profileOptions.woleetKey;
  848. woleetKeyInput.disabled = !profileOptions.addProof;
  849. saveToGDriveInput.checked = profileOptions.saveToGDrive;
  850. saveWithWebDAVInput.checked = profileOptions.saveWithWebDAV;
  851. webDAVURLInput.value = profileOptions.webDAVURL;
  852. webDAVURLInput.disabled = !profileOptions.saveWithWebDAV;
  853. webDAVUserInput.value = profileOptions.webDAVUser;
  854. webDAVUserInput.disabled = !profileOptions.saveWithWebDAV;
  855. webDAVPasswordInput.value = profileOptions.webDAVPassword;
  856. webDAVPasswordInput.disabled = !profileOptions.saveWithWebDAV;
  857. saveToGitHubInput.checked = profileOptions.saveToGitHub;
  858. githubTokenInput.value = profileOptions.githubToken;
  859. githubTokenInput.disabled = !profileOptions.saveToGitHub;
  860. githubUserInput.value = profileOptions.githubUser;
  861. githubUserInput.disabled = !profileOptions.saveToGitHub;
  862. githubRepositoryInput.value = profileOptions.githubRepository;
  863. githubRepositoryInput.disabled = !profileOptions.saveToGitHub;
  864. githubBranchInput.value = profileOptions.githubBranch;
  865. githubBranchInput.disabled = !profileOptions.saveToGitHub;
  866. saveWithCompanionInput.checked = profileOptions.saveWithCompanion;
  867. saveToFilesystemInput.checked = !profileOptions.saveToGDrive && !profileOptions.saveToGitHub && !profileOptions.saveWithCompanion && !profileOptions.saveToClipboard && !profileOptions.saveWithWebDAV;
  868. compressHTMLInput.checked = profileOptions.compressHTML;
  869. compressCSSInput.checked = profileOptions.compressCSS;
  870. moveStylesInHeadInput.checked = profileOptions.moveStylesInHead;
  871. loadDeferredImagesInput.checked = profileOptions.loadDeferredImages;
  872. loadDeferredImagesMaxIdleTimeInput.value = profileOptions.loadDeferredImagesMaxIdleTime;
  873. loadDeferredImagesKeepZoomLevelInput.checked = profileOptions.loadDeferredImagesKeepZoomLevel;
  874. loadDeferredImagesKeepZoomLevelInput.disabled = !profileOptions.loadDeferredImages;
  875. loadDeferredImagesMaxIdleTimeInput.disabled = !profileOptions.loadDeferredImages;
  876. loadDeferredImagesDispatchScrollEventInput.checked = profileOptions.loadDeferredImagesDispatchScrollEvent;
  877. loadDeferredImagesDispatchScrollEventInput.disabled = !profileOptions.loadDeferredImages;
  878. contextMenuEnabledInput.checked = profileOptions.contextMenuEnabled;
  879. filenameTemplateInput.value = profileOptions.filenameTemplate;
  880. filenameMaxLengthInput.value = profileOptions.filenameMaxLength;
  881. filenameMaxLengthUnitInput.value = profileOptions.filenameMaxLengthUnit;
  882. replaceEmojisInFilenameInput.checked = profileOptions.replaceEmojisInFilename;
  883. shadowEnabledInput.checked = profileOptions.shadowEnabled;
  884. maxResourceSizeEnabledInput.checked = profileOptions.maxResourceSizeEnabled;
  885. maxResourceSizeInput.value = profileOptions.maxResourceSizeEnabled ? profileOptions.maxResourceSize : 10;
  886. maxResourceSizeInput.disabled = !profileOptions.maxResourceSizeEnabled;
  887. maxResourceDelayEnabledInput.checked = Boolean(profileOptions.networkTimeout);
  888. maxResourceDelayInput.value = profileOptions.networkTimeout ? profileOptions.networkTimeout / 1000 : 60;
  889. maxResourceDelayInput.disabled = !profileOptions.networkTimeout;
  890. confirmFilenameInput.checked = profileOptions.confirmFilename;
  891. filenameConflictActionInput.value = profileOptions.filenameConflictAction;
  892. displayInfobarInput.checked = profileOptions.displayInfobar;
  893. displayStatsInput.checked = profileOptions.displayStats;
  894. backgroundSaveInput.checked = profileOptions.backgroundSave;
  895. autoSaveDelayInput.value = profileOptions.autoSaveDelay;
  896. autoSaveLoadInput.checked = !profileOptions.autoSaveLoadOrUnload && profileOptions.autoSaveLoad;
  897. autoSaveLoadOrUnloadInput.checked = profileOptions.autoSaveLoadOrUnload;
  898. autoSaveUnloadInput.checked = !profileOptions.autoSaveLoadOrUnload && profileOptions.autoSaveUnload;
  899. autoSaveLoadInput.disabled = profileOptions.autoSaveLoadOrUnload;
  900. autoSaveUnloadInput.disabled = profileOptions.autoSaveLoadOrUnload;
  901. autoSaveDiscardInput.checked = profileOptions.autoSaveDiscard;
  902. autoSaveRemoveInput.checked = profileOptions.autoSaveRemove;
  903. autoSaveRepeatInput.checked = profileOptions.autoSaveRepeat;
  904. autoSaveRepeatDelayInput.value = profileOptions.autoSaveRepeatDelay;
  905. autoSaveRepeatDelayInput.disabled = !profileOptions.autoSaveRepeat;
  906. autoSaveExternalSaveInput.checked = profileOptions.autoSaveExternalSave;
  907. autoSaveExternalSaveInput.parentElement.hidden = !companionState.enabled;
  908. removeAlternativeFontsInput.checked = profileOptions.removeAlternativeFonts;
  909. removeAlternativeImagesInput.checked = profileOptions.removeAlternativeImages;
  910. groupDuplicateImagesInput.checked = profileOptions.groupDuplicateImages;
  911. removeAlternativeMediasInput.checked = profileOptions.removeAlternativeMedias;
  912. saveCreatedBookmarksInput.checked = profileOptions.saveCreatedBookmarks;
  913. passReferrerOnErrorInput.checked = profileOptions.passReferrerOnError;
  914. replaceBookmarkURLInput.checked = profileOptions.replaceBookmarkURL;
  915. replaceBookmarkURLInput.disabled = !profileOptions.saveCreatedBookmarks;
  916. allowedBookmarkFoldersInput.value = profileOptions.allowedBookmarkFolders.map(folder => folder.replace(/,/g, "\\,")).join(","); // eslint-disable-line no-useless-escape
  917. allowedBookmarkFoldersInput.disabled = !profileOptions.saveCreatedBookmarks;
  918. ignoredBookmarkFoldersInput.value = profileOptions.ignoredBookmarkFolders.map(folder => folder.replace(/,/g, "\\,")).join(","); // eslint-disable-line no-useless-escape
  919. ignoredBookmarkFoldersInput.disabled = !profileOptions.saveCreatedBookmarks;
  920. infobarTemplateInput.value = profileOptions.infobarTemplate;
  921. blockMixedContentInput.checked = profileOptions.blockMixedContent;
  922. saveOriginalURLsInput.checked = profileOptions.saveOriginalURLs;
  923. includeInfobarInput.checked = profileOptions.includeInfobar;
  924. removeInfobarSavedDateInput.checked = profileOptions.removeSavedDate;
  925. confirmInfobarInput.checked = profileOptions.confirmInfobarContent;
  926. autoCloseInput.checked = profileOptions.autoClose;
  927. openEditorInput.checked = profileOptions.openEditor;
  928. openSavedPageInput.checked = profileOptions.openSavedPage;
  929. autoOpenEditorInput.checked = profileOptions.autoOpenEditor;
  930. defaultEditorModeInput.value = profileOptions.defaultEditorMode;
  931. applySystemThemeInput.checked = profileOptions.applySystemTheme;
  932. warnUnsavedPageInput.checked = profileOptions.warnUnsavedPage;
  933. }
  934. function getProfileText(profileName) {
  935. return profileName == DEFAULT_PROFILE_NAME ? browser.i18n.getMessage("profileDefaultSettings") : profileName == DISABLED_PROFILE_NAME ? browser.i18n.getMessage("profileDisabled") : profileName;
  936. }
  937. async function update() {
  938. try {
  939. await pendingSave;
  940. } catch (error) {
  941. // ignored
  942. }
  943. pendingSave = browser.runtime.sendMessage({
  944. method: "config.updateProfile",
  945. profileName: profileNamesInput.value,
  946. profile: {
  947. removeHiddenElements: removeHiddenElementsInput.checked,
  948. removeUnusedStyles: removeUnusedStylesInput.checked,
  949. removeUnusedFonts: removeUnusedFontsInput.checked,
  950. removeFrames: removeFramesInput.checked,
  951. blockScripts: blockScriptsInput.checked,
  952. blockVideos: blockVideosInput.checked,
  953. blockAudios: blockAudiosInput.checked,
  954. blockFonts: blockFontsInput.checked,
  955. blockStylesheets: blockStylesheetsInput.checked,
  956. blockImages: blockImagesInput.checked,
  957. acceptHeaders: {
  958. document: acceptHeaderDocumentInput.value,
  959. script: acceptHeaderScriptInput.value,
  960. audio: acceptHeaderAudioInput.value,
  961. video: acceptHeaderVideoInput.value,
  962. font: acceptHeaderFontInput.value,
  963. stylesheet: acceptHeaderStylesheetInput.value,
  964. image: acceptHeaderImageInput.value
  965. },
  966. saveRawPage: saveRawPageInput.checked,
  967. insertMetaCSP: insertMetaCSPInput.checked,
  968. saveToClipboard: saveToClipboardInput.checked,
  969. addProof: addProofInput.checked,
  970. woleetKey: woleetKeyInput.value,
  971. saveToGDrive: saveToGDriveInput.checked,
  972. saveWithWebDAV: saveWithWebDAVInput.checked,
  973. webDAVURL: webDAVURLInput.value,
  974. webDAVUser: webDAVUserInput.value,
  975. webDAVPassword: webDAVPasswordInput.value,
  976. saveToGitHub: saveToGitHubInput.checked,
  977. githubToken: githubTokenInput.value,
  978. githubUser: githubUserInput.value,
  979. githubRepository: githubRepositoryInput.value,
  980. githubBranch: githubBranchInput.value,
  981. saveWithCompanion: saveWithCompanionInput.checked,
  982. compressHTML: compressHTMLInput.checked,
  983. compressCSS: compressCSSInput.checked,
  984. moveStylesInHead: moveStylesInHeadInput.checked,
  985. loadDeferredImages: loadDeferredImagesInput.checked,
  986. loadDeferredImagesMaxIdleTime: Math.max(loadDeferredImagesMaxIdleTimeInput.value, 0),
  987. loadDeferredImagesKeepZoomLevel: loadDeferredImagesKeepZoomLevelInput.checked,
  988. loadDeferredImagesDispatchScrollEvent: loadDeferredImagesDispatchScrollEventInput.checked,
  989. contextMenuEnabled: contextMenuEnabledInput.checked,
  990. filenameTemplate: filenameTemplateInput.value,
  991. filenameMaxLength: filenameMaxLengthInput.value,
  992. filenameMaxLengthUnit: filenameMaxLengthUnitInput.value,
  993. replaceEmojisInFilename: replaceEmojisInFilenameInput.checked,
  994. shadowEnabled: shadowEnabledInput.checked,
  995. maxResourceSizeEnabled: maxResourceSizeEnabledInput.checked,
  996. maxResourceSize: maxResourceSizeEnabledInput.checked ? Math.max(maxResourceSizeInput.value, 0) : 10,
  997. networkTimeout: maxResourceDelayEnabledInput.checked ? Math.max(maxResourceDelayInput.value * 1000, 60) : 0,
  998. confirmFilename: confirmFilenameInput.checked,
  999. filenameConflictAction: filenameConflictActionInput.value,
  1000. displayInfobar: displayInfobarInput.checked,
  1001. displayStats: displayStatsInput.checked,
  1002. backgroundSave: backgroundSaveInput.checked,
  1003. autoSaveDelay: Math.max(autoSaveDelayInput.value, 0),
  1004. autoSaveLoad: autoSaveLoadInput.checked,
  1005. autoSaveUnload: autoSaveUnloadInput.checked,
  1006. autoSaveDiscard: autoSaveDiscardInput.checked,
  1007. autoSaveRemove: autoSaveRemoveInput.checked,
  1008. autoSaveLoadOrUnload: autoSaveLoadOrUnloadInput.checked,
  1009. autoSaveRepeat: autoSaveRepeatInput.checked,
  1010. autoSaveRepeatDelay: Math.max(autoSaveRepeatDelayInput.value, 1),
  1011. autoSaveExternalSave: autoSaveExternalSaveInput.checked,
  1012. removeAlternativeFonts: removeAlternativeFontsInput.checked,
  1013. removeAlternativeImages: removeAlternativeImagesInput.checked,
  1014. removeAlternativeMedias: removeAlternativeMediasInput.checked,
  1015. saveCreatedBookmarks: saveCreatedBookmarksInput.checked,
  1016. passReferrerOnError: passReferrerOnErrorInput.checked,
  1017. replaceBookmarkURL: replaceBookmarkURLInput.checked,
  1018. allowedBookmarkFolders: allowedBookmarkFoldersInput.value.replace(/([^\\]),/g, "$1 ,").split(/[^\\],/).map(folder => folder.replace(/\\,/g, ",")),
  1019. ignoredBookmarkFolders: ignoredBookmarkFoldersInput.value.replace(/([^\\]),/g, "$1 ,").split(/[^\\],/).map(folder => folder.replace(/\\,/g, ",")),
  1020. groupDuplicateImages: groupDuplicateImagesInput.checked,
  1021. infobarTemplate: infobarTemplateInput.value,
  1022. blockMixedContent: blockMixedContentInput.checked,
  1023. saveOriginalURLs: saveOriginalURLsInput.checked,
  1024. includeInfobar: includeInfobarInput.checked,
  1025. removeSavedDate: removeInfobarSavedDateInput.checked,
  1026. confirmInfobarContent: confirmInfobarInput.checked,
  1027. autoClose: autoCloseInput.checked,
  1028. openEditor: openEditorInput.checked,
  1029. openSavedPage: openSavedPageInput.checked,
  1030. autoOpenEditor: autoOpenEditorInput.checked,
  1031. defaultEditorMode: defaultEditorModeInput.value,
  1032. applySystemTheme: applySystemThemeInput.checked,
  1033. warnUnsavedPage: warnUnsavedPageInput.checked
  1034. }
  1035. });
  1036. try {
  1037. await pendingSave;
  1038. } catch (error) {
  1039. // ignored
  1040. }
  1041. }
  1042. async function refreshExternalComponents() {
  1043. try {
  1044. await browser.runtime.sendMessage({ method: "ui.refreshMenu" });
  1045. if (sidePanelDisplay) {
  1046. await browser.runtime.sendMessage({ method: "options.refresh", profileName: profileNamesInput.value });
  1047. } else {
  1048. await browser.runtime.sendMessage({ method: "options.refreshPanel", profileName: profileNamesInput.value });
  1049. }
  1050. } catch (error) {
  1051. // ignored
  1052. }
  1053. }
  1054. async function saveCreatedBookmarks() {
  1055. if (saveCreatedBookmarksInput.checked) {
  1056. saveCreatedBookmarksInput.checked = false;
  1057. try {
  1058. const permissionGranted = await browser.permissions.request({ permissions: ["bookmarks"] });
  1059. if (permissionGranted) {
  1060. saveCreatedBookmarksInput.checked = true;
  1061. await update();
  1062. await refresh();
  1063. await browser.runtime.sendMessage({ method: "bookmarks.saveCreatedBookmarks" });
  1064. } else {
  1065. await disableOption();
  1066. }
  1067. } catch (error) {
  1068. saveCreatedBookmarksInput.checked = false;
  1069. await disableOption();
  1070. }
  1071. } else {
  1072. try {
  1073. await browser.permissions.remove({ permissions: ["bookmarks"] });
  1074. } catch (error) {
  1075. // ignored
  1076. }
  1077. await disableOption();
  1078. }
  1079. async function disableOption() {
  1080. await update();
  1081. await refresh();
  1082. await browser.runtime.sendMessage({ method: "bookmarks.disable" });
  1083. }
  1084. }
  1085. async function onClickSaveToClipboard() {
  1086. if (saveToClipboardInput.checked) {
  1087. saveToClipboardInput.checked = false;
  1088. try {
  1089. const permissionGranted = await browser.permissions.request({ permissions: ["clipboardWrite"] });
  1090. if (permissionGranted) {
  1091. saveToClipboardInput.checked = true;
  1092. await browser.runtime.sendMessage({ method: "downloads.disableGDrive" });
  1093. }
  1094. } catch (error) {
  1095. saveToClipboardInput.checked = false;
  1096. }
  1097. }
  1098. await update();
  1099. await refresh();
  1100. }
  1101. async function onClickSaveToGDrive() {
  1102. if (saveToGDriveInput.checked) {
  1103. saveToGDriveInput.checked = false;
  1104. try {
  1105. if (requestPermissionIdentity) {
  1106. const permissionGranted = await browser.permissions.request({ permissions: ["identity"] });
  1107. if (permissionGranted) {
  1108. saveToGDriveInput.checked = true;
  1109. }
  1110. } else {
  1111. saveToGDriveInput.checked = true;
  1112. }
  1113. } catch (error) {
  1114. saveToGDriveInput.checked = false;
  1115. await browser.runtime.sendMessage({ method: "downloads.disableGDrive" });
  1116. }
  1117. }
  1118. await update();
  1119. await refresh();
  1120. }
  1121. async function disableDestinationPermissions(permissions, disableGDrive = true) {
  1122. if (disableGDrive) {
  1123. await browser.runtime.sendMessage({ method: "downloads.disableGDrive" });
  1124. }
  1125. try {
  1126. await browser.permissions.remove({ permissions });
  1127. } catch (error) {
  1128. //ignored
  1129. }
  1130. }
  1131. async function passReferrerOnError() {
  1132. if (passReferrerOnErrorInput.checked) {
  1133. passReferrerOnErrorInput.checked = false;
  1134. try {
  1135. const permissionGranted = await browser.permissions.request({ permissions: ["webRequest", "webRequestBlocking"] });
  1136. if (permissionGranted) {
  1137. passReferrerOnErrorInput.checked = true;
  1138. await update();
  1139. await refresh();
  1140. await browser.runtime.sendMessage({ method: "requests.enableReferrerOnError" });
  1141. } else {
  1142. await disableOption();
  1143. }
  1144. } catch (error) {
  1145. await disableOption();
  1146. }
  1147. } else {
  1148. await disableOption();
  1149. }
  1150. async function disableOption() {
  1151. await update();
  1152. await refresh();
  1153. await browser.runtime.sendMessage({ method: "requests.disableReferrerOnError" });
  1154. await browser.permissions.remove({ permissions: ["webRequest", "webRequestBlocking"] });
  1155. }
  1156. }
  1157. async function enableExternalSave(input) {
  1158. if (input.checked) {
  1159. input.checked = false;
  1160. try {
  1161. const permissionGranted = await browser.permissions.request({ permissions: ["nativeMessaging"] });
  1162. if (permissionGranted) {
  1163. input.checked = true;
  1164. await refreshOption();
  1165. if (window.chrome) {
  1166. window.chrome.runtime.reload();
  1167. }
  1168. } else {
  1169. await refreshOption();
  1170. }
  1171. } catch (error) {
  1172. input.checked = true;
  1173. await refreshOption();
  1174. }
  1175. } else {
  1176. await refreshOption();
  1177. }
  1178. async function refreshOption() {
  1179. await update();
  1180. await refresh();
  1181. }
  1182. }
  1183. async function confirm(message, positionY) {
  1184. document.getElementById("confirmLabel").textContent = message;
  1185. document.getElementById("formConfirmContainer").style.setProperty("display", "flex");
  1186. document.querySelector("#formConfirmContainer .popup-content").style.setProperty("margin-top", positionY + "px");
  1187. confirmButton.focus();
  1188. document.body.style.setProperty("overflow-y", "hidden");
  1189. return new Promise(resolve => {
  1190. confirmButton.onclick = event => hideAndResolve(event, true);
  1191. cancelButton.onclick = event => hideAndResolve(event);
  1192. window.onkeyup = event => {
  1193. if (event.key == "Escape") {
  1194. hideAndResolve(event);
  1195. }
  1196. };
  1197. function hideAndResolve(event, value) {
  1198. event.preventDefault();
  1199. document.getElementById("formConfirmContainer").style.setProperty("display", "none");
  1200. document.body.style.setProperty("overflow-y", "");
  1201. resolve(value);
  1202. }
  1203. });
  1204. }
  1205. async function reset(positionY) {
  1206. document.getElementById("formResetContainer").style.setProperty("display", "flex");
  1207. document.querySelector("#formResetContainer .popup-content").style.setProperty("margin-top", positionY + "px");
  1208. resetCancelButton.focus();
  1209. document.body.style.setProperty("overflow-y", "hidden");
  1210. return new Promise(resolve => {
  1211. resetAllButton.onclick = event => hideAndResolve(event, "all");
  1212. resetCurrentButton.onclick = event => hideAndResolve(event, "current");
  1213. resetCancelButton.onclick = event => hideAndResolve(event);
  1214. window.onkeyup = event => {
  1215. if (event.key == "Escape") {
  1216. hideAndResolve(event);
  1217. }
  1218. };
  1219. function hideAndResolve(event, value) {
  1220. event.preventDefault();
  1221. document.getElementById("formResetContainer").style.setProperty("display", "none");
  1222. document.body.style.setProperty("overflow-y", "");
  1223. resolve(value);
  1224. }
  1225. });
  1226. }
  1227. async function prompt(message, positionY, defaultValue = "") {
  1228. document.getElementById("promptLabel").textContent = message;
  1229. document.getElementById("formPromptContainer").style.setProperty("display", "flex");
  1230. document.querySelector("#formPromptContainer .popup-content").style.setProperty("margin-top", positionY + "px");
  1231. promptInput.value = defaultValue;
  1232. promptInput.focus();
  1233. document.body.style.setProperty("overflow-y", "hidden");
  1234. return new Promise(resolve => {
  1235. promptConfirmButton.onclick = event => hideAndResolve(event, promptInput.value);
  1236. promptCancelButton.onclick = event => hideAndResolve(event);
  1237. window.onkeyup = event => {
  1238. if (event.key == "Escape") {
  1239. hideAndResolve(event);
  1240. }
  1241. };
  1242. function hideAndResolve(event, value) {
  1243. event.preventDefault();
  1244. document.getElementById("formPromptContainer").style.setProperty("display", "none");
  1245. document.body.style.setProperty("overflow-y", "");
  1246. resolve(value);
  1247. }
  1248. });
  1249. }
  1250. async function getHelpContents() {
  1251. const helpPage = await fetch(browser.runtime.getURL(HELP_PAGE_PATH));
  1252. const content = new TextDecoder().decode(await helpPage.arrayBuffer());
  1253. const doc = (new DOMParser()).parseFromString(content, "text/html");
  1254. const items = doc.querySelectorAll("[data-options-label]");
  1255. items.forEach(itemElement => {
  1256. const optionLabel = document.getElementById(itemElement.dataset.optionsLabel);
  1257. if (optionLabel) {
  1258. const helpIconWrapper = document.createElement("span");
  1259. const helpIconContainer = document.createElement("span");
  1260. const helpIcon = document.createElement("img");
  1261. helpIcon.src = HELP_ICON_URL;
  1262. helpIconWrapper.className = "help-icon-wrapper";
  1263. const labelWords = optionLabel.textContent.split(/\s+/);
  1264. if (labelWords.length > 1) {
  1265. helpIconWrapper.textContent = labelWords.pop();
  1266. optionLabel.textContent = labelWords.join(" ") + " ";
  1267. }
  1268. helpIconContainer.className = "help-icon";
  1269. helpIconContainer.onclick = () => {
  1270. helpContent.hidden = !helpContent.hidden;
  1271. return false;
  1272. };
  1273. helpIcon.tabIndex = 0;
  1274. helpIconContainer.onkeyup = event => {
  1275. if (event.code == "Enter") {
  1276. helpContent.hidden = !helpContent.hidden;
  1277. return false;
  1278. }
  1279. };
  1280. helpIconContainer.appendChild(helpIcon);
  1281. helpIconWrapper.appendChild(helpIconContainer);
  1282. optionLabel.appendChild(helpIconWrapper);
  1283. const helpContent = document.createElement("div");
  1284. helpContent.hidden = true;
  1285. helpContent.className = "help-content";
  1286. itemElement.childNodes.forEach(node => {
  1287. if (node instanceof HTMLElement && node.className != "option") {
  1288. helpContent.appendChild(document.importNode(node, true));
  1289. }
  1290. });
  1291. helpContent.querySelectorAll("a[href]").forEach(linkElement => {
  1292. const hrefValue = linkElement.getAttribute("href");
  1293. if (hrefValue.startsWith("#")) {
  1294. linkElement.href = browser.runtime.getURL(HELP_PAGE_PATH + linkElement.getAttribute("href"));
  1295. linkElement.target = "_blank";
  1296. }
  1297. });
  1298. optionLabel.parentElement.insertAdjacentElement("afterEnd", helpContent);
  1299. }
  1300. });
  1301. }
  1302. function getLocalStorageItem(key) {
  1303. try {
  1304. return localStorage.getItem(key);
  1305. } catch (error) {
  1306. // ignored
  1307. }
  1308. }
  1309. function setLocalStorageItem(key, value) {
  1310. try {
  1311. return localStorage.setItem(key, value);
  1312. } catch (error) {
  1313. // ignored
  1314. }
  1315. }
  1316. function removeLocalStorageItem(key) {
  1317. try {
  1318. return localStorage.removeItem(key);
  1319. } catch (error) {
  1320. // ignored
  1321. }
  1322. }