import $ from 'jquery'; import { config, translations } from 'grav-config'; import request from '../utils/request'; import { Instance as gpm } from '../utils/gpm'; import { Promise } from 'es6-promise'; class Sorter { getElements(elements, container) { this.elements = elements || $('[data-gpm-plugin], [data-gpm-theme]'); this.container = container || $('.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 = '') { let elements = this.getElements().sort((a, b) => { let A = $(a).data(data).toString().toLowerCase(); let B = $(b).data(data).toString().toLowerCase(); return Sorter.sort(A, B, direction); }); return elements.appendTo(this.container); } byName(direction = 'asc', data = 'gpm-name') { return this.byCommon(direction, data); } byAuthor(direction = 'asc', data = 'gpm-author') { return this.byCommon(direction, data); } byOfficial(direction = 'asc', data = 'gpm-official') { return this.byCommon(direction, data); } byReleaseDate(direction = 'asc', data = 'gpm-release-date') { let elements = this.getElements().sort((a, b) => { let A = new Date($(a).data(data)).getTime(); let B = new Date($(b).data(data)).getTime(); return Sorter.sort(A, B, direction === 'asc' ? 'desc' : 'asc'); }); elements.appendTo(this.container); } byUpdatable(direction = 'asc', data = 'gpm-updatable') { return this.byCommon(direction, data); } byEnabled(direction = 'asc', data = 'gpm-enabled') { return this.byCommon(direction, data); } byTesting(direction = 'asc', data = 'gpm-testing') { return this.byCommon(direction, data); } } 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} Remove`; if (slug) { text += ` (was needed by ${slug})`; } container.append(`
  • ${text}
  • `); } 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($('Removed successfully')); 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(`
  • ${name ? name : slug}, ${translations.PLUGIN_ADMIN.FROM} v${current_version} ${translations.PLUGIN_ADMIN.TO} v${available_version}
  • `); } else { list.append(`
  • ${name ? name : slug}
  • `); } } 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); Promise.all(slugs.map((slug) => { return new 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(`
  • ${name ? name : slug}, ${translations.PLUGIN_ADMIN.FROM} v${current_version} ${translations.PLUGIN_ADMIN.TO} v${available_version}
  • `); } else { $('.packages-names-list').append(`
  • ${name ? name : slug}
  • `); } }); 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();