Merge pull request #19176 from MauricioFauth/footer-modals

Merge header.twig and footer.twig into base.twig
This commit is contained in:
Maurício Meneghini Fauth 2024-05-24 10:47:47 -03:00 committed by GitHub
commit 61e5dfa19f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 336 additions and 414 deletions

View File

@ -13620,8 +13620,6 @@
<code><![CDATA[Config::getInstance()]]></code>
<code><![CDATA[Config::getInstance()]]></code>
<code><![CDATA[Config::getInstance()]]></code>
<code><![CDATA[Config::getInstance()]]></code>
<code><![CDATA[Config::getInstance()]]></code>
</DeprecatedMethod>
<InaccessibleProperty>
<code><![CDATA[$config->config->debug->sql]]></code>
@ -13758,6 +13756,7 @@
<code><![CDATA[Config::getInstance()]]></code>
<code><![CDATA[Config::getInstance()]]></code>
<code><![CDATA[Config::getInstance()]]></code>
<code><![CDATA[Config::getInstance()]]></code>
<code><![CDATA[DatabaseInterface::getInstance()]]></code>
</DeprecatedMethod>
<PossiblyUnusedMethod>

View File

@ -1763,6 +1763,29 @@ function sqlPrettyPrint (string) {
return output;
}
function createFunctionConfirmModal (): void {
if ($('#functionConfirmModal').length > 0) {
return;
}
const functionConfirmModalTemplate = '<div class="modal fade" id="functionConfirmModal" tabindex="-1" aria-labelledby="functionConfirmModalLabel" aria-hidden="true">' +
' <div class="modal-dialog">' +
' <div class="modal-content">' +
' <div class="modal-header">' +
' <h5 class="modal-title" id="functionConfirmModalLabel">' + window.Messages.strConfirm + '</h5>' +
' <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="' + window.Messages.strClose + '"></button>' +
' </div>' +
' <div class="modal-body"></div>' +
' <div class="modal-footer">' +
' <button type="button" class="btn btn-secondary" id="functionConfirmOkButton">' + window.Messages.strOK + '</button>' +
' <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">' + window.Messages.strClose + '</button>' +
' </div>' +
' </div>' +
' </div>' +
'</div>';
$(functionConfirmModalTemplate).appendTo('body');
}
/**
* jQuery function that uses jQueryUI's dialogs to confirm with user. Does not
* return a jQuery object yet and hence cannot be chained
@ -1790,6 +1813,8 @@ function confirmDialog (question, url = undefined, callbackFn = undefined, openC
return true;
}
createFunctionConfirmModal();
const functionConfirmModal = $('#functionConfirmModal') as JQuery<HTMLDivElement>;
functionConfirmModal.modal('show');
functionConfirmModal.find('.modal-body').first().html(question);

View File

@ -322,6 +322,8 @@ function showAddIndexDialog (sourceArray, arrayIndex, targetColumns, colIndex, i
postData.columns = JSON.stringify(columns);
createAddIndexModal();
$('#addIndexModalGoButton').on('click', function () {
addIndexGo(sourceArray, arrayIndex, index, colIndex);
});
@ -447,6 +449,8 @@ function indexTypeSelectionDialog (sourceArray, indexChoice, colIndex): void {
$dialogContent.append($singleColumnRadio);
$dialogContent.append($compositeIndexRadio);
createAddIndexModal();
// 'OK' operation.
$('#addIndexModalGoButton').on('click', function () {
if ($('#single_column').is(':checked')) {
@ -543,6 +547,29 @@ function off () {
};
}
function createAddIndexModal (): void {
if ($('#addIndexModal').length > 0) {
return;
}
const addIndexModalTemplate = '<div class="modal fade" id="addIndexModal" tabindex="-1" aria-labelledby="addIndexModalLabel" aria-hidden="true">' +
' <div class="modal-dialog">' +
' <div class="modal-content">' +
' <div class="modal-header">' +
' <h5 class="modal-title" id="addIndexModalLabel">' + window.Messages.strLoading + '</h5>' +
' <button type="button" class="btn-close" id="addIndexModalCloseButton" aria-label="' + window.Messages.strClose + '"></button>' +
' </div>' +
' <div class="modal-body"></div>' +
' <div class="modal-footer">' +
' <button type="button" class="btn btn-secondary" id="addIndexModalGoButton">' + window.Messages.strGo + '</button>' +
' <button type="button" class="btn btn-secondary" id="addIndexModalCancelButton">' + window.Messages.strCancel + '</button>' +
' </div>' +
' </div>' +
' </div>' +
'</div>';
$(addIndexModalTemplate).appendTo('body');
}
/**
* @return {function}
*/

