您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

options.js 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /**********/
  2. /* EVENTS */
  3. /**********/
  4. /* Triggered when a click is received by the mode selector switch, or by
  5. either of the two labels ("Blacklist" and "Whitelist").
  6. */
  7. function modeSelectorInputReceived() {
  8. toggleModeSelectorState();
  9. // Activate the "Reset" and "Save" buttons, since changes have been made.
  10. setButtonsActive(true);
  11. }
  12. /***********/
  13. /* HELPERS */
  14. /***********/
  15. /* Toggles all UI state associated with mode selection. Called on input to
  16. the mode selector (see modeSelectorInputReceived()), OR when changes are
  17. reset (see resetChanges()).
  18. */
  19. function toggleModeSelectorState(newMode) {
  20. /* Update state of the checkbox itself, and the container div. */
  21. let container = document.querySelector(".mode-select-container");
  22. let checkbox = document.querySelector("input#whitelist-mode");
  23. newMode = newMode || (container.classList.contains("whitelist") ? "blacklist" : "whitelist");
  24. container.classList.toggle("whitelist", (newMode == "whitelist"));
  25. checkbox.checked = (newMode == "whitelist");
  26. /* Enable both spans (the "Blacklist" and "Whitelist" labels, then disable
  27. just the label associated with the now-enabled mode. */
  28. container.querySelectorAll("span").forEach(span => {
  29. span.classList.toggle("disabled", false);
  30. });
  31. document.querySelector(`.${newMode}-mode-label`).classList.toggle("disabled", true);
  32. /* In whitelist mode, the matching patterns textarea must be disabled,
  33. since the matching patterns list is treated as containing only the
  34. single pattern ".*". An overlay is shown, to indicate this. */
  35. document.querySelector("div#matchingPatterns").classList.toggle("disabled", (newMode == "whitelist"));
  36. document.querySelector("div#matchingPatterns textarea").disabled = (newMode == "whitelist");
  37. }
  38. /* Saves the entered state in storage.
  39. De-activate the "Reset" and "Save" buttons.
  40. */
  41. function saveChanges() {
  42. let matchingPatterns = document.querySelector("#matchingPatterns textarea").value;
  43. let exclusionPatterns = document.querySelector("#exclusionPatterns textarea").value;
  44. let mode = document.querySelector("input#whitelist-mode").checked ? "whitelist" : "blacklist";
  45. chrome.storage.sync.set({
  46. "matchingPatterns": matchingPatterns,
  47. "exclusionPatterns": exclusionPatterns,
  48. "mode": mode
  49. }, () => { setButtonsActive(false); });
  50. }
  51. /* Retrieves the saved state from storage and reset the UI to reflect it,
  52. discarding the user's changes.
  53. */
  54. function resetChanges(callback) {
  55. chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns", "mode" ], (result) => {
  56. AKS.matchingPatterns = result.matchingPatterns || "";
  57. AKS.exclusionPatterns = result.exclusionPatterns || ""
  58. AKS.mode = result.mode || "blacklist";
  59. document.querySelector("#matchingPatterns textarea").value = AKS.matchingPatterns;
  60. document.querySelector("#exclusionPatterns textarea").value = AKS.exclusionPatterns;
  61. toggleModeSelectorState(AKS.mode);
  62. // De-activate the "Reset" and "Save" buttons.
  63. setButtonsActive(false);
  64. // Expand all textareas.
  65. document.querySelectorAll("textarea").forEach(textarea => {
  66. expandTextarea(textarea);
  67. });
  68. // Trigger provided callback, if any.
  69. if (callback) callback();
  70. });
  71. }
  72. /* Activates or de-activates the "Reset" and "Save" buttons. Called when
  73. changes are made (to activate) or when changes are saved or reset (to
  74. de-activate).
  75. */
  76. function setButtonsActive(active) {
  77. document.querySelectorAll(".top-controls button").forEach(button => {
  78. button.disabled = !active;
  79. });
  80. }
  81. /* Enables or disables scrolling on the page body, depending on whether the
  82. help overlay is visible. */
  83. function setBodyScrollState() {
  84. document.querySelector("body").classList.toggle("noscroll", location.hash == "#help");
  85. }
  86. /* Expands a textarea to show all its contents (up to a maximum height which is
  87. set via CSS).
  88. */
  89. function expandTextarea(textarea) {
  90. let totalBorderHeight = 2;
  91. if (textarea.clientHeight == textarea.scrollHeight + totalBorderHeight) return;
  92. requestAnimationFrame(() => {
  93. textarea.style.height = 'auto';
  94. textarea.style.height = textarea.scrollHeight + totalBorderHeight + 'px';
  95. });
  96. }
  97. function setHelpOverlayVisible(visible) {
  98. location.hash = visible ? "help" : "";
  99. setBodyScrollState();
  100. }
  101. /******************/
  102. /* INITIALIZATION */
  103. /******************/
  104. function initialize() {
  105. window.AKS = { };
  106. /* Retrieve saved settings from storage, and set all UI elements to their
  107. proper state. Then, focus the first active textarea. */
  108. resetChanges(() => {
  109. let divToFocus = (AKS.mode == "whitelist") ? "#exclusionPatterns" : "#matchingPatterns";
  110. document.querySelector(`${divToFocus} textarea`).focus();
  111. });
  112. // Update version.
  113. document.querySelector(".bottom-info .version").innerHTML = chrome.runtime.getManifest().version;
  114. // Listeners for Reset and Save buttons.
  115. document.querySelectorAll("button").forEach(button => {
  116. button.addActivateEvent((event) => {
  117. event.target.blur();
  118. if (button.classList.contains("save-button"))
  119. saveChanges();
  120. else
  121. resetChanges();
  122. });
  123. });
  124. // Listeners to activate Reset/Save buttons when textareas get input.
  125. document.querySelectorAll("textarea").forEach(textarea => {
  126. textarea.addEventListener("input", (event) => {
  127. setButtonsActive(true);
  128. });
  129. });
  130. // Listeners to auto-expand textareas on input.
  131. document.querySelectorAll("textarea").forEach(textarea => {
  132. textarea.addEventListener("input", (event) => {
  133. expandTextarea(textarea);
  134. });
  135. });
  136. // Listeners for mode select switch.
  137. document.querySelector("input[type='checkbox']").addEventListener("change", (event) => {
  138. modeSelectorInputReceived();
  139. });
  140. document.querySelectorAll(".mode-select-container span").forEach(span => {
  141. span.addActivateEvent((event) => {
  142. modeSelectorInputReceived();
  143. });
  144. });
  145. // Listener for open help button.
  146. document.querySelector(".open-help-button").addActivateEvent((event) => {
  147. setHelpOverlayVisible(true);
  148. });
  149. // Listener for close help button.
  150. document.querySelector(".help-overlay .close-button").addActivateEvent((event) => {
  151. setHelpOverlayVisible(false);
  152. });
  153. // Disable scrolling on the document body, if need be (if help is open).
  154. setBodyScrollState();
  155. // Listener for Escape key (closes the help overlay).
  156. document.addEventListener("keyup", (event) => {
  157. if (event.keyCode == 27 && location.hash == "#help") {
  158. setHelpOverlayVisible(false);
  159. }
  160. });
  161. }
  162. initialize();