ui-button.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * Copyright 2018 Gildas Lormeau
  3. * contact : gildas.lormeau <at> gmail.com
  4. *
  5. * This file is part of SingleFile.
  6. *
  7. * SingleFile is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * SingleFile 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
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with SingleFile. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /* global browser, singlefile */
  21. singlefile.ui.button = (() => {
  22. const DEFAULT_ICON_PATH = "/extension/ui/resources/icon_16.png";
  23. const WAIT_ICON_PATH_PREFIX = "/extension/ui/resources/icon_16_wait";
  24. const DEFAULT_TITLE = "Save page with SingleFile";
  25. const DEFAULT_COLOR = [2, 147, 20, 255];
  26. const BUTTON_PROPERTIES = [{ name: "color", browserActionMethod: "setBadgeBackgroundColor" }, { name: "path", browserActionMethod: "setIcon" }, { name: "text", browserActionMethod: "setBadgeText" }, { name: "title", browserActionMethod: "setTitle" }];
  27. browser.browserAction.onClicked.addListener(async tab => {
  28. if (singlefile.core.isAllowedURL(tab.url)) {
  29. const tabs = await browser.tabs.query({ currentWindow: true, highlighted: true });
  30. if (!tabs.length) {
  31. singlefile.ui.processTab(tab);
  32. } else {
  33. tabs.forEach(tab => singlefile.core.isAllowedURL(tab.url) && singlefile.ui.processTab(tab));
  34. }
  35. }
  36. });
  37. browser.tabs.onActivated.addListener(async activeInfo => {
  38. const tab = await browser.tabs.get(activeInfo.tabId);
  39. await onTabActivated(tab);
  40. });
  41. browser.tabs.onCreated.addListener(onTabActivated);
  42. browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => onTabActivated(tab));
  43. browser.runtime.onMessage.addListener((request, sender) => {
  44. if (request.processProgress) {
  45. if (request.maxIndex) {
  46. onProgress(sender.tab.id, request.index, request.maxIndex, request.options);
  47. }
  48. }
  49. if (request.processEnd) {
  50. onEnd(sender.tab.id, request.options);
  51. }
  52. if (request.processError) {
  53. if (request.error) {
  54. console.error("Initialization error", request.error); // eslint-disable-line no-console
  55. }
  56. onError(sender.tab.id, request.options);
  57. }
  58. });
  59. return {
  60. onInitialize,
  61. onProgress,
  62. onEnd,
  63. onError,
  64. refresh: (tabId, options) => refresh(tabId, getProperties(tabId, options))
  65. };
  66. function onInitialize(tabId, options, step) {
  67. refresh(tabId, getProperties(tabId, options, "•••", step == 1 ? DEFAULT_COLOR : [4, 229, 36, 255], "Initializing SingleFile (" + step + "/2)"));
  68. }
  69. function onError(tabId, options) {
  70. refresh(tabId, getProperties(tabId, options, "ERR", [229, 4, 12, 255]));
  71. }
  72. async function onEnd(tabId, options) {
  73. refresh(tabId, getProperties(tabId, options, "OK", [4, 229, 36, 255]));
  74. }
  75. function onProgress(tabId, index, maxIndex, options) {
  76. const progress = Math.max(Math.min(20, Math.floor((index / maxIndex) * 20)), 0);
  77. const barProgress = Math.floor((index / maxIndex) * 8);
  78. refresh(tabId, getProperties(tabId, options, "", [4, 229, 36, 255], "Save progress: " + (progress * 5) + "%", WAIT_ICON_PATH_PREFIX + barProgress + ".png", progress, barProgress, [128, 128, 128, 255]));
  79. }
  80. async function onTabActivated(tab) {
  81. const autoSave = await singlefile.ui.autosave.isEnabled(tab.id);
  82. await refresh(tab.id, getProperties(tab.id, { autoSave }));
  83. if (singlefile.core.isAllowedURL(tab.url) && browser.browserAction && browser.browserAction.enable && browser.browserAction.disable) {
  84. if (singlefile.core.isAllowedURL(tab.url)) {
  85. try {
  86. await browser.browserAction.enable(tab.id);
  87. } catch (error) {
  88. /* ignored */
  89. }
  90. } else {
  91. try {
  92. await browser.browserAction.disable(tab.id);
  93. } catch (error) {
  94. /* ignored */
  95. }
  96. }
  97. }
  98. }
  99. function getProperties(tabId, options, text, color, title = DEFAULT_TITLE, path = DEFAULT_ICON_PATH, progress = -1, barProgress = -1, autoColor = [208, 208, 208, 255]) {
  100. return {
  101. text: options.autoSave ? "[A]" : (text || ""),
  102. color: options.autoSave ? autoColor : color || DEFAULT_COLOR,
  103. title: options.autoSave ? "Autosave active" : title,
  104. path: options.autoSave ? DEFAULT_ICON_PATH : path,
  105. progress: options.autoSave ? - 1 : progress,
  106. barProgress: options.autoSave ? - 1 : barProgress
  107. };
  108. }
  109. async function refresh(tabId, tabData) {
  110. const tabsData = await singlefile.storage.getTemporary();
  111. if (!tabsData[tabId]) {
  112. tabsData[tabId] = {};
  113. }
  114. if (!tabsData[tabId].pendingRefresh) {
  115. tabsData[tabId].pendingRefresh = Promise.resolve();
  116. }
  117. tabsData[tabId].pendingRefresh = tabsData[tabId].pendingRefresh.then(() => refreshAsync(tabId, tabsData, tabData));
  118. try {
  119. await tabsData[tabId].pendingRefresh;
  120. } catch (error) {
  121. /* ignored */
  122. }
  123. }
  124. async function refreshAsync(tabId, tabsData, tabData) {
  125. for (let property of BUTTON_PROPERTIES) {
  126. await refreshProperty(tabId, tabsData, property.name, property.browserActionMethod, tabData);
  127. }
  128. }
  129. async function refreshProperty(tabId, tabsData, property, browserActionMethod, tabData) {
  130. const value = tabData[property];
  131. const browserActionParameter = { tabId };
  132. if (browser.browserAction[browserActionMethod]) {
  133. browserActionParameter[property] = value;
  134. if (!tabsData[tabId]) {
  135. tabsData[tabId] = {};
  136. }
  137. if (!tabsData[tabId].button) {
  138. tabsData[tabId].button = {};
  139. }
  140. if (JSON.stringify(tabsData[tabId].button[browserActionMethod]) != JSON.stringify(value)) {
  141. tabsData[tabId].button[browserActionMethod] = value;
  142. await browser.browserAction[browserActionMethod](browserActionParameter);
  143. }
  144. }
  145. }
  146. })();