ui-button.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * Copyright 2010-2019 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_128.png";
  23. const WAIT_ICON_PATH_PREFIX = "/extension/ui/resources/icon_128_wait";
  24. const DEFAULT_TITLE = browser.i18n.getMessage("buttonDefaultTooltip");
  25. const DEFAULT_COLOR = [2, 147, 20, 255];
  26. browser.browserAction.onClicked.addListener(async tab => {
  27. const tabs = await singlefile.tabs.get({ currentWindow: true, highlighted: true });
  28. if (!tabs.length) {
  29. singlefile.core.saveTab(tab);
  30. } else {
  31. tabs.forEach(tab => (tab.active || tab.highlighted) && singlefile.core.saveTab(tab));
  32. }
  33. });
  34. return {
  35. onMessage,
  36. onTabCreated,
  37. onTabActivated,
  38. onTabUpdated,
  39. onInitialize,
  40. onProgress,
  41. onEnd,
  42. onError,
  43. refresh: async tab => {
  44. if (tab.id) {
  45. await refresh(tab.id, getProperties({ autoSave: await singlefile.autosave.isEnabled(tab) }));
  46. }
  47. }
  48. };
  49. function onMessage(message, sender) {
  50. if (message.loadURL) {
  51. onLoad(sender.tab.id);
  52. }
  53. if (message.processProgress) {
  54. if (message.maxIndex) {
  55. onProgress(sender.tab.id, message.index, message.maxIndex, message.options);
  56. }
  57. }
  58. if (message.processEnd) {
  59. onEnd(sender.tab.id, message.options);
  60. }
  61. if (message.processError) {
  62. if (message.error) {
  63. console.error("Initialization error", message.error); // eslint-disable-line no-console
  64. }
  65. onError(sender.tab.id, message.options);
  66. }
  67. if (message.processCancelled) {
  68. onCancelled(sender.tab.id, message.options);
  69. }
  70. }
  71. function onTabUpdated(tabId, changeInfo, tab) {
  72. refreshTab(tab);
  73. }
  74. async function onTabCreated(tab) {
  75. await refreshProperty(tab.id, "setBadgeBackgroundColor", { color: DEFAULT_COLOR });
  76. refreshTab(tab);
  77. }
  78. async function onTabActivated(tab) {
  79. refreshTab(tab);
  80. }
  81. function onLoad(tabId) {
  82. refresh(tabId, getProperties({}, "", DEFAULT_COLOR, DEFAULT_TITLE));
  83. }
  84. function onInitialize(tabId, options, step) {
  85. if (step == 1) {
  86. onLoad(tabId);
  87. }
  88. refresh(tabId, getProperties(options, browser.i18n.getMessage("buttonInitializingBadge"), step == 1 ? DEFAULT_COLOR : [4, 229, 36, 255], browser.i18n.getMessage("buttonInitializingTooltip") + " (" + step + "/2)", WAIT_ICON_PATH_PREFIX + "0.png"));
  89. }
  90. function onError(tabId, options) {
  91. refresh(tabId, getProperties(options, browser.i18n.getMessage("buttonErrorBadge"), [229, 4, 12, 255]));
  92. }
  93. function onCancelled(tabId, options) {
  94. refresh(tabId, getProperties(options, "", DEFAULT_COLOR, DEFAULT_TITLE));
  95. }
  96. function onEnd(tabId, options) {
  97. refresh(tabId, getProperties(options, browser.i18n.getMessage("buttonOKBadge"), [4, 229, 36, 255]));
  98. }
  99. function onProgress(tabId, index, maxIndex, options) {
  100. const progress = Math.max(Math.min(20, Math.floor((index / maxIndex) * 20)), 0);
  101. const barProgress = Math.min(Math.floor((index / maxIndex) * 8), 8);
  102. const path = WAIT_ICON_PATH_PREFIX + barProgress + ".png";
  103. refresh(tabId, getProperties(options, "", [4, 229, 36, 255], browser.i18n.getMessage("buttonSaveProgressTooltip") + (progress * 5) + "%", path, [128, 128, 128, 255]));
  104. }
  105. async function refreshTab(tab) {
  106. const properties = getCurrentProperties(tab.id, { autoSave: await singlefile.autosave.isEnabled(tab) });
  107. await refresh(tab.id, properties, true);
  108. if (browser.browserAction && browser.browserAction.enable && browser.browserAction.disable) {
  109. if (singlefile.util.isAllowedURL(tab.url)) {
  110. try {
  111. await browser.browserAction.enable(tab.id);
  112. } catch (error) {
  113. /* ignored */
  114. }
  115. } else {
  116. try {
  117. await browser.browserAction.disable(tab.id);
  118. } catch (error) {
  119. /* ignored */
  120. }
  121. }
  122. }
  123. }
  124. function getCurrentProperties(tabId, options) {
  125. if (options.autoSave) {
  126. return getProperties(options);
  127. } else {
  128. const tabsData = singlefile.tabsData.getTemporary(tabId);
  129. const tabData = tabsData[tabId].button;
  130. if (tabData) {
  131. return tabData;
  132. } else {
  133. return getProperties(options);
  134. }
  135. }
  136. }
  137. function getProperties(options, text, color, title = DEFAULT_TITLE, path = DEFAULT_ICON_PATH, autoColor = [208, 208, 208, 255]) {
  138. return {
  139. setBadgeText: { text: options.autoSave ? browser.i18n.getMessage("buttonAutoSaveActiveBadge") : (text || "") },
  140. setBadgeBackgroundColor: { color: options.autoSave ? autoColor : color || DEFAULT_COLOR },
  141. setTitle: { title: options.autoSave ? browser.i18n.getMessage("buttonAutoSaveActiveTooltip") : title },
  142. setIcon: { path: options.autoSave ? DEFAULT_ICON_PATH : path }
  143. };
  144. }
  145. async function refresh(tabId, tabData) {
  146. const tabsData = singlefile.tabsData.getTemporary(tabId);
  147. const oldTabData = tabsData[tabId].button || {};
  148. tabsData[tabId].button = tabData;
  149. if (!tabData.pendingRefresh) {
  150. tabData.pendingRefresh = Promise.resolve();
  151. }
  152. try {
  153. await tabData.pendingRefresh;
  154. } catch (error) {
  155. /* ignored */
  156. }
  157. tabData.pendingRefresh = refreshAsync(tabId, tabData, oldTabData);
  158. }
  159. async function refreshAsync(tabId, tabData, oldTabData) {
  160. for (const browserActionMethod of Object.keys(tabData)) {
  161. if (browserActionMethod == "setBadgeBackgroundColor" || !oldTabData[browserActionMethod] || JSON.stringify(oldTabData[browserActionMethod]) != JSON.stringify(tabData[browserActionMethod])) {
  162. try {
  163. await refreshProperty(tabId, browserActionMethod, tabData[browserActionMethod]);
  164. } catch (error) {
  165. /* ignored */
  166. }
  167. }
  168. }
  169. }
  170. async function refreshProperty(tabId, browserActionMethod, browserActionParameter) {
  171. if (browser.browserAction[browserActionMethod]) {
  172. const parameter = JSON.parse(JSON.stringify(browserActionParameter));
  173. parameter.tabId = tabId;
  174. await browser.browserAction[browserActionMethod](parameter);
  175. }
  176. }
  177. })();