From: Roland Häder Date: Wed, 26 Dec 2012 18:11:19 +0000 (+0000) Subject: Continued on AJAX installer to start first step (more are easily to add) X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=74b7fbc5030bb2938a9859020876da63e6d15c0b;p=mailer.git Continued on AJAX installer to start first step (more are easily to add) --- diff --git a/.gitattributes b/.gitattributes index 5ae2ba7aff..7664ed1696 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1683,6 +1683,7 @@ templates/de/html/admin/admin_welcome.tpl svneol=native#text/plain templates/de/html/admin/admin_welcome_admins.tpl svneol=native#text/plain templates/de/html/admin/admin_yoomedia_error.tpl svneol=native#text/plain templates/de/html/agb.tpl svneol=native#text/plain +templates/de/html/ajax_app_exit_message.tpl svneol=native#text/plain templates/de/html/ajax_test_passed.tpl svneol=native#text/plain templates/de/html/app_exit_message.tpl svneol=native#text/plain templates/de/html/beg/.htaccess svneol=native#text/plain diff --git a/inc/ajax-functions.php b/inc/ajax-functions.php index 1b46e221bb..59ad97d181 100644 --- a/inc/ajax-functions.php +++ b/inc/ajax-functions.php @@ -132,7 +132,7 @@ function sendAjaxContent () { // Is the status fine or template not found (404)? if (isAjaxHttpStatusAccepted()) { // Then output the JSON - outputHtml(json_encode($GLOBALS['ajax_reply'], JSON_FORCE_OBJECT)); + outputHtml(encodeJson($GLOBALS['ajax_reply'])); } // END - if } diff --git a/inc/ajax/ajax_installer.php b/inc/ajax/ajax_installer.php index 5267a3aee5..a1b7ed8568 100644 --- a/inc/ajax/ajax_installer.php +++ b/inc/ajax/ajax_installer.php @@ -40,6 +40,45 @@ if ((!defined('__SECURITY')) || (!isAjaxOutputMode()) || (!isInstallationPhase() die(); } // END - if +//----------------------------------------------------------------------------- +// Generic call-back functions, they all rely on session data +//----------------------------------------------------------------------------- + +// Establish a database link +function establishAjaxInstallerDatabaseLink () { + // This requires some session data + if (!isSessionDataSet(array('mysql_host', 'mysql_dbase', 'mysql_prefix', 'mysql_login', 'mysql_password1', 'mysql_password2', 'mysql_engine'))) { + // Some required session data is not set + reportBug(__FUNCTION__, __LINE__, 'Required session data for this step not found.'); + } // END - if + + // Establish link + $linkResource = SQL_CONNECT(getSession('mysql_host'), getSession('mysql_login'), getSession('mysql_password1'), __FUNCTION__, __LINE__); + + // Is this a link resource? + if (!is_resource($linkResource)) { + // Is not a resource + reportBug(__FUNCTION__, __LINE__, 'linkResource[]=' . gettype($linkResource) . ', expected: link resource'); + } // END - if + + // Does selecting the database work? + if (!SQL_SELECT_DB(getSession('mysql_dbase'), __FUNCTION__, __LINE__)) { + // Could not be selected + reportBug(__FUNCTION__, __LINE__, 'Could not select database ' . getSession('mysql_dbase')); + } elseif ((!isFileReadable(getPath() . 'install/tables.sql')) || (!isFileReadable(getPath() . 'install/menu-'.getLanguage().'.sql'))) { + // Installation area not found + reportBug(__FUNCTION__, __LINE__, 'SQL dumps not found. Please extract ALL files from the archive or checkout all files out from SVN.'); + } elseif (ifFatalErrorsDetected()) { + // Some other fatal error occured + reportBug(__FUNCTION__, __LINE__, 'Some fatal error detected, please check debug.log for details.'); + } // END - if + + // Set type, prefix from POST data and database name for later queries + setConfigEntry('_TABLE_TYPE' , getSession('mysql_engine')); + setConfigEntry('_MYSQL_PREFIX', getSession('mysql_prefix')); + setConfigEntry('__DB_NAME' , getSession('mysql_dbase')); +} + //----------------------------------------------------------------------------- // Call-back functions for processing AJAX requests //----------------------------------------------------------------------------- @@ -77,7 +116,7 @@ function doAjaxProcessInstall () { // Processes installer request for testing function doAjaxInstallerTest () { // Load the "test passed" template - setAjaxReplyContent(loadTemplate('ajax_test_passed', TRUE)); + setAjaxReplyContent(encodeJson(postRequestElement('step').'=OK')); // All okay if we reach this point setHttpStatus('200 OK'); @@ -122,7 +161,34 @@ function doAjaxInstallerFooterNavigation () { } // END - switch // Output the array for JSON reply - setAjaxReplyContent(json_encode($enabledNavigations, JSON_FORCE_OBJECT)); + setAjaxReplyContent(encodeJson($enabledNavigations)); + + // All okay if we reach this point + setHttpStatus('200 OK'); +} + +// Processes installer AJAX calls for content-requests +function doAjaxInstallerDoStep () { + // 'step' must be there + if (!isPostRequestElementSet('step')) { + // This shall not happen + reportBug(__FUNCTION__, __LINE__, 'The JavaScript did not send "step" which is fatal.'); + } // END - if + + // Construct call-back name + $callbackName = 'doAjaxInstallerStep' . capitalizeUnderscoreString(postRequestElement('step')); + + // Is the function there? + if (function_exists($callbackName)) { + // Call it for setting values in session + call_user_func($callbackName); + } else { + // Log missing functions + reportBug(__FUNCTION__, __LINE__, 'Call-back function ' . $callbackName . ' does not exist.'); + } + + // Set dummy content + setAjaxReplyContent(loadTemplate('install_step_passed', TRUE, postRequestElement('step'))); // All okay if we reach this point setHttpStatus('200 OK'); @@ -145,7 +211,7 @@ function doAjaxInstallerRequestContent () { call_user_func($callbackName); } else { // Log missing functions - logDebugMessage(__FUNCTION__, __LINE__, 'Call-back function ' . $callbackName . ' does not exist.'); + reportBug(__FUNCTION__, __LINE__, 'Call-back function ' . $callbackName . ' does not exist.'); } // Is the HTTP status still the same? (204 No Content) @@ -255,12 +321,16 @@ function doAjaxInstallerSaveChanges () { } // END - if // Output the status array for JSON reply - setAjaxReplyContent(json_encode($saveStatus, JSON_FORCE_OBJECT)); + setAjaxReplyContent(encodeJson($saveStatus)); // All okay if we reach this point setHttpStatus('200 OK'); } +// ---------------------------------------------------------------------------- +// Call-back functions for preparing installer page requests +// ---------------------------------------------------------------------------- + // Prepare AJAX request 'welcome' function doAjaxPrepareInstallerWelcome () { // Kept empty to prevent logfile entry @@ -326,15 +396,15 @@ function doAjaxPrepareInstallerDatabaseConfig () { } // END - if // Is 'mysql_dbase' not set? - if (!isSessionVariableSet('mysql_pass1')) { + if (!isSessionVariableSet('mysql_password1')) { // Then set it directly - setSession('mysql_pass1', ''); + setSession('mysql_password1', ''); } // END - if - // Is 'mysql_pass2' not set? - if (!isSessionVariableSet('mysql_pass2')) { + // Is 'mysql_password2' not set? + if (!isSessionVariableSet('mysql_password2')) { // Then set it directly - setSession('mysql_pass2', ''); + setSession('mysql_password2', ''); } // END - if // Is 'mysql_engine' not set? @@ -455,5 +525,30 @@ function doAjaxPrepareInstallerOverview () { } // END - if } +// ---------------------------------------------------------------------------- +// Call-back functions for doing installation steps +// ---------------------------------------------------------------------------- + +// Call-back function to import first tables.sql file +function doAjaxInstallerStepImportTablesSql () { + // Establish database link + establishAjaxInstallerDatabaseLink(); + + // Init SQL array + initSqls(); + + // Import tables.sql + importInstallSqlDump('tables'); + + // Are some SQLs found? + if (countSqls() == 0) { + // Abort here + reportBug(__FUNCTION__, __LINE__, '{--INSTALLER_SQL_IMPORT_FAILED--}'); + } // END - if + + // Now run all queries through + runFilterChain('run_sqls'); +} + // [EOF] ?> diff --git a/inc/session-functions.php b/inc/session-functions.php index cea985df62..ebee5cf6f1 100644 --- a/inc/session-functions.php +++ b/inc/session-functions.php @@ -143,7 +143,7 @@ function destroyAdminSession ($destroy = FALSE) { return destroySession(); } // END - if - // All fine if we shall not really destroy the session + // All fine if the session shall not really be destroyed return TRUE; } @@ -168,5 +168,20 @@ function isSessionValid () { return $GLOBALS[__FUNCTION__]; } +// Checks whether all given session data is set +function isSessionDataSet ($sessionData) { + // Default is set + $isset = TRUE; + + // Check all + foreach ($sessionData as $key) { + // Is this element set? + $isset = (($isset) && (isSessionVariableSet($key))); + } // END - foreach + + // Return result + return $isset; +} + // [EOF] ?> diff --git a/inc/stats-functions.php b/inc/stats-functions.php index c3f6071142..149e6820f2 100644 --- a/inc/stats-functions.php +++ b/inc/stats-functions.php @@ -55,7 +55,7 @@ function initStatsSystem () { } // END - if } -// Checks if we have a statistics entry +// Checks if a statistics entry has been set function isStatsEntrySet ($entry) { // Is there the entry? return (isset($GLOBALS['stats'][$entry])); diff --git a/inc/template-functions.php b/inc/template-functions.php index c57e2c52e2..00d4b9d9a5 100644 --- a/inc/template-functions.php +++ b/inc/template-functions.php @@ -1208,8 +1208,14 @@ function app_exit ($F, $L, $message) { // Make sure, that the script realy realy diese here and now $GLOBALS['app_died'] = TRUE; - // Set content type as text/html - setContentType('text/html'); + // Is this AJAX mode? + if (isAjaxOutputMode()) { + // Set content type as application/json + setContentType('application/json'); + } else { + // Set content type as text/html + setContentType('text/html'); + } // Load header loadIncludeOnce('inc/header.php'); @@ -1222,8 +1228,17 @@ function app_exit ($F, $L, $message) { $message ); - // Load the message template - loadTemplate('app_exit_message', FALSE, $message); + // Is this AJAX mode again + if (isAjaxOutputMode()) { + // Load the message template + $OUT = loadTemplate('ajax_app_exit_message', TRUE, $message); + + // Output it as JSON encoded + outputHtml(encodeJson(array('reply_content' => urlencode(doFinalCompilation($OUT))))); + } else { + // Load the message template + loadTemplate('app_exit_message', FALSE, $message); + } // Load footer loadIncludeOnce('inc/footer.php'); diff --git a/inc/wrapper-functions.php b/inc/wrapper-functions.php index 4bd75bad61..4324ae39c9 100644 --- a/inc/wrapper-functions.php +++ b/inc/wrapper-functions.php @@ -3348,5 +3348,11 @@ function wrapWords ($text) { return $wrapped; } +// Encodes given data into a JSON object +function encodeJson ($data) { + // Encode it + return json_encode($data, JSON_FORCE_OBJECT); +} + // [EOF] ?> diff --git a/js/ajax-common.js b/js/ajax-common.js index 5430232af8..ccef02a08a 100644 --- a/js/ajax-common.js +++ b/js/ajax-common.js @@ -28,9 +28,6 @@ // Init variables var currentTabId = null; -var processDisplayed = false; -var errorDisplayed = false; -var warningDisplayed = false; var defaultTabId = null; var footerElements = new Array(); var changedElements = new Array(); @@ -50,10 +47,27 @@ function setCurrentTabId (tabId) { currentTabId = tabId; } +// Checks whether a given element is visible by checking 'display: none' +function isElementVisible (prefix, element) { + // Get element + var el = document.getElementById(prefix + '_' + element); + + // Is element set? + if (el == null || el == undefined) { + throw new '"' + prefix + '_' + element + '" does not exist.'; + } + + // Default is visible + var isVisible = ((el.style.display == undefined) || ((el.style.display != 'none') && (el.style.display != ''))); + + // Return status + return isVisible; +} + // Marks a tab navigation entry function markTabNavigation (prefix, tab) { // Is process working? - if (processDisplayed == true) { + if (isElementVisible(prefix, 'process')) { // Then exit silently return; } // END - if @@ -253,7 +267,7 @@ function sendAjaxRequest (level, doValue, extra, isJson) { // Enables footer navigation buttons function enableFooterNavigation (prefix, tabId) { // Is process working? - if (processDisplayed == true) { + if (isElementVisible(prefix, 'process')) { // Then exit silently return; } // END - if @@ -277,7 +291,7 @@ function enableFooterNavigation (prefix, tabId) { // Requests an AJAX content function requestAjaxContent (prefix, htmlId, tabId, footerNavigation) { // Is process working? - if (processDisplayed == true) { + if (isElementVisible(prefix, 'process')) { // Then exit silently return; } // END - if @@ -357,9 +371,6 @@ function displayTestWindow (prefix, element) { // Enable element enableElement(element); }); - - // Mark 'warning' as displayed - warningDisplayed = true; } else { // Display error message displayErrorWindow(prefix, getAjaxContent()); @@ -375,8 +386,11 @@ function displayChangedWarningWindow (prefix, button) { // Fade error out for eye-candy, if open closeErrorWindow(prefix); + // Fade it out for eye-candy + closeProcessWindow(prefix); + // Abort here if warningDisplayed is still true - if (warningDisplayed == true) { + if (isElementVisible(prefix, 'warning')) { // Make sure this doesn't happen return; } // END - if @@ -388,8 +402,7 @@ function displayChangedWarningWindow (prefix, button) { // Fade the warning in $('#' + prefix + '_warning').fadeIn('slow', function() { - // Mark warning as displayed - warningDisplayed = true; + // Do nothing for now }); } else { // Display error message @@ -406,8 +419,11 @@ function displayErrorWindow (prefix, ajax_content) { // Fade it out for eye-candy closeErrorWindow(prefix); + // Fade it out for eye-candy + closeProcessWindow(prefix); + // Abort here if errorDisplayed is still true - if (errorDisplayed == true) { + if (isElementVisible(prefix, 'error')) { // Make sure this doesn't happen return; } // END - if @@ -421,8 +437,7 @@ function displayErrorWindow (prefix, ajax_content) { // Fade the error in $('#' + prefix + '_error').fadeIn('slow', function() { - // Mark error as displayed - errorDisplayed = true; + // Do nothing for now }); } @@ -439,29 +454,35 @@ function displayProcessWindow (prefix, ajax_content) { closeProcessWindow(prefix); // Abort here if processDisplayed is still true - if (processDisplayed == true) { + if (isElementVisible(prefix, 'process')) { // Make sure this doesn't happen return; } // END - if // Copy the response text to the process variable if (ajax_content.reply_content != undefined) { - $('#' + prefix + '_process_content').html(ajax_content.reply_content); + // Set HTML content + setProcessContent(prefix, ajax_content.reply_content); } else { - $('#' + prefix + '_process_content').html(ajax_content); + setProcessContent(prefix, ajax_content); } // Fade the process in $('#' + prefix + '_process').fadeIn('slow', function() { - // Mark process as displayed - processDisplayed = true; + // Do nothing for now }); } +// Sets "process content" +function setProcessContent (prefix, content) { + // Set HTML content + $('#' + prefix + '_process_content').html(content); +} + // Waits until the window has been closed function closeErrorLocked () { // Has all been loaded? - if (errorDisplayed == false) { + if (!isElementVisible(prefix, 'error')) { // Then release ready() $.holdReady(false); } else { @@ -473,7 +494,7 @@ function closeErrorLocked () { // Waits until the window has been closed function closeProcessLocked () { // Has all been loaded? - if (processDisplayed == false) { + if (!isElementVisible(prefix, 'process')) { // Then release ready() $.holdReady(false); } else { @@ -485,7 +506,7 @@ function closeProcessLocked () { // Closes an error window function closeErrorWindow (prefix, waitClose, resetCurrentTabId) { // Is the error displayed? - if (errorDisplayed == true) { + if (isElementVisible(prefix, 'error')) { // Shall we wait ("sync") until the animation has completed? if (waitClose == true) { // Hold the ready status @@ -498,9 +519,6 @@ function closeErrorWindow (prefix, waitClose, resetCurrentTabId) { if (resetCurrentTabId == true) { setCurrentTabId(defaultTabId); } // END - if - - // Mark it as closed - errorDisplayed = false; }); // Shall this animation be "synchronized"? @@ -514,7 +532,7 @@ function closeErrorWindow (prefix, waitClose, resetCurrentTabId) { // Closes an process window function closeProcessWindow (prefix, waitClose, resetCurrentTabId) { // Is the process displayed? - if (processDisplayed == true) { + if (isElementVisible(prefix, 'process')) { // Shall we wait ("sync") until the animation has completed? if (waitClose == true) { // Hold the ready status @@ -527,9 +545,6 @@ function closeProcessWindow (prefix, waitClose, resetCurrentTabId) { if (resetCurrentTabId == true) { setCurrentTabId(defaultTabId); } // END - if - - // Mark it as closed - processDisplayed = false; }); // Shall this animation be "synchronized"? @@ -543,7 +558,7 @@ function closeProcessWindow (prefix, waitClose, resetCurrentTabId) { // Waits until the window has been closed function closeWarningLocked () { // Has all been loaded? - if (warningDisplayed == false) { + if (!isElementVisible(prefix, 'warning')) { // Then release ready() $.holdReady(false); } else { @@ -556,7 +571,7 @@ function closeWarningLocked () { function closeWarningWindow (prefix, waitClose, resetCurrentTabId) { //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ' - ENTERED!'); // Is the warning displayed? - if (warningDisplayed == true) { + if (isElementVisible(prefix, 'warning')) { // Shall we wait ("sync") until the animation has completed? //* DEBUG: */ alert('prefix=' + prefix + ',waitClose=' + waitClose + ',warningDisplayed=true'); if (waitClose == true) { @@ -567,14 +582,9 @@ function closeWarningWindow (prefix, waitClose, resetCurrentTabId) { // Yes, then fade it out $('#' + prefix + '_warning').fadeOut('fast', function() { // Set current tab id to default - //* DEBUG: */ alert('closeWarningWindow(): prefix=' + prefix + ',waitClose=' + waitClose + ',defaultTab=' + defaultTabId + ' - Calling setCurrentTabId()'); if (resetCurrentTabId == true) { setCurrentTabId(defaultTabId); } // END - if - - // Mark it as closed - warningDisplayed = false; - //* DEBUG: */ alert('closeWarningWindow(): waitClose=' + waitClose + ',resetCurrentTabId=' + resetCurrentTabId + ',warningDisplayed=false'); }); // Shall this animation be "synchronized"? @@ -599,7 +609,7 @@ function doFooterPage (prefix, htmlId, button) { } // END - if // Is process working? - if (processDisplayed == true) { + if (isElementVisible(prefix, 'process')) { // Then exit silently return; } // END - if @@ -709,7 +719,7 @@ function processAjaxResponseContent (prefix, ajax_content) { // Saves changes by sending the data to the AJAX backend script function saveChanges (prefix) { // Is process working? - if (processDisplayed == true) { + if (isElementVisible(prefix, 'process')) { // Then exit silently return; } // END - if @@ -807,7 +817,7 @@ function doSaveChangesPage (prefix, htmlId, page) { // Saves changed settings and continues with given tab function doSaveChangesContinue (prefix, htmlId, tab) { // Is process working? - if (processDisplayed == true) { + if (isElementVisible(prefix, 'process')) { // Then exit silently return; } // END - if diff --git a/js/install-common.js b/js/install-common.js index 87fcbda4b0..2983c65431 100644 --- a/js/install-common.js +++ b/js/install-common.js @@ -29,11 +29,15 @@ // Installation steps array var installSteps = new Array(); +// Failed step +var failedStep = ''; +var counterSuccess = 0; + // Init all installation steps -installSteps[0] = ''; -installSteps[1] = ''; -installSteps[2] = ''; -installSteps[3] = ''; +installSteps[0] = 'import_tables_sql'; +installSteps[1] = 'import_menu_sql'; +installSteps[2] = 'write_local_config'; +installSteps[3] = 'install_extensions'; // Switches instaler by redirecting function switchInstaller (installer) { @@ -50,4 +54,48 @@ function doFinishInstallation () { // Display process window displayProcessWindow('install', ''); + + // Start installation loop + doInstallationLoop(); + + // Is success counter same as array size + if (counterSuccess != installSteps.length) { + // Display error message + displayErrorWindow('install', getAjaxContent()); + } +} + +// Does the "installation loop" +function doInstallationLoop () { + // For-loop for all installation steps + for (var i = 0; i < installSteps.length; i++) { + // Output message + outputInstallationStepMessage(installSteps[i]); + + // Initialize next step + if (!sendInstallationStepRequest(installSteps[i]) == true) { + // Failed step, so remember it for later display + failedStep = installSteps[i]; + + // Stop here + break; + } + + // Did went okay + counterSuccess++; + + // Wait a little + } // END - for +} + +// Sends an "installation step" request out +function sendInstallationStepRequest (step) { + // Send out the request + return sendAjaxRequest('install', 'do_step', '&step=' + step, true); +} + +// Outputs a "step message" +function outputInstallationStepMessage (step) { + // Set content + setProcessContent('install', step); } diff --git a/templates/de/html/ajax_app_exit_message.tpl b/templates/de/html/ajax_app_exit_message.tpl new file mode 100644 index 0000000000..46aa36b4c2 --- /dev/null +++ b/templates/de/html/ajax_app_exit_message.tpl @@ -0,0 +1,8 @@ +
+
+ {--APPLICATION_DIED_TITLE--} +
+
+ $content +
+
diff --git a/theme/business/css/general.css b/theme/business/css/general.css index 3ea07060a2..1172b6e262 100644 --- a/theme/business/css/general.css +++ b/theme/business/css/general.css @@ -202,7 +202,7 @@ a.logout_box { margin: 5px; } -.bug_table { +.bug_table, .ajax_bug_table { background-color: #ffffff; margin: 0px; max-width: 100%; @@ -250,7 +250,7 @@ a.logout_box { background-color: #ffffff; } -.table_header, .bug_table_header { +.table_header, .bug_table_header, .ajax_bug_table_header { text-align: center; color: #000000; vertical-align: middle; diff --git a/theme/default/css/general.css b/theme/default/css/general.css index f2e0ec517a..e48bab2239 100644 --- a/theme/default/css/general.css +++ b/theme/default/css/general.css @@ -224,10 +224,19 @@ a.logout_box { margin: 0px; max-width: 100%; min-width: 400px; - overflow: auto + overflow: auto; color: #000000; } +.ajax_bug_table { + background-color: #cc0000; + margin: 0px; + max-width: 100%; + min-width: 400px; + overflow: auto; + color: #ffffff; +} + .form_submitmenu { min-width: 500px; max-width: 90%; @@ -255,15 +264,23 @@ a.logout_box { background-color: #ddeedd; } -.table_header, .bug_table_header { +.table_header, .bug_table_header, .ajax_bug_table_header { text-align: center; color: #009900; vertical-align: middle; - background-color: #ddeedd; padding-bottom: 5px; padding-top: 5px; } +.table_header, .bug_table_header { + background-color: #ddeedd; +} + +.ajax_bug_table_header { + background-color: #cc0000; + color: #ffffff; +} + .guest_login_header { color: #009900; vertical-align: middle; diff --git a/theme/desert/css/general.css b/theme/desert/css/general.css index 4f1c2ba563..3e6a4dc547 100644 --- a/theme/desert/css/general.css +++ b/theme/desert/css/general.css @@ -182,7 +182,7 @@ a.logout_box { margin: 5px; } -.bug_table { +.bug_table, .ajax_bug_table { background-color: #ffffcc; margin: 0px; max-width: 100%; diff --git a/theme/org/css/general.css b/theme/org/css/general.css index 9c72b416b7..b9333764e6 100644 --- a/theme/org/css/general.css +++ b/theme/org/css/general.css @@ -219,7 +219,7 @@ pre { background-color : #DDEEDD; } -.table_header, .bug_table_header { +.table_header, .bug_table_header, .ajax_bug_table_header { color: #000000; vertical-align: middle; background-color: #DDEEDD; diff --git a/theme/schleuder/css/general.css b/theme/schleuder/css/general.css index 65e973e4fc..e8e3d53a2d 100644 --- a/theme/schleuder/css/general.css +++ b/theme/schleuder/css/general.css @@ -143,7 +143,7 @@ pre { align : center; } -.table_header, .bug_table_header { +.table_header, .bug_table_header, .ajax_bug_table_header { background-color: #69b2ff; color: #ffffff; text-align: center; diff --git a/theme/ship-simu/css/general.css b/theme/ship-simu/css/general.css index 88980acd9b..fed0ba9423 100644 --- a/theme/ship-simu/css/general.css +++ b/theme/ship-simu/css/general.css @@ -140,7 +140,7 @@ pre { color : #000000; } -.table_header, .bug_table_header { +.table_header, .bug_table_header, .ajax_bug_table_header { background-color : #EEEEFF; color : #000000; text-align : center;