View File

@ -1,5 +1,28 @@
import $ from 'jquery';
function createPageSettingsModal (): void {
if ($('#pageSettingsModal').length > 0) {
return;
}
const pageSettingsModalTemplate = '<div class="modal fade" id="pageSettingsModal" tabindex="-1" aria-labelledby="pageSettingsModalLabel" aria-hidden="true">' +
' <div class="modal-dialog modal-lg" id="pageSettingsModalDialog">' +
' <div class="modal-content">' +
' <div class="modal-header">' +
' <h5 class="modal-title" id="pageSettingsModalLabel">' + window.Messages.strPageSettings + '</h5>' +
' <button type="button" class="btn-close" id="pageSettingsModalCloseButton" aria-label="' + window.Messages.strClose + '"></button>' +
' </div>' +
' <div class="modal-body"></div>' +
' <div class="modal-footer">' +
' <button type="button" class="btn btn-secondary" id="pageSettingsModalApplyButton">' + window.Messages.strApply + '</button>' +
' <button type="button" class="btn btn-secondary" id="pageSettingsModalCancelButton">' + window.Messages.strCancel + '</button>' +
' </div>' +
' </div>' +
' </div>' +
'</div>';
$(pageSettingsModalTemplate).appendTo('body');
}
/**
* @fileoverview function used for page-related settings
* @name Page-related settings
@ -8,6 +31,8 @@ import $ from 'jquery';
*/
function showSettings (selector) {
createPageSettingsModal();
// Keeping a clone to restore in case the user cancels the operation
var $clone = $(selector + ' .page_settings').clone(true);

View File

@ -1 +1,170 @@
{{- header|raw -}}{{- content|raw -}}{{- footer|raw -}}
<!doctype html>
<html lang="{{ header.lang }}" dir="{{ header.text_dir }}" data-bs-theme="{{ header.theme_color_mode }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="referrer" content="same-origin">
<meta name="robots" content="noindex,nofollow,notranslate">
<meta name="google" content="notranslate">
<script>window.allowThirdPartyFraming = {{ header.allow_third_party_framing == 'sameorigin' ? '"sameorigin"' : (header.allow_third_party_framing ? '1' : '0') }};</script>
{% if not header.allow_third_party_framing -%}
<style id="cfs-style">html{display: none;}</style>
{%- endif %}
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" type="text/css" href="{{ header.theme_path }}/jquery/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="{{ header.base_dir }}js/vendor/codemirror/lib/codemirror.css?{{ header.version }}">
<link rel="stylesheet" type="text/css" href="{{ header.base_dir }}js/vendor/codemirror/addon/hint/show-hint.css?{{ header.version }}">
<link rel="stylesheet" type="text/css" href="{{ header.base_dir }}js/vendor/codemirror/addon/lint/lint.css?{{ header.version }}">
<link rel="stylesheet" type="text/css" href="{{ header.theme_path }}/css/theme{{ header.text_dir == 'rtl' ? '.rtl' }}.css?{{ header.version }}">
<title>{{ header.title }}</title>
{{ header.scripts|raw }}
<noscript><style>html{display:block}</style></noscript>
</head>
<body{{ header.body_id is not empty ? ' id=' ~ header.body_id }}>
{{ header.navigation|raw }}
{{ header.custom_header|raw }}
{{ header.load_user_preferences|raw }}
{% if not header.show_hint %}
<span id="no_hint" class="hide"></span>
{% endif %}
{% if header.is_warnings_enabled %}
<noscript>
{{ t('Javascript must be enabled past this point!')|error }}
</noscript>
{% endif %}
{% if header.is_menu_enabled and header.server > 0 %}
{{ header.menu|raw }}
<div id="page_nav_icons" class="row row-cols-sm-auto align-items-center d-print-none me-3 p-1">
<div class="col-12">
<div id="userAccountDropdown" class="dropdown">
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
{{- get_image('user', t('Open user account menu')) -}}
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item text-nowrap disableAjax" href="{{ url('/server/privileges', {'username': header.current_user[0], 'hostname': header.current_user[1]}) }}">
{{ get_image('user', '', {'aria-hidden': 'true'}) }} <span dir="ltr">{{ header.current_user|join('@') }}</span>
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item disableAjax" href="{{ get_docu_link('index') }}" target="_blank" rel="noopener noreferrer">
{{ get_icon('b_docs', t('phpMyAdmin documentation')) }}
</a>
</li>
<li>
<a class="dropdown-item disableAjax" href="{{ get_docu_url(header.is_mariadb) }}" target="_blank" rel="noopener noreferrer">
{{ get_icon('b_sqlhelp', header.is_mariadb ? t('MariaDB documentation') : t('MySQL documentation')) }}
</a>
</li>
<li><hr class="dropdown-divider"></li>
{% if header.theme_color_modes|length > 1 %}
<li>
<form method="post" action="{{ url('/themes/set') }}" class="dropdown-item py-0 disableAjax">
{{ get_hidden_inputs() }}
<input type="hidden" name="set_theme" value="{{ header.theme_id }}">
<div class="row row-cols-lg-auto align-items-center flex-nowrap">
<div class="col-12">
<label class="col-form-label" for="themeColorModeToggle">{{ get_icon('s_theme', t('Appearance:')) }}</label>
</div>
<div class="col-12">
<select class="form-select form-select-sm" name="themeColorMode" id="themeColorModeToggle" aria-label="{{ t('Color mode for the theme') }}">
{% for color_mode in header.theme_color_modes %}
<option value="{{ color_mode }}"{{ header.theme_color_mode == color_mode ? ' selected' }}>
{%- if color_mode == 'light' -%}
{{ t('Light', context = 'Light color mode of the theme') }}
{%- elseif color_mode == 'dark' -%}
{{ t('Dark', context = 'Dark color mode of the theme') }}
{%- else -%}
{{ color_mode|title }}
{%- endif -%}
</option>
{% endfor %}
</select>
</div>
</div>
</form>
</li>
{% endif %}
<li>
<a class="dropdown-item disableAjax" href="{{ url('/preferences/manage') }}">{{ get_icon('s_cog', t('Settings')) }}</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item logout disableAjax" href="{{ url('/logout') }}">{{ get_icon('s_loggoff', t('Log out')) }}</a>
</li>
</ul>
</div>
</div>
<div class="col-12">
<span id="lock_page_icon"></span>
<span id="page_settings_icon">
{{ get_image('s_cog', t('Page-related settings')) }}
</span>
<a id="goto_pagetop" href="#">{{ get_image('s_top', t('Click on the bar to scroll to top of page')) }}</a>
</div>
</div>
{% endif %}
{{ header.console|raw }}
<div id="page_content">
{{ header.messages|raw }}
{%- if header.is_logged_in -%}
{{ include('modals/preview_sql_modal.twig') }}
{{ include('modals/enum_set_editor.twig') }}
{{ include('modals/create_view.twig') }}
{%- endif -%}
{{ content|raw }}
</div>
{% if not footer.is_minimal %}
{% if footer.self_url is not empty %}
<div id="selflink" class="d-print-none">
<a href="{{ footer.self_url }}" title="{{ t('Open new phpMyAdmin window') }}" target="_blank" rel="noopener noreferrer">
{% if show_icons('TabsMode') %}
{{ get_image('window-new', t('Open new phpMyAdmin window')) }}
{% else %}
{{ t('Open new phpMyAdmin window') }}
{% endif %}
</a>
</div>
{% endif %}
<div class="clearfloat d-print-none" id="pma_errors">
{{ footer.error_messages|raw }}
</div>
{{ footer.scripts|raw }}
{% if footer.is_demo %}
<div id="pma_demo" class="d-print-none">
{% apply notice %}
<a href="{{ url('/') }}">{{ t('phpMyAdmin Demo Server') }}:</a>
{% if footer.git_revision_info is not empty %}
{% set revision_info -%}
<a target="_blank" rel="noopener noreferrer" href="{{ footer.git_revision_info.revisionUrl|link }}">{{ footer.git_revision_info.revision }}</a>
{%- endset %}
{% set branch_info -%}
<a target="_blank" rel="noopener noreferrer" href="{{ footer.git_revision_info.branchUrl|link }}">{{ footer.git_revision_info.branch }}</a>
{%- endset %}
{{ t('Currently running Git revision %1$s from the %2$s branch.')|format(revision_info, branch_info)|raw }}
{% else %}
{{ t('Git information missing!') }}
{% endif %}
{% endapply %}
</div>
{% endif %}
{{ footer.footer|raw }}
{% endif %}
</body>
</html>

View File

@ -1,50 +0,0 @@
{{ include('modals/function_confirm.twig') }}
{{ include('modals/add_index.twig') }}
{{ include('modals/page_settings.twig') }}
{% if not is_ajax %}
</div>
{% endif %}
{% if not is_ajax and not is_minimal %}
{% if self_url is not empty %}
<div id="selflink" class="d-print-none">
<a href="{{ self_url }}" title="{{ t('Open new phpMyAdmin window') }}" target="_blank" rel="noopener noreferrer">
{% if show_icons('TabsMode') %}
{{ get_image('window-new', t('Open new phpMyAdmin window')) }}
{% else %}
{{ t('Open new phpMyAdmin window') }}
{% endif %}
</a>
</div>
{% endif %}
<div class="clearfloat d-print-none" id="pma_errors">
{{ error_messages|raw }}
</div>
{{ scripts|raw }}
{% if is_demo %}
<div id="pma_demo" class="d-print-none">
{% apply notice %}
<a href="{{ url('/') }}">{{ t('phpMyAdmin Demo Server') }}:</a>
{% if git_revision_info is not empty %}
{% set revision_info -%}
<a target="_blank" rel="noopener noreferrer" href="{{ git_revision_info.revisionUrl|link }}">{{ git_revision_info.revision }}</a>
{%- endset %}
{% set branch_info -%}
<a target="_blank" rel="noopener noreferrer" href="{{ git_revision_info.branchUrl|link }}">{{ git_revision_info.branch }}</a>
{%- endset %}
{{ t('Currently running Git revision %1$s from the %2$s branch.')|format(revision_info, branch_info)|raw }}
{% else %}
{{ t('Git information missing!') }}
{% endif %}
{% endapply %}
</div>
{% endif %}
{{ footer|raw }}
{% endif %}
{% if not is_ajax %}
</body>
</html>
{% endif %}

View File

@ -1,124 +0,0 @@
<!doctype html>
<html lang="{{ lang }}" dir="{{ text_dir }}" data-bs-theme="{{ theme_color_mode }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="referrer" content="same-origin">
<meta name="robots" content="noindex,nofollow,notranslate">
<meta name="google" content="notranslate">
<script>window.allowThirdPartyFraming = {{ allow_third_party_framing == 'sameorigin' ? '"sameorigin"' : (allow_third_party_framing ? '1' : '0') }};</script>
{% if not allow_third_party_framing -%}
<style id="cfs-style">html{display: none;}</style>
{%- endif %}
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" type="text/css" href="{{ theme_path }}/jquery/jquery-ui.css">
<link rel="stylesheet" type="text/css" href="{{ base_dir }}js/vendor/codemirror/lib/codemirror.css?{{ version }}">
<link rel="stylesheet" type="text/css" href="{{ base_dir }}js/vendor/codemirror/addon/hint/show-hint.css?{{ version }}">
<link rel="stylesheet" type="text/css" href="{{ base_dir }}js/vendor/codemirror/addon/lint/lint.css?{{ version }}">
<link rel="stylesheet" type="text/css" href="{{ theme_path }}/css/theme{{ text_dir == 'rtl' ? '.rtl' }}.css?{{ version }}">
<title>{{ title }}</title>
{{ scripts|raw }}
<noscript><style>html{display:block}</style></noscript>
</head>
<body{{ body_id is not empty ? ' id=' ~ body_id }}>
{{ navigation|raw }}
{{ custom_header|raw }}
{{ load_user_preferences|raw }}
{% if not show_hint %}
<span id="no_hint" class="hide"></span>
{% endif %}
{% if is_warnings_enabled %}
<noscript>
{{ t('Javascript must be enabled past this point!')|error }}
</noscript>
{% endif %}
{% if is_menu_enabled and server > 0 %}
{{ menu|raw }}
<div id="page_nav_icons" class="row row-cols-sm-auto align-items-center d-print-none me-3 p-1">
<div class="col-12">
<div id="userAccountDropdown" class="dropdown">
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
{{- get_image('user', t('Open user account menu')) -}}
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item text-nowrap disableAjax" href="{{ url('/server/privileges', {'username': current_user[0], 'hostname': current_user[1]}) }}">
{{ get_image('user', '', {'aria-hidden': 'true'}) }} <span dir="ltr">{{ current_user|join('@') }}</span>
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item disableAjax" href="{{ get_docu_link('index') }}" target="_blank" rel="noopener noreferrer">
{{ get_icon('b_docs', t('phpMyAdmin documentation')) }}
</a>
</li>
<li>
<a class="dropdown-item disableAjax" href="{{ get_docu_url(is_mariadb) }}" target="_blank" rel="noopener noreferrer">
{{ get_icon('b_sqlhelp', is_mariadb ? t('MariaDB documentation') : t('MySQL documentation')) }}
</a>
</li>
<li><hr class="dropdown-divider"></li>
{% if theme_color_modes|length > 1 %}
<li>
<form method="post" action="{{ url('/themes/set') }}" class="dropdown-item py-0 disableAjax">
{{ get_hidden_inputs() }}
<input type="hidden" name="set_theme" value="{{ theme_id }}">
<div class="row row-cols-lg-auto align-items-center flex-nowrap">
<div class="col-12">
<label class="col-form-label" for="themeColorModeToggle">{{ get_icon('s_theme', t('Appearance:')) }}</label>
</div>
<div class="col-12">
<select class="form-select form-select-sm" name="themeColorMode" id="themeColorModeToggle" aria-label="{{ t('Color mode for the theme') }}">
{% for color_mode in theme_color_modes %}
<option value="{{ color_mode }}"{{ theme_color_mode == color_mode ? ' selected' }}>
{%- if color_mode == 'light' -%}
{{ t('Light', context = 'Light color mode of the theme') }}
{%- elseif color_mode == 'dark' -%}
{{ t('Dark', context = 'Dark color mode of the theme') }}
{%- else -%}
{{ color_mode|title }}
{%- endif -%}
</option>
{% endfor %}
</select>
</div>
</div>
</form>
</li>
{% endif %}
<li>
<a class="dropdown-item disableAjax" href="{{ url('/preferences/manage') }}">{{ get_icon('s_cog', t('Settings')) }}</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item logout disableAjax" href="{{ url('/logout') }}">{{ get_icon('s_loggoff', t('Log out')) }}</a>
</li>
</ul>
</div>
</div>
<div class="col-12">
<span id="lock_page_icon"></span>
<span id="page_settings_icon">
{{ get_image('s_cog', t('Page-related settings')) }}
</span>
<a id="goto_pagetop" href="#">{{ get_image('s_top', t('Click on the bar to scroll to top of page')) }}</a>
</div>
</div>
{% endif %}
{{ console|raw }}
<div id="page_content">
{{ messages|raw }}
{%- if is_logged_in -%}
{{ include('modals/preview_sql_modal.twig') }}
{{ include('modals/enum_set_editor.twig') }}
{{ include('modals/create_view.twig') }}
{%- endif -%}

View File

@ -1,15 +0,0 @@
<div class="modal fade" id="addIndexModal" tabindex="-1" aria-labelledby="addIndexModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addIndexModalLabel">{{ t('Loading') }}</h5>
<button type="button" class="btn-close" id="addIndexModalCloseButton" aria-label="{{ t('Close') }}"></button>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="addIndexModalGoButton">{{ t('Go') }}</button>
<button type="button" class="btn btn-secondary" id="addIndexModalCancelButton">{{ t('Cancel') }}</button>
</div>
</div>
</div>
</div>

View File

@ -1,15 +0,0 @@
<div class="modal fade" id="functionConfirmModal" tabindex="-1" aria-labelledby="functionConfirmModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="functionConfirmModalLabel">{{ t('Confirm') }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{{ t('Close') }}"></button>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="functionConfirmOkButton">{{ t('Ok') }}</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t('Close') }}</button>
</div>
</div>
</div>
</div>

