Replace themes preview popup with a modal

Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
This commit is contained in:
Maurício Meneghini Fauth 2021-02-04 23:21:31 -03:00
parent af946c5e53
commit 12d662baa3
No known key found for this signature in database
GPG Key ID: 6A16FD38AFC89CC8
14 changed files with 104 additions and 172 deletions

View File

@ -4479,46 +4479,16 @@ $(window).on('popstate', function () {
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
$(document).off('click', 'a.themeselect');
$(document).off('change', '.autosubmit');
$('a.take_theme').off('click');
});
AJAX.registerOnload('functions.js', function () {
/**
* Theme selector.
*/
$(document).on('click', 'a.themeselect', function (e) {
window.open(
e.target,
'themes',
'left=10,top=20,width=510,height=350,scrollbars=yes,status=yes,resizable=yes'
);
return false;
});
/**
* Automatic form submission on change.
*/
$(document).on('change', '.autosubmit', function () {
$(this).closest('form').trigger('submit');
});
/**
* Theme changer.
*/
$('a.take_theme').on('click', function () {
var what = this.name;
/* eslint-disable compat/compat */
if (window.opener && window.opener.document.forms.setTheme.elements.set_theme) {
window.opener.document.forms.setTheme.elements.set_theme.value = what;
window.opener.document.forms.setTheme.submit();
window.close();
return false;
}
/* eslint-enable compat/compat */
return true;
});
});
/**

11
js/src/home.js Normal file
View File

@ -0,0 +1,11 @@
AJAX.registerTeardown('home.js', function () {
$('#themesModal').off('show.bs.modal');
});
AJAX.registerOnload('home.js', function () {
$('#themesModal').on('show.bs.modal', function () {
$.get('index.php?route=/themes', function (data) {
$('#themesModal .modal-body').html(data.themes);
});
});
});

View File

@ -21,7 +21,6 @@ use PhpMyAdmin\Server\Select;
use PhpMyAdmin\Template;
use PhpMyAdmin\ThemeManager;
use PhpMyAdmin\Url;
use PhpMyAdmin\UserPreferences;
use PhpMyAdmin\Util;
use const E_USER_NOTICE;
use const E_USER_WARNING;
@ -68,6 +67,8 @@ class HomeController extends AbstractController
return;
}
$this->addScriptFiles(['home.js']);
// This is for $cfg['ShowDatabasesNavigationAsTree'] = false;
// See: https://github.com/phpmyadmin/phpmyadmin/issues/16520
// The DB is defined here and sent to the JS front-end to refresh the DB tree
@ -237,25 +238,13 @@ class HomeController extends AbstractController
'show_php_info' => $cfg['ShowPhpInfo'],
'is_version_checked' => $cfg['VersionCheck'],
'phpmyadmin_version' => PMA_VERSION,
'phpmyadmin_major_version' => PMA_MAJOR_VERSION,
'config_storage_message' => $configStorageMessage ?? '',
'has_theme_manager' => $cfg['ThemeManager'],
'themes' => $this->themeManager->getThemesArray(),
]);
}
public function setTheme(): void
{
$this->themeManager->setActiveTheme($_POST['set_theme']);
$this->themeManager->setThemeCookie();
$userPreferences = new UserPreferences();
$preferences = $userPreferences->load();
$preferences['config_data']['ThemeDefault'] = $_POST['set_theme'];
$userPreferences->save($preferences['config_data']);
$this->response->header('Location: index.php?route=/' . Url::getCommonRaw([], '&'));
}
public function setCollationConnection(): void
{
$this->config->setUserValue(

View File

@ -4,29 +4,52 @@ declare(strict_types=1);
namespace PhpMyAdmin\Controllers;
use PhpMyAdmin\Response;
use PhpMyAdmin\Template;
use PhpMyAdmin\ThemeManager;
use function preg_replace;
use PhpMyAdmin\Url;
use PhpMyAdmin\UserPreferences;
/**
* Displays list of themes.
*/
class ThemesController extends AbstractController
{
/** @var ThemeManager */
private $themeManager;
/**
* @param Response $response
*/
public function __construct($response, Template $template, ThemeManager $themeManager)
{
parent::__construct($response, $template);
$this->themeManager = $themeManager;
}
public function index(): void
{
$this->response->getFooter()->setMinimal();
$header = $this->response->getHeader();
$header->setBodyId('bodythemes');
$header->setTitle('phpMyAdmin - ' . __('Theme'));
$header->disableMenuAndConsole();
$themes = $this->themeManager->getThemesArray();
$themesList = $this->template->render('home/themes', ['themes' => $themes]);
$this->response->setAjax(true);
$this->response->addJSON('themes', $themesList);
}
$this->render('themes', [
'version' => preg_replace(
'/([0-9]*)\.([0-9]*)\..*/',
'\1_\2',
PMA_VERSION
),
'previews' => ThemeManager::getInstance()->getPrintPreviews(),
]);
public function setTheme(): void
{
global $cfg;
if (! $cfg['ThemeManager'] || ! isset($_POST['set_theme'])) {
$this->response->header('Location: index.php?route=/' . Url::getCommonRaw([], '&'));
return;
}
$this->themeManager->setActiveTheme($_POST['set_theme']);
$this->themeManager->setThemeCookie();
$userPreferences = new UserPreferences();
$preferences = $userPreferences->load();
$preferences['config_data']['ThemeDefault'] = $_POST['set_theme'];
$userPreferences->save($preferences['config_data']);
$this->response->header('Location: index.php?route=/' . Url::getCommonRaw([], '&'));
}
}

