From 332e43403992cc114a21cb03aa8296a9a8da16d8 Mon Sep 17 00:00:00 2001 From: Benaka Moorthi <benaka.moorthi@gmail.com> Date: Fri, 19 Jul 2013 10:27:58 -0400 Subject: [PATCH] Refs #3942, allow server-side and JS UI code to use colors defined in CSS. Notes: - Removed colors.piwik.json loading code. No longer necessary. - UserCountryMap is the only remaining portion of Piwik that doesn't use this technique. Not yet, anyway. --- core/API/DocumentationGenerator.php | 2 +- core/AssetManager.php | 1 + core/Controller.php | 9 +- core/Plugin/MetadataLoader.php | 49 +----- core/Twig.php | 10 +- core/Visualization/Chart.php | 4 +- core/Visualization/Chart/Evolution.php | 12 +- core/Visualization/Chart/Pie.php | 4 - core/Visualization/Chart/VerticalBar.php | 5 - core/Visualization/Sparkline.php | 32 ++-- core/testMinimumPhpVersion.php | 2 +- plugins/CoreHome/CoreHome.php | 2 + .../DataTableRowAction/RowEvolution.php | 9 +- plugins/CoreHome/javascripts/color_manager.js | 132 +++++++++++++++ .../javascripts/datatable_rowactions.js | 1 + plugins/CoreHome/javascripts/jqplot.js | 126 ++++++++------- plugins/CoreHome/javascripts/sparkline.js | 39 +++-- .../CoreHome/stylesheets/color_manager.css | 3 + .../getMultiRowEvolutionPopover.twig | 7 +- .../templates/getRowEvolutionPopover.twig | 13 +- plugins/Referers/Controller.php | 2 +- .../Transitions/javascripts/transitions.js | 62 +++++--- plugins/Zeitgeist/colors.piwik.json | 3 - plugins/Zeitgeist/stylesheets/base.less | 8 +- .../Zeitgeist/stylesheets/general/_misc.less | 7 + .../Zeitgeist/stylesheets/general/_utils.less | 8 + .../Zeitgeist/stylesheets/ui/_dataTable.less | 3 + plugins/Zeitgeist/stylesheets/ui/_jqplot.less | 150 ++++++++++++++++++ .../Zeitgeist/stylesheets/ui/_sparkline.less | 26 +++ .../stylesheets/ui/_transitions.less | 98 ++++++++++++ tests/PHPUnit/Core/AccessTest.php | 6 + 31 files changed, 639 insertions(+), 196 deletions(-) create mode 100644 plugins/CoreHome/javascripts/color_manager.js create mode 100644 plugins/CoreHome/stylesheets/color_manager.css delete mode 100644 plugins/Zeitgeist/colors.piwik.json create mode 100644 plugins/Zeitgeist/stylesheets/general/_misc.less create mode 100644 plugins/Zeitgeist/stylesheets/ui/_dataTable.less create mode 100644 plugins/Zeitgeist/stylesheets/ui/_jqplot.less create mode 100644 plugins/Zeitgeist/stylesheets/ui/_sparkline.less create mode 100644 plugins/Zeitgeist/stylesheets/ui/_transitions.less diff --git a/core/API/DocumentationGenerator.php b/core/API/DocumentationGenerator.php index bc3dcf8b01..ebc2b1ce98 100644 --- a/core/API/DocumentationGenerator.php +++ b/core/API/DocumentationGenerator.php @@ -98,7 +98,7 @@ class Piwik_API_DocumentationGenerator $str .= '</small>'; $str .= "</div>\n"; } - $str .= '<div style="margin:15px;"><a href="#topApiRef" style="color:#95AECB">↑ Back to top</a></div>'; + $str .= '<div style="margin:15px;"><a href="#topApiRef">↑ Back to top</a></div>'; } $str = "<h2 id='topApiRef' name='topApiRef'>Quick access to APIs</h2> diff --git a/core/AssetManager.php b/core/AssetManager.php index 307ad4a99a..761ea0d2ab 100644 --- a/core/AssetManager.php +++ b/core/AssetManager.php @@ -253,6 +253,7 @@ class Piwik_AssetManager { $priorityCssOrdered = array( 'libs/', + 'plugins/CoreHome/stylesheets/color_manager.css', // must be before other Piwik stylesheets 'plugins/Zeitgeist/stylesheets/base.less', 'plugins/Zeitgeist/stylesheets/', 'plugins/', diff --git a/core/Controller.php b/core/Controller.php index eb70f9a714..b37b7c57da 100644 --- a/core/Controller.php +++ b/core/Controller.php @@ -809,12 +809,13 @@ abstract class Piwik_Controller $titleEvolutionPercent = $evolutionPercent; if ($evolutionPercent < 0) { - $color = "#e02a3b"; //red + $class = "negative-evolution"; $img = "arrow_down.png"; } else if ($evolutionPercent == 0) { + $class = "neutral-evolution"; $img = "stop.png"; } else { - $color = "green"; + $class = "positive-evolution"; $img = "arrow_up.png"; $titleEvolutionPercent = '+' . $titleEvolutionPercent; } @@ -830,8 +831,8 @@ abstract class Piwik_Controller $result = '<span class="metricEvolution" title="' . $title . '"><img style="padding-right:4px" src="plugins/MultiSites/images/' . $img . '"/><strong'; - if (isset($color)) { - $result .= ' style="color:' . $color . '"'; + if (isset($class)) { + $result .= ' class="' . $class . '"'; } $result .= '>' . $evolutionPercent . '</strong></span>'; diff --git a/core/Plugin/MetadataLoader.php b/core/Plugin/MetadataLoader.php index 1fe999edce..8bdd5b9ff8 100644 --- a/core/Plugin/MetadataLoader.php +++ b/core/Plugin/MetadataLoader.php @@ -17,15 +17,10 @@ require_once PIWIK_INCLUDE_PATH . '/core/Version.php'; /** * Loads plugin metadata found in the following files: * - plugin.piwik.json - * - colors.piwik.json */ class Piwik_Plugin_MetadataLoader { const PLUGIN_JSON_FILENAME = 'plugin.piwik.json'; - const COLORS_JSON_FILENAME = 'colors.piwik.json'; - - const SHORT_COLOR_LENGTH = 4; - const LONG_COLOR_LENGTH = 7; /** * The name of the plugin whose metadata will be loaded. @@ -53,8 +48,7 @@ class Piwik_Plugin_MetadataLoader { return array_merge( $this->getDefaultPluginInformation(), - $this->loadPluginInfoJson(), - $this->loadPluginColorsJson() + $this->loadPluginInfoJson() ); } @@ -79,47 +73,6 @@ class Piwik_Plugin_MetadataLoader return $this->loadJsonMetadata($path); } - private function loadPluginColorsJson() - { - $path = Piwik_PluginsManager::getPluginsDirectory() . $this->pluginName . '/' . self::COLORS_JSON_FILENAME; - $info = $this->loadJsonMetadata($path); - $info = $this->cleanAndValidatePluginColorsJson($path, $info); - return $info; - } - - private function cleanAndValidatePluginColorsJson($path, $info) - { - // check that if "colors" exists, it is an array - $colors = isset($info["colors"]) ? $info["colors"] : array(); - if (!is_array($colors)) { - throw new Exception("The 'colors' value in '$path' must be an object mapping names with colors."); - } - - // validate each color - foreach ($colors as $color) { - if (!$this->isStringColorValid($color)) { - throw new Exception("Invalid color string '$color' in '$path'."); - } - } - - return array("colors" => $colors); // make sure only 'colors' element is loaded - } - - private function isStringColorValid($color) - { - if (strlen($color) !== self::SHORT_COLOR_LENGTH - && strlen($color) !== self::LONG_COLOR_LENGTH - ) { - return false; - } - - if ($color[0] !== '#') { - return false; - } - - return ctype_xdigit(substr($color, 1)); // check if other digits are hex - } - private function loadJsonMetadata($path) { if (!file_exists($path)) { diff --git a/core/Twig.php b/core/Twig.php index a3f69dbc7e..8e4bcb7c01 100644 --- a/core/Twig.php +++ b/core/Twig.php @@ -18,6 +18,9 @@ */ class Piwik_Twig { + const SPARKLINE_TEMPLATE = '<img class="sparkline" alt="" data-src="%s" width="%d" height="%d" /> + <script type="text/javascript">$(document).ready(function () { piwik.initSparklines(); });</script>'; + /** * @var Twig_Environment */ @@ -90,10 +93,9 @@ class Piwik_Twig protected function addFunction_sparkline() { $sparklineFunction = new Twig_SimpleFunction('sparkline', function ($src) { - $graph = new Piwik_Visualization_Sparkline(); - $width = $graph->getWidth(); - $height = $graph->getHeight(); - return sprintf('<img class="sparkline" alt="" src="%s" width="%d" height="%d" />', $src, $width, $height); + $width = Piwik_Visualization_Sparkline::DEFAULT_WIDTH; + $height = Piwik_Visualization_Sparkline::DEFAULT_HEIGHT; + return sprintf(Piwik_Twig::SPARKLINE_TEMPLATE, $src, $width, $height); }, array('is_safe' => array('html'))); $this->twig->addFunction($sparklineFunction); } diff --git a/core/Visualization/Chart.php b/core/Visualization/Chart.php index 74d4bf1b52..d825aefd98 100644 --- a/core/Visualization/Chart.php +++ b/core/Visualization/Chart.php @@ -24,7 +24,6 @@ abstract class Piwik_Visualization_Chart implements Piwik_View_Interface protected $data = array(); protected $axes = array(); protected $tooltip = array(); - protected $seriesColors = array('#000000'); protected $seriesPicker = array(); // other attributes (not directly used for jqplot) @@ -157,8 +156,7 @@ abstract class Piwik_Visualization_Chart implements Piwik_View_Interface $data = array( 'params' => array( 'axes' => &$this->axes, - 'series' => &$this->series, - 'seriesColors' => &$this->seriesColors + 'series' => &$this->series ), 'data' => &$this->data, 'tooltip' => &$this->tooltip, diff --git a/core/Visualization/Chart/Evolution.php b/core/Visualization/Chart/Evolution.php index e8e82527cf..db00d00bce 100644 --- a/core/Visualization/Chart/Evolution.php +++ b/core/Visualization/Chart/Evolution.php @@ -17,9 +17,7 @@ */ class Piwik_Visualization_Chart_Evolution extends Piwik_Visualization_Chart { - - protected $seriesColors = array('#5170AE', '#F29007', '#CC3399', '#9933CC', '#80a033', - '#246AD2', '#FD16EA', '#49C100'); + const SERIES_COLOR_COUNT = 8; public function customizeChartProperties() { @@ -34,14 +32,8 @@ class Piwik_Visualization_Chart_Evolution extends Piwik_Visualization_Chart } } - public function getSeriesColors() - { - return $this->seriesColors; - } - public function setSelectableRows($selectableRows) { $this->seriesPicker['selectableRows'] = $selectableRows; } - -} +} \ No newline at end of file diff --git a/core/Visualization/Chart/Pie.php b/core/Visualization/Chart/Pie.php index f37b079ddc..cd0e137ebf 100644 --- a/core/Visualization/Chart/Pie.php +++ b/core/Visualization/Chart/Pie.php @@ -17,10 +17,6 @@ */ class Piwik_Visualization_Chart_Pie extends Piwik_Visualization_Chart { - - protected $seriesColors = array('#59727F', '#7DAAC0', '#7F7259', '#C09E7D', '#9BB39B', - '#B1D8B3', '#B39BA7', '#D8B1C5', '#A5A5A5'); - function customizeChartProperties() { if (count($this->data) == 0) { diff --git a/core/Visualization/Chart/VerticalBar.php b/core/Visualization/Chart/VerticalBar.php index 89fe7fb9a1..dab4a8ef16 100644 --- a/core/Visualization/Chart/VerticalBar.php +++ b/core/Visualization/Chart/VerticalBar.php @@ -17,10 +17,6 @@ */ class Piwik_Visualization_Chart_VerticalBar extends Piwik_Visualization_Chart { - - protected $seriesColors = array('#5170AE', '#F3A010', '#CC3399', '#9933CC', '#80a033', - '#246AD2', '#FD16EA', '#49C100'); - public function customizeChartProperties() { parent::customizeChartProperties(); @@ -42,5 +38,4 @@ class Piwik_Visualization_Chart_VerticalBar extends Piwik_Visualization_Chart } } } - } diff --git a/core/Visualization/Sparkline.php b/core/Visualization/Sparkline.php index 5ea0ca1571..e7165fbb15 100644 --- a/core/Visualization/Sparkline.php +++ b/core/Visualization/Sparkline.php @@ -24,23 +24,28 @@ require_once PIWIK_INCLUDE_PATH . '/libs/sparkline/lib/Sparkline_Line.php'; */ class Piwik_Visualization_Sparkline implements Piwik_View_Interface { + const DEFAULT_WIDTH = 100; + const DEFAULT_HEIGHT = 25; + + private static $colorNames = array('lineColor', 'red', 'blue', 'green'); + /** * Width of the sparkline * @var int */ - protected $_width = 100; + protected $_width = self::DEFAULT_WIDTH; /** * Height of sparkline * @var int */ - protected $_height = 25; + protected $_height = self::DEFAULT_HEIGHT; /** * Array with format: array( x, y, z, ... ) * @param array $data */ - function setValues($data) + public function setValues($data) { $this->values = $data; } @@ -91,16 +96,13 @@ class Piwik_Visualization_Sparkline implements Piwik_View_Interface return $this->_height; } - function main() + public function main() { $width = $this->getWidth(); $height = $this->getHeight(); $sparkline = new Sparkline_Line(); - $sparkline->SetColor('lineColor', 22, 44, 74); // dark blue - $sparkline->SetColorHtml('red', '#FF7F7F'); - $sparkline->SetColorHtml('blue', '#55AAFF'); - $sparkline->SetColorHtml('green', '#75BF7C'); + $this->setSparklineColors($sparkline); $min = $max = $last = null; $i = 0; @@ -137,8 +139,20 @@ class Piwik_Visualization_Sparkline implements Piwik_View_Interface $this->sparkline = $sparkline; } - function render() + public function render() { $this->sparkline->Output(); } + + private function setSparklineColors($sparkline) + { + $colors = Piwik_Common::getRequestVar('colors', false, 'json'); + if (!empty($colors)) { + foreach (self::$colorNames as $name) { + if (!empty($colors[$name])) { + $sparkline->SetColorHtml($name, $colors[$name]); + } + } + } + } } diff --git a/core/testMinimumPhpVersion.php b/core/testMinimumPhpVersion.php index e44c39ea1e..845ba6002a 100644 --- a/core/testMinimumPhpVersion.php +++ b/core/testMinimumPhpVersion.php @@ -79,7 +79,7 @@ if (!function_exists('Piwik_ExitWithMessage')) { { @header('Content-Type: text/html; charset=utf-8'); if ($optionalTrace) { - $optionalTrace = '<span style="color:#888888">Backtrace:<br /><pre>' . $optionalTrace . '</pre></span>'; + $optionalTrace = '<span class="exception-backtrace">Backtrace:<br /><pre>' . $optionalTrace . '</pre></span>'; } if ($optionalLinks) { $optionalLinks = '<ul> diff --git a/plugins/CoreHome/CoreHome.php b/plugins/CoreHome/CoreHome.php index 07820ffe01..cd489cd764 100644 --- a/plugins/CoreHome/CoreHome.php +++ b/plugins/CoreHome/CoreHome.php @@ -47,6 +47,7 @@ class Piwik_CoreHome extends Piwik_Plugin $cssFiles[] = "plugins/CoreHome/stylesheets/jquery.ui.autocomplete.css"; $cssFiles[] = "plugins/CoreHome/stylesheets/jqplot.css"; $cssFiles[] = "plugins/CoreHome/stylesheets/promo.less"; + $cssFiles[] = "plugins/CoreHome/stylesheets/color_manager.css"; } public function getJsFiles(&$jsFiles) @@ -75,6 +76,7 @@ class Piwik_CoreHome extends Piwik_Plugin $jsFiles[] = "plugins/CoreHome/javascripts/jqplot.js"; $jsFiles[] = "libs/jqplot/jqplot-custom.min.js"; $jsFiles[] = "plugins/CoreHome/javascripts/promo.js"; + $jsFiles[] = "plugins/CoreHome/javascripts/color_manager.js"; } } diff --git a/plugins/CoreHome/DataTableRowAction/RowEvolution.php b/plugins/CoreHome/DataTableRowAction/RowEvolution.php index c15aaee7ec..6d2abe8a86 100644 --- a/plugins/CoreHome/DataTableRowAction/RowEvolution.php +++ b/plugins/CoreHome/DataTableRowAction/RowEvolution.php @@ -204,8 +204,7 @@ class Piwik_CoreHome_DataTableRowAction_RowEvolution protected function getMetricsToggles() { $chart = new Piwik_Visualization_Chart_Evolution; - $colors = $chart->getSeriesColors(); - + $i = 0; $metrics = array(); foreach ($this->availableMetrics as $metric => $metricData) { @@ -239,10 +238,8 @@ class Piwik_CoreHome_DataTableRowAction_RowEvolution $details .= ', ' . Piwik_Translate('RowEvolution_MetricChangeText', $change); } - $color = $colors[$i % count($colors)]; $newMetric = array( 'label' => $metricData['name'], - 'color' => $color, 'details' => $details, 'sparkline' => $this->getSparkline($metric), ); @@ -261,11 +258,11 @@ class Piwik_CoreHome_DataTableRowAction_RowEvolution protected function getSparkline($metric) { // sparkline is always echoed, so we need to buffer the output - ob_start(); $view = $this->getRowEvolutionGraph($graphType = 'sparkline', $metrics = array($metric => $metric)); $view->main(); - $view->getView()->render(); + ob_start(); + $view->getView()->render(); $spark = ob_get_contents(); ob_end_clean(); diff --git a/plugins/CoreHome/javascripts/color_manager.js b/plugins/CoreHome/javascripts/color_manager.js new file mode 100644 index 0000000000..cfdc26bbff --- /dev/null +++ b/plugins/CoreHome/javascripts/color_manager.js @@ -0,0 +1,132 @@ +/*! + * Piwik - Web Analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +(function ($) { + + /** + * The ColorManager class allows JS code to grab colors defined in CSS for + * components that don't manage HTML (like jqPlot or sparklines). Such components + * can't use CSS colors directly since the colors are used to generate images + * or by <canvas> elements. + * + * Colors obtained via ColorManager are defined in CSS like this: + * + * .my-color-namespace[data-name=color-name] { + * color: #fff + * } + * + * and can be accessed in JavaScript like this: + * + * piwik.ColorManager.getColor("my-color-namespace", "color-name"); + * + * The singleton instance of this class can be accessed via piwik.ColorManager. + */ + var ColorManager = function () { + // empty + }; + + ColorManager.prototype = { + + /** + * Returns the color for a namespace and name. + * + * @param {String} namespace The string identifier that groups related colors + * together. For example, 'sparkline-colors'. + * @param {String} name The name of the color to retrieve. For example, 'lineColor'. + * @return {String} A hex color, eg, '#fff'. + */ + getColor: function (namespace, name) { + var element = this._getElement(); + + element.attr('class', 'color-manager ' + namespace).attr('data-name', name); + return this._normalizeColor(element.css('color')); + }, + + /** + * Returns the colors for a namespace and a list of names. + * + * @param {String} namespace The string identifier that groups related colors + * together. For example, 'sparkline-colors'. + * @param {Array} names An array of color names to retrieve. + * @param {Boolean} asArray Whether the result should be an array or an object. + * @return {Object|Array} An object mapping color names with color values or an + * array of colors. + */ + getColors: function (namespace, names, asArray) { + var colors = asArray ? [] : {}; + for (var i = 0; i != names.length; ++i) { + var name = names[i], + color = this.getColor(namespace, name); + if (color) { + if (asArray) { + colors.push(color); + } else { + colors[name] = color; + } + } + } + return colors; + }, + + /** + * Turns a color string that might be an rgb value rgb(12, 34, 56) into + * a hex color string. + */ + _normalizeColor: function (color) { + if (color == this._getTransparentColor()) { + return null; + } + + if (color + && color[0] != '#' + ) { + // parse rgb(#, #, #) and get rgb numbers + var parts = color.split(/[()rgb,\s]+/); + parts = [+parts[1], +parts[2], +parts[3]]; + + // convert parts to hex with one leading 0 + for (var i = 0; i != parts.length; ++i) { + parts[i] = ("00" + parts[i].toString(16)).slice(-2); + } + + // create hex string + color = '#' + parts.join(''); + } + return color; + }, + + /** + * Returns the manufactured <div> element used to obtain color data. When + * getting color data the class and data-name attribute of this element are + * changed. + */ + _getElement: function () { + if (!this.$element) { + $('body').append('<div id="color-manager"></div>'); + this.$element = $('#color-manager'); + } + + return this.$element; + }, + + /** + * Returns this browser's representation of the 'transparent' color. Used to + * compare against colors obtained in getColor. If a color is 'transparent' + * it means there's no color for that namespace/name combination. + */ + _getTransparentColor: function () { + if (!this.transparentColor) { + this.transparentColor = $('<div style="color:transparent;"></div>').appendTo($('body')).css('color'); + } + + return this.transparentColor; + } + }; + + piwik.ColorManager = new ColorManager(); + +}(jQuery)); diff --git a/plugins/CoreHome/javascripts/datatable_rowactions.js b/plugins/CoreHome/javascripts/datatable_rowactions.js index 5aea12e4b1..510861f46b 100644 --- a/plugins/CoreHome/javascripts/datatable_rowactions.js +++ b/plugins/CoreHome/javascripts/datatable_rowactions.js @@ -376,6 +376,7 @@ DataTable_RowActions_RowEvolution.prototype.showRowEvolution = function (apiMeth requestParams.module = 'CoreHome'; requestParams.action = action; + requestParams.colors = JSON.stringify(piwik.getSparklineColors()); var ajaxRequest = new ajaxHelper(); ajaxRequest.addParams(requestParams, 'get'); diff --git a/plugins/CoreHome/javascripts/jqplot.js b/plugins/CoreHome/javascripts/jqplot.js index d77d7f582f..15ba8da0ab 100644 --- a/plugins/CoreHome/javascripts/jqplot.js +++ b/plugins/CoreHome/javascripts/jqplot.js @@ -8,7 +8,6 @@ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later */ - /** * Constructor function * @@ -27,33 +26,31 @@ JQPlot.prototype = { this.originalData = data; this.data = data.data; - defaultParams = {}; - defaultParams.grid = { - drawGridLines: false, - background: '#fff', - borderColor: '#f00', - borderWidth: 0, - shadow: false - }; - - defaultParams.title = { - show: false - }; - - defaultParams.axesDefaults = { - pad: 1.0, - tickRenderer: $.jqplot.CanvasAxisTickRenderer, - tickOptions: { - showMark: false, - fontSize: '11px', - fontFamily: 'Arial' + defaultParams = { + grid: { + drawGridLines: false, + borderWidth: 0, + shadow: false }, - rendererOptions: { - drawBaseline: false + title: { + show: false + }, + axesDefaults: { + pad: 1.0, + tickRenderer: $.jqplot.CanvasAxisTickRenderer, + tickOptions: { + showMark: false, + fontSize: '11px', + fontFamily: 'Arial' + }, + rendererOptions: { + drawBaseline: false + } } }; this.params = $.extend(true, {}, defaultParams, data.params); + this._setColors(); this.tooltip = data.tooltip; this.seriesPicker = data.seriesPicker; @@ -61,6 +58,7 @@ JQPlot.prototype = { if (typeof this.params.axes.yaxis == 'undefined') { this.params.axes.yaxis = {}; } + if (typeof this.params.axes.yaxis.tickOptions == 'undefined') { this.params.yaxis.tickOptions = { formatString: '%d' @@ -302,26 +300,26 @@ JQPlot.prototype = { }); var popover = $(document.createElement('div')); - - popover.append('<div style="font-size: 13px; margin-bottom: 10px;">' + + popover.append('<div style="font-size: 13px; margin-bottom: 10px;">' + lang.exportText + '</div>').append($(img)) - - popover.dialog({ - title: lang.exportTitle, - modal: true, - width: 'auto', - position: ['center', 'center'], - resizable: false, - autoOpen: true, - open: function (event, ui) { - $('.ui-widget-overlay').on('click.popover', function () { - popover.dialog('close'); - }); - }, - close: function (event, ui) { - $(this).dialog("destroy").remove(); - } - }); + + popover.dialog({ + title: lang.exportTitle, + modal: true, + width: 'auto', + position: ['center', 'center'], + resizable: false, + autoOpen: true, + open: function (event, ui) { + $('.ui-widget-overlay').on('click.popover', function () { + popover.dialog('close'); + }); + }, + close: function (event, ui) { + $(this).dialog("destroy").remove(); + } + }); }, @@ -355,7 +353,8 @@ JQPlot.prototype = { defaultParams.piwikTicks = { showTicks: true, showGrid: true, - showHighlight: true + showHighlight: true, + tickColor: this.tickColor }; this.params = $.extend(true, {}, defaultParams, this.params); @@ -433,18 +432,21 @@ JQPlot.prototype = { this.params.piwikTicks = { showTicks: false, showGrid: false, - showHighlight: false + showHighlight: false, + tickColor: this.tickColor }; this.params.legend = { show: false }; this.params.pieLegend = { - show: true + show: true, + labelColor: this.singleMetricColor }; this.params.canvasLegend = { show: true, - singleMetric: true + singleMetric: true, + singleMetricColor: this.singleMetricColor }; // pie charts have a different data format @@ -477,7 +479,8 @@ JQPlot.prototype = { this.params.piwikTicks = { showTicks: true, showGrid: false, - showHighlight: false + showHighlight: false, + tickColor: this.tickColor }; this.params.axes.xaxis.renderer = $.jqplot.CategoryAxisRenderer; @@ -592,8 +595,25 @@ JQPlot.prototype = { this.data = [this.data[0]]; this.params.series = [this.params.series[0]]; } - } + }, + /** + * Sets the colors used to render this graph. + */ + _setColors: function () { + var colorManager = piwik.ColorManager, + seriesColorNames = ['series1', 'series2', 'series3', 'series4', 'series5', + 'series6', 'series7', 'series8', 'series9', 'series10']; + + var graphType = $('#' + this.dataTableId).find('.piwik-graph').attr('data-graph-type'), + namespace = graphType + '-graph-colors'; + + this.params.seriesColors = colorManager.getColors(namespace, seriesColorNames, true); + this.params.grid.background = colorManager.getColor(namespace, 'grid-background'); + this.params.grid.borderColor = colorManager.getColor(namespace, 'grid-border'); + this.tickColor = colorManager.getColor(namespace, 'ticks'); + this.singleMetricColor = colorManager.getColor(namespace, 'single-metric-label') + } }; @@ -831,7 +851,7 @@ RowEvolutionSeriesToggle.prototype.beforeReplot = function () { for (var i = 0; i < ticks.length; i++) { var pos = Math.round(i * tickWidth + tickWidth / 2); var full = xaxisLabels[i] && xaxisLabels[i] != ' '; - drawLine(ctx, pos, full, c.showGrid); + drawLine(ctx, pos, full, c.showGrid, c.tickColor); } } }; @@ -840,9 +860,9 @@ RowEvolutionSeriesToggle.prototype.beforeReplot = function () { $.jqplot.postDrawHooks.push($.jqplot.PiwikTicks.postDraw); // draw a 1px line - function drawLine(ctx, x, full, showGrid) { + function drawLine(ctx, x, full, showGrid, color) { ctx.save(); - ctx.strokeStyle = '#cccccc'; + ctx.strokeStyle = color; ctx.beginPath(); ctx.lineWidth = 2; @@ -987,7 +1007,7 @@ RowEvolutionSeriesToggle.prototype.beforeReplot = function () { ctx.fillStyle = s.color; if (legend.singleMetric) { - ctx.fillStyle = '#666666'; + ctx.fillStyle = legend.singleMetricColor; } ctx.fillRect(x, 10, 10, 2); @@ -1387,7 +1407,7 @@ RowEvolutionSeriesToggle.prototype.beforeReplot = function () { var x = x2 - 9 - ctx.measureText(label).width; } - ctx.fillStyle = '#666666'; + ctx.fillStyle = legend.labelColor; ctx.fillText(label, x, y2 + 3); } diff --git a/plugins/CoreHome/javascripts/sparkline.js b/plugins/CoreHome/javascripts/sparkline.js index 712dd0e7a5..8e74dbf94c 100644 --- a/plugins/CoreHome/javascripts/sparkline.js +++ b/plugins/CoreHome/javascripts/sparkline.js @@ -5,7 +5,29 @@ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later */ -function initializeSparklines() { +(function ($) { + +var sparklineColorNames = ['lineColor', 'red', 'blue', 'green']; + +piwik.getSparklineColors = function () { + return piwik.ColorManager.getColors('sparkline-colors', sparklineColorNames); +}; + +// initializes each sparkline so they use colors defined in CSS +piwik.initSparklines = function () { + $('.sparkline').each(function () { + var $self = $(this); + + if ($self.attr('src')) { + return; + } + + var colors = JSON.stringify(piwik.getSparklineColors()); + $self.attr('src', $self.attr('data-src') + '&colors=' + encodeURIComponent(colors)); + }); +}; + +window.initializeSparklines = function () { var sparklineUrlParamsToIgnore = ['module', 'action', 'idSite', 'period', 'date', 'viewDataTable']; $("[data-graph-id]").each(function () { @@ -46,18 +68,9 @@ function initializeSparklines() { // reload the datatable w/ a new column & scroll to the graph dataTable.trigger('reload', params); }); - $(this).hover( - function () { - $(this).css({ - "cursor": "pointer", - "border-bottom": "1px dashed #C3C3C3" - }); - }, - function () { - $(this).css({"border-bottom": "1px solid white"}); - } - ); } }); }); -} +}; + +}(jQuery)); diff --git a/plugins/CoreHome/stylesheets/color_manager.css b/plugins/CoreHome/stylesheets/color_manager.css new file mode 100644 index 0000000000..725d3df59a --- /dev/null +++ b/plugins/CoreHome/stylesheets/color_manager.css @@ -0,0 +1,3 @@ +.color-manager { + color: transparent; +} \ No newline at end of file diff --git a/plugins/CoreHome/templates/getMultiRowEvolutionPopover.twig b/plugins/CoreHome/templates/getMultiRowEvolutionPopover.twig index daf93f91b7..7f027b458e 100644 --- a/plugins/CoreHome/templates/getMultiRowEvolutionPopover.twig +++ b/plugins/CoreHome/templates/getMultiRowEvolutionPopover.twig @@ -1,3 +1,4 @@ +{% set seriesColorCount = constant("Piwik_Visualization_Chart_Evolution::SERIES_COLOR_COUNT") %} <div class="rowevolution multirowevolution"> <div class="popover-title">{{ 'RowEvolution_MultiRowEvolutionTitle'|translate }}</div> <div class="graph"> @@ -6,7 +7,7 @@ <div class="metrics-container"> <h2>{{ availableRecordsText|translate }}</h2> <table class="metrics" border="0" cellpadding="0" cellspacing="0"> - {% for metric in metrics %} + {% for i, metric in metrics %} <tr> <td class="sparkline"> {{ metric.sparkline|raw }} @@ -14,7 +15,9 @@ <td class="text"> {% import 'macros.twig' as piwik %} {{ piwik.logoHtml(metric, "") }} - <span style="color:{{ metric.color }}">{{ metric.label|raw }}</span><br/> + <span class="evolution-graph-colors" data-name="series{{ (i % seriesColorCount) + 1 }}"> + {{- metric.label|raw -}} + </span> <span class="details">{{ metric.details }}</span> </td> </tr> diff --git a/plugins/CoreHome/templates/getRowEvolutionPopover.twig b/plugins/CoreHome/templates/getRowEvolutionPopover.twig index 6179cfd5cf..4c38c80ac7 100644 --- a/plugins/CoreHome/templates/getRowEvolutionPopover.twig +++ b/plugins/CoreHome/templates/getRowEvolutionPopover.twig @@ -1,3 +1,4 @@ +{% set seriesColorCount = constant("Piwik_Visualization_Chart_Evolution::SERIES_COLOR_COUNT") %} <div class="rowevolution"> <div class="popover-title">{{ popoverTitle | raw }}</div> <div class="graph"> @@ -9,14 +10,16 @@ <div class="rowevolution-documentation"> {{ 'RowEvolution_Documentation'|translate }} </div> - <table class="metrics" border="0" cellpadding="0" cellspacing="0"> - {% for metric in metrics %} - <tr> + <table class="metrics" border="0" cellpadding="0" cellspacing="0" data-thing="{{ seriesColorCount }}"> + {% for i, metric in metrics %} + <tr data-i="{{ i }}"> <td class="sparkline"> - {{ metric.sparkline | raw }} + {{ metric.sparkline|raw }} </td> <td class="text"> - <span style="color:{{ metric.color }}">{{ metric.label|raw }}</span> + <span class="evolution-graph-colors" data-name="series{{ (i % seriesColorCount) + 1 }}"> + {{- metric.label|raw -}} + </span> {% if metric.details %}: <span class="details">{{ metric.details }}</span> {% endif %} diff --git a/plugins/Referers/Controller.php b/plugins/Referers/Controller.php index 09fdad8cf3..e45dd6287b 100644 --- a/plugins/Referers/Controller.php +++ b/plugins/Referers/Controller.php @@ -226,7 +226,7 @@ class Piwik_Referers_Controller extends Piwik_Controller $label = strtolower(Piwik_Translate($indexTranslation)); // return html that displays it as grey & italic - return '<span style="color:#999"><em>(' . $label . ')</em></span>'; + return '<span class="datatable-label-category"><em>(' . $label . ')</em></span>'; } function getKeywords($fetch = false) diff --git a/plugins/Transitions/javascripts/transitions.js b/plugins/Transitions/javascripts/transitions.js index 14ccd28a19..da8522d11b 100644 --- a/plugins/Transitions/javascripts/transitions.js +++ b/plugins/Transitions/javascripts/transitions.js @@ -415,10 +415,10 @@ Piwik_Transitions.prototype.renderLoops = function () { Piwik_Transitions.prototype.renderEntries = function (onlyBg) { if (this.model.directEntries > 0) { var self = this; - var gradient = this.canvas.createHorizontalGradient('#FFFFFF', '#BACFE8', 'left'); - if (this.highlightedGroup == 'directEntries') { - gradient = this.canvas.createHorizontalGradient('#FFFFFF', '#FAD293', 'left'); - } + + var isHighlighted = this.highlightedGroup == 'directEntries'; + var gradient = this.canvas.createHorizontalGradient('entries', 'left', isHighlighted); + this.canvas.renderBox({ side: 'left', onlyBg: onlyBg, @@ -442,10 +442,10 @@ Piwik_Transitions.prototype.renderEntries = function (onlyBg) { Piwik_Transitions.prototype.renderExits = function (onlyBg) { if (this.model.exits > 0) { var self = this; - var gradient = this.canvas.createHorizontalGradient('#FFFFFF', '#BACFE8', 'right'); - if (this.highlightedGroup == 'exits') { - gradient = this.canvas.createHorizontalGradient('#FFFFFF', '#FAD293', 'right'); - } + + var isHighlighted = this.highlightedGroup == 'exits'; + var gradient = this.canvas.createHorizontalGradient('exits', 'right', isHighlighted); + this.canvas.renderBox({ side: 'right', onlyBg: onlyBg, @@ -481,12 +481,10 @@ Piwik_Transitions.prototype.renderOpenGroup = function (groupName, side, onlyBg) var details = self.model.getDetailsForGroup(groupName); // prepare gradients - var gradientItems = this.canvas.createHorizontalGradient('#E3DFD1', '#E8E4D5', side); - var gradientOthers = this.canvas.createHorizontalGradient('#F5F3EB', '#E8E4D5', side); - var gradientBackground = this.canvas.createHorizontalGradient('#FFFFFF', '#BACFE8', side); - if (groupName == this.highlightedGroup) { - gradientBackground = this.canvas.createHorizontalGradient('#FFFFFF', '#FAD293', side); - } + var gradientItems = this.canvas.createHorizontalGradient('items', side); + var gradientOthers = this.canvas.createHorizontalGradient('others', side); + var gradientBackground = + this.canvas.createHorizontalGradient('background', side, groupName == this.highlightedGroup); // remember current offsets to reset them later for drawing the background var boxPositionBefore, curvePositionBefore; @@ -600,10 +598,9 @@ Piwik_Transitions.prototype.renderOpenGroup = function (groupName, side, onlyBg) /** Render a closed group without detailed data, only one box for the sum */ Piwik_Transitions.prototype.renderClosedGroup = function (groupName, side, onlyBg) { var self = this; - var gradient = this.canvas.createHorizontalGradient('#DDE4ED', '#9BBADE', side); - if (groupName == this.highlightedGroup) { - gradient = this.canvas.createHorizontalGradient('#FAE2C0', '#FAD293', side); - } + + var isHighlighted = groupName == this.highlightedGroup; + var gradient = this.canvas.createHorizontalGradient('closed-group', side, isHighlighted); var nbTransitionsVarName = groupName + 'NbTransitions'; @@ -782,6 +779,16 @@ function Piwik_Transitions_Canvas(canvasBgLeft, canvasBgRight, canvasLeft, canva this.rightBoxEndX = this.width; this.rightBoxBeginX = this.rightCurveEndX = this.rightBoxEndX - this.boxWidth; this.rightCurveBeginX = this.rightCurveEndX - this.curveWidth; + + // load gradient colors from CSS + this.colors = {}; + + var transitionsColorNamespaces = ['entries', 'exits', 'background', 'closed-group', 'items', 'others', 'loops']; + var gradientColorNames = ['light', 'dark', 'light-highlighted', 'dark-highlighted']; + for (var i = 0; i != transitionsColorNamespaces.length; ++i) { + var namespace = 'transition-' + transitionsColorNamespaces[i]; + this.colors[namespace] = piwik.ColorManager.getColors(namespace, gradientColorNames); + } } /** @@ -800,13 +807,22 @@ Piwik_Transitions_Canvas.prototype.isNarrowMode = function () { /** * Helper to create horizontal gradients - * + * TODO * @param lightColor * @param darkColor * @param position left|right */ -Piwik_Transitions_Canvas.prototype.createHorizontalGradient = function (lightColor, darkColor, position) { - var fromX, toX, fromColor, toColor; +Piwik_Transitions_Canvas.prototype.createHorizontalGradient = function (colorGroup, position, isHighlighted) { + var fromX, toX, fromColor, toColor, lightColor, darkColor; + + colorGroup = 'transition-' + colorGroup; + if (isHighlighted) { + lightColor = this.colors[colorGroup]['light-highlighted']; + darkColor = this.colors[colorGroup]['dark-highlighted']; + } else { + lightColor = this.colors[colorGroup]['light']; + darkColor = this.colors[colorGroup]['dark']; + } if (position == 'left') { // gradient is used to fill a box on the left @@ -1109,8 +1125,8 @@ Piwik_Transitions_Canvas.prototype.renderLoops = function (share) { // create gradient var gradient = this.contextLoops.createLinearGradient(this.leftCurveEndX - 50, 0, this.rightCurveBeginX + 50, 0); - var light = '#F5F3EB'; - var dark = '#E8E4D5'; + var light = this.colors['transition-loops']['light']; + var dark = this.colors['transition-loops']['dark']; gradient.addColorStop(0, dark); gradient.addColorStop(.5, light); gradient.addColorStop(1, dark); diff --git a/plugins/Zeitgeist/colors.piwik.json b/plugins/Zeitgeist/colors.piwik.json deleted file mode 100644 index d2ca30e80e..0000000000 --- a/plugins/Zeitgeist/colors.piwik.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "colors": {} -} diff --git a/plugins/Zeitgeist/stylesheets/base.less b/plugins/Zeitgeist/stylesheets/base.less index d4a014f807..4f593a9c92 100644 --- a/plugins/Zeitgeist/stylesheets/base.less +++ b/plugins/Zeitgeist/stylesheets/base.less @@ -2,7 +2,7 @@ /* base.css is automatically generated. DO NOT MODIFY */ -/* Genreral styles */ +/* General styles */ @import "general/_default.less"; @import "general/_utils.less"; @@ -11,6 +11,7 @@ @import "general/_jqueryUI.less"; +@import "general/_misc.less"; /* Component styles */ @import "ui/_header.less"; @@ -25,6 +26,11 @@ @import "ui/_loading.less"; +@import "ui/_sparkline.less"; + +@import "ui/_jqplot.less"; + +@import "ui/_transitions.less"; /* Remote components */ @import "../../CoreHome/stylesheets/_donate.less"; diff --git a/plugins/Zeitgeist/stylesheets/general/_misc.less b/plugins/Zeitgeist/stylesheets/general/_misc.less new file mode 100644 index 0000000000..38ef9f463f --- /dev/null +++ b/plugins/Zeitgeist/stylesheets/general/_misc.less @@ -0,0 +1,7 @@ +#topApiRef { + color: #95AECB; +} + +.exception-backtrace { + color: #888; +} \ No newline at end of file diff --git a/plugins/Zeitgeist/stylesheets/general/_utils.less b/plugins/Zeitgeist/stylesheets/general/_utils.less index ae8f0915b5..0077685734 100644 --- a/plugins/Zeitgeist/stylesheets/general/_utils.less +++ b/plugins/Zeitgeist/stylesheets/general/_utils.less @@ -45,6 +45,14 @@ html.old-ie .ie-hide { opacity: 0.75; } +.metricEvolution > .positive-evolution { + color: green; +} + +.metricEvolution > .negative-evolution { + color: #e02a3b; +} + .reportsByDimensionView > .entityList { float: left; width: 220px; diff --git a/plugins/Zeitgeist/stylesheets/ui/_dataTable.less b/plugins/Zeitgeist/stylesheets/ui/_dataTable.less new file mode 100644 index 0000000000..f4303658c0 --- /dev/null +++ b/plugins/Zeitgeist/stylesheets/ui/_dataTable.less @@ -0,0 +1,3 @@ +.datatable-label-category { + color:#999; +} \ No newline at end of file diff --git a/plugins/Zeitgeist/stylesheets/ui/_jqplot.less b/plugins/Zeitgeist/stylesheets/ui/_jqplot.less new file mode 100644 index 0000000000..b8f47543d2 --- /dev/null +++ b/plugins/Zeitgeist/stylesheets/ui/_jqplot.less @@ -0,0 +1,150 @@ +// evolution graph colors +.evolution-graph-colors[data-name=series1] { + color: #5170AE; +} + +.evolution-graph-colors[data-name=series2] { + color: #F29007; +} + +.evolution-graph-colors[data-name=series3] { + color: #CC3399; +} + +.evolution-graph-colors[data-name=series4] { + color: #9933CC; +} + +.evolution-graph-colors[data-name=series5] { + color: #80a033; +} + +.evolution-graph-colors[data-name=series6] { + color: #246AD2; +} + +.evolution-graph-colors[data-name=series7] { + color: #FD16EA; +} + +.evolution-graph-colors[data-name=series8] { + color: #49C100; +} + +.evolution-graph-colors[data-name=grid-background] { + color: #fff; +} + +.evolution-graph-colors[data-name=grid-border] { + color: #f00; +} + +.evolution-graph-colors[data-name=ticks] { + color: #ccc; +} + +.evolution-graph-colors[data-name=single-metric-label] { + color: #666; +} + +// bar graph colors +.bar-graph-colors[data-name=series1] { + color: #5170AE; +} + +.bar-graph-colors[data-name=series2] { + color: #F3A010; +} + +.bar-graph-colors[data-name=series3] { + color: #CC3399; +} + +.bar-graph-colors[data-name=series4] { + color: #9933CC; +} + +.bar-graph-colors[data-name=series5] { + color: #80a033; +} + +.bar-graph-colors[data-name=series6] { + color: #246AD2; +} + +.bar-graph-colors[data-name=series7] { + color: #FD16EA; +} + +.bar-graph-colors[data-name=series8] { + color: #49C100; +} + +.bar-graph-colors[data-name=grid-background] { + color: #fff; +} + +.bar-graph-colors[data-name=grid-border] { + color: #f00; +} + +.bar-graph-colors[data-name=ticks] { + color: #ccc; +} + +.bar-graph-colors[data-name=single-metric-label] { + color: #666; +} + +// pie graph colors +.pie-graph-colors[data-name=series1] { + color: #59727F; +} + +.pie-graph-colors[data-name=series2] { + color: #7DAAC0; +} + +.pie-graph-colors[data-name=series3] { + color: #7F7259; +} + +.pie-graph-colors[data-name=series4] { + color: #C09E7D; +} + +.pie-graph-colors[data-name=series5] { + color: #9BB39B; +} + +.pie-graph-colors[data-name=series6] { + color: #B1D8B3; +} + +.pie-graph-colors[data-name=series7] { + color: #B39BA7; +} + +.pie-graph-colors[data-name=series8] { + color: #D8B1C5; +} + +.pie-graph-colors[data-name=series9] { + color: #A5A5A5; +} + +.pie-graph-colors[data-name=grid-background] { + color: #fff; +} + +.pie-graph-colors[data-name=grid-border] { + color: #f00; +} + +.pie-graph-colors[data-name=ticks] { + color: #ccc; +} + +.pie-graph-colors[data-name=single-metric-label] { + color: #666; +} diff --git a/plugins/Zeitgeist/stylesheets/ui/_sparkline.less b/plugins/Zeitgeist/stylesheets/ui/_sparkline.less new file mode 100644 index 0000000000..7d2b9c7c8b --- /dev/null +++ b/plugins/Zeitgeist/stylesheets/ui/_sparkline.less @@ -0,0 +1,26 @@ +// sparkline styles +div.sparkline { + border-bottom: 1px solid white; +} + +div.sparkline:hover { + cursor: pointer; + border-bottom: 1px dashed #c3c3c3; +} + +// sparkline colors +.sparkline-colors[data-name=lineColor] { + color: rgb(22, 44, 74); +} + +.sparkline-colors[data-name=red] { + color: #ff7f7f; +} + +.sparkline-colors[data-name=blue] { + color: #55AAFF; +} + +.sparkline-colors[data-name=green] { + color: #75BF7C; +} diff --git a/plugins/Zeitgeist/stylesheets/ui/_transitions.less b/plugins/Zeitgeist/stylesheets/ui/_transitions.less new file mode 100644 index 0000000000..e74d16b341 --- /dev/null +++ b/plugins/Zeitgeist/stylesheets/ui/_transitions.less @@ -0,0 +1,98 @@ +// +// transitions colors +// + +// colors for entries gradients +.transition-entries[data-name=light] { + color: #fff; +} + +.transition-entries[data-name=dark] { + color: #BACFE8; +} + +.transition-entries[data-name=light-highlighted] { + color: #fff; +} + +.transition-entries[data-name=dark-highlighted] { + color: #FAD293; +} + +// colors for exits gradients +.transition-exits[data-name=light] { + color: #fff; +} + +.transition-exits[data-name=dark] { + color: #BACFE8; +} + +.transition-exits[data-name=light-highlighted] { + color: #fff; +} + +.transition-exits[data-name=dark-highlighted] { + color: #FAD293; +} + +// background gradients colors +.transition-background[data-name=light] { + color: #fff; +} + +.transition-background[data-name=dark] { + color: #BACFE8; +} + +.transition-background[data-name=light-highlighted] { + color: #fff; +} + +.transition-background[data-name=dark-highlighted] { + color: #FAD293; +} + +// closed group gradient colors +.transition-closed-group[data-name=light] { + color: #DDE4ED; +} + +.transition-closed-group[data-name=dark] { + color: #9BBADE; +} + +.transition-closed-group[data-name=light-highlighted] { + color: #FAE2C0; +} + +.transition-closed-group[data-name=dark-highlighted] { + color: #FAD293; +} + +// items gradient colors +.transition-items[data-name=light] { + color: #E3DFD1; +} + +.transition-items[data-name=dark] { + color: #E8E4D5; +} + +// 'others' gradients colors +.transition-others[data-name=light] { + color: #F5F3EB; +} + +.transition-others[data-name=dark] { + color: #E8E4D5; +} + +// loop gradient colors +.transition-loops[data-name=light] { + color: #F5F3EB; +} + +.transition-loops[data-name=dark] { + color: #E8E4D5; +} \ No newline at end of file diff --git a/tests/PHPUnit/Core/AccessTest.php b/tests/PHPUnit/Core/AccessTest.php index 09637df503..a8c01a2ccd 100644 --- a/tests/PHPUnit/Core/AccessTest.php +++ b/tests/PHPUnit/Core/AccessTest.php @@ -7,6 +7,12 @@ */ class AccessTest extends DatabaseTestCase { + public function setUp() + { + parent::setUp(); + Piwik_Access::setSingletonInstance(null); + } + /** * @group Core * @group Access -- GitLab