diff options
author | matt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2009-05-05 02:55:35 +0400 |
---|---|---|
committer | matt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2009-05-05 02:55:35 +0400 |
commit | cb346a4546a53bdc5054129d3331470cb3a447fc (patch) | |
tree | 155a924d3e86b7869c89022e3fbf19ca7be2ce2f /core | |
parent | 92da6b8181282800f4f28cae77d776b67540b477 (diff) |
- ADDED search field below data tables is now using the regular expression syntax. For example, a search for "google|yahoo" would match all rows containing "google" or "yahoo". All search strings containing any of the special characters from this list: . \ + * ? [ ^ ] $ ( ) { } = ! < > | must be escaped with a back slash, eg. if you want to search for keywords containing "piwik!" you would search for "piwik\!".
- ADDED new configuration option: default number of rows returned in API responses "API_datatable_default_limit = 50"
- REMOVED the automatic generic filters. The limit and sort and safe decode are applied by each module when necessary.
- removed exact match filter. Now all searches are using regular expressions syntax. Exact match can be done using ^exact search here$
- fixed notice when natural sort on a non existing column
- fixed CSV export for datatable_array
- clarified code for plotting multiple lines in an evolution chart
- FIXED #624 Added icon "save as image" below all graphs (next to the Export icon)
- moved all JS functions into the piwikHelper static class
- added example in ExampleUI plugin to plot only visits from google and yahoo! in 4 lines of code
- added message when flash is disabled and graph not showing, linking to piwik faq.
- added expressInstall.swf feature
Diffstat (limited to 'core')
31 files changed, 314 insertions, 282 deletions
diff --git a/core/API/DataTableGenericFilter.php b/core/API/DataTableGenericFilter.php index 0143397d40..59e616e1ee 100644 --- a/core/API/DataTableGenericFilter.php +++ b/core/API/DataTableGenericFilter.php @@ -36,10 +36,6 @@ class Piwik_API_DataTableGenericFilter 'filter_column_recursive' => array('string'), 'filter_pattern_recursive' => array('string'), ), - 'ExactMatch' => array( - 'filter_exact_column' => array('string'), - 'filter_exact_pattern' => array('array'), - ), 'ExcludeLowPopulation' => array( 'filter_excludelowpop' => array('string'), 'filter_excludelowpop_value'=> array('float', '0'), @@ -52,13 +48,12 @@ class Piwik_API_DataTableGenericFilter ), 'Sort' => array( 'filter_sort_column' => array('string'), - 'filter_sort_order' => array('string', Zend_Registry::get('config')->General->dataTable_default_sort_order), + 'filter_sort_order' => array('string'), ), 'Limit' => array( 'filter_offset' => array('integer', '0'), - 'filter_limit' => array('integer', Zend_Registry::get('config')->General->dataTable_default_limit), + 'filter_limit' => array('integer'), ), - 'SafeDecodeLabel' => array(), ); return $genericFilters; diff --git a/core/API/Request.php b/core/API/Request.php index 60bef14822..c9d9d3202f 100644 --- a/core/API/Request.php +++ b/core/API/Request.php @@ -67,7 +67,6 @@ class Piwik_API_Request Piwik_PostEvent('API.Request.authenticate', $requestArray['token_auth']); Zend_Registry::get('access')->reloadAccess(); } - $requestArray = $requestArray + $defaultRequest; } diff --git a/core/API/ResponseBuilder.php b/core/API/ResponseBuilder.php index 1f6f04c8fb..87c279fabe 100644 --- a/core/API/ResponseBuilder.php +++ b/core/API/ResponseBuilder.php @@ -249,6 +249,9 @@ class Piwik_API_ResponseBuilder $genericFilter->filter(); } + // we automatically safe decode all datatable labels (against xss) + $datatable->queueFilter('SafeDecodeLabel'); + // if the flag disable_queued_filters is defined we skip the filters that were queued if(Piwik_Common::getRequestVar('disable_queued_filters', 'false', 'string', $this->request) == 'false') { diff --git a/core/Archive/Array/IndexedByDate.php b/core/Archive/Array/IndexedByDate.php index f9fe5eb3a1..3a84e30089 100644 --- a/core/Archive/Array/IndexedByDate.php +++ b/core/Archive/Array/IndexedByDate.php @@ -83,9 +83,7 @@ class Piwik_Archive_Array_IndexedByDate extends Piwik_Archive_Array FROM $table WHERE idarchive IN ( $inIds ) AND name IN ( $inNames )"; - $values = $db->fetchAll($sql); - foreach($values as $value) { $arrayValues[$value['timestamp']][$value['name']] = (float)$value['value']; diff --git a/core/ArchiveProcessing.php b/core/ArchiveProcessing.php index d2b5c6f72f..66d0a33a9b 100644 --- a/core/ArchiveProcessing.php +++ b/core/ArchiveProcessing.php @@ -592,11 +592,9 @@ abstract class Piwik_ArchiveProcessing protected function isArchivingDisabled() { static $archivingIsDisabled = null; - if(is_null($archivingIsDisabled)) { $archivingIsDisabled = false; - $enableBrowserArchivingTriggering = (bool)Zend_Registry::get('config')->General->enable_browser_archiving_triggering; if($enableBrowserArchivingTriggering == false) { @@ -606,7 +604,6 @@ abstract class Piwik_ArchiveProcessing } } } - return $archivingIsDisabled; } } diff --git a/core/Common.php b/core/Common.php index 8c3b79c25b..9c53ef72ce 100644 --- a/core/Common.php +++ b/core/Common.php @@ -46,17 +46,20 @@ class Piwik_Common */ static public function prefixTable($table) { - $prefixTable = false; - if(defined('PIWIK_TRACKER_MODE') && PIWIK_TRACKER_MODE) + static $prefixTable = null; + if(is_null($prefixTable)) { - $prefixTable = Piwik_Tracker_Config::getInstance()->database['tables_prefix']; - } - else - { - $config = Zend_Registry::get('config'); - if($config !== false) + if(defined('PIWIK_TRACKER_MODE') && PIWIK_TRACKER_MODE) { - $prefixTable = $config->database->tables_prefix; + $prefixTable = Piwik_Tracker_Config::getInstance()->database['tables_prefix']; + } + else + { + $config = Zend_Registry::get('config'); + if($config !== false) + { + $prefixTable = $config->database->tables_prefix; + } } } return $prefixTable . $table; @@ -402,9 +405,7 @@ class Piwik_Common { $requestArrayToUse = $_GET + $_POST; } - $varDefault = self::sanitizeInputValues( $varDefault ); - if($varType == 'int') { // settype accepts only integer @@ -435,7 +436,7 @@ class Piwik_Common return $varDefault; } } - + // Normal case, there is a value available in REQUEST for the requested varName $value = self::sanitizeInputValues( $requestArrayToUse[$varName] ); @@ -483,7 +484,6 @@ class Piwik_Common } } } - return $value; } diff --git a/core/Controller.php b/core/Controller.php index 36c56852a0..9d99b2f8ae 100644 --- a/core/Controller.php +++ b/core/Controller.php @@ -67,7 +67,7 @@ abstract class Piwik_Controller { return 'index'; } - + protected $standardColumnNameToTranslation = array( 'label' => 'General_ColumnLabel', 'nb_visits' => 'General_ColumnNbVisits', @@ -82,7 +82,7 @@ abstract class Piwik_Controller 'revenue_per_visit' => 'General_ColumnValuePerVisit', 'goals_conversion_rate' => 'General_ColumnVisitsWithConversions', ); - + /** * Given an Object implementing Piwik_iView interface, we either: * - echo the output of the rendering if fetch = false @@ -129,6 +129,9 @@ abstract class Piwik_Controller require_once "ViewDataTable/GenerateGraphHTML.php"; $view = Piwik_ViewDataTable::factory('graphEvolution'); $view->init( $currentModuleName, $currentControllerAction, $apiMethod ); + $view->disableExcludeLowPopulation(); + $view->disableShowAllViewsIcons(); + $view->disableShowTable(); // if the date is not yet a nicely formatted date range ie. YYYY-MM-DD,YYYY-MM-DD we build it // otherwise the current controller action is being called with the good date format already so it's fine diff --git a/core/DataTable/Filter.php b/core/DataTable/Filter.php index 46984d5426..64654905ce 100644 --- a/core/DataTable/Filter.php +++ b/core/DataTable/Filter.php @@ -57,7 +57,6 @@ require_once "DataTable/Filter/ReplaceColumnNames.php"; require_once "DataTable/Filter/Sort.php"; require_once "DataTable/Filter/AddSummaryRow.php"; require_once "DataTable/Filter/ReplaceSummaryRowLabel.php"; -require_once "DataTable/Filter/ExactMatch.php"; require_once "DataTable/Filter/SafeDecodeLabel.php"; require_once "DataTable/Filter/AddColumnsWhenShowAllColumns.php"; require_once "DataTable/Filter/UpdateColumnsWhenShowAllGoals.php"; diff --git a/core/DataTable/Filter/ExactMatch.php b/core/DataTable/Filter/ExactMatch.php deleted file mode 100644 index 3f68658d61..0000000000 --- a/core/DataTable/Filter/ExactMatch.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php -/** - * Piwik - Open source web analytics - * - * @link http://piwik.org - * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later - * @version $Id$ - * - * @package Piwik_DataTable - */ - -/** - * Delete all rows for which the given $columnToFilter do not equal $patternToSearch - * This filter can be used on both integer and string columns. - * You can pass an array of integers in $patternToSearch parameter. - * - * @package Piwik_DataTable - * @subpackage Piwik_DataTable_Filter - */ -class Piwik_DataTable_Filter_ExactMatch extends Piwik_DataTable_Filter -{ - private $columnToFilter; - private $patternToSearch; - - public function __construct( $table, $columnToFilter, $patternToSearch ) - { - parent::__construct($table); - $this->patternToSearch = $patternToSearch; - $this->columnToFilter = $columnToFilter; - $this->filter(); - } - - protected function filter() - { - foreach($this->table->getRows() as $key => $row) - { - if( is_array($this->patternToSearch) ) - { - if( in_array($row->getColumn($this->columnToFilter), $this->patternToSearch) == false ) - { - $this->table->deleteRow($key); - } - } - else if( $row->getColumn($this->columnToFilter) != $this->patternToSearch ) - { - $k = $row->getColumn($this->columnToFilter); - $this->table->deleteRow($key); - } - } - } -} - diff --git a/core/DataTable/Filter/Pattern.php b/core/DataTable/Filter/Pattern.php index d12e4920ec..8a3c1eb7fe 100644 --- a/core/DataTable/Filter/Pattern.php +++ b/core/DataTable/Filter/Pattern.php @@ -34,7 +34,7 @@ class Piwik_DataTable_Filter_Pattern extends Piwik_DataTable_Filter static public function getPatternQuoted( $pattern ) { - return "/". preg_quote($pattern, '/') ."/"; + return "/". str_replace('/','\/', $pattern) ."/"; } /* @@ -42,8 +42,7 @@ class Piwik_DataTable_Filter_Pattern extends Piwik_DataTable_Filter */ static public function match($pattern, $patternQuoted, $string) { - return preg_match($patternQuoted . "i", $string) == 1 - && stripos($string, $pattern) !== false; + return @preg_match($patternQuoted . "i", $string) == 1; } protected function filter() diff --git a/core/DataTable/Filter/Sort.php b/core/DataTable/Filter/Sort.php index 0b80a322d8..5c066cbe54 100644 --- a/core/DataTable/Filter/Sort.php +++ b/core/DataTable/Filter/Sort.php @@ -76,10 +76,20 @@ class Piwik_DataTable_Filter_Sort extends Piwik_DataTable_Filter function naturalSort($a, $b) { - return $this->sign * strnatcasecmp( - $a->c[Piwik_DataTable_Row::COLUMNS][$this->columnToSort], - $b->c[Piwik_DataTable_Row::COLUMNS][$this->columnToSort] - ); + return !isset($a->c[Piwik_DataTable_Row::COLUMNS][$this->columnToSort]) + && !isset($b->c[Piwik_DataTable_Row::COLUMNS][$this->columnToSort] ) + ? 0 + : (!isset($a->c[Piwik_DataTable_Row::COLUMNS][$this->columnToSort]) + ? 1 + : (!isset($b->c[Piwik_DataTable_Row::COLUMNS][$this->columnToSort] ) + ? -1 + : $this->sign * strnatcasecmp( + $a->c[Piwik_DataTable_Row::COLUMNS][$this->columnToSort], + $b->c[Piwik_DataTable_Row::COLUMNS][$this->columnToSort] + ) + ) + ) + ; } function sortString($a, $b) diff --git a/core/DataTable/Renderer/Csv.php b/core/DataTable/Renderer/Csv.php index 53dbc25a8d..567ece1b6f 100644 --- a/core/DataTable/Renderer/Csv.php +++ b/core/DataTable/Renderer/Csv.php @@ -65,7 +65,7 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer function render() { - return $this->renderTable($this->table); + return $this->output($this->renderTable($this->table)); } protected function renderTable($table) @@ -104,8 +104,7 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer { $str = $this->renderDataTable($table); } - - return $this->output($str); + return $str; } protected function renderDataTable( $table ) diff --git a/core/Date.php b/core/Date.php index 394adab8d4..001af599fa 100644 --- a/core/Date.php +++ b/core/Date.php @@ -67,16 +67,6 @@ class Piwik_Date $this->timestamp = $date ; } - /* - * @param int Timestamp - * @return string Pretty date in the current locale - */ - static public function getPrettyDateFromTimestamp($timestamp) - { - $date = Piwik_Date::factory($timestamp); - return $date->getLocalized(Piwik_Translate('CoreHome_LocalizedDateFormat')); - } - /** * Sets the time part of the date * Doesn't modify $this @@ -237,7 +227,12 @@ class Piwik_Date return date($part, $this->getTimestamp()); } - //TODO to test + /** + * Returns a localized date string, given a template. + * Allowed tags are: %day%, %shortDay%, %longDay%, etc. + * @param $template string eg. %shortMonth% %longYear% + * @return string eg. "Aug 2009" + */ public function getLocalized($template) { $day = $this->toString('j'); diff --git a/core/FrontController.php b/core/FrontController.php index 8270f53212..0eb1112c10 100644 --- a/core/FrontController.php +++ b/core/FrontController.php @@ -230,14 +230,9 @@ class Piwik_FrontController Piwik::createDatabaseObject(); Piwik::createLogObject(); - // creating the access object, so that core/Updates/* can enforce Super User and use some APIs Piwik::createAccessObject(); - - require_once "CoreUpdater/Controller.php"; - //TODO should not be a controller! - $updaterController = new Piwik_CoreUpdater_Controller(); - $updaterController->checkForCoreAndPluginsUpdates(); + Piwik::displayScreenForCoreAndPluginsUpdatesIfNecessary(); Piwik_PluginsManager::getInstance()->installLoadedPlugins(); Piwik::install(); diff --git a/core/Piwik.php b/core/Piwik.php index 8f928ccf3f..428b17ead6 100644 --- a/core/Piwik.php +++ b/core/Piwik.php @@ -904,6 +904,30 @@ class Piwik return false; } + static public function displayScreenForCoreAndPluginsUpdatesIfNecessary() + { + require_once "Updater.php"; + require_once "Version.php"; + $updater = new Piwik_Updater(); + $updater->addComponentToCheck('core', Piwik_Version::VERSION); + + $plugins = Piwik_PluginsManager::getInstance()->getInstalledPlugins(); + foreach($plugins as $pluginName => $plugin) + { + $updater->addComponentToCheck($pluginName, $plugin->getVersion()); + } + + $componentsWithUpdateFile = $updater->getComponentsWithUpdateFile(); + if(count($componentsWithUpdateFile) == 0) + { + return; + } + + require_once "CoreUpdater/Controller.php"; + $updaterController = new Piwik_CoreUpdater_Controller(); + $updaterController->runUpdaterAndExit($componentsWithUpdateFile); + } + /** * Sends http request ensuring the request will fail before $timeout seconds * Returns the response content (no header, trimmed) diff --git a/core/Url.php b/core/Url.php index 27b57310ec..c1fca7f647 100644 --- a/core/Url.php +++ b/core/Url.php @@ -165,14 +165,28 @@ class Piwik_Url static function getCurrentQueryStringWithParametersModified( $params ) { $urlValues = self::getArrayFromCurrentQueryString(); - foreach($params as $key => $value) { $urlValues[$key] = $value; } - + $query = self::getQueryStringFromParameters($urlValues); + if(strlen($query) > 0) + { + return '?'.$query; + } + return ''; + } + + /** + * Given an array of parameters name->value, returns the query string. + * Also works with array values using the php array syntax for GET parameters. + * @param $parameters eg. array( 'param1' => 10, 'param2' => array(1,2)) + * @return string eg. "param1=10¶m2[]=1¶m2[]=2" + */ + static public function getQueryStringFromParameters($parameters) + { $query = ''; - foreach($urlValues as $name => $value) + foreach($parameters as $name => $value) { if(empty($value)) { @@ -191,15 +205,7 @@ class Piwik_Url } } $query = substr($query, 0, -1); - - if(strlen($query) > 0) - { - return '?'.$query; - } - else - { - return ''; - } + return $query; } /** diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php index 0321171ba9..df329b585f 100644 --- a/core/ViewDataTable.php +++ b/core/ViewDataTable.php @@ -251,8 +251,10 @@ abstract class Piwik_ViewDataTable $this->viewProperties['show_goals'] = false; $this->viewProperties['show_search'] = Piwik_Common::getRequestVar('show_search', true); + $this->viewProperties['show_table'] = Piwik_Common::getRequestVar('show_table', true); $this->viewProperties['show_table_all_columns'] = Piwik_Common::getRequestVar('show_table_all_columns', true); $this->viewProperties['show_all_views_icons'] = Piwik_Common::getRequestVar('show_all_views_icons', true); + $this->viewProperties['show_export_as_image_icon'] = Piwik_Common::getRequestVar('show_export_as_image_icon', false); $this->viewProperties['show_exclude_low_population'] = Piwik_Common::getRequestVar('show_exclude_low_population', true); $this->viewProperties['show_offset_information'] = Piwik_Common::getRequestVar('show_offset_information', true);; $this->viewProperties['show_footer'] = Piwik_Common::getRequestVar('show_footer', true); @@ -368,8 +370,6 @@ abstract class Piwik_ViewDataTable 'filter_excludelowpop_value', 'filter_column', 'filter_pattern', - 'filter_exact_pattern', - 'filter_exact_column', 'disable_generic_filters', 'disable_queued_filters' ); @@ -666,6 +666,15 @@ abstract class Piwik_ViewDataTable } /** + * Whether or not to show the "View table" icon + * @return void + */ + public function disableShowTable() + { + $this->viewProperties['show_table'] = false; + } + + /** * Whether or not to show the "View more data" icon * @return void */ @@ -696,19 +705,6 @@ abstract class Piwik_ViewDataTable } /** - * Sets the pattern to look for in the table (only rows with column equal to the pattern will be kept) - * - * @param array $pattern arrays of patterns to look for - * @param string $column to compare the pattern to - * @return void - */ - public function setExactPattern($pattern, $column) - { - $this->variablesDefault['filter_exact_pattern'] = $pattern; - $this->variablesDefault['filter_exact_column'] = $column; - } - - /** * Sets the value to use for the Exclude low population filter. * * @param int|float If a row value is less than this value, it will be removed from the dataTable diff --git a/core/ViewDataTable/Cloud.php b/core/ViewDataTable/Cloud.php index c5fc45a67e..8c3d93a5f0 100644 --- a/core/ViewDataTable/Cloud.php +++ b/core/ViewDataTable/Cloud.php @@ -22,9 +22,9 @@ class Piwik_ViewDataTable_Cloud extends Piwik_ViewDataTable { protected $displayLogoInsteadOfLabel = false; - public function displayLogoInTagCloud() + public function setDisplayLogoInTagCloud($bool) { - $this->displayLogoInsteadOfLabel = true; + $this->displayLogoInsteadOfLabel = $bool; } protected function getViewDataTableId() @@ -79,6 +79,7 @@ class Piwik_ViewDataTable_Cloud extends Piwik_ViewDataTable $columnTranslation = $this->getColumnTranslation($columnToDisplay); $values = $this->dataTable->getColumn($columnToDisplay); $labels = $this->dataTable->getColumn('label'); + $labelMetadata = array(); foreach($this->dataTable->getRows() as $row) { $logo = false; diff --git a/core/ViewDataTable/GenerateGraphData.php b/core/ViewDataTable/GenerateGraphData.php index af61510bac..a197a88bf8 100644 --- a/core/ViewDataTable/GenerateGraphData.php +++ b/core/ViewDataTable/GenerateGraphData.php @@ -59,11 +59,27 @@ abstract class Piwik_ViewDataTable_GenerateGraphData extends Piwik_ViewDataTable * * @return int */ - function getGraphLimit() + public function getGraphLimit() { return $this->graphLimit; } + protected $displayPercentageInTooltip = true; + + /** + * The percentage in tooltips is computed based on the sum of all values for the plotted column. + * If the sum of the column in the data set is not the number of elements in the data set, + * for example when plotting visits that have a given plugin enabled: + * one visit can have several plugins, hence the sum is much greater than the number of visits. + * In this case displaying the percentage doesn't make sense. + * + * @return void + */ + public function disallowPercentageInGraphTooltip() + { + $this->displayPercentageInTooltip = false; + } + public function main() { if($this->mainAlreadyExecuted) @@ -74,7 +90,6 @@ abstract class Piwik_ViewDataTable_GenerateGraphData extends Piwik_ViewDataTable // the queued filters will be manually applied later. This is to ensure that filtering using search // will be done on the table before the labels are enhanced (see ReplaceColumnNames) - $this->disableGenericFilters(); $this->disableQueuedFilters(); $this->loadDataTableFromAPI(); @@ -97,14 +112,12 @@ abstract class Piwik_ViewDataTable_GenerateGraphData extends Piwik_ViewDataTable } else { - $this->generateDataFromDataTable(); + $this->initChartObjectData(); } - //TODO rename - $this->view->customizeGraph(); + $this->view->customizeChartProperties(); } - //TODO rename - protected function generateDataFromDataTable() + protected function initChartObjectData() { $this->dataTable->applyQueuedFilters(); @@ -118,16 +131,16 @@ abstract class Piwik_ViewDataTable_GenerateGraphData extends Piwik_ViewDataTable unset($columnNames[$labelColumnFound]); } - $columnNameToTranslation = $columnNameToValue = $columnNameToUnit = array(); + $columnNameToTranslation = $columnNameToValue = array(); foreach($columnNames as $columnName) { $columnNameToTranslation[$columnName] = $this->getColumnTranslation($columnName); $columnNameToValue[$columnName] = $this->dataTable->getColumn($columnName); - $columnNameToUnit[$columnName] = $this->yAxisUnit; } $this->view->setAxisXLabels($xLabels); $this->view->setAxisYValues($columnNameToValue); $this->view->setAxisYLabels($columnNameToTranslation); - $this->view->setAxisYUnits($columnNameToUnit); + $this->view->setAxisYUnit($this->yAxisUnit); + $this->view->setDisplayPercentageInTooltip($this->displayPercentageInTooltip); } } diff --git a/core/ViewDataTable/GenerateGraphData/ChartEvolution.php b/core/ViewDataTable/GenerateGraphData/ChartEvolution.php index dc4eab30c0..6e950a1ada 100644 --- a/core/ViewDataTable/GenerateGraphData/ChartEvolution.php +++ b/core/ViewDataTable/GenerateGraphData/ChartEvolution.php @@ -19,13 +19,32 @@ class Piwik_ViewDataTable_GenerateGraphData_ChartEvolution extends Piwik_ViewDat $this->view = new Piwik_Visualization_Chart_Evolution; } - protected function generateDataFromDataTable() + protected function guessUnitFromRequestedColumnNames($requestedColumnNames) + { + $nameToUnit = array( + '_rate' => '%', + '_revenue' => Piwik::getCurrency(), + ); + foreach($requestedColumnNames as $columnName) + { + foreach($nameToUnit as $pattern => $type) + { + if(strpos($columnName, $pattern) !== false) + { + return $type; + } + } + } + return false; + } + + protected function initChartObjectData() { // if the loaded datatable is a simple DataTable, it is most likely a plugin plotting some custom data // we don't expect plugin developers to return a well defined Piwik_DataTable_Array if($this->dataTable instanceof Piwik_DataTable) { - return parent::generateDataFromDataTable(); + return parent::initChartObjectData(); } $this->dataTable->applyQueuedFilters(); @@ -33,42 +52,53 @@ class Piwik_ViewDataTable_GenerateGraphData_ChartEvolution extends Piwik_ViewDat { throw new Exception("Expecting a DataTable_Array with custom format to draw an evolution chart"); } + + // the X label is extracted from the 'period' object in the table's metadata $xLabels = $uniqueIdsDataTable = array(); foreach($this->dataTable->metadata as $idDataTable => $metadataDataTable) { + //eg. "Aug 2009" $xLabels[] = $metadataDataTable['period']->getLocalizedShortString(); + // we keep track of all unique data table that we need to set a Y value for $uniqueIdsDataTable[] = $idDataTable; } - // list of column names requested to be plotted, we only need to forward these to the Graph object - $columnNameRequested = $this->getColumnsToDisplay(); - - $columnNameToValue = array(); + $requestedColumnNames = $this->getColumnsToDisplay(); + $yAxisLabelToValue = array(); foreach($this->dataTable->getArray() as $idDataTable => $dataTable) { - if($dataTable->getRowsCount() > 1) + foreach($dataTable->getRows() as $row) { - throw new Exception("Expecting only one row per DataTable"); - } - $row = $dataTable->getFirstRow(); - if($row !== false) - { - foreach($row->getColumns() as $columnName => $columnValue) + $rowLabel = $row->getColumn('label'); + foreach($requestedColumnNames as $requestedColumnName) { - if(array_search($columnName, $columnNameRequested) !== false) + $metricLabel = $this->getColumnTranslation($requestedColumnName); + if($rowLabel !== false) + { + // eg. "Yahoo! (Visits)" + $yAxisLabel = "$rowLabel ($metricLabel)"; + } + else { - $columnNameToValue[$columnName][$idDataTable] = $columnValue; + // eg. "Visits" + $yAxisLabel = $metricLabel; + } + if(($columnValue = $row->getColumn($requestedColumnName)) !== false) + { + $yAxisLabelToValue[$yAxisLabel][$idDataTable] = $columnValue; } } } } - // make sure all column values are set (at least zero) in order for all unique idDataTable - $columnNameToValueCleaned = array(); + // make sure all column values are set to at least zero (no gap in the graph) + $yAxisLabelToValueCleaned = array(); + $yAxisLabels = array(); foreach($uniqueIdsDataTable as $uniqueIdDataTable) { - foreach($columnNameToValue as $columnName => $idDataTableToColumnValue) + foreach($yAxisLabelToValue as $yAxisLabel => $idDataTableToColumnValue) { + $yAxisLabels[$yAxisLabel] = $yAxisLabel; if(isset($idDataTableToColumnValue[$uniqueIdDataTable])) { $columnValue = $idDataTableToColumnValue[$uniqueIdDataTable]; @@ -77,43 +107,20 @@ class Piwik_ViewDataTable_GenerateGraphData_ChartEvolution extends Piwik_ViewDat { $columnValue = 0; } - $columnNameToValueCleaned[$columnName][] = $columnValue; + $yAxisLabelToValueCleaned[$yAxisLabel][] = $columnValue; } } - $columnNames = array_keys($columnNameToValueCleaned); - $columnNameToTranslation = array(); - $columnNameToUnit = array(); - $nameToUnit = array( - '_rate' => '%', - '_revenue' => Piwik::getCurrency(), - ); - foreach($columnNames as $columnName) + + $unit = $this->yAxisUnit; + if(empty($unit)) { - $columnNameToTranslation[$columnName] = $this->getColumnTranslation($columnName); - - $columnNameToUnit[$columnName] = false; - // if the unit was specified, we use it - if(!empty($this->yAxisUnit)) - { - $columnNameToUnit[$columnName] = $this->yAxisUnit; - } - // otherwise we guess the unit from the column name - else - { - foreach($nameToUnit as $pattern => $type) - { - if(strpos($columnName, $pattern) !== false) - { - $columnNameToUnit[$columnName] = $type; - break; - } - } - } + $unit = $this->guessUnitFromRequestedColumnNames($requestedColumnNames); } + $this->view->setAxisXLabels($xLabels); - $this->view->setAxisYValues($columnNameToValueCleaned); - $this->view->setAxisYLabels($columnNameToTranslation); - $this->view->setAxisYUnits($columnNameToUnit); + $this->view->setAxisYValues($yAxisLabelToValueCleaned); + $this->view->setAxisYLabels($yAxisLabels); + $this->view->setAxisYUnit($unit); $firstDatatable = reset($this->dataTable->metadata); $period = $firstDatatable['period']; @@ -134,14 +141,14 @@ class Piwik_ViewDataTable_GenerateGraphData_ChartEvolution extends Piwik_ViewDat $period = $metadataDataTable['period']; $dateInUrl = $period->getDateStart(); $link = Piwik_Url::getCurrentUrlWithoutQueryString() . - Piwik_Url::getCurrentQueryStringWithParametersModified( array( - 'date' => $dateInUrl, + '?' . + Piwik_Url::getQueryStringFromParameters( array( 'module' => 'CoreHome', 'action' => 'index', - 'viewDataTable' => null, // we reset the viewDataTable parameter (useless in the link) - 'idGoal' => null, // we reset idGoal - 'columns' => null, - )); + 'idSite' => Piwik_Common::getRequestVar('idSite'), + 'period' => $period->getLabel(), + 'date' => $dateInUrl, + )); $axisXOnClick[] = $link; } $this->view->setAxisXOnClick($axisXOnClick); diff --git a/core/ViewDataTable/GenerateGraphHTML.php b/core/ViewDataTable/GenerateGraphHTML.php index 0523531a82..445824f98e 100644 --- a/core/ViewDataTable/GenerateGraphHTML.php +++ b/core/ViewDataTable/GenerateGraphHTML.php @@ -38,6 +38,8 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable $this->disableOffsetInformation(); $this->disableExcludeLowPopulation(); $this->disableSearchBox(); + $this->enableShowExportAsImageIcon(); + $this->parametersToModify = array( 'viewDataTable' => $this->getViewDataTableIdToLoad(), // in the case this controller is being executed by another controller @@ -48,6 +50,11 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable ); } + public function enableShowExportAsImageIcon() + { + $this->viewProperties['show_export_as_image_icon'] = true; + } + /** * Sets parameters to modify in the future generated URL * @param array $array array('nameParameter' => $newValue, ...) @@ -58,6 +65,15 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable } /** + * We persist the parametersToModify values in the javascript footer. + * This is used by the "export links" that use the "date" attribute from the json properties array in the datatable footer. + */ + protected function getJavascriptVariablesToSet() + { + return $this->parametersToModify + parent::getJavascriptVariablesToSet(); + } + + /** * @see Piwik_ViewDataTable::main() */ public function main() @@ -76,61 +92,73 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable $view = new Piwik_View($this->dataTableTemplate); $this->uniqueIdViewDataTable = $this->getUniqueIdViewDataTable(); $view->graphType = $this->graphType; + $this->chartDivId = $this->uniqueIdViewDataTable . "Chart_swf"; $this->parametersToModify['action'] = $this->currentControllerAction; + $this->parametersToModify = array_merge($this->variablesDefault, $this->parametersToModify); + $url = Piwik_Url::getCurrentQueryStringWithParametersModified($this->parametersToModify); $view->jsInvocationTag = $this->getFlashInvocationCode($url); $view->urlGraphData = $url; - + $view->chartDivId = $this->chartDivId; $view->formEmbedId = "formEmbed".$this->uniqueIdViewDataTable; - $view->graphCodeEmbed = $this->graphCodeEmbed; - $view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet(); $view->properties = $this->getViewProperties(); return $view; } - protected function getFlashInvocationCode( $url = 'libs/open-flash-chart/data-files/nodata.txt', $use_swfobject = true ) + protected function getFlashInvocationCode( $url = 'libs/open-flash-chart/data-files/nodata.txt' ) { $width = $this->width; $height = $this->height; - $libPathInPiwik = 'libs/open-flash-chart/'; $currentPath = Piwik_Url::getCurrentUrlWithoutFileName(); - $pathToLibraryOpenChart = $currentPath . $libPathInPiwik; + $pathToLibraryOpenChart = $currentPath . 'libs/open-flash-chart/'; + $pathToLibrarySwfObject = $currentPath . 'libs/swfobject/'; $url = Piwik_Url::getCurrentUrlWithoutQueryString() . $url; // escape the & and stuff: $url = urlencode($url); - $obj_id = $this->uniqueIdViewDataTable . "Chart"; - $div_name = $this->uniqueIdViewDataTable . "FlashContent"; - $return = ''; - if( $use_swfobject ) - { - // Using library for auto-enabling Flash object on IE, disabled-Javascript proof - $return .= ' -<div id="'. $div_name .'"><div id="'. $obj_id .'_swf"><noscript>'; - } - $urlGraph = $pathToLibraryOpenChart."open-flash-chart.swf?data=" . $url; - - // when the object/embed is changed, see also widgetize.js; it may require a logic update - $this->graphCodeEmbed .= '<div><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="' . $width . '" height="' . $height . '" id="'. $obj_id .'" > -<param name="movie" value="'.$urlGraph.'" /> -<param name="wmode" value="opaque" /> -<param name="allowScriptAccess" value="sameDomain" /> -<embed src="'.$urlGraph.'" wmode="opaque" allowScriptAccess="sameDomain" quality="high" bgcolor="#FFFFFF" width="'. $width .'" height="'. $height .'" name="open-flash-chart" type="application/x-shockwave-flash" id="'. $obj_id .'" /> -</object></div>'; - $return .= $this->graphCodeEmbed; - if( $use_swfobject ) - { - $return .= ' -</noscript></div></div> -<script type="text/javascript"> -swfobject.embedSWF("'.$pathToLibraryOpenChart.'open-flash-chart.swf", "'. $obj_id .'_swf", "'. $width . '", "' . $height . '", "9.0.0", false, {"data-file":"'.$url.'"}, {"allowScriptAccess":"sameDomain","wmode":"opaque"}, {"bgcolor":"#FFFFFF"}); -</script>'; - } + $requiredFlashVersion = "9.0.0"; + // - Export as Image feature from Open Flash Chart + // - Using library for auto-enabling Flash object on IE, disabled-Javascript proof + $return = ' + <div id="'. $this->chartDivId .'">Displaying Graphs in Piwik requires Flash >= '.$requiredFlashVersion.'. <a target="_blank" href="misc/redirectToUrl.php?url=http://piwik.org/faq/troubleshooting/#faq_53">More information about displaying graphs in Piwik.</a></div> + <script type="text/javascript"> + OFC = {}; + OFC.jquery = { + name: "jQuery", + rasterize: function (src, dst) { $("#"+ dst).replaceWith(Control.OFC.image(src)) }, + image: function(src) { return "<img title=\'Piwik Graph\' src=\'data:image/png;base64," + $("#"+src)[0].get_img_binary() + "\' />"}, + popup: function(src) { + var img_win = window.open("", "Charts: Export as Image") + with(img_win.document) { + write("<html><head><title>'.Piwik_Translate('General_ExportAsImage').'<\/title><\/head><body>" + Control.OFC.image(src) + "<br><br><p>'.htmlentities(Piwik_Translate('General_SaveImageOnYourComputer')).'</p><\/body><\/html>") } + } + } + if (typeof(Control == "undefined")) {var Control = {OFC: OFC.jquery}} + // By default, right-clicking on OFC and choosing "save image locally" calls this function. + function save_image() { OFC.jquery.popup("'.$this->chartDivId.'") } + + swfobject.embedSWF( + "'.$pathToLibraryOpenChart.'open-flash-chart.swf", + "'. $this->chartDivId .'", + "'. $width . '", "' . $height . '", + "'.$requiredFlashVersion.'", + "'.$pathToLibrarySwfObject.'expressInstall.swf", + { + "data-file":"'.$url.'", + "loading":"'.htmlspecialchars(Piwik_Translate('General_Loading')).'" + }, + { + "allowScriptAccess":"sameDomain", + "wmode":"opaque" + }, + {"bgcolor":"#FFFFFF"} + ); + </script>'; return $return; } } diff --git a/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php b/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php index 77082e99f9..8729a452f4 100644 --- a/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php +++ b/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php @@ -35,7 +35,8 @@ class Piwik_ViewDataTable_GenerateGraphHTML_ChartEvolution extends Piwik_ViewDat $apiMethodToRequestDataTable ); $this->setParametersToModify(array('date' => Piwik_Common::getRequestVar('date', 'last30', 'string'))); - $this->disableFooter(); + $this->disableShowAllViewsIcons(); + $this->disableShowTable(); } /** @@ -46,6 +47,10 @@ class Piwik_ViewDataTable_GenerateGraphHTML_ChartEvolution extends Piwik_ViewDat */ public function setColumnsToDisplay( $columnsNames) { + if(!is_array($columnsNames)) + { + $columnsNames = array($columnsNames); + } $this->setParametersToModify( array('columns' => $columnsNames) ); } } diff --git a/core/ViewDataTable/HtmlTable.php b/core/ViewDataTable/HtmlTable.php index cfd079da48..f3dab41d5f 100644 --- a/core/ViewDataTable/HtmlTable.php +++ b/core/ViewDataTable/HtmlTable.php @@ -48,7 +48,8 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable $controllerActionCalledWhenRequestSubTable); $this->dataTableTemplate = 'CoreHome/templates/datatable.tpl'; $this->variablesDefault['enable_sort'] = '1'; - + $this->setSortedColumn('nb_visits', 'desc'); + $this->setLimit(Zend_Registry::get('config')->General->datatable_default_limit); $this->handleLowPopulation(); } diff --git a/core/ViewDataTable/Sparkline.php b/core/ViewDataTable/Sparkline.php index 4a2d0c1514..3ada3c5fbe 100644 --- a/core/ViewDataTable/Sparkline.php +++ b/core/ViewDataTable/Sparkline.php @@ -34,7 +34,6 @@ class Piwik_ViewDataTable_Sparkline extends Piwik_ViewDataTable } $this->mainAlreadyExecuted = true; - $this->disableGenericFilters(); $this->loadDataTableFromAPI(); $this->isDataAvailable = $this->dataTable->getRowsCount() != 0; diff --git a/core/Visualization/Chart.php b/core/Visualization/Chart.php index 9a1ca5ebc2..f51e308519 100644 --- a/core/Visualization/Chart.php +++ b/core/Visualization/Chart.php @@ -29,7 +29,11 @@ abstract class Piwik_Visualization_Chart implements Piwik_iView protected $yLabels = array(); protected $yValues = array(); - protected $yUnits = array(); + protected $yUnit = ''; + + protected $maxValue; + protected $minValue; + protected $displayPercentageInTooltip = true; function __construct() { @@ -51,9 +55,12 @@ abstract class Piwik_Visualization_Chart implements Piwik_iView $this->yValues = $values; } - function setAxisYUnits($yUnits) + function setAxisYUnit($yUnit) { - $this->yUnits = $yUnits; + if(!empty($yUnit)) + { + $this->yUnit = $yUnit; + } } public function setAxisYLabels($labels) @@ -61,6 +68,11 @@ abstract class Piwik_Visualization_Chart implements Piwik_iView $this->yLabels = $labels; } + public function setDisplayPercentageInTooltip($bool) + { + $this->displayPercentageInTooltip = $bool; + } + //TODO call + make sure matches beginning of period? (hard..) // day -> every 7 days @@ -115,7 +127,7 @@ abstract class Piwik_Visualization_Chart implements Piwik_iView return $this->chart->toPrettyString(); } - function customizeGraph() + function customizeChartProperties() { $this->chart->set_number_format($num_decimals = 0, $is_fixed_num_decimals_forced = true, @@ -124,8 +136,8 @@ abstract class Piwik_Visualization_Chart implements Piwik_iView $gridColour = '#E0E1E4'; $countValues = count($this->xLabels); - $maxValue = $this->getMaxValue(); - $minValue = 0; + $this->maxValue = $this->getMaxValue(); + $this->minValue = 0; // X Axis $this->x = new x_axis(); @@ -154,21 +166,17 @@ abstract class Piwik_Visualization_Chart implements Piwik_iView $this->y->set_colour('#ffffff'); $this->y->set_grid_colour($gridColour); $stepsCount = 2; - $stepsEveryNLabel = ceil(($maxValue - $minValue) / $stepsCount); - if($maxValue == 0) + $stepsEveryNLabel = ceil(($this->maxValue - $this->minValue) / $stepsCount); + if($this->maxValue == 0) { - $maxValue = 1; + $this->maxValue = 1; } - $this->y->set_range( $minValue, $maxValue, $stepsEveryNLabel); + $this->y->set_range( $this->minValue, $this->maxValue, $stepsEveryNLabel); $dataSetsToDisplay = $this->getDataSetsToDisplay(); if($dataSetsToDisplay != false) { $dataSetToDisplay = current($dataSetsToDisplay); - if(isset($this->yUnits[$dataSetToDisplay])) - { - $unit = $this->yUnits[$dataSetToDisplay]; - $this->y->set_label_text("#val#$unit"); - } + $this->y->set_label_text("#val#".$this->yUnit); } // Tooltip diff --git a/core/Visualization/Chart/Evolution.php b/core/Visualization/Chart/Evolution.php index 314acbffd9..3b28fa3d4c 100644 --- a/core/Visualization/Chart/Evolution.php +++ b/core/Visualization/Chart/Evolution.php @@ -18,9 +18,9 @@ require_once "Visualization/Chart.php"; */ class Piwik_Visualization_Chart_Evolution extends Piwik_Visualization_Chart { - function customizeGraph() + function customizeChartProperties() { - parent::customizeGraph(); + parent::customizeChartProperties(); $dataSetsToDisplay = $this->getDataSetsToDisplay(); if($dataSetsToDisplay === false) { @@ -61,18 +61,14 @@ class Piwik_Visualization_Chart_Evolution extends Piwik_Visualization_Chart $lineValues = array(); $j = 0; foreach($this->xLabels as $label) { - $value = $yValues[$j]; + $value = (float)$yValues[$j]; $lineValue = new hollow_dot($value); - $unit = ''; - if(!empty($this->yUnits[$dataSetToDisplay])) - { - $unit = $this->yUnits[$dataSetToDisplay]; - } + $unit = $this->yUnit; $lineValue->tooltip("$label<br>$value$unit $labelName"); if(!empty($this->xOnClick)) { - $lineValue->on_click('redirectToUrl("'.$this->xOnClick[$j].'")'); + $lineValue->on_click('piwikHelper.redirectToUrl("'.$this->xOnClick[$j].'")'); } $lineValues[] = $lineValue; $j++; @@ -87,8 +83,8 @@ class Piwik_Visualization_Chart_Evolution extends Piwik_Visualization_Chart } // if one column is a percentage we set the grid accordingly // note: it is invalid to plot a percentage dataset along with a numeric dataset - //TODO only if the max was 100!! - if(array_search('%', $this->yUnits) !== false) + if($this->yUnit == '%' + && $this->maxValue > 90) { $this->y->set_range( 0, 100, 50); } diff --git a/core/Visualization/Chart/Pie.php b/core/Visualization/Chart/Pie.php index 12effb7f6c..542770e6f4 100644 --- a/core/Visualization/Chart/Pie.php +++ b/core/Visualization/Chart/Pie.php @@ -28,9 +28,9 @@ class Piwik_Visualization_Chart_Pie extends Piwik_Visualization_Chart return array_slice($dataSetsToDisplay, 0, 1); } - function customizeGraph() + function customizeChartProperties() { - parent::customizeGraph(); + parent::customizeChartProperties(); $dataSetsToDisplay = $this->getDataSetsToDisplay(); if($dataSetsToDisplay === false) { @@ -49,12 +49,12 @@ class Piwik_Visualization_Chart_Pie extends Piwik_Visualization_Chart // create the Pie values $yValues = $this->yValues[$dataSetToDisplay]; $labelName = $this->yLabels[$dataSetToDisplay]; - $unit = @$this->yUnits[$dataSetToDisplay]; + $unit = $this->yUnit; $sum = array_sum($yValues); $pieValues = array(); $i = 0; foreach($this->xLabels as $label) { - $value = $yValues[$i]; + $value = (float)$yValues[$i]; $i++; // we never plot empty pie slices (eg. visits by server time pie chart) if($value <= 0) { diff --git a/core/Visualization/Chart/VerticalBar.php b/core/Visualization/Chart/VerticalBar.php index c9794f4f00..5dbd954bac 100644 --- a/core/Visualization/Chart/VerticalBar.php +++ b/core/Visualization/Chart/VerticalBar.php @@ -29,9 +29,9 @@ class Piwik_Visualization_Chart_VerticalBar extends Piwik_Visualization_Chart return array_slice($dataSetsToDisplay, 0, 1); } - function customizeGraph() + function customizeChartProperties() { - parent::customizeGraph(); + parent::customizeChartProperties(); $dataSetsToDisplay = $this->getDataSetsToDisplay(); if($dataSetsToDisplay === false) { @@ -52,13 +52,21 @@ class Piwik_Visualization_Chart_VerticalBar extends Piwik_Visualization_Chart // create the bar values $yValues = $this->yValues[$dataSetToDisplay]; $labelName = $this->yLabels[$dataSetToDisplay]; - $unit = @$this->yUnits[$dataSetToDisplay]; + $unit = $this->yUnit; $barValues = array(); $i = 0; + $sum = array_sum($yValues); foreach($this->xLabels as $label) { - $value = $yValues[$i]; + $value = (float)$yValues[$i]; + + $displayPercentage = ''; + if($this->displayPercentageInTooltip) + { + $percentage = round(100 * $value / $sum); + $displayPercentage = "($percentage%)"; + } $barValue = new bar_value($value); - $barValue->set_tooltip("$label<br>$value$unit $labelName"); + $barValue->set_tooltip("$label<br>$value$unit $labelName $displayPercentage"); $barValues[] = $barValue; $i++; } diff --git a/core/Visualization/Cloud.php b/core/Visualization/Cloud.php index 287c57d86c..b3d6d26719 100644 --- a/core/Visualization/Cloud.php +++ b/core/Visualization/Cloud.php @@ -44,6 +44,9 @@ class Piwik_Visualization_Cloud { $this->shuffleCloud(); $return = array(); + if(empty($this->wordsArray)) { + return array(); + } $maxValue = max($this->wordsArray); foreach ($this->wordsArray as $word => $popularity) { diff --git a/core/Visualization/Sparkline.php b/core/Visualization/Sparkline.php index 5dba26696a..369f0b3e6c 100644 --- a/core/Visualization/Sparkline.php +++ b/core/Visualization/Sparkline.php @@ -69,7 +69,7 @@ class Piwik_Visualization_Sparkline implements Piwik_iView $i++; } $sparkline->SetYMin(0); - $sparkline->setYMax($max[1] + 1); // the +1 seems to be mandatory to not lose some pixels when value = max + $sparkline->setYMax($max[1] + 0.5); // the +0.5 seems to be mandatory to not lose some pixels when value = max $sparkline->SetPadding( 3, 0, 2, 0); $font = FONT_2; // the -0.5 is a hack as the sparkline samping rendering is obviously slightly bugged @@ -78,7 +78,9 @@ class Piwik_Visualization_Sparkline implements Piwik_iView $sparkline->SetFeaturePoint($max[0] -0.5, $max[1], 'green', 5); $sparkline->SetFeaturePoint($last[0] -0.5, $last[1], 'blue', 5); $sparkline->SetLineSize(3); // for renderresampled, linesize is on virtual image - $sparkline->RenderResampled($width, $height); + $ratio = 1; +// var_dump($min);var_dump($max);var_dump($lasts);exit; + $sparkline->RenderResampled($width*$ratio, $height*$ratio); $this->sparkline = $sparkline; } diff --git a/core/iView.php b/core/iView.php index 04c93c6600..6c21b1e94f 100644 --- a/core/iView.php +++ b/core/iView.php @@ -10,18 +10,13 @@ */ /** - * Piwik_ViewDataTable must create a $view attribute which implements this interface. - * * @package Piwik_Visualization */ interface Piwik_iView { /** * Outputs the data. - * Either outputs html, xml, an image, nothing, etc. - * - * @return mixed - * + * @return mixed (image, array, html...) */ function render(); } |