View File

@ -93,14 +93,6 @@ class Theme
'icons',
];
/** @var Template */
public $template;
public function __construct()
{
$this->template = new Template();
}
/**
* Loads theme information
*
@ -391,28 +383,4 @@ class Theme
return './themes/' . ThemeManager::FALLBACK_THEME . '/img/' . $file;
}
/**
* Renders the preview for this theme
*
* @return string
*
* @access public
*/
public function getPrintPreview()
{
$url_params = ['set_theme' => $this->getId()];
$screen = null;
if (@file_exists($this->getFsPath() . 'screen.png')) {
$screen = $this->getPath() . '/screen.png';
}
return $this->template->render('theme_preview', [
'url_params' => $url_params,
'name' => $this->getName(),
'version' => $this->getVersion(),
'id' => $this->getId(),
'screen' => $screen,
]);
}
}

View File

@ -269,21 +269,6 @@ class ThemeManager
return $themes;
}
/**
* Renders the previews for all themes
*
* @access public
*/
public function getPrintPreviews(): string
{
$retval = '';
foreach ($this->themes as $each_theme) {
$retval .= $each_theme->getPrintPreview();
}
return $retval;
}
public static function initializeTheme(): ?Theme
{
$themeManager = self::getInstance();

View File

@ -106,7 +106,6 @@ if (! defined('PHPMYADMIN')) {
return static function (RouteCollector $routes): void {
$routes->addGroup('', static function (RouteCollector $routes): void {
$routes->addRoute(['GET', 'POST'], '[/]', [HomeController::class, 'index']);
$routes->post('/set-theme', [HomeController::class, 'setTheme']);
$routes->post('/collation-connection', [HomeController::class, 'setCollationConnection']);
$routes->addRoute(['GET', 'POST'], '/recent-table', [HomeController::class, 'reloadRecentTablesList']);
$routes->addRoute(['GET', 'POST'], '/git-revision', [HomeController::class, 'gitRevision']);
@ -331,7 +330,10 @@ return static function (RouteCollector $routes): void {
$routes->addRoute(['GET', 'POST'], '/zoom-search', [ZoomSearchController::class, 'index']);
});
$routes->post('/tables', [TableController::class, 'all']);
$routes->get('/themes', [ThemesController::class, 'index']);
$routes->addGroup('/themes', static function (RouteCollector $routes): void {
$routes->get('', [ThemesController::class, 'index']);
$routes->post('/set', [ThemesController::class, 'setTheme']);
});
$routes->addGroup('/transformation', static function (RouteCollector $routes): void {
$routes->addRoute(['GET', 'POST'], '/overview', [TransformationOverviewController::class, 'index']);
$routes->addRoute(['GET', 'POST'], '/wrapper', [TransformationWrapperController::class, 'index']);

View File

@ -854,6 +854,7 @@ return [
'arguments' => [
'$response' => '@response',
'$template' => '@template',
'$themeManager' => '@theme_manager',
],
],
PhpMyAdmin\Controllers\TransformationOverviewController::class => [

View File

@ -98,12 +98,10 @@
{% if has_theme_manager %}
<li id="li_select_theme" class="list-group-item">
{{ get_image('s_theme') }}
<form name="setTheme" method="post" action="{{ url('/set-theme') }}" class="disableAjax">
<form method="post" action="{{ url('/themes/set') }}" class="disableAjax">
{{ get_hidden_inputs() }}
<a href="{{ url('/themes') }}" target="themes" class="themeselect">
{% trans 'Theme:' %}
<a href="#" data-bs-toggle="modal" data-bs-target="#themesModal" role="button">
{{- get_icon('s_theme', 'Theme:'|trans) -}}
</a>
<select name="set_theme" lang="en" dir="ltr" class="autosubmit" aria-label="{% trans 'Theme' %}">
{% for theme in themes %}
@ -241,4 +239,28 @@
</div>
</div>
{% if has_theme_manager %}
<div class="modal fade" id="themesModal" tabindex="-1" aria-labelledby="themesModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="themesModalLabel">{% trans 'phpMyAdmin Themes' %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans 'Close' %}"></button>
</div>
<div class="modal-body">
<div class="spinner-border" role="status">
<span class="visually-hidden">{% trans 'Loading…' %}</span>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans 'Close' %}</button>
<a href="{{ 'https://www.phpmyadmin.net/themes/'|link }}#pma_{{ phpmyadmin_major_version|replace({'.': '_'}) }}" class="btn btn-primary" rel="noopener noreferrer" target="_blank">
{% trans 'Get more themes!' %}
</a>
</div>
</div>
</div>
</div>
{% endif %}
{{ config_storage_message|raw }}

View File

@ -0,0 +1,18 @@
<form method="post" action="{{ url('/themes/set') }}" class="disableAjax">
{{ get_hidden_inputs() }}
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-4 g-4">
{% for theme in themes %}
<div class="col">
<div class="card">
<img src="./themes/{{ theme.id }}/screen.png" class="card-img-top" alt="{{ 'Screenshot of the %s theme.'|trans|format(theme.name) }}">
<div class="card-body">
<h5 class="card-title">{{ theme.name }} <small>({{ theme.version }})</small></h5>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-primary" name="set_theme" value="{{ theme.id }}">{% trans 'Take it' %}</button>
</div>
</div>
</div>
{% endfor %}
</div>
</form>

View File

@ -1,16 +0,0 @@
<div class="theme_preview">
<h2>
{{ name }} ({{ version }})
</h2>
<p>
<a class="take_theme" name="{{ id }}" href="{{ url('/set-theme', url_params) }}">
{% if screen is not empty %}
<img src="{{ screen }}" alt="{{ name }}" title="{{ name }}">
<br>
{% else %}
{% trans 'No preview available.' %}
{% endif %}
[ <strong>{% trans 'Take it' %}</strong> ]
</a>
</p>
</div>

View File

@ -1,7 +0,0 @@
<h1>phpMyAdmin - {% trans 'Theme' %}</h1>
<p>
<a href="{{ 'https://www.phpmyadmin.net/themes/'|link }}#pma_{{ version }}" rel="noopener noreferrer" target="_blank">
{% trans 'Get more themes!' %}
</a>
</p>
{{ previews|raw }}

View File

@ -71,18 +71,4 @@ class ThemeManagerTest extends AbstractTestCase
$tm->setThemeCookie()
);
}
/**
* Test for getPrintPreviews
*/
public function testGetPrintPreviews(): void
{
$tm = new ThemeManager();
$preview = $tm->getPrintPreviews();
$this->assertStringContainsString('<div class="theme_preview"', $preview);
$this->assertStringContainsString('Original', $preview);
$this->assertStringContainsString('set_theme=original', $preview);
$this->assertStringContainsString('pmahomme', $preview);
$this->assertStringContainsString('set_theme=pmahomme', $preview);
}
}

View File

@ -200,26 +200,6 @@ class ThemeTest extends AbstractTestCase
$this->assertEquals('/new/path', $this->object->getImgPath());
}
/**
* Test for getPrintPreview().
*/
public function testGetPrintPreview(): void
{
parent::setLanguage();
$this->assertStringContainsString(
'<h2>' . "\n" . ' (0.0.0.0)',
$this->object->getPrintPreview()
);
$this->assertStringContainsString(
'name="" href="index.php?route=/set-theme&amp;set_theme=&amp;server=99&amp;lang=en">',
$this->object->getPrintPreview()
);
$this->assertStringContainsString(
'No preview available.',
$this->object->getPrintPreview()
);
}
/**
* Test for getImgPath
*