manage.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /* global API msg */// msg.js
  2. /* global CHROME VIVALDI debounce */// toolbox.js
  3. /* global Events handleBulkChange handleVisibilityChange */// events.js
  4. /* global fitSelectBoxesIn switchUI showStyles */// render.js
  5. /* global prefs */
  6. /* global router */
  7. /* global sorter */
  8. /* global t */// localization.js
  9. /* global
  10. $
  11. $$
  12. $create
  13. animateElement
  14. setupLivePrefs
  15. waitForSelector
  16. waitForSheet
  17. */// dom.js
  18. 'use strict';
  19. /** @type {HTMLElement} */
  20. let installed;
  21. const changeQueue = [];
  22. changeQueue.THROTTLE = 100; // ms
  23. changeQueue.time = 0;
  24. // define pref-mapped ids separately
  25. const newUI = {
  26. enabled: null, // the global option should come first
  27. favicons: null,
  28. faviconsGray: null,
  29. targets: null,
  30. };
  31. // ...add utility functions
  32. Object.assign(newUI, {
  33. ids: Object.keys(newUI),
  34. prefKeyForId: id => `manage.newUI.${id}`.replace(/\.enabled$/, ''),
  35. renderClass: () => {
  36. const cl = document.documentElement.classList;
  37. cl.toggle('newUI', newUI.enabled);
  38. cl.toggle('oldUI', !newUI.enabled);
  39. },
  40. });
  41. // ...read the actual values
  42. for (const id of newUI.ids) {
  43. newUI[id] = prefs.get(newUI.prefKeyForId(id));
  44. }
  45. newUI.renderClass();
  46. (async function init() {
  47. const query = router.getSearch('search');
  48. const [styles, ids, el] = await Promise.all([
  49. API.styles.getAll(),
  50. query && API.styles.searchDB({query, mode: router.getSearch('searchMode')}),
  51. // needed to avoid flicker due to an extra frame and layout shift
  52. waitForSelector('#installed'),
  53. prefs.ready,
  54. ]);
  55. installed = el;
  56. installed.on('click', Events.entryClicked);
  57. installed.on('mouseover', Events.lazyAddEntryTitle, {passive: true});
  58. installed.on('mouseout', Events.lazyAddEntryTitle, {passive: true});
  59. $('#manage-options-button').onclick = () => router.updateHash('#stylus-options');
  60. $('#sync-styles').onclick = () => router.updateHash('#stylus-options');
  61. $$('#header a[href^="http"]').forEach(a => (a.onclick = Events.external));
  62. document.on('visibilitychange', handleVisibilityChange);
  63. setupLivePrefs();
  64. router.update();
  65. prefs.subscribe(newUI.ids.map(newUI.prefKeyForId), () => switchUI());
  66. switchUI({styleOnly: true});
  67. // translate CSS manually
  68. document.styleSheets[0].insertRule(
  69. `:root {${[
  70. 'genericDisabledLabel',
  71. 'updateAllCheckSucceededSomeEdited',
  72. 'filteredStylesAllHidden',
  73. ].map(id => `--${id}:"${CSS.escape(t(id))}";`).join('')
  74. }}`);
  75. if (!VIVALDI) {
  76. waitForSheet().then(() => {
  77. fitSelectBoxesIn($('#filters'));
  78. });
  79. }
  80. if (CHROME >= 80 && CHROME <= 88) {
  81. // Wrong checkboxes are randomly checked after going back in history, https://crbug.com/1138598
  82. window.on('pagehide', () => {
  83. $$('input[type=checkbox]').forEach((el, i) => (el.name = `bug${i}`));
  84. });
  85. }
  86. showStyles(styles, ids);
  87. require([
  88. '/manage/import-export',
  89. '/manage/incremental-search',
  90. '/manage/updater-ui',
  91. ]);
  92. })();
  93. msg.onExtension(onRuntimeMessage);
  94. window.on('closeOptions', () => router.updateHash(''));
  95. router.watch({hash: '#stylus-options'}, toggleEmbeddedOptions);
  96. function onRuntimeMessage(msg) {
  97. switch (msg.method) {
  98. case 'styleUpdated':
  99. case 'styleAdded':
  100. case 'styleDeleted':
  101. changeQueue.push(msg);
  102. if (performance.now() - (changeQueue.time || 0) < changeQueue.THROTTLE) {
  103. debounce(handleBulkChange, changeQueue.THROTTLE);
  104. } else {
  105. handleBulkChange();
  106. }
  107. break;
  108. case 'styleApply':
  109. case 'styleReplaceAll':
  110. break;
  111. default:
  112. return;
  113. }
  114. setTimeout(sorter.updateStripes, 0, {onlyWhenColumnsChanged: true});
  115. }
  116. async function toggleEmbeddedOptions(state) {
  117. const el = $('#stylus-embedded-options') ||
  118. state && document.documentElement.appendChild($create('iframe', {
  119. id: 'stylus-embedded-options',
  120. src: '/options.html',
  121. }));
  122. if (state) {
  123. el.focus();
  124. } else if (el) {
  125. el.contentDocument.body.classList.add('scaleout');
  126. await animateElement(el, 'fadeout');
  127. el.remove();
  128. }
  129. }