View File

@ -1,15 +0,0 @@
<div class="modal fade" id="pageSettingsModal" tabindex="-1" aria-labelledby="pageSettingsModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" id="pageSettingsModalDialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="pageSettingsModalLabel">{{ t('Page-related settings') }}</h5>
<button type="button" class="btn-close" id="pageSettingsModalCloseButton" aria-label="{{ t('Close') }}"></button>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="pageSettingsModalApplyButton">{{ t('Apply') }}</button>
<button type="button" class="btn btn-secondary" id="pageSettingsModalCancelButton">{{ t('Cancel') }}</button>
</div>
</div>
</div>
</div>

View File

@ -25,10 +25,6 @@ class Console
*/
private bool $isEnabled = true;
/**
* Whether we are servicing an ajax request.
*/
private bool $isAjax = false;
private readonly Config $config;
public function __construct(
@ -39,17 +35,6 @@ class Console
$this->config = Config::getInstance();
}
/**
* Set the ajax flag to indicate whether
* we are servicing an ajax request
*
* @param bool $isAjax Whether we are servicing an ajax request
*/
public function setAjax(bool $isAjax): void
{
$this->isAjax = $isAjax;
}
/**
* Disables the rendering of the footer
*/
@ -104,7 +89,7 @@ class Console
*/
public function getDisplay(): string
{
if ($this->isAjax || ! $this->isEnabled) {
if (! $this->isEnabled) {
return '';
}

View File

@ -359,6 +359,7 @@ final class JavaScriptMessagesController implements InvocableController
'strAddingPrimaryKey' => __('Adding primary key'),
'strOK' => __('OK'),
'strDismiss' => __('Click to dismiss this notification'),
'strConfirm' => __('Confirm'),
/* For database/operations.js */
'strRenamingDatabases' => __('Renaming databases'),

View File

@ -28,19 +28,16 @@ class Footer
* Scripts instance
*/
private Scripts $scripts;
/**
* Whether we are servicing an ajax request.
*/
private bool $isAjax = false;
/**
* Whether to only close the BODY and HTML tags
* or also include scripts, errors and links
*/
private bool $isMinimal = false;
public function __construct(private readonly Template $template, private readonly Config $config)
public function __construct(Template $template, private readonly Config $config)
{
$this->scripts = new Scripts($this->template);
$this->scripts = new Scripts($template);
}
/**
@ -151,17 +148,6 @@ class Footer
return $retval;
}
/**
* Set the ajax flag to indicate whether
* we are servicing an ajax request
*
* @param bool $isAjax Whether we are servicing an ajax request
*/
public function setAjax(bool $isAjax): void
{
$this->isAjax = $isAjax;
}
/**
* Turn on minimal display mode
*/
@ -180,12 +166,10 @@ class Footer
return $this->scripts;
}
/**
* Renders the footer
*/
public function getDisplay(): string
/** @return mixed[] */
public function getDisplay(): array
{
if (! $this->isAjax && ! $this->isMinimal) {
if (! $this->isMinimal) {
if (Core::getEnv('SCRIPT_NAME') !== '') {
$url = $this->getSelfUrl();
}
@ -201,8 +185,7 @@ class Footer
$footer = Config::renderFooter();
}
return $this->template->render('footer', [
'is_ajax' => $this->isAjax,
return [
'is_minimal' => $this->isMinimal,
'self_url' => $url ?? null,
'error_messages' => $errorMessages ?? '',
@ -210,6 +193,6 @@ class Footer
'is_demo' => $this->config->config->debug->demo,
'git_revision_info' => $gitRevisionInfo ?? [],
'footer' => $footer ?? '',
]);
];
}
}

View File

@ -55,15 +55,6 @@ class Header
* Whether to show the warnings
*/
private bool $warningsEnabled = true;
/**
* Whether we are servicing an ajax request.
*/
private bool $isAjax = false;
/**
* Whether the HTTP headers (and possibly some HTML)
* have already been sent to the browser
*/
private bool $headerIsSent = false;
private UserPreferences $userPreferences;
@ -159,18 +150,6 @@ class Header
return 'window.Navigation.update(window.CommonParams.setAll(' . json_encode($params, JSON_HEX_TAG) . '));';
}
/**
* Set the ajax flag to indicate whether
* we are servicing an ajax request
*
* @param bool $isAjax Whether we are servicing an ajax request
*/
public function setAjax(bool $isAjax): void
{
$this->isAjax = $isAjax;
$this->console->setAjax($isAjax);
}
/**
* Returns the Scripts object
*
@ -228,17 +207,9 @@ class Header
$this->warningsEnabled = false;
}
/**
* Generates the header
*
* @return string The header
*/
public function getDisplay(): string
/** @return mixed[] */
public function getDisplay(): array
{
if ($this->headerIsSent || $this->isAjax) {
return '';
}
$this->sendHttpHeaders();
$baseDir = defined('PMA_PATH_TO_BASEDIR') ? PMA_PATH_TO_BASEDIR : '';
@ -309,7 +280,7 @@ class Header
$this->scripts->addFile('datetimepicker.js');
$this->scripts->addFile('validator-messages.js');
return $this->template->render('header', [
return [
'lang' => $GLOBALS['lang'],
'allow_third_party_framing' => $this->config->settings['AllowThirdPartyFraming'],
'base_dir' => $baseDir,
@ -335,7 +306,7 @@ class Header
'theme_id' => $theme->getId(),
'current_user' => $dbi->getCurrentUserAndHost(),
'is_mariadb' => $dbi->isMariaDB(),
]);
];
}
/**
@ -386,8 +357,6 @@ class Header
foreach ($headers as $name => $value) {
header(sprintf('%s: %s', $name, $value));
}
$this->headerIsSent = true;
}
/** @return array<string, string> */

