1
0

updater-ui.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /* global messageBox */
  2. /* global ENTRY_ID_PREFIX, newUI */
  3. /* global filtersSelector, filterAndAppend */
  4. 'use strict';
  5. onDOMready().then(() => {
  6. $('#check-all-updates').onclick = checkUpdateAll;
  7. $('#check-all-updates-force').onclick = checkUpdateAll;
  8. $('#apply-all-updates').onclick = applyUpdateAll;
  9. $('#update-history').onclick = showUpdateHistory;
  10. });
  11. function applyUpdateAll() {
  12. const btnApply = $('#apply-all-updates');
  13. btnApply.disabled = true;
  14. setTimeout(() => {
  15. btnApply.classList.add('hidden');
  16. btnApply.disabled = false;
  17. renderUpdatesOnlyFilter({show: false});
  18. }, 1000);
  19. $$('.can-update .update').forEach(button => {
  20. scrollElementIntoView(button);
  21. button.click();
  22. });
  23. }
  24. function checkUpdateAll() {
  25. document.body.classList.add('update-in-progress');
  26. $('#check-all-updates').disabled = true;
  27. $('#check-all-updates-force').classList.add('hidden');
  28. $('#apply-all-updates').classList.add('hidden');
  29. $('#update-all-no-updates').classList.add('hidden');
  30. const ignoreDigest = this && this.id === 'check-all-updates-force';
  31. $$('.updatable:not(.can-update)' + (ignoreDigest ? '' : ':not(.update-problem)'))
  32. .map(el => checkUpdate(el, {single: false}));
  33. let total = 0;
  34. let checked = 0;
  35. let skippedEdited = 0;
  36. let updated = 0;
  37. BG.updater.checkAllStyles({observer, save: false, ignoreDigest}).then(done);
  38. function observer(state, value, details) {
  39. switch (state) {
  40. case BG.updater.COUNT:
  41. total = value;
  42. break;
  43. case BG.updater.UPDATED:
  44. if (++updated === 1) {
  45. $('#apply-all-updates').disabled = true;
  46. $('#apply-all-updates').classList.remove('hidden');
  47. }
  48. $('#apply-all-updates').dataset.value = updated;
  49. // fallthrough
  50. case BG.updater.SKIPPED:
  51. checked++;
  52. if (details === BG.updater.EDITED || details === BG.updater.MAYBE_EDITED) {
  53. skippedEdited++;
  54. }
  55. reportUpdateState(state, value, details);
  56. break;
  57. }
  58. const progress = $('#update-progress');
  59. const maxWidth = progress.parentElement.clientWidth;
  60. progress.style.width = Math.round(checked / total * maxWidth) + 'px';
  61. }
  62. function done() {
  63. document.body.classList.remove('update-in-progress');
  64. $('#check-all-updates').disabled = total === 0;
  65. $('#apply-all-updates').disabled = false;
  66. renderUpdatesOnlyFilter({check: updated + skippedEdited > 0});
  67. if (!updated) {
  68. $('#update-all-no-updates').dataset.skippedEdited = skippedEdited > 0;
  69. $('#update-all-no-updates').classList.remove('hidden');
  70. $('#check-all-updates-force').classList.toggle('hidden', skippedEdited === 0);
  71. }
  72. }
  73. }
  74. function checkUpdate(entry, {single = true} = {}) {
  75. $('.update-note', entry).textContent = t('checkingForUpdate');
  76. $('.check-update', entry).title = '';
  77. if (single) {
  78. BG.updater.checkStyle({
  79. save: false,
  80. ignoreDigest: entry.classList.contains('update-problem'),
  81. style: BG.cachedStyles.byId.get(entry.styleId),
  82. observer: reportUpdateState,
  83. });
  84. }
  85. entry.classList.remove('checking-update', 'no-update', 'update-problem');
  86. entry.classList.add('checking-update');
  87. }
  88. function reportUpdateState(state, style, details) {
  89. const entry = $(ENTRY_ID_PREFIX + style.id);
  90. entry.classList.remove('checking-update');
  91. switch (state) {
  92. case BG.updater.UPDATED:
  93. entry.classList.add('can-update');
  94. entry.updatedCode = style;
  95. $('.update-note', entry).textContent = '';
  96. $('#onlyUpdates').classList.remove('hidden');
  97. break;
  98. case BG.updater.SKIPPED: {
  99. if (entry.classList.contains('can-update')) {
  100. break;
  101. }
  102. const same = (
  103. details === BG.updater.SAME_MD5 ||
  104. details === BG.updater.SAME_CODE ||
  105. details === BG.updater.SAME_VERSION
  106. );
  107. const edited = details === BG.updater.EDITED || details === BG.updater.MAYBE_EDITED;
  108. entry.dataset.details = details;
  109. if (!details) {
  110. details = t('updateCheckFailServerUnreachable');
  111. } else if (typeof details === 'number') {
  112. details = t('updateCheckFailBadResponseCode', [details]);
  113. } else if (details === BG.updater.EDITED) {
  114. details = t('updateCheckSkippedLocallyEdited') + '\n' + t('updateCheckManualUpdateHint');
  115. } else if (details === BG.updater.MAYBE_EDITED) {
  116. details = t('updateCheckSkippedMaybeLocallyEdited') + '\n' + t('updateCheckManualUpdateHint');
  117. }
  118. const message = same ? t('updateCheckSucceededNoUpdate') : details;
  119. entry.classList.add('no-update');
  120. entry.classList.toggle('update-problem', !same);
  121. $('.update-note', entry).textContent = message;
  122. $('.check-update', entry).title = newUI.enabled ? message : '';
  123. $('.update', entry).title = t(edited ? 'updateCheckManualUpdateForce' : 'installUpdate');
  124. if (!document.body.classList.contains('update-in-progress')) {
  125. // this is a single update job so we can decide whether to hide the filter
  126. renderUpdatesOnlyFilter({show: $('.can-update, .update-problem')});
  127. }
  128. }
  129. }
  130. if (filtersSelector.hide) {
  131. filterAndAppend({entry});
  132. }
  133. }
  134. function renderUpdatesOnlyFilter({show, check} = {}) {
  135. const numUpdatable = $$('.can-update').length;
  136. const mightUpdate = numUpdatable > 0 || $('.update-problem');
  137. const checkbox = $('#onlyUpdates input');
  138. show = show !== undefined ? show : mightUpdate;
  139. check = check !== undefined ? show && check : checkbox.checked && mightUpdate;
  140. $('#onlyUpdates').classList.toggle('hidden', !show);
  141. checkbox.checked = check;
  142. checkbox.dispatchEvent(new Event('change'));
  143. const btnApply = $('#apply-all-updates');
  144. if (!btnApply.matches('.hidden')) {
  145. if (numUpdatable > 0) {
  146. btnApply.dataset.value = numUpdatable;
  147. } else {
  148. btnApply.classList.add('hidden');
  149. }
  150. }
  151. }
  152. function showUpdateHistory() {
  153. BG.chromeLocal.getValue('updateLog').then((lines = []) => {
  154. messageBox({
  155. title: t('updateCheckHistory'),
  156. contents: $element({
  157. className: 'update-history-log',
  158. textContent: lines.join('\n'),
  159. }),
  160. buttons: [t('confirmOK')],
  161. onshow: () => ($('#message-box-contents').scrollTop = 1e9),
  162. });
  163. });
  164. }
  165. function handleUpdateInstalled(entry) {
  166. entry.classList.add('update-done');
  167. entry.classList.remove('can-update', 'updatable');
  168. $('.update-note', entry).textContent = t('updateCompleted');
  169. renderUpdatesOnlyFilter();
  170. }