index.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import $ from 'jquery';
  2. import unique from 'mout/array/unique';
  3. import { config, translations } from 'grav-config';
  4. import { Instance as gpm } from '../utils/gpm';
  5. import Notifications from './notifications';
  6. import Feed from './feed';
  7. import './check';
  8. import './update';
  9. import './channel-switcher';
  10. export default class Updates {
  11. constructor(payload = {}) {
  12. this.setPayload(payload);
  13. this.task = `task${config.param_sep}`;
  14. this.updateURL = '';
  15. }
  16. setPayload(payload = {}) {
  17. this.payload = payload;
  18. return this;
  19. }
  20. fetch(force = false) {
  21. gpm.fetch((response) => this.setPayload(response), force);
  22. return this;
  23. }
  24. maintenance(mode = 'hide') {
  25. let element = $('#updates [data-update-packages]');
  26. element[mode === 'show' ? 'fadeIn' : 'fadeOut']();
  27. if (mode === 'hide') {
  28. $('.badges.with-updates').removeClass('with-updates').find('.badge.updates').remove();
  29. }
  30. return this;
  31. }
  32. grav() {
  33. let payload = this.payload.grav;
  34. if (payload && payload.isUpdatable) {
  35. let task = this.task;
  36. let bar = '';
  37. if (!payload.isSymlink) {
  38. this.updateURL = `${config.base_url_relative}/update.json/${task}updategrav/admin-nonce${config.param_sep}${config.admin_nonce}`;
  39. bar += `<button data-remodal-target="update-grav" class="button button-small secondary pointer-events-none" id="grav-update-button">${translations.PLUGIN_ADMIN.UPDATE_GRAV_NOW} <span class="cnt-down">(5s)</span></button>`;
  40. } else {
  41. bar += `<span class="hint--left" style="float: right;" data-hint="${translations.PLUGIN_ADMIN.GRAV_SYMBOLICALLY_LINKED}"><i class="fa fa-fw fa-link"></i></span>`;
  42. }
  43. bar += `
  44. Grav <b>v${payload.available}</b> ${translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE}! <span class="less">(${translations.PLUGIN_ADMIN.CURRENT} v${payload.version})</span>
  45. `;
  46. let element = $('[data-gpm-grav]').removeClass('hidden');
  47. if (element.is(':empty')) {
  48. element.hide();
  49. }
  50. element
  51. .addClass('grav')
  52. .html(`${bar}`)
  53. .slideDown(150, function() {
  54. var c = 5;
  55. var x = setInterval(function() {
  56. c -= 1;
  57. element.find('.pointer-events-none .cnt-down').text('(' + c + 's)');
  58. }, 1000);
  59. setTimeout(function() {
  60. clearInterval(x);
  61. element.find('.pointer-events-none .cnt-down').remove();
  62. element.find('.pointer-events-none').removeClass('pointer-events-none');
  63. }, 5000);
  64. })
  65. .parent('#messages').addClass('default-box-shadow');
  66. }
  67. return this;
  68. }
  69. resources() {
  70. if (!this.payload || !this.payload.resources || !this.payload.resources.total) {
  71. return this.maintenance('hide');
  72. }
  73. let is_current_package_latest = true;
  74. let map = ['plugins', 'themes'];
  75. let singles = ['plugin', 'theme'];
  76. let { plugins, themes } = this.payload.resources;
  77. if (!this.payload.resources.total) { return this; }
  78. [plugins, themes].forEach(function(resources, index) {
  79. if (!resources || Array.isArray(resources)) { return; }
  80. let length = Object.keys(resources).length;
  81. let type = map[index];
  82. // sidebar
  83. $(`#admin-menu a[href$="/${map[index]}"]`)
  84. .find('.badges')
  85. .addClass('with-updates')
  86. .find('.badge.updates').text(length);
  87. var type_translation = '';
  88. // update all
  89. if (type === 'plugins') {
  90. type_translation = translations.PLUGIN_ADMIN.PLUGINS;
  91. } else {
  92. type_translation = translations.PLUGIN_ADMIN.THEMES;
  93. }
  94. let updateAll = $(`.grav-update.${type}`);
  95. updateAll.css('display', 'block').html(`
  96. <p>
  97. <a href="#" class="button button-small secondary" data-remodal-target="update-packages" data-packages-slugs="${Object.keys(resources).join()}" data-${singles[index]}-action="start-packages-update">${translations.PLUGIN_ADMIN.UPDATE} ${translations.PLUGIN_ADMIN.ALL} ${type_translation}</a>
  98. <i class="fa fa-bullhorn"></i>
  99. ${length} ${translations.PLUGIN_ADMIN.OF_YOUR} ${type_translation.toLowerCase()} ${translations.PLUGIN_ADMIN.HAVE_AN_UPDATE_AVAILABLE}
  100. </p>
  101. `);
  102. let existing_slugs = $('[data-update-packages]').attr('data-packages-slugs') || '';
  103. if (existing_slugs) {
  104. existing_slugs = existing_slugs.split(',');
  105. } else {
  106. existing_slugs = [];
  107. }
  108. let slugs = unique(existing_slugs.concat(Object.keys(resources))).join();
  109. $('[data-update-packages]').attr('data-packages-slugs', `${slugs}`);
  110. Object.keys(resources).forEach(function(item) {
  111. // listing page
  112. let container = $(`[data-gpm-${singles[index]}="${item}"]`);
  113. let element = container.find('.gpm-name');
  114. let url = element.find('a');
  115. let content_wrapper = container.parents('.content-wrapper');
  116. if (type === 'plugins' && !element.find('.badge.update').length) {
  117. element.append(`<a class="plugin-update-button" href="${url.attr('href')}"><span class="badge update">${translations.PLUGIN_ADMIN.UPDATE_AVAILABLE}!</span></a>`);
  118. content_wrapper.addClass('has-updates');
  119. } else if (type === 'themes') {
  120. element.append(`<div class="gpm-ribbon"><a href="${url.attr('href')}">${translations.PLUGIN_ADMIN.UPDATE.toUpperCase()}</a></div>`);
  121. content_wrapper.addClass('has-updates');
  122. }
  123. // details page
  124. if (container.length) {
  125. let details = $(`.grav-update.${singles[index]}`);
  126. if (details.length) {
  127. let releaseType = resources[item].type === 'testing' ? '<span class="gpm-testing">test release</span>' : '';
  128. details.html(`
  129. <p>
  130. <a href="#" class="button button-small secondary" data-remodal-target="update-packages" data-packages-slugs="${item}" data-${singles[index]}-action="start-package-installation">${translations.PLUGIN_ADMIN.UPDATE} ${singles[index].charAt(0).toUpperCase() + singles[index].substr(1).toLowerCase()}</a>
  131. <i class="fa fa-bullhorn"></i>
  132. <strong>v${resources[item].available}</strong> ${releaseType} ${translations.PLUGIN_ADMIN.OF_THIS} ${singles[index]} ${translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE}!
  133. </p>
  134. `).css('display', 'block');
  135. is_current_package_latest = false;
  136. }
  137. }
  138. });
  139. $('[data-update-packages]').removeClass('hidden');
  140. });
  141. $('.content-wrapper').addClass('updates-checked');
  142. if (!is_current_package_latest) {
  143. $('.warning-reinstall-not-latest-release').removeClass('hidden');
  144. }
  145. }
  146. }
  147. let Instance = new Updates();
  148. export { Instance, Notifications, Feed };
  149. // automatically refresh UI for updates (graph, sidebar, plugin/themes pages) after every fetch
  150. gpm.on('fetched', (response, raw) => {
  151. Instance.setPayload(response.payload || {});
  152. Instance.grav().resources();
  153. });
  154. if (config.enable_auto_updates_check === '1') {
  155. gpm.fetch();
  156. }