From 0839be45a5ac3281a3e0bb863ae804780bb87d9d Mon Sep 17 00:00:00 2001 From: tyron Date: Mon, 16 May 2011 15:34:57 +0200 Subject: [PATCH 002/206] Status variables in one table, that can be filtered as-you-type with javascript also the query chart is loaded with ajax now. Both features degrade gracefully for non JS users. --- js/server_status.js | 36 +++++++++ server_status.php | 177 +++++++++++++++++++++----------------------- 2 files changed, 122 insertions(+), 91 deletions(-) create mode 100644 js/server_status.js diff --git a/js/server_status.js b/js/server_status.js new file mode 100644 index 0000000000..10c29bd9e1 --- /dev/null +++ b/js/server_status.js @@ -0,0 +1,36 @@ +$(function() { + var textFilter=null; + var alertFilter = false; + + // Filter options are invisible for disabled js users + $('#serverstatusvars fieldset').css('display',''); + + $('#serverstatusquerieschart a').first().click(function() { + $.get('server_status.php',window.parent.common_query+'&query_chart_ajax=1', function(data) { + $('#serverstatusquerieschart').html(data); + }); + return false; + }); + $('#serverstatusquerieschart div.notice').css('display','none'); + + $('#filterAlert').change(function() { + alertFilter = this.checked; + filterVariables(); + }); + + $('#filterText').keyup(function(e) { + if($(this).val().length==0) textFilter=null; + else textFilter = new RegExp("(^|_)"+$(this).val(),'i'); + filterVariables(); + }); + + function filterVariables() { + $('#serverstatusvariables th.name').each(function() { + if((textFilter==null || textFilter.exec($(this).text())) + && (!alertFilter || $(this).next().find('span.attention').length>0)) + $(this).parent().css('display',''); + else + $(this).parent().css('display','none'); + }); + } +}); \ No newline at end of file diff --git a/server_status.php b/server_status.php index 3b44a4adec..5437385c80 100644 --- a/server_status.php +++ b/server_status.php @@ -16,7 +16,32 @@ if (! defined('PMA_NO_VARIABLES_IMPORT')) { } require_once './libraries/common.inc.php'; +/** + * Chart generation + */ +require_once './libraries/chart.lib.php'; + +/** + * Ajax request + */ +if (isset($_REQUEST["query_chart_ajax"])) { + $com_vars = PMA_DBI_fetch_result("SHOW GLOBAL STATUS LIKE 'Com_%'", 0, 1); + // remove all zero values from the end + // variable empty for Drizzle + if ($com_vars) { + while (end($com_vars) == 0) { + array_pop($com_vars); + } + exit(PMA_chart_status($com_vars)); + } +} + +/** + * JS Includes + */ + $GLOBALS['js_include'][] = 'pMap.js'; +$GLOBALS['js_include'][] = 'server_status.js'; /** * Does the common work @@ -35,11 +60,6 @@ require './libraries/server_links.inc.php'; require './libraries/replication.inc.php'; require_once './libraries/replication_gui.lib.php'; -/** - * Chart generation - */ -require_once './libraries/chart.lib.php'; - /** * Messages are built using the message name */ @@ -325,7 +345,7 @@ $allocations = array( // variable name => section 'Com_' => 'com', - 'Innodb_' => 'innodb', + /* 'Innodb_' => 'innodb', 'Ndb_' => 'ndb', 'Handler_' => 'handler', 'Qcache_' => 'qcache', @@ -337,7 +357,7 @@ $allocations = array( 'Key_' => 'key', 'Delayed_' => 'delayed', - 'Not_flushed_delayed_rows' => 'delayed', + 'Not_flushed_delayed_rows' => 'delayed',*/ 'Flush_commands' => 'query', 'Last_query_cost' => 'query', @@ -345,7 +365,7 @@ $allocations = array( 'Queries' => 'query', 'Prepared_stmt_count' => 'query', - 'Select_' => 'select', + /* 'Select_' => 'select', 'Sort_' => 'sort', 'Open_tables' => 'table', @@ -363,13 +383,13 @@ $allocations = array( 'Open_files' => 'files', 'Open_streams' => 'files', - 'Opened_files' => 'files', + 'Opened_files' => 'files',*/ ); $sections = array( // section => section name (description) 'com' => array('title' => ''), - 'query' => array('title' => __('SQL query')), + /*'query' => array('title' => __('SQL query')), 'innodb' => array('title' => 'InnoDB'), 'ndb' => array('title' => 'NDB'), 'handler' => array('title' => __('Handler')), @@ -385,7 +405,7 @@ $sections = array( 'table' => array('title' => __('Tables')), 'tc' => array('title' => __('Transaction coordinator')), 'files' => array('title' => __('Files')), - 'ssl' => array('title' => 'SSL'), + 'ssl' => array('title' => 'SSL'),*/ ); /** @@ -435,7 +455,7 @@ $links['innodb'][__('InnoDB Status')] $links['innodb']['doc'] = 'innodb'; -// sort status vars into arrays +// sort com_ and query_ vars into arrays foreach ($server_status as $name => $value) { if (isset($allocations[$name])) { $sections[$allocations[$name]]['vars'][$name] = $value; @@ -450,6 +470,7 @@ foreach ($server_status as $name => $value) { } } } + unset($name, $value, $filter, $section, $allocations); // rest @@ -461,7 +482,7 @@ $hour_factor = 3600 / $server_status['Uptime']; * start output */ ?> - - - min value //'Handler read key' => '> ', ); + + /** + * define some needfull links/commands + */ + // variable or section name => (name => url) + $links = array(); + + $links['table'][__('Flush (close) all tables')] + = $PMA_PHP_SELF . '?flush=TABLES&' . PMA_generate_common_url(); + $links['table'][__('Show open tables')] + = 'sql.php?sql_query=' . urlencode('SHOW OPEN TABLES') . + '&goto=server_status.php&' . PMA_generate_common_url(); + + if ($server_master_status) { + $links['repl'][__('Show slave hosts')] + = 'sql.php?sql_query=' . urlencode('SHOW SLAVE HOSTS') . + '&goto=server_status.php&' . PMA_generate_common_url(); + $links['repl'][__('Show master status')] = '#replication_master'; + } + if ($server_slave_status) { + $links['repl'][__('Show slave status')] = '#replication_slave'; + } + + $links['repl']['doc'] = 'replication'; + + $links['qcache'][__('Flush query cache')] + = $PMA_PHP_SELF . '?flush=' . urlencode('QUERY CACHE') . '&' . + PMA_generate_common_url(); + $links['qcache']['doc'] = 'query_cache'; + + $links['threads'][__('Show processes')] + = 'server_processlist.php?' . PMA_generate_common_url(); + $links['threads']['doc'] = 'mysql_threads'; + + $links['key']['doc'] = 'myisam_key_cache'; + + $links['binlog_cache']['doc'] = 'binary_log'; + + $links['Slow_queries']['doc'] = 'slow_query_log'; + + $links['innodb'][__('Variables')] + = 'server_engines.php?engine=InnoDB&' . PMA_generate_common_url(); + $links['innodb'][__('InnoDB Status')] + = 'server_engines.php?engine=InnoDB&page=Status&' . + PMA_generate_common_url(); + $links['innodb']['doc'] = 'innodb'; + ?> @@ -924,6 +912,11 @@ function printVariablesTable($server_status,$server_variables,$allocationMap) { } function createQueryChart($com_vars=FALSE) { + /** + * Chart generation + */ + require_once './libraries/chart.lib.php'; + if(!$com_vars) $com_vars = PMA_DBI_fetch_result("SHOW GLOBAL STATUS LIKE 'Com\_%'", 0, 1); From df9bcddd39e9fd66c0002bdd4e5496616dc5bc60 Mon Sep 17 00:00:00 2001 From: tyron Date: Tue, 24 May 2011 19:30:42 +0200 Subject: [PATCH 014/206] re-initialize ajax loaded tooltip --- js/functions.js | 6 ++++-- js/server_status.js | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/js/functions.js b/js/functions.js index f745e8c106..38a5cc3f75 100644 --- a/js/functions.js +++ b/js/functions.js @@ -1974,8 +1974,10 @@ $(document).ready(function() { } }); +$(document).ready(initTooltips); + /* Displays tooltips */ -$(document).ready(function() { +function initTooltips() { // Hide the footnotes from the footer (which are displayed for // JavaScript-disabled browsers) since the tooltip is sufficient $(".footnotes").hide(); @@ -2001,7 +2003,7 @@ $(document).ready(function() { style: { background: '#ffffcc' } }); }); -}); +} function menuResize() { diff --git a/js/server_status.js b/js/server_status.js index abe30a60bc..8259d53b03 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -49,6 +49,7 @@ $(function() { switch(tab.attr('id')) { case 'statustabs_traffic': tab.html(data); + initTooltips(); $('#statustabs_traffic .statuslinks a').click(function() { return refreshHandler(this); }); break; case 'statustabs_queries': From b37f788a0bba35521a693da8651ff535daa56a25 Mon Sep 17 00:00:00 2001 From: tyron Date: Tue, 24 May 2011 20:41:07 +0200 Subject: [PATCH 015/206] Fix for bug #3242060. Total sum of queries sums up all Com_ vars instead of using the Questions var --- server_status.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/server_status.php b/server_status.php index b96f690107..ae3f56ff97 100644 --- a/server_status.php +++ b/server_status.php @@ -225,9 +225,8 @@ foreach ($server_status as $name => $value) { } } -// rest - not needed anymore -// $sections['all']['vars'] =& $server_status; - +// admin commands are not queries (e.g. they include COM_PING, which is excluded from $server_status['Questions']) +unset($used_queries['Com_admin_commands']); /* Ajax request refresh */ if(isset($_REQUEST['show']) && isset($_REQUEST['ajax_request'])) { @@ -356,6 +355,8 @@ function printQueryStatistics() { global $server_status, $used_queries, $url_query; $hour_factor = 3600 / $server_status['Uptime']; + + $total_queries = array_sum($used_queries); ?>
@@ -920,8 +921,11 @@ function createQueryChart($com_vars=FALSE) { if(!$com_vars) $com_vars = PMA_DBI_fetch_result("SHOW GLOBAL STATUS LIKE 'Com\_%'", 0, 1); + // admin commands are not queries (e.g. they include COM_PING, which is excluded from $server_status['Questions']) + unset($com_vars['Com_admin_commands']); + arsort($com_vars); - + $merge_minimum = array_sum($com_vars) * 0.005; $merged_value = 0; From 7a82a65c4ecfd513448a1be9e1b11c77d51292be Mon Sep 17 00:00:00 2001 From: tyron Date: Tue, 24 May 2011 20:45:44 +0200 Subject: [PATCH 016/206] Fixed wrong variable scoping --- server_status.php | 101 +++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/server_status.php b/server_status.php index ae3f56ff97..8aa17c4f22 100644 --- a/server_status.php +++ b/server_status.php @@ -207,6 +207,52 @@ $sections = array( 'ssl' => 'SSL', ); +/** + * define some needfull links/commands + */ +// variable or section name => (name => url) +$links = array(); + +$links['table'][__('Flush (close) all tables')] + = $PMA_PHP_SELF . '?flush=TABLES&' . PMA_generate_common_url(); +$links['table'][__('Show open tables')] + = 'sql.php?sql_query=' . urlencode('SHOW OPEN TABLES') . + '&goto=server_status.php&' . PMA_generate_common_url(); + +if ($server_master_status) { + $links['repl'][__('Show slave hosts')] + = 'sql.php?sql_query=' . urlencode('SHOW SLAVE HOSTS') . + '&goto=server_status.php&' . PMA_generate_common_url(); + $links['repl'][__('Show master status')] = '#replication_master'; +} +if ($server_slave_status) { + $links['repl'][__('Show slave status')] = '#replication_slave'; +} + +$links['repl']['doc'] = 'replication'; + +$links['qcache'][__('Flush query cache')] + = $PMA_PHP_SELF . '?flush=' . urlencode('QUERY CACHE') . '&' . + PMA_generate_common_url(); +$links['qcache']['doc'] = 'query_cache'; + +$links['threads'][__('Show processes')] + = 'server_processlist.php?' . PMA_generate_common_url(); +$links['threads']['doc'] = 'mysql_threads'; + +$links['key']['doc'] = 'myisam_key_cache'; + +$links['binlog_cache']['doc'] = 'binary_log'; + +$links['Slow_queries']['doc'] = 'slow_query_log'; + +$links['innodb'][__('Variables')] + = 'server_engines.php?engine=InnoDB&' . PMA_generate_common_url(); +$links['innodb'][__('InnoDB Status')] + = 'server_engines.php?engine=InnoDB&page=Status&' . + PMA_generate_common_url(); +$links['innodb']['doc'] = 'innodb'; + // Variable to contain all com_ variables $used_queries = Array(); @@ -352,7 +398,7 @@ echo __('Runtime Information'); '> ', ); - /** - * define some needfull links/commands - */ - // variable or section name => (name => url) - $links = array(); - - $links['table'][__('Flush (close) all tables')] - = $PMA_PHP_SELF . '?flush=TABLES&' . PMA_generate_common_url(); - $links['table'][__('Show open tables')] - = 'sql.php?sql_query=' . urlencode('SHOW OPEN TABLES') . - '&goto=server_status.php&' . PMA_generate_common_url(); - - if ($server_master_status) { - $links['repl'][__('Show slave hosts')] - = 'sql.php?sql_query=' . urlencode('SHOW SLAVE HOSTS') . - '&goto=server_status.php&' . PMA_generate_common_url(); - $links['repl'][__('Show master status')] = '#replication_master'; - } - if ($server_slave_status) { - $links['repl'][__('Show slave status')] = '#replication_slave'; - } - - $links['repl']['doc'] = 'replication'; - - $links['qcache'][__('Flush query cache')] - = $PMA_PHP_SELF . '?flush=' . urlencode('QUERY CACHE') . '&' . - PMA_generate_common_url(); - $links['qcache']['doc'] = 'query_cache'; - - $links['threads'][__('Show processes')] - = 'server_processlist.php?' . PMA_generate_common_url(); - $links['threads']['doc'] = 'mysql_threads'; - - $links['key']['doc'] = 'myisam_key_cache'; - - $links['binlog_cache']['doc'] = 'binary_log'; - - $links['Slow_queries']['doc'] = 'slow_query_log'; - - $links['innodb'][__('Variables')] - = 'server_engines.php?engine=InnoDB&' . PMA_generate_common_url(); - $links['innodb'][__('InnoDB Status')] - = 'server_engines.php?engine=InnoDB&page=Status&' . - PMA_generate_common_url(); - $links['innodb']['doc'] = 'innodb'; - - ?>
From 1a4fc3b87901e7d1edaefb3681a9619e890ec9d6 Mon Sep 17 00:00:00 2001 From: tyron Date: Tue, 24 May 2011 20:48:21 +0200 Subject: [PATCH 017/206] More wrong variable scoping --- server_status.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/server_status.php b/server_status.php index 8aa17c4f22..3d62cc319f 100644 --- a/server_status.php +++ b/server_status.php @@ -31,6 +31,12 @@ if (isset($_REQUEST["query_chart"]) && isset($_REQUEST['ajax_request'])) { exit(createQueryChart()); } +/** + * Replication library + */ +require './libraries/replication.inc.php'; +require_once './libraries/replication_gui.lib.php'; + /** * JS Includes */ @@ -490,15 +496,10 @@ function printQueryStatistics() { function printServerTraffic() { global $server_status,$PMA_PHP_SELF; - + global $server_master_status, $server_slave_status; + $hour_factor = 3600 / $server_status['Uptime']; - /** - * Replication library - */ - require './libraries/replication.inc.php'; - require_once './libraries/replication_gui.lib.php'; - /** * starttime calculation */ From c0270352d8dbe5573589d95ef87aed5983f6fde7 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 May 2011 19:00:09 +0200 Subject: [PATCH 018/206] Fixed expanded 'More menu' being behind jQuery tabs. --- themes/original/css/theme_right.css.php | 1 + themes/pmahomme/css/theme_right.css.php | 1 + 2 files changed, 2 insertions(+) diff --git a/themes/original/css/theme_right.css.php b/themes/original/css/theme_right.css.php index e7bbe41c91..dc134d73c5 100644 --- a/themes/original/css/theme_right.css.php +++ b/themes/original/css/theme_right.css.php @@ -678,6 +678,7 @@ ul#topmenu ul { list-style-type: none; display: none; border: 1px #666 solid; + z-index: 2; } ul#topmenu li:hover ul, ul#topmenu .submenuhover ul { diff --git a/themes/pmahomme/css/theme_right.css.php b/themes/pmahomme/css/theme_right.css.php index 7209b60337..dd2c9ef263 100644 --- a/themes/pmahomme/css/theme_right.css.php +++ b/themes/pmahomme/css/theme_right.css.php @@ -861,6 +861,7 @@ ul#topmenu ul { list-style-type: none; display: none; border: 1px #ddd solid; + z-index: 2; } ul#topmenu li:hover { From b161f43ec9089e0d2d5fb8a619056e6f9577a380 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 May 2011 19:25:33 +0200 Subject: [PATCH 019/206] Don't show 5 second long success message when reloading privs --- js/server_privileges.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/server_privileges.js b/js/server_privileges.js index 8b9c5e99c3..314663f2e4 100644 --- a/js/server_privileges.js +++ b/js/server_privileges.js @@ -241,11 +241,11 @@ $(document).ready(function() { $("#reload_privileges_anchor.ajax").live("click", function(event) { event.preventDefault(); - PMA_ajaxShowMessage(PMA_messages['strReloadingPrivileges']); + var $msgbox = PMA_ajaxShowMessage(PMA_messages['strReloadingPrivileges']); $.get($(this).attr("href"), {'ajax_request': true}, function(data) { if(data.success == true) { - PMA_ajaxShowMessage(data.message); + PMA_ajaxRemoveMessage($msgbox); } else { PMA_ajaxShowMessage(data.error); From 99775c9bad552aac8b904996d673f1023821ab13 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 May 2011 19:30:13 +0200 Subject: [PATCH 020/206] Don't show initials table for 20 privs or less --- server_privileges.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server_privileges.php b/server_privileges.php index ec2f0a7d79..2cc6bdcf45 100644 --- a/server_privileges.php +++ b/server_privileges.php @@ -1549,10 +1549,10 @@ if (empty($_REQUEST['adduser']) && (! isset($checkprivs) || ! strlen($checkprivs /** * Displays the initials - * In an Ajax request, we don't need to show this + * In an Ajax request, we don't need to show this. Also not necassary if there is less than 20 privileges */ - if( $GLOBALS['is_ajax_request'] != true ) { + if( $GLOBALS['is_ajax_request'] != true && PMA_DBI_num_rows($res) > 20 ) { // initialize to FALSE the letters A-Z for ($letter_counter = 1; $letter_counter < 27; $letter_counter++) { From 4a788b150596a84f34012cae1a5d62712e9b5bac Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 May 2011 19:34:53 +0200 Subject: [PATCH 021/206] Small adjustments --- js/server_status.js | 74 ++++++++++++++++++++++----------------------- server_status.php | 26 +++++++++------- 2 files changed, 52 insertions(+), 48 deletions(-) diff --git a/js/server_status.js b/js/server_status.js index 8259d53b03..9aebae33b8 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -23,9 +23,9 @@ $(function() { // Init imagemap again imageMap.init(); }); - - // Ajax reload of variables - $('.statuslinks a').click(function() { return refreshHandler(this); }); + + // Ajax reload of variables + $('.statuslinks a').click(function() { return refreshHandler(this); }); $('#filterAlert').change(function() { alertFilter = this.checked; @@ -43,41 +43,41 @@ $(function() { categoryFilter = $(this).val(); filterVariables(); }); - - /* Adjust DOM / Add handlers to the tabs */ - function initTab(tab,data) { - switch(tab.attr('id')) { - case 'statustabs_traffic': - tab.html(data); - initTooltips(); - $('#statustabs_traffic .statuslinks a').click(function() { return refreshHandler(this); }); - break; - case 'statustabs_queries': - tab.html(data); - $('#statustabs_queries .statuslinks a').click(function() { return refreshHandler(this); }); - break; - case 'statustabs_allvars': - tab.find('#serverstatusvariables').html(data); - filterVariables(); - tab.find('.statuslinks a img').hide(); - break; - } - } - function refreshHandler(element) { - // ui-tabs-panel class is added by the jquery tabs feature - var tab=$(element).parents('div.ui-tabs-panel'); - - // Show ajax load icon - $(element).find('img').show(); - - $.get($(element).attr('href'),{ajax_request:1},function(data) { - initTab(tab,data); - }); - - return false; - } - + /* Adjust DOM / Add handlers to the tabs */ + function initTab(tab,data) { + switch(tab.attr('id')) { + case 'statustabs_traffic': + tab.html(data); + initTooltips(); + $('#statustabs_traffic .statuslinks a').click(function() { return refreshHandler(this); }); + break; + case 'statustabs_queries': + tab.html(data); + $('#statustabs_queries .statuslinks a').click(function() { return refreshHandler(this); }); + break; + case 'statustabs_allvars': + tab.find('#serverstatusvariables').html(data); + filterVariables(); + tab.find('.statuslinks a img').hide(); + break; + } + } + + function refreshHandler(element) { + // ui-tabs-panel class is added by the jquery tabs feature + var tab=$(element).parents('div.ui-tabs-panel'); + + // Show ajax load icon + $(element).find('img').show(); + + $.get($(element).attr('href'),{ajax_request:1},function(data) { + initTab(tab,data); + }); + + return false; + } + function filterVariables() { var useful_links=0; var section = text; diff --git a/server_status.php b/server_status.php index 3d62cc319f..dba00f9e9a 100644 --- a/server_status.php +++ b/server_status.php @@ -427,15 +427,18 @@ function printQueryStatistics() {
ø : -
+
ø : -
+
+ = 1) { + ?> ø : -
- +
+ +
@@ -516,7 +520,7 @@ function printServerTraffic() {

Server traffic: These tables show the network traffic statistics of this MySQL server since its startup.');*/ echo sprintf(__('Network traffic since startup: %s'), - implode(' ', PMA_formatByteDown( $server_status['Bytes_received'] + $server_status['Bytes_sent'], 2, 1)) + implode(' ', PMA_formatByteDown( $server_status['Bytes_received'] + $server_status['Bytes_sent'], 3, 1)) ); ?>

@@ -574,34 +578,34 @@ function printServerTraffic() { + PMA_formatByteDown($server_status['Bytes_received'], 3, 1)); ?> + $server_status['Bytes_received'] * $hour_factor, 3, 1)); ?> + PMA_formatByteDown($server_status['Bytes_sent'], 3, 1)); ?> + $server_status['Bytes_sent'] * $hour_factor, 3, 1)); ?> From 58da05381ca6daf95d377c684f6f4b13aa467ec6 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Mon, 30 May 2011 17:01:09 +0200 Subject: [PATCH 022/206] Added realtime charting of processes with the highcart lib for testing --- js/highcharts/exporting.js | 21 + js/highcharts/highcharts.js | 162 ++++++ js/server_status.js | 81 +++ server_status.php | 1022 +++++++++++++++++++---------------- 4 files changed, 826 insertions(+), 460 deletions(-) create mode 100644 js/highcharts/exporting.js create mode 100644 js/highcharts/highcharts.js diff --git a/js/highcharts/exporting.js b/js/highcharts/exporting.js new file mode 100644 index 0000000000..792c1274f2 --- /dev/null +++ b/js/highcharts/exporting.js @@ -0,0 +1,21 @@ +/* + Highcharts JS v2.1.4 (2011-03-02) + Exporting module + + (c) 2010 Torstein H?nsi + + License: www.highcharts.com/license +*/ +(function(){var k=Highcharts,y=k.Chart,C=k.addEvent,r=k.createElement,z=k.discardElement,u=k.css,w=k.merge,s=k.each,p=k.extend,D=Math.max,q=document,E=window,A="ontouchstart"in q.documentElement,B=k.setOptions({lang:{downloadPNG:"Download PNG image",downloadJPEG:"Download JPEG image",downloadPDF:"Download PDF document",downloadSVG:"Download SVG vector image",exportButtonTitle:"Export to raster or vector image",printButtonTitle:"Print the chart"}});B.navigation={menuStyle:{border:"1px solid #A0A0A0", +background:"#FFFFFF"},menuItemStyle:{padding:"0 5px",background:"none",color:"#303030",fontSize:A?"14px":"11px"},menuItemHoverStyle:{background:"#4572A5",color:"#FFFFFF"},buttonOptions:{align:"right",backgroundColor:{linearGradient:[0,0,0,20],stops:[[0.4,"#F7F7F7"],[0.6,"#E3E3E3"]]},borderColor:"#B0B0B0",borderRadius:3,borderWidth:1,height:20,hoverBorderColor:"#909090",hoverSymbolFill:"#81A7CF",hoverSymbolStroke:"#4572A5",symbolFill:"#E0E0E0",symbolStroke:"#A0A0A0",symbolX:11.5,symbolY:10.5,verticalAlign:"top", +width:24,y:10}};B.exporting={type:"image/png",url:"http://export.highcharts.com/",width:800,buttons:{exportButton:{symbol:"exportIcon",x:-10,symbolFill:"#A8BF77",hoverSymbolFill:"#768F3E",_titleKey:"exportButtonTitle",menuItems:[{textKey:"downloadPNG",onclick:function(){this.exportChart()}},{textKey:"downloadJPEG",onclick:function(){this.exportChart({type:"image/jpeg"})}},{textKey:"downloadPDF",onclick:function(){this.exportChart({type:"application/pdf"})}},{textKey:"downloadSVG",onclick:function(){this.exportChart({type:"image/svg+xml"})}}]}, +printButton:{symbol:"printIcon",x:-36,symbolFill:"#B5C9DF",hoverSymbolFill:"#779ABF",_titleKey:"printButtonTitle",onclick:function(){this.print()}}}};p(y.prototype,{getSVG:function(b){var c=this,a,f,d,i,e,h,j=w(c.options,b);if(!q.createElementNS)q.createElementNS=function(l,g){var n=q.createElement(g);n.getBBox=function(){return c.renderer.Element.prototype.getBBox.apply({element:n})};return n};a=r("div",null,{position:"absolute",top:"-9999em",width:c.chartWidth+"px",height:c.chartHeight+"px"},q.body); +p(j.chart,{renderTo:a,forExport:true});j.exporting.enabled=false;j.chart.plotBackgroundImage=null;j.series=[];s(c.series,function(l){d=l.options;d.animation=false;d.showCheckbox=false;if(d&&d.marker&&/^url\(/.test(d.marker.symbol))d.marker.symbol="circle";d.data=[];s(l.data,function(g){i=g.config;e={x:g.x,y:g.y,name:g.name};typeof i=="object"&&g.config&&i.constructor!=Array&&p(e,i);d.data.push(e);(h=g.config&&g.config.marker)&&/^url\(/.test(h.symbol)&&delete h.symbol});j.series.push(d)});b=new Highcharts.Chart(j); +f=b.container.innerHTML;j=null;b.destroy();z(a);f=f.replace(/zIndex="[^"]+"/g,"").replace(/isShadow="[^"]+"/g,"").replace(/symbolName="[^"]+"/g,"").replace(/jQuery[0-9]+="[^"]+"/g,"").replace(/isTracker="[^"]+"/g,"").replace(/url\([^#]+#/g,"url(#").replace(/id=([^" >]+)/g,'id="$1"').replace(/class=([^" ]+)/g,'class="$1"').replace(/ transform /g," ").replace(/:(path|rect)/g,"$1").replace(/style="([^"]+)"/g,function(l){return l.toLowerCase()});f=f.replace(/(url\(#highcharts-[0-9]+)"/g,"$1").replace(/"/g, +"'");if(f.match(/ xmlns="/g).length==2)f=f.replace(/xmlns="[^"]+"/,"");return f},exportChart:function(b,c){var a,f=this.getSVG(c);b=w(this.options.exporting,b);a=r("form",{method:"post",action:b.url},{display:"none"},q.body);s(["filename","type","width","svg"],function(d){r("input",{type:"hidden",name:d,value:{filename:b.filename||"chart",type:b.type,width:b.width,svg:f}[d]},null,a)});a.submit();z(a)},print:function(){var b=this,c=b.container,a=[],f=c.parentNode,d=q.body,i=d.childNodes;if(!b.isPrinting){b.isPrinting= +true;s(i,function(e,h){if(e.nodeType==1){a[h]=e.style.display;e.style.display="none"}});d.appendChild(c);E.print();setTimeout(function(){f.appendChild(c);s(i,function(e,h){if(e.nodeType==1)e.style.display=a[h]});b.isPrinting=false},1E3)}},contextMenu:function(b,c,a,f,d,i){var e=this,h=e.options.navigation,j=h.menuItemStyle,l=e.chartWidth,g=e.chartHeight,n="cache-"+b,m=e[n],o=D(d,i),t,x;if(!m){e[n]=m=r("div",{className:"highcharts-"+b},{position:"absolute",zIndex:1E3,padding:o+"px"},e.container);t= +r("div",null,p({MozBoxShadow:"3px 3px 10px #888",WebkitBoxShadow:"3px 3px 10px #888",boxShadow:"3px 3px 10px #888"},h.menuStyle),m);x=function(){u(m,{display:"none"})};C(m,"mouseleave",x);s(c,function(v){if(v)r("div",{onmouseover:function(){u(this,h.menuItemHoverStyle)},onmouseout:function(){u(this,j)},innerHTML:v.text||k.getOptions().lang[v.textKey]},p({cursor:"pointer"},j),t)[A?"ontouchstart":"onclick"]=function(){x();v.onclick.apply(e,arguments)}});e.exportMenuWidth=m.offsetWidth;e.exportMenuHeight= +m.offsetHeight}b={display:"block"};if(a+e.exportMenuWidth>l)b.right=l-a-d-o+"px";else b.left=a-o+"px";if(f+i+e.exportMenuHeight>g)b.bottom=g-f-o+"px";else b.top=f+i-o+"px";u(m,b)},addButton:function(b){function c(){g.attr(o);l.attr(m)}var a=this,f=a.renderer,d=w(a.options.navigation.buttonOptions,b),i=d.onclick,e=d.menuItems,h=d.width,j=d.height,l,g,n;b=d.borderWidth;var m={stroke:d.borderColor},o={stroke:d.symbolStroke,fill:d.symbolFill};if(d.enabled!==false){l=f.rect(0,0,h,j,d.borderRadius,b).align(d, +true).attr(p({fill:d.backgroundColor,"stroke-width":b,zIndex:19},m)).add();n=f.rect(0,0,h,j,0).align(d).attr({fill:"rgba(255, 255, 255, 0.001)",title:k.getOptions().lang[d._titleKey],zIndex:21}).css({cursor:"pointer"}).on("mouseover",function(){g.attr({stroke:d.hoverSymbolStroke,fill:d.hoverSymbolFill});l.attr({stroke:d.hoverBorderColor})}).on("mouseout",c).on("click",c).add();if(e)i=function(){c();var t=n.getBBox();a.contextMenu("export-menu",e,t.x,t.y,h,j)};n.on("click",function(){i.apply(a,arguments)}); +g=f.symbol(d.symbol,d.symbolX,d.symbolY,(d.symbolSize||12)/2).align(d,true).attr(p(o,{"stroke-width":d.symbolStrokeWidth||1,zIndex:20})).add()}}});k.Renderer.prototype.symbols.exportIcon=function(b,c,a){return["M",b-a,c+a,"L",b+a,c+a,b+a,c+a*0.5,b-a,c+a*0.5,"Z","M",b,c+a*0.5,"L",b-a*0.5,c-a/3,b-a/6,c-a/3,b-a/6,c-a,b+a/6,c-a,b+a/6,c-a/3,b+a*0.5,c-a/3,"Z"]};k.Renderer.prototype.symbols.printIcon=function(b,c,a){return["M",b-a,c+a*0.5,"L",b+a,c+a*0.5,b+a,c-a/3,b-a,c-a/3,"Z","M",b-a*0.5,c-a/3,"L",b-a* +0.5,c-a,b+a*0.5,c-a,b+a*0.5,c-a/3,"Z","M",b-a*0.5,c+a*0.5,"L",b-a*0.75,c+a,b+a*0.75,c+a,b+a*0.5,c+a*0.5,"Z"]};y.prototype.callbacks.push(function(b){var c,a=b.options.exporting,f=a.buttons;if(a.enabled!==false)for(c in f)b.addButton(f[c])})})(); diff --git a/js/highcharts/highcharts.js b/js/highcharts/highcharts.js new file mode 100644 index 0000000000..aa9de94e13 --- /dev/null +++ b/js/highcharts/highcharts.js @@ -0,0 +1,162 @@ +/* + Highcharts JS v2.1.4 (2011-03-02) + + (c) 2009-2010 Torstein H?nsi + + License: www.highcharts.com/license +*/ +(function(){function qa(a,b){a||(a={});for(var c in b)a[c]=b[c];return a}function oa(a,b){return parseInt(a,b||10)}function Kb(a){return typeof a=="string"}function Eb(a){return typeof a=="object"}function ac(a){return typeof a=="number"}function mc(a,b){for(var c=a.length;c--;)if(a[c]==b){a.splice(c,1);break}}function J(a){return a!==Ra&&a!==null}function za(a,b,c){var d,e;if(Kb(b))if(J(c))a.setAttribute(b,c);else{if(a&&a.getAttribute)e=a.getAttribute(b)}else if(J(b)&&Eb(b))for(d in b)a.setAttribute(d, +b[d]);return e}function nc(a){if(!a||a.constructor!=Array)a=[a];return a}function y(){var a=arguments,b,c,d=a.length;for(b=0;b3?g%3:0;return e+(g?c.substr(0,g)+d:"")+c.substr(g).replace(/(\d{3})(?=\d)/g,"$1"+d)+(f?b+cb(a-c).toFixed(f).slice(2):"")}function Hc(){}function Hd(a,b){function c(m,h){function x(l, +p){this.pos=l;this.minor=p;this.isNew=true;p||this.addLabel()}function w(l){if(l){this.options=l;this.id=l.id}return this}function O(){var l=[],p=[],r;Ta=u=null;Z=[];t(Ba,function(o){r=false;t(["xAxis","yAxis"],function(la){if(o.isCartesian&&(la=="xAxis"&&ma||la=="yAxis"&&!ma)&&(o.options[la]==h.index||o.options[la]===Ra&&h.index===0)){o[la]=s;Z.push(o);r=true}});if(!o.visible&&v.ignoreHiddenSeries)r=false;if(r){var T,Y,G,B,ia;if(!ma){T=o.options.stacking;Ic=T=="percent";if(T){B=o.type+y(o.options.stack, +"");ia="-"+B;o.stackKey=B;Y=l[B]||[];l[B]=Y;G=p[ia]||[];p[ia]=G}if(Ic){Ta=0;u=99}}if(o.isCartesian){t(o.data,function(la){var C=la.x,na=la.y,S=na<0,$=S?G:Y;S=S?ia:B;if(Ta===null)Ta=u=la[H];if(ma)if(C>u)u=C;else{if(Cu)u=na;else if(la=0){Ta=0;Id=true}else if(u<0){u=0;Jd=true}}}})}function ja(l,p){var r; +Fb=p?1:Ua.pow(10,ob(Ua.log(l)/Ua.LN10));r=l/Fb;if(!p){p=[1,2,2.5,5,10];if(h.allowDecimals===false)if(Fb==1)p=[1,2,5,10];else if(Fb<=0.1)p=[1/Fb]}for(var o=0;o0||!Jd))P+=l*Kd}Wa=K==P?1:Mb&&!T&&Y==r.options.tickPixelInterval?r.tickInterval:y(T,Va?1:(P-K)*Y/A);if(!N&&!J(h.tickInterval))Wa=ja(Wa);s.tickInterval=Wa;Jc=h.minorTickInterval==="auto"&&Wa?Wa/5:h.minorTickInterval;if(N){ra=[];T=Sa.global.useUTC; +var G=1E3/qb,B=6E4/qb,ia=36E5/qb;Y=864E5/qb;l=6048E5/qb;o=2592E6/qb;var la=31556952E3/qb,C=[["second",G,[1,2,5,10,15,30]],["minute",B,[1,2,5,10,15,30]],["hour",ia,[1,2,3,4,6,8,12]],["day",Y,[1,2]],["week",l,[1,2]],["month",o,[1,2,3,4,6]],["year",la,null]],na=C[6],S=na[1],$=na[2];for(r=0;r=G)$.setSeconds(S>=B?0:C*ob($.getSeconds()/ +C));if(S>=B)$[Cd](S>=ia?0:C*ob($[bd]()/C));if(S>=ia)$[Dd](S>=Y?0:C*ob($[cd]()/C));if(S>=Y)$[ed](S>=o?1:C*ob($[oc]()/C));if(S>=o){$[Ed](S>=la?0:C*ob($[Dc]()/C));p=$[Ec]()}if(S>=la){p-=p%C;$[Fd](p)}S==l&&$[ed]($[oc]()-$[dd]()+h.startOfWeek);r=1;p=$[Ec]();G=$.getTime()/qb;B=$[Dc]();for(ia=$[oc]();Gp&&ra.shift();if(h.endOnTick)P=r;else PGb[H])Gb[H]=ra.length}}function Ea(){var l,p;gb=K;cc=P;O();ga();ha=D;D=A/(P-K||1);if(!ma)for(l in ea)for(p in ea[l])ea[l][p].cum=ea[l][p].total;if(!s.isDirty)s.isDirty=K!=gb||P!=cc}function ua(l){l= +(new w(l)).render();Nb.push(l);return l}function bb(){var l=h.title,p=h.alternateGridColor,r=h.lineWidth,o,T,Y=m.hasRendered,G=Y&&J(gb)&&!isNaN(gb);o=Z.length&&J(K)&&J(P);A=M?wa:sa;D=A/(P-K||1);xa=M?V:rb;if(o||Mb){if(Jc&&!Va)for(o=K+(ra[0]-K)%Jc;o<=P;o+=Jc){Wb[o]||(Wb[o]=new x(o,true));G&&Wb[o].isNew&&Wb[o].render(null,true);Wb[o].isActive=true;Wb[o].render()}t(ra,function(B,ia){if(!Mb||B>=K&&B<=P){G&&sb[B].isNew&&sb[B].render(ia,true);sb[B].isActive=true;sb[B].render(ia)}});p&&t(ra,function(B,ia){if(ia% +2===0&&B=1E3?Gd(l,0):l},Nc=M&&h.labels.staggerLines,Xb=h.reversed,Yb=Va&&h.tickmarkPlacement=="between"?0.5:0;x.prototype={addLabel:function(){var l=this.pos,p=h.labels,r=!(l== +K&&!y(h.showFirstLabel,1)||l==P&&!y(h.showLastLabel,0)),o=Va&&M&&Va.length&&!p.step&&!p.staggerLines&&!p.rotation&&wa/Va.length||!M&&wa/2,T=this.label;l=$d.call({isFirst:l==ra[0],isLast:l==ra[ra.length-1],dateTimeLabelFormat:Kc,value:Va&&Va[l]?Va[l]:l});o=o&&{width:o-2*(p.padding||10)+$a};o=qa(o,p.style);if(T===Ra)this.label=J(l)&&r&&p.enabled?aa.text(l,0,0).attr({align:p.align,rotation:p.rotation}).css(o).add(tb):null;else T&&T.attr({text:l}).css(o)},getLabelSize:function(){var l=this.label;return l? +(this.labelBBox=l.getBBox())[M?"height":"width"]:0},render:function(l,p){var r=!this.minor,o=this.label,T=this.pos,Y=h.labels,G=this.gridLine,B=r?h.gridLineWidth:h.minorGridLineWidth,ia=r?h.gridLineColor:h.minorGridLineColor,la=r?h.gridLineDashStyle:h.minorGridLineDashStyle,C=this.mark,na=r?h.tickLength:h.minorTickLength,S=r?h.tickWidth:h.minorTickWidth||0,$=r?h.tickColor:h.minorTickColor,pc=r?h.tickPosition:h.minorTickPosition;r=Y.step;var hb=p&&Oc||Pa,Ob;Ob=M?va(T+Yb,null,null,p)+xa:V+Q+(Oa?(p&& +jd||Xa)-Ab-V:0);hb=M?hb-rb+Q-(Oa?sa:0):hb-va(T+Yb,null,null,p)-xa;if(B){T=Ka(T+Yb,B,p);if(G===Ra){G={stroke:ia,"stroke-width":B};if(la)G.dashstyle=la;this.gridLine=G=B?aa.path(T).attr(G).add(Hb):null}G&&T&&G.animate({d:T})}if(S){if(pc=="inside")na=-na;if(Oa)na=-na;B=aa.crispLine([Za,Ob,hb,Da,Ob+(M?0:-na),hb+(M?na:0)],S);if(C)C.animate({d:B});else this.mark=aa.path(B).attr({stroke:$,"stroke-width":S}).add(tb)}if(o){Ob=Ob+Y.x-(Yb&&M?Yb*D*(Xb?-1:1):0);hb=hb+Y.y-(Yb&&!M?Yb*D*(Xb?1:-1):0);J(Y.y)||(hb+= +parseInt(o.styles.lineHeight)*0.9-o.getBBox().height/2);if(Nc)hb+=l%Nc*16;if(r)o[l%r?"hide":"show"]();o[this.isNew?"attr":"animate"]({x:Ob,y:hb})}this.isNew=false},destroy:function(){for(var l in this)this[l]&&this[l].destroy&&this[l].destroy()}};w.prototype={render:function(){var l=this,p=l.options,r=p.label,o=l.label,T=p.width,Y=p.to,G,B=p.from,ia=p.dashStyle,la=l.svgElem,C=[],na,S,$=p.color;S=p.zIndex;var pc=p.events;if(T){C=Ka(p.value,T);p={stroke:$,"stroke-width":T};if(ia)p.dashstyle=ia}else if(J(B)&& +J(Y)){B=Ca(B,K);Y=pb(Y,P);G=Ka(Y);if((C=Ka(B))&&G)C.push(G[4],G[5],G[1],G[2]);else C=null;p={fill:$}}else return;if(J(S))p.zIndex=S;if(la)if(C)la.animate({d:C},null,la.onGetPath);else{la.hide();la.onGetPath=function(){la.show()}}else if(C&&C.length){l.svgElem=la=aa.path(C).attr(p).add();if(pc){ia=function(hb){la.on(hb,function(Ob){pc[hb].apply(l,[Ob])})};for(na in pc)ia(na)}}if(r&&J(r.text)&&C&&C.length&&wa>0&&sa>0){r=ya({align:M&&G&&"center",x:M?!G&&4:10,verticalAlign:!M&&G&&"middle",y:M?G?16:10: +G?6:-4,rotation:M&&!G&&90},r);if(!o)l.label=o=aa.text(r.text,0,0).attr({align:r.textAlign||r.align,rotation:r.rotation,zIndex:S}).css(r.style).add();G=[C[1],C[4],C[6]||C[1]];C=[C[2],C[5],C[7]||C[2]];na=pb.apply(Ua,G);S=pb.apply(Ua,C);o.align(r,false,{x:na,y:S,width:Ca.apply(Ua,G)-na,height:Ca.apply(Ua,C)-S});o.show()}else o&&o.hide();return l},destroy:function(){for(var l in this){this[l]&&this[l].destroy&&this[l].destroy();delete this[l]}mc(Nb,this)}};va=function(l,p,r,o){var T=1,Y=0,G=o?ha:D;o= +o?gb:K;G||(G=D);if(r){T*=-1;Y=A}if(Xb){T*=-1;Y-=T*A}if(p){if(Xb)l=A-l;l=l/G+o}else l=T*(l-o)*G+Y;return l};Ka=function(l,p,r){var o,T,Y;l=va(l,null,null,r);var G=r&&Oc||Pa,B=r&&jd||Xa,ia;r=T=fa(l+xa);o=Y=fa(G-l-xa);if(isNaN(l))ia=true;else if(M){o=ba;Y=G-rb;if(rV+wa)ia=true}else{r=V;T=B-Ab;if(oba+sa)ia=true}return ia?null:aa.crispLine([Za,r,o,Da,T,Y],p||0)};if(Ga&&ma&&Xb===Ra)Xb=true;qa(s,{addPlotBand:ua,addPlotLine:ua,adjustTickAmount:function(){if(Gb&&!N&&!Va&&!Mb){var l=ec,p=ra.length; +ec=Gb[H];if(pl)l=K;else if(P', +A?Mc("%A, %b %e, %Y",D):D,"
"]:[];t(H,function(va){xa.push(va.point.tooltipFormatter(ha))});return xa.join("")}function x(H,A){E=ma?H:(2*E+H)/3;ea=ma?A:(ea+A)/2;s.translate(E,ea);kd=cb(H-E)>1||cb(A-ea)>1?function(){x(H,A)}:null}function w(){if(!ma){var H=q.hoverPoints;s.hide();t(ga,function(A){A&&A.hide()});H&&t(H,function(A){A.setState()});q.hoverPoints=null;ma=true}}var O,ja=m.borderWidth,L=m.crosshairs,ga=[],Ea=m.style,ua=m.shared,bb=oa(Ea.padding),Ja=ja+bb,ma=true,Oa,M,E=0,ea=0;Ea.padding= +0;var s=aa.g("tooltip").attr({zIndex:8}).add(),N=aa.rect(Ja,Ja,0,0,m.borderRadius,ja).attr({fill:m.backgroundColor,"stroke-width":ja}).add(s).shadow(m.shadow),Q=aa.text("",bb+Ja,oa(Ea.fontSize)+bb+Ja).attr({zIndex:1}).css(Ea).add(s);s.hide();return{shared:ua,refresh:function(H){var A,D,ha,xa=0,va={},Ka=[];ha=H.tooltipPos;A=m.formatter||h;va=q.hoverPoints;var tb=function(Fa){return{series:Fa.series,point:Fa,x:Fa.category,y:Fa.y,percentage:Fa.percentage,total:Fa.total||Fa.stackTotal}};if(ua){va&&t(va, +function(Fa){Fa.setState()});q.hoverPoints=H;t(H,function(Fa){Fa.setState(yb);xa+=Fa.plotY;Ka.push(tb(Fa))});D=H[0].plotX;xa=fa(xa)/H.length;va={x:H[0].category};va.points=Ka;H=H[0]}else va=tb(H);va=A.call(va);O=H.series;D=ua?D:H.plotX;xa=ua?xa:H.plotY;A=fa(ha?ha[0]:Ga?wa-xa:D);D=fa(ha?ha[1]:Ga?sa-D:xa);ha=ua||!H.series.isCartesian||hc(A,D);if(va===false||!ha)w();else{if(ma){s.show();ma=false}Q.attr({text:va});ha=Q.getBBox();Oa=ha.width+2*bb;M=ha.height+2*bb;N.attr({width:Oa,height:M,stroke:m.borderColor|| +H.color||O.color||"#606060"});A=A-Oa+V-25;D=D-M+ba+10;if(A<7){A=7;D-=30}if(D<5)D=5;else if(D+M>Pa)D=Pa-M-5;x(fa(A-Ja),fa(D-Ja))}if(L){L=nc(L);D=L.length;for(var Hb;D--;)if(L[D]&&(Hb=H.series[D?"yAxis":"xAxis"])){A=Hb.getPlotLinePath(H[D?"y":"x"],1);if(ga[D])ga[D].attr({d:A,visibility:Bb});else{ha={"stroke-width":L[D].width||1,stroke:L[D].color||"#C0C0C0",zIndex:2};if(L[D].dashStyle)ha.dashstyle=L[D].dashStyle;ga[D]=aa.path(A).attr(ha).add()}}}},hide:w}}function f(m,h){function x(E){var ea;E=E||ib.event; +if(!E.target)E.target=E.srcElement;ea=E.touches?E.touches.item(0):E;if(E.type!="mousemove"||ib.opera){for(var s=ta,N={left:s.offsetLeft,top:s.offsetTop};s=s.offsetParent;){N.left+=s.offsetLeft;N.top+=s.offsetTop;if(s!=Aa.body&&s!=Aa.documentElement){N.left-=s.scrollLeft;N.top-=s.scrollTop}}qc=N}if(Ac){E.chartX=E.x;E.chartY=E.y}else if(ea.layerX===Ra){E.chartX=ea.pageX-qc.left;E.chartY=ea.pageY-qc.top}else{E.chartX=E.layerX;E.chartY=E.layerY}return E}function w(E){var ea={xAxis:[],yAxis:[]};t(ab,function(s){var N= +s.translate,Q=s.isXAxis;ea[Q?"xAxis":"yAxis"].push({axis:s,value:N((Ga?!Q:Q)?E.chartX-V:sa-E.chartY+ba,true)})});return ea}function O(){var E=m.hoverSeries,ea=m.hoverPoint;ea&&ea.onMouseOut();E&&E.onMouseOut();rc&&rc.hide();ld=null}function ja(){if(ua){var E={xAxis:[],yAxis:[]},ea=ua.getBBox(),s=ea.x-V,N=ea.y-ba;if(Ea){t(ab,function(Q){var H=Q.translate,A=Q.isXAxis,D=Ga?!A:A,ha=H(D?s:sa-N-ea.height,true);H=H(D?s+ea.width:sa-N,true);E[A?"xAxis":"yAxis"].push({axis:Q,min:pb(ha,H),max:Ca(ha,H)})});La(m, +"selection",E,md)}ua=ua.destroy()}m.mouseIsDown=nd=Ea=false;Cb(Aa,Ib?"touchend":"mouseup",ja)}var L,ga,Ea,ua,bb=v.zoomType,Ja=/x/.test(bb),ma=/y/.test(bb),Oa=Ja&&!Ga||ma&&Ga,M=ma&&!Ga||Ja&&Ga;Pc=function(){if(Qc){Qc.translate(V,ba);Ga&&Qc.attr({width:m.plotWidth,height:m.plotHeight}).invert()}else m.trackerGroup=Qc=aa.g("tracker").attr({zIndex:9}).add()};Pc();if(h.enabled)m.tooltip=rc=e(h);(function(){var E=true;ta.onmousedown=function(s){s=x(s);m.mouseIsDown=nd=true;L=s.chartX;ga=s.chartY;Qa(Aa, +Ib?"touchend":"mouseup",ja)};var ea=function(s){if(!(s&&s.touches&&s.touches.length>1)){s=x(s);if(!Ib)s.returnValue=false;var N=s.chartX,Q=s.chartY,H=!hc(N-V,Q-ba);if(Ib&&s.type=="touchstart")if(za(s.target,"isTracker"))m.runTrackerClick||s.preventDefault();else!ae&&!H&&s.preventDefault();if(H){E||O();if(NV+wa)N=V+wa;if(Qba+sa)Q=ba+sa}if(nd&&s.type!="touchstart"){if(Ea=Math.sqrt(Math.pow(L-N,2)+Math.pow(ga-Q,2))>10){if(ic&&(Ja||ma)&&hc(L-V,ga-ba))ua||(ua=aa.rect(V, +ba,Oa?1:wa,M?1:sa,0).attr({fill:"rgba(69,114,167,0.25)",zIndex:7}).add());if(ua&&Oa){N=N-L;ua.attr({width:cb(N),x:(N>0?0:N)+L})}if(ua&&M){Q=Q-ga;ua.attr({height:cb(Q),y:(Q>0?0:Q)+ga})}}}else if(!H){var A;Q=m.hoverPoint;N=m.hoverSeries;var D,ha,xa=Xa,va=Ga?s.chartY:s.chartX-V;if(rc&&h.shared){A=[];D=Ba.length;for(ha=0;haxa&&A.splice(D, +1);if(A.length&&A[0].plotX!=ld){rc.refresh(A);ld=A[0].plotX}}if(N&&N.tracker)(s=N.tooltipPoints[va])&&s!=Q&&s.onMouseOver()}return(E=H)||!ic}};ta.onmousemove=ea;Qa(ta,"mouseleave",O);ta.ontouchstart=function(s){if(Ja||ma)ta.onmousedown(s);ea(s)};ta.ontouchmove=ea;ta.ontouchend=function(){Ea&&O()};ta.onclick=function(s){var N=m.hoverPoint;s=x(s);s.cancelBubble=true;if(!Ea)if(N&&za(s.target,"isTracker")){var Q=N.plotX,H=N.plotY;qa(N,{pageX:qc.left+V+(Ga?wa-H:Q),pageY:qc.top+ba+(Ga?sa-Q:H)});La(N.series, +"click",qa(s,{point:N}));N.firePointEvent("click",s)}else{qa(s,w(s));hc(s.chartX-V,s.chartY-ba)&&La(m,"click",s)}Ea=false}})();Nd=setInterval(function(){kd&&kd()},32);qa(this,{zoomX:Ja,zoomY:ma,resetTracker:O})}function g(m){var h=m.type||v.type||v.defaultSeriesType,x=ub[h],w=q.hasRendered;if(w)if(Ga&&h=="column")x=ub.bar;else if(!Ga&&h=="bar")x=ub.column;h=new x;h.init(q,m);if(!w&&h.inverted)Ga=true;if(h.isCartesian)ic=h.isCartesian;Ba.push(h);return h}function i(){v.alignTicks!==false&&t(ab,function(m){m.adjustTickAmount()}); +Gb=null}function k(m){var h=q.isDirtyLegend,x,w=q.isDirtyBox,O=Ba.length,ja=O,L=q.clipRect;for(bc(m,q);ja--;){m=Ba[ja];if(m.isDirty&&m.options.stacking){x=true;break}}if(x)for(ja=O;ja--;){m=Ba[ja];if(m.options.stacking)m.isDirty=true}t(Ba,function(ga){if(ga.isDirty){ga.cleanData();ga.getSegments();if(ga.options.legendType=="point")h=true}});if(h&&od.renderLegend){od.renderLegend();q.isDirtyLegend=false}if(ic){if(!Rc){Gb=null;t(ab,function(ga){ga.setScale()})}i();sc();t(ab,function(ga){if(ga.isDirty|| +w){ga.redraw();w=true}})}if(w){pd();Pc();if(L){Sc(L);L.animate({width:q.plotSizeX,height:q.plotSizeY})}}t(Ba,function(ga){if(ga.isDirty&&ga.visible&&(!ga.isCartesian||ga.xAxis))ga.redraw()});gc&&gc.resetTracker&&gc.resetTracker();La(q,"redraw")}function j(){var m=a.xAxis||{},h=a.yAxis||{},x;m=nc(m);t(m,function(w,O){w.index=O;w.isX=true});h=nc(h);t(h,function(w,O){w.index=O});ab=m.concat(h);q.xAxis=[];q.yAxis=[];ab=jc(ab,function(w){x=new c(q,w);q[x.isXAxis?"xAxis":"yAxis"].push(x);return x});i()} +function n(m,h){kc=ya(a.title,m);tc=ya(a.subtitle,h);t([["title",m,kc],["subtitle",h,tc]],function(x){var w=x[0],O=q[w],ja=x[1];x=x[2];if(O&&ja){O.destroy();O=null}if(x&&x.text&&!O)q[w]=aa.text(x.text,0,0).attr({align:x.align,"class":"highcharts-"+w,zIndex:1}).css(x.style).add().align(x,false,uc)})}function z(){jb=v.renderTo;Od=Zb+qd++;if(Kb(jb))jb=Aa.getElementById(jb);jb.innerHTML="";if(!jb.offsetWidth){Qb=jb.cloneNode(0);Ia(Qb,{position:lc,top:"-9999px",display:""});Aa.body.appendChild(Qb)}Tc= +(Qb||jb).offsetWidth;vc=(Qb||jb).offsetHeight;q.chartWidth=Xa=v.width||Tc||600;q.chartHeight=Pa=v.height||(vc>19?vc:400);q.container=ta=fb(Lb,{className:"highcharts-container"+(v.className?" "+v.className:""),id:Od},qa({position:Pd,overflow:vb,width:Xa+$a,height:Pa+$a,textAlign:"left"},v.style),Qb||jb);q.renderer=aa=v.forExport?new Uc(ta,Xa,Pa,true):new Qd(ta,Xa,Pa);var m,h;if(Rd&&ta.getBoundingClientRect){m=function(){Ia(ta,{left:0,top:0});h=ta.getBoundingClientRect();Ia(ta,{left:-h.left%1+$a,top:-h.top% +1+$a})};m();Qa(ib,"resize",m);Qa(q,"destroy",function(){Cb(ib,"resize",m)})}}function F(){function m(){var x=v.width||jb.offsetWidth,w=v.height||jb.offsetHeight;if(x&&w){if(x!=Tc||w!=vc){clearTimeout(h);h=setTimeout(function(){rd(x,w,false)},100)}Tc=x;vc=w}}var h;Qa(window,"resize",m);Qa(q,"destroy",function(){Cb(window,"resize",m)})}function W(){var m=a.labels,h=a.credits,x;n();od=q.legend=new be(q);sc();t(ab,function(w){w.setTickPositions(true)});i();sc();pd();ic&&t(ab,function(w){w.render()}); +if(!q.seriesGroup)q.seriesGroup=aa.g("series-group").attr({zIndex:3}).add();t(Ba,function(w){w.translate();w.setTooltipPoints();w.render()});m.items&&t(m.items,function(){var w=qa(m.style,this.style),O=oa(w.left)+V,ja=oa(w.top)+ba+12;delete w.left;delete w.top;aa.text(this.html,O,ja).attr({zIndex:2}).css(w).add()});if(!q.toolbar)q.toolbar=d(q);if(h.enabled&&!q.credits){x=h.href;aa.text(h.text,0,0).on("click",function(){if(x)location.href=x}).attr({align:h.position.align,zIndex:8}).css(h.style).add().align(h.position)}Pc(); +q.hasRendered=true;if(Qb){jb.appendChild(ta);Fc(Qb)}}function ca(){var m=Ba.length,h=ta&&ta.parentNode;La(q,"destroy");Cb(ib,"unload",ca);Cb(q);for(t(ab,function(x){Cb(x)});m--;)Ba[m].destroy();if(ta){ta.innerHTML="";Cb(ta);h&&h.removeChild(ta);ta=null}if(aa)aa.alignedObjects=null;clearInterval(Nd);for(m in q)delete q[m]}function ka(){if(!wc&&ib==ib.top&&Aa.readyState!="complete")Aa.attachEvent("onreadystatechange",function(){Aa.detachEvent("onreadystatechange",ka);ka()});else{z();sd();td();t(a.series|| +[],function(m){g(m)});q.inverted=Ga=y(Ga,a.chart.inverted);j();q.render=W;q.tracker=gc=new f(q,a.tooltip);W();La(q,"load");b&&b.apply(q,[q]);t(q.callbacks,function(m){m.apply(q,[q])})}}Lc=ya(Lc,Sa.xAxis);hd=ya(hd,Sa.yAxis);Sa.xAxis=Sa.yAxis=null;a=ya(Sa,a);var v=a.chart,I=v.margin;I=Eb(I)?I:[I,I,I,I];var da=y(v.marginTop,I[0]),X=y(v.marginRight,I[1]),U=y(v.marginBottom,I[2]),R=y(v.marginLeft,I[3]),Ha=v.spacingTop,Ya=v.spacingRight,ud=v.spacingBottom,Vc=v.spacingLeft,uc,kc,tc,ba,Ab,rb,V,Pb,jb,Qb,ta, +Od,Tc,vc,Xa,Pa,jd,Oc,Wc,vd,wd,Xc,q=this,ae=(I=v.events)&&!!I.click,xd,hc,rc,nd,$b,Sd,yd,sa,wa,gc,Qc,Pc,od,Rb,Sb,qc,ic=v.showAxes,Rc=0,ab=[],Gb,Ba=[],Ga,aa,kd,Nd,ld,pd,sc,sd,td,rd,md,Td,be=function(m){function h(u,Z){var pa=u.legendItem,Na=u.legendLine,P=u.legendSymbol,K=M.color,gb=Z?L.itemStyle.color:K;K=Z?u.color:K;pa&&pa.css({fill:gb});Na&&Na.attr({stroke:K});P&&P.attr({stroke:K,fill:K})}function x(u,Z,pa){var Na=u.legendItem,P=u.legendLine,K=u.legendSymbol;u=u.checkbox;Na&&Na.attr({x:Z,y:pa}); +P&&P.translate(Z,pa-4);K&&K.attr({x:Z+K.xOff,y:pa+K.yOff});if(u){u.x=Z;u.y=pa}}function w(){t(bb,function(u){var Z=u.checkbox;Z&&Ia(Z,{left:Ka.attr("translateX")+u.legendItemWidth+Z.x-40+$a,top:Ka.attr("translateY")+Z.y-11+$a})})}function O(u){var Z,pa,Na,P,K,gb=u.legendItem;P=u.series||u;if(!gb){K=/^(bar|pie|area|column)$/.test(P.type);u.legendItem=gb=aa.text(L.labelFormatter.call(u),0,0).css(u.visible?ma:M).on("mouseover",function(){u.setState(yb);gb.css(Oa)}).on("mouseout",function(){gb.css(u.visible? +ma:M);u.setState()}).on("click",function(){var Vb=function(){u.setVisible()};u.firePointEvent?u.firePointEvent("legendItemClick",null,Vb):La(u,"legendItemClick",null,Vb)}).attr({zIndex:2}).add(Ka);if(!K&&u.options&&u.options.lineWidth){var cc=u.options;P={"stroke-width":cc.lineWidth,zIndex:2};if(cc.dashStyle)P.dashstyle=cc.dashStyle;u.legendLine=aa.path([Za,-Ea-ua,0,Da,-ua,0]).attr(P).add(Ka)}if(K)Z=aa.rect(pa=-Ea-ua,Na=-11,Ea,12,2).attr({"stroke-width":0,zIndex:3}).add(Ka);else if(u.options&&u.options.marker&& +u.options.marker.enabled)Z=aa.symbol(u.symbol,pa=-Ea/2-ua,Na=-4,u.options.marker.radius).attr(u.pointAttr[db]).attr({zIndex:3}).add(Ka);if(Z){Z.xOff=pa;Z.yOff=Na}u.legendSymbol=Z;h(u,u.visible);if(u.options&&u.options.showCheckbox){u.checkbox=fb("input",{type:"checkbox",checked:u.selected,defaultChecked:u.selected},L.itemCheckboxStyle,ta);Qa(u.checkbox,"click",function(Vb){La(u,"checkboxClick",{checked:Vb.target.checked},function(){u.select()})})}}Z=gb.getBBox();pa=u.legendItemWidth=L.itemWidth|| +Ea+ua+Z.width+ea;D=Z.height;if(ga&&Q-N+pa>(Hb||Xa-2*E-N)){Q=N;H+=D}A=H;x(u,Q,H);if(ga)Q+=pa;else H+=D;tb=Hb||Ca(ga?Q-N:pa,tb);bb.push(u)}function ja(){Q=N;H=s;A=tb=0;bb=[];Ka||(Ka=aa.g("legend").attr({zIndex:7}).add());Ta&&Fa.reverse();t(Fa,function(Na){if(Na.options.showInLegend)t(Na.options.legendType=="point"?Na.data:[Na],O)});Ta&&Fa.reverse();Rb=Hb||tb;Sb=A-s+D;if(xa||va){Rb+=2*E;Sb+=2*E;if(ha)Rb>0&&Sb>0&&ha.animate(ha.crisp(null,null,null,Rb,Sb));else ha=aa.rect(0,0,Rb,Sb,L.borderRadius,xa|| +0).attr({stroke:L.borderColor,"stroke-width":xa||0,fill:va||nb}).add(Ka).shadow(L.shadow);ha[bb.length?"show":"hide"]()}for(var u=["left","right","top","bottom"],Z,pa=4;pa--;){Z=u[pa];if(Ja[Z]&&Ja[Z]!="auto"){L[pa<2?"align":"verticalAlign"]=Z;L[pa<2?"x":"y"]=oa(Ja[Z])*(pa%2?-1:1)}}Ka.align(qa(L,{width:Rb,height:Sb}),true,uc);Rc||w()}var L=m.options.legend;if(L.enabled){var ga=L.layout=="horizontal",Ea=L.symbolWidth,ua=L.symbolPadding,bb,Ja=L.style,ma=L.itemStyle,Oa=L.itemHoverStyle,M=L.itemHiddenStyle, +E=oa(Ja.padding),ea=20,s=18,N=4+E+Ea+ua,Q,H,A,D=0,ha,xa=L.borderWidth,va=L.backgroundColor,Ka,tb,Hb=L.width,Fa=m.series,Ta=L.reversed;ja();Qa(m,"endResize",w);return{colorizeItem:h,destroyItem:function(u){var Z=u.checkbox;t(["legendItem","legendLine","legendSymbol"],function(pa){u[pa]&&u[pa].destroy()});Z&&Fc(u.checkbox)},renderLegend:ja}}};hc=function(m,h){return m>=0&&m<=wa&&h>=0&&h<=sa};Td=function(){La(q,"selection",{resetSelection:true},md);q.toolbar.remove("zoom")};md=function(m){var h=Sa.lang, +x=q.pointCount<100;q.toolbar.add("zoom",h.resetZoom,h.resetZoomTitle,Td);!m||m.resetSelection?t(ab,function(w){w.setExtremes(null,null,false,x)}):t(m.xAxis.concat(m.yAxis),function(w){var O=w.axis;if(q.tracker[O.isXAxis?"zoomX":"zoomY"])O.setExtremes(w.min,w.max,false,x)});k()};sc=function(){var m=a.legend,h=y(m.margin,10),x=m.x,w=m.y,O=m.align,ja=m.verticalAlign,L;sd();if((q.title||q.subtitle)&&!J(da))if(L=Ca(q.title&&!kc.floating&&!kc.verticalAlign&&kc.y||0,q.subtitle&&!tc.floating&&!tc.verticalAlign&& +tc.y||0))ba=Ca(ba,L+y(kc.margin,15)+Ha);if(m.enabled&&!m.floating)if(O=="right")J(X)||(Ab=Ca(Ab,Rb-x+h+Ya));else if(O=="left")J(R)||(V=Ca(V,Rb+x+h+Vc));else if(ja=="top")J(da)||(ba=Ca(ba,Sb+w+h+Ha));else if(ja=="bottom")J(U)||(rb=Ca(rb,Sb-w+h+ud));ic&&t(ab,function(ga){ga.getOffset()});J(R)||(V+=Pb[3]);J(da)||(ba+=Pb[0]);J(U)||(rb+=Pb[2]);J(X)||(Ab+=Pb[1]);td()};rd=function(m,h,x){var w=q.title,O=q.subtitle;Rc+=1;bc(x,q);Oc=Pa;jd=Xa;Xa=fa(m);Pa=fa(h);Ia(ta,{width:Xa+$a,height:Pa+$a});aa.setSize(Xa, +Pa,x);wa=Xa-V-Ab;sa=Pa-ba-rb;Gb=null;t(ab,function(ja){ja.isDirty=true;ja.setScale()});t(Ba,function(ja){ja.isDirty=true});q.isDirtyLegend=true;q.isDirtyBox=true;sc();w&&w.align(null,null,uc);O&&O.align(null,null,uc);k(x);Oc=null;La(q,"resize");setTimeout(function(){La(q,"endResize",null,function(){Rc-=1})},Bc&&Bc.duration||500)};td=function(){q.plotLeft=V=fa(V);q.plotTop=ba=fa(ba);q.plotWidth=wa=fa(Xa-V-Ab);q.plotHeight=sa=fa(Pa-ba-rb);q.plotSizeX=Ga?sa:wa;q.plotSizeY=Ga?wa:sa;uc={x:Vc,y:Ha,width:Xa- +Vc-Ya,height:Pa-Ha-ud}};sd=function(){ba=y(da,Ha);Ab=y(X,Ya);rb=y(U,ud);V=y(R,Vc);Pb=[0,0,0,0]};pd=function(){var m=v.borderWidth||0,h=v.backgroundColor,x=v.plotBackgroundColor,w=v.plotBackgroundImage,O,ja={x:V,y:ba,width:wa,height:sa};O=m+(v.shadow?8:0);if(m||h)if(Wc)Wc.animate(Wc.crisp(null,null,null,Xa-O,Pa-O));else Wc=aa.rect(O/2,O/2,Xa-O,Pa-O,v.borderRadius,m).attr({stroke:v.borderColor,"stroke-width":m,fill:h||nb}).add().shadow(v.shadow);if(x)if(vd)vd.animate(ja);else vd=aa.rect(V,ba,wa,sa, +0).attr({fill:x}).add().shadow(v.plotShadow);if(w)if(wd)wd.animate(ja);else wd=aa.image(w,V,ba,wa,sa).add();if(v.plotBorderWidth)if(Xc)Xc.animate(Xc.crisp(null,V,ba,wa,sa));else Xc=aa.rect(V,ba,wa,sa,0,v.plotBorderWidth).attr({stroke:v.plotBorderColor,"stroke-width":v.plotBorderWidth,zIndex:4}).add();q.isDirtyBox=false};Yc=Jb=0;Qa(ib,"unload",ca);v.reflow!==false&&Qa(q,"load",F);if(I)for(xd in I)Qa(q,xd,I[xd]);q.options=a;q.series=Ba;q.addSeries=function(m,h,x){var w;if(m){bc(x,q);h=y(h,true);La(q, +"addSeries",{options:m},function(){w=g(m);w.isDirty=true;q.isDirtyLegend=true;h&&q.redraw()})}return w};q.animation=y(v.animation,true);q.destroy=ca;q.get=function(m){var h,x,w;for(h=0;h-1,f=e?7:3,g;b=b.split(" ");c=[].concat(c);var i,k,j=function(n){for(g=n.length;g--;)n[g]==Za&&n.splice(g+1,0,n[g+1],n[g+2],n[g+1],n[g+2])};if(e){j(b);j(c)}if(a.isArea){i= +b.splice(b.length-6,6);k=c.splice(c.length-6,6)}if(d){c=[].concat(c).splice(0,f).concat(c);a.shift=false}if(b.length)for(a=c.length;b.length255)b[e]=255}}return this},setOpacity:function(d){b[3]=d;return this}}};Mc=function(a,b,c){function d(F){return F.toString().replace(/^([0-9])$/,"0$1")}if(!J(b)||isNaN(b))return"Invalid date";a=y(a,"%Y-%m-%d %H:%M:%S");b=new Date(b* +qb);var e=b[cd](),f=b[dd](),g=b[oc](),i=b[Dc](),k=b[Ec](),j=Sa.lang,n=j.weekdays;j=j.months;b={a:n[f].substr(0,3),A:n[f],d:d(g),e:g,b:j[i].substr(0,3),B:j[i],m:d(i+1),y:k.toString().substr(2,2),Y:k,H:d(e),I:d(e%12||12),l:e%12||12,M:d(b[bd]()),p:e<12?"AM":"PM",P:e<12?"am":"pm",S:d(b.getSeconds())};for(var z in b)a=a.replace("%"+z,b[z]);return c?a.substr(0,1).toUpperCase()+a.substr(1):a};Hc.prototype={init:function(a,b){this.element=Aa.createElementNS("http://www.w3.org/2000/svg",b);this.renderer=a}, +animate:function(a,b,c){if(b=y(b,Bc,true)){b=ya(b);if(c)b.complete=c;Zc(this,a,b)}else{this.attr(a);c&&c()}},attr:function(a,b){var c,d,e,f,g=this.element,i=g.nodeName,k=this.renderer,j,n=this.shadows,z,F=this;if(Kb(a)&&J(b)){c=a;a={};a[c]=b}if(Kb(a)){c=a;if(i=="circle")c={x:"cx",y:"cy"}[c]||c;else if(c=="strokeWidth")c="stroke-width";F=za(g,c)||this[c]||0;if(c!="d"&&c!="visibility")F=parseFloat(F)}else for(c in a){j=false;d=a[c];if(c=="d"){if(d&&d.join)d=d.join(" ");if(/(NaN| {2}|^$)/.test(d))d= +"M 0 0";this.d=d}else if(c=="x"&&i=="text"){for(e=0;eg||!J(g)&& +J(b))){d.insertBefore(f,a);return this}}d.appendChild(f);this.added=true;return this},destroy:function(){var a=this.element||{},b=this.shadows,c=a.parentNode,d;a.onclick=a.onmouseout=a.onmouseover=a.onmousemove=null;Sc(this);c&&c.removeChild(a);b&&t(b,function(e){(c=e.parentNode)&&c.removeChild(e)});mc(this.renderer.alignedObjects,this);for(d in this)delete this[d];return null},empty:function(){for(var a=this.element,b=a.childNodes,c=b.length;c--;)a.removeChild(b[c])},shadow:function(a){var b=[], +c,d=this.element,e=this.parentInverted?"(-1,-1)":"(1,1)";if(a){for(a=1;a<=3;a++){c=d.cloneNode(0);za(c,{isShadow:"true",stroke:"rgb(0, 0, 0)","stroke-opacity":0.05*a,"stroke-width":7-2*a,transform:"translate"+e,fill:nb});d.parentNode.insertBefore(c,d);b.push(c)}this.shadows=b}return this}};var Uc=function(){this.init.apply(this,arguments)};Uc.prototype={init:function(a,b,c,d){var e=location,f;this.Element=Hc;f=this.createElement("svg").attr({xmlns:"http://www.w3.org/2000/svg",version:"1.1"});a.appendChild(f.element); +this.box=f.element;this.boxWrapper=f;this.alignedObjects=[];this.url=Ac?"":e.href.replace(/#.*?$/,"");this.defs=this.createElement("defs").add();this.forExport=d;this.setSize(b,c,false)},createElement:function(a){var b=new this.Element;b.init(this,a);return b},buildText:function(a){for(var b=a.element,c=y(a.textStr,"").toString().replace(/<(b|strong)>/g,'').replace(/<(i|em)>/g,'').replace(//g, +"").split(/]?>/g),d=b.childNodes,e=/style="([^"]+)"/,f=/href="([^"]+)"/,g=za(b,"x"),i=a.styles,k=Rd&&i&&i.HcDirection=="rtl"&&!this.forExport,j,n=i&&oa(i.width),z=i&&i.lineHeight,F,W=d.length;W--;)b.removeChild(d[W]);n&&!a.added&&this.box.appendChild(b);t(c,function(ca,ka){var v,I=0,da;ca=ca.replace(//g,"|||");v=ca.split("|||");t(v,function(X){if(X!==""||v.length==1){var U={},R=Aa.createElementNS("http://www.w3.org/2000/svg","tspan");e.test(X)&& +za(R,"style",X.match(e)[1].replace(/(;| |^)color([ :])/,"$1fill$2"));if(f.test(X)){za(R,"onclick",'location.href="'+X.match(f)[1]+'"');Ia(R,{cursor:"pointer"})}X=X.replace(/<(.|\n)*?>/g,"")||" ";if(k){j=[];for(W=X.length;W--;)j.push(X.charAt(W));X=j.join("")}R.appendChild(Aa.createTextNode(X));if(I)U.dx=3;else U.x=g;if(!I){if(ka){da=oa(window.getComputedStyle(F,null).getPropertyValue("line-height"));if(isNaN(da))da=z||F.offsetHeight||18;za(R,"dy",da)}F=R}za(R,U);b.appendChild(R);I++;if(n){X=X.replace(/-/g, +"- ").split(" ");for(var Ha,Ya=[];X.length||Ya.length;){Ha=b.getBBox().width;U=Ha>n;if(!U||X.length==1){X=Ya;Ya=[];if(X.length){R=Aa.createElementNS("http://www.w3.org/2000/svg","tspan");za(R,{x:g,dy:z||16});b.appendChild(R);if(Ha>n)n=Ha}}else{R.removeChild(R.firstChild);Ya.unshift(X.pop())}R.appendChild(Aa.createTextNode(X.join(" ").replace(/- /g,"-")))}}}})})},crispLine:function(a,b){if(a[1]==a[4])a[1]=a[4]=fa(a[1])+b%2/2;if(a[2]==a[5])a[2]=a[5]=fa(a[2])+b%2/2;return a},path:function(a){return this.createElement("path").attr({d:a, +fill:nb})},circle:function(a,b,c){a=Eb(a)?a:{x:a,y:b,r:c};return this.createElement("circle").attr(a)},arc:function(a,b,c,d,e,f){if(Eb(a)){b=a.y;c=a.r;d=a.innerR;e=a.start;f=a.end;a=a.x}return this.symbol("arc",a||0,b||0,c||0,{innerR:d||0,start:e||0,end:f||0})},rect:function(a,b,c,d,e,f){if(Eb(a)){b=a.y;c=a.width;d=a.height;e=a.r;a=a.x}e=this.createElement("rect").attr({rx:e,ry:e,fill:nb});return e.attr(e.crisp(f,a,b,Ca(c,0),Ca(d,0)))},setSize:function(a,b,c){var d=this.alignedObjects,e=d.length; +this.width=a;this.height=b;for(this.boxWrapper[y(c,true)?"animate":"attr"]({width:a,height:b});e--;)d[e].align()},g:function(a){return this.createElement("g").attr(J(a)&&{"class":Zb+a})},image:function(a,b,c,d,e){var f={preserveAspectRatio:nb};arguments.length>1&&qa(f,{x:b,y:c,width:d,height:e});f=this.createElement("image").attr(f);f.element.setAttributeNS("http://www.w3.org/1999/xlink","href",a);return f},symbol:function(a,b,c,d,e){var f,g=this.symbols[a];g=g&&g(b,c,d,e);var i=/^url\((.*?)\)$/; +if(g){f=this.path(g);qa(f,{symbolName:a,x:b,y:c,r:d});e&&qa(f,e)}else if(i.test(a)){a=a.match(i)[1];f=this.image(a).attr({x:b,y:c});fb("img",{onload:function(){var k=de[this.src]||[this.width,this.height];f.attr({width:k[0],height:k[1]}).translate(-fa(k[0]/2),-fa(k[1]/2))},src:a})}else f=this.circle(b,c,d);return f},symbols:{square:function(a,b,c){c=0.707*c;return[Za,a-c,b-c,Da,a+c,b-c,a+c,b+c,a-c,b+c,"Z"]},triangle:function(a,b,c){return[Za,a,b-1.33*c,Da,a+c,b+0.67*c,a-c,b+0.67*c,"Z"]},"triangle-down":function(a, +b,c){return[Za,a,b+1.33*c,Da,a-c,b-0.67*c,a+c,b-0.67*c,"Z"]},diamond:function(a,b,c){return[Za,a,b-c,Da,a+c,b,a,b+c,a-c,b,"Z"]},arc:function(a,b,c,d){var e=d.start,f=d.end-1.0E-6,g=d.innerR,i=kb(e),k=zb(e),j=kb(f);f=zb(f);d=d.end-e');if(b){c=b==Lb||b=="span"||b=="img"?c.join(""): +a.prepVML(c);this.element=fb(c)}this.renderer=a},add:function(a){var b=this.renderer,c=this.element,d=b.box;d=a?a.element||a:d;a&&a.inverted&&b.invertChild(c,d);yc&&d.gVis==vb&&Ia(c,{visibility:vb});d.appendChild(c);this.added=true;this.alignOnAdd&&this.updateTransform();return this},attr:function(a,b){var c,d,e,f=this.element||{},g=f.style,i=f.nodeName,k=this.renderer,j=this.symbolName,n,z,F=this.shadows,W=this;if(Kb(a)&&J(b)){c=a;a={};a[c]=b}if(Kb(a)){c=a;W=c=="strokeWidth"||c=="stroke-width"?this.strokeweight: +this[c]}else for(c in a){d=a[c];n=false;if(j&&/^(x|y|r|start|end|width|height|innerR)/.test(c)){if(!z){this.symbolAttr(a);z=true}n=true}else if(c=="d"){d=d||[];this.d=d.join(" ");e=d.length;for(n=[];e--;)n[e]=ac(d[e])?fa(d[e]*10)-5:d[e]=="Z"?"x":d[e];d=n.join(" ")||"x";f.path=d;if(F)for(e=F.length;e--;)F[e].path=d;n=true}else if(c=="zIndex"||c=="visibility"){if(yc&&c=="visibility"&&i=="DIV"){f.gVis=d;n=f.childNodes;for(e=n.length;e--;)Ia(n[e],{visibility:d});if(d==Bb)d=null}if(d)g[c]=d;n=true}else if(/^(width|height)$/.test(c)){if(this.updateClipping){this[c]= +d;this.updateClipping()}else g[c]=d;n=true}else if(/^(x|y)$/.test(c)){this[c]=d;if(f.tagName=="SPAN")this.updateTransform();else g[{x:"left",y:"top"}[c]]=d}else if(c=="class")f.className=d;else if(c=="stroke"){d=k.color(d,f,c);c="strokecolor"}else if(c=="stroke-width"||c=="strokeWidth"){f.stroked=d?true:false;c="strokeweight";this[c]=d;if(ac(d))d+=$a}else if(c=="dashstyle"){(f.getElementsByTagName("stroke")[0]||fb(k.prepVML([""]),null,null,f))[c]=d||"solid";this.dashstyle=d;n=true}else if(c== +"fill")if(i=="SPAN")g.color=d;else{f.filled=d!=nb?true:false;d=k.color(d,f,c);c="fillcolor"}else if(c=="translateX"||c=="translateY"||c=="rotation"||c=="align"){if(c=="align")c="textAlign";this[c]=d;this.updateTransform();n=true}else if(c=="text"){f.innerHTML=d;n=true}if(F&&c=="visibility")for(e=F.length;e--;)F[e].style[c]=d;if(!n)if(yc)f[c]=d;else za(f,c,d)}return W},clip:function(a){var b=this,c=a.members;c.push(b);b.destroyClip=function(){mc(c,b)};return b.css(a.getCSS(b.inverted))},css:function(a){var b= +this.element;if(b=a&&b.tagName=="SPAN"&&a.width){delete a.width;this.textWidth=b;this.updateTransform()}this.styles=qa(this.styles,a);Ia(this.element,a);return this},destroy:function(){this.destroyClip&&this.destroyClip();Hc.prototype.destroy.apply(this)},empty:function(){for(var a=this.element.childNodes,b=a.length,c;b--;){c=a[b];c.parentNode.removeChild(c)}},getBBox:function(){var a=this.element;if(a.nodeName=="text")a.style.position=lc;return{x:a.offsetLeft,y:a.offsetTop,width:a.offsetWidth,height:a.offsetHeight}}, +on:function(a,b){this.element["on"+a]=function(){var c=ib.event;c.target=c.srcElement;b(c)};return this},updateTransform:function(){if(this.added){var a=this,b=a.element,c=a.translateX||0,d=a.translateY||0,e=a.x||0,f=a.y||0,g=a.textAlign||"left",i={left:0,center:0.5,right:1}[g],k=g&&g!="left";if(c||d)a.css({marginLeft:c,marginTop:d});a.inverted&&t(b.childNodes,function(I){a.renderer.invertChild(I,b)});if(b.tagName=="SPAN"){var j,n;c=a.rotation;var z;j=0;d=1;var F=0,W;z=oa(a.textWidth);var ca=a.xCorr|| +0,ka=a.yCorr||0,v=[c,g,b.innerHTML,a.textWidth].join(",");if(v!=a.cTT){if(J(c)){j=c*Ud;d=kb(j);F=zb(j);Ia(b,{filter:c?["progid:DXImageTransform.Microsoft.Matrix(M11=",d,", M12=",-F,", M21=",F,", M22=",d,", sizingMethod='auto expand')"].join(""):nb})}j=b.offsetWidth;n=b.offsetHeight;if(j>z){Ia(b,{width:z+$a,display:"block",whiteSpace:"normal"});j=z}z=fa(oa(b.style.fontSize||12)*1.2);ca=d<0&&-j;ka=F<0&&-n;W=d*F<0;ca+=F*z*(W?1-i:i);ka-=d*z*(c?W?i:1-i:1);if(k){ca-=j*i*(d<0?-1:1);if(c)ka-=n*i*(F<0?-1: +1);Ia(b,{textAlign:g})}a.xCorr=ca;a.yCorr=ka}Ia(b,{left:e+ca,top:f+ka});a.cTT=v}}else this.alignOnAdd=true},shadow:function(a){var b=[],c=this.element,d=this.renderer,e,f=c.style,g,i=c.path;if(""+c.path==="")i="x";if(a){for(a=1;a<=3;a++){g=[''];e=fb(d.prepVML(g),null,{left:oa(f.left)+1,top:oa(f.top)+1});g=[''];fb(d.prepVML(g),null, +null,e);c.parentNode.insertBefore(e,c);b.push(e)}this.shadows=b}return this}});Ma=function(){this.init.apply(this,arguments)};Ma.prototype=ya(Uc.prototype,{isIE8:xc.indexOf("MSIE 8.0")>-1,init:function(a,b,c){var d;this.Element=ge;this.alignedObjects=[];d=this.createElement(Lb);a.appendChild(d.element);this.box=d.element;this.boxWrapper=d;this.setSize(b,c,false);if(!Aa.namespaces.hcv){Aa.namespaces.add("hcv","urn:schemas-microsoft-com:vml");Aa.createStyleSheet().cssText="hcv\\:fill, hcv\\:path, hcv\\:shape, hcv\\:stroke{ behavior:url(#default#VML); display: inline-block; } "}}, +clipRect:function(a,b,c,d){var e=this.createElement();return qa(e,{members:[],left:a,top:b,width:c,height:d,getCSS:function(f){var g=this.top,i=this.left,k=i+this.width,j=g+this.height;g={clip:"rect("+fa(f?i:g)+"px,"+fa(f?j:k)+"px,"+fa(f?k:j)+"px,"+fa(f?g:i)+"px)"};!f&&yc&&qa(g,{width:k+$a,height:j+$a});return g},updateClipping:function(){t(e.members,function(f){f.css(e.getCSS(f.inverted))})}})},color:function(a,b,c){var d,e=/^rgba/;if(a&&a.linearGradient){var f,g,i=a.linearGradient,k,j,n,z;t(a.stops, +function(F,W){if(e.test(F[1])){d=Ub(F[1]);f=d.get("rgb");g=d.get("a")}else{f=F[1];g=1}if(W){n=f;z=g}else{k=f;j=g}});a=90-Ua.atan((i[3]-i[1])/(i[2]-i[0]))*180/Tb;c=["<",c,' colors="0% ',k,",100% ",n,'" angle="',a,'" opacity="',z,'" o:opacity2="',j,'" type="gradient" focus="100%" />'];fb(this.prepVML(c),null,null,b)}else if(e.test(a)&&b.tagName!="IMG"){d=Ub(a);c=["<",c,' opacity="',d.get("a"),'"/>'];fb(this.prepVML(c),null,null,b);return d.get("rgb")}else return a},prepVML:function(a){var b=this.isIE8; +a=a.join("");if(b){a=a.replace("/>",' xmlns="urn:schemas-microsoft-com:vml" />');a=a.indexOf('style="')==-1?a.replace("/>",' style="display:inline-block;behavior:url(#default#VML);" />'):a.replace('style="','style="display:inline-block;behavior:url(#default#VML);')}else a=a.replace("<","1&&f.css({left:b,top:c,width:d,height:e});return f},rect:function(a,b,c,d,e,f){if(Eb(a)){b=a.y;c=a.width;d=a.height;e=a.r;a=a.x}var g=this.symbol("rect");g.r=e;return g.attr(g.crisp(f,a,b,Ca(c,0),Ca(d,0)))},invertChild:function(a,b){var c=b.style; +Ia(a,{flip:"x",left:oa(c.width)-10,top:oa(c.height)-10,rotation:-90})},symbols:{arc:function(a,b,c,d){var e=d.start,f=d.end,g=kb(e),i=zb(e),k=kb(f),j=zb(f);d=d.innerR;var n=0.07/c,z=d&&0.1/d||0;if(f-e===0)return["x"];else if(2*Tb-f+e=c.length)Jb=0}a.chart.pointCount++;return this},applyOptions:function(a){var b=this.series;this.config=a;if(ac(a)||a===null)this.y=a;else if(Eb(a)&&!ac(a.length)){qa(this,a);this.options=a}else if(Kb(a[0])){this.name=a[0];this.y=a[1]}else if(ac(a[0])){this.x=a[0];this.y=a[1]}if(this.x===Ra)this.x=b.autoIncrement()},destroy:function(){var a=this,b=a.series,c;b.chart.pointCount--;a==b.chart.hoverPoint&&a.onMouseOut();b.chart.hoverPoints=null;Cb(a);t(["graphic","tracker","group","dataLabel", +"connector"],function(d){a[d]&&a[d].destroy()});a.legendItem&&a.series.chart.legend.destroyItem(a);for(c in a)a[c]=null},select:function(a,b){var c=this,d=c.series.chart;c.selected=a=y(a,!c.selected);c.firePointEvent(a?"select":"unselect");c.setState(a&&"select");b||t(d.getSelectedPoints(),function(e){if(e.selected&&e!=c){e.selected=false;e.setState(db);e.firePointEvent("unselect")}})},onMouseOver:function(){var a=this.series.chart,b=a.tooltip,c=a.hoverPoint;c&&c!=this&&c.onMouseOut();this.firePointEvent("mouseOver"); +b&&!b.shared&&b.refresh(this);this.setState(yb);a.hoverPoint=this},onMouseOut:function(){this.firePointEvent("mouseOut");this.setState();this.series.chart.hoverPoint=null},tooltipFormatter:function(a){var b=this.series;return['',this.name||b.name,": ",!a?"x = "+(this.name||this.x)+", ":"","",!a?"y = ":"",this.y,"
"].join("")},getDataLabelText:function(){return this.series.options.dataLabels.formatter.call({x:this.x,y:this.y,series:this.series, +point:this,percentage:this.percentage,total:this.total||this.stackTotal})},update:function(a,b,c){var d=this,e=d.series,f=d.dataLabel,g=d.graphic,i=e.chart;b=y(b,true);d.firePointEvent("update",{options:a},function(){d.applyOptions(a);f&&f.attr({text:d.getDataLabelText()});if(Eb(a)){e.getAttribs();g&&g.attr(d.pointAttr[e.state])}e.isDirty=true;b&&i.redraw(c)})},remove:function(a,b){var c=this,d=c.series,e=d.chart,f=d.data;bc(b,e);a=y(a,true);c.firePointEvent("remove",null,function(){mc(f,c);c.destroy(); +d.isDirty=true;a&&e.redraw()})},firePointEvent:function(a,b,c){var d=this,e=this.series.options;if(e.point.events[a]||d.options&&d.options.events&&d.options.events[a])this.importEvents();if(a=="click"&&e.allowPointSelect)c=function(f){d.select(null,f.ctrlKey||f.metaKey||f.shiftKey)};La(this,a,b,c)},importEvents:function(){if(!this.hasImportedEvents){var a=ya(this.series.options.point,this.options).events,b;this.events=a;for(b in a)Qa(this,b,a[b]);this.hasImportedEvents=true}},setState:function(a){var b= +this.series,c=b.options.states,d=wb[b.type].marker&&b.options.marker,e=d&&!d.enabled,f=(d=d&&d.states[a])&&d.enabled===false,g=b.stateMarkerGraphic,i=b.chart,k=this.pointAttr;a||(a=db);if(!(a==this.state||this.selected&&a!="select"||c[a]&&c[a].enabled===false||a&&(f||e&&!d.enabled))){if(this.graphic)this.graphic.attr(k[a]);else{if(a){if(!g)b.stateMarkerGraphic=g=i.renderer.circle(0,0,k[a].r).attr(k[a]).add(b.group);g.translate(this.plotX,this.plotY)}if(g)g[a?"show":"hide"]()}this.state=a}}};var mb= +function(){};mb.prototype={isCartesian:true,type:"line",pointClass:zc,pointAttrToOptions:{stroke:"lineColor","stroke-width":"lineWidth",fill:"fillColor",r:"radius"},init:function(a,b){var c,d;d=a.series.length;this.chart=a;b=this.setOptions(b);qa(this,{index:d,options:b,name:b.name||"Series "+(d+1),state:db,pointAttr:{},visible:b.visible!==false,selected:b.selected===true});d=b.events;for(c in d)Qa(this,c,d[c]);if(d&&d.click||b.point&&b.point.events&&b.point.events.click||b.allowPointSelect)a.runTrackerClick= +true;this.getColor();this.getSymbol();this.setData(b.data,false)},autoIncrement:function(){var a=this.options,b=this.xIncrement;b=y(b,a.pointStart,0);this.pointInterval=y(this.pointInterval,a.pointInterval,1);this.xIncrement=b+this.pointInterval;return b},cleanData:function(){var a=this.chart,b=this.data,c,d,e=a.smallestInterval,f,g;b.sort(function(i,k){return i.x-k.x});for(g=b.length-1;g>=0;g--)b[g-1]&&b[g-1].x==b[g].x&&b.splice(g-1,1);for(g=b.length-1;g>=0;g--)if(b[g-1]){f=b[g].x-b[g-1].x;if(d=== +Ra||fa+1&&b.push(c.slice(a+1,e));a=e}else e==c.length-1&&b.push(c.slice(a+1,e+1))});this.segments=b},setOptions:function(a){var b=this.chart.options.plotOptions;return ya(b[this.type],b.series,a)},getColor:function(){var a=this.chart.options.colors;this.color=this.options.color||a[Jb++]||"#0000ff";if(Jb>=a.length)Jb=0},getSymbol:function(){var a= +this.chart.options.symbols;this.symbol=this.options.marker.symbol||a[Yc++];if(Yc>=a.length)Yc=0},addPoint:function(a,b,c,d){var e=this.data,f=this.graph,g=this.area,i=this.chart;a=(new this.pointClass).init(this,a);bc(d,i);if(f&&c)f.shift=c;if(g){g.shift=c;g.isArea=true}b=y(b,true);e.push(a);c&&e[0].remove(false);this.isDirty=true;b&&i.redraw()},setData:function(a,b){var c=this,d=c.data,e=c.initialColor,f=c.chart,g=d&&d.length||0;c.xIncrement=null;if(J(e))Jb=e;for(a=jc(nc(a||[]),function(i){return(new c.pointClass).init(c, +i)});g--;)d[g].destroy();c.data=a;c.cleanData();c.getSegments();c.isDirty=true;f.isDirtyBox=true;y(b,true)&&f.redraw(false)},remove:function(a,b){var c=this,d=c.chart;a=y(a,true);if(!c.isRemoving){c.isRemoving=true;La(c,"remove",null,function(){c.destroy();d.isDirtyLegend=d.isDirtyBox=true;a&&d.redraw(b)})}c.isRemoving=false},translate:function(){for(var a=this.chart,b=this.options.stacking,c=this.xAxis.categories,d=this.yAxis,e=this.data,f=e.length;f--;){var g=e[f],i=g.x,k=g.y,j=g.low,n=d.stacks[(k< +0?"-":"")+this.stackKey];g.plotX=this.xAxis.translate(i);if(b&&this.visible&&n&&n[i]){j=n[i];i=j.total;j.cum=j=j.cum-k;k=j+k;if(b=="percent"){j=i?j*100/i:0;k=i?k*100/i:0}g.percentage=i?g.y*100/i:0;g.stackTotal=i}if(J(j))g.yBottom=d.translate(j,0,1);if(k!==null)g.plotY=d.translate(k,0,1);g.clientX=a.inverted?a.plotHeight-g.plotX:g.plotX;g.category=c&&c[g.x]!==Ra?c[g.x]:g.x}},setTooltipPoints:function(a){var b=this.chart,c=b.inverted,d=[],e=fa((c?b.plotTop:b.plotLeft)+b.plotSizeX),f,g,i=[];if(a)this.tooltipPoints= +null;t(this.segments,function(k){d=d.concat(k)});if(this.xAxis&&this.xAxis.reversed)d=d.reverse();t(d,function(k,j){f=d[j-1]?d[j-1].high+1:0;for(g=k.high=d[j+1]?ob((k.plotX+(d[j+1]?d[j+1].plotX:e))/2):e;f<=g;)i[c?e-f++:f++]=k});this.tooltipPoints=i},onMouseOver:function(){var a=this.chart,b=a.hoverSeries;if(!(!Ib&&a.mouseIsDown)){b&&b!=this&&b.onMouseOut();this.options.events.mouseOver&&La(this,"mouseOver");this.tracker&&this.tracker.toFront();this.setState(yb);a.hoverSeries=this}},onMouseOut:function(){var a= +this.options,b=this.chart,c=b.tooltip,d=b.hoverPoint;d&&d.onMouseOut();this&&a.events.mouseOut&&La(this,"mouseOut");c&&!a.stickyTracking&&c.hide();this.setState();b.hoverSeries=null},animate:function(a){var b=this.chart,c=this.clipRect,d=this.options.animation;if(d&&!Eb(d))d={};if(a){if(!c.isAnimating){c.attr("width",0);c.isAnimating=true}}else{c.animate({width:b.plotSizeX},d);this.animate=null}},drawPoints:function(){var a,b=this.data,c=this.chart,d,e,f,g,i,k;if(this.options.marker.enabled)for(f= +b.length;f--;){g=b[f];d=g.plotX;e=g.plotY;k=g.graphic;if(e!==Ra&&!isNaN(e)){a=g.pointAttr[g.selected?"select":db];i=a.r;if(k)k.animate({x:d,y:e,r:i});else g.graphic=c.renderer.symbol(y(g.marker&&g.marker.symbol,this.symbol),d,e,i).attr(a).add(this.group)}}},convertAttribs:function(a,b,c,d){var e=this.pointAttrToOptions,f,g,i={};a=a||{};b=b||{};c=c||{};d=d||{};for(f in e){g=e[f];i[f]=y(a[g],b[f],c[f],d[f])}return i},getAttribs:function(){var a=this,b=wb[a.type].marker?a.options.marker:a.options,c= +b.states,d=c[yb],e,f=a.color,g={stroke:f,fill:f},i=a.data,k=[],j,n=a.pointAttrToOptions;if(a.options.marker){d.radius=d.radius||b.radius+2;d.lineWidth=d.lineWidth||b.lineWidth+1}else d.color=d.color||Ub(d.color||f).brighten(d.brightness).get();k[db]=a.convertAttribs(b,g);t([yb,"select"],function(F){k[F]=a.convertAttribs(c[F],k[db])});a.pointAttr=k;for(f=i.length;f--;){g=i[f];if((b=g.options&&g.options.marker||g.options)&&b.enabled===false)b.radius=0;e=false;if(g.options)for(var z in n)if(J(b[n[z]]))e= +true;if(e){j=[];c=b.states||{};e=c[yb]=c[yb]||{};if(!a.options.marker)e.color=Ub(e.color||g.options.color).brighten(e.brightness||d.brightness).get();j[db]=a.convertAttribs(b,k[db]);j[yb]=a.convertAttribs(c[yb],k[yb],j[db]);j.select=a.convertAttribs(c.select,k.select,j[db])}else j=k;g.pointAttr=j}},destroy:function(){var a=this,b=a.chart,c=/\/5[0-9\.]+ (Safari|Mobile)\//.test(xc),d,e;Cb(a);a.legendItem&&a.chart.legend.destroyItem(a);t(a.data,function(f){f.destroy()});t(["area","graph","dataLabelsGroup", +"group","tracker"],function(f){if(a[f]){d=c&&f=="group"?"hide":"destroy";a[f][d]()}});if(b.hoverSeries==a)b.hoverSeries=null;mc(b.series,a);for(e in a)delete a[e]},drawDataLabels:function(){if(this.options.dataLabels.enabled){var a,b,c=this.data,d=this.options.dataLabels,e,f=this.dataLabelsGroup,g=this.chart,i=g.inverted,k=this.type,j;if(!f)f=this.dataLabelsGroup=g.renderer.g(Zb+"data-labels").attr({visibility:this.visible?Bb:vb,zIndex:5}).translate(g.plotLeft,g.plotTop).add();j=d.color;if(j=="auto")j= +null;d.style.color=y(j,this.color);t(c,function(n){var z=n.barX;z=z&&z+n.barW/2||n.plotX||-999;var F=y(n.plotY,-999),W=n.dataLabel,ca=d.align;e=n.getDataLabelText();a=(i?g.plotWidth-F:z)+d.x;b=(i?g.plotHeight-z:F)+d.y;if(k=="column")a+={left:-1,right:1}[ca]*n.barW/2||0;if(W)W.animate({x:a,y:b});else if(J(e))W=n.dataLabel=g.renderer.text(e,a,b).attr({align:ca,rotation:d.rotation,zIndex:1}).css(d.style).add(f);i&&!d.y&&W.attr({y:b+parseInt(W.styles.lineHeight)*0.9-W.getBBox().height/2})})}},drawGraph:function(){var a= +this,b=a.options,c=a.graph,d=[],e,f=a.area,g=a.group,i=b.lineColor||a.color,k=b.lineWidth,j=b.dashStyle,n,z=a.chart.renderer,F=a.yAxis.getThreshold(b.threshold||0),W=/^area/.test(a.type),ca=[],ka=[];t(a.segments,function(v){n=[];t(v,function(U,R){if(a.getPointSpline)n.push.apply(n,a.getPointSpline(v,U,R));else{n.push(R?Da:Za);R&&b.step&&n.push(U.plotX,v[R-1].plotY);n.push(U.plotX,U.plotY)}});if(v.length>1)d=d.concat(n);else ca.push(v[0]);if(W){var I=[],da,X=n.length;for(da=0;da=0;da--)I.push(v[da].plotX,v[da].yBottom);else I.push(Da,v[v.length-1].plotX,F,Da,v[0].plotX,F);ka=ka.concat(I)}});a.graphPath=d;a.singlePoints=ca;if(W){e=y(b.fillColor,Ub(a.color).setOpacity(b.fillOpacity||0.75).get());if(f)f.animate({d:ka});else a.area=a.chart.renderer.path(ka).attr({fill:e}).add(g)}if(c)c.animate({d:d});else if(k){c={stroke:i,"stroke-width":k};if(j)c.dashstyle=j;a.graph=z.path(d).attr(c).add(g).shadow(b.shadow)}}, +render:function(){var a=this,b=a.chart,c,d,e=a.options,f=e.animation,g=f&&a.animate;f=g?f&&f.duration||500:0;var i=a.clipRect;d=b.renderer;if(!i){i=a.clipRect=!b.hasRendered&&b.clipRect?b.clipRect:d.clipRect(0,0,b.plotSizeX,b.plotSizeY);if(!b.clipRect)b.clipRect=i}if(!a.group){c=a.group=d.g("series");if(b.inverted){d=function(){c.attr({width:b.plotWidth,height:b.plotHeight}).invert()};d();Qa(b,"resize",d)}c.clip(a.clipRect).attr({visibility:a.visible?Bb:vb,zIndex:e.zIndex}).translate(b.plotLeft,b.plotTop).add(b.seriesGroup)}a.drawDataLabels(); +g&&a.animate(true);a.getAttribs();a.drawGraph&&a.drawGraph();a.drawPoints();a.options.enableMouseTracking!==false&&a.drawTracker();g&&a.animate();setTimeout(function(){i.isAnimating=false;if((c=a.group)&&i!=b.clipRect&&i.renderer){c.clip(a.clipRect=b.clipRect);i.destroy()}},f);a.isDirty=false},redraw:function(){var a=this.chart,b=this.group;if(b){a.inverted&&b.attr({width:a.plotWidth,height:a.plotHeight});b.animate({translateX:a.plotLeft,translateY:a.plotTop})}this.translate();this.setTooltipPoints(true); +this.render()},setState:function(a){var b=this.options,c=this.graph,d=b.states;b=b.lineWidth;a=a||db;if(this.state!=a){this.state=a;if(!(d[a]&&d[a].enabled===false)){if(a)b=d[a].lineWidth||b+1;if(c&&!c.dashstyle)c.attr({"stroke-width":b},a?0:500)}}},setVisible:function(a,b){var c=this.chart,d=this.legendItem,e=this.group,f=this.tracker,g=this.dataLabelsGroup,i,k=this.data,j=c.options.chart.ignoreHiddenSeries;i=this.visible;i=(this.visible=a=a===Ra?!i:a)?"show":"hide";e&&e[i]();if(f)f[i]();else for(e= +k.length;e--;){f=k[e];f.tracker&&f.tracker[i]()}g&&g[i]();d&&c.legend.colorizeItem(this,a);this.isDirty=true;this.options.stacking&&t(c.series,function(n){if(n.options.stacking&&n.visible)n.isDirty=true});if(j)c.isDirtyBox=true;b!==false&&c.redraw();La(this,i)},show:function(){this.setVisible(true)},hide:function(){this.setVisible(false)},select:function(a){this.selected=a=a===Ra?!this.selected:a;if(this.checkbox)this.checkbox.checked=a;La(this,a?"select":"unselect")},drawTracker:function(){var a= +this,b=a.options,c=[].concat(a.graphPath),d=c.length,e=a.chart,f=e.options.tooltip.snap,g=a.tracker,i=b.cursor;i=i&&{cursor:i};var k=a.singlePoints,j;if(d)for(j=d+1;j--;){c[j]==Za&&c.splice(j+1,0,c[j+1]-f,c[j+2],Da);if(j&&c[j]==Za||j==d)c.splice(j,0,Da,c[j-2]+f,c[j-1])}for(j=0;j +a&&k>e){k=Ca(a,e);n=2*e-k}else if(kg&&n>e){n=Ca(g,e);k=2*e-n}else if(nv?X-v:ka-(da<=ka?v:0)}Ya=R-3}qa(I,{barX:U,barY:R,barW:W,barH:Ha});I.shapeType="rect";I.shapeArgs={x:U,y:R,width:W,height:Ha,r:k.borderRadius}; +I.trackerArgs=J(Ya)&&ya(I.shapeArgs,{height:Ca(6,Ha+3),y:Ya})})},getSymbol:function(){},drawGraph:function(){},drawPoints:function(){var a=this,b=a.options,c=a.chart.renderer,d,e;t(a.data,function(f){var g=f.plotY;if(g!==Ra&&!isNaN(g)){d=f.graphic;e=f.shapeArgs;if(d){Sc(d);d.animate(e)}else f.graphic=c[f.shapeType](e).attr(f.pointAttr[f.selected?"select":db]).add(a.group).shadow(b.shadow)}})},drawTracker:function(){var a=this,b=a.chart,c=b.renderer,d,e,f=+new Date,g=a.options.cursor,i=g&&{cursor:g}, +k;t(a.data,function(j){e=j.tracker;d=j.trackerArgs||j.shapeArgs;if(j.y!==null)if(e)e.attr(d);else j.tracker=c[j.shapeType](d).attr({isTracker:f,fill:Vd,visibility:a.visible?Bb:vb,zIndex:1}).on(Ib?"touchstart":"mouseover",function(n){k=n.relatedTarget||n.fromElement;b.hoverSeries!=a&&za(k,"isTracker")!=f&&a.onMouseOver();j.onMouseOver()}).on("mouseout",function(n){if(!a.options.stickyTracking){k=n.relatedTarget||n.toElement;za(k,"isTracker")!=f&&a.onMouseOut()}}).css(i).add(b.trackerGroup)})},animate:function(a){var b= +this,c=b.data;if(!a){t(c,function(d){var e=d.graphic;if(e){e.attr({height:0,y:b.yAxis.translate(0,0,1)});e.animate({height:d.barH,y:d.barY},b.options.animation)}});b.animate=null}},remove:function(){var a=this,b=a.chart;b.hasRendered&&t(b.series,function(c){if(c.type==a.type)c.isDirty=true});mb.prototype.remove.apply(a,arguments)}});ub.column=ad;Ma=xb(ad,{type:"bar",init:function(a){a.inverted=this.inverted=true;ad.prototype.init.apply(this,arguments)}});ub.bar=Ma;Ma=xb(mb,{type:"scatter",translate:function(){var a= +this;mb.prototype.translate.apply(a);t(a.data,function(b){b.shapeType="circle";b.shapeArgs={x:b.plotX,y:b.plotY,r:a.chart.options.tooltip.snap}})},drawTracker:function(){var a=this,b=a.options.cursor,c=b&&{cursor:b},d;t(a.data,function(e){(d=e.graphic)&&d.attr({isTracker:true}).on("mouseover",function(){a.onMouseOver();e.onMouseOver()}).on("mouseout",function(){a.options.stickyTracking||a.onMouseOut()}).css(c)})},cleanData:function(){}});ub.scatter=Ma;Ma=xb(zc,{init:function(){zc.prototype.init.apply(this, +arguments);var a=this,b;qa(a,{visible:a.visible!==false,name:y(a.name,"Slice")});b=function(){a.slice()};Qa(a,"select",b);Qa(a,"unselect",b);return a},setVisible:function(a){var b=this.series.chart,c=this.tracker,d=this.dataLabel,e=this.connector,f;f=(this.visible=a=a===Ra?!this.visible:a)?"show":"hide";this.group[f]();c&&c[f]();d&&d[f]();e&&e[f]();this.legendItem&&b.legend.colorizeItem(this,a)},slice:function(a,b,c){var d=this.series.chart,e=this.slicedTranslation;bc(c,d);y(b,true);a=this.sliced= +J(a)?a:!this.sliced;this.group.animate({translateX:a?e[0]:d.plotLeft,translateY:a?e[1]:d.plotTop})}});Ma=xb(mb,{type:"pie",isCartesian:false,pointClass:Ma,pointAttrToOptions:{stroke:"borderColor","stroke-width":"borderWidth",fill:"color"},getColor:function(){this.initialColor=Jb},animate:function(){var a=this;t(a.data,function(b){var c=b.graphic;b=b.shapeArgs;var d=-Tb/2;if(c){c.attr({r:0,start:d,end:d});c.animate({r:b.r,start:b.start,end:b.end},a.options.animation)}});a.animate=null},translate:function(){var a= +0,b=-0.25,c=this.options,d=c.slicedOffset,e=d+c.borderWidth,f=c.center,g=this.chart,i=g.plotWidth,k=g.plotHeight,j,n,z,F=this.data,W=2*Tb,ca,ka=pb(i,k),v,I,da,X=c.dataLabels.distance;f.push(c.size,c.innerSize||0);f=jc(f,function(U,R){return(v=/%$/.test(U))?[i,k,ka,ka][R]*oa(U)/100:U});this.getX=function(U,R){z=Ua.asin((U-f[1])/(f[2]/2+X));return f[0]+(R?-1:1)*kb(z)*(f[2]/2+X)};this.center=f;t(F,function(U){a+=U.y});t(F,function(U){ca=a?U.y/a:0;j=fa(b*W*1E3)/1E3;b+=ca;n=fa(b*W*1E3)/1E3;U.shapeType= +"arc";U.shapeArgs={x:f[0],y:f[1],r:f[2]/2,innerR:f[3]/2,start:j,end:n};z=(n+j)/2;U.slicedTranslation=jc([kb(z)*d+g.plotLeft,zb(z)*d+g.plotTop],fa);I=kb(z)*f[2]/2;da=zb(z)*f[2]/2;U.tooltipPos=[f[0]+I*0.7,f[1]+da*0.7];U.labelPos=[f[0]+I+kb(z)*X,f[1]+da+zb(z)*X,f[0]+I+kb(z)*e,f[1]+da+zb(z)*e,f[0]+I,f[1]+da,X<0?"center":z0,j,n,z=this.center[1],F=[[],[],[],[]],W,ca,ka,v,I,da,X,U=4,R;mb.prototype.drawDataLabels.apply(this);t(a,function(Ha){var Ya=Ha.labelPos[7];F[Ya<0?0:YaYa.y};U--;){a=0;b=[].concat(F[U]);b.sort(X);for(R=b.length;R--;)b[R].rank=R;for(v=0;v<2;v++){n=(da=U%3)?9999:-9999;I=da?-1:1;for(R=0;Rn-j){ca=n+I*j;W=this.getX(ca,U>1);if(!da&&ca+j>z||da&&ca-j'+ this.series.name +'
'+ + Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'
'+ + Highcharts.numberFormat(this.y, 2); + } + }, + legend: { + enabled: false + }, + exporting: { + enabled: false + }, + series: [{ + name: '# Processes', + data: (function() { + // generate an array of random data + var data = [], + time = (new Date()).getTime(), + i; + for (i = -19; i <= 0; i++) { + data.push({ + x: time + i * 2000, + y: 0 //Math.random() + }); + } + return data; + })() + }] + }); + } }); \ No newline at end of file diff --git a/server_status.php b/server_status.php index dba00f9e9a..0f51c4c736 100644 --- a/server_status.php +++ b/server_status.php @@ -14,6 +14,7 @@ if (! defined('PMA_NO_VARIABLES_IMPORT')) { define('PMA_NO_VARIABLES_IMPORT', true); } + require_once './libraries/common.inc.php'; /** @@ -25,11 +26,17 @@ if (isset($_REQUEST['ajax_request'])) { header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past header_remove('Last-Modified'); - } - -if (isset($_REQUEST["query_chart"]) && isset($_REQUEST['ajax_request'])) { - exit(createQueryChart()); + + if (isset($_REQUEST["query_chart"])) { + exit(createQueryChart()); + } + if(isset($_REQUEST['chart_data'])) { + $result = PMA_DBI_query('SHOW PROCESSLIST'); + $num_procs = PMA_DBI_num_rows($result); + exit((time()*1000).','.$num_procs); + } } + /** * Replication library @@ -46,7 +53,7 @@ $GLOBALS['js_include'][] = 'server_status.js'; $GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js'; $GLOBALS['js_include'][] = 'jquery/jquery.tablesorter.min.js'; $GLOBALS['js_include'][] = 'jquery/jquery.cookie.js'; // For tab persistence - +$GLOBALS['js_include'][] = 'highcharts/highcharts.js'; /** * flush status variables if requested @@ -64,6 +71,20 @@ if (isset($_REQUEST['flush'])) { unset($_flush_commands); } +/** + * Kills a selected process + */ +if (!empty($_REQUEST['kill'])) { + if (PMA_DBI_try_query('KILL ' . $_REQUEST['kill'] . ';')) { + $message = PMA_Message::success(__('Thread %s was successfully killed.')); + } else { + $message = PMA_Message::error(__('phpMyAdmin was unable to kill thread %s. It probably has already been closed.')); + } + $message->addParam($_REQUEST['kill']); + $message->display(); +} + + /** * get status from server @@ -220,15 +241,15 @@ $sections = array( $links = array(); $links['table'][__('Flush (close) all tables')] - = $PMA_PHP_SELF . '?flush=TABLES&' . PMA_generate_common_url(); + = $PMA_PHP_SELF . '?flush=TABLES&' . PMA_generate_common_url(); $links['table'][__('Show open tables')] - = 'sql.php?sql_query=' . urlencode('SHOW OPEN TABLES') . - '&goto=server_status.php&' . PMA_generate_common_url(); + = 'sql.php?sql_query=' . urlencode('SHOW OPEN TABLES') . + '&goto=server_status.php&' . PMA_generate_common_url(); if ($server_master_status) { $links['repl'][__('Show slave hosts')] - = 'sql.php?sql_query=' . urlencode('SHOW SLAVE HOSTS') . - '&goto=server_status.php&' . PMA_generate_common_url(); + = 'sql.php?sql_query=' . urlencode('SHOW SLAVE HOSTS') . + '&goto=server_status.php&' . PMA_generate_common_url(); $links['repl'][__('Show master status')] = '#replication_master'; } if ($server_slave_status) { @@ -238,12 +259,12 @@ if ($server_slave_status) { $links['repl']['doc'] = 'replication'; $links['qcache'][__('Flush query cache')] - = $PMA_PHP_SELF . '?flush=' . urlencode('QUERY CACHE') . '&' . - PMA_generate_common_url(); + = $PMA_PHP_SELF . '?flush=' . urlencode('QUERY CACHE') . '&' . + PMA_generate_common_url(); $links['qcache']['doc'] = 'query_cache'; $links['threads'][__('Show processes')] - = 'server_processlist.php?' . PMA_generate_common_url(); + = 'server_processlist.php?' . PMA_generate_common_url(); $links['threads']['doc'] = 'mysql_threads'; $links['key']['doc'] = 'myisam_key_cache'; @@ -253,10 +274,10 @@ $links['binlog_cache']['doc'] = 'binary_log'; $links['Slow_queries']['doc'] = 'slow_query_log'; $links['innodb'][__('Variables')] - = 'server_engines.php?engine=InnoDB&' . PMA_generate_common_url(); + = 'server_engines.php?engine=InnoDB&' . PMA_generate_common_url(); $links['innodb'][__('InnoDB Status')] - = 'server_engines.php?engine=InnoDB&page=Status&' . - PMA_generate_common_url(); + = 'server_engines.php?engine=InnoDB&page=Status&' . + PMA_generate_common_url(); $links['innodb']['doc'] = 'innodb'; @@ -283,12 +304,12 @@ unset($used_queries['Com_admin_commands']); /* Ajax request refresh */ if(isset($_REQUEST['show']) && isset($_REQUEST['ajax_request'])) { switch($_REQUEST['show']) { - case 'query_statistics': - printQueryStatistics(); - exit(); - case 'server_traffic': - printServerTraffic(); - exit(); + case 'query_statistics': + printQueryStatistics(); + exit(); + case 'server_traffic': + printServerTraffic(); + exit(); case 'variables_table': // Prints the variables table printVariablesTable(); @@ -315,473 +336,554 @@ require './libraries/server_common.inc.php'; require './libraries/server_links.inc.php'; ?> +
-

'; - + echo ''; + echo __('Runtime Information'); ?>

-
- - -
- -
-
- -
-
-
-
- - Filters -
- - -
-
- - -
-
- -
-
- -
-
- -
-
-
+
+
    +
  • +
  • +
  • +
+ +
+ +
+
+
+ +
+
+
+
+ + Filters +
+ + +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+
- - -

Query statistics: Since its startup, %s queries have been sent to the server.'), - //PMA_formatNumber($server_status['Questions'], 0)); - sprintf('Queries since startup: %s',PMA_formatNumber($total_queries, 0)); - //echo PMA_showMySQLDocu('server-status-variables', 'server-status-variables', false, 'statvar_Questions'); - ?> -
- - ø : -
+ ?> + + +

Query statistics: Since its startup, %s queries have been sent to the server.'), + //PMA_formatNumber($server_status['Questions'], 0)); + sprintf('Queries since startup: %s',PMA_formatNumber($total_queries, 0)); + //echo PMA_showMySQLDocu('server-status-variables', 'server-status-variables', false, 'statvar_Questions'); + ?> +
+ + ø : +
- ø : -
+ ø : +
- = 1) { - ?> - ø : -
- - = 1) { + ?> + ø : +
+ + -

-

- - - - - - - - - + ?> + +
ø %
+ + + + + + + + + - $value) { - $odd_row = !$odd_row; + $value) { + $odd_row = !$odd_row; - // For the percentage column, use Questions - Connections, because - // the number of connections is not an item of the Query types - // but is included in Questions. Then the total of the percentages is 100. - $name = str_replace('Com_', '', $name); - $name = str_replace('_', ' ', $name); - ?> - - - - - - - - -
ø %
%
- -
- ['.__('Show query chart').']'; - } - ?> -
- + + + + + % + + + + + +
+ ['.__('Show query chart').']'; + } + ?> +
+ - - -

Server traffic: These tables show the network traffic statistics of this MySQL server since its startup.');*/ - echo sprintf(__('Network traffic since startup: %s'), - implode(' ', PMA_formatByteDown( $server_status['Bytes_received'] + $server_status['Bytes_sent'], 3, 1)) - ); - ?> -

+ ?> + + +

Server traffic: These tables show the network traffic statistics of this MySQL server since its startup.');*/ + echo sprintf(__('Network traffic since startup: %s'), + implode(' ', PMA_formatByteDown( $server_status['Bytes_received'] + $server_status['Bytes_sent'], 3, 1)) + ); + ?> +

-

- -

+

+ +

- '; - if ($server_master_status && $server_slave_status) { - echo __('This MySQL server works as master and slave in replication process.'); - } elseif ($server_master_status) { - echo __('This MySQL server works as master in replication process.'); - } elseif ($server_slave_status) { - echo __('This MySQL server works as slave in replication process.'); - } - echo __('For further information about replication status on the server, please visit the replication section.'); - echo '

'; - } + '; + if ($server_master_status && $server_slave_status) { + echo __('This MySQL server works as master and slave in replication process.'); + } elseif ($server_master_status) { + echo __('This MySQL server works as master in replication process.'); + } elseif ($server_slave_status) { + echo __('This MySQL server works as slave in replication process.'); + } + echo __('For further information about replication status on the server, please visit the replication section.'); + echo '

'; + } - /* if the server works as master or slave in replication process, display useful information */ - if ($server_master_status || $server_slave_status) - { - ?> -
+ /* if the server works as master or slave in replication process, display useful information */ + if ($server_master_status || $server_slave_status) + { + ?> +
-

- + + foreach ($replication_types as $type) + { + if (${"server_{$type}_status"}) { + PMA_replication_print_status_table($type); + } + } + unset($types); + } + ?> - - - - - - - - - - - - - - - - - - - - - - - - -
ø
+ + + + + + + + + + + + + + + + + + + + + + + + +
ø
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ø %
--- ---
0 - ? PMA_formatNumber( - $server_status['Aborted_connects'] * 100 / $server_status['Connections'], - 0, 2) . '%' - : '--- '; ?>
0 - ? PMA_formatNumber( - $server_status['Aborted_clients'] * 100 / $server_status['Connections'], - 0, 2) . '%' - : '--- '; ?>
%
- + + + + ø + % + + + + + + + --- + --- + + + + + + 0 + ? PMA_formatNumber( + $server_status['Aborted_connects'] * 100 / $server_status['Connections'], + 0, 2) . '%' + : '--- '; ?> + + + + + + 0 + ? PMA_formatNumber( + $server_status['Aborted_clients'] * 100 / $server_status['Connections'], + 0, 2) . '%' + : '--- '; ?> + + + + + + % + + + + 1)); + } + $result = PMA_DBI_query($sql_query); + + /** + * Displays the page + */ + ?> + + + + + + + + + + + + + + + + $v) { + $k = $k !== 'DB' + ? $k = ucfirst(strtolower($k)) + : 'db'; + $process[$k] = $v; + } + } + $url_params['kill'] = $process['Id']; + $kill_process = 'server_processlist.php' . PMA_generate_common_url($url_params); + ?> + + + + + + + + + + + + + +
+ + <?php echo empty($_REQUEST['full']) ? __('Show Full Queries') : __('Truncate Shown Queries'); ?> + + +
' . __('None') . '' : $process['db']); ?>
+ __('The number of transactions that used the temporary binary log cache but that exceeded the value of binlog_cache_size and used a temporary file to store statements from the transaction.'), - 'Binlog_cache_useDescr' => __('The number of transactions that used the temporary binary log cache.'), - 'Created_tmp_disk_tablesDescr' => __('The number of temporary tables on disk created automatically by the server while executing statements. If Created_tmp_disk_tables is big, you may want to increase the tmp_table_size value to cause temporary tables to be memory-based instead of disk-based.'), - 'Created_tmp_filesDescr' => __('How many temporary files mysqld has created.'), - 'Created_tmp_tablesDescr' => __('The number of in-memory temporary tables created automatically by the server while executing statements.'), - 'Delayed_errorsDescr' => __('The number of rows written with INSERT DELAYED for which some error occurred (probably duplicate key).'), - 'Delayed_insert_threadsDescr' => __('The number of INSERT DELAYED handler threads in use. Every different table on which one uses INSERT DELAYED gets its own thread.'), - 'Delayed_writesDescr' => __('The number of INSERT DELAYED rows written.'), - 'Flush_commandsDescr' => __('The number of executed FLUSH statements.'), - 'Handler_commitDescr' => __('The number of internal COMMIT statements.'), - 'Handler_deleteDescr' => __('The number of times a row was deleted from a table.'), - 'Handler_discoverDescr' => __('The MySQL server can ask the NDB Cluster storage engine if it knows about a table with a given name. This is called discovery. Handler_discover indicates the number of time tables have been discovered.'), - 'Handler_read_firstDescr' => __('The number of times the first entry was read from an index. If this is high, it suggests that the server is doing a lot of full index scans; for example, SELECT col1 FROM foo, assuming that col1 is indexed.'), - 'Handler_read_keyDescr' => __('The number of requests to read a row based on a key. If this is high, it is a good indication that your queries and tables are properly indexed.'), - 'Handler_read_nextDescr' => __('The number of requests to read the next row in key order. This is incremented if you are querying an index column with a range constraint or if you are doing an index scan.'), - 'Handler_read_prevDescr' => __('The number of requests to read the previous row in key order. This read method is mainly used to optimize ORDER BY ... DESC.'), - 'Handler_read_rndDescr' => __('The number of requests to read a row based on a fixed position. This is high if you are doing a lot of queries that require sorting of the result. You probably have a lot of queries that require MySQL to scan whole tables or you have joins that don\'t use keys properly.'), - 'Handler_read_rnd_nextDescr' => __('The number of requests to read the next row in the data file. This is high if you are doing a lot of table scans. Generally this suggests that your tables are not properly indexed or that your queries are not written to take advantage of the indexes you have.'), - 'Handler_rollbackDescr' => __('The number of internal ROLLBACK statements.'), - 'Handler_updateDescr' => __('The number of requests to update a row in a table.'), - 'Handler_writeDescr' => __('The number of requests to insert a row in a table.'), - 'Innodb_buffer_pool_pages_dataDescr' => __('The number of pages containing data (dirty or clean).'), - 'Innodb_buffer_pool_pages_dirtyDescr' => __('The number of pages currently dirty.'), - 'Innodb_buffer_pool_pages_flushedDescr' => __('The number of buffer pool pages that have been requested to be flushed.'), - 'Innodb_buffer_pool_pages_freeDescr' => __('The number of free pages.'), - 'Innodb_buffer_pool_pages_latchedDescr' => __('The number of latched pages in InnoDB buffer pool. These are pages currently being read or written or that can\'t be flushed or removed for some other reason.'), - 'Innodb_buffer_pool_pages_miscDescr' => __('The number of pages busy because they have been allocated for administrative overhead such as row locks or the adaptive hash index. This value can also be calculated as Innodb_buffer_pool_pages_total - Innodb_buffer_pool_pages_free - Innodb_buffer_pool_pages_data.'), - 'Innodb_buffer_pool_pages_totalDescr' => __('Total size of buffer pool, in pages.'), - 'Innodb_buffer_pool_read_ahead_rndDescr' => __('The number of "random" read-aheads InnoDB initiated. This happens when a query is to scan a large portion of a table but in random order.'), - 'Innodb_buffer_pool_read_ahead_seqDescr' => __('The number of sequential read-aheads InnoDB initiated. This happens when InnoDB does a sequential full table scan.'), - 'Innodb_buffer_pool_read_requestsDescr' => __('The number of logical read requests InnoDB has done.'), - 'Innodb_buffer_pool_readsDescr' => __('The number of logical reads that InnoDB could not satisfy from buffer pool and had to do a single-page read.'), - 'Innodb_buffer_pool_wait_freeDescr' => __('Normally, writes to the InnoDB buffer pool happen in the background. However, if it\'s necessary to read or create a page and no clean pages are available, it\'s necessary to wait for pages to be flushed first. This counter counts instances of these waits. If the buffer pool size was set properly, this value should be small.'), - 'Innodb_buffer_pool_write_requestsDescr' => __('The number writes done to the InnoDB buffer pool.'), - 'Innodb_data_fsyncsDescr' => __('The number of fsync() operations so far.'), - 'Innodb_data_pending_fsyncsDescr' => __('The current number of pending fsync() operations.'), - 'Innodb_data_pending_readsDescr' => __('The current number of pending reads.'), - 'Innodb_data_pending_writesDescr' => __('The current number of pending writes.'), - 'Innodb_data_readDescr' => __('The amount of data read so far, in bytes.'), - 'Innodb_data_readsDescr' => __('The total number of data reads.'), - 'Innodb_data_writesDescr' => __('The total number of data writes.'), - 'Innodb_data_writtenDescr' => __('The amount of data written so far, in bytes.'), - 'Innodb_dblwr_pages_writtenDescr' => __('The number of pages that have been written for doublewrite operations.'), - 'Innodb_dblwr_writesDescr' => __('The number of doublewrite operations that have been performed.'), - 'Innodb_log_waitsDescr' => __('The number of waits we had because log buffer was too small and we had to wait for it to be flushed before continuing.'), - 'Innodb_log_write_requestsDescr' => __('The number of log write requests.'), - 'Innodb_log_writesDescr' => __('The number of physical writes to the log file.'), - 'Innodb_os_log_fsyncsDescr' => __('The number of fsync() writes done to the log file.'), - 'Innodb_os_log_pending_fsyncsDescr' => __('The number of pending log file fsyncs.'), - 'Innodb_os_log_pending_writesDescr' => __('Pending log file writes.'), - 'Innodb_os_log_writtenDescr' => __('The number of bytes written to the log file.'), - 'Innodb_pages_createdDescr' => __('The number of pages created.'), - 'Innodb_page_sizeDescr' => __('The compiled-in InnoDB page size (default 16KB). Many values are counted in pages; the page size allows them to be easily converted to bytes.'), - 'Innodb_pages_readDescr' => __('The number of pages read.'), - 'Innodb_pages_writtenDescr' => __('The number of pages written.'), - 'Innodb_row_lock_current_waitsDescr' => __('The number of row locks currently being waited for.'), - 'Innodb_row_lock_time_avgDescr' => __('The average time to acquire a row lock, in milliseconds.'), - 'Innodb_row_lock_timeDescr' => __('The total time spent in acquiring row locks, in milliseconds.'), - 'Innodb_row_lock_time_maxDescr' => __('The maximum time to acquire a row lock, in milliseconds.'), - 'Innodb_row_lock_waitsDescr' => __('The number of times a row lock had to be waited for.'), - 'Innodb_rows_deletedDescr' => __('The number of rows deleted from InnoDB tables.'), - 'Innodb_rows_insertedDescr' => __('The number of rows inserted in InnoDB tables.'), - 'Innodb_rows_readDescr' => __('The number of rows read from InnoDB tables.'), - 'Innodb_rows_updatedDescr' => __('The number of rows updated in InnoDB tables.'), - 'Key_blocks_not_flushedDescr' => __('The number of key blocks in the key cache that have changed but haven\'t yet been flushed to disk. It used to be known as Not_flushed_key_blocks.'), - 'Key_blocks_unusedDescr' => __('The number of unused blocks in the key cache. You can use this value to determine how much of the key cache is in use.'), - 'Key_blocks_usedDescr' => __('The number of used blocks in the key cache. This value is a high-water mark that indicates the maximum number of blocks that have ever been in use at one time.'), - 'Key_read_requestsDescr' => __('The number of requests to read a key block from the cache.'), - 'Key_readsDescr' => __('The number of physical reads of a key block from disk. If Key_reads is big, then your key_buffer_size value is probably too small. The cache miss rate can be calculated as Key_reads/Key_read_requests.'), - 'Key_write_requestsDescr' => __('The number of requests to write a key block to the cache.'), - 'Key_writesDescr' => __('The number of physical writes of a key block to disk.'), - 'Last_query_costDescr' => __('The total cost of the last compiled query as computed by the query optimizer. Useful for comparing the cost of different query plans for the same query. The default value of 0 means that no query has been compiled yet.'), - 'Not_flushed_delayed_rowsDescr' => __('The number of rows waiting to be written in INSERT DELAYED queues.'), - 'Opened_tablesDescr' => __('The number of tables that have been opened. If opened tables is big, your table cache value is probably too small.'), - 'Open_filesDescr' => __('The number of files that are open.'), - 'Open_streamsDescr' => __('The number of streams that are open (used mainly for logging).'), - 'Open_tablesDescr' => __('The number of tables that are open.'), - 'Qcache_free_blocksDescr' => __('The number of free memory blocks in query cache. High numbers can indicate fragmentation issues, which may be solved by issuing a FLUSH QUERY CACHE statement.'), - 'Qcache_free_memoryDescr' => __('The amount of free memory for query cache.'), - 'Qcache_hitsDescr' => __('The number of cache hits.'), - 'Qcache_insertsDescr' => __('The number of queries added to the cache.'), - 'Qcache_lowmem_prunesDescr' => __('The number of queries that have been removed from the cache to free up memory for caching new queries. This information can help you tune the query cache size. The query cache uses a least recently used (LRU) strategy to decide which queries to remove from the cache.'), - 'Qcache_not_cachedDescr' => __('The number of non-cached queries (not cachable, or not cached due to the query_cache_type setting).'), - 'Qcache_queries_in_cacheDescr' => __('The number of queries registered in the cache.'), - 'Qcache_total_blocksDescr' => __('The total number of blocks in the query cache.'), - 'Rpl_statusDescr' => __('The status of failsafe replication (not yet implemented).'), - 'Select_full_joinDescr' => __('The number of joins that do not use indexes. If this value is not 0, you should carefully check the indexes of your tables.'), - 'Select_full_range_joinDescr' => __('The number of joins that used a range search on a reference table.'), - 'Select_range_checkDescr' => __('The number of joins without keys that check for key usage after each row. (If this is not 0, you should carefully check the indexes of your tables.)'), - 'Select_rangeDescr' => __('The number of joins that used ranges on the first table. (It\'s normally not critical even if this is big.)'), - 'Select_scanDescr' => __('The number of joins that did a full scan of the first table.'), - 'Slave_open_temp_tablesDescr' => __('The number of temporary tables currently open by the slave SQL thread.'), - 'Slave_retried_transactionsDescr' => __('Total (since startup) number of times the replication slave SQL thread has retried transactions.'), - 'Slave_runningDescr' => __('This is ON if this server is a slave that is connected to a master.'), - 'Slow_launch_threadsDescr' => __('The number of threads that have taken more than slow_launch_time seconds to create.'), - 'Slow_queriesDescr' => __('The number of queries that have taken more than long_query_time seconds.'), - 'Sort_merge_passesDescr' => __('The number of merge passes the sort algorithm has had to do. If this value is large, you should consider increasing the value of the sort_buffer_size system variable.'), - 'Sort_rangeDescr' => __('The number of sorts that were done with ranges.'), - 'Sort_rowsDescr' => __('The number of sorted rows.'), - 'Sort_scanDescr' => __('The number of sorts that were done by scanning the table.'), - 'Table_locks_immediateDescr' => __('The number of times that a table lock was acquired immediately.'), - 'Table_locks_waitedDescr' => __('The number of times that a table lock could not be acquired immediately and a wait was needed. If this is high, and you have performance problems, you should first optimize your queries, and then either split your table or tables or use replication.'), - 'Threads_cachedDescr' => __('The number of threads in the thread cache. The cache hit rate can be calculated as Threads_created/Connections. If this value is red you should raise your thread_cache_size.'), - 'Threads_connectedDescr' => __('The number of currently open connections.'), - 'Threads_createdDescr' => __('The number of threads created to handle connections. If Threads_created is big, you may want to increase the thread_cache_size value. (Normally this doesn\'t give a notable performance improvement if you have a good thread implementation.)'), - 'Threads_runningDescr' => __('The number of threads that are not sleeping.') + 'Aborted_connects' => __('The number of failed attempts to connect to the MySQL server.'), + 'Binlog_cache_disk_use' => __('The number of transactions that used the temporary binary log cache but that exceeded the value of binlog_cache_size and used a temporary file to store statements from the transaction.'), + 'Binlog_cache_use' => __('The number of transactions that used the temporary binary log cache.'), + 'Connections' => __('The number of connection attempts (successful or not) to the MySQL server.'), + 'Created_tmp_disk_tables' => __('The number of temporary tables on disk created automatically by the server while executing statements. If Created_tmp_disk_tables is big, you may want to increase the tmp_table_size value to cause temporary tables to be memory-based instead of disk-based.'), + 'Created_tmp_files' => __('How many temporary files mysqld has created.'), + 'Created_tmp_tables' => __('The number of in-memory temporary tables created automatically by the server while executing statements.'), + 'Delayed_errors' => __('The number of rows written with INSERT DELAYED for which some error occurred (probably duplicate key).'), + 'Delayed_insert_threads' => __('The number of INSERT DELAYED handler threads in use. Every different table on which one uses INSERT DELAYED gets its own thread.'), + 'Delayed_writes' => __('The number of INSERT DELAYED rows written.'), + 'Flush_commands' => __('The number of executed FLUSH statements.'), + 'Handler_commit' => __('The number of internal COMMIT statements.'), + 'Handler_delete' => __('The number of times a row was deleted from a table.'), + 'Handler_discover' => __('The MySQL server can ask the NDB Cluster storage engine if it knows about a table with a given name. This is called discovery. Handler_discover indicates the number of time tables have been discovered.'), + 'Handler_read_first' => __('The number of times the first entry was read from an index. If this is high, it suggests that the server is doing a lot of full index scans; for example, SELECT col1 FROM foo, assuming that col1 is indexed.'), + 'Handler_read_key' => __('The number of requests to read a row based on a key. If this is high, it is a good indication that your queries and tables are properly indexed.'), + 'Handler_read_next' => __('The number of requests to read the next row in key order. This is incremented if you are querying an index column with a range constraint or if you are doing an index scan.'), + 'Handler_read_prev' => __('The number of requests to read the previous row in key order. This read method is mainly used to optimize ORDER BY ... DESC.'), + 'Handler_read_rnd' => __('The number of requests to read a row based on a fixed position. This is high if you are doing a lot of queries that require sorting of the result. You probably have a lot of queries that require MySQL to scan whole tables or you have joins that don\'t use keys properly.'), + 'Handler_read_rnd_next' => __('The number of requests to read the next row in the data file. This is high if you are doing a lot of table scans. Generally this suggests that your tables are not properly indexed or that your queries are not written to take advantage of the indexes you have.'), + 'Handler_rollback' => __('The number of internal ROLLBACK statements.'), + 'Handler_update' => __('The number of requests to update a row in a table.'), + 'Handler_write' => __('The number of requests to insert a row in a table.'), + 'Innodb_buffer_pool_pages_data' => __('The number of pages containing data (dirty or clean).'), + 'Innodb_buffer_pool_pages_dirty' => __('The number of pages currently dirty.'), + 'Innodb_buffer_pool_pages_flushed' => __('The number of buffer pool pages that have been requested to be flushed.'), + 'Innodb_buffer_pool_pages_free' => __('The number of free pages.'), + 'Innodb_buffer_pool_pages_latched' => __('The number of latched pages in InnoDB buffer pool. These are pages currently being read or written or that can\'t be flushed or removed for some other reason.'), + 'Innodb_buffer_pool_pages_misc' => __('The number of pages busy because they have been allocated for administrative overhead such as row locks or the adaptive hash index. This value can also be calculated as Innodb_buffer_pool_pages_total - Innodb_buffer_pool_pages_free - Innodb_buffer_pool_pages_data.'), + 'Innodb_buffer_pool_pages_total' => __('Total size of buffer pool, in pages.'), + 'Innodb_buffer_pool_read_ahead_rnd' => __('The number of "random" read-aheads InnoDB initiated. This happens when a query is to scan a large portion of a table but in random order.'), + 'Innodb_buffer_pool_read_ahead_seq' => __('The number of sequential read-aheads InnoDB initiated. This happens when InnoDB does a sequential full table scan.'), + 'Innodb_buffer_pool_read_requests' => __('The number of logical read requests InnoDB has done.'), + 'Innodb_buffer_pool_reads' => __('The number of logical reads that InnoDB could not satisfy from buffer pool and had to do a single-page read.'), + 'Innodb_buffer_pool_wait_free' => __('Normally, writes to the InnoDB buffer pool happen in the background. However, if it\'s necessary to read or create a page and no clean pages are available, it\'s necessary to wait for pages to be flushed first. This counter counts instances of these waits. If the buffer pool size was set properly, this value should be small.'), + 'Innodb_buffer_pool_write_requests' => __('The number writes done to the InnoDB buffer pool.'), + 'Innodb_data_fsyncs' => __('The number of fsync() operations so far.'), + 'Innodb_data_pending_fsyncs' => __('The current number of pending fsync() operations.'), + 'Innodb_data_pending_reads' => __('The current number of pending reads.'), + 'Innodb_data_pending_writes' => __('The current number of pending writes.'), + 'Innodb_data_read' => __('The amount of data read so far, in bytes.'), + 'Innodb_data_reads' => __('The total number of data reads.'), + 'Innodb_data_writes' => __('The total number of data writes.'), + 'Innodb_data_written' => __('The amount of data written so far, in bytes.'), + 'Innodb_dblwr_pages_written' => __('The number of pages that have been written for doublewrite operations.'), + 'Innodb_dblwr_writes' => __('The number of doublewrite operations that have been performed.'), + 'Innodb_log_waits' => __('The number of waits we had because log buffer was too small and we had to wait for it to be flushed before continuing.'), + 'Innodb_log_write_requests' => __('The number of log write requests.'), + 'Innodb_log_writes' => __('The number of physical writes to the log file.'), + 'Innodb_os_log_fsyncs' => __('The number of fsync() writes done to the log file.'), + 'Innodb_os_log_pending_fsyncs' => __('The number of pending log file fsyncs.'), + 'Innodb_os_log_pending_writes' => __('Pending log file writes.'), + 'Innodb_os_log_written' => __('The number of bytes written to the log file.'), + 'Innodb_pages_created' => __('The number of pages created.'), + 'Innodb_page_size' => __('The compiled-in InnoDB page size (default 16KB). Many values are counted in pages; the page size allows them to be easily converted to bytes.'), + 'Innodb_pages_read' => __('The number of pages read.'), + 'Innodb_pages_written' => __('The number of pages written.'), + 'Innodb_row_lock_current_waits' => __('The number of row locks currently being waited for.'), + 'Innodb_row_lock_time_avg' => __('The average time to acquire a row lock, in milliseconds.'), + 'Innodb_row_lock_time' => __('The total time spent in acquiring row locks, in milliseconds.'), + 'Innodb_row_lock_time_max' => __('The maximum time to acquire a row lock, in milliseconds.'), + 'Innodb_row_lock_waits' => __('The number of times a row lock had to be waited for.'), + 'Innodb_rows_deleted' => __('The number of rows deleted from InnoDB tables.'), + 'Innodb_rows_inserted' => __('The number of rows inserted in InnoDB tables.'), + 'Innodb_rows_read' => __('The number of rows read from InnoDB tables.'), + 'Innodb_rows_updated' => __('The number of rows updated in InnoDB tables.'), + 'Key_blocks_not_flushed' => __('The number of key blocks in the key cache that have changed but haven\'t yet been flushed to disk. It used to be known as Not_flushed_key_blocks.'), + 'Key_blocks_unused' => __('The number of unused blocks in the key cache. You can use this value to determine how much of the key cache is in use.'), + 'Key_blocks_used' => __('The number of used blocks in the key cache. This value is a high-water mark that indicates the maximum number of blocks that have ever been in use at one time.'), + 'Key_read_requests' => __('The number of requests to read a key block from the cache.'), + 'Key_reads' => __('The number of physical reads of a key block from disk. If Key_reads is big, then your key_buffer_size value is probably too small. The cache miss rate can be calculated as Key_reads/Key_read_requests.'), + 'Key_write_requests' => __('The number of requests to write a key block to the cache.'), + 'Key_writes' => __('The number of physical writes of a key block to disk.'), + 'Last_query_cost' => __('The total cost of the last compiled query as computed by the query optimizer. Useful for comparing the cost of different query plans for the same query. The default value of 0 means that no query has been compiled yet.'), + 'Max_used_connections' => __('The maximum number of connections that have been in use simultaneously since the server started.'), + 'Not_flushed_delayed_rows' => __('The number of rows waiting to be written in INSERT DELAYED queues.'), + 'Opened_tables' => __('The number of tables that have been opened. If opened tables is big, your table cache value is probably too small.'), + 'Open_files' => __('The number of files that are open.'), + 'Open_streams' => __('The number of streams that are open (used mainly for logging).'), + 'Open_tables' => __('The number of tables that are open.'), + 'Qcache_free_blocks' => __('The number of free memory blocks in query cache. High numbers can indicate fragmentation issues, which may be solved by issuing a FLUSH QUERY CACHE statement.'), + 'Qcache_free_memory' => __('The amount of free memory for query cache.'), + 'Qcache_hits' => __('The number of cache hits.'), + 'Qcache_inserts' => __('The number of queries added to the cache.'), + 'Qcache_lowmem_prunes' => __('The number of queries that have been removed from the cache to free up memory for caching new queries. This information can help you tune the query cache size. The query cache uses a least recently used (LRU) strategy to decide which queries to remove from the cache.'), + 'Qcache_not_cached' => __('The number of non-cached queries (not cachable, or not cached due to the query_cache_type setting).'), + 'Qcache_queries_in_cache' => __('The number of queries registered in the cache.'), + 'Qcache_total_blocks' => __('The total number of blocks in the query cache.'), + 'Rpl_status' => __('The status of failsafe replication (not yet implemented).'), + 'Select_full_join' => __('The number of joins that do not use indexes. If this value is not 0, you should carefully check the indexes of your tables.'), + 'Select_full_range_join' => __('The number of joins that used a range search on a reference table.'), + 'Select_range_check' => __('The number of joins without keys that check for key usage after each row. (If this is not 0, you should carefully check the indexes of your tables.)'), + 'Select_range' => __('The number of joins that used ranges on the first table. (It\'s normally not critical even if this is big.)'), + 'Select_scan' => __('The number of joins that did a full scan of the first table.'), + 'Slave_open_temp_tables' => __('The number of temporary tables currently open by the slave SQL thread.'), + 'Slave_retried_transactions' => __('Total (since startup) number of times the replication slave SQL thread has retried transactions.'), + 'Slave_running' => __('This is ON if this server is a slave that is connected to a master.'), + 'Slow_launch_threads' => __('The number of threads that have taken more than slow_launch_time seconds to create.'), + 'Slow_queries' => __('The number of queries that have taken more than long_query_time seconds.'), + 'Sort_merge_passes' => __('The number of merge passes the sort algorithm has had to do. If this value is large, you should consider increasing the value of the sort_buffer_size system variable.'), + 'Sort_range' => __('The number of sorts that were done with ranges.'), + 'Sort_rows' => __('The number of sorted rows.'), + 'Sort_scan' => __('The number of sorts that were done by scanning the table.'), + 'Table_locks_immediate' => __('The number of times that a table lock was acquired immediately.'), + 'Table_locks_waited' => __('The number of times that a table lock could not be acquired immediately and a wait was needed. If this is high, and you have performance problems, you should first optimize your queries, and then either split your table or tables or use replication.'), + 'Threads_cached' => __('The number of threads in the thread cache. The cache hit rate can be calculated as Threads_created/Connections. If this value is red you should raise your thread_cache_size.'), + 'Threads_connected' => __('The number of currently open connections.'), + 'Threads_created' => __('The number of threads created to handle connections. If Threads_created is big, you may want to increase the thread_cache_size value. (Normally this doesn\'t give a notable performance improvement if you have a good thread implementation.)'), + 'Threads_running' => __('The number of threads that are not sleeping.') ); /** @@ -837,7 +939,7 @@ function printVariablesTable() { // variable => min value //'Handler read key' => '> ', ); - + ?> @@ -892,8 +994,8 @@ function printVariablesTable() { ?> From 3d62f95c89dbec80690fee0d92729317e5aff6c2 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Mon, 30 May 2011 22:57:08 +0200 Subject: [PATCH 025/206] Revert "timepicker.js is redundant, its already in the jquery ui js file" This reverts commit a0302c666c1bf9f9715364a6301238b474aedac1. --- js/jquery/timepicker.js | 480 ++++++++++++++++++++++++++++++++++++++++ tbl_change.php | 2 +- tbl_select.php | 2 +- 3 files changed, 482 insertions(+), 2 deletions(-) create mode 100644 js/jquery/timepicker.js diff --git a/js/jquery/timepicker.js b/js/jquery/timepicker.js new file mode 100644 index 0000000000..4d1845ec43 --- /dev/null +++ b/js/jquery/timepicker.js @@ -0,0 +1,480 @@ +/*! + * jQuery UI Timepicker 0.2.1 + * + * Copyright (c) 2009 Martin Milesich (http://milesich.com/) + * + * Some parts are + * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) + * + * $Id: timepicker.js 28 2009-08-11 20:31:23Z majlo $ + * + * Depends: + * ui.core.js + * ui.datepicker.js + * ui.slider.js + */ +(function($) { + +/** + * Extending default values + */ +$.extend($.datepicker._defaults, { + 'dateFormat': 'yy-mm-dd', + 'changeMonth': true, + 'changeYear': true, + 'stepSeconds': 1, // Number of seconds to step up/down + 'stepMinutes': 1, // Number of minutes to step up/down + 'stepHours': 1, // Number of hours to step up/down + 'time24h': false, // True if 24h time + 'showTime': false, // Show timepicker with datepicker + 'altTimeField': '', // Selector for an alternate field to store time into + 'hourText': 'Hour', + 'minuteText': 'Minute', + 'secondText': 'Second' +}); +$.extend($.datepicker.regional[''], { + 'hourText': 'Hour', + 'minuteText': 'Minute', + 'secondText': 'Second' +}); + +/** + * _hideDatepicker must be called with null + */ +$.datepicker._connectDatepickerOverride = $.datepicker._connectDatepicker; +$.datepicker._connectDatepicker = function(target, inst) { + $.datepicker._connectDatepickerOverride(target, inst); + + // showButtonPanel is required with timepicker + if (this._get(inst, 'showTime')) { + inst.settings['showButtonPanel'] = true; + } + + var showOn = this._get(inst, 'showOn'); + + if (showOn == 'button' || showOn == 'both') { + // Unbind all click events + inst.trigger.unbind('click'); + + // Bind new click event + inst.trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput == target) + $.datepicker._hideDatepicker(null); // This override is all about the "null" + else + $.datepicker._showDatepicker(target); + return false; + }); + } +}; + +/** + * Datepicker does not have an onShow event so I need to create it. + * What I actually doing here is copying original _showDatepicker + * method to _showDatepickerOverload method. + */ +$.datepicker._showDatepickerOverride = $.datepicker._showDatepicker; +$.datepicker._showDatepicker = function (input) { + // Call the original method which will show the datepicker + $.datepicker._showDatepickerOverride(input); + + input = input.target || input; + + // find from button/image trigger + if (input.nodeName.toLowerCase() != 'input') input = $('input', input.parentNode)[0]; + + // Do not show timepicker if datepicker is disabled + if ($.datepicker._isDisabledDatepicker(input)) return; + + // Get instance to datepicker + var inst = $.datepicker._getInst(input); + + var showTime = $.datepicker._get(inst, 'showTime'); + + // If showTime = True show the timepicker + if (showTime) $.timepicker.show(input); +}; + +/** + * Same as above. Here I need to extend the _checkExternalClick method + * because I don't want to close the datepicker when the sliders get focus. + */ +$.datepicker._checkExternalClickOverride = $.datepicker._checkExternalClick; +$.datepicker._checkExternalClick = function (event) { + if (!$.datepicker._curInst) return; + var $target = $(event.target); + + if (($target.parents('#' + $.timepicker._mainDivId).length == 0)) { + $.datepicker._checkExternalClickOverride(event); + } +}; + +/** + * Datepicker has onHide event but I just want to make it simple for you + * so I hide the timepicker when datepicker hides. + */ +$.datepicker._hideDatepickerOverride = $.datepicker._hideDatepicker; +$.datepicker._hideDatepicker = function(input, duration) { + // Some lines from the original method + var inst = this._curInst; + + if (!inst || (input && inst != $.data(input, PROP_NAME))) return; + + // Get the value of showTime property + var showTime = this._get(inst, 'showTime'); + + if (input === undefined && showTime) { + if (inst.input) { + inst.input.val(this._formatDate(inst)); + inst.input.trigger('change'); // fire the change event + } + + this._updateAlternate(inst); + + if (showTime) $.timepicker.update(this._formatDate(inst)); + } + + // Hide datepicker + $.datepicker._hideDatepickerOverride(input, duration); + + // Hide the timepicker if enabled + if (showTime) { + $.timepicker.hide(); + } +}; + +/** + * This is a complete replacement of the _selectDate method. + * If showed with timepicker do not close when date is selected. + */ +$.datepicker._selectDate = function(id, dateStr) { + var target = $(id); + var inst = this._getInst(target[0]); + var showTime = this._get(inst, 'showTime'); + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (!showTime) { + if (inst.input) + inst.input.val(dateStr); + this._updateAlternate(inst); + } + var onSelect = this._get(inst, 'onSelect'); + if (onSelect) + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + else if (inst.input && !showTime) + inst.input.trigger('change'); // fire the change event + if (inst.inline) + this._updateDatepicker(inst); + else if (!inst.stayOpen) { + if (showTime) { + this._updateDatepicker(inst); + } else { + this._hideDatepicker(null, this._get(inst, 'duration')); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) != 'object') + inst.input[0].focus(); // restore focus + this._lastInput = null; + } + } +}; + +/** + * We need to resize the timepicker when the datepicker has been changed. + */ +$.datepicker._updateDatepickerOverride = $.datepicker._updateDatepicker; +$.datepicker._updateDatepicker = function(inst) { + $.datepicker._updateDatepickerOverride(inst); + $.timepicker.resize(); +}; + +function Timepicker() {} + +Timepicker.prototype = { + init: function() + { + this._mainDivId = 'ui-timepicker-div'; + this._inputId = null; + this._orgValue = null; + this._orgHour = null; + this._orgMinute = null; + this._orgSecond = null; + this._colonPos = -1; + this._scolonPos = -1; + this._visible = false; + this.tpDiv = $(''); + this._generateHtml(); + }, + + show: function (input) + { + // Get instance to datepicker + var inst = $.datepicker._getInst(input); + + this._time24h = $.datepicker._get(inst, 'time24h'); + this._altTimeField = $.datepicker._get(inst, 'altTimeField'); + + var stepSeconds = parseInt($.datepicker._get(inst, 'stepSeconds'), 10) || 1; + var stepMinutes = parseInt($.datepicker._get(inst, 'stepMinutes'), 10) || 1; + var stepHours = parseInt($.datepicker._get(inst, 'stepHours'), 10) || 1; + + if (60 % stepSeconds != 0) { stepSeconds = 1; } + if (60 % stepMinutes != 0) { stepMinutes = 1; } + if (24 % stepHours != 0) { stepHours = 1; } + + $('#hourSlider').slider('option', 'max', 24 - stepHours); + $('#hourSlider').slider('option', 'step', stepHours); + + $('#minuteSlider').slider('option', 'max', 60 - stepMinutes); + $('#minuteSlider').slider('option', 'step', stepMinutes); + + $('#secondSlider').slider('option', 'max', 60 - stepSeconds); + $('#secondSlider').slider('option', 'step', stepSeconds); + + $('.hour_text').html($.datepicker._get(inst, 'hourText')); + $('.minute_text').html($.datepicker._get(inst, 'minuteText')); + $('.second_text').html($.datepicker._get(inst, 'secondText')); + + this._inputId = input.id; + + if (!this._visible) { + this._parseTime(); + this._orgValue = $('#' + this._inputId).val(); + } + + this.resize(); + + $('#' + this._mainDivId).show(); + + this._visible = true; + + var dpDiv = $('#' + $.datepicker._mainDivId); + var dpDivPos = dpDiv.position(); + + var viewWidth = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) + $(document).scrollLeft(); + var tpRight = this.tpDiv.offset().left + this.tpDiv.outerWidth(); + + if (tpRight > viewWidth) { + dpDiv.css('left', dpDivPos.left - (tpRight - viewWidth) - 5); + this.tpDiv.css('left', dpDiv.offset().left + dpDiv.outerWidth() + 'px'); + } + }, + + update: function (fd) + { + var curTime = $('#' + this._mainDivId + ' span.fragHours').text() + + ':' + + $('#' + this._mainDivId + ' span.fragMinutes').text() + + ':' + + $('#' + this._mainDivId + ' span.fragSeconds').text() + ; + + if (!this._time24h) { + curTime += ' ' + $('#' + this._mainDivId + ' span.fragAmpm').text(); + } + + var curDate = $('#' + this._inputId).val(); + + $('#' + this._inputId).val(fd + ' ' + curTime); + + if (this._altTimeField) { + $(this._altTimeField).each(function() { $(this).val(curTime); }); + } + }, + + hide: function () + { + this._visible = false; + $('#' + this._mainDivId).hide(); + }, + + resize: function () + { + var dpDiv = $('#' + $.datepicker._mainDivId); + var dpDivPos = dpDiv.position(); + + var hdrHeight = $('#' + $.datepicker._mainDivId + ' > div.ui-datepicker-header:first-child').height(); + + $('#' + this._mainDivId + ' > div.ui-datepicker-header:first-child').css('height', hdrHeight); + + this.tpDiv.css({ + 'height': dpDiv.height(), + 'top' : dpDivPos.top, + 'left' : dpDivPos.left + dpDiv.outerWidth() + 'px' + }); + + $('#hourSlider').css('height', this.tpDiv.height() - (3.5 * hdrHeight)); + $('#minuteSlider').css('height', this.tpDiv.height() - (3.5 * hdrHeight)); + $('#secondSlider').css('height', this.tpDiv.height() - (3.5 * hdrHeight)); + }, + + _generateHtml: function () + { + var html = ''; + + html += '
'; + html += '
'; + html += '08:45:45
Date: Mon, 30 May 2011 17:02:36 +0200 Subject: [PATCH 023/206] Merged processes page into server status page --- libraries/server_links.inc.php | 3 - server_processlist.php | 114 --------------------------------- 2 files changed, 117 deletions(-) delete mode 100644 server_processlist.php diff --git a/libraries/server_links.inc.php b/libraries/server_links.inc.php index b8b4dcdb0a..95e39153f2 100644 --- a/libraries/server_links.inc.php +++ b/libraries/server_links.inc.php @@ -54,9 +54,6 @@ if (!$GLOBALS['is_ajax_request']) { $tabs['binlog']['link'] = 'server_binlog.php'; $tabs['binlog']['text'] = __('Binary log'); } - $tabs['process']['icon'] = 's_process.png'; - $tabs['process']['link'] = 'server_processlist.php'; - $tabs['process']['text'] = __('Processes'); if ($is_superuser) { $tabs['rights']['icon'] = 's_rights.png'; diff --git a/server_processlist.php b/server_processlist.php deleted file mode 100644 index 78f0013da3..0000000000 --- a/server_processlist.php +++ /dev/null @@ -1,114 +0,0 @@ -' . "\n" - . ($GLOBALS['cfg']['MainPageIconic'] ? '' : '') - . ' ' . __('Processes') . "\n" - . '' . "\n"; - -/** - * Kills a selected process - */ -if (!empty($_REQUEST['kill'])) { - if (PMA_DBI_try_query('KILL ' . $_REQUEST['kill'] . ';')) { - $message = PMA_Message::success(__('Thread %s was successfully killed.')); - } else { - $message = PMA_Message::error(__('phpMyAdmin was unable to kill thread %s. It probably has already been closed.')); - } - $message->addParam($_REQUEST['kill']); - $message->display(); -} - -$url_params = array(); - -if (! empty($_REQUEST['full'])) { - $sql_query = 'SHOW FULL PROCESSLIST'; - $url_params['full'] = 1; - $full_text_link = 'server_processlist.php' . PMA_generate_common_url(array(), 'html', '?'); -} else { - $sql_query = 'SHOW PROCESSLIST'; - $full_text_link = 'server_processlist.php' . PMA_generate_common_url(array('full' => 1)); -} -$result = PMA_DBI_query($sql_query); - -/** - * Displays the page - */ -?> - - - - - - - - - - - - - - - - - - - - $v) { - $k = $k !== 'DB' - ? $k = ucfirst(strtolower($k)) - : 'db'; - $process[$k] = $v; - } - } - $url_params['kill'] = $process['Id']; - $kill_process = 'server_processlist.php' . PMA_generate_common_url($url_params); - ?> - - - - - - - - - - - - - -
- <?php echo empty($_REQUEST['full']) ? __('Show Full Queries') : __('Truncate Shown Queries'); ?> -
' . __('None') . '' : $process['db']); ?>
- From 4885b174da8c9dca2b0bea9f4ea38fb63bc76eb9 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Mon, 30 May 2011 22:37:18 +0200 Subject: [PATCH 024/206] - Implemented more reusable code for realtime charting - added 'queries per second' chart in the query statistics tab - removed test chart - fixed kill process url --- js/server_status.js | 131 +++++++++++++++++++++++----------- server_status.php | 166 +++++++++++++++++++++++--------------------- 2 files changed, 178 insertions(+), 119 deletions(-) diff --git a/js/server_status.js b/js/server_status.js index 7556eb0a7f..20476c3de8 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -1,12 +1,14 @@ $(function() { + // Filters for status variables var textFilter=null; var alertFilter = false; var categoryFilter=''; var odd_row=false; - var text=''; + var text=''; // Holds filter text - // Process chart - initChart(); + // Holds the tab contents when realtime charts are being displayed + var tabCache = new Object(); + var tabStatus = new Object(); // Add tabs $('#serverStatusTabs').tabs({ @@ -14,6 +16,7 @@ $(function() { cookie: { name: 'pma_serverStatusTabs', expires: 1 }, show: function() { menuResize(); } }); + // Fixes wrong tab height with floated elements. See also http://bugs.jqueryui.com/ticket/5601 $(".ui-widget-content:not(.ui-tabs):not(.ui-helper-clearfix)").addClass("ui-helper-clearfix"); @@ -28,8 +31,44 @@ $(function() { imageMap.init(); }); - // Ajax reload of variables - $('.statuslinks a').click(function() { return refreshHandler(this); }); + // Ajax reload of variables (always the first link) + $('.statuslinks a:nth-child(1)').click(function() { return refreshHandler(this); }); + // Realtime charting of variables (always the second link) + $('.statuslinks a:nth-child(2)').click(function() { + // ui-tabs-panel class is added by the jquery tabs feature + var tab=$(this).parents('div.ui-tabs-panel'); + + if(tabStatus[tab.attr('id')]!='realtime') { + var series, title; + var settings = {container:tab.attr('id')+"_chart_cnt"}; + + switch(tab.attr('id')) { + case 'statustabs_traffic': + break; + case 'statustabs_queries': + settings.series = [{name: 'Queries per second', + data: [] + }]; + settings.differentialData = true; + settings.dataType = 'queries'; + settings.chartTitle = 'Queries per second'; + break; + + default: + return; + } + + tabStatus[tab.attr('id')]='realtime'; + tabCache[tab.attr('id')]=tab.find('.tabInnerContent').html(); + tab.find('.tabInnerContent').html('
'); + //alert(tab.find('.tabInnerContent #'+tab.attr('id')+'_chart_cnt').length); + initChart(settings); + } else { + tab.find('.tabInnerContent').html(tabCache[tab.attr('id')]); + tabStatus[tab.attr('id')]='data'; + } + return false; + }); /* 3 Filtering functions */ $('#filterAlert').change(function() { @@ -53,18 +92,15 @@ $(function() { function initTab(tab,data) { switch(tab.attr('id')) { case 'statustabs_traffic': - tab.html(data); + tab.find('.tabInnerContent').html(data); initTooltips(); - $('#statustabs_traffic .statuslinks a').click(function() { return refreshHandler(this); }); break; case 'statustabs_queries': - tab.html(data); - $('#statustabs_queries .statuslinks a').click(function() { return refreshHandler(this); }); + tab.find('.tabInnerContent').html(data); break; case 'statustabs_allvars': - tab.find('#serverstatusvariables').html(data); + tab.find('.tabInnerContent').html(data); filterVariables(); - tab.find('.statuslinks a img').hide(); break; } } @@ -75,11 +111,14 @@ $(function() { // Show ajax load icon $(element).find('img').show(); - + $.get($(element).attr('href'),{ajax_request:1},function(data) { initTab(tab,data); + $(element).find('img').hide(); }); + tabStatus[tab.attr('id')]='data'; + return false; } @@ -126,35 +165,60 @@ $(function() { }); } - function initChart() { + function initChart(settings) { + if(settings.differentialData == undefined) + settings.differentialData = false; + if(settings.seriesType == undefined) + settings.seriesType = 'spline'; + if(settings.numPoints == undefined) + settings.numPoints=30; + + var numLoadedPoints=0; + chart = new Highcharts.Chart({ chart: { - renderTo: 'container', - defaultSeriesType: 'spline', + renderTo: settings.container, + defaultSeriesType: settings.seriesType, marginRight: 10, events: { load: function() { - + var thisChart = this; // set up the updating of the chart each second - var series = this.series[0]; + var lastValue=new Array(); var addnewPoint = function() { - $.get('server_status.php?'+url_query,{ajax_request:1, chart_data:1},function(data) { - var x=parseInt(data.split(',')[0]), - y=parseInt(data.split(',')[1]); - - series.addPoint([x,y], true, true); + // Stop loading data, if the chart has been removed + if($('#'+settings.container).length==0) return; + + $.get('server_status.php?'+url_query,{ajax_request:1, chart_data:1,type:settings.dataType},function(data) { + var splitData = data.split(','); + var x,y; + for(var i=0; i*2<=splitData.length; i++) { + x=parseFloat(splitData[i*2]); + y=parseFloat(splitData[i*2+1]); + + if(settings.differentialData) { + if(lastValue[i]!=undefined && thisChart.series[i]!=undefined) { + thisChart.series[i].addPoint([x,1000*(y-lastValue[i][1])/(x-lastValue[i][0])], true, numLoadedPoints++ >= settings.numPoints); + } + } else thisChart.series[i].addPoint([x,y], true, numLoadedPoints++ >= settings.numPoints); + + lastValue[i] = [x,y]; + } setTimeout(addnewPoint, 2000); }); } - - setTimeout(addnewPoint, 2000); + + addnewPoint(); } } }, + credits: { + enabled:false + }, title: { - text: 'Processes' + text: settings.chartTitle }, xAxis: { type: 'datetime', @@ -183,22 +247,7 @@ $(function() { exporting: { enabled: false }, - series: [{ - name: '# Processes', - data: (function() { - // generate an array of random data - var data = [], - time = (new Date()).getTime(), - i; - for (i = -19; i <= 0; i++) { - data.push({ - x: time + i * 2000, - y: 0 //Math.random() - }); - } - return data; - })() - }] + series: settings.series }); } }); \ No newline at end of file diff --git a/server_status.php b/server_status.php index 0f51c4c736..8ac0c80c81 100644 --- a/server_status.php +++ b/server_status.php @@ -31,9 +31,17 @@ if (isset($_REQUEST['ajax_request'])) { exit(createQueryChart()); } if(isset($_REQUEST['chart_data'])) { - $result = PMA_DBI_query('SHOW PROCESSLIST'); - $num_procs = PMA_DBI_num_rows($result); - exit((time()*1000).','.$num_procs); + switch($_REQUEST['type']) { + case 'proc': + $result = PMA_DBI_query('SHOW PROCESSLIST'); + $num_procs = PMA_DBI_num_rows($result); + exit((microtime(true)*1000).','.$num_procs); + case 'queries': + $result = PMA_DBI_query('SHOW GLOBAL STATUS LIKE \'Questions\''); + $status = PMA_DBI_fetch_result($result); + // print_r($status); + exit((microtime(true)*1000).','.$status[0]['Value']); + } } } @@ -81,7 +89,7 @@ if (!empty($_REQUEST['kill'])) { $message = PMA_Message::error(__('phpMyAdmin was unable to kill thread %s. It probably has already been closed.')); } $message->addParam($_REQUEST['kill']); - $message->display(); + //$message->display(); } @@ -263,8 +271,8 @@ $links['qcache'][__('Flush query cache')] PMA_generate_common_url(); $links['qcache']['doc'] = 'query_cache'; -$links['threads'][__('Show processes')] - = 'server_processlist.php?' . PMA_generate_common_url(); +//$links['threads'][__('Show processes')] +// = 'server_processlist.php?' . PMA_generate_common_url(); $links['threads']['doc'] = 'mysql_threads'; $links['key']['doc'] = 'myisam_key_cache'; @@ -359,67 +367,83 @@ echo __('Runtime Information');
- -
+ +
+ +
- + +
+ +
-
-
- - Filters -
- - -
-
- - -
-
- -
-
-
'; + html += ''; + html += ''; + html += '
'; + html += 'Hour'; + html += ''; + html += 'Minute'; + html += ''; + html += 'Second'; + html += '
'; + + this.tpDiv.empty().append(html); + $('body').append(this.tpDiv); + + var self = this; + + $('#hourSlider').slider({ + orientation: "vertical", + range: 'min', + min: 0, + max: 23, + step: 1, + slide: function(event, ui) { + self._writeTime('hour', ui.value); + }, + stop: function(event, ui) { + $('#' + self._inputId).focus(); + } + }); + + $('#minuteSlider').slider({ + orientation: "vertical", + range: 'min', + min: 0, + max: 59, + step: 1, + slide: function(event, ui) { + self._writeTime('minute', ui.value); + }, + stop: function(event, ui) { + $('#' + self._inputId).focus(); + } + }); + + $('#secondSlider').slider({ + orientation: "vertical", + range: 'min', + min: 0, + max: 59, + step: 1, + slide: function(event, ui) { + self._writeTime('second', ui.value); + }, + stop: function(event, ui) { + $('#' + self._inputId).focus(); + } + }); + + $('#hourSlider > a').css('padding', 0); + $('#minuteSlider > a').css('padding', 0); + $('#secondSlider > a').css('padding', 0); + }, + + _writeTime: function (type, value) + { + if (type == 'hour') { + if (!this._time24h) { + if (value < 12) { + $('#' + this._mainDivId + ' span.fragAmpm').text('am'); + } else { + $('#' + this._mainDivId + ' span.fragAmpm').text('pm'); + value -= 12; + } + + if (value == 0) value = 12; + } else { + $('#' + this._mainDivId + ' span.fragAmpm').text(''); + } + + if (value < 10) value = '0' + value; + $('#' + this._mainDivId + ' span.fragHours').text(value); + } + + if (type == 'minute') { + if (value < 10) value = '0' + value; + $('#' + this._mainDivId + ' span.fragMinutes').text(value); + } + + if (type == 'second') { + if (value < 10) value = '0' + value; + $('#' + this._mainDivId + ' span.fragSeconds').text(value); + } + }, + + _parseTime: function () + { + var dt = $('#' + this._inputId).val(); + + this._colonPos = dt.search(':'); + + var m = 0, h = 0, s = 0, a = ''; + + if (this._colonPos != -1) { + this._scolonPos = dt.substring(this._colonPos + 1).search(':'); + h = parseInt(dt.substr(this._colonPos - 2, 2), 10); + m = parseInt(dt.substr(this._colonPos + 1, 2), 10); + if (this._scolonPos != -1) { + this._scolonPos += this._colonPos + 1; + s = parseInt(dt.substr(this._scolonPos + 1, 2), 10); + a = jQuery.trim(dt.substr(this._scolonPos + 3, 3)); + } else { + a = jQuery.trim(dt.substr(this._colonPos + 3, 3)); + } + } + + a = a.toLowerCase(); + + if (a != 'am' && a != 'pm') { + a = ''; + } + + if (h < 0) h = 0; + if (m < 0) m = 0; + + if (h > 23) h = 23; + if (m > 59) m = 59; + + if (a == 'pm' && h < 12) h += 12; + if (a == 'am' && h == 12) h = 0; + + this._setTime('hour', h); + this._setTime('minute', m); + this._setTime('second', s); + + this._orgHour = h; + this._orgMinute = m; + this._orgSecond = s; + }, + + _setTime: function (type, value) + { + if (isNaN(value)) value = 0; + if (value < 0) value = 0; + if (value > 23 && type == 'hour') value = 23; + if (value > 59 && type == 'minute') value = 59; + if (value > 59 && type == 'second') value = 59; + + if (type == 'hour') { + $('#hourSlider').slider('value', value); + } + + if (type == 'minute') { + $('#minuteSlider').slider('value', value); + } + + if (type == 'second') { + $('#secondSlider').slider('value', value); + } + + this._writeTime(type, value); + } +}; + +$.timepicker = new Timepicker(); +$('document').ready(function () {$.timepicker.init();}); + +})(jQuery); diff --git a/tbl_change.php b/tbl_change.php index 78a6b52590..efdbd3fe73 100644 --- a/tbl_change.php +++ b/tbl_change.php @@ -113,7 +113,7 @@ if ($GLOBALS['cfg']['ShowPropertyComments']) { $GLOBALS['js_include'][] = 'functions.js'; $GLOBALS['js_include'][] = 'tbl_change.js'; $GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js'; -//$GLOBALS['js_include'][] = 'jquery/timepicker.js'; - already included in jquery-ui +$GLOBALS['js_include'][] = 'jquery/timepicker.js'; /** * HTTP and HTML headers */ diff --git a/tbl_select.php b/tbl_select.php index 61276aaca6..681083a696 100644 --- a/tbl_select.php +++ b/tbl_select.php @@ -19,7 +19,7 @@ require_once './libraries/mysql_charsets.lib.php'; $GLOBALS['js_include'][] = 'sql.js'; $GLOBALS['js_include'][] = 'tbl_select.js'; $GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js'; -//$GLOBALS['js_include'][] = 'jquery/timepicker.js'; - already included in jquery-ui +$GLOBALS['js_include'][] = 'jquery/timepicker.js'; if ($GLOBALS['cfg']['PropertiesIconic'] == true) { $titles['Browse'] = '' . PHP_EOL; - ?> + if (!$jsonly) + echo '

- + + ø % diff --git a/themes/pmahomme/css/theme_right.css.php b/themes/pmahomme/css/theme_right.css.php index 58e409cec6..d5824a6fb5 100644 --- a/themes/pmahomme/css/theme_right.css.php +++ b/themes/pmahomme/css/theme_right.css.php @@ -1166,6 +1166,23 @@ text-shadow:0 1px 0 #000000; /* serverstatus */ +img.sortableIcon { + width:16px; + height:16px; + float:right; + background-repeat:no-repeat; +} + +table#serverstatusqueriesdetails th img.sortableIcon, table#serverstatusvariables th img.sortableIcon { + background-image:url(getImgPath(); ?>s_sortable.png); +} +table#serverstatusqueriesdetails th.headerSortUp img.sortableIcon, table#serverstatusvariables th.headerSortUp img.sortableIcon { + background-image:url(getImgPath(); ?>s_asc.png); +} +table#serverstatusqueriesdetails th.headerSortDown img.sortableIcon, table#serverstatusvariables th.headerSortDown img.sortableIcon { + background-image:url(getImgPath(); ?>s_desc.png); +} + .statuslinks { float: ; } diff --git a/themes/pmahomme/img/cleardot.gif b/themes/pmahomme/img/cleardot.gif new file mode 100644 index 0000000000000000000000000000000000000000..35d42e808f0a8017b8d52a06be2f8fec0b466a66 GIT binary patch literal 43 scmZ?wbhEHbWMp7uXkcLY|NlP&1B2pE7Dgb&paUX6G7L;iE{qJ;0LZEa`2YX_ literal 0 HcmV?d00001 diff --git a/themes/pmahomme/img/s_sortable.png b/themes/pmahomme/img/s_sortable.png new file mode 100644 index 0000000000000000000000000000000000000000..0a341429eb8f909b4c3fc6825113c187a7bf6d02 GIT binary patch literal 1107 zcmV-Z1g!gsP)U8P*7-ZbZ>KLZ*U+lnSp_Ufq@}0xwybFAi#%#fq@|}KQEO56)-X|e7nZL z$iTqBa9P*U#mSX{G{Bl%P*lRez;J+pfx##xwK$o9f#C}S14DXwNkIt%17i#W1A|CX zc0maP17iUL1A|C*NRTrF17iyV0~1e4YDEbH0|SF|enDkXW_m`6f}y3QrGjHhep0GJ zaAk2xYHqQDXI^rCQ9*uDVo7QW0|Nup4h9AW240u^5(W3f%sd4n162kpgNVo|1qcff zJ_s=cNG>fZg9jx8g8+j9g8_pBLjXe}Lp{R+hNBE`7{wV~7)u#fFy3PlV+vxLz;uCG zm^qSpA@ds+OO_6nTdaDlt*rOhEZL^9ePa)2-_4=K(Z%tFGm-NGmm}8}ZcXk5JW@PU zd4+f<@d@)yL(o<5icqT158+-B6_LH7;i6x}CW#w~Uy-Pgl#@Irl`kzV zeL|*8R$ca%T%Wv){2zs_iiJvgN^h0dsuZZ2sQy$tsNSU!s;Q*;LF<6_B%M@UD?LHI zSNcZ`78uqV#TeU~$eS{ozBIdFzSClfs*^S+dw;4dus<{M;#|MXC)T}S9v!D zcV!QCPhBq)ZyO(X-(bH4|NMaZz==UigLj2o41F2S6d@OB6%`R(5i>J(Puzn9wnW{e zu;hl6HK{k#IWjCVGqdJqU(99Cv(K+6*i`tgSi2;vbXD1#3jNBGs$DgVwO(~o>mN4i zHPtkqZIx>)Y(Ls5-Br|mx>vQYvH$Kwn@O`L|D75??eGkZnfg$5<;Xeg_o%+-I&+-3%01W^SH2RkDT>t<8AY({UO#lFTB>(_`g8%^e z{{R4h=>PzAFaQARU;qF*m;eA5Z<1fdMgRZ+wMj%lRCwBA{Lg?NFfov#V2i|>*Nf$F zD%c?L`96cl#~WR8SQV_1_p8 Date: Wed, 1 Jun 2011 11:21:45 +0200 Subject: [PATCH 033/206] Reinitalize tablesorter after refresh --- js/server_status.js | 46 +++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/js/server_status.js b/js/server_status.js index 71f8f9453d..cb783d1b45 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -21,20 +21,6 @@ $(function() { // Fixes wrong tab height with floated elements. See also http://bugs.jqueryui.com/ticket/5601 $(".ui-widget-content:not(.ui-tabs):not(.ui-helper-clearfix)").addClass("ui-helper-clearfix"); - // Enable table sorting - $('#serverstatusvariables') - .tablesorter({ - sortList: [[0,0]], - widgets: ['zebra'] - }); - $('#serverstatusqueriesdetails') - .tablesorter({ - sortList: [[3,1]], - widgets: ['zebra'] - }); - - $('#serverstatusqueriesdetails tr:first th, #serverstatusvariables tr:first th').append(''); - // Load chart asynchronly so the page loads faster $.get($('#serverstatusquerieschart a').first().attr('href'),{ajax_request:1}, function(data) { $('#serverstatusquerieschart').html(data); @@ -42,6 +28,10 @@ $(function() { imageMap.init(); }); + // Table sorting + initTableSorter('statustabs_queries'); + initTableSorter('statustabs_allvars'); + // Ajax reload of variables (always the first link) $('.statuslinks a:nth-child(1)').click(function() { return refreshHandler(this); }); // Realtime charting of variables (always the second link) @@ -114,6 +104,8 @@ $(function() { filterVariables(); break; } + + initTableSorter(tab.attr('id')); } function refreshHandler(element) { @@ -133,6 +125,32 @@ $(function() { return false; } + function initTableSorter(tabid) { + switch(tabid) { + case 'statustabs_queries': + $('#serverstatusqueriesdetails').tablesorter({ + sortList: [[3,1]], + widgets: ['zebra'] + }); + + $('#serverstatusqueriesdetails tr:first th') + .append(''); + + break; + + case 'statustabs_allvars': + $('#serverstatusvariables').tablesorter({ + sortList: [[0,0]], + widgets: ['zebra'] + }); + + $('#serverstatusvariables tr:first th') + .append(''); + + break; + } + } + function filterVariables() { var useful_links=0; var section = text; From 71cc8fec3d2942871251918f38453d9ee65699f9 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Wed, 1 Jun 2011 17:49:27 +0200 Subject: [PATCH 034/206] - Query chart: - Point tooltip now shows what type of queries have been issued - Changed data from 'Seconds per Query' to 'Seconds since last refresh' --- js/messages.php | 8 +++ js/server_status.js | 171 ++++++++++++++++++++++++++++---------------- server_status.php | 56 +++++++++------ 3 files changed, 149 insertions(+), 86 deletions(-) diff --git a/js/messages.php b/js/messages.php index a710260a59..7ffab5fe1b 100644 --- a/js/messages.php +++ b/js/messages.php @@ -57,6 +57,14 @@ $js_messages['strReloadingPrivileges'] = __('Reloading Privileges'); $js_messages['strRemovingSelectedUsers'] = __('Removing Selected Users'); $js_messages['strClose'] = __('Close'); +/* for server_status.js */ +$js_messages['strRealtimeChart'] = __('Realtime chart'); +$js_messages['strStaticData'] = __('Static data'); +/* l10n: Total number of queries */ +$js_messages['strTotal'] = __('Total'); +/* l10n: Other, small valued, queries */ +$js_messages['strOther'] = __('Other'); + /* For inline query editing */ $js_messages['strGo'] = __('Go'); $js_messages['strCancel'] = __('Cancel'); diff --git a/js/server_status.js b/js/server_status.js index cb783d1b45..da60a373ae 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -5,6 +5,11 @@ $(function() { var categoryFilter=''; var odd_row=false; var text=''; // Holds filter text + /* Chart configuration */ + // Amount of points the chart should hold + var numMaxPoints=30; + // Time between each refresh + var refreshRate=3000; // Holds the tab contents when realtime charts are being displayed var tabCache = new Object(); @@ -34,25 +39,64 @@ $(function() { // Ajax reload of variables (always the first link) $('.statuslinks a:nth-child(1)').click(function() { return refreshHandler(this); }); - // Realtime charting of variables (always the second link) + + /** Realtime charting of variables (always the second link) **/ $('.statuslinks a:nth-child(2)').click(function() { // ui-tabs-panel class is added by the jquery tabs feature var tab=$(this).parents('div.ui-tabs-panel'); if(tabStatus[tab.attr('id')]!='realtime') { var series, title; - var settings = {container:tab.attr('id')+"_chart_cnt"}; + var settings = { chart: {renderTo:tab.attr('id')+"_chart_cnt"} } switch(tab.attr('id')) { case 'statustabs_traffic': break; case 'statustabs_queries': - settings.series = [{name: 'Queries per second', - data: [] - }]; - settings.differentialData = true; - settings.dataType = 'queries'; - settings.chartTitle = 'Queries per second'; + settings.chart = { + renderTo:tab.attr('id')+"_chart_cnt", + defaultSeriesType: 'spline', + events: { + load: function() { + var thisChart = this; + var lastValue=null; + var numLoadedPoints=0; + var otherSum=0; + + var addnewPoint = function() { + // Stop loading data, if the chart has been removed + if(tabStatus[tab.attr('id')]!='realtime') return; + + $.get('server_status.php?'+url_query,{ajax_request:1, chart_data:1, type:'queries'},function(data) { + var chartData = jQuery.parseJSON(data); + var pointInfo=''; + var i=0; + + chartData.x = parseInt(chartData.x); + chartData.y = parseInt(chartData.y); + + if(lastValue!=null) { + thisChart.series[0].addPoint({ + x:chartData.x, + y:chartData.y-lastValue.y, + name:sortedQueriesPointInfo(chartData,lastValue) + }, true, numLoadedPoints >= numMaxPoints); + } + + lastValue = chartData; + numLoadedPoints++; + setTimeout(addnewPoint, refreshRate); + }); + } + addnewPoint(); + } + } + }; + settings.c_differentialData = true; + settings.c_dataType = 'queries'; + settings.series = [{name:'Issued queries since last refresh', data:[]}]; + settings.title = {text:'Issued queries'}; + settings.tooltip = { formatter:function() { return this.point.name; } }; break; default: @@ -64,9 +108,13 @@ $(function() { tab.find('.tabInnerContent').html('
'); //alert(tab.find('.tabInnerContent #'+tab.attr('id')+'_chart_cnt').length); initChart(settings); + $(this).html(PMA_messages['strStaticData']); + $('.statuslinks a:nth-child(1)').hide(); } else { tab.find('.tabInnerContent').html(tabCache[tab.attr('id')]); tabStatus[tab.attr('id')]='data'; + $(this).html(PMA_messages['strRealtimeChart']); + $('.statuslinks a:nth-child(1)').show(); } return false; }); @@ -194,68 +242,22 @@ $(function() { }); } - function initChart(settings) { - if(settings.differentialData == undefined) - settings.differentialData = false; - if(settings.seriesType == undefined) - settings.seriesType = 'spline'; - if(settings.numPoints == undefined) - settings.numPoints=30; - - var numLoadedPoints=0; - - chart = new Highcharts.Chart({ + function initChart(passedSettings) { + var settings = { chart: { - renderTo: settings.container, - defaultSeriesType: settings.seriesType, + defaultSeriesType: 'spline', marginRight: 10, - events: { - load: function() { - var thisChart = this; - // set up the updating of the chart each second - var lastValue=new Array(); - - var addnewPoint = function() { - // Stop loading data, if the chart has been removed - if($('#'+settings.container).length==0) return; - - $.get('server_status.php?'+url_query,{ajax_request:1, chart_data:1,type:settings.dataType},function(data) { - var splitData = data.split(','); - var x,y; - for(var i=0; i*2<=splitData.length; i++) { - x=parseFloat(splitData[i*2]); - y=parseFloat(splitData[i*2+1]); - - if(settings.differentialData) { - if(lastValue[i]!=undefined && thisChart.series[i]!=undefined) { - thisChart.series[i].addPoint([x,1000*(y-lastValue[i][1])/(x-lastValue[i][0])], true, numLoadedPoints++ >= settings.numPoints); - } - } else thisChart.series[i].addPoint([x,y], true, numLoadedPoints++ >= settings.numPoints); - - lastValue[i] = [x,y]; - } - - setTimeout(addnewPoint, 2000); - }); - } - - addnewPoint(); - } - } }, credits: { enabled:false }, - title: { - text: settings.chartTitle - }, xAxis: { type: 'datetime', tickPixelInterval: 150 }, yAxis: { title: { - text: 'Value' + text: 'Total count' }, plotLines: [{ value: 0, @@ -270,13 +272,56 @@ $(function() { Highcharts.numberFormat(this.y, 2); } }, - legend: { - enabled: false - }, exporting: { enabled: false }, - series: settings.series - }); + series: [] } + + $.extend(true,settings,passedSettings); + + chart = new Highcharts.Chart(settings); + } + + function sortedQueriesPointInfo(queries, lastQueries){ + var max, maxIdx, num=0; + var queryKeys = new Array(); + var queryValues = new Array(); + var sumOther=0; + var sumTotal=0; + + // Separate keys and values, then sort them + $.each(queries.pointInfo, function(key,value) { + if(value-lastQueries.pointInfo[key] > 0) { + queryKeys.push(key); + queryValues.push(value-lastQueries.pointInfo[key]); + sumTotal+=value-lastQueries.pointInfo[key]; + } + }); + var numQueries = queryKeys.length; + var pointInfo = '' + PMA_messages['strTotal'] + ': ' + sumTotal + '
'; + + while(queryKeys.length > 0) { + max=0; + for(var i=0; i max) { + max = queryValues[i]; + maxIdx = i; + } + } + if(numQueries > 8 && num>=6) + sumOther+=queryValues[maxIdx]; + else pointInfo += queryKeys[maxIdx].substr(4).replace('_',' ') + ': ' + queryValues[maxIdx] + '
'; + + queryKeys.splice(maxIdx,1); + queryValues.splice(maxIdx,1); + num++; + } + + if(sumOther>0) + pointInfo += PMA_messages['strOther'] + ': ' + sumOther; + + return pointInfo; + } + }); \ No newline at end of file diff --git a/server_status.php b/server_status.php index 6dc224d6c7..4b470ce20a 100644 --- a/server_status.php +++ b/server_status.php @@ -37,10 +37,15 @@ if (isset($_REQUEST['ajax_request'])) { $num_procs = PMA_DBI_num_rows($result); exit((microtime(true)*1000).','.$num_procs); case 'queries': - $result = PMA_DBI_query('SHOW GLOBAL STATUS LIKE \'Questions\''); - $status = PMA_DBI_fetch_result($result); - // print_r($status); - exit((microtime(true)*1000).','.$status[0]['Value']); + $queries = PMA_DBI_fetch_result('SHOW GLOBAL STATUS WHERE Variable_name LIKE "Com_%" AND Value>0', 0, 1); + cleanDeprecated($queries); + // admin commands are not queries + unset($queries['Com_admin_commands']); + + $sum=array_sum($queries); + + $ret = Array('x'=>(microtime(true)*1000),'y'=>$sum,'pointInfo'=>$queries,'numQueries'=>count($queries)); + exit(json_encode($ret)); } } } @@ -105,22 +110,9 @@ $server_status = PMA_DBI_fetch_result('SHOW GLOBAL STATUS', 0, 1); $server_variables = PMA_DBI_fetch_result('SHOW GLOBAL VARIABLES', 0, 1); /** - * cleanup some deprecated values + * cleanup of some deprecated values */ -$deprecated = array( - 'Com_prepare_sql' => 'Com_stmt_prepare', - 'Com_execute_sql' => 'Com_stmt_execute', - 'Com_dealloc_sql' => 'Com_stmt_close', -); - -foreach ($deprecated as $old => $new) { - if (isset($server_status[$old]) - && isset($server_status[$new])) { - unset($server_status[$old]); - } -} -unset($deprecated); - +cleanDeprecated($server_status); /** * calculate some values @@ -497,10 +489,10 @@ function printQueryStatistics() { - + ø % @@ -1067,6 +1059,24 @@ function createQueryChart($com_vars=FALSE) { return ''; } +/** + * cleanup of some deprecated values + */ +function cleanDeprecated(&$server_status) { + $deprecated = array( + 'Com_prepare_sql' => 'Com_stmt_prepare', + 'Com_execute_sql' => 'Com_stmt_execute', + 'Com_dealloc_sql' => 'Com_stmt_close', + ); + + foreach ($deprecated as $old => $new) { + if (isset($server_status[$old]) + && isset($server_status[$new])) { + unset($server_status[$old]); + } + } +} + /** * Sends the footer */ From 3b6e1926711aecfb2997b685edbb5613d9358c92 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Wed, 1 Jun 2011 18:01:39 +0200 Subject: [PATCH 035/206] - Don't loose "sortability" when switching between realtime and static data - Chart: display 0 as first value --- js/server_status.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/js/server_status.js b/js/server_status.js index da60a373ae..c6ba5fd6a4 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -11,8 +11,7 @@ $(function() { // Time between each refresh var refreshRate=3000; - // Holds the tab contents when realtime charts are being displayed - var tabCache = new Object(); + // Defines what the tabs are currently displaying (realtime or data) var tabStatus = new Object(); // Add tabs @@ -75,13 +74,13 @@ $(function() { chartData.x = parseInt(chartData.x); chartData.y = parseInt(chartData.y); - if(lastValue!=null) { - thisChart.series[0].addPoint({ - x:chartData.x, - y:chartData.y-lastValue.y, - name:sortedQueriesPointInfo(chartData,lastValue) - }, true, numLoadedPoints >= numMaxPoints); - } + if(lastValue==null) lastValue = chartData; + + thisChart.series[0].addPoint({ + x:chartData.x, + y:chartData.y-lastValue.y, + name:sortedQueriesPointInfo(chartData,lastValue) + }, true, numLoadedPoints >= numMaxPoints); lastValue = chartData; numLoadedPoints++; @@ -104,14 +103,16 @@ $(function() { } tabStatus[tab.attr('id')]='realtime'; - tabCache[tab.attr('id')]=tab.find('.tabInnerContent').html(); - tab.find('.tabInnerContent').html('
'); - //alert(tab.find('.tabInnerContent #'+tab.attr('id')+'_chart_cnt').length); + tab.find('.tabInnerContent') + .hide() + .after('
'); + initChart(settings); $(this).html(PMA_messages['strStaticData']); $('.statuslinks a:nth-child(1)').hide(); } else { - tab.find('.tabInnerContent').html(tabCache[tab.attr('id')]); + tab.find('.tabInnerContent').show(); + tab.find('div#'+tab.attr('id')+'_chart_cnt').remove(); tabStatus[tab.attr('id')]='data'; $(this).html(PMA_messages['strRealtimeChart']); $('.statuslinks a:nth-child(1)').show(); From 349a650357bc0adacc139c3d5ffabfb0ad475bbd Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Wed, 1 Jun 2011 18:31:57 +0200 Subject: [PATCH 036/206] clear timeouts properly --- js/server_status.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/js/server_status.js b/js/server_status.js index c6ba5fd6a4..45334aabd4 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -13,6 +13,8 @@ $(function() { // Defines what the tabs are currently displaying (realtime or data) var tabStatus = new Object(); + // active timeouts that refresh the charts + var activeTimeouts = new Object(); // Add tabs $('#serverStatusTabs').tabs({ @@ -63,10 +65,9 @@ $(function() { var otherSum=0; var addnewPoint = function() { - // Stop loading data, if the chart has been removed - if(tabStatus[tab.attr('id')]!='realtime') return; - $.get('server_status.php?'+url_query,{ajax_request:1, chart_data:1, type:'queries'},function(data) { + if(activeTimeouts[tab.attr('id')+"_chart_cnt"]==null) return; + var chartData = jQuery.parseJSON(data); var pointInfo=''; var i=0; @@ -84,10 +85,11 @@ $(function() { lastValue = chartData; numLoadedPoints++; - setTimeout(addnewPoint, refreshRate); + activeTimeouts[tab.attr('id')+"_chart_cnt"] = setTimeout(addnewPoint, refreshRate); }); } - addnewPoint(); + + activeTimeouts[tab.attr('id')+"_chart_cnt"] = setTimeout(addnewPoint, 0); } } }; @@ -101,16 +103,17 @@ $(function() { default: return; } - - tabStatus[tab.attr('id')]='realtime'; + tab.find('.tabInnerContent') .hide() .after('
'); - + tabStatus[tab.attr('id')]='realtime'; initChart(settings); $(this).html(PMA_messages['strStaticData']); $('.statuslinks a:nth-child(1)').hide(); } else { + clearTimeout(activeTimeouts[tab.attr('id')+"_chart_cnt"]); + activeTimeouts[tab.attr('id')+"_chart_cnt"]=null; tab.find('.tabInnerContent').show(); tab.find('div#'+tab.attr('id')+'_chart_cnt').remove(); tabStatus[tab.attr('id')]='data'; From 948b85825313818654df7d6c5907f488dbcd8efc Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Wed, 1 Jun 2011 18:34:43 +0200 Subject: [PATCH 037/206] Default refreshrate 3sec => 5sec --- js/server_status.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/server_status.js b/js/server_status.js index 45334aabd4..293a6cb848 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -9,7 +9,7 @@ $(function() { // Amount of points the chart should hold var numMaxPoints=30; // Time between each refresh - var refreshRate=3000; + var refreshRate=5000; // Defines what the tabs are currently displaying (realtime or data) var tabStatus = new Object(); From 207bfd47e30d812126751440dc5ff8d9cb46fb2b Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Thu, 2 Jun 2011 15:22:28 +0200 Subject: [PATCH 038/206] - Fix: Hide refresh button only for current tab - Fix: Tablesorter sorts thousands-seperated values correctly --- js/messages.php | 4 ++++ js/server_status.js | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/js/messages.php b/js/messages.php index 7ffab5fe1b..f2485969b0 100644 --- a/js/messages.php +++ b/js/messages.php @@ -64,6 +64,10 @@ $js_messages['strStaticData'] = __('Static data'); $js_messages['strTotal'] = __('Total'); /* l10n: Other, small valued, queries */ $js_messages['strOther'] = __('Other'); +/* l10n: Thousands separator */ +$js_messages['strThousandsSeperator'] = __(','); +/* l10n: Decimal separator */ +$js_messages['strDecimalSeperator'] = __('.'); /* For inline query editing */ $js_messages['strGo'] = __('Go'); diff --git a/js/server_status.js b/js/server_status.js index 293a6cb848..f052ef5188 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -1,3 +1,26 @@ +$(function() { + jQuery.tablesorter.addParser({ + id: "fancyNumber", + is: function(s) { + return /^[0-9]?[0-9,\.]*\s?(k|M|G|T)?$/.test(s); + }, + format: function(s) { + var num = jQuery.tablesorter.formatFloat( s.replace(PMA_messages['strThousandsSeperator'],'').replace(PMA_messages['strDecimalSeperator'],'.') ); + var factor = 1; + switch (s.charAt(s.length-1)) { + case '%': factor = 0.01; break; + // Todo: Please complete this list + case 'k': factor = 1000; break; + case 'M': factor = 1000*1000; break; + case 'G': factor = 1000*1000*1000; break; + case 'T': factor = 1000*1000*1000*1000; break; + } + return num*factor; + }, + type: "numeric" + }); +}); + $(function() { // Filters for status variables var textFilter=null; @@ -110,7 +133,7 @@ $(function() { tabStatus[tab.attr('id')]='realtime'; initChart(settings); $(this).html(PMA_messages['strStaticData']); - $('.statuslinks a:nth-child(1)').hide(); + tab.find('.statuslinks a:nth-child(1)').hide(); } else { clearTimeout(activeTimeouts[tab.attr('id')+"_chart_cnt"]); activeTimeouts[tab.attr('id')+"_chart_cnt"]=null; @@ -118,7 +141,7 @@ $(function() { tab.find('div#'+tab.attr('id')+'_chart_cnt').remove(); tabStatus[tab.attr('id')]='data'; $(this).html(PMA_messages['strRealtimeChart']); - $('.statuslinks a:nth-child(1)').show(); + tab.find('.statuslinks a:nth-child(1)').show(); } return false; }); @@ -182,7 +205,11 @@ $(function() { case 'statustabs_queries': $('#serverstatusqueriesdetails').tablesorter({ sortList: [[3,1]], - widgets: ['zebra'] + widgets: ['zebra'], + headers: { + 1: { sorter: 'fancyNumber' }, + 2: { sorter: 'fancyNumber' } + } }); $('#serverstatusqueriesdetails tr:first th') @@ -193,7 +220,10 @@ $(function() { case 'statustabs_allvars': $('#serverstatusvariables').tablesorter({ sortList: [[0,0]], - widgets: ['zebra'] + widgets: ['zebra'], + headers: { + 1: { sorter: 'fancyNumber' } + } }); $('#serverstatusvariables tr:first th') @@ -250,7 +280,7 @@ $(function() { var settings = { chart: { defaultSeriesType: 'spline', - marginRight: 10, + marginRight: 10 }, credits: { enabled:false From 9fdbb850bb4bb6e13856d1124f5c360a8c02d892 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Thu, 2 Jun 2011 22:00:42 +0200 Subject: [PATCH 039/206] Proof of concept for svg->canvas->image export of charts --- chart_export.php | 11 + js/canvg/MIT-LICENSE.txt | 22 + js/canvg/canvg.js | 2215 ++++++++++++++++++++++++++++++++++++ js/canvg/rgbcolor.js | 288 +++++ js/highcharts/exporting.js | 1244 ++++++++++---------- js/server_status.js | 4 +- server_status.php | 4 + 7 files changed, 3169 insertions(+), 619 deletions(-) create mode 100644 chart_export.php create mode 100644 js/canvg/MIT-LICENSE.txt create mode 100644 js/canvg/canvg.js create mode 100644 js/canvg/rgbcolor.js diff --git a/chart_export.php b/chart_export.php new file mode 100644 index 0000000000..b31745a764 --- /dev/null +++ b/chart_export.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/js/canvg/MIT-LICENSE.txt b/js/canvg/MIT-LICENSE.txt new file mode 100644 index 0000000000..40f19bd70a --- /dev/null +++ b/js/canvg/MIT-LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2010-2011 Gabe Lerner (gabelerner@gmail.com) - http://code.google.com/p/canvg/ + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/js/canvg/canvg.js b/js/canvg/canvg.js new file mode 100644 index 0000000000..7c49891500 --- /dev/null +++ b/js/canvg/canvg.js @@ -0,0 +1,2215 @@ +/* + * canvg.js - Javascript SVG parser and renderer on Canvas + * MIT Licensed + * Gabe Lerner (gabelerner@gmail.com) + * http://code.google.com/p/canvg/ + * + * Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/ + */ +if(!window.console) { + window.console = {}; + window.console.log = function(str) {}; + window.console.dir = function(str) {}; +} + +// <3 IE +if(!Array.indexOf){ + Array.prototype.indexOf = function(obj){ + for(var i=0; i ignore mouse events + // ignoreAnimation: true => ignore animations + // ignoreDimensions: true => does not try to resize canvas + // ignoreClear: true => does not clear canvas + // offsetX: int => draws at a x offset + // offsetY: int => draws at a y offset + // scaleWidth: int => scales horizontally to width + // scaleHeight: int => scales vertically to height + // renderCallback: function => will call the function after the first render is completed + // forceRedraw: function => will call the function on every frame, if it returns true, will redraw + this.canvg = function (target, s, opts) { + // no parameters + if (target == null && s == null && opts == null) { + var svgTags = document.getElementsByTagName('svg'); + for (var i=0; i]*>/, ''); + var xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); + xmlDoc.async = 'false'; + xmlDoc.loadXML(xml); + return xmlDoc; + } + } + + svg.Property = function(name, value) { + this.name = name; + this.value = value; + + this.hasValue = function() { + return (this.value != null && this.value != ''); + } + + // return the numerical value of the property + this.numValue = function() { + if (!this.hasValue()) return 0; + + var n = parseFloat(this.value); + if ((this.value + '').match(/%$/)) { + n = n / 100.0; + } + return n; + } + + this.valueOrDefault = function(def) { + if (this.hasValue()) return this.value; + return def; + } + + this.numValueOrDefault = function(def) { + if (this.hasValue()) return this.numValue(); + return def; + } + + /* EXTENSIONS */ + var that = this; + + // color extensions + this.Color = { + // augment the current color value with the opacity + addOpacity: function(opacity) { + var newValue = that.value; + if (opacity != null && opacity != '') { + var color = new RGBColor(that.value); + if (color.ok) { + newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacity + ')'; + } + } + return new svg.Property(that.name, newValue); + } + } + + // definition extensions + this.Definition = { + // get the definition from the definitions table + getDefinition: function() { + var name = that.value.replace(/^(url\()?#([^\)]+)\)?$/, '$2'); + return svg.Definitions[name]; + }, + + isUrl: function() { + return that.value.indexOf('url(') == 0 + }, + + getFillStyle: function(e) { + var def = this.getDefinition(); + + // gradient + if (def != null && def.createGradient) { + return def.createGradient(svg.ctx, e); + } + + // pattern + if (def != null && def.createPattern) { + return def.createPattern(svg.ctx, e); + } + + return null; + } + } + + // length extensions + this.Length = { + DPI: function(viewPort) { + return 96.0; // TODO: compute? + }, + + EM: function(viewPort) { + var em = 12; + + var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize); + if (fontSize.hasValue()) em = fontSize.Length.toPixels(viewPort); + + return em; + }, + + // get the length as pixels + toPixels: function(viewPort) { + if (!that.hasValue()) return 0; + var s = that.value+''; + if (s.match(/em$/)) return that.numValue() * this.EM(viewPort); + if (s.match(/ex$/)) return that.numValue() * this.EM(viewPort) / 2.0; + if (s.match(/px$/)) return that.numValue(); + if (s.match(/pt$/)) return that.numValue() * 1.25; + if (s.match(/pc$/)) return that.numValue() * 15; + if (s.match(/cm$/)) return that.numValue() * this.DPI(viewPort) / 2.54; + if (s.match(/mm$/)) return that.numValue() * this.DPI(viewPort) / 25.4; + if (s.match(/in$/)) return that.numValue() * this.DPI(viewPort); + if (s.match(/%$/)) return that.numValue() * svg.ViewPort.ComputeSize(viewPort); + return that.numValue(); + } + } + + // time extensions + this.Time = { + // get the time as milliseconds + toMilliseconds: function() { + if (!that.hasValue()) return 0; + var s = that.value+''; + if (s.match(/s$/)) return that.numValue() * 1000; + if (s.match(/ms$/)) return that.numValue(); + return that.numValue(); + } + } + + // angle extensions + this.Angle = { + // get the angle as radians + toRadians: function() { + if (!that.hasValue()) return 0; + var s = that.value+''; + if (s.match(/deg$/)) return that.numValue() * (Math.PI / 180.0); + if (s.match(/grad$/)) return that.numValue() * (Math.PI / 200.0); + if (s.match(/rad$/)) return that.numValue(); + return that.numValue() * (Math.PI / 180.0); + } + } + } + + // fonts + svg.Font = new (function() { + this.Styles = ['normal','italic','oblique','inherit']; + this.Variants = ['normal','small-caps','inherit']; + this.Weights = ['normal','bold','bolder','lighter','100','200','300','400','500','600','700','800','900','inherit']; + + this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) { + var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font); + return { + fontFamily: fontFamily || f.fontFamily, + fontSize: fontSize || f.fontSize, + fontStyle: fontStyle || f.fontStyle, + fontWeight: fontWeight || f.fontWeight, + fontVariant: fontVariant || f.fontVariant, + toString: function () { return [this.fontStyle, this.fontVariant, this.fontWeight, this.fontSize, this.fontFamily].join(' ') } + } + } + + var that = this; + this.Parse = function(s) { + var f = {}; + var d = svg.trim(svg.compressSpaces(s || '')).split(' '); + var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false } + var ff = ''; + for (var i=0; i this.x2) this.x2 = x; + } + + if (y != null) { + if (isNaN(this.y1) || isNaN(this.y2)) { + this.y1 = y; + this.y2 = y; + } + if (y < this.y1) this.y1 = y; + if (y > this.y2) this.y2 = y; + } + } + this.addX = function(x) { this.addPoint(x, null); } + this.addY = function(y) { this.addPoint(null, y); } + + this.addBoundingBox = function(bb) { + this.addPoint(bb.x1, bb.y1); + this.addPoint(bb.x2, bb.y2); + } + + this.addQuadraticCurve = function(p0x, p0y, p1x, p1y, p2x, p2y) { + var cp1x = p0x + 2/3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0) + var cp1y = p0y + 2/3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0) + var cp2x = cp1x + 1/3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0) + var cp2y = cp1y + 1/3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0) + this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y); + } + + this.addBezierCurve = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) { + // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y]; + this.addPoint(p0[0], p0[1]); + this.addPoint(p3[0], p3[1]); + + for (i=0; i<=1; i++) { + var f = function(t) { + return Math.pow(1-t, 3) * p0[i] + + 3 * Math.pow(1-t, 2) * t * p1[i] + + 3 * (1-t) * Math.pow(t, 2) * p2[i] + + Math.pow(t, 3) * p3[i]; + } + + var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; + var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; + var c = 3 * p1[i] - 3 * p0[i]; + + if (a == 0) { + if (b == 0) continue; + var t = -c / b; + if (0 < t && t < 1) { + if (i == 0) this.addX(f(t)); + if (i == 1) this.addY(f(t)); + } + continue; + } + + var b2ac = Math.pow(b, 2) - 4 * c * a; + if (b2ac < 0) continue; + var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); + if (0 < t1 && t1 < 1) { + if (i == 0) this.addX(f(t1)); + if (i == 1) this.addY(f(t1)); + } + var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); + if (0 < t2 && t2 < 1) { + if (i == 0) this.addX(f(t2)); + if (i == 1) this.addY(f(t2)); + } + } + } + + this.isPointInBox = function(x, y) { + return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2); + } + + this.addPoint(x1, y1); + this.addPoint(x2, y2); + } + + // transforms + svg.Transform = function(v) { + var that = this; + this.Type = {} + + // translate + this.Type.translate = function(s) { + this.p = svg.CreatePoint(s); + this.apply = function(ctx) { + ctx.translate(this.p.x || 0.0, this.p.y || 0.0); + } + this.applyToPoint = function(p) { + p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); + } + } + + // rotate + this.Type.rotate = function(s) { + var a = svg.ToNumberArray(s); + this.angle = new svg.Property('angle', a[0]); + this.cx = a[1] || 0; + this.cy = a[2] || 0; + this.apply = function(ctx) { + ctx.translate(this.cx, this.cy); + ctx.rotate(this.angle.Angle.toRadians()); + ctx.translate(-this.cx, -this.cy); + } + this.applyToPoint = function(p) { + var a = this.angle.Angle.toRadians(); + p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); + p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]); + p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]); + } + } + + this.Type.scale = function(s) { + this.p = svg.CreatePoint(s); + this.apply = function(ctx) { + ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0); + } + this.applyToPoint = function(p) { + p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]); + } + } + + this.Type.matrix = function(s) { + this.m = svg.ToNumberArray(s); + this.apply = function(ctx) { + ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]); + } + this.applyToPoint = function(p) { + p.applyTransform(this.m); + } + } + + this.Type.SkewBase = function(s) { + this.base = that.Type.matrix; + this.base(s); + this.angle = new svg.Property('angle', s); + } + this.Type.SkewBase.prototype = new this.Type.matrix; + + this.Type.skewX = function(s) { + this.base = that.Type.SkewBase; + this.base(s); + this.m = [1, 0, Math.tan(this.angle.Angle.toRadians()), 1, 0, 0]; + } + this.Type.skewX.prototype = new this.Type.SkewBase; + + this.Type.skewY = function(s) { + this.base = that.Type.SkewBase; + this.base(s); + this.m = [1, Math.tan(this.angle.Angle.toRadians()), 0, 1, 0, 0]; + } + this.Type.skewY.prototype = new this.Type.SkewBase; + + this.transforms = []; + + this.apply = function(ctx) { + for (var i=0; i= this.tokens.length - 1; + } + + this.isCommandOrEnd = function() { + if (this.isEnd()) return true; + return this.tokens[this.i + 1].match(/[A-Za-z]/) != null; + } + + this.isRelativeCommand = function() { + return this.command == this.command.toLowerCase(); + } + + this.getToken = function() { + this.i = this.i + 1; + return this.tokens[this.i]; + } + + this.getScalar = function() { + return parseFloat(this.getToken()); + } + + this.nextCommand = function() { + this.previousCommand = this.command; + this.command = this.getToken(); + } + + this.getPoint = function() { + var p = new svg.Point(this.getScalar(), this.getScalar()); + return this.makeAbsolute(p); + } + + this.getAsControlPoint = function() { + var p = this.getPoint(); + this.control = p; + return p; + } + + this.getAsCurrentPoint = function() { + var p = this.getPoint(); + this.current = p; + return p; + } + + this.getReflectedControlPoint = function() { + if (this.previousCommand.toLowerCase() != 'c' && this.previousCommand.toLowerCase() != 's') { + return this.current; + } + + // reflect point + var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y); + return p; + } + + this.makeAbsolute = function(p) { + if (this.isRelativeCommand()) { + p.x = this.current.x + p.x; + p.y = this.current.y + p.y; + } + return p; + } + + this.addMarker = function(p, from) { + this.addMarkerAngle(p, from == null ? null : from.angleTo(p)); + } + + this.addMarkerAngle = function(p, a) { + this.points.push(p); + this.angles.push(a); + } + + this.getMarkerPoints = function() { return this.points; } + this.getMarkerAngles = function() { + for (var i=0; i 1) { + rx *= Math.sqrt(l); + ry *= Math.sqrt(l); + } + // cx', cy' + var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt( + ((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) / + (Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2)) + ); + if (isNaN(s)) s = 0; + var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx); + // cx, cy + var centp = new svg.Point( + (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y, + (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y + ); + // vector magnitude + var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); } + // ratio between two vectors + var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) } + // angle between two vectors + var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); } + // initial angle + var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]); + // angle delta + var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]; + var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry]; + var ad = a(u, v); + if (r(u,v) <= -1) ad = Math.PI; + if (r(u,v) >= 1) ad = 0; + + if (sweepFlag == 0 && ad > 0) ad = ad - 2 * Math.PI; + if (sweepFlag == 1 && ad < 0) ad = ad + 2 * Math.PI; + + // for markers + var halfWay = new svg.Point( + centp.x - rx * Math.cos((a1 + ad) / 2), + centp.y - ry * Math.sin((a1 + ad) / 2) + ); + pp.addMarkerAngle(halfWay, (a1 + ad) / 2 + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); + pp.addMarkerAngle(cp, ad + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); + + bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better + if (ctx != null) { + var r = rx > ry ? rx : ry; + var sx = rx > ry ? 1 : rx / ry; + var sy = rx > ry ? ry / rx : 1; + + ctx.translate(centp.x, centp.y); + ctx.rotate(xAxisRotation); + ctx.scale(sx, sy); + ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag); + ctx.scale(1/sx, 1/sy); + ctx.rotate(-xAxisRotation); + ctx.translate(-centp.x, -centp.y); + } + } + break; + case 'Z': + if (ctx != null) ctx.closePath(); + pp.current = pp.start; + } + } + + return bb; + } + + this.getMarkers = function() { + var points = this.PathParser.getMarkerPoints(); + var angles = this.PathParser.getMarkerAngles(); + + var markers = []; + for (var i=0; i this.maxDuration) { + // loop for indefinitely repeating animations + if (this.attribute('repeatCount').value == 'indefinite') { + this.duration = 0.0 + } + else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) { + this.removed = true; + this.getProperty().value = this.initialValue; + return true; + } + else { + return false; // no updates made + } + } + this.duration = this.duration + delta; + + // if we're past the begin time + var updated = false; + if (this.begin < this.duration) { + var newValue = this.calcValue(); // tween + + if (this.attribute('type').hasValue()) { + // for transform, etc. + var type = this.attribute('type').value; + newValue = type + '(' + newValue + ')'; + } + + this.getProperty().value = newValue; + updated = true; + } + + return updated; + } + + // fraction of duration we've covered + this.progress = function() { + return ((this.duration - this.begin) / (this.maxDuration - this.begin)); + } + } + svg.Element.AnimateBase.prototype = new svg.Element.ElementBase; + + // animate element + svg.Element.animate = function(node) { + this.base = svg.Element.AnimateBase; + this.base(node); + + this.calcValue = function() { + var from = this.attribute('from').numValue(); + var to = this.attribute('to').numValue(); + + // tween value linearly + return from + (to - from) * this.progress(); + }; + } + svg.Element.animate.prototype = new svg.Element.AnimateBase; + + // animate color element + svg.Element.animateColor = function(node) { + this.base = svg.Element.AnimateBase; + this.base(node); + + this.calcValue = function() { + var from = new RGBColor(this.attribute('from').value); + var to = new RGBColor(this.attribute('to').value); + + if (from.ok && to.ok) { + // tween color linearly + var r = from.r + (to.r - from.r) * this.progress(); + var g = from.g + (to.g - from.g) * this.progress(); + var b = from.b + (to.b - from.b) * this.progress(); + return 'rgb('+parseInt(r,10)+','+parseInt(g,10)+','+parseInt(b,10)+')'; + } + return this.attribute('from').value; + }; + } + svg.Element.animateColor.prototype = new svg.Element.AnimateBase; + + // animate transform element + svg.Element.animateTransform = function(node) { + this.base = svg.Element.animate; + this.base(node); + } + svg.Element.animateTransform.prototype = new svg.Element.animate; + + // text element + svg.Element.text = function(node) { + this.base = svg.Element.RenderedElementBase; + this.base(node); + + if (node != null) { + // add children + this.children = []; + for (var i=0; i + * @link http://www.phpied.com/rgb-color-parser-in-javascript/ + * @license Use it if you like it + */ +function RGBColor(color_string) +{ + this.ok = false; + + // strip any leading # + if (color_string.charAt(0) == '#') { // remove # if any + color_string = color_string.substr(1,6); + } + + color_string = color_string.replace(/ /g,''); + color_string = color_string.toLowerCase(); + + // before getting into regexps, try simple matches + // and overwrite the input + var simple_colors = { + aliceblue: 'f0f8ff', + antiquewhite: 'faebd7', + aqua: '00ffff', + aquamarine: '7fffd4', + azure: 'f0ffff', + beige: 'f5f5dc', + bisque: 'ffe4c4', + black: '000000', + blanchedalmond: 'ffebcd', + blue: '0000ff', + blueviolet: '8a2be2', + brown: 'a52a2a', + burlywood: 'deb887', + cadetblue: '5f9ea0', + chartreuse: '7fff00', + chocolate: 'd2691e', + coral: 'ff7f50', + cornflowerblue: '6495ed', + cornsilk: 'fff8dc', + crimson: 'dc143c', + cyan: '00ffff', + darkblue: '00008b', + darkcyan: '008b8b', + darkgoldenrod: 'b8860b', + darkgray: 'a9a9a9', + darkgreen: '006400', + darkkhaki: 'bdb76b', + darkmagenta: '8b008b', + darkolivegreen: '556b2f', + darkorange: 'ff8c00', + darkorchid: '9932cc', + darkred: '8b0000', + darksalmon: 'e9967a', + darkseagreen: '8fbc8f', + darkslateblue: '483d8b', + darkslategray: '2f4f4f', + darkturquoise: '00ced1', + darkviolet: '9400d3', + deeppink: 'ff1493', + deepskyblue: '00bfff', + dimgray: '696969', + dodgerblue: '1e90ff', + feldspar: 'd19275', + firebrick: 'b22222', + floralwhite: 'fffaf0', + forestgreen: '228b22', + fuchsia: 'ff00ff', + gainsboro: 'dcdcdc', + ghostwhite: 'f8f8ff', + gold: 'ffd700', + goldenrod: 'daa520', + gray: '808080', + green: '008000', + greenyellow: 'adff2f', + honeydew: 'f0fff0', + hotpink: 'ff69b4', + indianred : 'cd5c5c', + indigo : '4b0082', + ivory: 'fffff0', + khaki: 'f0e68c', + lavender: 'e6e6fa', + lavenderblush: 'fff0f5', + lawngreen: '7cfc00', + lemonchiffon: 'fffacd', + lightblue: 'add8e6', + lightcoral: 'f08080', + lightcyan: 'e0ffff', + lightgoldenrodyellow: 'fafad2', + lightgrey: 'd3d3d3', + lightgreen: '90ee90', + lightpink: 'ffb6c1', + lightsalmon: 'ffa07a', + lightseagreen: '20b2aa', + lightskyblue: '87cefa', + lightslateblue: '8470ff', + lightslategray: '778899', + lightsteelblue: 'b0c4de', + lightyellow: 'ffffe0', + lime: '00ff00', + limegreen: '32cd32', + linen: 'faf0e6', + magenta: 'ff00ff', + maroon: '800000', + mediumaquamarine: '66cdaa', + mediumblue: '0000cd', + mediumorchid: 'ba55d3', + mediumpurple: '9370d8', + mediumseagreen: '3cb371', + mediumslateblue: '7b68ee', + mediumspringgreen: '00fa9a', + mediumturquoise: '48d1cc', + mediumvioletred: 'c71585', + midnightblue: '191970', + mintcream: 'f5fffa', + mistyrose: 'ffe4e1', + moccasin: 'ffe4b5', + navajowhite: 'ffdead', + navy: '000080', + oldlace: 'fdf5e6', + olive: '808000', + olivedrab: '6b8e23', + orange: 'ffa500', + orangered: 'ff4500', + orchid: 'da70d6', + palegoldenrod: 'eee8aa', + palegreen: '98fb98', + paleturquoise: 'afeeee', + palevioletred: 'd87093', + papayawhip: 'ffefd5', + peachpuff: 'ffdab9', + peru: 'cd853f', + pink: 'ffc0cb', + plum: 'dda0dd', + powderblue: 'b0e0e6', + purple: '800080', + red: 'ff0000', + rosybrown: 'bc8f8f', + royalblue: '4169e1', + saddlebrown: '8b4513', + salmon: 'fa8072', + sandybrown: 'f4a460', + seagreen: '2e8b57', + seashell: 'fff5ee', + sienna: 'a0522d', + silver: 'c0c0c0', + skyblue: '87ceeb', + slateblue: '6a5acd', + slategray: '708090', + snow: 'fffafa', + springgreen: '00ff7f', + steelblue: '4682b4', + tan: 'd2b48c', + teal: '008080', + thistle: 'd8bfd8', + tomato: 'ff6347', + turquoise: '40e0d0', + violet: 'ee82ee', + violetred: 'd02090', + wheat: 'f5deb3', + white: 'ffffff', + whitesmoke: 'f5f5f5', + yellow: 'ffff00', + yellowgreen: '9acd32' + }; + for (var key in simple_colors) { + if (color_string == key) { + color_string = simple_colors[key]; + } + } + // emd of simple type-in colors + + // array of color definition objects + var color_defs = [ + { + re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, + example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], + process: function (bits){ + return [ + parseInt(bits[1]), + parseInt(bits[2]), + parseInt(bits[3]) + ]; + } + }, + { + re: /^(\w{2})(\w{2})(\w{2})$/, + example: ['#00ff00', '336699'], + process: function (bits){ + return [ + parseInt(bits[1], 16), + parseInt(bits[2], 16), + parseInt(bits[3], 16) + ]; + } + }, + { + re: /^(\w{1})(\w{1})(\w{1})$/, + example: ['#fb0', 'f0f'], + process: function (bits){ + return [ + parseInt(bits[1] + bits[1], 16), + parseInt(bits[2] + bits[2], 16), + parseInt(bits[3] + bits[3], 16) + ]; + } + } + ]; + + // search through the definitions to find a match + for (var i = 0; i < color_defs.length; i++) { + var re = color_defs[i].re; + var processor = color_defs[i].process; + var bits = re.exec(color_string); + if (bits) { + channels = processor(bits); + this.r = channels[0]; + this.g = channels[1]; + this.b = channels[2]; + this.ok = true; + } + + } + + // validate/cleanup values + this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); + this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); + this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); + + // some getters + this.toRGB = function () { + return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; + } + this.toHex = function () { + var r = this.r.toString(16); + var g = this.g.toString(16); + var b = this.b.toString(16); + if (r.length == 1) r = '0' + r; + if (g.length == 1) g = '0' + g; + if (b.length == 1) b = '0' + b; + return '#' + r + g + b; + } + + // help + this.getHelpXML = function () { + + var examples = new Array(); + // add regexps + for (var i = 0; i < color_defs.length; i++) { + var example = color_defs[i].example; + for (var j = 0; j < example.length; j++) { + examples[examples.length] = example[j]; + } + } + // add type-in colors + for (var sc in simple_colors) { + examples[examples.length] = sc; + } + + var xml = document.createElement('ul'); + xml.setAttribute('id', 'rgbcolor-examples'); + for (var i = 0; i < examples.length; i++) { + try { + var list_item = document.createElement('li'); + var list_color = new RGBColor(examples[i]); + var example_div = document.createElement('div'); + example_div.style.cssText = + 'margin: 3px; ' + + 'border: 1px solid black; ' + + 'background:' + list_color.toHex() + '; ' + + 'color:' + list_color.toHex() + ; + example_div.appendChild(document.createTextNode('test')); + var list_item_value = document.createTextNode( + ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() + ); + list_item.appendChild(example_div); + list_item.appendChild(list_item_value); + xml.appendChild(list_item); + + } catch(e){} + } + return xml; + + } + +} + diff --git a/js/highcharts/exporting.js b/js/highcharts/exporting.js index 4577f67a9a..ab4e718f3f 100644 --- a/js/highcharts/exporting.js +++ b/js/highcharts/exporting.js @@ -14,659 +14,669 @@ // create shortcuts var HC = Highcharts, - Chart = HC.Chart, - addEvent = HC.addEvent, - createElement = HC.createElement, - discardElement = HC.discardElement, - css = HC.css, - merge = HC.merge, - each = HC.each, - extend = HC.extend, - math = Math, - mathMax = math.max, - doc = document, - win = window, - hasTouch = 'ontouchstart' in doc.documentElement, - M = 'M', - L = 'L', - DIV = 'div', - HIDDEN = 'hidden', - NONE = 'none', - PREFIX = 'highcharts-', - ABSOLUTE = 'absolute', - PX = 'px', + Chart = HC.Chart, + addEvent = HC.addEvent, + createElement = HC.createElement, + discardElement = HC.discardElement, + css = HC.css, + merge = HC.merge, + each = HC.each, + extend = HC.extend, + math = Math, + mathMax = math.max, + doc = document, + win = window, + hasTouch = 'ontouchstart' in doc.documentElement, + M = 'M', + L = 'L', + DIV = 'div', + HIDDEN = 'hidden', + NONE = 'none', + PREFIX = 'highcharts-', + ABSOLUTE = 'absolute', + PX = 'px', - // Add language and get the defaultOptions - defaultOptions = HC.setOptions({ - lang: { - downloadPNG: 'Download PNG image', - downloadJPEG: 'Download JPEG image', - downloadPDF: 'Download PDF document', - downloadSVG: 'Download SVG vector image', - exportButtonTitle: 'Export to raster or vector image', - printButtonTitle: 'Print the chart' - } - }); + // Add language and get the defaultOptions + defaultOptions = HC.setOptions({ + lang: { + downloadPNG: 'Download PNG image', + downloadJPEG: 'Download JPEG image', + downloadPDF: 'Download PDF document', + downloadSVG: 'Download SVG vector image', + exportButtonTitle: 'Export to raster or vector image', + printButtonTitle: 'Print the chart' + } + }); // Buttons and menus are collected in a separate config option set called 'navigation'. // This can be extended later to add control buttons like zoom and pan right click menus. defaultOptions.navigation = { - menuStyle: { - border: '1px solid #A0A0A0', - background: '#FFFFFF' - }, - menuItemStyle: { - padding: '0 5px', - background: NONE, - color: '#303030', - fontSize: hasTouch ? '14px' : '11px' - }, - menuItemHoverStyle: { - background: '#4572A5', - color: '#FFFFFF' - }, - - buttonOptions: { - align: 'right', - backgroundColor: { - linearGradient: [0, 0, 0, 20], - stops: [ - [0.4, '#F7F7F7'], - [0.6, '#E3E3E3'] - ] - }, - borderColor: '#B0B0B0', - borderRadius: 3, - borderWidth: 1, - //enabled: true, - height: 20, - hoverBorderColor: '#909090', - hoverSymbolFill: '#81A7CF', - hoverSymbolStroke: '#4572A5', - symbolFill: '#E0E0E0', - //symbolSize: 12, - symbolStroke: '#A0A0A0', - //symbolStrokeWidth: 1, - symbolX: 11.5, - symbolY: 10.5, - verticalAlign: 'top', - width: 24, - y: 10 - } + menuStyle: { + border: '1px solid #A0A0A0', + background: '#FFFFFF' + }, + menuItemStyle: { + padding: '0 5px', + background: NONE, + color: '#303030', + fontSize: hasTouch ? '14px' : '11px' + }, + menuItemHoverStyle: { + background: '#4572A5', + color: '#FFFFFF' + }, + + buttonOptions: { + align: 'right', + backgroundColor: { + linearGradient: [0, 0, 0, 20], + stops: [ + [0.4, '#F7F7F7'], + [0.6, '#E3E3E3'] + ] + }, + borderColor: '#B0B0B0', + borderRadius: 3, + borderWidth: 1, + //enabled: true, + height: 20, + hoverBorderColor: '#909090', + hoverSymbolFill: '#81A7CF', + hoverSymbolStroke: '#4572A5', + symbolFill: '#E0E0E0', + //symbolSize: 12, + symbolStroke: '#A0A0A0', + //symbolStrokeWidth: 1, + symbolX: 11.5, + symbolY: 10.5, + verticalAlign: 'top', + width: 24, + y: 10 + } }; // Add the export related options defaultOptions.exporting = { - //enabled: true, - //filename: 'chart', - type: 'image/png', - url: 'http://export.highcharts.com/', - width: 800, - buttons: { - exportButton: { - //enabled: true, - symbol: 'exportIcon', - x: -10, - symbolFill: '#A8BF77', - hoverSymbolFill: '#768F3E', - _titleKey: 'exportButtonTitle', - menuItems: [{ - textKey: 'downloadPNG', - onclick: function() { - this.exportChart(); - } - }, { - textKey: 'downloadJPEG', - onclick: function() { - this.exportChart({ - type: 'image/jpeg' - }); - } - }, { - textKey: 'downloadPDF', - onclick: function() { - this.exportChart({ - type: 'application/pdf' - }); - } - }, { - textKey: 'downloadSVG', - onclick: function() { - this.exportChart({ - type: 'image/svg+xml' - }); - } - }/*, { - text: 'View SVG', - onclick: function() { - var svg = this.getSVG() - .replace(//g, '>'); - - doc.body.innerHTML = '
'+ svg +'
'; - } - }*/] - - }, - printButton: { - //enabled: true, - symbol: 'printIcon', - x: -36, - symbolFill: '#B5C9DF', - hoverSymbolFill: '#779ABF', - _titleKey: 'printButtonTitle', - onclick: function() { - this.print(); - } - } - } + //enabled: true, + //filename: 'chart', + type: 'image/png', + url: 'chart_export.php', + width: 800, + buttons: { + exportButton: { + //enabled: true, + symbol: 'exportIcon', + x: -10, + symbolFill: '#A8BF77', + hoverSymbolFill: '#768F3E', + _titleKey: 'exportButtonTitle', + menuItems: [{ + textKey: 'downloadPNG', + onclick: function() { + this.exportChart(); + } + }, { + textKey: 'downloadJPEG', + onclick: function() { + this.exportChart({ + type: 'image/jpeg' + }); + } + }, { + textKey: 'downloadPDF', + onclick: function() { + this.exportChart({ + type: 'application/pdf' + }); + } + }, { + textKey: 'downloadSVG', + onclick: function() { + this.exportChart({ + type: 'image/svg+xml' + }); + } + }/*, { + text: 'View SVG', + onclick: function() { + var svg = this.getSVG() + .replace(//g, '>'); + + doc.body.innerHTML = '
'+ svg +'
'; + } + }*/] + + }, + printButton: { + //enabled: true, + symbol: 'printIcon', + x: -36, + symbolFill: '#B5C9DF', + hoverSymbolFill: '#779ABF', + _titleKey: 'printButtonTitle', + onclick: function() { + this.print(); + } + } + } }; extend(Chart.prototype, { - /** - * Return an SVG representation of the chart - * - * @param additionalOptions {Object} Additional chart options for the generated SVG representation - */ - getSVG: function(additionalOptions) { - var chart = this, - chartCopy, - sandbox, - svg, - seriesOptions, - config, - pointOptions, - pointMarker, - options = merge(chart.options, additionalOptions); // copy the options and add extra options - - // IE compatibility hack for generating SVG content that it doesn't really understand - if (!doc.createElementNS) { - doc.createElementNS = function(ns, tagName) { - var elem = doc.createElement(tagName); - elem.getBBox = function() { - return chart.renderer.Element.prototype.getBBox.apply({ element: elem }); - }; - return elem; - }; - } - - // create a sandbox where a new chart will be generated - sandbox = createElement(DIV, null, { - position: ABSOLUTE, - top: '-9999em', - width: chart.chartWidth + PX, - height: chart.chartHeight + PX - }, doc.body); - - // override some options - extend(options.chart, { - renderTo: sandbox, - forExport: true - }); - options.exporting.enabled = false; // hide buttons in print - options.chart.plotBackgroundImage = null; // the converter doesn't handle images - // prepare for replicating the chart - options.series = []; - each(chart.series, function(serie) { - seriesOptions = serie.options; - - seriesOptions.animation = false; // turn off animation - seriesOptions.showCheckbox = false; - - // remove image markers - if (seriesOptions && seriesOptions.marker && /^url\(/.test(seriesOptions.marker.symbol)) { - seriesOptions.marker.symbol = 'circle'; - } - - seriesOptions.data = []; - - each(serie.data, function(point) { - - // extend the options by those values that can be expressed in a number or array config - config = point.config; - pointOptions = { - x: point.x, - y: point.y, - name: point.name - }; + /** + * Return an SVG representation of the chart + * + * @param additionalOptions {Object} Additional chart options for the generated SVG representation + */ + getSVG: function(additionalOptions) { + var chart = this, + chartCopy, + sandbox, + svg, + seriesOptions, + config, + pointOptions, + pointMarker, + options = merge(chart.options, additionalOptions); // copy the options and add extra options + + // IE compatibility hack for generating SVG content that it doesn't really understand + if (!doc.createElementNS) { + doc.createElementNS = function(ns, tagName) { + var elem = doc.createElement(tagName); + elem.getBBox = function() { + return chart.renderer.Element.prototype.getBBox.apply({ element: elem }); + }; + return elem; + }; + } + + // create a sandbox where a new chart will be generated + sandbox = createElement(DIV, null, { + position: ABSOLUTE, + top: '-9999em', + width: chart.chartWidth + PX, + height: chart.chartHeight + PX + }, doc.body); + + // override some options + extend(options.chart, { + renderTo: sandbox, + forExport: true + }); + options.exporting.enabled = false; // hide buttons in print + options.chart.plotBackgroundImage = null; // the converter doesn't handle images + // prepare for replicating the chart + options.series = []; + each(chart.series, function(serie) { + seriesOptions = serie.options; + + seriesOptions.animation = false; // turn off animation + seriesOptions.showCheckbox = false; + + // remove image markers + if (seriesOptions && seriesOptions.marker && /^url\(/.test(seriesOptions.marker.symbol)) { + seriesOptions.marker.symbol = 'circle'; + } + + seriesOptions.data = []; + + each(serie.data, function(point) { + + // extend the options by those values that can be expressed in a number or array config + config = point.config; + pointOptions = { + x: point.x, + y: point.y, + name: point.name + }; - if (typeof config == 'object' && point.config && config.constructor != Array) { - extend(pointOptions, config); - } + if (typeof config == 'object' && point.config && config.constructor != Array) { + extend(pointOptions, config); + } - seriesOptions.data.push(pointOptions); // copy fresh updated data - - // remove image markers - pointMarker = point.config && point.config.marker; - if (pointMarker && /^url\(/.test(pointMarker.symbol)) { - delete pointMarker.symbol; - } - }); - - options.series.push(seriesOptions); - }); - - // generate the chart copy - chartCopy = new Highcharts.Chart(options); - - // get the SVG from the container's innerHTML - svg = chartCopy.container.innerHTML; - - // free up memory - options = null; - chartCopy.destroy(); - discardElement(sandbox); - - // sanitize - svg = svg - .replace(/zIndex="[^"]+"/g, '') - .replace(/isShadow="[^"]+"/g, '') - .replace(/symbolName="[^"]+"/g, '') - .replace(/jQuery[0-9]+="[^"]+"/g, '') - .replace(/isTracker="[^"]+"/g, '') - .replace(/url\([^#]+#/g, 'url(#') - /*.replace(/')*/ - /* This fails in IE < 8 - .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight - return s2 +'.'+ s3[0]; - })*/ - - // IE specific - .replace(/id=([^" >]+)/g, 'id="$1"') - .replace(/class=([^" ]+)/g, 'class="$1"') - .replace(/ transform /g, ' ') - .replace(/:(path|rect)/g, '$1') - .replace(/style="([^"]+)"/g, function(s) { - return s.toLowerCase(); - }); - - // IE9 beta bugs with innerHTML. Test again with final IE9. - svg = svg.replace(/(url\(#highcharts-[0-9]+)"/g, '$1') - .replace(/"/g, "'"); - if (svg.match(/ xmlns="/g).length == 2) { - svg = svg.replace(/xmlns="[^"]+"/, ''); - } - - return svg; - }, - - /** - * Submit the SVG representation of the chart to the server - * @param {Object} options Exporting options. Possible members are url, type and width. - * @param {Object} chartOptions Additional chart options for the SVG representation of the chart - */ - exportChart: function(options, chartOptions) { - var form, - chart = this, - svg = chart.getSVG(chartOptions); - - // merge the options - options = merge(chart.options.exporting, options); - - // create the form - form = createElement('form', { - method: 'post', - action: options.url - }, { - display: NONE - }, doc.body); - - // add the values - each(['filename', 'type', 'width', 'svg'], function(name) { - createElement('input', { - type: HIDDEN, - name: name, - value: { - filename: options.filename || 'chart', - type: options.type, - width: options.width, - svg: svg - }[name] - }, null, form); - }); - - // submit - form.submit(); - - // clean up - discardElement(form); - }, - - /** - * Print the chart - */ - print: function() { - - var chart = this, - container = chart.container, - origDisplay = [], - origParent = container.parentNode, - body = doc.body, - childNodes = body.childNodes; - - if (chart.isPrinting) { // block the button while in printing mode - return; - } - - chart.isPrinting = true; - - // hide all body content - each(childNodes, function(node, i) { - if (node.nodeType == 1) { - origDisplay[i] = node.style.display; - node.style.display = NONE; - } - }); - - // pull out the chart - body.appendChild(container); - - // print - win.print(); - - // allow the browser to prepare before reverting - setTimeout(function() { + seriesOptions.data.push(pointOptions); // copy fresh updated data + + // remove image markers + pointMarker = point.config && point.config.marker; + if (pointMarker && /^url\(/.test(pointMarker.symbol)) { + delete pointMarker.symbol; + } + }); + + options.series.push(seriesOptions); + }); + + // generate the chart copy + chartCopy = new Highcharts.Chart(options); + + // get the SVG from the container's innerHTML + svg = chartCopy.container.innerHTML; + + // free up memory + options = null; + chartCopy.destroy(); + discardElement(sandbox); + + // sanitize + svg = svg + .replace(/zIndex="[^"]+"/g, '') + .replace(/isShadow="[^"]+"/g, '') + .replace(/symbolName="[^"]+"/g, '') + .replace(/jQuery[0-9]+="[^"]+"/g, '') + .replace(/isTracker="[^"]+"/g, '') + .replace(/url\([^#]+#/g, 'url(#') + /*.replace(/')*/ + /* This fails in IE < 8 + .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight + return s2 +'.'+ s3[0]; + })*/ + + // IE specific + .replace(/id=([^" >]+)/g, 'id="$1"') + .replace(/class=([^" ]+)/g, 'class="$1"') + .replace(/ transform /g, ' ') + .replace(/:(path|rect)/g, '$1') + .replace(/style="([^"]+)"/g, function(s) { + return s.toLowerCase(); + }); + + // IE9 beta bugs with innerHTML. Test again with final IE9. + svg = svg.replace(/(url\(#highcharts-[0-9]+)"/g, '$1') + .replace(/"/g, "'"); + if (svg.match(/ xmlns="/g).length == 2) { + svg = svg.replace(/xmlns="[^"]+"/, ''); + } + + return svg; + }, + + /** + * Submit the SVG representation of the chart to the server + * @param {Object} options Exporting options. Possible members are url, type and width. + * @param {Object} chartOptions Additional chart options for the SVG representation of the chart + */ + exportChart: function(options, chartOptions) { + var form, + chart = this, + canvas=createElement('canvas'); + + $('body').append(canvas); + $(canvas).hide(); + + // Generate data uri and submit once done + canvg(canvas, chart.getSVG(chartOptions),{ + ignoreAnimation:true, + ignoreMouse:true, + renderCallback:function() { + // merge the options + options = merge(chart.options.exporting, options); + + // create the form + form = createElement('form', { + method: 'post', + action: options.url + }, { + display: NONE + }, doc.body); + + // add the values + each(['filename', 'type', 'width', 'image'], function(name) { + createElement('input', { + type: HIDDEN, + name: name, + value: { + filename: options.filename || 'chart', + type: options.type, + width: options.width, + image: canvas.toDataURL() + }[name] + }, null, form); + }); + + // submit + form.submit(); + + // clean up + discardElement(form); + } + }); + }, + + /** + * Print the chart + */ + print: function() { + + var chart = this, + container = chart.container, + origDisplay = [], + origParent = container.parentNode, + body = doc.body, + childNodes = body.childNodes; + + if (chart.isPrinting) { // block the button while in printing mode + return; + } + + chart.isPrinting = true; + + // hide all body content + each(childNodes, function(node, i) { + if (node.nodeType == 1) { + origDisplay[i] = node.style.display; + node.style.display = NONE; + } + }); + + // pull out the chart + body.appendChild(container); + + // print + win.print(); + + // allow the browser to prepare before reverting + setTimeout(function() { - // put the chart back in - origParent.appendChild(container); - - // restore all body content - each(childNodes, function(node, i) { - if (node.nodeType == 1) { - node.style.display = origDisplay[i]; - } - }); - - chart.isPrinting = false; - - }, 1000); + // put the chart back in + origParent.appendChild(container); + + // restore all body content + each(childNodes, function(node, i) { + if (node.nodeType == 1) { + node.style.display = origDisplay[i]; + } + }); + + chart.isPrinting = false; + + }, 1000); - }, - - /** - * Display a popup menu for choosing the export type - * - * @param {String} name An identifier for the menu - * @param {Array} items A collection with text and onclicks for the items - * @param {Number} x The x position of the opener button - * @param {Number} y The y position of the opener button - * @param {Number} width The width of the opener button - * @param {Number} height The height of the opener button - */ - contextMenu: function(name, items, x, y, width, height) { - var chart = this, - navOptions = chart.options.navigation, - menuItemStyle = navOptions.menuItemStyle, - chartWidth = chart.chartWidth, - chartHeight = chart.chartHeight, - cacheName = 'cache-'+ name, - menu = chart[cacheName], - menuPadding = mathMax(width, height), // for mouse leave detection - boxShadow = '3px 3px 10px #888', - innerMenu, - hide, - menuStyle; - - // create the menu only the first time - if (!menu) { - - // create a HTML element above the SVG - chart[cacheName] = menu = createElement(DIV, { - className: PREFIX + name - }, { - position: ABSOLUTE, - zIndex: 1000, - padding: menuPadding + PX - }, chart.container); - - innerMenu = createElement(DIV, null, - extend({ - MozBoxShadow: boxShadow, - WebkitBoxShadow: boxShadow, - boxShadow: boxShadow - }, navOptions.menuStyle) , menu); - - // hide on mouse out - hide = function() { - css(menu, { display: NONE }); - }; - - addEvent(menu, 'mouseleave', hide); - - - // create the items - each(items, function(item) { - if (item) { - var div = createElement(DIV, { - onmouseover: function() { - css(this, navOptions.menuItemHoverStyle); - }, - onmouseout: function() { - css(this, menuItemStyle); - }, - innerHTML: item.text || HC.getOptions().lang[item.textKey] - }, extend({ - cursor: 'pointer' - }, menuItemStyle), innerMenu); - - div[hasTouch ? 'ontouchstart' : 'onclick'] = function() { - hide(); - item.onclick.apply(chart, arguments); - }; - - } - }); - - chart.exportMenuWidth = menu.offsetWidth; - chart.exportMenuHeight = menu.offsetHeight; - } - - menuStyle = { display: 'block' }; - - // if outside right, right align it - if (x + chart.exportMenuWidth > chartWidth) { - menuStyle.right = (chartWidth - x - width - menuPadding) + PX; - } else { - menuStyle.left = (x - menuPadding) + PX; - } - // if outside bottom, bottom align it - if (y + height + chart.exportMenuHeight > chartHeight) { - menuStyle.bottom = (chartHeight - y - menuPadding) + PX; - } else { - menuStyle.top = (y + height - menuPadding) + PX; - } - - css(menu, menuStyle); - }, - - /** - * Add the export button to the chart - */ - addButton: function(options) { - var chart = this, - renderer = chart.renderer, - btnOptions = merge(chart.options.navigation.buttonOptions, options), - onclick = btnOptions.onclick, - menuItems = btnOptions.menuItems, - /*position = chart.getAlignment(btnOptions), - buttonLeft = position.x, - buttonTop = position.y,*/ - buttonWidth = btnOptions.width, - buttonHeight = btnOptions.height, - box, - symbol, - button, - borderWidth = btnOptions.borderWidth, - boxAttr = { - stroke: btnOptions.borderColor - - }, - symbolAttr = { - stroke: btnOptions.symbolStroke, - fill: btnOptions.symbolFill - }; - - if (btnOptions.enabled === false) { - return; - } - - // element to capture the click - function revert() { - symbol.attr(symbolAttr); - box.attr(boxAttr); - } - - // the box border - box = renderer.rect( - 0, - 0, - buttonWidth, - buttonHeight, - btnOptions.borderRadius, - borderWidth - ) - //.translate(buttonLeft, buttonTop) // to allow gradients - .align(btnOptions, true) - .attr(extend({ - fill: btnOptions.backgroundColor, - 'stroke-width': borderWidth, - zIndex: 19 - }, boxAttr)).add(); - - // the invisible element to track the clicks - button = renderer.rect( - 0, - 0, - buttonWidth, - buttonHeight, - 0 - ) - .align(btnOptions) - .attr({ - fill: 'rgba(255, 255, 255, 0.001)', - title: HC.getOptions().lang[btnOptions._titleKey], - zIndex: 21 - }).css({ - cursor: 'pointer' - }) - .on('mouseover', function() { - symbol.attr({ - stroke: btnOptions.hoverSymbolStroke, - fill: btnOptions.hoverSymbolFill - }); - box.attr({ - stroke: btnOptions.hoverBorderColor - }); - }) - .on('mouseout', revert) - .on('click', revert) - .add(); - - //addEvent(button.element, 'click', revert); - - // add the click event - if (menuItems) { - onclick = function(e) { - revert(); - var bBox = button.getBBox(); - chart.contextMenu('export-menu', menuItems, bBox.x, bBox.y, buttonWidth, buttonHeight); - }; - } - /*addEvent(button.element, 'click', function() { - onclick.apply(chart, arguments); - });*/ - button.on('click', function() { - onclick.apply(chart, arguments); - }); - - // the icon - symbol = renderer.symbol( - btnOptions.symbol, - btnOptions.symbolX, - btnOptions.symbolY, - (btnOptions.symbolSize || 12) / 2 - ) - .align(btnOptions, true) - .attr(extend(symbolAttr, { - 'stroke-width': btnOptions.symbolStrokeWidth || 1, - zIndex: 20 - })).add(); - - - - } + }, + + /** + * Display a popup menu for choosing the export type + * + * @param {String} name An identifier for the menu + * @param {Array} items A collection with text and onclicks for the items + * @param {Number} x The x position of the opener button + * @param {Number} y The y position of the opener button + * @param {Number} width The width of the opener button + * @param {Number} height The height of the opener button + */ + contextMenu: function(name, items, x, y, width, height) { + var chart = this, + navOptions = chart.options.navigation, + menuItemStyle = navOptions.menuItemStyle, + chartWidth = chart.chartWidth, + chartHeight = chart.chartHeight, + cacheName = 'cache-'+ name, + menu = chart[cacheName], + menuPadding = mathMax(width, height), // for mouse leave detection + boxShadow = '3px 3px 10px #888', + innerMenu, + hide, + menuStyle; + + // create the menu only the first time + if (!menu) { + + // create a HTML element above the SVG + chart[cacheName] = menu = createElement(DIV, { + className: PREFIX + name + }, { + position: ABSOLUTE, + zIndex: 1000, + padding: menuPadding + PX + }, chart.container); + + innerMenu = createElement(DIV, null, + extend({ + MozBoxShadow: boxShadow, + WebkitBoxShadow: boxShadow, + boxShadow: boxShadow + }, navOptions.menuStyle) , menu); + + // hide on mouse out + hide = function() { + css(menu, { display: NONE }); + }; + + addEvent(menu, 'mouseleave', hide); + + + // create the items + each(items, function(item) { + if (item) { + var div = createElement(DIV, { + onmouseover: function() { + css(this, navOptions.menuItemHoverStyle); + }, + onmouseout: function() { + css(this, menuItemStyle); + }, + innerHTML: item.text || HC.getOptions().lang[item.textKey] + }, extend({ + cursor: 'pointer' + }, menuItemStyle), innerMenu); + + div[hasTouch ? 'ontouchstart' : 'onclick'] = function() { + hide(); + item.onclick.apply(chart, arguments); + }; + + } + }); + + chart.exportMenuWidth = menu.offsetWidth; + chart.exportMenuHeight = menu.offsetHeight; + } + + menuStyle = { display: 'block' }; + + // if outside right, right align it + if (x + chart.exportMenuWidth > chartWidth) { + menuStyle.right = (chartWidth - x - width - menuPadding) + PX; + } else { + menuStyle.left = (x - menuPadding) + PX; + } + // if outside bottom, bottom align it + if (y + height + chart.exportMenuHeight > chartHeight) { + menuStyle.bottom = (chartHeight - y - menuPadding) + PX; + } else { + menuStyle.top = (y + height - menuPadding) + PX; + } + + css(menu, menuStyle); + }, + + /** + * Add the export button to the chart + */ + addButton: function(options) { + var chart = this, + renderer = chart.renderer, + btnOptions = merge(chart.options.navigation.buttonOptions, options), + onclick = btnOptions.onclick, + menuItems = btnOptions.menuItems, + /*position = chart.getAlignment(btnOptions), + buttonLeft = position.x, + buttonTop = position.y,*/ + buttonWidth = btnOptions.width, + buttonHeight = btnOptions.height, + box, + symbol, + button, + borderWidth = btnOptions.borderWidth, + boxAttr = { + stroke: btnOptions.borderColor + + }, + symbolAttr = { + stroke: btnOptions.symbolStroke, + fill: btnOptions.symbolFill + }; + + if (btnOptions.enabled === false) { + return; + } + + // element to capture the click + function revert() { + symbol.attr(symbolAttr); + box.attr(boxAttr); + } + + // the box border + box = renderer.rect( + 0, + 0, + buttonWidth, + buttonHeight, + btnOptions.borderRadius, + borderWidth + ) + //.translate(buttonLeft, buttonTop) // to allow gradients + .align(btnOptions, true) + .attr(extend({ + fill: btnOptions.backgroundColor, + 'stroke-width': borderWidth, + zIndex: 19 + }, boxAttr)).add(); + + // the invisible element to track the clicks + button = renderer.rect( + 0, + 0, + buttonWidth, + buttonHeight, + 0 + ) + .align(btnOptions) + .attr({ + fill: 'rgba(255, 255, 255, 0.001)', + title: HC.getOptions().lang[btnOptions._titleKey], + zIndex: 21 + }).css({ + cursor: 'pointer' + }) + .on('mouseover', function() { + symbol.attr({ + stroke: btnOptions.hoverSymbolStroke, + fill: btnOptions.hoverSymbolFill + }); + box.attr({ + stroke: btnOptions.hoverBorderColor + }); + }) + .on('mouseout', revert) + .on('click', revert) + .add(); + + //addEvent(button.element, 'click', revert); + + // add the click event + if (menuItems) { + onclick = function(e) { + revert(); + var bBox = button.getBBox(); + chart.contextMenu('export-menu', menuItems, bBox.x, bBox.y, buttonWidth, buttonHeight); + }; + } + /*addEvent(button.element, 'click', function() { + onclick.apply(chart, arguments); + });*/ + button.on('click', function() { + onclick.apply(chart, arguments); + }); + + // the icon + symbol = renderer.symbol( + btnOptions.symbol, + btnOptions.symbolX, + btnOptions.symbolY, + (btnOptions.symbolSize || 12) / 2 + ) + .align(btnOptions, true) + .attr(extend(symbolAttr, { + 'stroke-width': btnOptions.symbolStrokeWidth || 1, + zIndex: 20 + })).add(); + + + + } }); // Create the export icon HC.Renderer.prototype.symbols.exportIcon = function(x, y, radius) { - return [ - M, // the disk - x - radius, y + radius, - L, - x + radius, y + radius, - x + radius, y + radius * 0.5, - x - radius, y + radius * 0.5, - 'Z', - M, // the arrow - x, y + radius * 0.5, - L, - x - radius * 0.5, y - radius / 3, - x - radius / 6, y - radius / 3, - x - radius / 6, y - radius, - x + radius / 6, y - radius, - x + radius / 6, y - radius / 3, - x + radius * 0.5, y - radius / 3, - 'Z' - ]; + return [ + M, // the disk + x - radius, y + radius, + L, + x + radius, y + radius, + x + radius, y + radius * 0.5, + x - radius, y + radius * 0.5, + 'Z', + M, // the arrow + x, y + radius * 0.5, + L, + x - radius * 0.5, y - radius / 3, + x - radius / 6, y - radius / 3, + x - radius / 6, y - radius, + x + radius / 6, y - radius, + x + radius / 6, y - radius / 3, + x + radius * 0.5, y - radius / 3, + 'Z' + ]; }; // Create the print icon HC.Renderer.prototype.symbols.printIcon = function(x, y, radius) { - return [ - M, // the printer - x - radius, y + radius * 0.5, - L, - x + radius, y + radius * 0.5, - x + radius, y - radius / 3, - x - radius, y - radius / 3, - 'Z', - M, // the upper sheet - x - radius * 0.5, y - radius / 3, - L, - x - radius * 0.5, y - radius, - x + radius * 0.5, y - radius, - x + radius * 0.5, y - radius / 3, - 'Z', - M, // the lower sheet - x - radius * 0.5, y + radius * 0.5, - L, - x - radius * 0.75, y + radius, - x + radius * 0.75, y + radius, - x + radius * 0.5, y + radius * 0.5, - 'Z' - ]; + return [ + M, // the printer + x - radius, y + radius * 0.5, + L, + x + radius, y + radius * 0.5, + x + radius, y - radius / 3, + x - radius, y - radius / 3, + 'Z', + M, // the upper sheet + x - radius * 0.5, y - radius / 3, + L, + x - radius * 0.5, y - radius, + x + radius * 0.5, y - radius, + x + radius * 0.5, y - radius / 3, + 'Z', + M, // the lower sheet + x - radius * 0.5, y + radius * 0.5, + L, + x - radius * 0.75, y + radius, + x + radius * 0.75, y + radius, + x + radius * 0.5, y + radius * 0.5, + 'Z' + ]; }; // Add the buttons on chart load Chart.prototype.callbacks.push(function(chart) { - var n, - exportingOptions = chart.options.exporting, - buttons = exportingOptions.buttons; + var n, + exportingOptions = chart.options.exporting, + buttons = exportingOptions.buttons; - if (exportingOptions.enabled !== false) { + if (exportingOptions.enabled !== false) { - for (n in buttons) { - chart.addButton(buttons[n]); - } - } + for (n in buttons) { + chart.addButton(buttons[n]); + } + } }); diff --git a/js/server_status.js b/js/server_status.js index f052ef5188..646295e958 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -2,7 +2,7 @@ $(function() { jQuery.tablesorter.addParser({ id: "fancyNumber", is: function(s) { - return /^[0-9]?[0-9,\.]*\s?(k|M|G|T)?$/.test(s); + return /^[0-9]?[0-9,\.]*\s?(k|M|G|T|%)?$/.test(s); }, format: function(s) { var num = jQuery.tablesorter.formatFloat( s.replace(PMA_messages['strThousandsSeperator'],'').replace(PMA_messages['strDecimalSeperator'],'.') ); @@ -307,7 +307,7 @@ $(function() { } }, exporting: { - enabled: false + enabled: true }, series: [] } diff --git a/server_status.php b/server_status.php index 4b470ce20a..bb023b9e3c 100644 --- a/server_status.php +++ b/server_status.php @@ -67,6 +67,10 @@ $GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js'; $GLOBALS['js_include'][] = 'jquery/jquery.tablesorter.js'; $GLOBALS['js_include'][] = 'jquery/jquery.cookie.js'; // For tab persistence $GLOBALS['js_include'][] = 'highcharts/highcharts.js'; +$GLOBALS['js_include'][] = 'highcharts/exporting.js'; +$GLOBALS['js_include'][] = 'canvg/canvg.js'; +$GLOBALS['js_include'][] = 'canvg/rgbcolor.js'; + /** * flush status variables if requested From e551c09604a3147b88ad5b8ef655f3563e110029 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Fri, 3 Jun 2011 12:10:53 +0200 Subject: [PATCH 040/206] js error fix when exporting a chart --- js/server_status.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/server_status.js b/js/server_status.js index 646295e958..74602913e6 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -87,6 +87,9 @@ $(function() { var numLoadedPoints=0; var otherSum=0; + // No realtime updates for graphs that are being exported + if(thisChart.options.chart.forExport==true) return; + var addnewPoint = function() { $.get('server_status.php?'+url_query,{ajax_request:1, chart_data:1, type:'queries'},function(data) { if(activeTimeouts[tab.attr('id')+"_chart_cnt"]==null) return; From 01511d1a9b6f93e1cb657c32a43aa314e42ec2a0 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Fri, 3 Jun 2011 12:20:36 +0200 Subject: [PATCH 041/206] Some commments --- chart_export.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/chart_export.php b/chart_export.php index b31745a764..018a8d0538 100644 --- a/chart_export.php +++ b/chart_export.php @@ -1,4 +1,11 @@ Date: Mon, 6 Jun 2011 13:16:35 +0200 Subject: [PATCH 042/206] Small code improvements --- js/server_status.js | 49 +++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/js/server_status.js b/js/server_status.js index 74602913e6..1a49429c2e 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -1,3 +1,19 @@ +/* vim: set expandtab sw=4 ts=4 sts=4: */ +/** + * @fileoverview functions used in server status pages + * @name Server Status + * + * @requires jQuery + * @requires jQueryUI + * @requires jQueryCookie + * @requires jQueryTablesorter + * @requires Highcharts + * @requires canvg + * @requires js/functions.js + * + */ + +// Add a tablesorter parser to properly handle thousands seperated numbers and SI units $(function() { jQuery.tablesorter.addParser({ id: "fancyNumber", @@ -8,14 +24,14 @@ $(function() { var num = jQuery.tablesorter.formatFloat( s.replace(PMA_messages['strThousandsSeperator'],'').replace(PMA_messages['strDecimalSeperator'],'.') ); var factor = 1; switch (s.charAt(s.length-1)) { - case '%': factor = 0.01; break; - // Todo: Please complete this list - case 'k': factor = 1000; break; - case 'M': factor = 1000*1000; break; - case 'G': factor = 1000*1000*1000; break; - case 'T': factor = 1000*1000*1000*1000; break; + case '%': factor = -2; break; + // Todo: Complete this list (as well as in the regexp a few lines up) + case 'k': factor = 3; break; + case 'M': factor = 6; break; + case 'G': factor = 9; break; + case 'T': factor = 12; break; } - return num*factor; + return num*Math.pow(10,factor); }, type: "numeric" }); @@ -71,15 +87,20 @@ $(function() { if(tabStatus[tab.attr('id')]!='realtime') { var series, title; - var settings = { chart: {renderTo:tab.attr('id')+"_chart_cnt"} } + var settings = new Object(); switch(tab.attr('id')) { case 'statustabs_traffic': + settings.chart = { + load: function() { + } + } + settings.series = [{name:'Issued queries since last refresh', data:[]}]; + settings.title = {text:'Issued queries'}; + settings.tooltip = { formatter:function() { return this.point.name; } }; break; case 'statustabs_queries': - settings.chart = { - renderTo:tab.attr('id')+"_chart_cnt", - defaultSeriesType: 'spline', + settings.chart = { events: { load: function() { var thisChart = this; @@ -119,8 +140,6 @@ $(function() { } } }; - settings.c_differentialData = true; - settings.c_dataType = 'queries'; settings.series = [{name:'Issued queries since last refresh', data:[]}]; settings.title = {text:'Issued queries'}; settings.tooltip = { formatter:function() { return this.point.name; } }; @@ -129,6 +148,8 @@ $(function() { default: return; } + + settings.chart.renderTo=tab.attr('id')+"_chart_cnt"; tab.find('.tabInnerContent') .hide() @@ -236,6 +257,7 @@ $(function() { } } + /* Filters the status variables by name/category/alert in the variables tab */ function filterVariables() { var useful_links=0; var section = text; @@ -320,6 +342,7 @@ $(function() { chart = new Highcharts.Chart(settings); } + // Provides a nicely formatted and sorted tooltip of each datapoint of the query statistics function sortedQueriesPointInfo(queries, lastQueries){ var max, maxIdx, num=0; var queryKeys = new Array(); From 9abc87d3a5915783f6e71ea56eefbce4c3196616 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Mon, 6 Jun 2011 13:50:17 +0200 Subject: [PATCH 043/206] Connection / Process charting on the server traffic tab --- js/server_status.js | 115 +++++++++++++++++++++++++------------------- server_status.php | 8 ++- 2 files changed, 73 insertions(+), 50 deletions(-) diff --git a/js/server_status.js b/js/server_status.js index 1a49429c2e..ceaeb14891 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -91,64 +91,44 @@ $(function() { switch(tab.attr('id')) { case 'statustabs_traffic': - settings.chart = { - load: function() { - } - } - settings.series = [{name:'Issued queries since last refresh', data:[]}]; - settings.title = {text:'Issued queries'}; - settings.tooltip = { formatter:function() { return this.point.name; } }; + settings = { + series: [{name:'Connections', data:[]},{name:'Processes', data:[]}], + title: {text:'Connections / Processes'}, + refresh:{ type: 'proc', + callback: function(chartObj, curVal, lastVal,numLoadedPoints) { + chartObj.series[0].addPoint( + { x:curVal.x, y:curVal.y_conn-lastVal.y_conn }, + true, numLoadedPoints >= numMaxPoints + ); + chartObj.series[1].addPoint( + { x:curVal.x, y:curVal.y_proc }, + true, numLoadedPoints >= numMaxPoints + ); + } + } + }; break; case 'statustabs_queries': - settings.chart = { - events: { - load: function() { - var thisChart = this; - var lastValue=null; - var numLoadedPoints=0; - var otherSum=0; - - // No realtime updates for graphs that are being exported - if(thisChart.options.chart.forExport==true) return; - - var addnewPoint = function() { - $.get('server_status.php?'+url_query,{ajax_request:1, chart_data:1, type:'queries'},function(data) { - if(activeTimeouts[tab.attr('id')+"_chart_cnt"]==null) return; - - var chartData = jQuery.parseJSON(data); - var pointInfo=''; - var i=0; - - chartData.x = parseInt(chartData.x); - chartData.y = parseInt(chartData.y); - - if(lastValue==null) lastValue = chartData; - - thisChart.series[0].addPoint({ - x:chartData.x, - y:chartData.y-lastValue.y, - name:sortedQueriesPointInfo(chartData,lastValue) - }, true, numLoadedPoints >= numMaxPoints); - - lastValue = chartData; - numLoadedPoints++; - activeTimeouts[tab.attr('id')+"_chart_cnt"] = setTimeout(addnewPoint, refreshRate); - }); + settings = { + series: [{name:'Issued queries since last refresh', data:[]}], + title: {text:'Issued queries'}, + tooltip: { formatter:function() { return this.point.name; } }, + refresh:{ type: 'queries', + callback: function(chartObj, curVal, lastVal,numLoadedPoints) { + chartObj.series[0].addPoint( + { x:curVal.x, y:curVal.y-lastVal.y, name:sortedQueriesPointInfo(curVal,lastVal) }, + true, numLoadedPoints >= numMaxPoints + ); + } } - - activeTimeouts[tab.attr('id')+"_chart_cnt"] = setTimeout(addnewPoint, 0); - } - } }; - settings.series = [{name:'Issued queries since last refresh', data:[]}]; - settings.title = {text:'Issued queries'}; - settings.tooltip = { formatter:function() { return this.point.name; } }; break; default: return; } + if(!settings.chart) settings.chart = {}; settings.chart.renderTo=tab.attr('id')+"_chart_cnt"; tab.find('.tabInnerContent') @@ -302,10 +282,46 @@ $(function() { } function initChart(passedSettings) { + var container = passedSettings.chart.renderTo; + var settings = { chart: { defaultSeriesType: 'spline', - marginRight: 10 + marginRight: 10, + events: { + load: function() { + var thisChart = this; + var lastValue=null; + var numLoadedPoints=0; + var otherSum=0; + + // No realtime updates for graphs that are being exported + if(thisChart.options.chart.forExport==true) return; + + var addnewPoint = function() { + $.get('server_status.php?'+url_query,{ajax_request:1, chart_data:1, type:passedSettings.refresh.type},function(data) { + if(activeTimeouts[container]==null) return; + + var chartData = jQuery.parseJSON(data); + var pointInfo=''; + var i=0; + + chartData.x = parseInt(chartData.x); + chartData.y = parseInt(chartData.y); + + if(lastValue==null) lastValue = chartData; + + passedSettings.refresh.callback(thisChart,chartData,lastValue,numLoadedPoints) + + lastValue = chartData; + numLoadedPoints++; + activeTimeouts[container] = setTimeout(addnewPoint, refreshRate); + }); + } + + activeTimeouts[container] = setTimeout(addnewPoint, 0); + } + } }, credits: { enabled:false @@ -337,6 +353,7 @@ $(function() { series: [] } + // Overwrite/Merge default settings with passedsettings $.extend(true,settings,passedSettings); chart = new Highcharts.Chart(settings); diff --git a/server_status.php b/server_status.php index bb023b9e3c..1ebb84772c 100644 --- a/server_status.php +++ b/server_status.php @@ -33,9 +33,12 @@ if (isset($_REQUEST['ajax_request'])) { if(isset($_REQUEST['chart_data'])) { switch($_REQUEST['type']) { case 'proc': + $c = PMA_DBI_fetch_result('SHOW GLOBAL STATUS WHERE Variable_name="Connections"', 0, 1); $result = PMA_DBI_query('SHOW PROCESSLIST'); $num_procs = PMA_DBI_num_rows($result); - exit((microtime(true)*1000).','.$num_procs); + + $ret = Array('x'=>(microtime(true)*1000),'y_proc'=>$num_procs,'y_conn'=>$c['Connections']); + exit(json_encode($ret)); case 'queries': $queries = PMA_DBI_fetch_result('SHOW GLOBAL STATUS WHERE Variable_name LIKE "Com_%" AND Value>0', 0, 1); cleanDeprecated($queries); @@ -369,6 +372,9 @@ echo __('Runtime Information'); ajax clock + + +

From 5e094266669b0ec306e7a836154373a52766fd98 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Mon, 6 Jun 2011 14:38:56 +0200 Subject: [PATCH 044/206] Merge --- .gitignore | 14 +- ChangeLog | 11 + Documentation.html | 19 +- browse_foreigners.php | 6 +- bs_disp_as_mime_type.php | 4 +- chk_rel.php | 2 +- db_create.php | 2 +- db_datadict.php | 6 +- db_sql.php | 2 +- db_structure.php | 4 +- export.php | 10 +- import.php | 64 +- index.php | 4 +- js/codemirror/LICENSE | 19 + js/codemirror/lib/codemirror.js | 2035 ++++++ js/codemirror/mode/mysql/mysql.js | 145 + js/functions.js | 46 +- js/messages.php | 3 + js/server_privileges.js | 88 +- js/sql.js | 35 +- libraries/File.class.php | 20 +- libraries/StorageEngine.class.php | 2 +- libraries/Theme_Manager.class.php | 2 +- libraries/Tracker.class.php | 4 +- libraries/auth/config.auth.lib.php | 14 +- libraries/auth/cookie.auth.lib.php | 3 +- libraries/auth/http.auth.lib.php | 2 +- libraries/auth/swekey/swekey.php | 2 +- libraries/blobstreaming.lib.php | 116 +- libraries/bookmark.lib.php | 4 +- libraries/chart/pma_pchart_chart.php | 6 +- libraries/chart/pma_pchart_multi_line.php | 2 +- libraries/chart/pma_pchart_multi_radar.php | 4 +- libraries/chart/pma_pchart_pie.php | 4 +- libraries/chart/pma_pchart_single_line.php | 2 +- libraries/chart/pma_pchart_single_radar.php | 4 +- libraries/common.inc.php | 2 +- libraries/common.lib.php | 7 +- libraries/config.default.php | 27 +- libraries/config.values.php | 1 + libraries/config/messages.inc.php | 9 +- libraries/config/setup.forms.php | 4 +- libraries/config/user_preferences.forms.php | 4 +- libraries/core.lib.php | 2 +- libraries/database_interface.lib.php | 20 +- libraries/dbi/mysql.dbi.lib.php | 2 +- libraries/dbi/mysqli.dbi.lib.php | 2 +- libraries/display_create_database.lib.php | 2 +- libraries/display_export.lib.php | 2 +- libraries/display_import.lib.php | 4 +- libraries/display_select_lang.lib.php | 2 +- libraries/display_tbl.lib.php | 102 +- libraries/export/codegen.php | 12 +- libraries/export/csv.php | 18 +- libraries/export/htmlword.php | 36 +- libraries/export/json.php | 2 +- libraries/export/latex.php | 34 +- libraries/export/mediawiki.php | 12 +- libraries/export/ods.php | 18 +- libraries/export/odt.php | 28 +- libraries/export/pdf.php | 16 +- libraries/export/php_array.php | 2 +- libraries/export/sql.php | 289 +- libraries/export/texytext.php | 26 +- libraries/export/xls.php | 16 +- libraries/export/xlsx.php | 16 +- libraries/export/xml.php | 96 +- libraries/export/yaml.php | 2 +- libraries/file_listing.php | 10 +- libraries/header_http.inc.php | 2 +- libraries/header_meta_style.inc.php | 4 +- libraries/header_printview.inc.php | 4 +- libraries/header_scripts.inc.php | 2 + libraries/iconv_wrapper.lib.php | 4 +- libraries/import.lib.php | 214 +- libraries/import/README | 4 +- libraries/import/csv.php | 58 +- libraries/import/docsql.php | 6 +- libraries/import/ldi.php | 10 +- libraries/import/ods.php | 8 +- libraries/import/sql.php | 26 +- libraries/import/xml.php | 6 +- libraries/kanji-encoding.lib.php | 4 +- libraries/mult_submits.inc.php | 18 +- libraries/mysql_charsets.lib.php | 14 +- libraries/navigation_header.inc.php | 2 +- libraries/relation.lib.php | 16 +- .../schema/Dia_Relation_Schema.class.php | 4 +- .../schema/Eps_Relation_Schema.class.php | 2 +- .../schema/Export_Relation_Schema.class.php | 10 +- .../schema/Pdf_Relation_Schema.class.php | 2 +- .../schema/Svg_Relation_Schema.class.php | 4 +- libraries/schema/User_Schema.class.php | 28 +- .../schema/Visio_Relation_Schema.class.php | 4 +- libraries/select_lang.lib.php | 9 +- libraries/server_links.inc.php | 49 +- libraries/sql_query_form.lib.php | 7 +- libraries/sqlparser.data.php | 35 +- libraries/sqlparser.lib.php | 344 +- libraries/sqlvalidator.class.php | 6 +- libraries/sqlvalidator.lib.php | 4 +- libraries/string.lib.php | 2 +- libraries/tbl_properties.inc.php | 2 +- libraries/zip_extension.lib.php | 2 +- main.php | 4 +- navigation.php | 18 +- pmd_general.php | 2 +- pmd_help.php | 6 +- pmd_pdf.php | 4 +- pmd_relation_new.php | 2 +- pmd_relation_upd.php | 2 +- po/af.po | 2111 +++--- po/ar.po | 2123 +++--- po/az.po | 2153 +++--- po/be.po | 2096 +++--- po/be@latin.po | 2109 +++--- po/bg.po | 2152 +++--- po/bn.po | 2140 +++--- po/bs.po | 2111 +++--- po/ca.po | 2139 +++--- po/cs.po | 2073 +++--- po/cy.po | 2119 +++--- po/da.po | 2097 +++--- po/de.po | 2139 +++--- po/el.po | 2147 +++--- po/en_GB.po | 2161 +++--- po/es.po | 2125 +++--- po/et.po | 2088 +++--- po/eu.po | 2111 +++--- po/fa.po | 2130 +++--- po/fi.po | 2130 +++--- po/fr.po | 2127 +++--- po/gl.po | 2132 +++--- po/he.po | 2103 +++--- po/hi.po | 2124 +++--- po/hr.po | 2100 +++--- po/hu.po | 2223 +++--- po/id.po | 2098 +++--- po/it.po | 2151 +++--- po/ja.po | 2142 +++--- po/ka.po | 2179 +++--- po/ko.po | 2120 +++--- po/lt.po | 2136 +++--- po/lv.po | 2115 +++--- po/mk.po | 2084 +++--- po/ml.po | 2135 +++--- po/mn.po | 2141 +++--- po/ms.po | 2111 +++--- po/nb.po | 2146 +++--- po/nl.po | 2201 +++--- po/phpmyadmin.pot | 2134 +++--- po/pl.po | 2143 +++--- po/pt.po | 2144 +++--- po/pt_BR.po | 2124 +++--- po/ro.po | 2096 +++--- po/ru.po | 2212 +++--- po/si.po | 2232 +++--- po/sk.po | 2233 +++--- po/sl.po | 2118 +++--- po/sq.po | 2114 +++--- po/sr.po | 2096 +++--- po/sr@latin.po | 2096 +++--- po/sv.po | 2238 +++--- po/ta.po | 2137 +++--- po/te.po | 2137 +++--- po/th.po | 2120 +++--- po/tr.po | 2126 +++--- po/tt.po | 2132 +++--- po/ug.po | 2125 +++--- po/uk.po | 2139 +++--- po/ur.po | 2122 +++--- po/uz.po | 2140 +++--- po/uz@latin.po | 2152 +++--- po/zh_CN.po | 2140 +++--- po/zh_TW.po | 6012 ++++++++--------- scripts/create_tables.sql | 45 +- server_collations.php | 2 +- server_privileges.php | 93 +- server_synchronize.php | 18 +- setup/lib/common.inc.php | 4 +- sql.php | 4 +- tbl_change.php | 24 +- tbl_relation.php | 16 +- tbl_row_action.php | 2 +- tbl_structure.php | 2 +- test/PMA_SQL_parser_data_test.php | 1 - test/PMA_SQL_parser_test.php | 1 - test/PMA_STR_sub_test.php | 2 - test/theme.php | 5 +- themes/original/css/theme_right.css.php | 110 +- themes/pmahomme/css/theme_right.css.php | 112 +- 191 files changed, 77268 insertions(+), 68146 deletions(-) create mode 100644 js/codemirror/LICENSE create mode 100644 js/codemirror/lib/codemirror.js create mode 100644 js/codemirror/mode/mysql/mysql.js diff --git a/.gitignore b/.gitignore index b492910cc1..dda2e0ecd9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,14 @@ # Directory for creating releases -release +/release/ # Configuration files config.inc.php config.header.inc.php config.footer.inc.php # Upload/save dirs -upload -save +/upload/ +/save/ # For setup script -config +/config/ # ctags tags # Editor files @@ -22,12 +22,12 @@ phpmyadmin.wpj .idea *.sw[op] # Locales -locale +/locale/ # Backups *~ # Javascript sources -sources +/sources/ # API documentation -apidoc +/apidoc/ # Demo server revision-info.php diff --git a/ChangeLog b/ChangeLog index 66bc93bc81..014bc49b4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,16 @@ + rfe #2098927 Remember recent tables + rfe #3078542 Remember the last sort order for each table + AJAX for Create table in navigation panel ++ rfe #3310562 Wording about Column ++ AJAX for Add a user in Database privileges ++ Patch #3271804 for rfe #3177495, new DisableMultiTableMaintenance directive + +3.4.3.0 (not yet released) +- bug #3311170 [sync] Missing helper icons in Synchronize +- patch #3304473 [setup] Redefine a lable that was wrong +- bug #3304544 [parser] master is not a reserved word +- bug #3307616 [edit] Inline edit updates multiple duplicate rows +- patch #3311539 [edit] Inline edit does not escape backslashes 3.4.2.0 (not yet released) - bug #3301249 [interface] Iconic table operations does not remove inline edit label @@ -24,6 +34,7 @@ - bug #3306958 [interface] Unnecessary Details slider - bug #3308476 [interface] "Show all" not persistent after a sort - bug #3308072 [auth] Version disclosure to anonymous visitors +- bug #3306981 [interface] pmahomme and table statistics 3.4.1.0 (2011-05-20) - bug #3301108 [interface] Synchronize and already configured host diff --git a/Documentation.html b/Documentation.html index 2ff0881ba0..6e987473e0 100644 --- a/Documentation.html +++ b/Documentation.html @@ -1845,6 +1845,15 @@ $cfg['TrustedProxies'] = Default is 1000. +
$cfg['DisableMultiTableMaintenance'] boolean
+
+ In the database Structure page, it's possible to mark some tables then + choose an operation like optimizing for many tables. This can slow down + a server; therefore, setting this to true prevents this kind + of multiple maintenance operation. Default is false. +
+
$cfg['NaviWidth'] integer
Navi frame width in pixels. See themes/themename/layout.inc.php.
@@ -1934,14 +1943,12 @@ $cfg['TrustedProxies'] =
Maximum number of characters shown in any non-numeric field on browse view. Can be turned off by a toggle button on the browse page.
-
$cfg['ModifyDeleteAtLeft'] boolean - $cfg['ModifyDeleteAtRight'] boolean +
$cfg['RowActionLinks'] string
Defines the place where table row links (Edit, Inline edit, Copy, - Delete) would be put when - tables contents are displayed (you may have them displayed both at the - left and at the right). - "Left" and "right" are parsed as "top" + Delete) would be put when tables contents are displayed (you may + have them displayed at the left side, right side, both sides or nowhere). + "left" and "right" are parsed as "top" and "bottom" with vertical display mode.
$cfg['DefaultDisplay'] string
diff --git a/browse_foreigners.php b/browse_foreigners.php index 16fa48c822..0b104841fe 100644 --- a/browse_foreigners.php +++ b/browse_foreigners.php @@ -23,9 +23,9 @@ require_once './libraries/header_http.inc.php'; */ require_once './libraries/transformations.lib.php'; // Transformations $cfgRelation = PMA_getRelationsParam(); -$foreigners = ($cfgRelation['relwork'] ? PMA_getForeigners($db, $table) : FALSE); +$foreigners = ($cfgRelation['relwork'] ? PMA_getForeigners($db, $table) : false); -$override_total = TRUE; +$override_total = true; if (! isset($pos)) { $pos = 0; @@ -180,7 +180,7 @@ if (is_array($foreignData['disp_row'])) { $values = array(); $keys = array(); foreach ($foreignData['disp_row'] as $relrow) { - if ($foreignData['foreign_display'] != FALSE) { + if ($foreignData['foreign_display'] != false) { $values[] = $relrow[$foreignData['foreign_display']]; } else { $values[] = ''; diff --git a/bs_disp_as_mime_type.php b/bs_disp_as_mime_type.php index 085d888236..03a8c8b3ac 100644 --- a/bs_disp_as_mime_type.php +++ b/bs_disp_as_mime_type.php @@ -31,13 +31,13 @@ if (empty($filename)) { $hdrs = get_headers($filename, 1); -if ($hdrs === FALSE) { +if ($hdrs === false) { die(__('Failed to fetch headers')); } $fHnd = fopen($filename, "rb"); -if ($fHnd === FALSE) { +if ($fHnd === false) { die(__('Failed to open remote URL')); } diff --git a/chk_rel.php b/chk_rel.php index 8955350b0f..d13f075ef0 100644 --- a/chk_rel.php +++ b/chk_rel.php @@ -15,7 +15,7 @@ require_once './libraries/header.inc.php'; /** * Gets the relation settings */ -$cfgRelation = PMA_getRelationsParam(TRUE); +$cfgRelation = PMA_getRelationsParam(true); /** diff --git a/db_create.php b/db_create.php index 3609bf6cf3..502ac7fcd0 100644 --- a/db_create.php +++ b/db_create.php @@ -49,7 +49,7 @@ if (! $result) { * If in an Ajax request, just display the message with {@link PMA_ajaxResponse} */ if($GLOBALS['is_ajax_request'] == true) { - PMA_ajaxResponse($message, FALSE); + PMA_ajaxResponse($message, false); } require_once './libraries/header.inc.php'; diff --git a/db_datadict.php b/db_datadict.php index 9941ef4440..102724d3ac 100644 --- a/db_datadict.php +++ b/db_datadict.php @@ -142,12 +142,12 @@ while ($row = PMA_DBI_fetch_assoc($rowset)) { $res_rel = PMA_getForeigners($db, $table); if (count($res_rel) > 0) { - $have_rel = TRUE; + $have_rel = true; } else { - $have_rel = FALSE; + $have_rel = false; } } else { - $have_rel = FALSE; + $have_rel = false; } // end if diff --git a/db_sql.php b/db_sql.php index 2020dea7d5..08eb5cac34 100644 --- a/db_sql.php +++ b/db_sql.php @@ -31,7 +31,7 @@ $back = 'db_sql.php'; require './libraries/db_info.inc.php'; if ($num_tables == 0 && empty($db_query_force)) { $sub_part = ''; - $is_info = TRUE; + $is_info = true; require './db_structure.php'; exit(); } diff --git a/db_structure.php b/db_structure.php index ebc69154e4..864a668116 100644 --- a/db_structure.php +++ b/db_structure.php @@ -28,7 +28,7 @@ if (empty($is_info)) { // db_structure.php -> libraries/mult_submits.inc.php -> sql.php // -> db_structure.php and if we got an error on the multi submit, // we must display it here and not call again mult_submits.inc.php - if (! isset($error) || FALSE === $error) { + if (! isset($error) || false === $error) { require './libraries/mult_submits.inc.php'; } if (empty($message)) { @@ -504,7 +504,7 @@ echo ' ' . "\n"; -if (!$db_is_information_schema) { +if (!$db_is_information_schema && !$cfg['DisableMultiTableMaintenance']) { echo ' ' . "\n"; echo '
diff --git a/libraries/display_select_lang.lib.php b/libraries/display_select_lang.lib.php index 5ce059953d..4f846bf96a 100644 --- a/libraries/display_select_lang.lib.php +++ b/libraries/display_select_lang.lib.php @@ -26,7 +26,7 @@ function PMA_language_cmp(&$a, &$b) { * * @access public */ -function PMA_select_language($use_fieldset = FALSE, $show_doc = TRUE) { +function PMA_select_language($use_fieldset = false, $show_doc = true) { global $cfg, $lang; ?> diff --git a/libraries/display_tbl.lib.php b/libraries/display_tbl.lib.php index 3fc2f77613..a16fc23d32 100644 --- a/libraries/display_tbl.lib.php +++ b/libraries/display_tbl.lib.php @@ -445,7 +445,7 @@ function PMA_displayTableHeaders(&$is_display, &$fields_meta, $fields_cnt = 0, $ global $sql_query, $num_rows; global $vertical_display, $highlight_columns; - // required to generate sort links that will remember whether the + // required to generate sort links that will remember whether the // "Show all" button has been clicked $sql_md5 = md5($GLOBALS['sql_query']); $session_max_rows = $_SESSION['tmp_user_values']['query'][$sql_md5]['max_rows']; @@ -661,7 +661,8 @@ function PMA_displayTableHeaders(&$is_display, &$fields_meta, $fields_cnt = 0, $ // ... at the left column of the result table header if possible // and required - elseif ($GLOBALS['cfg']['ModifyDeleteAtLeft'] && $is_display['text_btn'] == '1') { + elseif (($GLOBALS['cfg']['RowActionLinks'] == 'left' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && $is_display['text_btn'] == '1') { $vertical_display['emptypre'] = ($is_display['edit_lnk'] != 'nn' && $is_display['del_lnk'] != 'nn') ? 4 : 0; if ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped') { @@ -677,7 +678,7 @@ function PMA_displayTableHeaders(&$is_display, &$fields_meta, $fields_cnt = 0, $ } // ... elseif no button, displays empty(ies) col(s) if required - elseif ($GLOBALS['cfg']['ModifyDeleteAtLeft'] + elseif (($GLOBALS['cfg']['RowActionLinks'] == 'left' || $GLOBALS['cfg']['RowActionLinks'] == 'both') && ($is_display['edit_lnk'] != 'nn' || $is_display['del_lnk'] != 'nn')) { $vertical_display['emptypre'] = ($is_display['edit_lnk'] != 'nn' && $is_display['del_lnk'] != 'nn') ? 4 : 0; if ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' @@ -691,6 +692,12 @@ function PMA_displayTableHeaders(&$is_display, &$fields_meta, $fields_cnt = 0, $ } // end vertical mode } + // ... elseif display an empty column if the actions links are disabled to match the rest of the table + elseif ($GLOBALS['cfg']['RowActionLinks'] == 'none' && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' + || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) { + echo ''; + } + // 2. Displays the fields' name // 2.0 If sorting links should be used, checks if the query is a "JOIN" // statement (see 2.1.3) @@ -912,9 +919,9 @@ function PMA_displayTableHeaders(&$is_display, &$fields_meta, $fields_cnt = 0, $ // 3. Displays the needed checkboxes at the right // column of the result table header if possible and required... - if ($GLOBALS['cfg']['ModifyDeleteAtRight'] - && ($is_display['edit_lnk'] != 'nn' || $is_display['del_lnk'] != 'nn') - && $is_display['text_btn'] == '1') { + if (($GLOBALS['cfg']['RowActionLinks'] == 'right' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && ($is_display['edit_lnk'] != 'nn' || $is_display['del_lnk'] != 'nn') + && $is_display['text_btn'] == '1') { $vertical_display['emptyafter'] = ($is_display['edit_lnk'] != 'nn' && $is_display['del_lnk'] != 'nn') ? 4 : 1; if ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped') { @@ -933,7 +940,7 @@ function PMA_displayTableHeaders(&$is_display, &$fields_meta, $fields_cnt = 0, $ // ... elseif no button, displays empty columns if required // (unless coming from Browse mode print view) - elseif ($GLOBALS['cfg']['ModifyDeleteAtRight'] + elseif (($GLOBALS['cfg']['RowActionLinks'] == 'left' || $GLOBALS['cfg']['RowActionLinks'] == 'both') && ($is_display['edit_lnk'] == 'nn' && $is_display['del_lnk'] == 'nn') && (!$GLOBALS['is_header_sent'])) { $vertical_display['emptyafter'] = ($is_display['edit_lnk'] != 'nn' && $is_display['del_lnk'] != 'nn') ? 4 : 1; @@ -1026,6 +1033,11 @@ function PMA_addClass($class, $condition_field, $meta, $nowrap, $is_field_trunca $set_class = ' set'; } + $bit_class = ''; + if(strpos($meta->type, 'bit') !== false) { + $bit_class = ' bit'; + } + $mime_type_class = ''; if(isset($meta->mimetype)) { $mime_type_class = ' ' . preg_replace('/\//', '_', $meta->mimetype); @@ -1034,7 +1046,7 @@ function PMA_addClass($class, $condition_field, $meta, $nowrap, $is_field_trunca $result = $class . ($condition_field ? ' condition' : '') . $nowrap . ' ' . ($is_field_truncated ? ' truncated' : '') . ($transform_function != $default_function ? ' transformed' : '') - . $enum_class . $set_class . $mime_type_class; + . $enum_class . $set_class . $bit_class . $mime_type_class; return $result; } @@ -1249,13 +1261,20 @@ function PMA_displayTableBody(&$dt_result, &$is_display, $map, $analyzed_sql) { } // end if (1.2.2) // 1.3 Displays the links at left if required - if ($GLOBALS['cfg']['ModifyDeleteAtLeft'] - && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' - || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) { + if (($GLOBALS['cfg']['RowActionLinks'] == 'left' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' + || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) { if (! isset($js_conf)) { $js_conf = ''; } echo PMA_generateCheckboxAndLinks('left', $del_url, $is_display, $row_no, $where_clause, $where_clause_html, $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf); + } else if (($GLOBALS['cfg']['RowActionLinks'] == 'none') + && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' + || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) { + if (! isset($js_conf)) { + $js_conf = ''; + } + echo PMA_generateCheckboxAndLinks('none', $del_url, $is_display, $row_no, $where_clause, $where_clause_html, $del_query, 'l', $edit_url, $copy_url, $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf); } // end if (1.3) } // end if (1) @@ -1465,13 +1484,13 @@ function PMA_displayTableBody(&$dt_result, &$is_display, $map, $analyzed_sql) { } // end for (2) // 3. Displays the modify/delete links on the right if required - if ($GLOBALS['cfg']['ModifyDeleteAtRight'] - && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' - || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) { - if (! isset($js_conf)) { - $js_conf = ''; - } - echo PMA_generateCheckboxAndLinks('right', $del_url, $is_display, $row_no, $where_clause, $where_clause_html, $del_query, 'r', $edit_url, $copy_url, $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf); + if (($GLOBALS['cfg']['RowActionLinks'] == 'right' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' + || $_SESSION['tmp_user_values']['disp_direction'] == 'horizontalflipped')) { + if (! isset($js_conf)) { + $js_conf = ''; + } + echo PMA_generateCheckboxAndLinks('right', $del_url, $is_display, $row_no, $where_clause, $where_clause_html, $del_query, 'r', $edit_url, $copy_url, $edit_anchor_class, $edit_str, $copy_str, $del_str, $js_conf); } // end if (3) if ($_SESSION['tmp_user_values']['disp_direction'] == 'horizontal' @@ -1551,15 +1570,19 @@ function PMA_displayVerticalTable() global $vertical_display; // Displays "multi row delete" link at top if required - if ($GLOBALS['cfg']['ModifyDeleteAtLeft'] && is_array($vertical_display['row_delete']) && (count($vertical_display['row_delete']) > 0 || !empty($vertical_display['textbtn']))) { + if (($GLOBALS['cfg']['RowActionLinks'] != 'right') + && is_array($vertical_display['row_delete']) && (count($vertical_display['row_delete']) > 0 || !empty($vertical_display['textbtn']))) { echo '' . "\n"; + if ($GLOBALS['cfg']['RowActionLinks'] == 'none') { + // if we are not showing the RowActionLinks, then we need to show the Multi-Row-Action checkboxes + echo '' . "\n"; + } echo $vertical_display['textbtn']; $foo_counter = 0; foreach ($vertical_display['row_delete'] as $val) { if (($foo_counter != 0) && ($_SESSION['tmp_user_values']['repeat_cells'] != 0) && !($foo_counter % $_SESSION['tmp_user_values']['repeat_cells'])) { echo '' . "\n"; } - echo str_replace('[%_PMA_CHECKBOX_DIR_%]', '_left', $val); $foo_counter++; } // end while @@ -1567,7 +1590,8 @@ function PMA_displayVerticalTable() } // end if // Displays "edit" link at top if required - if ($GLOBALS['cfg']['ModifyDeleteAtLeft'] && is_array($vertical_display['edit']) && (count($vertical_display['edit']) > 0 || !empty($vertical_display['textbtn']))) { + if (($GLOBALS['cfg']['RowActionLinks'] == 'left' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && is_array($vertical_display['edit']) && (count($vertical_display['edit']) > 0 || !empty($vertical_display['textbtn']))) { echo '' . "\n"; if (! is_array($vertical_display['row_delete'])) { echo $vertical_display['textbtn']; @@ -1585,7 +1609,8 @@ function PMA_displayVerticalTable() } // end if // Displays "copy" link at top if required - if ($GLOBALS['cfg']['ModifyDeleteAtLeft'] && is_array($vertical_display['copy']) && (count($vertical_display['copy']) > 0 || !empty($vertical_display['textbtn']))) { + if (($GLOBALS['cfg']['RowActionLinks'] == 'left' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && is_array($vertical_display['copy']) && (count($vertical_display['copy']) > 0 || !empty($vertical_display['textbtn']))) { echo '' . "\n"; if (! is_array($vertical_display['row_delete'])) { echo $vertical_display['textbtn']; @@ -1603,7 +1628,8 @@ function PMA_displayVerticalTable() } // end if // Displays "delete" link at top if required - if ($GLOBALS['cfg']['ModifyDeleteAtLeft'] && is_array($vertical_display['delete']) && (count($vertical_display['delete']) > 0 || !empty($vertical_display['textbtn']))) { + if (($GLOBALS['cfg']['RowActionLinks'] == 'left' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && is_array($vertical_display['delete']) && (count($vertical_display['delete']) > 0 || !empty($vertical_display['textbtn']))) { echo '' . "\n"; if (! is_array($vertical_display['edit']) && ! is_array($vertical_display['row_delete'])) { echo $vertical_display['textbtn']; @@ -1640,7 +1666,8 @@ function PMA_displayVerticalTable() } // end while // Displays "multi row delete" link at bottom if required - if ($GLOBALS['cfg']['ModifyDeleteAtRight'] && is_array($vertical_display['row_delete']) && (count($vertical_display['row_delete']) > 0 || !empty($vertical_display['textbtn']))) { + if (($GLOBALS['cfg']['RowActionLinks'] == 'right' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && is_array($vertical_display['row_delete']) && (count($vertical_display['row_delete']) > 0 || !empty($vertical_display['textbtn']))) { echo '' . "\n"; echo $vertical_display['textbtn']; $foo_counter = 0; @@ -1656,7 +1683,8 @@ function PMA_displayVerticalTable() } // end if // Displays "edit" link at bottom if required - if ($GLOBALS['cfg']['ModifyDeleteAtRight'] && is_array($vertical_display['edit']) && (count($vertical_display['edit']) > 0 || !empty($vertical_display['textbtn']))) { + if (($GLOBALS['cfg']['RowActionLinks'] == 'right' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && is_array($vertical_display['edit']) && (count($vertical_display['edit']) > 0 || !empty($vertical_display['textbtn']))) { echo '' . "\n"; if (! is_array($vertical_display['row_delete'])) { echo $vertical_display['textbtn']; @@ -1674,7 +1702,8 @@ function PMA_displayVerticalTable() } // end if // Displays "copy" link at bottom if required - if ($GLOBALS['cfg']['ModifyDeleteAtRight'] && is_array($vertical_display['copy']) && (count($vertical_display['copy']) > 0 || !empty($vertical_display['textbtn']))) { + if (($GLOBALS['cfg']['RowActionLinks'] == 'right' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && is_array($vertical_display['copy']) && (count($vertical_display['copy']) > 0 || !empty($vertical_display['textbtn']))) { echo '' . "\n"; if (! is_array($vertical_display['row_delete'])) { echo $vertical_display['textbtn']; @@ -1692,7 +1721,8 @@ function PMA_displayVerticalTable() } // end if // Displays "delete" link at bottom if required - if ($GLOBALS['cfg']['ModifyDeleteAtRight'] && is_array($vertical_display['delete']) && (count($vertical_display['delete']) > 0 || !empty($vertical_display['textbtn']))) { + if (($GLOBALS['cfg']['RowActionLinks'] == 'right' || $GLOBALS['cfg']['RowActionLinks'] == 'both') + && is_array($vertical_display['delete']) && (count($vertical_display['delete']) > 0 || !empty($vertical_display['textbtn']))) { echo '' . "\n"; if (! is_array($vertical_display['edit']) && ! is_array($vertical_display['row_delete'])) { echo $vertical_display['textbtn']; @@ -2261,7 +2291,7 @@ function default_function($buffer) { function PMA_displayResultsOperations($the_disp_mode, $analyzed_sql) { global $db, $table, $sql_query, $unlim_num_rows; - $header_shown = FALSE; + $header_shown = false; $header = '
' . __('Query results operations') . ''; if ($the_disp_mode[6] == '1' || $the_disp_mode[9] == '1') { @@ -2270,7 +2300,7 @@ function PMA_displayResultsOperations($the_disp_mode, $analyzed_sql) { if (!$header_shown) { echo $header; - $header_shown = TRUE; + $header_shown = true; } $_url_params = array( @@ -2310,7 +2340,7 @@ function PMA_displayResultsOperations($the_disp_mode, $analyzed_sql) { } if (!$header_shown) { echo $header; - $header_shown = TRUE; + $header_shown = true; } $_url_params['unlim_num_rows'] = $unlim_num_rows; @@ -2348,7 +2378,7 @@ function PMA_displayResultsOperations($the_disp_mode, $analyzed_sql) { */ if (!$header_shown) { echo $header; - $header_shown = TRUE; + $header_shown = true; } if (! isset($analyzed_sql[0]['queryflags']['procedure'])) { echo PMA_linkOrButton( @@ -2387,7 +2417,7 @@ function PMA_handle_non_printable_contents($category, $content, $transform_funct } elseif (isset($content)) { $size = strlen($content); $display_size = PMA_formatByteDown($size, 3, 1); - $result .= ' - '. $display_size[0] . ' ' . $display_size[1]; + $result .= ' - '. $display_size[0] . ' ' . $display_size[1]; } $result .= ']'; @@ -2568,7 +2598,7 @@ function PMA_generateEditLink($edit_url, $class, $edit_str, $where_clause, $wher $ret = ''; if (! empty($edit_url)) { $ret .= '' - . PMA_linkOrButton($edit_url, $edit_str, array(), FALSE); + . PMA_linkOrButton($edit_url, $edit_str, array(), false); /* * Where clause for selecting this row uniquely is provided as * a hidden input. Used by jQuery scripts for handling inline editing @@ -2599,7 +2629,7 @@ function PMA_generateCopyLink($copy_url, $copy_str, $where_clause, $where_clause $ret .= 'class="' . $class . '" '; } $ret .= 'align="center" ' . ' >' - . PMA_linkOrButton($copy_url, $copy_str, array(), FALSE); + . PMA_linkOrButton($copy_url, $copy_str, array(), false); /* * Where clause for selecting this row uniquely is provided as * a hidden input. Used by jQuery scripts for handling inline editing @@ -2630,7 +2660,7 @@ function PMA_generateDeleteLink($del_url, $del_str, $js_conf, $class) { $ret .= 'class="' . $class . '" '; } $ret .= 'align="center" ' . ' >' - . PMA_linkOrButton($del_url, $del_str, $js_conf, FALSE) + . PMA_linkOrButton($del_url, $del_str, $js_conf, false) . ''; } return $ret; @@ -2680,6 +2710,8 @@ function PMA_generateCheckboxAndLinks($position, $del_url, $is_display, $row_no, $ret .= PMA_generateEditLink($edit_url, $class, $edit_str, $where_clause, $where_clause_html, ''); $ret .= PMA_generateCheckboxForMulti($del_url, $is_display, $row_no, $where_clause_html, $del_query, $id_suffix='_right', '', '', ''); + } else { // $position == 'none' + $ret .= PMA_generateCheckboxForMulti($del_url, $is_display, $row_no, $where_clause_html, $del_query, $id_suffix='_left', '', '', ''); } return $ret; } diff --git a/libraries/export/codegen.php b/libraries/export/codegen.php index 8e36f408f6..56c9d08572 100644 --- a/libraries/export/codegen.php +++ b/libraries/export/codegen.php @@ -54,7 +54,7 @@ if (isset($plugin_list)) { */ function PMA_exportComment($text) { - return TRUE; + return true; } /** @@ -66,7 +66,7 @@ function PMA_exportComment($text) */ function PMA_exportFooter() { - return TRUE; + return true; } /** @@ -78,7 +78,7 @@ function PMA_exportFooter() */ function PMA_exportHeader() { - return TRUE; + return true; } /** @@ -92,7 +92,7 @@ function PMA_exportHeader() */ function PMA_exportDBHeader($db) { - return TRUE; + return true; } /** @@ -106,7 +106,7 @@ function PMA_exportDBHeader($db) */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -120,7 +120,7 @@ function PMA_exportDBFooter($db) */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** diff --git a/libraries/export/csv.php b/libraries/export/csv.php index 6d6242ed7f..41c3cf39d7 100644 --- a/libraries/export/csv.php +++ b/libraries/export/csv.php @@ -40,7 +40,7 @@ if (isset($plugin_list)) { * @return bool Whether it suceeded */ function PMA_exportComment($text) { - return TRUE; + return true; } /** @@ -51,7 +51,7 @@ function PMA_exportComment($text) { * @access public */ function PMA_exportFooter() { - return TRUE; + return true; } /** @@ -98,7 +98,7 @@ function PMA_exportHeader() { } // end if $csv_separator = str_replace('\\t', "\011", $csv_separator); } - return TRUE; + return true; } /** @@ -111,7 +111,7 @@ function PMA_exportHeader() { * @access public */ function PMA_exportDBHeader($db) { - return TRUE; + return true; } /** @@ -124,7 +124,7 @@ function PMA_exportDBHeader($db) { * @access public */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -137,7 +137,7 @@ function PMA_exportDBFooter($db) { * @access public */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** @@ -179,7 +179,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { } // end for $schema_insert =trim(substr($schema_insert, 0, -1)); if (!PMA_exportOutputHandler($schema_insert . $csv_terminated)) { - return FALSE; + return false; } } // end if @@ -223,12 +223,12 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { } // end for if (!PMA_exportOutputHandler($schema_insert . $csv_terminated)) { - return FALSE; + return false; } } // end while PMA_DBI_free_result($result); - return TRUE; + return true; } // end of the 'PMA_getTableCsv()' function } diff --git a/libraries/export/htmlword.php b/libraries/export/htmlword.php index d23640a600..7b544764e9 100644 --- a/libraries/export/htmlword.php +++ b/libraries/export/htmlword.php @@ -41,7 +41,7 @@ if (isset($plugin_list)) { * @return bool Whether it suceeded */ function PMA_exportComment($text) { - return TRUE; + return true; } /** @@ -63,7 +63,7 @@ function PMA_exportFooter() { * @access public */ function PMA_exportHeader() { - global $charset, $charset_of_file; + global $charset_of_file; return PMA_exportOutputHandler(' @@ -71,7 +71,7 @@ xmlns="http://www.w3.org/TR/REC-html40"> - + '); } @@ -99,7 +99,7 @@ function PMA_exportDBHeader($db) { * @access public */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -112,7 +112,7 @@ function PMA_exportDBFooter($db) { * @access public */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** @@ -133,10 +133,10 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) global $what; if (! PMA_exportOutputHandler('

' . __('Dumping data for table') . ' ' . $table . '

')) { - return FALSE; + return false; } if (! PMA_exportOutputHandler('')) { - return FALSE; + return false; } // Gets the data from the database @@ -151,7 +151,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) } // end for $schema_insert .= ''; if (! PMA_exportOutputHandler($schema_insert)) { - return FALSE; + return false; } } // end if @@ -170,15 +170,15 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) } // end for $schema_insert .= ''; if (! PMA_exportOutputHandler($schema_insert)) { - return FALSE; + return false; } } // end while PMA_DBI_free_result($result); if (! PMA_exportOutputHandler('
')) { - return FALSE; + return false; } - return TRUE; + return true; } function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = false, $do_comments = false, $do_mime = false, $dates = false, $dummy) @@ -186,7 +186,7 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals global $cfgRelation; if (! PMA_exportOutputHandler('

' . __('Table structure for table') . ' ' .$table . '

')) { - return FALSE; + return false; } /** @@ -217,19 +217,19 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $res_rel = PMA_getForeigners($db, $table); if ($res_rel && count($res_rel) > 0) { - $have_rel = TRUE; + $have_rel = true; } else { - $have_rel = FALSE; + $have_rel = false; } } else { - $have_rel = FALSE; + $have_rel = false; } // end if /** * Displays the table structure */ if (! PMA_exportOutputHandler('')) { - return FALSE; + return false; } $columns_cnt = 4; @@ -262,7 +262,7 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $schema_insert .= ''; if (! PMA_exportOutputHandler($schema_insert)) { - return FALSE; + return false; } while ($row = PMA_DBI_fetch_assoc($result)) { @@ -340,7 +340,7 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $schema_insert .= ''; if (! PMA_exportOutputHandler($schema_insert)) { - return FALSE; + return false; } } // end while PMA_DBI_free_result($result); diff --git a/libraries/export/json.php b/libraries/export/json.php index 40f4a4db55..6f70dd451a 100644 --- a/libraries/export/json.php +++ b/libraries/export/json.php @@ -174,7 +174,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) $buffer .= ']'; if (! PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } PMA_DBI_free_result($result); diff --git a/libraries/export/latex.php b/libraries/export/latex.php index 2a434aed9e..9709dc4607 100644 --- a/libraries/export/latex.php +++ b/libraries/export/latex.php @@ -118,7 +118,7 @@ function PMA_exportComment($text) { * @access public */ function PMA_exportFooter() { - return TRUE; + return true; } /** @@ -174,7 +174,7 @@ function PMA_exportDBHeader($db) { * @access public */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -187,7 +187,7 @@ function PMA_exportDBFooter($db) { * @access public */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** @@ -226,7 +226,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { . '} \\label{' . PMA_expandUserString($GLOBALS['latex_data_label'], NULL, array('table' => $table, 'database' => $db)) . '} \\\\'; } if (!PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } // show column names @@ -238,17 +238,17 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { $buffer = substr($buffer, 0, -2) . '\\\\ \\hline \hline '; if (!PMA_exportOutputHandler($buffer . ' \\endfirsthead ' . $crlf)) { - return FALSE; + return false; } if (isset($GLOBALS['latex_caption'])) { - if (!PMA_exportOutputHandler('\\caption{' . PMA_expandUserString($GLOBALS['latex_data_continued_caption'], 'PMA_texEscape', array('table' => $table, 'database' => $db)) . '} \\\\ ')) return FALSE; + if (!PMA_exportOutputHandler('\\caption{' . PMA_expandUserString($GLOBALS['latex_data_continued_caption'], 'PMA_texEscape', array('table' => $table, 'database' => $db)) . '} \\\\ ')) return false; } if (!PMA_exportOutputHandler($buffer . '\\endhead \\endfoot' . $crlf)) { - return FALSE; + return false; } } else { if (!PMA_exportOutputHandler('\\\\ \hline')) { - return FALSE; + return false; } } @@ -274,17 +274,17 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { } $buffer .= ' \\\\ \\hline ' . $crlf; if (!PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } } $buffer = ' \\end{longtable}' . $crlf; if (!PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } PMA_DBI_free_result($result); - return TRUE; + return true; } // end getTableLaTeX @@ -337,12 +337,12 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $res_rel = PMA_getForeigners($db, $table); if ($res_rel && count($res_rel) > 0) { - $have_rel = TRUE; + $have_rel = true; } else { - $have_rel = FALSE; + $have_rel = false; } } else { - $have_rel = FALSE; + $have_rel = false; } // end if /** @@ -351,7 +351,7 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $buffer = $crlf . '%' . $crlf . '% ' . __('Structure') . ': ' . $table . $crlf . '%' . $crlf . ' \\begin{longtable}{'; if (!PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } $columns_cnt = 4; @@ -401,7 +401,7 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $buffer .= $header . ' \\\\ \\hline \\hline \\endhead \\endfoot ' . $crlf; if (!PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } while ($row = PMA_DBI_fetch_assoc($result)) { @@ -475,7 +475,7 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $buffer .= ' \\\\ \\hline ' . $crlf; if (!PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } } // end while PMA_DBI_free_result($result); diff --git a/libraries/export/mediawiki.php b/libraries/export/mediawiki.php index 9fa1b483ea..386b63e1d7 100644 --- a/libraries/export/mediawiki.php +++ b/libraries/export/mediawiki.php @@ -32,7 +32,7 @@ if (isset($plugin_list)) { * @return bool Whether it suceeded */ function PMA_exportComment($text) { - return TRUE; + return true; } /** @@ -43,7 +43,7 @@ function PMA_exportComment($text) { * @access public */ function PMA_exportFooter() { - return TRUE; + return true; } /** @@ -54,7 +54,7 @@ function PMA_exportFooter() { * @access public */ function PMA_exportHeader() { - return TRUE; + return true; } /** @@ -67,7 +67,7 @@ function PMA_exportHeader() { * @access public */ function PMA_exportDBHeader($db) { - return TRUE; + return true; } /** @@ -80,7 +80,7 @@ function PMA_exportDBHeader($db) { * @access public */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -93,7 +93,7 @@ function PMA_exportDBFooter($db) { * @access public */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** diff --git a/libraries/export/ods.php b/libraries/export/ods.php index 28a5dfd4cb..0237627e48 100644 --- a/libraries/export/ods.php +++ b/libraries/export/ods.php @@ -40,7 +40,7 @@ require_once './libraries/opendocument.lib.php'; * @return bool Whether it suceeded */ function PMA_exportComment($text) { - return TRUE; + return true; } /** @@ -55,9 +55,9 @@ function PMA_exportFooter() { . '' . ''; if (!PMA_exportOutputHandler(PMA_createOpenDocument('application/vnd.oasis.opendocument.spreadsheet', $GLOBALS['ods_buffer']))) { - return FALSE; + return false; } - return TRUE; + return true; } /** @@ -68,7 +68,7 @@ function PMA_exportFooter() { * @access public */ function PMA_exportHeader() { - $GLOBALS['ods_buffer'] .= '' + $GLOBALS['ods_buffer'] .= '' . '' . '' . '' @@ -106,7 +106,7 @@ function PMA_exportHeader() { . '' . '' . ''; - return TRUE; + return true; } /** @@ -119,7 +119,7 @@ function PMA_exportHeader() { * @access public */ function PMA_exportDBHeader($db) { - return TRUE; + return true; } /** @@ -132,7 +132,7 @@ function PMA_exportDBHeader($db) { * @access public */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -145,7 +145,7 @@ function PMA_exportDBFooter($db) { * @access public */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** @@ -228,7 +228,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { $GLOBALS['ods_buffer'] .= ''; - return TRUE; + return true; } } diff --git a/libraries/export/odt.php b/libraries/export/odt.php index d1324f0ecb..2210a1213d 100644 --- a/libraries/export/odt.php +++ b/libraries/export/odt.php @@ -72,7 +72,7 @@ require_once './libraries/opendocument.lib.php'; * @return bool Whether it suceeded */ function PMA_exportComment($text) { - return TRUE; + return true; } /** @@ -87,9 +87,9 @@ function PMA_exportFooter() { . '' . ''; if (!PMA_exportOutputHandler(PMA_createOpenDocument('application/vnd.oasis.opendocument.text', $GLOBALS['odt_buffer']))) { - return FALSE; + return false; } - return TRUE; + return true; } /** @@ -100,11 +100,11 @@ function PMA_exportFooter() { * @access public */ function PMA_exportHeader() { - $GLOBALS['odt_buffer'] .= '' + $GLOBALS['odt_buffer'] .= '' . '' . '' . ''; - return TRUE; + return true; } /** @@ -118,7 +118,7 @@ function PMA_exportHeader() { */ function PMA_exportDBHeader($db) { $GLOBALS['odt_buffer'] .= '' . htmlspecialchars(__('Database') . ' ' . $db) . ''; - return TRUE; + return true; } /** @@ -131,7 +131,7 @@ function PMA_exportDBHeader($db) { * @access public */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -144,7 +144,7 @@ function PMA_exportDBFooter($db) { * @access public */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** @@ -217,7 +217,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { $GLOBALS['odt_buffer'] .= ''; - return TRUE; + return true; } /** @@ -236,7 +236,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { * * @access public */ - // @@@ Table structure + // @@@ Table structure function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = false, $do_comments = false, $do_mime = false, $dates = false, $dummy) { global $cfgRelation; @@ -272,12 +272,12 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $res_rel = PMA_getForeigners($db, $table); if ($res_rel && count($res_rel) > 0) { - $have_rel = TRUE; + $have_rel = true; } else { - $have_rel = FALSE; + $have_rel = false; } } else { - $have_rel = FALSE; + $have_rel = false; } // end if /** @@ -412,7 +412,7 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals PMA_DBI_free_result($result); $GLOBALS['odt_buffer'] .= ''; - return TRUE; + return true; } // end of the 'PMA_exportStructure' function } // end else diff --git a/libraries/export/pdf.php b/libraries/export/pdf.php index 431df0da9a..fe9b46c874 100644 --- a/libraries/export/pdf.php +++ b/libraries/export/pdf.php @@ -365,7 +365,7 @@ $pdf = new PMA_PDF('L', 'pt', 'A3'); */ function PMA_exportComment($text) { - return TRUE; + return true; } /** @@ -381,10 +381,10 @@ function PMA_exportFooter() // instead of $pdf->Output(): if (!PMA_exportOutputHandler($pdf->getPDFData())) { - return FALSE; + return false; } - return TRUE; + return true; } /** @@ -412,7 +412,7 @@ function PMA_exportHeader() $pdf->setAttributes($attr); $pdf->setTopMargin(45); - return TRUE; + return true; } /** @@ -426,7 +426,7 @@ function PMA_exportHeader() */ function PMA_exportDBHeader($db) { - return TRUE; + return true; } /** @@ -440,7 +440,7 @@ function PMA_exportDBHeader($db) */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -454,7 +454,7 @@ function PMA_exportDBFooter($db) */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** @@ -479,7 +479,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) $pdf->setAttributes($attr); $pdf->mysql_report($sql_query); - return TRUE; + return true; } // end of the 'PMA_exportData()' function } ?> diff --git a/libraries/export/php_array.php b/libraries/export/php_array.php index 983673c68d..2c3b4e6348 100644 --- a/libraries/export/php_array.php +++ b/libraries/export/php_array.php @@ -167,7 +167,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) $buffer .= $crlf . ');' . $crlf; if (! PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } PMA_DBI_free_result($result); diff --git a/libraries/export/sql.php b/libraries/export/sql.php index 19f987364b..432aa78750 100644 --- a/libraries/export/sql.php +++ b/libraries/export/sql.php @@ -29,28 +29,55 @@ if (isset($plugin_list)) { $plugin_list['sql']['options'][] = array('type' => 'begin_group', 'name' => 'general_opts'); /* comments */ - $plugin_list['sql']['options'][] = - array('type' => 'begin_subgroup', 'subgroup_header' => array('type' => 'bool', 'name' => 'include_comments', 'text' => __('Display comments (includes info such as export timestamp, PHP version, and server version)'))); - $plugin_list['sql']['options'][] = - array('type' => 'text', 'name' => 'header_comment', 'text' => __('Additional custom header comment (\n splits lines):')); - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'dates', 'text' => __('Include a timestamp of when databases were created, last updated, and last checked')); + $plugin_list['sql']['options'][] = array( + 'type' => 'begin_subgroup', + 'subgroup_header' => array( + 'type' => 'bool', + 'name' => 'include_comments', + 'text' => __('Display comments (includes info such as export timestamp, PHP version, and server version)') + )); + $plugin_list['sql']['options'][] = array( + 'type' => 'text', + 'name' => 'header_comment', + 'text' => __('Additional custom header comment (\n splits lines):') + ); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'dates', + 'text' => __('Include a timestamp of when databases were created, last updated, and last checked') + ); if (!empty($GLOBALS['cfgRelation']['relation'])) { - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'relation', 'text' => __('Display foreign key relationships')); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'relation', + 'text' => __('Display foreign key relationships') + ); } if (!empty($GLOBALS['cfgRelation']['mimework'])) { - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'mime', 'text' => __('Display MIME types')); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'mime', + 'text' => __('Display MIME types') + ); } $plugin_list['sql']['options'][] = array('type' => 'end_subgroup'); /* end comments */ /* enclose in a transaction */ - $plugin_list['sql']['options'][] = array('type' => 'bool', 'name' => 'use_transaction', 'text' => __('Enclose export in a transaction'), 'doc' => array('programs', 'mysqldump', 'option_mysqldump_single-transaction')); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'use_transaction', + 'text' => __('Enclose export in a transaction'), + 'doc' => array('programs', 'mysqldump', 'option_mysqldump_single-transaction') + ); /* disable foreign key checks */ - $plugin_list['sql']['options'][] = array('type' => 'bool', 'name' => 'disable_fk', 'text' => __('Disable foreign key checks'), 'doc' => array('manual_MySQL_Database_Administration', 'server-system-variables', 'sysvar_foreign_key_checks')); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'disable_fk', + 'text' => __('Disable foreign key checks'), + 'doc' => array('manual_MySQL_Database_Administration', 'server-system-variables', 'sysvar_foreign_key_checks') + ); $plugin_list['sql']['options_text'] = __('Options'); @@ -61,34 +88,61 @@ if (isset($plugin_list)) { foreach($compats as $val) { $values[$val] = $val; } - $plugin_list['sql']['options'][] = - array('type' => 'select', 'name' => 'compatibility', 'text' => __('Database system or older MySQL server to maximize output compatibility with:'), 'values' => $values, 'doc' => array('manual_MySQL_Database_Administration', 'Server_SQL_mode')); + $plugin_list['sql']['options'][] = array( + 'type' => 'select', + 'name' => 'compatibility', + 'text' => __('Database system or older MySQL server to maximize output compatibility with:'), + 'values' => $values, + 'doc' => array('manual_MySQL_Database_Administration', 'Server_SQL_mode') + ); unset($values); } /* server export options */ if ($plugin_param['export_type'] == 'server') { - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'drop_database', 'text' => sprintf(__('Add %s statement'), 'DROP DATABASE')); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'drop_database', + 'text' => sprintf(__('Add %s statement'), 'DROP DATABASE') + ); } /* what to dump (structure/data/both) */ - $plugin_list['sql']['options'][] = - array('type' => 'begin_subgroup', 'subgroup_header' => array('type' => 'message_only', 'text' => __('Dump table'))); - $plugin_list['sql']['options'][] = - array('type' => 'radio', 'name' => 'structure_or_data', 'values' => array('structure' => __('structure'), 'data' => __('data'), 'structure_and_data' => __('structure and data'))); + $plugin_list['sql']['options'][] = array( + 'type' => 'begin_subgroup', + 'subgroup_header' => array( + 'type' => 'message_only', + 'text' => __('Dump table') + )); + $plugin_list['sql']['options'][] = array( + 'type' => 'radio', + 'name' => 'structure_or_data', + 'values' => array( + 'structure' => __('structure'), + 'data' => __('data'), + 'structure_and_data' => __('structure and data') + )); $plugin_list['sql']['options'][] = array('type' => 'end_subgroup'); $plugin_list['sql']['options'][] = array('type' => 'end_group'); /* begin Structure options */ if (!$hide_structure) { - $plugin_list['sql']['options'][] = - array('type' => 'begin_group', 'name' => 'structure', 'text' => __('Object creation options'), 'force' => 'data'); + $plugin_list['sql']['options'][] = array( + 'type' => 'begin_group', + 'name' => 'structure', + 'text' => __('Object creation options'), + 'force' => 'data' + ); /* begin SQL Statements */ - $plugin_list['sql']['options'][] = - array('type' => 'begin_subgroup', 'subgroup_header' => array('type' => 'message_only', 'name' => 'add_statements', 'text' => __('Add statements:'))); + $plugin_list['sql']['options'][] = array( + 'type' => 'begin_subgroup', + 'subgroup_header' => array( + 'type' => 'message_only', + 'name' => 'add_statements', + 'text' => __('Add statements:') + )); if ($plugin_param['export_type'] == 'table') { if (PMA_Table::isView($GLOBALS['db'], $GLOBALS['table'])) { $drop_clause = 'DROP VIEW'; @@ -101,74 +155,131 @@ if (isset($plugin_list)) { $drop_clause .= ' / EVENT'; } } - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'drop_table', 'text' => sprintf(__('Add %s statement'), $drop_clause)); - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'procedure_function', 'text' => sprintf(__('Add %s statement'), 'CREATE PROCEDURE / FUNCTION' . (PMA_MYSQL_INT_VERSION > 50100 ? ' / EVENT' : ''))); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'drop_table', + 'text' => sprintf(__('Add %s statement'), $drop_clause) + ); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'procedure_function', + 'text' => sprintf(__('Add %s statement'), 'CREATE PROCEDURE / FUNCTION' . (PMA_MYSQL_INT_VERSION > 50100 ? ' / EVENT' : '')) + ); /* begin CREATE TABLE statements*/ - $plugin_list['sql']['options'][] = - array('type' => 'begin_subgroup', 'subgroup_header' => array('type' => 'bool', 'name' => 'create_table_statements', 'text' => __('CREATE TABLE options:'))); - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'if_not_exists', 'text' => 'IF NOT EXISTS'); - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'auto_increment', 'text' => 'AUTO_INCREMENT'); + $plugin_list['sql']['options'][] = array( + 'type' => 'begin_subgroup', + 'subgroup_header' => array( + 'type' => 'bool', + 'name' => 'create_table_statements', + 'text' => __('CREATE TABLE options:') + )); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'if_not_exists', + 'text' => 'IF NOT EXISTS' + ); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'auto_increment', + 'text' => 'AUTO_INCREMENT' + ); $plugin_list['sql']['options'][] = array('type' => 'end_subgroup'); /* end CREATE TABLE statements */ $plugin_list['sql']['options'][] = array('type' => 'end_subgroup'); /* end SQL statements */ - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'backquotes', 'text' => __('Enclose table and field names with backquotes (Protects field and table names formed with special characters or keywords)')); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'backquotes', + 'text' => __('Enclose table and field names with backquotes (Protects field and table names formed with special characters or keywords)') + ); - $plugin_list['sql']['options'][] = - array('type' => 'end_group'); + $plugin_list['sql']['options'][] = array('type' => 'end_group'); } /* end Structure options */ /* begin Data options */ - $plugin_list['sql']['options'][] = - array('type' => 'begin_group', 'name' => 'data', 'text' => __('Data dump options'), 'force' => 'structure'); + $plugin_list['sql']['options'][] = array( + 'type' => 'begin_group', + 'name' => 'data', + 'text' => __('Data dump options'), + 'force' => 'structure' + ); /* begin SQL statements */ - $plugin_list['sql']['options'][] = - array('type' => 'begin_subgroup', 'subgroup_header' => array('type' => 'message_only', 'text' => __('Instead of INSERT statements, use:'))); - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'delayed', 'text' => __('INSERT DELAYED statements'), 'doc' => array('manual_MySQL_Database_Administration', 'insert_delayed')); - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'ignore', 'text' => __('INSERT IGNORE statements'), 'doc' => array('manual_MySQL_Database_Administration', 'insert')); - $plugin_list['sql']['options'][] = - array('type' => 'end_subgroup'); + $plugin_list['sql']['options'][] = array( + 'type' => 'begin_subgroup', + 'subgroup_header' => array( + 'type' => 'message_only', + 'text' => __('Instead of INSERT statements, use:') + )); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'delayed', + 'text' => __('INSERT DELAYED statements'), + 'doc' => array('manual_MySQL_Database_Administration', 'insert_delayed') + ); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'ignore', + 'text' => __('INSERT IGNORE statements'), + 'doc' => array('manual_MySQL_Database_Administration', 'insert') + ); + $plugin_list['sql']['options'][] = array('type' => 'end_subgroup'); /* end SQL statements */ /* Function to use when dumping data */ - $plugin_list['sql']['options'][] = - array('type' => 'select', 'name' => 'type', 'text' => __('Function to use when dumping data:'), 'values' => array('INSERT' => 'INSERT', 'UPDATE' => 'UPDATE', 'REPLACE' => 'REPLACE')); + $plugin_list['sql']['options'][] = array( + 'type' => 'select', + 'name' => 'type', + 'text' => __('Function to use when dumping data:'), + 'values' => array( + 'INSERT' => 'INSERT', + 'UPDATE' => 'UPDATE', + 'REPLACE' => 'REPLACE' + ) + ); /* Syntax to use when inserting data */ - $plugin_list['sql']['options'][] = - array('type' => 'begin_subgroup', 'subgroup_header' => array('type' => 'message_only', 'text' => __('Syntax to use when inserting data:'))); - $plugin_list['sql']['options'][] = - array('type' => 'radio', 'name' => 'insert_syntax', 'values' => array( + $plugin_list['sql']['options'][] = array( + 'type' => 'begin_subgroup', + 'subgroup_header' => array( + 'type' => 'message_only', + 'text' => __('Syntax to use when inserting data:') + )); + $plugin_list['sql']['options'][] = array( + 'type' => 'radio', + 'name' => 'insert_syntax', + 'values' => array( 'complete' => __('include column names in every INSERT statement
      Example: INSERT INTO tbl_name (col_A,col_B,col_C) VALUES (1,2,3)'), 'extended' => __('insert multiple rows in every INSERT statement
      Example: INSERT INTO tbl_name VALUES (1,2,3), (4,5,6), (7,8,9)'), 'both' => __('both of the above
      Example: INSERT INTO tbl_name (col_A,col_B) VALUES (1,2,3), (4,5,6), (7,8,9)'), - 'none' => __('neither of the above
      Example: INSERT INTO tbl_name VALUES (1,2,3)'))); - $plugin_list['sql']['options'][] = - array('type' => 'end_subgroup'); + 'none' => __('neither of the above
      Example: INSERT INTO tbl_name VALUES (1,2,3)') + )); + $plugin_list['sql']['options'][] = array('type' => 'end_subgroup'); /* Max length of query */ - $plugin_list['sql']['options'][] = - array('type' => 'text', 'name' => 'max_query_size', 'text' => __('Maximal length of created query')); + $plugin_list['sql']['options'][] = array( + 'type' => 'text', + 'name' => 'max_query_size', + 'text' => __('Maximal length of created query') + ); /* Dump binary columns in hexadecimal */ - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'hex_for_blob', 'text' => __('Dump binary columns in hexadecimal notation (for example, "abc" becomes 0x616263)')); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'hex_for_blob', + 'text' => __('Dump binary columns in hexadecimal notation (for example, "abc" becomes 0x616263)') + ); /* Dump time in UTC */ - $plugin_list['sql']['options'][] = - array('type' => 'bool', 'name' => 'utc_time', 'text' => __('Dump TIMESTAMP columns in UTC (enables TIMESTAMP columns to be dumped and reloaded between servers in different time zones)')); + $plugin_list['sql']['options'][] = array( + 'type' => 'bool', + 'name' => 'utc_time', + 'text' => __('Dump TIMESTAMP columns in UTC (enables TIMESTAMP columns to be dumped and reloaded between servers in different time zones)') + ); $plugin_list['sql']['options'][] = array('type' => 'end_group'); /* end Data options */ @@ -183,9 +294,9 @@ if (! isset($sql_backquotes)) { } /** - * Exports routines (procedures and functions) + * Exports routines (procedures and functions) * - * @param string $db + * @param string $db * * @return bool Whether it suceeded */ @@ -338,7 +449,11 @@ function PMA_exportHeader() . PMA_exportComment('version ' . PMA_VERSION) . PMA_exportComment('http://www.phpmyadmin.net') . PMA_exportComment(); - $head .= empty($cfg['Server']['port']) ? PMA_exportComment(__('Host') . ': ' . $cfg['Server']['host']) : PMA_exportComment(__('Host') . ': ' . $cfg['Server']['host'] . ':' . $cfg['Server']['port']); + $host_string = __('Host') . ': ' . $cfg['Server']['host']; + if (!empty($cfg['Server']['port'])) { + $host_string .= ':' . $cfg['Server']['port']; + } + $head .= PMA_exportComment($host_string); $head .= PMA_exportComment(__('Generation Time') . ': ' . PMA_localisedDate()) . PMA_exportComment(__('Server version') . ': ' . substr(PMA_MYSQL_INT_VERSION, 0, 1) . '.' . (int) substr(PMA_MYSQL_INT_VERSION, 1, 2) . '.' . (int) substr(PMA_MYSQL_INT_VERSION, 3)) @@ -389,7 +504,7 @@ function PMA_exportHeader() $set_names = $mysql_charset_map[$GLOBALS['charset_of_file']]; } else { // by default we use the connection charset - $set_names = $mysql_charset_map[$GLOBALS['charset']]; + $set_names = $mysql_charset_map['utf-8']; } $head .= $crlf . '/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;' . $crlf @@ -415,7 +530,7 @@ function PMA_exportDBCreate($db) global $crlf; if (isset($GLOBALS['sql_drop_database'])) { if (!PMA_exportOutputHandler('DROP DATABASE ' . (isset($GLOBALS['sql_backquotes']) ? PMA_backquote($db) : $db) . ';' . $crlf)) { - return FALSE; + return false; } } $create_query = 'CREATE DATABASE ' . (isset($GLOBALS['sql_backquotes']) ? PMA_backquote($db) : $db); @@ -427,7 +542,7 @@ function PMA_exportDBCreate($db) } $create_query .= ';' . $crlf; if (!PMA_exportOutputHandler($create_query)) { - return FALSE; + return false; } if (isset($GLOBALS['sql_backquotes']) && isset($GLOBALS['sql_compatibility']) && $GLOBALS['sql_compatibility'] == 'NONE') { $result = PMA_exportOutputHandler('USE ' . PMA_backquote($db) . ';' . $crlf); @@ -468,7 +583,7 @@ function PMA_exportDBFooter($db) { global $crlf; - $result = TRUE; + $result = true; if (isset($GLOBALS['sql_constraints'])) { $result = PMA_exportOutputHandler($GLOBALS['sql_constraints']); unset($GLOBALS['sql_constraints']); @@ -577,7 +692,7 @@ function PMA_getTableDef($db, $table, $crlf, $error_url, $show_dates = false, $a // need to use PMA_DBI_QUERY_STORE with PMA_DBI_num_rows() in mysqli $result = PMA_DBI_query('SHOW TABLE STATUS FROM ' . PMA_backquote($db) . ' LIKE \'' . PMA_sqlAddslashes($table) . '\'', null, PMA_DBI_QUERY_STORE); - if ($result != FALSE) { + if ($result != false) { if (PMA_DBI_num_rows($result) > 0) { $tmpres = PMA_DBI_fetch_assoc($result); // Here we optionally add the AUTO_INCREMENT next value, @@ -636,7 +751,7 @@ function PMA_getTableDef($db, $table, $crlf, $error_url, $show_dates = false, $a return PMA_exportComment(__('in use') . '(' . $tmp_error . ')'); } - if ($result != FALSE && ($row = PMA_DBI_fetch_row($result))) { + if ($result != false && ($row = PMA_DBI_fetch_row($result))) { $create_query = $row[1]; unset($row); @@ -710,13 +825,13 @@ function PMA_getTableDef($db, $table, $crlf, $error_url, $show_dates = false, $a $sql_constraints .= 'ALTER TABLE ' . PMA_backquote($table) . $crlf; $sql_drop_foreign_keys .= 'ALTER TABLE ' . PMA_backquote($db) . '.' . PMA_backquote($table) . $crlf; - $first = TRUE; + $first = true; for ($j = $i; $j < $sql_count; $j++) { if (preg_match('@CONSTRAINT|FOREIGN[\s]+KEY@', $sql_lines[$j])) { if (!$first) { $sql_constraints .= $crlf; } - if (strpos($sql_lines[$j], 'CONSTRAINT') === FALSE) { + if (strpos($sql_lines[$j], 'CONSTRAINT') === false) { $tmp_str = preg_replace('/(FOREIGN[\s]+KEY)/', 'ADD \1', $sql_lines[$j]); $sql_constraints_query .= $tmp_str; $sql_constraints .= $tmp_str; @@ -730,7 +845,7 @@ function PMA_getTableDef($db, $table, $crlf, $error_url, $show_dates = false, $a } $sql_drop_foreign_keys .= 'DROP FOREIGN KEY ' . $matches[3]; } - $first = FALSE; + $first = false; } else { break; } @@ -784,12 +899,12 @@ function PMA_getTableComments($db, $table, $crlf, $do_relation = false, $do_mim $res_rel = PMA_getForeigners($db, $table); if ($res_rel && count($res_rel) > 0) { - $have_rel = TRUE; + $have_rel = true; } else { - $have_rel = FALSE; + $have_rel = false; } } else { - $have_rel = FALSE; + $have_rel = false; } // end if if ($do_mime && $cfgRelation['mimework']) { @@ -847,7 +962,7 @@ function PMA_getTableComments($db, $table, $crlf, $do_relation = false, $do_mim * * @access public */ -function PMA_exportStructure($db, $table, $crlf, $error_url, $relation = FALSE, $comments = FALSE, $mime = FALSE, $dates = FALSE, $export_mode, $export_type) +function PMA_exportStructure($db, $table, $crlf, $error_url, $relation = false, $comments = false, $mime = false, $dates = false, $export_mode, $export_type) { $formatted_table_name = (isset($GLOBALS['sql_backquotes'])) ? PMA_backquote($table) @@ -947,7 +1062,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) . PMA_possibleCRLF(); if (! PMA_exportOutputHandler($head)) { - return FALSE; + return false; } return true; } @@ -967,7 +1082,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) return PMA_exportOutputHandler(PMA_exportComment(__('in use') . ' (' . $tmp_error . ')')); } - if ($result != FALSE) { + if ($result != false) { $fields_cnt = PMA_DBI_num_fields($result); // Get field information @@ -1044,7 +1159,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) . PMA_exportComment() . $crlf; if (! PMA_exportOutputHandler($head)) { - return FALSE; + return false; } } $current_row++; @@ -1110,7 +1225,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) $insert_line = '(' . implode(', ', $values) . ')'; if (isset($GLOBALS['sql_max_query_size']) && $GLOBALS['sql_max_query_size'] > 0 && $query_size + strlen($insert_line) > $GLOBALS['sql_max_query_size']) { if (!PMA_exportOutputHandler(';' . $crlf)) { - return FALSE; + return false; } $query_size = 0; $current_row = 1; @@ -1127,19 +1242,19 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) unset($values); if (!PMA_exportOutputHandler(($current_row == 1 ? '' : $separator . $crlf) . $insert_line)) { - return FALSE; + return false; } } // end while if ($current_row > 0) { if (!PMA_exportOutputHandler(';' . $crlf)) { - return FALSE; + return false; } } - } // end if ($result != FALSE) + } // end if ($result != false) PMA_DBI_free_result($result); - return TRUE; + return true; } // end of the 'PMA_exportData()' function } ?> diff --git a/libraries/export/texytext.php b/libraries/export/texytext.php index 1895bcf5ac..d15b43e1c3 100644 --- a/libraries/export/texytext.php +++ b/libraries/export/texytext.php @@ -39,7 +39,7 @@ if (isset($plugin_list)) { * @return bool Whether it suceeded */ function PMA_exportComment($text) { - return TRUE; + return true; } /** @@ -87,7 +87,7 @@ function PMA_exportDBHeader($db) { * @access public */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -100,7 +100,7 @@ function PMA_exportDBFooter($db) { * @access public */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** @@ -121,7 +121,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) global $what; if (! PMA_exportOutputHandler('== ' . __('Dumping data for table') . ' ' . $table . "\n\n")) { - return FALSE; + return false; } // Gets the data from the database @@ -136,7 +136,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) } // end for $text_output .= "\n|------\n"; if (! PMA_exportOutputHandler($text_output)) { - return FALSE; + return false; } } // end if @@ -155,12 +155,12 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) } // end for $text_output .= "\n"; if (! PMA_exportOutputHandler($text_output)) { - return FALSE; + return false; } } // end while PMA_DBI_free_result($result); - return TRUE; + return true; } function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = false, $do_comments = false, $do_mime = false, $dates = false, $dummy) @@ -168,7 +168,7 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals global $cfgRelation; if (! PMA_exportOutputHandler('== ' . __('Table structure for table') . ' ' .$table . "\n\n")) { - return FALSE; + return false; } /** @@ -199,12 +199,12 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $res_rel = PMA_getForeigners($db, $table); if ($res_rel && count($res_rel) > 0) { - $have_rel = TRUE; + $have_rel = true; } else { - $have_rel = FALSE; + $have_rel = false; } } else { - $have_rel = FALSE; + $have_rel = false; } // end if /** @@ -241,7 +241,7 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $text_output .= "\n|------\n"; if (! PMA_exportOutputHandler($text_output)) { - return FALSE; + return false; } while ($row = PMA_DBI_fetch_assoc($result)) { @@ -319,7 +319,7 @@ function PMA_exportStructure($db, $table, $crlf, $error_url, $do_relation = fals $text_output .= "\n"; if (! PMA_exportOutputHandler($text_output)) { - return FALSE; + return false; } } // end while PMA_DBI_free_result($result); diff --git a/libraries/export/xls.php b/libraries/export/xls.php index 599025d63b..01e2ae425b 100644 --- a/libraries/export/xls.php +++ b/libraries/export/xls.php @@ -43,7 +43,7 @@ require_once './libraries/PHPExcel/PHPExcel/Writer/Excel5.php'; * @return bool Whether it suceeded */ function PMA_exportComment($text) { - return TRUE; + return true; } /** @@ -64,7 +64,7 @@ function PMA_exportFooter() { $workbookWriter->save($tmp_filename); if (!PMA_exportOutputHandler(file_get_contents($tmp_filename))) { - return FALSE; + return false; } unlink($tmp_filename); @@ -72,7 +72,7 @@ function PMA_exportFooter() { unset($GLOBALS['workbook']); unset($GLOBALS['sheet_index']); - return TRUE; + return true; } /** @@ -95,7 +95,7 @@ function PMA_exportHeader() { $workbook->getProperties()->setTitle($db); $workbook->getProperties()->setSubject('phpMyAdmin ' . PMA_VERSION . ' XLS Dump'); - return TRUE; + return true; } /** @@ -110,7 +110,7 @@ function PMA_exportHeader() { function PMA_exportDBHeader($db) { - return TRUE; + return true; } /** @@ -123,7 +123,7 @@ function PMA_exportDBHeader($db) { * @access public */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -136,7 +136,7 @@ function PMA_exportDBFooter($db) { * @access public */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** @@ -200,7 +200,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { $sheet_index++; } - return TRUE; + return true; } } diff --git a/libraries/export/xlsx.php b/libraries/export/xlsx.php index 89c5288570..190cd2f1e5 100644 --- a/libraries/export/xlsx.php +++ b/libraries/export/xlsx.php @@ -43,7 +43,7 @@ require_once './libraries/PHPExcel/PHPExcel/Writer/Excel2007.php'; * @return bool Whether it suceeded */ function PMA_exportComment($text) { - return TRUE; + return true; } /** @@ -63,7 +63,7 @@ function PMA_exportFooter() { $workbookWriter->save($tmp_filename); if (!PMA_exportOutputHandler(file_get_contents($tmp_filename))) { - return FALSE; + return false; } unlink($tmp_filename); @@ -71,7 +71,7 @@ function PMA_exportFooter() { unset($GLOBALS['workbook']); unset($GLOBALS['sheet_index']); - return TRUE; + return true; } /** @@ -94,7 +94,7 @@ function PMA_exportHeader() { $workbook->getProperties()->setTitle($db); $workbook->getProperties()->setSubject('phpMyAdmin ' . PMA_VERSION . ' XLSX Dump'); - return TRUE; + return true; } /** @@ -109,7 +109,7 @@ function PMA_exportHeader() { function PMA_exportDBHeader($db) { - return TRUE; + return true; } /** @@ -122,7 +122,7 @@ function PMA_exportDBHeader($db) { * @access public */ function PMA_exportDBFooter($db) { - return TRUE; + return true; } /** @@ -135,7 +135,7 @@ function PMA_exportDBFooter($db) { * @access public */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } /** @@ -199,7 +199,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { $sheet_index++; } - return TRUE; + return true; } } diff --git a/libraries/export/xml.php b/libraries/export/xml.php index 9bafb0998d..e27bd2fa63 100644 --- a/libraries/export/xml.php +++ b/libraries/export/xml.php @@ -3,7 +3,7 @@ /** * Set of functions used to build XML dumps of tables * - * @todo + * @todo * @package phpMyAdmin-Export-XML */ if (! defined('PHPMYADMIN')) { @@ -24,7 +24,7 @@ if (isset($plugin_list)) { ), 'options_text' => __('Options') ); - + /* Export structure */ $plugin_list['xml']['options'][] = array('type' => 'begin_group', 'name' => 'structure', 'text' => __('Object creation options (all are recommended)')); @@ -39,7 +39,7 @@ if (isset($plugin_list)) { $plugin_list['xml']['options'][] = array('type' => 'bool', 'name' => 'export_views', 'text' => __('Views')); $plugin_list['xml']['options'][] = array('type' => 'end_group'); - + /* Data */ $plugin_list['xml']['options'][] = array('type' => 'begin_group', 'name' => 'data', 'text' => __('Data dump options')); @@ -68,7 +68,7 @@ function PMA_exportComment($text) { */ function PMA_exportFooter() { $foot = ''; - + return PMA_exportOutputHandler($foot); } @@ -86,14 +86,14 @@ function PMA_exportHeader() { global $db; global $table; global $tables; - + $export_struct = isset($GLOBALS[$what . '_export_struc']) ? true : false; $export_data = isset($GLOBALS[$what . '_export_contents']) ? true : false; if ($GLOBALS['output_charset_conversion']) { $charset = $GLOBALS['charset_of_file']; } else { - $charset = $GLOBALS['charset']; + $charset = 'utf-8'; } $head = '' . $crlf @@ -111,53 +111,53 @@ function PMA_exportHeader() { . '- ' . __('Server version') . ': ' . substr(PMA_MYSQL_INT_VERSION, 0, 1) . '.' . (int) substr(PMA_MYSQL_INT_VERSION, 1, 2) . '.' . (int) substr(PMA_MYSQL_INT_VERSION, 3) . $crlf . '- ' . __('PHP Version') . ': ' . phpversion() . $crlf . '-->' . $crlf . $crlf; - + $head .= '' . $crlf; - + if ($export_struct) { $result = PMA_DBI_fetch_result('SELECT `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME` FROM `information_schema`.`SCHEMATA` WHERE `SCHEMA_NAME` = \''.$db.'\' LIMIT 1'); $db_collation = $result[0]['DEFAULT_COLLATION_NAME']; $db_charset = $result[0]['DEFAULT_CHARACTER_SET_NAME']; - + $head .= ' ' . $crlf; $head .= ' ' . $crlf; $head .= ' ' . $crlf; - + if (count($tables) == 0) { $tables[] = $table; } - + foreach ($tables as $table) { // Export tables and views $result = PMA_DBI_fetch_result('SHOW CREATE TABLE ' . PMA_backquote($db) . '.' . PMA_backquote($table), 0); $tbl = $result[$table][1]; - + $is_view = PMA_isView($db, $table); - + if ($is_view) { $type = 'view'; } else { $type = 'table'; } - + if ($is_view && ! isset($GLOBALS[$what . '_export_views'])) { continue; } - + if (! $is_view && ! isset($GLOBALS[$what . '_export_tables'])) { continue; } - + $head .= ' ' . $crlf; - + $tbl = " " . $tbl; $tbl = str_replace("\n", "\n ", $tbl); - + $head .= $tbl . ';' . $crlf; $head .= ' ' . $crlf; - + if (isset($GLOBALS[$what . '_export_triggers']) && $GLOBALS[$what . '_export_triggers']) { // Export triggers $triggers = PMA_DBI_get_triggers($db, $table); @@ -165,78 +165,78 @@ function PMA_exportHeader() { foreach ($triggers as $trigger) { $code = $trigger['create']; $head .= ' ' . $crlf; - + // Do some formatting $code = substr(rtrim($code), 0, -3); $code = " " . $code; $code = str_replace("\n", "\n ", $code); - + $head .= $code . $crlf; $head .= ' ' . $crlf; } - + unset($trigger); unset($triggers); } } } - + if (isset($GLOBALS[$what . '_export_functions']) && $GLOBALS[$what . '_export_functions']) { // Export functions $functions = PMA_DBI_get_procedures_or_functions($db, 'FUNCTION'); if ($functions) { foreach ($functions as $function) { $head .= ' ' . $crlf; - + // Do some formatting $sql = PMA_DBI_get_definition($db, 'FUNCTION', $function); $sql = rtrim($sql); $sql = " " . $sql; $sql = str_replace("\n", "\n ", $sql); - + $head .= $sql . $crlf; $head .= ' ' . $crlf; } - + unset($create_func); unset($function); unset($functions); } } - + if (isset($GLOBALS[$what . '_export_procedures']) && $GLOBALS[$what . '_export_procedures']) { // Export procedures $procedures = PMA_DBI_get_procedures_or_functions($db, 'PROCEDURE'); if ($procedures) { foreach ($procedures as $procedure) { $head .= ' ' . $crlf; - + // Do some formatting $sql = PMA_DBI_get_definition($db, 'PROCEDURE', $procedure); $sql = rtrim($sql); $sql = " " . $sql; $sql = str_replace("\n", "\n ", $sql); - + $head .= $sql . $crlf; $head .= ' ' . $crlf; } - + unset($create_proc); unset($procedure); unset($procedures); } } - + unset($result); - + $head .= ' ' . $crlf; $head .= ' ' . $crlf; - + if ($export_data) { $head .= $crlf; } } - + return PMA_exportOutputHandler($head); } @@ -252,18 +252,18 @@ function PMA_exportHeader() { function PMA_exportDBHeader($db) { global $crlf; global $what; - + if (isset($GLOBALS[$what . '_export_contents']) && $GLOBALS[$what . '_export_contents']) { $head = ' ' . $crlf . ' ' . $crlf; - + return PMA_exportOutputHandler($head); } else { - return TRUE; + return true; } } @@ -279,13 +279,13 @@ function PMA_exportDBHeader($db) { function PMA_exportDBFooter($db) { global $crlf; global $what; - + if (isset($GLOBALS[$what . '_export_contents']) && $GLOBALS[$what . '_export_contents']) { return PMA_exportOutputHandler(' ' . $crlf); } else { - return TRUE; + return true; } } @@ -299,7 +299,7 @@ function PMA_exportDBFooter($db) { * @access public */ function PMA_exportDBCreate($db) { - return TRUE; + return true; } @@ -318,21 +318,21 @@ function PMA_exportDBCreate($db) { */ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { global $what; - + if (isset($GLOBALS[$what . '_export_contents']) && $GLOBALS[$what . '_export_contents']) { $result = PMA_DBI_query($sql_query, null, PMA_DBI_QUERY_UNBUFFERED); - + $columns_cnt = PMA_DBI_num_fields($result); for ($i = 0; $i < $columns_cnt; $i++) { $columns[$i] = stripslashes(str_replace(' ', '_', PMA_DBI_field_name($result, $i))); } unset($i); - + $buffer = ' ' . $crlf; if (!PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } - + while ($record = PMA_DBI_fetch_row($result)) { $buffer = '
' . $crlf; for ($i = 0; $i < $columns_cnt; $i++) { @@ -344,15 +344,15 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) { . '' . $crlf; } $buffer .= '
' . $crlf; - + if (!PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } } PMA_DBI_free_result($result); } - return TRUE; + return true; } // end of the 'PMA_getTableXML()' function } } diff --git a/libraries/export/yaml.php b/libraries/export/yaml.php index 550eb1d225..9d9f7e5b87 100644 --- a/libraries/export/yaml.php +++ b/libraries/export/yaml.php @@ -173,7 +173,7 @@ function PMA_exportData($db, $table, $crlf, $error_url, $sql_query) } if (! PMA_exportOutputHandler($buffer)) { - return FALSE; + return false; } } PMA_DBI_free_result($result); diff --git a/libraries/file_listing.php b/libraries/file_listing.php index 1ca97112b7..ff1cf9dbe7 100644 --- a/libraries/file_listing.php +++ b/libraries/file_listing.php @@ -12,7 +12,7 @@ * * @param string directory to list * @param string regular expression to match files - * @returns array sorted file list on success, FALSE on failure + * @returns array sorted file list on success, false on failure */ function PMA_getDirContent($dir, $expression = '') { @@ -32,7 +32,7 @@ function PMA_getDirContent($dir, $expression = '') asort($result); return $result; } else { - return FALSE; + return false; } } @@ -42,13 +42,13 @@ function PMA_getDirContent($dir, $expression = '') * @param string directory to list * @param string regullar expression to match files * @param string currently active choice - * @returns array sorted file list on success, FALSE on failure + * @returns array sorted file list on success, false on failure */ function PMA_getFileSelectOptions($dir, $extensions = '', $active = '') { $list = PMA_getDirContent($dir, $extensions); - if ($list === FALSE) { - return FALSE; + if ($list === false) { + return false; } $result = ''; foreach ($list as $key => $val) { diff --git a/libraries/header_http.inc.php b/libraries/header_http.inc.php index 9ad890dba9..f9d7d71483 100644 --- a/libraries/header_http.inc.php +++ b/libraries/header_http.inc.php @@ -30,6 +30,6 @@ header('Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-ch header('Pragma: no-cache'); // HTTP/1.0 if (!defined('IS_TRANSFORMATION_WRAPPER')) { // Define the charset to be used - header('Content-Type: text/html; charset=' . $GLOBALS['charset']); + header('Content-Type: text/html; charset=utf-8'); } ?> diff --git a/libraries/header_meta_style.inc.php b/libraries/header_meta_style.inc.php index 0c6633db68..5e5c533da4 100644 --- a/libraries/header_meta_style.inc.php +++ b/libraries/header_meta_style.inc.php @@ -28,14 +28,14 @@ if ($GLOBALS['text_dir'] == 'ltr') { } // removes the bug with the horizontal scrollbar in IE (it's allways shown, if need it or not) // xml declaration moves IE into quirks mode, making much trouble with CSS -/* echo ''; */ +/* echo ''; */ ?> - + <?php diff --git a/libraries/header_printview.inc.php b/libraries/header_printview.inc.php index 4a30f2b816..bef4658804 100644 --- a/libraries/header_printview.inc.php +++ b/libraries/header_printview.inc.php @@ -43,7 +43,7 @@ if ($text_dir == 'ltr') { <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $available_languages[$lang][1]; ?>" lang="<?php echo $available_languages[$lang][1]; ?>" dir="<?php echo $text_dir; ?>"> <head> -<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $charset; ?>" /> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="icon" href="./favicon.ico" type="image/x-icon" /> <link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" /> <title><?php echo __('SQL result'); ?> - phpMyAdmin <?php echo PMA_VERSION ?> @@ -69,5 +69,5 @@ if ($text_dir == 'ltr') { /** * Sets a variable to remember headers have been sent */ -$is_header_sent = TRUE; +$is_header_sent = true; ?> diff --git a/libraries/header_scripts.inc.php b/libraries/header_scripts.inc.php index c25aa990ea..2e0a9ca1e4 100644 --- a/libraries/header_scripts.inc.php +++ b/libraries/header_scripts.inc.php @@ -39,6 +39,8 @@ if (isset($GLOBALS['db'])) { $params['db'] = $GLOBALS['db']; } $GLOBALS['js_include'][] = 'messages.php' . PMA_generate_common_url($params); +$GLOBALS['js_include'][] = 'codemirror/lib/codemirror.js'; +$GLOBALS['js_include'][] = 'codemirror/mode/mysql/mysql.js'; /** * Here we add a timestamp when loading the file, so that users who diff --git a/libraries/iconv_wrapper.lib.php b/libraries/iconv_wrapper.lib.php index 2efd6158c3..1f00c13406 100644 --- a/libraries/iconv_wrapper.lib.php +++ b/libraries/iconv_wrapper.lib.php @@ -44,7 +44,7 @@ $gnu_iconv_to_aix_iconv_codepage_map = array ( * @param string output character set * @param string the string to convert * - * @return mixed converted string or FALSE on failure + * @return mixed converted string or false on failure * * @access public * @@ -55,7 +55,7 @@ function PMA_aix_iconv_wrapper($in_charset, $out_charset, $str) { // Check for transliteration argument at the end of output character set name $translit_search = strpos(strtolower($out_charset), '//translit'); - $using_translit = (!($translit_search === FALSE)); + $using_translit = (!($translit_search === false)); // Extract "plain" output character set name (without any transliteration argument) $out_charset_plain = ($using_translit ? substr($out_charset, 0, $translit_search) : $out_charset); diff --git a/libraries/import.lib.php b/libraries/import.lib.php index 0c77f5419c..11ae523172 100644 --- a/libraries/import.lib.php +++ b/libraries/import.lib.php @@ -29,15 +29,15 @@ function PMA_checkTimeout() { global $timestamp, $maximum_time, $timeout_passed; if ($maximum_time == 0) { - return FALSE; + return false; } elseif ($timeout_passed) { - return TRUE; + return true; /* 5 in next row might be too much */ } elseif ((time() - $timestamp) > ($maximum_time - 5)) { - $timeout_passed = TRUE; - return TRUE; + $timeout_passed = true; + return true; } else { - return FALSE; + return false; } } @@ -52,7 +52,7 @@ function PMA_detectCompression($filepath) { $file = @fopen($filepath, 'rb'); if (!$file) { - return FALSE; + return false; } $test = fread($file, 4); $len = strlen($test); @@ -101,14 +101,14 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false) && !$is_superuser && preg_match('@^[[:space:]]*DROP[[:space:]]+(IF EXISTS[[:space:]]+)?DATABASE @i', $import_run_buffer['sql'])) { $GLOBALS['message'] = PMA_Message::error(__('"DROP DATABASE" statements are disabled.')); - $error = TRUE; + $error = true; } else { $executed_queries++; if ($run_query && $GLOBALS['finished'] && empty($sql) && !$error && ( (!empty($import_run_buffer['sql']) && preg_match('/^[\s]*(SELECT|SHOW|HANDLER)/i', $import_run_buffer['sql'])) || ($executed_queries == 1) )) { - $go_sql = TRUE; + $go_sql = true; if (!$sql_query_disabled) { $complete_query = $sql_query; $display_query = $sql_query; @@ -126,18 +126,18 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false) $result = PMA_DBI_try_query($import_run_buffer['sql']); } $msg = '# '; - if ($result === FALSE) { // execution failed + if ($result === false) { // execution failed if (! isset($my_die)) { $my_die = array(); } $my_die[] = array('sql' => $import_run_buffer['full'], 'error' => PMA_DBI_getError()); - + if ($cfg['VerboseMultiSubmit']) { $msg .= __('Error'); } - + if (!$cfg['IgnoreMultiSubmitErrors']) { - $error = TRUE; + $error = true; return; } } elseif ($cfg['VerboseMultiSubmit']) { @@ -156,14 +156,14 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false) if (!$sql_query_disabled) { $sql_query .= $msg . "\n"; } - + // If a 'USE ' SQL-clause was found and the query succeeded, set our current $db to the new one - if ($result != FALSE) { + if ($result != false) { list($db, $reload) = PMA_lookForUse($import_run_buffer['sql'], $db, $reload); } - - if ($result != FALSE && preg_match('@^[\s]*(DROP|CREATE)[\s]+(IF EXISTS[[:space:]]+)?(TABLE|DATABASE)[[:space:]]+(.+)@im', $import_run_buffer['sql'])) { - $reload = TRUE; + + if ($result != false && preg_match('@^[\s]*(DROP|CREATE)[\s]+(IF EXISTS[[:space:]]+)?(TABLE|DATABASE)[[:space:]]+(.+)@im', $import_run_buffer['sql'])) { + $reload = true; } } // end run query } // end if not DROP DATABASE @@ -185,12 +185,12 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false) if ($cfg['VerboseMultiSubmit'] && ! empty($sql_query)) { if (strlen($sql_query) > 50000 || $executed_queries > 50 || $max_sql_len > 1000) { $sql_query = ''; - $sql_query_disabled = TRUE; + $sql_query_disabled = true; } } else { if (strlen($sql_query) > 10000 || $executed_queries > 10 || $max_sql_len > 500) { $sql_query = ''; - $sql_query_disabled = TRUE; + $sql_query_disabled = true; } } } @@ -206,20 +206,20 @@ function PMA_importRunQuery($sql = '', $full = '', $controluser = false) } /** - * Looks for the presence of USE to possibly change current db + * Looks for the presence of USE to possibly change current db * - * @param string buffer to examine - * @param string current db - * @param boolean reload - * @return array (current or new db, whether to reload) + * @param string buffer to examine + * @param string current db + * @param boolean reload + * @return array (current or new db, whether to reload) * @access public */ function PMA_lookForUse($buffer, $db, $reload) -{ +{ if (preg_match('@^[\s]*USE[[:space:]]*([\S]+)@i', $buffer, $match)) { $db = trim($match[1]); $db = trim($db,';'); // for example, USE abc; - $reload = TRUE; + $reload = true; } return(array($db, $reload)); } @@ -241,7 +241,7 @@ function PMA_lookForUse($buffer, $db, $reload) function PMA_importGetNextChunk($size = 32768) { global $compression, $import_handle, $charset_conversion, $charset_of_file, - $charset, $read_multiply; + $read_multiply; // Add some progression while reading large amount of data if ($read_multiply <= 8) { @@ -257,16 +257,16 @@ function PMA_importGetNextChunk($size = 32768) } if (PMA_checkTimeout()) { - return FALSE; + return false; } if ($GLOBALS['finished']) { - return TRUE; + return true; } if ($GLOBALS['import_file'] == 'none') { // Well this is not yet supported and tested, but should return content of textarea if (strlen($GLOBALS['import_text']) < $size) { - $GLOBALS['finished'] = TRUE; + $GLOBALS['finished'] = true; return $GLOBALS['import_text']; } else { $r = substr($GLOBALS['import_text'], 0, $size); @@ -298,7 +298,7 @@ function PMA_importGetNextChunk($size = 32768) $GLOBALS['offset'] += $size; if ($charset_conversion) { - return PMA_convert_string($charset_of_file, $charset, $result); + return PMA_convert_string($charset_of_file, 'utf-8', $result); } else { /** * Skip possible byte order marks (I do not think we need more @@ -328,9 +328,9 @@ function PMA_importGetNextChunk($size = 32768) * The column number (1-26) is converted to the responding ASCII character (A-Z) and returned. * * If the column number is bigger than 26 (= num of letters in alfabet), - * an extra character needs to be added. To find this extra character, the number is divided by 26 - * and this value is passed to another instance of the same function (hence recursion). - * In that new instance the number is evaluated again, and if it is still bigger than 26, it is divided again + * an extra character needs to be added. To find this extra character, the number is divided by 26 + * and this value is passed to another instance of the same function (hence recursion). + * In that new instance the number is evaluated again, and if it is still bigger than 26, it is divided again * and passed to another instance of the same function. This continues until the number is smaller than 26. * Then the last called function returns the corresponding ASCII character to the function that called it. * Each time a called function ends an extra character is added to the column name. @@ -489,10 +489,10 @@ function PMA_getDecimalSize(&$cell) { $curr_size = strlen((string)$cell); $decPos = strpos($cell, "."); $decPrecision = ($curr_size - 1) - $decPos; - + $m = $curr_size - 1; $d = $decPrecision; - + return array($m, $d, ($m . "," . $d)); } @@ -525,7 +525,7 @@ function PMA_getDecimalSize(&$cell) { */ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type, &$cell) { $curr_size = strlen((string)$cell); - + /** * If the cell is NULL, don't treat it as a varchar */ @@ -551,7 +551,7 @@ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type */ elseif ($last_cumulative_type == DECIMAL) { $oldM = PMA_getM($last_cumulative_size); - + if ($curr_size >= $oldM) { return $curr_size; } else { @@ -581,7 +581,7 @@ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type /** * TODO: Handle this MUCH more elegantly */ - + return -1; } } @@ -595,7 +595,7 @@ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type if ($last_cumulative_type == VARCHAR) { /* Convert $last_cumulative_size from varchar to decimal format */ $size = PMA_getDecimalSize($cell); - + if ($size[M] >= $last_cumulative_size) { return $size[M]; } else { @@ -607,10 +607,10 @@ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type */ elseif ($last_cumulative_type == DECIMAL) { $size = PMA_getDecimalSize($cell); - + $oldM = PMA_getM($last_cumulative_size); $oldD = PMA_getD($last_cumulative_size); - + /* New val if M or D is greater than current largest */ if ($size[M] > $oldM || $size[D] > $oldD) { /* Take the largest of both types */ @@ -625,7 +625,7 @@ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type elseif ($last_cumulative_type == BIGINT || $last_cumulative_type == INT) { /* Convert $last_cumulative_size from int to decimal format */ $size = PMA_getDecimalSize($cell); - + if ($size[M] >= $last_cumulative_size) { return $size[FULL]; } else { @@ -638,7 +638,7 @@ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type elseif (! isset($last_cumulative_type) || $last_cumulative_type == NONE) { /* First row of the column */ $size = PMA_getDecimalSize($cell); - + return $size[FULL]; } /** @@ -648,7 +648,7 @@ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type /** * TODO: Handle this MUCH more elegantly */ - + return -1; } } @@ -674,7 +674,7 @@ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type $oldD = PMA_getD($last_cumulative_size); $oldInt = $oldM - $oldD; $newInt = strlen((string)$cell); - + /* See which has the larger integer length */ if ($oldInt >= $newInt) { /* Use old decimal size */ @@ -707,7 +707,7 @@ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type /** * TODO: Handle this MUCH more elegantly */ - + return -1; } } @@ -718,7 +718,7 @@ function PMA_detectSize($last_cumulative_size, $last_cumulative_type, $curr_type /** * TODO: Handle this MUCH more elegantly */ - + return -1; } } @@ -747,7 +747,7 @@ function PMA_detectType($last_cumulative_type, &$cell) { * If numeric, determine if decimal, int or bigint * Else, we call it varchar for simplicity */ - + if (! strcmp('NULL', $cell)) { if ($last_cumulative_type === NULL || $last_cumulative_type == NONE) { return NONE; @@ -807,7 +807,7 @@ function PMA_analyzeTable(&$table) { for ($i = 0; $i < $numCols; ++$i) { $sizes[$i] = 0; } - + /* Initialize $types to NONE */ for ($i = 0; $i < $numCols; ++$i) { $types[$i] = NONE; @@ -816,7 +816,7 @@ function PMA_analyzeTable(&$table) { /* Temp vars */ $curr_type = NONE; $curr_size = 0; - + /* If the passed array is not of the correct form, do not process it */ if (is_array($table) && ! is_array($table[TBL_NAME]) && is_array($table[COL_NAMES]) && is_array($table[ROWS])) { /* Analyze each column */ @@ -827,7 +827,7 @@ function PMA_analyzeTable(&$table) { $curr_type = PMA_detectType($types[$i], $table[ROWS][$j][$i]); /* Determine size of the current cell */ $sizes[$i] = PMA_detectSize($sizes[$i], $types[$i], $curr_type, $table[ROWS][$j][$i]); - + /** * If a type for this column has already been declared, * only alter it if it was a number and a varchar was found @@ -851,7 +851,7 @@ function PMA_analyzeTable(&$table) { } } } - + /* Check to ensure that all types are valid */ $len = count($types); for ($n = 0; $n < $len; ++$n) { @@ -860,7 +860,7 @@ function PMA_analyzeTable(&$table) { $sizes[$n] = '10'; } } - + return array($types, $sizes); } else @@ -868,7 +868,7 @@ function PMA_analyzeTable(&$table) { /** * TODO: Handle this better */ - + return false; } } @@ -913,38 +913,38 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = } else { $collation = "utf8_general_ci"; } - + if (isset($options['db_charset']) && ! is_null($options['db_charset'])) { $charset = $options['db_charset']; } else { $charset = "utf8"; } - + if (isset($options['create_db'])) { $create_db = $options['create_db']; } else { $create_db = true; } - + /* Create SQL code to handle the database */ $sql = array(); - + if ($create_db) { $sql[] = "CREATE DATABASE IF NOT EXISTS " . PMA_backquote($db_name) . " DEFAULT CHARACTER SET " . $charset . " COLLATE " . $collation; } - + /** * The calling plug-in should include this statement, if necessary, in the $additional_sql parameter * * $sql[] = "USE " . PMA_backquote($db_name); */ - + /* Execute the SQL statements create above */ $sql_len = count($sql); for ($i = 0; $i < $sql_len; ++$i) { PMA_importRunQuery($sql[$i], $sql[$i]); } - + /* No longer needed */ unset($sql); @@ -952,7 +952,7 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = if ($additional_sql != NULL) { /* Clean the SQL first */ $additional_sql_len = count($additional_sql); - + /** * Only match tables for now, because CREATE IF NOT EXISTS * syntax is lacking or nonexisting for views, triggers, @@ -966,7 +966,7 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = */ $pattern = '/CREATE .*(TABLE)/'; $replacement = 'CREATE \\1 IF NOT EXISTS'; - + /* Change CREATE statements to CREATE IF NOT EXISTS to support inserting into existing structures */ for ($i = 0; $i < $additional_sql_len; ++$i) { $additional_sql[$i] = preg_replace($pattern, $replacement, $additional_sql[$i]); @@ -977,12 +977,12 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = if ($analyses != NULL) { $type_array = array(NONE => "NULL", VARCHAR => "varchar", INT => "int", DECIMAL => "decimal", BIGINT => "bigint"); - + /* TODO: Do more checking here to make sure they really are matched */ if (count($tables) != count($analyses)) { exit(); } - + /* Create SQL code to create the tables */ $tempSQLStr = ""; $num_tables = count($tables); @@ -994,15 +994,15 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = if ((int)$size == 0) { $size = 10; } - + $tempSQLStr .= PMA_backquote($tables[$i][COL_NAMES][$j]) . " " . $type_array[$analyses[$i][TYPES][$j]] . "(" . $size . ")"; - + if ($j != (count($tables[$i][COL_NAMES]) - 1)) { $tempSQLStr .= ", "; } } $tempSQLStr .= ") ENGINE=MyISAM DEFAULT CHARACTER SET " . $charset . " COLLATE " . $collation . ";"; - + /** * Each SQL statement is executed immediately * after it is formed so that we don't have @@ -1011,7 +1011,7 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = PMA_importRunQuery($tempSQLStr, $tempSQLStr); } } - + /** * Create the SQL statements to insert all the data * @@ -1023,65 +1023,65 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = for ($i = 0; $i < $num_tables; ++$i) { $num_cols = count($tables[$i][COL_NAMES]); $num_rows = count($tables[$i][ROWS]); - + $tempSQLStr = "INSERT INTO " . PMA_backquote($db_name) . '.' . PMA_backquote($tables[$i][TBL_NAME]) . " ("; - + for ($m = 0; $m < $num_cols; ++$m) { $tempSQLStr .= PMA_backquote($tables[$i][COL_NAMES][$m]); - + if ($m != ($num_cols - 1)) { $tempSQLStr .= ", "; } } - + $tempSQLStr .= ") VALUES "; - + for ($j = 0; $j < $num_rows; ++$j) { $tempSQLStr .= "("; - + for ($k = 0; $k < $num_cols; ++$k) { if ($analyses != NULL) { $is_varchar = ($analyses[$i][TYPES][$col_count] === VARCHAR); } else { $is_varchar = !is_numeric($tables[$i][ROWS][$j][$k]); } - + /* Don't put quotes around NULL fields */ if (! strcmp($tables[$i][ROWS][$j][$k], 'NULL')) { $is_varchar = false; } - + $tempSQLStr .= (($is_varchar) ? "'" : ""); $tempSQLStr .= PMA_sqlAddslashes((string)$tables[$i][ROWS][$j][$k]); $tempSQLStr .= (($is_varchar) ? "'" : ""); - + if ($k != ($num_cols - 1)) { $tempSQLStr .= ", "; } - + if ($col_count == ($num_cols - 1)) { $col_count = 0; } else { $col_count++; } - + /* Delete the cell after we are done with it */ unset($tables[$i][ROWS][$j][$k]); } - + $tempSQLStr .= ")"; - + if ($j != ($num_rows - 1)) { $tempSQLStr .= ",\n "; } - + $col_count = 0; /* Delete the row after we are done with it */ unset($tables[$i][ROWS][$j]); } - + $tempSQLStr .= ";"; - + /** * Each SQL statement is executed immediately * after it is formed so that we don't have @@ -1089,32 +1089,32 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = */ PMA_importRunQuery($tempSQLStr, $tempSQLStr); } - + /* No longer needed */ unset($tempSQLStr); - + /** * A work in progress */ - + /* Add the viewable structures from $additional_sql to $tables so they are also displayed */ - + $view_pattern = '@VIEW `[^`]+`\.`([^`]+)@'; $table_pattern = '@CREATE TABLE IF NOT EXISTS `([^`]+)`@'; /* Check a third pattern to make sure its not a "USE `db_name`;" statement */ - + $regs = array(); - + $inTables = false; - + $additional_sql_len = count($additional_sql); for ($i = 0; $i < $additional_sql_len; ++$i) { preg_match($view_pattern, $additional_sql[$i], $regs); - + if (count($regs) == 0) { preg_match($table_pattern, $additional_sql[$i], $regs); } - + if (count($regs)) { for ($n = 0; $n < $num_tables; ++$n) { if (!strcmp($regs[1], $tables[$n][TBL_NAME])) { @@ -1122,21 +1122,21 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = break; } } - + if (!$inTables) { $tables[] = array(TBL_NAME => $regs[1]); } } - + /* Reset the array */ $regs = array(); $inTables = false; } - + $params = array('db' => (string)$db_name); $db_url = 'db_structure.php' . PMA_generate_common_url($params); $db_ops_url = 'db_operations.php' . PMA_generate_common_url($params); - + $message = '

'; $message .= '' . __('The following structures have either been created or altered. Here you can:') . '
'; $message .= '
  • ' . __('View a structure`s contents by clicking on its name') . '
  • '; @@ -1148,11 +1148,11 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = $db_name, $db_ops_url, __('Edit') . ' ' . PMA_backquote($db_name) . ' ' . __('settings')); - + $message .= '
      '; - + unset($params); - + $num_tables = count($tables); for ($i = 0; $i < $num_tables; ++$i) { @@ -1160,9 +1160,9 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = $tbl_url = 'sql.php' . PMA_generate_common_url($params); $tbl_struct_url = 'tbl_structure.php' . PMA_generate_common_url($params); $tbl_ops_url = 'tbl_operations.php' . PMA_generate_common_url($params); - + unset($params); - + if (! PMA_isView($db_name, $tables[$i][TBL_NAME])) { $message .= sprintf('
    • %s (' . __('Structure') . ') (' . __('Options') . ')
    • ', $tbl_url, @@ -1179,12 +1179,12 @@ function PMA_buildSQL($db_name, &$tables, &$analyses = NULL, &$additional_sql = $tables[$i][TBL_NAME]); } } - + $message .= '
'; - + global $import_notice; $import_notice = $message; - + unset($tables); } diff --git a/libraries/import/README b/libraries/import/README index 6cb7d107c3..0f0d3d3547 100644 --- a/libraries/import/README +++ b/libraries/import/README @@ -22,11 +22,11 @@ if (isset($plugin_list)) { $buffer = ''; while (!($finished && $i >= $len) && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); - if ($data === FALSE) { + if ($data === false) { // subtract data we didn't handle yet and stop processing $offset -= strlen($buffer); break; - } elseif ($data === TRUE) { + } elseif ($data === true) { // Handle rest of buffer } else { // Append new data to buffer diff --git a/libraries/import/csv.php b/libraries/import/csv.php index 757e3b491d..6386333184 100644 --- a/libraries/import/csv.php +++ b/libraries/import/csv.php @@ -56,12 +56,12 @@ $csv_enclosed = strtr($csv_enclosed, $replacements); $csv_escaped = strtr($csv_escaped, $replacements); $csv_new_line = strtr($csv_new_line, $replacements); -$param_error = FALSE; +$param_error = false; if (strlen($csv_terminated) != 1) { $message = PMA_Message::error(__('Invalid parameter for CSV import: %s')); $message->addParam(__('Columns terminated by'), false); - $error = TRUE; - $param_error = TRUE; + $error = true; + $param_error = true; // The default dialog of MS Excel when generating a CSV produces a // semi-colon-separated file with no chance of specifying the // enclosing character. Thus, users who want to import this file @@ -73,18 +73,18 @@ if (strlen($csv_terminated) != 1) { } elseif (strlen($csv_enclosed) > 1) { $message = PMA_Message::error(__('Invalid parameter for CSV import: %s')); $message->addParam(__('Columns enclosed by'), false); - $error = TRUE; - $param_error = TRUE; + $error = true; + $param_error = true; } elseif (strlen($csv_escaped) != 1) { $message = PMA_Message::error(__('Invalid parameter for CSV import: %s')); $message->addParam(__('Columns escaped by'), false); - $error = TRUE; - $param_error = TRUE; + $error = true; + $param_error = true; } elseif (strlen($csv_new_line) != 1 && $csv_new_line != 'auto') { $message = PMA_Message::error(__('Invalid parameter for CSV import: %s')); $message->addParam(__('Lines terminated by'), false); - $error = TRUE; - $param_error = TRUE; + $error = true; + $param_error = true; } // If there is an error in the parameters entered, indicate that immediately. @@ -120,17 +120,17 @@ if (!$analyze) { } /* Trim also `, if user already included backquoted fields */ $val = trim($val, " \t\r\n\0\x0B`"); - $found = FALSE; + $found = false; foreach ($tmp_fields as $id => $field) { if ($field['Field'] == $val) { - $found = TRUE; + $found = true; break; } } if (!$found) { $message = PMA_Message::error(__('Invalid column (%s) specified! Ensure that columns names are spelled correctly, separated by commas, and not enclosed in quotes.' )); $message->addParam($val); - $error = TRUE; + $error = true; break; } $fields[] = $field; @@ -150,7 +150,7 @@ $len = 0; $line = 1; $lasti = -1; $values = array(); -$csv_finish = FALSE; +$csv_finish = false; $tempRow = array(); $rows = array(); @@ -162,19 +162,19 @@ $max_cols = 0; while (!($finished && $i >= $len) && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); - if ($data === FALSE) { + if ($data === false) { // subtract data we didn't handle yet and stop processing $offset -= strlen($buffer); break; - } elseif ($data === TRUE) { + } elseif ($data === true) { // Handle rest of buffer } else { // Append new data to buffer $buffer .= $data; unset($data); // Do not parse string when we're not at the end and don't have new line inside - if (($csv_new_line == 'auto' && strpos($buffer, "\r") === FALSE && strpos($buffer, "\n") === FALSE) - || ($csv_new_line != 'auto' && strpos($buffer, $csv_new_line) === FALSE)) { + if (($csv_new_line == 'auto' && strpos($buffer, "\r") === false && strpos($buffer, "\n") === false) + || ($csv_new_line != 'auto' && strpos($buffer, $csv_new_line) === false)) { continue; } } @@ -188,7 +188,7 @@ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { if ($lasti == $i && $lastlen == $len) { $message = PMA_Message::error(__('Invalid format of CSV input on line %d.')); $message->addParam($line); - $error = TRUE; + $error = true; break; } $lasti = $i; @@ -213,13 +213,13 @@ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { if ($i == $len - 1) { break; } - $need_end = TRUE; + $need_end = true; $i++; $ch = $buffer[$i]; } else { - $need_end = FALSE; + $need_end = false; } - $fail = FALSE; + $fail = false; $value = ''; while (($need_end && $ch != $csv_enclosed) || (!$need_end && !($ch == $csv_terminated @@ -227,7 +227,7 @@ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { && ($ch == "\r" || $ch == "\n"))))) { if ($ch == $csv_escaped) { if ($i == $len - 1) { - $fail = TRUE; + $fail = true; break; } $i++; @@ -236,7 +236,7 @@ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { $value .= $ch; if ($i == $len - 1) { if (!$finished) { - $fail = TRUE; + $fail = true; } break; } @@ -269,7 +269,7 @@ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { } // Are we at the end? if ($ch == $csv_new_line || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n")) || ($finished && $i == $len - 1)) { - $csv_finish = TRUE; + $csv_finish = true; } // Go to next char if ($ch == $csv_terminated) { @@ -323,12 +323,12 @@ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { } else { $message = PMA_Message::error(__('Invalid column count in CSV input on line %d.')); $message->addParam($line); - $error = TRUE; + $error = true; break; } } - $first = TRUE; + $first = true; $sql = $sql_template; foreach ($values as $key => $val) { if (!$first) { @@ -340,7 +340,7 @@ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { $sql .= '\'' . addslashes($val) . '\''; } - $first = FALSE; + $first = false; } $sql .= ')'; @@ -351,7 +351,7 @@ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { } $line++; - $csv_finish = FALSE; + $csv_finish = false; $values = array(); $buffer = substr($buffer, $i + 1); $len = strlen($buffer); @@ -435,6 +435,6 @@ PMA_importRunQuery(); if (count($values) != 0 && !$error) { $message = PMA_Message::error(__('Invalid format of CSV input on line %d.')); $message->addParam($line); - $error = TRUE; + $error = true; } ?> diff --git a/libraries/import/docsql.php b/libraries/import/docsql.php index a64a094106..f032e95577 100644 --- a/libraries/import/docsql.php +++ b/libraries/import/docsql.php @@ -42,10 +42,10 @@ $buffer = ''; /* Read whole buffer, we except it is small enough */ while (!$finished && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); - if ($data === FALSE) { + if ($data === false) { // subtract data we didn't handle yet and stop processing break; - } elseif ($data === TRUE) { + } elseif ($data === true) { // nothing to read break; } else { @@ -54,7 +54,7 @@ while (!$finished && !$error && !$timeout_passed) { } } // End of import loop /* Process the data */ -if ($data === TRUE && !$error && !$timeout_passed) { +if ($data === true && !$error && !$timeout_passed) { $buffer = str_replace("\r\n", "\n", $buffer); $buffer = str_replace("\r", "\n", $buffer); $lines = explode("\n", $buffer); diff --git a/libraries/import/ldi.php b/libraries/import/ldi.php index e6eb56d233..979013dec0 100644 --- a/libraries/import/ldi.php +++ b/libraries/import/ldi.php @@ -18,13 +18,13 @@ if ($plugin_param !== 'table') { if (isset($plugin_list)) { if ($GLOBALS['cfg']['Import']['ldi_local_option'] == 'auto') { - $GLOBALS['cfg']['Import']['ldi_local_option'] = FALSE; + $GLOBALS['cfg']['Import']['ldi_local_option'] = false; $result = PMA_DBI_try_query('SHOW VARIABLES LIKE \'local\\_infile\';'); - if ($result != FALSE && PMA_DBI_num_rows($result) > 0) { + if ($result != false && PMA_DBI_num_rows($result) > 0) { $tmp = PMA_DBI_fetch_row($result); if ($tmp[1] == 'ON') { - $GLOBALS['cfg']['Import']['ldi_local_option'] = TRUE; + $GLOBALS['cfg']['Import']['ldi_local_option'] = true; } } PMA_DBI_free_result($result); @@ -54,7 +54,7 @@ if (isset($plugin_list)) { if ($import_file == 'none' || $compression != 'none' || $charset_conversion) { // We handle only some kind of data! $message = PMA_Message::error(__('This plugin does not support compressed imports!')); - $error = TRUE; + $error = true; return; } @@ -105,5 +105,5 @@ if (strlen($ldi_columns) > 0) { PMA_importRunQuery($sql, $sql); PMA_importRunQuery(); -$finished = TRUE; +$finished = true; ?> diff --git a/libraries/import/ods.php b/libraries/import/ods.php index 4bf5200169..9d41bb44b3 100644 --- a/libraries/import/ods.php +++ b/libraries/import/ods.php @@ -48,11 +48,11 @@ $buffer = ""; */ while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { $data = PMA_importGetNextChunk(); - if ($data === FALSE) { + if ($data === false) { /* subtract data we didn't handle yet and stop processing */ $offset -= strlen($buffer); break; - } elseif ($data === TRUE) { + } elseif ($data === true) { /* Handle rest of buffer */ } else { /* Append new data to buffer */ @@ -74,11 +74,11 @@ $xml = simplexml_load_string($buffer, "SimpleXMLElement", LIBXML_COMPACT); unset($buffer); -if ($xml === FALSE) { +if ($xml === false) { $sheets = array(); /* TODO: this message should be improved later, used existing because of string freeze */ $message = PMA_Message::error(__('Error in Processing Request')); - $error = TRUE; + $error = true; } else { $sheets = $xml->children('office', true)->{'body'}->{'spreadsheet'}->children('table', true); } diff --git a/libraries/import/sql.php b/libraries/import/sql.php index 0e61080cac..4bb65d6c38 100644 --- a/libraries/import/sql.php +++ b/libraries/import/sql.php @@ -93,11 +93,11 @@ $GLOBALS['finished'] = false; while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); - if ($data === FALSE) { + if ($data === false) { // subtract data we didn't handle yet and stop processing $offset -= strlen($buffer); break; - } elseif ($data === TRUE) { + } elseif ($data === true) { // Handle rest of buffer } else { // Append new data to buffer @@ -105,7 +105,7 @@ while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) { // free memory unset($data); // Do not parse string when we're not at the end and don't have ; inside - if ((strpos($buffer, $sql_delimiter, $i) === FALSE) && !$GLOBALS['finished']) { + if ((strpos($buffer, $sql_delimiter, $i) === false) && !$GLOBALS['finished']) { continue; } } @@ -132,7 +132,7 @@ while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) { */ // the cost of doing this one with preg_match() would be too high $first_sql_delimiter = strpos($buffer, $sql_delimiter, $i); - if ($first_sql_delimiter === FALSE) { + if ($first_sql_delimiter === false) { $first_sql_delimiter = $big_value; } else { $found_delimiter = true; @@ -162,9 +162,9 @@ while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) { $ch = $buffer[$i]; // Quotes - if (strpos('\'"`', $ch) !== FALSE) { + if (strpos('\'"`', $ch) !== false) { $quote = $ch; - $endq = FALSE; + $endq = false; while (!$endq) { // Find next quote $pos = strpos($buffer, $quote, $i + 1); @@ -178,13 +178,13 @@ while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) { * * SELECT * FROM `table` */ - if ($pos === FALSE && $quote == '`' && $found_delimiter) { + if ($pos === false && $quote == '`' && $found_delimiter) { $pos = $first_sql_delimiter - 1; // No quote? Too short string - } elseif ($pos === FALSE) { + } elseif ($pos === false) { // We hit end of string => unclosed quote, but we handle it as end of query if ($GLOBALS['finished']) { - $endq = TRUE; + $endq = true; $i = $len - 1; } $found_delimiter = false; @@ -238,7 +238,7 @@ while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) { // file might have been produced on a different system $i = strpos($buffer, $ch == '/' ? '*/' : "\n", $i); // didn't we hit end of string? - if ($i === FALSE) { + if ($i === false) { if ($GLOBALS['finished']) { $i = $len - 1; } else { @@ -270,7 +270,7 @@ while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) { // (see previous comment about PHP_EOL) $new_line_pos = strpos($buffer, "\n", $i + $length_of_delimiter_keyword); // it might happen that there is no EOL - if (FALSE === $new_line_pos) { + if (false === $new_line_pos) { $new_line_pos = $len; } $sql_delimiter = substr($buffer, $i + $length_of_delimiter_keyword, $new_line_pos - $i - $length_of_delimiter_keyword); @@ -303,8 +303,8 @@ while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) { $i = 0; $start_pos = 0; // Any chance we will get a complete query? - //if ((strpos($buffer, ';') === FALSE) && !$GLOBALS['finished']) { - if ((strpos($buffer, $sql_delimiter) === FALSE) && !$GLOBALS['finished']) { + //if ((strpos($buffer, ';') === false) && !$GLOBALS['finished']) { + if ((strpos($buffer, $sql_delimiter) === false) && !$GLOBALS['finished']) { break; } } else { diff --git a/libraries/import/xml.php b/libraries/import/xml.php index 640aac8119..d3d17b25c5 100644 --- a/libraries/import/xml.php +++ b/libraries/import/xml.php @@ -41,11 +41,11 @@ $buffer = ""; */ while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) { $data = PMA_importGetNextChunk(); - if ($data === FALSE) { + if ($data === false) { /* subtract data we didn't handle yet and stop processing */ $offset -= strlen($buffer); break; - } elseif ($data === TRUE) { + } elseif ($data === true) { /* Handle rest of buffer */ } else { /* Append new data to buffer */ @@ -70,7 +70,7 @@ unset($buffer); /** * The XML was malformed */ -if ($xml === FALSE) { +if ($xml === false) { PMA_Message::error(__('The XML file specified was either malformed or incomplete. Please correct the issue and try again.'))->display(); unset($xml); $GLOBALS['finished'] = false; diff --git a/libraries/kanji-encoding.lib.php b/libraries/kanji-encoding.lib.php index 67c8b1cddf..552bd1356d 100644 --- a/libraries/kanji-encoding.lib.php +++ b/libraries/kanji-encoding.lib.php @@ -35,7 +35,7 @@ function PMA_internal_enc_check() { $enc_list = 'ASCII,SJIS,EUC-JP,JIS'; } - return TRUE; + return true; } // end of the 'PMA_internal_enc_check' function @@ -57,7 +57,7 @@ function PMA_change_enc_order() { $enc_list = 'ASCII,EUC-JP,SJIS,JIS'; } - return TRUE; + return true; } // end of the 'PMA_change_enc_order' function diff --git a/libraries/mult_submits.inc.php b/libraries/mult_submits.inc.php index 7c8f27cdc9..8038705c20 100644 --- a/libraries/mult_submits.inc.php +++ b/libraries/mult_submits.inc.php @@ -302,8 +302,8 @@ elseif ($mult_btn == __('Yes')) { $sql_query_views = ''; } $selected_cnt = count($selected); - $run_parts = FALSE; // whether to run query after each pass - $use_sql = FALSE; // whether to include sql.php at the end (to display results) + $run_parts = false; // whether to run query after each pass + $use_sql = false; // whether to include sql.php at the end (to display results) if ($query_type == 'primary_fld') { // Gets table primary key @@ -325,7 +325,7 @@ elseif ($mult_btn == __('Yes')) { switch ($query_type) { case 'row_delete': $a_query = $selected[$i]; - $run_parts = TRUE; + $run_parts = true; break; case 'drop_db': @@ -333,7 +333,7 @@ elseif ($mult_btn == __('Yes')) { $a_query = 'DROP DATABASE ' . PMA_backquote($selected[$i]); $reload = 1; - $run_parts = TRUE; + $run_parts = true; $rebuild_database_list = true; break; @@ -353,31 +353,31 @@ elseif ($mult_btn == __('Yes')) { case 'check_tbl': $sql_query .= (empty($sql_query) ? 'CHECK TABLE ' : ', ') . PMA_backquote($selected[$i]); - $use_sql = TRUE; + $use_sql = true; break; case 'optimize_tbl': $sql_query .= (empty($sql_query) ? 'OPTIMIZE TABLE ' : ', ') . PMA_backquote($selected[$i]); - $use_sql = TRUE; + $use_sql = true; break; case 'analyze_tbl': $sql_query .= (empty($sql_query) ? 'ANALYZE TABLE ' : ', ') . PMA_backquote($selected[$i]); - $use_sql = TRUE; + $use_sql = true; break; case 'repair_tbl': $sql_query .= (empty($sql_query) ? 'REPAIR TABLE ' : ', ') . PMA_backquote($selected[$i]); - $use_sql = TRUE; + $use_sql = true; break; case 'empty_tbl': $a_query = 'TRUNCATE '; $a_query .= PMA_backquote($selected[$i]); - $run_parts = TRUE; + $run_parts = true; break; case 'drop_fld': diff --git a/libraries/mysql_charsets.lib.php b/libraries/mysql_charsets.lib.php index 51b79ba27d..c77aee0e50 100644 --- a/libraries/mysql_charsets.lib.php +++ b/libraries/mysql_charsets.lib.php @@ -11,7 +11,7 @@ if (! defined('PHPMYADMIN')) { /** * */ -if (! PMA_cacheExists('mysql_charsets_count', true)) { +if (! PMA_cacheExists('mysql_charsets', true)) { $sql = PMA_DRIZZLE ? 'SELECT * FROM data_dictionary.CHARACTER_SETS' : 'SELECT * FROM information_schema.CHARACTER_SETS'; @@ -26,7 +26,6 @@ if (! PMA_cacheExists('mysql_charsets_count', true)) { } PMA_DBI_free_result($res); - $mysql_charsets_count = count($mysql_charsets); sort($mysql_charsets, SORT_STRING); $mysql_collations = array_flip($mysql_charsets); @@ -60,7 +59,6 @@ if (! PMA_cacheExists('mysql_charsets_count', true)) { unset($mysql_collations['utf8_general_ci']); } - $mysql_collations_count = count($mysql_collations_flat); sort($mysql_collations_flat, SORT_STRING); foreach ($mysql_collations AS $key => $value) { sort($mysql_collations[$key], SORT_STRING); @@ -70,22 +68,18 @@ if (! PMA_cacheExists('mysql_charsets_count', true)) { PMA_cacheSet('mysql_charsets', $GLOBALS['mysql_charsets'], true); PMA_cacheSet('mysql_charsets_descriptions', $GLOBALS['mysql_charsets_descriptions'], true); - PMA_cacheSet('mysql_charsets_count', $GLOBALS['mysql_charsets_count'], true); PMA_cacheSet('mysql_charsets_available', $GLOBALS['mysql_charsets_available'], true); PMA_cacheSet('mysql_collations', $GLOBALS['mysql_collations'], true); PMA_cacheSet('mysql_default_collations', $GLOBALS['mysql_default_collations'], true); PMA_cacheSet('mysql_collations_flat', $GLOBALS['mysql_collations_flat'], true); - PMA_cacheSet('mysql_collations_count', $GLOBALS['mysql_collations_count'], true); PMA_cacheSet('mysql_collations_available', $GLOBALS['mysql_collations_available'], true); } else { $GLOBALS['mysql_charsets'] = PMA_cacheGet('mysql_charsets', true); $GLOBALS['mysql_charsets_descriptions'] = PMA_cacheGet('mysql_charsets_descriptions', true); - $GLOBALS['mysql_charsets_count'] = PMA_cacheGet('mysql_charsets_count', true); $GLOBALS['mysql_charsets_available'] = PMA_cacheGet('mysql_charsets_available', true); $GLOBALS['mysql_collations'] = PMA_cacheGet('mysql_collations', true); $GLOBALS['mysql_default_collations'] = PMA_cacheGet('mysql_default_collations', true); $GLOBALS['mysql_collations_flat'] = PMA_cacheGet('mysql_collations_flat', true); - $GLOBALS['mysql_collations_count'] = PMA_cacheGet('mysql_collations_count', true); $GLOBALS['mysql_collations_available'] = PMA_cacheGet('mysql_collations_available', true); } @@ -93,8 +87,8 @@ define('PMA_CSDROPDOWN_COLLATION', 0); define('PMA_CSDROPDOWN_CHARSET', 1); function PMA_generateCharsetDropdownBox($type = PMA_CSDROPDOWN_COLLATION, - $name = null, $id = null, $default = null, $label = TRUE, $indent = 0, - $submitOnChange = FALSE, $displayUnavailable = FALSE) + $name = null, $id = null, $default = null, $label = true, $indent = 0, + $submitOnChange = false, $displayUnavailable = false) { global $mysql_charsets, $mysql_charsets_descriptions, $mysql_charsets_available, $mysql_collations, $mysql_collations_available; @@ -318,7 +312,7 @@ function PMA_getCollationDescr($collation) { $descr = __('Unicode') . ' (' . __('multilingual') . ')'; break; case 'bin': - $is_bin = TRUE; + $is_bin = true; case 'general': switch ($parts[0]) { // Unicode charsets diff --git a/libraries/navigation_header.inc.php b/libraries/navigation_header.inc.php index fa5255a569..e8db6a20af 100644 --- a/libraries/navigation_header.inc.php +++ b/libraries/navigation_header.inc.php @@ -99,7 +99,7 @@ if ($GLOBALS['cfg']['LeftDisplayLogo']) { .' alt="' . __('phpMyAdmin documentation') . '" />'; } echo ''; - echo ' ' . PMA_showMySQLDocu('', '', TRUE) . "\n"; + echo ' ' . PMA_showMySQLDocu('', '', true) . "\n"; $params = array('uniqid' => uniqid()); if (!empty($GLOBALS['db'])) { diff --git a/libraries/relation.lib.php b/libraries/relation.lib.php index 20ddf97b7b..7075cc83b6 100644 --- a/libraries/relation.lib.php +++ b/libraries/relation.lib.php @@ -1034,18 +1034,18 @@ function PMA_getForeignData($foreigners, $field, $override_total, $foreign_filte $the_total = PMA_Table::countRecords($foreign_db, $foreign_table); if ($override_total == true || $the_total < $GLOBALS['cfg']['ForeignKeyMaxLimit']) { - // foreign_display can be FALSE if no display field defined: + // foreign_display can be false if no display field defined: $foreign_display = PMA_getDisplayField($foreign_db, $foreign_table); $f_query_main = 'SELECT ' . PMA_backquote($foreign_field) - . (($foreign_display == FALSE) ? '' : ', ' . PMA_backquote($foreign_display)); + . (($foreign_display == false) ? '' : ', ' . PMA_backquote($foreign_display)); $f_query_from = ' FROM ' . PMA_backquote($foreign_db) . '.' . PMA_backquote($foreign_table); $f_query_filter = empty($foreign_filter) ? '' : ' WHERE ' . PMA_backquote($foreign_field) - . ' LIKE "%' . PMA_sqlAddslashes($foreign_filter, TRUE) . '%"' - . (($foreign_display == FALSE) ? '' : ' OR ' . PMA_backquote($foreign_display) - . ' LIKE "%' . PMA_sqlAddslashes($foreign_filter, TRUE) . '%"' + . ' LIKE "%' . PMA_sqlAddslashes($foreign_filter, true) . '%"' + . (($foreign_display == false) ? '' : ' OR ' . PMA_backquote($foreign_display) + . ' LIKE "%' . PMA_sqlAddslashes($foreign_filter, true) . '%"' ); - $f_query_order = ($foreign_display == FALSE) ? '' :' ORDER BY ' . PMA_backquote($foreign_table) . '.' . PMA_backquote($foreign_display); + $f_query_order = ($foreign_display == false) ? '' :' ORDER BY ' . PMA_backquote($foreign_table) . '.' . PMA_backquote($foreign_display); $f_query_limit = isset($foreign_limit) ? $foreign_limit : ''; if (!empty($foreign_filter)) { @@ -1091,7 +1091,7 @@ function PMA_getForeignData($foreigners, $field, $override_total, $foreign_filte * @uses $GLOBALS['cfgRelation'] * @uses $GLOBALS['db'] * @param string whether to go from master to foreign or vice versa - * @return boolean always TRUE + * @return boolean always true * @global array $tab_left the list of tables that we still couldn't connect * @global array $tab_know the list of allready connected tables * @global string $fromclause @@ -1202,7 +1202,7 @@ function PMA_REL_create_page($newpage, $cfgRelation, $db, $query_default_option) $ins_query = 'INSERT INTO ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($cfgRelation['pdf_pages']) . ' (db_name, page_descr)' . ' VALUES (\'' . PMA_sqlAddslashes($db) . '\', \'' . PMA_sqlAddslashes($newpage) . '\')'; - PMA_query_as_controluser($ins_query, FALSE, $query_default_option); + PMA_query_as_controluser($ins_query, false, $query_default_option); return PMA_DBI_insert_id(isset($GLOBALS['controllink']) ? $GLOBALS['controllink'] : ''); } ?> diff --git a/libraries/schema/Dia_Relation_Schema.class.php b/libraries/schema/Dia_Relation_Schema.class.php index a7813078a8..6cf77e3a1a 100644 --- a/libraries/schema/Dia_Relation_Schema.class.php +++ b/libraries/schema/Dia_Relation_Schema.class.php @@ -41,7 +41,7 @@ class PMA_DIA extends XMLWriter * so output is formatted */ - $this->setIndent(TRUE); + $this->setIndent(true); $this->setIndentString(' '); /* * Create the XML document @@ -694,7 +694,7 @@ class PMA_Dia_Relation_Schema extends PMA_Export_Relation_Schema /* put the foreign table on the schema only if selected * by the user * (do not use array_search() because we would have to - * to do a === FALSE and this is not PHP3 compatible) + * to do a === false and this is not PHP3 compatible) */ if (in_array($rel['foreign_table'], $alltables)) { $this->_addRelation($one_table, $master_field, $rel['foreign_table'], $rel['foreign_field'],$this->showKeys); diff --git a/libraries/schema/Eps_Relation_Schema.class.php b/libraries/schema/Eps_Relation_Schema.class.php index edea703943..4f2f8cbba0 100644 --- a/libraries/schema/Eps_Relation_Schema.class.php +++ b/libraries/schema/Eps_Relation_Schema.class.php @@ -777,7 +777,7 @@ class PMA_Eps_Relation_Schema extends PMA_Export_Relation_Schema /* put the foreign table on the schema only if selected * by the user * (do not use array_search() because we would have to - * to do a === FALSE and this is not PHP3 compatible) + * to do a === false and this is not PHP3 compatible) */ if (in_array($rel['foreign_table'], $alltables)) { $this->_addRelation($one_table,$eps->getFont(),$eps->getFontSize(), $master_field, $rel['foreign_table'], $rel['foreign_field'], $this->tableDimension); diff --git a/libraries/schema/Export_Relation_Schema.class.php b/libraries/schema/Export_Relation_Schema.class.php index 2d23c5bbf8..e75b3e86a8 100644 --- a/libraries/schema/Export_Relation_Schema.class.php +++ b/libraries/schema/Export_Relation_Schema.class.php @@ -186,22 +186,14 @@ class PMA_Export_Relation_Schema * @param string type Schema Type * @param string error_message the error mesage * @global array the PMA configuration array - * @global integer the current server id - * @global string the current language - * @global string the charset to convert to * @global string the current database name - * @global string the current charset - * @global string the current text direction - * @global string a localized string - * @global string an other localized string * @access public * @return void */ function dieSchema($pageNumber, $type = '', $error_message = '') { global $cfg; - global $server, $lang, $convcharset, $db; - global $charset, $text_dir; + global $db; require_once './libraries/header.inc.php'; echo "

" . __("SCHEMA ERROR: ") . $type ."

" . "\n"; diff --git a/libraries/schema/Pdf_Relation_Schema.class.php b/libraries/schema/Pdf_Relation_Schema.class.php index 39fa62bc1f..41ebf57d06 100644 --- a/libraries/schema/Pdf_Relation_Schema.class.php +++ b/libraries/schema/Pdf_Relation_Schema.class.php @@ -919,7 +919,7 @@ class PMA_Pdf_Relation_Schema extends PMA_Export_Relation_Schema // put the foreign table on the schema only if selected // by the user // (do not use array_search() because we would have to - // to do a === FALSE and this is not PHP3 compatible) + // to do a === false and this is not PHP3 compatible) if (in_array($rel['foreign_table'], $alltables)) { $this->_addRelation($one_table, $master_field, $rel['foreign_table'], $rel['foreign_field'], $this->tableDimension); } diff --git a/libraries/schema/Svg_Relation_Schema.class.php b/libraries/schema/Svg_Relation_Schema.class.php index 0f6b55bd4c..c1ff0f14fa 100644 --- a/libraries/schema/Svg_Relation_Schema.class.php +++ b/libraries/schema/Svg_Relation_Schema.class.php @@ -41,7 +41,7 @@ class PMA_SVG extends XMLWriter * so output is formatted */ - $this->setIndent(TRUE); + $this->setIndent(true); $this->setIndentString(' '); /* * Create the XML document @@ -760,7 +760,7 @@ class PMA_Svg_Relation_Schema extends PMA_Export_Relation_Schema /* put the foreign table on the schema only if selected * by the user * (do not use array_search() because we would have to - * to do a === FALSE and this is not PHP3 compatible) + * to do a === false and this is not PHP3 compatible) */ if (in_array($rel['foreign_table'], $alltables)) { $this->_addRelation($one_table,$svg->getFont(),$svg->getFontSize(), $master_field, $rel['foreign_table'], $rel['foreign_field'], $this->tableDimension); diff --git a/libraries/schema/User_Schema.class.php b/libraries/schema/User_Schema.class.php index 7e8dbfb205..20af01e8e4 100644 --- a/libraries/schema/User_Schema.class.php +++ b/libraries/schema/User_Schema.class.php @@ -139,7 +139,7 @@ class PMA_User_Schema global $db,$table,$query_default_option,$cfgRelation; $page_query = 'SELECT * FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($cfgRelation['pdf_pages']) . ' WHERE db_name = \'' . PMA_sqlAddslashes($db) . '\''; - $page_rs = PMA_query_as_controluser($page_query, FALSE, $query_default_option); + $page_rs = PMA_query_as_controluser($page_query, false, $query_default_option); if ($page_rs && PMA_DBI_num_rows($page_rs) > 0) { ?>
@@ -213,7 +213,7 @@ class PMA_User_Schema $page_query = 'SELECT * FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($cfgRelation['table_coords']) . ' WHERE db_name = \'' . PMA_sqlAddslashes($db) . '\'' . ' AND pdf_page_number = \'' . PMA_sqlAddslashes($this->chosenPage) . '\''; - $page_rs = PMA_query_as_controluser($page_query, FALSE, $query_default_option); + $page_rs = PMA_query_as_controluser($page_query, false, $query_default_option); $array_sh_page = array(); while ($temp_sh_page = @PMA_DBI_fetch_assoc($page_rs)) { $array_sh_page[] = $temp_sh_page; @@ -223,7 +223,7 @@ class PMA_User_Schema */ if (! isset($_POST['with_field_names']) && ! isset($_POST['showwysiwyg'])) { - $with_field_names = TRUE; + $with_field_names = true; } $this->_displayScratchboardTables($array_sh_page); ?> @@ -248,7 +248,7 @@ class PMA_User_Schema $odd_row = true; foreach ($array_sh_page as $dummy_sh_page => $sh_page) { $_mtab = $sh_page['table_name']; - $tabExist[$_mtab] = FALSE; + $tabExist[$_mtab] = false; echo "\n" . ' ' . htmlspecialchars($value) . ''; } @@ -427,13 +427,13 @@ class PMA_User_Schema { $_strtrans = ''; $_strname = ''; - $shoot = FALSE; + $shoot = false; if (!empty($tabExist) && is_array($tabExist)) { foreach ($tabExist as $key => $value) { if (!$value) { $_strtrans .= '' . "\n"; $_strname .= '
  • ' . htmlspecialchars($key) . '
  • ' . "\n"; - $shoot = TRUE; + $shoot = true; } } if ($shoot) { @@ -548,7 +548,7 @@ class PMA_User_Schema . ' AND table_name = \'' . PMA_sqlAddslashes($current_row) . '\'' . "\n" . ' AND pdf_page_number = \'' . PMA_sqlAddslashes($chpage) . '\''; echo $del_query; - PMA_query_as_controluser($del_query, FALSE, $query_default_option); + PMA_query_as_controluser($del_query, false, $query_default_option); } } @@ -591,7 +591,7 @@ class PMA_User_Schema $query = 'DELETE FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($cfgRelation['table_coords']) . ' WHERE db_name = \'' . PMA_sqlAddslashes($db) . '\'' . ' AND pdf_page_number = \'' . PMA_sqlAddslashes($choosePage) . '\''; - PMA_query_as_controluser($query, FALSE, $query_default_option); + PMA_query_as_controluser($query, false, $query_default_option); } /** @@ -608,7 +608,7 @@ class PMA_User_Schema $query = 'DELETE FROM ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($cfgRelation['pdf_pages']) . ' WHERE db_name = \'' . PMA_sqlAddslashes($db) . '\'' . ' AND page_nr = \'' . PMA_sqlAddslashes($choosePage) . '\''; - PMA_query_as_controluser($query, FALSE, $query_default_option); + PMA_query_as_controluser($query, false, $query_default_option); } /** @@ -667,7 +667,7 @@ class PMA_User_Schema . ' WHERE master_db = \'' . $db . '\'' . ' GROUP BY master_table' . ' ORDER BY ' . PMA_backquote('COUNT(master_table)') . ' DESC '; - $master_tables_rs = PMA_query_as_controluser($master_tables, FALSE, $query_default_option); + $master_tables_rs = PMA_query_as_controluser($master_tables, false, $query_default_option); if ($master_tables_rs && PMA_DBI_num_rows($master_tables_rs) > 0) { /* first put all the master tables at beginning * of the list, so they are near the center of @@ -739,7 +739,7 @@ class PMA_User_Schema $insert_query = 'INSERT INTO ' . PMA_backquote($GLOBALS['cfgRelation']['db']) . '.' . PMA_backquote($cfgRelation['table_coords']) . ' ' . '(db_name, table_name, pdf_page_number, x, y) ' . 'VALUES (\'' . PMA_sqlAddslashes($db) . '\', \'' . PMA_sqlAddslashes($current_table) . '\',' . $pageNumber . ',' . $pos_x . ',' . $pos_y . ')'; - PMA_query_as_controluser($insert_query, FALSE, $query_default_option); + PMA_query_as_controluser($insert_query, false, $query_default_option); /* * compute for the next table @@ -794,7 +794,7 @@ class PMA_User_Schema . ' WHERE db_name = \'' . PMA_sqlAddslashes($db) . '\'' . ' AND table_name = \'' . PMA_sqlAddslashes($arrvalue['name']) . '\'' . ' AND pdf_page_number = \'' . PMA_sqlAddslashes($this->chosenPage) . '\''; - $test_rs = PMA_query_as_controluser($test_query, FALSE, $query_default_option); + $test_rs = PMA_query_as_controluser($test_query, false, $query_default_option); //echo $test_query; if ($test_rs && PMA_DBI_num_rows($test_rs) > 0) { if (isset($arrvalue['delete']) && $arrvalue['delete'] == 'y') { @@ -815,7 +815,7 @@ class PMA_User_Schema . 'VALUES (\'' . PMA_sqlAddslashes($db) . '\', \'' . PMA_sqlAddslashes($arrvalue['name']) . '\', \'' . PMA_sqlAddslashes($this->chosenPage) . '\',' . $arrvalue['x'] . ',' . $arrvalue['y'] . ')'; } //echo $ch_query; - PMA_query_as_controluser($ch_query, FALSE, $query_default_option); + PMA_query_as_controluser($ch_query, false, $query_default_option); } // end if } // end for } diff --git a/libraries/schema/Visio_Relation_Schema.class.php b/libraries/schema/Visio_Relation_Schema.class.php index a9be6227aa..fb4340129c 100644 --- a/libraries/schema/Visio_Relation_Schema.class.php +++ b/libraries/schema/Visio_Relation_Schema.class.php @@ -41,7 +41,7 @@ class PMA_VISIO extends XMLWriter * so output is formatted */ - $this->setIndent(TRUE); + $this->setIndent(true); $this->setIndentString(' '); /* * Create the XML document @@ -519,7 +519,7 @@ class PMA_Visio_Relation_Schema extends PMA_Export_Relation_Schema /* put the foreign table on the schema only if selected * by the user * (do not use array_search() because we would have to - * to do a === FALSE and this is not PHP3 compatible) + * to do a === false and this is not PHP3 compatible) */ if (in_array($rel['foreign_table'], $alltables)) { $this->_addRelation($one_table, $master_field, $rel['foreign_table'], $rel['foreign_field'],$this->showKeys); diff --git a/libraries/select_lang.lib.php b/libraries/select_lang.lib.php index 08a5b2fa13..aa3f81d3be 100644 --- a/libraries/select_lang.lib.php +++ b/libraries/select_lang.lib.php @@ -157,7 +157,7 @@ function PMA_langDetect($str, $envType) // $envType = 1 for the 'HTTP_ACCEPT_LANGUAGE' environment variable, // 2 for the 'HTTP_USER_AGENT' one $expr = $value[0]; - if (strpos($expr, '[-_]') === FALSE) { + if (strpos($expr, '[-_]') === false) { $expr = str_replace('|', '([-_][[:alpha:]]{2,3})?|', $expr); } if (($envType == 1 && preg_match('/^(' . addcslashes($expr,'/') . ')(;q=[0-9]\\.[0-9])?$/i', $str)) @@ -347,12 +347,12 @@ function PMA_langList() /* Open the directory */ $handle = @opendir($GLOBALS['lang_path']); /* This can happen if the kit is English-only */ - if ($handle === FALSE) { + if ($handle === false) { return $result; } /* Process all files */ - while (FALSE !== ($file = readdir($handle))) { + while (false !== ($file = readdir($handle))) { if ($file != "." && $file != ".." && file_exists($GLOBALS['lang_path'] . '/' . $file . '/LC_MESSAGES/phpmyadmin.mo')) { $result[$file] = PMA_langDetails($file); } @@ -478,9 +478,6 @@ if (! function_exists('__')) { die('Bad invocation!'); } -/* We use only utf-8 */ -$charset = 'utf-8'; - /* l10n: Text direction, use either ltr or rtl */ $GLOBALS['text_dir'] = __('ltr'); diff --git a/libraries/server_links.inc.php b/libraries/server_links.inc.php index 95e39153f2..2c1ac6aeaa 100644 --- a/libraries/server_links.inc.php +++ b/libraries/server_links.inc.php @@ -14,7 +14,7 @@ if (! defined('PHPMYADMIN')) { require_once './libraries/common.inc.php'; require_once './libraries/server_common.inc.php'; -PMA_checkParameters(array('is_superuser', 'url_query'), TRUE, FALSE); +PMA_checkParameters(array('is_superuser', 'url_query'), true, false); // Don't print all these links if in an Ajax request if (!$GLOBALS['is_ajax_request']) { @@ -34,6 +34,7 @@ if (!$GLOBALS['is_ajax_request']) { /** * Displays tab links + * Put the links we assume are used less, towards the end */ $tabs = array(); @@ -49,11 +50,9 @@ if (!$GLOBALS['is_ajax_request']) { $tabs['status']['link'] = 'server_status.php'; $tabs['status']['text'] = __('Status'); - if (! empty($binary_logs)) { - $tabs['binlog']['icon'] = 's_tbl.png'; - $tabs['binlog']['link'] = 'server_binlog.php'; - $tabs['binlog']['text'] = __('Binary log'); - } + $tabs['process']['icon'] = 's_process.png'; + $tabs['process']['link'] = 'server_processlist.php'; + $tabs['process']['text'] = __('Processes'); if ($is_superuser) { $tabs['rights']['icon'] = 's_rights.png'; @@ -69,6 +68,28 @@ if (!$GLOBALS['is_ajax_request']) { $tabs['import']['link'] = 'server_import.php'; $tabs['import']['text'] = __('Import'); + $tabs['settings']['icon'] = 'b_tblops.png'; + $tabs['settings']['link'] = 'prefs_manage.php'; + $tabs['settings']['text'] = __('Settings'); + $tabs['settings']['active'] = in_array(basename($GLOBALS['PMA_PHP_SELF']), + array('prefs_forms.php', 'prefs_manage.php')); + + $tabs['synchronize']['icon'] = 's_sync.png'; + $tabs['synchronize']['link'] = 'server_synchronize.php'; + $tabs['synchronize']['text'] = __('Synchronize'); + + if (! empty($binary_logs)) { + $tabs['binlog']['icon'] = 's_tbl.png'; + $tabs['binlog']['link'] = 'server_binlog.php'; + $tabs['binlog']['text'] = __('Binary log'); + } + + if ($is_superuser) { + $tabs['replication']['icon'] = 's_replication.png'; + $tabs['replication']['link'] = 'server_replication.php'; + $tabs['replication']['text'] = __('Replication'); + } + $tabs['vars']['icon'] = 's_vars.png'; $tabs['vars']['link'] = 'server_variables.php'; $tabs['vars']['text'] = __('Variables'); @@ -81,22 +102,6 @@ if (!$GLOBALS['is_ajax_request']) { $tabs['engine']['link'] = 'server_engines.php'; $tabs['engine']['text'] = __('Engines'); - if ($is_superuser) { - $tabs['replication']['icon'] = 's_replication.png'; - $tabs['replication']['link'] = 'server_replication.php'; - $tabs['replication']['text'] = __('Replication'); - } - - $tabs['synchronize']['icon'] = 's_sync.png'; - $tabs['synchronize']['link'] = 'server_synchronize.php'; - $tabs['synchronize']['text'] = __('Synchronize'); - - $tabs['settings']['icon'] = 'b_tblops.png'; - $tabs['settings']['link'] = 'prefs_manage.php'; - $tabs['settings']['text'] = __('Settings'); - $tabs['settings']['active'] = in_array(basename($GLOBALS['PMA_PHP_SELF']), - array('prefs_forms.php', 'prefs_manage.php')); - echo PMA_generate_html_tabs($tabs, array()); unset($tabs); diff --git a/libraries/sql_query_form.lib.php b/libraries/sql_query_form.lib.php index 25f67cdbb8..5dd48d2972 100644 --- a/libraries/sql_query_form.lib.php +++ b/libraries/sql_query_form.lib.php @@ -58,7 +58,7 @@ require_once './libraries/bookmark.lib.php'; // used for file listing * @uses function_exists() * @param boolean|string $query query to display in the textarea * or true to display last executed - * @param boolean|string $display_tab sql|files|history|full|FALSE + * @param boolean|string $display_tab sql|files|history|full|false * what part to display * false if not inside querywindow * @param string $delimiter @@ -464,7 +464,6 @@ function PMA_sqlQueryFormBookmark() * @uses $GLOBALS['cfg']['BZipDump'] * @uses $GLOBALS['cfg']['UploadDir'] * @uses $GLOBALS['cfg']['AvailableCharsets'] - * @uses $GLOBALS['charset'] * @uses $GLOBALS['max_upload_size'] * @uses PMA_supportedDecompressions() * @uses PMA_getFileSelectOptions() @@ -496,7 +495,7 @@ function PMA_sqlQueryFormUpload(){ echo PMA_generateHiddenMaxFileSize($GLOBALS['max_upload_size']) . "\n"; echo ''; - if ($files === FALSE) { + if ($files === false) { $errors[] = PMA_Message::error( __('The directory you set for upload work cannot be reached')); } elseif (!empty($files)) { echo '
    '; @@ -515,7 +514,7 @@ function PMA_sqlQueryFormUpload(){ echo '
    '; echo __('Character set of the file:') . "\n"; echo PMA_generateCharsetDropdownBox(PMA_CSDROPDOWN_CHARSET, - 'charset_of_file', null, 'utf8', FALSE); + 'charset_of_file', null, 'utf8', false); echo '' . "\n"; echo '
    ' . "\n"; diff --git a/libraries/sqlparser.data.php b/libraries/sqlparser.data.php index e8a3115815..5011ca7f82 100644 --- a/libraries/sqlparser.data.php +++ b/libraries/sqlparser.data.php @@ -12,9 +12,7 @@ * (around 4.0.2) as well as the MySQL documentation. * * Note: before adding a value in the arrays, ensure that you respect - * proper sorting, especially with underscores. And don't forget to - * update the _cnt variable at the end of each array. - * (It's slower to have PHP do the count). + * proper sorting, especially with underscores. * * It's easier to use only uppercase for proper sorting. In case of * doubt, use the test case to verify. @@ -332,12 +330,6 @@ $PMA_SQPdata_function_name = array ( 'YEAR', 'YEARWEEK' ); -/** - * $PMA_SQPdata_function_name_cnt = count($PMA_SQPdata_function_name); - * - * @global integer MySQL attributes count - */ -$PMA_SQPdata_function_name_cnt = 298; /** * @global array MySQL attributes @@ -374,12 +366,6 @@ $PMA_SQPdata_column_attrib = array ( 'VARYING', 'ZEROFILL' ); -/** - * $PMA_SQPdata_column_attrib_cnt = count($PMA_SQPdata_column_attrib); - * - * @global integer MySQL attributes count - */ -$PMA_SQPdata_column_attrib_cnt = 30; /** * words that are reserved by MySQL and may not be used as identifiers without quotes @@ -527,7 +513,6 @@ $PMA_SQPdata_reserved_word = array ( 'LOGS', 'LOW_PRIORITY', 'MARIA', // 5.1 ? - 'MASTER', 'MASTER_CONNECT_RETRY', 'MASTER_HOST', 'MASTER_LOG_FILE', @@ -680,12 +665,6 @@ $PMA_SQPdata_reserved_word = array ( 'XOR', 'YEAR_MONTH' ); -/** - * $PMA_SQPdata_reserved_word_cnt = count($PMA_SQPdata_reserved_word); - * - * @global integer MySQL reserved words count - */ -$PMA_SQPdata_reserved_word_cnt = 288; /** * words forbidden to be used as column or table name wihtout quotes @@ -1177,12 +1156,6 @@ $PMA_SQPdata_forbidden_word = array ( 'YEAR_MONTH', 'ZEROFILL' ); -/** - * count($PMA_SQPdata_forbidden_word); - * - * @global integer MySQL forbidden words count - */ -$PMA_SQPdata_forbidden_word_cnt = 482; /** * the MySQL column/data types @@ -1248,11 +1221,5 @@ $PMA_SQPdata_column_type = array ( 'VARCHAR', 'YEAR' ); -/** - * $PMA_SQPdata_column_type_cnt = count($PMA_SQPdata_column_type); - * - * @global integer MySQL column types count - */ -$PMA_SQPdata_column_type_cnt = 54; ?> diff --git a/libraries/sqlparser.lib.php b/libraries/sqlparser.lib.php index 5000f4c189..e05d0118ee 100644 --- a/libraries/sqlparser.lib.php +++ b/libraries/sqlparser.lib.php @@ -48,9 +48,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { } if (! isset($mysql_charsets)) { $mysql_charsets = array(); - $mysql_charsets_count = 0; $mysql_collations_flat = array(); - $mysql_collations_count = 0; } if (!defined('DEBUG_TIMING')) { @@ -193,23 +191,16 @@ if (! defined('PMA_MINIMUM_COMMON')) { * @global array MySQL reserved words * @global array MySQL column types * @global array MySQL function names - * @global integer MySQL column attributes count - * @global integer MySQL reserved words count - * @global integer MySQL column types count - * @global integer MySQL function names count * @global array List of available character sets * @global array List of available collations - * @global integer Character sets count - * @global integer Collations count * * @access public */ function PMA_SQP_parse($sql) { - global $PMA_SQPdata_column_attrib, $PMA_SQPdata_reserved_word, $PMA_SQPdata_column_type, $PMA_SQPdata_function_name, - $PMA_SQPdata_column_attrib_cnt, $PMA_SQPdata_reserved_word_cnt, $PMA_SQPdata_column_type_cnt, $PMA_SQPdata_function_name_cnt; - global $mysql_charsets, $mysql_collations_flat, $mysql_charsets_count, $mysql_collations_count; - global $PMA_SQPdata_forbidden_word, $PMA_SQPdata_forbidden_word_cnt; + global $PMA_SQPdata_column_attrib, $PMA_SQPdata_reserved_word, $PMA_SQPdata_column_type; + global $PMA_SQPdata_function_name, $PMA_SQPdata_forbidden_word; + global $mysql_charsets, $mysql_collations_flat; // Convert all line feeds to Unix style $sql = str_replace("\r\n", "\n", $sql); @@ -220,6 +211,15 @@ if (! defined('PMA_MINIMUM_COMMON')) { return array(); } + // Get counts of some arrays + $PMA_SQPdata_column_attrib_cnt = count($PMA_SQPdata_column_attrib); + $PMA_SQPdata_function_name_cnt = count($PMA_SQPdata_function_name); + $PMA_SQPdata_reserved_word_cnt = count($PMA_SQPdata_reserved_word); + $PMA_SQPdata_forbidden_word_cnt = count($PMA_SQPdata_forbidden_word); + $PMA_SQPdata_column_type_cnt = count($PMA_SQPdata_column_type); + $mysql_charsets_count = count($mysql_charsets); + $mysql_collations_count = count($mysql_collations_flat); + $sql_array = array(); $sql_array['raw'] = $sql; $count1 = 0; @@ -328,14 +328,14 @@ if (! defined('PMA_MINIMUM_COMMON')) { $startquotepos = $count2; $quotetype = $c; $count2++; - $escaped = FALSE; - $escaped_escaped = FALSE; + $escaped = false; + $escaped_escaped = false; $pos = $count2; $oldpos = 0; do { $oldpos = $pos; $pos = $GLOBALS['PMA_strpos'](' ' . $sql, $quotetype, $oldpos + 1) - 1; - // ($pos === FALSE) + // ($pos === false) if ($pos < 0) { if ($c == '`') { /* @@ -477,7 +477,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { $is_digit = !$is_identifier && !$is_sql_variable && $GLOBALS['PMA_STR_isDigit']($c); $is_hex_digit = $is_digit && $c == '0' && $count2 < $len && $GLOBALS['PMA_substr']($sql, $count2, 1) == 'x'; $is_float_digit = $c == '.'; - $is_float_digit_exponent = FALSE; + $is_float_digit_exponent = false; /* DEBUG echo '
    2';
    @@ -513,7 +513,7 @@ if (! defined('PMA_MINIMUM_COMMON')) {
                         if ($is_digit && (!$is_hex_digit) && ($c2 == '.')) {
                             $count2++;
                             if (!$is_float_digit) {
    -                            $is_float_digit = TRUE;
    +                            $is_float_digit = true;
                                 continue;
                             } else {
                                 $debugstr = __('Invalid Identifer') . ' @ ' . ($count1+1) . "\n"
    @@ -524,21 +524,21 @@ if (! defined('PMA_MINIMUM_COMMON')) {
                         }
                         if ($is_digit && (!$is_hex_digit) && (($c2 == 'e') || ($c2 == 'E'))) {
                             if (!$is_float_digit_exponent) {
    -                            $is_float_digit_exponent = TRUE;
    -                            $is_float_digit          = TRUE;
    +                            $is_float_digit_exponent = true;
    +                            $is_float_digit          = true;
                                 $count2++;
                                 continue;
                             } else {
    -                            $is_digit                = FALSE;
    -                            $is_float_digit          = FALSE;
    +                            $is_digit                = false;
    +                            $is_float_digit          = false;
                             }
                         }
                         if (($is_hex_digit && PMA_STR_isHexDigit($c2)) || ($is_digit && $GLOBALS['PMA_STR_isDigit']($c2))) {
                             $count2++;
                             continue;
                         } else {
    -                        $is_digit     = FALSE;
    -                        $is_hex_digit = FALSE;
    +                        $is_digit     = false;
    +                        $is_hex_digit = false;
                         }
     
                         $count2++;
    @@ -559,7 +559,7 @@ if (! defined('PMA_MINIMUM_COMMON')) {
                         }
                     } elseif ($is_user) {
                         $type = 'punct_user';
    -                } elseif ($is_sql_variable != FALSE) {
    +                } elseif ($is_sql_variable != false) {
                         $type = 'alpha_variable';
                     } else {
                         $type = 'alpha';
    @@ -776,9 +776,9 @@ if (! defined('PMA_MINIMUM_COMMON')) {
                     }
                     // check if present in the list of forbidden words
                     if ($t_suffix == '_reservedWord' && PMA_STR_binarySearchInArr($d_cur_upper, $PMA_SQPdata_forbidden_word, $PMA_SQPdata_forbidden_word_cnt)) {
    -                    $sql_array[$i]['forbidden'] = TRUE;
    +                    $sql_array[$i]['forbidden'] = true;
                     } else {
    -                    $sql_array[$i]['forbidden'] = FALSE;
    +                    $sql_array[$i]['forbidden'] = false;
                     }
                     $sql_array[$i]['type'] .= $t_suffix;
                 }
    @@ -807,12 +807,12 @@ if (! defined('PMA_MINIMUM_COMMON')) {
         {
             $typeSeperator = '_';
             if (strcmp($whatWeWant, $toCheck) == 0) {
    -            return TRUE;
    +            return true;
             } else {
    -            if (strpos($whatWeWant, $typeSeperator) === FALSE) {
    +            if (strpos($whatWeWant, $typeSeperator) === false) {
                     return strncmp($whatWeWant, $toCheck, strpos($toCheck, $typeSeperator)) == 0;
                 } else {
    -                return FALSE;
    +                return false;
                 }
             }
         }
    @@ -853,8 +853,8 @@ if (! defined('PMA_MINIMUM_COMMON')) {
                 'create_table_fields' => array()
             );
             $subresult_empty = $subresult;
    -        $seek_queryend         = FALSE;
    -        $seen_end_of_table_ref = FALSE;
    +        $seek_queryend         = false;
    +        $seen_end_of_table_ref = false;
             $number_of_brackets_in_extract = 0;
             $number_of_brackets_in_group_concat = 0;
     
    @@ -866,10 +866,10 @@ if (! defined('PMA_MINIMUM_COMMON')) {
             // for SELECT EXTRACT(YEAR_MONTH FROM CURDATE())
             // we must not use CURDATE as a table_ref
             // so we track whether we are in the EXTRACT()
    -        $in_extract          = FALSE;
    +        $in_extract          = false;
     
             // for GROUP_CONCAT(...)
    -        $in_group_concat     = FALSE;
    +        $in_group_concat     = false;
     
     /* Description of analyzer results
      *
    @@ -1038,9 +1038,9 @@ if (! defined('PMA_MINIMUM_COMMON')) {
     //DEBUG echo "Loop1 "  . $arr[$i]['data'] . " (" . $arr[$i]['type'] . ")
    "; // High speed seek for locating the end of the current query - if ($seek_queryend == TRUE) { + if ($seek_queryend == true) { if ($arr[$i]['type'] == 'punct_queryend') { - $seek_queryend = FALSE; + $seek_queryend = false; } else { continue; } // end if (type == punct_queryend) @@ -1075,13 +1075,13 @@ if (! defined('PMA_MINIMUM_COMMON')) { if ($in_extract) { $number_of_brackets_in_extract--; if ($number_of_brackets_in_extract == 0) { - $in_extract = FALSE; + $in_extract = false; } } if ($in_group_concat) { $number_of_brackets_in_group_concat--; if ($number_of_brackets_in_group_concat == 0) { - $in_group_concat = FALSE; + $in_group_concat = false; } } } @@ -1101,18 +1101,18 @@ if (! defined('PMA_MINIMUM_COMMON')) { if ($arr[$i]['type'] == 'alpha_functionName') { $upper_data = strtoupper($arr[$i]['data']); if ($upper_data =='EXTRACT') { - $in_extract = TRUE; + $in_extract = true; $number_of_brackets_in_extract = 0; } if ($upper_data =='GROUP_CONCAT') { - $in_group_concat = TRUE; + $in_group_concat = true; $number_of_brackets_in_group_concat = 0; } } // ============================================================== if ($arr[$i]['type'] == 'alpha_reservedWord' -// && $arr[$i]['forbidden'] == FALSE) { +// && $arr[$i]['forbidden'] == false) { ) { // We don't know what type of query yet, so run this if ($subresult['querytype'] == '') { @@ -1122,7 +1122,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { // Check if we support this type of query if (!PMA_STR_binarySearchInArr($subresult['querytype'], $supported_query_types, $supported_query_types_cnt)) { // Skip ahead to the next one if we don't - $seek_queryend = TRUE; + $seek_queryend = true; continue; } // end if (query not supported) @@ -1139,17 +1139,17 @@ if (! defined('PMA_MINIMUM_COMMON')) { // this is a subquery so do not analyze inside it continue; } - $seen_from = FALSE; - $previous_was_identifier = FALSE; + $seen_from = false; + $previous_was_identifier = false; $current_select_expr = -1; - $seen_end_of_table_ref = FALSE; + $seen_end_of_table_ref = false; } // end if (data == SELECT) if ($upper_data =='FROM' && !$in_extract) { $current_table_ref = -1; - $seen_from = TRUE; - $previous_was_identifier = FALSE; - $save_table_ref = TRUE; + $seen_from = true; + $previous_was_identifier = false; + $save_table_ref = true; } // end if (data == FROM) // here, do not 'continue' the loop, as we have more work for @@ -1162,7 +1162,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { || $arr[$i]['type'] == 'quote_single' || $arr[$i]['type'] == 'alpha_identifier' || ($arr[$i]['type'] == 'alpha_reservedWord' - && $arr[$i]['forbidden'] == FALSE)) { + && $arr[$i]['forbidden'] == false)) { switch ($arr[$i]['type']) { case 'alpha_identifier': @@ -1197,7 +1197,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { $alias_for_select_expr = $identifier; } else { $chain[] = $identifier; - $previous_was_identifier = TRUE; + $previous_was_identifier = true; } // end if !$previous_was_identifier } else { @@ -1209,7 +1209,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { $alias_for_table_ref = $identifier; } else { $chain[] = $identifier; - $previous_was_identifier = TRUE; + $previous_was_identifier = true; } // end if ($previous_was_identifier) } // end if ($save_table_ref &&!$seen_end_of_table_ref) @@ -1220,7 +1220,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { // =================================== if ($arr[$i]['type'] == 'punct_qualifier') { // to be able to detect an identifier following another - $previous_was_identifier = FALSE; + $previous_was_identifier = false; continue; } // end if (punct_qualifier) @@ -1285,7 +1285,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { */ if (($arr[$i]['type'] == 'alpha_reservedWord') && ($upper_data != 'FROM')) { - $previous_was_identifier = TRUE; + $previous_was_identifier = true; } } // end if (save a select expr) @@ -1340,7 +1340,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { .= ' ' . $subresult['table_ref'][$current_table_ref]['table_alias']; unset($chain); - $previous_was_identifier = TRUE; + $previous_was_identifier = true; //continue; } // end if (save a table ref) @@ -1367,29 +1367,29 @@ if (! defined('PMA_MINIMUM_COMMON')) { // e n d i n g l o o p #1 - // set the $previous_was_identifier to FALSE if the current + // set the $previous_was_identifier to false if the current // token is not an identifier if (($arr[$i]['type'] != 'alpha_identifier') && ($arr[$i]['type'] != 'quote_double') && ($arr[$i]['type'] != 'quote_single') && ($arr[$i]['type'] != 'quote_backtick')) { - $previous_was_identifier = FALSE; + $previous_was_identifier = false; } // end if // however, if we are on AS, we must keep the $previous_was_identifier if (($arr[$i]['type'] == 'alpha_reservedWord') && ($upper_data == 'AS')) { - $previous_was_identifier = TRUE; + $previous_was_identifier = true; } if (($arr[$i]['type'] == 'alpha_reservedWord') && ($upper_data =='ON' || $upper_data =='USING')) { - $save_table_ref = FALSE; + $save_table_ref = false; } // end if (data == ON) if (($arr[$i]['type'] == 'alpha_reservedWord') && ($upper_data =='JOIN' || $upper_data =='FROM')) { - $save_table_ref = TRUE; + $save_table_ref = true; } // end if (data == JOIN) /** @@ -1411,19 +1411,19 @@ if (! defined('PMA_MINIMUM_COMMON')) { || ($arr[$i]['type'] == 'alpha_reservedWord' && !$in_group_concat && PMA_STR_binarySearchInArr($upper_data, $words_ending_table_ref, $words_ending_table_ref_cnt))) { - $seen_end_of_table_ref = TRUE; + $seen_end_of_table_ref = true; // to be able to save the last table ref, but do not // set it true if we found a word like "ON" that has // already set it to false - if (isset($save_table_ref) && $save_table_ref != FALSE) { - $save_table_ref = TRUE; + if (isset($save_table_ref) && $save_table_ref != false) { + $save_table_ref = true; } //end if } // end if (check for end of table ref) } //end if (!$seen_end_of_table_ref) if ($seen_end_of_table_ref) { - $save_table_ref = FALSE; + $save_table_ref = false; } // end if } // end for $i (loop #1) @@ -1465,20 +1465,20 @@ if (! defined('PMA_MINIMUM_COMMON')) { $section_before_limit = ''; $section_after_limit = ''; // truly the section after the limit clause - $seen_reserved_word = FALSE; - $seen_group = FALSE; - $seen_order = FALSE; - $seen_order_by = FALSE; - $in_group_by = FALSE; // true when we are inside the GROUP BY clause - $in_order_by = FALSE; // true when we are inside the ORDER BY clause - $in_having = FALSE; // true when we are inside the HAVING clause - $in_select_expr = FALSE; // true when we are inside the select expr clause - $in_where = FALSE; // true when we are inside the WHERE clause - $seen_limit = FALSE; // true if we have seen a LIMIT clause - $in_limit = FALSE; // true when we are inside the LIMIT clause - $after_limit = FALSE; // true when we are after the LIMIT clause - $in_from = FALSE; // true when we are in the FROM clause - $in_group_concat = FALSE; + $seen_reserved_word = false; + $seen_group = false; + $seen_order = false; + $seen_order_by = false; + $in_group_by = false; // true when we are inside the GROUP BY clause + $in_order_by = false; // true when we are inside the ORDER BY clause + $in_having = false; // true when we are inside the HAVING clause + $in_select_expr = false; // true when we are inside the select expr clause + $in_where = false; // true when we are inside the WHERE clause + $seen_limit = false; // true if we have seen a LIMIT clause + $in_limit = false; // true when we are inside the LIMIT clause + $after_limit = false; // true when we are after the LIMIT clause + $in_from = false; // true when we are in the FROM clause + $in_group_concat = false; $first_reserved_word = ''; $current_identifier = ''; $unsorted_query = $arr['raw']; // in case there is no ORDER BY @@ -1521,7 +1521,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { if (!$seen_reserved_word) { $first_reserved_word = $upper_data; $subresult['querytype'] = $upper_data; - $seen_reserved_word = TRUE; + $seen_reserved_word = true; // if the first reserved word is DROP or DELETE, // we know this is a query that needs to be confirmed @@ -1543,22 +1543,22 @@ if (! defined('PMA_MINIMUM_COMMON')) { if ($upper_data == 'LIMIT' && ! $in_subquery) { $section_before_limit = substr($arr['raw'], 0, $arr[$i]['pos'] - 5); - $in_limit = TRUE; - $seen_limit = TRUE; + $in_limit = true; + $seen_limit = true; $limit_clause = ''; - $in_order_by = FALSE; // @todo maybe others to set FALSE + $in_order_by = false; // @todo maybe others to set false } if ($upper_data == 'PROCEDURE') { $subresult['queryflags']['procedure'] = 1; - $in_limit = FALSE; - $after_limit = TRUE; + $in_limit = false; + $after_limit = true; } /** - * @todo set also to FALSE if we find FOR UPDATE or LOCK IN SHARE MODE + * @todo set also to false if we find FOR UPDATE or LOCK IN SHARE MODE */ if ($upper_data == 'SELECT') { - $in_select_expr = TRUE; + $in_select_expr = true; $select_expr_clause = ''; } if ($upper_data == 'DISTINCT' && !$in_group_concat) { @@ -1579,75 +1579,75 @@ if (! defined('PMA_MINIMUM_COMMON')) { // if this is a real SELECT...FROM if ($upper_data == 'FROM' && isset($subresult['queryflags']['select_from']) && $subresult['queryflags']['select_from'] == 1) { - $in_from = TRUE; + $in_from = true; $from_clause = ''; - $in_select_expr = FALSE; + $in_select_expr = false; } - // (we could have less resetting of variables to FALSE + // (we could have less resetting of variables to false // if we trust that the query respects the standard // MySQL order for clauses) // we use $seen_group and $seen_order because we are looking // for the BY if ($upper_data == 'GROUP') { - $seen_group = TRUE; - $seen_order = FALSE; - $in_having = FALSE; - $in_order_by = FALSE; - $in_where = FALSE; - $in_select_expr = FALSE; - $in_from = FALSE; + $seen_group = true; + $seen_order = false; + $in_having = false; + $in_order_by = false; + $in_where = false; + $in_select_expr = false; + $in_from = false; } if ($upper_data == 'ORDER' && !$in_group_concat) { - $seen_order = TRUE; - $seen_group = FALSE; - $in_having = FALSE; - $in_group_by = FALSE; - $in_where = FALSE; - $in_select_expr = FALSE; - $in_from = FALSE; + $seen_order = true; + $seen_group = false; + $in_having = false; + $in_group_by = false; + $in_where = false; + $in_select_expr = false; + $in_from = false; } if ($upper_data == 'HAVING') { - $in_having = TRUE; + $in_having = true; $having_clause = ''; - $seen_group = FALSE; - $seen_order = FALSE; - $in_group_by = FALSE; - $in_order_by = FALSE; - $in_where = FALSE; - $in_select_expr = FALSE; - $in_from = FALSE; + $seen_group = false; + $seen_order = false; + $in_group_by = false; + $in_order_by = false; + $in_where = false; + $in_select_expr = false; + $in_from = false; } if ($upper_data == 'WHERE') { - $in_where = TRUE; + $in_where = true; $where_clause = ''; $where_clause_identifiers = array(); - $seen_group = FALSE; - $seen_order = FALSE; - $in_group_by = FALSE; - $in_order_by = FALSE; - $in_having = FALSE; - $in_select_expr = FALSE; - $in_from = FALSE; + $seen_group = false; + $seen_order = false; + $in_group_by = false; + $in_order_by = false; + $in_having = false; + $in_select_expr = false; + $in_from = false; } if ($upper_data == 'BY') { if ($seen_group) { - $in_group_by = TRUE; + $in_group_by = true; $group_by_clause = ''; } if ($seen_order) { - $seen_order_by = TRUE; + $seen_order_by = true; // Here we assume that the ORDER BY keywords took // exactly 8 characters. // We use PMA_substr() to be charset-safe; otherwise // if the table name contains accents, the unsorted // query would be missing some characters. $unsorted_query = PMA_substr($arr['raw'], 0, $arr[$i]['pos'] - 8); - $in_order_by = TRUE; + $in_order_by = true; $order_by_clause = ''; } } @@ -1655,12 +1655,12 @@ if (! defined('PMA_MINIMUM_COMMON')) { // if we find one of the words that could end the clause if (PMA_STR_binarySearchInArr($upper_data, $words_ending_clauses, $words_ending_clauses_cnt)) { - $in_group_by = FALSE; - $in_order_by = FALSE; - $in_having = FALSE; - $in_where = FALSE; - $in_select_expr = FALSE; - $in_from = FALSE; + $in_group_by = false; + $in_order_by = false; + $in_having = false; + $in_where = false; + $in_select_expr = false; + $in_from = false; } } // endif (reservedWord) @@ -1676,7 +1676,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { $sep=''; $upper_data = strtoupper($arr[$i]['data']); if ($upper_data =='GROUP_CONCAT') { - $in_group_concat = TRUE; + $in_group_concat = true; $number_of_brackets_in_group_concat = 0; } } @@ -1690,7 +1690,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { if ($in_group_concat) { $number_of_brackets_in_group_concat--; if ($number_of_brackets_in_group_concat == 0) { - $in_group_concat = FALSE; + $in_group_concat = false; } } } @@ -1781,17 +1781,17 @@ if (! defined('PMA_MINIMUM_COMMON')) { // not a timestamp, it will be useful when logic has been // added for complete field attributes analysis. - $seen_foreign = FALSE; - $seen_references = FALSE; - $seen_constraint = FALSE; + $seen_foreign = false; + $seen_references = false; + $seen_constraint = false; $foreign_key_number = -1; - $seen_create_table = FALSE; - $seen_create = FALSE; - $seen_alter = FALSE; - $in_create_table_fields = FALSE; + $seen_create_table = false; + $seen_create = false; + $seen_alter = false; + $in_create_table_fields = false; $brackets_level = 0; - $in_timestamp_options = FALSE; - $seen_default = FALSE; + $in_timestamp_options = false; + $seen_default = false; for ($i = 0; $i < $size; $i++) { // DEBUG echo "Loop 3 " . $arr[$i]['data'] . " " . $arr[$i]['type'] . "
    "; @@ -1800,46 +1800,46 @@ if (! defined('PMA_MINIMUM_COMMON')) { $upper_data = strtoupper($arr[$i]['data']); if ($upper_data == 'NOT' && $in_timestamp_options) { - $create_table_fields[$current_identifier]['timestamp_not_null'] = TRUE; + $create_table_fields[$current_identifier]['timestamp_not_null'] = true; } if ($upper_data == 'CREATE') { - $seen_create = TRUE; + $seen_create = true; } if ($upper_data == 'ALTER') { - $seen_alter = TRUE; + $seen_alter = true; } if ($upper_data == 'TABLE' && $seen_create) { - $seen_create_table = TRUE; + $seen_create_table = true; $create_table_fields = array(); } if ($upper_data == 'CURRENT_TIMESTAMP') { if ($in_timestamp_options) { if ($seen_default) { - $create_table_fields[$current_identifier]['default_current_timestamp'] = TRUE; + $create_table_fields[$current_identifier]['default_current_timestamp'] = true; } } } if ($upper_data == 'CONSTRAINT') { $foreign_key_number++; - $seen_foreign = FALSE; - $seen_references = FALSE; - $seen_constraint = TRUE; + $seen_foreign = false; + $seen_references = false; + $seen_constraint = true; } if ($upper_data == 'FOREIGN') { - $seen_foreign = TRUE; - $seen_references = FALSE; - $seen_constraint = FALSE; + $seen_foreign = true; + $seen_references = false; + $seen_constraint = false; } if ($upper_data == 'REFERENCES') { - $seen_foreign = FALSE; - $seen_references = TRUE; - $seen_constraint = FALSE; + $seen_foreign = false; + $seen_references = true; + $seen_constraint = false; } @@ -1884,8 +1884,8 @@ if (! defined('PMA_MINIMUM_COMMON')) { } elseif ($third_upper_data == 'CURRENT_TIMESTAMP') { if ($clause == 'on_update' && $in_timestamp_options) { - $create_table_fields[$current_identifier]['on_update_current_timestamp'] = TRUE; - $seen_default = FALSE; + $create_table_fields[$current_identifier]['on_update_current_timestamp'] = true; + $seen_default = false; } } else { @@ -1905,7 +1905,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { if ($arr[$i]['type'] == 'punct_bracket_open_round') { $brackets_level++; if ($seen_create_table && $brackets_level == 1) { - $in_create_table_fields = TRUE; + $in_create_table_fields = true; } } @@ -1913,10 +1913,10 @@ if (! defined('PMA_MINIMUM_COMMON')) { if ($arr[$i]['type'] == 'punct_bracket_close_round') { $brackets_level--; if ($seen_references) { - $seen_references = FALSE; + $seen_references = false; } if ($seen_create_table && $brackets_level == 0) { - $in_create_table_fields = FALSE; + $in_create_table_fields = false; } } @@ -1924,7 +1924,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { $upper_data = strtoupper($arr[$i]['data']); if ($seen_create_table && $in_create_table_fields) { if ($upper_data == 'DEFAULT') { - $seen_default = TRUE; + $seen_default = true; $create_table_fields[$current_identifier]['default_value'] = $arr[$i + 1]['data']; } } @@ -1939,9 +1939,9 @@ if (! defined('PMA_MINIMUM_COMMON')) { $create_table_fields[$current_identifier]['type'] = $upper_data; if ($upper_data == 'TIMESTAMP') { $arr[$i]['type'] = 'alpha_columnType'; - $in_timestamp_options = TRUE; + $in_timestamp_options = true; } else { - $in_timestamp_options = FALSE; + $in_timestamp_options = false; if ($upper_data == 'CHAR') { $arr[$i]['type'] = 'alpha_columnType'; } @@ -1962,7 +1962,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { if ($seen_create_table && $in_create_table_fields) { $current_identifier = $identifier; // we set this one even for non TIMESTAMP type - $create_table_fields[$current_identifier]['timestamp_not_null'] = FALSE; + $create_table_fields[$current_identifier]['timestamp_not_null'] = false; } if ($seen_constraint) { @@ -2103,17 +2103,17 @@ if (! defined('PMA_MINIMUM_COMMON')) { case 'color': $str = ''; $html_line_break = '
    '; - $docu = TRUE; + $docu = true; break; case 'query_only': $str = ''; $html_line_break = "\n"; - $docu = FALSE; + $docu = false; break; case 'text': $str = ''; $html_line_break = '
    '; - $docu = TRUE; + $docu = true; break; } // end switch // inner_sql is a span that exists for all cases, except query_only @@ -2126,7 +2126,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { $indent = 0; $bracketlevel = 0; $functionlevel = 0; - $infunction = FALSE; + $infunction = false; $space_punct_listsep = ' '; $space_punct_listsep_function_name = ' '; // $space_alpha_reserved_word = '
    '."\n"; @@ -2193,7 +2193,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { $typearr[3] = $arr[$start_token]['type']; } - $in_priv_list = FALSE; + $in_priv_list = false; for ($i = $start_token; $i < $arraysize; $i++) { // DEBUG echo "Loop format " . $arr[$i]['data'] . " " . $arr[$i]['type'] . "
    "; $before = ''; @@ -2227,7 +2227,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { break; case 'punct_bracket_open_round': $bracketlevel++; - $infunction = FALSE; + $infunction = false; // Make sure this array is sorted! if (($typearr[1] == 'alpha_functionName') || ($typearr[1] == 'alpha_columnType') || ($typearr[1] == 'punct') || ($typearr[3] == 'digit_integer') || ($typearr[3] == 'digit_hex') || ($typearr[3] == 'digit_float') @@ -2237,7 +2237,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { && PMA_STR_binarySearchInArr(strtoupper($arr[$i - 1]['data']), $keywords_with_brackets_1before, $keywords_with_brackets_1before_cnt)) ) { $functionlevel++; - $infunction = TRUE; + $infunction = true; $after .= ' '; } else { $indent++; @@ -2263,7 +2263,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { $after = ''; break; case 'punct_listsep': - if ($infunction == TRUE) { + if ($infunction == true) { $after .= $space_punct_listsep_function_name; } else { $after .= $space_punct_listsep; @@ -2277,7 +2277,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { $space_punct_listsep = ' '; $space_punct_listsep_function_name = ' '; $space_alpha_reserved_word = ' '; - $in_priv_list = FALSE; + $in_priv_list = false; break; case 'comment_mysql': case 'comment_ansi': @@ -2300,7 +2300,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { // only close bracket level when it was opened before if ($bracketlevel > 0) { $bracketlevel--; - if ($infunction == TRUE) { + if ($infunction == true) { $functionlevel--; $after .= ' '; $before .= ' '; @@ -2308,7 +2308,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { $indent--; $before .= ($mode != 'query_only' ? '
    ' : ' '); } - $infunction = ($functionlevel > 0) ? TRUE : FALSE; + $infunction = ($functionlevel > 0) ? true : false; } break; case 'alpha_columnType': @@ -2430,7 +2430,7 @@ if (! defined('PMA_MINIMUM_COMMON')) { // on first keyword, check if it introduces a // privilege list if (PMA_STR_binarySearchInArr($arr[$i]['data'], $keywords_priv_list, $keywords_priv_list_cnt)) { - $in_priv_list = TRUE; + $in_priv_list = true; } } } else { diff --git a/libraries/sqlvalidator.class.php b/libraries/sqlvalidator.class.php index 8d1aac6713..f7b836a162 100644 --- a/libraries/sqlvalidator.class.php +++ b/libraries/sqlvalidator.class.php @@ -34,7 +34,7 @@ if (class_exists('SOAPClient')) { $GLOBALS['sqlvalidator_error'] = false; } else { $GLOBALS['sqlvalidator_soap'] = 'NONE'; - $GLOBALS['sqlvalidator_error'] = TRUE; + $GLOBALS['sqlvalidator_error'] = true; PMA_warnMissingExtension('soap'); } } @@ -84,7 +84,7 @@ if (!$GLOBALS['sqlvalidator_error']) { if ($GLOBALS['sqlvalidator_soap'] == 'PHP') { $obj = new SOAPClient($url); } else { - $obj = new SOAP_Client($url, TRUE); + $obj = new SOAP_Client($url, true); } return $obj; } // end of the "openService()" function @@ -431,7 +431,7 @@ if (!$GLOBALS['sqlvalidator_error']) { //add an extra check to ensure that the class was defined without errors if (!class_exists('PMA_SQLValidator')) { - $GLOBALS['sqlvalidator_error'] = TRUE; + $GLOBALS['sqlvalidator_error'] = true; } } // end else diff --git a/libraries/sqlvalidator.lib.php b/libraries/sqlvalidator.lib.php index aaa79c0766..a559ccff3d 100644 --- a/libraries/sqlvalidator.lib.php +++ b/libraries/sqlvalidator.lib.php @@ -38,9 +38,9 @@ if (! defined('PHPMYADMIN')) { * I'm not sure if PEAR was available before this point * For now we actually use a configuration flag */ -if ($cfg['SQLValidator']['use'] == TRUE) { +if ($cfg['SQLValidator']['use'] == true) { require_once './libraries/sqlvalidator.class.php'; -} // if ($cfg['SQLValidator']['use'] == TRUE) +} // if ($cfg['SQLValidator']['use'] == true) /** diff --git a/libraries/string.lib.php b/libraries/string.lib.php index e17a935b9d..650a2efb51 100644 --- a/libraries/string.lib.php +++ b/libraries/string.lib.php @@ -28,7 +28,7 @@ $GLOBALS['PMA_allow_mbstr'] = @function_exists('mb_strlen'); $GLOBALS['PMA_allow_ctype'] = @extension_loaded('ctype'); if ($GLOBALS['PMA_allow_mbstr']) { - mb_internal_encoding($GLOBALS['charset']); + mb_internal_encoding('utf-8'); } /** diff --git a/libraries/tbl_properties.inc.php b/libraries/tbl_properties.inc.php index 501e243bb6..4f1b647fe0 100644 --- a/libraries/tbl_properties.inc.php +++ b/libraries/tbl_properties.inc.php @@ -95,7 +95,7 @@ $is_backup = ($action != 'tbl_create.php' && $action != 'tbl_addfield.php'); $header_cells = array(); $content_cells = array(); -$header_cells[] = __('Column'); +$header_cells[] = __('Name'); $header_cells[] = __('Type') . ($GLOBALS['cfg']['ReplaceHelpImg'] ? PMA_showMySQLDocu('SQL-Syntax', 'data-types') diff --git a/libraries/zip_extension.lib.php b/libraries/zip_extension.lib.php index 435d319147..05279118e1 100644 --- a/libraries/zip_extension.lib.php +++ b/libraries/zip_extension.lib.php @@ -44,7 +44,7 @@ function PMA_getZipContents($file) * haven't found 'content.xml' or there was a parsing * error that we must display */ - if ($entry === FALSE) { + if ($entry === false) { $error_message = __('Error in ZIP archive:') . ' Could not find "content.xml"'; } else { $error_message = __('Error in ZIP archive:') . ' ' . PMA_getZipError($zip_handle); diff --git a/main.php b/main.php index c4c2b2ae58..c508bd0f09 100644 --- a/main.php +++ b/main.php @@ -168,8 +168,8 @@ if ($server > 0 && $GLOBALS['cfg']['ShowServerInfo']) { echo '
  • '; echo ' ' . __('MySQL charset') . ': ' . ' ' - . ' ' . $mysql_charsets_descriptions[$mysql_charset_map[strtolower($charset)]] . "\n" - . ' (' . $mysql_charset_map[strtolower($charset)] . ')' . "\n" + . ' ' . $mysql_charsets_descriptions[$mysql_charset_map['utf-8']] . "\n" + . ' (' . $mysql_charset_map['utf-8'] . ')' . "\n" . ' ' . "\n" . '
  • ' . "\n"; echo ' '; diff --git a/navigation.php b/navigation.php index dc68489d01..76f5b98055 100644 --- a/navigation.php +++ b/navigation.php @@ -11,7 +11,6 @@ * @uses $GLOBALS['available_languages'] * @uses $GLOBALS['lang'] * @uses $GLOBALS['text_dir'] - * @uses $GLOBALS['charset'] * @uses $GLOBALS['pmaThemeImage'] * @uses $GLOBALS['cfg']['LeftFrameLight'] * @uses $GLOBALS['cfg']['ShowTooltip'] @@ -118,7 +117,7 @@ require_once './libraries/header_http.inc.php'; * Displays the frame */ // xml declaration moves IE into quirks mode, making much trouble with CSS -/* echo ''; */ +/* echo ''; */ ?> @@ -131,16 +130,17 @@ require_once './libraries/header_http.inc.php'; phpMyAdmin - + - - - - - + From 14001bcc3b8202636c29e1bb66fdff342e6107b2 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Mon, 6 Jun 2011 15:29:35 +0200 Subject: [PATCH 046/206] -tabs +spaces --- chart_export.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/chart_export.php b/chart_export.php index 8a2139553b..f1c73b8a6b 100644 --- a/chart_export.php +++ b/chart_export.php @@ -12,19 +12,19 @@ define('PMA_MINIMUM_COMMON',true); require_once './libraries/common.inc.php'; if(isset($_REQUEST['filename']) && isset($_REQUEST['image'])) { - $allowed = Array( 'image/png'=>'png', 'image/svg+xml'=>'svg'); - - if(!isset($allowed[$_REQUEST['type']])) exit('Invalid filename'); - - if(!preg_match("/(".implode("|",$allowed).")$/i",$_REQUEST['filename'])) - $_REQUEST['filename'].='.'.$allowed[$_REQUEST['type']]; + $allowed = Array( 'image/png'=>'png', 'image/svg+xml'=>'svg'); + + if(!isset($allowed[$_REQUEST['type']])) exit('Invalid export type'); + + if(!preg_match("/(".implode("|",$allowed).")$/i",$_REQUEST['filename'])) + $_REQUEST['filename'].='.'.$allowed[$_REQUEST['type']]; - header("Cache-Control: public"); - header("Content-Description: File Transfer"); - header("Content-Disposition: attachment; filename=".$_REQUEST['filename']); - header("Content-Type: ".$_REQUEST['type']); - header("Content-Transfer-Encoding: binary"); - - echo base64_decode(substr($_REQUEST['image'],strpos($_REQUEST['image'],',')+1)); + header("Cache-Control: public"); + header("Content-Description: File Transfer"); + header("Content-Disposition: attachment; filename=".$_REQUEST['filename']); + header("Content-Type: ".$_REQUEST['type']); + header("Content-Transfer-Encoding: binary"); + + echo base64_decode(substr($_REQUEST['image'],strpos($_REQUEST['image'],',')+1)); } else exit('Invalid request'); ?> \ No newline at end of file From ed40e7f7bb6172607294c9a769ae7d5b4b6029b2 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Mon, 6 Jun 2011 15:46:01 +0200 Subject: [PATCH 047/206] Small changes/fixes --- js/server_status.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/server_status.js b/js/server_status.js index ceaeb14891..019967f166 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -92,13 +92,13 @@ $(function() { switch(tab.attr('id')) { case 'statustabs_traffic': settings = { - series: [{name:'Connections', data:[]},{name:'Processes', data:[]}], + series: [{name:'Connections since last refresh', data:[]},{name:'Processes', data:[]}], title: {text:'Connections / Processes'}, refresh:{ type: 'proc', callback: function(chartObj, curVal, lastVal,numLoadedPoints) { chartObj.series[0].addPoint( { x:curVal.x, y:curVal.y_conn-lastVal.y_conn }, - true, numLoadedPoints >= numMaxPoints + false, numLoadedPoints >= numMaxPoints ); chartObj.series[1].addPoint( { x:curVal.x, y:curVal.y_proc }, @@ -331,6 +331,7 @@ $(function() { tickPixelInterval: 150 }, yAxis: { + min: 0, title: { text: 'Total count' }, From 855532ea2eddd7f669a52adc6838e716e19fe902 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Tue, 7 Jun 2011 14:54:51 +0200 Subject: [PATCH 048/206] replace pChart with highchart for the query statistics --- js/functions.js | 101 ++++++++++++++++++++++++- js/messages.php | 4 + js/server_status.js | 175 ++++++++++++++++---------------------------- server_status.php | 30 +++++--- 4 files changed, 186 insertions(+), 124 deletions(-) diff --git a/js/functions.js b/js/functions.js index 9bf0fe646d..24f658ef99 100644 --- a/js/functions.js +++ b/js/functions.js @@ -25,6 +25,13 @@ var ajax_message_init = false; */ var codemirror_editor = false; +/** + * @var chart_activeTimeouts object active timeouts that refresh the charts. When disabling a realtime chart, this can be used to stop the continuous ajax requests + */ +var chart_activeTimeouts = new Object(); + + + /** * Add a hidden field to the form to indicate that this will be an * Ajax request (only if this hidden field does not exist) @@ -1237,6 +1244,7 @@ $(document).ready(function(){ * optional, defaults to 'Loading...' * @param var timeout number of milliseconds for the message to be visible * optional, defaults to 5000 + * @return jQuery object jQuery Element that holds the message div */ function PMA_ajaxShowMessage(message, timeout) { @@ -1301,7 +1309,7 @@ function PMA_ajaxShowMessage(message, timeout) { }) } - return $("#loading"); + return $("#loading"); } /** @@ -1332,7 +1340,7 @@ function PMA_showNoticeForEnum(selectElement) { /** * Generates a dialog box to pop up the create_table form */ -function PMA_createTableDialog( div, url , target){ +function PMA_createTableDialog( div, url , target) { /** * @var button_options Object that stores the options passed to jQueryUI * dialog @@ -1376,6 +1384,95 @@ function PMA_createTableDialog( div, url , target){ } +/** + * Creates a highcharts chart in the given container + * + * @param var settings object with highcharts properties that should be applied. (See also http://www.highcharts.com/ref/) + * requires at least settings.chart.renderTo and settings.series to be set. + * In addition there may be an additional property object 'realtime' that allows for realtime charting: + * realtime: { + * url: adress to get the data from (will always add token, ajax_request=1 and chart_data=1 to the GET request) + * type: the GET request will also add type=[value of the type property] to the request + * callback: Callback function that should draw the point, it's called with 4 parameters in this order: + * - the chart object + * - the current response value of the GET request, JSON parsed + * - the previous response value of the GET request, JSON parsed + * - the number of added points + * + * @return object The created highcharts instance + */ +function PMA_createChart(passedSettings) { + var container = passedSettings.chart.renderTo; + + var settings = { + chart: { + type: 'spline', + marginRight: 10, + events: { + load: function() { + var thisChart = this; + var lastValue=null, curValue=null; + var numLoadedPoints=0, otherSum=0; + + // No realtime updates for graphs that are being exported, and disabled when no callback is set + if(thisChart.options.chart.forExport==true || !passedSettings.realtime || !passedSettings.realtime.callback) return; + + var addnewPoint = function() { + $.get(passedSettings.realtime.url,{ajax_request:1, chart_data:1, type:passedSettings.realtime.type},function(data) { + if(chart_activeTimeouts[container]==null) return; + + curValue = jQuery.parseJSON(data); + if(lastValue==null) lastValue = curValue; + + passedSettings.realtime.callback(thisChart,curValue,lastValue,numLoadedPoints) + + lastValue = curValue; + numLoadedPoints++; + chart_activeTimeouts[container] = setTimeout(addnewPoint, refreshRate); + }); + } + + chart_activeTimeouts[container] = setTimeout(addnewPoint, 0); + } + } + }, + credits: { + enabled:false + }, + xAxis: { + type: 'datetime', + tickPixelInterval: 150 + }, + yAxis: { + min: 0, + title: { + text: PMA_messages['strTotalCount'] + }, + plotLines: [{ + value: 0, + width: 1, + color: '#808080' + }] + }, + tooltip: { + formatter: function() { + return ''+ this.series.name +'
    '+ + Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'
    '+ + Highcharts.numberFormat(this.y, 2); + } + }, + exporting: { + enabled: true + }, + series: [] + } + + // Overwrite/Merge default settings with passedsettings + $.extend(true,settings,passedSettings); + + return new Highcharts.Chart(settings); +} + /** * jQuery function that uses jQueryUI's dialogs to confirm with user. Does not * return a jQuery object yet and hence cannot be chained diff --git a/js/messages.php b/js/messages.php index 6235079dab..f58a5a4ac1 100644 --- a/js/messages.php +++ b/js/messages.php @@ -46,6 +46,10 @@ $js_messages['strBLOBRepositoryDisableAreYouSure'] = sprintf(__('Are you sure yo $js_messages['strFormEmpty'] = __('Missing value in the form!'); $js_messages['strNotNumber'] = __('This is not a number!'); +/* Charts */ +/* l10n: Default description for the y-Axis of Charts */ +$js_messages['strTotalCount'] = __('Total count'); + /* For server_privileges.js */ $js_messages['strHostEmpty'] = __('The host name is empty!'); $js_messages['strUserEmpty'] = __('The user name is empty!'); diff --git a/js/server_status.js b/js/server_status.js index 019967f166..b996846717 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -13,7 +13,7 @@ * */ -// Add a tablesorter parser to properly handle thousands seperated numbers and SI units +// Add a tablesorter parser to properly handle thousands seperated numbers and SI prefixes $(function() { jQuery.tablesorter.addParser({ id: "fancyNumber", @@ -52,9 +52,6 @@ $(function() { // Defines what the tabs are currently displaying (realtime or data) var tabStatus = new Object(); - // active timeouts that refresh the charts - var activeTimeouts = new Object(); - // Add tabs $('#serverStatusTabs').tabs({ // Tab persistence @@ -66,19 +63,64 @@ $(function() { // Fixes wrong tab height with floated elements. See also http://bugs.jqueryui.com/ticket/5601 $(".ui-widget-content:not(.ui-tabs):not(.ui-helper-clearfix)").addClass("ui-helper-clearfix"); - // Load chart asynchronly so the page loads faster - $.get($('#serverstatusquerieschart a').first().attr('href'),{ajax_request:1}, function(data) { - $('#serverstatusquerieschart').html(data); - // Init imagemap again - imageMap.init(); + // Build query statistics chart + var cdata = new Array(); + $.each(jQuery.parseJSON($('#serverstatusquerieschart').html()),function(key,value) { + cdata.push([key,parseInt(value)]); + }); + + PMA_createChart({ + chart: { + renderTo: 'serverstatusquerieschart' + + }, + title: { + text:'', + margin:0 + }, + series: [{ + type:'pie', + name: 'Query statistics', + data: cdata + }], + plotOptions: { + pie: { + allowPointSelect: true, + cursor: 'pointer', + dataLabels: { + enabled: true, + formatter: function() { + return ''+ this.point.name +'
    '+ Highcharts.numberFormat(this.percentage, 2) +' %'; + } + } + } + }, + tooltip: { + formatter: function() { return ''+ this.point.name +'
    '+Highcharts.numberFormat(this.y, 2)+'
    ('+Highcharts.numberFormat(this.percentage, 2) +' %)'; } + } }); // Table sorting initTableSorter('statustabs_queries'); initTableSorter('statustabs_allvars'); - // Ajax reload of variables (always the first link) - $('.statuslinks a:nth-child(1)').click(function() { return refreshHandler(this); }); + // Ajax refresh of variables (always the first link in each tab) + $('.statuslinks a:nth-child(1)').click(function() { + // ui-tabs-panel class is added by the jquery tabs feature + var tab=$(element).parents('div.ui-tabs-panel'); + + // Show ajax load icon + $(element).find('img').show(); + + $.get($(element).attr('href'),{ajax_request:1},function(data) { + initTab(tab,data); + $(element).find('img').hide(); + }); + + tabStatus[tab.attr('id')]='data'; + + return false; + }); /** Realtime charting of variables (always the second link) **/ $('.statuslinks a:nth-child(2)').click(function() { @@ -94,8 +136,9 @@ $(function() { settings = { series: [{name:'Connections since last refresh', data:[]},{name:'Processes', data:[]}], title: {text:'Connections / Processes'}, - refresh:{ type: 'proc', - callback: function(chartObj, curVal, lastVal,numLoadedPoints) { + realtime:{ url:'server_status.php?'+url_query, + type: 'proc', + callback: function(chartObj, curVal, lastVal,numLoadedPoints) { chartObj.series[0].addPoint( { x:curVal.x, y:curVal.y_conn-lastVal.y_conn }, false, numLoadedPoints >= numMaxPoints @@ -113,7 +156,8 @@ $(function() { series: [{name:'Issued queries since last refresh', data:[]}], title: {text:'Issued queries'}, tooltip: { formatter:function() { return this.point.name; } }, - refresh:{ type: 'queries', + realtime:{ url:'server_status.php?'+url_query, + type: 'queries', callback: function(chartObj, curVal, lastVal,numLoadedPoints) { chartObj.series[0].addPoint( { x:curVal.x, y:curVal.y-lastVal.y, name:sortedQueriesPointInfo(curVal,lastVal) }, @@ -135,12 +179,12 @@ $(function() { .hide() .after('
    '); tabStatus[tab.attr('id')]='realtime'; - initChart(settings); + PMA_createChart(settings); $(this).html(PMA_messages['strStaticData']); tab.find('.statuslinks a:nth-child(1)').hide(); } else { - clearTimeout(activeTimeouts[tab.attr('id')+"_chart_cnt"]); - activeTimeouts[tab.attr('id')+"_chart_cnt"]=null; + clearTimeout(chart_activeTimeouts[tab.attr('id')+"_chart_cnt"]); + chart_activeTimeouts[tab.attr('id')+"_chart_cnt"]=null; tab.find('.tabInnerContent').show(); tab.find('div#'+tab.attr('id')+'_chart_cnt').remove(); tabStatus[tab.attr('id')]='data'; @@ -150,6 +194,7 @@ $(function() { return false; }); + /* 3 Filtering functions */ $('#filterAlert').change(function() { alertFilter = this.checked; @@ -187,23 +232,6 @@ $(function() { initTableSorter(tab.attr('id')); } - function refreshHandler(element) { - // ui-tabs-panel class is added by the jquery tabs feature - var tab=$(element).parents('div.ui-tabs-panel'); - - // Show ajax load icon - $(element).find('img').show(); - - $.get($(element).attr('href'),{ajax_request:1},function(data) { - initTab(tab,data); - $(element).find('img').hide(); - }); - - tabStatus[tab.attr('id')]='data'; - - return false; - } - function initTableSorter(tabid) { switch(tabid) { case 'statustabs_queries': @@ -281,85 +309,6 @@ $(function() { }); } - function initChart(passedSettings) { - var container = passedSettings.chart.renderTo; - - var settings = { - chart: { - defaultSeriesType: 'spline', - marginRight: 10, - events: { - load: function() { - var thisChart = this; - var lastValue=null; - var numLoadedPoints=0; - var otherSum=0; - - // No realtime updates for graphs that are being exported - if(thisChart.options.chart.forExport==true) return; - - var addnewPoint = function() { - $.get('server_status.php?'+url_query,{ajax_request:1, chart_data:1, type:passedSettings.refresh.type},function(data) { - if(activeTimeouts[container]==null) return; - - var chartData = jQuery.parseJSON(data); - var pointInfo=''; - var i=0; - - chartData.x = parseInt(chartData.x); - chartData.y = parseInt(chartData.y); - - if(lastValue==null) lastValue = chartData; - - passedSettings.refresh.callback(thisChart,chartData,lastValue,numLoadedPoints) - - lastValue = chartData; - numLoadedPoints++; - activeTimeouts[container] = setTimeout(addnewPoint, refreshRate); - }); - } - - activeTimeouts[container] = setTimeout(addnewPoint, 0); - } - } - }, - credits: { - enabled:false - }, - xAxis: { - type: 'datetime', - tickPixelInterval: 150 - }, - yAxis: { - min: 0, - title: { - text: 'Total count' - }, - plotLines: [{ - value: 0, - width: 1, - color: '#808080' - }] - }, - tooltip: { - formatter: function() { - return ''+ this.series.name +'
    '+ - Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'
    '+ - Highcharts.numberFormat(this.y, 2); - } - }, - exporting: { - enabled: true - }, - series: [] - } - - // Overwrite/Merge default settings with passedsettings - $.extend(true,settings,passedSettings); - - chart = new Highcharts.Chart(settings); - } - // Provides a nicely formatted and sorted tooltip of each datapoint of the query statistics function sortedQueriesPointInfo(queries, lastQueries){ var max, maxIdx, num=0; diff --git a/server_status.php b/server_status.php index c4189401b9..6d215879b8 100644 --- a/server_status.php +++ b/server_status.php @@ -64,12 +64,12 @@ require_once './libraries/replication_gui.lib.php'; * JS Includes */ -$GLOBALS['js_include'][] = 'pMap.js'; $GLOBALS['js_include'][] = 'server_status.js'; $GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js'; $GLOBALS['js_include'][] = 'jquery/jquery.tablesorter.js'; $GLOBALS['js_include'][] = 'jquery/jquery.cookie.js'; // For tab persistence $GLOBALS['js_include'][] = 'highcharts/highcharts.js'; +/* Files required for chart exporting */ $GLOBALS['js_include'][] = 'highcharts/exporting.js'; $GLOBALS['js_include'][] = 'canvg/canvg.js'; $GLOBALS['js_include'][] = 'canvg/rgbcolor.js'; @@ -511,14 +511,20 @@ function printQueryStatistics() { $value) { $odd_row = !$odd_row; - // For the percentage column, use Questions - Connections, because - // the number of connections is not an item of the Query types - // but is included in Questions. Then the total of the percentages is 100. - $name = str_replace('Com_', '', $name); - $name = str_replace('_', ' ', $name); + // For the percentage column, use Questions - Connections, because + // the number of connections is not an item of the Query types + // but is included in Questions. Then the total of the percentages is 100. + $name = str_replace(Array('Com_','_'), Array('',' '), $name); + + if($value < $query_sum * 0.02) + $other_sum += $value; + else $chart_json[$name] = $value; ?> @@ -534,15 +540,21 @@ function printQueryStatistics() { -
    +
    ['.__('Show query chart').']'; - } + }*/ + + if($other_sum>0) + $chart_json[__('Other')] = $other_sum; + + echo json_encode($chart_json); + ?>
    Date: Tue, 7 Jun 2011 14:56:34 +0200 Subject: [PATCH 049/206] Fixed refreshrate --- js/functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/functions.js b/js/functions.js index 24f658ef99..8a80ecde14 100644 --- a/js/functions.js +++ b/js/functions.js @@ -1428,7 +1428,7 @@ function PMA_createChart(passedSettings) { lastValue = curValue; numLoadedPoints++; - chart_activeTimeouts[container] = setTimeout(addnewPoint, refreshRate); + chart_activeTimeouts[container] = setTimeout(addnewPoint, passedSettings.realtime.refreshRate || 5000); }); } From 86323a781560b4526b5f5010a1c93adeb410ba51 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Tue, 7 Jun 2011 20:50:38 +0200 Subject: [PATCH 050/206] Better PMA_formatNumber() behaviour. --- libraries/common.lib.php | 67 +++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/libraries/common.lib.php b/libraries/common.lib.php index b09570c630..0a40f79b16 100644 --- a/libraries/common.lib.php +++ b/libraries/common.lib.php @@ -1402,7 +1402,6 @@ function PMA_localizeNumber($value) /** * Formats $value to the given length and appends SI prefixes - * $comma is not substracted from the length * with a $length of 0 no truncation occurs, number is only formated * to the current locale * @@ -1416,10 +1415,11 @@ function PMA_localizeNumber($value) * echo PMA_formatNumber(0, 6); // 0 * * - * @param double $value the value to format - * @param integer $length the max length - * @param integer $comma the number of decimals to retain - * @param boolean $only_down do not reformat numbers below 1 + * @param double $value the value to format + * @param integer $digits_left number of digits left of the comma + * @param integer $digits_right number of digits right of the comma + * @param boolean $only_down do not reformat numbers below 1 + * @param boolean $noTrailingZero removes trailing zeros right of the comma (default: true) * * @return string the formatted value and its unit * @@ -1427,13 +1427,15 @@ function PMA_localizeNumber($value) * * @version 1.1.0 - 2005-10-27 */ -function PMA_formatNumber($value, $length = 3, $comma = 0, $only_down = false) +function PMA_formatNumber($value, $digits_left = 3, $digits_right = 0, $only_down = false, $noTrailingZero = true) { + if($value==0) return '0'; + $originalValue = $value; //number_format is not multibyte safe, str_replace is safe - if ($length === 0) { - $value = number_format($value, $comma); - if($originalValue!=0 && floatval($value) == 0) $value = ' <'.(1/PMA_pow(10,$comma)); + if ($digits_left === 0) { + $value = number_format($value, $digits_right); + if($originalValue!=0 && floatval($value) == 0) $value = ' <'.(1/PMA_pow(10,$digits_right)); return PMA_localizeNumber($value); } @@ -1459,11 +1461,6 @@ function PMA_formatNumber($value, $length = 3, $comma = 0, $only_down = false) 8 => 'Y' ); - // we need at least 3 digits to be displayed - if (3 > $length + $comma) { - $length = 3 - $comma; - } - // check for negative value to retain sign if ($value < 0) { $sign = '-'; @@ -1472,33 +1469,25 @@ function PMA_formatNumber($value, $length = 3, $comma = 0, $only_down = false) $sign = ''; } - $dh = PMA_pow(10, $comma); - $li = PMA_pow(10, $length); - $unit = $units[0]; - - if ($value >= 1) { - for ($d = 8; $d >= 0; $d--) { - if (isset($units[$d]) && $value >= $li * PMA_pow(1000, $d-1)) { - $value = round($value / (PMA_pow(1000, $d) / $dh)) /$dh; - $unit = $units[$d]; - break 1; - } // end if - } // end for - } elseif (!$only_down && (float) $value !== 0.0) { - for ($d = -8; $d <= 8; $d++) { - // force using pow() because of the negative exponent - if (isset($units[$d]) && $value <= $li * PMA_pow(1000, $d-1, 'pow')) { - $value = round($value / (PMA_pow(1000, $d, 'pow') / $dh)) /$dh; - $unit = $units[$d]; - break 1; - } // end if - } // end for - } // end if ($value >= 1) elseif (!$only_down && (float) $value !== 0.0) - + $dh = PMA_pow(10, $digits_right); + $li = PMA_pow(10, $digits_left); + + $d=-8; + if($only_down || $value>=1) $d=0; + while($value / (PMA_pow(1000, $d, 'pow')) > $li && $d<8) + $d++; + //number_format is not multibyte safe, str_replace is safe - $value = PMA_localizeNumber(number_format($value, $comma)); + $value = round($value / (PMA_pow(1000, $d, 'pow') / $dh)) /$dh; + $unit = $units[$d]; - if($originalValue!=0 && floatval($value) == 0) return ' <'.(1/PMA_pow(10,$comma)).' '.$unit; + // If we dont want any zeros after the comma just add the thousand seperator + if($noTrailingZero) + $value = PMA_localizeNumber(preg_replace("/(?<=\d)(?=(\d{3})+(?!\d))/",",",$value)); + else + $value = PMA_localizeNumber(number_format($value, $digits_right)); + + if($originalValue!=0 && floatval($value) == 0) return ' <'.(1/PMA_pow(10,$digits_right)).' '.$unit; return $sign . $value . ' ' . $unit; } // end of the 'PMA_formatNumber' function From e913dcc6e115a52b2a3305e53cc74fcc3d4d1a46 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Tue, 7 Jun 2011 20:58:56 +0200 Subject: [PATCH 051/206] -Tabs +Spaces --- libraries/common.lib.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/common.lib.php b/libraries/common.lib.php index 0a40f79b16..7290ece898 100644 --- a/libraries/common.lib.php +++ b/libraries/common.lib.php @@ -1429,8 +1429,8 @@ function PMA_localizeNumber($value) */ function PMA_formatNumber($value, $digits_left = 3, $digits_right = 0, $only_down = false, $noTrailingZero = true) { - if($value==0) return '0'; - + if($value==0) return '0'; + $originalValue = $value; //number_format is not multibyte safe, str_replace is safe if ($digits_left === 0) { @@ -1471,15 +1471,15 @@ function PMA_formatNumber($value, $digits_left = 3, $digits_right = 0, $only_dow $dh = PMA_pow(10, $digits_right); $li = PMA_pow(10, $digits_left); - - $d=-8; - if($only_down || $value>=1) $d=0; - while($value / (PMA_pow(1000, $d, 'pow')) > $li && $d<8) - $d++; - + + $d=-8; + if($only_down || $value>=1) $d=0; + while($value / (PMA_pow(1000, $d, 'pow')) > $li && $d<8) + $d++; + //number_format is not multibyte safe, str_replace is safe - $value = round($value / (PMA_pow(1000, $d, 'pow') / $dh)) /$dh; - $unit = $units[$d]; + $value = round($value / (PMA_pow(1000, $d, 'pow') / $dh)) /$dh; + $unit = $units[$d]; // If we dont want any zeros after the comma just add the thousand seperator if($noTrailingZero) From 902fc1d95da7c912993b893ce8f883569fb41da0 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Tue, 7 Jun 2011 21:32:05 +0200 Subject: [PATCH 052/206] - Replaced pChart profiling chart with highchart chart - Moved PMA_profilingResults() function code inline in sql.php as its used at only one place --- js/sql.js | 44 +++++++++++++++++++++++++++++++++++++++- libraries/common.lib.php | 37 --------------------------------- sql.php | 34 +++++++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/js/sql.js b/js/sql.js index a165e4adce..444a813149 100644 --- a/js/sql.js +++ b/js/sql.js @@ -1155,6 +1155,48 @@ $(document).ready(function() { $('.column_heading').live('click', function() { PMA_changeClassForColumn($(this), 'marked'); }); -}) +}); + +/* + * Profiling Chart + */ +$(document).ready(function() { + if($('#profilingchart').length==0) return; + + var cdata = new Array(); + + $.each(jQuery.parseJSON($('#profilingchart').html()),function(key,value) { + cdata.push([key,parseFloat(value)]); + }); + + PMA_createChart({ + chart: { + renderTo: 'profilingchart', + backgroundColor: $('#sqlqueryresults fieldset').css('background-color') + }, + title: { text:'', margin:0 }, + series: [{ + type:'pie', + name: 'Query execution time', + data: cdata + }], + plotOptions: { + pie: { + allowPointSelect: true, + cursor: 'pointer', + dataLabels: { + enabled: true, + distance: 35, + formatter: function() { + return ''+ this.point.name +'
    '+ Highcharts.numberFormat(this.percentage, 2) +' %'; + } + } + } + }, + tooltip: { + formatter: function() { return ''+ this.point.name +'
    '+this.y+'s
    ('+Highcharts.numberFormat(this.percentage, 2) +' %)'; } + } + }); +}); /**#@- */ diff --git a/libraries/common.lib.php b/libraries/common.lib.php index 7290ece898..54ce4e8f9c 100644 --- a/libraries/common.lib.php +++ b/libraries/common.lib.php @@ -1302,43 +1302,6 @@ function PMA_profilingCheckbox($sql_query) } } -/** - * Displays the results of SHOW PROFILE - * - * @param array the results - * @param boolean show chart - * @access public - * - */ -function PMA_profilingResults($profiling_results, $show_chart = false) -{ - echo '
    ' . __('Profiling') . '' . "\n"; - echo '
    '; - echo '' . "\n"; - echo ' ' . "\n"; - echo ' ' . "\n"; - echo ' ' . "\n"; - echo ' ' . "\n"; - - foreach($profiling_results as $one_result) { - echo ' ' . "\n"; - echo '' . "\n"; - echo '' . "\n"; - } - - echo '
    ' . __('Status') . '' . __('Time') . '
    ' . $one_result['Status'] . '' . $one_result['Duration'] . '
    ' . "\n"; - echo '
    '; - - if ($show_chart) { - require_once './libraries/chart.lib.php'; - echo '
    '; - PMA_chart_profiling($profiling_results); - echo '
    '; - } - - echo '
    ' . "\n"; -} - /** * Formats $value to byte view * diff --git a/sql.php b/sql.php index 61a4668ec6..9d01a7b822 100644 --- a/sql.php +++ b/sql.php @@ -15,7 +15,14 @@ require_once './libraries/check_user_privileges.lib.php'; require_once './libraries/bookmark.lib.php'; $GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js'; -$GLOBALS['js_include'][] = 'pMap.js'; + +if(isset($_SESSION['profiling'])) { + $GLOBALS['js_include'][] = 'highcharts/highcharts.js'; + /* Files required for chart exporting */ + $GLOBALS['js_include'][] = 'highcharts/exporting.js'; + $GLOBALS['js_include'][] = 'canvg/canvg.js'; + $GLOBALS['js_include'][] = 'canvg/rgbcolor.js'; +} /** * Defines the url to return to in case of error in a sql statement @@ -890,7 +897,30 @@ else { } if (isset($profiling_results)) { - PMA_profilingResults($profiling_results, true); + echo '
    ' . __('Profiling') . '' . "\n"; + echo '
    '; + echo '' . "\n"; + echo ' ' . "\n"; + echo ' ' . "\n"; + echo ' ' . "\n"; + echo ' ' . "\n"; + + $chart_json = Array(); + foreach($profiling_results as $one_result) { + echo ' ' . "\n"; + echo '' . "\n"; + echo '' . "\n"; + $chart_json[ucwords($one_result['Status'])] = $one_result['Duration']; + } + + echo '
    ' . __('Status') . '' . __('Time') . '
    ' . ucwords($one_result['Status']) . '' . (PMA_formatNumber($one_result['Duration'],3,1)) . 's
    ' . "\n"; + echo '
    '; + //require_once './libraries/chart.lib.php'; + echo '
    '; + //PMA_chart_profiling($profiling_results); + echo json_encode($chart_json); + echo '
    '; + echo '
    ' . "\n"; } // Displays the results in a table From fcb3273c64d588f32b733aae0e8b95aa2d920523 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Wed, 8 Jun 2011 01:53:21 +0200 Subject: [PATCH 053/206] -Tabs +Spaces --- js/sql.js | 71 ++++++++++++++++++++++++++++--------------------------- sql.php | 54 +++++++++++++++++++++--------------------- 2 files changed, 63 insertions(+), 62 deletions(-) diff --git a/js/sql.js b/js/sql.js index 444a813149..f58a172db2 100644 --- a/js/sql.js +++ b/js/sql.js @@ -1161,42 +1161,43 @@ $(document).ready(function() { * Profiling Chart */ $(document).ready(function() { - if($('#profilingchart').length==0) return; - - var cdata = new Array(); - - $.each(jQuery.parseJSON($('#profilingchart').html()),function(key,value) { - cdata.push([key,parseFloat(value)]); - }); + if($('#profilingchart').length==0) return; + + var cdata = new Array(); + var i=1; + $.each(jQuery.parseJSON($('#profilingchart').html()),function(key,value) { + cdata.push([key,parseFloat(value)]); + i++; + }); - PMA_createChart({ - chart: { - renderTo: 'profilingchart', - backgroundColor: $('#sqlqueryresults fieldset').css('background-color') - }, - title: { text:'', margin:0 }, - series: [{ - type:'pie', - name: 'Query execution time', - data: cdata - }], - plotOptions: { - pie: { - allowPointSelect: true, - cursor: 'pointer', - dataLabels: { - enabled: true, - distance: 35, - formatter: function() { - return ''+ this.point.name +'
    '+ Highcharts.numberFormat(this.percentage, 2) +' %'; - } - } - } - }, - tooltip: { - formatter: function() { return ''+ this.point.name +'
    '+this.y+'s
    ('+Highcharts.numberFormat(this.percentage, 2) +' %)'; } - } - }); + PMA_createChart({ + chart: { + renderTo: 'profilingchart', + backgroundColor: $('#sqlqueryresults fieldset').css('background-color') + }, + title: { text:'', margin:0 }, + series: [{ + type:'pie', + name: 'Query execution time', + data: cdata + }], + plotOptions: { + pie: { + allowPointSelect: true, + cursor: 'pointer', + dataLabels: { + enabled: true, + distance: 35, + formatter: function() { + return ''+ this.point.name +'
    '+ Highcharts.numberFormat(this.percentage, 2) +' %'; + } + } + } + }, + tooltip: { + formatter: function() { return ''+ this.point.name +'
    '+this.y+'s
    ('+Highcharts.numberFormat(this.percentage, 2) +' %)'; } + } + }); }); /**#@- */ diff --git a/sql.php b/sql.php index 9d01a7b822..1d7933c6b1 100644 --- a/sql.php +++ b/sql.php @@ -17,11 +17,11 @@ require_once './libraries/bookmark.lib.php'; $GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js'; if(isset($_SESSION['profiling'])) { - $GLOBALS['js_include'][] = 'highcharts/highcharts.js'; - /* Files required for chart exporting */ - $GLOBALS['js_include'][] = 'highcharts/exporting.js'; - $GLOBALS['js_include'][] = 'canvg/canvg.js'; - $GLOBALS['js_include'][] = 'canvg/rgbcolor.js'; + $GLOBALS['js_include'][] = 'highcharts/highcharts.js'; + /* Files required for chart exporting */ + $GLOBALS['js_include'][] = 'highcharts/exporting.js'; + $GLOBALS['js_include'][] = 'canvg/canvg.js'; + $GLOBALS['js_include'][] = 'canvg/rgbcolor.js'; } /** @@ -897,30 +897,30 @@ else { } if (isset($profiling_results)) { - echo '
    ' . __('Profiling') . '' . "\n"; - echo '
    '; - echo '' . "\n"; - echo ' ' . "\n"; - echo ' ' . "\n"; - echo ' ' . "\n"; - echo ' ' . "\n"; + echo '
    ' . __('Profiling') . '' . "\n"; + echo '
    '; + echo '
    ' . __('Status') . '' . __('Time') . '
    ' . "\n"; + echo ' ' . "\n"; + echo ' ' . "\n"; + echo ' ' . "\n"; + echo ' ' . "\n"; - $chart_json = Array(); - foreach($profiling_results as $one_result) { - echo ' ' . "\n"; - echo '' . "\n"; - echo '' . "\n"; - $chart_json[ucwords($one_result['Status'])] = $one_result['Duration']; - } + $chart_json = Array(); + foreach($profiling_results as $one_result) { + echo ' ' . "\n"; + echo '' . "\n"; + echo '' . "\n"; + $chart_json[ucwords($one_result['Status'])] = $one_result['Duration']; + } - echo '
    ' . __('Status') . '' . __('Time') . '
    ' . ucwords($one_result['Status']) . '' . (PMA_formatNumber($one_result['Duration'],3,1)) . 's
    ' . ucwords($one_result['Status']) . '' . (PMA_formatNumber($one_result['Duration'],3,1)) . 's
    ' . "\n"; - echo '
    '; - //require_once './libraries/chart.lib.php'; - echo '
    '; - //PMA_chart_profiling($profiling_results); - echo json_encode($chart_json); - echo '
    '; - echo '
    ' . "\n"; + echo '' . "\n"; + echo '
    '; + //require_once './libraries/chart.lib.php'; + echo '
    '; + //PMA_chart_profiling($profiling_results); + echo json_encode($chart_json); + echo '
    '; + echo '
    ' . "\n"; } // Displays the results in a table From 0d1872595f6f1c14602a7edd1d652bc84ffe0b3f Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Wed, 8 Jun 2011 10:19:59 +0200 Subject: [PATCH 054/206] Math to the resuce! Nicer calculation of PMA_formatNumber() without any loops --- libraries/common.lib.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/libraries/common.lib.php b/libraries/common.lib.php index 54ce4e8f9c..2d3de6743d 100644 --- a/libraries/common.lib.php +++ b/libraries/common.lib.php @@ -1432,15 +1432,18 @@ function PMA_formatNumber($value, $digits_left = 3, $digits_right = 0, $only_dow $sign = ''; } - $dh = PMA_pow(10, $digits_right); - $li = PMA_pow(10, $digits_left); + // This gives us the right SI prefix already, but $digits_left parameter not included + $d = floor($log10 / 3); - $d=-8; - if($only_down || $value>=1) $d=0; - while($value / (PMA_pow(1000, $d, 'pow')) > $li && $d<8) - $d++; + // Lowering the SI prefix by 1 gives us an additional 3 zeros + // So if we have 3,6,9,12.. free zeros ($digits_left - $cur_digits) to use, then lower the SI prefix + $cur_digits = log10($value / PMA_pow(1000, $d, 'pow'))+1; + if($digits_left > $cur_digits) { + $d-= floor(($digits_left - $cur_digits)/3); + } + + if($d<0 && $only_down) $d=0; - //number_format is not multibyte safe, str_replace is safe $value = round($value / (PMA_pow(1000, $d, 'pow') / $dh)) /$dh; $unit = $units[$d]; @@ -1448,7 +1451,7 @@ function PMA_formatNumber($value, $digits_left = 3, $digits_right = 0, $only_dow if($noTrailingZero) $value = PMA_localizeNumber(preg_replace("/(?<=\d)(?=(\d{3})+(?!\d))/",",",$value)); else - $value = PMA_localizeNumber(number_format($value, $digits_right)); + $value = PMA_localizeNumber(number_format($value, $digits_right)); //number_format is not multibyte safe, str_replace is safe if($originalValue!=0 && floatval($value) == 0) return ' <'.(1/PMA_pow(10,$digits_right)).' '.$unit; From 9410a4cfd9d92342e9c30ae3c43c64ceb45462b0 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Wed, 8 Jun 2011 10:31:22 +0200 Subject: [PATCH 055/206] Forgot 2 lines in PMA_formatNumber() --- libraries/common.lib.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/common.lib.php b/libraries/common.lib.php index 2d3de6743d..45ca1c39a5 100644 --- a/libraries/common.lib.php +++ b/libraries/common.lib.php @@ -1432,11 +1432,12 @@ function PMA_formatNumber($value, $digits_left = 3, $digits_right = 0, $only_dow $sign = ''; } - // This gives us the right SI prefix already, but $digits_left parameter not included - $d = floor($log10 / 3); + $dh = PMA_pow(10, $digits_right); + // This gives us the right SI prefix already, but $digits_left parameter not included + $d = floor(log10($value) / 3); // Lowering the SI prefix by 1 gives us an additional 3 zeros - // So if we have 3,6,9,12.. free zeros ($digits_left - $cur_digits) to use, then lower the SI prefix + // So if we have 3,6,9,12.. free zeros ($digits_left - $cur_digits) to use, then lower the SI prefix $cur_digits = log10($value / PMA_pow(1000, $d, 'pow'))+1; if($digits_left > $cur_digits) { $d-= floor(($digits_left - $cur_digits)/3); From 80bf93d5a1dd5fc0a2f83030d7223e54b5187248 Mon Sep 17 00:00:00 2001 From: Burak Yavuz Date: Wed, 8 Jun 2011 16:26:07 +0200 Subject: [PATCH 056/206] Translation update done using Pootle. --- po/tr.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/tr.po b/po/tr.po index 61c405ce3b..60b1c4597c 100644 --- a/po/tr.po +++ b/po/tr.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-08 16:25+0200\n" +"PO-Revision-Date: 2011-06-08 16:26+0200\n" "Last-Translator: Burak Yavuz \n" "Language-Team: turkish \n" "Language: tr\n" @@ -3978,7 +3978,7 @@ msgstr "" #: libraries/config/messages.inc.php:416 msgid "Signon session name" -msgstr "Oturum açma oturumu adı" +msgstr "Oturumu açma oturumu adı" #: libraries/config/messages.inc.php:417 msgid "Signon URL" From 3a24c80b85daeaef3834a9137cde6835e3a4201c Mon Sep 17 00:00:00 2001 From: Burak Yavuz Date: Wed, 8 Jun 2011 16:26:12 +0200 Subject: [PATCH 057/206] Translation update done using Pootle. --- po/tr.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/tr.po b/po/tr.po index 60b1c4597c..433d171a09 100644 --- a/po/tr.po +++ b/po/tr.po @@ -3982,7 +3982,7 @@ msgstr "Oturumu açma oturumu adı" #: libraries/config/messages.inc.php:417 msgid "Signon URL" -msgstr "Oturum açma URL'si" +msgstr "Oturumu açma URL'si" #: libraries/config/messages.inc.php:418 msgid "Socket on which MySQL server is listening, leave empty for default" From 58b3e78d8fe105b77c589ce46de4dc89a706437b Mon Sep 17 00:00:00 2001 From: Burak Yavuz Date: Wed, 8 Jun 2011 16:26:35 +0200 Subject: [PATCH 058/206] Translation update done using Pootle. --- po/tr.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/tr.po b/po/tr.po index 433d171a09..10b637adfe 100644 --- a/po/tr.po +++ b/po/tr.po @@ -4474,7 +4474,7 @@ msgstr "HTTP kimlik doğrulaması" #: libraries/config/setup.forms.php:51 msgid "Signon authentication" -msgstr "Oturum kaydı kimlik doğrulaması" +msgstr "Oturumu açma kimlik doğrulaması" #: libraries/config/setup.forms.php:244 #: libraries/config/user_preferences.forms.php:146 libraries/import/ldi.php:34 From 2c73ec9ec4c7c6e5c7b9e8118037b7317d0ac478 Mon Sep 17 00:00:00 2001 From: Burak Yavuz Date: Wed, 8 Jun 2011 16:29:28 +0200 Subject: [PATCH 059/206] Translation update done using Pootle. --- po/tr.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/tr.po b/po/tr.po index 10b637adfe..6135d4d72c 100644 --- a/po/tr.po +++ b/po/tr.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-08 16:26+0200\n" +"PO-Revision-Date: 2011-06-08 16:29+0200\n" "Last-Translator: Burak Yavuz \n" "Language-Team: turkish \n" "Language: tr\n" @@ -4545,7 +4545,7 @@ msgstr "Yapılandırma kimlik doğrulaması yöntemi kullanırken kullanıcı ad #: libraries/config/validate.lib.php:238 msgid "Empty signon session name while using signon authentication method" msgstr "" -"Oturum kaydı kimlik doğrulaması yöntemi kullanırken oturum kaydı oturumu adı " +"Oturumu açma kimlik doğrulaması yöntemi kullanırken oturumu açma oturum adı " "boş" #: libraries/config/validate.lib.php:242 From 407f1c7d052873e1bbd2f32f8e7524bc65396244 Mon Sep 17 00:00:00 2001 From: Burak Yavuz Date: Wed, 8 Jun 2011 16:29:47 +0200 Subject: [PATCH 060/206] Translation update done using Pootle. --- po/tr.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/tr.po b/po/tr.po index 6135d4d72c..a64d1e6e8f 100644 --- a/po/tr.po +++ b/po/tr.po @@ -3978,7 +3978,7 @@ msgstr "" #: libraries/config/messages.inc.php:416 msgid "Signon session name" -msgstr "Oturumu açma oturumu adı" +msgstr "Oturumu açma oturum adı" #: libraries/config/messages.inc.php:417 msgid "Signon URL" From e1e81c0914b50f34b02636973da63885c987bbf4 Mon Sep 17 00:00:00 2001 From: Burak Yavuz Date: Wed, 8 Jun 2011 16:30:14 +0200 Subject: [PATCH 061/206] Translation update done using Pootle. --- po/tr.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/tr.po b/po/tr.po index a64d1e6e8f..2bac6dfaf6 100644 --- a/po/tr.po +++ b/po/tr.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-08 16:29+0200\n" +"PO-Revision-Date: 2011-06-08 16:30+0200\n" "Last-Translator: Burak Yavuz \n" "Language-Team: turkish \n" "Language: tr\n" @@ -4551,7 +4551,7 @@ msgstr "" #: libraries/config/validate.lib.php:242 msgid "Empty signon URL while using signon authentication method" msgstr "" -"Oturum kaydı kimlik doğrulaması yöntemi kullanırken oturum kaydı URL'si boş" +"Oturumu açma kimlik doğrulaması yöntemi kullanırken oturumu açma URL'si boş" #: libraries/config/validate.lib.php:276 msgid "Empty phpMyAdmin control user while using pmadb" From a6361f718becdb92a0db018153aad14cdc6f658b Mon Sep 17 00:00:00 2001 From: Victor Volkov Date: Thu, 9 Jun 2011 00:18:15 +0200 Subject: [PATCH 062/206] Translation update done using Pootle. --- po/ru.po | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/po/ru.po b/po/ru.po index 42830b7f85..65f29638a2 100644 --- a/po/ru.po +++ b/po/ru.po @@ -4,13 +4,13 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-01 22:34+0200\n" +"PO-Revision-Date: 2011-06-09 00:18+0200\n" "Last-Translator: Victor Volkov \n" "Language-Team: russian \n" +"Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ru\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%" "10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Pootle 2.0.5\n" @@ -1034,10 +1034,9 @@ msgstr "Некорректное подтверждение пароля!" #: js/messages.php:54 server_privileges.php:1679 server_privileges.php:1703 #: server_privileges.php:2108 server_privileges.php:2302 -#, fuzzy #| msgid "Any user" msgid "Add user" -msgstr "Любой пользователь" +msgstr "Добавить пользователя" #: js/messages.php:55 msgid "Reloading Privileges" From c24d36436f5fe6e0de79ab9ae2e19d8d2cc450b2 Mon Sep 17 00:00:00 2001 From: Victor Volkov Date: Thu, 9 Jun 2011 00:18:36 +0200 Subject: [PATCH 063/206] Translation update done using Pootle. --- po/ru.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/ru.po b/po/ru.po index 65f29638a2..f828ef59b9 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1108,10 +1108,9 @@ msgid "Create Table" msgstr "Создать таблицу" #: js/messages.php:82 -#, fuzzy #| msgid "Use Tables" msgid "Insert Table" -msgstr "Использовать таблицы" +msgstr "Вставить таблицу" #: js/messages.php:85 msgid "Searching" From bcc7282f35e658e4e8f67eeac8412f744ca40e31 Mon Sep 17 00:00:00 2001 From: Victor Volkov Date: Thu, 9 Jun 2011 00:19:36 +0200 Subject: [PATCH 064/206] Translation update done using Pootle. --- po/ru.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/ru.po b/po/ru.po index f828ef59b9..2f3863b3b5 100644 --- a/po/ru.po +++ b/po/ru.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 00:18+0200\n" +"PO-Revision-Date: 2011-06-09 00:19+0200\n" "Last-Translator: Victor Volkov \n" "Language-Team: russian \n" "Language: ru\n" @@ -1802,10 +1802,9 @@ msgid "Wrong username/password. Access denied." msgstr "Данные для входа не верны. В доступе отказано." #: libraries/auth/signon.auth.lib.php:87 -#, fuzzy #| msgid "Config authentication" msgid "Can not find signon authentication script:" -msgstr "Авторизация через конфигурационный файл" +msgstr "Не найден скрипт авторизации методом signon:" #: libraries/auth/swekey/swekey.auth.lib.php:118 #, php-format From 7f59b0027c5b278e8fe7b7dfd772ab8d289ad224 Mon Sep 17 00:00:00 2001 From: Victor Volkov Date: Thu, 9 Jun 2011 00:20:17 +0200 Subject: [PATCH 065/206] Translation update done using Pootle. --- po/ru.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/ru.po b/po/ru.po index 2f3863b3b5..5fbf11a99d 100644 --- a/po/ru.po +++ b/po/ru.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 00:19+0200\n" +"PO-Revision-Date: 2011-06-09 00:20+0200\n" "Last-Translator: Victor Volkov \n" "Language-Team: russian \n" "Language: ru\n" @@ -2225,7 +2225,7 @@ msgstr "Оба" #: libraries/config.values.php:47 msgid "Nowhere" -msgstr "" +msgstr "Нигде" #: libraries/config.values.php:47 msgid "Left" From b5319a4a984b34dee5c8dd47a529cd58650d9617 Mon Sep 17 00:00:00 2001 From: Victor Volkov Date: Thu, 9 Jun 2011 00:20:44 +0200 Subject: [PATCH 066/206] Translation update done using Pootle. --- po/ru.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/ru.po b/po/ru.po index 5fbf11a99d..cd46558a3b 100644 --- a/po/ru.po +++ b/po/ru.po @@ -2229,7 +2229,7 @@ msgstr "Нигде" #: libraries/config.values.php:47 msgid "Left" -msgstr "" +msgstr "Налево" #: libraries/config.values.php:47 #, fuzzy From c4900cac8a9b4cdab0d82979927c7245aafc16ff Mon Sep 17 00:00:00 2001 From: Victor Volkov Date: Thu, 9 Jun 2011 00:20:52 +0200 Subject: [PATCH 067/206] Translation update done using Pootle. --- po/ru.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/ru.po b/po/ru.po index cd46558a3b..731633c2b3 100644 --- a/po/ru.po +++ b/po/ru.po @@ -2232,10 +2232,9 @@ msgid "Left" msgstr "Налево" #: libraries/config.values.php:47 -#, fuzzy #| msgid "Height" msgid "Right" -msgstr "Высота" +msgstr "Направо" #: libraries/config.values.php:75 msgid "Open" From d3e72447bb548fcf1598e22ace786b7970452421 Mon Sep 17 00:00:00 2001 From: Victor Volkov Date: Thu, 9 Jun 2011 00:22:17 +0200 Subject: [PATCH 068/206] Translation update done using Pootle. --- po/ru.po | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/po/ru.po b/po/ru.po index 731633c2b3..5cb73ab6bf 100644 --- a/po/ru.po +++ b/po/ru.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 00:20+0200\n" +"PO-Revision-Date: 2011-06-09 00:22+0200\n" "Last-Translator: Victor Volkov \n" "Language-Team: russian \n" "Language: ru\n" @@ -2603,6 +2603,8 @@ msgid "" "Disable the table maintenance mass operations, like optimizing or repairing " "the selected tables of a database." msgstr "" +"Отключить массовые операции обслуживания, такие как оптимизация или " +"восстановление выбранных таблиц базы данных." #: libraries/config/messages.inc.php:61 #, fuzzy From 6a6840f98424df97c866279df34601f224d60c1d Mon Sep 17 00:00:00 2001 From: Victor Volkov Date: Thu, 9 Jun 2011 00:23:04 +0200 Subject: [PATCH 069/206] Translation update done using Pootle. --- po/ru.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/ru.po b/po/ru.po index 5cb73ab6bf..6b646ea926 100644 --- a/po/ru.po +++ b/po/ru.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 00:22+0200\n" +"PO-Revision-Date: 2011-06-09 00:23+0200\n" "Last-Translator: Victor Volkov \n" "Language-Team: russian \n" "Language: ru\n" @@ -2607,10 +2607,9 @@ msgstr "" "восстановление выбранных таблиц базы данных." #: libraries/config/messages.inc.php:61 -#, fuzzy #| msgid "Table maintenance" msgid "Disable multi table maintenance" -msgstr "Обслуживание таблицы" +msgstr "Отключить операции обслуживания таблиц" #: libraries/config/messages.inc.php:62 msgid "Edit SQL queries in popup window" From dead14ef30487d3d5c669c594747857b4b9b8113 Mon Sep 17 00:00:00 2001 From: Victor Volkov Date: Thu, 9 Jun 2011 00:24:54 +0200 Subject: [PATCH 070/206] Translation update done using Pootle. --- po/ru.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/ru.po b/po/ru.po index 6b646ea926..aa77380973 100644 --- a/po/ru.po +++ b/po/ru.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 00:23+0200\n" +"PO-Revision-Date: 2011-06-09 00:24+0200\n" "Last-Translator: Victor Volkov \n" "Language-Team: russian \n" "Language: ru\n" @@ -3545,7 +3545,7 @@ msgstr "Это ссылки Редактировать, Редактироват #: libraries/config/messages.inc.php:320 msgid "Where to show the table row links" -msgstr "" +msgstr "Где вывести ссылки строки таблицы" #: libraries/config/messages.inc.php:321 msgid "Use natural order for sorting table and database names" From 7a1ccb81416831f3e6d524ffc53eaeb8abe6398a Mon Sep 17 00:00:00 2001 From: Victor Volkov Date: Thu, 9 Jun 2011 00:25:18 +0200 Subject: [PATCH 071/206] Translation update done using Pootle. --- po/ru.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/ru.po b/po/ru.po index aa77380973..a474517e7e 100644 --- a/po/ru.po +++ b/po/ru.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 00:24+0200\n" +"PO-Revision-Date: 2011-06-09 00:25+0200\n" "Last-Translator: Victor Volkov \n" "Language-Team: russian \n" "Language: ru\n" @@ -8072,10 +8072,9 @@ msgid "wildcard" msgstr "Групповой символ" #: server_privileges.php:2295 -#, fuzzy #| msgid "View %s has been dropped" msgid "User has been added." -msgstr "Представление %s было удалено" +msgstr "Пользователь был добавлен." #: server_processlist.php:29 #, php-format From f4fa0d9f797d36ccf648f32dcf4738b09e1ec457 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Thu, 9 Jun 2011 00:53:32 +0200 Subject: [PATCH 072/206] - Dynamic chart with for the server status chart - Table chart replaced with a Highcharts generated chart that also behaves somewhat more intellegently --- js/server_status.js | 8 +- js/sql.js | 10 +- js/tbl_chart.js | 185 ++++++++++++++++++++++++ sql.php | 11 +- tbl_chart.php | 153 +++++++------------- themes/pmahomme/css/theme_right.css.php | 30 +++- 6 files changed, 285 insertions(+), 112 deletions(-) create mode 100644 js/tbl_chart.js diff --git a/js/server_status.js b/js/server_status.js index b996846717..c70da12a39 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -52,6 +52,9 @@ $(function() { // Defines what the tabs are currently displaying (realtime or data) var tabStatus = new Object(); + // Holds the current chart instances for each tab + var tabChart = new Object(); + // Add tabs $('#serverStatusTabs').tabs({ // Tab persistence @@ -177,9 +180,9 @@ $(function() { tab.find('.tabInnerContent') .hide() - .after('
    '); + .after('
    '); tabStatus[tab.attr('id')]='realtime'; - PMA_createChart(settings); + tabChart[tab.attr('id')]=PMA_createChart(settings); $(this).html(PMA_messages['strStaticData']); tab.find('.statuslinks a:nth-child(1)').hide(); } else { @@ -188,6 +191,7 @@ $(function() { tab.find('.tabInnerContent').show(); tab.find('div#'+tab.attr('id')+'_chart_cnt').remove(); tabStatus[tab.attr('id')]='data'; + tabChart[tab.attr('id')].destroy(); $(this).html(PMA_messages['strRealtimeChart']); tab.find('.statuslinks a:nth-child(1)').show(); } diff --git a/js/sql.js b/js/sql.js index f58a172db2..0b129394b3 100644 --- a/js/sql.js +++ b/js/sql.js @@ -1164,11 +1164,12 @@ $(document).ready(function() { if($('#profilingchart').length==0) return; var cdata = new Array(); - var i=1; $.each(jQuery.parseJSON($('#profilingchart').html()),function(key,value) { cdata.push([key,parseFloat(value)]); - i++; }); + + // Prevent the user from seeing the JSON code + $('div#profilingchart').html('').show(); PMA_createChart({ chart: { @@ -1193,11 +1194,12 @@ $(document).ready(function() { } } } - }, + }, tooltip: { formatter: function() { return ''+ this.point.name +'
    '+this.y+'s
    ('+Highcharts.numberFormat(this.percentage, 2) +' %)'; } } }); -}); +}); + /**#@- */ diff --git a/js/tbl_chart.js b/js/tbl_chart.js new file mode 100644 index 0000000000..16c42c3113 --- /dev/null +++ b/js/tbl_chart.js @@ -0,0 +1,185 @@ +var chart_xaxis_idx = 0; + + +$(document).ready(function() { + var currentChart=null; + var chart_data = jQuery.parseJSON($('#querychart').html()); + + chart_xaxis_idx = $('select[name="chartXAxis"]').attr('value'); + + $('#resizer').resizable({ + minHeight:240, + minWidth:300, + // On resize, set the chart size to that of the + // resizer minus padding. If your chart has a lot of data or other + // content, the redrawing might be slow. In that case, we recommend + // that you use the 'stop' event instead of 'resize'. + resize: function() { + currentChart.setSize( + this.offsetWidth - 20, + this.offsetHeight - 20, + false + ); + } + }); + + var currentSettings = { + chart: { + type:'line', + width:$('#resizer').width()-20, + height:$('#resizer').height()-20 + }, + xAxis: { + title: { text: $('input[name="xaxis_label"]').attr('value') } + }, + yAxis: { + title: { text: $('input[name="yaxis_label"]').attr('value') } + }, + title: { text: $('input[name="chartTitle"]').attr('value'), margin:20 } + } + + $('#querychart').html(''); + + $('input[name="chartType"]').click(function() { + currentSettings.chart.type=$(this).attr('value'); + + drawChart(); + + if($(this).attr('value')=='bar' || $(this).attr('value')=='column') + $('span.barStacked').show(); + else + $('span.barStacked').hide(); + }); + + $('input[name="barStacked"]').click(function() { + if(this.checked) + $.extend(true,currentSettings,{ plotOptions: { series: { stacking:'normal' } } }); + else + $.extend(true,currentSettings,{ plotOptions: { series: { stacking:null } } }); + drawChart(); + }); + + $('input[name="chartTitle"]').keyup(function() { + var title=$(this).attr('value'); + if(title.length==0) title=' '; + currentChart.setTitle({text: title}); + }); + + $('select[name="chartXAxis"]').change(function() { + chart_xaxis_idx = $('select[name="chartXAxis"]').attr('value'); + drawChart(); + }); + + /* Sucks, we cannot just set axis labels, we have to redraw the chart completely */ + $('input[name="xaxis_label"]').keyup(function() { + currentSettings.xAxis.title.text = $(this).attr('value'); + drawChart(); + }); + $('input[name="yaxis_label"]').keyup(function() { + currentSettings.yAxis.title.text = $(this).attr('value'); + drawChart(); + }); + + function drawChart() { + currentSettings.chart.width=$('#resizer').width()-20; + currentSettings.chart.height=$('#resizer').height()-20; + + if(currentChart!=null) currentChart.destroy(); + currentChart = PMA_queryChart(chart_data,currentSettings); + } + + drawChart(); +}); + +function PMA_queryChart(data,passedSettings) { + if($('#querychart').length==0) return; + + var columnNames = Array(); + + var series = new Array(); + var xaxis = new Object(); + var yaxis = new Object(); + + $.each(data[0],function(index,element) { + columnNames.push(index); + }); + + switch(passedSettings.chart.type) { + case 'column': + case 'spline': + case 'line': + case 'bar': + xaxis.categories = new Array(); + //xaxis.title = { text: columnNames[chart_xaxis_idx] }; + var j=0; + for(var i=0; i'+ this.point.name +'
    '+ Highcharts.numberFormat(this.percentage, 2) +' %'; + } + } + } + }, + credits: { + enabled:false + }, + exporting: { + enabled: true + }, + tooltip: { + formatter: function() { return ''+this.series.name+'
    '+this.y; } + } + }; + + + + if(passedSettings.chart.type=='pie') + settings.tooltip.formatter = function() { return ''+columnNames[0]+'
    '+this.y; } + + // Overwrite/Merge default settings with passedsettings + $.extend(true,settings,passedSettings); + + return new Highcharts.Chart(settings); +} diff --git a/sql.php b/sql.php index 1d7933c6b1..9725f1fb80 100644 --- a/sql.php +++ b/sql.php @@ -897,6 +897,13 @@ else { } if (isset($profiling_results)) { + // pma_token/url_query needed for chart export +?> + +' . __('Profiling') . '' . "\n"; echo '
    '; echo '' . "\n"; @@ -916,13 +923,13 @@ else { echo '
    ' . "\n"; echo '
    '; //require_once './libraries/chart.lib.php'; - echo '
    '; + echo ''; echo '' . "\n"; } - + // Displays the results in a table if (empty($disp_mode)) { // see the "PMA_setDisplayMode()" function in diff --git a/tbl_chart.php b/tbl_chart.php index f4b8bd3adb..c47b0f788d 100644 --- a/tbl_chart.php +++ b/tbl_chart.php @@ -19,7 +19,16 @@ if (! defined('PMA_NO_VARIABLES_IMPORT')) { */ require_once './libraries/common.inc.php'; -$GLOBALS['js_include'][] = 'pMap.js'; +$GLOBALS['js_include'][] = 'tbl_chart.js'; + +$GLOBALS['js_include'][] = 'highcharts/highcharts.js'; +/* Files required for chart exporting */ +$GLOBALS['js_include'][] = 'highcharts/exporting.js'; +$GLOBALS['js_include'][] = 'canvg/canvg.js'; +$GLOBALS['js_include'][] = 'canvg/rgbcolor.js'; + + + /** * Runs common work @@ -72,113 +81,57 @@ $url_params['reload'] = 1; /** * Displays the page */ +// pma_token/url_query needed for chart export ?> +
    - -
    - +
    + + + + + + +
    + + +
    +
    +
    + +
    +

     

    +
    +
    +
    + +
    +
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - - -
    - - - - -
    - > - > - > - - > - -
    - > - > -
    - > - -
    -

    - -

    -
    -

    - FAQ 6.29'); ?> -

    -
    - -
    -
    -
    diff --git a/themes/pmahomme/css/theme_right.css.php b/themes/pmahomme/css/theme_right.css.php index e5835e9d08..aa10a8fdbb 100644 --- a/themes/pmahomme/css/theme_right.css.php +++ b/themes/pmahomme/css/theme_right.css.php @@ -284,13 +284,15 @@ table{border-collapse:collapse;} th{border-right:1px solid #fff; text-align:left;} -img, -input, -select, -button { +img, button { vertical-align: middle; } +input[type="checkbox"],input[type="radio"] { + vertical-align: -11%; +} + + select{ -moz-border-radius:2px; -webkit-border-radius:2px; @@ -1239,6 +1241,26 @@ div#querywindowcontainer fieldset { } /* END querywindow */ +/* profiling */ + +div#profilingchart { + width:550px; + height:370px; + float:left; +} + +/* END profiling */ + +/* table charting */ + +#resizer { + border: 1px solid silver; +} +#inner-resizer { /* make room for the resize handle */ + padding: 10px; +} + +/* END table charting */ /* querybox */ From 217338f21196c20f7245cb7242cb30a635112ce6 Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:12:21 +0200 Subject: [PATCH 073/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index af570579c7..0cf7d31dd7 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-08 08:42+0200\n" +"PO-Revision-Date: 2011-06-09 09:12+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -3076,7 +3076,7 @@ msgstr "" #: libraries/config/messages.inc.php:224 msgid "Tabs" -msgstr "Табулатори" +msgstr "Подпрозорци" #: libraries/config/messages.inc.php:225 msgid "Choose how you want tabs to work" From cfb14e50c457b89de23f3db92afe40f71958b1d4 Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:14:35 +0200 Subject: [PATCH 074/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index 0cf7d31dd7..e50637c854 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:12+0200\n" +"PO-Revision-Date: 2011-06-09 09:14+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -2844,7 +2844,7 @@ msgstr "Настройки за разработчици на phpMyAdmin" #: libraries/config/messages.inc.php:162 msgid "Edit mode" -msgstr "" +msgstr "Редактиране" #: libraries/config/messages.inc.php:163 msgid "Customize edit mode" From 1a5a82e468e0421e7e3e10c96e6da15137265e7d Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:15:59 +0200 Subject: [PATCH 075/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index e50637c854..2795aaa5b2 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:14+0200\n" +"PO-Revision-Date: 2011-06-09 09:15+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -2848,7 +2848,7 @@ msgstr "Редактиране" #: libraries/config/messages.inc.php:163 msgid "Customize edit mode" -msgstr "" +msgstr "Персонализиране на редактирането" #: libraries/config/messages.inc.php:165 msgid "Export defaults" From fb021f98c3ca16307700820cd259deccdcc8419e Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:16:26 +0200 Subject: [PATCH 076/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index 2795aaa5b2..c18dab6f4a 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:15+0200\n" +"PO-Revision-Date: 2011-06-09 09:16+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -2813,7 +2813,7 @@ msgstr "" #: libraries/config/messages.inc.php:154 msgid "Browse mode" -msgstr "" +msgstr "Преглеждане" #: libraries/config/messages.inc.php:155 msgid "Customize browse mode" From 914783e085bd8fcf545eb8c26b25a10e3fcaf52c Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:16:42 +0200 Subject: [PATCH 077/206] Translation update done using Pootle. --- po/bg.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/bg.po b/po/bg.po index c18dab6f4a..e6b1502c02 100644 --- a/po/bg.po +++ b/po/bg.po @@ -2817,7 +2817,7 @@ msgstr "Преглеждане" #: libraries/config/messages.inc.php:155 msgid "Customize browse mode" -msgstr "" +msgstr "Персонализиране на преглеждането" #: libraries/config/messages.inc.php:157 libraries/config/messages.inc.php:159 #: libraries/config/messages.inc.php:176 libraries/config/messages.inc.php:187 From c7c3def3c971036cc06341dc46384a2ce97efeff Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:17:11 +0200 Subject: [PATCH 078/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index e6b1502c02..8dc28f06f1 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:16+0200\n" +"PO-Revision-Date: 2011-06-09 09:17+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -3040,7 +3040,7 @@ msgstr "" #: libraries/config/messages.inc.php:213 libraries/config/messages.inc.php:218 #: setup/frames/menu.inc.php:17 msgid "SQL queries" -msgstr "SQL заявкаи" +msgstr "SQL заявки" #: libraries/config/messages.inc.php:215 msgid "SQL Query box" From d1bd8677f30161421d18e215c374706654d9306e Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:18:52 +0200 Subject: [PATCH 079/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index 8dc28f06f1..244f945988 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:17+0200\n" +"PO-Revision-Date: 2011-06-09 09:18+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -7172,7 +7172,7 @@ msgstr "Информация" #: server_collations.php:39 msgid "Character Sets and Collations" -msgstr "Набори от знаци и колации" +msgstr "Знакови набори и колации" #: server_databases.php:64 msgid "No databases selected." From b0da5fdcbbee63a3d908b1ab4d59cfe2ec65052d Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:19:35 +0200 Subject: [PATCH 080/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index 244f945988..6be63522d3 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:18+0200\n" +"PO-Revision-Date: 2011-06-09 09:19+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -5717,7 +5717,7 @@ msgstr "Традиционен китайски" #: libraries/mysql_charsets.lib.php:228 libraries/mysql_charsets.lib.php:414 msgid "case-insensitive" -msgstr "нечувствително към регистъра" +msgstr "нечувствителен към регистъра" #: libraries/mysql_charsets.lib.php:231 libraries/mysql_charsets.lib.php:416 msgid "case-sensitive" From e2904e0c2cfdc763530af1545826bbc9be45e5ae Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:20:16 +0200 Subject: [PATCH 081/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index 6be63522d3..d49f346ef3 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:19+0200\n" +"PO-Revision-Date: 2011-06-09 09:20+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -5701,7 +5701,7 @@ msgstr "Знаков набор" #: libraries/mysql_charsets.lib.php:206 libraries/mysql_charsets.lib.php:407 #: tbl_change.php:552 msgid "Binary" -msgstr "Двоично" +msgstr "двоичен" #: libraries/mysql_charsets.lib.php:218 msgid "Bulgarian" From 46b649929f1237753df29e67d9c151e7494d7acc Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:21:11 +0200 Subject: [PATCH 082/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index d49f346ef3..1e48c92e41 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:20+0200\n" +"PO-Revision-Date: 2011-06-09 09:21+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -7074,7 +7074,7 @@ msgstr "Импорт от файл" #: prefs_manage.php:245 msgid "Import from browser's storage" -msgstr "" +msgstr "Импорт от хранилището на браузъра" #: prefs_manage.php:248 msgid "Settings will be imported from your browser's local storage." From 0c817f30037168b89bfb72965f2b3df1aad446e8 Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:22:12 +0200 Subject: [PATCH 083/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index 1e48c92e41..6f1208541b 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:21+0200\n" +"PO-Revision-Date: 2011-06-09 09:22+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -7078,7 +7078,7 @@ msgstr "Импорт от хранилището на браузъра" #: prefs_manage.php:248 msgid "Settings will be imported from your browser's local storage." -msgstr "" +msgstr "Настройки ще бъдат импортирани от локалното хранилище на браузъра." #: prefs_manage.php:254 msgid "You have no saved settings!" From 874535d36b50aa0101a110d0a1003d51ecbad7c8 Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:22:38 +0200 Subject: [PATCH 084/206] Translation update done using Pootle. --- po/bg.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/bg.po b/po/bg.po index 6f1208541b..53454cdc64 100644 --- a/po/bg.po +++ b/po/bg.po @@ -7090,7 +7090,7 @@ msgstr "Тази функционалност не се поддържа от в #: prefs_manage.php:263 msgid "Merge with current configuration" -msgstr "" +msgstr "Сливане с текущите настройки" #: prefs_manage.php:277 #, php-format From 83a895bd11024be936e2c543d693ea5563427fca Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:23:16 +0200 Subject: [PATCH 085/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index 53454cdc64..3b11fe146f 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:22+0200\n" +"PO-Revision-Date: 2011-06-09 09:23+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -7101,7 +7101,7 @@ msgstr "" #: prefs_manage.php:302 msgid "Save to browser's storage" -msgstr "" +msgstr "Запис в хранилището на браузъра" #: prefs_manage.php:306 msgid "Settings will be saved in your browser's local storage." From 9573954addf270fb067b378347130a27920104f2 Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:24:15 +0200 Subject: [PATCH 086/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index 3b11fe146f..50348a4d0e 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:23+0200\n" +"PO-Revision-Date: 2011-06-09 09:24+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -7109,7 +7109,7 @@ msgstr "" #: prefs_manage.php:308 msgid "Existing settings will be overwritten!" -msgstr "" +msgstr "Съществуващи настройки ще бъдат презаписани!" #: prefs_manage.php:323 msgid "You can reset all your settings and restore them to default values." From 05b8974425b7202dc2f93122cf5a759c8adb6d5c Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:24:57 +0200 Subject: [PATCH 087/206] Translation update done using Pootle. --- po/bg.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/bg.po b/po/bg.po index 50348a4d0e..fc8014fa66 100644 --- a/po/bg.po +++ b/po/bg.po @@ -6732,7 +6732,7 @@ msgstr "Web сървър" #: main.php:187 msgid "MySQL client version" -msgstr "Версия на MySQL клиент" +msgstr "MySQL клиент" #: main.php:189 msgid "PHP extension" From 814a352efd28065385255deaa8e0057f5acaf6ab Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:30:21 +0200 Subject: [PATCH 088/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index fc8014fa66..b97f851df6 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:24+0200\n" +"PO-Revision-Date: 2011-06-09 09:30+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -4857,7 +4857,7 @@ msgstr "Връзките не са намерени" #: libraries/engines/bdb.lib.php:20 main.php:211 msgid "Version information" -msgstr "Информация за весията" +msgstr "Весия" #: libraries/engines/innodb.lib.php:22 msgid "Data home directory" From e3949be9f0a80b7ec5d06f34e7b832ef325eab2d Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:33:46 +0200 Subject: [PATCH 089/206] Translation update done using Pootle. --- po/bg.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/bg.po b/po/bg.po index b97f851df6..3891f83e3d 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:30+0200\n" +"PO-Revision-Date: 2011-06-09 09:33+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -1673,7 +1673,7 @@ msgstr "Прегледът не е достъпен." #: libraries/Theme.class.php:383 msgid "take it" -msgstr "" +msgstr "взимам я" #: libraries/Theme_Manager.class.php:109 #, php-format From 8a36b8441b12403b78281b25b6359c688d393152 Mon Sep 17 00:00:00 2001 From: stoyanster Date: Thu, 9 Jun 2011 09:35:25 +0200 Subject: [PATCH 090/206] Translation update done using Pootle. --- po/bg.po | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/po/bg.po b/po/bg.po index 3891f83e3d..ce8b95c011 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 09:33+0200\n" +"PO-Revision-Date: 2011-06-09 09:35+0200\n" "Last-Translator: \n" "Language-Team: bulgarian \n" "Language: bg\n" @@ -1712,6 +1712,8 @@ msgid "" "You probably did not create a configuration file. You might want to use the %" "1$ssetup script%2$s to create one." msgstr "" +"Изглежда не се създали конфигурационен файл. Вероятно ще искате да " +"използвате %1$sскрипта за настройки%2$s, за да го създадете" #: libraries/auth/config.auth.lib.php:115 msgid "" From c928d53ef83438bbd1639a473dfcd4ecaa43101d Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Thu, 9 Jun 2011 12:33:07 +0200 Subject: [PATCH 091/206] Fix that single column results work too --- js/tbl_chart.js | 6 ++---- tbl_chart.php | 9 +++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/js/tbl_chart.js b/js/tbl_chart.js index 16c42c3113..91084fea2c 100644 --- a/js/tbl_chart.js +++ b/js/tbl_chart.js @@ -1,4 +1,4 @@ -var chart_xaxis_idx = 0; +var chart_xaxis_idx = -1; $(document).ready(function() { @@ -119,7 +119,7 @@ function PMA_queryChart(data,passedSettings) { series[j].name = columnNames[i]; $.each(data,function(key,value) { series[j].data.push(parseFloat(value[columnNames[i]])); - if(j==0) + if(j==0 && chart_xaxis_idx!=-1 && !xaxis.categories[value[columnNames[chart_xaxis_idx]]]) xaxis.categories.push(value[columnNames[chart_xaxis_idx]]); }); j++; @@ -172,8 +172,6 @@ function PMA_queryChart(data,passedSettings) { formatter: function() { return ''+this.series.name+'
    '+this.y; } } }; - - if(passedSettings.chart.type=='pie') settings.tooltip.formatter = function() { return ''+columnNames[0]+'
    '+this.y; } diff --git a/tbl_chart.php b/tbl_chart.php index c47b0f788d..49635175cf 100644 --- a/tbl_chart.php +++ b/tbl_chart.php @@ -104,10 +104,12 @@ url_query = '';
    - $key) { if($yaxis==-1 && ($idx==count($data[0])-1 || preg_match("/(date|time)/i",$key))) { echo ''; @@ -119,6 +121,9 @@ url_query = ''; ?> +

    From 21b65e56f4decdce8c634272c59329fe95a47136 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Thu, 9 Jun 2011 15:36:41 +0200 Subject: [PATCH 092/206] A currently rather strange series selection to behave similar to the old charting system --- js/tbl_chart.js | 95 ++++++++++++++++++++++++++++++++++++------------- tbl_chart.php | 21 ++++++++--- 2 files changed, 86 insertions(+), 30 deletions(-) diff --git a/js/tbl_chart.js b/js/tbl_chart.js index 91084fea2c..0148ec79f7 100644 --- a/js/tbl_chart.js +++ b/js/tbl_chart.js @@ -1,10 +1,11 @@ var chart_xaxis_idx = -1; - +var chart_series; +var chart_series_index = -1; $(document).ready(function() { var currentChart=null; var chart_data = jQuery.parseJSON($('#querychart').html()); - + chart_series = 'columns'; chart_xaxis_idx = $('select[name="chartXAxis"]').attr('value'); $('#resizer').resizable({ @@ -35,7 +36,10 @@ $(document).ready(function() { yAxis: { title: { text: $('input[name="yaxis_label"]').attr('value') } }, - title: { text: $('input[name="chartTitle"]').attr('value'), margin:20 } + title: { text: $('input[name="chartTitle"]').attr('value'), margin:20 }, + plotOptions: { + series: {} + } } $('#querychart').html(''); @@ -66,26 +70,34 @@ $(document).ready(function() { }); $('select[name="chartXAxis"]').change(function() { - chart_xaxis_idx = $('select[name="chartXAxis"]').attr('value'); + chart_xaxis_idx = this.value; + drawChart(); + }); + $('select[name="chartSeries"]').change(function() { + chart_series = this.value; + chart_series_index = this.selectedIndex; drawChart(); }); /* Sucks, we cannot just set axis labels, we have to redraw the chart completely */ $('input[name="xaxis_label"]').keyup(function() { currentSettings.xAxis.title.text = $(this).attr('value'); - drawChart(); + drawChart(true); }); $('input[name="yaxis_label"]').keyup(function() { currentSettings.yAxis.title.text = $(this).attr('value'); - drawChart(); + drawChart(true); }); - function drawChart() { + function drawChart(noAnimation) { currentSettings.chart.width=$('#resizer').width()-20; currentSettings.chart.height=$('#resizer').height()-20; if(currentChart!=null) currentChart.destroy(); + + if(noAnimation) currentSettings.plotOptions.series.animation = false; currentChart = PMA_queryChart(chart_data,currentSettings); + if(noAnimation) currentSettings.plotOptions.series.animation = true; } drawChart(); @@ -102,28 +114,58 @@ function PMA_queryChart(data,passedSettings) { $.each(data[0],function(index,element) { columnNames.push(index); - }); - + }); + switch(passedSettings.chart.type) { case 'column': case 'spline': case 'line': case 'bar': xaxis.categories = new Array(); - //xaxis.title = { text: columnNames[chart_xaxis_idx] }; - var j=0; - for(var i=0; i'+this.series.name+'
    '+this.y; } + formatter: function() { + if(this.point.name) return ''+this.series.name+'
    '+this.point.name+'
    '+this.y; + return ''+this.series.name+'
    '+this.y; + } } }; @@ -178,6 +223,6 @@ function PMA_queryChart(data,passedSettings) { // Overwrite/Merge default settings with passedsettings $.extend(true,settings,passedSettings); - + return new Highcharts.Chart(settings); } diff --git a/tbl_chart.php b/tbl_chart.php index 49635175cf..a7aed61248 100644 --- a/tbl_chart.php +++ b/tbl_chart.php @@ -105,8 +105,9 @@ url_query = '';
    1) { - echo __('X-Axis:'); ?> '; } ?> +
    + + - + +

    From 64a16e92023bdf4237280ffc27c6665396eccf0e Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Thu, 9 Jun 2011 15:49:15 +0200 Subject: [PATCH 093/206] undefined variable fix on single column result --- tbl_chart.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tbl_chart.php b/tbl_chart.php index a7aed61248..ef9d353e84 100644 --- a/tbl_chart.php +++ b/tbl_chart.php @@ -105,11 +105,12 @@ url_query = '';
    1) { echo '
    '; echo __('X-Axis:'); ?>
    +

     

    From dc433429e870da823130d63f08e5055e7d4fc1af Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Thu, 9 Jun 2011 16:06:04 +0200 Subject: [PATCH 094/206] Don't add duplicates to xaxis --- js/tbl_chart.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/js/tbl_chart.js b/js/tbl_chart.js index 0148ec79f7..763b34e28e 100644 --- a/js/tbl_chart.js +++ b/js/tbl_chart.js @@ -103,6 +103,12 @@ $(document).ready(function() { drawChart(); }); +function in_array(element,array) { + for(var i=0; i Date: Thu, 9 Jun 2011 17:00:19 +0200 Subject: [PATCH 095/206] Translation update done using Pootle. --- po/sl.po | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/po/sl.po b/po/sl.po index 852b6f91c0..389c6d3074 100644 --- a/po/sl.po +++ b/po/sl.po @@ -4,15 +4,15 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-05 21:27+0200\n" +"PO-Revision-Date: 2011-06-09 17:00+0200\n" "Last-Translator: Domen \n" "Language-Team: slovenian \n" +"Language: sl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: sl\n" -"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" -"%100==4 ? 2 : 3);\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || " +"n%100==4 ? 2 : 3);\n" "X-Generator: Pootle 2.0.5\n" #: browse_foreigners.php:35 browse_foreigners.php:53 @@ -1032,10 +1032,9 @@ msgstr "Gesli se ne ujemata!" #: js/messages.php:54 server_privileges.php:1679 server_privileges.php:1703 #: server_privileges.php:2108 server_privileges.php:2302 -#, fuzzy #| msgid "Any user" msgid "Add user" -msgstr "Kateri koli uporabnik" +msgstr "Dodaj uporabnika" #: js/messages.php:55 msgid "Reloading Privileges" From e0c1c4b458955d8bac3885ee6a803b83c959088c Mon Sep 17 00:00:00 2001 From: Domen Date: Thu, 9 Jun 2011 17:00:25 +0200 Subject: [PATCH 096/206] Translation update done using Pootle. --- po/sl.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/sl.po b/po/sl.po index 389c6d3074..c5d1114505 100644 --- a/po/sl.po +++ b/po/sl.po @@ -1106,10 +1106,9 @@ msgid "Create Table" msgstr "Ustvari tabelo" #: js/messages.php:82 -#, fuzzy #| msgid "Use Tables" msgid "Insert Table" -msgstr "Uporabi tabele" +msgstr "Vstavi tabelo" #: js/messages.php:85 msgid "Searching" From 1959168a2fdff7e5203086e43faf385575813aca Mon Sep 17 00:00:00 2001 From: Domen Date: Thu, 9 Jun 2011 17:00:56 +0200 Subject: [PATCH 097/206] Translation update done using Pootle. --- po/sl.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/sl.po b/po/sl.po index c5d1114505..12c6910be1 100644 --- a/po/sl.po +++ b/po/sl.po @@ -8010,10 +8010,9 @@ msgid "wildcard" msgstr "nadomestni znak" #: server_privileges.php:2295 -#, fuzzy #| msgid "View %s has been dropped" msgid "User has been added." -msgstr "Pogled %s je zavržen" +msgstr "Uporabnik je dodan." #: server_processlist.php:29 #, php-format From ffe2eac57fadd5fe9af6c37b065f0cafae539a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Bellone?= Date: Thu, 9 Jun 2011 17:23:41 +0200 Subject: [PATCH 098/206] Translation update done using Pootle. --- po/es.po | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/po/es.po b/po/es.po index fb8f5de915..adaf1f145b 100644 --- a/po/es.po +++ b/po/es.po @@ -4,13 +4,13 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-03 21:27+0200\n" +"PO-Revision-Date: 2011-06-09 17:23+0200\n" "Last-Translator: Matías Bellone \n" "Language-Team: spanish \n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Pootle 2.0.5\n" @@ -1036,10 +1036,9 @@ msgstr "¡Las contraseñas no coinciden!" #: js/messages.php:54 server_privileges.php:1679 server_privileges.php:1703 #: server_privileges.php:2108 server_privileges.php:2302 -#, fuzzy #| msgid "Any user" msgid "Add user" -msgstr "Cualquier usuario" +msgstr "Agregar usuario" #: js/messages.php:55 msgid "Reloading Privileges" From 7b6e75a68c68a094a4328468dc3179e4a32e0f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Bellone?= Date: Thu, 9 Jun 2011 17:23:53 +0200 Subject: [PATCH 099/206] Translation update done using Pootle. --- po/es.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/es.po b/po/es.po index adaf1f145b..8071b94348 100644 --- a/po/es.po +++ b/po/es.po @@ -1110,10 +1110,9 @@ msgid "Create Table" msgstr "Crear tabla" #: js/messages.php:82 -#, fuzzy #| msgid "Use Tables" msgid "Insert Table" -msgstr "Usar tablas" +msgstr "Insertar tablas" #: js/messages.php:85 msgid "Searching" From af8840daee0308764befaf68a01c9671db94df9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Bellone?= Date: Thu, 9 Jun 2011 17:24:13 +0200 Subject: [PATCH 100/206] Translation update done using Pootle. --- po/es.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/es.po b/po/es.po index 8071b94348..cd41ef787d 100644 --- a/po/es.po +++ b/po/es.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 17:23+0200\n" +"PO-Revision-Date: 2011-06-09 17:24+0200\n" "Last-Translator: Matías Bellone \n" "Language-Team: spanish \n" "Language: es\n" @@ -1809,10 +1809,9 @@ msgstr "" "El nombre de usuario o la contraseña es incorrecto. El acceso fue denegado." #: libraries/auth/signon.auth.lib.php:87 -#, fuzzy #| msgid "Config authentication" msgid "Can not find signon authentication script:" -msgstr "Autenticación por configuración" +msgstr "No se pudo encontrar el script de autenticación «signon»" #: libraries/auth/swekey/swekey.auth.lib.php:118 #, php-format From 4e7105230a489216e55cc8781e27cbbe6ea6d4e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Bellone?= Date: Thu, 9 Jun 2011 17:24:53 +0200 Subject: [PATCH 101/206] Translation update done using Pootle. --- po/es.po | 2 ++ 1 file changed, 2 insertions(+) diff --git a/po/es.po b/po/es.po index cd41ef787d..2d5e6e9911 100644 --- a/po/es.po +++ b/po/es.po @@ -2616,6 +2616,8 @@ msgid "" "Disable the table maintenance mass operations, like optimizing or repairing " "the selected tables of a database." msgstr "" +"Desactivar las operaciones masivas de mantenimiento en tablas como " +"optimización y reparación de las tablas seleccionadas de una base de datos." #: libraries/config/messages.inc.php:61 #, fuzzy From f67b4d8c1f69e2857bb170b56c4f2b9bfc2684d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Bellone?= Date: Thu, 9 Jun 2011 17:25:07 +0200 Subject: [PATCH 102/206] Translation update done using Pootle. --- po/es.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/es.po b/po/es.po index 2d5e6e9911..f4270578d8 100644 --- a/po/es.po +++ b/po/es.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 17:24+0200\n" +"PO-Revision-Date: 2011-06-09 17:25+0200\n" "Last-Translator: Matías Bellone \n" "Language-Team: spanish \n" "Language: es\n" @@ -2620,10 +2620,9 @@ msgstr "" "optimización y reparación de las tablas seleccionadas de una base de datos." #: libraries/config/messages.inc.php:61 -#, fuzzy #| msgid "Table maintenance" msgid "Disable multi table maintenance" -msgstr "Mantenimiento de la tabla" +msgstr "Dsactivar mantenimiento de muchas tabla" #: libraries/config/messages.inc.php:62 msgid "Edit SQL queries in popup window" From 09f480fb2d96e247a1129ddffad5fd13eb236f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Bellone?= Date: Thu, 9 Jun 2011 17:25:28 +0200 Subject: [PATCH 103/206] Translation update done using Pootle. --- po/es.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/es.po b/po/es.po index f4270578d8..2e3d62b149 100644 --- a/po/es.po +++ b/po/es.po @@ -8146,10 +8146,9 @@ msgid "wildcard" msgstr "comodín" #: server_privileges.php:2295 -#, fuzzy #| msgid "View %s has been dropped" msgid "User has been added." -msgstr "Se descartó el modo de visualización %s" +msgstr "Se agregó el usuario." #: server_processlist.php:29 #, php-format From 831da843c1f9d72d59f1fff8452a59188d9409bc Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Thu, 9 Jun 2011 20:08:17 +0200 Subject: [PATCH 104/206] Fixes of some bugs --- js/functions.js | 4 ++-- js/server_status.js | 22 +++++++++++----------- server_status.php | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/js/functions.js b/js/functions.js index 8a80ecde14..46eff423e3 100644 --- a/js/functions.js +++ b/js/functions.js @@ -1425,10 +1425,10 @@ function PMA_createChart(passedSettings) { if(lastValue==null) lastValue = curValue; passedSettings.realtime.callback(thisChart,curValue,lastValue,numLoadedPoints) - + lastValue = curValue; numLoadedPoints++; - chart_activeTimeouts[container] = setTimeout(addnewPoint, passedSettings.realtime.refreshRate || 5000); + chart_activeTimeouts[container] = setTimeout(addnewPoint, thisChart.options.realtime.refreshRate || 5000); }); } diff --git a/js/server_status.js b/js/server_status.js index c70da12a39..d2cbb6c8b6 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -44,17 +44,16 @@ $(function() { var categoryFilter=''; var odd_row=false; var text=''; // Holds filter text + /* Chart configuration */ // Amount of points the chart should hold var numMaxPoints=30; - // Time between each refresh - var refreshRate=5000; // Defines what the tabs are currently displaying (realtime or data) var tabStatus = new Object(); - // Holds the current chart instances for each tab - var tabChart = new Object(); - + // Holds the current chart instances for each tab + var tabChart = new Object(); + // Add tabs $('#serverStatusTabs').tabs({ // Tab persistence @@ -110,14 +109,15 @@ $(function() { // Ajax refresh of variables (always the first link in each tab) $('.statuslinks a:nth-child(1)').click(function() { // ui-tabs-panel class is added by the jquery tabs feature - var tab=$(element).parents('div.ui-tabs-panel'); - + var tab=$(this).parents('div.ui-tabs-panel'); + var that = this; + // Show ajax load icon - $(element).find('img').show(); + $(this).find('img').show(); - $.get($(element).attr('href'),{ajax_request:1},function(data) { + $.get($(this).attr('href'),{ajax_request:1},function(data) { + $(that).find('img').hide(); initTab(tab,data); - $(element).find('img').hide(); }); tabStatus[tab.attr('id')]='data'; @@ -191,7 +191,7 @@ $(function() { tab.find('.tabInnerContent').show(); tab.find('div#'+tab.attr('id')+'_chart_cnt').remove(); tabStatus[tab.attr('id')]='data'; - tabChart[tab.attr('id')].destroy(); + tabChart[tab.attr('id')].destroy(); $(this).html(PMA_messages['strRealtimeChart']); tab.find('.statuslinks a:nth-child(1)').show(); } diff --git a/server_status.php b/server_status.php index 6d215879b8..79ae331f7c 100644 --- a/server_status.php +++ b/server_status.php @@ -1012,7 +1012,7 @@ function printVariablesTable() { } elseif (is_numeric($value) && $value == (int) $value && $value > 1000) { echo PMA_formatNumber($value, 3, 1); } elseif (is_numeric($value) && $value == (int) $value) { - echo PMA_formatNumber($value, 4, 0); + echo PMA_formatNumber($value, 3, 0); } elseif (is_numeric($value)) { echo PMA_formatNumber($value, 3, 1); } else { From 659252cd71eab4e6f7f648c5339e6a5f0910a938 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Thu, 9 Jun 2011 20:08:38 +0200 Subject: [PATCH 105/206] pChart is not needed anymore --- js/pMap.js | 164 - libraries/chart.lib.php | 256 -- libraries/chart/pChart/fonts/DejaVuSans.ttf | Bin 683528 -> 0 bytes libraries/chart/pChart/fonts/LICENSE | 99 - libraries/chart/pChart/fonts/README | 6 - libraries/chart/pChart/pCache.class | 119 - libraries/chart/pChart/pChart.class | 3626 ------------------- libraries/chart/pChart/pData.class | 260 -- libraries/chart/pma_chart.php | 183 - libraries/chart/pma_pchart_chart.php | 402 -- libraries/chart/pma_pchart_multi.php | 117 - libraries/chart/pma_pchart_multi_bar.php | 37 - libraries/chart/pma_pchart_multi_line.php | 38 - libraries/chart/pma_pchart_multi_radar.php | 107 - libraries/chart/pma_pchart_pie.php | 109 - libraries/chart/pma_pchart_single.php | 56 - libraries/chart/pma_pchart_single_bar.php | 34 - libraries/chart/pma_pchart_single_line.php | 34 - libraries/chart/pma_pchart_single_radar.php | 96 - libraries/chart/pma_pchart_stacked_bar.php | 35 - 20 files changed, 5778 deletions(-) delete mode 100644 js/pMap.js delete mode 100644 libraries/chart.lib.php delete mode 100644 libraries/chart/pChart/fonts/DejaVuSans.ttf delete mode 100644 libraries/chart/pChart/fonts/LICENSE delete mode 100644 libraries/chart/pChart/fonts/README delete mode 100644 libraries/chart/pChart/pCache.class delete mode 100644 libraries/chart/pChart/pChart.class delete mode 100644 libraries/chart/pChart/pData.class delete mode 100644 libraries/chart/pma_chart.php delete mode 100644 libraries/chart/pma_pchart_chart.php delete mode 100644 libraries/chart/pma_pchart_multi.php delete mode 100644 libraries/chart/pma_pchart_multi_bar.php delete mode 100644 libraries/chart/pma_pchart_multi_line.php delete mode 100644 libraries/chart/pma_pchart_multi_radar.php delete mode 100644 libraries/chart/pma_pchart_pie.php delete mode 100644 libraries/chart/pma_pchart_single.php delete mode 100644 libraries/chart/pma_pchart_single_bar.php delete mode 100644 libraries/chart/pma_pchart_single_line.php delete mode 100644 libraries/chart/pma_pchart_single_radar.php delete mode 100644 libraries/chart/pma_pchart_stacked_bar.php diff --git a/js/pMap.js b/js/pMap.js deleted file mode 100644 index b63221cdc0..0000000000 --- a/js/pMap.js +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Holds the definition and the creation of the imageMap object - * @author Martynas Mickevicius - * @package phpMyAdmin - */ - -/** - * responsible for showing tooltips above the image chart - */ -var imageMap = { - 'mouseMoved': function(event, cont) { - // return if no imageMap set - // this can happen if server has no json - if (!this.imageMap) { - return; - } - - // get mouse coordinated relative to image - var mouseX = event.pageX - cont.offsetLeft; - var mouseY = event.pageY - cont.offsetTop; - - //console.log("X: " + mouseX + ", Y: " + mouseY); - - /* Check if we are flying over a map zone - * Lets use the following method to check if a given - * point is in any convex polygon. - * http://www.programmingforums.org/post168124-3.html - */ - var found = false; - for (var key = 0; key < this.imageMap.length; key++) - { - var seriesName = this.imageMap[key]['n']; - var seriesValue = this.imageMap[key]['v']; - - var signSum = 0; - for (var i = 0; i < this.imageMap[key]['p'].length; i++) - { - var index1; - var index2; - - if (i == this.imageMap[key]['p'].length - 1) - { - index1 = i; - index2 = 0; - } - else - { - index1 = i; - index2 = i+1; - } - var result = this.getDeterminant( - this.imageMap[key]['p'][index1][0], - this.imageMap[key]['p'][index1][1], - this.imageMap[key]['p'][index2][0], - this.imageMap[key]['p'][index2][1], - mouseX, - mouseY - ); - if (result > 0) { signSum += 1; } else { signSum += -1; } - } - - if (Math.abs(signSum) == this.imageMap[key]['p'].length) - { - found = true; - if (this.currentKey != key) - { - this.tooltip.show(); - this.tooltip.title(seriesName); - this.tooltip.text(seriesValue); - this.currentKey = key; - } - this.tooltip.move(mouseX + 20, mouseY + 20); - } - } - if (!found && this.currentKey != -1 ) - { - this.tooltip.hide(); - this.currentKey = -1; - } - }, - - 'getDeterminant': function (X1, Y1, X2, Y2, X3, Y3) { - return (X2*Y3 - X3*Y2) - (X1*Y3 - X3*Y1) + (X1*Y2 - X2*Y1); - }, - - 'loadImageMap': function(map) { - this.imageMap = JSON.parse(map); - for (key in this.imageMap) - { - // FIXME - // without this loop image map does not work - // on IE8 in the status page - } - }, - - 'init': function() { - this.tooltip.init(); - - $("div#chart").bind('mousemove',function(e) { - imageMap.mouseMoved(e, this); - }); - - this.tooltip.attach("div#chart"); - - this.currentKey = -1; - }, - - 'tooltip': { - 'init': function () { - this.el = $('
    '); - this.el.css('position', 'absolute'); - this.el.css('font-family', 'tahoma'); - this.el.css('background-color', '#373737'); - this.el.css('color', '#BEBEBE'); - this.el.css('padding', '3px'); - - var title = $('

    '); - title.attr('id', 'title'); - title.css('margin', '0px'); - title.css('padding', '3px'); - title.css('background-color', '#606060'); - title.css('text-align', 'center'); - title.html('Title'); - this.el.append(title); - - var text = $('

    '); - text.attr('id', 'text'); - text.css('margin', '0'); - text.html('Text'); - this.el.append(text); - - this.hide(); - }, - - 'attach': function (element) { - $(element).prepend(this.el); - }, - - 'move': function (x, y) { - this.el.css('margin-left', x); - this.el.css('margin-top', y); - }, - - 'hide': function () { - this.el.css('display', 'none'); - }, - - 'show': function () { - this.el.css('display', 'block'); - }, - - 'title': function (title) { - this.el.find("p#title").html(title); - }, - - 'text': function (text) { - this.el.find("p#text").html(text.replace(/;/g, "
    ")); - } - } -}; - -$(document).ready(function() { - imageMap.init(); -}); diff --git a/libraries/chart.lib.php b/libraries/chart.lib.php deleted file mode 100644 index 83791fb425..0000000000 --- a/libraries/chart.lib.php +++ /dev/null @@ -1,256 +0,0 @@ - $dataValue) { - $key = ucwords(str_replace(array('Com_', '_'), array('', ' '), $dataKey)); - $value = (int)$dataValue; - $chartData[$key] = $value; - } - - $chart = new PMA_pChart_Pie( - $chartData, - array('titleText' => __('Query statistics')) - ); - $chartCode = $chart->toString(); - PMA_handle_chart_err($chart->getErrors()); - echo $chartCode; -} - -/** - * Formats a chart for the profiling page. - * @param array $data data for the status chart - * @return string HTML and JS code for the chart - */ -function PMA_chart_profiling($data) -{ - $chartData = array(); - foreach($data as $dataValue) { - $value = (int)($dataValue['Duration'] * 1000000); - $key = ucwords($dataValue['Status']); - $chartData[$key] = $value; - } - - $chart = new PMA_pChart_Pie( - $chartData, - array('titleText' => __('Query execution time comparison (in microseconds)')) - ); - $chartCode = $chart->toString(); - PMA_handle_chart_err($chart->getErrors()); - echo $chartCode; -} - -/** - * Formats a chart for the query results page. - * @param array $data data for the status chart - * @param array $chartSettings settings used to generate the chart - * @return string HTML and JS code for the chart - */ -function PMA_chart_results($data, &$chartSettings) -{ - $chartData = array(); - $chart = null; - - // set default title if not already set - if (empty($chartSettings['titleText'])) { - $chartSettings['titleText'] = __('Query results'); - } - - // set default type if not already set - if (empty($chartSettings['type'])) { - $chartSettings['type'] = 'bar'; - } - - // set default type if not already set - if (empty($chartSettings['continuous'])) { - $chartSettings['continuous'] = 'off'; - } - - // set default bar type if needed - if ($chartSettings['type'] == 'bar' && empty($chartSettings['barType'])) { - $chartSettings['barType'] = 'stacked'; - } - - // default for legend - $chartSettings['legend'] = false; - - // default for muti series - $chartSettings['multi'] = false; - - if (! isset($data[0])) { - // empty data - return __('No data found for the chart.'); - } - - if (count($data[0]) == 1 || count($data[0]) == 2) { - // One or two columns in every row. - // This data is suitable for a simple bar chart. - - if ($chartSettings['type'] == 'pie') { - // loop through the rows, data for pie chart has to be formated - // in a different way then in other charts. - foreach ($data as $rowKey => $row) { - $values = array_values($row); - - if (count($row) == 1) { - $chartData[$rowKey] = $values[0]; - } - else { - $chartData[$values[1]] = $values[0]; - } - } - - $chartSettings['legend'] = true; - $chart = new PMA_pChart_pie($chartData, $chartSettings); - } - else { - // loop through the rows - foreach ($data as $rowKey => $row) { - - // loop through the columns in the row - foreach ($row as $valueKey => $value) { - $chartData[$valueKey][] = $value; - } - - // if only one column, we need to add - // placeholder data for x axis - if (count($row) == 1) { - $chartData[''][] = $rowKey; - } - } - - switch ($chartSettings['type']) { - case 'bar': - default: - $chart = new PMA_pChart_single_bar($chartData, $chartSettings); - break; - case 'line': - $chart = new PMA_pChart_single_line($chartData, $chartSettings); - break; - case 'radar': - $chart = new PMA_pChart_single_radar($chartData, $chartSettings); - break; - } - } - } - else if (count($data[0]) == 3) { - // Three columns (x axis, y axis, series) in every row. - // This data is suitable for a stacked bar chart. - $chartSettings['multi'] = true; - - $keys = array_keys($data[0]); - $yAxisKey = $keys[0]; - $xAxisKey = $keys[1]; - $seriesKey = $keys[2]; - - // get all the series labels - $seriesLabels = array(); - foreach ($data as $row) { - $seriesLabels[] = $row[$seriesKey]; - } - $seriesLabels = array_unique($seriesLabels); - - // loop through the rows - $currentXLabel = $data[0][$xAxisKey]; - foreach ($data as $row) { - - // save the label - // use the same value as the key and the value to get rid of duplicate results - $chartData[$xAxisKey][$row[$xAxisKey]] = $row[$xAxisKey]; - - // make sure to set value to every serie - $currentSeriesLabel = (string)$row[$seriesKey]; - foreach ($seriesLabels as $seriesLabelsValue) { - if ($currentSeriesLabel == $seriesLabelsValue) { - // the value os for this serie - $chartData[$yAxisKey][$seriesLabelsValue][$row[$xAxisKey]] = (int)$row[$yAxisKey]; - } - else if (! isset($chartData[$yAxisKey][$seriesLabelsValue][$row[$xAxisKey]])) { - // if the value for this serie is not set, set it to 0 - $chartData[$yAxisKey][$seriesLabelsValue][$row[$xAxisKey]] = 0; - } - } - } - - $chartSettings['legend'] = true; - - // determine the chart type - switch ($chartSettings['type']) { - case 'bar': - default: - - // determine the bar chart type - switch ($chartSettings['barType']) { - case 'stacked': - default: - $chart = new PMA_pChart_stacked_bar($chartData, $chartSettings); - break; - case 'multi': - $chart = new PMA_pChart_multi_bar($chartData, $chartSettings); - break; - } - break; - - case 'line': - $chart = new PMA_pChart_multi_line($chartData, $chartSettings); - break; - case 'radar': - $chart = new PMA_pChart_multi_radar($chartData, $chartSettings); - break; - } - } - else { - // unknown data format - return ''; - } - - $chartCode = $chart->toString(); - $chartSettings = $chart->getSettings(); - $chartErrors = $chart->getErrors(); - PMA_handle_chart_err($chartErrors); - - return $chartCode; -} - -/** - * Simple handler of chart errors. - * @param array $errors all occured errors - */ -function PMA_handle_chart_err($errors) -{ - if (in_array(ERR_NO_GD, $errors)) { - PMA_warnMissingExtension('GD', false, __('GD extension is needed for charts.')); - } - else if (in_array(ERR_NO_JSON, $errors)) { - PMA_warnMissingExtension('JSON', false, __('JSON encoder is needed for chart tooltips.')); - } -} - -?> diff --git a/libraries/chart/pChart/fonts/DejaVuSans.ttf b/libraries/chart/pChart/fonts/DejaVuSans.ttf deleted file mode 100644 index a99969e1b2db618ae9611559809c9216fa4e303a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 683528 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 ~u)_bK}Pg4}4??MlNhO;bvdi*^ledba7{ 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

    t^u_5RHBh!i1(o`7<dOrQH5;as%Dc? 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

    dt+%8+82Xh+<7?Ar2r^hMNkz4)aXqMA(1Iro1 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%0Ah(=#pI`jt+7G6r-1Od^=i5-6H#Onusd|Hx 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. - - Class initialisation : - pCache($CacheFolder="Cache/") - Cache management : - IsInCache($Data) - GetFromCache($ID,$Data) - WriteToCache($ID,$Data,$Picture) - DeleteFromCache($ID,$Data) - ClearCache() - Inner functions : - GetHash($ID,$Data) - */ - - /* pCache class definition */ - class pCache - { - var $HashKey = ""; - var $CacheFolder = "Cache/"; - - /* Create the pCache object */ - function pCache($CacheFolder="Cache/") - { - $this->CacheFolder = $CacheFolder; - } - - /* This function is clearing the cache folder */ - function ClearCache() - { - if ($handle = opendir($this->CacheFolder)) - { - while (false !== ($file = readdir($handle))) - { - if ( $file != "." && $file != ".." ) - unlink($this->CacheFolder.$file); - } - closedir($handle); - } - } - - /* This function is checking if we have an offline version of this chart */ - function IsInCache($ID,$Data,$Hash="") - { - if ( $Hash == "" ) - $Hash = $this->GetHash($ID,$Data); - - if ( file_exists($this->CacheFolder.$Hash) ) - return(TRUE); - else - return(FALSE); - } - - /* This function is making a copy of drawn chart in the cache folder */ - function WriteToCache($ID,$Data,$Picture) - { - $Hash = $this->GetHash($ID,$Data); - $FileName = $this->CacheFolder.$Hash; - - imagepng($Picture->Picture,$FileName); - } - - /* This function is removing any cached copy of this chart */ - function DeleteFromCache($ID,$Data) - { - $Hash = $this->GetHash($ID,$Data); - $FileName = $this->CacheFolder.$Hash; - - if ( file_exists($FileName ) ) - unlink($FileName); - } - - /* This function is retrieving the cached picture if applicable */ - function GetFromCache($ID,$Data) - { - $Hash = $this->GetHash($ID,$Data); - if ( $this->IsInCache("","",$Hash ) ) - { - $FileName = $this->CacheFolder.$Hash; - - header('Content-type: image/png'); - @readfile($FileName); - exit(); - } - } - - /* This function is building the graph unique hash key */ - function GetHash($ID,$Data) - { - $mKey = "$ID"; - foreach($Data as $key => $Values) - { - $tKey = ""; - foreach($Values as $Serie => $Value) - $tKey = $tKey.$Serie.$Value; - $mKey = $mKey.md5($tKey); - } - return(md5($mKey)); - } - } -?> \ No newline at end of file diff --git a/libraries/chart/pChart/pChart.class b/libraries/chart/pChart/pChart.class deleted file mode 100644 index 2b5a077213..0000000000 --- a/libraries/chart/pChart/pChart.class +++ /dev/null @@ -1,3626 +0,0 @@ -. - - Class initialisation : - pChart($XSize,$YSize) - Draw methods : - drawBackground($R,$G,$B) - drawRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B) - drawFilledRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B,$DrawBorder=TRUE,$Alpha=100) - drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B) - drawFilledRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B) - drawCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0) - drawFilledCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0) - drawEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B) - drawFilledEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B) - drawLine($X1,$Y1,$X2,$Y2,$R,$G,$B,$GraphFunction=FALSE) - drawDottedLine($X1,$Y1,$X2,$Y2,$DotSize,$R,$G,$B) - drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B) - drawFromPNG($FileName,$X,$Y,$Alpha=100) - drawFromGIF($FileName,$X,$Y,$Alpha=100) - drawFromJPG($FileName,$X,$Y,$Alpha=100) - Graph setup methods : - addBorder($Width=3,$R=0,$G=0,$B=0) - clearScale() - clearShadow() - createColorGradientPalette($R1,$G1,$B1,$R2,$G2,$B2,$Shades) - drawGraphArea($R,$G,$B,$Stripe=FALSE) - drawScale($Data,$DataDescription,$ScaleMode,$R,$G,$B,$DrawTicks=TRUE,$Angle=0,$Decimals=1,$WithMargin=FALSE,$SkipLabels=1,$RightScale=FALSE) - drawRightScale($Data,$DataDescription,$ScaleMode,$R,$G,$B,$DrawTicks=TRUE,$Angle=0,$Decimals=1,$WithMargin=FALSE,$SkipLabels=1) - drawXYScale($Data,$DataDescription,$YSerieName,$XSerieName,$R,$G,$B,$WithMargin=0,$Angle=0,$Decimals=1) - drawGrid($LineWidth,$Mosaic=TRUE,$R=220,$G=220,$B=220,$Alpha=100) - drawLegend($XPos,$YPos,$DataDescription,$R,$G,$B,$Rs=-1,$Gs=-1,$Bs=-1,$Rt=0,$Gt=0,$Bt=0,$Border=FALSE) - drawPieLegend($XPos,$YPos,$Data,$DataDescription,$R,$G,$B) - drawTitle($XPos,$YPos,$Value,$R,$G,$B,$XPos2=-1,$YPos2=-1,$Shadow=FALSE) - drawTreshold($Value,$R,$G,$B,$ShowLabel=FALSE,$ShowOnRight=FALSE,$TickWidth=4,$FreeText=NULL) - drawArea($Data,$Serie1,$Serie2,$R,$G,$B,$Alpha = 50) - drawRadarAxis($Data,$DataDescription,$Mosaic=TRUE,$BorderOffset=10,$A_R=60,$A_G=60,$A_B=60,$S_R=200,$S_G=200,$S_B=200,$MaxValue=-1) - drawGraphAreaGradient($R,$G,$B,$Decay,$Target=TARGET_GRAPHAREA) - drawTextBox($X1,$Y1,$X2,$Y2,$Text,$Angle=0,$R=255,$G=255,$B=255,$Align=ALIGN_LEFT,$Shadow=TRUE,$BgR=-1,$BgG=-1,$BgB=-1,$Alpha=100) - getLegendBoxSize($DataDescription) - loadColorPalette($FileName,$Delimiter=",") - reportWarnings($Interface="CLI") - setGraphArea($X1,$Y1,$X2,$Y2) - setLabel($Data,$DataDescription,$SerieName,$ValueName,$Caption,$R=210,$G=210,$B=210) - setColorPalette($ID,$R,$G,$B) - setCurrency($Currency) - setDateFormat($Format) - setFontProperties($FontName,$FontSize) - setLineStyle($Width=1,$DotSize=0) - setFixedScale($VMin,$VMax,$Divisions=5,$VXMin=0,$VXMin=0,$XDivisions=5) - setShadowProperties($XDistance=1,$YDistance=1,$R=60,$G=60,$B=60,$Alpha) - writeValues($Data,$DataDescription,$Series) - Graphs methods : - drawPlotGraph($Data,$DataDescription,$BigRadius=5,$SmallRadius=2,$R2=-1,$G2=-1,$B2=-1,$Shadow=FALSE) - drawXYPlotGraph($Data,$DataDescription,$YSerieName,$XSerieName,$PaletteID=0,$BigRadius=5,$SmallRadius=2,$R2=-1,$G2=-1,$B2=-1) - drawLineGraph($Data,$DataDescription,$SerieName="") - drawXYGraph($Data,$DataDescription,$YSerieName,$XSerieName,$PaletteID=0) - drawFilledLineGraph($Data,$DataDescription,$Alpha=100,$AroundZero=FALSE) - drawCubicCurve($Data,$DataDescription,$Accuracy=.1,$SerieName="") - drawFilledCubicCurve($Data,$DataDescription,$Accuracy=.1,$Alpha=100,$AroundZero=FALSE) - drawOverlayBarGraph($Data,$DataDescription,$Alpha=50) - drawBarGraph($Data,$DataDescription,$Shadow=FALSE) - drawStackedBarGraph($Data,$DataDescription,$Alpha=50,$Contiguous=FALSE) - drawLimitsGraph($Data,$DataDescription,$R=0,$G=0,$B=0) - drawRadar($Data,$DataDescription,$BorderOffset=10,$MaxValue=-1) - drawFilledRadar($Data,$DataDescription,$Alpha=50,$BorderOffset=10,$MaxValue=-1) - drawBasicPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$R=255,$G=255,$B=255,$Decimals=0) - drawFlatPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$SpliceDistance=0,$Decimals = 0) - drawFlatPieGraphWithShadow($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$SpliceDistance=0,$Decimals = 0) - drawPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$EnhanceColors=TRUE,$Skew=60,$SpliceHeight=20,$SpliceDistance=0,$Decimals=0) - Other methods : - setImageMap($Mode=TRUE,$GraphID="MyGraph") - getImageMap() - getSavedImageMap($MapName,$Flush=TRUE) - Render($FileName) - Stroke() - */ - - /* Declare some script wide constants */ - define("SCALE_NORMAL",1); - define("SCALE_ADDALL",2); - define("SCALE_START0",3); - define("SCALE_ADDALLSTART0",4); - define("PIE_PERCENTAGE", 1); - define("PIE_LABELS",2); - define("PIE_NOLABEL",3); - define("PIE_PERCENTAGE_LABEL", 4); - define("TARGET_GRAPHAREA",1); - define("TARGET_BACKGROUND",2); - define("ALIGN_TOP_LEFT",1); - define("ALIGN_TOP_CENTER",2); - define("ALIGN_TOP_RIGHT",3); - define("ALIGN_LEFT",4); - define("ALIGN_CENTER",5); - define("ALIGN_RIGHT",6); - define("ALIGN_BOTTOM_LEFT",7); - define("ALIGN_BOTTOM_CENTER",8); - define("ALIGN_BOTTOM_RIGHT",9); - - /* pChart class definition */ - class pChart - { - /* Palettes definition */ - var $Palette = array("0"=>array("R"=>188,"G"=>224,"B"=>46), - "1"=>array("R"=>224,"G"=>100,"B"=>46), - "2"=>array("R"=>224,"G"=>214,"B"=>46), - "3"=>array("R"=>46,"G"=>151,"B"=>224), - "4"=>array("R"=>176,"G"=>46,"B"=>224), - "5"=>array("R"=>224,"G"=>46,"B"=>117), - "6"=>array("R"=>92,"G"=>224,"B"=>46), - "7"=>array("R"=>224,"G"=>176,"B"=>46)); - - /* Some static vars used in the class */ - var $XSize = NULL; - var $YSize = NULL; - var $Picture = NULL; - var $ImageMap = NULL; - - /* Error management */ - var $ErrorReporting = FALSE; - var $ErrorInterface = "CLI"; - var $Errors = NULL; - var $ErrorFontName = "Fonts/pf_arma_five.ttf"; - var $ErrorFontSize = 6; - - /* vars related to the graphing area */ - var $GArea_X1 = NULL; - var $GArea_Y1 = NULL; - var $GArea_X2 = NULL; - var $GArea_Y2 = NULL; - var $GAreaXOffset = NULL; - var $VMax = NULL; - var $VMin = NULL; - var $VXMax = NULL; - var $VXMin = NULL; - var $Divisions = NULL; - var $XDivisions = NULL; - var $DivisionHeight = NULL; - var $XDivisionHeight = NULL; - var $DivisionCount = NULL; - var $XDivisionCount = NULL; - var $DivisionRatio = NULL; - var $XDivisionRatio = NULL; - var $DivisionWidth = NULL; - var $DataCount = NULL; - var $Currency = "\$"; - - /* Text format related vars */ - var $FontName = NULL; - var $FontSize = NULL; - var $DateFormat = "d/m/Y"; - - /* Lines format related vars */ - var $LineWidth = 1; - var $LineDotSize = 0; - - /* Layer related vars */ - var $Layers = NULL; - - /* Set antialias quality : 0 is maximum, 100 minimum*/ - var $AntialiasQuality = 0; - - /* Shadow settings */ - var $ShadowActive = FALSE; - var $ShadowXDistance = 1; - var $ShadowYDistance = 1; - var $ShadowRColor = 60; - var $ShadowGColor = 60; - var $ShadowBColor = 60; - var $ShadowAlpha = 50; - var $ShadowBlur = 0; - - /* Image Map settings */ - var $BuildMap = FALSE; - var $MapFunction = NULL; - var $tmpFolder = "tmp/"; - var $MapID = NULL; - - /* This function create the background picture */ - function pChart($XSize,$YSize) - { - $this->XSize = $XSize; - $this->YSize = $YSize; - $this->Picture = imagecreatetruecolor($XSize,$YSize); - $C_White =$this->AllocateColor($this->Picture,255,255,255); - imagefilledrectangle($this->Picture,0,0,$XSize,$YSize,$C_White); - imagecolortransparent($this->Picture,$C_White); - $this->setFontProperties("tahoma.ttf",8); - } - - /* Set if warnings should be reported */ - function reportWarnings($Interface="CLI") - { - $this->ErrorReporting = TRUE; - $this->ErrorInterface = $Interface; - } - - /* Set the font properties */ - function setFontProperties($FontName,$FontSize) - { - $this->FontName = $FontName; - $this->FontSize = $FontSize; - } - - /* Set the shadow properties */ - function setShadowProperties($XDistance=1,$YDistance=1,$R=60,$G=60,$B=60,$Alpha=50,$Blur=0) - { - $this->ShadowActive = TRUE; - $this->ShadowXDistance = $XDistance; - $this->ShadowYDistance = $YDistance; - $this->ShadowRColor = $R; - $this->ShadowGColor = $G; - $this->ShadowBColor = $B; - $this->ShadowAlpha = $Alpha; - $this->ShadowBlur = $Blur; - } - - /* Remove shadow option */ - function clearShadow() - { - $this->ShadowActive = FALSE; - } - - /* Set Palette color */ - function setColorPalette($ID,$R,$G,$B) - { - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $this->Palette[$ID]["R"] = $R; - $this->Palette[$ID]["G"] = $G; - $this->Palette[$ID]["B"] = $B; - } - - /* Create a color palette shading from one color to another */ - function createColorGradientPalette($R1,$G1,$B1,$R2,$G2,$B2,$Shades) - { - $RFactor = ($R2-$R1)/$Shades; - $GFactor = ($G2-$G1)/$Shades; - $BFactor = ($B2-$B1)/$Shades; - - for($i=0;$i<=$Shades-1;$i++) - { - $this->Palette[$i]["R"] = $R1+$RFactor*$i; - $this->Palette[$i]["G"] = $G1+$GFactor*$i; - $this->Palette[$i]["B"] = $B1+$BFactor*$i; - } - } - - /* Load Color Palette from file */ - function loadColorPalette($FileName,$Delimiter=",") - { - $handle = @fopen($FileName,"r"); - $ColorID = 0; - if ($handle) - { - while (!feof($handle)) - { - $buffer = fgets($handle, 4096); - $buffer = str_replace(chr(10),"",$buffer); - $buffer = str_replace(chr(13),"",$buffer); - $Values = split($Delimiter,$buffer); - if ( count($Values) == 3 ) - { - $this->Palette[$ColorID]["R"] = $Values[0]; - $this->Palette[$ColorID]["G"] = $Values[1]; - $this->Palette[$ColorID]["B"] = $Values[2]; - $ColorID++; - } - } - } - } - - /* Set line style */ - function setLineStyle($Width=1,$DotSize=0) - { - $this->LineWidth = $Width; - $this->LineDotSize = $DotSize; - } - - /* Set currency symbol */ - function setCurrency($Currency) - { - $this->Currency = $Currency; - } - - /* Set the graph area location */ - function setGraphArea($X1,$Y1,$X2,$Y2) - { - $this->GArea_X1 = $X1; - $this->GArea_Y1 = $Y1; - $this->GArea_X2 = $X2; - $this->GArea_Y2 = $Y2; - } - - /* Prepare the graph area */ - function drawGraphArea($R,$G,$B,$Stripe=FALSE) - { - $this->drawFilledRectangle($this->GArea_X1,$this->GArea_Y1,$this->GArea_X2,$this->GArea_Y2,$R,$G,$B,FALSE); - $this->drawRectangle($this->GArea_X1,$this->GArea_Y1,$this->GArea_X2,$this->GArea_Y2,$R-40,$G-40,$B-40); - - if ( $Stripe ) - { - $R2 = $R-15; if ( $R2 < 0 ) { $R2 = 0; } - $G2 = $R-15; if ( $G2 < 0 ) { $G2 = 0; } - $B2 = $R-15; if ( $B2 < 0 ) { $B2 = 0; } - - $LineColor =$this->AllocateColor($this->Picture,$R2,$G2,$B2); - $SkewWidth = $this->GArea_Y2-$this->GArea_Y1-1; - - for($i=$this->GArea_X1-$SkewWidth;$i<=$this->GArea_X2;$i=$i+4) - { - $X1 = $i; $Y1 = $this->GArea_Y2; - $X2 = $i+$SkewWidth; $Y2 = $this->GArea_Y1; - - - if ( $X1 < $this->GArea_X1 ) - { $X1 = $this->GArea_X1; $Y1 = $this->GArea_Y1 + $X2 - $this->GArea_X1 + 1; } - - if ( $X2 >= $this->GArea_X2 ) - { $Y2 = $this->GArea_Y1 + $X2 - $this->GArea_X2 +1; $X2 = $this->GArea_X2 - 1; } -// * Fixed in 1.27 * { $X2 = $this->GArea_X2 - 1; $Y2 = $this->GArea_Y2 - ($this->GArea_X2 - $X1); } - - imageline($this->Picture,$X1,$Y1,$X2,$Y2+1,$LineColor); - } - } - } - - /* Allow you to clear the scale : used if drawing multiple charts */ - function clearScale() - { - $this->VMin = NULL; - $this->VMax = NULL; - $this->VXMin = NULL; - $this->VXMax = NULL; - $this->Divisions = NULL; - $this->XDivisions = NULL; } - - /* Allow you to fix the scale, use this to bypass the automatic scaling */ - function setFixedScale($VMin,$VMax,$Divisions=5,$VXMin=0,$VXMax=0,$XDivisions=5) - { - $this->VMin = $VMin; - $this->VMax = $VMax; - $this->Divisions = $Divisions; - - if ( !$VXMin == 0 ) - { - $this->VXMin = $VXMin; - $this->VXMax = $VXMax; - $this->XDivisions = $XDivisions; - } - } - - /* Wrapper to the drawScale() function allowing a second scale to be drawn */ - function drawRightScale($Data,$DataDescription,$ScaleMode,$R,$G,$B,$DrawTicks=TRUE,$Angle=0,$Decimals=1,$WithMargin=FALSE,$SkipLabels=1) - { - $this->drawScale($Data,$DataDescription,$ScaleMode,$R,$G,$B,$DrawTicks,$Angle,$Decimals,$WithMargin,$SkipLabels,TRUE); - } - - /* Compute and draw the scale */ - function drawScale($Data,$DataDescription,$ScaleMode,$R,$G,$B,$DrawTicks=TRUE,$Angle=0,$Decimals=1,$WithMargin=FALSE,$SkipLabels=1,$RightScale=FALSE) - { - /* Validate the Data and DataDescription array */ - $this->validateData("drawScale",$Data); - - $C_TextColor =$this->AllocateColor($this->Picture,$R,$G,$B); - - $this->drawLine($this->GArea_X1,$this->GArea_Y1,$this->GArea_X1,$this->GArea_Y2,$R,$G,$B); - $this->drawLine($this->GArea_X1,$this->GArea_Y2,$this->GArea_X2,$this->GArea_Y2,$R,$G,$B); - - if ( $this->VMin == NULL && $this->VMax == NULL) - { - if (isset($DataDescription["Values"][0])) - { - $this->VMin = $Data[0][$DataDescription["Values"][0]]; - $this->VMax = $Data[0][$DataDescription["Values"][0]]; - } - else { $this->VMin = 2147483647; $this->VMax = -2147483647; } - - /* Compute Min and Max values */ - if ( $ScaleMode == SCALE_NORMAL || $ScaleMode == SCALE_START0 ) - { - if ( $ScaleMode == SCALE_START0 ) { $this->VMin = 0; } - - foreach ( $Data as $Key => $Values ) - { - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - if (isset($Data[$Key][$ColName])) - { - $Value = $Data[$Key][$ColName]; - - if ( is_numeric($Value) ) - { - if ( $this->VMax < $Value) { $this->VMax = $Value; } - if ( $this->VMin > $Value) { $this->VMin = $Value; } - } - } - } - } - } - elseif ( $ScaleMode == SCALE_ADDALL || $ScaleMode == SCALE_ADDALLSTART0 ) /* Experimental */ - { - if ( $ScaleMode == SCALE_ADDALLSTART0 ) { $this->VMin = 0; } - - foreach ( $Data as $Key => $Values ) - { - $Sum = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - if (isset($Data[$Key][$ColName])) - { - $Value = $Data[$Key][$ColName]; - if ( is_numeric($Value) ) - $Sum += $Value; - } - } - if ( $this->VMax < $Sum) { $this->VMax = $Sum; } - if ( $this->VMin > $Sum) { $this->VMin = $Sum; } - } - } - - if ( $this->VMax > preg_replace('/\.[0-9]+/','',$this->VMax) ) - $this->VMax = preg_replace('/\.[0-9]+/','',$this->VMax)+1; - - /* If all values are the same */ - if ( $this->VMax == $this->VMin ) - { - if ( $this->VMax >= 0 ) { $this->VMax++; } - else { $this->VMin--; } - } - - $DataRange = $this->VMax - $this->VMin; - if ( $DataRange == 0 ) { $DataRange = .1; } - - /* Compute automatic scaling */ - $ScaleOk = FALSE; $Factor = 1; - $MinDivHeight = 25; $MaxDivs = ($this->GArea_Y2 - $this->GArea_Y1) / $MinDivHeight; - - if ( $this->VMin == 0 && $this->VMax == 0 ) - { $this->VMin = 0; $this->VMax = 2; $Scale = 1; $Divisions = 2;} - elseif ($MaxDivs > 1) - { - while(!$ScaleOk) - { - $Scale1 = ( $this->VMax - $this->VMin ) / $Factor; - $Scale2 = ( $this->VMax - $this->VMin ) / $Factor / 2; - $Scale4 = ( $this->VMax - $this->VMin ) / $Factor / 4; - - if ( $Scale1 > 1 && $Scale1 <= $MaxDivs && !$ScaleOk) { $ScaleOk = TRUE; $Divisions = floor($Scale1); $Scale = 1;} - if ( $Scale2 > 1 && $Scale2 <= $MaxDivs && !$ScaleOk) { $ScaleOk = TRUE; $Divisions = floor($Scale2); $Scale = 2;} - if (!$ScaleOk) - { - if ( $Scale2 > 1 ) { $Factor = $Factor * 10; } - if ( $Scale2 < 1 ) { $Factor = $Factor / 10; } - } - } - - if ( floor($this->VMax / $Scale / $Factor) != $this->VMax / $Scale / $Factor) - { - $GridID = floor ( $this->VMax / $Scale / $Factor) + 1; - $this->VMax = $GridID * $Scale * $Factor; - $Divisions++; - } - - if ( floor($this->VMin / $Scale / $Factor) != $this->VMin / $Scale / $Factor) - { - $GridID = floor( $this->VMin / $Scale / $Factor); - $this->VMin = $GridID * $Scale * $Factor; - $Divisions++; - } - } - else /* Can occurs for small graphs */ - $Scale = 1; - - if ( !isset($Divisions) ) - $Divisions = 2; - - if ($Scale == 1 && $Divisions%2 == 1) - $Divisions--; - } - else - $Divisions = $this->Divisions; - - $this->DivisionCount = $Divisions; - - $DataRange = $this->VMax - $this->VMin; - if ( $DataRange == 0 ) { $DataRange = .1; } - - $this->DivisionHeight = ( $this->GArea_Y2 - $this->GArea_Y1 ) / $Divisions; - $this->DivisionRatio = ( $this->GArea_Y2 - $this->GArea_Y1 ) / $DataRange; - - $this->GAreaXOffset = 0; - if ( count($Data) > 1 ) - { - if ( $WithMargin == FALSE ) - $this->DivisionWidth = ( $this->GArea_X2 - $this->GArea_X1 ) / (count($Data)-1); - else - { - $this->DivisionWidth = ( $this->GArea_X2 - $this->GArea_X1 ) / (count($Data)); - $this->GAreaXOffset = $this->DivisionWidth / 2; - } - } - else - { - $this->DivisionWidth = $this->GArea_X2 - $this->GArea_X1; - $this->GAreaXOffset = $this->DivisionWidth / 2; - } - - $this->DataCount = count($Data); - - if ( $DrawTicks == FALSE ) - return(0); - - $YPos = $this->GArea_Y2; $XMin = NULL; - for($i=1;$i<=$Divisions+1;$i++) - { - if ( $RightScale ) - $this->drawLine($this->GArea_X2,$YPos,$this->GArea_X2+5,$YPos,$R,$G,$B); - else - $this->drawLine($this->GArea_X1,$YPos,$this->GArea_X1-5,$YPos,$R,$G,$B); - - $Value = $this->VMin + ($i-1) * (( $this->VMax - $this->VMin ) / $Divisions); - $Value = round($Value * pow(10,$Decimals)) / pow(10,$Decimals); - if ( $DataDescription["Format"]["Y"] == "number" ) - $Value = $Value.$DataDescription["Unit"]["Y"]; - if ( $DataDescription["Format"]["Y"] == "time" ) - $Value = $this->ToTime($Value); - if ( $DataDescription["Format"]["Y"] == "date" ) - $Value = $this->ToDate($Value); - if ( $DataDescription["Format"]["Y"] == "metric" ) - $Value = $this->ToMetric($Value); - if ( $DataDescription["Format"]["Y"] == "currency" ) - $Value = $this->ToCurrency($Value); - - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); - $TextWidth = $Position[2]-$Position[0]; - - if ( $RightScale ) - { - imagettftext($this->Picture,$this->FontSize,0,$this->GArea_X2+10,$YPos+($this->FontSize/2),$C_TextColor,$this->FontName,$Value); - if ( $XMin < $this->GArea_X2+15+$TextWidth || $XMin == NULL ) { $XMin = $this->GArea_X2+15+$TextWidth; } - } - else - { - imagettftext($this->Picture,$this->FontSize,0,$this->GArea_X1-10-$TextWidth,$YPos+($this->FontSize/2),$C_TextColor,$this->FontName,$Value); - if ( $XMin > $this->GArea_X1-10-$TextWidth || $XMin == NULL ) { $XMin = $this->GArea_X1-10-$TextWidth; } - } - - $YPos = $YPos - $this->DivisionHeight; - } - - /* Write the Y Axis caption if set */ - if ( isset($DataDescription["Axis"]["Y"]) ) - { - $Position = imageftbbox($this->FontSize,90,$this->FontName,$DataDescription["Axis"]["Y"]); - $TextHeight = abs($Position[1])+abs($Position[3]); - $TextTop = (($this->GArea_Y2 - $this->GArea_Y1) / 2) + $this->GArea_Y1 + ($TextHeight/2); - - if ( $RightScale ) - imagettftext($this->Picture,$this->FontSize,90,$XMin+$this->FontSize,$TextTop,$C_TextColor,$this->FontName,$DataDescription["Axis"]["Y"]); - else - imagettftext($this->Picture,$this->FontSize,90,$XMin-$this->FontSize,$TextTop,$C_TextColor,$this->FontName,$DataDescription["Axis"]["Y"]); - } - - /* Horizontal Axis */ - $XPos = $this->GArea_X1 + $this->GAreaXOffset; - $ID = 1; $YMax = NULL; - foreach ( $Data as $Key => $Values ) - { - if ( $ID % $SkipLabels == 0 ) - { - $this->drawLine(floor($XPos),$this->GArea_Y2,floor($XPos),$this->GArea_Y2+5,$R,$G,$B); - $Value = $Data[$Key][$DataDescription["Position"]]; - if ( $DataDescription["Format"]["X"] == "number" ) - $Value = $Value.$DataDescription["Unit"]["X"]; - if ( $DataDescription["Format"]["X"] == "time" ) - $Value = $this->ToTime($Value); - if ( $DataDescription["Format"]["X"] == "date" ) - $Value = $this->ToDate($Value); - if ( $DataDescription["Format"]["X"] == "metric" ) - $Value = $this->ToMetric($Value); - if ( $DataDescription["Format"]["X"] == "currency" ) - $Value = $this->ToCurrency($Value); - - $Position = imageftbbox($this->FontSize,$Angle,$this->FontName,$Value); - $TextWidth = abs($Position[2])+abs($Position[0]); - $TextHeight = abs($Position[1])+abs($Position[3]); - - if ( $Angle == 0 ) - { - $YPos = $this->GArea_Y2+18; - imagettftext($this->Picture,$this->FontSize,$Angle,floor($XPos)-floor($TextWidth/2),$YPos,$C_TextColor,$this->FontName,$Value); - } - else - { - $YPos = $this->GArea_Y2+10+$TextHeight; - if ( $Angle <= 90 ) - imagettftext($this->Picture,$this->FontSize,$Angle,floor($XPos)-$TextWidth+5,$YPos,$C_TextColor,$this->FontName,$Value); - else - imagettftext($this->Picture,$this->FontSize,$Angle,floor($XPos)+$TextWidth+5,$YPos,$C_TextColor,$this->FontName,$Value); - } - if ( $YMax < $YPos || $YMax == NULL ) { $YMax = $YPos; } - } - - $XPos = $XPos + $this->DivisionWidth; - $ID++; - } - - /* Write the X Axis caption if set */ - if ( isset($DataDescription["Axis"]["X"]) ) - { - $Position = imageftbbox($this->FontSize,90,$this->FontName,$DataDescription["Axis"]["X"]); - $TextWidth = abs($Position[2])+abs($Position[0]); - $TextLeft = (($this->GArea_X2 - $this->GArea_X1) / 2) + $this->GArea_X1 + ($TextWidth/2); - imagettftext($this->Picture,$this->FontSize,0,$TextLeft,$YMax+$this->FontSize+5,$C_TextColor,$this->FontName,$DataDescription["Axis"]["X"]); - } - } - - /* Compute and draw the scale for X/Y charts */ - function drawXYScale($Data,$DataDescription,$YSerieName,$XSerieName,$R,$G,$B,$WithMargin=0,$Angle=0,$Decimals=1) - { - /* Validate the Data and DataDescription array */ - $this->validateData("drawScale",$Data); - - $C_TextColor =$this->AllocateColor($this->Picture,$R,$G,$B); - - $this->drawLine($this->GArea_X1,$this->GArea_Y1,$this->GArea_X1,$this->GArea_Y2,$R,$G,$B); - $this->drawLine($this->GArea_X1,$this->GArea_Y2,$this->GArea_X2,$this->GArea_Y2,$R,$G,$B); - - /* Process Y scale */ - if ( $this->VMin == NULL && $this->VMax == NULL) - { - $this->VMin = $Data[0][$YSerieName]; - $this->VMax = $Data[0][$YSerieName]; - - foreach ( $Data as $Key => $Values ) - { - if (isset($Data[$Key][$YSerieName])) - { - $Value = $Data[$Key][$YSerieName]; - if ( $this->VMax < $Value) { $this->VMax = $Value; } - if ( $this->VMin > $Value) { $this->VMin = $Value; } - } - } - - if ( $this->VMax > preg_replace('/\.[0-9]+/','',$this->VMax) ) - $this->VMax = preg_replace('/\.[0-9]+/','',$this->VMax)+1; - - $DataRange = $this->VMax - $this->VMin; - if ( $DataRange == 0 ) { $DataRange = .1; } - - /* Compute automatic scaling */ - $ScaleOk = FALSE; $Factor = 1; - $MinDivHeight = 25; $MaxDivs = ($this->GArea_Y2 - $this->GArea_Y1) / $MinDivHeight; - - if ( $this->VMin == 0 && $this->VMax == 0 ) - { $this->VMin = 0; $this->VMax = 2; $Scale = 1; $Divisions = 2;} - elseif ($MaxDivs > 1) - { - while(!$ScaleOk) - { - $Scale1 = ( $this->VMax - $this->VMin ) / $Factor; - $Scale2 = ( $this->VMax - $this->VMin ) / $Factor / 2; - $Scale4 = ( $this->VMax - $this->VMin ) / $Factor / 4; - - if ( $Scale1 > 1 && $Scale1 <= $MaxDivs && !$ScaleOk) { $ScaleOk = TRUE; $Divisions = floor($Scale1); $Scale = 1;} - if ( $Scale2 > 1 && $Scale2 <= $MaxDivs && !$ScaleOk) { $ScaleOk = TRUE; $Divisions = floor($Scale2); $Scale = 2;} - if (!$ScaleOk) - { - if ( $Scale2 > 1 ) { $Factor = $Factor * 10; } - if ( $Scale2 < 1 ) { $Factor = $Factor / 10; } - } - } - - if ( floor($this->VMax / $Scale / $Factor) != $this->VMax / $Scale / $Factor) - { - $GridID = floor ( $this->VMax / $Scale / $Factor) + 1; - $this->VMax = $GridID * $Scale * $Factor; - $Divisions++; - } - - if ( floor($this->VMin / $Scale / $Factor) != $this->VMin / $Scale / $Factor) - { - $GridID = floor( $this->VMin / $Scale / $Factor); - $this->VMin = $GridID * $Scale * $Factor; - $Divisions++; - } - } - else /* Can occurs for small graphs */ - $Scale = 1; - - if ( !isset($Divisions) ) - $Divisions = 2; - - if ( $this->isRealInt(($this->VMax-$this->VMin)/($Divisions-1))) - $Divisions--; - elseif ( $this->isRealInt(($this->VMax-$this->VMin)/($Divisions+1))) - $Divisions++; - } - else - $Divisions = $this->Divisions; - - $this->DivisionCount = $Divisions; - - $DataRange = $this->VMax - $this->VMin; - if ( $DataRange == 0 ) { $DataRange = .1; } - - $this->DivisionHeight = ( $this->GArea_Y2 - $this->GArea_Y1 ) / $Divisions; - $this->DivisionRatio = ( $this->GArea_Y2 - $this->GArea_Y1 ) / $DataRange; - - $YPos = $this->GArea_Y2; $XMin = NULL; - for($i=1;$i<=$Divisions+1;$i++) - { - $this->drawLine($this->GArea_X1,$YPos,$this->GArea_X1-5,$YPos,$R,$G,$B); - $Value = $this->VMin + ($i-1) * (( $this->VMax - $this->VMin ) / $Divisions); - $Value = round($Value * pow(10,$Decimals)) / pow(10,$Decimals); - if ( $DataDescription["Format"]["Y"] == "number" ) - $Value = $Value.$DataDescription["Unit"]["Y"]; - if ( $DataDescription["Format"]["Y"] == "time" ) - $Value = $this->ToTime($Value); - if ( $DataDescription["Format"]["Y"] == "date" ) - $Value = $this->ToDate($Value); - if ( $DataDescription["Format"]["Y"] == "metric" ) - $Value = $this->ToMetric($Value); - if ( $DataDescription["Format"]["Y"] == "currency" ) - $Value = $this->ToCurrency($Value); - - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); - $TextWidth = $Position[2]-$Position[0]; - imagettftext($this->Picture,$this->FontSize,0,$this->GArea_X1-10-$TextWidth,$YPos+($this->FontSize/2),$C_TextColor,$this->FontName,$Value); - - if ( $XMin > $this->GArea_X1-10-$TextWidth || $XMin == NULL ) { $XMin = $this->GArea_X1-10-$TextWidth; } - - $YPos = $YPos - $this->DivisionHeight; - } - - /* Process X scale */ - if ( $this->VXMin == NULL && $this->VXMax == NULL) - { - $this->VXMin = $Data[0][$XSerieName]; - $this->VXMax = $Data[0][$XSerieName]; - - foreach ( $Data as $Key => $Values ) - { - if (isset($Data[$Key][$XSerieName])) - { - $Value = $Data[$Key][$XSerieName]; - if ( $this->VXMax < $Value) { $this->VXMax = $Value; } - if ( $this->VXMin > $Value) { $this->VXMin = $Value; } - } - } - - if ( $this->VXMax > preg_replace('/\.[0-9]+/','',$this->VXMax) ) - $this->VXMax = preg_replace('/\.[0-9]+/','',$this->VXMax)+1; - - $DataRange = $this->VMax - $this->VMin; - if ( $DataRange == 0 ) { $DataRange = .1; } - - /* Compute automatic scaling */ - $ScaleOk = FALSE; $Factor = 1; - $MinDivWidth = 25; $MaxDivs = ($this->GArea_X2 - $this->GArea_X1) / $MinDivWidth; - - if ( $this->VXMin == 0 && $this->VXMax == 0 ) - { $this->VXMin = 0; $this->VXMax = 2; $Scale = 1; $XDivisions = 2;} - elseif ($MaxDivs > 1) - { - while(!$ScaleOk) - { - $Scale1 = ( $this->VXMax - $this->VXMin ) / $Factor; - $Scale2 = ( $this->VXMax - $this->VXMin ) / $Factor / 2; - $Scale4 = ( $this->VXMax - $this->VXMin ) / $Factor / 4; - - if ( $Scale1 > 1 && $Scale1 <= $MaxDivs && !$ScaleOk) { $ScaleOk = TRUE; $XDivisions = floor($Scale1); $Scale = 1;} - if ( $Scale2 > 1 && $Scale2 <= $MaxDivs && !$ScaleOk) { $ScaleOk = TRUE; $XDivisions = floor($Scale2); $Scale = 2;} - if (!$ScaleOk) - { - if ( $Scale2 > 1 ) { $Factor = $Factor * 10; } - if ( $Scale2 < 1 ) { $Factor = $Factor / 10; } - } - } - - if ( floor($this->VXMax / $Scale / $Factor) != $this->VXMax / $Scale / $Factor) - { - $GridID = floor ( $this->VXMax / $Scale / $Factor) + 1; - $this->VXMax = $GridID * $Scale * $Factor; - $XDivisions++; - } - - if ( floor($this->VXMin / $Scale / $Factor) != $this->VXMin / $Scale / $Factor) - { - $GridID = floor( $this->VXMin / $Scale / $Factor); - $this->VXMin = $GridID * $Scale * $Factor; - $XDivisions++; - } - } - else /* Can occurs for small graphs */ - $Scale = 1; - - if ( !isset($XDivisions) ) - $XDivisions = 2; - - if ( $this->isRealInt(($this->VXMax-$this->VXMin)/($XDivisions-1))) - $XDivisions--; - elseif ( $this->isRealInt(($this->VXMax-$this->VXMin)/($XDivisions+1))) - $XDivisions++; - } - else - $XDivisions = $this->XDivisions; - - $this->XDivisionCount = $Divisions; - $this->DataCount = $Divisions + 2; - - $XDataRange = $this->VXMax - $this->VXMin; - if ( $XDataRange == 0 ) { $XDataRange = .1; } - - $this->DivisionWidth = ( $this->GArea_X2 - $this->GArea_X1 ) / $XDivisions; - $this->XDivisionRatio = ( $this->GArea_X2 - $this->GArea_X1 ) / $XDataRange; - - $XPos = $this->GArea_X1; $YMax = NULL; - for($i=1;$i<=$XDivisions+1;$i++) - { - $this->drawLine($XPos,$this->GArea_Y2,$XPos,$this->GArea_Y2+5,$R,$G,$B); - - $Value = $this->VXMin + ($i-1) * (( $this->VXMax - $this->VXMin ) / $XDivisions); - $Value = round($Value * pow(10,$Decimals)) / pow(10,$Decimals); - if ( $DataDescription["Format"]["Y"] == "number" ) - $Value = $Value.$DataDescription["Unit"]["Y"]; - if ( $DataDescription["Format"]["Y"] == "time" ) - $Value = $this->ToTime($Value); - if ( $DataDescription["Format"]["Y"] == "date" ) - $Value = $this->ToDate($Value); - if ( $DataDescription["Format"]["Y"] == "metric" ) - $Value = $this->ToMetric($Value); - if ( $DataDescription["Format"]["Y"] == "currency" ) - $Value = $this->ToCurrency($Value); - - $Position = imageftbbox($this->FontSize,$Angle,$this->FontName,$Value); - $TextWidth = abs($Position[2])+abs($Position[0]); - $TextHeight = abs($Position[1])+abs($Position[3]); - - if ( $Angle == 0 ) - { - $YPos = $this->GArea_Y2+18; - imagettftext($this->Picture,$this->FontSize,$Angle,floor($XPos)-floor($TextWidth/2),$YPos,$C_TextColor,$this->FontName,$Value); - } - else - { - $YPos = $this->GArea_Y2+10+$TextHeight; - if ( $Angle <= 90 ) - imagettftext($this->Picture,$this->FontSize,$Angle,floor($XPos)-$TextWidth+5,$YPos,$C_TextColor,$this->FontName,$Value); - else - imagettftext($this->Picture,$this->FontSize,$Angle,floor($XPos)+$TextWidth+5,$YPos,$C_TextColor,$this->FontName,$Value); - } - - if ( $YMax < $YPos || $YMax == NULL ) { $YMax = $YPos; } - - $XPos = $XPos + $this->DivisionWidth; - } - - /* Write the Y Axis caption if set */ - if ( isset($DataDescription["Axis"]["Y"]) ) - { - $Position = imageftbbox($this->FontSize,90,$this->FontName,$DataDescription["Axis"]["Y"]); - $TextHeight = abs($Position[1])+abs($Position[3]); - $TextTop = (($this->GArea_Y2 - $this->GArea_Y1) / 2) + $this->GArea_Y1 + ($TextHeight/2); - imagettftext($this->Picture,$this->FontSize,90,$XMin-$this->FontSize,$TextTop,$C_TextColor,$this->FontName,$DataDescription["Axis"]["Y"]); - } - - /* Write the X Axis caption if set */ - if ( isset($DataDescription["Axis"]["X"]) ) - { - $Position = imageftbbox($this->FontSize,90,$this->FontName,$DataDescription["Axis"]["X"]); - $TextWidth = abs($Position[2])+abs($Position[0]); - $TextLeft = (($this->GArea_X2 - $this->GArea_X1) / 2) + $this->GArea_X1 + ($TextWidth/2); - imagettftext($this->Picture,$this->FontSize,0,$TextLeft,$YMax+$this->FontSize+5,$C_TextColor,$this->FontName,$DataDescription["Axis"]["X"]); - } - } - - /* Compute and draw the scale */ - function drawGrid($LineWidth,$Mosaic=TRUE,$R=220,$G=220,$B=220,$Alpha=100) - { - /* Draw mosaic */ - if ( $Mosaic ) - { - $LayerWidth = $this->GArea_X2-$this->GArea_X1; - $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; - - $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); - $C_White =$this->AllocateColor($this->Layers[0],255,255,255); - imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); - imagecolortransparent($this->Layers[0],$C_White); - - $C_Rectangle =$this->AllocateColor($this->Layers[0],250,250,250); - - $YPos = $LayerHeight; //$this->GArea_Y2-1; - $LastY = $YPos; - for($i=0;$i<=$this->DivisionCount;$i++) - { - $LastY = $YPos; - $YPos = $YPos - $this->DivisionHeight; - - if ( $YPos <= 0 ) { $YPos = 1; } - - if ( $i % 2 == 0 ) - { - imagefilledrectangle($this->Layers[0],1,$YPos,$LayerWidth-1,$LastY,$C_Rectangle); - } - } - imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); - imagedestroy($this->Layers[0]); - } - - /* Horizontal lines */ - $YPos = $this->GArea_Y2 - $this->DivisionHeight; - for($i=1;$i<=$this->DivisionCount;$i++) - { - if ( $YPos > $this->GArea_Y1 && $YPos < $this->GArea_Y2 ) - $this->drawDottedLine($this->GArea_X1,$YPos,$this->GArea_X2,$YPos,$LineWidth,$R,$G,$B); - - $YPos = $YPos - $this->DivisionHeight; - } - - /* Vertical lines */ - if ( $this->GAreaXOffset == 0 ) - { $XPos = $this->GArea_X1 + $this->DivisionWidth + $this->GAreaXOffset; $ColCount = $this->DataCount-2; } - else - { $XPos = $this->GArea_X1 + $this->GAreaXOffset; $ColCount = floor( ($this->GArea_X2 - $this->GArea_X1) / $this->DivisionWidth ); } - - for($i=1;$i<=$ColCount;$i++) - { - if ( $XPos > $this->GArea_X1 && $XPos < $this->GArea_X2 ) - $this->drawDottedLine(floor($XPos),$this->GArea_Y1,floor($XPos),$this->GArea_Y2,$LineWidth,$R,$G,$B); - $XPos = $XPos + $this->DivisionWidth; - } - } - - /* retrieve the legends size */ - function getLegendBoxSize($DataDescription) - { - if ( !isset($DataDescription["Description"]) ) - return(-1); - - /* <-10->[8]<-4->Text<-10-> */ - $MaxWidth = 0; $MaxHeight = 8; - foreach($DataDescription["Description"] as $Key => $Value) - { - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); - $TextWidth = $Position[2]-$Position[0]; - $TextHeight = $Position[1]-$Position[7]; - if ( $TextWidth > $MaxWidth) { $MaxWidth = $TextWidth; } - $MaxHeight = $MaxHeight + $TextHeight + 4; - } - $MaxHeight = $MaxHeight - 3; - $MaxWidth = $MaxWidth + 32; - - return(array($MaxWidth,$MaxHeight)); - } - - function getPieLegendBoxSize($Data) - { - $MaxWidth = 0; $MaxHeight = 8; - foreach($Data as $Value) - { - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value['Keys']); - $TextWidth = $Position[2]-$Position[0]; - $TextHeight = $Position[1]-$Position[7]; - if ( $TextWidth > $MaxWidth) { $MaxWidth = $TextWidth; } - $MaxHeight = $MaxHeight + $TextHeight + 4; - } - $MaxHeight = $MaxHeight - 3; - $MaxWidth = $MaxWidth + 32; - - return(array($MaxWidth,$MaxHeight)); - } - - /* Draw the data legends */ - function drawLegend($XPos,$YPos,$DataDescription,$R,$G,$B,$Rs=-1,$Gs=-1,$Bs=-1,$Rt=0,$Gt=0,$Bt=0,$Border=TRUE) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawLegend",$DataDescription); - - if ( !isset($DataDescription["Description"]) ) - return(-1); - - $C_TextColor =$this->AllocateColor($this->Picture,$Rt,$Gt,$Bt); - - /* <-10->[8]<-4->Text<-10-> */ - $MaxWidth = 0; $MaxHeight = 8; - foreach($DataDescription["Description"] as $Key => $Value) - { - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); - $TextWidth = $Position[2]-$Position[0]; - $TextHeight = $Position[1]-$Position[7]; - if ( $TextWidth > $MaxWidth) { $MaxWidth = $TextWidth; } - $MaxHeight = $MaxHeight + $TextHeight + 4; - } - $MaxHeight = $MaxHeight - 5; - $MaxWidth = $MaxWidth + 32; - - if ( $Rs == -1 || $Gs == -1 || $Bs == -1 ) - { $Rs = $R-30; $Gs = $G-30; $Bs = $B-30; } - - if ( $Border ) - { - $this->drawFilledRoundedRectangle($XPos+1,$YPos+1,$XPos+$MaxWidth+1,$YPos+$MaxHeight+1,5,$Rs,$Gs,$Bs); - $this->drawFilledRoundedRectangle($XPos,$YPos,$XPos+$MaxWidth,$YPos+$MaxHeight,5,$R,$G,$B); - } - - $YOffset = 4 + $this->FontSize; $ID = 0; - foreach($DataDescription["Description"] as $Key => $Value) - { - $this->drawFilledRoundedRectangle($XPos+10,$YPos+$YOffset-4,$XPos+14,$YPos+$YOffset-4,2,$this->Palette[$ID]["R"],$this->Palette[$ID]["G"],$this->Palette[$ID]["B"]); - imagettftext($this->Picture,$this->FontSize,0,$XPos+22,$YPos+$YOffset,$C_TextColor,$this->FontName,$Value); - - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); - $TextHeight = $Position[1]-$Position[7]; - - $YOffset = $YOffset + $TextHeight + 4; - $ID++; - } - } - - /* Draw the data legends */ - function drawPieLegend($XPos,$YPos,$Data,$DataDescription,$R,$G,$B) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawPieLegend",$DataDescription,FALSE); - $this->validateData("drawPieLegend",$Data); - - if ( !isset($DataDescription["Position"]) ) - return(-1); - - $C_TextColor =$this->AllocateColor($this->Picture,0,0,0); - - /* <-10->[8]<-4->Text<-10-> */ - $MaxWidth = 0; $MaxHeight = 8; - foreach($Data as $Key => $Value) - { - $Value2 = $Value[$DataDescription["Position"]]; - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value2); - $TextWidth = $Position[2]-$Position[0]; - $TextHeight = $Position[1]-$Position[7]; - if ( $TextWidth > $MaxWidth) { $MaxWidth = $TextWidth; } - - $MaxHeight = $MaxHeight + $TextHeight + 4; - } - $MaxHeight = $MaxHeight - 3; - $MaxWidth = $MaxWidth + 32; - - $this->drawFilledRoundedRectangle($XPos+1,$YPos+1,$XPos+$MaxWidth+1,$YPos+$MaxHeight+1,5,$R-30,$G-30,$B-30); - $this->drawFilledRoundedRectangle($XPos,$YPos,$XPos+$MaxWidth,$YPos+$MaxHeight,5,$R,$G,$B); - - $YOffset = 4 + $this->FontSize; $ID = 0; - foreach($Data as $Key => $Value) - { - $Value2 = $Value[$DataDescription["Position"]]; - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value2); - $TextHeight = $Position[1]-$Position[7]; - $this->drawFilledRectangle($XPos+10,$YPos+$YOffset-6,$XPos+14,$YPos+$YOffset-2,$this->Palette[$ID]["R"],$this->Palette[$ID]["G"],$this->Palette[$ID]["B"]); - - imagettftext($this->Picture,$this->FontSize,0,$XPos+22,$YPos+$YOffset,$C_TextColor,$this->FontName,$Value2); - $YOffset = $YOffset + $TextHeight + 4; - $ID++; - } - } - - /* Draw the graph title */ - function drawTitle($XPos,$YPos,$Value,$R,$G,$B,$XPos2=-1,$YPos2=-1,$Shadow=FALSE) - { - $C_TextColor = $this->AllocateColor($this->Picture,$R,$G,$B); - - if ( $XPos2 != -1 ) - { - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); - $TextWidth = $Position[2]-$Position[0]; - $XPos = floor(( $XPos2 - $XPos - $TextWidth ) / 2 ) + $XPos; - } - - if ( $YPos2 != -1 ) - { - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); - $TextHeight = $Position[5]-$Position[3]; - $YPos = floor(( $YPos2 - $YPos - $TextHeight ) / 2 ) + $YPos; - } - - if ( $Shadow ) - { - $C_ShadowColor = $this->AllocateColor($this->Picture,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor); - imagettftext($this->Picture,$this->FontSize,0,$XPos+$this->ShadowXDistance,$YPos+$this->ShadowYDistance,$C_ShadowColor,$this->FontName,$Value); - } - - imagettftext($this->Picture,$this->FontSize,0,$XPos,$YPos,$C_TextColor,$this->FontName,$Value); - } - - /* Draw a text box with text align & alpha properties */ - function drawTextBox($X1,$Y1,$X2,$Y2,$Text,$Angle=0,$R=255,$G=255,$B=255,$Align=ALIGN_LEFT,$Shadow=TRUE,$BgR=-1,$BgG=-1,$BgB=-1,$Alpha=100) - { - $Position = imageftbbox($this->FontSize,$Angle,$this->FontName,$Text); - $TextWidth = $Position[2]-$Position[0]; - $TextHeight = $Position[5]-$Position[3]; - $AreaWidth = $X2 - $X1; - $AreaHeight = $Y2 - $Y1; - - if ( $BgR != -1 && $BgG != -1 && $BgB != -1 ) - $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$BgR,$BgG,$BgB,FALSE,$Alpha); - - if ( $Align == ALIGN_TOP_LEFT ) { $X = $X1+1; $Y = $Y1+$this->FontSize+1; } - if ( $Align == ALIGN_TOP_CENTER ) { $X = $X1+($AreaWidth/2)-($TextWidth/2); $Y = $Y1+$this->FontSize+1; } - if ( $Align == ALIGN_TOP_RIGHT ) { $X = $X2-$TextWidth-1; $Y = $Y1+$this->FontSize+1; } - if ( $Align == ALIGN_LEFT ) { $X = $X1+1; $Y = $Y1+($AreaHeight/2)-($TextHeight/2); } - if ( $Align == ALIGN_CENTER ) { $X = $X1+($AreaWidth/2)-($TextWidth/2); $Y = $Y1+($AreaHeight/2)-($TextHeight/2); } - if ( $Align == ALIGN_RIGHT ) { $X = $X2-$TextWidth-1; $Y = $Y1+($AreaHeight/2)-($TextHeight/2); } - if ( $Align == ALIGN_BOTTOM_LEFT ) { $X = $X1+1; $Y = $Y2-1; } - if ( $Align == ALIGN_BOTTOM_CENTER ) { $X = $X1+($AreaWidth/2)-($TextWidth/2); $Y = $Y2-1; } - if ( $Align == ALIGN_BOTTOM_RIGHT ) { $X = $X2-$TextWidth-1; $Y = $Y2-1; } - - $C_TextColor =$this->AllocateColor($this->Picture,$R,$G,$B); - $C_ShadowColor =$this->AllocateColor($this->Picture,0,0,0); - if ( $Shadow ) - imagettftext($this->Picture,$this->FontSize,$Angle,$X+1,$Y+1,$C_ShadowColor,$this->FontName,$Text); - - imagettftext($this->Picture,$this->FontSize,$Angle,$X,$Y,$C_TextColor,$this->FontName,$Text); - } - - /* Compute and draw the scale */ - function drawTreshold($Value,$R,$G,$B,$ShowLabel=FALSE,$ShowOnRight=FALSE,$TickWidth=4,$FreeText=NULL) - { - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $C_TextColor =$this->AllocateColor($this->Picture,$R,$G,$B); - $Y = $this->GArea_Y2 - ($Value - $this->VMin) * $this->DivisionRatio; - - if ( $Y <= $this->GArea_Y1 || $Y >= $this->GArea_Y2 ) - return(-1); - - if ( $TickWidth == 0 ) - $this->drawLine($this->GArea_X1,$Y,$this->GArea_X2,$Y,$R,$G,$B); - else - $this->drawDottedLine($this->GArea_X1,$Y,$this->GArea_X2,$Y,$TickWidth,$R,$G,$B); - - if ( $ShowLabel ) - { - if ( $FreeText == NULL ) - { $Label = $Value; } else { $Label = $FreeText; } - - if ( $ShowOnRight ) - imagettftext($this->Picture,$this->FontSize,0,$this->GArea_X2+2,$Y+($this->FontSize/2),$C_TextColor,$this->FontName,$Label); - else - imagettftext($this->Picture,$this->FontSize,0,$this->GArea_X1+2,$Y-($this->FontSize/2),$C_TextColor,$this->FontName,$Label); - } - } - - /* This function put a label on a specific point */ - function setLabel($Data,$DataDescription,$SerieName,$ValueName,$Caption,$R=210,$G=210,$B=210) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("setLabel",$DataDescription); - $this->validateData("setLabel",$Data); - $ShadowFactor = 100; - $C_Label =$this->AllocateColor($this->Picture,$R,$G,$B); - $C_Shadow =$this->AllocateColor($this->Picture,$R-$ShadowFactor,$G-$ShadowFactor,$B-$ShadowFactor); - $C_TextColor =$this->AllocateColor($this->Picture,0,0,0); - - $Cp = 0; $Found = FALSE; - foreach ( $Data as $Key => $Value ) - { - if ( $Data[$Key][$DataDescription["Position"]] == $ValueName ) - { $NumericalValue = $Data[$Key][$SerieName]; $Found = TRUE; } - if ( !$Found ) - $Cp++; - } - - $XPos = $this->GArea_X1 + $this->GAreaXOffset + ( $this->DivisionWidth * $Cp ) + 2; - $YPos = $this->GArea_Y2 - ($NumericalValue - $this->VMin) * $this->DivisionRatio; - - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Caption); - $TextHeight = $Position[3] - $Position[5]; - $TextWidth = $Position[2]-$Position[0] + 2; - $TextOffset = floor($TextHeight/2); - - // Shadow - $Poly = array($XPos+1,$YPos+1,$XPos + 9,$YPos - $TextOffset,$XPos + 8,$YPos + $TextOffset + 2); - imagefilledpolygon($this->Picture,$Poly,3,$C_Shadow); - $this->drawLine($XPos,$YPos+1,$XPos + 9,$YPos - $TextOffset - .2,$R-$ShadowFactor,$G-$ShadowFactor,$B-$ShadowFactor); - $this->drawLine($XPos,$YPos+1,$XPos + 9,$YPos + $TextOffset + 2.2,$R-$ShadowFactor,$G-$ShadowFactor,$B-$ShadowFactor); - $this->drawFilledRectangle($XPos + 9,$YPos - $TextOffset-.2,$XPos + 13 + $TextWidth,$YPos + $TextOffset + 2.2,$R-$ShadowFactor,$G-$ShadowFactor,$B-$ShadowFactor); - - // Label background - $Poly = array($XPos,$YPos,$XPos + 8,$YPos - $TextOffset - 1,$XPos + 8,$YPos + $TextOffset + 1); - imagefilledpolygon($this->Picture,$Poly,3,$C_Label); - $this->drawLine($XPos-1,$YPos,$XPos + 8,$YPos - $TextOffset - 1.2,$R,$G,$B); - $this->drawLine($XPos-1,$YPos,$XPos + 8,$YPos + $TextOffset + 1.2,$R,$G,$B); - $this->drawFilledRectangle($XPos + 8,$YPos - $TextOffset - 1.2,$XPos + 12 + $TextWidth,$YPos + $TextOffset + 1.2,$R,$G,$B); - - imagettftext($this->Picture,$this->FontSize,0,$XPos + 10,$YPos + $TextOffset,$C_TextColor,$this->FontName,$Caption); - } - - /* This function draw a plot graph */ - function drawPlotGraph($Data,$DataDescription,$BigRadius=5,$SmallRadius=2,$R2=-1,$G2=-1,$B2=-1,$Shadow=FALSE) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawPlotGraph",$DataDescription); - $this->validateData("drawPlotGraph",$Data); - - $GraphID = 0; - $Ro = $R2; $Go = $G2; $Bo = $B2; - - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } - - $R = $this->Palette[$ColorID]["R"]; - $G = $this->Palette[$ColorID]["G"]; - $B = $this->Palette[$ColorID]["B"]; - $R2 = $Ro; $G2 = $Go; $B2 = $Bo; - - if ( isset($DataDescription["Symbol"][$ColName]) ) - { - $Is_Alpha = ((ord ( file_get_contents ($DataDescription["Symbol"][$ColName], false, null, 25, 1)) & 6) & 4) == 4; - - $Infos = getimagesize($DataDescription["Symbol"][$ColName]); - $ImageWidth = $Infos[0]; - $ImageHeight = $Infos[1]; - $Symbol = imagecreatefromgif($DataDescription["Symbol"][$ColName]); - } - - $XPos = $this->GArea_X1 + $this->GAreaXOffset; - $Hsize = round($BigRadius/2); - $R3 = -1; $G3 = -1; $B3 = -1; - foreach ( $Data as $Key => $Values ) - { - $Value = $Data[$Key][$ColName]; - $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); - - /* Save point into the image map if option activated */ - if ( $this->BuildMap ) - $this->addToImageMap($XPos-$Hsize,$YPos-$Hsize,$XPos+1+$Hsize,$YPos+$Hsize+1,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Plot"); - - if ( is_numeric($Value) ) - { - if ( !isset($DataDescription["Symbol"][$ColName]) ) - { - - if ( $Shadow ) - { - if ( $R3 !=-1 && $G3 !=-1 && $B3 !=-1 ) - $this->drawFilledCircle($XPos+2,$YPos+2,$BigRadius,$R3,$G3,$B3); - else - { - $R3 = $this->Palette[$ColorID]["R"]-20; if ( $R3 < 0 ) { $R3 = 0; } - $G3 = $this->Palette[$ColorID]["G"]-20; if ( $G3 < 0 ) { $G3 = 0; } - $B3 = $this->Palette[$ColorID]["B"]-20; if ( $B3 < 0 ) { $B3 = 0; } - $this->drawFilledCircle($XPos+2,$YPos+2,$BigRadius,$R3,$G3,$B3); - } - } - - $this->drawFilledCircle($XPos+1,$YPos+1,$BigRadius,$R,$G,$B); - - if ( $SmallRadius != 0 ) - { - if ( $R2 !=-1 && $G2 !=-1 && $B2 !=-1 ) - $this->drawFilledCircle($XPos+1,$YPos+1,$SmallRadius,$R2,$G2,$B2); - else - { - $R2 = $this->Palette[$ColorID]["R"]-15; if ( $R2 < 0 ) { $R2 = 0; } - $G2 = $this->Palette[$ColorID]["G"]-15; if ( $G2 < 0 ) { $G2 = 0; } - $B2 = $this->Palette[$ColorID]["B"]-15; if ( $B2 < 0 ) { $B2 = 0; } - - $this->drawFilledCircle($XPos+1,$YPos+1,$SmallRadius,$R2,$G2,$B2); - } - } - } - else - { - imagecopymerge($this->Picture,$Symbol,$XPos+1-$ImageWidth/2,$YPos+1-$ImageHeight/2,0,0,$ImageWidth,$ImageHeight,100); - } - } - - $XPos = $XPos + $this->DivisionWidth; - } - $GraphID++; - } - } - - /* This function draw a plot graph in an X/Y space */ - function drawXYPlotGraph($Data,$DataDescription,$YSerieName,$XSerieName,$PaletteID=0,$BigRadius=5,$SmallRadius=2,$R2=-1,$G2=-1,$B2=-1,$Shadow=TRUE) - { - $R = $this->Palette[$PaletteID]["R"]; - $G = $this->Palette[$PaletteID]["G"]; - $B = $this->Palette[$PaletteID]["B"]; - $R3 = -1; $G3 = -1; $B3 = -1; - - $YLast = -1; $XLast = -1; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$YSerieName]) && isset($Data[$Key][$XSerieName]) ) - { - $X = $Data[$Key][$XSerieName]; - $Y = $Data[$Key][$YSerieName]; - - $Y = $this->GArea_Y2 - (($Y-$this->VMin) * $this->DivisionRatio); - $X = $this->GArea_X1 + (($X-$this->VXMin) * $this->XDivisionRatio); - - - if ( $Shadow ) - { - if ( $R3 !=-1 && $G3 !=-1 && $B3 !=-1 ) - $this->drawFilledCircle($X+2,$Y+2,$BigRadius,$R3,$G3,$B3); - else - { - $R3 = $this->Palette[$PaletteID]["R"]-20; if ( $R < 0 ) { $R = 0; } - $G3 = $this->Palette[$PaletteID]["G"]-20; if ( $G < 0 ) { $G = 0; } - $B3 = $this->Palette[$PaletteID]["B"]-20; if ( $B < 0 ) { $B = 0; } - $this->drawFilledCircle($X+2,$Y+2,$BigRadius,$R3,$G3,$B3); - } - } - - $this->drawFilledCircle($X+1,$Y+1,$BigRadius,$R,$G,$B); - - if ( $R2 !=-1 && $G2 !=-1 && $B2 !=-1 ) - $this->drawFilledCircle($X+1,$Y+1,$SmallRadius,$R2,$G2,$B2); - else - { - $R2 = $this->Palette[$PaletteID]["R"]+20; if ( $R > 255 ) { $R = 255; } - $G2 = $this->Palette[$PaletteID]["G"]+20; if ( $G > 255 ) { $G = 255; } - $B2 = $this->Palette[$PaletteID]["B"]+20; if ( $B > 255 ) { $B = 255; } - $this->drawFilledCircle($X+1,$Y+1,$SmallRadius,$R2,$G2,$B2); - } - } - } - - } - - /* This function draw an area between two series */ - function drawArea($Data,$Serie1,$Serie2,$R,$G,$B,$Alpha = 50) - { - /* Validate the Data and DataDescription array */ - $this->validateData("drawArea",$Data); - - $LayerWidth = $this->GArea_X2-$this->GArea_X1; - $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; - - $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); - $C_White =$this->AllocateColor($this->Layers[0],255,255,255); - imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); - imagecolortransparent($this->Layers[0],$C_White); - - $C_Graph =$this->AllocateColor($this->Layers[0],$R,$G,$B); - - $XPos = $this->GAreaXOffset; - $LastXPos = -1; - foreach ( $Data as $Key => $Values ) - { - $Value1 = $Data[$Key][$Serie1]; - $Value2 = $Data[$Key][$Serie2]; - $YPos1 = $LayerHeight - (($Value1-$this->VMin) * $this->DivisionRatio); - $YPos2 = $LayerHeight - (($Value2-$this->VMin) * $this->DivisionRatio); - - if ( $LastXPos != -1 ) - { - $Points = ""; - $Points[] = $LastXPos; $Points[] = $LastYPos1; - $Points[] = $LastXPos; $Points[] = $LastYPos2; - $Points[] = $XPos; $Points[] = $YPos2; - $Points[] = $XPos; $Points[] = $YPos1; - - imagefilledpolygon($this->Layers[0],$Points,4,$C_Graph); - } - - $LastYPos1 = $YPos1; - $LastYPos2 = $YPos2; - $LastXPos = $XPos; - - $XPos = $XPos + $this->DivisionWidth; - } - - imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); - imagedestroy($this->Layers[0]); - } - - - /* This function write the values of the specified series */ - function writeValues($Data,$DataDescription,$Series) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("writeValues",$DataDescription); - $this->validateData("writeValues",$Data); - - if ( !is_array($Series) ) { $Series = array($Series); } - - foreach($Series as $Key => $Serie) - { - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $Serie ) { $ColorID = $ID; }; $ID++; } - - $XPos = $this->GArea_X1 + $this->GAreaXOffset; - $XLast = -1; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$Serie]) && is_numeric($Data[$Key][$Serie])) - { - $Value = $Data[$Key][$Serie]; - $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); - - $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$Value); - $Width = $Positions[2] - $Positions[6]; $XOffset = $XPos - ($Width/2); - $Height = $Positions[3] - $Positions[7]; $YOffset = $YPos - 4; - - $C_TextColor =$this->AllocateColor($this->Picture,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); - imagettftext($this->Picture,$this->FontSize,0,$XOffset,$YOffset,$C_TextColor,$this->FontName,$Value); - } - $XPos = $XPos + $this->DivisionWidth; - } - - } - } - - /* This function draw a line graph */ - function drawLineGraph($Data,$DataDescription,$SerieName="") - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawLineGraph",$DataDescription); - $this->validateData("drawLineGraph",$Data); - - $GraphID = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } - - if ( $SerieName == "" || $SerieName == $ColName ) - { - $XPos = $this->GArea_X1 + $this->GAreaXOffset; - $XLast = -1; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName])) - { - $Value = $Data[$Key][$ColName]; - $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); - - /* Save point into the image map if option activated */ - if ( $this->BuildMap ) - $this->addToImageMap($XPos-3,$YPos-3,$XPos+3,$YPos+3,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Line"); - - if (!is_numeric($Value)) { $XLast = -1; } - if ( $XLast != -1 ) - $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE); - - $XLast = $XPos; - $YLast = $YPos; - if (!is_numeric($Value)) { $XLast = -1; } - } - $XPos = $XPos + $this->DivisionWidth; - } - $GraphID++; - } - } - } - - /* This function draw a line graph */ - function drawXYGraph($Data,$DataDescription,$YSerieName,$XSerieName,$PaletteID=0) - { - $YLast = -1; $XLast = -1; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$YSerieName]) && isset($Data[$Key][$XSerieName]) ) - { - $X = $Data[$Key][$XSerieName]; - $Y = $Data[$Key][$YSerieName]; - - $Y = $this->GArea_Y2 - (($Y-$this->VMin) * $this->DivisionRatio); - $X = $this->GArea_X1 + (($X-$this->VXMin) * $this->XDivisionRatio); - - if ($XLast != -1 && $YLast != -1) - { - $this->drawLine($XLast,$YLast,$X,$Y,$this->Palette[$PaletteID]["R"],$this->Palette[$PaletteID]["G"],$this->Palette[$PaletteID]["B"],TRUE); - } - - $XLast = $X; - $YLast = $Y; - } - } - } - - /* This function draw a cubic curve */ - function drawCubicCurve($Data,$DataDescription,$Accuracy=.1,$SerieName="") - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawCubicCurve",$DataDescription); - $this->validateData("drawCubicCurve",$Data); - - $GraphID = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - if ( $SerieName == "" || $SerieName == $ColName ) - { - $XIn = ""; $Yin = ""; $Yt = ""; $U = ""; - $XIn[0] = 0; $YIn[0] = 0; - - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } - - $Index = 1; - $XLast = -1; $Missing = ""; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName]) ) - { - $Value = $Data[$Key][$ColName]; - $XIn[$Index] = $Index; - $YIn[$Index] = $Value; - if ( !is_numeric($Value) ) { $Missing[$Index] = TRUE; } - $Index++; - } - } - $Index--; - - $Yt[0] = 0; - $Yt[1] = 0; - $U[1] = 0; - for($i=2;$i<=$Index-1;$i++) - { - $Sig = ($XIn[$i] - $XIn[$i-1]) / ($XIn[$i+1] - $XIn[$i-1]); - $p = $Sig * $Yt[$i-1] + 2; - $Yt[$i] = ($Sig - 1) / $p; - $U[$i] = ($YIn[$i+1] - $YIn[$i]) / ($XIn[$i+1] - $XIn[$i]) - ($YIn[$i] - $YIn[$i-1]) / ($XIn[$i] - $XIn[$i-1]); - $U[$i] = (6 * $U[$i] / ($XIn[$i+1] - $XIn[$i-1]) - $Sig * $U[$i-1]) / $p; - } - - $qn = 0; - $un = 0; - $Yt[$Index] = ($un - $qn * $U[$Index-1]) / ($qn * $Yt[$Index-1] + 1); - - for($k=$Index-1;$k>=1;$k--) - $Yt[$k] = $Yt[$k] * $Yt[$k+1] + $U[$k]; - - $XPos = $this->GArea_X1 + $this->GAreaXOffset; - for($X=1;$X<=$Index;$X=$X+$Accuracy) - { - $klo = 1; - $khi = $Index; - $k = $khi - $klo; - while($k > 1) - { - $k = $khi - $klo; - If ( $XIn[$k] >= $X ) - $khi = $k; - else - $klo = $k; - } - $klo = $khi - 1; - - $h = $XIn[$khi] - $XIn[$klo]; - $a = ($XIn[$khi] - $X) / $h; - $b = ($X - $XIn[$klo]) / $h; - $Value = $a * $YIn[$klo] + $b * $YIn[$khi] + (($a*$a*$a - $a) * $Yt[$klo] + ($b*$b*$b - $b) * $Yt[$khi]) * ($h*$h) / 6; - - $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); - - if ( $XLast != -1 && !isset($Missing[floor($X)]) && !isset($Missing[floor($X+1)]) ) - $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE); - - $XLast = $XPos; - $YLast = $YPos; - $XPos = $XPos + $this->DivisionWidth * $Accuracy; - } - - // Add potentialy missing values - $XPos = $XPos - $this->DivisionWidth * $Accuracy; - if ( $XPos < ($this->GArea_X2 - $this->GAreaXOffset) ) - { - $YPos = $this->GArea_Y2 - (($YIn[$Index]-$this->VMin) * $this->DivisionRatio); - $this->drawLine($XLast,$YLast,$this->GArea_X2-$this->GAreaXOffset,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE); - } - - $GraphID++; - } - } - } - - /* This function draw a filled cubic curve */ - function drawFilledCubicCurve($Data,$DataDescription,$Accuracy=.1,$Alpha=100,$AroundZero=FALSE) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawFilledCubicCurve",$DataDescription); - $this->validateData("drawFilledCubicCurve",$Data); - - $LayerWidth = $this->GArea_X2-$this->GArea_X1; - $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; - $YZero = $LayerHeight - ((0-$this->VMin) * $this->DivisionRatio); - if ( $YZero > $LayerHeight ) { $YZero = $LayerHeight; } - - $GraphID = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - $XIn = ""; $Yin = ""; $Yt = ""; $U = ""; - $XIn[0] = 0; $YIn[0] = 0; - - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } - - $Index = 1; - $XLast = -1; $Missing = ""; - foreach ( $Data as $Key => $Values ) - { - $Value = $Data[$Key][$ColName]; - $XIn[$Index] = $Index; - $YIn[$Index] = $Value; - if ( !is_numeric($Value) ) { $Missing[$Index] = TRUE; } - $Index++; - } - $Index--; - - $Yt[0] = 0; - $Yt[1] = 0; - $U[1] = 0; - for($i=2;$i<=$Index-1;$i++) - { - $Sig = ($XIn[$i] - $XIn[$i-1]) / ($XIn[$i+1] - $XIn[$i-1]); - $p = $Sig * $Yt[$i-1] + 2; - $Yt[$i] = ($Sig - 1) / $p; - $U[$i] = ($YIn[$i+1] - $YIn[$i]) / ($XIn[$i+1] - $XIn[$i]) - ($YIn[$i] - $YIn[$i-1]) / ($XIn[$i] - $XIn[$i-1]); - $U[$i] = (6 * $U[$i] / ($XIn[$i+1] - $XIn[$i-1]) - $Sig * $U[$i-1]) / $p; - } - - $qn = 0; - $un = 0; - $Yt[$Index] = ($un - $qn * $U[$Index-1]) / ($qn * $Yt[$Index-1] + 1); - - for($k=$Index-1;$k>=1;$k--) - $Yt[$k] = $Yt[$k] * $Yt[$k+1] + $U[$k]; - - $Points = ""; - $Points[] = $this->GAreaXOffset; - $Points[] = $LayerHeight; - - $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); - $C_White =$this->AllocateColor($this->Layers[0],255,255,255); - imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); - imagecolortransparent($this->Layers[0],$C_White); - - $YLast = NULL; - $XPos = $this->GAreaXOffset; $PointsCount = 2; - for($X=1;$X<=$Index;$X=$X+$Accuracy) - { - $klo = 1; - $khi = $Index; - $k = $khi - $klo; - while($k > 1) - { - $k = $khi - $klo; - If ( $XIn[$k] >= $X ) - $khi = $k; - else - $klo = $k; - } - $klo = $khi - 1; - - $h = $XIn[$khi] - $XIn[$klo]; - $a = ($XIn[$khi] - $X) / $h; - $b = ($X - $XIn[$klo]) / $h; - $Value = $a * $YIn[$klo] + $b * $YIn[$khi] + (($a*$a*$a - $a) * $Yt[$klo] + ($b*$b*$b - $b) * $Yt[$khi]) * ($h*$h) / 6; - - $YPos = $LayerHeight - (($Value-$this->VMin) * $this->DivisionRatio); - - if ( $YLast != NULL && $AroundZero && !isset($Missing[floor($X)]) && !isset($Missing[floor($X+1)])) - { - $aPoints = ""; - $aPoints[] = $XLast; - $aPoints[] = $YLast; - $aPoints[] = $XPos; - $aPoints[] = $YPos; - $aPoints[] = $XPos; - $aPoints[] = $YZero; - $aPoints[] = $XLast; - $aPoints[] = $YZero; - - $C_Graph =$this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); - imagefilledpolygon($this->Layers[0],$aPoints,4,$C_Graph); - } - - if ( !isset($Missing[floor($X)]) || $YLast == NULL ) - { - $PointsCount++; - $Points[] = $XPos; - $Points[] = $YPos; - } - else - { - $PointsCount++; $Points[] = $XLast; $Points[] = $LayerHeight; - } - - $YLast = $YPos; $XLast = $XPos; - $XPos = $XPos + $this->DivisionWidth * $Accuracy; - } - - // Add potentialy missing values - $XPos = $XPos - $this->DivisionWidth * $Accuracy; - if ( $XPos < ($LayerWidth-$this->GAreaXOffset) ) - { - $YPos = $LayerHeight - (($YIn[$Index]-$this->VMin) * $this->DivisionRatio); - - if ( $YLast != NULL && $AroundZero ) - { - $aPoints = ""; - $aPoints[] = $XLast; - $aPoints[] = $YLast; - $aPoints[] = $LayerWidth-$this->GAreaXOffset; - $aPoints[] = $YPos; - $aPoints[] = $LayerWidth-$this->GAreaXOffset; - $aPoints[] = $YZero; - $aPoints[] = $XLast; - $aPoints[] = $YZero; - - $C_Graph =$this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); - imagefilledpolygon($this->Layers[0],$aPoints,4,$C_Graph); - } - - if ( $YIn[$klo] != "" && $YIn[$khi] != "" || $YLast == NULL ) - { - $PointsCount++; - $Points[] = $LayerWidth-$this->GAreaXOffset; - $Points[] = $YPos; - } - } - - $Points[] = $LayerWidth-$this->GAreaXOffset; - $Points[] = $LayerHeight; - - if ( !$AroundZero ) - { - $C_Graph =$this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); - imagefilledpolygon($this->Layers[0],$Points,$PointsCount,$C_Graph); - } - - imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); - imagedestroy($this->Layers[0]); - - $this->drawCubicCurve($Data,$DataDescription,$Accuracy,$ColName); - - $GraphID++; - } - } - - /* This function draw a filled line graph */ - function drawFilledLineGraph($Data,$DataDescription,$Alpha=100,$AroundZero=FALSE) - { - $Empty = -2147483647; - - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawFilledLineGraph",$DataDescription); - $this->validateData("drawFilledLineGraph",$Data); - - $LayerWidth = $this->GArea_X2-$this->GArea_X1; - $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; - - $GraphID = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } - - $aPoints = ""; - $aPoints[] = $this->GAreaXOffset; - $aPoints[] = $LayerHeight; - - $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); - $C_White = $this->AllocateColor($this->Layers[0],255,255,255); - imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); - imagecolortransparent($this->Layers[0],$C_White); - - $XPos = $this->GAreaXOffset; - $XLast = -1; $PointsCount = 2; - $YZero = $LayerHeight - ((0-$this->VMin) * $this->DivisionRatio); - if ( $YZero > $LayerHeight ) { $YZero = $LayerHeight; } - - $YLast = $Empty; - foreach ( $Data as $Key => $Values ) - { - $Value = $Data[$Key][$ColName]; - $YPos = $LayerHeight - (($Value-$this->VMin) * $this->DivisionRatio); - - /* Save point into the image map if option activated */ - if ( $this->BuildMap ) - $this->addToImageMap($XPos-3,$YPos-3,$XPos+3,$YPos+3,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"FLine"); - - if ( !is_numeric($Value) ) - { - $PointsCount++; - $aPoints[] = $XLast; - $aPoints[] = $LayerHeight; - - $YLast = $Empty; - } - else - { - $PointsCount++; - if ( $YLast <> $Empty ) - { $aPoints[] = $XPos; $aPoints[] = $YPos; } - else - { $PointsCount++; $aPoints[] = $XPos; $aPoints[] = $LayerHeight; $aPoints[] = $XPos; $aPoints[] = $YPos; } - - if ($YLast <> $Empty && $AroundZero) - { - $Points = ""; - $Points[] = $XLast; $Points[] = $YLast; - $Points[] = $XPos; - $Points[] = $YPos; - $Points[] = $XPos; - $Points[] = $YZero; - $Points[] = $XLast; - $Points[] = $YZero; - - $C_Graph = $this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); - imagefilledpolygon($this->Layers[0],$Points,4,$C_Graph); - } - $YLast = $YPos; - } - - $XLast = $XPos; - $XPos = $XPos + $this->DivisionWidth; - } - $aPoints[] = $LayerWidth - $this->GAreaXOffset; - $aPoints[] = $LayerHeight; - - if ( $AroundZero == FALSE ) - { - $C_Graph = $this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); - imagefilledpolygon($this->Layers[0],$aPoints,$PointsCount,$C_Graph); - } - - imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); - imagedestroy($this->Layers[0]); - $GraphID++; - $this->drawLineGraph($Data,$DataDescription,$ColName); - } - } - - /* This function draw a bar graph */ - function drawOverlayBarGraph($Data,$DataDescription,$Alpha=50) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawOverlayBarGraph",$DataDescription); - $this->validateData("drawOverlayBarGraph",$Data); - - $LayerWidth = $this->GArea_X2-$this->GArea_X1; - $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; - - $GraphID = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } - - $this->Layers[$GraphID] = imagecreatetruecolor($LayerWidth,$LayerHeight); - $C_White = $this->AllocateColor($this->Layers[$GraphID],255,255,255); - $C_Graph = $this->AllocateColor($this->Layers[$GraphID],$this->Palette[$GraphID]["R"],$this->Palette[$GraphID]["G"],$this->Palette[$GraphID]["B"]); - imagefilledrectangle($this->Layers[$GraphID],0,0,$LayerWidth,$LayerHeight,$C_White); - imagecolortransparent($this->Layers[$GraphID],$C_White); - - $XWidth = $this->DivisionWidth / 4; - $XPos = $this->GAreaXOffset; - $YZero = $LayerHeight - ((0-$this->VMin) * $this->DivisionRatio); - $XLast = -1; $PointsCount = 2; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName]) ) - { - $Value = $Data[$Key][$ColName]; - if ( is_numeric($Value) ) - { - $YPos = $LayerHeight - (($Value-$this->VMin) * $this->DivisionRatio); - - imagefilledrectangle($this->Layers[$GraphID],$XPos-$XWidth,$YPos,$XPos+$XWidth,$YZero,$C_Graph); - - $X1 = floor($XPos - $XWidth + $this->GArea_X1); $Y1 = floor($YPos+$this->GArea_Y1) + .2; - $X2 = floor($XPos + $XWidth + $this->GArea_X1); $Y2 = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio); - if ( $X1 <= $this->GArea_X1 ) { $X1 = $this->GArea_X1 + 1; } - if ( $X2 >= $this->GArea_X2 ) { $X2 = $this->GArea_X2 - 1; } - - /* Save point into the image map if option activated */ - if ( $this->BuildMap ) - $this->addToImageMap($X1,min($Y1,$Y2),$X2,max($Y1,$Y2),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"oBar"); - - $this->drawLine($X1,$Y1,$X2,$Y1,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE); - } - } - $XPos = $XPos + $this->DivisionWidth; - } - - $GraphID++; - } - - for($i=0;$i<=($GraphID-1);$i++) - { - imagecopymerge($this->Picture,$this->Layers[$i],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); - imagedestroy($this->Layers[$i]); - } - } - - /* This function draw a bar graph */ - function drawBarGraph($Data,$DataDescription,$Shadow=FALSE,$Alpha=100) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawBarGraph",$DataDescription); - $this->validateData("drawBarGraph",$Data); - - $GraphID = 0; - $Series = count($DataDescription["Values"]); - $SeriesWidth = $this->DivisionWidth / ($Series+1); - $SerieXOffset = $this->DivisionWidth / 2 - $SeriesWidth / 2; - - $YZero = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio); - if ( $YZero > $this->GArea_Y2 ) { $YZero = $this->GArea_Y2; } - - $SerieID = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } - - $XPos = $this->GArea_X1 + $this->GAreaXOffset - $SerieXOffset + $SeriesWidth * $SerieID; - $XLast = -1; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName])) - { - if ( is_numeric($Data[$Key][$ColName]) ) - { - $Value = $Data[$Key][$ColName]; - $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); - - /* Save point into the image map if option activated */ - if ( $this->BuildMap ) - { - $this->addToImageMap($XPos+1,min($YZero,$YPos),$XPos+$SeriesWidth-1,max($YZero,$YPos),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Bar"); - } - - if ( $Shadow && $Alpha == 100 ) - $this->drawRectangle($XPos+1,$YZero,$XPos+$SeriesWidth-1,$YPos,25,25,25,TRUE,$Alpha); - - $this->drawFilledRectangle($XPos+1,$YZero,$XPos+$SeriesWidth-1,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE,$Alpha); - } - } - $XPos = $XPos + $this->DivisionWidth; - } - $SerieID++; - } - } - - /* This function draw a stacked bar graph */ - function drawStackedBarGraph($Data,$DataDescription,$Alpha=50,$Contiguous=FALSE) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawBarGraph",$DataDescription); - $this->validateData("drawBarGraph",$Data); - - $GraphID = 0; - $Series = count($DataDescription["Values"]); - if ( $Contiguous ) - $SeriesWidth = $this->DivisionWidth; - else - $SeriesWidth = $this->DivisionWidth * .8; - - $YZero = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio); - if ( $YZero > $this->GArea_Y2 ) { $YZero = $this->GArea_Y2; } - - $SerieID = 0; $LastValue = ""; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } - - $XPos = $this->GArea_X1 + $this->GAreaXOffset - $SeriesWidth / 2; - $XLast = -1; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName])) - { - if ( is_numeric($Data[$Key][$ColName]) ) - { - $Value = $Data[$Key][$ColName]; - - if ( isset($LastValue[$Key]) ) - { - $YPos = $this->GArea_Y2 - ((($Value+$LastValue[$Key])-$this->VMin) * $this->DivisionRatio); - $YBottom = $this->GArea_Y2 - (($LastValue[$Key]-$this->VMin) * $this->DivisionRatio); - $LastValue[$Key] += $Value; - } - else - { - $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); - $YBottom = $YZero; - $LastValue[$Key] = $Value; - } - - /* Save point into the image map if option activated */ - if ( $this->BuildMap ) - $this->addToImageMap($XPos+1,min($YBottom,$YPos),$XPos+$SeriesWidth-1,max($YBottom,$YPos),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"sBar"); - - $this->drawFilledRectangle($XPos+1,$YBottom,$XPos+$SeriesWidth-1,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE,$Alpha); - } - } - $XPos = $XPos + $this->DivisionWidth; - } - $SerieID++; - } - } - - /* This function draw a limits bar graphs */ - function drawLimitsGraph($Data,$DataDescription,$R=0,$G=0,$B=0) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawLimitsGraph",$DataDescription); - $this->validateData("drawLimitsGraph",$Data); - - $XWidth = $this->DivisionWidth / 4; - $XPos = $this->GArea_X1 + $this->GAreaXOffset; - - foreach ( $Data as $Key => $Values ) - { - $Min = $Data[$Key][$DataDescription["Values"][0]]; - $Max = $Data[$Key][$DataDescription["Values"][0]]; - $GraphID = 0; $MaxID = 0; $MinID = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - if ( isset($Data[$Key][$ColName]) ) - { - if ( $Data[$Key][$ColName] > $Max && is_numeric($Data[$Key][$ColName])) - { $Max = $Data[$Key][$ColName]; $MaxID = $GraphID; } - } - if ( isset($Data[$Key][$ColName]) && is_numeric($Data[$Key][$ColName])) - { - if ( $Data[$Key][$ColName] < $Min ) - { $Min = $Data[$Key][$ColName]; $MinID = $GraphID; } - $GraphID++; - } - } - - $YPos = $this->GArea_Y2 - (($Max-$this->VMin) * $this->DivisionRatio); - $X1 = floor($XPos - $XWidth); $Y1 = floor($YPos) - .2; - $X2 = floor($XPos + $XWidth); - if ( $X1 <= $this->GArea_X1 ) { $X1 = $this->GArea_X1 + 1; } - if ( $X2 >= $this->GArea_X2 ) { $X2 = $this->GArea_X2 - 1; } - - $YPos = $this->GArea_Y2 - (($Min-$this->VMin) * $this->DivisionRatio); - $Y2 = floor($YPos) + .2; - - $this->drawLine(floor($XPos)-.2,$Y1+1,floor($XPos)-.2,$Y2-1,$R,$G,$B,TRUE); - $this->drawLine(floor($XPos)+.2,$Y1+1,floor($XPos)+.2,$Y2-1,$R,$G,$B,TRUE); - $this->drawLine($X1,$Y1,$X2,$Y1,$this->Palette[$MaxID]["R"],$this->Palette[$MaxID]["G"],$this->Palette[$MaxID]["B"],FALSE); - $this->drawLine($X1,$Y2,$X2,$Y2,$this->Palette[$MinID]["R"],$this->Palette[$MinID]["G"],$this->Palette[$MinID]["B"],FALSE); - - $XPos = $XPos + $this->DivisionWidth; - } - } - - /* This function draw radar axis centered on the graph area */ - function drawRadarAxis($Data,$DataDescription,$Mosaic=TRUE,$BorderOffset=10,$A_R=60,$A_G=60,$A_B=60,$S_R=200,$S_G=200,$S_B=200,$MaxValue=-1,$valueMod=1) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawRadarAxis",$DataDescription); - $this->validateData("drawRadarAxis",$Data); - - $C_TextColor = $this->AllocateColor($this->Picture,$A_R,$A_G,$A_B); - - /* Draw radar axis */ - $Points = count($Data); - $Radius = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset; - $XCenter = ( $this->GArea_X2 - $this->GArea_X1 ) / 2 + $this->GArea_X1; - $YCenter = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 + $this->GArea_Y1; - - /* Search for the max value */ - if ( $MaxValue == -1 ) - { - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName])) - if ( $Data[$Key][$ColName] > $MaxValue ) { $MaxValue = $Data[$Key][$ColName]; } - } - } - } - - /* Draw the mosaic */ - if ( $Mosaic ) - { - $RadiusScale = $Radius / $MaxValue; - for ( $t=1; $t<=$MaxValue-1; $t++) - { - $TRadius = $RadiusScale * $t; - $LastX1 = -1; - - for ( $i=0; $i<=$Points; $i++) - { - $Angle = -90 + $i * 360/$Points; - $X1 = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter; - $Y1 = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter; - $X2 = cos($Angle * 3.1418 / 180 ) * ($TRadius+$RadiusScale) + $XCenter; - $Y2 = sin($Angle * 3.1418 / 180 ) * ($TRadius+$RadiusScale) + $YCenter; - - if ( $t % 2 == 1 && $LastX1 != -1) - { - $Plots = ""; - $Plots[] = $X1; $Plots[] = $Y1; - $Plots[] = $X2; $Plots[] = $Y2; - $Plots[] = $LastX2; $Plots[] = $LastY2; - $Plots[] = $LastX1; $Plots[] = $LastY1; - - $C_Graph = $this->AllocateColor($this->Picture,250,250,250); - imagefilledpolygon($this->Picture,$Plots,(count($Plots)+1)/2,$C_Graph); - } - - $LastX1 = $X1; $LastY1= $Y1; - $LastX2 = $X2; $LastY2= $Y2; - } - } - } - - - /* Draw the spider web */ - for ( $t=1; $t<=$MaxValue; $t++) - { - $TRadius = ( $Radius / $MaxValue ) * $t; - $LastX = -1; - - for ( $i=0; $i<=$Points; $i++) - { - $Angle = -90 + $i * 360/$Points; - $X = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter; - $Y = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter; - - if ( $LastX != -1 ) - $this->drawDottedLine($LastX,$LastY,$X,$Y,4,$S_R,$S_G,$S_B); - - $LastX = $X; $LastY= $Y; - } - } - - /* Draw the axis */ - for ( $i=0; $i<=$Points; $i++) - { - $Angle = -90 + $i * 360/$Points; - $X = cos($Angle * 3.1418 / 180 ) * $Radius + $XCenter; - $Y = sin($Angle * 3.1418 / 180 ) * $Radius + $YCenter; - - $this->drawLine($XCenter,$YCenter,$X,$Y,$A_R,$A_G,$A_B); - - $XOffset = 0; $YOffset = 0; - if (isset($Data[$i][$DataDescription["Position"]])) - { - $Label = $Data[$i][$DataDescription["Position"]]; - - $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$Label); - $Width = $Positions[2] - $Positions[6]; - $Height = $Positions[3] - $Positions[7]; - - if ( $Angle >= 0 && $Angle <= 90 ) - $YOffset = $Height; - - if ( $Angle > 90 && $Angle <= 180 ) - { $YOffset = $Height; $XOffset = -$Width; } - - if ( $Angle > 180 && $Angle <= 270 ) - { $XOffset = -$Width; } - - imagettftext($this->Picture,$this->FontSize,0,$X+$XOffset,$Y+$YOffset,$C_TextColor,$this->FontName,$Label); - - if ( $this->BuildMap ) - { - $vecX = $X - $XCenter; - $vecY = $Y - $YCenter; - - // get a perpendicular vector - $vecXtemp = $vecX; - $vecX = -$vecY; - $vecY = $vecXtemp; - - // normalization - $vecLength = sqrt($vecX * $vecX + $vecY * $vecY); - $vecX = $vecX / $vecLength; - $vecY = $vecY / $vecLength; - - $tooltipValue = ''; - foreach ($DataDescription['Description'] as $key => $value) { - $tooltipValue .= $value.' : '.sprintf("%.2f", $Data[$i][$key]).';'; - } - - $offset = 10; - $poly = array( - array($X+$vecX*-$offset,$Y+$vecY*-$offset), - array($X+$vecX*+$offset,$Y+$vecY*+$offset), - array($XCenter+$vecX*+$offset,$YCenter+$vecY*+$offset), - array($XCenter+$vecX*-$offset,$YCenter+$vecY*-$offset), - ); - $this->addPolyToImageMap($poly,$Label,$tooltipValue,'Radar'); - } - } - } - - /* Write the values */ - for ( $t=1; $t<=$MaxValue; $t++) - { - if ($t % $valueMod != 0) - { continue; } - - $TRadius = ( $Radius / $MaxValue ) * $t; - - $Angle = -90 + 360 / $Points; - $X1 = $XCenter; - $Y1 = $YCenter - $TRadius; - $X2 = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter; - $Y2 = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter; - - $XPos = floor(($X2-$X1)/2) + $X1; - $YPos = floor(($Y2-$Y1)/2) + $Y1; - - $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$t); - $X = $XPos - ( $X+$Positions[2] - $X+$Positions[6] ) / 2; - $Y = $YPos + $this->FontSize; - - $this->drawFilledRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,240,240,240); - $this->drawRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,220,220,220); - imagettftext($this->Picture,$this->FontSize,0,$X,$Y,$C_TextColor,$this->FontName,$t); - } - } - - /* This function draw a radar graph centered on the graph area */ - function drawRadar($Data,$DataDescription,$BorderOffset=10,$MaxValue=-1) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawRadar",$DataDescription); - $this->validateData("drawRadar",$Data); - - $Points = count($Data); - $Radius = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset; - $XCenter = ( $this->GArea_X2 - $this->GArea_X1 ) / 2 + $this->GArea_X1; - $YCenter = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 + $this->GArea_Y1; - - /* Search for the max value */ - if ( $MaxValue == -1 ) - { - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName])) - if ( $Data[$Key][$ColName] > $MaxValue ) { $MaxValue = $Data[$Key][$ColName]; } - } - } - } - - $GraphID = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } - - $Angle = -90; - $XLast = -1; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName])) - { - $Value = $Data[$Key][$ColName]; - $Strength = ( $Radius / $MaxValue ) * $Value; - - $XPos = cos($Angle * 3.1418 / 180 ) * $Strength + $XCenter; - $YPos = sin($Angle * 3.1418 / 180 ) * $Strength + $YCenter; - - if ( $XLast != -1 ) - $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); - - if ( $XLast == -1 ) - { $FirstX = $XPos; $FirstY = $YPos; } - - $Angle = $Angle + (360/$Points); - $XLast = $XPos; - $YLast = $YPos; - } - } - $this->drawLine($XPos,$YPos,$FirstX,$FirstY,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); - $GraphID++; - } - } - - /* This function draw a radar graph centered on the graph area */ - function drawFilledRadar($Data,$DataDescription,$Alpha=50,$BorderOffset=10,$MaxValue=-1) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawFilledRadar",$DataDescription); - $this->validateData("drawFilledRadar",$Data); - - $Points = count($Data); - $LayerWidth = $this->GArea_X2-$this->GArea_X1; - $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; - $Radius = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset; - $XCenter = ( $this->GArea_X2 - $this->GArea_X1 ) / 2; - $YCenter = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2; - - /* Search for the max value */ - if ( $MaxValue == -1 ) - { - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName])) - if ( $Data[$Key][$ColName] > $MaxValue && is_numeric($Data[$Key][$ColName])) { $MaxValue = $Data[$Key][$ColName]; } - } - } - } - - $GraphID = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - $ID = 0; - foreach ( $DataDescription["Description"] as $keyI => $ValueI ) - { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } - - $Angle = -90; - $XLast = -1; - $Plots = ""; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName])) - { - $Value = $Data[$Key][$ColName]; - if ( !is_numeric($Value) ) { $Value = 0; } - $Strength = ( $Radius / $MaxValue ) * $Value; - - $XPos = cos($Angle * 3.1418 / 180 ) * $Strength + $XCenter; - $YPos = sin($Angle * 3.1418 / 180 ) * $Strength + $YCenter; - - $Plots[] = $XPos; - $Plots[] = $YPos; - - $Angle = $Angle + (360/$Points); - $XLast = $XPos; - $YLast = $YPos; - } - } - - if (isset($Plots[0])) - { - $Plots[] = $Plots[0]; - $Plots[] = $Plots[1]; - - $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); - $C_White = $this->AllocateColor($this->Layers[0],255,255,255); - imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); - imagecolortransparent($this->Layers[0],$C_White); - - $C_Graph = $this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); - imagefilledpolygon($this->Layers[0],$Plots,(count($Plots)+1)/2,$C_Graph); - - imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); - imagedestroy($this->Layers[0]); - - for($i=0;$i<=count($Plots)-4;$i=$i+2) - $this->drawLine($Plots[$i]+$this->GArea_X1,$Plots[$i+1]+$this->GArea_Y1,$Plots[$i+2]+$this->GArea_X1,$Plots[$i+3]+$this->GArea_Y1,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); - } - - $GraphID++; - } - } - - /* This function draw a flat pie chart */ - function drawBasicPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$R=255,$G=255,$B=255,$Decimals=0) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawBasicPieGraph",$DataDescription,FALSE); - $this->validateData("drawBasicPieGraph",$Data); - - /* Determine pie sum */ - $Series = 0; $PieSum = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - if ( $ColName != $DataDescription["Position"] ) - { - $Series++; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName])) - $PieSum = $PieSum + $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]]; - } - } - } - - /* Validate serie */ - if ( $Series != 1 ) - RaiseFatal("Pie chart can only accept one serie of data."); - - $SpliceRatio = 360 / $PieSum; - $SplicePercent = 100 / $PieSum; - - /* Calculate all polygons */ - $Angle = 0; $TopPlots = ""; - foreach($iValues as $Key => $Value) - { - $TopPlots[$Key][] = $XPos; - $TopPlots[$Key][] = $YPos; - - /* Process labels position & size */ - $Caption = ""; - if ( !($DrawLabels == PIE_NOLABEL) ) - { - $TAngle = $Angle+($Value*$SpliceRatio/2); - if ($DrawLabels == PIE_PERCENTAGE) - $Caption = (round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; - elseif ($DrawLabels == PIE_LABELS) - $Caption = $iLabels[$Key]; - elseif ($DrawLabels == PIE_PERCENTAGE_LABEL) - $Caption = $iLabels[$Key]."\r\n".(round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; - elseif ($DrawLabels == PIE_PERCENTAGE_LABEL) - $Caption = $iLabels[$Key]."\r\n".(round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; - - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Caption); - $TextWidth = $Position[2]-$Position[0]; - $TextHeight = abs($Position[1])+abs($Position[3]); - - $TX = cos(($TAngle) * 3.1418 / 180 ) * ($Radius+10) + $XPos; - - if ( $TAngle > 0 && $TAngle < 180 ) - $TY = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+10) + $YPos + 4; - else - $TY = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+4) + $YPos - ($TextHeight/2); - - if ( $TAngle > 90 && $TAngle < 270 ) - $TX = $TX - $TextWidth; - - $C_TextColor = $this->AllocateColor($this->Picture,70,70,70); - imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption); - } - - /* Process pie slices */ - for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5) - { - $TopX = cos($iAngle * 3.1418 / 180 ) * $Radius + $XPos; - $TopY = sin($iAngle * 3.1418 / 180 ) * $Radius + $YPos; - - $TopPlots[$Key][] = $TopX; - $TopPlots[$Key][] = $TopY; - } - - $TopPlots[$Key][] = $XPos; - $TopPlots[$Key][] = $YPos; - - $Angle = $iAngle; - } - $PolyPlots = $TopPlots; - - /* Set array values type to float --- PHP Bug with imagefilledpolygon casting to integer */ - foreach ($TopPlots as $Key => $Value) - { foreach ($TopPlots[$Key] as $Key2 => $Value2) { settype($TopPlots[$Key][$Key2],"float"); } } - - /* Draw Top polygons */ - foreach ($PolyPlots as $Key => $Value) - { - $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]); - imagefilledpolygon($this->Picture,$PolyPlots[$Key],(count($PolyPlots[$Key])+1)/2,$C_GraphLo); - } - - $this->drawCircle($XPos-.5,$YPos-.5,$Radius,$R,$G,$B); - $this->drawCircle($XPos-.5,$YPos-.5,$Radius+.5,$R,$G,$B); - - /* Draw Top polygons */ - foreach ($TopPlots as $Key => $Value) - { - for($j=0;$j<=count($TopPlots[$Key])-4;$j=$j+2) - $this->drawLine($TopPlots[$Key][$j],$TopPlots[$Key][$j+1],$TopPlots[$Key][$j+2],$TopPlots[$Key][$j+3],$R,$G,$B); - } - } - - function drawFlatPieGraphWithShadow($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$SpliceDistance=0,$Decimals=0) - { - $this->drawFlatPieGraph($Data,$DataDescription,$XPos+$this->ShadowXDistance,$YPos+$this->ShadowYDistance,$Radius,PIE_NOLABEL,$SpliceDistance,$Decimals,TRUE); - $this->drawFlatPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius,$DrawLabels,$SpliceDistance,$Decimals,FALSE); - } - - /* This function draw a flat pie chart */ - function drawFlatPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$SpliceDistance=0,$Decimals=0,$AllBlack=FALSE) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawFlatPieGraph",$DataDescription,FALSE); - $this->validateData("drawFlatPieGraph",$Data); - - $ShadowStatus = $this->ShadowActive ; $this->ShadowActive = FALSE; - - /* Determine pie sum */ - $Series = 0; $PieSum = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - if ( $ColName != $DataDescription["Position"] ) - { - $Series++; - foreach ( $Data as $Key => $Values ) - { - if ( isset($Data[$Key][$ColName])) - $PieSum = $PieSum + $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]]; - } - } - } - - /* Validate serie */ - if ( $Series != 1 ) - { - RaiseFatal("Pie chart can only accept one serie of data."); - return(0); - } - - $SpliceRatio = 360 / $PieSum; - $SplicePercent = 100 / $PieSum; - - /* Calculate all polygons */ - $Angle = 0; $TopPlots = ""; - foreach($iValues as $Key => $Value) - { - $XOffset = cos(($Angle+($Value/2*$SpliceRatio)) * 3.1418 / 180 ) * $SpliceDistance; - $YOffset = sin(($Angle+($Value/2*$SpliceRatio)) * 3.1418 / 180 ) * $SpliceDistance; - - $TopPlots[$Key][] = round($XPos + $XOffset); - $TopPlots[$Key][] = round($YPos + $YOffset); - - if ( $AllBlack ) - { $Rc = $this->ShadowRColor; $Gc = $this->ShadowGColor; $Bc = $this->ShadowBColor; } - else - { $Rc = $this->Palette[$Key]["R"]; $Gc = $this->Palette[$Key]["G"]; $Bc = $this->Palette[$Key]["B"]; } - - $XLineLast = ""; $YLineLast = ""; - - /* Process labels position & size */ - $Caption = ""; - if ( !($DrawLabels == PIE_NOLABEL) ) - { - $TAngle = $Angle+($Value*$SpliceRatio/2); - if ($DrawLabels == PIE_PERCENTAGE) - $Caption = (round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; - elseif ($DrawLabels == PIE_LABELS) - $Caption = $iLabels[$Key]; - elseif ($DrawLabels == PIE_PERCENTAGE_LABEL) - $Caption = $iLabels[$Key]."\r\n".(round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; - elseif ($DrawLabels == PIE_PERCENTAGE_LABEL) - $Caption = $iLabels[$Key]."\r\n".(round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; - - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Caption); - $TextWidth = $Position[2]-$Position[0]; - $TextHeight = abs($Position[1])+abs($Position[3]); - - $TX = cos(($TAngle) * 3.1418 / 180 ) * ($Radius+10+$SpliceDistance) + $XPos; - - if ( $TAngle > 0 && $TAngle < 180 ) - $TY = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+10+$SpliceDistance) + $YPos + 4; - else - $TY = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+$SpliceDistance+4) + $YPos - ($TextHeight/2); - - if ( $TAngle > 90 && $TAngle < 270 ) - $TX = $TX - $TextWidth; - - $C_TextColor = $this->AllocateColor($this->Picture,70,70,70); - imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption); - } - - /* Process pie slices */ - if ( !$AllBlack ) - $LineColor = $this->AllocateColor($this->Picture,$Rc,$Gc,$Bc); - else - $LineColor = $this->AllocateColor($this->Picture,$Rc,$Gc,$Bc); - - $XLineLast = ""; $YLineLast = ""; - for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5) - { - $PosX = cos($iAngle * 3.1418 / 180 ) * $Radius + $XPos + $XOffset; - $PosY = sin($iAngle * 3.1418 / 180 ) * $Radius + $YPos + $YOffset; - - $TopPlots[$Key][] = round($PosX); $TopPlots[$Key][] = round($PosY); - - if ( $iAngle == $Angle || $iAngle == $Angle+$Value*$SpliceRatio || $iAngle +.5 > $Angle+$Value*$SpliceRatio) - $this->drawLine($XPos+$XOffset,$YPos+$YOffset,$PosX,$PosY,$Rc,$Gc,$Bc); - - if ( $XLineLast != "" ) - $this->drawLine($XLineLast,$YLineLast,$PosX,$PosY,$Rc,$Gc,$Bc); - - $XLineLast = $PosX; $YLineLast = $PosY; - } - - $TopPlots[$Key][] = round($XPos + $XOffset); $TopPlots[$Key][] = round($YPos + $YOffset); - - $Angle = $iAngle; - } - $PolyPlots = $TopPlots; - - /* Draw Top polygons */ - foreach ($PolyPlots as $Key => $Value) - { - if ( !$AllBlack ) - $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]); - else - $C_GraphLo = $this->AllocateColor($this->Picture,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor); - - imagefilledpolygon($this->Picture,$PolyPlots[$Key],(count($PolyPlots[$Key])+1)/2,$C_GraphLo); - } - $this->ShadowActive = $ShadowStatus; - } - - /* This function draw a pseudo-3D pie chart */ - function drawPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$EnhanceColors=TRUE,$Skew=60,$SpliceHeight=20,$SpliceDistance=0,$Decimals=0) - { - /* Validate the Data and DataDescription array */ - $this->validateDataDescription("drawPieGraph",$DataDescription,FALSE); - $this->validateData("drawPieGraph",$Data); - - /* Determine pie sum */ - $Series = 0; $PieSum = 0; $rPieSum = 0; - foreach ( $DataDescription["Values"] as $Key2 => $ColName ) - { - if ( $ColName != $DataDescription["Position"] ) - { - $Series++; - foreach ( $Data as $Key => $Values ) - if ( isset($Data[$Key][$ColName])) - { - if ( $Data[$Key][$ColName] == 0 ) - { $iValues[] = 0; $rValues[] = 0; $iLabels[] = $Data[$Key][$DataDescription["Position"]]; } - // Removed : $PieSum++; $rValues[] = 1; - else - { $PieSum += $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]]; $rValues[] = $Data[$Key][$ColName]; $rPieSum += $Data[$Key][$ColName];} - } - } - } - - /* Validate serie */ - if ( $Series != 1 ) - RaiseFatal("Pie chart can only accept one serie of data."); - - $SpliceDistanceRatio = $SpliceDistance; - $SkewHeight = ($Radius * $Skew) / 100; - $SpliceRatio = (360 - $SpliceDistanceRatio * count($iValues) ) / $PieSum; - $SplicePercent = 100 / $PieSum; - $rSplicePercent = 100 / $rPieSum; - - /* Calculate all polygons */ - $Angle = 0; $CDev = 5; - $TopPlots = ""; $BotPlots = ""; - $aTopPlots = ""; $aBotPlots = ""; - foreach($iValues as $Key => $Value) - { - $XCenterPos = cos(($Angle-$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $XPos; - $YCenterPos = sin(($Angle-$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $YPos; - $XCenterPos2 = cos(($Angle+$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $XPos; - $YCenterPos2 = sin(($Angle+$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $YPos; - - $TopPlots[$Key][] = round($XCenterPos); $BotPlots[$Key][] = round($XCenterPos); - $TopPlots[$Key][] = round($YCenterPos); $BotPlots[$Key][] = round($YCenterPos + $SpliceHeight); - $aTopPlots[$Key][] = $XCenterPos; $aBotPlots[$Key][] = $XCenterPos; - $aTopPlots[$Key][] = $YCenterPos; $aBotPlots[$Key][] = $YCenterPos + $SpliceHeight; - - /* Process labels position & size */ - $Caption = ""; - if ( !($DrawLabels == PIE_NOLABEL) ) - { - $TAngle = $Angle+($Value*$SpliceRatio/2); - if ($DrawLabels == PIE_PERCENTAGE) - $Caption = (round($rValues[$Key] * pow(10,$Decimals) * $rSplicePercent)/pow(10,$Decimals))."%"; - elseif ($DrawLabels == PIE_LABELS) - $Caption = $iLabels[$Key]; - elseif ($DrawLabels == PIE_PERCENTAGE_LABEL) - $Caption = $iLabels[$Key]."\r\n".(round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; - - $Position = imageftbbox($this->FontSize,0,$this->FontName,$Caption); - $TextWidth = $Position[2]-$Position[0]; - $TextHeight = abs($Position[1])+abs($Position[3]); - - $TX = cos(($TAngle) * 3.1418 / 180 ) * ($Radius + 10)+ $XPos; - - if ( $TAngle > 0 && $TAngle < 180 ) - $TY = sin(($TAngle) * 3.1418 / 180 ) * ($SkewHeight + 10) + $YPos + $SpliceHeight + 4; - else - $TY = sin(($TAngle) * 3.1418 / 180 ) * ($SkewHeight + 4) + $YPos - ($TextHeight/2); - - if ( $TAngle > 90 && $TAngle < 270 ) - $TX = $TX - $TextWidth; - - $C_TextColor = $this->AllocateColor($this->Picture,70,70,70); - imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption); - } - - /* Process pie slices */ - for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5) - { - $TopX = cos($iAngle * 3.1418 / 180 ) * $Radius + $XPos; - $TopY = sin($iAngle * 3.1418 / 180 ) * $SkewHeight + $YPos; - - $TopPlots[$Key][] = round($TopX); $BotPlots[$Key][] = round($TopX); - $TopPlots[$Key][] = round($TopY); $BotPlots[$Key][] = round($TopY + $SpliceHeight); - $aTopPlots[$Key][] = $TopX; $aBotPlots[$Key][] = $TopX; - $aTopPlots[$Key][] = $TopY; $aBotPlots[$Key][] = $TopY + $SpliceHeight; - } - - $TopPlots[$Key][] = round($XCenterPos2); $BotPlots[$Key][] = round($XCenterPos2); - $TopPlots[$Key][] = round($YCenterPos2); $BotPlots[$Key][] = round($YCenterPos2 + $SpliceHeight); - $aTopPlots[$Key][] = $XCenterPos2; $aBotPlots[$Key][] = $XCenterPos2; - $aTopPlots[$Key][] = $YCenterPos2; $aBotPlots[$Key][] = $YCenterPos2 + $SpliceHeight; - - $Angle = $iAngle + $SpliceDistanceRatio; - } - - /* Draw Bottom polygons */ - foreach($iValues as $Key => $Value) - { - $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"],-20); - imagefilledpolygon($this->Picture,$BotPlots[$Key],(count($BotPlots[$Key])+1)/2,$C_GraphLo); - - if ( $EnhanceColors ) { $En = -10; } else { $En = 0; } - - for($j=0;$j<=count($aBotPlots[$Key])-4;$j=$j+2) - $this->drawLine($aBotPlots[$Key][$j],$aBotPlots[$Key][$j+1],$aBotPlots[$Key][$j+2],$aBotPlots[$Key][$j+3],$this->Palette[$Key]["R"]+$En,$this->Palette[$Key]["G"]+$En,$this->Palette[$Key]["B"]+$En); - } - - /* Draw pie layers */ - if ( $EnhanceColors ) { $ColorRatio = 30 / $SpliceHeight; } else { $ColorRatio = 25 / $SpliceHeight; } - for($i=$SpliceHeight-1;$i>=1;$i--) - { - foreach($iValues as $Key => $Value) - { - $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"],-10); - $Plots = ""; $Plot = 0; - foreach($TopPlots[$Key] as $Key2 => $Value2) - { - $Plot++; - if ( $Plot % 2 == 1 ) - $Plots[] = $Value2; - else - $Plots[] = $Value2+$i; - } - imagefilledpolygon($this->Picture,$Plots,(count($Plots)+1)/2,$C_GraphLo); - - $Index = count($Plots); - if ($EnhanceColors ) {$ColorFactor = -20 + ($SpliceHeight - $i) * $ColorRatio; } else { $ColorFactor = 0; } - - $this->drawAntialiasPixel($Plots[0],$Plots[1],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor); - $this->drawAntialiasPixel($Plots[2],$Plots[3],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor); - $this->drawAntialiasPixel($Plots[$Index-4],$Plots[$Index-3],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor); - } - } - - if ( $this->BuildMap ) - { - // Add points to Image Map. - foreach ($TopPlots as $key => $PointArr) - { - $serieName = $Data[$key][$DataDescription['Values'][1]]; - $serieValue = $Data[$key][$DataDescription['Values'][0]]; - - // last point of the arc - $lastX = $PointArr[count($PointArr)-4]; - $lastY = $PointArr[count($PointArr)-3]; - - // the point at the middle - $middleX = $PointArr[0]; - $middleY = $PointArr[1]; - - // first point in the arc - $firstX = $PointArr[2]; - $firstY = $PointArr[3]; - - // point on the first third of the arc - $firstThird = count($PointArr)/3; - $firstThirdX = $PointArr[$firstThird + ($firstThird % 2)]; - $firstThirdY = $PointArr[$firstThird + ($firstThird % 2)+1]; - - // point on the second third of the arc - $secondThird = count($PointArr)/3*2; - $secondThirdX = $PointArr[$secondThird + ($secondThird % 2)]; - $secondThirdY = $PointArr[$secondThird + ($secondThird % 2)+1]; - - // Will create three polygons for every piece of the pie. In such way - // no polygon will be concave. JS only works with convex polygons. - $poly = array( - array($middleX,$middleY), - array($firstX,$firstY), - array($firstThirdX,$firstThirdY), - ); - $this->addPolyToImageMap($poly,$serieName,$serieValue,"Pie"); - - $poly = array( - array($middleX,$middleY), - array($firstThirdX,$firstThirdY), - array($secondThirdX,$secondThirdY), - ); - $this->addPolyToImageMap($poly,$serieName,$serieValue,"Pie"); - - $poly = array( - array($middleX,$middleY), - array($secondThirdX,$secondThirdY), - array($lastX,$lastY), - ); - $this->addPolyToImageMap($poly,$serieName,$serieValue,"Pie"); - } - } - - /* Draw Top polygons */ - for($Key=count($iValues)-1;$Key>=0;$Key--) - { - $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]); - imagefilledpolygon($this->Picture,$TopPlots[$Key],(count($TopPlots[$Key])+1)/2,$C_GraphLo); - - if ( $EnhanceColors ) { $En = 10; } else { $En = 0; } - for($j=0;$j<=count($aTopPlots[$Key])-4;$j=$j+2) - $this->drawLine($aTopPlots[$Key][$j],$aTopPlots[$Key][$j+1],$aTopPlots[$Key][$j+2],$aTopPlots[$Key][$j+3],$this->Palette[$Key]["R"]+$En,$this->Palette[$Key]["G"]+$En,$this->Palette[$Key]["B"]+$En); - } - } - - /* This function can be used to set the background color */ - function drawBackground($R,$G,$B) - { - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $C_Background = $this->AllocateColor($this->Picture,$R,$G,$B); - imagefilledrectangle($this->Picture,0,0,$this->XSize,$this->YSize,$C_Background); - } - - /* This function can be used to set the background color */ - function drawGraphAreaGradient($R,$G,$B,$Decay,$Target=TARGET_GRAPHAREA) - { - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - if ( $Target == TARGET_GRAPHAREA ) { $X1 = $this->GArea_X1+1; $X2 = $this->GArea_X2-1; $Y1 = $this->GArea_Y1+1; $Y2 = $this->GArea_Y2; } - if ( $Target == TARGET_BACKGROUND ) { $X1 = 0; $X2 = $this->XSize; $Y1 = 0; $Y2 = $this->YSize; } - - /* Positive gradient */ - if ( $Decay > 0 ) - { - $YStep = ($Y2 - $Y1 - 2) / $Decay; - for($i=0;$i<=$Decay;$i++) - { - $R-=1;$G-=1;$B-=1; - $Yi1 = $Y1 + ( $i * $YStep ); - $Yi2 = ceil( $Yi1 + ( $i * $YStep ) + $YStep ); - if ( $Yi2 >= $Yi2 ) { $Yi2 = $Y2-1; } - - $C_Background = $this->AllocateColor($this->Picture,$R,$G,$B); - imagefilledrectangle($this->Picture,$X1,$Yi1,$X2,$Yi2,$C_Background); - } - } - - /* Negative gradient */ - if ( $Decay < 0 ) - { - $YStep = ($Y2 - $Y1 - 2) / -$Decay; - $Yi1 = $Y1; $Yi2 = $Y1+$YStep; - for($i=-$Decay;$i>=0;$i--) - { - $R+=1;$G+=1;$B+=1; - $C_Background = $this->AllocateColor($this->Picture,$R,$G,$B); - imagefilledrectangle($this->Picture,$X1,$Yi1,$X2,$Yi2,$C_Background); - - $Yi1+= $YStep; - $Yi2+= $YStep; - if ( $Yi2 >= $Yi2 ) { $Yi2 = $Y2-1; } - } - } - } - - /* This function create a rectangle with antialias */ - function drawRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B) - { - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $C_Rectangle = $this->AllocateColor($this->Picture,$R,$G,$B); - - $X1=$X1-.2;$Y1=$Y1-.2; - $X2=$X2+.2;$Y2=$Y2+.2; - $this->drawLine($X1,$Y1,$X2,$Y1,$R,$G,$B); - $this->drawLine($X2,$Y1,$X2,$Y2,$R,$G,$B); - $this->drawLine($X2,$Y2,$X1,$Y2,$R,$G,$B); - $this->drawLine($X1,$Y2,$X1,$Y1,$R,$G,$B); - } - - /* This function create a filled rectangle with antialias */ - function drawFilledRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B,$DrawBorder=TRUE,$Alpha=100,$NoFallBack=FALSE) - { - if ( $X2 < $X1 ) { list($X1, $X2) = array($X2, $X1); } - if ( $Y2 < $Y1 ) { list($Y1, $Y2) = array($Y2, $Y1); } - - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - if ( $Alpha == 100 ) - { - /* Process shadows */ - if ( $this->ShadowActive && !$NoFallBack ) - { - $this->drawFilledRectangle($X1+$this->ShadowXDistance,$Y1+$this->ShadowYDistance,$X2+$this->ShadowXDistance,$Y2+$this->ShadowYDistance,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor,FALSE,$this->ShadowAlpha,TRUE); - if ( $this->ShadowBlur != 0 ) - { - $AlphaDecay = ($this->ShadowAlpha / $this->ShadowBlur); - - for($i=1; $i<=$this->ShadowBlur; $i++) - $this->drawFilledRectangle($X1+$this->ShadowXDistance-$i/2,$Y1+$this->ShadowYDistance-$i/2,$X2+$this->ShadowXDistance-$i/2,$Y2+$this->ShadowYDistance-$i/2,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor,FALSE,$this->ShadowAlpha-$AlphaDecay*$i,TRUE); - for($i=1; $i<=$this->ShadowBlur; $i++) - $this->drawFilledRectangle($X1+$this->ShadowXDistance+$i/2,$Y1+$this->ShadowYDistance+$i/2,$X2+$this->ShadowXDistance+$i/2,$Y2+$this->ShadowYDistance+$i/2,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor,FALSE,$this->ShadowAlpha-$AlphaDecay*$i,TRUE); - } - } - - $C_Rectangle = $this->AllocateColor($this->Picture,$R,$G,$B); - imagefilledrectangle($this->Picture,round($X1),round($Y1),round($X2),round($Y2),$C_Rectangle); - } - else - { - $LayerWidth = abs($X2-$X1)+2; - $LayerHeight = abs($Y2-$Y1)+2; - - $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); - $C_White = $this->AllocateColor($this->Layers[0],255,255,255); - imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); - imagecolortransparent($this->Layers[0],$C_White); - - $C_Rectangle = $this->AllocateColor($this->Layers[0],$R,$G,$B); - imagefilledrectangle($this->Layers[0],round(1),round(1),round($LayerWidth-1),round($LayerHeight-1),$C_Rectangle); - - imagecopymerge($this->Picture,$this->Layers[0],round(min($X1,$X2)-1),round(min($Y1,$Y2)-1),0,0,$LayerWidth,$LayerHeight,$Alpha); - imagedestroy($this->Layers[0]); - } - - if ( $DrawBorder ) - { - $ShadowSettings = $this->ShadowActive; $this->ShadowActive = FALSE; - $this->drawRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B); - $this->ShadowActive = $ShadowSettings; - } - } - - /* This function create a rectangle with rounded corners and antialias */ - function drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B) - { - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $C_Rectangle = $this->AllocateColor($this->Picture,$R,$G,$B); - - $Step = 90 / ((3.1418 * $Radius)/2); - - for($i=0;$i<=90;$i=$i+$Step) - { - $X = cos(($i+180)*3.1418/180) * $Radius + $X1 + $Radius; - $Y = sin(($i+180)*3.1418/180) * $Radius + $Y1 + $Radius; - $this->drawAntialiasPixel($X,$Y,$R,$G,$B); - - $X = cos(($i-90)*3.1418/180) * $Radius + $X2 - $Radius; - $Y = sin(($i-90)*3.1418/180) * $Radius + $Y1 + $Radius; - $this->drawAntialiasPixel($X,$Y,$R,$G,$B); - - $X = cos(($i)*3.1418/180) * $Radius + $X2 - $Radius; - $Y = sin(($i)*3.1418/180) * $Radius + $Y2 - $Radius; - $this->drawAntialiasPixel($X,$Y,$R,$G,$B); - - $X = cos(($i+90)*3.1418/180) * $Radius + $X1 + $Radius; - $Y = sin(($i+90)*3.1418/180) * $Radius + $Y2 - $Radius; - $this->drawAntialiasPixel($X,$Y,$R,$G,$B); - } - - $X1=$X1-.2;$Y1=$Y1-.2; - $X2=$X2+.2;$Y2=$Y2+.2; - $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$R,$G,$B); - $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$R,$G,$B); - $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$R,$G,$B); - $this->drawLine($X1,$Y2-$Radius,$X1,$Y1+$Radius,$R,$G,$B); - } - - /* This function create a filled rectangle with rounded corners and antialias */ - function drawFilledRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B) - { - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $C_Rectangle = $this->AllocateColor($this->Picture,$R,$G,$B); - - $Step = 90 / ((3.1418 * $Radius)/2); - - for($i=0;$i<=90;$i=$i+$Step) - { - $Xi1 = cos(($i+180)*3.1418/180) * $Radius + $X1 + $Radius; - $Yi1 = sin(($i+180)*3.1418/180) * $Radius + $Y1 + $Radius; - - $Xi2 = cos(($i-90)*3.1418/180) * $Radius + $X2 - $Radius; - $Yi2 = sin(($i-90)*3.1418/180) * $Radius + $Y1 + $Radius; - - $Xi3 = cos(($i)*3.1418/180) * $Radius + $X2 - $Radius; - $Yi3 = sin(($i)*3.1418/180) * $Radius + $Y2 - $Radius; - - $Xi4 = cos(($i+90)*3.1418/180) * $Radius + $X1 + $Radius; - $Yi4 = sin(($i+90)*3.1418/180) * $Radius + $Y2 - $Radius; - - imageline($this->Picture,$Xi1,$Yi1,$X1+$Radius,$Yi1,$C_Rectangle); - imageline($this->Picture,$X2-$Radius,$Yi2,$Xi2,$Yi2,$C_Rectangle); - imageline($this->Picture,$X2-$Radius,$Yi3,$Xi3,$Yi3,$C_Rectangle); - imageline($this->Picture,$Xi4,$Yi4,$X1+$Radius,$Yi4,$C_Rectangle); - - $this->drawAntialiasPixel($Xi1,$Yi1,$R,$G,$B); - $this->drawAntialiasPixel($Xi2,$Yi2,$R,$G,$B); - $this->drawAntialiasPixel($Xi3,$Yi3,$R,$G,$B); - $this->drawAntialiasPixel($Xi4,$Yi4,$R,$G,$B); - } - - imagefilledrectangle($this->Picture,$X1,$Y1+$Radius,$X2,$Y2-$Radius,$C_Rectangle); - imagefilledrectangle($this->Picture,$X1+$Radius,$Y1,$X2-$Radius,$Y2,$C_Rectangle); - - $X1=$X1-.2;$Y1=$Y1-.2; - $X2=$X2+.2;$Y2=$Y2+.2; - $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$R,$G,$B); - $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$R,$G,$B); - $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$R,$G,$B); - $this->drawLine($X1,$Y2-$Radius,$X1,$Y1+$Radius,$R,$G,$B); - } - - /* This function create a circle with antialias */ - function drawCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0) - { - if ( $Width == 0 ) { $Width = $Height; } - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $C_Circle = $this->AllocateColor($this->Picture,$R,$G,$B); - $Step = 360 / (2 * 3.1418 * max($Width,$Height)); - - for($i=0;$i<=360;$i=$i+$Step) - { - $X = cos($i*3.1418/180) * $Height + $Xc; - $Y = sin($i*3.1418/180) * $Width + $Yc; - $this->drawAntialiasPixel($X,$Y,$R,$G,$B); - } - } - - /* This function create a filled circle/ellipse with antialias */ - function drawFilledCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0) - { - if ( $Width == 0 ) { $Width = $Height; } - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $C_Circle = $this->AllocateColor($this->Picture,$R,$G,$B); - $Step = 360 / (2 * 3.1418 * max($Width,$Height)); - - for($i=90;$i<=270;$i=$i+$Step) - { - $X1 = cos($i*3.1418/180) * $Height + $Xc; - $Y1 = sin($i*3.1418/180) * $Width + $Yc; - $X2 = cos((180-$i)*3.1418/180) * $Height + $Xc; - $Y2 = sin((180-$i)*3.1418/180) * $Width + $Yc; - - $this->drawAntialiasPixel($X1-1,$Y1-1,$R,$G,$B); - $this->drawAntialiasPixel($X2-1,$Y2-1,$R,$G,$B); - - if ( ($Y1-1) > $Yc - max($Width,$Height) ) - imageline($this->Picture,$X1,$Y1-1,$X2-1,$Y2-1,$C_Circle); - } - } - - /* This function will draw a filled ellipse */ - function drawEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B) - { $this->drawCircle($Xc,$Yc,$Height,$R,$G,$B,$Width); } - - /* This function will draw an ellipse */ - function drawFilledEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B) - { $this->drawFilledCircle($Xc,$Yc,$Height,$R,$G,$B,$Width); } - - /* This function create a line with antialias */ - function drawLine($X1,$Y1,$X2,$Y2,$R,$G,$B,$GraphFunction=FALSE) - { - if ( $this->LineDotSize > 1 ) { $this->drawDottedLine($X1,$Y1,$X2,$Y2,$this->LineDotSize,$R,$G,$B,$GraphFunction); return(0); } - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $Distance = sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1)); - if ( $Distance == 0 ) - return(-1); - $XStep = ($X2-$X1) / $Distance; - $YStep = ($Y2-$Y1) / $Distance; - - for($i=0;$i<=$Distance;$i++) - { - $X = $i * $XStep + $X1; - $Y = $i * $YStep + $Y1; - - if ( ($X >= $this->GArea_X1 && $X <= $this->GArea_X2 && $Y >= $this->GArea_Y1 && $Y <= $this->GArea_Y2) || !$GraphFunction ) - { - if ( $this->LineWidth == 1 ) - $this->drawAntialiasPixel($X,$Y,$R,$G,$B); - else - { - $StartOffset = -($this->LineWidth/2); $EndOffset = ($this->LineWidth/2); - for($j=$StartOffset;$j<=$EndOffset;$j++) - $this->drawAntialiasPixel($X+$j,$Y+$j,$R,$G,$B); - } - } - } - } - - /* This function create a line with antialias */ - function drawDottedLine($X1,$Y1,$X2,$Y2,$DotSize,$R,$G,$B,$GraphFunction=FALSE) - { - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $Distance = sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1)); - - $XStep = ($X2-$X1) / $Distance; - $YStep = ($Y2-$Y1) / $Distance; - - $DotIndex = 0; - for($i=0;$i<=$Distance;$i++) - { - $X = $i * $XStep + $X1; - $Y = $i * $YStep + $Y1; - - if ( $DotIndex <= $DotSize) - { - if ( ($X >= $this->GArea_X1 && $X <= $this->GArea_X2 && $Y >= $this->GArea_Y1 && $Y <= $this->GArea_Y2) || !$GraphFunction ) - { - if ( $this->LineWidth == 1 ) - $this->drawAntialiasPixel($X,$Y,$R,$G,$B); - else - { - $StartOffset = -($this->LineWidth/2); $EndOffset = ($this->LineWidth/2); - for($j=$StartOffset;$j<=$EndOffset;$j++) - $this->drawAntialiasPixel($X+$j,$Y+$j,$R,$G,$B); - } - } - } - - $DotIndex++; - if ( $DotIndex == $DotSize * 2 ) - $DotIndex = 0; - } - } - - /* Load a PNG file and draw it over the chart */ - function drawFromPNG($FileName,$X,$Y,$Alpha=100) - { $this->drawFromPicture(1,$FileName,$X,$Y,$Alpha); } - - /* Load a GIF file and draw it over the chart */ - function drawFromGIF($FileName,$X,$Y,$Alpha=100) - { $this->drawFromPicture(2,$FileName,$X,$Y,$Alpha); } - - /* Load a JPEG file and draw it over the chart */ - function drawFromJPG($FileName,$X,$Y,$Alpha=100) - { $this->drawFromPicture(3,$FileName,$X,$Y,$Alpha); } - - /* Generic loader function for external pictures */ - function drawFromPicture($PicType,$FileName,$X,$Y,$Alpha=100) - { - if ( file_exists($FileName)) - { - $Infos = getimagesize($FileName); - $Width = $Infos[0]; - $Height = $Infos[1]; - if ( $PicType == 1 ) { $Raster = imagecreatefrompng($FileName); } - if ( $PicType == 2 ) { $Raster = imagecreatefromgif($FileName); } - if ( $PicType == 3 ) { $Raster = imagecreatefromjpeg($FileName); } - - imagecopymerge($this->Picture,$Raster,$X,$Y,0,0,$Width,$Height,$Alpha); - imagedestroy($Raster); - } - } - - /* Draw an alpha pixel */ - function drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B) - { - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - if ( $X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize ) - return(-1); - - $RGB2 = imagecolorat($this->Picture, $X, $Y); - $R2 = ($RGB2 >> 16) & 0xFF; - $G2 = ($RGB2 >> 8) & 0xFF; - $B2 = $RGB2 & 0xFF; - - $iAlpha = (100 - $Alpha)/100; - $Alpha = $Alpha / 100; - - $Ra = floor($R*$Alpha+$R2*$iAlpha); - $Ga = floor($G*$Alpha+$G2*$iAlpha); - $Ba = floor($B*$Alpha+$B2*$iAlpha); - - $C_Aliased = $this->AllocateColor($this->Picture,$Ra,$Ga,$Ba); - imagesetpixel($this->Picture,$X,$Y,$C_Aliased); - } - - /* Color helper */ - function AllocateColor($Picture,$R,$G,$B,$Factor=0) - { - $R = $R + $Factor; - $G = $G + $Factor; - $B = $B + $Factor; - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - return(imagecolorallocate($Picture,$R,$G,$B)); - } - - /* Add a border to the picture */ - function addBorder($Size=3,$R=0,$G=0,$B=0) - { - $Width = $this->XSize+2*$Size; - $Height = $this->YSize+2*$Size; - - $Resampled = imagecreatetruecolor($Width,$Height); - $C_Background = $this->AllocateColor($Resampled,$R,$G,$B); - imagefilledrectangle($Resampled,0,0,$Width,$Height,$C_Background); - - imagecopy($Resampled,$this->Picture,$Size,$Size,0,0,$this->XSize,$this->YSize); - imagedestroy($this->Picture); - - $this->XSize = $Width; - $this->YSize = $Height; - - $this->Picture = imagecreatetruecolor($this->XSize,$this->YSize); - $C_White = $this->AllocateColor($this->Picture,255,255,255); - imagefilledrectangle($this->Picture,0,0,$this->XSize,$this->YSize,$C_White); - imagecolortransparent($this->Picture,$C_White); - imagecopy($this->Picture,$Resampled,0,0,0,0,$this->XSize,$this->YSize); - } - - /* Render the current picture to a file */ - function Render($FileName) - { - if ( $this->ErrorReporting ) - $this->printErrors($this->ErrorInterface); - - /* Save image map if requested */ - if ( $this->BuildMap ) - $this->SaveImageMap(); - - imagepng($this->Picture,$FileName); - } - - /* Render the current picture to STDOUT */ - function Stroke() - { - if ( $this->ErrorReporting ) - $this->printErrors("GD"); - - /* Save image map if requested */ - if ( $this->BuildMap ) - $this->SaveImageMap(); - - header('Content-type: image/png'); - imagepng($this->Picture); - } - - /* Private functions for internal processing */ - function drawAntialiasPixel($X,$Y,$R,$G,$B,$Alpha=100,$NoFallBack=FALSE) - { - /* Process shadows */ - if ( $this->ShadowActive && !$NoFallBack ) - { - $this->drawAntialiasPixel($X+$this->ShadowXDistance,$Y+$this->ShadowYDistance,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor,$this->ShadowAlpha,TRUE); - if ( $this->ShadowBlur != 0 ) - { - $AlphaDecay = ($this->ShadowAlpha / $this->ShadowBlur); - - for($i=1; $i<=$this->ShadowBlur; $i++) - $this->drawAntialiasPixel($X+$this->ShadowXDistance-$i/2,$Y+$this->ShadowYDistance-$i/2,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor,$this->ShadowAlpha-$AlphaDecay*$i,TRUE); - for($i=1; $i<=$this->ShadowBlur; $i++) - $this->drawAntialiasPixel($X+$this->ShadowXDistance+$i/2,$Y+$this->ShadowYDistance+$i/2,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor,$this->ShadowAlpha-$AlphaDecay*$i,TRUE); - } - } - - if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } - if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } - if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } - - $Plot = ""; - $Xi = floor($X); - $Yi = floor($Y); - - if ( $Xi == $X && $Yi == $Y) - { - if ( $Alpha == 100 ) - { - $C_Aliased = $this->AllocateColor($this->Picture,$R,$G,$B); - imagesetpixel($this->Picture,$X,$Y,$C_Aliased); - } - else - $this->drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B); - } - else - { - $Alpha1 = (((1 - ($X - floor($X))) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha; - if ( $Alpha1 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi,$Alpha1,$R,$G,$B); } - - $Alpha2 = ((($X - floor($X)) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha; - if ( $Alpha2 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi,$Alpha2,$R,$G,$B); } - - $Alpha3 = (((1 - ($X - floor($X))) * ($Y - floor($Y)) * 100) / 100) * $Alpha; - if ( $Alpha3 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi+1,$Alpha3,$R,$G,$B); } - - $Alpha4 = ((($X - floor($X)) * ($Y - floor($Y)) * 100) / 100) * $Alpha; - if ( $Alpha4 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi+1,$Alpha4,$R,$G,$B); } - } - } - - /* Validate data contained in the description array */ - function validateDataDescription($FunctionName,&$DataDescription,$DescriptionRequired=TRUE) - { - if (!isset($DataDescription["Position"])) - { - $this->Errors[] = "[Warning] ".$FunctionName." - Y Labels are not set."; - $DataDescription["Position"] = "Name"; - } - - if ( $DescriptionRequired ) - { - if (!isset($DataDescription["Description"])) - { - $this->Errors[] = "[Warning] ".$FunctionName." - Series descriptions are not set."; - foreach($DataDescription["Values"] as $key => $Value) - { - $DataDescription["Description"][$Value] = $Value; - } - } - - if (count($DataDescription["Description"]) < count($DataDescription["Values"])) - { - $this->Errors[] = "[Warning] ".$FunctionName." - Some series descriptions are not set."; - foreach($DataDescription["Values"] as $key => $Value) - { - if ( !isset($DataDescription["Description"][$Value])) - $DataDescription["Description"][$Value] = $Value; - } - } - } - } - - /* Validate data contained in the data array */ - function validateData($FunctionName,&$Data) - { - $DataSummary = array(); - - foreach($Data as $key => $Values) - { - foreach($Values as $key2 => $Value) - { - if (!isset($DataSummary[$key2])) - $DataSummary[$key2] = 1; - else - $DataSummary[$key2]++; - } - } - - if ( max($DataSummary) == 0 ) - $this->Errors[] = "[Warning] ".$FunctionName." - No data set."; - - foreach($DataSummary as $key => $Value) - { - if ($Value < max($DataSummary)) - { - $this->Errors[] = "[Warning] ".$FunctionName." - Missing data in serie ".$key."."; - } - } - } - - /* Print all error messages on the CLI or graphically */ - function printErrors($Mode="CLI") - { - if (count($this->Errors) == 0) - return(0); - - if ( $Mode == "CLI" ) - { - foreach($this->Errors as $key => $Value) - echo $Value."\r\n"; - } - elseif ( $Mode == "GD" ) - { - $this->setLineStyle($Width=1); - $MaxWidth = 0; - foreach($this->Errors as $key => $Value) - { - $Position = imageftbbox($this->ErrorFontSize,0,$this->ErrorFontName,$Value); - $TextWidth = $Position[2]-$Position[0]; - if ( $TextWidth > $MaxWidth ) { $MaxWidth = $TextWidth; } - } - $this->drawFilledRoundedRectangle($this->XSize-($MaxWidth+20),$this->YSize-(20+(($this->ErrorFontSize+4)*count($this->Errors))),$this->XSize-10,$this->YSize-10,6,233,185,185); - $this->drawRoundedRectangle($this->XSize-($MaxWidth+20),$this->YSize-(20+(($this->ErrorFontSize+4)*count($this->Errors))),$this->XSize-10,$this->YSize-10,6,193,145,145); - - $C_TextColor = $this->AllocateColor($this->Picture,133,85,85); - $YPos = $this->YSize - (18 + (count($this->Errors)-1) * ($this->ErrorFontSize + 4)); - foreach($this->Errors as $key => $Value) - { - imagettftext($this->Picture,$this->ErrorFontSize,0,$this->XSize-($MaxWidth+15),$YPos,$C_TextColor,$this->ErrorFontName,$Value); - $YPos = $YPos + ($this->ErrorFontSize + 4); - } - } - } - - /* Activate the image map creation process */ - function setImageMap($Mode=TRUE,$GraphID="MyGraph") - { - $this->BuildMap = $Mode; - $this->MapID = $GraphID; - } - - /* Add a box into the image map */ - function addToImageMap($X1,$Y1,$X2,$Y2,$SerieName,$Value,$CallerFunction) - { - $poly = array(array($X1,$Y1),array($X2,$Y1),array($X2,$Y2),array($X1,$Y2)); - $this->addPolyToImageMap($poly,$SerieName,$Value,$CallerFunction); - } - - function addPolyToImageMap($poly,$SerieName,$Value,$CallerFunction) - { - if ( $this->MapFunction == NULL || $this->MapFunction == $CallerFunction) - { - $this->ImageMap[] = array( - 'n' => (string)$SerieName, - 'v' => (string)$Value, - 'p' => $poly, - ); - $this->MapFunction = $CallerFunction; - } - } - - /* Draw image map to the current chart image */ - function debugImageMap() - { - foreach ($this->ImageMap as $polygon) - { - $points = array(); - foreach ($polygon['p'] as $point) - { - $points[] = $point[0]; - $points[] = $point[1]; - } - - $color = $this->AllocateColor($this->Picture,rand(0,255),rand(0,255),rand(0,255)); - imagefilledpolygon($this->Picture,$points,(count($points)+1)/2,$color); - } - - } - - /* Get the current image map */ - function getImageMap() - { - return $this->ImageMap; - } - - /* Load and cleanup the image map from disk */ - function getSavedImageMap($MapName,$Flush=TRUE) - { - /* Strip HTML query strings */ - $Values = $this->tmpFolder.$MapName; - $Value = split("\?",$Values); - $FileName = $Value[0]; - - if ( file_exists($FileName) ) - { - $Handle = fopen($FileName, "r"); - $MapContent = fread($Handle, filesize($FileName)); - fclose($Handle); - echo $MapContent; - - if ( $Flush ) - unlink($FileName); - - exit(); - } - else - { - header("HTTP/1.0 404 Not Found"); - exit(); - } - } - - /* Save the image map to the disk */ - function SaveImageMap() - { - if ( !$this->BuildMap ) { return(-1); } - - if ( $this->ImageMap == NULL ) - { - $this->Errors[] = "[Warning] SaveImageMap - Image map is empty."; - return(-1); - } - - $Handle = fopen($this->tmpFolder.$this->MapID, 'w'); - if ( !$Handle ) - { - $this->Errors[] = "[Warning] SaveImageMap - Cannot save the image map."; - return(-1); - } - else - { - fwrite($Handle, serialize($this->getImageMap())); - } - fclose ($Handle); - } - - /* Convert seconds to a time format string */ - function ToTime($Value) - { - $Hour = floor($Value/3600); - $Minute = floor(($Value - $Hour*3600)/60); - $Second = floor($Value - $Hour*3600 - $Minute*60); - - if (strlen($Hour) == 1 ) { $Hour = "0".$Hour; } - if (strlen($Minute) == 1 ) { $Minute = "0".$Minute; } - if (strlen($Second) == 1 ) { $Second = "0".$Second; } - - return($Hour.":".$Minute.":".$Second); - } - - /* Convert to metric system */ - function ToMetric($Value) - { - $Go = floor($Value/1000000000); - $Mo = floor(($Value - $Go*1000000000)/1000000); - $Ko = floor(($Value - $Go*1000000000 - $Mo*1000000)/1000); - $o = floor($Value - $Go*1000000000 - $Mo*1000000 - $Ko*1000); - - if ($Go != 0) { return($Go.".".$Mo."g"); } - if ($Mo != 0) { return($Mo.".".$ko."m"); } - if ($Ko != 0) { return($Ko.".".$o)."k"; } - return($o); - } - - /* Convert to curency */ - function ToCurrency($Value) - { - $Go = floor($Value/1000000000); - $Mo = floor(($Value - $Go*1000000000)/1000000); - $Ko = floor(($Value - $Go*1000000000 - $Mo*1000000)/1000); - $o = floor($Value - $Go*1000000000 - $Mo*1000000 - $Ko*1000); - - if ( strlen($o) == 1 ) { $o = "00".$o; } - if ( strlen($o) == 2 ) { $o = "0".$o; } - - $ResultString = $o; - if ( $Ko != 0 ) { $ResultString = $Ko.".".$ResultString; } - if ( $Mo != 0 ) { $ResultString = $Mo.".".$ResultString; } - if ( $Go != 0 ) { $ResultString = $Go.".".$ResultString; } - - $ResultString = $this->Currency.$ResultString; - return($ResultString); - } - - /* Set date format for axis labels */ - function setDateFormat($Format) - { - $this->DateFormat = $Format; - } - - /* Convert TS to a date format string */ - function ToDate($Value) - { - return(date($this->DateFormat,$Value)); - } - - /* Check if a number is a full integer (for scaling) */ - function isRealInt($Value) - { - if ($Value == floor($Value)) - return(TRUE); - return(FALSE); - } - } - - function RaiseFatal($Message) - { - echo "[FATAL] ".$Message."\r\n"; - exit(); - } -?> \ No newline at end of file diff --git a/libraries/chart/pChart/pData.class b/libraries/chart/pChart/pData.class deleted file mode 100644 index 1c4a301f0f..0000000000 --- a/libraries/chart/pChart/pData.class +++ /dev/null @@ -1,260 +0,0 @@ -. - - Class initialisation : - pData() - Data populating methods : - ImportFromCSV($FileName,$Delimiter=",",$DataColumns=-1,$HasHeader=FALSE,$DataName=-1) - AddPoint($Value,$Serie="Serie1",$Description="") - Series manipulation methods : - AddSerie($SerieName="Serie1") - AddAllSeries() - RemoveSerie($SerieName="Serie1") - SetAbsciseLabelSerie($SerieName = "Name") - SetSerieName($Name,$SerieName="Serie1") - + SetSerieSymbol($Name,$Symbol) - SetXAxisName($Name="X Axis") - SetYAxisName($Name="Y Axis") - SetXAxisFormat($Format="number") - SetYAxisFormat($Format="number") - SetXAxisUnit($Unit="") - SetYAxisUnit($Unit="") - removeSerieName($SerieName) - removeAllSeries() - Data retrieval methods : - GetData() - GetDataDescription() - */ - - /* pData class definition */ - class pData - { - var $Data; - var $DataDescription; - - function pData() - { - $this->Data = array(); - $this->DataDescription = ""; - $this->DataDescription["Position"] = "Name"; - $this->DataDescription["Format"]["X"] = "number"; - $this->DataDescription["Format"]["Y"] = "number"; - $this->DataDescription["Unit"]["X"] = NULL; - $this->DataDescription["Unit"]["Y"] = NULL; - } - - function ImportFromCSV($FileName,$Delimiter=",",$DataColumns=-1,$HasHeader=FALSE,$DataName=-1) - { - $handle = @fopen($FileName,"r"); - if ($handle) - { - $HeaderParsed = FALSE; - while (!feof($handle)) - { - $buffer = fgets($handle, 4096); - $buffer = str_replace(chr(10),"",$buffer); - $buffer = str_replace(chr(13),"",$buffer); - $Values = split($Delimiter,$buffer); - - if ( $buffer != "" ) - { - if ( $HasHeader == TRUE && $HeaderParsed == FALSE ) - { - if ( $DataColumns == -1 ) - { - $ID = 1; - foreach($Values as $key => $Value) - { $this->SetSerieName($Value,"Serie".$ID); $ID++; } - } - else - { - $SerieName = ""; - - foreach($DataColumns as $key => $Value) - $this->SetSerieName($Values[$Value],"Serie".$Value); - } - $HeaderParsed = TRUE; - } - else - { - if ( $DataColumns == -1 ) - { - $ID = 1; - foreach($Values as $key => $Value) - { $this->AddPoint(intval($Value),"Serie".$ID); $ID++; } - } - else - { - $SerieName = ""; - if ( $DataName != -1 ) - $SerieName = $Values[$DataName]; - - foreach($DataColumns as $key => $Value) - $this->AddPoint($Values[$Value],"Serie".$Value,$SerieName); - } - } - } - } - fclose($handle); - } - } - - function AddPoint($Value,$Serie="Serie1",$Description="") - { - if (is_array($Value) && count($Value) == 1) - $Value = array_pop($Value); - - $ID = 0; - for($i=0;$i<=count($this->Data);$i++) - { if(isset($this->Data[$i][$Serie])) { $ID = $i+1; } } - - if ( count($Value) == 1 ) - { - $this->Data[$ID][$Serie] = $Value; - if ( $Description != "" ) - $this->Data[$ID]["Name"] = $Description; - elseif (!isset($this->Data[$ID]["Name"])) - $this->Data[$ID]["Name"] = $ID; - } - else - { - foreach($Value as $key => $Val) - { - $this->Data[$ID][$Serie] = $Val; - if (!isset($this->Data[$ID]["Name"])) - $this->Data[$ID]["Name"] = $ID; - $ID++; - } - } - } - - function AddSerie($SerieName="Serie1") - { - if ( !isset($this->DataDescription["Values"]) ) - { - $this->DataDescription["Values"][] = $SerieName; - } - else - { - $Found = FALSE; - foreach($this->DataDescription["Values"] as $key => $Value ) - if ( $Value == $SerieName ) { $Found = TRUE; } - - if ( !$Found ) - $this->DataDescription["Values"][] = $SerieName; - } - } - - function AddAllSeries() - { - unset($this->DataDescription["Values"]); - - if ( isset($this->Data[0]) ) - { - foreach($this->Data[0] as $Key => $Value) - { - if ( $Key != "Name" ) - $this->DataDescription["Values"][] = $Key; - } - } - } - - function RemoveSerie($SerieName="Serie1") - { - if ( !isset($this->DataDescription["Values"]) ) - return(0); - - $Found = FALSE; - foreach($this->DataDescription["Values"] as $key => $Value ) - { - if ( $Value == $SerieName ) - unset($this->DataDescription["Values"][$key]); - } - } - - function SetAbsciseLabelSerie($SerieName = "Name") - { - $this->DataDescription["Position"] = $SerieName; - } - - function SetSerieName($Name,$SerieName="Serie1") - { - $this->DataDescription["Description"][$SerieName] = $Name; - } - - function SetXAxisName($Name="X Axis") - { - $this->DataDescription["Axis"]["X"] = $Name; - } - - function SetYAxisName($Name="Y Axis") - { - $this->DataDescription["Axis"]["Y"] = $Name; - } - - function SetXAxisFormat($Format="number") - { - $this->DataDescription["Format"]["X"] = $Format; - } - - function SetYAxisFormat($Format="number") - { - $this->DataDescription["Format"]["Y"] = $Format; - } - - function SetXAxisUnit($Unit="") - { - $this->DataDescription["Unit"]["X"] = $Unit; - } - - function SetYAxisUnit($Unit="") - { - $this->DataDescription["Unit"]["Y"] = $Unit; - } - - function SetSerieSymbol($Name,$Symbol) - { - $this->DataDescription["Symbol"][$Name] = $Symbol; - } - - function removeSerieName($SerieName) - { - if ( isset($this->DataDescription["Description"][$SerieName]) ) - unset($this->DataDescription["Description"][$SerieName]); - } - - function removeAllSeries() - { - foreach($this->DataDescription["Values"] as $Key => $Value) - unset($this->DataDescription["Values"][$Key]); - } - - function GetData() - { - return($this->Data); - } - - function GetDataDescription() - { - return($this->DataDescription); - } - } -?> \ No newline at end of file diff --git a/libraries/chart/pma_chart.php b/libraries/chart/pma_chart.php deleted file mode 100644 index 670880417f..0000000000 --- a/libraries/chart/pma_chart.php +++ /dev/null @@ -1,183 +0,0 @@ - 'Chart', - - // The style of the chart title. - 'titleColor' => '#FAFAFA', - - // Colors for the different slices in the pie chart. - 'colors' => array( - '#BCE02E', - '#E0642E', - '#E0D62E', - '#2E97E0', - '#B02EE0', - '#E02E75', - '#5CE02E', - '#E0B02E', - '#000000', - '#0022E0', - '#726CB1', - '#481A36', - '#BAC658', - '#127224', - '#825119', - '#238C74', - '#4C489B', - '#87C9BF', - ), - - // Chart background color. - 'bgColor' => '#84AD83', - - // The width of the chart. - 'width' => 520, - - // The height of the chart. - 'height' => 325, - - // Default X Axis label. If empty, label will be taken from the data. - 'xLabel' => '', - - // Default Y Axis label. If empty, label will be taken from the data. - 'yLabel' => '', - ); - - /** - * @var array Options that the user has specified - */ - private $userSpecifiedSettings = null; - - /** - * @var array Error codes will be stored here - */ - protected $errors = array(); - - /** - * Store user specified options - * @param array $options users specified options - */ - function __construct($options = null) - { - $this->userSpecifiedSettings = $options; - } - - /** - * All the variable initialization has to be done here. - */ - protected function init() - { - $this->handleOptions(); - } - - /** - * A function which handles passed parameters. Useful if desired - * chart needs to be a little bit different from the default one. - */ - private function handleOptions() - { - if (is_null($this->userSpecifiedSettings)) { - return; - } - - $this->settings = array_merge($this->settings, $this->userSpecifiedSettings); - } - - protected function getTitleText() - { - return $this->settings['titleText']; - } - - protected function getTitleColor($component) - { - return $this->hexStrToDecComp($this->settings['titleColor'], $component); - } - - protected function getColors() - { - return $this->settings['colors']; - } - - protected function getWidth() - { - return $this->settings['width']; - } - - protected function getHeight() - { - return $this->settings['height']; - } - - protected function getBgColor($component) - { - return $this->hexStrToDecComp($this->settings['bgColor'], $component); - } - - protected function setXLabel($label) - { - $this->settings['xLabel'] = $label; - } - - protected function getXLabel() - { - return $this->settings['xLabel']; - } - - protected function setYLabel($label) - { - $this->settings['yLabel'] = $label; - } - - protected function getYLabel() - { - return $this->settings['yLabel']; - } - - public function getSettings() - { - return $this->settings; - } - - public function getErrors() - { - return $this->errors; - } - - /** - * Get one the dec color component from the hex color string - * @param string $colorString color string, i.e. #5F22A99 - * @param int $component color component to get, i.e. 0 gets red. - */ - protected function hexStrToDecComp($colorString, $component) - { - return hexdec(substr($colorString, ($component * 2) + 1, 2)); - } -} - -?> diff --git a/libraries/chart/pma_pchart_chart.php b/libraries/chart/pma_pchart_chart.php deleted file mode 100644 index e68a9b31c5..0000000000 --- a/libraries/chart/pma_pchart_chart.php +++ /dev/null @@ -1,402 +0,0 @@ -data = $data; - - $this->settings['fontPath'] = './libraries/chart/pChart/fonts/'; - - $this->settings['scale'] = SCALE_ADDALLSTART0; - - $this->settings['labelHeight'] = 20; - - $this->settings['fontSize'] = 8; - - $this->settings['continuous'] = 'off'; - - // as in CSS (top, right, bottom, left) - $this->setAreaMargins(array(20, 20, 40, 60)); - - // Get color settings from theme - $this->settings = array_merge($this->settings,$GLOBALS['cfg']['chartColor']); - } - - protected function init() - { - parent::init(); - - // create pChart object - $this->chart = new pChart($this->getWidth(), $this->getHeight()); - - // create pData object - $this->dataSet = new pData; - - $this->chart->reportWarnings('GD'); - $this->chart->ErrorFontName = $this->getFontPath().'DejaVuSans.ttf'; - - // initialize colors - foreach ($this->getColors() as $key => $color) { - $this->chart->setColorPalette( - $key, - hexdec(substr($color, 1, 2)), - hexdec(substr($color, 3, 2)), - hexdec(substr($color, 5, 2)) - ); - } - - $this->chart->setFontProperties($this->getFontPath().'DejaVuSans.ttf', $this->getFontSize()); - - $this->chart->setImageMap(true, 'mapid'); - } - - /** - * data is put to the $dataSet object according to what type chart is - * @abstract - */ - abstract protected function prepareDataSet(); - - /** - * all components of the chart are drawn - */ - protected function prepareChart() - { - $this->drawBackground(); - $this->drawChart(); - } - - /** - * draws the background - */ - protected function drawBackground() - { - $this->drawCommon(); - $this->drawTitle(); - $this->setGraphAreaDimensions(); - $this->drawGraphArea(); - } - - /** - * draws the part of the background which is common to most of the charts - */ - protected function drawCommon() - { - $this->chart->drawGraphAreaGradient( - $this->getBgColor(RED), - $this->getBgColor(GREEN), - $this->getBgColor(BLUE), - // With a gradientIntensity of 0 the background does't draw, oddly - ($this->settings['gradientIntensity']==0)?1:$this->settings['gradientIntensity'],TARGET_BACKGROUND); - - if(is_string($this->settings['border'])) - $this->chart->addBorder(1,$this->getBorderColor(RED),$this->getBorderColor(GREEN),$this->getBorderColor(BLUE)); - } - - /** - * draws the chart title - */ - protected function drawTitle() - { - // Draw the title - $this->chart->drawTextBox( - 0, - 0, - $this->getWidth(), - $this->getLabelHeight(), - $this->getTitleText(), - 0, - $this->getTitleColor(RED), - $this->getTitleColor(GREEN), - $this->getTitleColor(BLUE), - ALIGN_CENTER, - false, - $this->getTitleBgColor(RED), - $this->getTitleBgColor(GREEN), - $this->getTitleBgColor(BLUE) - ); - } - - /** - * calculates and sets the dimensions that will be used for the actual graph - */ - protected function setGraphAreaDimensions() - { - $this->chart->setGraphArea( - $this->getAreaMargin(LEFT), - $this->getLabelHeight() + $this->getAreaMargin(TOP), - $this->getWidth() - $this->getAreaMargin(RIGHT), - $this->getHeight() - $this->getAreaMargin(BOTTOM) - ); - } - - /** - * draws graph area (the area where all bars, lines, points will be seen) - */ - protected function drawGraphArea() - { - $this->chart->drawGraphArea( - $this->getGraphAreaColor(RED), - $this->getGraphAreaColor(GREEN), - $this->getGraphAreaColor(BLUE), - false - ); - $this->chart->drawScale( - $this->dataSet->GetData(), - $this->dataSet->GetDataDescription(), - $this->getScale(), - $this->getScaleColor(RED), - $this->getScaleColor(GREEN), - $this->getScaleColor(BLUE), - true,0,2,true - ); - - if($this->settings['gradientIntensity']>0) - $this->chart->drawGraphAreaGradient( - $this->getGraphAreaGradientColor(RED), - $this->getGraphAreaGradientColor(GREEN), - $this->getGraphAreaGradientColor(BLUE), - $this->settings['gradientIntensity'] - ); - else - $this->chart->drawGraphArea( - $this->getGraphAreaGradientColor(RED), - $this->getGraphAreaGradientColor(GREEN), - $this->getGraphAreaGradientColor(BLUE) - ); - - $this->chart->drawGrid( - 4, - true, - $this->getGridColor(RED), - $this->getGridColor(GREEN), - $this->getGridColor(BLUE), - 20 - ); - } - - /** - * draws the chart - * @abstract - */ - protected abstract function drawChart(); - - /** - * Renders the chart, base 64 encodes the output and puts it into - * array partsEncoded. - * - * Parameter can be used to slice the chart vertically into parts. This - * solves an issue where some browsers (IE8) accept base64 images only up - * to some length. - * - * @param integer $parts number of parts to render. - * Default value 1 means that all the - * chart will be in one piece. - */ - protected function render($parts = 1) - { - $fullWidth = 0; - - for ($i = 0; $i < $parts; $i++) { - - // slicing is vertical so part height is the full height - $partHeight = $this->chart->YSize; - - // there will be some rounding erros, will compensate later - $partWidth = round($this->chart->XSize / $parts); - $fullWidth += $partWidth; - $partX = $partWidth * $i; - - if ($i == $parts - 1) { - // if this is the last part, compensate for the rounding errors - $partWidth += $this->chart->XSize - $fullWidth; - } - - // get a part from the full chart image - $part = imagecreatetruecolor($partWidth, $partHeight); - imagecopy($part, $this->chart->Picture, 0, 0, $partX, 0, $partWidth, $partHeight); - - // render part and save it to variable - ob_start(); - imagepng($part, NULL, 9, PNG_ALL_FILTERS); - $output = ob_get_contents(); - ob_end_clean(); - - // base64 encode the current part - $partEncoded = base64_encode($output); - $this->partsEncoded[$i] = $partEncoded; - } - } - - /** - * get the HTML and JS code for the configured chart - * @return string HTML and JS code for the chart - */ - public function toString() - { - if (!function_exists('gd_info')) { - array_push($this->errors, ERR_NO_GD); - return ''; - } - - $this->init(); - $this->prepareDataSet(); - $this->prepareChart(); - - //$this->chart->debugImageMap(); - //$this->chart->printErrors('GD'); - - // check if a user wanted a chart in one part - if ($this->isContinuous()) { - $this->render(1); - } - else { - $this->render(20); - } - - $returnData = '
    '; - foreach ($this->partsEncoded as $part) { - $returnData .= ''; - } - $returnData .= '
    '; - - // add tooltips only if json is available - if (function_exists('json_encode')) { - $returnData .= ' - - '; - } - else { - array_push($this->errors, ERR_NO_JSON); - } - - return $returnData; - } - - protected function getLabelHeight() - { - return $this->settings['labelHeight']; - } - - protected function setAreaMargins($areaMargins) - { - $this->settings['areaMargins'] = $areaMargins; - } - - protected function getAreaMargin($side) - { - return $this->settings['areaMargins'][$side]; - } - - protected function getFontPath() - { - return $this->settings['fontPath']; - } - - protected function getScale() - { - return $this->settings['scale']; - } - - protected function getFontSize() - { - return $this->settings['fontSize']; - } - - protected function isContinuous() - { - return $this->settings['continuous'] == 'on'; - } - - protected function getImageMap() - { - return $this->chart->getImageMap(); - } - - protected function getGraphAreaColor($component) - { - return $this->hexStrToDecComp($this->settings['graphAreaColor'], $component); - } - - protected function getGraphAreaGradientColor($component) - { - return $this->hexStrToDecComp($this->settings['graphAreaGradientColor'], $component); - } - - protected function getGridColor($component) - { - return $this->hexStrToDecComp($this->settings['gridColor'], $component); - } - - protected function getScaleColor($component) - { - return $this->hexStrToDecComp($this->settings['scaleColor'], $component); - } - - protected function getTitleBgColor($component) - { - return $this->hexStrToDecComp($this->settings['titleBgColor'], $component); - } - - protected function getBorderColor($component) - { - return $this->hexStrToDecComp($this->settings['border'], $component); - } -} - -?> diff --git a/libraries/chart/pma_pchart_multi.php b/libraries/chart/pma_pchart_multi.php deleted file mode 100644 index 171cc50fe5..0000000000 --- a/libraries/chart/pma_pchart_multi.php +++ /dev/null @@ -1,117 +0,0 @@ -setLegendMargins(array(20, 10, 0, 0)); - } - - /** - * data set preparation for multi serie graphs - */ - protected function prepareDataSet() - { - $values = array_values($this->data); - $keys = array_keys($this->data); - - // Dataset definition - $this->dataSet->AddPoint($values[0], "Keys"); - - $i = 0; - foreach ($values[1] as $seriesName => $seriesData) { - $this->dataSet->AddPoint($seriesData, "Values".$i); - $this->dataSet->SetSerieName($seriesName, "Values".$i); - $i++; - } - $this->dataSet->AddAllSeries(); - - $this->dataSet->RemoveSerie("Keys"); - $this->dataSet->SetAbsciseLabelSerie("Keys"); - - $xLabel = $this->getXLabel(); - if (empty($xLabel)) { - $this->setXLabel($keys[0]); - } - $yLabel = $this->getYLabel(); - if (empty($yLabel)) { - $this->setYLabel($keys[1]); - } - - $this->dataSet->SetXAxisName($this->getXLabel()); - $this->dataSet->SetYAxisName($this->getYLabel()); - } - - /** - * set graph area dimensions with respect to legend box size - */ - protected function setGraphAreaDimensions() - { - $this->chart->setGraphArea( - $this->getAreaMargin(LEFT), - $this->getLabelHeight() + $this->getAreaMargin(TOP), - $this->getWidth() - $this->getAreaMargin(RIGHT) - $this->getLegendBoxWidth() - $this->getLegendMargin(LEFT) - $this->getLegendMargin(RIGHT), - $this->getHeight() - $this->getAreaMargin(BOTTOM) - ); - } - - /** - * multi serie charts need a legend. draw it - */ - protected function drawChart() - { - $this->drawLegend(); - } - - /** - * draws a legend - */ - protected function drawLegend() - { - // Draw the legend - $this->chart->drawLegend( - $this->getWidth() - $this->getLegendMargin(RIGHT) - $this->getLegendBoxWidth(), - $this->getLabelHeight() + $this->getLegendMargin(TOP), - $this->dataSet->GetDataDescription(), - 250,250,250,50,50,50 - ); - } - - protected function setLegendMargins($legendMargins) - { - if (!isset($this->settings['legendMargins'])) { - $this->settings['legendMargins'] = $legendMargins; - } - } - - protected function getLegendMargin($side) - { - return $this->settings['legendMargins'][$side]; - } - - protected function getLegendBoxWidth() - { - $legendSize = $this->chart->getLegendBoxSize($this->dataSet->GetDataDescription()); - return $legendSize[0]; - } -} - -?> diff --git a/libraries/chart/pma_pchart_multi_bar.php b/libraries/chart/pma_pchart_multi_bar.php deleted file mode 100644 index 619ef1a170..0000000000 --- a/libraries/chart/pma_pchart_multi_bar.php +++ /dev/null @@ -1,37 +0,0 @@ -settings['scale'] = SCALE_NORMAL; - } - - /** - * draws multi bar graph - */ - protected function drawChart() - { - parent::drawChart(); - - // Draw the bar chart - $this->chart->drawBarGraph($this->dataSet->GetData(), $this->dataSet->GetDataDescription(), 70); - } -} - -?> diff --git a/libraries/chart/pma_pchart_multi_line.php b/libraries/chart/pma_pchart_multi_line.php deleted file mode 100644 index 502f386c0a..0000000000 --- a/libraries/chart/pma_pchart_multi_line.php +++ /dev/null @@ -1,38 +0,0 @@ -settings['scale'] = SCALE_NORMAL; - } - - /** - * draws multi line chart - */ - protected function drawChart() - { - parent::drawChart(); - - // Draw the bar chart - $this->chart->drawLineGraph($this->dataSet->GetData(), $this->dataSet->GetDataDescription()); - $this->chart->drawPlotGraph($this->dataSet->GetData(), $this->dataSet->GetDataDescription(), 3, 1, -1, -1, -1, true); - } -} - -?> diff --git a/libraries/chart/pma_pchart_multi_radar.php b/libraries/chart/pma_pchart_multi_radar.php deleted file mode 100644 index 8c32cb33be..0000000000 --- a/libraries/chart/pma_pchart_multi_radar.php +++ /dev/null @@ -1,107 +0,0 @@ -normalizeValues(); - } - - /** - * Get the largest value from the data and normalize all the other values. - */ - private function normalizeValues() - { - $maxValue = 0; - $keys = array_keys($this->data); - $valueKey = $keys[1]; - - // get the max value - foreach ($this->data[$valueKey] as $values) { - if (max($values) > $maxValue) { - $maxValue = max($values); - } - } - - // normalize all the values according to the max value - foreach ($this->data[$valueKey] as &$values) { - foreach ($values as &$value) { - $value = $value / $maxValue * 10; - } - } - } - - /** - * graph area for the radar chart does not include grid lines - */ - protected function drawGraphArea() - { - $this->chart->drawGraphArea( - $this->getGraphAreaColor(RED), - $this->getGraphAreaColor(GREEN), - $this->getGraphAreaColor(BLUE), - false - ); - - if($this->settings['gradientIntensity']>0) - $this->chart->drawGraphAreaGradient( - $this->getGraphAreaGradientColor(RED), - $this->getGraphAreaGradientColor(GREEN), - $this->getGraphAreaGradientColor(BLUE), - $this->settings['gradientIntensity'] - ); - else - $this->chart->drawGraphArea( - $this->getGraphAreaGradientColor(RED), - $this->getGraphAreaGradientColor(GREEN), - $this->getGraphAreaGradientColor(BLUE) - ); - } - - /** - * draw multi radar chart - */ - protected function drawChart() - { - parent::drawChart(); - - // when drawing radar graph we can specify the border from the top of - // graph area. We want border to be dynamic, so that either the top - // or the side of the radar is some distance away from the top or the - // side of the graph area. - $areaWidth = $this->chart->GArea_X2 - $this->chart->GArea_X1; - $areaHeight = $this->chart->GArea_Y2 - $this->chart->GArea_Y1; - - if ($areaHeight > $areaWidth) { - $borderOffset = ($areaHeight - $areaWidth) / 2; - } - else { - $borderOffset = 0; - } - - // the least ammount that radar is away from the graph area side. - $borderOffset += 40; - - // Draw the radar chart - $this->chart->drawRadarAxis($this->dataSet->GetData(), $this->dataSet->GetDataDescription(), true, $borderOffset, - 120, 120, 120, 230, 230, 230, -1, 2); - $this->chart->drawFilledRadar($this->dataSet->GetData(), $this->dataSet->GetDataDescription(), 50, $borderOffset); - } -} - -?> diff --git a/libraries/chart/pma_pchart_pie.php b/libraries/chart/pma_pchart_pie.php deleted file mode 100644 index 56148e072b..0000000000 --- a/libraries/chart/pma_pchart_pie.php +++ /dev/null @@ -1,109 +0,0 @@ -setAreaMargins(array(20, 10, 20, 20)); - } - - /** - * prepare data set for the pie chart - */ - protected function prepareDataSet() - { - // Dataset definition - $this->dataSet->AddPoint(array_values($this->data), "Values"); - $this->dataSet->AddPoint(array_keys($this->data), "Keys"); - $this->dataSet->AddAllSeries(); - $this->dataSet->SetAbsciseLabelSerie("Keys"); - } - - /** - * graph area for the pie chart does not include grid lines - */ - protected function drawGraphArea() - { - $this->chart->drawGraphArea( - $this->getGraphAreaColor(RED), - $this->getGraphAreaColor(GREEN), - $this->getGraphAreaColor(BLUE), - false - ); - - if($this->settings['gradientIntensity']>0) - $this->chart->drawGraphAreaGradient( - $this->getGraphAreaGradientColor(RED), - $this->getGraphAreaGradientColor(GREEN), - $this->getGraphAreaGradientColor(BLUE), - $this->settings['gradientIntensity'] - ); - else - $this->chart->drawGraphArea( - $this->getGraphAreaGradientColor(RED), - $this->getGraphAreaGradientColor(GREEN), - $this->getGraphAreaGradientColor(BLUE) - ); - - } - - /** - * draw the pie chart - */ - protected function drawChart() - { - parent::drawChart(); - - // draw pie chart in the middle of graph area - $middleX = ($this->chart->GArea_X1 + $this->chart->GArea_X2) / 2; - $middleY = ($this->chart->GArea_Y1 + $this->chart->GArea_Y2) / 2; - - $this->chart->drawPieGraph( - $this->dataSet->GetData(), - $this->dataSet->GetDataDescription(), - $middleX, - // pie graph is skewed. Upper part is shorter than the - // lower part. This is why we set an offset to the - // Y middle coordiantes. - $middleY - 15, - 120, PIE_PERCENTAGE, false, 60, 30, 10, 1); - } - - /** - * draw legend for the pie chart - */ - protected function drawLegend() - { - $this->chart->drawPieLegend( - $this->getWidth() - $this->getLegendMargin(RIGHT) - $this->getLegendBoxWidth(), - $this->getLabelHeight() + $this->getLegendMargin(TOP), - $this->dataSet->GetData(), - $this->dataSet->GetDataDescription(), - 250, 250, 250); - } - - protected function getLegendBoxWidth() - { - $legendSize = $this->chart->getPieLegendBoxSize($this->dataSet->GetData()); - return $legendSize[0]; - } -} - -?> diff --git a/libraries/chart/pma_pchart_single.php b/libraries/chart/pma_pchart_single.php deleted file mode 100644 index 6579a9bc3d..0000000000 --- a/libraries/chart/pma_pchart_single.php +++ /dev/null @@ -1,56 +0,0 @@ -data); - $keys = array_keys($this->data); - - // Dataset definition - $this->dataSet->AddPoint($values[0], "Values"); - $this->dataSet->AddPoint($values[1], "Keys"); - - //$this->dataSet->AddAllSeries(); - $this->dataSet->AddSerie("Values"); - - $this->dataSet->SetAbsciseLabelSerie("Keys"); - - $yLabel = $this->getYLabel(); - if (empty($yLabel)) { - $this->setYLabel($keys[0]); - } - $xLabel = $this->getXLabel(); - if (empty($xLabel)) { - $this->setXLabel($keys[1]); - } - - $this->dataSet->SetXAxisName($this->getXLabel()); - $this->dataSet->SetYAxisName($this->getYLabel()); - $this->dataSet->SetSerieName($this->getYLabel(), "Values"); - } -} - -?> diff --git a/libraries/chart/pma_pchart_single_bar.php b/libraries/chart/pma_pchart_single_bar.php deleted file mode 100644 index e6519700a6..0000000000 --- a/libraries/chart/pma_pchart_single_bar.php +++ /dev/null @@ -1,34 +0,0 @@ -chart->drawStackedBarGraph($this->dataSet->GetData(), $this->dataSet->GetDataDescription(), 70); - } -} - -?> diff --git a/libraries/chart/pma_pchart_single_line.php b/libraries/chart/pma_pchart_single_line.php deleted file mode 100644 index 3003581f8a..0000000000 --- a/libraries/chart/pma_pchart_single_line.php +++ /dev/null @@ -1,34 +0,0 @@ -chart->drawLineGraph($this->dataSet->GetData(), $this->dataSet->GetDataDescription()); - $this->chart->drawPlotGraph($this->dataSet->GetData(), $this->dataSet->GetDataDescription(), 3, 1, -1, -1, -1, true); - } -} - -?> diff --git a/libraries/chart/pma_pchart_single_radar.php b/libraries/chart/pma_pchart_single_radar.php deleted file mode 100644 index 0c5d9ec32d..0000000000 --- a/libraries/chart/pma_pchart_single_radar.php +++ /dev/null @@ -1,96 +0,0 @@ -normalizeValues(); - } - - /** - * Get the largest value from the data and normalize all the other values. - */ - private function normalizeValues() - { - $maxValue = 0; - $keys = array_keys($this->data); - $valueKey = $keys[0]; - $maxValue = max($this->data[$valueKey]); - - foreach ($this->data[$valueKey] as &$value) { - $value = $value / $maxValue * 10; - } - } - - /** - * graph area for the radar chart does not include grid lines - */ - protected function drawGraphArea() - { - $this->chart->drawGraphArea( - $this->getGraphAreaColor(RED), - $this->getGraphAreaColor(GREEN), - $this->getGraphAreaColor(BLUE), - false - ); - - if($this->settings['gradientIntensity']>0) - $this->chart->drawGraphAreaGradient( - $this->getGraphAreaGradientColor(RED), - $this->getGraphAreaGradientColor(GREEN), - $this->getGraphAreaGradientColor(BLUE), - $this->settings['gradientIntensity'] - ); - else - $this->chart->drawGraphArea( - $this->getGraphAreaGradientColor(RED), - $this->getGraphAreaGradientColor(GREEN), - $this->getGraphAreaGradientColor(BLUE) - ); - - } - - /** - * draws the radar chart - */ - protected function drawChart() - { - // when drawing radar graph we can specify the border from the top of - // graph area. We want border to be dynamic, so that either the top - // or the side of the radar is some distance away from the top or the - // side of the graph area. - $areaWidth = $this->chart->GArea_X2 - $this->chart->GArea_X1; - $areaHeight = $this->chart->GArea_Y2 - $this->chart->GArea_Y1; - - if ($areaHeight > $areaWidth) { - $borderOffset = ($areaHeight - $areaWidth) / 2; - } - else { - $borderOffset = 0; - } - - // the least ammount that radar is away from the graph area side. - $borderOffset += 40; - - $this->chart->drawRadarAxis($this->dataSet->GetData(), $this->dataSet->GetDataDescription(), - true, $borderOffset, 120, 120, 120, 230, 230, 230, -1, 2); - $this->chart->drawFilledRadar($this->dataSet->GetData(), $this->dataSet->GetDataDescription(), 50, $borderOffset); - } -} - -?> diff --git a/libraries/chart/pma_pchart_stacked_bar.php b/libraries/chart/pma_pchart_stacked_bar.php deleted file mode 100644 index 0ef72ec51f..0000000000 --- a/libraries/chart/pma_pchart_stacked_bar.php +++ /dev/null @@ -1,35 +0,0 @@ -chart->drawStackedBarGraph($this->dataSet->GetData(), $this->dataSet->GetDataDescription(), 70); - } -} - -?> From ef3ac2e3dc914eaf056d5d76b1039ec3a5547c80 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Thu, 9 Jun 2011 22:11:47 +0200 Subject: [PATCH 106/206] Translation update done using Pootle. --- po/en_GB.po | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/po/en_GB.po b/po/en_GB.po index 330618afaf..b2d153d6bd 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -4,13 +4,13 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-07 12:36+0200\n" +"PO-Revision-Date: 2011-06-09 22:11+0200\n" "Last-Translator: Marc Delisle \n" "Language-Team: english-gb \n" +"Language: en_GB\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: en_GB\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Pootle 2.0.5\n" @@ -1023,10 +1023,9 @@ msgstr "The passwords aren't the same!" #: js/messages.php:54 server_privileges.php:1679 server_privileges.php:1703 #: server_privileges.php:2108 server_privileges.php:2302 -#, fuzzy #| msgid "Any user" msgid "Add user" -msgstr "Any user" +msgstr "Add user" #: js/messages.php:55 msgid "Reloading Privileges" From 6c34080a5f4d114d4a6b8955fde341574a403e65 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Thu, 9 Jun 2011 22:12:10 +0200 Subject: [PATCH 107/206] Translation update done using Pootle. --- po/en_GB.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/en_GB.po b/po/en_GB.po index b2d153d6bd..40e6e0b48f 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 22:11+0200\n" +"PO-Revision-Date: 2011-06-09 22:12+0200\n" "Last-Translator: Marc Delisle \n" "Language-Team: english-gb \n" "Language: en_GB\n" @@ -1787,10 +1787,9 @@ msgid "Wrong username/password. Access denied." msgstr "Wrong username/password. Access denied." #: libraries/auth/signon.auth.lib.php:87 -#, fuzzy #| msgid "Config authentication" msgid "Can not find signon authentication script:" -msgstr "Config authentication" +msgstr "Can not find signon authentication script:" #: libraries/auth/swekey/swekey.auth.lib.php:118 #, php-format From b48a4fbf9694a4eb83f1ceacfbe65ec5cca5ba03 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Thu, 9 Jun 2011 22:12:19 +0200 Subject: [PATCH 108/206] Translation update done using Pootle. --- po/en_GB.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/en_GB.po b/po/en_GB.po index 40e6e0b48f..0cd76f6515 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -7963,10 +7963,9 @@ msgid "wildcard" msgstr "wildcard" #: server_privileges.php:2295 -#, fuzzy #| msgid "View %s has been dropped" msgid "User has been added." -msgstr "View %s has been dropped" +msgstr "User has been added." #: server_processlist.php:29 #, php-format From d03ed4581f79a7dbe13ee9b03d594ec86a2ce467 Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Thu, 9 Jun 2011 22:12:52 +0200 Subject: [PATCH 109/206] Translation update done using Pootle. --- po/fr.po | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/po/fr.po b/po/fr.po index f4b2828e4d..e9b06bad36 100644 --- a/po/fr.po +++ b/po/fr.po @@ -4,13 +4,13 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-07 12:48+0200\n" +"PO-Revision-Date: 2011-06-09 22:12+0200\n" "Last-Translator: Marc Delisle \n" "Language-Team: french \n" +"Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Pootle 2.0.5\n" @@ -1036,10 +1036,9 @@ msgstr "Les mots de passe doivent être identiques !" #: js/messages.php:54 server_privileges.php:1679 server_privileges.php:1703 #: server_privileges.php:2108 server_privileges.php:2302 -#, fuzzy #| msgid "Any user" msgid "Add user" -msgstr "Tout utilisateur" +msgstr "Ajouter un utilisateur" #: js/messages.php:55 msgid "Reloading Privileges" From 505448c01322b620119a1552f4fad4dc620cd45c Mon Sep 17 00:00:00 2001 From: Marc Delisle Date: Thu, 9 Jun 2011 22:13:26 +0200 Subject: [PATCH 110/206] Translation update done using Pootle. --- po/fr.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/fr.po b/po/fr.po index e9b06bad36..07ca5a4127 100644 --- a/po/fr.po +++ b/po/fr.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 22:12+0200\n" +"PO-Revision-Date: 2011-06-09 22:13+0200\n" "Last-Translator: Marc Delisle \n" "Language-Team: french \n" "Language: fr\n" @@ -1804,10 +1804,9 @@ msgid "Wrong username/password. Access denied." msgstr "Erreur d'utilisateur/mot de passe. Accès refusé." #: libraries/auth/signon.auth.lib.php:87 -#, fuzzy #| msgid "Config authentication" msgid "Can not find signon authentication script:" -msgstr "Mode d'authentification « config »" +msgstr "Ne peut trouver le script d'authentification pour le mode signon:" #: libraries/auth/swekey/swekey.auth.lib.php:118 #, php-format From 7a6ad35f2fcd1989496306e18c65a73fa8243071 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 22:33:35 +0200 Subject: [PATCH 111/206] Translation update done using Pootle. --- po/sv.po | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/po/sv.po b/po/sv.po index 1d5635cd8e..c2205d75bd 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,13 +4,13 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-05-30 20:24+0200\n" +"PO-Revision-Date: 2011-06-09 22:33+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" +"Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: sv\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Pootle 2.0.5\n" @@ -1022,10 +1022,9 @@ msgstr "Lösenorden överensstämmer inte!" #: js/messages.php:54 server_privileges.php:1679 server_privileges.php:1703 #: server_privileges.php:2108 server_privileges.php:2302 -#, fuzzy #| msgid "Any user" msgid "Add user" -msgstr "Vilken användare som helst" +msgstr "Lägg till en användare" #: js/messages.php:55 msgid "Reloading Privileges" From d21ad24e331086fcec2b926dd27bd2cb1f8d1111 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 22:34:03 +0200 Subject: [PATCH 112/206] Translation update done using Pootle. --- po/sv.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/sv.po b/po/sv.po index c2205d75bd..19079657b8 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 22:33+0200\n" +"PO-Revision-Date: 2011-06-09 22:34+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -1096,10 +1096,9 @@ msgid "Create Table" msgstr "Skapa tabell" #: js/messages.php:82 -#, fuzzy #| msgid "Use Tables" msgid "Insert Table" -msgstr "Använd tabeller" +msgstr "Lägg till en tabell" #: js/messages.php:85 msgid "Searching" From 0552e3843f7738b0fa5b5407669c21f71371056b Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 22:35:30 +0200 Subject: [PATCH 113/206] Translation update done using Pootle. --- po/sv.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/sv.po b/po/sv.po index 19079657b8..287b5eec70 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 22:34+0200\n" +"PO-Revision-Date: 2011-06-09 22:35+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -1605,10 +1605,9 @@ msgstr[0] "%1$d rad infogad." msgstr[1] "%1$d rader infogade." #: libraries/RecentTable.class.php:113 -#, fuzzy #| msgid "Could not save configuration" msgid "Could not save recent table" -msgstr "Kunde inte spara konfigurationen" +msgstr "Kunde inte spara den senaste tabellen" #: libraries/RecentTable.class.php:148 #, fuzzy From 449997606f0f2bc1ce05f047fa28cdcd0457a129 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 22:37:02 +0200 Subject: [PATCH 114/206] Translation update done using Pootle. --- po/sv.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/sv.po b/po/sv.po index 287b5eec70..1ea18ae717 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 22:35+0200\n" +"PO-Revision-Date: 2011-06-09 22:37+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -1610,10 +1610,9 @@ msgid "Could not save recent table" msgstr "Kunde inte spara den senaste tabellen" #: libraries/RecentTable.class.php:148 -#, fuzzy #| msgid "Count tables" msgid "Recent tables" -msgstr "Räkna tabeller" +msgstr "De senaste tabellerna" #: libraries/RecentTable.class.php:154 #, fuzzy From 1994d15b670b60d58b679bd28753a88bdc2799f7 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 22:37:59 +0200 Subject: [PATCH 115/206] Translation update done using Pootle. --- po/sv.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/sv.po b/po/sv.po index 1ea18ae717..a8bcf43c76 100644 --- a/po/sv.po +++ b/po/sv.po @@ -1615,10 +1615,9 @@ msgid "Recent tables" msgstr "De senaste tabellerna" #: libraries/RecentTable.class.php:154 -#, fuzzy #| msgid "There are no configured servers" msgid "There are no recent tables" -msgstr "Det finns inga konfigurerade servrar" +msgstr "Det finns inga nya tabeller" #: libraries/StorageEngine.class.php:194 msgid "" From cdbf0b5780c9c5fb88aa148dde4b3588663d333c Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 22:59:03 +0200 Subject: [PATCH 116/206] Translation update done using Pootle. --- po/sv.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/sv.po b/po/sv.po index a8bcf43c76..74a9f1645d 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 22:37+0200\n" +"PO-Revision-Date: 2011-06-09 22:59+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -1661,7 +1661,7 @@ msgstr "Tabell %s har döpts om till %s" #: libraries/Table.class.php:1250 msgid "Could not save table UI preferences" -msgstr "" +msgstr "Kunde inte spara UI inställningarna för tabellen" #: libraries/Theme.class.php:160 #, php-format From 701dfb287e7cf5e100167059401577e399affa43 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:01:16 +0200 Subject: [PATCH 117/206] Translation update done using Pootle. --- po/sv.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/sv.po b/po/sv.po index 74a9f1645d..c314e75fd6 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 22:59+0200\n" +"PO-Revision-Date: 2011-06-09 23:01+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -1789,10 +1789,9 @@ msgid "Wrong username/password. Access denied." msgstr "Felaktigt användarnamn/lösenord. Åtkomst nekad." #: libraries/auth/signon.auth.lib.php:87 -#, fuzzy #| msgid "Config authentication" msgid "Can not find signon authentication script:" -msgstr "Config autentisering" +msgstr "Kan du inte hitta scriptet för iverifiering av inloggning." #: libraries/auth/swekey/swekey.auth.lib.php:118 #, php-format From 81cdc55c48940b92b3bc46fa919508621e48dd4a Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:01:49 +0200 Subject: [PATCH 118/206] Translation update done using Pootle. --- po/sv.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/sv.po b/po/sv.po index c314e75fd6..383c4a9bca 100644 --- a/po/sv.po +++ b/po/sv.po @@ -2207,7 +2207,7 @@ msgstr "Båda" #: libraries/config.values.php:47 msgid "Nowhere" -msgstr "" +msgstr "Ingenstans" #: libraries/config.values.php:47 msgid "Left" From 1db44625195b952c6fc905bb3a32f0b6450a9103 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:02:03 +0200 Subject: [PATCH 119/206] Translation update done using Pootle. --- po/sv.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/sv.po b/po/sv.po index 383c4a9bca..816bfc1b4f 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:01+0200\n" +"PO-Revision-Date: 2011-06-09 23:02+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -2211,7 +2211,7 @@ msgstr "Ingenstans" #: libraries/config.values.php:47 msgid "Left" -msgstr "" +msgstr "Vänster" #: libraries/config.values.php:47 #, fuzzy From f0bb0047fd013c40714e857f90a44939f4b35cbe Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:02:13 +0200 Subject: [PATCH 120/206] Translation update done using Pootle. --- po/sv.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/sv.po b/po/sv.po index 816bfc1b4f..20ad72fd19 100644 --- a/po/sv.po +++ b/po/sv.po @@ -2214,10 +2214,9 @@ msgid "Left" msgstr "Vänster" #: libraries/config.values.php:47 -#, fuzzy #| msgid "Height" msgid "Right" -msgstr "Höjd" +msgstr "Höger" #: libraries/config.values.php:75 msgid "Open" From 4a7653239928b970ed5231d8e08adc20f0f9c365 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:04:21 +0200 Subject: [PATCH 121/206] Translation update done using Pootle. --- po/sv.po | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/po/sv.po b/po/sv.po index 20ad72fd19..f0a2b8e320 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:02+0200\n" +"PO-Revision-Date: 2011-06-09 23:04+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -2583,6 +2583,8 @@ msgid "" "Disable the table maintenance mass operations, like optimizing or repairing " "the selected tables of a database." msgstr "" +"Inaktivera tabellen underhåll av en mängd operationer, som att optimera " +"eller reparera den valda tabeller i en databas." #: libraries/config/messages.inc.php:61 #, fuzzy From 83e68c748284dd362f4f0328b874b75beb6a5321 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:07:01 +0200 Subject: [PATCH 122/206] Translation update done using Pootle. --- po/sv.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/sv.po b/po/sv.po index f0a2b8e320..d0dd240d55 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:04+0200\n" +"PO-Revision-Date: 2011-06-09 23:07+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -2587,10 +2587,9 @@ msgstr "" "eller reparera den valda tabeller i en databas." #: libraries/config/messages.inc.php:61 -#, fuzzy #| msgid "Table maintenance" msgid "Disable multi table maintenance" -msgstr "Tabellunderhåll" +msgstr "Inaktivera underhåll av många tabeller" #: libraries/config/messages.inc.php:62 msgid "Edit SQL queries in popup window" From 0f561df611835622db68ac980a1a17e6b9685163 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:08:20 +0200 Subject: [PATCH 123/206] Translation update done using Pootle. --- po/sv.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/sv.po b/po/sv.po index d0dd240d55..160f2dce52 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:07+0200\n" +"PO-Revision-Date: 2011-06-09 23:08+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -3350,10 +3350,9 @@ msgid "Enable highlighting" msgstr "Aktivera framhävning" #: libraries/config/messages.inc.php:288 -#, fuzzy #| msgid "Maximum number of tables displayed in table list" msgid "Maximum number of recently used tables; set 0 to disable" -msgstr "Maximalt antal tabeller som visas i tabellista" +msgstr "Maximalt antal nyligen använa tabeller, ange 0 för att avaktivera" #: libraries/config/messages.inc.php:289 #, fuzzy From 6fc90101ef90fd1d5d069e8d35522b6dd7d27c94 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:09:00 +0200 Subject: [PATCH 124/206] Translation update done using Pootle. --- po/sv.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/sv.po b/po/sv.po index 160f2dce52..d98eb492b6 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:08+0200\n" +"PO-Revision-Date: 2011-06-09 23:09+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -3355,9 +3355,8 @@ msgid "Maximum number of recently used tables; set 0 to disable" msgstr "Maximalt antal nyligen använa tabeller, ange 0 för att avaktivera" #: libraries/config/messages.inc.php:289 -#, fuzzy msgid "Recently used tables" -msgstr "Nuvarande anslutning" +msgstr "Nyligen använda tabeller" #: libraries/config/messages.inc.php:290 msgid "Use less graphically intense tabs" From 50e52f40d3df3dded87580443c0093c94fc67636 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:11:41 +0200 Subject: [PATCH 125/206] Translation update done using Pootle. --- po/sv.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/sv.po b/po/sv.po index d98eb492b6..27b7ca030c 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:09+0200\n" +"PO-Revision-Date: 2011-06-09 23:11+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -3511,7 +3511,7 @@ msgstr "Dessa är redigera, infogad redigering, kopiera och ta bort länkar" #: libraries/config/messages.inc.php:320 msgid "Where to show the table row links" -msgstr "" +msgstr "Var länkarna i tabellraden visas" #: libraries/config/messages.inc.php:321 msgid "Use natural order for sorting table and database names" From 5f86388dda13a97a452133124e91556e39c504d4 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:13:54 +0200 Subject: [PATCH 126/206] Translation update done using Pootle. --- po/sv.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/sv.po b/po/sv.po index 27b7ca030c..dfad74b544 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:11+0200\n" +"PO-Revision-Date: 2011-06-09 23:13+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -3641,7 +3641,7 @@ msgstr "Omvandlingsmotor" #: libraries/config/messages.inc.php:350 msgid "When browsing tables, the sorting of each table is remembered" -msgstr "" +msgstr "Vid bläddring i tabeller, är sorteringen av varje tabell ihågkommen" #: libraries/config/messages.inc.php:351 #, fuzzy From c229c45c1225566d03caa925352e474203ef5a22 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:14:59 +0200 Subject: [PATCH 127/206] Translation update done using Pootle. --- po/sv.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/sv.po b/po/sv.po index dfad74b544..ade6036200 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:13+0200\n" +"PO-Revision-Date: 2011-06-09 23:14+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -3644,10 +3644,9 @@ msgid "When browsing tables, the sorting of each table is remembered" msgstr "Vid bläddring i tabeller, är sorteringen av varje tabell ihågkommen" #: libraries/config/messages.inc.php:351 -#, fuzzy #| msgid "Rename table to" msgid "Remember table's sorting" -msgstr "Döp om tabellen till" +msgstr "Kom ihåg tabellens sortering" #: libraries/config/messages.inc.php:352 msgid "Repeat the headers every X cells, [kbd]0[/kbd] deactivates this feature" From 4f894fdea3151a5ff9ce9c1f08fc10079c90a553 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:20:23 +0200 Subject: [PATCH 128/206] Translation update done using Pootle. --- po/sv.po | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/po/sv.po b/po/sv.po index ade6036200..3aeaea2497 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:14+0200\n" +"PO-Revision-Date: 2011-06-09 23:20+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -3924,7 +3924,6 @@ msgid "Server port" msgstr "Serverport" #: libraries/config/messages.inc.php:409 -#, fuzzy #| msgid "" #| "Leave blank for no user preferences storage in database, suggested: [kbd]" #| "pma_config[/kbd]" @@ -3932,8 +3931,8 @@ msgid "" "Leave blank for no \"persistent\" recently used tables across sessions, " "suggested: [kbd]pma_recent[/kbd]" msgstr "" -"Lämna tomt för iatt inte spara användarinställningar i databasen, förslag: " -"[kbd]pma_config[/kbd]" +"Lämna tomt för iatt inte spara nyligen använda användarinställningar " +"tabeller för alla sessioner i databasen, förslag: [kbd]pma_config[/kbd]" #: libraries/config/messages.inc.php:410 #, fuzzy From 043be57506cf4cdd7cfb690e0e5b8e877969de8a Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:20:46 +0200 Subject: [PATCH 129/206] Translation update done using Pootle. --- po/sv.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/sv.po b/po/sv.po index 3aeaea2497..4d7b5dda5e 100644 --- a/po/sv.po +++ b/po/sv.po @@ -3935,9 +3935,8 @@ msgstr "" "tabeller för alla sessioner i databasen, förslag: [kbd]pma_config[/kbd]" #: libraries/config/messages.inc.php:410 -#, fuzzy msgid "Recently used table" -msgstr "Nuvarande anslutning" +msgstr "Nyligen använd tabell" #: libraries/config/messages.inc.php:411 msgid "" From 3f8e99754f8fafb161fdba13247748687c1667d1 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:23:23 +0200 Subject: [PATCH 130/206] Translation update done using Pootle. --- po/sv.po | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/po/sv.po b/po/sv.po index 4d7b5dda5e..3fe95115c1 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:20+0200\n" +"PO-Revision-Date: 2011-06-09 23:23+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -4014,7 +4014,6 @@ msgid "Display columns table" msgstr "Visa tabellkolumner" #: libraries/config/messages.inc.php:426 -#, fuzzy #| msgid "" #| "Leave blank for no user preferences storage in database, suggested: [kbd]" #| "pma_config[/kbd]" @@ -4022,8 +4021,8 @@ msgid "" "Leave blank for no \"persistent\" tables'UI preferences across sessions, " "suggested: [kbd]pma_table_uiprefs[/kbd]" msgstr "" -"Lämna tomt för iatt inte spara användarinställningar i databasen, förslag: " -"[kbd]pma_config[/kbd]" +"Lämna tomt för iatt inte spara nyligen använda användarinställningstabeller " +"för alla sessioner, förslag: [kbd]pma_config[/kbd]" #: libraries/config/messages.inc.php:427 #, fuzzy From 7222290858a0b8a2fff81a869570be42182dbd12 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:26:42 +0200 Subject: [PATCH 131/206] Translation update done using Pootle. --- po/sv.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/sv.po b/po/sv.po index 3fe95115c1..d3019811cb 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:23+0200\n" +"PO-Revision-Date: 2011-06-09 23:26+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -4025,10 +4025,9 @@ msgstr "" "för alla sessioner, förslag: [kbd]pma_config[/kbd]" #: libraries/config/messages.inc.php:427 -#, fuzzy #| msgid "User preferences storage table" msgid "UI preferences table" -msgstr "Användarinställningar lagringstabell" +msgstr "Tabell för inställningar av användargränssnittet" #: libraries/config/messages.inc.php:428 msgid "" From 2c72b8da7eb0e75711a5bb4ca8c4156370431918 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:28:03 +0200 Subject: [PATCH 132/206] Translation update done using Pootle. --- po/sv.po | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/po/sv.po b/po/sv.po index d3019811cb..332bec67d1 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:26+0200\n" +"PO-Revision-Date: 2011-06-09 23:28+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -6239,10 +6239,9 @@ msgid "SQL history" msgstr "SQL-historik" #: libraries/relation.lib.php:143 -#, fuzzy #| msgid "Persistent connections" msgid "Persistent recently used tables" -msgstr "Bestående anslutningar" +msgstr "Beständiga, nyligen använda tabeller" #: libraries/relation.lib.php:147 msgid "Persistent tables' UI preferences" From 6adf04837d3031549df7f2b3a71c7c711526f7b3 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:29:24 +0200 Subject: [PATCH 133/206] Translation update done using Pootle. --- po/sv.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/sv.po b/po/sv.po index 332bec67d1..ba71dc9111 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: phpMyAdmin 3.5.0-dev\n" "Report-Msgid-Bugs-To: phpmyadmin-devel@lists.sourceforge.net\n" "POT-Creation-Date: 2011-06-07 06:41-0400\n" -"PO-Revision-Date: 2011-06-09 23:28+0200\n" +"PO-Revision-Date: 2011-06-09 23:29+0200\n" "Last-Translator: \n" "Language-Team: swedish \n" "Language: sv\n" @@ -6245,7 +6245,7 @@ msgstr "Beständiga, nyligen använda tabeller" #: libraries/relation.lib.php:147 msgid "Persistent tables' UI preferences" -msgstr "" +msgstr "Bestående tabeller för inställninar av användargränssnittet" #: libraries/relation.lib.php:155 msgid "User preferences" From 7e809b9049e2eeff5615f1a25d156e31aa7dc0e6 Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 9 Jun 2011 23:29:52 +0200 Subject: [PATCH 134/206] Translation update done using Pootle. --- po/sv.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/po/sv.po b/po/sv.po index ba71dc9111..e23bc7d5b3 100644 --- a/po/sv.po +++ b/po/sv.po @@ -7988,10 +7988,9 @@ msgid "wildcard" msgstr "jokertecken" #: server_privileges.php:2295 -#, fuzzy #| msgid "View %s has been dropped" msgid "User has been added." -msgstr "Vyn %s har tagits bort" +msgstr "En användare har skapats." #: server_processlist.php:29 #, php-format From b3c988157206c81c1c09c6720dbe8fe2797f98c7 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Fri, 10 Jun 2011 14:23:46 +0200 Subject: [PATCH 135/206] Better realtime chart behaviour when the chart hasn't been filled with data yet --- js/functions.js | 27 ++++++++++++++++++++++----- js/server_status.js | 14 +++++++------- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/js/functions.js b/js/functions.js index 46eff423e3..f1faccb007 100644 --- a/js/functions.js +++ b/js/functions.js @@ -1413,7 +1413,7 @@ function PMA_createChart(passedSettings) { var thisChart = this; var lastValue=null, curValue=null; var numLoadedPoints=0, otherSum=0; - + var diff; // No realtime updates for graphs that are being exported, and disabled when no callback is set if(thisChart.options.chart.forExport==true || !passedSettings.realtime || !passedSettings.realtime.callback) return; @@ -1422,13 +1422,19 @@ function PMA_createChart(passedSettings) { if(chart_activeTimeouts[container]==null) return; curValue = jQuery.parseJSON(data); - if(lastValue==null) lastValue = curValue; + //if(lastValue==null) lastValue = curValue; - passedSettings.realtime.callback(thisChart,curValue,lastValue,numLoadedPoints) + if(lastValue==null) diff = curValue.x - thisChart.xAxis[0].getExtremes().max; + else diff = parseInt(curValue.x - lastValue.x); + + thisChart.xAxis[0].setExtremes(thisChart.xAxis[0].getExtremes().min+diff, thisChart.xAxis[0].getExtremes().max+diff, false); + + passedSettings.realtime.callback(thisChart,curValue,lastValue,numLoadedPoints); lastValue = curValue; numLoadedPoints++; - chart_activeTimeouts[container] = setTimeout(addnewPoint, thisChart.options.realtime.refreshRate || 5000); + chart_activeTimeouts[container] = setTimeout(addnewPoint, thisChart.options.realtime.refreshRate); + }); } @@ -1441,7 +1447,6 @@ function PMA_createChart(passedSettings) { }, xAxis: { type: 'datetime', - tickPixelInterval: 150 }, yAxis: { min: 0, @@ -1467,6 +1472,18 @@ function PMA_createChart(passedSettings) { series: [] } + /* Set/Get realtime chart default values */ + if(passedSettings.realtime) { + if(!passedSettings.realtime.refreshRate) + passedSettings.realtime.refreshRate = 4000; + + if(!passedSettings.realtime.numMaxPoints) + passedSettings.realtime.numMaxPoints = 30; + + settings.xAxis.min = new Date().getTime() - passedSettings.realtime.numMaxPoints * passedSettings.realtime.refreshRate, + settings.xAxis.max = new Date().getTime() + passedSettings.realtime.refreshRate + } + // Overwrite/Merge default settings with passedsettings $.extend(true,settings,passedSettings); diff --git a/js/server_status.js b/js/server_status.js index d2cbb6c8b6..e6b5c28103 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -46,8 +46,6 @@ $(function() { var text=''; // Holds filter text /* Chart configuration */ - // Amount of points the chart should hold - var numMaxPoints=30; // Defines what the tabs are currently displaying (realtime or data) var tabStatus = new Object(); @@ -111,12 +109,12 @@ $(function() { // ui-tabs-panel class is added by the jquery tabs feature var tab=$(this).parents('div.ui-tabs-panel'); var that = this; - + // Show ajax load icon $(this).find('img').show(); $.get($(this).attr('href'),{ajax_request:1},function(data) { - $(that).find('img').hide(); + $(that).find('img').hide(); initTab(tab,data); }); @@ -142,13 +140,14 @@ $(function() { realtime:{ url:'server_status.php?'+url_query, type: 'proc', callback: function(chartObj, curVal, lastVal,numLoadedPoints) { + if(lastVal==null) return; chartObj.series[0].addPoint( { x:curVal.x, y:curVal.y_conn-lastVal.y_conn }, - false, numLoadedPoints >= numMaxPoints + false, numLoadedPoints >= chartObj.options.realtime.numMaxPoints ); chartObj.series[1].addPoint( { x:curVal.x, y:curVal.y_proc }, - true, numLoadedPoints >= numMaxPoints + true, numLoadedPoints >= chartObj.options.realtime.numMaxPoints ); } } @@ -162,9 +161,10 @@ $(function() { realtime:{ url:'server_status.php?'+url_query, type: 'queries', callback: function(chartObj, curVal, lastVal,numLoadedPoints) { + if(lastVal==null) return; chartObj.series[0].addPoint( { x:curVal.x, y:curVal.y-lastVal.y, name:sortedQueriesPointInfo(curVal,lastVal) }, - true, numLoadedPoints >= numMaxPoints + true, numLoadedPoints >= chartObj.options.realtime.numMaxPoints ); } } From bccbff41aed68bfdabaf5578d862ba6fb2929d07 Mon Sep 17 00:00:00 2001 From: Tyron Madlener Date: Fri, 10 Jun 2011 15:17:52 +0200 Subject: [PATCH 136/206] Configurable refresh rate for real-time charts in the status page --- js/functions.js | 2 +- js/server_status.js | 16 ++++++++++++---- server_status.php | 25 +++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/js/functions.js b/js/functions.js index f1faccb007..38be6961c3 100644 --- a/js/functions.js +++ b/js/functions.js @@ -1475,7 +1475,7 @@ function PMA_createChart(passedSettings) { /* Set/Get realtime chart default values */ if(passedSettings.realtime) { if(!passedSettings.realtime.refreshRate) - passedSettings.realtime.refreshRate = 4000; + passedSettings.realtime.refreshRate = 5000; if(!passedSettings.realtime.numMaxPoints) passedSettings.realtime.numMaxPoints = 30; diff --git a/js/server_status.js b/js/server_status.js index e6b5c28103..60ae6fe1b2 100644 --- a/js/server_status.js +++ b/js/server_status.js @@ -104,8 +104,14 @@ $(function() { initTableSorter('statustabs_queries'); initTableSorter('statustabs_allvars'); + $('.statuslinks select').change(function() { + var chart=tabChart[$(this).parents('div.ui-tabs-panel').attr('id')]; + chart.options.realtime.refreshRate = 1000*parseInt(this.value); + chart.xAxis[0].setExtremes(new Date().getTime() - chart.options.realtime.numMaxPoints * chart.options.realtime.refreshRate, chart.xAxis[0].getExtremes().max, true); + }); + // Ajax refresh of variables (always the first link in each tab) - $('.statuslinks a:nth-child(1)').click(function() { + $('.statuslinks a:nth-child(2)').click(function() { // ui-tabs-panel class is added by the jquery tabs feature var tab=$(this).parents('div.ui-tabs-panel'); var that = this; @@ -124,7 +130,7 @@ $(function() { }); /** Realtime charting of variables (always the second link) **/ - $('.statuslinks a:nth-child(2)').click(function() { + $('.statuslinks a:nth-child(3)').click(function() { // ui-tabs-panel class is added by the jquery tabs feature var tab=$(this).parents('div.ui-tabs-panel'); @@ -184,7 +190,8 @@ $(function() { tabStatus[tab.attr('id')]='realtime'; tabChart[tab.attr('id')]=PMA_createChart(settings); $(this).html(PMA_messages['strStaticData']); - tab.find('.statuslinks a:nth-child(1)').hide(); + tab.find('.statuslinks a:nth-child(2)').hide(); + $('.statuslinks select').show(); } else { clearTimeout(chart_activeTimeouts[tab.attr('id')+"_chart_cnt"]); chart_activeTimeouts[tab.attr('id')+"_chart_cnt"]=null; @@ -193,7 +200,8 @@ $(function() { tabStatus[tab.attr('id')]='data'; tabChart[tab.attr('id')].destroy(); $(this).html(PMA_messages['strRealtimeChart']); - tab.find('.statuslinks a:nth-child(1)').show(); + tab.find('.statuslinks a:nth-child(2)').show(); + $('.statuslinks select').hide(); } return false; }); diff --git a/server_status.php b/server_status.php index 79ae331f7c..18d9179fe3 100644 --- a/server_status.php +++ b/server_status.php @@ -369,6 +369,19 @@ echo __('Runtime Information');

    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�dCRp=zUF}_`)_2m^bu*fSoS28eGIQ1 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�XLWN^w!@- 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