ui-options.js 70 KB

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