View File

@ -165,8 +165,6 @@ class ResponseRenderer
public function setAjax(bool $isAjax): void
{
$this->isAjax = $isAjax;
$this->header->setAjax($this->isAjax);
$this->footer->setAjax($this->isAjax);
}
/**
@ -242,10 +240,6 @@ class ResponseRenderer
*/
private function getDisplay(): string
{
// The header may contain nothing at all,
// if its content was already rendered
// and, in this case, the header will be
// in the content part of the request
return $this->template->render('base', [
'header' => $this->header->getDisplay(),
'content' => $this->HTML,
@ -259,7 +253,7 @@ class ResponseRenderer
private function ajaxResponse(): string
{
if (! isset($this->JSON['message'])) {
$this->JSON['message'] = $this->getDisplay();
$this->JSON['message'] = $this->HTML;
} elseif ($this->JSON['message'] instanceof Message) {
$this->JSON['message'] = $this->JSON['message']->getDisplay();
}

View File

@ -10,7 +10,6 @@ use PhpMyAdmin\Console;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Template;
use PHPUnit\Framework\Attributes\CoversClass;
use ReflectionProperty;
#[CoversClass(Console::class)]
class ConsoleTest extends AbstractTestCase
@ -24,19 +23,4 @@ class ConsoleTest extends AbstractTestCase
$console = new Console($relation, new Template(), $bookmarkRepository);
self::assertSame(['console.js'], $console->getScripts());
}
public function testSetAjax(): void
{
$isAjax = new ReflectionProperty(Console::class, 'isAjax');
$dbi = $this->createDatabaseInterface();
$relation = new Relation($dbi);
$bookmarkRepository = new BookmarkRepository($dbi, $relation);
$console = new Console($relation, new Template(), $bookmarkRepository);
self::assertFalse($isAjax->getValue($console));
$console->setAjax(true);
self::assertTrue($isAjax->getValue($console));
$console->setAjax(false);
self::assertFalse($isAjax->getValue($console));
}
}

View File

@ -12,7 +12,6 @@ use PhpMyAdmin\Footer;
use PhpMyAdmin\Template;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use ReflectionProperty;
use function json_encode;
@ -100,19 +99,6 @@ class FooterTest extends AbstractTestCase
);
}
public function testGetDisplayWhenAjaxIsEnabled(): void
{
$template = new Template();
$footer = new Footer($template, Config::getInstance());
$footer->setAjax(true);
self::assertSame(
$template->render('modals/function_confirm') . "\n"
. $template->render('modals/add_index') . "\n"
. $template->render('modals/page_settings') . "\n",
$footer->getDisplay(),
);
}
/**
* Test for footer get Scripts
*/
@ -132,10 +118,27 @@ class FooterTest extends AbstractTestCase
public function testDisplay(): void
{
$footer = new Footer(new Template(), Config::getInstance());
self::assertStringContainsString(
'Open new phpMyAdmin window',
$footer->getDisplay(),
);
$scripts = <<<'HTML'
<script data-cfasync="false">
// <![CDATA[
window.Console.debugSqlInfo = 'false';
// ]]>
</script>
HTML;
$expected = [
'is_minimal' => false,
'self_url' => 'index.php?route=%2F&server=1&lang=en',
'error_messages' => '',
'scripts' => $scripts,
'is_demo' => false,
'git_revision_info' => [],
'footer' => '',
];
self::assertSame($expected, $footer->getDisplay());
}
/**
@ -146,24 +149,15 @@ class FooterTest extends AbstractTestCase
$template = new Template();
$footer = new Footer($template, Config::getInstance());
$footer->setMinimal();
self::assertSame(
$template->render('modals/function_confirm') . "\n"
. $template->render('modals/add_index') . "\n"
. $template->render('modals/page_settings')
. "\n </div>\n </body>\n</html>\n",
$footer->getDisplay(),
);
}
public function testSetAjax(): void
{
$isAjax = new ReflectionProperty(Footer::class, 'isAjax');
$footer = new Footer(new Template(), Config::getInstance());
self::assertFalse($isAjax->getValue($footer));
$footer->setAjax(true);
self::assertTrue($isAjax->getValue($footer));
$footer->setAjax(false);
self::assertFalse($isAjax->getValue($footer));
$expected = [
'is_minimal' => true,
'self_url' => null,
'error_messages' => '',
'scripts' => '',
'is_demo' => false,
'git_revision_info' => [],
'footer' => '',
];
self::assertSame($expected, $footer->getDisplay());
}
}

View File

@ -12,6 +12,7 @@ use PhpMyAdmin\Current;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Header;
use PhpMyAdmin\Template;
use PhpMyAdmin\Version;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Medium;
@ -64,30 +65,52 @@ class HeaderTest extends AbstractTestCase
);
}
/**
* Test for enable
*/
public function testEnable(): void
{
Current::$server = 0;
$header = $this->getNewHeaderInstance();
self::assertStringContainsString(
'<title>phpMyAdmin</title>',
$header->getDisplay(),
);
}
$GLOBALS['message'] = '';
$config = Config::getInstance();
$config->settings['CodemirrorEnable'] = false;
$config->settings['SendErrorReports'] = 'never';
$config->settings['enable_drag_drop_import'] = false;
$config->settings['DisableShortcutKeys'] = true;
$dbi = $this->createDatabaseInterface();
DatabaseInterface::$instance = $dbi;
$relation = new Relation($dbi);
$template = new Template($config);
$console = new Console($relation, $template, new BookmarkRepository($dbi, $relation));
$header = new Header($template, $console, $config);
/**
* Test for Set BodyId
*/
public function testSetBodyId(): void
{
$header = $this->getNewHeaderInstance();
$header->setBodyId('PMA_header_id');
self::assertStringContainsString(
'PMA_header_id',
$header->getDisplay(),
);
$actual = $header->getDisplay();
$expected = [
'lang' => 'en',
'allow_third_party_framing' => false,
'base_dir' => '',
'theme_path' => '',
'version' => 'v=' . Version::VERSION,
'text_dir' => 'ltr',
'server' => 0,
'title' => 'phpMyAdmin',
'scripts' => $header->getScripts()->getDisplay(),
'body_id' => 'PMA_header_id',
'navigation' => '',
'custom_header' => '',
'load_user_preferences' => '',
'show_hint' => true,
'is_warnings_enabled' => true,
'is_menu_enabled' => true,
'is_logged_in' => true,
'menu' => '',
'console' => $console->getDisplay(),
'messages' => '',
'theme_color_mode' => 'light',
'theme_color_modes' => ['light'],
'theme_id' => '',
'current_user' => ['pma_test', 'localhost'],
'is_mariadb' => false,
];
self::assertSame($expected, $actual);
}
/**
@ -269,22 +292,4 @@ class HeaderTest extends AbstractTestCase
];
self::assertSame($expected, $scripts->getFiles());
}
public function testSetAjax(): void
{
$header = $this->getNewHeaderInstance();
$console = (new ReflectionProperty(Header::class, 'console'))->getValue($header);
self::assertInstanceOf(Console::class, $console);
$isAjax = new ReflectionProperty(Header::class, 'isAjax');
$consoleIsAjax = new ReflectionProperty(Console::class, 'isAjax');
self::assertFalse($isAjax->getValue($header));
self::assertFalse($consoleIsAjax->getValue($console));
$header->setAjax(true);
self::assertTrue($isAjax->getValue($header));
self::assertTrue($consoleIsAjax->getValue($console));
$header->setAjax(false);
self::assertFalse($isAjax->getValue($header));
self::assertFalse($consoleIsAjax->getValue($console));
}
}

View File

@ -6,15 +6,12 @@ namespace PhpMyAdmin\Tests;
use Fig\Http\Message\StatusCodeInterface;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Footer;
use PhpMyAdmin\Header;
use PhpMyAdmin\Html\MySQLDocumentation;
use PhpMyAdmin\Message;
use PhpMyAdmin\ResponseRenderer;
use PhpMyAdmin\Scripts;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\PreserveGlobalState;
use PHPUnit\Framework\Attributes\RunInSeparateProcess;
use ReflectionProperty;
use function array_column;
@ -31,32 +28,16 @@ class ResponseRendererTest extends AbstractTestCase
$GLOBALS['lang'] = 'en';
}
#[RunInSeparateProcess]
#[PreserveGlobalState(false)]
public function testSetAjax(): void
{
$_REQUEST = [];
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
$response = ResponseRenderer::getInstance();
$header = $response->getHeader();
$footer = (new ReflectionProperty(ResponseRenderer::class, 'footer'))->getValue($response);
self::assertInstanceOf(Footer::class, $footer);
$headerIsAjax = new ReflectionProperty(Header::class, 'isAjax');
$footerIsAjax = new ReflectionProperty(Footer::class, 'isAjax');
self::assertFalse($response->isAjax());
self::assertFalse($headerIsAjax->getValue($header));
self::assertFalse($footerIsAjax->getValue($footer));
$response->setAjax(true);
self::assertTrue($response->isAjax());
self::assertTrue($headerIsAjax->getValue($header));
self::assertTrue($footerIsAjax->getValue($footer));
$response->setAjax(false);
self::assertFalse($response->isAjax());
self::assertFalse($headerIsAjax->getValue($header));
self::assertFalse($footerIsAjax->getValue($footer));
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
}