news/plugins/admin/themes/grav/app/utils/packages.js

498 lines
18 KiB
JavaScript

import $ from 'jquery';
import { config, translations } from 'grav-config';
import request from '../utils/request';
import { Instance as gpm } from '../utils/gpm';
class Sorter {
getElements(elements, container) {
this.elements = elements || document.querySelectorAll('[data-gpm-plugin], [data-gpm-theme]');
this.container = container || document.querySelector('.gpm-plugins > table > tbody, .gpm-themes > .themes.card-row');
return this.elements;
}
static sort(A, B, direction = 'asc') {
if (A > B) { return (direction === 'asc') ? 1 : -1; }
if (A < B) { return (direction === 'asc') ? -1 : 1; }
return 0;
}
byCommon(direction = 'asc', data = '') {
const elements = this.getElements();
this.removeGumroad();
Array.from(elements).sort((a, b) => {
let A = a.dataset[data].toString().toLowerCase();
let B = b.dataset[data].toString().toLowerCase();
return Sorter.sort(A, B, direction);
}).forEach((element) => {
this.container.appendChild(element);
});
this.addGumroad();
return this.container;
}
byName(direction = 'asc', data = 'gpmName') {
return this.byCommon(direction, data);
}
byAuthor(direction = 'asc', data = 'gpmAuthor') {
return this.byCommon(direction, data);
}
byOfficial(direction = 'asc', data = 'gpmOfficial') {
return this.byCommon(direction, data);
}
byPremium(direction = 'asc', data = 'gpmPremium') {
return this.byCommon(direction, data);
}
byReleaseDate(direction = 'asc', data = 'gpmReleaseDate') {
const elements = this.getElements();
this.removeGumroad();
Array.from(elements).sort((a, b) => {
let A = new Date(a.dataset[data]).getTime();
let B = new Date(b.dataset[data]).getTime();
return Sorter.sort(A, B, direction === 'asc' ? 'desc' : 'asc');
}).forEach((element) => {
this.container.appendChild(element);
});
this.addGumroad();
return this.container;
}
byUpdatable(direction = 'asc', data = 'gpmUpdatable') {
return this.byCommon(direction, data);
}
byEnabled(direction = 'asc', data = 'gpmEnabled') {
return this.byCommon(direction, data);
}
byTesting(direction = 'asc', data = 'gpmTesting') {
return this.byCommon(direction, data);
}
addGumroad() {
if (window.GumroadOverlay) {
window.GumroadOverlay.startNodeAdditionObserver();
}
}
removeGumroad() {
if (window.GumroadOverlay) {
window.GumroadOverlay.nodeAdditionObserver.disconnect();
}
}
}
class Packages {
constructor() {
this.Sort = new Sorter();
}
static getBackToList(type) {
global.location.href = `${config.base_url_relative}/${type}s`;
}
static addDependencyToList(type, dependency, slug = '') {
if (['admin', 'form', 'login', 'email', 'grav'].indexOf(dependency) !== -1) { return; }
let container = $('.package-dependencies-container');
let text = `${dependency} <a href="#" class="button" data-dependency-slug="${dependency}" data-${type}-action="remove-dependency-package">Remove</a>`;
if (slug) {
text += ` (was needed by ${slug})`;
}
container.append(`<li>${text}</li>`);
}
addDependenciesToList(dependencies, slug = '') {
dependencies.forEach((dependency) => {
Packages.addDependencyToList('plugin', dependency.name || dependency, slug);
});
}
static getTaskUrl(type, task) {
let url = `${config.base_url_relative}`;
url += `/${type}s.json`;
url += `/task${config.param_sep}${task}`;
return url;
}
static getRemovePackageUrl(type) {
return `${Packages.getTaskUrl(type, 'removePackage')}`;
}
static getReinstallPackageUrl(type) {
return `${Packages.getTaskUrl(type, 'reinstallPackage')}`;
}
static getGetPackagesDependenciesUrl(type) {
return `${Packages.getTaskUrl(type, 'getPackagesDependencies')}`;
}
static getInstallDependenciesOfPackagesUrl(type) {
return `${Packages.getTaskUrl(type, 'installDependenciesOfPackages')}`;
}
static getInstallPackageUrl(type) {
return `${Packages.getTaskUrl(type, 'installPackage')}`;
}
removePackage(type, slug) {
let url = Packages.getRemovePackageUrl(type);
request(url, {
method: 'post',
body: {
package: slug
}
}, (response) => {
if (response.status === 'success') {
$('.remove-package-confirm').addClass('hidden');
if (response.dependencies && response.dependencies.length > 0) {
this.addDependenciesToList(response.dependencies);
$('.remove-package-dependencies').removeClass('hidden');
} else {
$('.remove-package-done').removeClass('hidden');
}
// The package was removed. When the modal closes, move to the packages list
$(document).on('closing', '[data-remodal-id="remove-package"]', () => {
Packages.getBackToList(type);
});
} else {
$('.remove-package-confirm').addClass('hidden');
$('.remove-package-error').removeClass('hidden');
}
});
}
reinstallPackage(type, slug, package_name, current_version) {
$('.button-bar button').addClass('hidden');
$('.button-bar .spinning-wheel').removeClass('hidden');
let url = Packages.getReinstallPackageUrl(type);
request(url, {
method: 'post',
body: {
slug: slug,
type: type,
package_name: package_name,
current_version: current_version
}
}, (response) => {
if (response.status === 'success') {
$('.reinstall-package-confirm').addClass('hidden');
$('.reinstall-package-done').removeClass('hidden');
} else {
$('.reinstall-package-confirm').addClass('hidden');
$('.reinstall-package-error').removeClass('hidden');
}
window.location.reload();
});
}
removeDependency(type, slug, button) {
let url = Packages.getRemovePackageUrl(type);
request(url, {
method: 'post',
body: {
package: slug
}
}, (response) => {
if (response.status === 'success') {
button.removeClass('button');
button.replaceWith($('<span>Removed successfully</span>'));
if (response.dependencies && response.dependencies.length > 0) {
this.addDependenciesToList(response.dependencies, slug);
}
}
});
}
static addNeededDependencyToList(action, slug) {
$('.install-dependencies-package-container .type-' + action).removeClass('hidden');
let list = $('.install-dependencies-package-container .type-' + action + ' ul');
if (action !== 'install') {
let current_version = '';
let available_version = '';
let name = '';
let resources = gpm.payload.payload.resources;
if (resources.plugins[slug]) {
available_version = resources.plugins[slug].available;
current_version = resources.plugins[slug].version;
name = resources.plugins[slug].name;
} else if (resources.themes[slug]) {
available_version = resources.themes[slug].available;
current_version = resources.themes[slug].version;
name = resources.themes[slug].name;
}
list.append(`<li>${name ? name : slug}, ${translations.PLUGIN_ADMIN.FROM} v<strong>${current_version}</strong> ${translations.PLUGIN_ADMIN.TO} v<strong>${available_version}</strong></li>`);
} else {
list.append(`<li>${name ? name : slug}</li>`);
}
}
getPackagesDependencies(type, slugs, finishedLoadingCallback) {
let url = Packages.getGetPackagesDependenciesUrl(type);
request(url, {
method: 'post',
body: {
packages: slugs
}
}, (response) => {
finishedLoadingCallback();
if (response.status === 'success') {
if (response.dependencies) {
let hasDependencies = false;
for (var dependency in response.dependencies) {
if (response.dependencies.hasOwnProperty(dependency)) {
if (dependency === 'grav') {
continue;
}
hasDependencies = true;
let dependencyName = dependency;
let action = response.dependencies[dependency];
Packages.addNeededDependencyToList(action, dependencyName);
}
}
if (hasDependencies) {
$('[data-packages-modal] .install-dependencies-package-container').removeClass('hidden');
} else {
$('[data-packages-modal] .install-package-container').removeClass('hidden');
}
} else {
$('[data-packages-modal] .install-package-container').removeClass('hidden');
}
} else {
$('[data-packages-modal] .install-package-error').removeClass('hidden');
}
});
}
installDependenciesOfPackages(type, slugs, callbackSuccess, callbackError) {
let url = Packages.getInstallDependenciesOfPackagesUrl(type);
request(url, {
method: 'post',
body: {
packages: slugs
}
}, callbackSuccess);
}
installPackages(type, slugs, callbackSuccess) {
let url = Packages.getInstallPackageUrl(type);
global.Promise.all(slugs.map((slug) => {
return new global.Promise((resolve, reject) => {
request(url, {
method: 'post',
body: {
package: slug,
type: type
}
}, (response) => {
resolve(response);
});
});
})).then(callbackSuccess);
}
static getSlugsFromEvent(event) {
let slugs = '';
if ($(event.target).is('[data-packages-slugs]')) {
slugs = $(event.target).attr('data-packages-slugs');
} else {
slugs = $(event.target).parent('[data-packages-slugs]').attr('data-packages-slugs');
}
if (typeof slugs === 'undefined') {
return null;
}
slugs = slugs.split(',');
return typeof slugs === 'string' ? [slugs] : slugs;
}
handleGettingPackageDependencies(type, event, action = 'update') {
let slugs = Packages.getSlugsFromEvent(event);
if (!slugs) {
alert('No slug set');
return;
}
// Cleanup
$('.packages-names-list').html('');
$('.install-dependencies-package-container li').remove();
slugs.forEach((slug) => {
if (action === 'update') {
let current_version = '';
let available_version = '';
let name = '';
let resources = gpm.payload.payload.resources;
if (resources.plugins[slug]) {
available_version = resources.plugins[slug].available;
current_version = resources.plugins[slug].version;
name = resources.plugins[slug].name;
} else if (resources.themes[slug]) {
available_version = resources.themes[slug].available;
current_version = resources.themes[slug].version;
name = resources.themes[slug].name;
}
$('.packages-names-list').append(`<li>${name ? name : slug}, ${translations.PLUGIN_ADMIN.FROM} v<strong>${current_version}</strong> ${translations.PLUGIN_ADMIN.TO} v<strong>${available_version}</strong></li>`);
} else {
$('.packages-names-list').append(`<li>${name ? name : slug}</li>`);
}
});
event.preventDefault();
event.stopPropagation();
// fix mismatching types when sharing install modal between plugins/themes
const query = '[data-packages-modal] [data-theme-action], [data-packages-modal] [data-plugin-action]';
const data = $(query).data('themeAction') || $(query).data('pluginAction');
$(query).removeAttr('data-theme-action').removeAttr('data-plugin-action').attr(`data-${type}-action`, data);
// Restore original state
$('[data-packages-modal] .loading').removeClass('hidden');
$('[data-packages-modal] .install-dependencies-package-container').addClass('hidden');
$('[data-packages-modal] .install-package-container').addClass('hidden');
$('[data-packages-modal] .installing-dependencies').addClass('hidden');
$('[data-packages-modal] .installing-package').addClass('hidden');
$('[data-packages-modal] .installation-complete').addClass('hidden');
$('[data-packages-modal] .install-package-error').addClass('hidden');
this.getPackagesDependencies(type, slugs, () => {
let slugs_string = slugs.join();
$(`[data-packages-modal] [data-${type}-action="install-dependencies-and-package"]`).attr('data-packages-slugs', slugs_string);
$(`[data-packages-modal] [data-${type}-action="install-package"]`).attr('data-packages-slugs', slugs_string);
$('[data-packages-modal] .loading').addClass('hidden');
});
}
handleInstallingDependenciesAndPackage(type, event) {
let slugs = Packages.getSlugsFromEvent(event);
event.preventDefault();
event.stopPropagation();
$('[data-packages-modal] .install-dependencies-package-container').addClass('hidden');
$('[data-packages-modal] .install-package-container').addClass('hidden');
$('[data-packages-modal] .installing-dependencies').removeClass('hidden');
this.installDependenciesOfPackages(type, slugs, (response) => {
$('[data-packages-modal] .installing-dependencies').addClass('hidden');
$('[data-packages-modal] .installing-package').removeClass('hidden');
this.installPackages(type, slugs, () => {
$('[data-packages-modal] .installing-package').addClass('hidden');
$('[data-packages-modal] .installation-complete').removeClass('hidden');
if (response.status === 'error') {
let remodal = $.remodal.lookup[$('[data-packages-modal]').data('remodal')];
remodal.close();
return;
}
setTimeout(() => {
if (slugs.length === 1) {
global.location.href = `${config.base_url_relative}/${type}s/${slugs[0]}`;
} else {
global.location.href = `${config.base_url_relative}/${type}s`;
}
}, 1000);
});
});
}
handleInstallingPackage(type, event) {
let slugs = Packages.getSlugsFromEvent(event);
event.preventDefault();
event.stopPropagation();
$('[data-packages-modal] .install-package-container').addClass('hidden');
$('[data-packages-modal] .installing-package').removeClass('hidden');
this.installPackages(type, slugs, (response) => {
$('[data-packages-modal] .installing-package').addClass('hidden');
$('[data-packages-modal] .installation-complete').removeClass('hidden');
const errors = Array.from(response).filter((r) => r.status === 'error');
if (errors && errors.length) {
let remodal = $.remodal.lookup[$('[data-packages-modal].remodal-is-opened').data('remodal')];
remodal.close();
return;
}
if (slugs.length === 1) {
global.location.href = `${config.base_url_relative}/${type}s/${slugs[0]}`;
} else {
global.location.href = `${config.base_url_relative}/${type}s`;
}
});
}
handleRemovingPackage(type, event) {
let slug = $(event.target).attr('data-packages-slugs');
event.preventDefault();
event.stopPropagation();
this.removePackage(type, slug);
}
handleReinstallPackage(type, event) {
let target = $(event.target);
let slug = target.attr('data-package-slug');
let package_name = target.attr('data-package-name');
let current_version = target.attr('data-package-current-version');
event.preventDefault();
event.stopPropagation();
this.reinstallPackage(type, slug, package_name, current_version);
}
handleRemovingDependency(type, event) {
let slug = $(event.target).attr('data-dependency-slug');
let button = $(event.target);
event.preventDefault();
event.stopPropagation();
this.removeDependency(type, slug, button);
}
}
export default new Packages();