diff options
281 files changed, 6651 insertions, 3983 deletions
@@ -23,7 +23,7 @@ Piwik is released under the GPL v3 (or later) license, see [misc/gpl-3.0.txt](mi ## Requirements - * PHP 5.1.3 or greater, and recommended PHP 5.3 or greater + * PHP 5.3 or greater * MySQL 4.1 or greater, and either MySQLi or PDO library must be enabled * Piwik is OS / server independent diff --git a/config/global.ini.php b/config/global.ini.php index 10d71efd31..1114efc681 100644 --- a/config/global.ini.php +++ b/config/global.ini.php @@ -494,6 +494,7 @@ logger_file_path = tmp/logs Plugins[] = CorePluginsAdmin Plugins[] = CoreAdminHome Plugins[] = CoreHome +Plugins[] = CoreVisualizations Plugins[] = Proxy Plugins[] = API Plugins[] = Widgetize diff --git a/core/API/DataTableManipulator.php b/core/API/DataTableManipulator.php index e93c1f5c87..9e5d3d9868 100644 --- a/core/API/DataTableManipulator.php +++ b/core/API/DataTableManipulator.php @@ -77,6 +77,9 @@ abstract class DataTableManipulator /** * Manipulates child DataTables of a DataTable_Array. See @manipulate for more info. + * + * @param DataTable\Map $dataTable + * @return DataTable\Map */ protected function manipulateDataTableArray($dataTable) { diff --git a/core/API/DataTableManipulator/LabelFilter.php b/core/API/DataTableManipulator/LabelFilter.php index fdc5114c98..45ca278fc1 100644 --- a/core/API/DataTableManipulator/LabelFilter.php +++ b/core/API/DataTableManipulator/LabelFilter.php @@ -64,7 +64,7 @@ class LabelFilter extends DataTableManipulator * * @param array $labelParts * @param DataTable $dataTable - * @return Row|false + * @return Row|bool */ private function doFilterRecursiveDescend($labelParts, $dataTable) { diff --git a/core/API/DocumentationGenerator.php b/core/API/DocumentationGenerator.php index 50362fc60b..a419895a42 100644 --- a/core/API/DocumentationGenerator.php +++ b/core/API/DocumentationGenerator.php @@ -123,7 +123,7 @@ class DocumentationGenerator * @param string $class the class * @param string $methodName the method * @param array $parametersToSet parameters to set - * @return string|false when not possible + * @return string|bool when not possible */ public function getExampleUrl($class, $methodName, $parametersToSet = array()) { diff --git a/core/Access.php b/core/Access.php index 4866080812..303e5d638d 100644 --- a/core/Access.php +++ b/core/Access.php @@ -13,6 +13,7 @@ namespace Piwik; use Piwik\Config; use Piwik\Common; use Piwik\Auth; +use Piwik\Site; use Piwik\Db; /** @@ -421,7 +422,7 @@ class Access $idSites = $this->getSitesIdWithAtLeastViewAccess(); } - $idSites = \Piwik\Site::getIdSitesFromIdSitesString($idSites); + $idSites = Site::getIdSitesFromIdSitesString($idSites); if (empty($idSites)) { throw new NoAccessException("The parameter 'idSite=' is missing from the request."); } diff --git a/core/Archive.php b/core/Archive.php index 1d7d226f33..2c53a8e665 100644 --- a/core/Archive.php +++ b/core/Archive.php @@ -169,9 +169,9 @@ class Archive * * @param string|array $names One or more archive names, eg, 'nb_visits', 'Referers_distinctKeywords', * etc. - * @return numeric|array|false False if no value with the given name, numeric if only one site - * and date and we're not forcing an index, and array if multiple - * sites/dates are queried. + * @return mixed False if no value with the given name, numeric if only one site + * and date and we're not forcing an index, and array if multiple + * sites/dates are queried. */ public function getNumeric($names) { @@ -200,7 +200,7 @@ class Archive * * @param string|array $names One or more archive names, eg, 'Referers_keywordBySearchEngine'. * @param null $idSubtable - * @return string|array|false False if no value with the given name, numeric if only one site + * @return string|array|bool False if no value with the given name, numeric if only one site * and date and we're not forcing an index, and array if multiple * sites/dates are queried. */ @@ -217,9 +217,9 @@ class Archive * * @param string|array $names One or more archive names, eg, 'nb_visits', 'Referers_distinctKeywords', * etc. - * @return DataTable|false False if no value with the given names. Based on the number - * of sites/periods, the result can be a DataTable_Array, which - * contains DataTable instances. + * @return DataTable|DataTable\Map|bool False if no value with the given names. Based on the number + * of sites/periods, the result can be a DataTable_Array, which + * contains DataTable instances. */ public function getDataTableFromNumeric($names) { @@ -237,7 +237,7 @@ class Archive * * @param string $name The name of the record to get. * @param int|string|null $idSubtable The subtable ID (if any) or 'all' if requesting every datatable. - * @return DataTable|false + * @return DataTable|DataTable\Map|bool */ public function getDataTable($name, $idSubtable = null) { @@ -251,15 +251,17 @@ class Archive * Manager::getTable() function. * * @param string $name The name of the record to get. - * @param int|string|null $idSubtable The subtable ID (if any) or self::ID_SUBTABLE_LOAD_ALL_SUBTABLES if requesting every datatable. + * @param int|string|null $idSubtable The subtable ID (if any) or self::ID_SUBTABLE_LOAD_ALL_SUBTABLES + * if requesting every datatable. + * @param int|null $depth The maximum number of subtable levels to load. If null, all levels are loaded. * @param bool $addMetadataSubtableId Whether to add the DB subtable ID as metadata to each datatable, * or not. * @return DataTable */ - public function getDataTableExpanded($name, $idSubtable = null, $addMetadataSubtableId = true) + public function getDataTableExpanded($name, $idSubtable = null, $depth = null, $addMetadataSubtableId = true) { $data = $this->get($name, 'blob', self::ID_SUBTABLE_LOAD_ALL_SUBTABLES); - return $data->getExpandedDataTable($this->getResultIndices(), $idSubtable, $addMetadataSubtableId); + return $data->getExpandedDataTable($this->getResultIndices(), $idSubtable, $depth, $addMetadataSubtableId); } /** @@ -291,7 +293,8 @@ class Archive * @param int|null $idSubtable * @return DataTable|DataTable\Map */ - public static function getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded, $idSubtable = null) + public static function getDataTableFromArchive($name, $idSite, $period, $date, $segment, $expanded, + $idSubtable = null, $depth = null) { Piwik::checkUserHasViewAccess($idSite); $archive = Archive::build($idSite, $period, $date, $segment); @@ -300,7 +303,7 @@ class Archive } if ($expanded) { - $dataTable = $archive->getDataTableExpanded($name, $idSubtable); + $dataTable = $archive->getDataTableExpanded($name, $idSubtable, $depth); } else { $dataTable = $archive->getDataTable($name, $idSubtable); } @@ -320,7 +323,7 @@ class Archive * @param array|string $archiveNames * @param $archiveDataType * @param null|int $idSubtable - * @return DataCollection + * @return Archive\DataCollection */ private function get($archiveNames, $archiveDataType, $idSubtable = null) { diff --git a/core/Archive/DataCollection.php b/core/Archive/DataCollection.php index 4b05615c21..9103ae8ad6 100644 --- a/core/Archive/DataCollection.php +++ b/core/Archive/DataCollection.php @@ -93,7 +93,7 @@ class DataCollection * '2012-02-01,2012-02-28' => new Period(...), * ) * - * @var array + * @var \Piwik\Period[] */ private $periods; @@ -103,7 +103,7 @@ class DataCollection * @param array $dataNames @see $this->dataNames * @param string $dataType @see $this->dataType * @param array $sitesId @see $this->sitesId - * @param array $periods @see $this->periods + * @param \Piwik\Period[] $periods @see $this->periods * @param array $defaultRow @see $this->defaultRow */ public function __construct($dataNames, $dataType, $sitesId, $periods, $defaultRow = null) @@ -204,7 +204,7 @@ class DataCollection * by the metadata specified here. * * Eg, array('site' => 'idSite', 'period' => 'Date') - * @return \Piwik\DataTable|Set + * @return DataTable|DataTable\Map */ public function getDataTable($resultIndices) { @@ -228,13 +228,14 @@ class DataCollection * by the metadata specified here. * * Eg, array('site' => 'idSite', 'period' => 'Date') - * @param int $idSubtable The subtable to return. - * @param bool $addMetadataSubtableId Whether to add the DB subtable ID as metadata + * @param int|null $idSubTable The subtable to return. + * @param int|null $depth max depth for subtables. + * @param bool $addMetadataSubTableId Whether to add the DB subtable ID as metadata * to each datatable, or not. * @throws Exception - * @return \Piwik\DataTable|Set + * @return DataTable|DataTable\Map */ - public function getExpandedDataTable($resultIndices, $idSubtable = null, $addMetadataSubtableId = false) + public function getExpandedDataTable($resultIndices, $idSubTable = null, $depth = null, $addMetadataSubTableId = false) { if ($this->dataType != 'blob') { throw new Exception("DataCollection: cannot call getExpandedDataTable with " @@ -248,8 +249,8 @@ class DataCollection $dataTableFactory = new DataTableFactory( $this->dataNames, 'blob', $this->sitesId, $this->periods, $this->defaultRow); - $dataTableFactory->expandDataTable($addMetadataSubtableId); - $dataTableFactory->useSubtable($idSubtable); + $dataTableFactory->expandDataTable($depth, $addMetadataSubTableId); + $dataTableFactory->useSubtable($idSubTable); $index = $this->getArray($resultIndices); return $dataTableFactory->make($index, $resultIndices); diff --git a/core/Archive/DataTableFactory.php b/core/Archive/DataTableFactory.php index d571b06d60..6d6e170d7e 100644 --- a/core/Archive/DataTableFactory.php +++ b/core/Archive/DataTableFactory.php @@ -15,8 +15,6 @@ use Piwik\Site; use Piwik\DataTable; use Piwik\DataTable\Row; -const FIX_ME_OMG = 'this is a warning and reminder to fix this code '; - /** * Creates a DataTable or Set instance based on an array * index created by DataCollection. @@ -53,6 +51,14 @@ class DataTableFactory private $addMetadataSubtableId = false; /** + * The maximum number of subtable levels to create when creating an expanded + * DataTable. + * + * @var int + */ + private $maxSubtableDepth = null; + + /** * @see DataCollection::$sitesId. */ private $sitesId; @@ -92,13 +98,15 @@ class DataTableFactory * Tells the factory instance to expand the DataTables that are created by * creating subtables and setting the subtable IDs of rows w/ subtables correctly. * + * @param null|int $maxSubtableDepth max depth for subtables. * @param bool $addMetadataSubtableId Whether to add the subtable ID used in the * database to the in-memory DataTables as * metadata or not. */ - public function expandDataTable($addMetadataSubtableId = false) + public function expandDataTable($maxSubtableDepth = null, $addMetadataSubtableId = false) { $this->expandDataTable = true; + $this->maxSubtableDepth = $maxSubtableDepth; $this->addMetadataSubtableId = $addMetadataSubtableId; } @@ -126,7 +134,7 @@ class DataTableFactory * @param array $index @see DataCollection * @param array $resultIndices an array mapping metadata names with pretty metadata * labels. - * @return DataTable|Set + * @return DataTable|DataTable\Map */ public function make($index, $resultIndices) { @@ -160,7 +168,7 @@ class DataTableFactory * the created DataTable's subtables will be expanded. * * @param array $blobRow - * @return DataTable|Set + * @return DataTable|DataTable\Map */ private function makeFromBlobRow($blobRow) { @@ -237,7 +245,7 @@ class DataTableFactory * @param array $index @see DataCollection * @param array $resultIndices @see make * @param array $keyMetadata The metadata to add to the table when it's created. - * @return Set + * @return DataTable\Map */ private function createDataTableArrayFromIndex($index, $resultIndices, $keyMetadata = array()) { @@ -267,7 +275,7 @@ class DataTableFactory /** * Creates a DataTable instance from an index row. * - * @param array|false $data An archive data row. + * @param array $data An archive data row. * @param array $keyMetadata The metadata to add to the table(s) when created. * @return DataTable|DataTable\Map */ @@ -292,9 +300,7 @@ class DataTableFactory // would break. if (count($this->dataNames) == 1) { $name = reset($this->dataNames); - $table->addRow(new Row(array( - Row::COLUMNS => array($name => 0) - ))); + $table->addRow(new Row(array(Row::COLUMNS => array($name => 0)))); } } @@ -329,8 +335,19 @@ class DataTableFactory * with blob values. This should hold every subtable blob for * the loaded DataTable. */ - private function setSubtables($dataTable, $blobRow) + private function setSubtables($dataTable, $blobRow, $treeLevel = 0) { + if ($this->maxSubtableDepth + && $treeLevel >= $this->maxSubtableDepth + ) { + // unset the subtables so DataTableManager doesn't throw + foreach ($dataTable->getRows() as $row) { + $row->removeSubtable(); + } + + return; + } + $dataName = reset($this->dataNames); foreach ($dataTable->getRows() as $row) { @@ -342,7 +359,7 @@ class DataTableFactory $blobName = $dataName . "_" . $sid; if (isset($blobRow[$blobName])) { $subtable = DataTable::fromSerializedArray($blobRow[$blobName]); - $this->setSubtables($subtable, $blobRow); + $this->setSubtables($subtable, $blobRow, $treeLevel + 1); // we edit the subtable ID so that it matches the newly table created in memory // NB: we dont overwrite the datatableid in the case we are displaying the table expanded. @@ -366,9 +383,7 @@ class DataTableFactory $periods = $this->periods; $table->filter(function ($table) use ($periods) { $table->metadata['site'] = new Site($table->metadata['site']); - $table->metadata['period'] = empty($periods[$table->metadata['period']]) - ? FIX_ME_OMG - : $periods[$table->metadata['period']]; + $table->metadata['period'] = $periods[$table->metadata['period']]; }); } @@ -381,12 +396,9 @@ class DataTableFactory */ private function prettifyIndexLabel($labelType, $label) { - if (empty($this->periods[$label])) { - return $label; // BAD BUG FIXME - } if ($labelType == 'period') { // prettify period labels return $this->periods[$label]->getPrettyString(); } return $label; } -} +}
\ No newline at end of file diff --git a/core/ArchiveProcessor/Period.php b/core/ArchiveProcessor/Period.php index 6f7085c1a9..778b41f075 100644 --- a/core/ArchiveProcessor/Period.php +++ b/core/ArchiveProcessor/Period.php @@ -165,7 +165,7 @@ class Period extends ArchiveProcessor $table->setColumnAggregationOperations($columnAggregationOperations); } - $data = $this->archiver->getDataTableExpanded($name, $idSubTable = null, $addMetadataSubtableId = false); + $data = $this->archiver->getDataTableExpanded($name, $idSubTable = null, $depth = null, $addMetadataSubtableId = false); if ($data instanceof DataTable\Map) { foreach ($data->getArray() as $date => $tableToSum) { $table->addDataTable($tableToSum); diff --git a/core/ArchiveProcessor/Rules.php b/core/ArchiveProcessor/Rules.php index 9b22d018bd..b1d1d57eb2 100644 --- a/core/ArchiveProcessor/Rules.php +++ b/core/ArchiveProcessor/Rules.php @@ -144,7 +144,8 @@ class Rules return false; } - public static function getMinTimeProcessedForTemporaryArchive(Date $dateStart, \Piwik\Period $period, Segment $segment, Site $site) + public static function getMinTimeProcessedForTemporaryArchive( + Date $dateStart, \Piwik\Period $period, Segment $segment, Site $site) { $now = time(); $minimumArchiveTime = $now - Rules::getTodayArchiveTimeToLive(); diff --git a/core/AssetManager.php b/core/AssetManager.php index df3448126e..79f81fafe1 100644 --- a/core/AssetManager.php +++ b/core/AssetManager.php @@ -103,9 +103,7 @@ class AssetManager $mergedCssAlreadyGenerated = self::isGenerated(self::MERGED_CSS_FILE); $isDevelopingPiwik = self::isMergedAssetsDisabled(); - if ($mergedCssAlreadyGenerated - && !$isDevelopingPiwik - ) { + if ($mergedCssAlreadyGenerated && !$isDevelopingPiwik) { return; } @@ -154,8 +152,8 @@ class AssetManager $mergedContent = $firstLineCompileHash . "\n" - . "/* Piwik CSS file is compiled with Less. You may be interested in writing a custom Theme for Piwik! */\n" - . $mergedContent; + . "/* Piwik CSS file is compiled with Less. You may be interested in writing a custom Theme for Piwik! */\n" + . $mergedContent; self::writeAssetToFile($mergedContent, self::MERGED_CSS_FILE); } @@ -171,7 +169,7 @@ class AssetManager /* * Rewrite css url directives - * - assumes these are all relative paths + * - rewrites relative paths * - rewrite windows directory separator \\ to / */ protected static function rewriteCssPathsDirectives($relativePath, $content) @@ -184,10 +182,16 @@ class AssetManager $baseDirectory = dirname($relativePath); $content = preg_replace_callback( "/(url\(['\"]?)([^'\")]*)/", - create_function( - '$matches', - "return \$matches[1] . str_replace('\\\\', '/', substr(realpath(PIWIK_DOCUMENT_ROOT . '/$baseDirectory/' . \$matches[2]), $rootDirectoryLength));" - ), + function ($matches) use ($rootDirectoryLength, $baseDirectory) { + $absolutePath = substr(realpath(PIWIK_DOCUMENT_ROOT . "/$baseDirectory/" . $matches[2]), $rootDirectoryLength); + $rewritten = str_replace('\\', '/', $absolutePath); + + if (is_file($rewritten)) { // only rewrite the URL if transforming it points to a valid file + return $matches[1] . $rewritten; + } else { + return $matches[1] . $matches[2]; + } + }, $content ); return $content; @@ -268,6 +272,7 @@ class AssetManager 'plugins/Zeitgeist/stylesheets/base.less', 'plugins/Zeitgeist/stylesheets/', 'plugins/', + 'plugins/Dashboard/stylesheets/dashboard.less', ); return self::prioritySort($priorityCssOrdered, $cssFiles); diff --git a/core/Common.php b/core/Common.php index 2a1bae68d9..9b7373ef2c 100644 --- a/core/Common.php +++ b/core/Common.php @@ -505,7 +505,7 @@ class Common // $_GET and $_REQUEST already urldecode()'d // decode // note: before php 5.2.7, htmlspecialchars() double encodes &#x hex items - $value = html_entity_decode($value, \Piwik\Common::HTML_ENCODING_QUOTE_STYLE, 'UTF-8'); + $value = html_entity_decode($value, self::HTML_ENCODING_QUOTE_STYLE, 'UTF-8'); // filter $value = str_replace(array("\n", "\r", "\0"), '', $value); @@ -790,36 +790,6 @@ class Common } /** - * Should we use the replacement json_encode/json_decode functions? - * - * @return bool True if broken; false otherwise - */ - private static function useJsonLibrary() - { - static $useLib; - - if (!isset($useLib)) { - /* - * 5.1.x - doesn't have json extension; we use lib/upgradephp instead - * 5.2 to 5.2.4 - broken in various ways, including: - * - * @see https://bugs.php.net/bug.php?id=38680 'json_decode cannot decode basic types' - * @see https://bugs.php.net/bug.php?id=41403 'json_decode cannot decode floats' - * @see https://bugs.php.net/bug.php?id=42785 'json_encode outputs numbers according to locale' - */ - $useLib = false; - if (version_compare(PHP_VERSION, '5.2.1') < 0) { - $useLib = true; - } else if (version_compare(PHP_VERSION, '5.2.5') < 0) { - $info = localeconv(); - $useLib = $info['decimal_point'] != '.'; - } - } - - return $useLib; - } - - /** * JSON encode wrapper * - missing or broken in some php 5.x versions * @@ -828,10 +798,6 @@ class Common */ public static function json_encode($value) { - if (self::useJsonLibrary()) { - return _json_encode($value); - } - return @json_encode($value); } @@ -845,10 +811,6 @@ class Common */ public static function json_decode($json, $assoc = false) { - if (self::useJsonLibrary()) { - return _json_decode($json, $assoc); - } - return json_decode($json, $assoc); } @@ -1209,7 +1171,7 @@ class Common * * @see unit tests in /tests/core/Common.test.php * @param string $referrerUrl URL referer URL, eg. $_SERVER['HTTP_REFERER'] - * @return array|false false if a keyword couldn't be extracted, + * @return array|bool false if a keyword couldn't be extracted, * or array( * 'name' => 'Google', * 'keywords' => 'my searched keywords') diff --git a/core/Config.php b/core/Config.php index 40f032d851..ef3ad1dc8f 100644 --- a/core/Config.php +++ b/core/Config.php @@ -73,6 +73,9 @@ class Config protected $pathGlobal = null; protected $pathLocal = null; + /** + * Constructor + */ protected function __construct() { $this->pathGlobal = self::getGlobalConfigPath(); diff --git a/core/Controller.php b/core/Controller.php index dd122579bd..8eb9774f05 100644 --- a/core/Controller.php +++ b/core/Controller.php @@ -19,6 +19,7 @@ use Piwik\Period\Range; use Piwik\Piwik; use Piwik\Common; use Piwik\Access; +use Piwik\NoAccessException; use Piwik\Date; use Piwik\Site; use Piwik\Plugins\API\API; @@ -30,7 +31,6 @@ use Piwik\Url; use Piwik\Plugins\UsersManager\API as UsersManagerAPI; use Piwik\View; use Piwik\ViewDataTable; -use Piwik\ViewDataTable\GenerateGraphHTML\ChartEvolution; use Zend_Registry; /** @@ -173,12 +173,13 @@ abstract class Controller * @param string $currentModuleName * @param string $currentControllerAction * @param string $apiMethod - * @return ChartEvolution + * @return ViewDataTable */ protected function getLastUnitGraph($currentModuleName, $currentControllerAction, $apiMethod) { - $view = ViewDataTable::factory('graphEvolution'); - $view->init($currentModuleName, $currentControllerAction, $apiMethod); + $view = ViewDataTable::factory( + 'graphEvolution', $apiMethod, $currentModuleName . '.' . $currentControllerAction, $forceDefault = true); + $view->show_goals = false; return $view; } @@ -194,7 +195,7 @@ abstract class Controller * @param bool|string $reportDocumentation * @param string $apiMethod The method to request the report from * (by default, this is API.get but it can be changed for custom stuff) - * @return ChartEvolution + * @return ViewDataTable */ protected function getLastUnitGraphAcrossPlugins($currentModuleName, $currentControllerAction, $columnsToDisplay, $selectableColumns = array(), $reportDocumentation = false, $apiMethod = 'API.get') @@ -220,14 +221,14 @@ abstract class Controller // initialize the graph and load the data $view = $this->getLastUnitGraph($currentModuleName, $currentControllerAction, $apiMethod); $view->columns_to_display = $columnsToDisplay; - $view->selectable_columns = array_merge($view->selectable_columns, $selectableColumns); + $view->visualization_properties->selectable_columns = + array_merge($view->visualization_properties->selectable_columns ?: array(), $selectableColumns); $view->translations += $translations; if ($reportDocumentation) { $view->documentation = $reportDocumentation; } - $view->main(); return $view; } @@ -268,7 +269,7 @@ abstract class Controller } if (is_null($this->site)) { - throw new \Piwik\NoAccessException("Website not initialized, check that you are logged in and/or using the correct token_auth."); + throw new NoAccessException("Website not initialized, check that you are logged in and/or using the correct token_auth."); } $paramDate = self::getDateRangeRelativeToEndDate($period, $range, $endDate, $this->site); @@ -572,39 +573,6 @@ abstract class Controller } /** - * Set metrics variables (displayed metrics, available metrics) used by template - * Handles the server-side of the metrics picker - * - * @param View|ViewDataTable $view - * @param string $defaultMetricDay name of the default metric for period=day - * @param string $defaultMetric name of the default metric for other periods - * @param array $metricsForDay metrics that are only available for period=day - * @param array $metricsForAllPeriods metrics that are available for all periods - * @param bool $labelDisplayed add 'label' to columns to display? - * @return void - */ - protected function setMetricsVariablesView(ViewDataTable $view, $defaultMetricDay = 'nb_uniq_visitors', - $defaultMetric = 'nb_visits', $metricsForDay = array('nb_uniq_visitors'), - $metricsForAllPeriods = array('nb_visits', 'nb_actions'), $labelDisplayed = true) - {// TODO: needed? - // columns is set in the request if metrics picker has been used - $columns = Common::getRequestVar('columns', false); - if ($columns !== false) { - $columns = Piwik::getArrayFromApiParameter($columns); - $firstColumn = $columns[0]; - } else { - // default columns - $firstColumn = isset($view->period) && $view->period == 'day' ? $defaultMetricDay : $defaultMetric; - $columns = array($firstColumn); - } - // displayed columns - if ($labelDisplayed) { - array_unshift($columns, 'label'); - } - $view->columns_to_display = $columns; - } - - /** * Helper method used to redirect the current http request to another module/action * If specified, will also redirect to a given website, period and /or date * @@ -744,7 +712,7 @@ abstract class Controller protected function checkTokenInUrl() { if (Common::getRequestVar('token_auth', false) != Piwik::getCurrentUserTokenAuth()) { - throw new \Piwik\NoAccessException(Piwik_TranslateException('General_ExceptionInvalidToken')); + throw new NoAccessException(Piwik_TranslateException('General_ExceptionInvalidToken')); } } diff --git a/core/DataAccess/LogAggregator.php b/core/DataAccess/LogAggregator.php index b05bd327cb..afc262529f 100644 --- a/core/DataAccess/LogAggregator.php +++ b/core/DataAccess/LogAggregator.php @@ -66,6 +66,13 @@ class LogAggregator /** @var \Piwik\Segment */ protected $segment; + /** + * Constructor + * @param Date $dateStart + * @param Date $dateEnd + * @param Site $site + * @param Segment $segment + */ public function __construct(Date $dateStart, Date $dateEnd, Site $site, Segment $segment) { $this->dateStart = $dateStart; diff --git a/core/DataTable.php b/core/DataTable.php index e655587652..de2ba54fbf 100644 --- a/core/DataTable.php +++ b/core/DataTable.php @@ -470,7 +470,7 @@ class DataTable * Returns the Row that has a column 'label' with the value $label * * @param string $label Value of the column 'label' of the row to return - * @return \Piwik\DataTable\Row|false The row if found, false otherwise + * @return \Piwik\DataTable\Row|bool The row if found, false otherwise */ public function getRowFromLabel($label) { @@ -564,7 +564,7 @@ class DataTable * Returns a row that has the subtable ID matching the parameter * * @param int $idSubTable - * @return \Piwik\DataTable\Row|false if not found + * @return \Piwik\DataTable\Row|bool false if not found */ public function getRowFromIdSubDataTable($idSubTable) { @@ -714,13 +714,23 @@ class DataTable */ public function getColumns() { + $result = array(); foreach ($this->getRows() as $row) { $columns = $row->getColumns(); if (!empty($columns)) { - return array_keys($columns); + $result = array_keys($columns); + break; + } + } + + // make sure column names are not DB index values + foreach ($result as &$column) { + if (isset(Metrics::$mappingFromIdToName[$column])) { + $column = Metrics::$mappingFromIdToName[$column]; } } - return array(); + + return $result; } /** diff --git a/core/DataTable/Filter/AddColumnsProcessedMetrics.php b/core/DataTable/Filter/AddColumnsProcessedMetrics.php index 99503a522b..1a4dfbf8bc 100644 --- a/core/DataTable/Filter/AddColumnsProcessedMetrics.php +++ b/core/DataTable/Filter/AddColumnsProcessedMetrics.php @@ -102,9 +102,9 @@ class AddColumnsProcessedMetrics extends Filter * - raw datatables coming from the archive DB, which columns are int indexed * - datatables processed resulting of API calls, which columns have human readable english names * - * @param Row $row + * @param Row|array $row * @param int $columnIdRaw see consts in Archive:: - * @param bool $mappingIdToName + * @param bool|array $mappingIdToName * @return mixed Value of column, false if not found */ protected function getColumn($row, $columnIdRaw, $mappingIdToName = false) diff --git a/core/DataTable/Filter/CalculateEvolutionFilter.php b/core/DataTable/Filter/CalculateEvolutionFilter.php index f8d5886d25..ec39aa7d08 100755 --- a/core/DataTable/Filter/CalculateEvolutionFilter.php +++ b/core/DataTable/Filter/CalculateEvolutionFilter.php @@ -30,6 +30,8 @@ class CalculateEvolutionFilter extends ColumnCallbackAddColumnPercentage { /** * The the DataTable that contains past data. + * + * @var DataTable */ private $pastDataTable; @@ -42,7 +44,7 @@ class CalculateEvolutionFilter extends ColumnCallbackAddColumnPercentage * Constructor. * * @param DataTable $table The DataTable being filtered. - * @param string $pastDataTable + * @param DataTable $pastDataTable * @param string $columnToAdd * @param string $columnToRead * @param int $quotientPrecision @@ -125,6 +127,7 @@ class CalculateEvolutionFilter extends ColumnCallbackAddColumnPercentage * Utility function. Returns the current row in the past DataTable. * * @param Row $row The row in the 'current' DataTable. + * @return bool|Row */ private function getPastRowFromCurrent($row) { diff --git a/core/DataTable/Filter/MetadataCallbackReplace.php b/core/DataTable/Filter/MetadataCallbackReplace.php index affbc6f4ab..e10119c9fe 100644 --- a/core/DataTable/Filter/MetadataCallbackReplace.php +++ b/core/DataTable/Filter/MetadataCallbackReplace.php @@ -49,7 +49,7 @@ class MetadataCallbackReplace extends ColumnCallbackReplace /** * @param Row $row * @param string $metadataToFilter - * @return array|false|mixed + * @return array|bool|mixed */ protected function getElementToReplace($row, $metadataToFilter) { diff --git a/core/DataTable/Filter/ReplaceColumnNames.php b/core/DataTable/Filter/ReplaceColumnNames.php index 0e1d40fe75..a11d5e3c9f 100644 --- a/core/DataTable/Filter/ReplaceColumnNames.php +++ b/core/DataTable/Filter/ReplaceColumnNames.php @@ -66,6 +66,9 @@ class ReplaceColumnNames extends Filter } } + /** + * @param DataTable $table + */ protected function filterTable($table) { foreach ($table->getRows() as $key => $row) { @@ -76,6 +79,9 @@ class ReplaceColumnNames extends Filter } } + /** + * @param Simple $table + */ protected function filterSimple(Simple $table) { foreach ($table->getRows() as $row) { diff --git a/core/DataTable/Map.php b/core/DataTable/Map.php index 76a2c642f8..ea35f0365d 100644 --- a/core/DataTable/Map.php +++ b/core/DataTable/Map.php @@ -290,7 +290,7 @@ class Map * This function can be used, for example, to smoosh IndexedBySite archive * query results into one DataTable w/ different rows differentiated by site ID. * - * @return DataTable|Set + * @return DataTable|Map */ public function mergeChildren() { @@ -367,7 +367,7 @@ class Map * * @see DataTable::mergeSubtables * - * @return Set + * @return Map */ public function mergeSubtables() { @@ -382,7 +382,7 @@ class Map * Returns a new DataTable_Array w/o any child DataTables, but with * the same key name as this instance. * - * @return Set + * @return Map */ public function getEmptyClone() { diff --git a/core/DataTable/Renderer.php b/core/DataTable/Renderer.php index 0cefcc5f29..d62514c1f4 100644 --- a/core/DataTable/Renderer.php +++ b/core/DataTable/Renderer.php @@ -11,6 +11,7 @@ namespace Piwik\DataTable; use Exception; +use Piwik\Loader; use Piwik\Metrics; use Piwik\Piwik; use Piwik\DataTable; @@ -30,6 +31,10 @@ use Piwik\DataTable\Simple; abstract class Renderer { protected $table; + + /** + * @var Exception + */ protected $exception; protected $renderSubTables = false; protected $hideIdSubDatatable = false; @@ -107,7 +112,7 @@ abstract class Renderer /** * Computes the dataTable output and returns the string/binary * - * @return string + * @return mixed */ abstract public function render(); @@ -200,7 +205,7 @@ abstract class Renderer $className = ucfirst(strtolower($name)); $className = 'Piwik\DataTable\Renderer\\' . $className; try { - \Piwik\Loader::loadClass($className); + Loader::loadClass($className); return new $className; } catch (Exception $e) { $availableRenderers = implode(', ', self::getRenderers()); diff --git a/core/DataTable/Renderer/Csv.php b/core/DataTable/Renderer/Csv.php index 03074897d4..48b107877f 100644 --- a/core/DataTable/Renderer/Csv.php +++ b/core/DataTable/Renderer/Csv.php @@ -182,7 +182,7 @@ class Csv extends Renderer /** * Converts the output of the given simple data table * - * @param Simple $table + * @param DataTable|Simple $table * @param array $allColumns * @return string */ diff --git a/core/DataTable/Renderer/Html.php b/core/DataTable/Renderer/Html.php index 035726a9ed..ccac0c07d9 100644 --- a/core/DataTable/Renderer/Html.php +++ b/core/DataTable/Renderer/Html.php @@ -107,7 +107,7 @@ class Html extends Renderer /** * Adds the given data table to the table structure array * - * @param Simple $table + * @param DataTable $table * @param null|string $columnToAdd * @param null|string $valueToAdd * @throws Exception diff --git a/core/DataTable/Renderer/Php.php b/core/DataTable/Renderer/Php.php index 6717746295..9dbf3800c8 100644 --- a/core/DataTable/Renderer/Php.php +++ b/core/DataTable/Renderer/Php.php @@ -123,7 +123,7 @@ class Php extends Renderer * 'col2_name' => value2, * 'metadata1_name' => value_metadata ) * - * @param null|DataTable\Map|Simple $dataTable + * @param null|DataTable|DataTable\Map|Simple $dataTable * @return array Php array representing the 'flat' version of the datatable */ public function flatRender($dataTable = null) diff --git a/core/DataTable/Renderer/Rss.php b/core/DataTable/Renderer/Rss.php index 3061ddbc67..491962f5db 100644 --- a/core/DataTable/Renderer/Rss.php +++ b/core/DataTable/Renderer/Rss.php @@ -74,6 +74,7 @@ class Rss extends Renderer $out = ""; $moreRecentFirst = array_reverse($table->getArray(), true); foreach ($moreRecentFirst as $date => $subtable) { + /** @var DataTable $subtable */ $timestamp = $subtable->getMetadata('period')->getDateStart()->getTimestamp(); $site = $subtable->getMetadata('site'); @@ -141,6 +142,11 @@ class Rss extends Renderer return $header; } + /** + * @param DataTable $table + * + * @return string + */ protected function renderDataTable($table) { if ($table->getRowsCount() == 0) { diff --git a/core/DataTable/Renderer/Xml.php b/core/DataTable/Renderer/Xml.php index bc5e34ad87..b3bba128cc 100644 --- a/core/DataTable/Renderer/Xml.php +++ b/core/DataTable/Renderer/Xml.php @@ -63,7 +63,7 @@ class Xml extends Renderer /** * Converts the given data table to an array * - * @param DataTable $table data table to convert + * @param DataTable|DataTable/Map $table data table to convert * @return array */ protected function getArrayFromDataTable($table) @@ -83,7 +83,7 @@ class Xml extends Renderer /** * Computes the output for the given data table * - * @param DataTable $table + * @param DataTable|DataTable/Map $table * @param bool $returnOnlyDataTableXml * @param string $prefixLines * @return array|string @@ -343,6 +343,8 @@ class Xml extends Renderer } return $xml; } + + return ''; } /** diff --git a/core/DataTable/Row.php b/core/DataTable/Row.php index 3b4a0d6df9..286c56c177 100644 --- a/core/DataTable/Row.php +++ b/core/DataTable/Row.php @@ -202,7 +202,7 @@ class Row * Returns the given column * * @param string $name Column name - * @return mixed|false The column value + * @return mixed|bool The column value or false if it doesn't exist */ public function getColumn($name) { @@ -217,7 +217,7 @@ class Row * or the specified metadata * * @param string $name Metadata name - * @return mixed|array|false + * @return mixed */ public function getMetadata($name = null) { @@ -261,7 +261,7 @@ class Row /** * Returns the associated subtable, if one exists. * - * @return DataTable|false + * @return DataTable|bool false if no subtable loaded */ public function getSubtable() { @@ -519,6 +519,9 @@ class Row return $newValue; } + /** + * @param Row $rowToSum + */ public function sumRowMetadata($rowToSum) { if (!empty($rowToSum->c[self::METADATA]) diff --git a/core/DataTable/Row/DataTableSummaryRow.php b/core/DataTable/Row/DataTableSummaryRow.php index f4203d9489..b98343f91f 100644 --- a/core/DataTable/Row/DataTableSummaryRow.php +++ b/core/DataTable/Row/DataTableSummaryRow.php @@ -40,14 +40,14 @@ class DataTableSummaryRow extends Row } /** - * Reset this row to an empty one and sum the associated subtable again. + * Reset this row to an empty one and sum the associated subTable again. */ public function recalculate() { $id = $this->getIdSubDataTable(); if ($id !== null) { - $subtable = Manager::getInstance()->getTable($id); - $this->sumTable($subtable); + $subTable = Manager::getInstance()->getTable($id); + $this->sumTable($subTable); } } diff --git a/core/DataTableVisualization.php b/core/DataTableVisualization.php new file mode 100644 index 0000000000..e0be29e8d1 --- /dev/null +++ b/core/DataTableVisualization.php @@ -0,0 +1,232 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ + +namespace Piwik; + +use Piwik\DataTable; + +/** + * Base class for all DataTable visualizations. Different visualizations are used to + * handle different values of the viewDataTable query parameter. Each one will display + * DataTable data in a different way. + * + * TODO: must be more in depth + */ +abstract class DataTableVisualization +{ + /** + * This event is used to gather all available DataTable visualizations. Callbacks + * should add visualization class names to the incoming array. + * + * Callback Signature: function (&$visualizations) {} + */ + const GET_AVAILABLE_EVENT = 'DataTableVisualization.getAvailable'; + + /** + * Rendering function. Must return the view HTML. + * + * @param DataTable|DataTable\Map $dataTable The data. + * @param array $properties The view properties. + * @return string The visualization HTML. + */ + public abstract function render($dataTable, $properties); + + /** + * Returns the array of view properties that a DataTable visualization will require + * to be both visible to client side JavaScript, and passed along as query parameters + * in every AJAX request. + * + * Derived DataTableVisualizations can specify client side parameters by declaring + * a static $clientSideParameters field. + * + * @return array + */ + public static function getClientSideParameters() + { + if (isset(static::$clientSideParameters)) { + $result = array(); + + $lineage = static::getVisualizationClassLineage(get_called_class()); + foreach ($lineage as $klass) { + if (isset($klass::$clientSideParameters)) { + $result = array_merge($result, $klass::$clientSideParameters); + } + } + + return array_unique($result); + } else { + return array(); + } + } + + /** + * Returns an array of view property names that a DataTable visualization will + * require to be visible to client side JavaScript. Unlike 'client side parameters', + * these will not be passed with AJAX requests as query parameters. + * + * Derived DataTableVisualizations can specify client side properties by declaring + * a static $clientSideProperties field. + * + * @return array + */ + public static function getClientSideProperties() + { + if (isset(static::$clientSideProperties)) { + $result = array(); + + $lineage = static::getVisualizationClassLineage(get_called_class()); + foreach ($lineage as $klass) { + if (isset($klass::$clientSideProperties)) { + $result = array_merge($result, $klass::$clientSideProperties); + } + } + + return array_unique($result); + } else { + return array(); + } + } + + /** + * Returns the viewDataTable ID for this DataTable visualization. Derived classes + * should declare a const ID field with the viewDataTable ID. + * + * @return string + */ + public static function getViewDataTableId() + { + if (defined('static::ID')) { + return static::ID; + } else { + return Piwik::getUnnamespacedClassName($this); + } + } + + /** + * Returns the list of parents for a DataTableVisualization class excluding the + * DataTableVisualization class and above. + * + * @param string $klass The class name of the DataTableVisualization. + * @return DataTableVisualization[] The list of parent classes in order from highest + * ancestor to the descended class. + */ + public static function getVisualizationClassLineage($klass) + { + $klasses = array_merge(array($klass), class_parents($klass, $autoload = false)); + + $idx = array_search('Piwik\\DataTableVisualization', $klasses); + if ($idx !== false) { + unset($klasses[$idx]); + } + + return array_reverse($klasses); + } + + /** + * Returns the viewDataTable IDs of a visualization's class lineage. + * + * @see self::getVisualizationClassLineage + * + * @param string $klass The visualization class. + * + * @return DataTableVisualization[] + */ + public static function getVisualizationIdsWithInheritance($klass) + { + $klasses = self::getVisualizationClassLineage($klass); + + $result = array(); + foreach ($klasses as $klass) { + $result[] = $klass::getViewDataTableId(); + } + return $result; + } + + /** + * Returns all registered visualization classes. Uses the 'DataTableVisualization.getAvailable' + * event to retrieve visualizations. + * + * @return array Array mapping visualization IDs with their associated visualization classes. + * @throws \Exception If a visualization class does not exist or if a duplicate visualization ID + * is found. + */ + public static function getAvailableVisualizations() + { + $visualizations = array(); + Piwik_PostEvent(self::GET_AVAILABLE_EVENT, array(&$visualizations)); + + $result = array(); + foreach ($visualizations as $viz) { + if (!class_exists($viz)) { + throw new \Exception( + "Invalid visualization class '$viz' found in DataTableVisualization.getAvailableVisualizations."); + } + + if (is_subclass_of($viz, __CLASS__)) { + $vizId = $viz::getViewDataTableId(); + if (isset($result[$vizId])) { + throw new \Exception("Visualization ID '$vizId' is already in use!"); + } + + $result[$vizId] = $viz; + } + } + return $result; + } + + /** + * Returns all available visualizations that are not part of the CoreVisualizations plugin. + * + * @return array Array mapping visualization IDs with their associated visualization classes. + */ + public static function getNonCoreVisualizations() + { + $result = array(); + foreach (self::getAvailableVisualizations() as $vizId => $vizClass) { + if (strpos($vizClass, 'Piwik\\Plugins\\CoreVisualizations') === false) { + $result[$vizId] = $vizClass; + } + } + return $result; + } + + /** + * Returns an array mapping visualization IDs with information necessary for adding the + * visualizations to the footer of DataTable views. + * + * @param array $visualizations An array mapping visualization IDs w/ their associated classes. + * @return array + */ + public static function getVisualizationInfoFor($visualizations) + { + $result = array(); + foreach ($visualizations as $vizId => $vizClass) { + $result[$vizId] = array('table_icon' => $vizClass::FOOTER_ICON, 'title' => $vizClass::FOOTER_ICON_TITLE); + } + return $result; + } + + /** + * Returns the visualization class by it's viewDataTable ID. + * + * @param string $id The visualization ID. + * @return string The visualization class name. + * @throws \Exception if $id is not a valid visualization ID. + */ + public static function getClassFromId($id) + { + $visualizationClasses = self::getAvailableVisualizations(); + if (!isset($visualizationClasses[$id])) { + throw new \Exception("Invalid DataTable visualization ID: '$id'."); + } + return $visualizationClasses[$id]; + } +}
\ No newline at end of file diff --git a/core/Date.php b/core/Date.php index 3fb96665e0..22580bd492 100644 --- a/core/Date.php +++ b/core/Date.php @@ -19,6 +19,8 @@ use Exception; */ class Date { + const NUM_SECONDS_IN_DAY = 86400; + /** * The stored timestamp is always UTC based. * The returned timestamp via getTimestamp() will have the conversion applied @@ -641,4 +643,15 @@ class Date { return $this->addPeriod(-$n, $period); } + + /** + * Returns the number of days represented by a number of seconds. + * + * @param int $secs + * @return float + */ + public static function secondsToDays($secs) + { + return $secs / self::NUM_SECONDS_IN_DAY; + } } diff --git a/core/Db/Adapter.php b/core/Db/Adapter.php index ca66d53c91..55283b608d 100644 --- a/core/Db/Adapter.php +++ b/core/Db/Adapter.php @@ -75,7 +75,7 @@ class Adapter */ private static function getAdapterClassName($adapterName) { - return 'Piwik\Db\Adapter\\' . str_replace(' ', '\\', ucwords(str_replace('_', ' ', strtolower($adapterName)))); + return 'Piwik\Db\Adapter\\' . str_replace(' ', '\\', ucwords(str_replace(array('_','\\'), ' ', strtolower($adapterName)))); } /** diff --git a/core/Db/Adapter/Pdo/Mysql.php b/core/Db/Adapter/Pdo/Mysql.php index 34ec106a87..bd14b9ddf4 100644 --- a/core/Db/Adapter/Pdo/Mysql.php +++ b/core/Db/Adapter/Pdo/Mysql.php @@ -198,6 +198,9 @@ class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface return null; } + /** + * @var \Zend_Db_Statement_Pdo[] + */ private $cachePreparedStatement = array(); /** diff --git a/core/FrontController.php b/core/FrontController.php index 5837256a55..88ddad8cf8 100644 --- a/core/FrontController.php +++ b/core/FrontController.php @@ -10,7 +10,7 @@ */ namespace Piwik; -use \Piwik\NoAccessException; +use Piwik\NoAccessException; use Exception; use Piwik\API\Request; use Piwik\API\ResponseBuilder; @@ -63,7 +63,7 @@ class FrontController * @param string $module * @param string $action * @param array $parameters - * @return mixed The returned value of the calls, often nothing as the module print but don't return data + * @return void|mixed The returned value of the calls, often nothing as the module print but don't return data * @see fetchDispatch() */ public function dispatch($module = null, $action = null, $parameters = null) @@ -128,7 +128,7 @@ class FrontController try { return call_user_func_array(array($params[0], $params[1]), $params[2]); - } catch (\Piwik\NoAccessException $e) { + } catch (NoAccessException $e) { Piwik_PostEvent('FrontController.NoAccessException', array($e), $pending = true); } catch (Exception $e) { $debugTrace = $e->getTraceAsString(); @@ -373,5 +373,3 @@ class PluginDeactivatedException extends Exception parent::__construct("The plugin $module is not enabled. You can activate the plugin on Settings > Plugins page in Piwik."); } } - - diff --git a/core/IP.php b/core/IP.php index e4a87cb9ee..2940884ba8 100644 --- a/core/IP.php +++ b/core/IP.php @@ -39,7 +39,7 @@ class IP * Sanitize human-readable IP address. * * @param string $ipString IP address - * @return string|false + * @return string */ public static function sanitizeIp($ipString) { @@ -87,7 +87,7 @@ class IP * - wildcards, e.g., 192.168.0.* * * @param string $ipRangeString IP address range - * @return string|false IP address range in CIDR notation + * @return string|bool IP address range in CIDR notation OR false */ public static function sanitizeIpRange($ipRangeString) { @@ -261,7 +261,7 @@ class IP * Get low and high IP addresses for a specified range. * * @param array $ipRange An IP address range in presentation format - * @return array|false Array ($lowIp, $highIp) in network address format, or false if failure + * @return array|bool Array ($lowIp, $highIp) in network address format, or false if failure */ public static function getIpsForRange($ipRange) { @@ -449,7 +449,7 @@ class IP * @link http://php.net/inet_ntop * * @param string $in_addr 32-bit IPv4 or 128-bit IPv6 address - * @return string|false string representation of address or false on failure + * @return string|bool string representation of address or false on failure */ static public function php_compat_inet_ntop($in_addr) { diff --git a/core/Log.php b/core/Log.php index 7d1348f172..7b048d851c 100644 --- a/core/Log.php +++ b/core/Log.php @@ -33,6 +33,13 @@ abstract class Log extends \Zend_Log protected $screenFormatter = null; protected $currentRequestKey; + /** + * @param string $logToFileFilename filename of logfile + * @param \Zend_Log_Formatter_Interface $fileFormatter + * @param \Zend_Log_Formatter_Interface $screenFormatter + * @param string $logToDatabaseTableName + * @param array $logToDatabaseColumnMapping + */ function __construct($logToFileFilename, $fileFormatter, $screenFormatter, diff --git a/core/Log/ScreenFormatter.php b/core/Log/ScreenFormatter.php index 550ad628b0..cc8778beeb 100644 --- a/core/Log/ScreenFormatter.php +++ b/core/Log/ScreenFormatter.php @@ -17,17 +17,35 @@ use Piwik\Common; */ class ScreenFormatter implements \Zend_Log_Formatter_Interface { + /** + * Returns the formatted event array + * + * @param array $event + * @return array + */ function formatEvent($event) { // no injection in error messages, backtrace when displayed on screen return array_map(array('Piwik\Common', 'sanitizeInputValue'), $event); } + /** + * Returns the formatted String + * + * @param string $string + * @return string + */ function format($string) { return self::getFormattedString($string); } + /** + * Returns the formatted String + * + * @param string $string + * @return string + */ static public function getFormattedString($string) { if (!Common::isPhpCliMode()) { diff --git a/core/Nonce.php b/core/Nonce.php index 8f876b1890..d7606854f9 100644 --- a/core/Nonce.php +++ b/core/Nonce.php @@ -103,7 +103,7 @@ class Nonce /** * Get ORIGIN header, false if not found * - * @return string|false + * @return string|bool */ static public function getOrigin() { diff --git a/core/Option.php b/core/Option.php index 653363bfc1..dab41eac1e 100644 --- a/core/Option.php +++ b/core/Option.php @@ -61,7 +61,7 @@ class Option * Returns the option value for the requested option $name, fetching from database, if not in cache. * * @param string $name Key - * @return string|false Value or false, if not found + * @return string|bool Value or false, if not found */ public function get($name) { diff --git a/core/Period/Range.php b/core/Period/Range.php index 65e4854de0..4ee8baa2b5 100644 --- a/core/Period/Range.php +++ b/core/Period/Range.php @@ -266,8 +266,8 @@ class Range extends Period * Determine which kind of period is best to use * See Range.test.php * - * @param $startDate - * @param $endDate + * @param Date $startDate + * @param Date $endDate */ protected function processOptimalSubperiods($startDate, $endDate) { diff --git a/core/Period/Week.php b/core/Period/Week.php index c975aba135..622bf4ba94 100644 --- a/core/Period/Week.php +++ b/core/Period/Week.php @@ -49,6 +49,13 @@ class Week extends Period return Piwik_Translate('CoreHome_PeriodWeek') . " " . $string; } + /** + * @param string $format + * @param \Piwik\Date $dateStart + * @param \Piwik\Date $dateEnd + * + * @return mixed + */ static protected function getTranslatedRange($format, $dateStart, $dateEnd) { $string = str_replace('From%', '%', $format); diff --git a/core/Piwik.php b/core/Piwik.php index 7dff9430aa..af4a187c4b 100644 --- a/core/Piwik.php +++ b/core/Piwik.php @@ -12,6 +12,7 @@ namespace Piwik; use Exception; use Piwik\Access; +use Piwik\NoAccessException; use Piwik\AssetManager; use Piwik\Common; use Piwik\Config; @@ -251,8 +252,8 @@ class Piwik } /* - * File and directory operations - */ + * File and directory operations + */ /** * Copy recursively from $source to $target. @@ -887,8 +888,8 @@ class Piwik } /* - * PHP environment settings - */ + * PHP environment settings + */ /** * Set maximum script execution time. @@ -909,7 +910,7 @@ class Piwik * compile-time default, so ini_get('memory_limit') may return false. * * @see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes - * @return int|false memory limit in megabytes, or false if there is no limit + * @return int|bool memory limit in megabytes, or false if there is no limit */ static public function getMemoryLimitValue() { @@ -984,10 +985,11 @@ class Piwik return false; } - /* - * Logging and error handling - */ - + /** + * Logging and error handling + * + * @var bool|null + */ public static $shouldLog = null; /** @@ -1059,8 +1061,8 @@ class Piwik } /* - * Profiling - */ + * Profiling + */ /** * Get total number of queries @@ -1131,6 +1133,7 @@ class Piwik /** * Outputs SQL Profiling reports * It is automatically called when enabling the SQL profiling in the config file enable_sql_profiler + * * @throws Exception */ static function printSqlProfilingReportZend() @@ -1243,9 +1246,9 @@ class Piwik return "$usage Mb"; } -/* - * Amounts, Percentages, Currency, Time, Math Operations, and Pretty Printing - */ + /* + * Amounts, Percentages, Currency, Time, Math Operations, and Pretty Printing + */ /** * Returns a list of currency symbols @@ -1561,8 +1564,8 @@ class Piwik } /* - * Access - */ + * Access + */ /** * Get current user email address @@ -1640,7 +1643,7 @@ class Piwik * Check that current user is either the specified user or the superuser * * @param string $theUser - * @throws \Piwik\NoAccessException if the user is neither the super user nor the user $theUser + * @throws NoAccessException if the user is neither the super user nor the user $theUser */ static public function checkUserIsSuperUserOrTheUser($theUser) { @@ -1649,8 +1652,8 @@ class Piwik // or to the super user Piwik::checkUserIsSuperUser(); } - } catch (\Piwik\NoAccessException $e) { - throw new \Piwik\NoAccessException(Piwik_Translate('General_ExceptionCheckUserIsSuperUserOrTheUser', array($theUser))); + } catch (NoAccessException $e) { + throw new NoAccessException(Piwik_Translate('General_ExceptionCheckUserIsSuperUserOrTheUser', array($theUser))); } } @@ -1682,12 +1685,12 @@ class Piwik /** * Checks if user is not the anonymous user. * - * @throws \Piwik\NoAccessException if user is anonymous. + * @throws NoAccessException if user is anonymous. */ static public function checkUserIsNotAnonymous() { if (self::isUserIsAnonymous()) { - throw new \Piwik\NoAccessException(Piwik_Translate('General_YouMustBeLoggedIn')); + throw new NoAccessException(Piwik_Translate('General_YouMustBeLoggedIn')); } } @@ -1817,8 +1820,8 @@ class Piwik } /* - * Current module, action, plugin - */ + * Current module, action, plugin + */ /** * Returns the name of the Login plugin currently being used. @@ -1902,8 +1905,8 @@ class Piwik } /* - * Global database object - */ + * Global database object + */ /** * Create database object and connect to database @@ -1962,12 +1965,12 @@ class Piwik } /* - * Global log object - */ + * Global log object + */ /* - * User input validation - */ + * User input validation + */ /** * Returns true if the email is a valid email @@ -2032,8 +2035,8 @@ class Piwik } /* - * Date / Timezone - */ + * Date / Timezone + */ /** * Determine if this php version/build supports timezone manipulation @@ -2053,8 +2056,8 @@ class Piwik } /* - * Database and table definition methods - */ + * Database and table definition methods + */ /** * Is the schema available? @@ -2482,4 +2485,17 @@ class Piwik { return "lastRunArchive" . $period . "_" . $idSite; } + + /** + * Returns the class name of an object without its namespace. + * + * @param mixed|string $object + * @return string + */ + public static function getUnnamespacedClassName($object) + { + $className = is_string($object) ? $object : get_class($object); + $parts = explode('\\', $className); + return end($parts); + } } diff --git a/core/Plugin.php b/core/Plugin.php index 756d4ae4f3..03db5df17c 100644 --- a/core/Plugin.php +++ b/core/Plugin.php @@ -13,7 +13,7 @@ use Piwik\Common; use Piwik\Plugin\MetadataLoader; /** - * @see core/Plugin/MetadataLoader.php + * @see Piwik\Plugin\MetadataLoader */ require_once PIWIK_INCLUDE_PATH . '/core/Plugin/MetadataLoader.php'; diff --git a/core/PluginsArchiver.php b/core/PluginsArchiver.php index eb3b24592d..2e76fd3fcd 100644 --- a/core/PluginsArchiver.php +++ b/core/PluginsArchiver.php @@ -23,6 +23,10 @@ abstract class PluginsArchiver { protected $processor; + /** + * Constructor + * @param ArchiveProcessor $processing + */ public function __construct(ArchiveProcessor $processing) { $this->maximumRows = Config::getInstance()->General['datatable_archiving_maximum_rows_standard']; diff --git a/core/PluginsManager.php b/core/PluginsManager.php index b4af8fbac0..50ede0d98d 100644 --- a/core/PluginsManager.php +++ b/core/PluginsManager.php @@ -43,6 +43,7 @@ class PluginsManager 'CoreUpdater', 'CoreAdminHome', 'CorePluginsAdmin', + 'CoreVisualizations', 'Installation', 'SitesManager', 'UsersManager', @@ -281,13 +282,21 @@ class PluginsManager return; } + // Only one theme enabled at a time + $themeAlreadyEnabled = $this->getThemeEnabled(); + if($themeAlreadyEnabled) { + $plugin = $this->loadPlugin($pluginName); + if($plugin->isTheme()) { + $plugins = $this->deactivatePlugin( $themeAlreadyEnabled, $plugins ); + } + } + + // Load plugin $plugin = $this->loadPlugin($pluginName); if ($plugin === null) { return; } - $this->installPluginIfNecessary($plugin); - $plugin->activate(); // we add the plugin to the list of activated plugins @@ -296,12 +305,6 @@ class PluginsManager } $plugins = array_unique($plugins); - // Only one theme enabled at a time - $themeAlreadyEnabled = $this->getThemeEnabled(); - if($plugin->isTheme() - && $themeAlreadyEnabled) { - $plugins = $this->deactivatePlugin( $themeAlreadyEnabled, $plugins ); - } // the config file will automatically be saved with the new plugin $this->updatePluginsConfig($plugins); @@ -605,7 +608,7 @@ class PluginsManager { // we are in Tracker mode if Loader is not (yet) loaded if (!class_exists('Piwik\Loader', false)) { - return; + return false; } $pluginName = $plugin->getPluginName(); @@ -652,7 +655,7 @@ class PluginsManager $plugins = Config::getInstance()->Plugins['Plugins']; foreach ($plugins as $pluginName) { // if a plugin is listed in the config, but is not loaded, it does not exist in the folder - if (!\Piwik\PluginsManager::getInstance()->isPluginLoaded($pluginName)) { + if (!self::getInstance()->isPluginLoaded($pluginName)) { $missingPlugins[] = $pluginName; } } diff --git a/core/ScheduledTime.php b/core/ScheduledTime.php index af6c82c946..ec4d3fcab8 100644 --- a/core/ScheduledTime.php +++ b/core/ScheduledTime.php @@ -48,6 +48,11 @@ abstract class ScheduledTime */ public $day = 1; + /** + * @param $period + * @return Daily|Monthly|Weekly + * @throws \Exception + */ static public function getScheduledTimeForPeriod($period) { switch ($period) { diff --git a/core/ScheduledTime/Daily.php b/core/ScheduledTime/Daily.php index af6a6e4f4f..28505c616b 100644 --- a/core/ScheduledTime/Daily.php +++ b/core/ScheduledTime/Daily.php @@ -22,6 +22,10 @@ use Piwik\ScheduledTime; */ class Daily extends ScheduledTime { + /** + * @see ScheduledTime::getRescheduledTime + * @return int + */ public function getRescheduledTime() { $currentTime = $this->getTime(); @@ -41,6 +45,11 @@ class Daily extends ScheduledTime return $rescheduledTime; } + /** + * @see ScheduledTime::setDay + * @param int $_day + * @throws \Exception + */ public function setDay($_day) { throw new Exception ("Method not supported"); diff --git a/core/ScheduledTime/Hourly.php b/core/ScheduledTime/Hourly.php index 70a62bb757..4a88042834 100644 --- a/core/ScheduledTime/Hourly.php +++ b/core/ScheduledTime/Hourly.php @@ -22,6 +22,10 @@ use Piwik\ScheduledTime; */ class Hourly extends ScheduledTime { + /** + * @see ScheduledTime::getRescheduledTime + * @return int + */ public function getRescheduledTime() { $currentTime = $this->getTime(); @@ -37,11 +41,23 @@ class Hourly extends ScheduledTime return $rescheduledTime; } + /** + * @see ScheduledTime::setHour + * @param int $_hour + * @throws \Exception + * @return int + */ public function setHour($_hour) { throw new Exception ("Method not supported"); } + /** + * @see ScheduledTime::setDay + * @param int $_day + * @throws \Exception + * @return int + */ public function setDay($_day) { throw new Exception ("Method not supported"); diff --git a/core/ScheduledTime/Weekly.php b/core/ScheduledTime/Weekly.php index 40b348c153..8cad7961f6 100644 --- a/core/ScheduledTime/Weekly.php +++ b/core/ScheduledTime/Weekly.php @@ -23,6 +23,10 @@ use Piwik\ScheduledTime; class Weekly extends ScheduledTime { + /** + * @see ScheduledTime::getRescheduledTime + * @return int + */ public function getRescheduledTime() { $currentTime = $this->getTime(); diff --git a/core/Session/SaveHandler/DbTable.php b/core/Session/SaveHandler/DbTable.php index 3f1d53a08f..60f5c77d9d 100644 --- a/core/Session/SaveHandler/DbTable.php +++ b/core/Session/SaveHandler/DbTable.php @@ -134,7 +134,7 @@ class DbTable implements Zend_Session_SaveHandler_Interface * than $maxlifetime (in seconds) * * @param int $maxlifetime timestamp in seconds - * @return true + * @return bool always true */ public function gc($maxlifetime) { diff --git a/core/TaskScheduler.php b/core/TaskScheduler.php index a102e55252..6ca306bcde 100644 --- a/core/TaskScheduler.php +++ b/core/TaskScheduler.php @@ -48,6 +48,7 @@ class TaskScheduler // collect tasks $tasks = array(); Piwik_PostEvent(self::GET_TASKS_EVENT, array(&$tasks)); + /** @var ScheduledTask[] $tasks */ // remove from timetable tasks that are not active anymore $activeTaskNames = array(); diff --git a/core/Timer.php b/core/Timer.php index d3f1e29d79..c1d17a8020 100644 --- a/core/Timer.php +++ b/core/Timer.php @@ -21,43 +21,71 @@ class Timer private $timerStart; private $memoryStart; + /** + * @return \Piwik\Timer + */ public function __construct() { $this->init(); } + /** + * @return void + */ public function init() { $this->timerStart = $this->getMicrotime(); $this->memoryStart = $this->getMemoryUsage(); } + /** + * @param int $decimals + * @return string + */ public function getTime($decimals = 3) { return number_format($this->getMicrotime() - $this->timerStart, $decimals, '.', ''); } + /** + * @param int $decimals + * @return string + */ public function getTimeMs($decimals = 3) { return number_format(1000 * ($this->getMicrotime() - $this->timerStart), $decimals, '.', ''); } + /** + * @return string + */ public function getMemoryLeak() { return "Memory delta: " . Piwik::getPrettySizeFromBytes($this->getMemoryUsage() - $this->memoryStart); } + /** + * @return string + */ public function __toString() { return "Time elapsed: " . $this->getTime() . "s"; } + /** + * @return float + */ private function getMicrotime() { list($micro_seconds, $seconds) = explode(" ", microtime()); return ((float)$micro_seconds + (float)$seconds); } + /** + * Returns current memory usage, if available + * + * @return int + */ private function getMemoryUsage() { if (function_exists('memory_get_usage')) { diff --git a/core/Tracker.php b/core/Tracker.php index 4042524422..8b28a73596 100644 --- a/core/Tracker.php +++ b/core/Tracker.php @@ -24,6 +24,7 @@ use Piwik\Tracker\Db\Pdo\Mysql; use Piwik\Tracker\Request; use Piwik\Tracker\Visit; use Piwik\Tracker\VisitInterface; +use Piwik\PluginsManager; use Zend_Registry; /** @@ -134,11 +135,17 @@ class Tracker return self::$pluginsNotToLoad; } + /** + * @return array + */ static public function getPluginsToLoad() { return self::$pluginsToLoad; } + /** + * @param array $plugins + */ static public function setPluginsToLoad($plugins) { self::$pluginsToLoad = $plugins; @@ -363,7 +370,7 @@ class Tracker Piwik::createDatabaseObject(); } - $pluginsManager = \Piwik\PluginsManager::getInstance(); + $pluginsManager = PluginsManager::getInstance(); $pluginsToLoad = Config::getInstance()->Plugins['Plugins']; $pluginsForcedNotToLoad = Tracker::getPluginsNotToLoad(); $pluginsToLoad = array_diff($pluginsToLoad, $pluginsForcedNotToLoad); @@ -477,7 +484,8 @@ class Tracker public static function factory($configDb) { switch ($configDb['adapter']) { - case 'PDO_MYSQL': + case 'PDO\MYSQL': + case 'PDO_MYSQL': // old format pre Piwik 2 require_once PIWIK_INCLUDE_PATH . '/core/Tracker/Db/Pdo/Mysql.php'; return new Mysql($configDb); @@ -614,9 +622,9 @@ class Tracker $pluginsTracker = Config::getInstance()->Plugins_Tracker['Plugins_Tracker']; if (count($pluginsTracker) > 0) { $pluginsTracker = array_diff($pluginsTracker, self::getPluginsNotToLoad()); - \Piwik\PluginsManager::getInstance()->doNotLoadAlwaysActivatedPlugins(); + PluginsManager::getInstance()->doNotLoadAlwaysActivatedPlugins(); - \Piwik\PluginsManager::getInstance()->loadPlugins($pluginsTracker); + PluginsManager::getInstance()->loadPlugins($pluginsTracker); Common::printDebug("Loading plugins: { " . implode(",", $pluginsTracker) . " }"); } diff --git a/core/Tracker/Action.php b/core/Tracker/Action.php index 3d9e290876..ee434789ec 100644 --- a/core/Tracker/Action.php +++ b/core/Tracker/Action.php @@ -713,7 +713,7 @@ class Action implements ActionInterface /** * Returns the ID of the newly created record in the log_link_visit_action table * - * @return int | false + * @return int */ public function getIdLinkVisitAction() { diff --git a/core/Tracker/GoalManager.php b/core/Tracker/GoalManager.php index 56c989ffa9..7e36d61a72 100644 --- a/core/Tracker/GoalManager.php +++ b/core/Tracker/GoalManager.php @@ -57,6 +57,10 @@ class GoalManager protected $request; protected $orderId; + /** + * Constructor + * @param Request $request + */ public function __construct(Request $request) { $this->request = $request; @@ -224,7 +228,7 @@ class GoalManager * @param int $idSite * @param array $visitorInformation * @param array $visitCustomVariables - * @param string $action + * @param Action $action */ public function recordGoals($idSite, $visitorInformation, $visitCustomVariables, $action) { @@ -411,7 +415,7 @@ class GoalManager /** * Returns Items read from the request string - * @return array|false + * @return array|bool */ protected function getEcommerceItemsFromRequest() { diff --git a/core/Tracker/Request.php b/core/Tracker/Request.php index e52e89424a..dce2aceaf3 100644 --- a/core/Tracker/Request.php +++ b/core/Tracker/Request.php @@ -29,6 +29,10 @@ class Request protected $forcedVisitorId = false; + /** + * @param $params + * @param bool|string $tokenAuth + */ public function __construct($params, $tokenAuth = false) { if (!is_array($params)) { @@ -56,6 +60,9 @@ class Request const UNKNOWN_RESOLUTION = 'unknown'; + /** + * @return bool + */ public function isAuthenticated() { return $this->isAuthenticated; @@ -112,6 +119,9 @@ class Request return false; } + /** + * @return float|int + */ public function getDaysSinceFirstVisit() { $cookieFirstVisitTimestamp = $this->getParam('_idts'); @@ -125,6 +135,9 @@ class Request return $daysSinceFirstVisit; } + /** + * @return bool|float|int + */ public function getDaysSinceLastOrder() { $daysSinceLastOrder = false; @@ -138,6 +151,9 @@ class Request return $daysSinceLastOrder; } + /** + * @return float|int + */ public function getDaysSinceLastVisit() { $daysSinceLastVisit = 0; @@ -151,6 +167,9 @@ class Request return $daysSinceLastVisit; } + /** + * @return int|mixed + */ public function getVisitCount() { $visitCount = $this->getParam('_idvc'); @@ -170,6 +189,9 @@ class Request return Common::getRequestVar('lang', Common::getBrowserLanguage(), 'string', $this->params); } + /** + * @return string + */ public function getLocalTime() { $localTimes = array( diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php index 9121936339..74ab001bae 100644 --- a/core/Tracker/Visit.php +++ b/core/Tracker/Visit.php @@ -16,9 +16,16 @@ namespace Piwik\Tracker; */ interface VisitInterface { - function setRequest(Request $request); + /** + * @param Request $request + * @return void + */ + public function setRequest(Request $request); - function handle(); + /** + * @return void + */ + public function handle(); } use Piwik\Config; @@ -68,7 +75,10 @@ class Visit implements Tracker\VisitInterface protected $visitorCustomVariables = array(); protected $visitorKnown; - function setRequest(Request $request) + /** + * @param Request $request + */ + public function setRequest(Request $request) { $this->request = $request; } @@ -603,7 +613,7 @@ class Visit implements Tracker\VisitInterface /** * Returns visitor cookie * - * @return binary + * @return string binary */ protected function getVisitorIdcookie() { @@ -631,7 +641,7 @@ class Visit implements Tracker\VisitInterface /** * Returns the visitor's IP address * - * @return long + * @return string */ protected function getVisitorIp() { diff --git a/core/Tracker/VisitExcluded.php b/core/Tracker/VisitExcluded.php index c7a43ddda6..3ee3234f48 100644 --- a/core/Tracker/VisitExcluded.php +++ b/core/Tracker/VisitExcluded.php @@ -21,6 +21,11 @@ use Piwik\Tracker\Request; */ class VisitExcluded { + /** + * @param Request $request + * @param bool|string $ip + * @param bool|string $userAgent + */ public function __construct(Request $request, $ip = false, $userAgent = false) { if ($ip === false) { diff --git a/core/Twig.php b/core/Twig.php index ae79b90e89..5f6550512e 100644 --- a/core/Twig.php +++ b/core/Twig.php @@ -34,8 +34,8 @@ use Twig_SimpleFunction; */ class 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>'; + const SPARKLINE_TEMPLATE = '<img alt="" data-src="%s" width="%d" height="%d" /> + <script type="text/javascript">$(function() { piwik.initSparklines(); });</script>'; /** * @var Twig_Environment @@ -74,6 +74,15 @@ class Twig $this->addFunction_loadJavascriptTranslations(); $this->addFunction_sparkline(); $this->addFunction_postEvent(); + $this->addFunction_isPluginLoaded(); + } + + protected function addFunction_isPluginLoaded() + { + $isPluginLoadedFunction = new Twig_SimpleFunction('isPluginLoaded', function ($pluginName) { + return PluginsManager::getInstance()->isPluginLoaded($pluginName); + }); + $this->twig->addFunction($isPluginLoadedFunction); } protected function addFunction_includeAssets() diff --git a/core/UpdateCheck.php b/core/UpdateCheck.php index 29261f8341..770a69eff3 100644 --- a/core/UpdateCheck.php +++ b/core/UpdateCheck.php @@ -83,7 +83,7 @@ class UpdateCheck /** * Returns version number of a newer Piwik release. * - * @return string|false false if current version is the latest available, + * @return string|bool false if current version is the latest available, * or the latest version number if a newest release is available */ public static function isNewestVersionAvailable() diff --git a/core/Updater.php b/core/Updater.php index b6b13de4c6..eca0d3fd4f 100644 --- a/core/Updater.php +++ b/core/Updater.php @@ -29,6 +29,9 @@ class Updater private $componentsToCheck = array(); private $hasMajorDbUpdate = false; + /** + * Constructor + */ public function __construct() { $this->pathUpdateFileCore = PIWIK_INCLUDE_PATH . '/core/Updates/'; diff --git a/core/Updates.php b/core/Updates.php index 9f5e7ab1ee..e54ff50569 100644 --- a/core/Updates.php +++ b/core/Updates.php @@ -45,6 +45,8 @@ abstract class Updates /** * Tell the updater that this is a major update. * Leads to a more visible notice. + * + * @return bool */ static function isMajorUpdate() { diff --git a/core/Url.php b/core/Url.php index 80923d972c..d3a22688d6 100644 --- a/core/Url.php +++ b/core/Url.php @@ -250,7 +250,7 @@ class Url * * @param bool $checkIfTrusted Whether to do trusted host check. Should ALWAYS be true, * except in Controller. - * @return string|false + * @return string|bool false if no host found */ static public function getHost($checkIfTrusted = true) { @@ -408,7 +408,7 @@ class Url /** * Returns the HTTP_REFERER header, false if not found. * - * @return string|false + * @return string|bool */ static public function getReferer() { diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php index e6ee1289be..3744eb7160 100644 --- a/core/ViewDataTable.php +++ b/core/ViewDataTable.php @@ -16,6 +16,7 @@ use Piwik\Period; use Piwik\API\Request; use Piwik\Period\Range; use Piwik\Piwik; +use Piwik\NoAccessException; use Piwik\Common; use Piwik\Date; use Piwik\DataTable; @@ -60,10 +61,11 @@ use Piwik\Plugins\API\API; class ViewDataTable { /** - * TODO - * TODO: change to private + * The class name of the visualization to use. + * + * @var string|null */ - protected $visualization; + private $visualizationClass; /** * Cache for getAllReportDisplayProperties result. @@ -73,13 +75,6 @@ class ViewDataTable public static $reportPropertiesCache = null; /** - * Flag used to make sure the main() is only executed once - * - * @var bool - */ - protected $mainAlreadyExecuted = false; - - /** * Array of properties that are available in the view * Used to store UI properties, eg. "show_footer", "show_search", etc. * @@ -102,20 +97,6 @@ class ViewDataTable protected $dataTable = null; /** - * List of filters to apply after the data has been loaded from the API - * - * @var array - */ - protected $queuedFilters = array(); - - /** - * List of filter to apply just before the 'Generic' filters - * These filters should delete rows from the table - * @var array - */ - protected $queuedFiltersPriority = array(); - - /** * @see init() * @var string */ @@ -138,65 +119,66 @@ class ViewDataTable /** * Default constructor. */ - public function __construct($visualization = null) + public function __construct($currentControllerAction, + $apiMethodToRequestDataTable, + $viewProperties = array(), + $visualizationId = null) { - $this->visualization = $visualization; - - $this->viewProperties['visualization_properties'] = new VisualizationPropertiesProxy(null); - $this->viewProperties['datatable_template'] = '@CoreHome/_dataTable'; - $this->viewProperties['show_goals'] = false; - $this->viewProperties['show_ecommerce'] = false; - $this->viewProperties['show_search'] = true; - $this->viewProperties['show_table'] = true; - $this->viewProperties['show_table_all_columns'] = true; - $this->viewProperties['show_all_views_icons'] = true; - $this->viewProperties['show_active_view_icon'] = true; - $this->viewProperties['hide_annotations_view'] = true; - $this->viewProperties['show_bar_chart'] = true; - $this->viewProperties['show_pie_chart'] = true; - $this->viewProperties['show_tag_cloud'] = true; - $this->viewProperties['show_export_as_image_icon'] = false; - $this->viewProperties['show_export_as_rss_feed'] = true; - $this->viewProperties['show_exclude_low_population'] = true; - $this->viewProperties['show_offset_information'] = true; - $this->viewProperties['show_pagination_control'] = true; - $this->viewProperties['show_limit_control'] = false; - $this->viewProperties['show_footer'] = true; - $this->viewProperties['show_related_reports'] = true; - $this->viewProperties['exportLimit'] = Config::getInstance()->General['API_datatable_default_limit']; - $this->viewProperties['highlight_summary_row'] = false; + $visualizationClass = $visualizationId ? DataTableVisualization::getClassFromId($visualizationId) : null; + $this->visualizationClass = $visualizationClass; + + list($currentControllerName, $currentControllerAction) = explode('.', $currentControllerAction); + $this->currentControllerName = $currentControllerName; + $this->currentControllerAction = $currentControllerAction; + + $this->viewProperties['visualization_properties'] = new VisualizationPropertiesProxy($visualizationClass); $this->viewProperties['metadata'] = array(); - $this->viewProperties['relatedReports'] = array(); - $this->viewProperties['title'] = 'unknown'; - $this->viewProperties['tooltip_metadata_name'] = false; - $this->viewProperties['enable_sort'] = true; - $this->viewProperties['disable_generic_filters'] = false; - $this->viewProperties['disable_queued_filters'] = false; - $this->viewProperties['keep_summary_row'] = false; - $this->viewProperties['filter_excludelowpop'] = false; - $this->viewProperties['filter_excludelowpop_value'] = false; - $this->viewProperties['filter_pattern'] = false; - $this->viewProperties['filter_column'] = false; - $this->viewProperties['filter_limit'] = false; - $this->viewProperties['filter_sort_column'] = false; - $this->viewProperties['filter_sort_order'] = false; - $this->viewProperties['custom_parameters'] = array(); - $this->viewProperties['translations'] = array_merge( - Metrics::getDefaultMetrics(), - Metrics::getDefaultProcessedMetrics() - ); - $this->viewProperties['request_parameters_to_modify'] = array(); - $this->viewProperties['documentation'] = false; - $this->viewProperties['subtable_controller_action'] = false; - $this->viewProperties['datatable_css_class'] = $this->getDefaultDataTableCssClass(); - $this->viewProperties['selectable_columns'] = array(); // TODO: only valid for graphs... shouldn't be here. - $this->viewProperties['columns_to_display'] = array(); - - $columns = Common::getRequestVar('columns', false); - if ($columns !== false) { - $this->viewProperties['columns_to_display'] = Piwik::getArrayFromApiParameter($columns); - array_unshift($this->viewProperties['columns_to_display'], 'label'); + $this->viewProperties['translations'] = array(); + $this->viewProperties['filters'] = array(); + $this->viewProperties['related_reports'] = array(); + $this->viewProperties['subtable_controller_action'] = $currentControllerAction; + + $this->setDefaultProperties(); + + foreach ($viewProperties as $name => $value) { + $this->setViewProperty($name, $value); + } + + $queryParams = Url::getArrayFromCurrentQueryString(); + foreach ($this->getClientSideProperties() as $name) { + if (isset($queryParams[$name])) { + $this->setViewProperty($name, $queryParams[$name]); + } + } + + $this->idSubtable = Common::getRequestVar('idSubtable', false, 'int'); + $this->viewProperties['show_footer_icons'] = ($this->idSubtable == false); + $this->viewProperties['apiMethodToRequestDataTable'] = $apiMethodToRequestDataTable; + + $this->viewProperties['report_id'] = $currentControllerName . '.' . $currentControllerAction; + $this->viewProperties['self_url'] = $this->getBaseReportUrl($currentControllerName, $currentControllerAction); + + // the exclude low population threshold value is sometimes obtained by requesting data. + // to avoid issuing unecessary requests when display properties are determined by metadata, + // we allow it to be a closure. + if (isset($this->viewProperties['filter_excludelowpop_value']) + && $this->viewProperties['filter_excludelowpop_value'] instanceof \Closure + ) { + $function = $this->viewProperties['filter_excludelowpop_value']; + $this->viewProperties['filter_excludelowpop_value'] = $function(); } + + $this->loadDocumentation(); + } + + /** + * Returns the view's associated visualization class name. + * + * @return string + */ + public function getVisualizationClass() + { + return $this->visualizationClass; } /** @@ -229,28 +211,11 @@ class ViewDataTable } /** - * TODO + * Hack to allow property access in Twig (w/ property name checking). */ - public function main() + public function __call($name, $arguments) { - if ($this->mainAlreadyExecuted) { - return; - } - $this->mainAlreadyExecuted = true; - - try { - $this->loadDataTableFromAPI(); - } catch (\Piwik\NoAccessException $e) { - throw $e; - } catch (\Exception $e) { - Piwik::log("Failed to get data from API: " . $e->getMessage()); - - $this->loadingError = array('message' => $e->getMessage()); - } - - $this->postDataTableLoadedFromAPI(); - - $this->view = $this->buildView($this->visualization); + return $this->$name; } /** @@ -258,12 +223,10 @@ class ViewDataTable * * @return string */ - protected function getViewDataTableId() + public function getViewDataTableId() { - if (method_exists($this->visualization, 'getViewDataTableId')) { - return $this->visualization->getViewDataTableId(); - } - return false; + $klass = $this->visualizationClass; + return $klass::getViewDataTableId($this); } /** @@ -278,89 +241,45 @@ class ViewDataTable * @param string|bool $controllerAction * @return ViewDataTable */ - static public function factory($defaultType = null, $apiAction = false, $controllerAction = false) + static public function factory($defaultType = null, $apiAction = false, $controllerAction = false, $forceDefault = false) { - if ($apiAction !== false) { - $defaultProperties = self::getDefaultPropertiesForReport($apiAction); - if (isset($defaultProperties['default_view_type'])) { - $defaultType = $defaultProperties['default_view_type']; - } - - if ($controllerAction === false) { - $controllerAction = $apiAction; - } + if ($controllerAction === false) { + $controllerAction = $apiAction; } - if ($defaultType === null) { - $defaultType = 'table'; + $defaultProperties = self::getDefaultPropertiesForReport($apiAction); + if (!empty($defaultProperties['default_view_type']) + && !$forceDefault + ) { + $defaultType = $defaultProperties['default_view_type']; } - $type = Common::getRequestVar('viewDataTable', $defaultType, 'string'); - switch ($type) { - case 'cloud': - $result = new ViewDataTable\Cloud(); - break; - - case 'graphPie': - $result = new ViewDataTable\GenerateGraphHTML\ChartPie(); - break; - - case 'graphVerticalBar': - $result = new ViewDataTable\GenerateGraphHTML\ChartVerticalBar(); - break; - - case 'graphEvolution': - $result = new ViewDataTable\GenerateGraphHTML\ChartEvolution(); - break; + $type = Common::getRequestVar('viewDataTable', $defaultType ?: 'table', 'string'); - case 'sparkline': - $result = new ViewDataTable\Sparkline(); - break; - - case 'tableAllColumns': - $result = new ViewDataTable\HtmlTable\AllColumns(); - break; - - case 'tableGoals': - $result = new ViewDataTable\HtmlTable\Goals(); - break; - - case 'table': - default: - $result = new ViewDataTable(new Visualization\HtmlTable()); - break; - } - - if ($apiAction !== false) { - list($plugin, $controllerAction) = explode('.', $controllerAction); - - $subtableAction = $controllerAction; - if (isset($defaultProperties['subtable_action'])) { - $subtableAction = $defaultProperties['subtable_action']; - } - - $result->init($plugin, $controllerAction, $apiAction, $subtableAction, $defaultProperties); + if ($type == 'sparkline') { + $result = new ViewDataTable\Sparkline($controllerAction, $apiAction, $defaultProperties); + } else { + $result = new ViewDataTable($controllerAction, $apiAction, $defaultProperties, $type); } return $result; } /** - * Returns the list of view properties that can be overridden by query parameters. + * TODO * * @return array */ - public function getOverridableProperties() + public function getClientSideProperties() { - return array( + $result = array( 'show_search', 'show_table', 'show_table_all_columns', 'show_all_views_icons', 'show_active_view_icon', - 'hide_annotations_view', - 'show_barchart', - 'show_piechart', + 'show_bar_chart', + 'show_pie_chart', 'show_tag_cloud', 'show_export_as_image_icon', 'show_export_as_rss_feed', @@ -369,8 +288,16 @@ class ViewDataTable 'show_pagination_control', 'show_footer', 'show_related_reports', - 'columns' + 'keep_summary_row', + 'subtable_controller_action', ); + + if ($this->visualizationClass) { + $klass = $this->visualizationClass; + $result = array_merge($result, $klass::getClientSideProperties()); + } + + return $result; } /** @@ -379,13 +306,12 @@ class ViewDataTable * * @return array */ - public function getJavaScriptProperties() + public function getClientSideParameters() { $result = array( 'enable_sort', 'disable_generic_filters', 'disable_queued_filters', - 'keep_summary_row', 'filter_excludelowpop', 'filter_excludelowpop_value', 'filter_pattern', @@ -395,104 +321,14 @@ class ViewDataTable 'filter_sort_order', ); - if (method_exists($this->visualization, 'getJavaScriptProperties')) { - $result = array_merge($result, $this->visualization->getJavaScriptProperties()); + if ($this->visualizationClass) { + $klass = $this->visualizationClass; + $result = array_merge($result, $klass::getClientSideParameters()); } return $result; } - /** - * Inits the object given the $currentControllerName, $currentControllerAction of - * the calling controller action, eg. 'Referers' 'getLongListOfKeywords'. - * The initialization also requires the $apiMethodToRequestDataTable of the API method - * to call in order to get the DataTable, eg. 'Referers.getKeywords'. - * The optional $controllerActionCalledWhenRequestSubTable defines the method name of the API to call when there is a idSubtable. - * This value would be used by the javascript code building the GET request to the API. - * - * Example: - * For the keywords listing, a click on the row loads the subTable of the Search Engines for this row. - * In this case $controllerActionCalledWhenRequestSubTable = 'getSearchEnginesFromKeywordId'. - * The GET request will hit 'Referers.getSearchEnginesFromKeywordId'. - * - * @param string $currentControllerName eg. 'Referers' - * @param string $currentControllerAction eg. 'getKeywords' - * @param string $apiMethodToRequestDataTable eg. 'Referers.getKeywords' - * @param string $controllerActionCalledWhenRequestSubTable eg. 'getSearchEnginesFromKeywordId' - * @param array $defaultProperties - */ - public function init($currentControllerName, - $currentControllerAction, - $apiMethodToRequestDataTable, - $controllerActionCalledWhenRequestSubTable = null, - $defaultProperties = array()) - { - $this->currentControllerName = $currentControllerName; - $this->currentControllerAction = $currentControllerAction; - $this->viewProperties['subtable_controller_action'] = $controllerActionCalledWhenRequestSubTable; - $this->idSubtable = Common::getRequestVar('idSubtable', false, 'int'); - - foreach ($defaultProperties as $name => $value) { - $this->setViewProperty($name, $value); - } - - $queryParams = Url::getArrayFromCurrentQueryString(); - foreach ($this->getOverridableProperties() as $name) { - if (isset($queryParams[$name])) { - $this->setViewProperty($name, $queryParams[$name]); - } - } - - $this->viewProperties['show_footer_icons'] = ($this->idSubtable == false); - $this->viewProperties['apiMethodToRequestDataTable'] = $apiMethodToRequestDataTable; - - $this->viewProperties['report_id'] = $currentControllerName . '.' . $currentControllerAction; - $this->viewProperties['self_url'] = $this->getBaseReportUrl($currentControllerName, $currentControllerAction); - - // the exclude low population threshold value is sometimes obtained by requesting data. - // to avoid issuing unecessary requests when display properties are determined by metadata, - // we allow it to be a closure. - if (isset($this->viewProperties['filter_excludelowpop_value']) - && $this->viewProperties['filter_excludelowpop_value'] instanceof \Closure - ) { - $function = $this->viewProperties['filter_excludelowpop_value']; - $this->viewProperties['filter_excludelowpop_value'] = $function(); - } - - $this->loadDocumentation(); - } - - /** - * Forces the View to use a given template. - * Usually the template to use is set in the specific ViewDataTable_* - * eg. 'CoreHome/templates/cloud' - * But some users may want to force this template to some other value - * - * TODO: after visualization refactor, should remove this. - * - * @param string $tpl eg .'@MyPlugin/templateToUse' - */ - public function setTemplate($tpl) - { - $this->viewProperties['datatable_template'] = $tpl; - } - - /** - * Returns the View_Interface. - * You can then call render() on this object. - * - * @return View\ViewInterface - * @throws \Exception if the view object was not created - */ - public function getView() - { - if (is_null($this->view)) { - throw new \Exception('The $this->view object has not been created. - It should be created in the main() method of the ViewDataTable_* subclass you are using.'); - } - return $this->view; - } - public function getCurrentControllerAction() { return $this->currentControllerAction; @@ -558,13 +394,14 @@ class ViewDataTable return self::$reportPropertiesCache; } - + /** * Sets a view property by name. This function handles special view properties - * like 'translations' & 'relatedReports' that store arrays. + * like 'translations' & 'related_reports' that store arrays. * * @param string $name * @param mixed $value For array properties, $value can be a comma separated string. + * @throws \Exception */ private function setViewProperty($name, $value) { @@ -575,21 +412,44 @@ class ViewDataTable $value = Piwik::getArrayFromApiParameter($value); } - if ($name == 'translations') { + if ($name == 'translations' + || $name == 'filters' + ) { $this->viewProperties[$name] = array_merge($this->viewProperties[$name], $value); - } else if ($name == 'relatedReports') { + } else if ($name == 'related_reports') { // TODO: should process after (in overrideViewProperties) $this->addRelatedReports($value); - } else if ($name == 'filters') { - foreach ($value as $filterInfo) { - if (!is_array($filterInfo)) { - $this->queueFilter($filterInfo); + } else if ($name == 'visualization_properties') { + $this->setVisualizationPropertiesFromMetadata($value); + } else if (Properties::isCoreViewProperty($name)) { + $this->viewProperties[$name] = $value; + } else { + $report = $this->currentControllerName . '.' . $this->currentControllerAction; + throw new \Exception("Invalid view property '$name' specified in view property metadata for '$report'."); + } + } + + /** + * TODO + */ + private function setVisualizationPropertiesFromMetadata($properties) + { + if ($this->visualizationClass === null) { + return null; + } + + $visualizationIds = DataTableVisualization::getVisualizationIdsWithInheritance($this->visualizationClass); + foreach ($visualizationIds as $visualizationId) { + if (empty($properties[$visualizationId])) { + continue; + } + + foreach ($properties[$visualizationId] as $key => $value) { + if (Properties::isCoreViewProperty($key)) { + $this->viewProperties[$key] = $value; } else { - @list($filter, $params, $isPriority) = $filterInfo; - $this->queueFilter($filter, $params, $isPriority); + $this->viewProperties['visualization_properties']->$key = $value; } } - } else { - $this->viewProperties[$name] = $value; } } @@ -629,6 +489,34 @@ class ViewDataTable Piwik::checkObjectTypeIs($this->dataTable, array('\Piwik\DataTable')); } + private function getFiltersToRun() + { + $priorityFilters = array(); + $presentationFilters = array(); + + foreach ($this->viewProperties['filters'] as $filterInfo) { + if ($filterInfo instanceof \Closure) { + $nameOrClosure = $filterInfo; + $parameters = array(); + $priority = false; + } else { + @list($nameOrClosure, $parameters, $priority) = $filterInfo; + } + + if ($nameOrClosure instanceof \Closure) { + $parameters[] = $this; + } + + if ($priority) { + $priorityFilters[] = array($nameOrClosure, $parameters); + } else { + $presentationFilters[] = array($nameOrClosure, $parameters); + } + } + + return array($priorityFilters, $presentationFilters); + } + /** * Hook called after the dataTable has been loaded from the API * Can be used to add, delete or modify the data freshly loaded @@ -637,21 +525,24 @@ class ViewDataTable */ protected function postDataTableLoadedFromAPI() { - $this->overrideViewProperties(); - if (empty($this->dataTable)) { return false; } + $columns = $this->dataTable->getColumns(); + $haveNbVisits = in_array('nb_visits', $columns); + $haveNbUniqVisitors = in_array('nb_uniq_visitors', $columns); + // default columns_to_display to label, nb_uniq_visitors/nb_visits if those columns exist in the // dataset. otherwise, default to all columns in dataset. - $columns = $this->dataTable->getColumns(); if (empty($this->viewProperties['columns_to_display'])) { - if ($this->dataTableColumnsContains($columns, array('nb_visits', 'nb_uniq_visitors'))) { + if ($haveNbVisits + || $haveNbUniqVisitors + ) { $columnsToDisplay = array('label'); // if unique visitors data is available, show it, otherwise just visits - if ($this->dataTableColumnsContains($columns, 'nb_uniq_visitors')) { + if ($haveNbUniqVisitors) { $columnsToDisplay[] = 'nb_uniq_visitors'; } else { $columnsToDisplay[] = 'nb_visits'; @@ -667,7 +558,7 @@ class ViewDataTable // default sort order to visits/visitors data if (empty($this->viewProperties['filter_sort_column'])) { - if ($this->dataTableColumnsContains($columns, 'nb_uniq_visitors')) { + if ($haveNbUniqVisitors) { $this->viewProperties['filter_sort_column'] = 'nb_uniq_visitors'; } else { $this->viewProperties['filter_sort_column'] = 'nb_visits'; @@ -685,16 +576,11 @@ class ViewDataTable } } - // First, filters that delete rows - foreach ($this->queuedFiltersPriority as $filter) { - $filterName = $filter[0]; - - $filterParameters = $filter[1]; - if ($filterName instanceof \Closure) { - $filterParameters[] = $this; - } + list($priorityFilters, $otherFilters) = $this->getFiltersToRun(); - $this->dataTable->filter($filterName, $filterParameters); + // First, filters that delete rows + foreach ($priorityFilters as $filter) { + $this->dataTable->filter($filter[0], $filter[1]); } if (!$this->areGenericFiltersDisabled()) { @@ -713,15 +599,8 @@ class ViewDataTable if (!$this->areQueuedFiltersDisabled()) { // Finally, apply datatable filters that were queued (should be 'presentation' filters that // do not affect the number of rows) - foreach ($this->queuedFilters as $filter) { - $filterName = $filter[0]; - - $filterParameters = $filter[1]; - if ($filterName instanceof \Closure) { - $filterParameters[] = $this; - } - - $this->dataTable->filter($filterName, $filterParameters); + foreach ($otherFilters as $filter) { + $this->dataTable->filter($filter[0], $filter[1]); } } @@ -885,11 +764,14 @@ class ViewDataTable // case of the filter without default values and parameters set directly in this class // for example setExcludeLowPopulation // we go through all the $this->viewProperties array and set the variables not set yet - foreach ($this->getJavaScriptProperties() as $name) { - if (!isset($javascriptVariablesToSet[$name]) - && !empty($this->viewProperties[$name]) - ) { - $javascriptVariablesToSet[$name] = $this->viewProperties[$name]; + foreach ($this->getClientSideParameters() as $name) { + if (!isset($javascriptVariablesToSet[$name])) { + if (!empty($this->viewProperties[$name])) { + $javascriptVariablesToSet[$name] = $this->convertForJson($this->viewProperties[$name]); + } else if (Properties::isValidVisualizationProperty($this->visualizationClass, $name)) { + $javascriptVariablesToSet[$name] = + $this->convertForJson($this->viewProperties['visualization_properties']->$name); + } } } @@ -908,7 +790,6 @@ class ViewDataTable if (!isset($javascriptVariablesToSet['viewDataTable'])) { $javascriptVariablesToSet['viewDataTable'] = $this->getViewDataTableId(); } - $javascriptVariablesToSet['controllerActionCalledWhenRequestSubTable'] = $this->viewProperties['subtable_controller_action']; if ($this->dataTable && // Set doesn't have the method @@ -948,6 +829,25 @@ class ViewDataTable } /** + * Returns array of properties that should be visible to client side JavaScript. The data + * will be available in the data-props HTML attribute of the .dataTable div. + * + * @return array Maps property names w/ property values. + */ + private function getClientSidePropertiesToSet() + { + $result = array(); + foreach ($this->getClientSideProperties() as $name) { + if (isset($this->viewProperties[$name])) { + $result[$name] = $this->convertForJson($this->viewProperties[$name]); + } else if (Properties::isValidVisualizationProperty($this->visualizationClass, $name)) { + $result[$name] = $this->convertForJson($this->viewProperties['visualization_properties']->$name); + } + } + return $result; + } + + /** * Returns, for a given parameter, the value of this parameter in the REQUEST array. * If not set, returns the default value for this parameter @see getDefault() * @@ -1016,26 +916,6 @@ class ViewDataTable } } - /** - * Queues a Datatable filter, that will be applied once the datatable is loaded from the API. - * Useful when the controller needs to add columns, or decorate existing columns, when these filters don't - * necessarily make sense directly in the API. - * - * @param string $filterName - * @param mixed $parameters - * @param bool $runBeforeGenericFilters Set to true if the filter will delete rows from the table, - * and should therefore be ran before Sort, Limit, etc. - * @return void - */ - public function queueFilter($filterName, $parameters = array(), $runBeforeGenericFilters = false) - { - if ($runBeforeGenericFilters) { - $this->queuedFiltersPriority[] = array($filterName, $parameters); - } else { - $this->queuedFilters[] = array($filterName, $parameters); - } - } - private function addRelatedReport($module, $action, $title, $queryParams = array()) { // don't add the related report if it references this report @@ -1044,7 +924,7 @@ class ViewDataTable } $url = $this->getBaseReportUrl($module, $action, $queryParams); - $this->viewProperties['relatedReports'][$url] = $title; + $this->viewProperties['related_reports'][$url] = $title; } private function addRelatedReports($relatedReports) @@ -1156,8 +1036,8 @@ class ViewDataTable */ public function render() { - $this->main(); - return $this->getView()->render(); + $this->buildView(); + return $this->view->render(); } /** @@ -1175,55 +1055,33 @@ class ViewDataTable && Common::getRequestVar('flat', false) === false; } - /** - * Returns true if the first array contains one or more of the specified - * column names or their associated integer INDEX_ value. - * - * @param array $columns Row columns. - * @param array|string $columnsToCheckFor eg, array('nb_visits', 'nb_uniq_visitors') - * @return bool - */ - protected function dataTableColumnsContains($columns, $columnsToCheckFor) + protected function overrideViewProperties() { - if (!is_array($columnsToCheckFor)) { - $columnsToCheckFor = array($columnsToCheckFor); + if (!PluginsManager::getInstance()->isPluginActivated('Goals')) { + $this->viewProperties['show_goals'] = false; } - foreach ($columnsToCheckFor as $columnToCheckFor) { - foreach ($columns as $column) { - // check for the column name and its associated integer INDEX_ value - if ($column == $columnToCheckFor - || (isset(Metrics::$mappingFromNameToId[$columnToCheckFor]) - && $column == Metrics::$mappingFromNameToId[$columnToCheckFor]) - ) { - return true; - } - } + if ($this->viewProperties['filter_limit'] == 0) { + $this->viewProperties['filter_limit'] = false; } - - return false; } - protected function overrideViewProperties() + protected function buildView() { - if (!\Piwik\PluginsManager::getInstance()->isPluginActivated('Goals')) { - $this->viewProperties['show_goals'] = false; - } + $visualization = new $this->visualizationClass($this); - if (!\Piwik\PluginsManager::getInstance()->isPluginLoaded('Annotations')) { - $this->viewProperties['hide_annotations_view'] = true; - } + try { + $this->loadDataTableFromAPI(); + $this->postDataTableLoadedFromAPI(); + } catch (NoAccessException $e) { + throw $e; + } catch (\Exception $e) { + Piwik::log("Failed to get data from API: " . $e->getMessage()); - if ($this->idSubtable) { - $this->viewProperties['datatable_template'] = $this->viewProperties['subtable_template']; + $this->loadingError = array('message' => $e->getMessage()); } - } - protected function buildView($visualization) - { - if (method_exists($visualization, 'getDefaultPropertyValues')) { - $this->setPropertyDefaults($visualization->getDefaultPropertyValues()); - } + $this->overrideViewProperties(); $template = $this->viewProperties['datatable_template']; $view = new View($template); @@ -1233,7 +1091,8 @@ class ViewDataTable } $view->visualization = $visualization; - + $view->visualizationCssClass = $this->getDefaultDataTableCssClass(); + if (!$this->dataTable === null) { $view->dataTable = null; } else { @@ -1245,25 +1104,42 @@ class ViewDataTable $view->deleteReportsOlderThan = Piwik_GetOption('delete_reports_older_than'); } $view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet(); - $view->properties = $this->viewProperties; - return $view; + $view->clientSidePropertiesToSet = $this->getClientSidePropertiesToSet(); + $view->properties = $this->viewProperties; // TODO: should be $this. need to move non-view properties from the class + + $nonCoreVisualizations = DataTableVisualization::getNonCoreVisualizations(); + $view->nonCoreVisualizations = DataTableVisualization::getVisualizationInfoFor($nonCoreVisualizations); + $this->view = $view; } public function getDefaultDataTableCssClass() { - $parts = explode('\\', get_class($this->visualization)); - return 'dataTableViz' . end($parts); + return 'dataTableViz' . Piwik::getUnnamespacedClassName($this->visualizationClass); } - /** - * Sets view properties if they have not been set already. - */ - private function setPropertyDefaults($defaultValues) + private function setViewProperties($values) { - foreach ($defaultValues as $name => $value) { - if (empty($this->viewProperties[$name])) { - $this->viewProperties[$name] = $value; - } + foreach ($values as $name => $value) { + $this->setViewProperty($name, $value); } } + + private function setDefaultProperties() + { + // set core default properties + $this->setViewProperties(Properties::getDefaultPropertyValues()); + + // set visualization default properties + if ($this->visualizationClass === null) { + return; + } + + $visualizationClass = $this->visualizationClass; + $this->setViewProperties($visualizationClass::getDefaultPropertyValues()); + } + + private function convertForJson($value) + { + return is_bool($value) ? (int)$value : $value; + } } diff --git a/core/ViewDataTable/Cloud.php b/core/ViewDataTable/Cloud.php deleted file mode 100644 index 60488ff8df..0000000000 --- a/core/ViewDataTable/Cloud.php +++ /dev/null @@ -1,73 +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 - * - * @category Piwik - * @package Piwik - */ -namespace Piwik\ViewDataTable; - -use Exception; -use Piwik\ViewDataTable; -use Piwik\View; -use Piwik; -use Piwik\Visualization; - -/** - * Reads the requested DataTable from the API, and prepares the data to give - * to Cloud that will display the tag cloud (via the template _dataTable_cloud.twig). - * - * @package Piwik - * @subpackage ViewDataTable - */ -class Cloud extends ViewDataTable -{ - public function setDisplayLogoInTagCloud($bool) - { - $this->viewProperties['display_logo_instead_of_label'] = $bool; - } - - protected function getViewDataTableId() - { - return 'cloud'; - } - - public function __construct() - { - parent::__construct(); - - $this->viewProperties['show_offset_information'] = false; - $this->viewProperties['show_exclude_low_population'] = false; - $this->viewProperties['display_logo_instead_of_label'] = false; - } - - /** - * @see ViewDataTable::main() - * - * @return null - */ - public function main() - { - if ($this->mainAlreadyExecuted) { - return; - } - $this->mainAlreadyExecuted = true; - - try { - $this->loadDataTableFromAPI(); - } catch (Exception $e) { - Piwik\Piwik::log("Failed to get data from API: " . $e->getMessage()); - - $this->loadingError = array('message' => $e->getMessage()); - } - - $this->checkStandardDataTable(); - $this->postDataTableLoadedFromAPI(); - - $visualization = new Visualization\Cloud(); - $this->view = $this->buildView($visualization); - } -} diff --git a/core/ViewDataTable/GenerateGraphHTML.php b/core/ViewDataTable/GenerateGraphHTML.php deleted file mode 100644 index 078571109d..0000000000 --- a/core/ViewDataTable/GenerateGraphHTML.php +++ /dev/null @@ -1,175 +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 - * - * @category Piwik - * @package Piwik - */ -namespace Piwik\ViewDataTable; - -use Exception; -use Piwik\API\Request; -use Piwik\Piwik; -use Piwik\Access; -use Piwik\Common; -use Piwik\JqplotDataGenerator; -use Piwik\ViewDataTable; -use Piwik\View; -use Piwik\Visualization\JqplotGraph; - -/** - * This class generates the HTML code to embed graphs in the page. - * It doesn't call the API but simply prints the html snippet. - * - * @package Piwik - * @subpackage ViewDataTable - */ -abstract class GenerateGraphHTML extends ViewDataTable -{ - const DEFAULT_GRAPH_HEIGHT = 250; - - protected $graphType; - - /** - * Default constructor. - */ - public function __construct() - { - parent::__construct(); - - $this->viewProperties['show_offset_information'] = false; - $this->viewProperties['show_pagination_control'] = false; - $this->viewProperties['show_exclude_low_population'] = false; - $this->viewProperties['show_search'] = false; - $this->viewProperties['show_export_as_image_icon'] = true; - $this->viewProperties['display_percentage_in_tooltip'] = true; - $this->viewProperties['y_axis_unit'] = ''; - $this->viewProperties['show_all_ticks'] = 0; - $this->viewProperties['add_total_row'] = 0; - $this->viewProperties['graph_limit'] = null; - $this->viewProperties['allow_multi_select_series_picker'] = true; - $this->viewProperties['row_picker_mach_rows_by'] = false; - $this->viewProperties['row_picker_visible_rows'] = array(); - $this->viewProperties['selectable_columns'] = array(); - $this->viewProperties['graph_width'] = '100%'; - $this->viewProperties['graph_height'] = self::DEFAULT_GRAPH_HEIGHT . 'px'; - } - - public function init($currentControllerName, - $currentControllerAction, - $apiMethodToRequestDataTable, - $controllerActionCalledWhenRequestSubTable = null, - $defaultProperties = array()) - { - parent::init($currentControllerName, $currentControllerAction, $apiMethodToRequestDataTable, - $controllerActionCalledWhenRequestSubTable, $defaultProperties); - - // in the case this controller is being executed by another controller - // eg. when being widgetized in an IFRAME - // we need to put in the URL of the graph data the real module and action - $this->viewProperties['request_parameters_to_modify']['module'] = $currentControllerName; - $this->viewProperties['request_parameters_to_modify']['action'] = $currentControllerAction; - - // do not sort if sorted column was initially "label" or eg. it would make "Visits by Server time" not pretty - if ($this->viewProperties['filter_sort_column'] != 'label') { - $columns = $this->viewProperties['columns_to_display']; - - $firstColumn = reset($columns); - if ($firstColumn == 'label') { - $firstColumn = next($columns); - } - - $this->viewProperties['filter_sort_column'] = $firstColumn; - $this->viewProperties['filter_sort_order'] = 'desc'; - } - - // selectable columns - if ($this->viewProperties['graph_type'] != 'evolution') { - $selectableColumns = array('nb_visits', 'nb_actions'); - if (Common::getRequestVar('period', false) == 'day') { - $selectableColumns[] = 'nb_uniq_visitors'; - } - $this->viewProperties['selectable_columns'] = $selectableColumns; - } - } - - /** - * We persist the 'request_parameters_to_modify' 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. - * @return array - */ - protected function getJavascriptVariablesToSet() - { - $original = parent::getJavascriptVariablesToSet(); - $originalViewDataTable = $original['viewDataTable']; - - $result = $this->viewProperties['request_parameters_to_modify'] + $original; - $result['viewDataTable'] = $originalViewDataTable; - - return $result; - } - - /** - * @see ViewDataTable::main() - * @throws \Exception|\Piwik\NoAccessException - * @return null - */ - public function main() - { - if ($this->mainAlreadyExecuted) { - return; - } - $this->mainAlreadyExecuted = true; - - // Graphs require the full dataset, so no filters - $this->disable_generic_filters = true; - - // 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->disable_queued_filters = true; - - try { - $this->loadDataTableFromAPI(); - } catch (\Piwik\NoAccessException $e) { - throw $e; - } catch (Exception $e) { - Piwik::log("Failed to get data from API: " . $e->getMessage()); - - $this->loadingError = array('message' => $e->getMessage()); - } - - if ($this->viewProperties['graph_type'] != 'evolution') { - $this->checkStandardDataTable(); - } - $this->postDataTableLoadedFromAPI(); - - // re-enable generic & queued filters so they do not appear in JS output - $this->viewProperties['disable_generic_filters'] = false; - $this->viewProperties['disable_queued_filters'] = false; - - $visualization = new JqplotGraph(); - $this->view = $this->buildView($visualization); - } - - public function getDefaultDataTableCssClass() - { - return 'dataTableGraph'; - } - - protected function overrideViewProperties() - { - parent::overrideViewProperties(); - - if ($this->viewProperties['show_goals']) { - $goalMetrics = array('nb_conversions', 'revenue'); - $this->viewProperties['selectable_columns'] = array_merge($this->viewProperties['selectable_columns'], $goalMetrics); - - $this->translations['nb_conversions'] = Piwik_Translate('Goals_ColumnConversions'); - $this->translations['revenue'] = Piwik_Translate('General_TotalRevenue'); - } - } -} diff --git a/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php b/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php deleted file mode 100644 index 919b002587..0000000000 --- a/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php +++ /dev/null @@ -1,203 +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 - * - * @category Piwik - * @package Piwik - */ - -namespace Piwik\ViewDataTable\GenerateGraphHTML; - -use Piwik\Common; -use Piwik\Period\Range; -use Piwik\Controller; -use Piwik\Site; -use Piwik\ViewDataTable\GenerateGraphHTML; - -/** - * Generates HTML embed for the Evolution graph - * - * @package Piwik - * @subpackage ViewDataTable - */ -class ChartEvolution extends GenerateGraphHTML -{ - const GRAPH_HEIGHT = 170; - - /** - * The value of the date query parameter (or a default value) before it is turned - * into a date range. Set in 'calculateEvolutionDateRange' and used by - * 'getJavascriptVariablesToSet'. - * - * @var string - */ - private $originalDate; - - public function __construct() - { - parent::__construct(); - $this->viewProperties['graph_type'] = 'evolution'; - $this->viewProperties['graph_height'] = self::GRAPH_HEIGHT . 'px'; - } - - protected function getViewDataTableId() - { - return 'graphEvolution'; - } - - protected function getViewDataTableIdToLoad() - { - return 'generateDataChartEvolution'; - } - - public function init($currentControllerName, - $currentControllerAction, - $apiMethodToRequestDataTable, - $controllerActionCalledWhenRequestSubTable = null, - $defaultProperties = array()) - { - parent::init($currentControllerName, - $currentControllerAction, - $apiMethodToRequestDataTable, - $controllerActionCalledWhenRequestSubTable, - $defaultProperties); - - $this->calculateEvolutionDateRange(); - $this->viewProperties['show_all_views_icons'] = false; - $this->viewProperties['show_table'] = false; - $this->viewProperties['show_table'] = false; - $this->viewProperties['show_table_all_columns'] = false; - $this->viewProperties['hide_annotations_view'] = false; - } - - /** - * Makes sure 'date' parameter is not overridden. - */ - protected function getJavascriptVariablesToSet() - { - $result = parent::getJavascriptVariablesToSet(); - - // Graphs use a Range instead of the input date - we will use this same range for "Export" icons - $result['dateUsedInGraph'] = $result['date']; - - // Other datatable features may require the original input date (eg. the limit dropdown below evolution graph) - $result['date'] = $this->originalDate; - return $result; - } - - /** - * Based on the period, date and evolution_{$period}_last_n query parameters, - * calculates the date range this evolution chart will display data for. - */ - private function calculateEvolutionDateRange() - { - $period = Common::getRequestVar('period'); - - $defaultLastN = self::getDefaultLastN($period); - $this->originalDate = Common::getRequestVar('date', 'last' . $defaultLastN, 'string'); - - if ($period != 'range') { // show evolution limit if the period is not a range - $this->viewProperties['show_limit_control'] = true; - - // set the evolution_{$period}_last_n query param - if (Range::parseDateRange($this->originalDate)) { // if a multiple period - // overwrite last_n param using the date range - $oPeriod = new Range($period, $this->originalDate); - $lastN = count($oPeriod->getSubperiods()); - } else { // if not a multiple period - list($newDate, $lastN) = self::getDateRangeAndLastN($period, $this->originalDate, $defaultLastN); - $this->viewProperties['request_parameters_to_modify']['date'] = $newDate; - } - $lastNParamName = self::getLastNParamName($period); - $this->viewProperties['request_parameters_to_modify'][$lastNParamName] = $lastN; - } - } - - /** - * Returns the entire date range and lastN value for the current request, based on - * a period type and end date. - * - * @param string $period The period type, 'day', 'week', 'month' or 'year' - * @param string $endDate The end date. - * @param int|null $defaultLastN The default lastN to use. If null, the result of - * getDefaultLastN is used. - * @return array An array w/ two elements. The first is a whole date range and the second - * is the lastN number used, ie, array('2010-01-01,2012-01-02', 2). - */ - public static function getDateRangeAndLastN($period, $endDate, $defaultLastN = null) - { - if ($defaultLastN === null) { - $defaultLastN = self::getDefaultLastN($period); - } - - $lastNParamName = self::getLastNParamName($period); - $lastN = Common::getRequestVar($lastNParamName, $defaultLastN, 'int'); - - $site = new Site(Common::getRequestVar('idSite')); - - $dateRange = Controller::getDateRangeRelativeToEndDate($period, 'last' . $lastN, $endDate, $site); - - return array($dateRange, $lastN); - } - - /** - * Returns the default last N number of dates to display for a given period. - * - * @param string $period 'day', 'week', 'month' or 'year' - * @return int - */ - public static function getDefaultLastN($period) - { - switch ($period) { - case 'week': - return 26; - case 'month': - return 24; - case 'year': - return 5; - case 'day': - default: - return 30; - } - } - - /** - * Returns the query parameter that stores the lastN number of periods to get for - * the evolution graph. - * - * @param string $period The period type, 'day', 'week', 'month' or 'year'. - * @return string - */ - public static function getLastNParamName($period) - { - return "evolution_{$period}_last_n"; - } - - protected function getRequestArray() - { - // period will be overridden when 'range' is requested in the UI // TODO: this code probably shouldn't be here... - // but the graph will display for each day of the range. - // Default 'range' behavior is to return the 'sum' for the range - if (Common::getRequestVar('period', false) == 'range') { - $this->viewProperties['request_parameters_to_modify']['period'] = 'day'; - } - - // FIXME: This appears to be a hack used to ensure a graph is plotted even if there is no data. there's probably - // a less complicated way of doing it... (this is complicated because it modifies the request used to get - // data so a loop is entered in JqplotDataGenerator_Evolution::initChartObjectData) - if (!empty($this->viewProperties['columns_to_display'])) { - $columns = implode(',', $this->viewProperties['columns_to_display']); - $this->viewProperties['request_parameters_to_modify']['columns'] = $columns; - } - - return parent::getRequestArray(); - } - - public function getDefaultDataTableCssClass() - { - return 'dataTableEvolutionGraph'; - } -} diff --git a/core/ViewDataTable/GenerateGraphHTML/ChartPie.php b/core/ViewDataTable/GenerateGraphHTML/ChartPie.php deleted file mode 100644 index de5e541b33..0000000000 --- a/core/ViewDataTable/GenerateGraphHTML/ChartPie.php +++ /dev/null @@ -1,40 +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 - * - * @category Piwik - * @package Piwik - */ -namespace Piwik\ViewDataTable\GenerateGraphHTML; - -use Piwik\ViewDataTable\GenerateGraphHTML; - -/** - * Generates HTML embed for the Pie chart - * - * @package Piwik - * @subpackage ViewDataTable - */ -class ChartPie extends GenerateGraphHTML -{ - public function __construct() - { - parent::__construct(); - $this->viewProperties['graph_type'] = 'pie'; - $this->viewProperties['graph_limit'] = 6; - $this->viewProperties['allow_multi_select_series_picker'] = false; - } - - protected function getViewDataTableId() - { - return 'graphPie'; - } - - protected function getViewDataTableIdToLoad() - { - return 'generateDataChartPie'; - } -} diff --git a/core/ViewDataTable/GenerateGraphHTML/ChartVerticalBar.php b/core/ViewDataTable/GenerateGraphHTML/ChartVerticalBar.php deleted file mode 100644 index 78d9f3c3a3..0000000000 --- a/core/ViewDataTable/GenerateGraphHTML/ChartVerticalBar.php +++ /dev/null @@ -1,40 +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 - * - * @category Piwik - * @package Piwik - */ -namespace Piwik\ViewDataTable\GenerateGraphHTML; -use Piwik\ViewDataTable\GenerateGraphHTML; - -/** - * - * Generates HTML embed for the vertical bar chart - * - * @package Piwik - * @subpackage ViewDataTable - */ - -class ChartVerticalBar extends GenerateGraphHTML -{ - public function __construct() - { - parent::__construct(); - $this->viewProperties['graph_type'] = 'bar'; - $this->viewProperties['graph_limit'] = 6; - } - - protected function getViewDataTableId() - { - return 'graphVerticalBar'; - } - - protected function getViewDataTableIdToLoad() - { - return 'generateDataChartVerticalBar'; - } -} diff --git a/core/ViewDataTable/HtmlTable.php b/core/ViewDataTable/HtmlTable.php deleted file mode 100644 index e9a6250c4c..0000000000 --- a/core/ViewDataTable/HtmlTable.php +++ /dev/null @@ -1,37 +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 - * - * @category Piwik - * @package Piwik - */ -namespace Piwik\ViewDataTable; - -use Piwik\Config; -use Piwik\DataTable\Renderer; -use Piwik\Piwik; -use Piwik\Common; -use Piwik\ViewDataTable; -use Piwik\View; -use Piwik\Visualization; - -/** - * Outputs an AJAX Table for a given DataTable. - * - * Reads the requested DataTable from the API. - * - * @package Piwik - * @subpackage ViewDataTable - */ -class HtmlTable extends ViewDataTable -{ - public function __construct() - { - parent::__construct(); - - $this->visualization = new Visualization\HtmlTable(); - } -}
\ No newline at end of file diff --git a/core/ViewDataTable/HtmlTable/AllColumns.php b/core/ViewDataTable/HtmlTable/AllColumns.php deleted file mode 100644 index 9b29f72b75..0000000000 --- a/core/ViewDataTable/HtmlTable/AllColumns.php +++ /dev/null @@ -1,70 +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 - * - * @category Piwik - * @package Piwik - */ -namespace Piwik\ViewDataTable\HtmlTable; - -use Piwik\Controller; -use Piwik\ViewDataTable\HtmlTable; - -/** - * @package Piwik - * @subpackage ViewDataTable - */ -class AllColumns extends HtmlTable -{ - protected function getViewDataTableId() - { - return 'tableAllColumns'; - } - - public function main() - { - $this->viewProperties['show_exclude_low_population'] = true; - parent::main(); - } - - protected function getRequestArray() - { - $requestArray = parent::getRequestArray(); - $requestArray['filter_add_columns_when_show_all_columns'] = 1; - return $requestArray; - } - - protected function postDataTableLoadedFromAPI() - { - $valid = parent::postDataTableLoadedFromAPI(); - if (!$valid) return false; - - $columnUniqueVisitors = false; - if ($this->dataTableColumnsContains($this->dataTable->getColumns(), 'nb_uniq_visitors')) { - $columnUniqueVisitors = 'nb_uniq_visitors'; - } - - // only display conversion rate for the plugins that do not provide "per goal" metrics - // otherwise, conversion rate is meaningless as a whole (since we don't process 'cross goals' conversions) - $columnConversionRate = false; - if (empty($this->viewProperties['show_goals'])) { - $columnConversionRate = 'conversion_rate'; - } - $this->viewProperties['columns_to_display'] = array_filter(array( - 'label', 'nb_visits', $columnUniqueVisitors, 'nb_actions', 'nb_actions_per_visit', 'avg_time_on_site', - 'bounce_rate', $columnConversionRate - )); - $this->dataTable->filter('ColumnCallbackReplace', array('avg_time_on_site', create_function('$averageTimeOnSite', - 'return \Piwik\Piwik::getPrettyTimeFromSeconds($averageTimeOnSite);'))); - - return true; - } - - public function getDefaultDataTableCssClass() - { - return 'dataTableAllColumns'; - } -} diff --git a/core/ViewDataTable/HtmlTable/Goals.php b/core/ViewDataTable/HtmlTable/Goals.php deleted file mode 100644 index 88f3ab4b1a..0000000000 --- a/core/ViewDataTable/HtmlTable/Goals.php +++ /dev/null @@ -1,273 +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 - * - * @category Piwik - * @package Piwik - */ -namespace Piwik\ViewDataTable\HtmlTable; - -use Piwik\Piwik; -use Piwik\Common; -use Piwik\Site; -use Piwik\ViewDataTable\HtmlTable; -use Piwik\DataTable\Filter\AddColumnsProcessedMetricsGoal; -use Piwik\Plugins\Goals\API; - -/** - * @package Piwik - * @subpackage ViewDataTable - */ -class Goals extends HtmlTable -{ - private $processOnlyIdGoal = null; - private $isEcommerce = false; - - protected function getViewDataTableId() - { - return 'tableGoals'; - } - - public function main() - { - if (!empty($this->viewProperties['disable_subtable_when_show_goals'])) { - $this->viewProperties['subtable_controller_action'] = null; - } - - $this->idSite = Common::getRequestVar('idSite', null, 'int'); - $this->processOnlyIdGoal = Common::getRequestVar('idGoal', AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW, 'string'); - $this->isEcommerce = $this->processOnlyIdGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER; - $this->viewProperties['show_exclude_low_population'] = true; - $this->viewProperties['show_goals'] = true; - - if (Common::getRequestVar('documentationForGoalsPage', 0, 'int') == 1) { - $this->viewProperties['documentation'] = Piwik_Translate('Goals_ConversionByTypeReportDocumentation', - array('<br />', '<br />', '<a href="http://piwik.org/docs/tracking-goals-web-analytics/" target="_blank">', '</a>')); - } - - $this->viewProperties['metrics_documentation']['nb_visits'] = Piwik_Translate('Goals_ColumnVisits'); - if ($this->isEcommerce) { - $this->viewProperties['metrics_documentation']['revenue_per_visit'] = - Piwik_Translate('Goals_ColumnRevenuePerVisitDocumentation', Piwik_Translate('General_EcommerceOrders')); - $this->viewProperties['translations'] += array( - 'goal_%s_conversion_rate' => Piwik_Translate('Goals_ConversionRate'), - 'goal_%s_nb_conversions' => Piwik_Translate('General_EcommerceOrders'), - 'goal_%s_revenue' => Piwik_Translate('General_TotalRevenue'), - 'goal_%s_revenue_per_visit' => Piwik_Translate('General_ColumnValuePerVisit'), - 'goal_%s_avg_order_revenue' => Piwik_Translate('General_AverageOrderValue'), - 'goal_%s_items' => Piwik_Translate('General_PurchasedProducts') - ); - - $this->viewProperties['columns_to_display'] = array( - 'label', 'nb_visits', 'goal_%s_nb_conversions', 'goal_%s_revenue', 'goal_%s_conversion_rate', - 'goal_%s_avg_order_revenue', 'goal_%s_items', 'goal_%s_revenue_per_visit'); - - // Default sort column - $this->viewProperties['filter_sort_column'] = 'goal_ecommerceOrder_revenue'; - $this->viewProperties['filter_sort_order'] = 'desc'; - } else { - $this->viewProperties['metrics_documentation'] = - Piwik_Translate('Goals_ColumnRevenuePerVisitDocumentation', Piwik_Translate('Goals_EcommerceAndGoalsMenu')); - $this->viewProperties['translations'] += array( - 'goal_%s_conversion_rate' => Piwik_Translate('Goals_ConversionRate'), - 'goal_%s_nb_conversions' => Piwik_Translate('Goals_Conversions'), - 'goal_%s_revenue' => '%s ' . Piwik_Translate('Goals_ColumnRevenue'), - 'goal_%s_revenue_per_visit' => '%s ' . Piwik_Translate('General_ColumnValuePerVisit'), - 'nb_conversions' => Piwik_Translate('Goals_ColumnConversions'), - 'conversion_rate' => Piwik_Translate('General_ColumnConversionRate'), - 'revenue' => Piwik_Translate('Goals_ColumnRevenue'), - 'revenue_per_visit' => Piwik_Translate('General_ColumnValuePerVisit'), - ); - - $this->viewProperties['columns_to_display'] = array( - 'label', 'nb_visits', 'goal_%s_nb_conversions', 'goal_%s_conversion_rate', 'goal_%s_revenue', - 'goal_%s_revenue_per_visit', 'revenue_per_visit'); - - // Default sort column - $columnsToDisplay = $this->viewProperties['columns_to_display']; - $columnNbConversionsCurrentGoal = $columnsToDisplay[2]; - if ($this->processOnlyIdGoal > 0 - && strpos($columnNbConversionsCurrentGoal, '_nb_conversions') !== false - ) { - $this->viewProperties['filter_sort_column'] = $columnNbConversionsCurrentGoal; - $this->viewProperties['filter_sort_order'] = 'desc'; - } - } - - parent::main(); - } - - /** - * Find the appropriate metric documentation for a goal column - * @param string $genericMetricName - * @param string $metricName - * @param string $goalName - * @param int $idGoal - */ - private function setDynamicMetricDocumentation($genericMetricName, $metricName, $goalName, $idGoal) - { - if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { - $goalName = Piwik_Translate('General_EcommerceOrders'); - } else { - $goalName = '"' . $goalName . '"'; - } - - $langString = false; - switch ($genericMetricName) { - case 'goal_%s_nb_conversions': - $langString = 'Goals_ColumnConversionsDocumentation'; - break; - case 'goal_%s_conversion_rate': - $langString = 'Goals_ColumnConversionRateDocumentation'; - break; - case 'goal_%s_revenue_per_visit': - $langString = 'Goals_ColumnRevenuePerVisitDocumentation'; - break; - case 'goal_%s_revenue': - $langString = 'Goals_ColumnRevenueDocumentation'; - break; - case 'goal_%s_avg_order_revenue': - $langString = 'Goals_ColumnAverageOrderRevenueDocumentation'; - break; - case 'goal_%s_items': - $langString = 'Goals_ColumnPurchasedProductsDocumentation'; - break; - } - - if ($langString) { - $doc = Piwik_Translate($langString, $goalName); - $this->viewProperties['metrics_documentation'][$metricName] = $doc; - } - } - - protected function getRequestArray() - { - $requestArray = parent::getRequestArray(); - if ($this->processOnlyIdGoal > AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE - || $this->isEcommerce - ) { - $requestArray["idGoal"] = $this->processOnlyIdGoal; - } - $requestArray['filter_update_columns_when_show_all_goals'] = 1; - return $requestArray; - } - - protected $columnsToRevenueFilter = array(); - protected $columnsToConversionFilter = array(); - protected $idSite = false; - - private function getIdSite() - { - return $this->idSite; - } - - protected function postDataTableLoadedFromAPI() - { - $valid = parent::postDataTableLoadedFromAPI(); - if ($valid === false) return false; - - foreach ($this->viewProperties['columns_to_display'] as $columnName) { - if (strpos($columnName, 'conversion_rate')) { - $this->dataTable->filter('ColumnCallbackReplace', array($columnName, create_function('$rate', 'if($rate==0) return "0%"; else return $rate;'))); - } - } - $this->columnsToRevenueFilter[] = 'revenue_per_visit'; - foreach ($this->columnsToRevenueFilter as $columnName) { - $this->dataTable->filter('ColumnCallbackReplace', array($columnName, create_function('$value', 'return sprintf("%.1f",$value);'))); - $this->dataTable->filter('ColumnCallbackReplace', array($columnName, '\Piwik\Piwik::getPrettyMoney', array($this->getIdSite()))); - } - - foreach ($this->columnsToConversionFilter as $columnName) { - // this ensures that the value is set to zero for all rows where the value was not set (no conversion) - $this->dataTable->filter('ColumnCallbackReplace', array($columnName, create_function('$value', 'return $value;'))); - } - return true; - } - - protected function overrideViewProperties() - { - parent::overrideViewProperties(); - - $columnsNames = $this->viewProperties['columns_to_display']; - - $newColumnsNames = array(); - $goals = array(); - $idSite = $this->getIdSite(); - if ($idSite) { - $goals = API::getInstance()->getGoals($idSite); - - $ecommerceGoal = array( - 'idgoal' => Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER, - 'name' => Piwik_Translate('Goals_EcommerceOrder') - ); - - $site = new Site($idSite); - //Case Ecommerce report table - if ($this->isEcommerce) { - $goals = array($ecommerceGoal); - } // Case tableGoals - elseif ($site->isEcommerceEnabled()) { - $goals = array_merge( - array($ecommerceGoal), - $goals - ); - } - } - foreach ($columnsNames as $columnName) { - if (in_array($columnName, array( - 'goal_%s_conversion_rate', - 'goal_%s_nb_conversions', - 'goal_%s_revenue_per_visit', - 'goal_%s_revenue', - 'goal_%s_avg_order_revenue', - 'goal_%s_items', - - )) - ) { - foreach ($goals as $goal) { - $idgoal = $goal['idgoal']; - - $goal['name'] = Common::unsanitizeInputValue($goal['name']); - - if ($this->processOnlyIdGoal > AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE - && $this->processOnlyIdGoal != $idgoal - && !$this->isEcommerce - ) { - continue; - } - $column = isset($this->viewProperties['translations'][$columnName]) ? - $this->viewProperties['translations'][$columnName] : $columnName; - $name = Piwik_Translate($column, $goal['name']); - $columnNameGoal = str_replace('%s', $idgoal, $columnName); - $this->viewProperties['translations'][$columnNameGoal] = $name; - $this->setDynamicMetricDocumentation($columnName, $columnNameGoal, $goal['name'], $goal['idgoal']); - if (strpos($columnNameGoal, '_rate') === false - // For the goal table (when the flag icon is clicked), we only display the per Goal Conversion rate - && $this->processOnlyIdGoal == AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW - ) { - continue; - } - - if (strstr($columnNameGoal, '_revenue') !== false) { - $this->columnsToRevenueFilter[] = $columnNameGoal; - } else { - $this->columnsToConversionFilter[] = $columnNameGoal; - } - $newColumnsNames[] = $columnNameGoal; - } - } else { - $newColumnsNames[] = $columnName; - } - } - - $this->viewProperties['columns_to_display'] = $newColumnsNames; - } - - public function getDefaultDataTableCssClass() - { - return 'dataTableGoals'; - } -} diff --git a/core/ViewDataTable/Properties.php b/core/ViewDataTable/Properties.php index 9d0a08d558..b0001be374 100644 --- a/core/ViewDataTable/Properties.php +++ b/core/ViewDataTable/Properties.php @@ -13,18 +13,29 @@ namespace Piwik\ViewDataTable; use Exception; use ReflectionClass; +use Piwik\Piwik; +use Piwik\Config; +use Piwik\Metrics; +use Piwik\Common; /** * Contains the list of all core DataTable display properties for use with ViewDataTable. * * @see ViewDataTable - for more info. * - * TODO: change the names of properties to match the const names where appropriate. * TODO: list default value for each property */ class Properties { /** + * The default viewDataTable ID to use when determining which visualization to use. + * This property is only valid for reports whose properties are determined by the + * ViewDataTable.getReportDisplayProperties event. When manually creating ViewDataTables, + * setting this property will have no effect. + */ + const DEFAULT_VIEW_TYPE = 'default_view_type'; + + /** * This property determines which Twig template to use when rendering a ViewDataTable. * * TODO: shouldn't have this property. should only use visualization classes. @@ -54,13 +65,6 @@ class Properties const SORT_ORDER = 'filter_sort_order'; /** - * The limit used when rendering a jqPlot graph. - * - * TODO: either replace w/ filter_limit, or make it a visualization property. - */ - const GRAPH_LIMIT = 'graph_limit'; - - /** * The number of items to truncate the data set to before rendering the DataTable view. */ const LIMIT = 'filter_limit'; @@ -118,23 +122,13 @@ class Properties const SHOW_ACTIVE_VIEW_ICON = 'show_active_view_icon'; /** - * TODO: this property is specific ONLY to the row evolution popup. Need to move it. - */ - const EXTERNAL_SERIES_TOGGLE = 'external_series_toggle'; - - /** - * TODO: this property is specific ONLY to the row evolution popup. Need to move it. - */ - const EXTERNAL_SERIES_TOGGLE_SHOW_ALL = 'external_series_toggle_show_all'; - - /** * Related reports are listed below a datatable view. When clicked, the original report will * change to the clicked report and the list will change so the original report can be * navigated back to. * * @see also self::TITLE. Both must be set if associating related reports. */ - const RELATED_REPORTS = 'relatedReports'; + const RELATED_REPORTS = 'related_reports'; /** * The report title. Used with related reports so report headings can be changed when switching @@ -150,13 +144,6 @@ class Properties const SHOW_RELATED_REPORTS = 'show_related_reports'; /** - * Array property that contains the names of columns that can be selected in the Series Picker. - * - * TODO: this is only applicable to graph views. move this. - */ - const SELECTABLE_COLUMNS = 'selectable_columns'; - - /** * Contains the documentation for a report. */ const REPORT_DOCUMENTATION = 'documentation'; @@ -196,7 +183,7 @@ class Properties * * @see self::ROW_PICKER_VISIBLE_VALUES */ - const ROW_PICKER_VALUE_COLUMN = 'row_picker_mach_rows_by'; + const ROW_PICKER_VALUE_COLUMN = 'row_picker_match_rows_by'; /** * Contains the list of values available for the Row Picker. @@ -228,13 +215,6 @@ class Properties const ALWAYS_SHOW_LIMIT_DROPDOWN = 'show_limit_control'; /** - * Controls whether offset information (ie, '5-10 of 20') is shown under the datatable. - * - * @see TODO - */ - const SHOW_OFFSET_INFORMATION = 'show_offset_information'; - - /** * Controls whether the search box under the datatable is shown. */ const SHOW_SEARCH_BOX = 'show_search'; @@ -245,12 +225,6 @@ class Properties const ENABLE_SORT = 'enable_sort'; /** - * Controls whether annotations are shown or not. - * TODO: This is only appropriate for evolution graphs. Move it. - */ - const HIDE_ANNOTATIONS_VIEW = 'hide_annotations_view'; - - /** * Controls whether the footer icon that allows users to view data as a bar chart is shown. */ const SHOW_BAR_CHART_ICON = 'show_bar_chart'; @@ -339,18 +313,8 @@ class Properties const VISUALIZATION_PROPERTIES = 'visualization_properties'; /** - * Custom template used if displaying a subtable. - * - * TODO: This is specific to HtmlTable and should be replaced w/ allowing custom visualization for - * subtables. Should not directly touch template. - */ - const SUBTABLE_TEMPLATE = 'subtable_template'; - - /** - * CSS class to use in the output HTML div. - * - * TODO: This only changes based on the visualization type. Would be good if it didn't need to be - * set at all... + * CSS class to use in the output HTML div. This is added in addition to the visualization CSS + * class. */ const DATATABLE_CSS_CLASS = 'datatable_css_class'; @@ -361,14 +325,6 @@ class Properties const DATATABLE_JS_TYPE = 'datatable_js_type'; /** - * Controls whether the entire DataTable should be rendered (including subtables) or just one - * specific table in the tree. - * - * TODO: specific to htmltable. make a visualization property. - */ - const SHOW_EXPANDED = 'show_expanded'; - - /** * If true, searching through the DataTable will search through all subtables. * * @see also self::FILTER_PATTERN @@ -376,61 +332,67 @@ class Properties const DO_RECURSIVE_SEARCH = 'search_recursive'; /** - * Controls whether the row evolution DataTable Row Action icon is shown or not. - * - * TODO: specific to HtmlTable. move. - * - * @see also self::DISABLE_ROW_ACTIONS + * The unit of the displayed column. Valid if only one non-label column is displayed. */ - const DISABLE_ROW_EVOLUTION = 'disable_row_evolution'; + const DISPLAYED_COLUMN_UNIT = 'y_axis_unit'; /** - * Controls whether any DataTable Row Action icons are shown. If true, no icons are shown. + * Controls whether to show the 'Export as Image' footer icon. + */ + const SHOW_EXPORT_AS_IMAGE_ICON = 'show_export_as_image_icon'; + + /** + * Array of DataTable filters that should be run before displaying a DataTable. Elements + * of this array can either be a closure or an array with at most three elements, including: + * - the filter name (or a closure) + * - an array of filter parameters + * - a boolean indicating if the filter is a priority filter or not * - * TODO: specific to HtmlTable. move. + * Priority filters are run before queued filters. These filters should be filters that + * add/delete rows. * - * @see also self::DISABLE_ROW_EVOLUTION + * If a closure is used, the view is appended as a parameter. */ - const DISABLE_ROW_ACTIONS = 'disable_row_actions'; + const FILTERS = 'filters'; /** - * The unit of the displayed column. Valid if only one non-label column is displayed. + * Contains the controller action to call when requesting subtables of the current report. */ - const DISPLAYED_COLUMN_UNIT = 'y_axis_unit'; + const SUBTABLE_CONTROLLER_ACTION = 'subtable_controller_action'; /** - * Controls whether the percentage of the total is displayed as a tooltip in Jqplot graphs. + * Controls whether the 'prev'/'next' links are shown in the DataTable footer. These links + * change the 'filter_offset' query parameter, thus allowing pagination. * - * NOTE: Sometimes this percentage is meaningless (when the total of the column values is - * not the total number of elements in the set). In this case the tooltip should not be - * displayed. + * @see self::SHOW_OFFSET_INFORMATION + */ + const SHOW_PAGINATION_CONTROL = 'show_pagination_control'; + + /** + * Controls whether offset information (ie, '5-10 of 20') is shown under the datatable. * - * TODO: only valid for graphs... move it. + * @see self::SHOW_PAGINATION_CONTROL */ - const DISPLAY_PERCENTAGE_IN_TOOLTIP = 'display_percentage_in_tooltip'; + const SHOW_OFFSET_INFORMATION = 'show_offset_information'; /** - * Controls whether to show the 'Export as Image' footer icon. + * Controls whether annotations are shown or not. */ - const SHOW_EXPORT_AS_IMAGE_ICON = 'show_export_as_image_icon'; + const HIDE_ANNOTATIONS_VIEW = 'hide_annotations_view'; /** - * Controls whether all ticks & labels are shown on a graph's x-axis or just some. - * - * TODO: only for jqplot graphs. + * The filter_limit query parameter value to use in export links. */ - const SHOW_ALL_TICKS = 'show_all_ticks'; + const EXPORT_LIMIT = 'export_limit'; /** - * If true, a row with totals of each DataTable column is added. - * - * TODO: only for jqplot graphs. also doesn't seem necessary w/ AddSummaryRow + * Controls whether non-Core DataTable visualizations are shown or not. */ - const ADD_TOTAL_ROW = 'add_total_row'; + const SHOW_NON_CORE_VISUALIZATIONS = 'show_non_core_visualizations'; /** * Returns the set of all valid ViewDataTable properties. The result is an array with property - * name as a key. Values of the array are undefined. + * names as keys. Values of the array are undefined. * * @return array */ @@ -439,14 +401,62 @@ class Properties static $propertiesCache = null; if ($propertiesCache === null) { - $klass = new ReflectionClass(__CLASS__); - $propertiesCache = array_flip($klass->getConstants()); + $propertiesCache = self::getFlippedClassConstantMap(__CLASS__); } return $propertiesCache; } /** + * Returns the set of all valid properties for the given visualization class. The result is an + * array with property names as keys. Values of the array are undefined. + * + * @return array + */ + public static function getVisualizationProperties($visualizationClass) + { + static $propertiesCache = array(); + + if ($visualizationClass === null) { + return array(); + } + + if (!isset($propertiesCache[$visualizationClass])) { + $properties = self::getFlippedClassConstantMap($visualizationClass); + + $parentClass = get_parent_class($visualizationClass); + if ($parentClass != 'Piwik\\DataTableVisualization') { + $properties += self::getVisualizationProperties($parentClass); + } + + $propertiesCache[$visualizationClass] = $properties; + } + + return $propertiesCache[$visualizationClass]; + } + + /** + * Returns true if $name is a core ViewDataTable property, false if not. + * + * @param string $name + * @return bool + */ + public static function isCoreViewProperty($name) + { + $properties = self::getAllProperties(); + return isset($properties[$name]); + } + + /** + * Returns true if $name is a valid visualization property for the given visualization class. + */ + public static function isValidVisualizationProperty($visualizationClass, $name) + { + $properties = self::getVisualizationProperties($visualizationClass); + return isset($properties[$name]); + } + + /** * Checks if a property is a valid ViewDataTable property, and if not, throws an exception. * * @param string $name The property name. @@ -454,10 +464,99 @@ class Properties */ public static function checkValidPropertyName($name) { - $properties = self::getAllProperties(); - if (!isset($properties[$name])) { - throw new Exception("Invalid ViewDataTable display property '$name'. Is this a visualization property? " - . "If so, set it with \$view->visualization_properties->$name = ..."); + if (!self::isCoreViewProperty($name)) { + throw new Exception("Invalid ViewDataTable display property '$name'."); + } + } + + /** + * Checks if a property is a valid visualization property for the given visualization class, + * and if not, throws an exception. + * + * @param string $visualizationClass + * @param string $name The property name. + * @throws Exception + */ + public static function checkValidVisualizationProperty($visualizationClass, $name) + { + if (!self::isValidVisualizationProperty($visualizationClass, $name)) { + throw new Exception("Invalid Visualization display property '$name' for '$visualizationClass'."); } } + + /** + * Returns the default values for each core view property. + * + * @return array + */ + public static function getDefaultPropertyValues() + { + $result = array( + 'datatable_template' => '@CoreHome/_dataTable', + 'show_goals' => false, + 'show_ecommerce' => false, + 'show_search' => true, + 'show_table' => true, + 'show_table_all_columns' => true, + 'show_all_views_icons' => true, + 'show_active_view_icon' => true, + 'show_bar_chart' => true, + 'show_pie_chart' => true, + 'show_tag_cloud' => true, + 'show_export_as_image_icon' => false, + 'show_export_as_rss_feed' => true, + 'show_exclude_low_population' => true, + 'show_offset_information' => true, + 'show_pagination_control' => true, + 'show_limit_control' => false, + 'show_footer' => true, + 'show_related_reports' => true, + 'show_non_core_visualizations' => true, + 'export_limit' => Config::getInstance()->General['API_datatable_default_limit'], + 'highlight_summary_row' => false, + 'related_reports' => array(), + 'title' => 'unknown', + 'tooltip_metadata_name' => false, + 'enable_sort' => true, + 'disable_generic_filters' => false, + 'disable_queued_filters' => false, + 'keep_summary_row' => false, + 'filter_excludelowpop' => false, + 'filter_excludelowpop_value' => false, + 'filter_pattern' => false, + 'filter_column' => false, + 'filter_limit' => false, + 'filter_sort_column' => false, + 'filter_sort_order' => false, + 'custom_parameters' => array(), + 'translations' => array_merge( + Metrics::getDefaultMetrics(), + Metrics::getDefaultProcessedMetrics() + ), + 'request_parameters_to_modify' => array(), + 'documentation' => false, + 'datatable_css_class' => false, + 'filters' => array(), + 'hide_annotations_view' => true, + 'columns_to_display' => array(), + ); + + $columns = Common::getRequestVar('columns', false); + if ($columns !== false) { + $result['columns_to_display'] = Piwik::getArrayFromApiParameter($columns); + array_unshift($result['columns_to_display'], 'label'); + } + + return $result; + } + + private static function getFlippedClassConstantMap($klass) + { + $klass = new ReflectionClass($klass); + $constants = $klass->getConstants(); + unset($constants['ID']); + unset($constants['FOOTER_ICON']); + unset($constants['FOOTER_ICON_TITLE']); + return array_flip($constants); + } }
\ No newline at end of file diff --git a/core/ViewDataTable/Sparkline.php b/core/ViewDataTable/Sparkline.php index 1c31ddeea1..c3fd116114 100644 --- a/core/ViewDataTable/Sparkline.php +++ b/core/ViewDataTable/Sparkline.php @@ -23,7 +23,12 @@ use Piwik\ViewDataTable; */ class Sparkline extends ViewDataTable { - protected function getViewDataTableId() + /** + * Returns dataTable id for view + * + * @return string + */ + public function getViewDataTableId() { return 'sparkline'; } @@ -32,13 +37,8 @@ class Sparkline extends ViewDataTable * @see ViewDataTable::main() * @return mixed */ - public function main() + protected function buildView() { - if ($this->mainAlreadyExecuted) { - return; - } - $this->mainAlreadyExecuted = true; - // If period=range, we force the sparkline to draw daily data points $period = Common::getRequestVar('period'); if ($period == 'range') { @@ -71,6 +71,13 @@ class Sparkline extends ViewDataTable $this->view = $graph; } + /** + * @param DataTable\Map $dataTableArray + * @param string $columnToPlot + * + * @return array + * @throws \Exception + */ protected function getValuesFromDataTableArray($dataTableArray, $columnToPlot) { $dataTableArray->applyQueuedFilters(); diff --git a/core/ViewDataTable/VisualizationPropertiesProxy.php b/core/ViewDataTable/VisualizationPropertiesProxy.php index c6ef3f079e..8930cb9696 100644 --- a/core/ViewDataTable/VisualizationPropertiesProxy.php +++ b/core/ViewDataTable/VisualizationPropertiesProxy.php @@ -20,11 +20,11 @@ use Piwik\ViewDataTable\Properties; class VisualizationPropertiesProxy { /** - * The visualization instance. + * The visualization class name. * - * @var array + * @var string */ - private $visualization; + private $visualizationClass; /** * Stores visualization properties. @@ -36,11 +36,19 @@ class VisualizationPropertiesProxy /** * Constructor. * - * @param \Piwik\Visualization\ $visualization The visualization to get/set properties of. + * @param string $visualizationClass The visualization class to get/set properties of. + */ + public function __construct($visualizationClass) + { + $this->visualizationClass = $visualizationClass; + } + + /** + * Hack to allow property access in Twig (w/ property name checking). */ - public function __construct($visualization) + public function __call($name, $arguments) { - $this->visualization = $visualization; + return $this->$name; } /** @@ -52,7 +60,10 @@ class VisualizationPropertiesProxy */ public function &__get($name) { - Properties::checkValidVisualizationProperty($this->visualization, $name); + if ($this->visualizationClass !== null) { + Properties::checkValidVisualizationProperty($this->visualizationClass, $name); + } + return $this->visualizationProperties[$name]; } @@ -66,7 +77,29 @@ class VisualizationPropertiesProxy */ public function __set($name, $value) { - Properties::checkValidVisualizationProperty($this->visualization, $name); + if ($this->visualizationClass !== null) { + Properties::checkValidVisualizationProperty($this->visualizationClass, $name); + } + return $this->visualizationProperties[$name] = $value; } + + /** + * Sets a visualization property, but only if the visualization is an instance of a + * certain class. + * + * @param string $forClass The visualization class to check for. + * @param string $name A valid property name for the current visualization. + * @param mixed $value + * @return mixed Returns $value. + * @throws \Exception if the property name is invalid. + */ + public function setForVisualization($forClass, $name, $value) + { + if ($forClass == $this->visualizationClass + || is_subclass_of($this->visualizationClass, $forClass) + ) { + return $this->__set($name, $value); + } + } }
\ No newline at end of file diff --git a/core/Visualization/HtmlTable.php b/core/Visualization/HtmlTable.php deleted file mode 100644 index 036f7eb9ed..0000000000 --- a/core/Visualization/HtmlTable.php +++ /dev/null @@ -1,81 +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 - * - * @category Piwik - * @package Piwik - */ - -namespace Piwik\Visualization; - -use Piwik\DataTable; -use Piwik\View; -use Piwik\Config; -use Piwik\Common; - -/** - * DataTable visualization that shows DataTable data in an HTML table. - */ -class HtmlTable -{ - /** - * TODO - */ - public function getJavaScriptProperties() - { - return array('search_recursive'); - } - - /** - * TODO - * @deprecated - */ - public function getViewDataTableId() - { - return 'table'; - } - - /** - * Renders this visualization. - * - * @param DataTable $dataTable - * @param array $properties View Properties. - * @return string - */ - public function render(DataTable $dataTable, $properties) - { - $view = new View("@CoreHome/_dataTableViz_htmlTable.twig"); - $view->properties = $properties; - $view->dataTable = $dataTable; - return $view->render(); - } - - /** - * TODO - */ - public function getDefaultPropertyValues() - { - $defaults = array( - 'enable_sort' => true, - 'disable_row_evolution' => false, - 'disable_row_actions' => false, - 'subtable_template' => "@CoreHome/_dataTable.twig", - 'datatable_js_type' => 'dataTable' - ); - - $defaultLimit = Config::getInstance()->General['datatable_default_limit']; - if ($defaultLimit !== 0) { - $defaults['filter_limit'] = $defaultLimit; - } - - if (Common::getRequestVar('enable_filter_excludelowpop', false) == '1') { - $defaults['filter_excludelowpop'] = 'nb_visits'; - $defaults['filter_excludelowpop_value'] = null; - } - - return $defaults; - } -}
\ No newline at end of file diff --git a/core/Visualization/JqplotGraph.php b/core/Visualization/JqplotGraph.php deleted file mode 100644 index fc2cd9e6cb..0000000000 --- a/core/Visualization/JqplotGraph.php +++ /dev/null @@ -1,50 +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 - * - * @category Piwik - * @package Piwik - */ - -namespace Piwik\Visualization; - -use Piwik\View; -use Piwik\JqplotDataGenerator; -use Piwik\DataTable; - -/** - * DataTable visualization that displays DataTable data in a JQPlot graph. - */ -class JqplotGraph -{ - /** - * Renders this visualization. - * - * @param DataTable $dataTable - * @param array $properties View Properties. - * @return string - */ - public function render($dataTable, $properties) - { - $view = new View("@CoreHome/_dataTableViz_jqplotGraph.twig"); - $view->properties = $properties; - $view->dataTable = $dataTable; - $view->data = $this->getGraphData($dataTable, $properties); - return $view->render(); - } - - /** - * Generats JQPlot graph data for a DataTable. - */ - private function getGraphData($dataTable, $properties) - { - $properties = array_merge($properties, $properties['request_parameters_to_modify']); - $dataGenerator = JqplotDataGenerator::factory($properties['graph_type'], $properties); - - $jsonData = $dataGenerator->generate($dataTable); - return str_replace(array("\r", "\n"), '', $jsonData); - } -}
\ No newline at end of file diff --git a/core/Visualization/Sparkline.php b/core/Visualization/Sparkline.php index 7d5c643436..d781e8a95d 100644 --- a/core/Visualization/Sparkline.php +++ b/core/Visualization/Sparkline.php @@ -33,7 +33,7 @@ class Sparkline implements ViewInterface const DEFAULT_WIDTH = 100; const DEFAULT_HEIGHT = 25; - private static $colorNames = array('lineColor', 'red', 'blue', 'green'); + private static $colorNames = array('backgroundColor', 'lineColor', 'minPointColor', 'lastPointColor', 'maxPointColor'); /** * Width of the sparkline @@ -136,9 +136,9 @@ class Sparkline implements ViewInterface $sparkline->SetYMin(0); $sparkline->SetYMax($max[1]); $sparkline->SetPadding(3, 0, 2, 0); // top, right, bottom, left - $sparkline->SetFeaturePoint($min[0], $min[1], 'red', 5); - $sparkline->SetFeaturePoint($max[0], $max[1], 'green', 5); - $sparkline->SetFeaturePoint($last[0], $last[1], 'blue', 5); + $sparkline->SetFeaturePoint($min[0], $min[1], 'minPointColor', 5); + $sparkline->SetFeaturePoint($max[0], $max[1], 'maxPointColor', 5); + $sparkline->SetFeaturePoint($last[0], $last[1], 'lastPointColor', 5); $sparkline->SetLineSize(3); // for renderresampled, linesize is on virtual image $ratio = 1; $sparkline->RenderResampled($width * $ratio, $height * $ratio); diff --git a/core/functions.php b/core/functions.php index 25dfaedf9b..98c27e322a 100644 --- a/core/functions.php +++ b/core/functions.php @@ -97,7 +97,7 @@ namespace { * Returns the option value for the requested option $name * * @param string $name Key - * @return string|false Value or false, if not found + * @return string|bool Value or false, if not found */ function Piwik_GetOption($name) { diff --git a/core/testMinimumPhpVersion.php b/core/testMinimumPhpVersion.php index 8917bfad47..64cc206d44 100644 --- a/core/testMinimumPhpVersion.php +++ b/core/testMinimumPhpVersion.php @@ -17,8 +17,8 @@ $piwik_errorMessage = ''; -// Minimum requirement: ->newInstanceArgs in 5.1.3 -$piwik_minimumPHPVersion = '5.1.3RC'; +// Minimum requirement: Namespaces in 5.3 +$piwik_minimumPHPVersion = '5.3'; $piwik_currentPHPVersion = PHP_VERSION; $minimumPhpInvalid = version_compare($piwik_minimumPHPVersion, $piwik_currentPHPVersion) > 0; if ($minimumPhpInvalid) { diff --git a/lang/ca.php b/lang/ca.php index 7487155b1c..c09ef9a53f 100644 --- a/lang/ca.php +++ b/lang/ca.php @@ -969,7 +969,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>El Piwik és un programari d\'anàlisi web de codi obert que facilita la presa d\'informació dels vostres visitants.</p><p>Aquest procés està dividit en %s passos fàcils i trigarà uns 5 minuts.</p>', 'Installation_ConfigurationHelp' => 'Sembla que el vostre fitxer de configuració del Piwik no està definit correctament. Podeu eliminar el fitxer confi/config.ini.php i torna a començar la instal·lació o corregir les preferències de connexió a la Base de dades.', 'Installation_ErrorInvalidState' => 'Hi ha hagut un error: sembla que esteu intentant saltar-vos un pas de la instal·lació, o teniu les galetes desactivades o el fitxer de configuració del Piwik ja existeix. %1$sAssegureu-vos que teniu les galetes activades%2$s i torneu enrera %3$s al primer pas de la instal·lació %4$s.', - 'Installation_InsufficientPrivileges' => 'Privilegis insuficients: L\'usuari de la base de dades ha de tenir els següents privilegis: %s', 'Installation_InsufficientPrivilegesHelp' => 'Podeu afegir aquest usuaris previlegiats utiltizat eines com el phpMyAdmin o executant les sentències SQL corresponents. Si no sabeu com fer cap d\'aquestes coses, siusplau poseu-vos amb contacte amb el vostre administrador de sistemes per donar aquestos privilegis per vosaltres.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Ohhh! El piwik ha trobat algunes %1$s incidències crítiques %2$s amb la vostra configuració de Piwik. %3$s Aquestes incidències s\'han de solucionar inmediatament. %4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Hi ha alguna incidència amb el vostre sistema. El Piwik funcionarà, però podeu tenir alguns problemes menors.', diff --git a/lang/da.php b/lang/da.php index 5fde22def8..284ad25f8f 100644 --- a/lang/da.php +++ b/lang/da.php @@ -1074,7 +1074,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik er et Open Source statistik-program som gør det nemt at finde information om besøgende.</p><p> Processen er delt op i %s lette trin og vil tage ca. 5 minutter.</p>', 'Installation_ConfigurationHelp' => 'Piwik konfigurationsfil synes at være konfigureret forkert. Fjern enten config/config.ini.php og genoptage installation eller ret database forbindelsesindstillinger.', 'Installation_ErrorInvalidState' => 'Fejl: Det lader til at du forsøger at springe et skridt af installationen over, eller cookies er slået fra, eller Piwik konfigurationsfil allerede er oprettet. %1$sSørg for, at cookies er aktiveret%2$s og gå tilbage %3$s til den første side i installationen %4$s.', - 'Installation_InsufficientPrivileges' => 'Utilstrækkelige rettigheder. Databasebrugeren skal have følgende rettigheder: %s', 'Installation_InsufficientPrivilegesHelp' => 'Du kan tilføje disse rettigheder ved at bruge et værktøj som phpMyAdmin eller ved at udføre de rigtige SQL-forespørgsler. Hvis du ikke ved hvordan man gør, skal du bede din sysadmin til at tildele rettighederne.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Ups! Piwik har opdaget nogle %1$skritiske problemer%2$s med din Piwik opsætning. %3$sDisse problemer skal løses øjeblikkeligt.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Der er nogle problemer med dit system. Piwik vil virke, men du kan opleve nogle mindre problemer.', diff --git a/lang/de.php b/lang/de.php index 48676110a5..579da7d184 100644 --- a/lang/de.php +++ b/lang/de.php @@ -403,7 +403,7 @@ $translations = array( 'Actions_WidgetExitPageTitles' => 'Titel der Ausgangsseiten', 'Actions_SubmenuPageTitles' => 'Seitentitel', 'Actions_WidgetPageTitles' => 'Seitentitel', - 'Actions_WidgetSearchKeywords' => 'Suchbegriffe', + 'Actions_WidgetSearchKeywords' => 'Suchbegriffe (interne Suche)', 'Actions_WidgetSearchCategories' => 'Suchkategorien', 'Actions_WidgetSearchNoResultKeywords' => 'Suchbegriffe ohne Ergebnisse', 'Actions_WidgetPageUrlsFollowingSearch' => 'Besuchte Seiten nach einer internen Suche', @@ -723,6 +723,7 @@ $translations = array( 'CorePluginsAdmin_Inactive' => 'Inaktiv', 'CorePluginsAdmin_Deactivate' => 'Deaktivieren', 'CorePluginsAdmin_Activate' => 'Aktivieren', + 'CorePluginsAdmin_MenuPlatform' => 'Plattform', 'CorePluginsAdmin_MenuExtend' => 'Erweitern', 'CorePluginsAdmin_PluginCannotBeFound' => 'Plugin konnte nicht gefunden werden!', 'CoreUpdater_PluginDescription' => 'Piwik-Aktualisierung', @@ -1069,7 +1070,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik ist eine freiverfügbare Webanalyse-Software, um einfach Informationen über die Besucher Ihrer Webseite zu erhalten.</p><p>Der Prozess teilt sich in %s einfache Schritte und wird rund 5 Minuten dauern.</p>', 'Installation_ConfigurationHelp' => 'Ihre Konfigurationsdatei enthält Fehler. Sie können entweder die config/config.php löschen und neu installieren, oder die Einstellung zur Datenbankverbindung korrigieren.', 'Installation_ErrorInvalidState' => 'Fehler: Sie scheinen zu versuchen, einen Schritt des Installationsvorgangs zu überspringen oder Ihre Cookies sind deaktiviert, oder die Piwik-Konfigurationsdatei wurde bereits erstellt. %1$sStellen Sie sicher, dass Ihre Cookies aktiviert%2$s sind und gehen Sie zurück %3$s zur ersten Seite der Installation. %4$s', - 'Installation_InsufficientPrivileges' => 'Unzureichende Benutzerrechte. Der Datenbank Benutzer muss über folgende Rechte verfügen: %s', 'Installation_InsufficientPrivilegesHelp' => 'Sie können diese Rechte mit einem Tool wie phpMyAdmin oder den entsprechenden SQL Kommandos hinzufügen. Wenn Sie nicht wissen, was zu tun ist, wenden Sie sich bitte an den System Administrator, damit er für Sie diese Rechte setzt.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Ohje! Piwik hat einige %1$skritische Fehler%2$s mit Ihrer Installation festgestellt. %3$sDiese sollten schnellstmöglich behoben werden.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Es gibt einige Ungereimtheiten mit Ihrem System. Piwik wird funktionieren, aber es könnten geringfügige Probleme auftauchen.', diff --git a/lang/el.php b/lang/el.php index 46f97ddade..f1db5f9d87 100644 --- a/lang/el.php +++ b/lang/el.php @@ -1,7 +1,7 @@ <?php $translations = array( 'General_Locale' => 'el_GR.UTF-8', - 'General_TranslatorName' => 'Jim Black www.jblack.info, Γεώργιος Τέλλος OnSite.Net VoIP & IT Solutions, Παναγιώτης Παπάζογλου Δρ. Δασολόγος-Περιβαλλοντολόγος', + 'General_TranslatorName' => 'Jim Black www.jblack.info, Γεώργιος Τέλλος OnSite.Net VoIP & IT Solutions, Παναγιώτης Παπάζογλου Δρ. Δασολόγος-Περιβαλλοντολόγος, Λούρδας Βασίλειος (www.lourdas.name)', 'General_TranslatorEmail' => 'jimaek@hotmail.com, info@onsite.net.gr, papaz_p@yahoo.com', 'General_EnglishLanguageName' => 'Hellenic', 'General_OriginalLanguageName' => 'Ελληνικά', @@ -708,9 +708,13 @@ $translations = array( 'CoreHome_MakeOneTimeDonation' => 'Εναλλακτικά, κάντε μια εφάπαξ δωρεά.', 'CorePluginsAdmin_PluginDescription' => 'Περιβάλλον εργασίας Διαχείρισης Προσθέτων.', 'CorePluginsAdmin_Plugins' => 'Πρόσθετα', + 'CorePluginsAdmin_Themes' => 'Θεματικές παραλλαγές', 'CorePluginsAdmin_PluginsManagement' => 'Διαχείριση προσθέτων', + 'CorePluginsAdmin_ThemesManagement' => 'Διαχείριση θεματικών παραλλαγών', 'CorePluginsAdmin_MainDescription' => 'Τα πρόσθετα (Plugins) επεκτείνουν και διευρύνουν την λειτουργικότητα του Piwik. Αφού εγκατασταθεί ένα πρόσθετο, μπορείτε να το ενεργοποιήσετε ή να το απενεργοποιήσετε εδώ.', + 'CorePluginsAdmin_ThemesDescription' => 'Οι θεματικές παραλλαγές αλλάζουν την εμφάνιση διεπαφής χρήστη του Piwik και παρέχουν μια τελείως νέα οπτική εμπειρία προκειμένου να απολαμβάνετε τις αναφορές σας.', 'CorePluginsAdmin_Plugin' => 'Πρόσθετο', + 'CorePluginsAdmin_Theme' => 'Θεματική παραλλαγή', 'CorePluginsAdmin_Version' => 'Έκδοση', 'CorePluginsAdmin_Status' => 'Κατάσταση', 'CorePluginsAdmin_Action' => 'Δραστηριότητα', @@ -722,6 +726,8 @@ $translations = array( 'CorePluginsAdmin_Inactive' => 'Ανενεργό', 'CorePluginsAdmin_Deactivate' => 'Απενεργοποίηση', 'CorePluginsAdmin_Activate' => 'Ενεργοποίηση', + 'CorePluginsAdmin_MenuPlatform' => 'Πλατφόρμα', + 'CorePluginsAdmin_MenuExtend' => 'Επέκταση', 'CorePluginsAdmin_PluginCannotBeFound' => 'Αυτό το πρόσθετο δεν μπορεί να βρεθεί!', 'CoreUpdater_PluginDescription' => 'Μηχανισμός ενημέρωσης Piwik', 'CoreUpdater_UpdateTitle' => 'Ενημέρωση', @@ -1067,7 +1073,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Το Piwik είναι ένα λογισμικό ανοιχτού κώδικα ανάλυσης ιστοσελίδων που συλλέγει τις πληροφορίες που θέλετε από του επισκέπτες σας.</p><p>Αυτή η διαδικασία είναι χωρισμένη σε %s απλά βήματα και θα πάρει περίπου 5 λεπτά.</p>', 'Installation_ConfigurationHelp' => 'Οι ρυθμίσεις του Piwik φαίνεται ότι έχουν πρόβλημα. Μπορείτε να απομακρύνετε το config/config.ini.php και να συνεχίσετε την εγκατάσταση ή διορθώστε τις ρυθμίσεις σύνδεσης της βάσης δεδομένων.', 'Installation_ErrorInvalidState' => 'Σφάλμα: φαίνεται ότι προσπαθείτε να παραλείψετε ένα βήμα από τη διαδικασία εγκατάστασης ή τα cookies είναι απενεργοποιημένα ή έχει ήδη δημιουργηθεί το αρχείο ρυθμίσεων του Piwik. %1$sΣιγουρευτείτε ότι τα cookies είναι ενεργοποιημένα%2$s και επιστρέψτε %3$s στην πρώτη σελίδα της εγκατάστασης %4$s.', - 'Installation_InsufficientPrivileges' => 'Ελλειπή δικαιώματα. Ο χρήστης της βάσης δεδομένων πρέπει να έχει τα ακόλουθα δικαιώματα: %s', 'Installation_InsufficientPrivilegesHelp' => 'Μπορείτε να προσθέσετε αυτά τα δικαιώματα χρησιμοποιώντας ένα εργαλείο όπως το phpMyAdmin ή εκτελόντας τα κατάλληλα ερωτήματα SQL. Αν δεν ξέρετε πως τα κάνετε αυτά, ρωτήστε το διαχειριστή του συστήματος για να δώσει αυτά τα δικαιώματα.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Ώωχ, το Piwik εντόπισε %1$sκρίσιμα θέματα%2$s με την εγκατάσταση του Piwik. %3$sΑυτά τα θέματα πρέπει να διορθωθούν άμεσα.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Υπάρχουν ορισμένα ζητήματα με το σύστημά σας. Το Piwik θα τρέξει, αλλά μπορεί να αντιμετωπίσετε κάποια μικροπροβλήματα.', diff --git a/lang/en.php b/lang/en.php index db86f10267..745b5b0471 100644 --- a/lang/en.php +++ b/lang/en.php @@ -1079,7 +1079,7 @@ Piwik will let you track visitors to your website for free. You should definitel 'Installation_WelcomeHelp' => '<p>Piwik is an open source web analytics software that makes it easy to get the information you want from your visitors.</p><p>This process is split up into %s easy steps and will take around 5 minutes.</p>', 'Installation_ConfigurationHelp' => 'Your Piwik configuration file appears to be misconfigured. You can either remove config/config.ini.php and resume installation, or correct the database connection settings.', 'Installation_ErrorInvalidState' => 'Error: it seems you tried to skip a step of the Installation process, or your cookies are disabled, or the Piwik configuration file was already created. %1$sMake sure your cookies are enabled%2$s and go back %3$s to the first page of the installation %4$s.', - 'Installation_InsufficientPrivileges' => 'Insufficient privileges. Database user must have following privileges: %s', + 'Installation_InsufficientPrivilegesMain' => 'Either the Database does not exist (and could not be created), or the specified User has insufficient privileges. Database user must have the following privileges: %s', 'Installation_InsufficientPrivilegesHelp' => 'You can add these privileges by using a tool such as phpMyAdmin or by executing the right SQL queries. If you don\'t know how to do these things, please ask your sysadmin to grant these privileges for you.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Uh-oh! Piwik has detected some %1$scritical issues%2$s with your Piwik setup. %3$sThese issues should be fixed immediately.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'There are some issues with your system. Piwik will run, but you might experience some minor problems.', @@ -1119,6 +1119,7 @@ Piwik will let you track visitors to your website for free. You should definitel 'Live_NbVisitor' => '1 visitor', 'Live_RealTimeVisitorCount' => 'Real Time Visitor Count', 'Live_SimpleRealTimeWidget_Message' => '%s and %s in the last %s', + 'Live_VisitorProfile' => 'Visitor profile', 'Login_PluginDescription' => 'Login Authentication plugin, reading the credentials from the config/config.inc.php file for the Super User, and from the Database for the other users. Can be easily replaced to introduce a new Authentication mechanism (OpenID, htaccess, custom Auth, etc.).', 'Login_LoginPasswordNotCorrect' => 'Wrong Username and password combination.', 'Login_Password' => 'Password', diff --git a/lang/es.php b/lang/es.php index ef086b3e71..6558809b98 100644 --- a/lang/es.php +++ b/lang/es.php @@ -964,7 +964,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik es un software de análisis web de código abierto que facilita el obtener la información que desea de sus visitantes.</p><p>Este proceso se divide en %s sencillos pasos que le llevarán en torno a 5 minutos.</p>', 'Installation_ConfigurationHelp' => 'Su archivo de configuración de Piwik parece estar desconfigurado. Puede remover el archivo config/config.ini.php y seguir la instalación, o corregir la configuración de conexión de la base de datos.', 'Installation_ErrorInvalidState' => 'Error: parece que trata de saltar un paso del proceso de instalación, o sus cookies están desactivadas, o el archivo de configuración de Piwik ya está creado. %1$sAsegúrese de que las cookies están activadas%2$s y vuelva %3$s a la primera página de la instalación %4$s.', - 'Installation_InsufficientPrivileges' => 'Privilegios insuficientes. El usuario de la base de datos debe tener los siguientes privilegios: %s', 'Installation_InsufficientPrivilegesHelp' => 'Puedes agregar estos privilegios utilizando una herramienta como phpMyAdmin o ejecutando las consultas SQL correspondientes. Si no sabes cómo hacer ninguna de estas operaciones, por favor solicita asistencia a tu sysadmin para que te conceda estos privilegios.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Oh! Piwik ha detectado algunos %1$sproblemas críticos%2$s con su configuración Piwik. %3$sLos mismos deben ser arreglados inmediatamente.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Existen ciertos problemas en su sistema. Piwik correrá, pero puede experimentar ciertos pequeños problemas.', diff --git a/lang/fa.php b/lang/fa.php index 58c87a4686..174feb9985 100644 --- a/lang/fa.php +++ b/lang/fa.php @@ -923,7 +923,6 @@ $translations = array( 'Installation_Welcome' => 'خوش آمدید!', 'Installation_WelcomeHelp' => '<p>پیویک یک نرم افزار آمار وب متن باز است که بدست آوردن اطلاعات بازدیدکنندگان وبسایت شما را آسان کرده است.</p><p>فرآیند نصب پیویک به %s مرحله ی آسان تقسیم شده است و فقط حدود 5 دقیقه زمان می برد.</p>', 'Installation_ConfigurationHelp' => 'فایل پیکربندی Piwik شما به نظر می رسد بد باشد. شما هم می توانید پیکربندی / config.ini.php و حذف از سر نصب و راه اندازی و یا اصلاح تنظیمات اتصال پایگاه داده.', - 'Installation_InsufficientPrivileges' => 'مجوزها کافی نیست. کاربر پایگاه داده باید این مجوزها را داشته باشد: %s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'چند مشکل با سیستم شما وجود دارد. پیویک اجرا خواهد شد ولی ممکن است شما با مشکلات جزئی را تجربه کنید.', 'Installation_SystemCheckSummaryNoProblems' => 'هورا! هیچ مشکلی با نصب پیویک شما نیست.', 'Installation_SeeBelowForMoreInfo' => 'برای اطلاعات بیشتر پایین را ببینید.', diff --git a/lang/fi.php b/lang/fi.php index 04458ab26f..2d35019c0b 100644 --- a/lang/fi.php +++ b/lang/fi.php @@ -924,7 +924,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik on vapaan lähdekoodin verkkosivujen analysointityökalu, joka tekee kävijöiden tietojen keräämisen ja analysoinnin helpoksi.</p><p>Tämä prosessi on jaettu %s helppoon osaan ja vie aikaa noin viisi minuuttia.</p>', 'Installation_ConfigurationHelp' => 'Piwikin asetustiedosto on luotu väärin. Voit joko poistaa tiedoston config/config.ini.php ja käyttää asennusohjelmaa uudelleen tai korjata tietokannan asetukset.', 'Installation_ErrorInvalidState' => 'Virhe: yrität ohittaa vaiheen asennusprosessista tai keksit (cookies) ei ole sallittu. %1$sVarmista, että keksit on sallittu%2$s ja mene takaisin %3$s asennuksen ensimmäiselle sivulle %4$s.', - 'Installation_InsufficientPrivileges' => 'Ei oikeuksia. Tietokannan käyttäjällä pitää olla seuraavat oikeudet: %s', 'Installation_InsufficientPrivilegesHelp' => 'Voit lisätä nämä oikeudet esim. phpMyAdminilla tai ajamalla oikeat SQL-kyselyt. Jos et tiedä miten tehdä nämä asiat, pyydä järjestelmän ylläpitäjää säätämään oikeudet oikein.', 'Installation_SeeBelowForMoreInfo' => 'Katso alempaa lisätietoja.', 'Installation_DatabaseAbilities' => 'Tietokannan toiminnot', diff --git a/lang/fr.php b/lang/fr.php index 5dbc60f48a..471fcd5860 100644 --- a/lang/fr.php +++ b/lang/fr.php @@ -416,20 +416,20 @@ $translations = array( 'Actions_PageTitlesReportDocumentation' => 'Ce rapport contient des informations à propos des titres des pages qui ont été visitées. %s Le titre de la page est le tag HTML %s que la plupart des navigateurs affichent dans le titre de la fenêtre.', 'Actions_OutlinksReportDocumentation' => 'Ce rapport affiche une liste hiérarchique de liens sortants sur lesquels ont cliqué vos visiteurs.', 'Actions_OutlinkDocumentation' => 'Un lien sortant est un lien qui mène le visiteur en dehors de votre site web (vers un autre domaine).', - 'Actions_DownloadsReportDocumentation' => 'Dans ce rapport vous pouvez voir quels fichiers les utilisateurs ont téléchargés. %s Ce que Piwik compte comme un téléchargement est le click sur le lien de téléchargement. Le fait que le téléchargement ait été terminé ou non n\'est pas connu de Piwik.', + 'Actions_DownloadsReportDocumentation' => 'Dans ce rapport vous pouvez voir quels fichiers les utilisateurs ont téléchargés. %s Ce que Piwik compte comme un téléchargement est un clic sur un lien de téléchargement. Le fait que le téléchargement ait été terminé ou non n\'est pas connu de Piwik.', 'Actions_ColumnClicks' => 'Clics', - 'Actions_ColumnClicksDocumentation' => 'Nombre de clics que le lien a reçu.', + 'Actions_ColumnClicksDocumentation' => 'Nombre de clics sur ce lien.', 'Actions_ColumnUniqueClicks' => 'Clics uniques', 'Actions_ColumnUniqueClicksDocumentation' => 'Nombre de visites qui ont impliqué un clic sur ce lien. Si un lien a été cliqué plusieurs fois en une seule visite, il n\'est compté qu\'une seule fois.', 'Actions_ColumnDownloads' => 'Téléchargements', 'Actions_ColumnUniqueDownloads' => 'Téléchargements uniques', - 'Actions_ColumnOutlinks' => 'liens sortant', - 'Actions_ColumnUniqueOutlinks' => 'liens sortant unique', + 'Actions_ColumnOutlinks' => 'Liens sortant', + 'Actions_ColumnUniqueOutlinks' => 'Liens sortants uniques', 'Actions_ColumnPageName' => 'Nom de la page', 'Actions_ColumnPageURL' => 'URL de la page', - 'Actions_ColumnSearchCategory' => 'Recherche d\'une catégorie', - 'Actions_ColumnSearchResultsCount' => 'Résultats de la recherche', - 'Actions_ColumnSearchKeyword' => 'Mot clés', + 'Actions_ColumnSearchCategory' => 'Catégorie de recherche', + 'Actions_ColumnSearchResultsCount' => 'Nombre de résultats de la recherche', + 'Actions_ColumnSearchKeyword' => 'Mot-clé', 'Actions_SiteSearchKeyword' => 'Mot clef (recherche du site)', 'Actions_ColumnClickedURL' => 'URL cliquées', 'Actions_ColumnDownloadURL' => 'URL de téléchargement', @@ -437,14 +437,14 @@ $translations = array( 'Actions_ColumnEntryPageTitle' => 'Titre de la page d\'entrée', 'Actions_ColumnExitPageURL' => 'URL de la page de sortie', 'Actions_ColumnExitPageTitle' => 'Titre de la page de sortie', - 'Actions_ColumnNoResultKeyword' => 'Mot clés sans résultats', + 'Actions_ColumnNoResultKeyword' => 'Mots-clés sans résultats de recherche', 'Actions_ColumnSearches' => 'Recherches', - 'Actions_ColumnSiteSearchKeywords' => 'Mot clés unique', - 'Actions_ColumnSearchesDocumentation' => 'Le nombre de visites pour ce mot-clé sur le moteur de recherche votre site web', - 'Actions_ColumnSearchExits' => '% Taux de rebond', - 'Actions_ColumnSearchExitsDocumentation' => 'Le taux de visiteurs qui ont quitté le site après avoir effectué une recherche pour ce mot clef avec le moteur de recherche de votre site.', - 'Actions_ColumnPagesPerSearch' => 'Résultats de la recherche', - 'Actions_ColumnPagesPerSearchDocumentation' => 'Les visiteurs vont effectuer des recherches sur votre site web et parfois cliquer sur "suivant" pour afficher plus de résultats. Ceci est le nombre moyen de résultats de recherche vus pour ce mot clef.', + 'Actions_ColumnSiteSearchKeywords' => 'Mot-clés uniques', + 'Actions_ColumnSearchesDocumentation' => 'Le nombre de visites pour lesquelles une recherche pour ce mot-clé a été effectuée avec le moteur de recherche de votre site web', + 'Actions_ColumnSearchExits' => '% Taux de rebond après recherche', + 'Actions_ColumnSearchExitsDocumentation' => 'Le taux de visites après lesquelles les utilisateurs on quitté le site après avoir effectué une recherche pour ce mot clef avec le moteur de recherche de votre site.', + 'Actions_ColumnPagesPerSearch' => 'Pages des résultats de la recherche', + 'Actions_ColumnPagesPerSearchDocumentation' => 'Les visiteurs vont effectuer des recherches sur votre site web et parfois cliquer sur "suivant" pour afficher plus de résultats. Ceci est le nombre moyen de pages de résultats de recherche vues pour ce mot-clef.', 'Actions_EntryPagesReportDocumentation' => 'Ce rapport contient des informations à propos des pages d\'entrées qui ont été utilisées durant la période spécifiée. Une page d\'entrée est lapremière page qu\'un utilisateur voit pendant sa visite. %s Les URLs des pages d\'entrée sont affichées dans une structure de dossier.', 'Actions_EntryPageTitlesReportDocumentation' => 'Ce rapport contient des informations à propos des titres des pages d\'entrée qui ont été utilisées durant la période spécifiée.', 'Actions_ExitPagesReportDocumentation' => 'Ce rapport contient des informations à propos des pages de sortie utilisées durant la période sélectionnée. Une page de sortie est là dernière page de la visite que l\'utilisateur voit avant de sortir du site. %s Les Urls de sorties sont affichées dans une structure de dossier.', @@ -709,9 +709,13 @@ $translations = array( 'CoreHome_MakeOneTimeDonation' => 'Faire un don unique à la place.', 'CorePluginsAdmin_PluginDescription' => 'Interface d\'administration des plugins.', 'CorePluginsAdmin_Plugins' => 'Plugins', + 'CorePluginsAdmin_Themes' => 'Thèmes', 'CorePluginsAdmin_PluginsManagement' => 'Gestionnaire de plugins', + 'CorePluginsAdmin_ThemesManagement' => 'Gérer les thèmes', 'CorePluginsAdmin_MainDescription' => 'Les plugins étendent et ajoutent des fonctionnalités à Piwik. Une fois un plugin installé, vous pouvez l\'activer ou le désactiver ici.', + 'CorePluginsAdmin_ThemesDescription' => 'Les thèmes peuvent modifier l\'apparence de l\'interface utilisateur et fournir une expérience visuelle nouvelle pour apprécier les rapports de suivi de trafic.', 'CorePluginsAdmin_Plugin' => 'Plugin', + 'CorePluginsAdmin_Theme' => 'Thème', 'CorePluginsAdmin_Version' => 'Version', 'CorePluginsAdmin_Status' => 'État', 'CorePluginsAdmin_Action' => 'Action', @@ -723,6 +727,8 @@ $translations = array( 'CorePluginsAdmin_Inactive' => 'Inactif', 'CorePluginsAdmin_Deactivate' => 'Désactiver', 'CorePluginsAdmin_Activate' => 'Activer', + 'CorePluginsAdmin_MenuPlatform' => 'Plate-forme', + 'CorePluginsAdmin_MenuExtend' => 'Ajouter des outils', 'CorePluginsAdmin_PluginCannotBeFound' => 'Ce plugin est introuvable !', 'CoreUpdater_PluginDescription' => 'Mécanisme de mise à jour Piwik', 'CoreUpdater_UpdateTitle' => 'Mise à jour', @@ -1068,7 +1074,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik est une application d\'analyse du web Open Source qui vous permet d\'obtenir facilement les informations que vous désirez sur vos visiteurs.</p> <p>Ce procédé est divisé en %s étapes faciles et vous prendra 5 minutes environ.</p>', 'Installation_ConfigurationHelp' => 'Votre configuration de Piwik semble être erronée. Vous pouvez ou bien supprimer config/config.inc.php et reprendre l\'installation ou corriger les paramètres de connexion.', 'Installation_ErrorInvalidState' => 'Erreur: il semble que vous essayez de sauter une étape du processus d\'installation, ou vous avez désactivé les cookies, ou le fichier de configuration de Piwik est déjà créé. %1$sAssurez vous que les cookies sont bien activés%2$s et retournez %3$s à la première page d\'installation %4$s.', - 'Installation_InsufficientPrivileges' => 'Droits insuffisants. L\'utilisateur de base de données doit avoir les droits suivants : %s', 'Installation_InsufficientPrivilegesHelp' => 'Vous pouvez donner ces droits en utilisant un outils tel que phpMyAdmin ou en exécutant les requêtes SQL appropriées. Si vous ne savez pas comment effectuer cela veuillez demander à votre administrateur système de donner ces droits pour vous.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Oh-oh! Piwik a détecté des %1$sproblèmes critiques%2$s avec votre installation de Piwik. %3$sCes problèmes critiques doivent être fixés immédiatement.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Il y a des problèmes avec votre système. Piwik va fonctionner, mais vous pourriez rencontrer des problèmes mineurs.', diff --git a/lang/hi.php b/lang/hi.php index 3579a58303..f5b2fa06e9 100644 --- a/lang/hi.php +++ b/lang/hi.php @@ -5,6 +5,7 @@ $translations = array( 'General_TranslatorEmail' => 'hello@piwik.org', 'General_EnglishLanguageName' => 'Hindi', 'General_OriginalLanguageName' => 'मानक हिन्दी', + 'General_HelloUser' => 'हैलो, %s!', 'General_OpenSourceWebAnalytics' => 'ओपन सोर्स वेब विश्लेषिकी', 'General_Dashboard' => 'डैशबोर्ड', 'General_DashboardForASpecificWebsite' => 'एक विशिष्ट वेबसाइट के लिए डैशबोर्ड', @@ -18,6 +19,8 @@ $translations = array( 'General_Unknown' => 'अज्ञात', 'General_Never' => 'कभी नहीं', 'General_Required' => '%s आवश्यकता', + 'General_NotValid' => '%s मान्य नहीं है', + 'General_NotDefined' => '%s परिभाषित नहीं', 'General_Id' => 'पहचान', 'General_Error' => 'त्रुटि', 'General_Warning' => 'चेतावनी', @@ -75,6 +78,7 @@ $translations = array( 'General_VisitorIP' => 'आगंतुक आईपी', 'General_VisitorID' => 'आगंतुक आईडी', 'General_VisitType' => 'आगंतुक के प्रकार', + 'General_VisitTypeExample' => 'उदाहरण के लिए, अपने पिछले दौरों में कुछ खरीदा है जो उन सहित, वेबसाइट पर लौट आए हैं, जो सभी आगंतुकों का चयन करने के लिए, एपीआई अनुरोध %s शामिल होगा', 'General_DaysSinceLastVisit' => 'अंतिम यात्रा के बाद दिन', 'General_DaysSinceFirstVisit' => 'पहली यात्रा के बाद से दिन', 'General_DaysSinceLastEcommerceOrder' => 'पिछले ईकॉमर्स आदेश के बाद दिन', @@ -82,6 +86,7 @@ $translations = array( 'General_VisitConvertedGoal' => 'परिवर्तित कम से कम एक लक्ष्य पर जाएँ', 'General_VisitConvertedGoalId' => 'परिवर्तित एक विशिष्ट लक्ष्य आईडी पर जाएँ', 'General_EcommerceVisitStatusDesc' => 'यात्रा के अंत में ईकॉमर्स स्थिति पर जाएँ', + 'General_EcommerceVisitStatusEg' => 'उदाहरण के लिए, एक ईकॉमर्स आदेश दिया है कि सभी यात्राओं का चयन करने के लिए, एपीआई अनुरोध शामिल %s होगा', 'General_NewVisitor' => 'नई आगंतुक', 'General_NewVisits' => 'नए दौरों', 'General_ReturningVisitor' => 'आगंतुक वापस आ रहें', @@ -102,8 +107,13 @@ $translations = array( 'General_InvalidDateRange_js' => 'अमान्य तिथि सीमा, फिर से कोशिश करो कृपया', 'General_DateRangeFrom_js' => 'से', 'General_DateRangeTo_js' => 'से', + 'General_LastDaysShort' => 'अंतिम %s दिवस', + 'General_PreviousDaysShort' => 'पिछले %s दिनों', + 'General_PreviousDays' => 'पिछला %s दिन (नहीं सहित आज)', + 'General_LastDays' => 'अंतिम %s दिन (आज सहित)', 'General_LoadingData' => 'डेटा लोड हो रहा है ...', 'General_Loading_js' => 'लोड हो रहा है ...', + 'General_GoTo' => '%s पर जाएं', 'General_Next' => 'अगला', 'General_Previous' => 'पिछला', 'General_First' => 'पहले', @@ -121,6 +131,7 @@ $translations = array( 'General_ExportThisReport' => 'इस डाटा सेट का अन्य प्रारूपों में निर्यात', 'General_ExportAsImage_js' => 'छवि के रूप में निर्यात', 'General_Export' => 'निर्यात', + 'General_ParameterMustIntegerBetween' => 'पैरामीटर %s और %s के बीच में एक पूर्णांक मान %s होना चाहिए.', 'General_YourChangesHaveBeenSaved' => 'आपके परिवर्तन को सहेजा गया है.', 'General_ErrorRequest' => 'ओह ... अनुरोध के दौरान समस्या, पुन: प्रयास करें.', 'General_ColumnNbUniqVisitors' => 'अद्वितीय आगंतुकों', @@ -173,7 +184,11 @@ $translations = array( 'General_ColumnAverageGenerationTimeDocumentation' => 'औसत समय यह पेज बनाने में लिया. इस मीट्रिक में समय शामिल है जो यह वेब पेज उत्पन्न करने के लिए सर्वर ने लिया, इस के अलावा समय आगंतुक को सर्वर से प्रतिक्रिया डाउनलोड करने के लिए लिया. एक कम \'औसत. पीढ़ी समय\' का मतलब अपने दर्शकों के लिए एक तेज वेबसाइट है!', 'General_ColumnValuePerVisit' => 'भेंट प्रति राजस्व', 'General_ColumnVisitsWithConversions' => 'रूपांतरण के साथ दौरा', + 'General_VisitsWith' => '%s साथ दौरा', 'General_YearsDays' => '%1$s साल %2$s दिन', + 'General_DaysHours' => '%1$s दिन %2$s घंटे', + 'General_HoursMinutes' => '%1$s घंटे %2$s मिनट', + 'General_MinutesSeconds' => '%1$s मिनिट %2$s', 'General_Seconds' => '%ss', 'General_Save' => 'सहेजें', 'General_Faq' => 'पूछे जाने वाले प्रश्न', @@ -183,16 +198,27 @@ $translations = array( 'General_GeneralSettings' => 'सामान्य व्यवस्था', 'General_AllowPiwikArchivingToTriggerBrowser' => 'रिपोर्ट को ब्राउज़र से देखा जाता है जब Piwik पुरालेखण को सक्रिय करने के लिए अनुमति दें', 'General_ArchivingInlineHelp' => 'मध्यम से उच्च यातायात वेबसाइटों के लिए,यह Piwik ब्राउज़र से सक्रिय करने के लिए पुरालेखण को निष्क्रिय करने की सिफारिश की है.इसके बजाय, हम आपको Piwik रिपोर्टों के हर घंटे की प्रक्रिया के लिए एक क्रॉन जॉब सेटअप करने की सलाह देते हैं.', + 'General_ArchivingTriggerDescription' => 'बड़ा Piwik स्थापित के लिए सिफारिश है, आपको स्वतः रिपोर्टों को संसाधित करने के लिए %s एक क्रॉन जॉब सेटअप %s की जरूरत है.', + 'General_SeeTheOfficialDocumentationForMoreInformation' => 'अधिक जानकारी के लिए %sआधिकारिक दस्तावेज %s देखें.', 'General_ReportsContainingTodayWillBeProcessedAtMostEvery' => 'आज के लिए रिपोर्ट (या आज सहित किसी भी अन्य तिथि सीमा) हर अधिकांश पर कार्रवाई की जाएगी', + 'General_NSeconds' => '%s सेकंड्स', + 'General_SmallTrafficYouCanLeaveDefault' => 'छोटे यातायात वेबसाइटों के लिए, यदि आप डिफ़ॉल्ट %sसेकंड हटा देते हैं, और वास्तविक समय में सभी रिपोर्टों का उपयोग कर सकते हैं.', + 'General_MediumToHighTrafficItIsRecommendedTo' => 'मध्यम उच्च यातायात वेबसाइटों के लिए, हम ज्यादा से ज्यादा हर आधे घंटे (%s सेकंड) या हर घंटे (%s सेकंड) में आज के लिए रिपोर्ट को संसाधित करने की सलाह देते हैं.', 'General_RequiresFlash' => 'Piwik में रेखाचित्र प्रदर्शित करने में फ्लैश की आवश्यकता है', 'General_GraphHelp' => 'Piwik में रेखांकन प्रदर्शित करने के बारे में अधिक जानकारी.', 'General_NoDataForGraph_js' => 'इस ग्राफ के लिए कोई डेटा नहीं.', + 'General_DataForThisGraphHasBeenPurged' => 'इस ग्राफ के लिए डेटा %s महीनों की तुलना में अधिक पुराना है और शुद्ध किया गया है.', 'General_NoDataForTagCloud' => 'इस टैग क्लाउड के लिए कोई डेटा नहीं.', + 'General_DataForThisTagCloudHasBeenPurged' => 'इस टैग क्लाउड के लिए डेटा %s महीनों से अधिक पुराना है और शुद्ध किया गया है.', 'General_DisplaySimpleTable' => 'साधारण तालिका प्रदर्शित', 'General_DisplayTableWithMoreMetrics' => 'अधिक मैट्रिक्स के साथ एक तालिका प्रदर्शित', 'General_DisplayTableWithGoalMetrics' => 'लक्ष्य मैट्रिक्स के साथ एक तालिका प्रदर्शित', + 'General_PiwikIsACollaborativeProjectYouCanContributeAndDonate' => '%1$s Piwik %2$s एक सहयोगी परियोजना है. %3$s आप Piwik के एक प्रशंसक रहे हैं, आप मदद कर सकते हैं:पता लगाएँ %4$sकैसे %5$sPiwik %6$sमें भाग ले %7$s या फंड %8$sPiwik 2.0 मदद करने के लिए अब दान करे!', 'General_YouAreViewingDemoShortMessage' => 'आप वर्तमान में Piwik का डेमो देख रहे हैं', 'General_YouAreCurrentlyUsing' => 'आप वर्तमान में Piwik %s का उपयोग कर रहे हैं.', + 'General_DownloadFullVersion' => '%1$sपूर्ण संस्करण डाउनलोड%2$s करें!%3$s बाहर की जाँच करें', + 'General_NewUpdatePiwikX' => 'नई अद्यतन: Piwik %s', + 'General_AboutPiwikX' => '%s Piwik के बारे में', 'General_PiwikXIsAvailablePleaseUpdateNow' => 'Piwik %1$s उपलब्ध है. %2$s अभी अपडेट करें! %3$s (%4$s परिवर्तन %5$s देखें).', 'General_NewReportsWillBeProcessedByCron' => 'Piwik पुरालेखण ब्राउज़र द्वारा सक्रिय नहीं करते हैं,नई रिपोर्ट के क्रॉन टैब द्वारा कार्रवाई की जाएगी.', 'General_ReportsWillBeProcessedAtMostEveryHour' => 'रिपोर्टें इसलिए अधिकांश हर घंटे पर कार्रवाई की जाएगी.', @@ -249,14 +275,35 @@ $translations = array( 'General_MonthlyReports' => 'मासिक रिपोर्ट', 'General_YearlyReports' => 'वार्षिक रिपोर्टों में', 'General_RangeReports' => 'विशिष्ट तिथि सीमाएं', + 'General_ConfigFileIsNotWritable' => 'Piwik विन्यास फाइल %sलिखने योग्य नहीं है, अपने परिवर्तनों से कुछ नहीं बचाया जा सकता है. यह लिखने योग्य बनाने के लिए %sविन्यास फाइल की अनुमति में बदलाव करें.', 'General_StatisticsAreNotRecorded' => 'Piwik आगंतुक के खोज वर्तमान में अक्षम है! अपने config / config.ini.php फ़ाइल में रिकॉर्ड आंकड़े = 1 सेट करके खोज पुन: सक्षम करे', 'General_ExceptionDatabaseVersion' => 'आपका %1$s संस्करण %2$s है लेकिन Piwik कम से कम %3$s की आवश्यकता है', + 'General_ExceptionIncompatibleClientServerVersions' => 'अपने %1$sग्राहक के संस्करण%2$s जो है सर्वर संस्करण%3$s के साथ असंगत है', + 'General_ExceptionMissingFile' => 'लापता फ़ाइल: %s', + 'General_ExceptionFilesizeMismatch' => 'फ़ाइल का आकार बेमेल है:%1$s (अपेक्षित लंबाई:%2$s,पाया :%3$s)', + 'General_ExceptionFileIntegrity' => 'अखंडता की जाँच विफल: %s', 'General_ExceptionNonceMismatch' => 'इस प्रपत्र पर सुरक्षा टोकन को सत्यापित नहीं किया जा सका.', 'General_PleaseSpecifyValue' => '\'%s\' के लिए एक मूल्य निर्दिष्ट करें.', + 'General_ExceptionMethodNotFound' => 'विधि \'%s\' मौजूद नहीं या भाग में उपलब्ध नहीं \'%s\' है.', + 'General_ExceptionInvalidRendererFormat' => 'प्रतिपादक स्वरूप \'%s\' मान्य नहीं. इसके बजाय निम्न में से किसी का प्रयास करें: %s', + 'General_ExceptionInvalidReportRendererFormat' => 'रिपोर्ट प्रारूप \'%s\' मान्य नहीं. इसके बजाय निम्न में से किसी का प्रयास करें: %s', + 'General_ExceptionInvalidStaticGraphType' => 'स्थैतिक रेखाचित्र के प्रकार \'%s\' मान्य नहीं. इसके बजाय निम्न में से किसी का प्रयास करें: %s.', + 'General_ExceptionInvalidAggregateReportsFormat' => 'सकल रिपोर्टों स्वरूप \'%s\' मान्य नहीं है. इसके बजाय निम्नलिखित में से किसी का प्रयास करें:%s.', + 'General_ExceptionInvalidPeriod' => 'अवधि \'%s\' समर्थित नहीं है. इसके बजाय निम्न में से किसी का प्रयास करें: %s', + 'General_ExceptionInvalidDateRange' => 'तारीख की एक सही तिथि \'%s\' सीमा नहीं है. यह निम्न स्वरूप होना चाहिए: %s', 'General_ExceptionGoalNotFound' => 'लक्ष्य आईडी =%s को पाया नहीं जा सका.', + 'General_ExceptionUndeletableFile' => '%s हटाने में असमर्थ', + 'General_ExceptionPrivilege' => 'इसे एक %s पहुँच की आवश्यकता के रूप में आप इस संसाधन तक पहुँच नहीं सकते हैं.', + 'General_ExceptionPrivilegeAtLeastOneWebsite' => 'इसे कम से कम एक वेबसाइट के लिए किसी पहुँच की आवश्यकता के रूप %s में आप इस संसाधन तक पहुँच नहीं सकते हैं.', + 'General_ExceptionPrivilegeAccessWebsite' => 'यह वेबसाइट आईडी के लिए एक %s पहुँच की आवश्यकता के रूप में आप इस संसाधन तक पहुँच नहीं सकते हैं = %d', 'General_ExceptionInvalidArchiveTimeToLive' => 'आज संग्रह जीने के लिए शून्य से अधिक सेकंड की संख्या होनी चाहिए', + 'General_ExceptionConfigurationFileNotFound' => 'विन्यास फाइल {%s} नहीं पाया गया है.', + 'General_ExceptionUnreadableFileDisabledMethod' => 'विन्यास फाइल {%s} नहीं पढ़ी जा सकी. आपका मेजबान %s निष्क्रिय हो सकता है', 'General_ExceptionInvalidToken' => 'टोकन मान्य नहीं है.', + 'General_ExceptionInvalidDateFormat' => 'तिथि प्रारूप में होना चाहिए:%s या (अधिक जानकारी के लिए %s देखें) प्रकार्य %sद्वारा किसी भी शब्द का समर्थन किया', + 'General_ExceptionLanguageFileNotFound' => 'भाषा फाइल \'%s\' नहीं मिली.', 'General_ExceptionUnableToStartSession' => 'सत्र प्रारंभ करने में अक्षम.', + 'General_ExceptionCheckUserIsSuperUserOrTheUser' => 'उपयोगकर्ता तो सुपर उपयोगकर्ता या उपयोगकर्ता \'%s\' ही होना है.', 'General_WarningFileIntegrityNoManifest' => 'फ़ाइल अखंडता की जांच manifest.inc.php गुम की वजह से नहीं किया जा सकता है.', 'General_WarningFileIntegrityNoMd5file' => 'फ़ाइल अखंडता की जांच लापता md5_file () फ़ंक्शन के कारण पूरा नहीं हो सका.', 'General_FileIntegrityWarningExplanation' => 'फ़ाइल अखंडता की जाँच विफल रही है और कुछ त्रुटियों की सूचना दी. यह सबसे अधिक संभावना एक आंशिक के कारण है या Piwik फ़ाइलों में से कुछ का अपलोड विफल रहा है. तुम्हें बायनरी मोड में सभी Piwik फाइलें फिर से अपलोड करनी चाहिए', @@ -272,6 +319,7 @@ $translations = array( 'General_OnlyUsedIfUserPwdIsSet' => 'एक उपयोगकर्ता नाम / पासवर्ड सेट है, तो ही प्रयोग किया जाता है,आपको उपयोग करने के लिए विधि अनिश्चित हैं, तो अपने प्रदाता से पूछें.', 'General_OnlyEnterIfRequired' => 'आपके एसएमटीपी सर्वर की आवश्यकता है तो एक उपयोगकर्ता सिर्फ़ नाम दर्ज करें.', 'General_OnlyEnterIfRequiredPassword' => 'आपके एसएमटीपी सर्वर की आवश्यकता है यह तो सिर्फ़ पासवर्ड दर्ज करें.', + 'General_WarningPasswordStored' => '%sचेतावनी:%s यह पासवर्ड config फाइल में संग्रहीत किया जाएगा यह उपयोग कर सकते हैं जो हर किसी को दिखाई दे.', 'General_EncryptedSmtpTransport' => 'आपके एसएमटीपी सर्वर द्वारा आवश्यक परिवहन परत गूढ़लेखन दर्ज करें.', 'General_InvalidResponse' => 'प्राप्त डेटा अमान्य है.', 'General_ChooseLanguage' => 'भाषा चुनें', @@ -292,10 +340,13 @@ $translations = array( 'General_AfterEntry' => 'यहां प्रवेश करने के बाद', 'General_Metadata' => 'मेटाडाटा', 'General_OneVisit' => '1 यात्रा', + 'General_NVisits' => '%s दौरों', 'General_OneAction' => 'क्रिया', 'General_EvolutionSummaryGeneric' => '%1$s में %2$s की तुलना मे %3$s में %4$s. विकास:%5$s', 'General_OneDay' => '1 दिन', + 'General_NDays' => '%s दिन', 'General_OneMinute' => '1 मिनिट', + 'General_NMinutes' => '%s मिनट', 'General_MainMetrics' => 'मुख्य मैट्रिक्स', 'General_Mobile' => 'गतिशील', 'General_Desktop' => 'डेस्कटॉप', @@ -306,12 +357,16 @@ $translations = array( 'General_NotInstalled' => 'स्थापित नहीं', 'General_Installed' => 'स्थापित', 'General_Broken' => 'टूटा', + 'General_InfoFor' => '%s के लिए जानकारी', 'General_Add' => 'जोड़ना', + 'General_CannotUnzipFile' => 'फ़ाइल नहीं खोल सकते %1$s: %2$s', 'General_GetStarted' => 'शुरू हो जाओ', 'General_Continue' => 'जारी', 'General_Note' => 'नोट', + 'General_DownloadFail_FileExists' => 'फ़ाइल %s पहले से मौजूद है!', 'General_DownloadPleaseRemoveExisting' => 'आप इसे बदला जाना चाहते हैं, मौजूदा फ़ाइल को हटा दें', 'General_DownloadFail_HttpRequestFail' => 'फाइल डाउनलोड नहीं कर सकता!कुछ वेबसाइट से गलत हो सकता है जिस में से डाउनलोड कर रहे हैं.आप बाद में फिर कोशिश करें या अपने आप से फ़ाइल मिल सकती है.', + 'General_DownloadFail_FileExistsContinue' => 'डाउनलोड %s जारी रखने के लिए कोशिश कर रहा है, लेकिन एक पूरी तरह से डाउनलोड की गई फ़ाइल पहले से मौजूद है!', 'General_Show_js' => 'दिखाना', 'General_Hide_js' => 'छिपाना', 'General_Donate' => 'दान करना', @@ -331,6 +386,7 @@ $translations = array( 'General_OperationIsNot' => 'नहीं है', 'General_DefaultAppended' => '(डिफ़ॉल्ट)', 'General_SearchNoResults' => 'कोई परिणाम नहीं', + 'General_ReadThisToLearnMore' => '%1$sअधिक जानने के लिए इस पढ़ें.%2$s', 'Actions_PluginDescription' => 'पृष्ठ विचारों, आउटलिंक और डाउनलोड के बारे में रिपोर्टें. आउटलिंक और डाउनलोड ट्रैकिंग स्वचालित है! आप भी अपनी आंतरिक वेबसाइट की खोज इंजन को ट्रैक कर सकते हैं.', 'Actions_Actions' => 'प्रक्रिया', 'Actions_SubmenuPages' => 'पृष्ठ', @@ -353,8 +409,11 @@ $translations = array( 'Actions_SubmenuOutlinks' => 'आउटलिंक', 'Actions_SubmenuDownloads' => 'डाउनलोड', 'Actions_SubmenuSitesearch' => 'साइट खोज', + 'Actions_PagesReportDocumentation' => 'इस रिपोर्ट का दौरा किया गया है कि पृष्ठ यूआरएल के बारे में जानकारी शामिल हैं. तालिका %s पदानुक्रम रूप से आयोजित किया जाता है, यूआरएल एक फ़ोल्डर संरचना के रूप में प्रदर्शित कर रहे हैं.', + 'Actions_PageTitlesReportDocumentation' => 'इस रिपोर्ट का दौरा किया गया है कि पृष्ठों के शीर्षक के बारे में जानकारी शामिल हैं. %s पृष्ठ शीर्षक सबसे ब्राउज़रों अपने विंडो शीर्षक में पता चलता है कि एचटीएमएल %s टैग है.', 'Actions_OutlinksReportDocumentation' => 'इस रिपोर्ट में अपने आगंतुकों द्वारा क्लिक किया गया है कि बाहर कड़ी यूआरएल की एक पदानुक्रमित सूची दिखाता है.', 'Actions_OutlinkDocumentation' => 'आउटलिंक उस लिंक को कहा जाता है जो आपकी वेबसाइट पर आये व्यक्तियों को किसी अन्य वेबसाइट पर ले जाता है।', + 'Actions_DownloadsReportDocumentation' => 'यह रिपोर्ट आपकी वेबसाइट पर आने वाले व्यक्तियों द्वारा डाउनलोड की गयी फाइलों को दर्शाती है। जब कोई व्यक्ति किसी डाउनलोड लिंक %s पर क्लिक करता है, तो पिविक उसे डाउनलोड की दृष्टि से देखता है। डाउनलोड सही रूप से हुआ या नहीं, इस बात की जानकारी पिविक को नहीं होती।', 'Actions_ColumnClicks' => 'क्लिकों', 'Actions_ColumnClicksDocumentation' => 'बार की संख्या इस लिंक पर क्लिक किया गया था', 'Actions_ColumnUniqueClicks' => 'विशिष्ट क्लिक', @@ -383,7 +442,9 @@ $translations = array( 'Actions_ColumnSearchExitsDocumentation' => 'अपनी साइट खोज इंजन पर इस कीवर्ड के लिए खोज करने के बाद वेबसाइट छोड़ दिया कि यात्राओं का प्रतिशत.', 'Actions_ColumnPagesPerSearch' => 'खोज परिणाम के पन्नों', 'Actions_ColumnPagesPerSearchDocumentation' => 'आपकी वेबसाइट पर आने वाले व्यक्ति जानकारी ढूंढते हुए अक्सर और अधिक नतीजे देखने के लिए “नेक्स्ट” पर क्लिक करेंगे। यह इस खोजशब्द के लिए देखे गए सभी नतीजों वाले पृष्ठों की औसत है।', + 'Actions_EntryPagesReportDocumentation' => 'इस रिपोर्ट में निर्दिष्ट अवधि के दौरान इस्तेमाल किया गया है कि प्रवेश पृष्ठों के बारे में जानकारी शामिल हैं. एक प्रवेश पृष्ठ एक उपयोगकर्ता अपनी यात्रा के दौरान विचार है कि प्रथम पृष्ठ है. प्रवेश यूआरएल %s एक फ़ोल्डर संरचना के रूप में प्रदर्शित कर रहे हैं.', 'Actions_EntryPageTitlesReportDocumentation' => 'इस रिपोर्ट में निर्दिष्ट अवधि के दौरान इस्तेमाल किया गया है कि प्रवेश पृष्ठों के शीर्षक के बारे में जानकारी शामिल हैं.', + 'Actions_ExitPagesReportDocumentation' => 'इस रिपोर्ट में निर्दिष्ट अवधि के दौरान हुई कि निकास पृष्ठों के बारे में जानकारी शामिल हैं. एक बाहर निकलें पृष्ठ एक उपयोगकर्ता अपनी यात्रा के दौरान विचार है कि पिछले पृष्ठ है. बाहर निकलने के यूआरएल %s एक फ़ोल्डर संरचना के रूप में प्रदर्शित कर रहे हैं.', 'Actions_ExitPageTitlesReportDocumentation' => 'इस रिपोर्ट में निर्दिष्ट अवधि के दौरान हुई कि निकास पृष्ठों के शीर्षक के बारे में जानकारी शामिल हैं.', 'Actions_SiteSearchKeywordsDocumentation' => 'यह रिपोर्ट आपकी वेबसाइट के आंतरिक सर्च इंजन पर ढूंढे गए खोजशब्दों को दर्शाती है।', 'Actions_LearnMoreAboutSiteSearchLink' => 'आपकी वेबसाइट पर आने वाले व्यक्ति वेबसाइट के सर्च इंजन को किस प्रकार से इस्तेमाल करते हैं के विषय में और जानें।', @@ -395,7 +456,12 @@ $translations = array( 'AnonymizeIP_PluginDescription' => 'अपने स्थानीय गोपनीयता कानून / दिशा निर्देशों का अनुपालन करने के लिए आगंतुकों आईपी पतों की अज्ञात आखिरी बाइट', 'API_PluginDescription' => 'Piwik में सभी डेटा सरल एपीआई के माध्यम से उपलब्ध है.यह प्लगइन वेब सेवा प्रवेश बिंदु है जो प्राप्त करने के लिए आप कॉल करे अपने वेब विश्लेषिकी डेटा xml, json, PHP, csv, आदि में', 'API_QuickDocumentationTitle' => 'एपीआई त्वरित प्रलेखन', + 'API_GenerateVisits' => 'आप आज के लिए डेटा नहीं है, तो आप पहले %s प्लगइन का उपयोग कर कुछ डेटा उत्पन्न कर सकते हैं. आप %s प्लगइन सक्षम कर सकते हैं, तो Piwik व्यवस्थापक क्षेत्र में \'आगंतुक जेनरेटर\' मेनू पर क्लिक करें.', + 'API_MoreInformation' => 'Piwik एपीआई के बारे में अधिक जानकारी के लिए,कृपया %s Piwik एपीआई %s और %s Piwik एपीआई संदर्भ %s के परिचय पर एक नजर डाले', 'API_UserAuthentication' => 'प्रयोगकर्ता का प्रामाणीकरण', + 'API_UsingTokenAuth' => 'आप एक स्क्रिप्ट के भीतर %s डेटा, एक crontab, आदि %s के लिए अनुरोध करना चाहते हैं तो प्रमाणीकरण की आवश्यकता है कि यूआरएल कॉल आप एपीआई के लिए पैरामीटर %s जोड़ने की जरूरत है.', + 'API_KeepTokenSecret' => 'इस टोकन प्रमाणन अपने लॉगिन और पासवर्ड के रूप में गुप्त रूप है, %s %s यह साझा नहीं करते हैं!', + 'API_LoadedAPIs' => 'सफलतापूर्वक लोड %s एपीआई', 'API_TopLinkTooltip' => 'Json, xml, आदि में एक सरल एपीआई के माध्यम से प्रोग्राम के रूप में अपने वेब विश्लेषिकी डेटा का उपयोग करे', 'CoreAdminHome_PluginDescription' => 'Piwik का प्रशासन क्षेत्र.', 'CoreAdminHome_MenuCommunity' => 'सम्प्रदाय', @@ -406,6 +472,7 @@ $translations = array( 'CoreAdminHome_EmailServerSettings' => 'ईमेल सर्वर की सेटिंग्स', 'CoreAdminHome_OptOutForYourVisitors' => 'अपने दर्शकों के लिए Piwik ऑप्ट आउट', 'CoreAdminHome_OptOutExplanation' => 'Piwik इंटरनेट पर गोपनीयता प्रदान करने के लिए समर्पित है. Piwik वेब विश्लेषिकी से बाहर निकलने के विकल्प के साथ अपने आगंतुकों प्रदान करने के लिए, आप अपनी वेबसाइट के पेज में से एक पर निम्नलिखित HTML कोड जोड़ सकते हैं, एक गोपनीयता नीति पेज में उदाहरण के लिए.', + 'CoreAdminHome_OptOutExplanationBis' => 'यह कोड अपने दर्शकों के लिए एक कड़ी युक्त एक iframe को प्रदर्शित करेगा अपने ब्राउज़र में एक कुकी को सेट करके Piwik से लिए ऑप्ट बाहर जाने के लिए आइफ्रेम द्वारा प्रदर्शित की जाने वाली सामग्री को देखने के लिए %s यहां क्लिक करें %s.', 'CoreAdminHome_OptOutComplete' => 'ऑप्ट-आउट कम्पलीट: इस वेबसाइट के लिए अपने दौरे वेब विश्लेषिकी उपकरण द्वारा दर्ज नहीं किया जाएगा.', 'CoreAdminHome_OptOutCompleteBis' => 'आप अपने कुकी साफ़ करें, अगर कुकी को हटा सकते हैं, या आप कंप्यूटर या वेब ब्राउज़र को बदलते हैं, तो आप फिर से ऑप्ट-आउट कार्यविधि को पूरा करने की आवश्यकता होगी.', 'CoreAdminHome_YouMayOptOut' => 'आप इस वेबसाइट पर एकत्र आंकड़ों का एकत्रीकरण और विश्लेषण से बचने के लिए अपने कंप्यूटर के लिए आवंटित एक अद्वितीय वेब विश्लेषण कुकी पहचान संख्या नहीं चुन सकते हैं.', @@ -416,18 +483,27 @@ $translations = array( 'CoreAdminHome_ClickHereToOptIn' => 'इस विकल्प को चुनने के लिए यहाँ क्लिक करें।', 'CoreAdminHome_BrandingSettings' => 'ब्रांडिंग सेटिंग्स', 'CoreAdminHome_CustomLogoHelpText' => 'आप Piwik प्रतीक चिन्ह को अनुकूलित कर सकते हैं जो यूजर इंटरफेस और ईमेल रिपोर्ट में प्रदर्शित किया जाएगा', + 'CoreAdminHome_CustomLogoFeedbackInfo' => 'आप Piwik प्रतीक चिन्ह अनुकूलित करे, तो आप भी शीर्ष मेनू में लिंक %s को छिपाने के लिए दिलचस्पी हो सकती है. ऐसा करने के लिए, आप प्रबंधित प्लगइन्स पृष्ठ में %s प्रतिक्रिया प्लगइन %s निष्क्रिय कर सकते हैं.', 'CoreAdminHome_UseCustomLogo' => 'एक विशिष्ट प्रतीक चिन्ह का प्रयोग करें', 'CoreAdminHome_LogoUpload' => 'अपलोड करने के लिए किसी लोगो को चुनें', + 'CoreAdminHome_LogoUploadDescription' => '%s पिक्सल के एक न्यूनतम ऊंचाई के साथ %s प्रारूप में एक फ़ाइल, कोई पारदर्शी पृष्ठभूमि, अपलोड करें.', + 'CoreAdminHome_LogoNotWriteable' => 'एक कस्टम प्रतीक चिन्ह Piwik उपयोग करने के लिए विषयों निर्देशिका के भीतर प्रतीक चिन्ह फाइल करने के लिए उपयोग लिखने की आवश्यकता है: %s', 'CoreAdminHome_TrustedHostSettings' => 'Piwik विश्वसनीय परिचारक नाम', 'CoreAdminHome_TrustedHostConfirm' => 'क्या आप विश्वसनीय Piwik परिचारक नाम बदलना चाहते हैं?', 'CoreAdminHome_PiwikIsInstalledAt' => 'Piwik में स्थापित किया गया है', 'CoreAdminHome_ValidPiwikHostname' => 'Piwik वैध परिचारक नाम', + 'CoreAdminHome_MissingPluginsWarning' => '%1$s वे \'प्लग इन\' निर्देशिका में पाया नहीं जा सका क्योंकि निम्न प्लग इन लोड नहीं किया गया:. आप %2$s प्रबंधित प्लगइन्स %3$s पृष्ठ पर इन प्लग इन को निष्क्रिय कर सकते हैं.', 'CoreAdminHome_JSTrackingIntro1' => 'आपकी वेबसाइट पर आने वाले लोगों को आप कई तरीकों से ट्रैक कर सकते हैं। हमरी सलाह है कि आप इसके लिए जावास्क्रिप्ट का प्रयोग करें। इस तरीके को इस्तेमाल करने के लिए सुनिश्चित कर लें की आपकी वेबसाइट के प्रत्येक पृष्ट पर जावास्क्रिप्ट कोड हो। जावास्क्रिप्ट कोड को आप यहाँ से जेनरेट कर सकते हैं।', 'CoreAdminHome_JSTrackingIntro2' => 'एक बार जब आप अपनी वेबसाइट के लिए जावास्क्रिप्ट ट्रैकिंग कोड है कॉपी और सभी पृष्ठों पर जोड़ दें आप Piwik के साथ ट्रैक करना चाहते हैं', + 'CoreAdminHome_JSTrackingIntro3' => 'सबसे वेबसाइटों में, ब्लॉग, सीएमएस, आदि आप के लिए तकनीकी काम करने के लिए एक पूर्व बनाया प्लगइन का उपयोग कर सकते हैं. (Piwik %2$s एकीकृत करने के लिए प्रयोग किया जाता plugins की हमारी %1$s सूची देखें.) कोई प्लगइन आप "पाद" फाइल में अपनी वेबसाइट टेम्पलेट्स संपादित करें और इस कोड जोड़ सकते हैं', + 'CoreAdminHome_JSTrackingIntro4' => 'आप आगंतुकों को ट्रैक करने के लिए जावास्क्रिप्ट का उपयोग नहीं करना चाहते हैं, %1$s तो नीचे एक छवि ट्रैकिंग %2$s लिंक उत्पन्न करते हैं.', + 'CoreAdminHome_JSTrackingIntro5' => 'आप ट्रैक पृष्ठ विचारों से अधिक करना चाहते हैं, उपलब्ध कार्यों की सूची के लिए %1$s Piwik जावास्क्रिप्ट ट्रैकिंग दस्तावेज़ीकरण %2$s की जाँच करें. इन कार्यों का उपयोग कर आप लक्ष्यों, कस्टम चर, ईकॉमर्स आदेश, परित्यक्त गाड़ियां और अधिक ट्रैक कर सकते हैं.', 'CoreAdminHome_TrackingCode' => 'कोड देखना', 'CoreAdminHome_JSTracking_MergeSubdomains' => 'के सभी उप डोमेंस भर में आगंतुकों खोज', + 'CoreAdminHome_JSTracking_MergeSubdomainsDesc' => 'तो एक आगंतुक का दौरा %1$s और %2$s अगर वे एक अद्वितीय आगंतुक के रूप में गिना जाएगा.', 'CoreAdminHome_JSTracking_MergeAliases' => '"आउटलिंक" रिपोर्ट में,', 'CoreAdminHome_JSTracking_GroupPageTitlesByDomain' => 'ट्रैकिंग से पहले साइट डोमेन पृष्ठ शीर्षक में जोड़े', + 'CoreAdminHome_JSTracking_GroupPageTitlesByDomainDesc1' => 'किसी के ब्लॉग पर \'के बारे में\' पृष्ठ पर जाता है तो अगर. %1$s यह ब्लॉग के बारे में / \'के रूप में दर्ज किया जाएगा. इस उप डोमेन से अपने यातायात का अवलोकन प्राप्त करने के लिए सबसे आसान तरीका है.', 'CoreAdminHome_JSTracking_VisitorCustomVars' => 'इस आगंतुक के लिए कस्टम चर खोजे', 'CoreAdminHome_JSTracking_VisitorCustomVarsDesc' => 'उदाहरण के लिए, चर नाम "प्रकार" के साथ और मूल्य "ग्राहक".', 'CoreAdminHome_JSTracking_PageCustomVars' => 'प्रत्येक पृष्ठ को देखने के लिए एक विशिष्ट चर खोज', @@ -438,22 +514,38 @@ $translations = array( 'CoreAdminHome_JSTracking_CustomCampaignQueryParam' => 'अभियान का नाम और कीवर्ड के लिए कस्टम क्वेरी प्राचल नाम का प्रयोग करें', 'CoreAdminHome_JSTracking_CampaignNameParam' => 'अभियान का नाम प्राचल', 'CoreAdminHome_JSTracking_CampaignKwdParam' => 'अभियान खोजशब्द प्राचल', + 'CoreAdminHome_JSTracking_CodeNote' => 'इस कोड %1$s टैग से पहले अपनी वेबसाइट के हर पृष्ठ पर है सुनिश्चित करें.', + 'CoreAdminHome_JSTracking_CustomCampaignQueryParamDesc' => 'नोट: %1$s Piwik स्वतः गूगल एनालिटिक्स मापदंडों की पहचान करेगा.%2$s', 'CoreAdminHome_ImageTrackingIntro1' => 'एक आगंतुक जावास्क्रिप्ट निष्क्रिय कर दिया या जावास्क्रिप्ट प्रयोग नहीं किया, आप आगंतुकों को ट्रैक करने के लिए एक छवि ट्रैकिंग लिंक का उपयोग कर सकते हैं.', + 'CoreAdminHome_ImageTrackingIntro2' => 'नीचे लिंक उत्पन्न करें और उत्पन्न HTML को पृष्ठ में कॉपी पेस्ट करें. आप जावास्क्रिप्ट पर नज़र रखने के लिए एक fallback के रूप में इस का उपयोग कर रहे हैं, तो आप %1$s टैग में घेर कर सकते हैं.', + 'CoreAdminHome_ImageTrackingIntro3' => 'विकल्पों की पूरी सूची के लिए एक छवि ट्रैकिंग लिंक का उपयोग कर सकते हैं , %1$s ट्रैकिंग एपीआई प्रलेखन %2$s देखें.', 'CoreAdminHome_ImageTracking' => 'इमेज ट्रैकिंग', 'CoreAdminHome_TrackAGoal' => 'एक लक्ष्य की खोज', 'CoreAdminHome_WithOptionalRevenue' => 'वैकल्पिक राजस्व के साथ', 'CoreAdminHome_ImageTrackingLink' => 'इमेज ट्रैकिंग का लिंक', 'CoreAdminHome_ImportingServerLogs' => 'सर्वर लॉग्स का आयात', + 'CoreAdminHome_ImportingServerLogsDesc' => 'ब्राउज़र (या तो जावास्क्रिप्ट या एक छवि लिंक के माध्यम से) के माध्यम से दर्शकों ट्रैकिंग के लिए एक विकल्प लगातार सर्वर लॉग आयात है. सर्वर %1$s लॉग फ़ाइल एनालिटिक्स %2$s के बारे में अधिक जानें.', 'CoreAdminHome_JavaScriptTracking' => 'जावास्क्रिप्ट ट्रैकिंग', 'CoreAdminHome_LatestStableRelease' => 'नवीनतम स्थायी रिलीज़', 'CoreAdminHome_LatestBetaRelease' => 'नवीनतम बीटा रिलीज़', 'CoreAdminHome_ForBetaTestersOnly' => 'केवल बीटा परीक्षकों के लिए', 'CoreAdminHome_CheckReleaseGetVersion' => 'Piwik के नए संस्करण की जाँच करते समय, हमेशा मिलता', + 'CoreAdminHome_DevelopmentProcess' => 'हमारी %s विकास प्रक्रिया %s मे हजारों स्वचालित परीक्षण शामिल हैं, जबकि बीटा परीक्षक Piwik में "कोई बग नीति" को प्राप्त करने में एक महत्वपूर्ण भूमिका निभाते हैं.', + 'CoreAdminHome_StableReleases' => 'Piwik अपने व्यापार का एक महत्वपूर्ण हिस्सा है, तो हम आपको नवीनतम स्थिर रिलीज उपयोग की सलाह देते हैं. आप नवीनतम बीटा का उपयोग करें और आप एक बग मिल या एक सलाह देना चाहते हैं, %sयहां देखें%s.', + 'CoreAdminHome_YouAreCurrentlyUsingPHP' => 'आप वर्तमान में PHP %1$s का उपयोग कर रहे हैं', + 'CoreAdminHome_OldPHPVersionWarning_Part1' => 'Piwik जल्दी से सुधार आ रहा है और कला वेब विश्लेषिकी मंच का एक बेहतर राज्य के साथ उपलब्ध कराने के क्रम में, हम जल्द ही 5.3 PHP के लिए न्यूनतम आवश्यक PHP संस्करण में वृद्धि होगी. %1$s अपने PHP अद्यतन करने के लिए होस्टिंग प्रदाता अपने सर्वर व्यवस्थापक या वेब पूछें नवीनतम संस्करण, आदर्श PHP 5.4. %2$s', + 'CoreAdminHome_OldPHPVersionWarning_Part2' => 'आप PHP 5.3 या उच्चतर के लिए नवीनीकरण करते हैं, तो यह संदेश गायब हो जाएगा और अपने Piwik सर्वर कम स्मृति का उपयोग बहुत तेजी से रिपोर्टों कार्रवाई करेंगे. अद्यतन PHP और Piwik का %1$s सबसे बाहर निकलो!%2$s', + 'CoreHome_InjectedHostWarningIntro' => '%2$sअब आप%1$s Piwik से पहुँच रहे हैं, लेकिन Piwik इस पते पर चलाने के लिए समाकृति किया गया है:', + 'CoreHome_InjectedHostSuperUserWarning' => 'Piwik गलत हो सकता है (उदाहरण के लिए, अगर Piwik हाल ही में एक नया सर्वर या यूआरएल के लिए ले जाया गया था)आप या तो यहाँ %1$sक्लिक करें और परिचारक नाम वैध Piwik (यदि आप इसे पर भरोसा है अगर)%3$s के %4$s रूप में जोड़े%2$s, या यहाँ क्लिक करें और %5$sसुरक्षित रूप से Piwik तक पहुँच सकते हैं%6$s.', + 'CoreHome_InjectedHostNonSuperUserWarning' => 'सुरक्षित %2$s Piwik का उपयोग और इस चेतावनी को दूर करने के लिए यहां क्लिक %1$s करें. आप भी अपनी Piwik व्यवस्थापक से संपर्क करें और इस मुद्दे (%3$sईमेल के लिए यहां क्लिक %4$s करें) के बारे में उन्हें सूचित करना चाहिए', + 'CoreHome_InjectedHostEmailSubject' => 'Piwik एक अज्ञात परिचारक नाम से पहुँचा था: %s', 'CoreHome_InjectedHostEmailBody' => 'नमस्कार, मैं आज Piwik का उपयोग करने की कोशिश की और अज्ञात परिचारक नाम चेतावनी का सामना करना पड़ा.', 'CoreHome_CheckForUpdates' => 'अद्यतन देखें', 'CoreHome_YouAreUsingTheLatestVersion_js' => 'आप Piwik का नवीनतम संस्करण का उपयोग कर रहे हैं!', + 'CoreHome_MakeADifference' => 'एक फर्क: निधि Piwik 2.0 के लिए %1$sअभी दान करे%2$s!', 'CoreHome_DonateCall1' => 'Piwik उपयोग करने के लिए आपके कुछ भी खर्च नहीं होंगे, लेकिन यह मतलब नहीं बनाने के लिए कोई खर्च नहीं लगता है.', 'CoreHome_DonateCall2' => 'Piwik के बढ़ने और फूलने के लिए आपके निरंतर समर्थन की जरूरत है.', + 'CoreHome_DonateCall3' => 'आपको लग रहा है Piwik ने आपके व्यवसाय या प्रयास के लिए महत्वपूर्ण मूल्य जोड़ा है, %1$s कृपया दान करने पर विचार करे!%2$s', 'CoreHome_HowMuchIsPiwikWorth' => 'आप के लिए Piwik कितना लायक है?', 'CoreHome_SupportPiwik' => 'पिविक को अपना सहयोग दें।', 'CoreHome_OnlyForAdmin' => 'यह केवल आप के लिए प्रदर्शित किया जाता है, सुपर उपयोक्ता.', @@ -473,6 +565,7 @@ $translations = array( 'PrivacyManager_AnonymizeIpMaskLengtDescription' => 'आवृत किया जाना चाहिए कि कितने बाइट्स \'दर्शकों के आईपी का चयन करें.', 'PrivacyManager_AnonymizeIpMaskLength' => '%s बाइट - e.g. %s', 'PrivacyManager_DeleteDataSettings' => 'पुराने आगंतुक लॉग और रिपोर्ट हटाएं', + 'PrivacyManager_DeleteLogInfo' => 'निम्न तालिका से लॉग्स हटा दिया जाएगा: %s', 'PrivacyManager_UseDeleteLog' => 'नियमित रूप से डेटाबेस से पुराने आगंतुक लॉग को हटाना', 'PrivacyManager_DeleteDataDescription' => 'आप नियमित रूप से अपने डेटाबेस का आकार छोटा रखने के लिए पुराने आगंतुक लॉग और / या प्रसंस्कृत रिपोर्टों को नष्ट करने के लिए Piwik विन्यस्त कर सकते हैं.', 'PrivacyManager_DeleteDataDescription2' => 'वांछित, पूर्व संसाधित रिपोर्टों को नष्ट नहीं किया जाएगा, केवल, यात्रा पृष्ठदृश्य और रूपांतरण लॉग डेटा को हटा दिया जाएगा. या, पूर्व संसाधित रिपोर्टों को नष्ट कर दिया जा सकता है और लॉग डेटा रखा जा सकता है.', @@ -485,8 +578,13 @@ $translations = array( 'PrivacyManager_NextDelete' => 'में अगले अनुसूचित को हटाएँ', 'PrivacyManager_ClickHereSettings' => '%s की सेटिंग्स का उपयोग करने के लिए यहां क्लिक करें.', 'PrivacyManager_LeastDaysInput' => '%s की तुलना में अधिक से अधिक दिनों की संख्या का उल्लेख करें.', + 'PrivacyManager_LeastMonthsInput' => '%s की तुलना में अधिक से अधिक महीनों की संख्या का उल्लेख करें.', 'PrivacyManager_UseDeleteReports' => 'नियमित रूप से डेटाबेस से पुरानी रिपोर्टें हटाना', 'PrivacyManager_DeleteReportsOlderThan' => 'की तुलना में पुराने रिपोर्टों को हटाएँ', + 'PrivacyManager_DeleteReportsInfo' => 'यदि सक्षम, पुराने रिपोर्ट हटा दी जाएगी। %sहम केवल जब अपने डेटाबेस स्थान सीमित है को सक्षम करने के लिए सलाह देते हैं। %s', + 'PrivacyManager_DeleteReportsInfo2' => 'आपका "%s" सक्षम नहीं है, तो अनुरोध किए जाने पर, पुरानी रिपोर्टों को स्वचालित रूप से निर्मित किया जाएगा.', + 'PrivacyManager_DeleteReportsInfo3' => 'आप "%s" को सक्षम किया है, डेटा स्थायी रूप से नष्ट हो जाएंगे.', + 'PrivacyManager_DeleteReportsDetailedInfo' => 'डेटाबेस सांख्यिक संग्रह तालिकाओं (%s) और ब्लॉब संग्रह तालिकाओं (%s) से डेटा हटा दिया जाएगा.', 'PrivacyManager_DeleteSchedulingSettings' => 'निर्धारण सेटिंग्स', 'PrivacyManager_ReportsDataSavedEstimate' => 'डेटाबेस विस्तार', 'PrivacyManager_KeepBasicMetrics' => 'बुनियादी मैट्रिक्स (दौरा, पृष्ठ विचारों, उछाल दर, लक्ष्य रूपांतरण, ईकॉमर्स रूपांतरण, आदि) रखें', @@ -511,15 +609,24 @@ $translations = array( 'PrivacyManager_DoNotTrack_Enable' => 'सक्षम करें समर्थन \'ट्रैक नहीं\'', 'PrivacyManager_DoNotTrack_Disable' => 'निष्क्रिय करें समर्थन ट्रैक नहीं', 'PrivacyManager_GetPurgeEstimate' => 'शुद्ध अनुमान करें', + 'PrivacyManager_CannotLockSoDeleteLogActions' => 'Log_action तालिका शुद्ध नहीं किया जाएगा: \'%s\' में MYSQL उपयोगकर्ता के लिए LOCK TABLES विशेषाधिकार का अनुदान करे कृपया.', 'PrivacyManager_DBPurged' => 'डीबी शुद्ध किए गए.', 'PrivacyManager_GeolocationAnonymizeIpNote' => 'नोट: जियोलोकेशन लगभग 1 बाइट अनाम के साथ ही परिणाम होगा. 2 बाइट या अधिक के साथ, जियोलोकेशन गलत हो जाएगा.', 'CoreHome_PluginDescription' => 'वेब विश्लेषिकी रिपोर्टें संरचना.', 'CoreHome_WebAnalyticsReports' => 'वेब विश्लेषिकी रिपोर्टें', + 'CoreHome_JavascriptDisabled' => 'आप मानक दृश्य में Piwik का उपयोग करने के लिए जावास्क्रिप्ट क्रम में सक्षम होना चाहिए. <br /> हालांकि, ऐसा लगता है कि या तो जावास्क्रिप्ट आपके ब्राउज़र से अक्षम या समर्थित नहीं है.<br />मानक दृश्य का उपयोग करने के लिए, अपने ब्राउज़र के विकल्प बदलकर JavaScript सक्षम करें, तब %1$s फिर कोशिश करें %2$s. <br/>', 'CoreHome_ThereIsNoDataForThisReport' => 'इस रिपोर्ट के लिए कोई डाटा नहीं है.', + 'CoreHome_DataForThisReportHasBeenPurged' => 'इस रिपोर्ट के लिए डेटा %s महीनोंकी तुलना में अधिक पुराना है और शुद्ध किया गया है.', 'CoreHome_CategoryNoData' => 'इस श्रेणी में कोई डेटा नहीं. "सभी लोगों को शामिल" करने का प्रयास करें.', 'CoreHome_ShowJSCode' => 'सम्मिलित करने के लिए जावास्क्रिप्ट कोड दिखाएँ', + 'CoreHome_IncludeRowsWithLowPopulation_js' => 'कम आबादी के साथ पंक्तियाँ छिपे %s हुए हैं, सभी पंक्तियों दिखाएँ', + 'CoreHome_ExcludeRowsWithLowPopulation_js' => 'सभी पंक्तियों %s को दिखाया जाता है कम आबादी बाहर निकालें', + 'CoreHome_DataTableIncludeAggregateRows_js' => 'कुल पंक्तियों को छिपा रहे हैं, %s उन्हें दिखाओ', + 'CoreHome_DataTableExcludeAggregateRows_js' => 'कुल पंक्तियों %s को दिखाया जाता है उन्हें छुपाने', 'CoreHome_Default_js' => 'डिफ़ॉल्ट', 'CoreHome_PageOf_js' => '%1$s का %2$s', + 'CoreHome_FlattenDataTable_js' => 'रिपोर्ट श्रेणीबद्ध %s है यह फ्लैट बनाओ है', + 'CoreHome_UnFlattenDataTable_js' => 'रिपोर्ट फ्लैट %s है इसे श्रेणीबद्ध करें', 'CoreHome_DateFormat' => 'लंबेदिन दिन लंबेमहीना लंबेसाल', 'CoreHome_LongMonthFormat' => 'लंबेसाल लंबेमाह', 'CoreHome_LongWeekFormat' => 'दिन से लंबे महीना से करने के लिए दिन करने के लिए लंबे समय तक महीना करने के लिए लंबी वर्ष', @@ -578,6 +685,10 @@ $translations = array( 'General_MonthOctober_js' => 'अक्टूबर', 'General_MonthNovember_js' => 'नवंबर', 'General_MonthDecember_js' => 'दिसंबर', + 'CoreHome_ReportGeneratedOn' => '%s पर उत्पन्न रिपोर्ट', + 'CoreHome_ReportGeneratedXAgo' => '%s रिपोर्ट के पहले उत्पन्न', + 'General_LoadingPopover_js' => '%s लोड हो रहा है...', + 'General_LoadingPopoverFor_js' => '%s के लिए लोड हो रहा है', 'General_RowEvolutionRowActionTooltipTitle_js' => 'खुला पंक्ति विकास', 'General_RowEvolutionRowActionTooltip_js' => 'इस पंक्ति के लिए मैट्रिक्स समय के साथ कैसे बदलें देखें', 'General_TransitionsRowActionTooltipTitle_js' => 'ओपन बदलाव', @@ -587,9 +698,13 @@ $translations = array( 'CoreHome_MakeOneTimeDonation' => 'इसके बजाय, एक समय दान करें.', 'CorePluginsAdmin_PluginDescription' => 'प्लगइन्स प्रशासन इंटरफ़ेस.', 'CorePluginsAdmin_Plugins' => 'प्लगइन्स', + 'CorePluginsAdmin_Themes' => 'विषय', 'CorePluginsAdmin_PluginsManagement' => 'प्लगइन्स प्रबंधन', + 'CorePluginsAdmin_ThemesManagement' => 'विषय प्रबंधन', 'CorePluginsAdmin_MainDescription' => 'प्लगइन्स Piwik का विस्तार और कार्यक्षमता का विस्तार करते है, एक प्लगइन स्थापित हो जाने के बाद, आप इसे सक्रिय करने या यहाँ इसे निष्क्रिय कर सकते हैं.', + 'CorePluginsAdmin_ThemesDescription' => 'थीम्स, Piwik यूजर इंटरफेस के स्वरूप को बदल सकते हैं और अपने विश्लेषण रिपोर्टों के आनंद के लिए एक पूरी तरह से नए दृश्य का अनुभव प्रदान करते हैं.', 'CorePluginsAdmin_Plugin' => 'प्लगइन', + 'CorePluginsAdmin_Theme' => 'विषय', 'CorePluginsAdmin_Version' => 'संस्करण', 'CorePluginsAdmin_Status' => 'स्थिति', 'CorePluginsAdmin_Action' => 'कार्रवाई', @@ -601,12 +716,17 @@ $translations = array( 'CorePluginsAdmin_Inactive' => 'निष्क्रिय', 'CorePluginsAdmin_Deactivate' => 'निष्क्रिय करें', 'CorePluginsAdmin_Activate' => 'सक्रिय करें', + 'CorePluginsAdmin_MenuPlatform' => 'मंच', + 'CorePluginsAdmin_MenuExtend' => 'बढ़ाएँ', 'CorePluginsAdmin_PluginCannotBeFound' => 'यह प्लगइन नहीं ढूँढा जा सकता!', 'CoreUpdater_PluginDescription' => 'Piwik तंत्र को अद्यतन', 'CoreUpdater_UpdateTitle' => 'अद्यतन', 'CoreUpdater_DatabaseUpgradeRequired' => 'डेटाबेस नवीनीकरण आवश्यक', 'CoreUpdater_YourDatabaseIsOutOfDate' => 'आपकी Piwik डेटाबेस अप्रचलित है, और जारी रखने से पहले अपग्रेड किया जाना चाहिए.', + 'CoreUpdater_PiwikWillBeUpgradedFromVersionXToVersionY' => 'Piwik डेटाबेस संस्करण%1$s से नए संस्करण %2$s के लिए उन्नत किया जाएगा', + 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX' => 'निम्नलिखित प्लगिन अद्यतन किया जाएगा:%s', 'CoreUpdater_NoteForLargePiwikInstances' => 'बड़े Piwik प्रतिष्ठानों के लिए महत्वपूर्ण सूचनाएं', + 'CoreUpdater_TheUpgradeProcessMayFailExecuteCommand' => 'यदि आप एक बड़े Piwik डेटाबेस है, तो अद्यतन ब्राउज़र में चलाने के लिए बहुत लंबा समय लग सकता है. इस स्थिति में, आप अपने कमांड लाइन से अद्यतन अमल कर सकते हैं: %s', 'CoreUpdater_YouCouldManuallyExecuteSqlQueries' => 'आप कमांड लाइन updater का उपयोग करने में सक्षम नहीं हैं और Piwik (डेटाबेस, एक ब्राउज़र मध्यांतर, या किसी भी अन्य मुद्दे के एक मध्यांतर के कारण) अपग्रेड करने में विफल रहता है, तो आप मैन्युअल Piwik अद्यतन करने के लिए एसक्यूएल प्रश्नों पर अमल कर सकते है.', 'CoreUpdater_ClickHereToViewSqlQueries' => 'क्रियान्वित किया जाएगा कि एसक्यूएल प्रश्नों की सूची देखने और कॉपी करने के लिए यहां क्लिक करें', 'CoreUpdater_NoteItIsExpectedThatQueriesFail' => 'नोट: यदि आप मैन्युअल रूप से इन प्रश्नों पर अमल करते हैं, यह उनमें से कुछ असफल उम्मीद है. इस मामले में, बस त्रुटियों पर ध्यान न दें, और सूची में अगले वाले चलाये.', @@ -619,21 +739,33 @@ $translations = array( 'CoreUpdater_ErrorDIYHelp_3' => 'स्वयं अपने Piwik डेटाबेस के \'विकल्प\' तालिका अद्यतन,अद्यतन के संस्करण के संस्करण कोर के मूल्य की स्थापना में विफल रहा है', 'CoreUpdater_ErrorDIYHelp_4' => 'शेष अद्यतन के साथ जारी रखने के लिए अपडेटर को फिर से चलाएँ (ब्राउज़र या कमांड लाइन के माध्यम से)', 'CoreUpdater_ErrorDIYHelp_5' => 'समस्या (और समाधान) की रिपोर्ट ताकि Piwik में सुधार किया जा सकता है', + 'CoreUpdater_HelpMessageContent' => '%1$s नवीनीकरण के दौरान %2$s सबसे आम त्रुटियों पर किये गए Piwik सवाल जाँच करें. %3$sअपने सिस्टम प्रशासक से पूछें - वे सबसे अधिक संभावना आपके सर्वर या MySQL सेटअप से संबंधित है जो त्रुटि में मदद करने में सक्षम हो सकता है.', 'CoreUpdater_CriticalErrorDuringTheUpgradeProcess' => 'अद्यतन प्रक्रिया के दौरान गंभीर त्रुटि:', 'CoreUpdater_HelpMessageIntroductionWhenError' => 'ऊपर कोर त्रुटि संदेश है यह कारण की व्याख्या करने में मदद करेगा लेकिन आप की आवश्यकता होती है तो आगे कृपया', 'CoreUpdater_HelpMessageIntroductionWhenWarning' => 'अद्यतन, सफलता से पूरा कर लिया लेकिन इस प्रक्रिया के दौरान मुद्दों थे. विवरण के लिए ऊपर वर्णन पढ़ें. आगे की मदद के लिए:', 'CoreUpdater_UpgradeComplete' => 'पूरा अपग्रेड करें!', 'CoreUpdater_WarningMessages' => 'चेतावनी संदेश:', 'CoreUpdater_ErrorDuringPluginsUpdates' => 'प्लगइन अद्यतन के दौरान त्रुटि:', + 'CoreUpdater_WeAutomaticallyDeactivatedTheFollowingPlugins' => 'हमने स्वचालित रूप से निम्नलिखित प्लगिन निष्क्रिय किया: %s', 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded' => 'Piwik सफलतापूर्वक अद्यतन किया गया है!', 'CoreUpdater_ContinueToPiwik' => 'Piwik पर जारी', 'CoreUpdater_UpdateAutomatically' => 'स्वचालित रूप से अद्यतन', 'CoreUpdater_ThereIsNewVersionAvailableForUpdate' => 'नवीनीकरण के लिए उपलब्ध है Piwik का एक नया संस्करण है', + 'CoreUpdater_YouCanUpgradeAutomaticallyOrDownloadPackage' => 'आप स्वतः संस्करण %s के लिए अद्यतन या पैकेज को डाउनलोड और स्वयं इसे स्थापित कर सकते हैं:', + 'CoreUpdater_YouMustDownloadPackageOrFixPermissions' => 'Piwik अपने मौजूदा स्थापना अधिलेखित करने में असमर्थ है. आप या तो निर्देशिका / फाइल अनुमति , या पैकेज को डाउनलोड करने और मैन्युअल %s संस्करण स्थापित कर सकते हैं:', + 'CoreUpdater_DownloadX' => '%s डाउनलोड', + 'CoreUpdater_UpdateHasBeenCancelledExplanation' => 'Piwik एक क्लिक अद्यतन रद्द कर दिया गया. आप ऊपर त्रुटि संदेश को ठीक नहीं कर सकते हैं, यह आप मैन्युअल Piwik अद्यतन की सिफारिश है. %1$sआरंभ करने के लिए अद्यतन%2$s दस्तावेज़ीकरण %2$sकी जाँच करें!', + 'CoreUpdater_DownloadingUpdateFromX' => '%s से अद्यतन डाउनलोड कर रहा है', 'CoreUpdater_UnpackingTheUpdate' => 'अद्यतन को खोल', 'CoreUpdater_VerifyingUnpackedFiles' => 'अनपैक फ़ाइलों को सत्यापित करना', + 'CoreUpdater_CreatingBackupOfConfigurationFile' => '%s में विन्यास फाइल का बैकअप बनाना', 'CoreUpdater_InstallingTheLatestVersion' => 'नवीनतम संस्करण स्थापित कर रहा', 'CoreUpdater_PiwikUpdatedSuccessfully' => 'Piwik सफलतापूर्वक अद्यतन!', + 'CoreUpdater_EmptyDatabaseError' => 'डाटाबेस %s खाली है. आप अपने Piwik का विन्यास फ़ाइल संपादित या निकालना आवश्यक है.', + 'CoreUpdater_ExceptionAlreadyLatestVersion' => 'आपका Piwik संस्करण %s नवीनतम है.', + 'CoreUpdater_ExceptionArchiveIncompatible' => 'असंगत संग्रह: %s', 'CoreUpdater_ExceptionArchiveEmpty' => 'खाली संग्रह.', + 'CoreUpdater_ExceptionArchiveIncomplete' => 'संग्रह अधूरा है: कुछ फ़ाइलें (जैसे %s) लापता हैं.', 'CoreUpdater_MajorUpdateWarning1' => 'यह एक प्रमुख अद्यतन है! इसे सामान्य से अधिक समय लगेगा.', 'CoreUpdater_MajorUpdateWarning2' => 'सलाह के बाद बड़े प्रतिष्ठानों के लिए विशेष रूप से महत्वपूर्ण है.', 'CustomVariables_PluginDescription' => 'कस्टम चर नाम, मूल्य जोड़े रहे हैं, आप जावास्क्रिप्ट एपीआई setVisitCustomVariables () फ़ंक्शन का उपयोग कर एक भ्रमण करने के लिए सेट कर सकते हैं.Piwik तो इन कस्टम नाम और मूल्यों से प्रत्येक के लिए कितने यात्राओं, पृष्ठों, रूपांतरण रिपोर्ट देंगे.', @@ -642,6 +774,8 @@ $translations = array( 'CustomVariables_ColumnCustomVariableValue' => 'विशेष चर मूल्य', 'CustomVariables_ScopeVisit' => 'प्रसार यात्रा', 'CustomVariables_ScopePage' => 'प्रसार पृष्ठ', + 'CustomVariables_TrackingHelp' => 'मदद: %1$s Piwik में %2$s विशेष चर खोजे', + 'CustomVariables_CustomVariablesReportDocumentation' => 'यह रिपोर्ट आपके कस्टम चर के बारे में जानकारी शामिल हैं. मूल्यों के वितरण को देखने के लिए एक चर के नाम पर क्लिक करें. %sसामान्य रूप में %sकस्टम चर के बारे में अधिक जानकारी के लिए, piwik.org %s पर कस्टम चर दस्तावेज़ पढ़ें', 'Dashboard_PluginDescription' => 'आपका वेब विश्लेषिकी डैशबोर्ड. आप अपने डैशबोर्ड को अनुकूलित कर सकते हैं:, नए विगेट्स जोड़ने अपने विगेट्स के क्रम बदल सकते हैं. प्रत्येक उपयोगकर्ता के लिए अपने स्वयं के विशेष डैशबोर्ड का उपयोग कर सकते हैं.', 'Dashboard_Dashboard' => 'डैशबोर्ड', 'Dashboard_AddAWidget' => 'एक विजेट जोड़ें', @@ -662,6 +796,7 @@ $translations = array( 'Dashboard_WidgetsAndDashboard' => 'विजेट और डैशबोर्ड', 'Dashboard_ChangeDashboardLayout' => 'डैशबोर्ड अभिन्यास बदलें', 'Dashboard_SelectDashboardLayout' => 'अपना नया डैशबोर्ड अभिन्यास का चयन करें', + 'Dashboard_DashboardOf' => '%s से डैशबोर्ड', 'Dashboard_ManageDashboard' => 'डैशबोर्ड प्रबंधन', 'Dashboard_CreateNewDashboard' => 'नया डैशबोर्ड बनाएँ', 'Dashboard_RenameDashboard' => 'डैशबोर्ड का नाम बदलें', @@ -673,10 +808,15 @@ $translations = array( 'Dashboard_DashboardCopied_js' => 'वर्तमान डैशबोर्ड सफलतापूर्वक चयनित उपयोगकर्ता के लिए नकल की.', 'Dashboard_SetAsDefaultWidgets' => 'डिफ़ॉल्ट विगेट्स चयन के रूप में सेट करें', 'Dashboard_SetAsDefaultWidgetsConfirm' => 'आप सुनिश्चित कर रहे हैं, आप डिफ़ॉल्ट डैशबोर्ड टेम्पलेट के रूप में मौजूदा विगेट्स चयन और डैशबोर्ड अभिन्यास सेट करना चाहते हैं?', + 'Dashboard_SetAsDefaultWidgetsConfirmHelp' => 'इस विगेट्स चयन और डैशबोर्ड कॉलम अभिन्यास का उपयोग किया जाएगा जब कोई उपयोगकर्ता एक नया डैशबोर्ड बनाता है, या जब "%s" सुविधा का उपयोग करता है.', + 'Dashboard_RemoveDashboardConfirm' => 'आप सुनिश्चित कर रहे हैं, आप "%s" डैशबोर्ड को हटाना चाहते हैं?', 'Dashboard_NotUndo' => 'आप इस कार्रवाई को पूर्ववत् करने सक्षम नहीं होंगे.', 'Dashboard_DashboardEmptyNotification' => 'अपने डैशबोर्ड पर कोई भी विगेट्स शामिल नहीं है. कुछ विगेट्स जोड़ने से शुरू करो या बस डिफ़ॉल्ट विजेट चयन करने के लिए डैशबोर्ड रीसेट करें.', + 'Dashboard_TopLinkTooltip' => '%s के लिए वेब विश्लेषिकी रिपोर्ट देखें', 'DBStats_PluginDescription' => 'यह प्लगइन Piwik तालिकाएँ से डाटाबेस के उपयोग की रिपोर्ट है', 'DBStats_DatabaseUsage' => 'डेटाबेस के उपयोग', + 'DBStats_MainDescription' => 'Piwik MYSQL डाटाबेस में सभी अपने वेब विश्लेषण डेटा स्टोर करता है. वर्तमान में, Piwik तालिकाओं %s की जगह ले।', + 'DBStats_LearnMore' => 'Piwik प्रक्रियाओं डेटा और कैसे मध्यम और उच्च यातायात वेबसाइटों के साथ अच्छी तरह से Piwik काम करता है दस्तावेज़ देखें कैसे के इस बारे में अधिक जानने के लिए:%s', 'DBStats_Table' => 'तालिका', 'DBStats_RowCount' => 'गिनती पंक्ति के', 'DBStats_DataSize' => 'डाटा आकार', @@ -693,10 +833,13 @@ $translations = array( 'DoNotTrack_PluginDescription' => '"Do Not Track or DNT" शीर्षक के साथ यात्राओं पर ध्यान न दें.', 'Feedback_PluginDescription' => 'Piwik टीम के लिए अपने प्रतिक्रिया भेजें. हमारे साथ अपने विचारों और सुझावों को साझा करें!', 'Feedback_DoYouHaveBugReportOrFeatureRequest' => 'क्या आपके पास एक बग की रिपोर्ट या एक सुविधा का अनुरोध है?', + 'Feedback_ViewAnswersToFAQ' => '%s अक्सर पूछे जाने वाले प्रश्नों %s के उत्तर देखें', 'Feedback_WhyAreMyVisitsNoTracked' => 'क्यों मेरी वेबसाइट को दौरा करने के लिए नहीं खोजा जा रहा है?', 'Feedback_HowToExclude' => 'कैसे मैं अपने दौरों को खोज से निकालूं?', 'Feedback_WhyWrongCountry' => 'क्यों Piwik गलत देश से मेरी यात्रा दिखाता है?', 'Feedback_HowToAnonymizeIP' => 'कैसे मैं मेरे डेटाबेस में आगंतुक आईपी पते को छिपाऊ?', + 'Feedback_VisitTheForums' => '%s विचार मंच %s पर जाएँ', + 'Feedback_LearnWaysToParticipate' => 'सभी तरीकों के बारे में जानें, आप %s भाग %s ले सकते हैं', 'Feedback_SpecialRequest' => 'आपका Piwik टीम के लिए एक विशेष अनुरोध है?', 'Feedback_ContactThePiwikTeam' => 'Piwik टीम से संपर्क!', 'Feedback_IWantTo' => 'मैं चाहता हूँ:', @@ -723,12 +866,18 @@ $translations = array( 'Goals_EcommerceOrder' => 'ईकॉमर्स के आदेश', 'Goals_EcommerceLog' => 'ईकॉमर्स अभिलेख', 'Goals_AbandonedCart' => 'परित्यक्त कार्ट', + 'Goals_LeftInCart' => '%s कार्ट में छोड़ दिया', 'Goals_GoalsOverview' => 'लक्ष्य अवलोकन', + 'Goals_GoalsOverviewDocumentation' => 'यह अपने लक्ष्य रूपांतरण का अवलोकन है. प्रारंभ में, ग्राफ सभी रूपांतरणों की राशि को दर्शाता है. ग्राफ नीचे %s, आप अपने लक्ष्यों में से प्रत्येक के लिए रूपांतरण रिपोर्ट देख सकते हैं. स्पार्कलाइन उन पर क्लिक करके विस्तारित किया जा सकता है.', 'Goals_SingleGoalOverviewDocumentation' => 'यह एक ही लक्ष्य के लिए रूपांतरण का अवलोकन है. %s ग्राफ नीचे स्पार्कलाइन उन पर क्लिक करके विस्तारित किया जा सकता है.', 'Goals_GoalsManagement' => 'लक्ष्य प्रबंधन', 'Goals_EcommerceReports' => 'ईकॉमर्स रिपोर्टें', + 'Goals_YouCanEnableEcommerceReports' => 'आपको %s पेज में इस वेबसाइट को सक्षम %s कर सकते हैं.', 'Goals_ConversionsOverviewBy' => 'यात्रा के प्रकार से रूपांतरण अवलोकन', + 'Goals_GoalConversionsBy' => 'यात्रा के प्रकार से लक्ष्य %s का रूपांतरण', + 'Goals_ViewGoalsBy' => '%s द्वारा लक्ष्यों को देखें', 'Goals_PluginDescription' => 'लक्ष्य बनाएं और अपने लक्ष्य रूपांतरण के बारे में रिपोर्ट देखें: समय के साथ विकास यात्रा के प्रति राजस्व, कीवर्ड प्रति संदर्भ प्रति रूपांतरण, आदि', + 'Goals_ConversionByTypeReportDocumentation' => 'इस रिपोर्ट के बाएं पैनल में उपलब्ध श्रेणियों में से प्रत्येक के लिए लक्ष्य प्रदर्शन (रूपांतरण, रूपांतरण दर और यात्रा के प्रति राजस्व) के बारे में विस्तृत जानकारी प्रदान करता है.%s रिपोर्ट देखने के लिए श्रेणियों में से एक पर क्लिक करें. %sअधिक जानकारी के लिए, %sट्रैकिंग लक्ष्य प्रलेखन%s पढ़ें', 'Goals_ColumnConversions' => 'रूपांतरण', 'Goals_ColumnConversionsDocumentation' => '%s के लिए रूपांतरण की संख्या.', 'Goals_ColumnRevenue' => 'राजस्व', @@ -739,22 +888,28 @@ $translations = array( 'Goals_ColumnAverageOrderRevenueDocumentation' => 'औसत ऑर्डर मूल्य (AOV) आदेश की संख्या से विभाजित सभी ईकॉमर्स आदेश से कुल राजस्व है.', 'Goals_ColumnPurchasedProductsDocumentation' => 'खरीदे गए उत्पादों की संख्या में सभी ईकॉमर्स आदेश में बेचा उत्पाद मात्रा का योग है.', 'Goals_ColumnQuantityDocumentation' => 'प्रत्येक मात्रा %s के लिए बेचा उत्पादों की कुल संख्या है.', + 'Goals_ColumnOrdersDocumentation' => 'कम से कम एक बार जिसमें %s ईकॉमर्स आदेशों की कुल संख्या.', 'Goals_ColumnAveragePriceDocumentation' => 'इस %s के लिए औसत राजस्व.', 'Goals_ColumnAverageQuantityDocumentation' => 'इस %s की औसत मात्रा ईकॉमर्स आदेश में बेच दिया.', + 'Goals_ColumnVisitsProductDocumentation' => 'उत्पाद / श्रेणी पेज पर यात्राओं की संख्या. यह भी %s की रूपांतरण दर संसाधित करने के लिए प्रयोग किया जाता है. ईकॉमर्स दृश्य ट्रैकिंग उत्पाद / श्रेणी पृष्ठों पर सेटअप किया गया तो यह मीट्रिक रिपोर्ट में है.', + 'Goals_ColumnConversionRateProductDocumentation' => 'रूपांतरण %s दर उत्पाद पृष्ठ पर यात्राओं की संख्या से विभाजित इस उत्पाद से युक्त आदेश की संख्या है.', 'Goals_ColumnVisits' => 'यात्राओं की कुल संख्या,परवाह किए बिना एक लक्ष्य सक्रिय हो गया था या नहीं.', 'Goals_GoalX' => 'लक्ष्य %s', 'Goals_GoalConversion' => 'लक्ष्य रूपांतरण', 'Goals_GoalConversions' => 'लक्ष्य रूपांतरण', 'Goals_OverallRevenue' => '%s कुल राजस्व', 'Goals_OverallConversionRate' => '%s कुल रूपांतरण दर (एक पूरा लक्ष्य के साथ दौरा)', + 'Goals_ConversionRate' => '%s रूपांतरण दर', 'Goals_NoGoalsNeedAccess' => 'केवल एक प्रशासक या सुपर प्रयोक्ता किसी वेबसाइट के लिए लक्ष्यों को जोड़ सकते हैं. अपनी वेबसाइट के लिए एक लक्ष्य स्थापित करने के लिए अपने Piwik व्यवस्थापक से संपर्क करें. <br> ट्रैकिंग लक्ष्य अपनी वेबसाइट के प्रदर्शन को समझने और अधिकतम मदद करने के लिए एक शानदार तरीका है!', 'Goals_AddNewGoal' => 'एक नया लक्ष्य जोड़ें', 'Goals_NewGoalIntro' => 'लक्ष्य रूपांतरण ट्रैकिंग अपने व्यापार के लक्ष्यों को मापने के लिए और बेहतर बनाने के लिए सबसे कारगर तरीकों में से एक है.', 'Goals_NewGoalDescription' => 'Piwik में एक लक्ष्य अपनी रणनीति, अपनी प्राथमिकता है, और बहुत सी बातें आवश्यक कर सकते हैं: "डाउनलोड विवरणिका", "पंजीकृत समाचार पत्र", आदि, "पृष्ठ services.html दौरा"', 'Goals_NewWhatDoYouWantUsersToDo' => 'आप अपने उपयोगकर्ताओं को अपनी वेबसाइट पर क्या करना चाहते हो?', 'Goals_NewGoalYouWillBeAbleTo' => 'यदि आप प्रत्येक लक्ष्य के लिए अपने प्रदर्शन को को देखने और विश्लेषण करने में सक्षम हो जाएगा, और रूपांतरण, रूपांतरण दर और यात्रा के प्रति राजस्व में वृद्धि करने के लिए.', + 'Goals_AddNewGoalOrEditExistingGoal' => '%sएक नया लक्ष्य जोड़ें%s या %sमौजूदा लक्ष्य %sको संपादित करें', 'Goals_AddGoal_js' => 'लक्ष्य जोड़ें', 'Goals_UpdateGoal_js' => 'लक्ष्य अद्यतन', + 'Goals_DeleteGoalConfirm_js' => 'आप अपने लक्ष्य %s को नष्ट करना चाहते हैं?', 'Goals_CreateNewGOal' => 'एक नया लक्ष्य बनाएं', 'Goals_ViewAndEditGoals' => 'लक्ष्य देखें और संपादित करें', 'Goals_GoalName' => 'लक्ष्य नाम', @@ -773,6 +928,7 @@ $translations = array( 'Goals_VisitPageTitle' => 'किसी दिए गए पृष्ठ शीर्षक पर जाएँ', 'Goals_ClickOutlink' => 'एक बाहरी वेबसाइट के लिए एक लिंक पर क्लिक करें', 'Goals_Optional' => '(वैकल्पिक)', + 'Goals_WhereVisitedPageManuallyCallsJavascriptTrackerLearnMore' => 'दौरा पेज जावास्क्रिप्ट \'trackGoal\' के लिए एक कॉल शामिल है जहां विधि (%s अधिक जानें%s)', 'Goals_AllowMultipleConversionsPerVisit' => 'प्रति यात्रा कई रूपांतरणों की अनुमति दें', 'Goals_DefaultGoalConvertedOncePerVisit' => '(डिफ़ॉल्ट) लक्ष्य केवल यात्रा के प्रति एक बार परिवर्तित किया जा सकता है', 'Goals_HelpOneConversionPerVisit' => 'यह लक्ष्य मिलान एक पृष्ठ एक यात्रा में रीफ़्रेश या एक से अधिक बार देखा जाता है तो लक्ष्य केवल पृष्ठ पर इस यात्रा के दौरान लोड किया गया था पहली बार ट्रैक किया जाएगा.', @@ -784,8 +940,14 @@ $translations = array( 'Goals_BestKeywords' => 'आपका शीर्ष परिवर्तित कीवर्ड हैं:', 'Goals_BestReferers' => 'आपका सबसे अच्छा परिवर्तित वेबसाइटों सन्दर्भदाता हैं:', 'Goals_ReturningVisitorsConversionRateIs' => 'आगंतुकों रूपांतरण दर रिटर्निंग %s है', + 'Goals_NewVisitorsConversionRateIs' => 'नई आगंतुक रूपांतरण दर %s है', + 'Goals_Contains' => '%s में शामिल', + 'Goals_IsExactly' => '%s ठीक है', + 'Goals_MatchesExpression' => '%s अभिव्यक्ति से मेल खाता है', 'Goals_CaseSensitive' => 'संवेदनशील प्रकरण मिलना', 'Goals_Pattern' => 'प्रतिमान', + 'Goals_ExceptionInvalidMatchingString' => 'आप \'सटीक मैच\' चुनते हैं, तो मिलान स्ट्रिंग %s की शुरुआत के साथ एक URL होना चाहिए. उदाहरण के लिए, \'%s\' में.', + 'Goals_LearnMoreAboutGoalTrackingDocumentation' => 'उपयोगकर्ता दस्तावेज में Piwik %s में लक्ष्य ट्रैकिंग के बारे में और अधिक जानें %s, या अभी एक लक्ष्य बनाने के लिए!', 'Goals_ProductSKU' => 'उत्पाद SKU', 'Goals_ProductName' => 'उत्पाद का नाम', 'Goals_ProductCategory' => 'उत्पाद श्रेणी', @@ -812,6 +974,7 @@ $translations = array( 'Installation_PleaseFixTheFollowingErrors' => 'निम्न त्रुटियों को ठीक करें', 'Installation_LargePiwikInstances' => 'उच्च यातायात वेबसाइटों के साथ उपयोगकर्ताओं के लिए मदद', 'Installation_JsTag' => 'जावास्क्रिप्ट ट्रैकिंग कोड', + 'Installation_JsTagArchivingHelp1' => 'मध्यम और उच्च यातायात वेबसाइटों के लिए कुछ अनुकूलन रहे हैं कि Piwik (जैसे %1$sऑटो संग्रह की स्थापना के रूप%2$s में) तेजी से चलाने में मदद के लिए बनाया जाना चाहिए.', 'Installation_Congratulations' => 'बधाई हो', 'Installation_CongratulationsHelp' => '<p> बधाई हो! आपकी Piwik स्थापना पूरा हो गया है.</p><p>अपने जावास्क्रिप्ट कोड को अपने पन्नों पर दर्ज किया जाता है सुनिश्चित करें, और अपने पहले आगंतुकों के लिए प्रतीक्षा करें </ p>', 'Installation_ContinueToPiwik' => 'Piwik पर जारी रहे', @@ -822,6 +985,7 @@ $translations = array( 'Installation_Timezone' => 'वेबसाइट समय क्षेत्र', 'Installation_SiteSetupFootnote' => 'नोट: Piwik स्थापित समाप्त हो गया है, एक बार आप ट्रैक करने के लिए और अधिक वेबसाइट जोड़ने के लिए सक्षम हो जाएंगे!', 'Installation_SetupWebsiteError' => 'वेबसाइट जोड़ते समय एक त्रुटि हुई थी', + 'Installation_SetupWebsiteSetupSuccess' => 'वेबसाइट %s सफलता के साथ बनाई गई!', 'Installation_SuperUser' => 'उत्कृष्ट प्रयोक्ता', 'Installation_SuperUserSetupSuccess' => 'उत्कृष्ट प्रयोक्ता सफलता के साथ बनाया!', 'Installation_SuperUserLogin' => 'उत्कृष्ट उपयोगकर्ता लॉगिन', @@ -840,7 +1004,9 @@ $translations = array( 'Installation_SystemCheckPhp' => 'PHP संस्करण', 'Installation_SystemCheckExtensions' => 'अन्य जरूरी विस्तार', 'Installation_SystemCheckDatabaseHelp' => 'Piwik mysqli विस्तार या तो या पीडीओ और pdo_mysql एक्सटेंशन दोनों की आवश्यकता है.', + 'Installation_SystemCheckPdoAndMysqliHelp' => 'एक लिनक्स सर्वर पर आप निम्नलिखित विकल्पों के साथ php का संकलन कर सकते हैं:%1$s अपने php.ini में निम्नलिखित लाइनें जोड़ने:%2$s', 'Installation_SystemCheckPhpPdoAndMysqliSite' => 'पर अधिक जानकारी: <a style="color:red" href="http://php.net/pdo"> PHP पीडीओ </ a> और <एक शैली = "रंग: लाल" href = "http:// php.net / mysqli "> mysqli </ a>.', + 'Installation_SystemCheckWinPdoAndMysqliHelp' => 'एक विंडोज़ सर्वर पर आप अपने php.ini के लिए निम्न पंक्तियाँ जोड़ सकते हैं: %s', 'Installation_SystemCheckSplHelp' => 'आप मानक PHP पुस्तकालय (एसपीएल) सक्षम (डिफ़ॉल्ट रूप से) के साथ PHP कॉन्फ़िगर और पुनर्निर्माण की जरूरत है.', 'Installation_SystemCheckZlibHelp' => 'आप सक्षम "जेडलिब्" समर्थन के साथ PHP कॉन्फ़िगर और पुनर्निर्माण की आवश्यकता, - साथ zlib.', 'Installation_SystemCheckIconvHelp' => 'आप PHP कॉन्फ़िगर और पुनर्निर्माण की जरूरत "iconv" समर्थन सक्षम के साथ - साथ iconv.', @@ -882,26 +1048,34 @@ $translations = array( 'Installation_SystemCheckTracker' => 'ट्रैकर स्थिति', 'Installation_SystemCheckTrackerHelp' => 'Piwik.php के लिए अनुरोध विफल मिलता है. HTTP प्रमाणीकरण से इस यूआरएल को श्वेत सूची बनाओ कोशिश करो और (आपको अपने webhost पूछने के लिए हो सकता है) mod_security अक्षम करें.', 'Installation_Tables' => 'तालिकाएँ बनाना', + 'Installation_TablesWithSameNamesFound' => 'अपने डेटाबेस से कुछ %1$s तालिकाओं के रूप में %2$sएक ही नाम हैPiwik बनाने की कोशिश कर रहा है', 'Installation_TablesFound' => 'निम्न तालिकाओं को डेटाबेस में पाया गया है', 'Installation_TablesWarningHelp' => 'या तो मौजूदा डेटाबेस तालिकाओं का पुन: उपयोग करने के लिए चुन सकते हैं या डेटाबेस से सभी मौजूदा डेटा को मिटाने के लिए एक साफ स्थापित का चयन करें.', 'Installation_TablesReuse' => 'मौजूदा तालिकाओं का पुनः उपयोग', 'Installation_TablesDelete' => 'पता लगाया तालिकाओं को हटाएँ', 'Installation_TablesDeletedSuccess' => 'सफलता साथ नष्ट कर दिया मौजूदा Piwik तालिकाएँ', 'Installation_TablesCreatedSuccess' => 'तालिकाएँ सफलता के साथ बनाई गई!', + 'Installation_DatabaseCreatedSuccess' => 'डाटाबेस %s सफलता के साथ बनाया!', 'Installation_GoBackAndDefinePrefix' => 'वापस जाओ और Piwik टेबल्स के लिए एक उपसर्ग को परिभाषित करे.', + 'Installation_ConfirmDeleteExistingTables' => 'अपने डेटाबेस से %s: क्या आप तालिकाओं को हटाना चाहते हैं? चेतावनी: इन तालिकाओं से डेटा बरामद नहीं किया जा सकता है!', 'Installation_Welcome' => 'आपका स्वागत है!', + 'Installation_WelcomeHelp' => '<p>Piwik अपने आगंतुकों से इच्छित जानकारी प्राप्त करने के लिए यह आसान बनाता है एक ओपन स्रोत वेब विश्लेषिकी सॉफ्टवेयर है.</p><p> यह प्रक्रिया %s आसान चरणों में विभाजित है और 5 मिनट के करीब का समय लगेगा.</p>', 'Installation_ConfigurationHelp' => 'आपकी Piwik विन्यास फाइल गलत प्रतीत होता है. आप या तो विन्यास / config.ini.php हटाने और स्थापना को फिर से शुरू, या डेटाबेस कनेक्शन सेटिंग्स को सही कर सकते हैं.', + 'Installation_ErrorInvalidState' => 'त्रुटि: यह आपकी स्थापना प्रक्रिया का एक कदम को छोड़ की कोशिश की लगती है,या आपके कुकीज़ अक्षम कर रहे हैं, या Piwik विन्यास फाइल पहले से ही बनाया गया था.%1$s आपके कुकीज़ सक्षम हैं%2$s सुनिश्चित करें और %3$sस्थापना के पहले पृष्ठ%4$s पर वापस जाओ.', 'Installation_InsufficientPrivilegesHelp' => 'आप ऐसे phpMyAdmin के रूप में एक उपकरण का उपयोग करके या सही एसक्यूएल प्रश्नों को क्रियान्वित करने से इन विशेषाधिकारों को जोड़ सकते हैं. आपको इन चीजों को कैसे करना है पता नहीं है, आप के लिए इन विशेषाधिकार प्रदान करने के लिए अपने सिस्टम प्रशासक से पूछे कृपया.', + 'Installation_SystemCheckSummaryThereWereErrors' => 'ओह! Piwik अपने Piwik स्थापना के साथ कुछ %1$sगंभीर समस्याओं%2$s का पता लगाया गया है. %3$sये समस्याएँ तुरंत निर्धारित की जानी चाहिए.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'आपके सिस्टम के साथ कुछ मुद्दे हैं. Piwik चलाया जाएगा, लेकिन आपको कुछ मामूली समस्याओं का अनुभव हो सकता है.', 'Installation_SystemCheckSummaryNoProblems' => 'हुज़्ज़ाह! अपने Piwik सेटअप के साथ कोई समस्या नहीं हैं. अपने आप को पीठ पर एक पॅट दे.', 'Installation_SeeBelowForMoreInfo' => 'अधिक जानकारी के लिए नीचे देखें.', 'Installation_DatabaseAbilities' => 'डेटाबेस की क्षमताओं', + 'Installation_LoadDataInfileUnavailableHelp' => '%1$s का प्रयोग बहुत Piwik का संग्रह करने की प्रक्रिया को गति देगा. Piwik लिए उपलब्ध बनाने के लिए, अपने PHP और MySQL सॉफ्टवेयर अद्यतन करने की कोशिश और अपने डेटाबेस उपयोगकर्ता के %2$sविशेषाधिकार है सुनिश्चित करें.', 'Installation_LoadDataInfileRecommended' => 'अपने Piwik सर्वर उच्च यातायात वेबसाइटों को (प्रति माह जैसे> 100,000 पृष्ठों) ट्रैक करता है, तो हम इस समस्या को ठीक करने की कोशिश करने की सलाह देते हैं.', 'Installation_Filesystem' => 'संचिकातंत्र', 'Installation_NfsFilesystemWarning' => 'आपका सर्वर एक NFS फाइल सिस्टम का उपयोग कर रहा है.', 'Installation_NfsFilesystemWarningSuffixAdmin' => 'इसका मतलब यह है Piwik अत्यंत धीमी हो जाएगा फ़ाइल आधारित सत्रों का उपयोग करते समय.', 'Installation_NfsFilesystemWarningSuffixInstall' => 'एनएफएस पर फ़ाइल आधारित सत्रों का प्रयोग अत्यंत धीमा है, तो Piwik डेटाबेस सत्र का उपयोग करेगा. आप कई समवर्ती डैशबोर्ड उपयोगकर्ताओं है, तो आप डेटाबेस सर्वर से ग्राहक कनेक्शन की अधिकतम संख्या में वृद्धि करने की आवश्यकता हो सकती है.', 'Installation_JSTracking_Intro' => 'Piwik साथ अपने वेब यातायात को ट्रैक करने के लिए आप कुछ अतिरिक्त कोड अपने वेब पृष्ठों में से प्रत्येक के लिए जोड़ा जाता है सुनिश्चित करने की जरूरत है.', + 'Installation_JSTracking_EndNote' => 'नोट: स्थापना प्रक्रिया के बाद, आप ट्रैकिंग कोड व्यवस्थापक अनुभाग में अनुकूलित %1$sट्रैकिंग कोड%2$s उत्पन्न कर सकते हैं.', 'LanguagesManager_PluginDescription' => 'यह प्लगइन Piwik इंटरफेस के लिए उपलब्ध भाषाओं की सूची प्रदर्शित करेगा. चयनित भाषा प्रत्येक उपयोगकर्ता के लिए वरीयताओं से सहेजा जाएगा.', 'LanguagesManager_AboutPiwikTranslations' => 'Piwik अनुवाद के बारे में', 'Live_PluginDescription' => 'अपने दर्शकों के वास्तविक समय में रहते देखो!', @@ -912,13 +1086,17 @@ $translations = array( 'Live_VisitorLog' => 'आगंतुक प्रवेश', 'Live_Time' => 'समय', 'Live_Referrer_URL' => 'संदर्भ URL', + 'Live_LastMinutes' => 'अंतिम %s मिनट', + 'Live_LastHours' => 'अंतिम %s घंटे', 'Live_MorePagesNotDisplayed' => 'इस आगंतुक से अधिक पृष्ठों को प्रदर्शित नहीं कर रहे हैं', 'Live_GoalType' => 'प्रकार', 'Live_PageRefreshed' => 'यह पृष्ठ देखा गया था / एक पंक्ति में रिफ्रेश की संख्या।', 'Live_GoalTime' => '1 रूपांतरण समय', + 'Live_KeywordRankedOnSearchResultForThisVisitor' => 'खोजशब्द %1$sके इस आगंतुक %2$sके लिए %3$sखोज परिणाम पृष्ठ पर स्थान दिया गया था', 'Live_GoalRevenue' => 'राजस्व', 'Live_GoalDetails' => 'विवरण', 'Live_VisitorsLastVisit' => 'इस आगंतुक की आखिरी यात्रा %s दिन पहले की बात है.', + 'Live_NbVisitors' => '%s आगंतुकों', 'Live_NbVisitor' => '1 आगंतुक', 'Live_RealTimeVisitorCount' => 'रीयल टाइम आगंतुक गणना', 'Live_SimpleRealTimeWidget_Message' => 'अंतिम %s में %s और %s है.', @@ -934,12 +1112,23 @@ $translations = array( 'Login_LostYourPassword' => 'अपना पासवर्ड खो गया?', 'Login_PasswordsDoNotMatch' => 'पासवर्ड मेल नहीं खाते.', 'Login_InvalidUsernameEmail' => 'अमान्य उपयोगकर्ता नाम या ई - मेल का पता.', + 'Login_InvalidNonceOrHeadersOrReferer' => 'प्रपत्र सुरक्षा में विफल रहा है. प्रपत्र लोड करें और अपने कुकीज़ सक्षम किए गए हैं कि जांच करें. आप एक प्रॉक्सी सर्वर का उपयोग करते हैं, तो आपको चाहिए% है कि होस्ट हेडर प्रॉक्सी हैडर %s को आगे स्वीकार करने के लिए Piwik %s कॉन्फ़िगर करें. इसके अलावा, आपके जो Referer हेडर सही ढंग से भेजा गया है कि जांच ले.', 'Login_InvalidOrExpiredToken' => 'टोकन अमान्य है या समाप्त हो गया है.', 'Login_MailTopicPasswordChange' => 'पासवर्ड परिवर्तन की पुष्टि', + 'Login_MailPasswordChangeBody' => 'नमस्ते %1$s,
+
+एक पासवर्ड रीसेट अनुरोध %2$s से प्राप्त किया गया था. आप अपनी नई पहचान के साथ प्रवेश कर सकते हैं तो यह पासवर्ड परिवर्तन की पुष्टि करने के लिए नीचे दिए गए लिंक पर जाएँ:
+
+%3$s
+
+नोट: यह टोकन 24 घंटों में समाप्त हो जाएगा.
+
+और Piwik इस्तेमाल करने के लिए धन्यवाद!', 'Login_ConfirmationLinkSent' => 'एक पुष्टिकरण लिंक आपके इनबॉक्स के लिए भेजा गया है. अपने ई - मेल की जाँच करें और अपने पासवर्ड बदलने का अनुरोध अधिकृत करने के लिए इस लिंक पर जाएं.', 'Login_PasswordChanged' => 'आपका पासवर्ड बदल दिया गया है.', 'Login_ContactAdmin' => 'संभावित कारण: आपके मेजबान मेल () फलन में अक्षम हो सकता है. <br /> अपने Piwik प्रशासक से संपर्क करें.', 'Login_ExceptionPasswordMD5HashExpected' => 'पासवर्ड पैरामीटर पासवर्ड का एक एमडी 5 हैश होने की उम्मीद है.', + 'Login_ExceptionInvalidSuperUserAuthenticationMethod' => 'सुपर प्रयोक्ता \'%s\' तंत्र का उपयोग कर प्रमाणीकृत नहीं किया जा सकता.', 'Login_ResetPasswordInstructions' => 'अपने खाते के लिए एक नया पासवर्ड दर्ज करें.', 'Mobile_Accounts' => 'लेखा', 'Mobile_AddAccount' => 'खाता जोड़ें', @@ -953,12 +1142,14 @@ $translations = array( 'Mobile_HelpUsToImprovePiwikMobile' => 'आप Piwik मोबाइल में अज्ञात उपयोग के ट्रैकिंग सक्षम करना चाहेंगे?', 'Mobile_HttpIsNotSecureWarning' => 'आप \'एचटीटीपी\' का उपयोग यदि आपकी Piwik प्राधिकरण टोकन (token_auth) स्पष्ट टेक्स्ट में भेजा गया है. इस कारण से हम इंटरनेट पर डेटा के सुरक्षित परिवहन के लिए HTTPS की सलाह देते हैं. आप आगे बढ़ना चाहते हैं?', 'Mobile_HowtoDeleteAnAccountOniOS' => 'एक खाते को हटाने के लिए बाएँ से दाएँ खिसकाए', + 'Mobile_LastUpdated' => 'पिछला परिवर्तन: %s', 'Mobile_LoginCredentials' => 'साख', 'Mobile_LoginUseHttps' => 'एचटीटीपी का प्रयोग करें', 'Mobile_PullDownToRefresh' => 'रीफ़्रेश करने के लिए नीचे खींचो ...', 'Mobile_RatingNotNow' => 'अभी नहीं', 'Mobile_RatingNow' => 'ठीक है, मैं अब यह दर दूँगा', 'Mobile_RatingDontRemindMe' => 'मुझे याद मत दिलाओ', + 'Mobile_RatingPleaseRateUs' => 'आप में अनुप्रयोग दर करने के लिए 1 मिनट ले लिया %sतो हम सच में जानना चाहेंगे Piwik मोबाइल एक फ्री सॉफ्टवेयर है.आपको नई सुविधाओं या बग रिपोर्ट का सुझाव हैं तो कृपया %sसंपर्क करें', 'Mobile_Refresh' => 'रिफ्रेश', 'Mobile_Reloading' => 'पुन: लोड ...', 'Mobile_ReleaseToRefresh' => 'रीफ़्रेश करने के लिए छोड़ दें ...', @@ -974,6 +1165,7 @@ $translations = array( 'Mobile_StaticGraph' => 'अवलोकन ग्राफ', 'Mobile_DefaultReportDate' => 'तारीख रिपोर्ट', 'Mobile_MultiChartLabel' => 'स्पार्कलाइन प्रदर्शित', + 'Mobile_NetworkErrorWithStatusCode' => 'कोई त्रुटि "%s" थी. अनुरोध स्थिति लौट "%s" आए. यूआरएल "%s" था. अधिक त्रुटि के बारे में जानकारी और कैसे इसे हल करने के लिए इस सर्वर पर आपके द्वारा दर्ज URL और त्रुटि लॉग की जाँच करें.', 'Mobile_NetworkNotReachable' => 'पहुंच के बाहर नेटवर्क', 'Mobile_NavigationBack' => 'वापस जाएँ', 'Mobile_NoPiwikAccount' => 'नहीं है Piwik खाता?', @@ -982,11 +1174,13 @@ $translations = array( 'Mobile_SaveSuccessError' => 'Piwik यूआरएल या उपयोगकर्ता नाम और पासवर्ड गलत है.', 'Mobile_SearchWebsite' => 'खोज वेबसाइटों', 'Mobile_YouAreOffline' => 'क्षमा करें, आप वर्तमान में ऑफ़लाइन हैं', + 'MobileMessaging_Exception_UnknownProvider' => 'प्रदाता का नाम \'%s\' अज्ञात है. बजाय निम्न में से किसी का प्रयास करें:%s.', 'MobileMessaging_PluginDescription' => 'बनाने के लिए और डाउनलोड करें कस्टम एसएमएस रिपोर्ट और उन्हें एक दैनिक, साप्ताहिक या मासिक आधार पर अपने मोबाइल के लिए भेजे .', 'MobileMessaging_TopMenu' => 'ईमेल और एसएमएस रिपोर्टें', 'MobileMessaging_TopLinkTooltip' => 'आपके ईमेल इनबॉक्स या आपके मोबाइल फोन के लिए वेब विश्लेषिकी रिपोर्ट प्राप्त करें!', 'MobileMessaging_SettingsMenu' => 'मोबाइल संदेश', 'MobileMessaging_Settings_SuperAdmin' => 'सुपर प्रयोक्ता सेटिंग्स', + 'MobileMessaging_VerificationText' => 'प्रविष्ट कोड %s है. अपना फोन नंबर मान्य है और Piwik एसएमएस रिपोर्ट प्राप्त करने के लिए. Piwik के माध्यम से सुलभ रूप से यह कोड की नकल बनाये कृपया > %s > %s.', 'MobileMessaging_Settings_LetUsersManageAPICredential' => 'उपयोक्ता अपने एसएमएस एपीआई क्रेडेंशियल्स प्रबंधित करने की अनुमति दें', 'MobileMessaging_Settings_LetUsersManageAPICredential_No_Help' => 'सभी उपयोगकर्ता एसएमएस रिपोर्टें प्राप्त कर सकते हैं और अपने खाते के क्रेडिट का इस्तेमाल करेंगे.', 'MobileMessaging_Settings_LetUsersManageAPICredential_Yes_Help' => 'प्रत्येक उपयोगकर्ता अपनी एसएमएस एपीआई खाता सेटअप करने के लिए सक्षम हो जाएगा, आपके क्रेडिट का उपयोग नहीं करेगा', @@ -1008,8 +1202,11 @@ $translations = array( 'MobileMessaging_Settings_AddPhoneNumber' => 'जोड़ना', 'MobileMessaging_Settings_ValidatePhoneNumber' => 'मान्य करें', 'MobileMessaging_Settings_RemovePhoneNumber' => 'हटाएँ', + 'MobileMessaging_Settings_SuspiciousPhoneNumber' => 'आपको टेक्स्ट संदेश नहीं मिलता, तो आप अग्रणी शून्य के बिना कोशिश कर सकते हैं. अर्थात्. %s', 'MobileMessaging_Settings_CredentialNotProvidedByAdmin' => 'आपको फोन नंबर बनाने और प्रबंधित करने के पहले, एक एसएमएस खाते से Piwik कनेक्ट करने के लिए अपने व्यवस्थापक से संपर्क करें.', 'MobileMessaging_Settings_CredentialNotProvided' => 'आपको फोन नंबर बनाने और प्रबंधित करने के पहले, ऊपर अपने एसएमएस खाते से Piwik कनेक्ट करें.', + 'MobileMessaging_Settings_CredentialProvided' => 'अपने %s एसएमएस एपीआई खाते को सही ढंग से कॉन्फ़िगर किया गया है!', + 'MobileMessaging_Settings_UpdateOrDeleteAccount' => 'आप भी %sअपडेट%s करने या इस खाते को %sहटा%s सकते हैं.', 'MobileMessaging_Settings_DeleteAccountConfirm' => 'क्या आप इस एसएमएस खाते को हटाना चाहते हैं?', 'MobileMessaging_MobileReport_PhoneNumbers' => 'फोन नंबर', 'MobileMessaging_MobileReport_NoPhoneNumbers' => 'अभिगम के द्वारा कम से कम एक फोन नंबर को सक्रिय करें', @@ -1024,23 +1221,32 @@ $translations = array( 'Provider_WidgetProviders' => 'प्रदाता', 'Provider_ColumnProvider' => 'प्रदाता', 'Provider_SubmenuLocationsProvider' => 'स्थान और प्रदाता', + 'Provider_ProviderReportDocumentation' => 'इस रिपोर्ट से पता चलता है आपके आगंतुकों को वेबसाइट का उपयोग करने के लिए जो इंटरनेट सेवा प्रदाता इस्तेमाल किया है. आप अधिक जानकारी के लिए एक प्रदाता के नाम पर क्लिक कर सकते हैं. %sPiwik एक आगंतुक प्रदाता निर्धारित नहीं कर सकते हैं, यह आईपी के रूप में सूचीबद्ध किया जाता है.', 'Referers_PluginDescription' => 'खोज इंजन, कीवर्ड, वेबसाइट, अभियान ट्रैकिंग, डायरेक्ट एंट्री: सन्दर्भदाता डेटा की रिपोर्ट.', 'Referers_Referrer' => 'संदर्भ', 'Referers_Referers' => 'सन्दर्भदाता', 'Referers_ReferrersOverview' => 'सन्दर्भदाता अवलोकन', 'Referers_EvolutionDocumentation' => 'इससे आपकी वेबसाइट पर आगंतुकों का नेतृत्व किया जो सन्दर्भदाता का अवलोकन है.', + 'Referers_EvolutionDocumentationMoreInfo' => 'अलग संदर्भ प्रकार के बारे में अधिक जानकारी के लिए, %sतालिका के दस्तावेज़ देखें.', 'Referers_SearchEngines' => 'सर्च इंजन', + 'Referers_SearchEnginesReportDocumentation' => 'यह रिपोर्ट जो दर्शाता है खोज इंजन का आपकी वेबसाइट पर उपयोगकर्ताओं को भेजा जाता. तालिका में एक पंक्ति पर%s क्लिक करते हुए आप देख सकते हैं क्या उपयोगकर्ताओं को एक विशिष्ट खोज इंजन का उपयोग करने की खोज कर रहे थे', 'Referers_Keywords' => 'खोजशब्द', + 'Referers_KeywordsReportDocumentation' => 'यह रिपोर्ट कि वे आपकी वेबसाइट पर निर्दिष्ट किये जाने से पहले उपयोगकर्ताओं द्वारा खोजे जा रहे कीवर्ड दिखाता है तालिका में एक पंक्ति पर %s क्लिक करते हुए आप कीवर्ड की पूछा था कि खोज इंजन का वितरण देख सकते हैं.', 'Referers_DirectEntry' => 'प्रत्यक्ष प्रवेश', 'Referers_Websites' => 'वेबसाइटें', 'Referers_Socials' => 'सामाजिक संजाल', 'Referers_AllReferersReportDocumentation' => 'इस रिपोर्ट में अपनी वेबसाइट खोजने के लिए अपने आगंतुकों द्वारा उपयोग किए गए सभी वेबसाइटों, खोज कीवर्ड और अभियान को सूचीबद्ध, एक एकीकृत रिपोर्ट में आपके सभी सन्दर्भदाता दिखाता है.', + 'Referers_WebsitesReportDocumentation' => 'इस तालिका में, आप अपनी वेबसाइट पर आगंतुकों को भेजने वाले वेबसाइट देख सकते हैं. तालिका में %s एक पंक्ति पर क्लिक करते हुए आप देख सकते हैं जो यूआरएल आपकी वेबसाइट के लिए लिंक किया गया है', 'Referers_SocialsReportDocumentation' => 'यह रिपोर्ट दिखाता है जो सामाजिक नेटवर्क आपकी वेबसाइट पर आगंतुकों का नेतृत्व किया.<br /> तालिका में एक पंक्ति पर क्लिक करते हुए आप देख सकते जिसमें सामाजिक नेटवर्क पृष्ठों से आगंतुकों को अपनी वेबसाइट पर आया था', 'Referers_Campaigns' => 'अभियान', + 'Referers_CampaignsReportDocumentation' => 'इस रिपोर्ट में आपकी वेबसाइट पर आगंतुकों का नेतृत्व किया जो अभियान से पता चलता है. ट्रैकिंग अभियान के बारे में %s अधिक जानकारी के लिए, piwik.org %sपर अभियान%s प्रलेखन पढ़ें', 'Referers_Evolution' => 'अवधि में विकास', 'Referers_Type' => 'संदर्भ प्रकार', 'Referers_TypeReportDocumentation' => 'इस तालिका में संदर्भ प्रकार के वितरण के बारे में जानकारी शामिल हैं.', 'Referers_DirectEntryDocumentation' => 'एक आगंतुक अपने ब्राउज़र में URL दर्ज किया है और आपकी वेबसाइट पर ब्राउज़िंग शुरू कर दी है - उन्होंने सीधे वेबसाइट में प्रवेश किया.', + 'Referers_SearchEnginesDocumentation' => 'एक आगंतुक एक खोज इंजन से आपकी वेबसाइट पर भेजा गया था. अधिक जानकारी के लिए %sरिपोर्ट देखें%s.', + 'Referers_WebsitesDocumentation' => 'आगंतुक अपनी साइट का नेतृत्व करने के लिए एक और वेबसाइट पर एक लिंक का पालन किया. %s अधिक जानकारी के लिए रिपोर्ट%s देखें.', + 'Referers_CampaignsDocumentation' => 'आगंतुकों जो एक अभियान के परिणाम के रूप में अपनी वेबसाइट पर आए. अधिक जानकारी के लिए %sरिपोर्ट %s देखें.', 'Referers_ColumnRefererType' => 'संदर्भ प्रकार', 'Referers_ColumnSearchEngine' => 'सर्च इंजिन', 'Referers_ColumnWebsite' => 'वेबसाइट', @@ -1048,13 +1254,19 @@ $translations = array( 'Referers_ColumnSocial' => 'सामाजिक संजाल', 'Referers_ColumnKeyword' => 'खोजशब्द', 'Referers_ColumnCampaign' => 'अभियान', + 'Referers_CampaignFooterHelp' => 'मदद: Piwik%s URL निर्माता उपकरण का अभियान %sट्रैकिंग', 'Referers_RefererName' => 'संदर्भ का नाम', 'Referers_DetailsByRefererType' => 'संदर्भ प्रकार से विवरण', + 'Referers_TypeDirectEntries' => '%s प्रत्यक्ष प्रविष्टियां', + 'Referers_TypeSearchEngines' => 'सर्च इंजन से %s', + 'Referers_TypeWebsites' => 'वेबसाइटों से %s', + 'Referers_TypeCampaigns' => 'अभियान से %s', 'Referers_Distinct' => 'संदर्भ प्रकार से अलग सन्दर्भदाता', 'Referers_DistinctSearchEngines' => 'विशिष्ट सर्च इंजन', 'Referers_DistinctKeywords' => 'विशिष्ट खोजशब्दों', 'Referers_DistinctCampaigns' => 'विशिष्ट अभियानों', 'Referers_DistinctWebsites' => 'विशिष्ट वेबसाइटों', + 'Referers_UsingNDistinctUrls' => '(%s विशिष्ट यूआरएल का उपयोग करके)', 'Referers_SubmenuOverview' => 'अवलोकन', 'Referers_SubmenuSearchEngines' => 'सर्च इंजन और खोजशब्द', 'Referers_SubmenuWebsites' => 'वेबसाइटों और सामाजिक', @@ -1087,19 +1299,36 @@ $translations = array( 'SEO_ExternalBacklinks' => 'बाह्य बैकलिंक (राजसी)', 'SEO_ReferrerDomains' => 'संदर्भ डोमेन (राजसी)', 'SEO_ViewBacklinksOnMajesticSEO' => 'MajesticSEO.com पर बाह्य बैकलिंक रिपोर्ट देखें', + 'SitesManager_PluginDescription' => 'Piwik में वेबसाइटों प्रबंधन: एक नई वेबसाइट में जोड़ें, एक मौजूदा एक संपादित करें, अपने पृष्ठों पर शामिल करने के लिए जावास्क्रिप्ट कोड दिखाएं. सभी कार्यों एपीआई के माध्यम से भी उपलब्ध हैं.', + 'SitesManager_Sites' => 'वेबसाइटें', + 'SitesManager_TrackingTags' => '%s के लिए ट्रैकिंग कोड', + 'SitesManager_WebsitesManagement' => 'वेबसाइटों के प्रबंधन', 'SitesManager_MainDescription' => 'आपकी वेब Analytics रिपोर्ट में वेबसाइट की जरूरत है! जोड़ें,अद्यतन,वेबसाइटें हटाने, और अपने पृष्ठों में सम्मिलित करने के लिए जावास्क्रिप्ट दिखाए.', + 'SitesManager_YouCurrentlyHaveAccessToNWebsites' => 'अपने वर्तमान में %s वेबसाइटों का उपयोग किया है.', + 'SitesManager_OnlyOneSiteAtTime_js' => 'आप केवल एक समय में एक वेबसाइट को संपादित कर सकते हैं. वेबसाइट %sके लिए अपने मौजूदा संशोधनों सहेजें या रद्द करें.', 'SitesManager_JsTrackingTag' => 'जावास्क्रिप्ट ट्रैकिंग कोड', 'SitesManager_JsTrackingTagHelp' => 'यहाँ जावास्क्रिप्ट ट्रैकिंग कोड आपके सभी पृष्ठों पर शामिल करने के लिए है', + 'SitesManager_ShowTrackingTag' => 'ट्रैकिंग कोड देखें', 'SitesManager_NoWebsites' => 'आपके पास प्रबंधन के लिए कोई भी वेबसाइट नहीं है.', 'SitesManager_AddSite' => 'एक नई वेबसाइट जोड़ें', 'SitesManager_NotFound' => 'वेबसाइटों के लिए नहीं मिला', + 'SitesManager_AliasUrlHelp' => 'यह सिफारिश की है, लेकिन आवश्यकता नहीं है, अपने दर्शकों के इस वेबसाइट का उपयोग करने के लिए उपयोग, विभिन्न यूआरएल, एक प्रति पंक्ति निर्दिष्ट करने के लिए है. एक वेबसाइट के लिए Alias यूआरएल सन्दर्भदाता वेबसाइटों रिपोर्ट में दिखाई नहीं देगा. यह Piwik स्वतः दोनों को समझता है \'www\' के साथ और बिना यूआरएल निर्दिष्ट करने की आवश्यक नहीं है कि ध्यान दें.', + 'SitesManager_Urls' => 'यूआरएल', 'SitesManager_MenuSites' => 'वेबसाइटें', + 'SitesManager_DeleteConfirm_js' => 'आपको यकीन है कि आप वेबसाइट%s को हटाना चाहते हैं?', + 'SitesManager_ExceptionDeleteSite' => 'यह केवल पंजीकृत वेबसाइट है जैसा कि इस वेबसाइट को हटाना संभव नहीं है. पहले एक नई वेबसाइट जोड़ें, तो यह नष्ट करे.', 'SitesManager_ExceptionNoUrl' => 'आपको वेबसाइट के लिए कम से कम एक URL निर्दिष्ट करना होगा.', 'SitesManager_ExceptionEmptyName' => 'वेबसाइट का नाम खाली नहीं हो सकता.', + 'SitesManager_ExceptionInvalidUrl' => 'यूआरएल \'%s\' एक मान्य URL नहीं है.', + 'SitesManager_ExceptionInvalidTimezone' => 'समय क्षेत्र "%s" मान्य नहीं है. एक वैध समयक्षेत्र दर्ज करें.', + 'SitesManager_ExceptionInvalidCurrency' => 'मुद्रा मान्य "%s" नहीं है. एक वैध मुद्रा प्रतीक (जैसे %s) दर्ज करें', + 'SitesManager_ExceptionInvalidIPFormat' => '"%s" को बाहर करने के लिए आईपी एक वैध आईपी प्रारूप (जैसे %s) नहीं है.', + 'SitesManager_SuperUserCan' => 'सुपर प्रयोक्ता भी नई वेबसाइट के लिए %sवैश्विक सेटिंग्स निर्दिष्ट%s कर सकते हैं.', 'SitesManager_ExcludedIps' => 'बहिष्कृत IP', 'SitesManager_GlobalListExcludedIps' => 'अपवर्जित आईपी की वैश्विक सूची', 'SitesManager_ExcludedUserAgents' => 'अपवर्जित प्रयोक्ता एजेंटों', 'SitesManager_GlobalListExcludedUserAgents' => 'बाहर करने के उपयोगकर्ता एजेंट की वैश्विक सूची', + 'SitesManager_GlobalListExcludedUserAgents_Desc' => 'यदि आपके द्वारा किसी भी आगंतुक के उपयोगकर्ता एजेंट स्ट्रिंग शामिल हैं, आगंतुक Piwik से बाहर रखा जाएगा।', 'SitesManager_GlobalExcludedUserAgentHelp1' => 'Piwik द्वारा ट्रैक किये जा रहे से बाहर करने के लिए उपयोगकर्ता एजेंटों की सूची दर्ज करें.', 'SitesManager_GlobalExcludedUserAgentHelp2' => 'आप ट्रैक किए जाने से बाहर रहने के लिए कुछ बॉट का उपयोग कर सकते हैं.', 'SitesManager_ListOfIpsToBeExcludedOnAllWebsites' => 'नीचे आईपी सभी वेबसाइटों पर ट्रैक किए जाने से बाहर रखा जाएगा.', @@ -1107,11 +1336,18 @@ $translations = array( 'SitesManager_GlobalListExcludedQueryParameters' => 'बाहर करने के प्रश्न यूआरएल मापदंडों की वैश्विक सूची', 'SitesManager_ListOfQueryParametersToBeExcludedOnAllWebsites' => 'नीचे प्रश्न यूआरएल मापदंडों को सभी वेबसाइटों को यूआरएल से बाहर रखा जाएगा.', 'SitesManager_ListOfQueryParametersToExclude' => 'URL प्रश्न पैरामीटर, एक प्रति पंक्ति, पृष्ठ यूआरएल रिपोर्टों से को बाहर करने की सूची दर्ज करें.', + 'SitesManager_PiwikWillAutomaticallyExcludeCommonSessionParameters' => 'Piwik स्वतः सामान्य सत्र के मापदंडों(%s) से अलग रहेगा', + 'SitesManager_HelpExcludedIps' => 'आप Piwik द्वारा नज़र रखे जाने से बाहर रखना चाहते हैं तो आईपी, एक प्रति पंक्ति की सूची दर्ज करें. आप वाइल्डकार्ड का उपयोग कर सकते हैं उदा. %1$s या %2$s', + 'SitesManager_YourCurrentIpAddressIs' => 'आपका मौजूदा आईपी पता %s है', 'SitesManager_SelectACity' => 'कोई नगर चुनें', 'SitesManager_ChooseCityInSameTimezoneAsYou' => 'आप के रूप में एक ही समय क्षेत्र में एक शहर चुनें.', + 'SitesManager_ChangingYourTimezoneWillOnlyAffectDataForward' => 'अपना समय क्षेत्र बदलना ही आगे जा रहे डेटा को प्रभावित करेगा, और पूर्वव्यापी प्रभाव से लागू नहीं किया जाएगा.', 'SitesManager_AdvancedTimezoneSupportNotFound' => 'उन्नत समय क्षेत्र समर्थन (PHP>=5.2 में समर्थन) आपके PHP में नहीं मिला. आप अभी भी एक मैनुअल यूटीसी ऑफसेट चुन सकते हैं.', + 'SitesManager_UTCTimeIs' => 'यूटीसी समय %s है.', + 'SitesManager_Timezone' => 'समय क्षेत्र', 'SitesManager_GlobalWebsitesSettings' => 'वैश्विक वेबसाइटों के सेटिंग्स', 'SitesManager_DefaultTimezoneForNewWebsites' => 'नई वेबसाइट के लिए तयशुदा समय क्षेत्र', + 'SitesManager_SelectDefaultTimezone' => 'आप नई वेबसाइट के लिए डिफ़ॉल्ट रूप से चयन करने के लिए समय क्षेत्र का चयन कर सकते हैं.', 'SitesManager_Currency' => 'मुद्रा', 'SitesManager_CurrencySymbolWillBeUsedForGoals' => 'मुद्रा प्रतीक लक्ष्य राजस्व के बगल में प्रदर्शित किया जाएगा.', 'SitesManager_DefaultCurrencyForNewWebsites' => 'नई वेबसाइट के लिए डिफ़ॉल्ट मुद्रा', @@ -1121,16 +1357,48 @@ $translations = array( 'SitesManager_EnableSiteSearch' => 'साइट खोज ट्रैकिंग सक्षम', 'SitesManager_DisableSiteSearch' => 'साइट खोज ट्रैक न करें', 'SitesManager_EcommerceHelp' => 'जब सक्रिय किया, "लक्ष्य" रिपोर्ट एक नया "ईकॉमर्स" खंड होगा.', + 'SitesManager_PiwikOffersEcommerceAnalytics' => 'Piwik ट्रैकिंग और रिपोर्टिंग उन्नत ईकॉमर्स एनालिटिक्स के लिए अनुमति देता है. %sईकॉमर्स एनालिटिक्स%s के बारे में अधिक जानें.', + 'SitesManager_TrackingSiteSearch' => 'आंतरिक साइट खोज ट्रैकिंग', + 'SitesManager_SiteSearchUse' => 'आप ट्रैक और आगंतुकों को अपनी वेबसाइट के आंतरिक खोज इंजन में क्या खोज रहे हैं रिपोर्ट करने के लिए Piwik उपयोग कर सकते हैं.', 'SitesManager_SearchKeywordParametersDesc' => 'साइट खोज कीवर्ड वाली सभी प्रश्न को पैरामीटर नाम की एक अल्पविराम से अलग सूची दर्ज करें.', 'SitesManager_SearchCategoryDesc' => 'Piwik भी एक आंतरिक साइट खोज कीवर्ड के लिए खोज श्रेणी ट्रैक कर सकता हैं.', 'SitesManager_SearchCategoryParametersDesc' => 'आप खोज श्रेणी को निर्दिष्ट करने क्वेरी पैरामीटर को एक अल्पविराम से अलग सूची दर्ज कर सकते हैं.', + 'SitesManager_SearchParametersNote' => 'नोट: क्वेरी पैरामीटर और श्रेणी मापदंडों वेबसाइटों के लिए ही इस्तेमाल किया जाएगा जो साइट खोज सक्षम लेकिन इन मानकों को खाली छोड़ दिया है.', 'SitesManager_SearchParametersNote2' => 'नई वेबसाइटों के लिए साइट खोज को निष्क्रिय करने के लिए, इन दो क्षेत्रों को खाली छोड़ दें.', 'SitesManager_SearchKeywordLabel' => 'प्रश्न पैरामीटर', 'SitesManager_SearchCategoryLabel' => 'श्रेणी पैरामीटर', + 'SitesManager_SearchUseDefault' => '%sडिफ़ॉल्ट%s साइट खोज मापदंडों का उपयोग करें', 'SitesManager_EnableSiteSpecificUserAgentExclude' => 'वेबसाइट विशिष्ट उपयोगकर्ता एजेंट बहिष्कार सक्षम करें.', + 'SitesManager_EnableSiteSpecificUserAgentExclude_Help' => 'अगर आप की जरूरत है अलग वेबसाइटों के लिए अलग अलग उपयोगकर्ता एजेंटों को बाहर करने की, इस बॉक्स की जाँच करें, सहेजें क्लिक करें और %1$sइसके बाद संस्करण उपयोगकर्ता एजेंट%2$s जोड़ें।', 'SitesManager_KeepURLFragments' => 'ट्रैकिंग पृष्ठ URL टुकड़े', + 'SitesManager_KeepURLFragmentsHelp' => 'यदि नीचे चेक बॉक्स अनियंत्रित है, पृष्ठ URL टुकड़े को (%1$s के बाद सब कुछ) जब ट्रैकिंग से निकाल दिया जाएगा: %2$s के %3$s रूप में नज़र रखी जाएगी', 'SitesManager_KeepURLFragmentsHelp2' => 'तुम भी ऊपर व्यक्तिगत वेबसाइटों के लिए इस सेटिंग को अध्यारोहित कर सकते हैं.', 'SitesManager_KeepURLFragmentsLong' => 'पृष्ठ यूआरएल ट्रैकिंग जब पृष्ठ URL टुकड़े रखो', + 'TranslationsAdmin_PluginDescription' => 'अपनी भाषा में Piwik अनुवाद में मदद करें.', + 'TranslationsAdmin_MenuTranslations' => 'अनुवाद', + 'TranslationsAdmin_MenuLanguages' => 'भाषाएँ', + 'TranslationsAdmin_LanguageCode' => 'भाषा कोड', + 'TranslationsAdmin_Plugin' => 'प्लगइन', + 'TranslationsAdmin_Definition' => 'परिभाषा', + 'TranslationsAdmin_DefaultString' => 'डिफ़ॉल्ट स्ट्रिंग (अंग्रेजी)', + 'TranslationsAdmin_TranslationString' => 'अनुवाद स्ट्रिंग (वर्तमान भाषा: %s)', + 'TranslationsAdmin_StatusOfStringsTranslated' => 'स्थिति: %1$s का %2$s स्ट्रिंग्स अनुवाद किया.', + 'TranslationsAdmin_Translations' => 'अनुवाद', + 'TranslationsAdmin_FixPermissions' => 'फाइल सिस्टम अनुमति तय करें', + 'TranslationsAdmin_AddLanguage' => 'भाषा जोड़ें', + 'TranslationsAdmin_Export' => 'भाषा निर्यात', + 'TranslationsAdmin_Import' => 'आयात भाषा', + 'TranslationsAdmin_ShowOnlyEmpty' => 'केवल लापता अनुवाद दिखाएं', + 'TranslationsAdmin_OptionalCountry' => 'वैकल्पिक देश', + 'TranslationsAdmin_TranslationAlreadyExists' => 'अनुवाद पहले से मौजूद है', + 'TranslationsAdmin_CannotOpenForWriting' => 'लेखन के लिए %s को नहीं खोल सकते हैं', + 'TranslationsAdmin_InvalidCountry' => 'अवैध देश', + 'TranslationsAdmin_InvalidLanguage' => 'अवैध भाषा', + 'UserCountry_Country' => 'देश', + 'UserCountry_Continent' => 'महाद्वीप', + 'UserCountry_City' => 'शहर', + 'UserCountry_DistinctCountries' => '%s विशिष्ट देशों', + 'UserCountry_country_ac' => 'उदगम द्वीप', 'UserCountry_country_ad' => 'अन्डोरा', 'UserCountry_country_ae' => 'संयुक्त अरब अमीरात', 'UserCountry_country_af' => 'अफ़गानिस्तान', @@ -1161,9 +1429,11 @@ $translations = array( 'UserCountry_country_bm' => 'बरमूडा', 'UserCountry_country_bn' => 'ब्रुनेई', 'UserCountry_country_bo' => 'बोलीविया', + 'UserCountry_country_bq' => 'बोनेयर, सिंट Eustatius और सबा', 'UserCountry_country_br' => 'ब्राजील', 'UserCountry_country_bs' => 'बहामा', 'UserCountry_country_bt' => 'भूटान', + 'UserCountry_country_bu' => 'बर्मा', 'UserCountry_country_bv' => 'बौवेत द्वीप', 'UserCountry_country_bw' => 'बोत्स्वाना', 'UserCountry_country_by' => 'बेलारूस', @@ -1180,19 +1450,23 @@ $translations = array( 'UserCountry_country_cm' => 'कैमरून', 'UserCountry_country_cn' => 'चीन', 'UserCountry_country_co' => 'कोलम्बिया', + 'UserCountry_country_cp' => 'क्लिपर्टन द्वीप', 'UserCountry_country_cr' => 'कोस्टारीका', 'UserCountry_country_cs' => 'सर्बिया व मॉण्टेनेग्रो', 'UserCountry_country_cu' => 'क्यूबा', 'UserCountry_country_cv' => 'कैप वर्डे', + 'UserCountry_country_cw' => 'करकाउ', 'UserCountry_country_cx' => 'क्रिसमस द्वीप', 'UserCountry_country_cy' => 'साइप्रस', 'UserCountry_country_cz' => 'चेक गणराज्य', 'UserCountry_country_de' => 'जर्मनी', + 'UserCountry_country_dg' => 'डिएगो गार्सिया', 'UserCountry_country_dj' => 'जिबूती', 'UserCountry_country_dk' => 'डेनमार्क', 'UserCountry_country_dm' => 'डोमिनिक', 'UserCountry_country_do' => 'डोमिनिकन गणराज्य', 'UserCountry_country_dz' => 'अल्जीरिया', + 'UserCountry_country_ea' => 'सेउटा, मेलिला', 'UserCountry_country_ec' => 'इक्वाडोर', 'UserCountry_country_ee' => 'एस्टोनिया', 'UserCountry_country_eg' => 'मिस्र', @@ -1200,12 +1474,14 @@ $translations = array( 'UserCountry_country_er' => 'इरिट्रिया', 'UserCountry_country_es' => 'स्पेन', 'UserCountry_country_et' => 'इथियोपिया', + 'UserCountry_country_eu' => 'यूरोपीय संघ', 'UserCountry_country_fi' => 'फिनलैंड', 'UserCountry_country_fj' => 'फिजी', 'UserCountry_country_fk' => 'फ़ॉकलैंड द्वीप', 'UserCountry_country_fm' => 'माइक्रोनेशिया', 'UserCountry_country_fo' => 'फरोए द्वीप', 'UserCountry_country_fr' => 'फ्रांस', + 'UserCountry_country_fx' => 'फ्रांस महानगर', 'UserCountry_country_ga' => 'गैबॉन', 'UserCountry_country_gb' => 'ब्रितन', 'UserCountry_country_gd' => 'ग्रेनेडा', @@ -1231,6 +1507,7 @@ $translations = array( 'UserCountry_country_hr' => 'क्रोशिया', 'UserCountry_country_ht' => 'हाइती', 'UserCountry_country_hu' => 'हंगरी', + 'UserCountry_country_ic' => 'कैनेरी आइलैंड', 'UserCountry_country_id' => 'इंडोनेशिया', 'UserCountry_country_ie' => 'आयरलैंड', 'UserCountry_country_il' => 'इसराइल', @@ -1300,6 +1577,7 @@ $translations = array( 'UserCountry_country_no' => 'नॉर्वे', 'UserCountry_country_np' => 'नेपाल', 'UserCountry_country_nr' => 'नाउरु', + 'UserCountry_country_nt' => 'तटस्थ क्षेत्र', 'UserCountry_country_nu' => 'नीयू', 'UserCountry_country_nz' => 'न्यूज़ीलैंड', 'UserCountry_country_om' => 'ओमान', @@ -1328,6 +1606,7 @@ $translations = array( 'UserCountry_country_sc' => 'सेशेल्स', 'UserCountry_country_sd' => 'सूडान', 'UserCountry_country_se' => 'स्वीडन', + 'UserCountry_country_sf' => 'फ़िनलैंड', 'UserCountry_country_sg' => 'सिंगापुर', 'UserCountry_country_sh' => 'सेंट हेलेना', 'UserCountry_country_si' => 'स्लोवेनिया', @@ -1338,10 +1617,14 @@ $translations = array( 'UserCountry_country_sn' => 'सेनेगल', 'UserCountry_country_so' => 'सोमालिया', 'UserCountry_country_sr' => 'सुरिनाम', + 'UserCountry_country_ss' => 'दक्षिण सूडान', 'UserCountry_country_st' => 'साउ-तोम-प्रिंसिप', + 'UserCountry_country_su' => 'पुराना U.S.S.R', + 'UserCountry_country_sx' => 'सिंट मार्टेन (डच भाग)', 'UserCountry_country_sv' => 'अल साल्वाडोर', 'UserCountry_country_sy' => 'सीरिया', 'UserCountry_country_sz' => 'सुआजीलैंड', + 'UserCountry_country_ta' => 'त्रिस्तान दा कुन्हा', 'UserCountry_country_tc' => 'तुर्क् और् कैकोज़ द्वीप', 'UserCountry_country_td' => 'चाड', 'UserCountry_country_tf' => 'फ़्रांसीसी दक्षिणी क्षेत्र', @@ -1353,13 +1636,16 @@ $translations = array( 'UserCountry_country_tm' => 'तुर्कमेनिस्तान', 'UserCountry_country_tn' => 'तुनिशिया', 'UserCountry_country_to' => 'टोंगा', + 'UserCountry_country_tp' => 'पूर्वी तिमोर', 'UserCountry_country_tr' => 'तुर्की', 'UserCountry_country_tt' => 'त्रिनिडाड और टोबैगो', 'UserCountry_country_tv' => 'तुवालु', 'UserCountry_country_tw' => 'ताइवान', 'UserCountry_country_tz' => 'तंजा़निया', + 'UserCountry_country_ti' => 'तिब्बत', 'UserCountry_country_ua' => 'यूक्रेन', 'UserCountry_country_ug' => 'युगांडा', + 'UserCountry_country_uk' => 'यूनाइटेड किंगडम', 'UserCountry_country_um' => 'युनाइटेड स्टेट्स माइनर आउटलाइंग द्वीपसमूह', 'UserCountry_country_us' => 'संयुक्त राज्य अमेरिका', 'UserCountry_country_uy' => 'युरूगुए', @@ -1375,9 +1661,48 @@ $translations = array( 'UserCountry_country_ws' => 'समोआ', 'UserCountry_country_ye' => 'यमन', 'UserCountry_country_yt' => 'मैयट', + 'UserCountry_country_yu' => 'यूगोस्लाविया', 'UserCountry_country_za' => 'दक्षिण अफ्रीका', 'UserCountry_country_zm' => 'जाम्बिया', + 'UserCountry_country_zr' => 'ज़ैरे', 'UserCountry_country_zw' => 'जिम्बाब्वे', + 'UserCountry_country_a2' => 'सैटेलाइट प्रदाता', + 'UserCountry_country_ap' => 'एशिया / प्रशांत क्षेत्र', + 'UserCountry_country_o1' => 'अन्य देश', + 'UserCountry_country_cat' => 'कैटलन भाषी समुदायों', + 'UserCountry_continent_eur' => 'यूरोप', + 'UserCountry_continent_afr' => 'अफ़्रीका', + 'UserCountry_continent_ant' => 'अंटार्टिका', + 'UserCountry_continent_asi' => 'एशिया', + 'UserCountry_continent_amn' => 'उत्तरी अमेरिका', + 'UserCountry_continent_amc' => 'मध्य अमेरिका', + 'UserCountry_continent_ams' => 'दक्षिण अमेरिका', + 'UserCountry_continent_oce' => 'ओशिनिया', + 'UserCountry_GeoIPDatabases' => 'GeoIP डेटाबेस', + 'UserCountry_DefaultLocationProviderDesc1' => 'एक आगंतुक का देश डिफ़ॉल्ट स्थान प्रदाता के अनुमान का इस्तेमाल वे भाषा के आधार पर करते है.', + 'UserCountry_DefaultLocationProviderDesc2' => 'यह बहुत सही नहीं है, तो %1$sहम स्थापित करने और %2$sGeoIP%3$s का उपयोग करना चाहिये.%4$s', + 'UserCountry_GeoIpLocationProviderDesc_Php1' => 'यह स्थान प्रदाता के रूप में स्थापित करने के लिए सबसे आसान है इसे सर्वर विन्यास (साझा होस्टिंग के लिए आदर्श!) की आवश्यकता नहीं है यह सही रूप में आपके आगंतुकों का स्थान निर्धारित करने के लिए एक GeoIP डेटाबेस और MaxMind के PHP एपीआई का उपयोग करता है.', + 'UserCountry_GeoIpLocationProviderDesc_Php2' => 'आपकी वेबसाइट पर यातायात बहुत हो जाता है, तो आप पाएंगे की यह स्थान प्रदाता धीमा है इस मामले में, आप %1$s PECL एक्सटेंशन %2$s या %3$s सर्वर मॉड्यूल %4$s को स्थापित करना चाहिए.', + 'UserCountry_GeoIpLocationProviderDesc_ServerBased1' => 'यह स्थान प्रदाता अपने HTTP सर्वर में स्थापित किया गया है जो GeoIP मॉड्यूल का उपयोग करता है. यह प्रदाता तेज और सटीक है, लेकिन %1$s स्कैन केवल सामान्य ब्राउज़र ट्रैकिंग के साथ इस्तेमाल किया जा सकता है .%2$s', + 'UserCountry_GeoIpLocationProviderDesc_ServerBased2' => 'आप लॉग इन फ़ाइलों को आयात या कुछ और करना है कि आईपी पतों को स्थापित करने की आवश्यकता हो, तो %1$s PECL GeoIP कार्यान्वयन (अनुशंसित) %2$s या %3$s PHP GeoIP कार्यान्वयन %4$s का उपयोग करें.', + 'UserCountry_CurrentLocationIntro' => 'इस प्रदाता के अनुसार, आपका वर्तमान स्थान है', + 'UserCountry_CannotFindPeclGeoIPDb' => 'GeoIP PECL मॉड्यूल के लिए एक देश, क्षेत्र या शहर डेटाबेस नहीं मिल सका. अपने GeoIP डेटाबेस %1$s में स्थित है और %2$s या %3$s नाम है अन्यथा PECL मॉड्यूल यह नोटिस नहीं होगा सुनिश्चित करें.', + 'UserCountry_GeoIpLocationProviderDesc_Pecl1' => 'यह स्थान प्रदाता एक GeoIP डेटाबेस और सही ढंग से और कुशलता से अपने आगंतुकों का स्थान निर्धारित करने के लिए एक PECL मॉड्यूल का उपयोग करता है.', + 'UserCountry_GeoIpLocationProviderDesc_Pecl2' => 'इस प्रदाता के साथ कोई सीमा नहीं है, तो यह हम उपयोग करने की सिफारिश करते है.', + 'UserCountry_GeoIPImplHasAccessTo' => 'इस GeoIP कार्यान्वयन का डेटाबेस के निम्नलिखित प्रकार के लिए उपयोग किया है', + 'UserCountry_CannotFindGeoIPServerVar' => '%s के चर स्थापित नहीं है. आपका सर्वर ठीक से कॉन्फ़िगर नहीं किया जा सकता है.', + 'UserCountry_GeoIPCannotFindMbstringExtension' => 'फ़ंक्शन %1$s नहीं मिल सकता है. विस्तार स्थापित और लोड किया जाता है%2$s सुनिश्चित करें.', + 'UserCountry_CannotLocalizeLocalIP' => 'आईपी पते %s में एक स्थानीय पता है और भू स्थित नहीं किया जा सकता.', + 'UserCountry_GeoIPDocumentationSuffix' => 'इस रिपोर्ट के लिए डेटा को देखने के लिए, आप जियोलोकेशन व्यवस्थापक टैब में GeoIP सेटअप चाहिए. वाणिज्यिक %1$sMaxmind%2$s GeoIP डेटाबेस मुक्त वालों की तुलना में अधिक सटीक हैं. वे कितने सटीक है देखने के लिए यहां %3$sक्लिक%4$s करें.', + 'UserCountry_AssumingNonApache' => 'गैर अपाचे वेबसर्वर मानते हुए, apache_get_modules फ़ंक्शन नहीं मिल सकता है.', + 'UserCountry_FoundApacheModules' => 'Piwik को निम्नलिखित अपाचे मॉड्यूल ने पाया', + 'UserCountry_DownloadingDb' => 'अधीभारण %s', + 'UserCountry_CannotSetupGeoIPAutoUpdating' => 'ऐसा लगता है (वहाँ उपनिर्देशिका विविध में कोई डेटाबेस नहीं है, लेकिन अपने GeoIP काम कर रहा है के बाद से हम बता सकते हैं) आप Piwik के बाहर अपने GeoIP डेटाबेस भंडारण कर रहे हैं वे विविध निर्देशिका के बाहर स्थित हैं अगर Piwik स्वचालित रूप से आपके GeoIP डेटाबेस अद्यतन नहीं कर सकता.', + 'UserCountry_CannotListContent' => '%1$s के लिए सामग्री की सूची नहीं कर सका: %2$s', + 'UserCountry_CannotFindGeoIPDatabaseInArchive' => 'टार अभिलेख %2$s में %1$s फाइल नहीं मिल सकता है!', + 'UserCountry_CannotUnzipDatFile' => '%1$s में .dat फ़ाइल खोली नहीं जा सकी: %2$s', + 'UserCountry_FatalErrorDuringDownload_js' => 'इस फाइल को डाउनलोड करते समय एक गंभीर त्रुटि हुई. आप डाउनलोड या Piwik GeoIP डेटाबेस के साथ, अपने इंटरनेट कनेक्शन के साथ कुछ गलत हो सकता है. डाउनलोड करने और इसे मैन्युअल रूप से स्थापित करने की कोशिश करें.', + 'UserCountry_DownloadNewDatabasesEvery' => 'हर डेटाबेस का अद्यतन', 'PDFReports_PluginDescription' => 'बनाएँ और डाउनलोड करें अपने विशिष्ट प्रतिवेदन, और उन्हें दैनिक, साप्ताहिक या मासिक ईमेल किया.', 'PDFReports_ManageEmailReports' => 'ईमेल प्रतिवेदन प्रबंधन', 'PDFReports_EmailReports' => 'ईमेल प्रतिवेदन', @@ -1394,8 +1719,12 @@ $translations = array( 'PDFReports_AggregateReportsFormat_TablesAndGraphs' => 'सभी रिपोर्टों के लिए रिपोर्ट तालिकाएँ और रेखांकन प्रदर्शित', 'PDFReports_DisplayFormat_TablesOnly' => 'केवल तालिकाएँ (कोई रेखांकन) प्रदर्शित करें', 'PDFReports_SentToMe' => 'मुझे भेजें', + 'PDFReports_EvolutionGraph' => 'शीर्ष %sमूल्यों के लिए ऐतिहासिक रेखाचित्र दिखाएँ', 'PDFReports_CreateAndScheduleReport' => 'एक रिपोर्ट तैयार करें और कार्यक्रम तय करे', + 'PDFReports_CancelAndReturnToReports' => 'रद्द करें और %sरिपोर्ट की सूची पर वापस%s जाए', 'PDFReports_DescriptionOnFirstPage' => 'रिपोर्ट विवरण रिपोर्ट के पहले पृष्ठ पर प्रदर्शित किया जाएगा.', + 'PDFReports_Segment_Help' => 'आप इस ईमेल रिपोर्ट में डेटा को लागू करने के लिए एक मौजूदा विशिष्ट खंड का चयन कर सकते हैं. तुम्हें अपने डैशबोर्ड में विशिष्ट खंडों %s(खोलने के लिए यहां क्लिक करें)%s बना सकते हैं और संपादित कर सकते हैं, तो "%s", फिर "%s" के बॉक्स पर क्लिक करें.', + 'PDFReports_Segment_Deletion_Error' => 'यह ईमेल रिपोर्ट (s)%s उत्पन्न करने के लिए प्रयोग किया जाता है इस कारण से इस खंड, हटाया नहीं जा सकता. वे इस खंड का उपयोग नहीं करते तो इस खंड को नष्ट करने के लिए, आपको पहले इन रिपोर्टों को संपादित कर सकते हैं.', 'PDFReports_WeeklyScheduleHelp' => 'साप्ताहिक कार्यक्रम: रिपोर्ट प्रत्येक सप्ताह के सोमवार को भेजी जाएगी.', 'PDFReports_MonthlyScheduleHelp' => 'मासिक अनुसूची: रिपोर्ट प्रत्येक माह के पहले दिन भेजी जाएगी.', 'PDFReports_ReportHour' => 'पर रिपोर्ट भेजें', @@ -1409,25 +1738,60 @@ $translations = array( 'PDFReports_EmailHello' => 'नमस्ते', 'PDFReports_PleaseFindAttachedFile' => 'संलग्न फाइल में %2$s के लिए अपने %1$s रिपोर्ट मिल दें', 'PDFReports_PleaseFindBelow' => '%2$s के लिए अपने %1$s रिपोर्ट के नीचे खोजे .', + 'PDFReports_SegmentAppliedToReports' => 'खंड \'%s\' को रिपोर्ट करने के लिए लागू किया जाता है.', 'PDFReports_CustomVisitorSegment' => 'विशिष्ट आगंतुक खंड', 'PDFReports_AreYouSureDeleteReport' => 'क्या आप इस रिपोर्ट को और इसके निर्धारित समय को हटाना चाहते हैं?', + 'PDFReports_ThereIsNoReportToManage' => '%s वेबसाइट के लिए प्रबंधन की कोई प्रतिवेदन नहीं है', 'PDFReports_MustBeLoggedIn' => 'तुम्हें विशिष्ट प्रतिवेदन बनाने और अनुसूची करने के लिए लॉग इन होना चाहिए.', 'PDFReports_FrontPage' => 'मुखपृष्ठ', 'PDFReports_TableOfContent' => 'प्रतिवेदन सूची', 'PDFReports_TopOfReport' => 'शीर्ष पर वापस जाएँ', 'PDFReports_Pagination' => '%s का %s पृष्ठ', + 'PDFReports_ReportIncludeNWebsites' => 'रिपोर्ट में कम से कम एक यात्रा (वेबसाइटों से %sवर्तमान में उपलब्ध) है कि सभी वेबसाइटों के मुख्य मैट्रिक्स शामिल होंगे.', 'PDFReports_TopLinkTooltip' => 'Piwik आँकड़े आपके ईमेल या स्वचालित रूप से आपके ग्राहकों के पते पर दिया प्राप्त करने के लिए ईमेल रिपोर्ट बनाएँ!', 'ImageGraph_PluginDescription' => 'किसी भी Piwik रिपोर्ट के लिए सुंदर स्थिर पीएनजी ग्राफ छवियों को उत्पन्न करता है.', + 'ImageGraph_ColumnOrdinateMissing' => 'स्तंभ \'%s\' इस रिपोर्ट में नहीं मिला था. किसी %sका प्रयास करें', 'RowEvolution_MetricsFor' => '%s के लिए मेट्रिक्स', 'RowEvolution_AvailableMetrics' => 'उपलब्ध मीट्रिक', 'RowEvolution_MetricBetweenText' => '%s और %s के बीच', 'RowEvolution_MetricChangeText' => 'अवधि %s से अधिक है', 'RowEvolution_Documentation' => 'विशाल विकास ग्राफ में उन्हें प्रदर्शित करने के लिए मेट्रिक्स क्लिक करें. प्रयोग एक ही बार में एकाधिक मैट्रिक्स प्रदर्शित करने के लिए शिफ्ट क्लिक करें.', 'RowEvolution_CompareRows' => 'रिकॉर्ड की तुलना करें', + 'RowEvolution_ComparingRecords' => 'पंक्तियों की %s तुलना करना', 'RowEvolution_CompareDocumentation' => 'नीचे दिए गए लिंक पर क्लिक करें और कई रिकॉर्ड की तुलना में एक ही तालिका से दूसरी पंक्ति के लिए इस पॉपअप को खोले .', 'RowEvolution_PickARow' => 'तुलना करने के लिए एक पंक्ति उठाओ', 'RowEvolution_PickAnotherRow' => 'तुलना करने के लिए एक और पंक्ति उठाओ', 'RowEvolution_MultiRowEvolutionTitle' => 'एकाधिक पंक्तियों का विकास', + 'Transitions_PluginDescription' => 'प्रत्येक पृष्ठ यूआरएल के लिए पिछले और अगले कार्यों के बारे में रिपोर्ट.', + 'Transitions_IncomingTraffic' => 'आने वाले यातायात', + 'Transitions_OutgoingTraffic' => 'निवर्तमान यातायात', + 'Transitions_XOfAllPageviews' => 'इस पृष्ठ के सभी दृश्यों का %s', + 'Transitions_ToInternalPages' => 'आंतरिक पृष्ठों के लिए', + 'Transitions_Including' => 'सहित', + 'Transitions_LoopsInline' => 'पृष्ठ पुनः लोड %s', + 'Transitions_XOutOfYVisits' => '%s (बाहर %s)', + 'Transitions_FromPreviousPages' => 'आंतरिक पृष्ठों से', + 'Transitions_FromPreviousPagesInline' => '%s आंतरिक पृष्ठों से', + 'Transitions_FromPreviousSiteSearches' => 'आंतरिक खोज से', + 'Transitions_FromPreviousSiteSearchesInline' => '%s आंतरिक खोजों से', + 'Transitions_ToFollowingSiteSearches' => 'आंतरिक खोजें', + 'Transitions_ToFollowingSiteSearchesInline' => '%s आंतरिक खोजें', + 'Transitions_ToFollowingPages' => 'आंतरिक पृष्ठ', + 'Transitions_ToFollowingPagesInline' => '%s आंतरिक पृष्ठ', + 'Transitions_DirectEntries' => 'सीधी प्रविष्टियां', + 'Transitions_PageviewsInline' => '%s पृष्ठ दृश्यों', + 'Transitions_FromSearchEngines' => 'खोज इंजन से', + 'Transitions_FromSearchEnginesInline' => '%s खोज इंजन से', + 'Transitions_FromWebsites' => 'वेबसाइटों से', + 'Transitions_FromWebsitesInline' => 'वेबसाइटों से %s', + 'Transitions_FromCampaigns' => 'अभियान से', + 'Transitions_FromCampaignsInline' => '%s अभियान से', + 'Transitions_ExitsInline' => '%s बाहर निकलता है', + 'Transitions_BouncesInline' => '%s उछाल', + 'Transitions_ShareOfAllPageviews' => 'यह पृष्ठ का %s पृष्ठ दृश्य (सभी पृष्ठ दृश्य का %s)किया था', + 'Transitions_NoDataForAction' => '%s के लिए कोई डेटा नहीं है', + 'Transitions_NoDataForActionDetails' => 'या तो कार्रवाई की अवधि %s के दौरान कोई पेज देखा गया था या यह अवैध है.', + 'Transitions_ErrorBack' => 'पिछली कार्रवाई के लिए वापस जाओ', 'Overlay_Overlay' => 'पृष्ठ आवरण', 'Overlay_PluginDescription' => 'आपकी वास्तविक वेबसाइट पर आच्छादन के रूप में एनालिटिक्स डेटा देखें.', 'Overlay_Location' => 'स्थिति', @@ -1435,8 +1799,12 @@ $translations = array( 'Overlay_NoData' => 'चयनित अवधि के दौरान इस पृष्ठ के लिए कोई डाटा नहीं है.', 'Overlay_OpenFullScreen' => 'पूर्ण स्क्रीन (कोई साइडबार नहीं ) के लिए जाओ', 'Overlay_OneClick' => '1 क्लिक करें', + 'Overlay_Clicks' => '%s क्लिक करता है', + 'Overlay_ClicksFromXLinks' => '%1$s एक %2$sलिंक से क्लिक करता है', 'Overlay_Link' => 'लिंक', + 'Overlay_RedirectUrlError' => 'आप यूआरएल "%s" के लिए पृष्ठ आवरण खोलने के लिए प्रयास कर रहे हैं. Piwik सेटिंग से डोमेन में से कोई%s भी लिंक से मेल नहीं खाता है.', 'Overlay_RedirectUrlErrorUser' => 'एक अतिरिक्त URL के रूप में डोमेन को जोड़ने के लिए अपने व्यवस्थापक से पूछें.', + 'Overlay_RedirectUrlErrorAdmin' => 'आप सेटिंग्स%s से एक अतिरिक्त URL%s के रूप में डोमेन जोड़ सकते हैं', 'Overlay_Domain' => 'डोमेन', 'Overlay_ErrorNotLoading' => 'पृष्ठ आवरण सत्र अभी तक शुरू नहीं किया जा सका.', 'Overlay_ErrorNotLoadingDetails' => 'शायद दाएँ तरफ लोड किया पृष्ठ पर Piwik ट्रैकर कोड नहीं है. इस मामले में, पृष्ठों की रिपोर्ट से एक अलग पेज के लिए आवरण शुरू करने का प्रयास करें.', @@ -1449,12 +1817,16 @@ $translations = array( 'Annotations_IconDescHideNotes_js' => 'इस समय अवधि के लिए नोट्स छुपाये .', 'Annotations_NoAnnotations' => 'स्पष्ट की गयी तारीख की सीमा के लिए कोई टिपण्णी मौजूद नहीं है।', 'Annotations_InlineQuickHelp' => 'आप विशेष घटनाओं (जैसे की नया ब्लॉग पोस्ट या वेबसाइट को पुनः डिज़ाइन करना) को अंकित करने के लिए या अपने डेटा के विश्लेषण अथवा ऐसी कोई भी चीज़ जो कि आप के अनुसार महत्वपूर्ण है को सुरक्षित रखने के लिए टिप्पणियों का प्रयोग कर सकते हैं।', + 'Annotations_ViewAndAddAnnotations_js' => '%s टिप्पणियां देखें और जोड़...', + 'Annotations_HideAnnotationsFor_js' => '%s एनोटेशन छुपाएं...', + 'Annotations_AddAnnotationsFor_js' => '%s एनोटेशन जोड़ें', 'Annotations_ClickToEdit' => 'इस टिपण्णी में बदलाव करने के लिए क्लिक करें।', 'Annotations_ClickToDelete' => 'इस टिपण्णी को हटाने के लिए क्लिक करें।', 'Annotations_ClickToStarOrUnstar' => 'इस टिप्पणी को स्टार या अतारांकित करने के लिए क्लिक करें.', 'Annotations_YouCannotModifyThisNote' => 'आप इस टिपण्णी में परिवर्तन नहीं कर सकते हैं क्योंकि न तो आपने इसके लेखक हैं और न ही आपके पास इस साइट के लिए एडमिन एक्सेस है।', 'Annotations_CreateNewAnnotation' => 'नयी टिपण्णी बनाएं।', 'Annotations_LoginToAnnotate' => 'नयी टिपण्णी बनाने के लिए लौग इन करें।', + 'Annotations_AnnotationOnDate' => '%1$s एनोटेशन तारीख: %2$s', 'Annotations_ClickToEditOrAdd' => 'टिपण्णी में बदलाव करने के लिए या नयी टिपण्णी बनाने के लिए क्लिक करें।', 'UserLanguage_Language_aa' => 'अफ़ार', 'UserLanguage_Language_ab' => 'अब्खाज़ियन्', @@ -1648,6 +2020,7 @@ $translations = array( 'SegmentEditor_OperatorAND' => 'और', 'SegmentEditor_OperatorOR' => 'या', 'SegmentEditor_DefaultAllVisits' => 'सभी का दौरा', + 'SegmentEditor_AddANDorORCondition' => 'शर्त %s जोड़ें', 'SegmentEditor_ThisSegmentIsVisibleTo' => 'इस खंड के लिए दिख रहा है:', 'SegmentEditor_VisibleToMe' => 'मुझे', 'SegmentEditor_VisibleToAllUsers' => 'सभी उपयोगकर्ताओं', diff --git a/lang/id.php b/lang/id.php index 47dfff0563..4476cccd60 100644 --- a/lang/id.php +++ b/lang/id.php @@ -1068,7 +1068,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik merupakan piranti lunak analisa ramatraya yang memudahkan Anda mendapatkan informasi yang diinginkan dari pengunjung.</p><p>Proses ini dibagi menjadi %s langkah mudah dan membutuhkan sekitar 5 menit.</p>', 'Installation_ConfigurationHelp' => 'Tampaknya berkas konfigurasi Piwik Anda terdapat kesalahan. Anda dapat menghapus config/config.ini.php dan melanjutkan instalasi, atau memperbaiki pengaturan sambungan basisdata.', 'Installation_ErrorInvalidState' => 'Galat: tampaknya Anda mencoba melewati proses Instalasi, atau kuki Anda telah dimatikan, atau berkas konfigurasi Piwik telah tersedia. %1$sPeriksalah apakah kuki Anda telah aktif kemudian %2$s kembali %3$s ke halaman pertama instalasi %4$s.', - 'Installation_InsufficientPrivileges' => 'Kekurangan hak akses. Pengguna basisdata harus memiliki hak akses berikut: %s', 'Installation_InsufficientPrivilegesHelp' => 'Anda dapat menambah hak akses tersrbut menggunakan perangkat seperti phpMyAdmin atau mengeksekusi kueri SQL yang sesuai. Apabila Anda tak mengetahui bagaimana melakukannya, harap bertanya kepada pengurus sistem Anda untuk memperoleh hak tersebut.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Uh-oh! Piwik mendeteksi beberapa %1$spermsalahan kritis%2$s dalam with your Piwik setup. %3$sPermasalahan tersebut harus segera diperbaiki segera.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Terdapat beberapa permasalahan dalam sistem Anda. Piwik akan berjalan, tetapi Anda mungkin mengalami beberapa permasalahan kecil.', diff --git a/lang/it.php b/lang/it.php index e0306eecbe..9f97b08a79 100644 --- a/lang/it.php +++ b/lang/it.php @@ -973,7 +973,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik è un software open source che ti permette di analizzare facilmente le informazioni dei visitatori che visitano i tuoi siti web.</p><p>Questa procedura si divide in %s semplici passaggi e si completa nel giro di 5 minuti.</p>', 'Installation_ConfigurationHelp' => 'Il tuo file di configurazioni Piwik sembra essere configurato male. Puoi rimuovere il file config/config.ini.php e ricominciare l\'installazione, o correggere i dati di connessione al database.', 'Installation_ErrorInvalidState' => 'Errore: sembra che stai tentando di saltare un passaggio del processo di installazione, i tuoi Cookies sono disabilitati o il file di configurazione Piwik è stato già creato. %1$sControlla che i Cookies siano attivati%2$s e %3$s ripeti l\'installazione dal primo passaggio %4$s.', - 'Installation_InsufficientPrivileges' => 'Privilegi insufficienti. L\' utente del database deve disporre dei seguenti privilegi: %s', 'Installation_InsufficientPrivilegesHelp' => 'È possibile aggiungere questi privilegi utilizzando uno strumento come phpMyAdmin o per l\'esecuzione di corrette query SQL. Se non sai come fare queste cose, chiedi al tuo amministratore di sistema di concederti questi privilegi.', 'Installation_Filesystem' => 'Filesystem', 'LanguagesManager_PluginDescription' => 'Questo plugin mostrerà la lista delle lingue disponibili per l\'interfaccia Piwik. La lingua selezionata sarà salvata nelle preferenze per ciascun utente.', diff --git a/lang/ja.php b/lang/ja.php index 08e1ba76eb..9a691f1607 100644 --- a/lang/ja.php +++ b/lang/ja.php @@ -396,6 +396,7 @@ $translations = array( 'API_UsingTokenAuth' => '%sスクリプト(crontab 等)でリクエストデータを得たい場合%sは、API をコールする URL(認証が必要)にパラメータ %s を付加する必要があります。', 'API_KeepTokenSecret' => 'token_auth は、ログイン名とパスワードのように秘密にし、%s絶対に共有しないでください%s!', 'API_LoadedAPIs' => '%s API が正常に読み込まれました', + 'API_TopLinkTooltip' => 'jsopn、xml等シンプルなAPIを介して、プログラムで分析データにアクセスできます', 'CoreAdminHome_PluginDescription' => 'Piwik の管理エリアです。', 'CoreAdminHome_MenuGeneralSettings' => '全般の設定', 'CoreAdminHome_Administration' => '管理', @@ -418,6 +419,7 @@ $translations = array( 'CoreAdminHome_LogoUpload' => 'アップロードするロゴを選択', 'CoreAdminHome_LogoUploadDescription' => 'ファイルは %s フォーマット、透明背景なし、最小高さ %s ピクセルでアップロードしてください。', 'CoreAdminHome_LogoNotWriteable' => 'カスタムロゴを使用するにはthemesディレクトリ:%s の中のロゴファイルへの書き込み権限が必要です。', + 'CoreAdminHome_CheckReleaseGetVersion' => 'Piwikの新バージョンをチェックする時に常に取得するのは', 'PrivacyManager_TeaserHeadline' => 'プライバシー設定', 'PrivacyManager_Teaser' => 'このページでは、既存の法律にのっとり、Piwikがプライバシーに準拠するようカスタマイズすることができます:%s 匿名の訪問者のIPアドレス %s、%s 自動的にデータベースから古いビジターのログを削除 %s、%sウェブサイトをオプトアウトする仕組みの提供%s による。', 'PrivacyManager_MenuPrivacySettings' => 'プライバシー', @@ -886,7 +888,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik は、ビジターからあなたが必要とする情報を収集することを容易にする、オープンソースのウェブ解析ソフトウェアです。</p><p>この処理は %s の簡単なステップに分かれていて、5分程度で完了します。</p>', 'Installation_ConfigurationHelp' => 'Piwik 設定ファイルが誤設定されているようです。 config/config.ini.php を削除してインストールを再開するか、データベースの接続設定を修正してください。', 'Installation_ErrorInvalidState' => 'エラー: インストール処理のステップを省略しようとしたか、Cookie が無効か、Piwik 設定ファイルがすでに作成されています。%1$sCookie が有効になっていることを確認してから%2$s、%3$sインストールの最初のページ%4$sに戻ってください。', - 'Installation_InsufficientPrivileges' => '権限が不十分です。データベースユーザーには以下の権限が必要です: %s', 'Installation_InsufficientPrivilegesHelp' => 'phpMyAdminのようなツールを使用するか、正しいSQLクエリを実行することにより、これらの権限を追加できます。やり方がわからない場合は、システム管理者に依頼して、権限を付与してもらってください。', 'LanguagesManager_PluginDescription' => 'Piwik インターフェイスで利用可能な言語リストを表示します。 選択された言語は、各ユーザーの優先設定に保存されます。', 'LanguagesManager_AboutPiwikTranslations' => 'Piwik の翻訳について', @@ -1566,16 +1567,22 @@ $translations = array( 'PDFReports_TopOfReport' => 'トップへ戻る', 'PDFReports_Pagination' => 'Page %s of %s', 'ImageGraph_PluginDescription' => 'Piwikリポートの美しい静的PNGグラフ画像を生成します。', + 'Annotations_PluginDescription' => 'あなたのウェブサイトの変更を日毎にメモを付けることができます。データの分析結果を記録し、仲間と互いに考えを共有しましょう。注釈を付けることによって、なぜデータがそうなっているのかを思い出す手助けになるでしょう。', 'Annotations_Annotations' => '注釈', 'Annotations_EnterAnnotationText' => 'メモを入力して下さい', 'Annotations_IconDesc_js' => 'この期間内のメモを参照する', 'Annotations_IconDescHideNotes_js' => 'この期間内のメモを隠す', + 'Annotations_NoAnnotations' => 'この期間内の注釈はありません', + 'Annotations_InlineQuickHelp' => 'データの分析結果や重要と思うものを記録するのに、特別なイベントとして注釈を作成できます(新しいブログの投稿、ウェブサイトのリニューアルなど)。', + 'Annotations_ViewAndAddAnnotations_js' => '%sの注釈の表示と追加', 'Annotations_HideAnnotationsFor_js' => '%sの注釈を隠す…', 'Annotations_AddAnnotationsFor_js' => '%sの注釈を追加…', 'Annotations_ClickToEdit' => 'クリックしてこの注釈を編集', 'Annotations_ClickToDelete' => 'クリックしてこの注釈を削除', 'Annotations_ClickToStarOrUnstar' => 'クリックして注釈に星印を付ける、または外す', + 'Annotations_YouCannotModifyThisNote' => 'この注釈は変更できません。あなたが生成した注釈ではないか、このサイトの管理者権限がないからです', 'Annotations_CreateNewAnnotation' => '新しい注釈を作成する', + 'Annotations_LoginToAnnotate' => 'ログインして注釈を作成する', 'Annotations_AnnotationOnDate' => '%1$sの注釈: %2$s', 'Annotations_ClickToEditOrAdd' => 'クリックして新しい注釈を編集または作成', 'UserLanguage_Language_aa' => 'アファル語', diff --git a/lang/ko.php b/lang/ko.php index cf907a16f6..c463fc11e3 100644 --- a/lang/ko.php +++ b/lang/ko.php @@ -992,7 +992,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik 은 오픈 소스 웹 분석 소프트웨어로써 쉽고 원하는 정보를 당신의 방문자들로부터 얻을 수 있게 해줍니다.</p><p>이 과정은 %s 의 쉬운 단계로 나뉘어 있고 5분 정도만 소요됩니다.</p>', 'Installation_ConfigurationHelp' => 'Piwik 설정 파일이 잘못 설정되어있는 것 같습니다. config/config.ini.php를 제거하고 설치를 다시 시작하거나 데이터베이스의 연결 설정을 수정하세요.', 'Installation_ErrorInvalidState' => '에러: 설치 과정의 단계를 뛰어넘으려고 하는 것 같습니다, 또는 쿠키가 비활성화거나, 또는 Piwik 설정 파일이 이미 생성되었습니다. %1$s쿠키가 활성화되어 있는지 확인하시고%2$s 설치 첫페이지로 %3$s 돌아가세요 %4$s.', - 'Installation_InsufficientPrivileges' => '권한이 부족합니다. 데이터베이스 사용자에게 다음 권한이 있어야합니다: %s', 'Installation_InsufficientPrivilegesHelp' => 'phpMyAdmin 같은 도구를 사용하거나 올바른 SQL 쿼리를 실행하여 이러한 권한을 추가 할 수 있습니다. 방법을 잘 모를 경우 시스템 관리자에게 문의하여 권한을 부여 받으세요.', 'Installation_SystemCheckSummaryThereWereErrors' => '헐! Piwik 설정에서 일부 %1$s심각한 오류%2$s를 감지했습니다. %3$s이 문제는 즉시 해결해야합니다.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => '시스템에 몇몇 문제가 있습니다. Piwik가 설치되었지만 몇가지 사소한 문제가 발생할 수 있습니다.', diff --git a/lang/nb.php b/lang/nb.php index 4d46328bef..ea757755aa 100644 --- a/lang/nb.php +++ b/lang/nb.php @@ -678,7 +678,6 @@ $translations = array( 'Installation_Welcome' => 'Velkommen!', 'Installation_WelcomeHelp' => '<p>Piwik er åpen kildekode nettstatistikk-programvare som gjør det enkelt å finne informasjonen du ønsker om dine besøkende.</p><p>Denne prossessen er delt opp i %s lette steg og vil ta ca 5 minutter.</p>', 'Installation_ErrorInvalidState' => 'Feil: Det ser ut som om du prøver å hoppe over et steg i installasjonsprosessen eller informasjonskapsler (cookies) er deaktivert eller Piwik sin konfigurasjon er allerede opprettet. %1$sForsikre deg om at du har aktivert informasjonskapsler%2$s og gå tilbake %3$s til første side av installasjonen %4$s.', - 'Installation_InsufficientPrivileges' => 'Utilstrekkelige rettigheter. Brukeren må ha følgende rettigheter: %s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Det er noen problemer med systemet ditt. Piwik vil kjøre, men du kan oppleve noen mindre problemer.', 'Installation_SystemCheckSummaryNoProblems' => 'Hurra! Det er ingen problemer med ditt Piwik-oppsett. Gi deg selv et klapp på skulderen.', 'Installation_SeeBelowForMoreInfo' => 'Se nedenfor for mer informasjon.', diff --git a/lang/nl.php b/lang/nl.php index d6e669bfe0..e876d91c3b 100644 --- a/lang/nl.php +++ b/lang/nl.php @@ -974,7 +974,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik is een open source web analytics software pakket die u op simpele wijze de gegevens van uw bezoekers presenteert.</p><p>Dit proces is opgedeeld in %s simpele stappen welke ongeveer 5 minuten in beslag nemen.</p>', 'Installation_ConfigurationHelp' => 'Uw Piwik configuratie bestand is waarschijnlijk niet correct geconfigureerd. U kunt ofwel config/config.ini.php verwijderen en de installatie vervolgen of de toegangsgegevens voor de database corrigeren.', 'Installation_ErrorInvalidState' => 'Fout: Het lijkt erop dat u probeerde een stap van het installatieproces over te slaan, of dat cookies uitgeschakeld zijn, of dat uw Piwik configuratie bestand reeds was aangemaakt. %1$s Zorg ervoor dat uw cookies zijn ingeschakeld%2$s en ga terug %3$s naar de eerste pagina van de installatie %4$s.', - 'Installation_InsufficientPrivileges' => 'Onvoldoende privileges. De databasegebruiker dient de volgende privileges te hebben: %s', 'Installation_InsufficientPrivilegesHelp' => 'U kunt deze privileges toeveoegen door gebruik te maken van een tool als phpMyAdmin of door het uitvoeren van de juiste SQL queries. Als u niet weet hoe dit moet, dan kunt u het beste de beheerder van uw webserver vragen om de privileges aan te passen.', 'Installation_SeeBelowForMoreInfo' => 'Zie hieronder voor meer informatie.', 'Installation_Filesystem' => 'Bestandsssysteem', diff --git a/lang/pt-br.php b/lang/pt-br.php index d929861bbf..ae11fa6d4e 100644 --- a/lang/pt-br.php +++ b/lang/pt-br.php @@ -709,9 +709,13 @@ $translations = array( 'CoreHome_MakeOneTimeDonation' => 'Em vez disso, faça uma doação.', 'CorePluginsAdmin_PluginDescription' => 'Interface de Administração de Plugins', 'CorePluginsAdmin_Plugins' => 'Plugins', + 'CorePluginsAdmin_Themes' => 'Temas', 'CorePluginsAdmin_PluginsManagement' => 'Gerenciamento de plugins', + 'CorePluginsAdmin_ThemesManagement' => 'Gerenciar Temas', 'CorePluginsAdmin_MainDescription' => 'Plugins estendem e expandem a funcionalidade do Piwik. Uma vez que um plugin for instalado, você pode ativá-lo ou desativá-lo aqui.', + 'CorePluginsAdmin_ThemesDescription' => 'Os temas podem alterar a aparência da interface do usuário do Piwik, e fornecer uma experiência completamente nova visual para desfrutar dos seus relatórios de análise.', 'CorePluginsAdmin_Plugin' => 'Plugin', + 'CorePluginsAdmin_Theme' => 'Tema', 'CorePluginsAdmin_Version' => 'Versão', 'CorePluginsAdmin_Status' => 'Status', 'CorePluginsAdmin_Action' => 'Ação', @@ -723,6 +727,8 @@ $translations = array( 'CorePluginsAdmin_Inactive' => 'Inativo', 'CorePluginsAdmin_Deactivate' => 'Desativar', 'CorePluginsAdmin_Activate' => 'Ativar', + 'CorePluginsAdmin_MenuPlatform' => 'Plataforma', + 'CorePluginsAdmin_MenuExtend' => 'Extender', 'CorePluginsAdmin_PluginCannotBeFound' => 'Este plugin não pode ser encontrado!', 'CoreUpdater_PluginDescription' => 'Mecanismo de update Piwik', 'CoreUpdater_UpdateTitle' => 'Atualiza', @@ -1068,7 +1074,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik é um analisador de tráfego open source que torna fácil obter informações sobre os seus visitantes.</p><p>Este processo é dividido em %s passos fáceis e irá demorar por volta de 5 minutos.</p>', 'Installation_ConfigurationHelp' => 'Seu arquivo de configuração Piwik parece estar desconfigurado. Você pode ou remover config/config.ini.php e fechar a instalação, ou corrigir as configurações de conexão com banco de dados.', 'Installation_ErrorInvalidState' => 'Erro: parece que você está tentando pular um passo do processo de instalação, ou seus cookies estão desligados, ou o arquivo de configuração do Piwik já foi criado. %1$sTenha certeza de que seus cookies estão ativados%2$s e volte %3$spara a página inicial da instalação%4$s.', - 'Installation_InsufficientPrivileges' => 'Privilégios insuficientes. Usuário de banco de dados deve ter os seguintes privilégios: %s', 'Installation_InsufficientPrivilegesHelp' => 'Você pode adicionar esses privilégios usando uma ferramenta como o phpMyAdmin ou executando as consultas SQL de permissões. Se você não sabe como fazer essas coisas, por favor, peça ao seu sysadmin para conceder esses privilégios para você.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Uh-oh! Piwik detectou algunas %1$squestões críticas%2$s com as suas configurações. %3$s Estas questões devem ser corrigidas imediatamente. %4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Existem alguns problemas com o seu sistema. Piwik será executado, mas você pode experimentar alguns problemas menores.', diff --git a/lang/ro.php b/lang/ro.php index 09ce4987f6..5a58907a7d 100644 --- a/lang/ro.php +++ b/lang/ro.php @@ -6,7 +6,7 @@ $translations = array( 'General_EnglishLanguageName' => 'Romanian', 'General_OriginalLanguageName' => 'Română', 'General_LayoutDirection' => 'ltr', - 'General_HelloUser' => 'Salut, %s!', + 'General_HelloUser' => 'Să trăieşti, %s!', 'General_OpenSourceWebAnalytics' => 'Analiza trafic web sursa libera', 'General_Dashboard' => 'Panoul de control', 'General_DashboardForASpecificWebsite' => 'Panol de control pentru un site', @@ -14,7 +14,7 @@ $translations = array( 'General_AllWebsitesDashboard' => 'Panoul de control pentru toate site-urile', 'General_API' => 'API', 'General_Widgets' => 'Dispozitive', - 'General_Settings' => 'Setari', + 'General_Settings' => 'Setări', 'General_GiveUsYourFeedback' => 'Trimite sesizarii!', 'General_Unknown' => 'Necunoscut', 'General_Never' => 'Niciodata', @@ -41,7 +41,8 @@ $translations = array( 'General_Close' => 'Inchide', 'General_Cancel' => 'Anulează', 'General_OrCancel' => 'sau %s Anuleaza %s', - 'General_Logout' => 'Iesire', + 'General_And' => 'şi', + 'General_Logout' => 'Ieşire', 'General_Username' => 'Nume utilizator', 'General_Description' => 'Descriere', 'General_Done' => 'Gata', @@ -78,12 +79,13 @@ $translations = array( 'General_DaysSinceFirstVisit' => 'Zile de la prima vizita', 'General_DaysSinceLastEcommerceOrder' => 'Zile de la ultima comanda', 'General_NumberOfVisits' => 'Numar de vizite', - 'General_VisitConvertedGoal' => 'Vizite care au convertit in cel putin un Scop', - 'General_VisitConvertedGoalId' => 'Vizite care au convertit intr-un anumit Scop', - 'General_VisitConvertedNGoals' => 'Vizite convertite in %s scopuri', + 'General_VisitConvertedGoal' => 'Vizită care a atins cel putin o ţintă', + 'General_VisitConvertedGoalId' => 'Vizită care a atins o ţintă anumită', + 'General_VisitConvertedNGoals' => 'Vizita a atins %s ţinte', 'General_NewVisitor' => 'Vizitator nou', 'General_NewVisits' => 'Vizite noi', 'General_ReturningVisitor' => 'Vizitator ce revine', + 'General_ReturningVisitorAllVisits' => 'Vezi toate vizitele', 'General_Visitor' => 'Vizitator', 'General_Date' => 'Data', 'General_Period' => 'Perioada', @@ -100,6 +102,7 @@ $translations = array( 'General_InvalidDateRange_js' => 'Interval invalid, va rugam mai incercati', 'General_DateRangeFrom_js' => 'De la', 'General_DateRangeTo_js' => 'la', + 'General_LastDaysShort' => 'Ultimele %s zile', 'General_PreviousDays' => 'Ultimele %s zile (excluzand azi)', 'General_LastDays' => 'Ultimele %s zile (incluzand azi)', 'General_LoadingData' => 'Se incarca datele...', @@ -148,7 +151,7 @@ $translations = array( 'General_ColumnBounceRateDocumentation' => 'Procentajul de vizite care au avut o singura afisare. Vizitatorul a parasit site-ul direct de la pagina de intrare', 'General_ColumnBounceRateForPageDocumentation' => 'Procentajul de vizite care au inceput si s-au terminat pe aceasta pagina', 'General_ColumnPageBounceRateDocumentation' => 'Procentajul de vizite care au inceput pe aceasta pagina si au parasit imediat site-ul', - 'General_ColumnExitRate' => 'Rata de iesire', + 'General_ColumnExitRate' => 'Rata de ieşire', 'General_ColumnExitRateDocumentation' => 'Procentajul de vizite care au parasit site-ul dupa ce au vizualizat aceasta pagina', 'General_ColumnPageviews' => 'Pagini vizualizate', 'General_ColumnPageviewsDocumentation' => 'De cate ori a fost vizitata pagina', @@ -163,6 +166,7 @@ $translations = array( 'General_ColumnUniqueExits' => 'Iesiri unice', 'General_ColumnExitsDocumentation' => 'Numarul de vizite care s-au terminat pe aceasta pagina', 'General_ColumnAverageTimeOnPage' => 'Timp mediu pe pagina', + 'General_TimeOnPage' => 'Timp pe pagină', 'General_ColumnAverageTimeOnPageDocumentation' => 'Timpul mediu pe care vizitatorii il petrec pe aceasta pagina', 'General_ColumnValuePerVisit' => 'Venit per vizita', 'General_ColumnVisitsWithConversions' => 'Vizite cu conversii', @@ -177,7 +181,7 @@ $translations = array( 'General_ForExampleShort' => 'ex.', 'General_YouMustBeLoggedIn' => 'Trebuie sa fiti logat pentru a accesa aceasta functionalitate.', 'General_Website' => 'Website', - 'General_GeneralSettings' => 'Setari generale', + 'General_GeneralSettings' => 'Setări generale', 'General_AllowPiwikArchivingToTriggerBrowser' => 'Permite arhivare Piwik sa porneasca atunci cand rapoartele sunt vizualizate din browser.', 'General_ArchivingInlineHelp' => 'Pentru site-uri cu trafic mediu sau mare, este recomandata dezactivarea arhivari Piwik din browser. Recomandat sa faceti setup la un cron job pentru a procesa rapoarte Piwik in fiecare ora', 'General_ArchivingTriggerDescription' => 'Recomandat pentru instalari mari, trebuie sa %ssetup un cron job%s pentru procesarea automata a rapoartelor', @@ -193,7 +197,7 @@ $translations = array( 'General_DataForThisTagCloudHasBeenPurged' => 'Datele din acest nor de etichete sunt mai vechi de %s luni şi au fost curăţate.', 'General_DisplaySimpleTable' => 'Afisarea unui tabel simplu', 'General_DisplayTableWithMoreMetrics' => 'Afisarea unui tabel cu mai multi metrici', - 'General_DisplayTableWithGoalMetrics' => 'Afisarea unui tabel cu scopurile', + 'General_DisplayTableWithGoalMetrics' => 'Afişează tabelul cu parametrii ţintelor', 'General_YouAreViewingDemoShortMessage' => 'Vizualizati o versiune demo a Piwik', 'General_YouAreCurrentlyUsing' => 'Foloseşti Piwik %s.', 'General_DownloadFullVersion' => '%1$sDescarcati%2$s versiunea full! Accesati %3$s', @@ -247,6 +251,10 @@ $translations = array( 'General_Daily' => 'Zilnic', 'General_Weekly' => 'Saptamanal', 'General_Monthly' => 'Lunar', + 'General_DailyReport' => 'zilnic', + 'General_WeeklyReport' => 'săptămânal', + 'General_MonthlyReport' => 'lunar', + 'General_YearlyReport' => 'anual', 'General_DailyReports' => 'Rapoarte zilnice', 'General_WeeklyReports' => 'Rapoarte săptămânale', 'General_MonthlyReports' => 'Rapoarte lunare', @@ -267,7 +275,7 @@ $translations = array( 'General_ExceptionInvalidAggregateReportsFormat' => 'Formatul rapoartelor agregate \'%s\' este invalid. Incercati-l pe oricare dintre acestea: %s.', 'General_ExceptionInvalidPeriod' => 'Perioada \'%s\' nu este suportata. Incercati-o pe oricare dintre acestea: %s.', 'General_ExceptionInvalidDateRange' => 'Data \'%s\' nu este un interval corect. Ar trebui sa aiba urmatorul format: %s.', - 'General_ExceptionGoalNotFound' => 'ID-ul scopului = %s nu a putut fi gasit.', + 'General_ExceptionGoalNotFound' => 'Ţinta cu id = %s nu a putut fi găsită.', 'General_ExceptionUndeletableFile' => 'Nu s-a putut sterge %s', 'General_ExceptionPrivilege' => 'Nu puteti accesa resursa pentru ca necesita acces la %s', 'General_ExceptionPrivilegeAtLeastOneWebsite' => 'Nu puteti accesa resursa pentru ca necesita acces %s pentru cel putin un site', @@ -277,7 +285,7 @@ $translations = array( 'General_ExceptionUnreadableFileDisabledMethod' => 'Fisierul de configurare {%s} nu a putut fi citit. Hosting-ul dvs. ar fi putut dezactiva %s.', 'General_ExceptionInvalidToken' => 'Token invalid', 'General_ExceptionInvalidDateFormat' => 'Formatul datei trebuie sa fie: %s sau alt cuvant cheie suportat de functia %s (vedeti %s pentru mai multe informatii)', - 'General_ExceptionLanguageFileNotFound' => 'Fisierul de limba \'%s\' nu a fost gasit.', + 'General_ExceptionLanguageFileNotFound' => 'Fişierul de limba \'%s\' nu a fost găsit.', 'General_ExceptionUnableToStartSession' => 'Sesiunea nu a putut fi pornita', 'General_ExceptionCheckUserIsSuperUserOrTheUser' => 'Utilizatorul trebuie să fie ori Super User ori utilizatorul \'%s\' însuşi.', 'General_WarningFileIntegrityNoManifest' => 'Verificare integritatii fisierelor nu a putut fi efectuata din cauza lipsei manifest.inc.php.', @@ -298,7 +306,7 @@ $translations = array( 'General_WarningPasswordStored' => '%sAtentie:%s Parola va fi stocata in fisierul config vizibil oricui il poate accesa.', 'General_EncryptedSmtpTransport' => 'Introduceti transport layer encryption cerut de serverul SMTP', 'General_InvalidResponse' => 'Datele primite sunt invalide', - 'General_ChooseLanguage' => 'Alegeti limba', + 'General_ChooseLanguage' => 'Alege limba', 'General_ChoosePeriod' => 'Alegeti interval', 'General_ChooseWebsite' => 'Alegeti website', 'General_Language' => 'Limba', @@ -309,7 +317,7 @@ $translations = array( 'General_ChangeTagCloudView' => 'Va rugam notati, puteti vizualiza rapoartele in alte feluri, pe langa tag cloud. Folositi controalele din josul raportului pentru a face asta', 'General_Recommended' => '(recomandat)', 'General_NotRecommended' => '(nerecomandat)', - 'General_Goal' => 'Scop', + 'General_Goal' => 'Ţintă', 'General_Outlink' => 'Link extern', 'General_Help' => 'Ajutor', 'General_DailySum' => 'suma zilnica', @@ -317,29 +325,55 @@ $translations = array( 'General_Metadata' => 'Metadata', 'General_OneVisit' => '1 vizita', 'General_NVisits' => '%s vizite', + 'General_OneAction' => '1 acţiune', 'General_OneDay' => '1 zi', 'General_NDays' => '%s zile', + 'General_OneMinute' => '1 minut', + 'General_NMinutes' => '%s minute', 'General_MainMetrics' => 'Metrici principali', 'General_Mobile' => 'Mobil', 'General_Desktop' => 'Desktop', 'General_Rows' => 'Linii', 'General_GeneralInformation' => 'Informaţii Generale', + 'General_ReportGeneratedFrom' => 'Acest raport a fost creat în baza datelor din %s.', + 'General_Installed' => 'Instalat', + 'General_Add' => 'Adaugă', + 'General_Continue' => 'Continuă', + 'General_Note' => 'Notă', + 'General_Show_js' => 'arată', + 'General_Hide_js' => 'ascunde', + 'General_Donate' => 'Donează', + 'General_MoreDetails' => 'Mai multe detalii', + 'General_Source' => 'Sursa', + 'General_Options' => 'Opţiuni', + 'General_OperationEquals' => 'Egal', + 'General_OperationLessThan' => 'Mai mic de', + 'General_OperationGreaterThan' => 'Mai mare de', + 'General_OperationContains' => 'Conţine', + 'General_OperationIs' => 'Este', + 'General_OperationIsNot' => 'nu este', + 'General_DefaultAppended' => '(implicit)', 'Actions_PluginDescription' => 'Rapoarte despre numărul de pagini văzute, outlink-uri şi descărcări. Outlink-uri şi Descărcările sunt urmărite automat!', - 'Actions_Actions' => 'Actiune', + 'Actions_Actions' => 'Acţiuni', 'Actions_SubmenuPages' => 'Pagini', 'Actions_SubmenuPagesEntry' => 'Pagini de intrare', + 'Actions_WidgetPagesEntry' => 'Pagini de intrare', 'Actions_SubmenuPagesExit' => 'Pagini de ieşire', - 'Actions_WidgetPagesExit' => 'Pagini de iesire', + 'Actions_WidgetPagesExit' => 'Pagini de ieşire', 'Actions_EntryPageTitles' => 'Titlurile paginilor de intrare', + 'Actions_WidgetEntryPageTitles' => 'Titlurile paginii de intrare', 'Actions_ExitPageTitles' => 'Titlurile paginilor de ieşire', - 'Actions_WidgetExitPageTitles' => 'Titlurile paginii de iesire', + 'Actions_WidgetExitPageTitles' => 'Titlurile paginilor de ieşire', 'Actions_SubmenuPageTitles' => 'Titluri pagini', + 'Actions_WidgetPageTitles' => 'Titluri pagini', + 'Actions_WidgetSearchKeywords' => 'Cuvinte-cheie pentru căutare pe site', 'Actions_WidgetSearchCategories' => 'Categorii de cautare', - 'Actions_WidgetSearchNoResultKeywords' => 'Interogari de cautare fara rezultat', + 'Actions_WidgetSearchNoResultKeywords' => 'CUvinte-cheie de căutare fără rezultat', + 'Actions_WidgetPageTitlesFollowingSearch' => 'Titluri pagini urmărind căutarea pe site', 'Actions_PageUrls' => 'URL-uri pagini', 'Actions_SubmenuOutlinks' => 'Linkuri externe', - 'Actions_SubmenuDownloads' => 'Descarcari', - 'Actions_SubmenuSitesearch' => 'Cautare pe site', + 'Actions_SubmenuDownloads' => 'Descărcări', + 'Actions_SubmenuSitesearch' => 'Căutare pe site', 'Actions_PagesReportDocumentation' => 'Acest raport conţine informaţii despre URL-urile paginilor ce au fost vizitate. %s Acest tabel este organizat ierarhic,URL-urile sunt afişate într-o structură tip arbore.', 'Actions_PageTitlesReportDocumentation' => 'Acest raport conţine informaţii despre titlurile paginilor ce au fost vizitate. %s Titlul paginii este Tag-ul HTML %s afişat de cele mai multe browsere ca nume al ferestrei.', 'Actions_OutlinksReportDocumentation' => 'Acest raport arată o listă ierarhică al URL-urilor outlink-urilor ce au fost click-uite de vizitatorii tăi.', @@ -356,9 +390,10 @@ $translations = array( 'Actions_ColumnPageName' => 'Numele Paginii', 'Actions_ColumnPageURL' => 'URL-ul Paginii', 'Actions_ColumnSearchCategory' => 'Categorie căutare', - 'Actions_ColumnSearchKeyword' => 'Cuvant cheie', - 'Actions_SiteSearchKeyword' => 'Intereogare (Cautare pe site)', - 'Actions_ColumnClickedURL' => 'URL-uri Click-uite', + 'Actions_ColumnSearchResultsCount' => 'Numărul rezultate căutare', + 'Actions_ColumnSearchKeyword' => 'Cuvânt-cheie', + 'Actions_SiteSearchKeyword' => 'Cuvânt-cheie (căutare pe site)', + 'Actions_ColumnClickedURL' => 'URL-uri accesate', 'Actions_ColumnDownloadURL' => 'URL Descărcare', 'Actions_ColumnEntryPageURL' => 'URL Paginii de Intrare', 'Actions_ColumnEntryPageTitle' => 'Titlul Paginii de Intrare', @@ -366,31 +401,88 @@ $translations = array( 'Actions_ColumnExitPageTitle' => 'Titlul Paginii de Ieşire', 'Actions_ColumnNoResultKeyword' => 'Cuvânt cheie fără rezultate în căutări', 'Actions_ColumnSearches' => 'Căutări', - 'Actions_ColumnSiteSearchKeywords' => 'Cuvinte cheie unice', + 'Actions_ColumnSiteSearchKeywords' => 'Cuvinte-cheie unice', 'Actions_ColumnSearchesDocumentation' => 'Numărul de vizite care au căutat după acest cuvânt cheie folosind motorul de căutare de pe site-ul dvs web.', + 'Actions_ColumnSearchExits' => '% Căutări abandonate', 'Actions_ColumnPagesPerSearch' => 'Pagini cu rezultate căutări', 'Actions_ColumnPagesPerSearchDocumentation' => 'Vizitatorii vor căuta pe site-ul dvs web şi uneori vor apăsa "următorul" pentru a vizualiza mai multe rezultate. Acesta este numărul mediu de pagini cu rezultate ale căutării vizualizate pentru acest cuvânt cheie.', 'Actions_EntryPagesReportDocumentation' => 'Acest raport conţinte informaţii despre paginile de intrare ce au fost folosite în perioada specificată. O pagină de intrare este prima pagină ce a fost văzută de un vizitator în timpul vizitei sale. %s URL-urile de intrare sunt afişate într-o structură arborescentă.', 'Actions_EntryPageTitlesReportDocumentation' => 'Acest raport conţine informaţii despre titlurile paginilor de intrare ce au fost folosite în timpul perioadei specificate.', 'Actions_ExitPagesReportDocumentation' => 'Acest raport conţine informaţii despre paginile de ieşire ce au fost folosite în timpul perioadei specificate. O pagină de ieşire este ultima pagină ce a fost văzută de un vizitator în timpul vizitei sale. %s URL-urile de ieşire sunt afişate ca o structură tip arbore.', 'Actions_ExitPageTitlesReportDocumentation' => 'Acest raport conţine informaţii despre titlurile paginilor de ieşire ce au fost folosite în timpul perioadei specificate.', + 'Actions_LearnMoreAboutSiteSearchLink' => 'Află mai multe despre urmărirea utilizării motorului de căutare de pe situl tău.', 'AnonymizeIP_PluginDescription' => 'Ascunde ultimele cifre ale IP-ului vizitatorilor pentru a fi în conformitate cu legile privind protecţia datelor personale.', 'API_QuickDocumentationTitle' => 'Demonstrare rapida API', 'API_UserAuthentication' => 'Identificare utilizator', - 'API_LoadedAPIs' => 'Incarcare de succes %s al API', + 'API_LoadedAPIs' => '%s API-uri încarcate cu succes', + 'CoreAdminHome_PluginDescription' => 'Zona de administrare Piwik.', + 'CoreAdminHome_MenuCommunity' => 'Comunitate', + 'CoreAdminHome_MenuDiagnostic' => 'Diagnosticare', + 'CoreAdminHome_MenuGeneralSettings' => 'Setări generale', + 'CoreAdminHome_MenuManage' => 'Administrare', 'CoreAdminHome_Administration' => 'Administrare', - 'CoreAdminHome_EmailServerSettings' => 'Setarile serverului email', - 'CoreAdminHome_JSTracking_CustomCampaignQueryParamDesc' => 'Nota: %1$sPiwik va detecta automat parametrii Google Analytics.%2$s', - 'CoreAdminHome_ImageTracking' => 'Urmarire prin imagine', - 'CoreAdminHome_ImageTrackingLink' => 'Legatura de urmarire prin imagine', - 'CoreAdminHome_JavaScriptTracking' => 'Urmarire prin JavaScript', + 'CoreAdminHome_EmailServerSettings' => 'Setările serverului email', + 'CoreAdminHome_CustomLogoHelpText' => 'Poţi personaliza logoul Piwik care va fi afişat în interfaţa de utilizator şi în rapoartele email.', + 'CoreAdminHome_UseCustomLogo' => 'Foloseşte un logou personalizat', + 'CoreAdminHome_LogoUpload' => 'Alege logo-ul pentru încărcare', + 'CoreAdminHome_TrustedHostConfirm' => 'Eşti sigur că doreşti să schimbi numele hostului de încredere Piwik_', + 'CoreAdminHome_PiwikIsInstalledAt' => 'Piwik este instalat în', + 'CoreAdminHome_TrackingCode' => 'Codul de urmărire', + 'CoreAdminHome_JSTracking_VisitorCustomVars' => 'Urmăreşte variabile personalizate pentru acest vizitator', + 'CoreAdminHome_JSTracking_PageCustomVars' => 'Urmăreşte o variabilă personalizată pentru fiecare vizualitare a paginii', + 'CoreAdminHome_JSTracking_CustomCampaignQueryParamDesc' => 'Notă: %1$sPiwik va detecta automat parametrii Google Analytics.%2$s', + 'CoreAdminHome_ImageTracking' => 'Urmărire prin imagine', + 'CoreAdminHome_TrackAGoal' => 'Urmăreşte o ţintă', + 'CoreAdminHome_WithOptionalRevenue' => 'cu venit opţional', + 'CoreAdminHome_ImageTrackingLink' => 'Link-ul către imaginea de urmărire', + 'CoreAdminHome_ImportingServerLogs' => 'Importarea log-urilor server-ului', + 'CoreAdminHome_JavaScriptTracking' => 'Urmărire prin JavaScript', + 'CoreAdminHome_LatestStableRelease' => 'Ultima versiune stabilă', + 'CoreAdminHome_LatestBetaRelease' => 'Ultima versiune beta', + 'CoreAdminHome_ForBetaTestersOnly' => 'Numai pentru beta-testeri', + 'CoreAdminHome_YouAreCurrentlyUsingPHP' => 'Actualmente foloseşti PHP %1$s.', + 'CoreHome_InjectedHostEmailSubject' => 'Piwik a fost acesat de pe un hostname necunoscut: %s', + 'CoreHome_CheckForUpdates' => 'Verifică actualizări', + 'CoreHome_YouAreUsingTheLatestVersion_js' => 'Foloseşti ultima versiune Piwik!', + 'CoreHome_HowMuchIsPiwikWorth' => 'Cât valorează Piwik pentru tine?', + 'CoreHome_SupportPiwik' => 'Susţine Piwik!', + 'CoreHome_OnlyForAdmin' => 'Acest widget este accesibil doar ţie, utilizator privilegiat.', + 'CoreHome_ShareThis' => 'Distribuie', + 'CoreHome_SharePiwikShort' => 'Piwik! Analiză liberă şi open-source a activităţii web. Fii stăpân pe datele tale.', + 'PrivacyManager_TeaserHeadline' => 'Setări confidenţialitate', + 'PrivacyManager_MenuPrivacySettings' => 'Confidenţialitate', + 'PrivacyManager_DeleteDataSettings' => 'Şterge înregistrări şi raportare vechi', + 'PrivacyManager_DeleteLogInfo' => 'Registrele din următoarele tabele vor fi șterse: %s', + 'PrivacyManager_DeleteLogsOlderThan' => 'Șterge înregistrări mai vechi decât', + 'PrivacyManager_DeleteDataInterval' => 'Şterge datele vechi fiecare', + 'PrivacyManager_DeleteMaxRowsNoLimit' => 'nelimitat', + 'PrivacyManager_ClickHereSettings' => 'Dă click aici pentru a accesa setările %s.', + 'PrivacyManager_ReportsDataSavedEstimate' => 'Mărimea bazei de date', + 'PrivacyManager_KeepDataFor' => 'Păstrează toate datele:', + 'PrivacyManager_DoNotTrack_Enabled' => 'Bravo, respecţi confidenţialitatea utilizatorilor tăi!', + 'PrivacyManager_DoNotTrack_DisabledMoreInfo' => 'Recomandăm să respecţi confidenţialitatea vizitatorilor şi să activezi funcţia DoNotTrack.', + 'CoreHome_WebAnalyticsReports' => 'Rapoarte de analitică web', + 'CoreHome_ThereIsNoDataForThisReport' => 'Nu există date pentru acest raport.', + 'CoreHome_DataForThisReportHasBeenPurged' => 'Datele din acest raport sunt mai vechi decât %s luni şi au fost şterse.', 'CoreHome_CategoryNoData' => 'Nici o data in aceasta categorie. Incearca "Include toata populatia".', - 'CoreHome_ShowJSCode' => 'Arat codul javascript ce trebuie folosit', - 'CoreHome_PageOf_js' => '%1$s al %2$s', + 'CoreHome_ShowJSCode' => 'Arată codul JavaScript ce trebuie folosit', + 'CoreHome_Default_js' => 'implicit', + 'CoreHome_PageOf_js' => '%1$s din %2$s', + 'CoreHome_ShortDateFormat' => '%shortDay%, %day% %shortMonth%', + 'CoreHome_ShortDateFormatWithYear' => '%day% %shortMonth% %shortYear%', + 'CoreHome_ShortMonthFormat' => '%shortMonth% %longYear%', + 'CoreHome_LongMonthFormat' => '%longMonth% %longYear%', + 'CoreHome_ShortWeekFormat' => '%dayFrom% %shortMonthFrom% - %dayTo% %shortMonthTo% %shortYearTo%', 'CoreHome_PeriodDay' => 'Zi', - 'CoreHome_PeriodWeek' => 'Saptamana', - 'CoreHome_PeriodMonth' => 'Luna', + 'CoreHome_PeriodWeek' => 'Săptamână', + 'CoreHome_PeriodMonth' => 'Lună', 'CoreHome_PeriodYear' => 'An', + 'CoreHome_PeriodRange' => 'Perioadă', + 'CoreHome_PeriodDays' => 'zile', + 'CoreHome_PeriodWeeks' => 'săptămâni', + 'CoreHome_PeriodMonths' => 'luni', + 'CoreHome_PeriodYears' => 'ani', + 'General_YearShort_js' => 'an', 'General_DaySu_js' => 'Du', 'General_DayMo_js' => 'Lu', 'General_DayTu_js' => 'Ma', @@ -436,102 +528,206 @@ $translations = array( 'General_MonthOctober_js' => 'Octombrie', 'General_MonthNovember_js' => 'Noiembrie', 'General_MonthDecember_js' => 'Decembrie', + 'CoreHome_ReportGeneratedOn' => 'Raport creat la %s', + 'CoreHome_ReportGeneratedXAgo' => 'Raport creat %s în urmă', + 'General_TransitionsRowActionTooltip_js' => 'Vezi ce au făcut vizitatorii până la şi după vizionarea acestei pagini', + 'CoreHome_MakeOneTimeDonation' => 'În schimb, donează o dată (fără subscriere).', + 'CorePluginsAdmin_PluginDescription' => 'Interfaţa de administrare plugin-uri.', 'CorePluginsAdmin_Plugins' => 'Pluginuri', + 'CorePluginsAdmin_Themes' => 'Teme', 'CorePluginsAdmin_PluginsManagement' => 'Managementul pluginurilor', + 'CorePluginsAdmin_ThemesManagement' => 'Gestionează Teme', 'CorePluginsAdmin_MainDescription' => 'Pluginurile extind functionaliatatea lui Piwik. Orice plugin instalat , poate fi activat sau dezactivat aici.', 'CorePluginsAdmin_Plugin' => 'Pluginuri', - 'CorePluginsAdmin_Version' => 'Versiuni', + 'CorePluginsAdmin_Theme' => 'Temă', + 'CorePluginsAdmin_Version' => 'Versiune', 'CorePluginsAdmin_Status' => 'Stare', - 'CorePluginsAdmin_Action' => 'Actiune', + 'CorePluginsAdmin_Action' => 'Acţiune', + 'CorePluginsAdmin_AuthorHomepage' => 'Pagina autorului', 'CorePluginsAdmin_PluginHomepage' => 'Pagina Pluginurilor', - 'CorePluginsAdmin_Activated' => 'Activare', + 'CorePluginsAdmin_Activated' => 'Activat', 'CorePluginsAdmin_Active' => 'Activ', 'CorePluginsAdmin_Inactive' => 'Inactiv', 'CorePluginsAdmin_Deactivate' => 'Dezactivare', 'CorePluginsAdmin_Activate' => 'Activare', - 'CoreUpdater_UpdateTitle' => 'Piwik › Actualizare', + 'CorePluginsAdmin_MenuPlatform' => 'Platformă', + 'CorePluginsAdmin_MenuExtend' => 'Extinde', + 'CorePluginsAdmin_PluginCannotBeFound' => 'Plugin-ul nu poate fi găsit!', + 'CoreUpdater_PluginDescription' => 'Mecanismul de actualizare Piwik', + 'CoreUpdater_UpdateTitle' => 'Actualizare', 'CoreUpdater_DatabaseUpgradeRequired' => 'Actualizare necesara a bazei de date', 'CoreUpdater_YourDatabaseIsOutOfDate' => 'Baza ta de date este expirata, si trebuie actualizata inainte de a continua.', 'CoreUpdater_PiwikWillBeUpgradedFromVersionXToVersionY' => 'Baza de date Piwik va fi upgradata pentru versiunea %1$s la noua versiune %2$s.', 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX' => 'Urmatoarele pluginuri vor fi actualizate: %s.', + 'CoreUpdater_ReadyToGo' => 'Eşti gata să procedezi?', 'CoreUpdater_TheUpgradeProcessMayTakeAWhilePleaseBePatient' => 'Procesul de actualizarea al bazei de date va dura ceva timp, deci aveti putina rabdare.', - 'CoreUpdater_UpgradePiwik' => 'Actualizea-za Piwik', - 'CoreUpdater_HelpMessageContent' => 'Verifica %1$s Piwik FAQ %2$s ce explica cele mai comune errori privind actualizarea. %3$s Intreaba administratorul de sistem - daca te poate ajuta sa rezolvi erorile ce tin de server si setarile MySQL .', + 'CoreUpdater_UpgradePiwik' => 'Actualizează Piwik', + 'CoreUpdater_ErrorDIYHelp' => 'Dacă eşti utilizator avansat şi vezi erori în timpul actualizării bazei de date:', + 'CoreUpdater_HelpMessageContent' => 'Verifică %1$s Piwik FAQ %2$s ce explică cele mai comune errori privind actualizarea. %3$s Intreabă administratorul de sistem - dacă te poate ajuta să rezolvi erorile ce ţin de server sau de setările MySQL.', 'CoreUpdater_CriticalErrorDuringTheUpgradeProcess' => 'Eroare critica a procesului de actualizare :', 'CoreUpdater_HelpMessageIntroductionWhenError' => 'Eroare de core . Consulta documentatia de ajutor:', 'CoreUpdater_HelpMessageIntroductionWhenWarning' => 'Actualizarea s-a efectuat cu succes, oricum mai sunt cateva lucruri ce sunt necesare pentru a finaliza procesul . Citeste descrierea pentru detalii. Pentru ajutor:', - 'CoreUpdater_UpgradeComplete' => 'Actualizare completa!', + 'CoreUpdater_UpgradeComplete' => 'Actualizare finisată!', 'CoreUpdater_WarningMessages' => 'Mesaj avertisment:', 'CoreUpdater_ErrorDuringPluginsUpdates' => 'Eroare in actualizarea pluginurilor:', 'CoreUpdater_WeAutomaticallyDeactivatedTheFollowingPlugins' => 'Au fost dezactivate urmatoarele pluginuri : %s', - 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded' => 'Piwik s-a actualizat cu succes!', - 'CoreUpdater_ContinueToPiwik' => 'Continua catre Piwik', - 'CoreUpdater_UpdateAutomatically' => 'Actualizare automata', + 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded' => 'Piwik a fost actualizat cu succes!', + 'CoreUpdater_ContinueToPiwik' => 'Continuă către Piwik', + 'CoreUpdater_UpdateAutomatically' => 'Actualizare automată', 'CoreUpdater_ThereIsNewVersionAvailableForUpdate' => 'Nu este disponibila o noua versiune actualizata Piwik', 'CoreUpdater_YouCanUpgradeAutomaticallyOrDownloadPackage' => 'Poti actualiza versiunea %s automat sau puteti o instala manual :', - 'CoreUpdater_DownloadX' => 'Descarca %s', + 'CoreUpdater_DownloadX' => 'Descarcă %s', + 'CoreUpdater_DownloadingUpdateFromX' => 'Se descarcă actualizarea de pe %s', + 'CoreUpdater_UnpackingTheUpdate' => 'Dezarchivez actualizarea', 'CoreUpdater_VerifyingUnpackedFiles' => 'Se verifica fisierele impachetate', - 'CoreUpdater_CreatingBackupOfConfigurationFile' => 'Creaza o copie a fisierului configuratie in %s', - 'CoreUpdater_InstallingTheLatestVersion' => 'Instaleaza ultima versiune', + 'CoreUpdater_CreatingBackupOfConfigurationFile' => 'Crează o copie a fişierului configuraţie în %s', + 'CoreUpdater_InstallingTheLatestVersion' => 'Se instalează ultima versiune', 'CoreUpdater_PiwikUpdatedSuccessfully' => 'Piwik actualizat cu succes!', - 'Dashboard_PluginDescription' => 'Tabloul tău de control. Poţi particulariza tabloul tău de control: adaugă noi widget-uri, schimbă ordinea widget-urilor. Fiecare utilizator îşi poate accesa tabloul său de control particularizat.', - 'Dashboard_Dashboard' => 'Tablou de bord', + 'CoreUpdater_EmptyDatabaseError' => 'Baza de date %s este goală. Trebuie să modifici sau să ştergi fişierul de configurare Piwik.', + 'CoreUpdater_ExceptionArchiveIncompatible' => 'Arhivă incompatibilă: %s', + 'CoreUpdater_ExceptionArchiveEmpty' => 'Arhivă goală.', + 'CoreUpdater_ExceptionArchiveIncomplete' => 'Arhiva este incompletă: unele fişiere lipsesc (de ex., %s)', + 'CoreUpdater_MajorUpdateWarning1' => 'Este o actualizare majoră! Va dura mai mult decât de obicei.', + 'CoreUpdater_MajorUpdateWarning2' => 'Următorul sfat este îndeosebi important pentru instalaţii mari.', + 'CustomVariables_CustomVariables' => 'Variabile personalizate', + 'CustomVariables_ColumnCustomVariableName' => 'Denumirea variabilei personalizate', + 'CustomVariables_ColumnCustomVariableValue' => 'Valoarea variabilei personalizate', + 'CustomVariables_ScopeVisit' => 'scop vizită', + 'CustomVariables_ScopePage' => 'scop pagină', + 'CustomVariables_TrackingHelp' => 'Ajutor: %1$sUrmărirea variabilelor personalizate în Piwik%2$s', + 'Dashboard_PluginDescription' => 'Panoul tău de control. Poţi personaliza panoul tău de control: adaugă noi widget-uri, schimbă ordinea widget-urilor. Fiecare utilizator îşi poate accesa panoul său de control personalizat.', + 'Dashboard_Dashboard' => 'Panou de control', 'Dashboard_AddAWidget' => 'Adaugă un widget', - 'Dashboard_DeleteWidgetConfirm' => 'Esti sigur ca doresti sa stergi dispozitivul din tabloul de bord ?', - 'Dashboard_SelectWidget' => 'Selecteaza dispozitivul ce doresti sa-l adaugi in tabloul de bord', - 'Dashboard_AddPreviewedWidget_js' => 'Dă click ca să adaugi un widget la tabloul tău de control', + 'Dashboard_DeleteWidgetConfirm' => 'Esti sigur că doreşti să ştergi widget-ul din panoul de control?', + 'Dashboard_SelectWidget' => 'Selectează widget-ul ce doreşti să-l adaugi în panoul de control', + 'Dashboard_AddPreviewedWidget_js' => 'Dă click ca să adaugi un widget la panoul de control', 'Dashboard_WidgetPreview_js' => 'Previzualizează widget-ul', 'Dashboard_Close_js' => 'Închide', 'Dashboard_Maximise_js' => 'Maximizează', 'Dashboard_Minimise_js' => 'Minimizează', - 'Dashboard_TitleWidgetInDashboard_js' => 'Dispozitivul este in tabloul de bord', - 'Dashboard_TitleClickToAdd_js' => 'Adauga la tabloul de bord', + 'Dashboard_TitleWidgetInDashboard_js' => 'Widget-ul deja este în panoul de control', + 'Dashboard_TitleClickToAdd_js' => 'Adaugă la panoul de control', 'Dashboard_LoadingWidget_js' => 'Se incarca dispozitivul, asteapta...', 'Dashboard_WidgetNotFound_js' => 'Dispozitivul nu exista', - 'Dashboard_ResetDashboard' => 'Resetează tabloul de control', - 'Dashboard_ResetDashboardConfirm' => 'Eşti sigur(ă) că vrei să resetezi aspectul tabloului de control la selecţia implicită de Widget-uri?', - 'Dashboard_WidgetsAndDashboard' => 'Widget-uri & Tabloul de control', - 'Dashboard_ChangeDashboardLayout' => 'Schimbă aşezarea tabloului de control', - 'Dashboard_SelectDashboardLayout' => 'Te rog selectează aşezarea noului tablou de control', - 'Dashboard_DashboardOf' => 'Tabloul de control %s', - 'Dashboard_ManageDashboard' => 'Administreză tablou de comandă', - 'Dashboard_CreateNewDashboard' => 'Creează un tablou de comandă nou', - 'Dashboard_RenameDashboard' => 'Redenumeşte tabloul de comandă', - 'Dashboard_DashboardName' => 'Numele tabloului de comandă:', - 'Dashboard_EmptyDashboard' => 'Tablou de comandă gol - Alege-ţi widget-urile preferate', - 'Dashboard_DefaultDashboard' => 'Tablou de comandă implicit - Folosind widget-urile selectate şi coloanele implicite', - 'Dashboard_RemoveDashboard' => 'Şterge tabloul de comandă', + 'Dashboard_ResetDashboard' => 'Resetează panoul de control', + 'Dashboard_ResetDashboardConfirm' => 'Eşti sigur(ă) că vrei să resetezi aspectul panoului de control la selecţia implicită de Widget-uri?', + 'Dashboard_WidgetsAndDashboard' => 'Widget-uri & Panoul de control', + 'Dashboard_ChangeDashboardLayout' => 'Schimbă aspectul panoului de control', + 'Dashboard_SelectDashboardLayout' => 'Te rog selectează aspectul noului panou de control', + 'Dashboard_DashboardOf' => 'Panoul de control %s', + 'Dashboard_ManageDashboard' => 'Administreză panou de control', + 'Dashboard_CreateNewDashboard' => 'Creează un panou de control nou', + 'Dashboard_RenameDashboard' => 'Redenumeşte panoul de control', + 'Dashboard_DashboardName' => 'Numele panoului de control:', + 'Dashboard_EmptyDashboard' => 'Panou de control gol - Alege widget-urile preferate', + 'Dashboard_DefaultDashboard' => 'Panou de control implicit - Foloseşte widget-urile selectate şi coloanele implicite', + 'Dashboard_RemoveDashboard' => 'Şterge panoul de control', + 'Dashboard_CopyDashboardToUser' => 'Crează o copie a panoului de control pentru utilizator', + 'Dashboard_DashboardCopied_js' => 'Panoul de control copiat cu succes pentru utilizatorul selectat.', 'Dashboard_SetAsDefaultWidgets' => 'Stabileşte ca implicită selecţia de widget-uri', - 'Dashboard_SetAsDefaultWidgetsConfirm' => 'Eşti sigur(ă) că vrei să stabileşti selecţia curentă de widget-uri şi aşezarea tabloului de comandă ca fiind şablonul implicit al tabloului de comandă?', - 'Dashboard_SetAsDefaultWidgetsConfirmHelp' => 'Această selecţie de widget-uri şi aşezarea coloanelor tabloului de comandă va fi folosită când un utilizator creează un tablou de comandă nou sau când caracteristica "%s" este folosită.', - 'Dashboard_RemoveDashboardConfirm' => 'Eşti sigur(ă) că vrei să ştergi tabloul de comandă "%s"?', + 'Dashboard_SetAsDefaultWidgetsConfirm' => 'Eşti sigur(ă) că vrei să stabileşti selecţia curentă de widget-uri şi aspectul panoului de control ca fiind şablonul implicit al panoului de control?', + 'Dashboard_SetAsDefaultWidgetsConfirmHelp' => 'Această selecţie de widget-uri şi aspectul coloanelor panoului de control va fi folosită când un utilizator creează un panou de control nou sau când este folosită caracteristica "%s".', + 'Dashboard_RemoveDashboardConfirm' => 'Eşti sigur(ă) că vrei să ştergi panoul de control "%s"?', 'Dashboard_NotUndo' => 'Nu o să poţi revoca acestă operaţie.', - 'Dashboard_DashboardEmptyNotification' => 'Tabloul tău de comandă nu conţine niciun widget. Începi prin a adăuga câteva widget-uri sau doar resetează tabloul de comandă către selecţia implicită de widget-uri.', + 'Dashboard_DashboardEmptyNotification' => 'Panoul tău de control nu conţine niciun widget. Începi prin a adăuga câteva widget-uri sau doar resetează panoul de control către selecţia implicită de widget-uri.', + 'Dashboard_TopLinkTooltip' => 'Vizualizează rapoarte web analitică pentru %s.', 'DBStats_DatabaseUsage' => 'Utilizare baza date', 'DBStats_MainDescription' => 'Piwik stocheaza toate datele statistice in baza de date Mysql . Curent, tabela Piwik utilizeaza %s.', - 'DBStats_Table' => 'Tabela', + 'DBStats_Table' => 'Tabel', + 'DBStats_RowCount' => 'Numărul de înregistrări', 'DBStats_DataSize' => 'Marime date', 'DBStats_IndexSize' => 'Marime index', 'DBStats_TotalSize' => 'Marime totala', + 'DBStats_DBSize' => 'Mărimea bazei de date', + 'DBStats_ReportDataByYear' => 'Tabele din raport pentru anul', + 'DBStats_EstimatedSize' => 'Mărimea anticipată', + 'DBStats_ReportTables' => 'Tabele din raport', + 'DBStats_MetricTables' => 'Tabele Metrici', + 'DBStats_OtherTables' => 'Alte tablete', + 'Feedback_DoYouHaveBugReportOrFeatureRequest' => 'Doreşti să raportezi o problemă sau să propui o înbunătăţire?', + 'Feedback_HowToExclude' => 'Cum să exclud urmărirea vizitelor mele?', + 'Feedback_SpecialRequest' => 'Ai o cerece deosebită către echipa Piwik?', + 'Feedback_ContactThePiwikTeam' => 'Contactează echipa Piwik!', + 'Feedback_IWantTo' => 'Doresc să:', + 'Feedback_CategorySponsor' => 'Devine sponsor Piwik', + 'Feedback_CategoryHire' => 'Angajază un consultant Piwik', + 'Feedback_MyEmailAddress' => 'Adresa mea e-mail:', + 'Feedback_MyMessage' => 'Mesajul meu:', + 'Feedback_DetailsPlease' => '(te rog, adaugă detaili aici)', + 'Feedback_MessageSent' => 'Mesajul tău a fost expetiat către echipa Piwik.', + 'Feedback_ThePiwikTeam' => 'Echipa Piwik', + 'Feedback_ExceptionBodyLength' => 'Mesajul trebuie să conţină cel puţin %s simboluri.', + 'Feedback_WantToThankConsiderDonating' => 'Crezi că Piwik e superb şi doreşti să ne mulţumeşti? Ai putea să donezi', + 'Goals_Goals' => 'Ţinte', + 'Goals_Ecommerce' => 'Ecomerţ', + 'Goals_EcommerceLog' => 'Log Ecomerţ', + 'Goals_GoalsOverview' => 'Rezumat ţinte', + 'Goals_GoalsManagement' => 'Gestionarea ţintelor', + 'Goals_EcommerceReports' => 'Rapoarte Ecomerţ', + 'Goals_YouCanEnableEcommerceReports' => 'Poţi activa %s pentru acest site pe pagina %s.', + 'Goals_ColumnConversions' => 'Conversii', + 'Goals_ColumnRevenue' => 'Venit', + 'Goals_ColumnRevenueDocumentation' => 'Venit total obţinut prin %s.', + 'Goals_ColumnAveragePriceDocumentation' => 'Venit mediu pentru acest %s.', + 'Goals_GoalX' => 'Ţinta %s', + 'Goals_AddNewGoal' => 'Agaugă o ţintă nouă', + 'Goals_AddNewGoalOrEditExistingGoal' => '%sAdaugă o ţintă nouă sau%s sau %sModifică%s ţinte existente', + 'Goals_AddGoal_js' => 'Adaugă o ţintă', + 'Goals_UpdateGoal_js' => 'Actualizează ţinta', + 'Goals_DeleteGoalConfirm_js' => 'Eşti sigur că doreşti să ştergi ţinta %s?', + 'Goals_CreateNewGOal' => 'Crează o ţintă nouă', + 'Goals_ViewAndEditGoals' => 'Vizualizarea şi editarea ţintelor', + 'Goals_GoalName' => 'Nume ţintă', + 'Goals_WhenVisitors' => 'când vizitatorii', + 'Goals_WhereThe' => 'unde', + 'Goals_Manually' => 'manual', + 'Goals_URL' => 'URL', + 'Goals_PageTitle' => 'Titlul paginii', + 'Goals_Filename' => 'nume fişier', + 'Goals_ExternalWebsiteUrl' => 'URL Site web extern', + 'Goals_Download' => 'Descarcă un fişier', + 'Goals_Optional' => '(opţional)', + 'Goals_Contains' => 'conţine %s', + 'Goals_IsExactly' => 'este exact %s', + 'Goals_MatchesExpression' => 'se portiveşte cu expresia %s', + 'Goals_ProductName' => 'Denumirea produsului', + 'Goals_ProductCategory' => 'Categorie de produse', + 'Goals_Products' => 'Produse', 'Installation_Installation' => 'Installation', 'Installation_InstallationStatus' => 'Installation status', 'Installation_PercentDone' => '%s %% Done', 'Installation_NoConfigFound' => 'The Piwik configuration file couldn\'t be found and you are trying to access a Piwik page.<br /><b> » You can <a href=\'index.php\'>install Piwik now</a></b><br /><small>If you installed Piwik before and have some tables in your DB, don\'t worry, you can reuse the same tables and keep your existing data!</small>', + 'Installation_DatabaseSetup' => 'Setare Bază de date', + 'Installation_DatabaseSetupServer' => 'server bază de date', + 'Installation_DatabaseSetupPassword' => 'parola', + 'Installation_DatabaseSetupDatabaseName' => 'nume bază de date', + 'Installation_DatabaseSetupTablePrefix' => 'prefix tabel', + 'Installation_DatabaseServerVersion' => 'Versiune server Bază de date', + 'Installation_DatabaseCreation' => 'Creare bază de date', + 'Installation_LargePiwikInstances' => 'Ajutor pentru utilizatorii site-urilor cu trafic intens', 'Installation_JsTag' => 'Javascript tag', 'Installation_Congratulations' => 'Congratulations', 'Installation_CongratulationsHelp' => '<p>Congratulations! Your Piwik installation is complete.</p><p>Make sure your javascript code is entered on your pages, and wait for your first visitors!</p>', 'Installation_ContinueToPiwik' => 'Continue to Piwik', 'Installation_SetupWebsite' => 'Setup a website', + 'Installation_SetupWebSiteName' => 'nume size web', + 'Installation_SetupWebSiteURL' => 'URL site web', 'Installation_SetupWebsiteError' => 'There was an error when adding the website', - 'Installation_SuperUserLogin' => 'super user login', + 'Installation_SuperUser' => 'Utilizator privilegiat', + 'Installation_SuperUserSetupSuccess' => 'Utilizator privilegiat creat cu succes!', + 'Installation_SuperUserLogin' => 'login utilizator privilegiat', 'Installation_Password' => 'password', 'Installation_PasswordRepeat' => 'password (repeat)', 'Installation_Email' => 'email', 'Installation_SecurityNewsletter' => 'email me with major Piwik upgrades and security alerts', 'Installation_CommunityNewsletter' => 'email me with community updates (new plugins, new features, etc.)', 'Installation_PasswordDoNotMatch' => 'password do not match', + 'Installation_Optional' => 'Opţional', + 'Installation_Legend' => 'Legenda', + 'Installation_Extension' => 'extensie', 'Installation_SystemCheck' => 'System check', 'Installation_SystemCheckPhp' => 'PHP version', + 'Installation_SystemCheckOtherExtensions' => 'Alte extensii', 'Installation_SystemCheckWriteDirs' => 'Directories with write access', 'Installation_SystemCheckWriteDirsHelp' => 'To fix this error on your Linux system, try typing in the following command(s)', 'Installation_SystemCheckMemoryLimit' => 'Memory limit', @@ -551,49 +747,111 @@ $translations = array( 'Installation_DatabaseCreatedSuccess' => 'Database %s created with success!', 'Installation_Welcome' => 'Bine ai venit!', 'Installation_WelcomeHelp' => '<p>Piwik is an open source web analytics software that makes it easy to get the information you want from your visitors.</p><p>This process is split up into %s easy steps and will take around 5 minutes.</p>', + 'Live_LinkVisitorLog' => 'Vezi registrul detalizat al vizitatorilor', + 'Live_Actions' => 'Acţiuni', + 'Live_Action' => 'Acţiune', + 'Live_VisitorsInRealTime' => 'Vizitatori în timp real', + 'Live_VisitorLog' => 'Registrul vizitatorilor', + 'Live_LastMinutes' => 'Ultimele %s minute', + 'Live_LastHours' => 'Ultimele %s ore', + 'Live_GoalType' => 'Tip', + 'Live_GoalRevenue' => 'Venit', + 'Live_GoalDetails' => 'Detalii', + 'Live_VisitorsLastVisit' => 'Ultima vizită a acestui vizitator a avut loc cu %s zile în urmă.', + 'Live_NbVisitors' => '%s vizitatori', + 'Live_NbVisitor' => '1 vizitator', + 'Live_RealTimeVisitorCount' => 'Numărul vizitatori în timp real', + 'Live_SimpleRealTimeWidget_Message' => '%s și %s în ultimele %s', 'Login_PluginDescription' => 'Modul de autentintificare, ce citeşte credenţialele din fişierul config/config.inc.php pentru Super User şi din Baza de date pentru alţi useri. Poate fi uşor schimbat pentru a folosi un nou mecanism de Autentificare (OpenID, htaccess, custom Auth, etc.).', - 'Login_LoginPasswordNotCorrect' => 'Numele si parola nu sunt corecte', + 'Login_LoginPasswordNotCorrect' => 'Numele sau parola sunt greşite.', 'Login_Password' => 'Parola', 'Login_PasswordRepeat' => 'Parolă (repetă)', 'Login_ChangePassword' => 'Schimbă parola', 'Login_LoginOrEmail' => 'Login sau E-mail', 'Login_RememberMe' => 'Ţine-mă minte', 'Login_LogIn' => 'Intrare', - 'Login_Logout' => 'Iesire', + 'Login_Logout' => 'Ieșire', 'Login_LostYourPassword' => 'Ai pierdut parola?', 'Login_PasswordsDoNotMatch' => 'Parolele nu se potrivesc.', - 'Login_InvalidUsernameEmail' => 'Nume/adresa mail invalida', + 'Login_InvalidUsernameEmail' => 'Nume sau adresa email invalidă.', 'Login_InvalidOrExpiredToken' => 'Jetonul este invalid sau expirat.', + 'Login_MailTopicPasswordChange' => 'Confirmă schimbarea parolei', + 'Login_PasswordChanged' => 'Parola ta a fost schimbată', 'Login_ContactAdmin' => 'Motiv posibil: gazda ta poate avea dezactivata functia email . <br/>Contactati adminstratorul.', 'Login_ExceptionPasswordMD5HashExpected' => 'Parametrul parolei este aşteptat să fie un hash MD5 al parolei.', 'Login_ExceptionInvalidSuperUserAuthenticationMethod' => 'Super Userul nu poate fi autentificat folosind \'%s\' mecanism.', + 'Login_ResetPasswordInstructions' => 'Introduce o parolă nouă pentru contul tău.', + 'Mobile_ChooseMetric' => 'Alege Metrica', + 'Mobile_ChooseReport' => 'Alege raportul', + 'Mobile_LoginUseHttps' => 'Folosește https', + 'Mobile_RatingNotNow' => 'Nu acum', + 'Mobile_VerifyLoginData' => 'Ai grijă să introduci corect numele şi parola utilizatorului.', + 'Mobile_AccessUrlLabel' => 'URL Acces Piwik', + 'Mobile_DefaultReportDate' => 'Data raportului', + 'Mobile_NavigationBack' => 'Înapoi', + 'Mobile_NoVisitorFound' => 'Nu a fost găsit nici un vizitator', + 'Mobile_SaveSuccessError' => 'URL-ul Piwik sau combinaţia nume utilizator şi parolă este greşită.', + 'MobileMessaging_Settings_SuperAdmin' => 'Setările utilizatorului privilegiat', + 'MobileMessaging_Settings_LetUsersManageAPICredential' => 'Permite utilizatorilor să gestioneze propriile date SMS API', + 'MobileMessaging_Settings_SMSProvider' => 'Operator SMS', + 'MobileMessaging_Settings_PhoneNumbers' => 'Numere de telefon', + 'MobileMessaging_Settings_PhoneNumbers_Add' => 'Adaugă un Număr de Telefon nou', + 'MobileMessaging_Settings_CountryCode' => 'Codul ţării', + 'MobileMessaging_Settings_PhoneNumber' => 'Număr de telefon', + 'MobileMessaging_Settings_APIKey' => 'Cheie API', + 'MobileMessaging_Settings_AddPhoneNumber' => 'Adaugă', + 'MobileMessaging_Settings_ValidatePhoneNumber' => 'Verifică', + 'MobileMessaging_Settings_RemovePhoneNumber' => 'Şterge', + 'MobileMessaging_Settings_DeleteAccountConfirm' => 'Sigur doriţi să ştergeţi acest cont SMS ?', + 'MobileMessaging_MobileReport_PhoneNumbers' => 'Numere de telefon', + 'MobileMessaging_MobileReport_MobileMessagingSettingsLink' => 'Pagina setări mesage mobile', + 'MobileMessaging_MobileReport_AdditionalPhoneNumbers' => 'Poţi adîuga mai multe numele de telefon accesând', + 'MobileMessaging_SMS_Content_Too_Long' => '[prea lung]', + 'MultiSites_Evolution' => 'Evoluţie', 'Provider_WidgetProviders' => 'Provideri', - 'Provider_SubmenuLocationsProvider' => 'Locatie si provideri', + 'Provider_ColumnProvider' => 'Operator', + 'Provider_SubmenuLocationsProvider' => 'Locație și operatori', 'Referers_Referers' => 'Referinte', - 'Referers_SearchEngines' => 'Motoare cautare', - 'Referers_Keywords' => 'Cuvinte', - 'Referers_DirectEntry' => 'Intrare directa', + 'Referers_SearchEngines' => 'Motoare căutare', + 'Referers_Keywords' => 'Cuvinte-cheie', + 'Referers_DirectEntry' => 'Intrare directă', 'Referers_Websites' => 'Siteuri', + 'Referers_Socials' => 'Reţele sociale', 'Referers_Campaigns' => 'Campanii', 'Referers_Evolution' => 'Evolutii in afara perioadei', 'Referers_Type' => 'Tipuri referinta', + 'Referers_ColumnSearchEngine' => 'Motor de căutare', + 'Referers_ColumnWebsite' => 'Site web', + 'Referers_ColumnSocial' => 'Reţea socială', + 'Referers_ColumnKeyword' => 'Cuvânt-cheie', + 'Referers_ColumnCampaign' => 'Campanie', 'Referers_TypeDirectEntries' => '%s intrari directe', 'Referers_TypeSearchEngines' => '%s de la motoare cautare', 'Referers_TypeWebsites' => '%s de la siteuri', 'Referers_TypeCampaigns' => '%s de la campanii', - 'Referers_SubmenuSearchEngines' => 'Motoare cautare si cuvinte', + 'Referers_DistinctSearchEngines' => 'motoare căutare distincte', + 'Referers_DistinctKeywords' => 'cuvinte cheie distincte', + 'Referers_DistinctCampaigns' => 'campanii distincte', + 'Referers_DistinctWebsites' => 'situri web distincte', + 'Referers_SubmenuSearchEngines' => 'Motoare căutare şi cuvinte', 'Referers_SubmenuWebsites' => 'Siteuri', 'Referers_SubmenuCampaigns' => 'Campanii', 'Referers_WidgetKeywords' => 'Lista cuvintelor', 'Referers_WidgetCampaigns' => 'Lista campaniilor', 'Referers_WidgetExternalWebsites' => 'Lista siteurilor externe', + 'Referers_WidgetSocials' => 'Listă de reţele sociale', 'Referers_WidgetSearchEngines' => 'Cel mai bun motor cautare', 'Referers_WidgetOverview' => 'Rezumat', + 'SecurityInfo_Security' => 'Securitate', + 'SecurityInfo_Test' => 'Test', + 'SecurityInfo_Result' => 'Rezultat', 'SEO_SeoRankings' => 'Poziţionări SEO', 'SEO_AlexaRank' => 'Poziţie în Alexa', 'SEO_DomainAge' => 'Vechime domeniu', 'SEO_Rank' => 'Poziţie', 'SEO_Pages' => 'Pagini', + 'SEO_Google_IndexedPages' => 'Pagini indexate de Google', + 'SEO_Bing_IndexedPages' => 'Pagini indexate de Bing', 'SEO_SEORankingsFor' => 'Poziţionări SEO pentru %s', 'SitesManager_Sites' => 'Situri', 'SitesManager_WebsitesManagement' => 'Mangementul siteurilor', @@ -602,27 +860,43 @@ $translations = array( 'SitesManager_AddSite' => 'Adauga un site', 'SitesManager_Urls' => 'Adresa', 'SitesManager_MenuSites' => 'Situri', - 'SitesManager_DeleteConfirm_js' => 'Are you sure you want to delete the website %s?', + 'SitesManager_DeleteConfirm_js' => 'Eşti sigur că doreşti să ştergi site-ul %s?', 'SitesManager_ExceptionDeleteSite' => 'It is not possible to delete this website as it is the only registered website. Add a new website first, then delete this one.', 'SitesManager_ExceptionNoUrl' => 'You must specify at least one URL for the site.', 'SitesManager_ExceptionEmptyName' => 'The site name can\'t be empty.', 'SitesManager_ExceptionInvalidUrl' => 'The url \'%s\' is not a valid URL.', + 'SitesManager_ExcludedIps' => 'IP-uri excluse', + 'SitesManager_ExcludedParameters' => 'Parametri excluşi', + 'SitesManager_SelectACity' => 'Selectează un oraş', + 'SitesManager_ChooseCityInSameTimezoneAsYou' => 'Selectează un oraş din fusul tău orar.', + 'SitesManager_UTCTimeIs' => 'Timpul UTC este %s.', + 'SitesManager_Timezone' => 'Fus orar', + 'SitesManager_Currency' => 'Unitate monetară', + 'SitesManager_NotAnEcommerceSite' => 'Nu este un site de e-comerţ', 'TranslationsAdmin_MenuTranslations' => 'Traducere', - 'TranslationsAdmin_MenuLanguages' => 'Limba', - 'TranslationsAdmin_LanguageCode' => 'Cod limba', + 'TranslationsAdmin_MenuLanguages' => 'Limbi', + 'TranslationsAdmin_LanguageCode' => 'Cod limbă', 'TranslationsAdmin_Plugin' => 'Plugin', - 'TranslationsAdmin_Definition' => 'Definitie', + 'TranslationsAdmin_Definition' => 'Definiţie', 'TranslationsAdmin_DefaultString' => 'Limba curenta (English)', 'TranslationsAdmin_TranslationString' => 'Traducere (Limba curenta: %s)', 'TranslationsAdmin_Translations' => 'Traducere', 'TranslationsAdmin_FixPermissions' => 'Rezolva permisiile fisierelor', - 'TranslationsAdmin_AddLanguage' => 'Adauga limba', + 'TranslationsAdmin_AddLanguage' => 'Adaugă limba', 'TranslationsAdmin_Export' => 'Exporta limba', 'TranslationsAdmin_Import' => 'Importa limba', - 'UserCountry_Country' => 'Tara', + 'TranslationsAdmin_InvalidCountry' => 'Ţară invalidă', + 'TranslationsAdmin_InvalidLanguage' => 'Limbă invalidă', + 'UserCountry_Country' => 'Ţară', 'UserCountry_Continent' => 'Continent', - 'UserCountry_DistinctCountries' => '%s tari distincte', - 'UserCountry_SubmenuLocations' => 'Locatie', + 'UserCountry_Region' => 'Regiune', + 'UserCountry_City' => 'Oraş', + 'UserCountry_Latitude' => 'Latitudine', + 'UserCountry_Longitude' => 'Longitudine', + 'UserCountry_Organization' => 'Organizaţie', + 'UserCountry_DistinctCountries' => '%s ţări distincte', + 'UserCountry_SubmenuLocations' => 'Locații', + 'UserCountry_WidgetLocation' => 'Locaţia vizitatorului', 'UserCountry_country_ac' => 'Ascension Islands', 'UserCountry_country_ad' => 'Andorra', 'UserCountry_country_ae' => 'United Arab Emirates', @@ -840,6 +1114,7 @@ $translations = array( 'UserCountry_country_sn' => 'Senegal', 'UserCountry_country_so' => 'Somalia', 'UserCountry_country_sr' => 'Suriname', + 'UserCountry_country_ss' => 'Sudanul de Sud', 'UserCountry_country_st' => 'Sao Tome and Principe', 'UserCountry_country_su' => 'Old U.S.S.R', 'UserCountry_country_sv' => 'El Salvador', @@ -863,6 +1138,7 @@ $translations = array( 'UserCountry_country_tv' => 'Tuvalu', 'UserCountry_country_tw' => 'Taiwan', 'UserCountry_country_tz' => 'Tanzania, United Republic of', + 'UserCountry_country_ti' => 'Tibet', 'UserCountry_country_ua' => 'Ukraine', 'UserCountry_country_ug' => 'Uganda', 'UserCountry_country_uk' => 'United Kingdom', @@ -886,54 +1162,103 @@ $translations = array( 'UserCountry_country_zm' => 'Zambia', 'UserCountry_country_zr' => 'Zaire', 'UserCountry_country_zw' => 'Zimbabwe', + 'UserCountry_country_a1' => 'Proxy anonim', + 'UserCountry_country_a2' => 'Provider Satelit', + 'UserCountry_country_ap' => 'Regiunea Asia/Pacific', + 'UserCountry_country_o1' => 'Altă ţară', 'UserCountry_continent_eur' => 'Europe', 'UserCountry_continent_afr' => 'Africa', + 'UserCountry_continent_ant' => 'Antarctica', 'UserCountry_continent_asi' => 'Asia', 'UserCountry_continent_amn' => 'North America', + 'UserCountry_continent_amc' => 'America Centrală', 'UserCountry_continent_ams' => 'South and Central America', 'UserCountry_continent_oce' => 'Oceania', + 'UserCountryMap_VisitorMap' => 'Harta vizitatori', + 'UserCountryMap_Countries' => 'Ţări', + 'UserCountryMap_Regions' => 'Regiuni', + 'UserCountryMap_Cities' => 'Oraşe', + 'UserCountryMap_WorldWide' => 'World-Wide', + 'UserCountryMap_None' => 'Nu sunt', + 'UserCountryMap_LoginToViewRealTime' => 'Intră pentru a vizualiza harta vizitatorilor în timp real', + 'UserCountryMap_RealTimeMap' => 'Harta în timp real', + 'UserCountryMap_Seconds' => 'secunde', + 'UserCountryMap_Minutes' => 'minute', + 'UserCountryMap_Hours' => 'ore', + 'UserCountry_GeoIPDatabases' => 'Bazele de date GeoIP', + 'UserCountry_ISPDatabase' => 'Baza de date provideri internet', + 'UserCountry_DownloadingDb' => 'Se descarcă %s', + 'UserCountry_DownloadNewDatabasesEvery' => 'Actializează baza de date fiecare', + 'UserSettings_VisitorSettings' => 'Setări vizitatori', 'UserSettings_BrowserFamilies' => 'Tip browser', 'UserSettings_Browsers' => 'Browsere', + 'UserSettings_BrowserWithNoPluginsEnabled' => '%1$s fără plugin-uri activate', + 'UserSettings_BrowserWithPluginsEnabled' => '%1$s cu plugin-uri %2$s activate', 'UserSettings_Plugins' => 'Pluginuri', 'UserSettings_Configurations' => 'Configurare', 'UserSettings_OperatingSystems' => 'Sisteme operare', + 'UserSettings_OperatingSystemFamily' => 'Sistem de operare după familie', + 'UserSettings_WidgetOperatingSystemFamily' => 'Sisteme de operare dup@ familie', 'UserSettings_Resolutions' => 'Rezolutii', 'UserSettings_WideScreen' => 'Ecran extins', + 'UserSettings_ColumnBrowserFamily' => 'Browser după familie', + 'UserSettings_ColumnBrowser' => 'Browser', + 'UserSettings_ColumnBrowserVersion' => 'Versiunea browser-ului', + 'UserSettings_ColumnPlugin' => 'Plugin', + 'UserSettings_ColumnConfiguration' => 'Configuraţia', + 'UserSettings_ColumnOperatingSystem' => 'Sistem de operare', + 'UserSettings_ColumnResolution' => 'Rezoluţie ecran', + 'UserSettings_ColumnTypeOfScreen' => 'Tip ecran', 'UserSettings_WidgetResolutions' => 'Rezolutii ecran', 'UserSettings_WidgetBrowsers' => 'Browsere vizitatori', + 'UserSettings_WidgetBrowserVersion' => 'Versiunea browser-ului', 'UserSettings_WidgetPlugins' => 'Lista pluginurilor', 'UserSettings_WidgetWidescreen' => 'Normal / Ecran extins', 'UserSettings_WidgetBrowserFamilies' => 'Browser dupa familie', 'UserSettings_WidgetOperatingSystems' => 'Sisteme operare', 'UserSettings_WidgetGlobalVisitors' => 'Configurare vizitatori globala', - 'UserSettings_SubmenuSettings' => 'Setari', + 'UserSettings_SubmenuSettings' => 'Setări', + 'UserSettings_GamingConsole' => 'Consolă de joc', + 'UserSettings_MobileVsDesktop' => 'Mobil vs Desktop', 'UsersManager_UsersManagement' => 'Management useri', 'UsersManager_UsersManagementMainDescription' => 'Creaza user nou sau actualizeaza userul existent. Poti seta permisiunile lor.', + 'UsersManager_ThereAreCurrentlyNRegisteredUsers' => 'La moment există %s utilizatori înregistraţi.', 'UsersManager_ManageAccess' => 'Manageriaza accesul', 'UsersManager_MainDescription' => 'Decide userul ce are acces la propriul website . Poti de asemenea seta permisiunile la toate siteurile in acelasi timp.', 'UsersManager_Sites' => 'Siteuri', 'UsersManager_AllWebsites' => 'Toate siteurile', 'UsersManager_ApplyToAllWebsites' => 'Aplica tuturor siteurilor', 'UsersManager_User' => 'Utilizator', - 'UsersManager_PrivNone' => 'Fara acces', + 'UsersManager_PrivNone' => 'Fără acces', 'UsersManager_PrivView' => 'Vezi', 'UsersManager_PrivAdmin' => 'Admin', 'UsersManager_ChangeAllConfirm' => 'Esti sigur ca vrei sa scimbi \'%s\' permisiunile tuturor siteurilor?', + 'UsersManager_ChangePasswordConfirm' => 'Schimbarea parolei va modifica token_auth al utilizatorului. Într-adevăr doreşti să continui?', + 'UsersManager_AnonymousUserHasViewAccess' => 'Notă: utilizatorul %1$s are acces %2$s la acest website.', 'UsersManager_Password' => 'Parola', 'UsersManager_Email' => 'Email', 'UsersManager_Alias' => 'Alias', - 'UsersManager_Edit' => 'Editeaza', - 'UsersManager_AddUser' => 'Adauga user', - 'UsersManager_MenuUsers' => 'Useri', - 'UsersManager_DeleteConfirm_js' => 'Esti sigur ca vrei sa stergi userul %s?', - 'UsersManager_ExceptionLoginExists' => 'Login \'%s\' exista deja.', - 'UsersManager_ExceptionEmailExists' => 'Userul \'%s\' exista deja.', + 'UsersManager_ForAnonymousUsersReportDateToLoadByDefault' => 'Pentru utilizatori anonimi, implicit se încarcă raportul pentru data', + 'UsersManager_ExcludeVisitsViaCookie' => 'Exclude vizitele tale cu ajutorul unui cookie', + 'UsersManager_Edit' => 'Editează', + 'UsersManager_AddUser' => 'Adaugă utilizator nou', + 'UsersManager_MenuUsers' => 'Utilizatori', + 'UsersManager_MenuUserSettings' => 'Setări utilizator', + 'UsersManager_MenuAnonymousUserSettings' => 'Setările utilizatorului anonim', + 'UsersManager_ChangePassword' => 'Schimbă parola', + 'UsersManager_TypeYourPasswordAgain' => 'Introduce parola nouă încă o dată.', + 'UsersManager_TheLoginScreen' => 'Pagina de autentificare', + 'UsersManager_DeleteConfirm_js' => 'Eşti sigur că vrei să ştergi utilizatorul %s?', + 'UsersManager_YourUsernameCannotBeChanged' => 'Numele tău de utilizator nu poate fi schimbat.', + 'UsersManager_ExceptionLoginExists' => 'Login \'%s\' există deja.', + 'UsersManager_ExceptionEmailExists' => 'Deja există un utilizator cu adresa \'%s\'.', 'UsersManager_ExceptionInvalidLoginFormat' => 'The login must be between %1$s and %2$s characters long and contain only letters, numbers, or the characters \'_\' or \'-\' or \'.\'', + 'UsersManager_ExceptionInvalidPassword' => 'Lungimea parolei trebuie să fie între %1$s şi %2$s simboluri.', 'UsersManager_ExceptionInvalidEmail' => 'Emailul nu are un format valid.', 'UsersManager_ExceptionDeleteDoesNotExist' => 'Userul \'%s\' nu exista pentru ca a fost sters.', 'UsersManager_ExceptionAdminAnonymous' => 'Nu poti autoriza \'admin\' accesul la \'anonymous\' user.', 'UsersManager_ExceptionEditAnonymous' => 'Userul anonim nu poate fi editat sau sters.De exemplu poti face ca statisticile tale sa fie publice autorizand \'view\' accesul la \'anonymous\' user.', - 'UsersManager_ExceptionUserDoesNotExist' => 'User \'%s\' nu exista.', + 'UsersManager_ExceptionUserDoesNotExist' => 'Utilizatorul \'%s\' nu există.', 'UsersManager_ExceptionAccessValues' => 'The parameter access must have one of the following values : [ %s ]', 'VisitFrequency_Evolution' => 'Evolutii peste perioada', 'VisitFrequency_ReturnVisits' => '%s vizitatori intorsi', @@ -941,16 +1266,39 @@ $translations = array( 'VisitFrequency_WidgetOverview' => 'Rezumat periodic', 'VisitFrequency_WidgetGraphReturning' => 'Graficul vizitelor intoarse', 'VisitFrequency_SubmenuFrequency' => 'Frecventa', + 'VisitorGenerator_VisitorGenerator' => 'Generatorul de vizite', + 'VisitorGenerator_AreYouSure' => 'Eşti sigur(ă) că doreşti să generezi vizite false?', + 'VisitorGenerator_ChoiceYes' => 'Da, sunt sigut(ă)!', + 'VisitorGenerator_SelectWebsite' => 'Alege site-ul', 'VisitorInterest_VisitsPerDuration' => 'Vizite per durata', 'VisitorInterest_VisitsPerNbOfPages' => 'Vizite per numar pagini', + 'VisitorInterest_ColumnVisitDuration' => 'Durata vizitei', + 'VisitorInterest_ColumnPagesPerVisit' => 'Pagini pentru o vizită', + 'VisitorInterest_visitsByVisitCount' => 'VIzite ordonate după numărul de vizite', + 'VisitorInterest_VisitNum' => 'Numărul de vizite', 'VisitorInterest_WidgetLengths' => 'Durata vizitelor', 'VisitorInterest_WidgetPages' => 'Pagini per vizita', + 'VisitorInterest_OneMinute' => '1 min', 'VisitorInterest_PlusXMin' => '%s min', + 'VisitorInterest_BetweenXYMinutes' => '%1$s-%2$s min', 'VisitorInterest_OnePage' => '1 pagina', 'VisitorInterest_NPages' => '%s pagini', + 'VisitorInterest_BetweenXYSeconds' => '%1$s-%2$ssec.', + 'VisitorInterest_VisitsByDaysSinceLast' => 'Vizite ordonate după zile de la ultima vizită', + 'VisitorInterest_WidgetVisitsByDaysSinceLast' => 'Vizite ordonate după zile de la ultima vizită', + 'VisitsSummary_VisitsSummary' => 'Rezumatul vizitelor', + 'VisitsSummary_VisitsSummaryDocumentation' => 'Acesta este un rezumat a evoluţiei vizitelor.', 'VisitsSummary_NbVisits' => '%s vizitari', 'VisitsSummary_NbUniqueVisitors' => '%s vizitatori unici', + 'VisitsSummary_NbActionsDescription' => '%s acţiuni', + 'VisitsSummary_NbPageviewsDescription' => '%s vizionări de pagine', + 'VisitsSummary_NbDownloadsDescription' => '%s descărcări', + 'VisitsSummary_NbUniqueDownloadsDescription' => '%s descărcări unice', + 'VisitsSummary_NbSearchesDescription' => 'total %s căutări pe site-ul tău', + 'VisitsSummary_NbKeywordsDescription' => '%s cuvinte-cheie unice', + 'VisitsSummary_AverageVisitDuration' => '%s durata medie a vizitei', 'VisitsSummary_MaxNbActions' => '%s actiuni maxime pe vizita', + 'VisitsSummary_NbActionsPerVisit' => '%s acţiuni (vizionări de pagini, descîrcîri, linkuri externe şi căutări pe site) pentru o vizită', 'VisitsSummary_GenerateTime' => '%s secunde pentru generarea pagini', 'VisitsSummary_GenerateQueries' => '%s interogari executate', 'VisitsSummary_WidgetLastVisits' => 'Grafic ultima vizita', @@ -967,14 +1315,48 @@ $translations = array( 'VisitTime_WidgetServerTime' => 'Vizite dupa timpul serverului', 'VisitTime_SubmenuTimes' => 'Timp', 'VisitTime_NHour' => '%sh', + 'VisitTime_VisitsByDayOfWeek' => 'Vizite ordonate după ziua săptămânii', + 'VisitTime_DayOfWeek' => 'Zi a săptămânii', + 'PDFReports_EmailReports' => 'Expediază raport prin e-mail', + 'PDFReports_PDF' => 'PDF', + 'PDFReports_SendReportNow' => 'Expediază raportul imediat', + 'PDFReports_SendReportTo' => 'Exediază raportul către', + 'PDFReports_ReportType' => 'Expediază raportul prin', + 'PDFReports_ReportFormat' => 'Formatul raportului', + 'PDFReports_AggregateReportsFormat' => '(opţional) opţiuni de vizualizare', + 'PDFReports_SentToMe' => 'Expediază mie', + 'PDFReports_ReportHour' => 'Expediază raportul la', + 'PDFReports_OClock' => 'ore', + 'PDFReports_ReportsIncluded' => 'Statistici incluse', + 'PDFReports_CreateReport' => 'Creare raport', + 'PDFReports_UpdateReport' => 'Actualizează raportul', + 'PDFReports_PiwikReports' => 'Rapoarte Piwik', + 'PDFReports_EmailHello' => 'Să trăieşti,', + 'PDFReports_CustomVisitorSegment' => 'Segment personalizat de vizitatori', + 'PDFReports_Pagination' => 'Pagina %s din %s', + 'RowEvolution_MetricBetweenText' => 'între %s şi %s', + 'Transitions_Including' => 'inclusiv', + 'Transitions_ExitsInline' => '%s există', + 'Overlay_Location' => 'Localitate', + 'Overlay_OneClick' => '1 click', + 'Overlay_Clicks' => '%s click-uri', + 'Overlay_Link' => 'Legătură', + 'Overlay_Domain' => 'Domeniu', 'Annotations_Annotations' => 'Note', 'Annotations_EnterAnnotationText' => 'Introdu nota...', 'Annotations_IconDesc_js' => 'Vezi notele pentru aceasta data de interval.', - 'Annotations_ViewAndAddAnnotations_js' => 'Vezi si adauga nota pentru %s...', + 'Annotations_IconDescHideNotes_js' => 'Ascunde notiţele pentru acest interval', + 'Annotations_NoAnnotations' => 'Nu există notiţe pentru acest interval', + 'Annotations_ViewAndAddAnnotations_js' => 'Vezi şi adaugă notiţe pentru %s...', + 'Annotations_HideAnnotationsFor_js' => 'Ascunde adnotaiile pentru %s...', + 'Annotations_AddAnnotationsFor_js' => 'Adaugă notiţe pentru %s...', + 'Annotations_ClickToEdit' => 'Dă clic pentru a modifica aceasă notiţă.', 'Annotations_ClickToDelete' => 'Click pentru a sterge acesta nota', 'Annotations_ClickToStarOrUnstar' => 'Click pentru a marca sau demarca aceasta nota.', + 'Annotations_CreateNewAnnotation' => 'Crează o notiţă nouă...', 'Annotations_LoginToAnnotate' => 'Conecteaza-te pentru a crea o nota.', 'Annotations_AnnotationOnDate' => 'Comentariu in %1$s: %2$s', + 'Annotations_ClickToEditOrAdd' => 'Dă click pentru a edita sau a adăuga o notiţă.', 'UserLanguage_Language_ab' => 'abhază', 'UserLanguage_Language_af' => 'afrikaans', 'UserLanguage_Language_am' => 'amharică', @@ -1039,8 +1421,11 @@ $translations = array( 'UserLanguage_Language_km' => 'khmeră', 'UserLanguage_Language_kn' => 'kannada', 'UserLanguage_Language_ko' => 'coreeană', + 'UserLanguage_Language_kr' => 'kanuri', 'UserLanguage_Language_ks' => 'cașmireză', 'UserLanguage_Language_ku' => 'kurdă', + 'UserLanguage_Language_kv' => 'komi', + 'UserLanguage_Language_kw' => 'cornică', 'UserLanguage_Language_ky' => 'kîrgîză', 'UserLanguage_Language_la' => 'latină', 'UserLanguage_Language_lb' => 'luxemburgheză', @@ -1113,4 +1498,26 @@ $translations = array( 'UserLanguage_Language_yo' => 'yoruba', 'UserLanguage_Language_zh' => 'chineză', 'UserLanguage_Language_zu' => 'zulu', + 'UserSettings_BrowserLanguage' => 'Limba browser-ului', + 'SegmentEditor_AddNewSegment' => 'Adaugă segment nou', + 'SegmentEditor_NewSegment' => 'Segment nou', + 'SegmentEditor_OperatorAND' => 'ŞI', + 'SegmentEditor_OperatorOR' => 'SAU', + 'SegmentEditor_DefaultAllVisits' => 'Toate vizite', + 'SegmentEditor_AddANDorORCondition' => 'Adaugă condiţia %s', + 'SegmentEditor_VisibleToMe' => 'mie', + 'SegmentEditor_VisibleToAllUsers' => 'tuturor utilizatorilor', + 'SegmentEditor_SegmentDisplayedThisWebsiteOnly' => 'numai acest site web', + 'SegmentEditor_SegmentDisplayedAllWebsites' => 'toate siturile web', + 'SegmentEditor_SaveAndApply' => 'Salvează şi aplică', + 'SegmentEditor_ChooseASegment' => 'Selectare segment', + 'SegmentEditor_AutoArchiveRealTime' => 'rapoartele segmentate sunt procesate în timp real', + + // FOR REVIEW + 'Forecast_Column' => 'Prognoză', + 'Forecast_Visitors' => 'Vizitatori', + 'Forecast_Widget' => 'Prognoza pentru astăzi', + 'UserLanguage_Language' => 'Limbi', + 'UserLanguage_SubmenuLanguage' => 'Limbi', + 'UserLanguage_WidgetLanguage' => 'Limbile vizitatorilor', ); diff --git a/lang/ru.php b/lang/ru.php index fea3a68752..d63cab1e56 100644 --- a/lang/ru.php +++ b/lang/ru.php @@ -1050,7 +1050,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik - это открытое программное обеспечение, позволяющее вам вести статистический учет посещений ваших сайтов и анализировать полученную информацию о посетителях. Этот процесс состоит из %s простых шагов и занимает около пяти минут времени.</p>', 'Installation_ConfigurationHelp' => 'Похоже, конфигурационный файл Piwik не сконфигурирован надлежащим образом. Вы можете удалить config/config.ini.php, и продолжить установку, или исправить настройки соединения с базой данных.', 'Installation_ErrorInvalidState' => 'Ошибка: Похоже, Вы пытаетесь пропустить шаг установочной программы, или cookie запрещены в брауезере, или файл конфигурации Piwik уже существует. %sУбедитесь, что cookies разрешены%s и вернитесь назад %s к первому шагу установки %s.', - 'Installation_InsufficientPrivileges' => 'Недостаточно прав. Пользователь базы данных должен иметь следующие права: %s', 'Installation_InsufficientPrivilegesHelp' => 'Вы можете добавить эти права, используя, например, phpMyAdmin или с помощью соответствующих SQL-запросов. Если вы не знаете, как это работает, пожалуйста, попросите вашего сисадмина, чтобы он добавил вам права.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Ой-ой! Piwik обнаружил некоторые %1$sкритические ошибки%2$s. %3$sЭти ошибки должны быть исправленные немедленно.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Есть некоторые проблемы с вашей системой. Piwik будет работать, но вы можете столкнуться с некоторыми незначительными проблемами.', @@ -1085,6 +1084,8 @@ $translations = array( 'Live_VisitorsLastVisit' => 'Последнее посещение этого пользователя было %s дней назад.', 'Live_NbVisitors' => '%s посетителей', 'Live_NbVisitor' => '1 посетитель', + 'Live_RealTimeVisitorCount' => 'Счётчик посетителей в реальном времени', + 'Live_SimpleRealTimeWidget_Message' => '%s и %s за последние %s', 'Login_PluginDescription' => 'Плагин аутентификации логина читает учетные данные из файла config/config.inc.php для суперпользователя, и из базы данных для других пользователей. Может быть легко применен для введения новых механизмов аутентификации (OpenID, htaccess, custom Auth, etc.).', 'Login_LoginPasswordNotCorrect' => 'Логин или пароль неверны', 'Login_Password' => 'Пароль', @@ -1725,7 +1726,7 @@ $translations = array( 'UserCountry_DownloadNewDatabasesEvery' => 'Обновлять базу раз в', 'UserCountry_GeoLiteCityLink' => 'Если вы используете базу данных GeoLite City, воспользуйтесь этой ссылкой: %1$s%2$s%3$s.', 'UserCountry_UpdaterHasNotBeenRun' => 'Обновления никогда не производились.', - 'UserSettings_VisitorSettings' => 'Настройки пользователя', + 'UserSettings_VisitorSettings' => 'Настройки посетителей', 'UserSettings_BrowserFamilies' => 'По семейству браузеров', 'UserSettings_Browsers' => 'По браузерам', 'UserSettings_Plugins' => 'Плагины', @@ -2225,6 +2226,7 @@ $translations = array( 'SegmentEditor_SegmentDisplayedAllWebsites' => 'все сайты', 'SegmentEditor_SaveAndApply' => 'Сохранить и применить', 'SegmentEditor_ChooseASegment' => 'Выбрать сегмент', + 'SegmentEditor_AutoArchiveRealTime' => 'отчёты по сегментам обрабатываются в реальном времени', // FOR REVIEW 'EntryPage_Bounces' => 'Отскоки', diff --git a/lang/sr.php b/lang/sr.php index 52ec9a7d23..a6a85ec692 100644 --- a/lang/sr.php +++ b/lang/sr.php @@ -1067,7 +1067,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik je alat otvorenog koda za analizu saobraćaja na sajtovima koji vam na lak način pruža željene informacije o vašim posetiocima.</p><p>Proces instalacije je podeljen na %s jednostavnih koraka i zahteva svega 5 minuta vašeg vremena.</p>', 'Installation_ConfigurationHelp' => 'Vaša Piwik podešavanja kao da nisu dobra. Možete ili ukloniti config/config.ini.php datoteku i nastaviti sa instalacijom, ili ispraviti podešavanja u vezi sa povezivanjem na bazu podataka.', 'Installation_ErrorInvalidState' => 'Greška: izgleda da ste pokušali da preskočite korak u instalalciji, ili vam je podrška za cookie onemogućena u vašem web čitaču, ili je Piwik datoteka sa podešavanjima već kreirana. %1$sPostarajte se da je podrška za cookie omogućena%2$s i vratite se nazad %3$s na prvu stranicu Piwik instalacije %4$s.', - 'Installation_InsufficientPrivileges' => 'Nedovoljne privilegije. Korisnik baze mora da ima sledeće privilegije: %s', 'Installation_InsufficientPrivilegesHelp' => 'Ove privilegije možete dodati alatima poput phpMyAdmin ili izvršavanjem odgovarajućih SQL komandi. Ukoliko to niste u stanju, zamolite administratora sistema da vam omogući ove privilegije.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Piwik je otkrio %1$skritične probleme%2$s sa vašom instalacijom. %3$sPotrebno je da ih odmah rešite.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Postoje izvesni problemi sa vašim sistemom. Piwik će raditi ali možete iskusiti manje probleme.', diff --git a/lang/sv.php b/lang/sv.php index ad7cb50efe..c9b927e40b 100644 --- a/lang/sv.php +++ b/lang/sv.php @@ -445,6 +445,7 @@ $translations = array( 'Actions_SiteSearchCategories2' => 'T.ex. så har e-handelssidor vanligtvis kategorier som gör att besökarna kan begränsa sökningen till produkter i en vald kategori', 'Actions_SiteSearchKeywordsNoResultDocumentation' => 'Den här rapporten listar sökorden som inte gav något resultat. Möjligtvis kan webbplatsens sökmotor förbättras eller så letar besökarna efter innehåll som inte finns (ännu?)', 'Actions_SiteSearchFollowingPagesDoc' => 'När besökare söker på din webbplats så letar dom efter en speciell sida, innehåll, produkt eller tjänst. Den här rapporten listar de sidor med flest klick efter en intern sökning. Med andra ord, en lista med dom mest sökta sidorna av besökare som redan hittat till din webbplats.', + 'Actions_AvgGenerationTimeTooltip' => 'Medel baseras på %s träff(ar) %s mellan %s och %s', 'AnonymizeIP_PluginDescription' => 'Anonymisera den sista byten av besökarnas IP-adress för att följa lokala lagar om personlig integritet/riktlinjer.', 'API_PluginDescription' => 'All data i Piwik finns tillgängligt via enkla API\'er. Denna plugin är webbtjänstens ingångspunkt som du kan anropa för att få tillgång till din webbanalysdata i xml, json, php, csv, osv.', 'API_QuickDocumentationTitle' => 'API snabbdokumentation', @@ -490,7 +491,6 @@ $translations = array( 'CoreAdminHome_JSTracking_GroupPageTitlesByDomain' => 'Lägg till webbplatsens domän till sidans titel vid spårning', 'CoreAdminHome_JSTracking_VisitorCustomVars' => 'Spåra anpassade variabler för denna besökare', 'CoreAdminHome_JSTracking_PageCustomVars' => 'Spåra en anpassad variabel för varje sidvisning', - 'CoreAdminHome_JSTracking_CampaignKwdParam' => 'Framsteg 100%', 'CoreAdminHome_JSTracking_CodeNote' => 'Se till att denna kod finns på varje sida av din hemsida före %1$s taggen.', 'CoreAdminHome_ImageTrackingIntro1' => 'När en besökare har inaktiverat JavaScript, eller när JavaScript inte kan användas, så kan du använda bildspårning för att spåra besökare.', 'CoreAdminHome_ImageTrackingIntro2' => 'Generera länken här nedanför och klistra in HTML-koden på din sida. Om du använder det här som reservför språning med JavaScript, så kan du omringa koden med %1$s-taggar.', @@ -504,7 +504,6 @@ $translations = array( 'CoreAdminHome_LatestStableRelease' => 'Senaste stabila versionen', 'CoreAdminHome_LatestBetaRelease' => 'Senaste betaversionen', 'CoreAdminHome_ForBetaTestersOnly' => 'Endast för betatestare', - 'CoreAdminHome_CheckReleaseGetVersion' => 'Progress 100%', 'CoreAdminHome_YouAreCurrentlyUsingPHP' => 'Du använder för närvarande PHP %1$s.', 'CoreHome_InjectedHostWarningIntro' => 'Du ansluter till Piwik från %1$s, men Piwik har konfigurerats att köras från den här adressen: %2$s.', 'CoreHome_InjectedHostSuperUserWarning' => 'Piwik kan vara felkonfigurerat (t.ex. om Pwiwik nyligen har flyttats till en ny server eller URL). Du kan antigen %1$sklicka här och lägga till %2$s som ett giltigt värdnamn för Piwik (om det är giltigt)%3$s, eller %4$sklicka här för att gå till %5$s och ansluta till Piwik säkert%6$s.', @@ -1031,7 +1030,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik är ett open source webbanalysprogram som gör det enkelt att få den information du vill ha från dina besökare.</p><p>Denna process är uppdelad i %s enkla steg och tar ca 5 minuter.</p>', 'Installation_ConfigurationHelp' => 'Din Piwik konfigurationsfil verkar vara felkonfigurerad. Du kan antingen ta bort config / config.ini.php och återuppta installationen, eller korrigera inställningarna för databasanslutningen.', 'Installation_ErrorInvalidState' => 'Fel: det verkar som att du försökte hoppa över ett steg av installationsprocessen, eller att dina cookies är inaktiverade eller Piwik\'s konfigurationsfil redan skapats. %1$s Säkerställ att dina cookies är aktiverade%2$s och gå tillbaka %3$s till första sidan av installationen %4$s.', - 'Installation_InsufficientPrivileges' => 'Otillräckliga rättigheter. Databasanvändaren måste ha följande rättigheter: %s', 'Installation_InsufficientPrivilegesHelp' => 'Du kan lägga till dessa behörigheter genom att använda ett verktyg som tex phpMyAdmin eller genom att köra rätt SQL-frågor. Om du inte vet hur man gör dessa saker, vänd dig till din systemadministratör för hjälp med dessa behörigheter.', 'Installation_SystemCheckSummaryThereWereErrors' => 'Oj då.. Piwik har upptäckt några %1$skritiska problem%2$s med installationen. %3$sDessa problem bör åtgärdas omgående.%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => 'Det finns vissa problem med systemet. Piwik kommer att köras, men du kan uppleva vissa smärre problem.', diff --git a/lang/zh-cn.php b/lang/zh-cn.php index 4425f2eeb4..c268d00eb1 100644 --- a/lang/zh-cn.php +++ b/lang/zh-cn.php @@ -42,6 +42,7 @@ $translations = array( 'General_Close' => '关闭', 'General_Cancel' => '取消', 'General_OrCancel' => '或 %s 取消 %s', + 'General_And' => '和', 'General_Logout' => '退出', 'General_Username' => '用户名', 'General_Description' => '简介', @@ -167,7 +168,7 @@ $translations = array( 'General_ColumnDestinationPage' => '结果页面', 'General_ColumnPageviews' => '浏览次数', 'General_ColumnPageviewsDocumentation' => '页面被查看的次数。', - 'General_ColumnUniquePageviews' => '访问次数', + 'General_ColumnUniquePageviews' => '唯一页面浏览量', 'General_ColumnUniquePageviewsDocumentation' => '浏览了该页面的访问次数。如果一次访问中多次浏览同一页面,只统计一次。', 'General_ColumnBounces' => '跳出次数', 'General_ColumnBouncesDocumentation' => '从这个页面开始并结束的访问次数。说明访客只查看该页面后就离开网站。', @@ -268,6 +269,10 @@ $translations = array( 'General_Daily' => '每天', 'General_Weekly' => '每周', 'General_Monthly' => '每月', + 'General_DailyReport' => '每日', + 'General_WeeklyReport' => '每周', + 'General_MonthlyReport' => '每月', + 'General_YearlyReport' => '每年', 'General_DailyReports' => '日报', 'General_WeeklyReports' => '周报', 'General_MonthlyReports' => '月报', @@ -371,6 +376,18 @@ $translations = array( 'General_MoreDetails' => '详情', 'General_Source' => '来源', 'General_Options' => '选项', + 'General_OperationEquals' => '等于', + 'General_OperationNotEquals' => '不等于', + 'General_OperationAtMost' => '至多', + 'General_OperationAtLeast' => '至少', + 'General_OperationLessThan' => '小于', + 'General_OperationGreaterThan' => '大于', + 'General_OperationContains' => '包括', + 'General_OperationDoesNotContain' => '不包括', + 'General_OperationIs' => '是', + 'General_OperationIsNot' => '不是', + 'General_DefaultAppended' => '(默认)', + 'General_SearchNoResults' => '没有结果', 'General_ReadThisToLearnMore' => '%1$s了解详情。%2$s', 'Actions_PluginDescription' => '报表显示页面浏览量、离站链接和下载次数。离站链接及下载跟踪是自动的!您也可以统计站内搜索。', 'Actions_Actions' => '页面分析', @@ -690,9 +707,13 @@ $translations = array( 'CoreHome_MakeOneTimeDonation' => '一次性捐款', 'CorePluginsAdmin_PluginDescription' => '插件管理界面。', 'CorePluginsAdmin_Plugins' => '插件', + 'CorePluginsAdmin_Themes' => '主题', 'CorePluginsAdmin_PluginsManagement' => '插件管理', + 'CorePluginsAdmin_ThemesManagement' => '管理主题', 'CorePluginsAdmin_MainDescription' => '插件延伸并扩展了 Piwik 的功能。 当一个插件安装了以后,您可以在这里启用或停用它。', + 'CorePluginsAdmin_ThemesDescription' => '主题可以改变piwik外观界面,并提供一个全新的视觉体验,并让您享受您的分析报告。', 'CorePluginsAdmin_Plugin' => '插件', + 'CorePluginsAdmin_Theme' => '主题', 'CorePluginsAdmin_Version' => '版本', 'CorePluginsAdmin_Status' => '状态', 'CorePluginsAdmin_Action' => '操作', @@ -704,6 +725,7 @@ $translations = array( 'CorePluginsAdmin_Inactive' => '不活动的', 'CorePluginsAdmin_Deactivate' => '停用', 'CorePluginsAdmin_Activate' => '启用', + 'CorePluginsAdmin_MenuPlatform' => '平台', 'CorePluginsAdmin_PluginCannotBeFound' => '插件没有找到', 'CoreUpdater_PluginDescription' => 'Piwik 更新机制', 'CoreUpdater_UpdateTitle' => '升级', @@ -1049,7 +1071,6 @@ $translations = array( 'Installation_WelcomeHelp' => '<p>Piwik 是一个让您能够轻易取得您所想要的访客信息的开放原始码页面分析软件!</p><p>此安装过程分为 %s 个简易的步骤,并且将仅花大约 5 分钟的时间!</p>', 'Installation_ConfigurationHelp' => '您的 Piwik 配置文件可能出错了,您可以删除 config/config.ini.php 然后继续安裝,或者改正数据库的参数设定。', 'Installation_ErrorInvalidState' => '错误: 看来您正在尝试停止安裝程序的某个步驟,或是您的 cookies 功能未启用,或者 Piwik 配置文件已经建立。%1$s请确定您的 cookies 功能已启用%2$s然后返回%3$s至安裝程序的初始画面 %4$s。', - 'Installation_InsufficientPrivileges' => '权限不足,数据库用户需要以下权限: %s', 'Installation_InsufficientPrivilegesHelp' => '您可以使用 phpMyAdmin 等工具或运行 SQL 语句来添加权限,如果您不知道如何操作,请联系管理员帮忙设置权限。', 'Installation_SystemCheckSummaryThereWereErrors' => '糟糕! Piwik 检查到一些 %1$s严重的问题%2$s,%3$s这些问题需要马上修复。%4$s', 'Installation_SystemCheckSummaryThereWereWarnings' => '您的系统有些问题,Piwik 可以运行,但是可能会出现些小错误。', @@ -1875,7 +1896,7 @@ $translations = array( 'VisitFrequency_ColumnBounceCountForReturningVisits' => '老访客的跳出次数', 'VisitFrequency_ColumnAvgActionsPerReturningVisit' => '老访客的平均活动次数', 'VisitFrequency_ColumnMaxActionsInReturningVisit' => '老访客的最大活动次数', - 'VisitFrequency_ColumnUniqueReturningVisitors' => '老访客数', + 'VisitFrequency_ColumnUniqueReturningVisitors' => '独立重访客数', 'VisitFrequency_ColumnNbReturningVisitsConverted' => '老访客的转化次数', 'VisitFrequency_ColumnSumVisitLengthReturning' => '老访客总的停留时间 (秒)', 'VisitFrequency_ReturnVisits' => '%s 个老访客的访问次数', @@ -1922,7 +1943,7 @@ $translations = array( 'VisitsSummary_VisitsSummary' => '访客总表', 'VisitsSummary_VisitsSummaryDocumentation' => '这是访客趋势总表。', 'VisitsSummary_NbVisits' => '%s 次访问', - 'VisitsSummary_NbUniqueVisitors' => '%s 个访客数', + 'VisitsSummary_NbUniqueVisitors' => '%s 个独立访客数', 'VisitsSummary_NbActionsDescription' => '%s 次活动', 'VisitsSummary_NbPageviewsDescription' => '%s 次浏览', 'VisitsSummary_NbUniquePageviewsDescription' => '%s 次唯一浏览', @@ -2266,6 +2287,14 @@ $translations = array( 'UserLanguage_Language_zh' => '中文', 'UserLanguage_Language_zu' => '祖鲁文', 'UserSettings_BrowserLanguage' => '浏览器语言', + 'SegmentEditor_OperatorAND' => '和', + 'SegmentEditor_OperatorOR' => '或', + 'SegmentEditor_DefaultAllVisits' => '所有的访问', + 'SegmentEditor_VisibleToMe' => '我', + 'SegmentEditor_VisibleToAllUsers' => '所有用户', + 'SegmentEditor_SegmentDisplayedThisWebsiteOnly' => '仅这个网站', + 'SegmentEditor_SegmentDisplayedAllWebsites' => '所有网站', + 'SegmentEditor_SaveAndApply' => '保存并应用', // FOR REVIEW 'EntryPage_Bounces' => '跳出', diff --git a/plugins/SegmentEditor/images/down_arrow.png b/libs/jquery/images/down_arrow.png Binary files differindex a364892c7d..a364892c7d 100644 --- a/plugins/SegmentEditor/images/down_arrow.png +++ b/libs/jquery/images/down_arrow.png diff --git a/plugins/SegmentEditor/images/scroller.png b/libs/jquery/images/scroller.png Binary files differindex ddcab93426..ddcab93426 100644 --- a/plugins/SegmentEditor/images/scroller.png +++ b/libs/jquery/images/scroller.png diff --git a/plugins/SegmentEditor/images/slide.png b/libs/jquery/images/slide.png Binary files differindex 657b9a6de5..657b9a6de5 100644 --- a/plugins/SegmentEditor/images/slide.png +++ b/libs/jquery/images/slide.png diff --git a/plugins/SegmentEditor/images/up_arrow.png b/libs/jquery/images/up_arrow.png Binary files differindex c7cb24c2b4..c7cb24c2b4 100644 --- a/plugins/SegmentEditor/images/up_arrow.png +++ b/libs/jquery/images/up_arrow.png diff --git a/plugins/SegmentEditor/javascripts/jquery.jscrollpane.js b/libs/jquery/jquery.jscrollpane.js index 48d8be8537..48d8be8537 100644 --- a/plugins/SegmentEditor/javascripts/jquery.jscrollpane.js +++ b/libs/jquery/jquery.jscrollpane.js diff --git a/plugins/SegmentEditor/javascripts/jquery.mousewheel.js b/libs/jquery/jquery.mousewheel.js index 9d65c7162b..9d65c7162b 100644 --- a/plugins/SegmentEditor/javascripts/jquery.mousewheel.js +++ b/libs/jquery/jquery.mousewheel.js diff --git a/plugins/SegmentEditor/javascripts/mwheelIntent.js b/libs/jquery/mwheelIntent.js index 72b7d135ca..72b7d135ca 100644 --- a/plugins/SegmentEditor/javascripts/mwheelIntent.js +++ b/libs/jquery/mwheelIntent.js diff --git a/plugins/SegmentEditor/stylesheets/jquery.jscrollpane.css b/libs/jquery/stylesheets/jquery.jscrollpane.css index 0364216fe0..0364216fe0 100644 --- a/plugins/SegmentEditor/stylesheets/jquery.jscrollpane.css +++ b/libs/jquery/stylesheets/jquery.jscrollpane.css diff --git a/plugins/SegmentEditor/stylesheets/scroll.less b/libs/jquery/stylesheets/scroll.less index 508adb4c7a..508adb4c7a 100644 --- a/plugins/SegmentEditor/stylesheets/scroll.less +++ b/libs/jquery/stylesheets/scroll.less diff --git a/libs/sparkline/lib/Sparkline.php b/libs/sparkline/lib/Sparkline.php index eed708aaae..f9dc98bc6c 100644 --- a/libs/sparkline/lib/Sparkline.php +++ b/libs/sparkline/lib/Sparkline.php @@ -69,15 +69,11 @@ class Sparkline extends Object { // $this->SetColorDefaults(); while (list($k, $v) = each($this->colorList)) { - $this->SetColorHandle($k, $this->DrawColorAllocate($k, $this->imageHandle)); + $this->SetColorHandle($k, $this->DrawColorAllocate($k)); } reset($this->colorList); - if ($this->IsError()) { - return false; - } else { - return true; - } + return !$this->IsError(); } //////////////////////////////////////////////////////////////////////////// @@ -95,9 +91,8 @@ class Sparkline extends Object { if (array_key_exists($name, $this->colorList)) { $this->colorList[$name]['handle'] = $handle; return true; - } else { - return false; } + return false; } function SetColorHex($name, $r, $g, $b) { @@ -117,6 +112,7 @@ class Sparkline extends Object { } function GetColor($name) { + $name = strtolower($name); if (array_key_exists($name, $this->colorList)) { return $this->colorList[$name]['rgb']; } else { @@ -229,7 +225,6 @@ class Sparkline extends Object { function DrawColorAllocate($color, $handle = false) { $this->Debug("Sparkline :: DrawColorAllocate('$color')", DEBUG_DRAW); - if (!$this->IsError() && $colorRGB = $this->GetColor($color)) { if ($handle === false) $handle = $this->imageHandle; diff --git a/libs/sparkline/lib/Sparkline_Line.php b/libs/sparkline/lib/Sparkline_Line.php index 292b3b3ed8..59b5a2eff7 100644 --- a/libs/sparkline/lib/Sparkline_Line.php +++ b/libs/sparkline/lib/Sparkline_Line.php @@ -31,7 +31,7 @@ class Sparkline_Line extends Sparkline { $this->dataSeries = array(); $this->dataSeriesStats = array(); $this->dataSeriesConverted = array(); - + $this->colorBackground = 'backgroundColor'; $this->featurePoint = array(); } // function Sparkline @@ -167,7 +167,7 @@ class Sparkline_Line extends Sparkline { $this->dataSeriesConverted[1][$i][1] + $this->graphAreaPx[0][1], $this->dataSeriesConverted[1][$i+1][0] + $this->graphAreaPx[0][0], $this->dataSeriesConverted[1][$i+1][1] + $this->graphAreaPx[0][1], - 'black'); + 'lineColor'); } // draw features @@ -245,7 +245,7 @@ class Sparkline_Line extends Sparkline { $this->dataSeriesConverted[1][$i][1], $this->dataSeriesConverted[1][$i+1][0], $this->dataSeriesConverted[1][$i+1][1], - 'black', + 'lineColor', $this->GetLineSize(), $imageVCHandle); } diff --git a/libs/upgradephp/upgrade.php b/libs/upgradephp/upgrade.php index 4d6bd7bbe2..a9fa7262a8 100644 --- a/libs/upgradephp/upgrade.php +++ b/libs/upgradephp/upgrade.php @@ -38,22 +38,6 @@ use Piwik\Common; /** - * @since PHP 5 - */ -if(!defined('E_STRICT')) { define('E_STRICT', 2048); } - -/** - * @since PHP 5.2.0 - */ -if(!defined('E_RECOVERABLE_ERROR')) { define('E_RECOVERABLE_ERROR', 4096); } - -/** - * @since PHP 5.3.0 - */ -if(!defined('E_DEPRECATED')) { define('E_DEPRECATED', 8192); } -if(!defined('E_USER_DEPRECATED')) { define('E_USER_DEPRECATED', 16384); } - -/** * ------------------------------ 5.2 --- * @group 5_2 * @since 5.2 @@ -96,310 +80,12 @@ if(!defined('E_USER_DEPRECATED')) { define('E_USER_DEPRECATED', 16384); } */ /** - * Converts PHP variable or array into a "JSON" (JavaScript value expression - * or "object notation") string. - * - * @compat - * Output seems identical to PECL versions. "Only" 20x slower than PECL version. - * @bugs - * Doesn't take care with unicode too much - leaves UTF-8 sequences alone. - * - * @param $var mixed PHP variable/array/object - * @return string transformed into JSON equivalent - */ -function _json_encode($var, /*emu_args*/$obj=FALSE) { - - #-- handle locale differences - $locale = localeconv(); - - #-- prepare JSON string - $json = ""; - - #-- add array entries - if (is_array($var) || ($obj=is_object($var))) { - - #-- check if array is associative - if (!$obj) { - $expect = 0; - foreach ((array)$var as $i=>$v) { - if (!is_int($i) || $i !== $expect++) { - $obj = 1; - break; - } - } - } - - #-- concat invidual entries - foreach ((array)$var as $i=>$v) { - $json .= ($json !== '' ? "," : "") // comma separators - . ($obj ? ("\"$i\":") : "") // assoc prefix - . (_json_encode($v)); // value - } - - #-- enclose into braces or brackets - $json = $obj ? "{".$json."}" : "[".$json."]"; - } - - #-- strings need some care - elseif (is_string($var)) { - if (!utf8_decode($var)) { - $var = utf8_encode($var); - } - $var = str_replace(array("\\", "\"", "/", "\b", "\f", "\n", "\r", "\t"), array("\\\\", '\"', "\\/", "\\b", "\\f", "\\n", "\\r", "\\t"), $var); - $json = '"' . $var . '"'; - //@COMPAT: for fully-fully-compliance $var = preg_replace("/[\000-\037]/", "", $var); - } - - #-- basic types - elseif (is_bool($var)) { - $json = $var ? "true" : "false"; - } - elseif ($var === NULL) { - $json = "null"; - } - elseif (is_int($var)) { - $json = "$var"; - } - elseif (is_float($var)) { - $json = str_replace( - array($locale['mon_thousands_sep'], $locale['mon_decimal_point']), - array('', '.'), - $var - ); - } - - #-- something went wrong - else { - trigger_error("json_encode: don't know what a '" .gettype($var). "' is.", E_USER_ERROR); - } - - #-- done - return($json); -} -if (!function_exists("json_encode")) { - function json_encode($var, /*emu_args*/$obj=FALSE) { - return _json_encode($var); - } -} - -/** - * Parses a JSON (JavaScript value expression) string into a PHP variable - * (array or object). - * - * @compat - * Behaves similar to PECL version, but is less quiet on errors. - * Now even decodes unicode \uXXXX string escapes into UTF-8. - * "Only" 27 times slower than native function. - * @bugs - * Might parse some misformed representations, when other implementations - * would scream error or explode. - * @code - * This is state machine spaghetti code. Needs the extranous parameters to - * process subarrays, etc. When it recursively calls itself, $n is the - * current position, and $waitfor a string with possible end-tokens. - * - * @param $json string JSON encoded values - * @param $assoc bool (optional) if outer shell should be decoded as object always - * @return mixed parsed into PHP variable/array/object - */ -function _json_decode($json, $assoc=FALSE, /*emu_args*/$n=0,$state=0,$waitfor=0) { - - #-- result var - $val = NULL; - static $lang_eq = array("true" => TRUE, "false" => FALSE, "null" => NULL); - static $str_eq = array("n"=>"\012", "r"=>"\015", "\\"=>"\\", '"'=>'"', "f"=>"\f", "b"=>"\b", "t"=>"\t", "/"=>"/"); - - #-- flat char-wise parsing - for (/*n*/; $n<strlen($json); /*n*/) { - $c = $json[$n]; - - #-= in-string - if ($state==='"') { - - if ($c == '\\') { - $c = $json[++$n]; - // simple C escapes - if (isset($str_eq[$c])) { - $val .= $str_eq[$c]; - } - - // here we transform \uXXXX Unicode (always 4 nibbles) references to UTF-8 - elseif ($c == "u") { - // read just 16bit (therefore value can't be negative) - $hex = hexdec( substr($json, $n+1, 4) ); - $n += 4; - // Unicode ranges - if ($hex < 0x80) { // plain ASCII character - $val .= chr($hex); - } - elseif ($hex < 0x800) { // 110xxxxx 10xxxxxx - $val .= chr(0xC0 + $hex>>6) . chr(0x80 + $hex&63); - } - elseif ($hex <= 0xFFFF) { // 1110xxxx 10xxxxxx 10xxxxxx - $val .= chr(0xE0 + $hex>>12) . chr(0x80 + ($hex>>6)&63) . chr(0x80 + $hex&63); - } - // other ranges, like 0x1FFFFF=0xF0, 0x3FFFFFF=0xF8 and 0x7FFFFFFF=0xFC do not apply - } - - // no escape, just a redundant backslash - //@COMPAT: we could throw an exception here - else { - $val .= "\\" . $c; - } - } - - // end of string - elseif ($c == '"') { - $state = 0; - } - - // yeeha! a single character found!!!!1! - else/*if (ord($c) >= 32)*/ { //@COMPAT: specialchars check - but native json doesn't do it? - $val .= $c; - } - } - - #-> end of sub-call (array/object) - elseif ($waitfor && (strpos($waitfor, $c) !== false)) { - return array($val, $n); // return current value and state - } - - #-= in-array - elseif ($state===']') { - list($v, $n) = _json_decode($json, 0, $n, 0, ",]"); - $val[] = $v; - if ($json[$n] == "]") { return array($val, $n); } - } - - #-= in-object - elseif ($state==='}') { - list($i, $n) = _json_decode($json, 0, $n, 0, ":"); // this allowed non-string indicies - list($v, $n) = _json_decode($json, $assoc, $n+1, 0, ",}"); - $val[$i] = $v; - if ($json[$n] == "}") { return array($val, $n); } - } - - #-- looking for next item (0) - else { - - #-> whitespace - if (preg_match("/\s/", $c)) { - // skip - } - - #-> string begin - elseif ($c == '"') { - $state = '"'; - } - - #-> object - elseif ($c == "{") { - list($val, $n) = _json_decode($json, $assoc, $n+1, '}', "}"); - if ($val && $n && !$assoc) { - $obj = new stdClass(); - foreach ($val as $i=>$v) { - $obj->{$i} = $v; - } - $val = $obj; - unset($obj); - } - } - #-> array - elseif ($c == "[") { - list($val, $n) = _json_decode($json, $assoc, $n+1, ']', "]"); - } - - #-> comment - elseif (($c == "/") && ($json[$n+1]=="*")) { - // just find end, skip over - ($n = strpos($json, "*/", $n+1)) or ($n = strlen($json)); - } - - #-> numbers - elseif (preg_match("#^(-?\d+(?:\.\d+)?)(?:[eE]([-+]?\d+))?#", substr($json, $n), $uu)) { - $val = $uu[1]; - $n += strlen($uu[0]) - 1; - if (strpos($val, ".")) { // float - $val = (float)$val; - } - elseif ($val[0] == "0") { // oct - $val = octdec($val); - } - else { - $val = (int)$val; - } - // exponent? - if (isset($uu[2])) { - $val *= pow(10, (int)$uu[2]); - } - } - - #-> boolean or null - elseif (preg_match("#^(true|false|null)\b#", substr($json, $n), $uu)) { - $val = $lang_eq[$uu[1]]; - $n += strlen($uu[1]) - 1; - } - - #-- parsing error - else { - // PHPs native json_decode() breaks here usually and QUIETLY - trigger_error("json_decode: error parsing '$c' at position $n", E_USER_WARNING); - return $waitfor ? array(NULL, 1<<30) : NULL; - } - - }//state - - #-- next char - if ($n === NULL) { return NULL; } - $n++; - }//for - - #-- final result - return ($val); -} -if (!function_exists("json_decode")) { - function json_decode($json, $assoc=FALSE) { - return _json_decode($json, $assoc); - } -} - -/** * Constants for future 64-bit integer support. * */ if (!defined("PHP_INT_SIZE")) { define("PHP_INT_SIZE", 4); } if (!defined("PHP_INT_MAX")) { define("PHP_INT_MAX", 2147483647); } -/** - * @flag bugfix - * @see #33895 - * - * Missing constants in 5.1, originally appeared in 4.0. - */ -if (!defined("M_SQRTPI")) { define("M_SQRTPI", 1.7724538509055); } -if (!defined("M_LNPI")) { define("M_LNPI", 1.1447298858494); } -if (!defined("M_EULER")) { define("M_EULER", 0.57721566490153); } -if (!defined("M_SQRT3")) { define("M_SQRT3", 1.7320508075689); } - -/** - * removes entities < > & and eventually " from HTML string - * - */ -if (!function_exists("htmlspecialchars_decode")) { - if (!defined("ENT_COMPAT")) { define("ENT_COMPAT", 2); } - if (!defined("ENT_QUOTES")) { define("ENT_QUOTES", 3); } - if (!defined("ENT_NOQUOTES")) { define("ENT_NOQUOTES", 0); } - function htmlspecialchars_decode($string, $quotes=2) { - $d = $quotes & ENT_COMPAT; - $s = $quotes & ENT_QUOTES; - return str_replace( - array("<", ">", ($s ? """ : "&.-;"), ($d ? "'" : "&.-;"), "&"), - array("<", ">", "'", "\"", "&"), - $string - ); - } -} - /* These functions emulate the "character type" extension, which is present in PHP first since version 4.3 per default. In this variant @@ -408,43 +94,6 @@ if (!function_exists("htmlspecialchars_decode")) { */ -#-- regex variants -if (!function_exists("ctype_alnum")) { - function ctype_alnum($text) { - return preg_match("/^[A-Za-z\d\300-\377]+$/", $text); - } - function ctype_alpha($text) { - return preg_match("/^[a-zA-Z\300-\377]+$/", $text); - } - function ctype_digit($text) { - return preg_match("/^\d+$/", $text); - } - function ctype_xdigit($text) { - return preg_match("/^[a-fA-F0-9]+$/", $text); - } - function ctype_cntrl($text) { - return preg_match("/^[\000-\037]+$/", $text); - } - function ctype_space($text) { - return preg_match("/^\s+$/", $text); - } - function ctype_upper($text) { - return preg_match("/^[A-Z\300-\337]+$/", $text); - } - function ctype_lower($text) { - return preg_match("/^[a-z\340-\377]+$/", $text); - } - function ctype_graph($text) { - return preg_match("/^[\041-\176\241-\377]+$/", $text); - } - function ctype_punct($text) { - return preg_match("/^[^0-9A-Za-z\000-\040\177-\240\300-\377]+$/", $text); - } - function ctype_print($text) { - return ctype_punct($text) && ctype_graph($text); - } -} - /** * Sets the default client character set. * @@ -593,31 +242,6 @@ if(function_exists('parse_ini_file')) { } /** - * fnmatch() replacement - * - * @since fnmatch() added to PHP 4.3.0; PHP 5.3.0 on Windows - * @author jk at ricochetsolutions dot com - * @author anthon (dot) pang (at) gmail (dot) com - * - * @param string $pattern shell wildcard pattern - * @param string $string tested string - * @param int $flags FNM_CASEFOLD (other flags not supported) - * @return bool True if there is a match, false otherwise - */ -if(!defined('FNM_CASEFOLD')) { define('FNM_CASEFOLD', 16); } -if(function_exists('fnmatch')) { - // provide a wrapper - function _fnmatch($pattern, $string, $flags = 0) { - return fnmatch($pattern, $string, $flags); - } -} else { - function _fnmatch($pattern, $string, $flags = 0) { - $regex = '#^' . strtr(preg_quote($pattern, '#'), array('\*' => '.*', '\?' => '.')) . '$#' . ($flags & FNM_CASEFOLD ? 'i' : ''); - return preg_match($regex, $string); - } -} - -/** * glob() replacement. * Behaves like glob($pattern, $flags) * @@ -642,7 +266,7 @@ if(function_exists('glob')) { $matches = array(); while(($file = readdir($handle)) !== false) { if(($file[0] != '.') - && _fnmatch($filePattern, $file) + && fnmatch($filePattern, $file) && (!($flags & GLOB_ONLYDIR) || is_dir("$path/$file"))) { $matches[] = "$path/$file" . ($flags & GLOB_MARK ? '/' : ''); } @@ -1052,28 +676,3 @@ if(!function_exists('mb_strtolower')) { return strtolower($input); } } - -/** - * str_getcsv - parse CSV string into array - * - * @since php 5.3.0 - * - * @param string $input - * @param string $delimeter - * @param string $enclosure - * @param string $escape (Not supported) - * @return array - */ -if(!function_exists('str_getcsv')) { - function str_getcsv($input, $delimiter=',', $enclosure='"', $escape='\\') { - $handle = fopen('php://memory', 'rw'); - $input = str_replace("\n", "\r", $input); - fwrite($handle, $input); - fseek($handle, 0); - $r = array(); - $data = fgetcsv($handle, strlen($input), $delimiter, $enclosure /*, $escape='\\' */); - $data = str_replace("\r", "\n", $data); - fclose($handle); - return $data; - } -} diff --git a/misc/log-analytics/import_logs.py b/misc/log-analytics/import_logs.py index 5869a2bd87..944795bbc6 100755 --- a/misc/log-analytics/import_logs.py +++ b/misc/log-analytics/import_logs.py @@ -763,6 +763,7 @@ class Piwik(object): elif not isinstance(data, basestring) and headers['Content-type'] == 'application/json': data = json.dumps(data) + headers['User-Agent'] = 'Piwik/LogImport' request = urllib2.Request(url + path, data, headers) response = urllib2.urlopen(request) result = response.read() diff --git a/plugins/API/ProcessedReport.php b/plugins/API/ProcessedReport.php index 8e46cec774..92e82aa275 100644 --- a/plugins/API/ProcessedReport.php +++ b/plugins/API/ProcessedReport.php @@ -316,7 +316,7 @@ class ProcessedReport * - translate metric names to a separate array : $columns * * @param int $idSite enables monetary value formatting based on site currency - * @param \Piwik\DataTable\Set $dataTable + * @param \Piwik\DataTable\Map|\Piwik\DataTable\Simple $dataTable * @param array $reportMetadata * @param bool $showRawMetrics * @return array Simple|Set $newReport with human readable format & array $columns list of translated column names & Simple|Set $rowsMetadata diff --git a/plugins/API/RowEvolution.php b/plugins/API/RowEvolution.php index ac0b7d5e30..8557043ccc 100644 --- a/plugins/API/RowEvolution.php +++ b/plugins/API/RowEvolution.php @@ -93,6 +93,11 @@ class RowEvolution return $dataTable; } + /** + * @param DataTable\Map $dataTable + * @param array $labels + * @return array + */ protected function getLabelsFromDataTable($dataTable, $labels) { // if no labels specified, use all possible labels as list @@ -114,7 +119,7 @@ class RowEvolution /** * Get row evolution for a single label - * @param DataTable $dataTable + * @param DataTable\Map $dataTable * @param array $metadata * @param string $apiModule * @param string $apiAction @@ -175,6 +180,13 @@ class RowEvolution return $return; } + /** + * @param Row $row + * @param string $apiModule + * @param string $apiAction + * @param bool $labelUseAbsoluteUrl + * @return bool|string + */ private function getRowUrlForEvolutionLabel($row, $apiModule, $apiAction, $labelUseAbsoluteUrl) { $url = $row->getMetadata('url'); @@ -191,14 +203,14 @@ class RowEvolution } /** - * @param $idSite - * @param $period - * @param $date - * @param $apiModule - * @param $apiAction - * @param $label - * @param $segment - * @param $idGoal + * @param int $idSite + * @param string $period + * @param string $date + * @param string $apiModule + * @param string $apiAction + * @param string|bool $label + * @param string|bool $segment + * @param int|bool $idGoal * @throws Exception * @return DataTable\Map|DataTable */ diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php index 1804ca4a07..81402e5f2d 100644 --- a/plugins/Actions/API.php +++ b/plugins/Actions/API.php @@ -129,9 +129,11 @@ class API * * @return DataTable|DataTable\Map */ - public function getPageUrls($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false) + public function getPageUrls($idSite, $period, $date, $segment = false, $expanded = false, $idSubtable = false, + $depth = false) { - $dataTable = Archive::getDataTableFromArchive('Actions_actions_url', $idSite, $period, $date, $segment, $expanded, $idSubtable); + $dataTable = Archive::getDataTableFromArchive( + 'Actions_actions_url', $idSite, $period, $date, $segment, $expanded, $idSubtable, $depth); $this->filterPageDatatable($dataTable); $this->filterActionsDataTable($dataTable, $expanded); return $dataTable; @@ -295,7 +297,12 @@ class API return $dataTable; } - //Visitors can search, and then click "next" to view more results. This is the average number of search results pages viewed for this keyword. + /** + * Visitors can search, and then click "next" to view more results. This is the average number of search results pages viewed for this keyword. + * + * @param DataTable|DataTable\Simple|DataTable\Map $dataTable + * @param string $columnToRead + */ protected function addPagesPerSearchColumn($dataTable, $columnToRead = 'nb_hits') { $dataTable->filter('ColumnCallbackAddColumnQuotient', array('nb_pages_per_search', $columnToRead, 'nb_visits', $precision = 1)); @@ -469,6 +476,8 @@ class API /** * Common filters for Page URLs and Page Titles + * + * @param DataTable|DataTable\Simple|DataTable\Map $dataTable */ protected function filterPageDatatable($dataTable) { @@ -513,7 +522,10 @@ class API } /** - * Common filters for all Actions API getters + * Common filters for all Actions API + * + * @param DataTable|DataTable\Simple|DataTable\Map $dataTable + * @param bool $expanded */ protected function filterActionsDataTable($dataTable, $expanded = false) { diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php index 665e0511f1..1fd74b5efe 100644 --- a/plugins/Actions/Actions.php +++ b/plugins/Actions/Actions.php @@ -61,10 +61,16 @@ class Actions extends \Piwik\Plugin 'API.getReportMetadata' => 'getReportMetadata', 'API.getSegmentsMetadata' => 'getSegmentsMetadata', 'ViewDataTable.getReportDisplayProperties' => 'getReportDisplayProperties', + 'AssetManager.getCssFiles' => 'getCssFiles', ); return $hooks; } + public function getCssFiles(&$cssFiles) + { + $cssFiles[] = "plugins/Actions/stylesheets/dataTableActions.less"; + } + public function getSegmentsMetadata(&$segments) { $sqlFilter = array($this, 'getIdActionFromSegment'); @@ -648,9 +654,9 @@ class Actions extends \Piwik\Plugin private function addBaseDisplayProperties(&$result) { - $result['datatable_css_class'] = 'dataTableActions'; $result['datatable_js_type'] = 'actionDataTable'; - $result['subtable_template'] = '@CoreHome/_dataTableActions_subDataTable.twig'; + $result['visualization_properties']['table']['subtable_template'] = + '@CoreHome/_dataTableActions_subDataTable.twig'; $result['search_recursive'] = true; $result['show_all_views_icons'] = false; $result['show_table_all_columns'] = false; @@ -661,16 +667,26 @@ class Actions extends \Piwik\Plugin $result['custom_parameters'] = array('flat' => 0); if (ViewDataTable::shouldLoadExpanded()) { - $result['show_expanded'] = true; - + $result['visualization_properties']['table']['show_expanded'] = true; + $result['filters'][] = function ($dataTable) { Actions::setDataTableRowLevels($dataTable); }; } + $result['filters'][] = function ($dataTable, $view) { + if ($view->getViewDataTableId() == 'table') { + $view->datatable_css_class = 'dataTableActions'; + } + }; + return $result; } + /** + * @param \Piwik\DataTable $dataTable + * @param int $level + */ public static function setDataTableRowLevels($dataTable, $level = 0) { foreach ($dataTable->getRows() as $row) { @@ -777,7 +793,7 @@ class Actions extends \Piwik\Plugin 'filter_sort_column' => 'entry_nb_visits', 'filter_sort_order' => 'desc', 'title' => Piwik_Translate('Actions_SubmenuPagesEntry'), - 'relatedReports' => array( + 'related_reports' => array( 'Actions.getEntryPageTitles' => Piwik_Translate('Actions_EntryPageTitles') ), 'self_url' => $reportUrl @@ -805,7 +821,7 @@ class Actions extends \Piwik\Plugin 'filter_sort_column' => 'exit_nb_visits', 'filter_sort_order' => 'desc', 'title' => Piwik_Translate('Actions_SubmenuPagesExit'), - 'relatedReports' => array( + 'related_reports' => array( 'Actions.getExitPageTitles' => Piwik_Translate('Actions_ExitPageTitles') ), 'self_url' => $reportUrl, @@ -863,7 +879,11 @@ class Actions extends \Piwik\Plugin 'columns_to_display' => array('label', 'nb_visits', 'nb_pages_per_search'), 'show_table_all_columns' => false, 'show_bar_chart' => false, - 'disable_row_evolution' => false, + 'visualization_properties' => array( + 'table' => array( + 'disable_row_evolution' => false, + ) + ) ); } @@ -888,7 +908,7 @@ class Actions extends \Piwik\Plugin 'filter_sort_order' => 'desc', 'show_exclude_low_population' => false, 'title' => $title, - 'relatedReports' => $relatedReports + 'related_reports' => $relatedReports ); $this->addExcludeLowPopDisplayProperties($result); @@ -911,7 +931,7 @@ class Actions extends \Piwik\Plugin 'columns_to_display' => array('label', 'nb_hits', 'nb_visits', 'bounce_rate', 'avg_time_on_page', 'exit_rate', 'avg_time_generation'), 'title' => Piwik_Translate('Actions_SubmenuPageTitles'), - 'relatedReports' => array( + 'related_reports' => array( 'Actions.getEntryPageTitles' => Piwik_Translate('Actions_EntryPageTitles'), 'Actions.getExitPageTitles' => Piwik_Translate('Actions_ExitPageTitles'), ), @@ -937,7 +957,7 @@ class Actions extends \Piwik\Plugin ), 'columns_to_display' => array('label', 'entry_nb_visits', 'entry_bounce_count', 'bounce_rate'), 'title' => Piwik_Translate('Actions_EntryPageTitles'), - 'relatedReports' => array( + 'related_reports' => array( 'Actions.getPageTitles' => Piwik_Translate('Actions_SubmenuPageTitles'), "Actions.$entryPageUrlAction" => Piwik_Translate('Actions_SubmenuPagesEntry') ), @@ -961,7 +981,7 @@ class Actions extends \Piwik\Plugin ), 'columns_to_display' => array('label', 'exit_nb_visits', 'nb_visits', 'exit_rate'), 'title' => Piwik_Translate('Actions_ExitPageTitles'), - 'relatedReports' => array( + 'related_reports' => array( 'Actions.getPageTitles' => Piwik_Translate('Actions_SubmenuPageTitles'), "Actions.$exitPageUrlAction" => Piwik_Translate('Actions_SubmenuPagesExit'), ), diff --git a/plugins/Actions/stylesheets/dataTableActions.less b/plugins/Actions/stylesheets/dataTableActions.less new file mode 100644 index 0000000000..7c059d948b --- /dev/null +++ b/plugins/Actions/stylesheets/dataTableActions.less @@ -0,0 +1,4 @@ +.dataTableActions > .dataTableWrapper { + width: 500px; + min-height: 1px; +}
\ No newline at end of file diff --git a/plugins/Annotations/API.php b/plugins/Annotations/API.php index cf0b9de7bf..0e946b7302 100755 --- a/plugins/Annotations/API.php +++ b/plugins/Annotations/API.php @@ -17,6 +17,7 @@ use Piwik\Piwik; use Piwik\Date; use Piwik\Plugins\Annotations\AnnotationList; use Piwik\ViewDataTable; +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution as EvolutionViz; /** * @see plugins/Annotations/AnnotationList.php @@ -310,7 +311,7 @@ class API * @param bool|int $lastN Whether to include the last N periods in the range or not. * Ignored if period == range. * - * @return array + * @return Date[] array of Date objects or array(false, false) * @ignore */ public static function getDateRangeForPeriod($date, $period, $lastN = false) @@ -333,7 +334,7 @@ class API $endDate = $oPeriod->getDateEnd(); } else // if the range includes the last N periods { - list($date, $lastN) = \Piwik\ViewDataTable\GenerateGraphHTML\ChartEvolution::getDateRangeAndLastN($period, $date, $lastN); + list($date, $lastN) = EvolutionViz::getDateRangeAndLastN($period, $date, $lastN); list($startDate, $endDate) = explode(',', $date); $startDate = Date::factory($startDate); diff --git a/plugins/Annotations/javascripts/annotations.js b/plugins/Annotations/javascripts/annotations.js index 56e1572843..628d9f2ea1 100755 --- a/plugins/Annotations/javascripts/annotations.js +++ b/plugins/Annotations/javascripts/annotations.js @@ -184,7 +184,7 @@ $('.annotation-period-edit', manager).each(function () { createDatePicker($(this).parent().parent()); }); - } + }; /** * Replaces the HTML of an annotation manager element, and resets date/period @@ -223,7 +223,7 @@ var newHtml = $(html); annotation.html(newHtml.html()).attr('data-date', newHtml.attr('data-date')); createDatePicker(annotation); - } + }; /** * Binds events to an annotation manager element. diff --git a/plugins/CoreAdminHome/Controller.php b/plugins/CoreAdminHome/Controller.php index c70ad35501..f8a23c8dc2 100644 --- a/plugins/CoreAdminHome/Controller.php +++ b/plugins/CoreAdminHome/Controller.php @@ -36,7 +36,8 @@ class Controller extends \Piwik\Controller\Admin public function index() { - return $this->redirectToIndex('UsersManager', 'userSettings'); + $this->redirectToIndex('UsersManager', 'userSettings'); + return; } public function generalSettings() diff --git a/plugins/CoreAdminHome/stylesheets/generalSettings.less b/plugins/CoreAdminHome/stylesheets/generalSettings.less index 71871038b0..c372146971 100644 --- a/plugins/CoreAdminHome/stylesheets/generalSettings.less +++ b/plugins/CoreAdminHome/stylesheets/generalSettings.less @@ -7,13 +7,14 @@ } #content.admin { - margin: 0 15px 0 270px; + margin: 0 0 0 260px; padding: 0 0 40px; + display: table; font: 13px Arial, Helvetica, sans-serif; } .admin #header_message { - margin-top: -10px; + margin-top: 10px; } table.admin { diff --git a/plugins/CoreAdminHome/stylesheets/menu.less b/plugins/CoreAdminHome/stylesheets/menu.less index 4621613aae..f6686a3cdb 100644 --- a/plugins/CoreAdminHome/stylesheets/menu.less +++ b/plugins/CoreAdminHome/stylesheets/menu.less @@ -1,8 +1,11 @@ +#container { + clear: left; +} + #menu { - padding: 0 0 0 0; + padding: 0; float: left; width: 240px; - position: absolute; } #tablist { diff --git a/plugins/CoreHome/Controller.php b/plugins/CoreHome/Controller.php index 8af95e6449..33c9e61abe 100644 --- a/plugins/CoreHome/Controller.php +++ b/plugins/CoreHome/Controller.php @@ -158,8 +158,8 @@ class Controller extends \Piwik\Controller public function getRowEvolutionGraph($fetch = false, $rowEvolution = null) { if (empty($rowEvolution)) { - $paramName = Piwik_CoreHome_DataTableRowAction_MultiRowEvolution::IS_MULTI_EVOLUTION_PARAM; - $isMultiRowEvolution = Common::getRequestVar($paramName, false, 'int'); + $label = Common::getRequestVar('label', '', 'string'); + $isMultiRowEvolution = strpos($label, ',') !== false; $rowEvolution = $this->makeRowEvolution($isMultiRowEvolution, $graphType = 'graphEvolution'); $rowEvolution->useAvailableMetrics(); diff --git a/plugins/CoreHome/CoreHome.php b/plugins/CoreHome/CoreHome.php index afb6744bf3..e2e32b1a6b 100644 --- a/plugins/CoreHome/CoreHome.php +++ b/plugins/CoreHome/CoreHome.php @@ -42,15 +42,19 @@ class CoreHome extends \Piwik\Plugin public function getCssFiles(&$cssFiles) { $cssFiles[] = "libs/jquery/themes/base/jquery-ui.css"; + $cssFiles[] = "libs/jquery/stylesheets/jquery.jscrollpane.css"; + $cssFiles[] = "libs/jquery/stylesheets/scroll.less"; $cssFiles[] = "plugins/Zeitgeist/stylesheets/base.less"; $cssFiles[] = "plugins/CoreHome/stylesheets/coreHome.less"; $cssFiles[] = "plugins/CoreHome/stylesheets/menu.less"; $cssFiles[] = "plugins/CoreHome/stylesheets/dataTable.less"; $cssFiles[] = "plugins/CoreHome/stylesheets/cloud.less"; $cssFiles[] = "plugins/CoreHome/stylesheets/jquery.ui.autocomplete.css"; - $cssFiles[] = "plugins/CoreHome/stylesheets/jqplot.css"; + $cssFiles[] = "plugins/CoreHome/stylesheets/jqplotColors.less"; + $cssFiles[] = "plugins/CoreHome/stylesheets/sparklineColors.less"; $cssFiles[] = "plugins/CoreHome/stylesheets/promo.less"; $cssFiles[] = "plugins/CoreHome/stylesheets/color_manager.css"; + $cssFiles[] = "plugins/CoreHome/stylesheets/sparklineColors.less"; } public function getJsFiles(&$jsFiles) @@ -61,11 +65,14 @@ class CoreHome extends \Piwik\Plugin $jsFiles[] = "libs/jquery/jquery.truncate.js"; $jsFiles[] = "libs/jquery/jquery.scrollTo.js"; $jsFiles[] = "libs/jquery/jquery.history.js"; + $jsFiles[] = "libs/jquery/jquery.jscrollpane.js"; + $jsFiles[] = "libs/jquery/jquery.mousewheel.js"; + $jsFiles[] = "libs/jquery/mwheelIntent.js"; $jsFiles[] = "libs/javascript/sprintf.js"; $jsFiles[] = "plugins/Zeitgeist/javascripts/piwikHelper.js"; $jsFiles[] = "plugins/Zeitgeist/javascripts/ajaxHelper.js"; - $jsFiles[] = "plugins/CoreHome/javascripts/datatable.js"; - $jsFiles[] = "plugins/CoreHome/javascripts/datatable_rowactions.js"; + $jsFiles[] = "plugins/CoreHome/javascripts/dataTable.js"; + $jsFiles[] = "plugins/CoreHome/javascripts/dataTable_rowactions.js"; $jsFiles[] = "plugins/CoreHome/javascripts/popover.js"; $jsFiles[] = "plugins/CoreHome/javascripts/broadcast.js"; $jsFiles[] = "plugins/CoreHome/javascripts/menu.js"; @@ -74,11 +81,10 @@ class CoreHome extends \Piwik\Plugin $jsFiles[] = "plugins/CoreHome/javascripts/autocomplete.js"; $jsFiles[] = "plugins/CoreHome/javascripts/sparkline.js"; $jsFiles[] = "plugins/CoreHome/javascripts/corehome.js"; - $jsFiles[] = "plugins/CoreHome/javascripts/datatable_manager.js"; + $jsFiles[] = "plugins/CoreHome/javascripts/dataTable_manager.js"; $jsFiles[] = "plugins/CoreHome/javascripts/donate.js"; - $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"; } -} +}
\ No newline at end of file diff --git a/plugins/CoreHome/DataTableRowAction/MultiRowEvolution.php b/plugins/CoreHome/DataTableRowAction/MultiRowEvolution.php index c2a7506147..0af3a81115 100644 --- a/plugins/CoreHome/DataTableRowAction/MultiRowEvolution.php +++ b/plugins/CoreHome/DataTableRowAction/MultiRowEvolution.php @@ -19,8 +19,6 @@ use Piwik\ViewDataTable; class Piwik_CoreHome_DataTableRowAction_MultiRowEvolution extends Piwik_CoreHome_DataTableRowAction_RowEvolution { - const IS_MULTI_EVOLUTION_PARAM = 'is_multi_evolution'; - /** The requested metric */ protected $metric; @@ -72,17 +70,4 @@ class Piwik_CoreHome_DataTableRowAction_MultiRowEvolution return parent::renderPopover($controller, $view); } - - /** - * Generic method to get an evolution graph or a sparkline for the row evolution popover. - * Do as much as possible from outside the controller. - * - * @return ViewDataTable - */ - public function getRowEvolutionGraph($graphType = false, $metrics = false) - { - $view = parent::getRowEvolutionGraph($graphType, $metrics); - $view->custom_parameters[self::IS_MULTI_EVOLUTION_PARAM] = 1; // set in JS - return $view; - } } diff --git a/plugins/CoreHome/DataTableRowAction/RowEvolution.php b/plugins/CoreHome/DataTableRowAction/RowEvolution.php index 37e6e52439..c23235009c 100644 --- a/plugins/CoreHome/DataTableRowAction/RowEvolution.php +++ b/plugins/CoreHome/DataTableRowAction/RowEvolution.php @@ -15,8 +15,8 @@ use Piwik\Metrics; use Piwik\Date; use Piwik\ViewDataTable; use Piwik\Url; -use Piwik\ViewDataTable\GenerateGraphHTML\ChartEvolution; use Piwik\Visualization\Chart\Evolution; +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution as EvolutionViz; /** * ROW EVOLUTION @@ -52,7 +52,7 @@ class Piwik_CoreHome_DataTableRowAction_RowEvolution /** * The data - * @var DataTable + * @var Piwik\DataTable */ protected $dataTable; @@ -98,8 +98,7 @@ class Piwik_CoreHome_DataTableRowAction_RowEvolution if ($this->period != 'range') { // handle day, week, month and year: display last X periods $end = $date->toString(); - list($this->date, $lastN) = - ChartEvolution::getDateRangeAndLastN($this->period, $end); + list($this->date, $lastN) = EvolutionViz::getDateRangeAndLastN($this->period, $end); } $this->segment = \Piwik\API\Request::getRawSegmentFromRequest(); @@ -180,29 +179,33 @@ class Piwik_CoreHome_DataTableRowAction_RowEvolution /** * Generic method to get an evolution graph or a sparkline for the row evolution popover. * Do as much as possible from outside the controller. + * @param string|bool $graphType + * @param array|bool $metrics * @return ViewDataTable */ public function getRowEvolutionGraph($graphType = false, $metrics = false) { // set up the view data table - $view = ViewDataTable::factory( - $graphType ?: $this->graphType, $this->apiMethod, $controllerAction = 'CoreHome.getRowEvolutionGraph'); + $view = ViewDataTable::factory($graphType ?: $this->graphType, $this->apiMethod, + $controllerAction = 'CoreHome.getRowEvolutionGraph', $forceDefault = true); $view->setDataTable($this->dataTable); if (!empty($this->graphMetrics)) { // In row Evolution popover, this is empty $view->columns_to_display = array_keys($metrics ?: $this->graphMetrics); } + $view->show_goals = false; $view->show_all_views_icons = false; $view->show_active_view_icon = false; $view->show_related_reports = false; + $view->visualization_properties->show_series_picker = false; foreach ($this->availableMetrics as $metric => $metadata) { $view->translations[$metric] = $metadata['name']; } - $view->external_series_toggle = 'RowEvolutionSeriesToggle'; - $view->external_series_toggle_show_all = $this->initiallyShowAllMetrics; + $view->visualization_properties->external_series_toggle = 'RowEvolutionSeriesToggle'; + $view->visualization_properties->external_series_toggle_show_all = $this->initiallyShowAllMetrics; return $view; } @@ -269,10 +272,9 @@ class Piwik_CoreHome_DataTableRowAction_RowEvolution { // sparkline is always echoed, so we need to buffer the output $view = $this->getRowEvolutionGraph($graphType = 'sparkline', $metrics = array($metric => $metric)); - $view->main(); ob_start(); - $view->getView()->render(); + $view->render(); $spark = ob_get_contents(); ob_end_clean(); diff --git a/plugins/CoreHome/javascripts/autocomplete.js b/plugins/CoreHome/javascripts/autocomplete.js index d30197e8d0..2679865a55 100644 --- a/plugins/CoreHome/javascripts/autocomplete.js +++ b/plugins/CoreHome/javascripts/autocomplete.js @@ -147,26 +147,26 @@ $(function () { // close it $('body').on('mouseup', function (e) { var closestSelector = $(e.target).closest('.sites_autocomplete'); - if (closestSelector != selector) { - reset(selector); - $('.custom_select_block', selector).removeClass('custom_select_block_show'); + if (!closestSelector.length || !closestSelector.is(selector)) { + if ($('.custom_select_block', selector).hasClass('custom_select_block_show')) { + reset(selector); + $('.custom_select_block', selector).removeClass('custom_select_block_show'); + }1 } }); // set event handling code for non-jquery-autocomplete parts of widget if ($('li', selector).length > 1) { // event handler for when site selector is clicked. shows dropdown w/ first X sites - $(".custom_select_main_link", selector).click(function () { - $(".custom_select_block", selector).addClass("custom_select_block_show"); - $('.custom_select_ul_list', selector).show(); - $('.websiteSearch', selector).val('').focus(); + $(".custom_select_main_link", selector).click(function() { + $(".custom_select_block", selector).toggleClass("custom_select_block_show"); + $(".websiteSearch", selector).val("").focus(); return false; }); - $('.custom_select_block', selector).on('mouseenter', function () { - $('.custom_select_ul_list li a', selector).each(function () { + $('.custom_select_block', selector).on('mouseenter', function() { + $('.custom_select_ul_list > li > a', selector).each(function() { var idSite = $(this).attr('siteid'); - var linkUrl = getUrlForWebsiteId(idSite); $(this).attr('href', linkUrl); }); @@ -174,7 +174,7 @@ $(function () { // change selection. fire's site selector's on select event and modifies the attributes // of the selected link - $('.custom_select_ul_list li a', selector).each(function () { + $('.custom_select_ul_list li a', selector).each(function() { $(this).click(function (e) { var idsite = $(this).attr('siteid'), name = $(this).text(); @@ -201,9 +201,6 @@ $(function () { $(".custom_select_block", selector).css('width', widthSitesSelection); } } - else { - $('.custom_select_main_link', selector).addClass('noselect'); - } // handle multi-sites link click (triggers site selected event w/ id=all) $('.custom_select_all', selector).click(function () { diff --git a/plugins/CoreHome/javascripts/calendar.js b/plugins/CoreHome/javascripts/calendar.js index 44bf7b9d17..e0580b1be0 100644 --- a/plugins/CoreHome/javascripts/calendar.js +++ b/plugins/CoreHome/javascripts/calendar.js @@ -16,7 +16,7 @@ daysSinceYearStart = (this_utc - onejan_utc) / 86400000; // constant is millisecs in one day return Math.ceil((daysSinceYearStart + onejan.getDay()) / 7); - } + }; var currentYear, currentMonth, currentDay, currentDate, currentWeek; @@ -449,7 +449,8 @@ }); $('body').on('click', function(e) { - if (!$(e.target).parents('#periodString').length && !$(e.target).is('#periodString') && !$(e.target).is('option') && $("#periodMore").is(":visible")) { + var target = $(e.target); + if (target.closest('html').length && !target.closest('#periodString').length && !target.is('option') && $("#periodMore").is(":visible")) { $("#periodMore").hide(); } }); @@ -532,8 +533,7 @@ return !isNaN(d.getTime()); } - var period = broadcast.getValueFromUrl('period'); - if (period == 'range') { + if (piwik.period == 'range') { $("#period_id_range").click(); } }); diff --git a/plugins/CoreHome/javascripts/datatable.js b/plugins/CoreHome/javascripts/dataTable.js index bf85c07d1c..8c229be1f3 100644 --- a/plugins/CoreHome/javascripts/datatable.js +++ b/plugins/CoreHome/javascripts/dataTable.js @@ -282,22 +282,20 @@ dataTable.prototype = $('.limitSelection ul li:last', domElem).addClass('last'); if (!self.isEmpty) { - var show = function () { + var show = function() { $('.limitSelection ul', domElem).show(); $('.limitSelection', domElem).addClass('visible'); - $(document).on('mouseup.limitSelection', function (e) { - if ((!$(e.target).parents('.limitSelection').length - || $(e.target).parents('.limitSelection') != $('.limitSelection', domElem)) - && !$(e.target).is('.limitSelection')) { + $(document).on('mouseup.limitSelection', function(e) { + if (!$(e.target).closest('.limitSelection').length) { hide(); } }); - } + }; var hide = function () { $('.limitSelection ul', domElem).hide(); $('.limitSelection', domElem).removeClass('visible'); $(document).off('mouseup.limitSelection'); - } + }; $('.limitSelection div', domElem).on('click', function () { $('.limitSelection', domElem).is('.visible') ? hide() : show(); }); @@ -363,11 +361,13 @@ dataTable.prototype = var imageSortSrc = getSortImageSrc(); var imageSortWidth = 16; var imageSortHeight = 16; + var ImageSortClass = self.param.filter_sort_order.charAt(0).toUpperCase() + self.param.filter_sort_order.substr(1); + // we change the style of the column currently used as sort column // adding an image and the class columnSorted to the TD $(".sortable#" + self.param.filter_sort_column + ' #thDIV', domElem).parent() .addClass('columnSorted') - .prepend('<div id="sortIconContainer"><img id="sortIcon" width="' + imageSortWidth + '" height="' + imageSortHeight + '" src="' + imageSortSrc + '" /></div>'); + .prepend('<div class="sortIconContainer sortIconContainer' + ImageSortClass + '"><img class="sortIcon" width="' + imageSortWidth + '" height="' + imageSortHeight + '" src="' + imageSortSrc + '" /></div>'); } } }, @@ -391,10 +391,10 @@ dataTable.prototype = currentPattern = piwikHelper.htmlDecode(currentPattern); $('.dataTableSearchPattern', domElem) - .show() + .css({display: 'block'}) .each(function () { // when enter is pressed in the input field we submit the form - $('#keyword', this) + $('.searchInput', this) .on("keyup", function (e) { if (isEnterKey(e)) { @@ -407,7 +407,7 @@ dataTable.prototype = $(':submit', this).submit( function () { - var keyword = $(this).siblings('#keyword').val(); + var keyword = $(this).siblings('.searchInput').val(); self.param.filter_offset = 0; if (self.param.search_recursive) { @@ -436,10 +436,10 @@ dataTable.prototype = <img src="plugins/CoreHome/images/reset_search.png" style="position: absolute; top: 4px; left: -15px; cursor: pointer; display: inline;" title="Clear" />\ </span>') .click(function () { - $('#keyword', target).val(''); + $('.searchInput', target).val(''); $(':submit', target).submit(); }); - $('#keyword', this).after(clearImg); + $('.searchInput', this).after(clearImg); } } @@ -457,7 +457,7 @@ dataTable.prototype = var totalRows = Number(self.param.totalRows); var offsetEndDisp = offsetEnd; - if (self.param.keep_summary_row == 1) --totalRows; + if (self.props.keep_summary_row == 1) --totalRows; if (offsetEnd > totalRows) offsetEndDisp = totalRows; @@ -475,7 +475,7 @@ dataTable.prototype = var offsetEnd = Number(self.param.filter_offset) + Number(self.param.filter_limit); var totalRows = Number(self.param.totalRows); - if (self.param.keep_summary_row == 1) --totalRows; + if (self.props.keep_summary_row == 1) --totalRows; if (offsetEnd < totalRows) { $(this).css('display', 'inline'); } @@ -726,7 +726,7 @@ dataTable.prototype = self.reloadAjaxDataTable(); self.notifyWidgetParametersChange($(this), {viewDataTable: self.param.viewDataTable}); } - ) + ); //handle Graph View icons $('.tableGraphViews a', domElem) @@ -781,7 +781,7 @@ dataTable.prototype = }); self.exportToFormatHide(domElem); }, - function () { + function() { //Graph icon onmouseout if (self.graphViewStartingKeep) return self.graphViewStartingKeep = false; //exit while icons animate $('a', this).each(function (i) { @@ -876,16 +876,14 @@ dataTable.prototype = str += '&filter_limit=' + filter_limit; } if (label) { - if (self.param.is_multi_evolution) { - label = label.split(','); - } + label = label.split(','); - if (label instanceof Array) { + if (label.length > 1) { for (var i = 0; i != label.length; ++i) { str += '&label[]=' + encodeURIComponent(label[i]); } } else { - str += '&label=' + encodeURIComponent(label); + str += '&label=' + encodeURIComponent(label[0]); } } return str; @@ -1151,8 +1149,8 @@ dataTable.prototype = $("th:first-child", domElem).addClass('label'); $("td:first-child:odd", domElem).addClass('label labeleven'); $("td:first-child:even", domElem).addClass('label labelodd'); - $("tr:odd td", domElem).slice(1).addClass('columnodd'); - $("tr:even td", domElem).slice(1).addClass('columneven'); + $("tr:odd td", domElem).slice(1).addClass('column columnodd'); + $("tr:even td", domElem).slice(1).addClass('column columneven'); $('td span.label', domElem).each(function () { self.truncate($(this)); }); @@ -1193,7 +1191,7 @@ dataTable.prototype = self.param.enable_filter_excludelowpop = filtersToRestore.enable_filter_excludelowpop; self.param.idSubtable = idSubTable; - self.param.action = self.param.controllerActionCalledWhenRequestSubTable; + self.param.action = self.props.subtable_controller_action; delete self.param.totalRows; @@ -1429,8 +1427,8 @@ dataTable.prototype = doHandleRowActions: function (trs) { var self = this; - var availableActionsForReport = DataTable_RowActions_Registry - .getAvailableActionsForReport(self.param); + var merged = $.extend({}, self.param, self.props); + var availableActionsForReport = DataTable_RowActions_Registry.getAvailableActionsForReport(merged); if (availableActionsForReport.length == 0) { return; @@ -1712,6 +1710,8 @@ actionDataTable.prototype = // label (first column of a data row) or not $("td:first-child:odd", this).addClass('label labeleven'); $("td:first-child:even", this).addClass('label labelodd'); + $("tr:odd td", domElem).slice(1).addClass('column columnodd'); + $("tr:even td", domElem).slice(1).addClass('column columneven'); }); }, @@ -1761,7 +1761,7 @@ actionDataTable.prototype = this.param['enable_filter_excludelowpop'] = filtersToRestore['enable_filter_excludelowpop']; self.param.idSubtable = idSubTable; - self.param.action = self.param.controllerActionCalledWhenRequestSubTable; + self.param.action = self.props.subtable_controller_action; self.reloadAjaxDataTable(false, function (resp) { self.actionsSubDataTableLoaded(resp, idSubTable); diff --git a/plugins/CoreHome/javascripts/datatable_manager.js b/plugins/CoreHome/javascripts/dataTable_manager.js index a1ea816484..e2f81250ca 100644 --- a/plugins/CoreHome/javascripts/datatable_manager.js +++ b/plugins/CoreHome/javascripts/dataTable_manager.js @@ -51,10 +51,8 @@ $('div.dataTable').each(function () { if (!$(this).attr('id')) { var params = JSON.parse($(this).attr('data-params') || '{}'); - var tableType = $(this).attr('data-table-type'); - if (!tableType) { - tableType = 'dataTable'; - } + var props = JSON.parse($(this).attr('data-props') || '{}'); + var tableType = $(this).attr('data-table-type') || 'dataTable'; // convert values in params that are arrays to comma separated string lists for (var key in params) { @@ -63,7 +61,7 @@ } } - self.initSingleDataTable(this, window[tableType], params); + self.initSingleDataTable(this, window[tableType], params, props); } }); }, @@ -74,8 +72,9 @@ * @param {Element} domElem The DataTable div element. * @param {Function} klass The DataTable's JS class. * @param {Object} params The request params used. + * @param {Object} props The view properties that should be visible to the JS. */ - initSingleDataTable: function (domElem, klass, params) { + initSingleDataTable: function (domElem, klass, params, props) { var newId = this.getNextId(); $(domElem).attr('id', newId); @@ -84,6 +83,7 @@ $(domElem).data('dataTableInstance', table); table.param = params; + table.props = props; table.init(newId); // if the datatable has a graph, init the graph diff --git a/plugins/CoreHome/javascripts/datatable_rowactions.js b/plugins/CoreHome/javascripts/dataTable_rowactions.js index ab5fb7b7b2..ab5fb7b7b2 100644 --- a/plugins/CoreHome/javascripts/datatable_rowactions.js +++ b/plugins/CoreHome/javascripts/dataTable_rowactions.js diff --git a/plugins/CoreHome/javascripts/menu.js b/plugins/CoreHome/javascripts/menu.js index 4a00c16ff0..d83ddb718f 100644 --- a/plugins/CoreHome/javascripts/menu.js +++ b/plugins/CoreHome/javascripts/menu.js @@ -28,9 +28,10 @@ menu.prototype = outMainLI: function () { clearTimeout(menu.prototype.resetTimer); - menu.prototype.resetTimer = setTimeout(function () { - $('.nav>.sfHover').removeClass('sfHover'); - $('.nav>.sfActive').addClass('sfHover'); + menu.prototype.resetTimer = setTimeout(function() { + $('.nav_tab > .sfHover').removeClass('sfHover'); + $('.nav_tab > .sfActive').addClass('sfHover'); + menu.prototype.adaptSubMenuHeight(); }, 2000); }, diff --git a/plugins/CoreHome/javascripts/popover.js b/plugins/CoreHome/javascripts/popover.js index 4287782142..27c07dc334 100644 --- a/plugins/CoreHome/javascripts/popover.js +++ b/plugins/CoreHome/javascripts/popover.js @@ -17,10 +17,11 @@ var Piwik_Popover = (function () { } }; - var openPopover = function (title) { + var openPopover = function (title, dialogClass) { createContainer(); - container.dialog({ + var options = + { title: title, modal: true, width: '950px', @@ -28,6 +29,10 @@ var Piwik_Popover = (function () { resizable: false, autoOpen: true, open: function (event, ui) { + if (dialogClass) { + $(this).parent().addClass(dialogClass).attr('style', ''); + } + $('.ui-widget-overlay').on('click.popover', function () { container.dialog('close'); }); @@ -45,7 +50,9 @@ var Piwik_Popover = (function () { closeCallback = false; } } - }); + }; + + container.dialog(options); // override the undocumented _title function to ensure that the title attribute is not escaped (according to jQueryUI bug #6016) container.data( "uiDialog" )._title = function(title) { @@ -70,7 +77,7 @@ var Piwik_Popover = (function () { * @param {string} [popoverSubject] subject of the popover (e.g. url, optional) * @param {int} [height] height of the popover in px (optional) */ - showLoading: function (popoverName, popoverSubject, height) { + showLoading: function (popoverName, popoverSubject, height, dialogClass) { var loading = $(document.createElement('div')).addClass('Piwik_Popover_Loading'); var loadingMessage = popoverSubject ? translations.General_LoadingPopoverFor_js : @@ -94,7 +101,7 @@ var Piwik_Popover = (function () { } if (!isOpen) { - openPopover(); + openPopover(null, dialogClass); } this.setContent(loading); @@ -203,9 +210,18 @@ var Piwik_Popover = (function () { * @param {string} url * @param {string} loadingName */ - createPopupAndLoadUrl: function (url, loadingName) { + createPopupAndLoadUrl: function (url, loadingName, dialogClass) { + // make sure the minimum top position of the popover is 106px + var ensureMinimumTop = function () { + var popoverContainer = $('#Piwik_Popover').parent(); + if (popoverContainer.position().top < 106) { + popoverContainer.css('top', '106px'); + } + }; + // open the popover - var box = Piwik_Popover.showLoading(loadingName); + var box = Piwik_Popover.showLoading(loadingName, null, null, dialogClass); + ensureMinimumTop(); var callback = function (html) { function setPopoverTitleIfOneFoundInContainer() { @@ -218,7 +234,8 @@ var Piwik_Popover = (function () { Piwik_Popover.setContent(html); setPopoverTitleIfOneFoundInContainer(); - } + ensureMinimumTop(); + }; var ajaxRequest = new ajaxHelper(); ajaxRequest.addParams(piwikHelper.getArrayFromQueryString(url), 'get'); ajaxRequest.setCallback(callback); @@ -226,6 +243,4 @@ var Piwik_Popover = (function () { ajaxRequest.send(false); } }; - -})(); - +})();
\ No newline at end of file diff --git a/plugins/CoreHome/javascripts/sparkline.js b/plugins/CoreHome/javascripts/sparkline.js index 6093955eeb..5b308c9606 100644 --- a/plugins/CoreHome/javascripts/sparkline.js +++ b/plugins/CoreHome/javascripts/sparkline.js @@ -7,15 +7,15 @@ (function ($) { -var sparklineColorNames = ['lineColor', 'red', 'blue', 'green']; +var sparklineColorNames = ['backgroundColor', 'lineColor', 'minPointColor', 'maxPointColor', 'lastPointColor']; piwik.getSparklineColors = function () { return piwik.ColorManager.getColors('sparkline-colors', sparklineColorNames); }; // initializes each sparkline so they use colors defined in CSS -piwik.initSparklines = function () { - $('img.sparkline').each(function () { +piwik.initSparklines = function() { + $('.sparkline > img').each(function () { var $self = $(this); if ($self.attr('src')) { @@ -36,7 +36,7 @@ window.initializeSparklines = function () { // try to find sparklines and add them clickable behaviour graph.parent().find('div.sparkline').each(function () { // find the sparkline and get it's src attribute - var sparklineUrl = $('img.sparkline', this).attr('data-src'); + var sparklineUrl = $('img', this).attr('data-src'); if (sparklineUrl != "") { var params = broadcast.getValuesFromUrl(sparklineUrl); @@ -62,7 +62,7 @@ window.initializeSparklines = function () { // if this happens, we can't find the graph using $('#'+idDataTable+"Chart"); // instead, we just use the first evolution graph we can find. if (dataTable.length == 0) { - dataTable = $('div.dataTableEvolutionGraph'); + dataTable = $('div.dataTableVizEvolution'); } // reload the datatable w/ a new column & scroll to the graph diff --git a/plugins/CoreHome/stylesheets/coreHome.less b/plugins/CoreHome/stylesheets/coreHome.less index 041bc1a936..2c82ad95b4 100644 --- a/plugins/CoreHome/stylesheets/coreHome.less +++ b/plugins/CoreHome/stylesheets/coreHome.less @@ -159,7 +159,7 @@ div.pk-emptyGraph { line-height: 20px; font-weight: normal; text-align: center; - background: url(../../Zeitgeist/images/loading-blue.gif) no-repeat center 20px; + background: url(plugins/Zeitgeist/images/loading-blue.gif) no-repeat center 20px; } .Piwik_Popover_Loading_NameWithSubject { diff --git a/plugins/CoreHome/stylesheets/dataTable.less b/plugins/CoreHome/stylesheets/dataTable.less index 239d0c8423..d3760872fd 100644 --- a/plugins/CoreHome/stylesheets/dataTable.less +++ b/plugins/CoreHome/stylesheets/dataTable.less @@ -1,781 +1,10 @@ -.widget { - z-index: 1; -} - -.widget p { - margin-left: 10px; -} - -/* container of each table */ -.dataTableVizHtmlTable > .dataTableWrapper { - width: 450px; - /* not more than 450px to make sure 2 tables can fit horizontally on a 1024 screen */ -} - -.dataTableAllColumns > .dataTableWrapper { - width: 535px; -} - -.dataTableActions > .dataTableWrapper { - width: 500px; - min-height: 1px; -} - -.subDataTable > .dataTableWrapper { - width: 95%; -} - -.dataTableGraph > .dataTableWrapper { - width: 500px; - min-height: 1px; -} - -.dataTableEvolutionGraph > .dataTableWrapper { - width: 100%; -} - -/*Overriding some dataTable css for better dashboard display*/ -.widget .dataTableWrapper { - width: 100%; -} - -/* main data table */ -table.dataTable { - border: 0; - width: 100%; - padding: 0; - border-spacing: 0; - margin: 0; -} - -table.dataTable td.label, -table.subDataTable td.label { - width: 100%; - white-space: nowrap; -} - -table.dataTable img, -table.subDataTable img { - vertical-align: middle; -} - -#UserCountrygetCountry table.dataTable img { - vertical-align: baseline; -} - -table.dataTable img { - border: 0; - margin-right: 1em; - margin-left: 0.5em; -} - -table.dataTable tr.subDataTable { - cursor: pointer; -} - -table.dataTable th { - margin: 0; - color: #255792; - text-align: left; - padding: 6px 6px 6px 12px; - background: #e4e2d7; - font-size: 12px; - font-weight: normal; - border-left: 1px solid #d4d0c4; - vertical-align: top; -} - -table.dataTable th.sortable { - cursor: pointer; -} - -table.dataTable th.first { -} - -table.dataTable th.last { -} - -table.dataTable th.columnSorted { - font-weight: bold; - padding-right: 20px; - background: #d5d3c8; -} - -table.dataTable td { - padding: 5px 5px 5px 12px; - background: #fff; - border-left: 1px solid #e7e7e7; - border-bottom: 1px solid #e7e7e7; -} - -table.dataTable td, table.dataTable td a { - margin: 0; - text-decoration: none; - color: #444; -} - -table.dataTable tr:hover>td, -table.dataTable tr:hover>td .dataTableRowActions { - background-color: #FFFFF7; -} - -table.dataTable tr.subDataTable:hover>td, -table.dataTable tr.subDataTable:hover>td .dataTableRowActions { - background-color: #ffffcb; -} - -table.dataTable tr:hover>td.cellSubDataTable -table.dataTable tr:hover>td.cellSubDataTable .dataTableRowActions { - background-color: #fff; -} - -td.clean { - background-color: #fff !important; -} - -table.dataTable td.columneven { - background: #efeeec; -} - -table.dataTable td.columnodd { - background: #f6f5f3; -} - -table.dataTable td.labeleven { - background: #F9FAFA url(../images/bullet2.gif) no-repeat; -} - -table.dataTable td.labelodd { - background: #fff url(../images/bullet1.gif) no-repeat; -} - -.dataTable tr.highlight td { - background-color: #ECF9DD; - font-weight: bold; -} - -table.dataTable td.label, table.subActionsDataTable td.label, table.actionsDataTable td.label { - border-top: 0; - border-left: 0; -} - -table.dataTable th.label { - border-left: 0; -} - -.dataTableActions table.dataTable th.label { - /* Ensures tables have enough space to display subtable on click, and prevent the jumping effect */ - min-width: 250px; -} - -table.dataTable span.label.highlighted { - font-style: italic; -} - -/* the cell containing the subdatatable */ -table.dataTable .cellSubDataTable { - margin: 0; - border-left: 0; -} - -/* A link in a column in the DataTable */ -table.dataTable td #urlLink { - display: none; -} - -/* SUBDATATABLE */ -/* a datatable inside another datatable */ -table.subDataTable { - background: #FFFFFF; - margin: 5px 10px; -} - -table.subDataTable td { - border: 0; -} - -table.subDataTable thead th { - font-weight: normal; - font-size: 12px; - text-align: left; - padding: .3em 1em; - background: #f1f0eb; - border: 0; - border-top: 1px solid #e7e7e7; - border-bottom: 1px solid #e7e7e7; -} - -table.subDataTable th.columnSorted { - background: #e3e1d9; -} - -table.subDataTable td.labeleven, table.subDataTable td.labelodd { - background-image: none; -} - -table.subDataTable td { - border-bottom: 1px solid #e7e7e7; - border-left: 0; -} - -table.subDataTable td, table.subDataTable td a { - color: #615B53; -} - -table.subDataTable td.labeleven, table.subDataTable td.columneven { - color: #2D2A27; -} - -table.subDataTable td.label { - width: 80%; -} - -table.subDataTable td.labelodd, table.subDataTable td.labelodd a { - background: #fff; -} - -table.subDataTable td.label { - padding: 5px; -} - -table.dataTable img { - margin-left: 0; -} - -/* misc SPAN and DIV */ -table thead div { - -} - -#sortIconContainer { - float: right; - position: relative; -} - -#sortIcon { - margin: 0; - position: absolute; -} - -.datatableFooterMessage { - color: #888; - text-align: left; - margin: 10px; -} - -.dataTablePages { - color: #BFBFBF; - font-weight: bold; - margin: 10px; - font-size: 12px; -} - -.dataTableSearchPattern { - margin: 8px 0 0 0; - height: 30px; - display: block !important; - white-space: nowrap; - background: url(../../Zeitgeist/images/search_bg.png) no-repeat center 0; - text-align: center; -} - -.dataTableSearchPattern input { - vertical-align: top; - font-size: 10px !important; - color: #454545 !important; - border: 0 !important; - background: transparent !important; - width: 21px; - height: 17px; - overflow: hidden; - opacity: 0; - filter: Alpha(opacity=0); - cursor: pointer; -} - -.dataTableSearchPattern input:hover { - -} - -.dataTableSearchPattern #keyword { - width: 114px; - height: auto; - overflow: visible; - padding: 2px 6px; - opacity: 1; - cursor: text; - filter: Alpha(opacity=100); -} - -.dataTableNext, .dataTablePrevious { - font-size: 12px; - color: #184A83; - cursor: pointer; -} - -.datatableRelatedReports { - color: #888; - font-size: 11px; - padding-bottom: 5px; -} - -.datatableRelatedReports span { - cursor: pointer; - font-weight: bold; -} - -/* are the following two supposed to be together? */ -.subDataTable.dataTableFeatures { - padding-top: 0; - padding-bottom: 5px; -} - -.dataTableFeatures { - padding-top: 10px; - text-align: center; -} - -.dataTableNext, .dataTablePrevious, .dataTableSearchPattern { - display: none; -} - -.dataTableFeatures .loadingPiwik { - font-size: 0.9em; -} - -.subDataTable .dataTableFooterIcons { - height: 0; -} - -.dataTable .loadingPiwikBelow { - padding-bottom: 5px; - display: block; - text-align: center; -} - -.dataTableFooterIcons { - display: block; - height: 20px; - white-space: nowrap; - font-size: 10px; - padding: 6px 5px; - border-top: 1px solid #B6B0A6; -} - -.dataTableFooterWrap { - position: relative; - float: left; -} - -.dataTableFooterWrap select { - float: left; - margin: 1px 0 1px 10px; -} - -.tableIcon { - background: #f2f1ed; - display: inline-block; - float: left; - margin: 0 1px 0 0; - padding: 2px; - border-radius: 2px; -} - -.tableIcon:hover { - background: #e9e8e1; -} - -.activeIcon { - background: #e9e8e1; -} - -.dataTableFooterActiveItem { - position: absolute; - top: -6px; - left: 0; -} - -.exportToFormatItems { - background: #dcdacf; - float: left; - margin: 0 1px 0 0; - padding: 4px 6px 3px 6px; - color: #968d7f; - border-radius: 2px; -} - -.exportToFormatItems img { - vertical-align: middle; - margin: -4px -3px -2px 2px; -} - -.tableIconsGroup { - float: left; - padding-right: 4px; -} - -.tableIconsGroup .tableIcon span { - margin-right: 5px; - margin-left: 5px; -} - -.tableIconsGroup img { - vertical-align: bottom; -} - -.tableIconsGroupActive { - display: block; - float: left; - background: #dcdacf; - border-radius: 2px; -} - -.tableIconsGroupActive .tableIcon { - background: none; -} - -.tableIconsGroupActive .tableIcon:hover { - background: #e9e8e1; -} - -.exportToFormatIcons { - float: left; -} - -.dataTableFooterIconsShow { - float: left; -} - -.dataTableFooterIcons, .dataTableFooterIcons a { - text-decoration: none; - color: #255792; -} - -.dataTableSpacer { - clear: both; -} - -/* Actions table */ -.dataTableActions table.dataTable tr td.labelodd { - background-image: none; -} - -/* levels higher than 4 have a default padding left */ -.actionsDataTable tr td.label { - padding-left: 7em; -} - -tr.level0 td.label { - padding-left: 1.5em; -} - -tr.level1 td.label { - padding-left: 2.5em; -} - -tr.level2 td.label { - padding-left: 3.5em; -} - -tr.level3 td.label { - padding-left: 4.5em; -} - -tr.level4 td.label { - padding-left: 5em; -} - -/* less right margins for the link image in the Pa*/ -.dataTableActions table.dataTable img.link { - margin-right: 0.3em; - margin-left: -0.5em; -} - -tr td.label img.plusMinus { - margin-left: -1em; - margin-right: 3px; -} - -.pk-emptyDataTable { - padding-top: 20px; - padding-bottom: 10px; - text-align: center; - font-style: italic; -} - -/* Documentation */ - -table.dataTable th .columnDocumentation { - display: none; - width: 165px; - text-align: left; - background: #f7f7f7; - color: #444; - font-size: 11px; - font-weight: normal; - border: 1px solid #e4e5e4; - padding: 5px 10px 6px 10px; - border-radius: 4px; - z-index: 125; - position: absolute; - box-shadow: 0 0 4px #e4e5e4; - cursor: default; -} - -table.dataTable th .columnDocumentationTitle { - background: url(../../Zeitgeist/images/help.png) no-repeat; - line-height: 14px; - padding: 2px 0 3px 21px; - font-weight: bold; -} - -.reportDocumentation { - display: none; - background: #f7f7f7; - font-size: 12px; - font-weight: normal; - border: 1px solid #e4e5e4; - margin: 0 0 10px 0; - padding: 0; - border-radius: 4px; - max-width: 500px; -} - -.reportDocumentation p { - padding: 5px 10px 6px 10px; - margin: 0; - color: #444; - font-size: 12px; -} - -.reportDocumentationIcon { - display: block; - width: 16px; - height: 16px; - margin: 10px 0; - background: url(../../Zeitgeist/images/help.png) no-repeat; -} - -h2 .reportDocumentationIcon { - position: absolute; - margin: 4px 0 0 0; - display: none; - background: url(../../Zeitgeist/images/help_grey.png) no-repeat; -} - -h2 .reportDocumentationIcon.hidden { - background: none; -} - -.helpDate { - color: #777777; - font-size: 11px; - font-style: italic; - padding: 4px; - text-align: right; - display: block; -} - -table.dataTable .dataTableRowActions { - position: absolute; - display: none; - overflow: hidden; - margin-top: -5px; -} - -*+html table.dataTable .dataTableRowActions { - margin-top: -7px; -} - -table.dataTable .dataTableRowActions a { - display: block; - float: left; - padding: 6px 4px 6px 0; - margin: 0; -} - -table.dataTable .dataTableRowActions a.leftmost { - padding-left: 4px; -} - -table.dataTable .dataTableRowActions a.rightmost { - padding-right: 8px; -} - -table.dataTable .dataTableRowActions a img { - margin: 0; - padding: 0; - border: 0; - width: 20px; - height: 17px; -} - -body .ui-tooltip.rowActionTooltip { - font-size: 11px; - padding: 3px 5px 3px 6px; -} - -.limitSelection { - float: right; - position: relative; - margin-left: 5px; - min-height: 20px; - z-index: 1; -} - -.limitSelection.hidden { - display: none; -} - -.limitSelection div { - border: 1px solid #DFDFDF; - border-radius: 4px; - background: url(../../Zeitgeist/images/sort_subtable_desc_light.png) no-repeat right 2px; - padding: 0 14px 0 4px; - display: block; - width: 24px; - height: 20px; - cursor: pointer; -} - -.limitSelection.disabled div { - opacity: 0.5; - cursor: not-allowed; - filter: Alpha(opacity=50); -} - -.limitSelection.visible div { - border-radius: 0 0 4px 4px; - background-image: url(../../Zeitgeist/images/sort_subtable_asc_light.png) -} - -.limitSelection ul { - margin-top: 1px; - overflow: visible; - background-color: #fff; -} - -.limitSelection ul li { - cursor: pointer; - width: 28px; - padding: 0 10px 0 4px; - font-size: 1.1em; - font-weight: bold; - height: 20px; - margin-top: -40px; - background-color: #fff; - border-left: 1px solid #DFDFDF; - border-right: 1px solid #DFDFDF; - vertical-align: middle; - text-align: right; -} - -.limitSelection ul li.last { - border-top: 1px solid #DFDFDF; - border-radius: 4px 4px 0 0; -} - -.limitSelection ul li:hover { - background-color: #EBEAE6; -} - -.limitSelection span { - padding-top: 3px; - display: inline-block; -} - -.tableConfiguration { - float: right; - position: relative; - margin-left: 5px; - min-height: 20px; - min-width: 25px; -} - -a.tableConfigurationIcon { - display: block; - width: 30px; - height: 22px; - background: url(../../Zeitgeist/images/configure.png) no-repeat center 2px; - position: absolute; - z-index: 9; - right: 0; -} - -a.tableConfigurationIcon.highlighted { - display: block; - width: 30px; - height: 22px; - background-image: url(../../Zeitgeist/images/configure-highlight.png); - position: absolute; - z-index: 9; - right: 0; -} - -.tableConfiguration ul { - overflow: visible; - background-color: #fff; - display: none; - position: relative; - z-index: 8; - text-align: left; -} - -.tableConfiguration ul.open { - display: block; -} - -.tableConfiguration ul li { - padding: 0; - font-size: 1.1em; - height: 40px; - margin-top: -80px; - background-color: #fff; - border-left: 1px solid #DFDFDF; - border-right: 1px solid #DFDFDF; - vertical-align: middle; -} - -.tableConfiguration ul li.firstDummy { - border-bottom: 1px solid #DFDFDF; - border-radius: 0 0 4px 4px; - height: 25px; - cursor: default; - margin-top: -4px; -} - -.tableConfiguration ul li.first { - margin-top: -65px; -} - -.tableConfiguration ul li.last { - border-top: 1px solid #DFDFDF; - border-radius: 4px 4px 0 0; -} - -.tableConfiguration div.configItem { - cursor: pointer; - padding: 5px 10px; - line-height: 15px; - color: #444; -} - -.tableConfiguration div.configItem:hover { - background-color: #EBEAE6; -} - -.tableConfiguration div.configItem span.action { - color: #255792; -} - -table.dataTable span.cell-tooltip { - cursor: default; -} - -.dataTable .jqplot-graph { - padding-left: 6px; - - > div { - position: relative; - } -}
\ No newline at end of file +@dataTable-link-color: #255792; +@dataTable-header-background: #e4e2d7; +@dataTable-headerActive-background: #D5D3C8; + +@import "dataTable/_dataTable.less"; +@import "dataTable/_limitSelection.less"; +@import "dataTable/_reportDocumentation.less"; +@import "dataTable/_rowActions.less"; +@import "dataTable/_subDataTable.less"; +@import "dataTable/_tableConfiguration.less";
\ No newline at end of file diff --git a/plugins/CoreHome/stylesheets/dataTable/_dataTable.less b/plugins/CoreHome/stylesheets/dataTable/_dataTable.less new file mode 100644 index 0000000000..6083dd1cca --- /dev/null +++ b/plugins/CoreHome/stylesheets/dataTable/_dataTable.less @@ -0,0 +1,424 @@ +/* main data table */ +.dataTable { + border: 0; + width: 100%; + padding: 0; + border-spacing: 0; + margin: 0; +} + +table.dataTable td.label, +table.subDataTable td.label { + width: 100%; + white-space: nowrap; +} + +table.dataTable img, +table.subDataTable img { + vertical-align: middle; +} + +table.dataTable img { + border: 0; + margin-right: 1em; + margin-left: 0.5em; +} + +table.dataTable tr.subDataTable { + cursor: pointer; +} + +table.dataTable th { + margin: 0; + color: @dataTable-link-color; + text-align: left; + padding: 6px 6px 6px 12px; + background: @dataTable-header-background; + font-size: 12px; + font-weight: normal; + border-left: 1px solid #d4d0c4; + vertical-align: top; +} + +table.dataTable th.sortable { + cursor: pointer; +} + +table.dataTable th.columnSorted { + font-weight: bold; + padding-right: 20px; + background: @dataTable-headerActive-background; +} + +table.dataTable td { + padding: 5px 5px 5px 12px; + background: #fff; + border-left: 1px solid #e7e7e7; + border-bottom: 1px solid #e7e7e7; +} + +table.dataTable td, +table.dataTable td a { + margin: 0; + text-decoration: none; + color: #444; +} + +table.dataTable tr:hover > td, +table.dataTable tr:hover > td .dataTableRowActions { + background-color: #FFFFF7; +} + +table.dataTable tr.subDataTable:hover > td, +table.dataTable tr.subDataTable:hover > td .dataTableRowActions { + background-color: #ffffcb; +} + +table.dataTable tr:hover > td.cellSubDataTable +table.dataTable tr:hover > td.cellSubDataTable .dataTableRowActions { + background-color: #fff; +} + +td.clean { + background-color: #fff; +} + +table.dataTable td.columneven { + background: #efeeec; +} + +table.dataTable td.columnodd { + background: #f6f5f3; +} + +table.dataTable td.labeleven { + background: #F9FAFA url(plugins/CoreHome/images/bullet2.gif) no-repeat; +} + +table.dataTable td.labelodd { + background: #fff url(plugins/CoreHome/images/bullet1.gif) no-repeat; +} + +.dataTable tr.highlight td { + background-color: #ECF9DD; + font-weight: bold; +} + +table.dataTable td.label, +table.subActionsDataTable td.label, +table.actionsDataTable td.label { + border-top: 0; + border-left: 0; +} + +table.dataTable th.label { + border-left: 0; +} + +.dataTableActions table.dataTable th.label { + /* Ensures tables have enough space to display subtable on click, and prevent the jumping effect */ + min-width: 250px; +} + +table.dataTable span.label.highlighted { + font-style: italic; +} + +/* the cell containing the subdatatable */ +table.dataTable .cellSubDataTable { + margin: 0; + border-left: 0; + padding: 12px 12px 0; +} + +/* A link in a column in the DataTable */ +table.dataTable td #urlLink { + display: none; +} + +table.dataTable img { + margin-left: 0; +} + +.dataTable > .dataTableWrapper { + width: 450px; +} + +.subDataTable > .dataTableWrapper { + width: 95%; +} + +.sortIconContainer { + float: right; + position: relative; +} + +.sortIcon { + margin: 0; + position: absolute; +} + +.datatableFooterMessage { + color: #888; + text-align: left; + margin: 10px; +} + +.dataTablePages { + color: #BFBFBF; + font-weight: bold; + margin: 10px; + font-size: 12px; +} + +.dataTableSearchPattern { + margin: 5px 0 2px 0; + height: 20px; + display: block; + white-space: nowrap; + background: url(plugins/Zeitgeist/images/search_bg.png) no-repeat center 0; + text-align: center; +} + +.dataTableSearchPattern input { + vertical-align: top; + font-size: 10px; + color: #454545; + border: 0; + background: transparent; + width: 21px; + height: 17px; + overflow: hidden; + opacity: 0; + filter: Alpha(opacity=0); + cursor: pointer; +} + +.dataTableSearchPattern .searchInput { + width: 114px; + height: auto; + overflow: visible; + padding: 2px 6px; + opacity: 1; + cursor: text; + filter: Alpha(opacity=100); +} + +.dataTableNext, +.dataTablePrevious { + font-size: 12px; + color: #184A83; + cursor: pointer; +} + +.datatableRelatedReports { + color: #888; + font-size: 11px; + padding-bottom: 5px; +} + +.datatableRelatedReports span { + cursor: pointer; + font-weight: bold; +} + +.dataTableFeatures { + text-align: center; +} + +.dataTableFooterNavigation { + padding: 5px 0; +} + +.dataTableNext, +.dataTablePrevious, +.dataTableSearchPattern { + display: none; +} + +.dataTableFeatures .loadingPiwik { + font-size: 0.9em; +} + +.subDataTable .dataTableFooterIcons { + height: 0; +} + +.dataTable .loadingPiwikBelow { + padding-bottom: 5px; + display: block; + text-align: center; +} + +.dataTableFooterIcons { + display: block; + height: 20px; + white-space: nowrap; + font-size: 10px; + padding: 6px 5px; + border-top: 1px solid #B6B0A6; +} + +.dataTableFooterWrap { + position: relative; + float: left; +} + +.dataTableFooterWrap select { + float: left; + margin: 1px 0 1px 10px; +} + +.tableIcon { + background: #f2f1ed; + display: inline-block; + float: left; + margin: 0 1px 0 0; + padding: 2px; + border-radius: 2px; +} + +.tableIcon:hover { + background: #e9e8e1; +} + +.activeIcon { + background: #e9e8e1; +} + +.dataTableFooterActiveItem { + position: absolute; + top: -6px; + left: 0; +} + +.exportToFormatItems { + background: #dcdacf; + float: left; + margin: 0 1px 0 0; + padding: 4px 6px 3px 6px; + color: #968d7f; + border-radius: 2px; +} + +.exportToFormatItems img { + vertical-align: middle; + margin: -4px -3px -2px 2px; +} + +.tableIconsGroup { + float: left; + padding-right: 4px; +} + +.tableIconsGroup .tableIcon span { + margin-right: 5px; + margin-left: 5px; +} + +.tableIconsGroup img { + vertical-align: bottom; +} + +.tableIconsGroupActive { + display: block; + float: left; + background: #dcdacf; + border-radius: 2px; +} + +.tableIconsGroupActive .tableIcon { + background: none; +} + +.tableIconsGroupActive .tableIcon:hover { + background: #e9e8e1; +} + +.exportToFormatIcons, +.dataTableFooterIconsShow { + float: left; +} + +.dataTableFooterIcons, +.dataTableFooterIcons a { + text-decoration: none; + color: @dataTable-link-color; +} + +.dataTableSpacer { + clear: both; +} + +/* Actions table */ +.dataTableActions table.dataTable tr td.labelodd { + background-image: none; +} + +/* levels higher than 4 have a default padding left */ +.actionsDataTable tr td.label { + padding-left: 7em; +} + +tr.level0 td.label { + padding-left: 1.5em; +} + +tr.level1 td.label { + padding-left: 2.5em; +} + +tr.level2 td.label { + padding-left: 3.5em; +} + +tr.level3 td.label { + padding-left: 4.5em; +} + +tr.level4 td.label { + padding-left: 5em; +} + +/* less right margins for the link image in the Pa*/ +.dataTableActions table.dataTable img.link { + margin-right: 0.3em; + margin-left: -0.5em; +} + +tr td.label img.plusMinus { + margin-left: -1em; + margin-right: 3px; +} + +.pk-emptyDataTable { + padding-top: 20px; + padding-bottom: 10px; + text-align: center; + font-style: italic; +} + +.helpDate { + color: #777777; + font-size: 11px; + font-style: italic; + padding: 4px; + text-align: right; + display: block; +} + +body .ui-tooltip.rowActionTooltip { + font-size: 11px; + padding: 3px 5px 3px 6px; +} + +table.dataTable span.cell-tooltip { + cursor: default; +} + +.dataTable .jqplot-graph { + padding-left: 6px; + > div { + position: relative; + } +}
\ No newline at end of file diff --git a/plugins/CoreHome/stylesheets/dataTable/_limitSelection.less b/plugins/CoreHome/stylesheets/dataTable/_limitSelection.less new file mode 100644 index 0000000000..6d899d89ef --- /dev/null +++ b/plugins/CoreHome/stylesheets/dataTable/_limitSelection.less @@ -0,0 +1,68 @@ +.limitSelection { + float: right; + position: relative; + margin-left: 5px; + min-height: 20px; + z-index: 1; +} + +.limitSelection.hidden { + display: none; +} + +.limitSelection > div { + border: 1px solid #DFDFDF; + border-radius: 4px; + background: url(plugins/Zeitgeist/images/sort_subtable_desc_light.png) no-repeat right 2px; + padding: 0 14px 0 4px; + display: block; + width: 24px; + height: 20px; + cursor: pointer; +} + +.limitSelection.disabled > div { + opacity: 0.5; + cursor: not-allowed; + filter: Alpha(opacity=50); +} + +.limitSelection.visible > div { + border-radius: 0 0 4px 4px; + background-image: url(plugins/Zeitgeist/images/sort_subtable_asc_light.png) +} + +.limitSelection > ul { + margin-top: 1px; + overflow: visible; + background-color: #fff; +} + +.limitSelection > ul > li { + cursor: pointer; + width: 28px; + padding: 0 10px 0 4px; + font-size: 1.1em; + font-weight: bold; + height: 20px; + margin-top: -40px; + background-color: #fff; + border-left: 1px solid #DFDFDF; + border-right: 1px solid #DFDFDF; + vertical-align: middle; + text-align: right; +} + +.limitSelection > ul > li.last { + border-top: 1px solid #DFDFDF; + border-radius: 4px 4px 0 0; +} + +.limitSelection > ul > li:hover { + background-color: #EBEAE6; +} + +.limitSelection span { + padding-top: 3px; + display: inline-block; +}
\ No newline at end of file diff --git a/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less b/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less new file mode 100644 index 0000000000..1661ddb5ec --- /dev/null +++ b/plugins/CoreHome/stylesheets/dataTable/_reportDocumentation.less @@ -0,0 +1,62 @@ +/* Documentation */ +table.dataTable th .columnDocumentation { + display: none; + width: 165px; + text-align: left; + background: #f7f7f7; + color: #444; + font-size: 11px; + font-weight: normal; + border: 1px solid #e4e5e4; + padding: 5px 10px 6px 10px; + border-radius: 4px; + z-index: 125; + position: absolute; + box-shadow: 0 0 4px #e4e5e4; + cursor: default; +} + +table.dataTable th .columnDocumentationTitle { + background: url(plugins/Zeitgeist/images/help.png) no-repeat; + line-height: 14px; + padding: 2px 0 3px 21px; + font-weight: bold; +} + +.reportDocumentation { + display: none; + background: #f7f7f7; + font-size: 12px; + font-weight: normal; + border: 1px solid #e4e5e4; + margin: 0 0 10px 0; + padding: 0; + border-radius: 4px; + max-width: 500px; +} + +.reportDocumentation p { + padding: 5px 10px 6px 10px; + margin: 0; + color: #444; + font-size: 12px; +} + +.reportDocumentationIcon { + display: block; + width: 16px; + height: 16px; + margin: 10px 0; + background: url(plugins/Zeitgeist/images/help.png) no-repeat; +} + +h2 .reportDocumentationIcon { + position: absolute; + margin: 4px 0 0 0; + display: none; + background: url(plugins/Zeitgeist/images/help_grey.png) no-repeat; +} + +h2 .reportDocumentationIcon.hidden { + background: none; +}
\ No newline at end of file diff --git a/plugins/CoreHome/stylesheets/dataTable/_rowActions.less b/plugins/CoreHome/stylesheets/dataTable/_rowActions.less new file mode 100644 index 0000000000..55f9876e4c --- /dev/null +++ b/plugins/CoreHome/stylesheets/dataTable/_rowActions.less @@ -0,0 +1,35 @@ + + +table.dataTable .dataTableRowActions { + position: absolute; + display: none; + overflow: hidden; + margin-top: -5px; +} + +*+html table.dataTable .dataTableRowActions { + margin-top: -7px; +} + +table.dataTable .dataTableRowActions a { + display: block; + float: left; + padding: 6px 4px 6px 0; + margin: 0; +} + +table.dataTable .dataTableRowActions a.leftmost { + padding-left: 4px; +} + +table.dataTable .dataTableRowActions a.rightmost { + padding-right: 8px; +} + +table.dataTable .dataTableRowActions a img { + margin: 0; + padding: 0; + border: 0; + width: 20px; + height: 17px; +}
\ No newline at end of file diff --git a/plugins/CoreHome/stylesheets/dataTable/_subDataTable.less b/plugins/CoreHome/stylesheets/dataTable/_subDataTable.less new file mode 100644 index 0000000000..7e540c2b62 --- /dev/null +++ b/plugins/CoreHome/stylesheets/dataTable/_subDataTable.less @@ -0,0 +1,46 @@ +/* SUBDATATABLE */ +/* a datatable inside another datatable */ +table.subDataTable td { + border: 0; +} + +table.subDataTable thead th { + font-weight: normal; + font-size: 12px; + text-align: left; + padding: .3em 1em; + border: 0; + border-top: 1px solid #e7e7e7; + border-bottom: 1px solid #e7e7e7; +} + +table.subDataTable td.labeleven, table.subDataTable td.labelodd { + background-image: none; +} + +table.subDataTable td { + border-bottom: 1px solid #e7e7e7; + border-left: 0; +} + +table.subDataTable td, table.subDataTable td a { + color: #615B53; +} + +table.subDataTable td.labeleven, table.subDataTable td.columneven { + color: #2D2A27; +} + +table.subDataTable td.label { + width: 80%; +} + +table.subDataTable td.label { + padding: 5px; +} + +/* are the following two supposed to be together? */ +.subDataTable.dataTableFeatures { + padding-top: 0; + padding-bottom: 5px; +}
\ No newline at end of file diff --git a/plugins/CoreHome/stylesheets/dataTable/_tableConfiguration.less b/plugins/CoreHome/stylesheets/dataTable/_tableConfiguration.less new file mode 100644 index 0000000000..fff7c3d1bf --- /dev/null +++ b/plugins/CoreHome/stylesheets/dataTable/_tableConfiguration.less @@ -0,0 +1,82 @@ +.tableConfiguration { + float: right; + position: relative; + margin-left: 5px; + min-height: 20px; + min-width: 25px; +} + +a.tableConfigurationIcon { + display: block; + width: 30px; + height: 22px; + background: url(plugins/Zeitgeist/images/configure.png) no-repeat center 2px; + position: absolute; + z-index: 9; + right: 0; +} + +a.tableConfigurationIcon.highlighted { + display: block; + width: 30px; + height: 22px; + background-image: url(plugins/Zeitgeist/images/configure-highlight.png); + position: absolute; + z-index: 9; + right: 0; +} + +.tableConfiguration ul { + overflow: visible; + display: none; + position: relative; + z-index: 8; + text-align: left; +} + +.tableConfiguration ul.open { + display: block; +} + +.tableConfiguration ul li { + padding: 0; + font-size: 1.1em; + height: 40px; + margin-top: -80px; + background-color: #fff; + border: 1px solid #DFDFDF; + border-width: 0 1px; + vertical-align: middle; +} + +.tableConfiguration ul li.firstDummy { + border-bottom-width: 1px; + border-radius: 0 0 4px 4px; + height: 25px; + cursor: default; + margin-top: -4px; +} + +.tableConfiguration ul li.first { + margin-top: -65px; +} + +.tableConfiguration ul li.last { + border-top-width: 1px; + border-radius: 4px 4px 0 0; +} + +.tableConfiguration div.configItem { + cursor: pointer; + padding: 5px 10px; + line-height: 15px; + color: #444; +} + +.tableConfiguration div.configItem:hover { + background-color: #EBEAE6; +} + +.tableConfiguration div.configItem span.action { + color: @dataTable-link-color; +}
\ No newline at end of file diff --git a/plugins/Zeitgeist/stylesheets/ui/_jqplot.less b/plugins/CoreHome/stylesheets/jqplotColors.less index b8f47543d2..01dd9b8444 100644 --- a/plugins/Zeitgeist/stylesheets/ui/_jqplot.less +++ b/plugins/CoreHome/stylesheets/jqplotColors.less @@ -1,4 +1,12 @@ // evolution graph colors +.evolution-graph-colors[data-name=grid-background] { + color: #fff; +} + +.evolution-graph-colors[data-name=grid-border] { + color: #f00; +} + .evolution-graph-colors[data-name=series1] { color: #5170AE; } @@ -31,14 +39,6 @@ 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; } @@ -48,6 +48,14 @@ } // bar graph colors +.bar-graph-colors[data-name=grid-background] { + color: #fff; +} + +.bar-graph-colors[data-name=grid-border] { + color: #f00; +} + .bar-graph-colors[data-name=series1] { color: #5170AE; } @@ -80,14 +88,6 @@ 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; } @@ -97,6 +97,14 @@ } // pie graph colors +.pie-graph-colors[data-name=grid-background] { + color: #fff; +} + +.pie-graph-colors[data-name=grid-border] { + color: #f00; +} + .pie-graph-colors[data-name=series1] { color: #59727F; } @@ -133,14 +141,6 @@ 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; } diff --git a/plugins/CoreHome/stylesheets/menu.less b/plugins/CoreHome/stylesheets/menu.less index 2bd0f491c5..87705376a6 100644 --- a/plugins/CoreHome/stylesheets/menu.less +++ b/plugins/CoreHome/stylesheets/menu.less @@ -31,7 +31,7 @@ font-size: 18px; display: block; float: left; - padding: 8px 27px 0 27px; + padding: 8px 27px 0; height: 25px; text-decoration: none; font-weight: normal; @@ -91,7 +91,7 @@ /* LEVEL2 HOVER */ .nav_tab > li.sfHover > ul, .nav_tab > li:hover > ul { - z-index: 50; + z-index: 1; top: 100%; opacity: 1; -webkit-transition: opacity 300ms ease-out 10ms; /* property duration timing-function delay */ diff --git a/plugins/Zeitgeist/stylesheets/ui/_sparkline.less b/plugins/CoreHome/stylesheets/sparklineColors.less index 7d2b9c7c8b..9eef3ff955 100644 --- a/plugins/Zeitgeist/stylesheets/ui/_sparkline.less +++ b/plugins/CoreHome/stylesheets/sparklineColors.less @@ -9,18 +9,22 @@ div.sparkline:hover { } // sparkline colors +.sparkline-colors[data-name=backgroundColor] { + color: white; +} + .sparkline-colors[data-name=lineColor] { color: rgb(22, 44, 74); } -.sparkline-colors[data-name=red] { +.sparkline-colors[data-name=minPointColor] { color: #ff7f7f; } -.sparkline-colors[data-name=blue] { +.sparkline-colors[data-name=lastPointColor] { color: #55AAFF; } -.sparkline-colors[data-name=green] { +.sparkline-colors[data-name=maxPointColor] { color: #75BF7C; } diff --git a/plugins/CoreHome/templates/_dataTable.twig b/plugins/CoreHome/templates/_dataTable.twig index 4e12cac5a4..5b04fdf9f7 100644 --- a/plugins/CoreHome/templates/_dataTable.twig +++ b/plugins/CoreHome/templates/_dataTable.twig @@ -1,8 +1,9 @@ {% set summaryRowId = constant('Piwik\\DataTable::ID_SUMMARY_ROW') %}{# ID_SUMMARY_ROW #} {% set isSubtable = javascriptVariablesToSet.idSubtable is defined and javascriptVariablesToSet.idSubtable != 0 %} -<div class="dataTable {{ properties.datatable_css_class }} {% if isSubtable %}subDataTable{% endif %}" +<div class="dataTable {{ visualizationCssClass }} {{ properties.datatable_css_class|default('') }} {% if isSubtable %}subDataTable{% endif %}" data-table-type="{{ properties.datatable_js_type|default('dataTable') }}" data-report="{{ properties.report_id }}" + data-props="{{ clientSidePropertiesToSet|json_encode }}" data-params="{{ javascriptVariablesToSet|json_encode }}"> <div class="reportDocumentation"> {% if properties.documentation|default is not empty %}<p>{{ properties.documentation|raw }}</p>{% endif %} diff --git a/plugins/CoreHome/templates/_dataTableActions_subDataTable.twig b/plugins/CoreHome/templates/_dataTableActions_subDataTable.twig index 72bf6607c1..696c4a5a72 100644 --- a/plugins/CoreHome/templates/_dataTableActions_subDataTable.twig +++ b/plugins/CoreHome/templates/_dataTableActions_subDataTable.twig @@ -1,14 +1,14 @@ {% if error is defined %} {{ error.message }} {% else %} - {% if (dataTable is empty or dataTable.getRowsCount() == 0) and not properties.show_expanded|default(false) %} + {% if (dataTable is empty or dataTable.getRowsCount() == 0) and not properties.visualization_properties.show_expanded|default(false) %} <tr> <td colspan="{{ properties.columns_to_display|length }}">{{ 'CoreHome_CategoryNoData'|translate }}</td> </tr> {% else %} {% for row in dataTable.getRows() %} {# display this row if it doesn't have a subtable or if we don't replace the row with the subtable #} - {% if not row.getIdSubDataTable() or not properties.show_expanded|default(false) or not properties.replace_row_with_subtable|default(false) %} + {% if not row.getIdSubDataTable() or not properties.visualization_properties.show_expanded|default(false) or not properties.replace_row_with_subtable|default(false) %} <tr {% if row.getIdSubDataTable() %}id="{{ row.getIdSubDataTable() }}"{% endif %} class="{{ row.getMetadata('css_class') }} {% if row.getIdSubDataTable() %}subDataTable{% endif %}"> {% for column in properties.columns_to_display %} @@ -20,8 +20,8 @@ {% endif %} {# display subtable if present and showing expanded datatable #} - {% if properties.show_expanded|default(false) and row.getIdSubDataTable() %} - {% include properties.subtable_template|default("@CoreHome/_dataTable.twig") with {'dataTable': row.getSubtable()} %} + {% if properties.visualization_properties.show_expanded|default(false) and row.getIdSubDataTable() %} + {% include properties.visualization_properties.subtable_template|default("@CoreHome/_dataTable.twig") with {'dataTable': row.getSubtable()} %} {% endif %} {% endfor %} {% endif %} diff --git a/plugins/CoreHome/templates/_dataTableFooter.twig b/plugins/CoreHome/templates/_dataTableFooter.twig index 5a74cf4a74..44b776b31d 100644 --- a/plugins/CoreHome/templates/_dataTableFooter.twig +++ b/plugins/CoreHome/templates/_dataTableFooter.twig @@ -1,24 +1,26 @@ <div class="dataTableFeatures"> - {% if properties.show_offset_information %} - <span> - <span class="dataTablePages"></span> - </span> - {% endif %} + <div class="dataTableFooterNavigation"> + {% if properties.show_offset_information %} + <span> + <span class="dataTablePages"></span> + </span> + {% endif %} - {% if properties.show_pagination_control %} - <span> - <span class="dataTablePrevious">‹ {% if javascriptVariablesToSet.dataTablePreviousIsFirst is defined %}{{ 'General_First'|translate }}{% else %}{{ 'General_Previous'|translate }}{% endif %} </span> - <span class="dataTableNext">{{ 'General_Next'|translate }} ›</span> - </span> - {% endif %} + {% if properties.show_pagination_control %} + <span> + <span class="dataTablePrevious">‹ {% if javascriptVariablesToSet.dataTablePreviousIsFirst is defined %}{{ 'General_First'|translate }}{% else %}{{ 'General_Previous'|translate }}{% endif %} </span> + <span class="dataTableNext">{{ 'General_Next'|translate }} ›</span> + </span> + {% endif %} - {% if properties.show_search %} - <span class="dataTableSearchPattern"> - <input id="keyword" type="text" length="15" /> - <input type="submit" value="{{ 'General_Search'|translate }}" /> - </span> - {% endif %} + {% if properties.show_search %} + <span class="dataTableSearchPattern"> + <input type="text" class="searchInput" length="15" /> + <input type="submit" value="{{ 'General_Search'|translate }}" /> + </span> + {% endif %} + </div> <span class="loadingPiwik" style='display:none'><img src="plugins/Zeitgeist/images/loading-blue.gif"/> {{ 'General_LoadingData'|translate }}</span> {% if properties.show_footer_icons %} @@ -75,6 +77,13 @@ <img width="16" height="16" src="plugins/Zeitgeist/images/tagcloud.png" title="{{ 'General_TagCloud'|translate }}"/> </a> {% endif %} + {% if properties.show_non_core_visualizations %} + {% for format, info in nonCoreVisualizations %} + <a class="tableIcon" format="{{ format }}" var="{{ format }}"> + <img width="16" height="16" src="{{ info.table_icon }}" title="{{ info.title|translate }}"/> + </a> + {% endfor %} + {% endif %} </span> </div> {% endif %} @@ -86,14 +95,14 @@ </span> <span class="exportToFormatItems" style="display:none"> {{ 'General_Export'|translate }}: - <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="CSV" filter_limit="{{ properties.exportLimit }}">CSV</a> | - <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="TSV" filter_limit="{{ properties.exportLimit }}">TSV (Excel)</a> | - <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="XML" filter_limit="{{ properties.exportLimit }}">XML</a> | - <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="JSON" filter_limit="{{ properties.exportLimit }}">Json</a> | - <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="PHP" filter_limit="{{ properties.exportLimit }}">Php</a> + <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="CSV" filter_limit="{{ properties.export_limit }}">CSV</a> | + <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="TSV" filter_limit="{{ properties.export_limit }}">TSV (Excel)</a> | + <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="XML" filter_limit="{{ properties.export_limit }}">XML</a> | + <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="JSON" filter_limit="{{ properties.export_limit }}">Json</a> | + <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="PHP" filter_limit="{{ properties.export_limit }}">Php</a> {% if properties.show_export_as_rss_feed %} | - <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="RSS" filter_limit="{{ properties.exportLimit }}" date="last10"> + <a target="_blank" methodToCall="{{ properties.apiMethodToRequestDataTable }}" format="RSS" filter_limit="{{ properties.export_limit }}" date="last10"> <img border="0" src="plugins/Zeitgeist/images/feed.png"/> </a> {% endif %} @@ -128,7 +137,7 @@ {% endif %} </ul> </div> - {% if not properties.hide_annotations_view %} + {% if isPluginLoaded('Annotations') and not properties.hide_annotations_view %} <div class="annotationView" title="{{ 'Annotations_IconDesc_js'|translate }}"> <a class="tableIcon"> <img width="16" height="16" src="plugins/Zeitgeist/images/grey_marker.png"/> @@ -140,16 +149,16 @@ {% endif %} <div class="datatableRelatedReports"> - {% if (properties.relatedReports is not empty) and properties.show_related_reports %} - {% if properties.relatedReports|length == 1 %} + {% if (properties.related_reports is not empty) and properties.show_related_reports %} + {% if properties.related_reports|length == 1 %} {{ 'General_RelatedReport'|translate }}: {% else %} {{ 'General_RelatedReports'|translate }}: {% endif %} - <ul style="list-style:none;{% if properties.relatedReports|length == 1 %}display:inline-block;{% endif %}}"> + <ul style="list-style:none;{% if properties.related_reports|length == 1 %}display:inline-block;{% endif %}}"> <li><span href="{{ properties.self_url }}" style="display:none;">{{ properties.title }}</span></li> - {% for reportUrl,reportTitle in properties.relatedReports %} + {% for reportUrl,reportTitle in properties.related_reports %} <li><span href="{{ reportUrl }}">{{ reportTitle }}</span></li> {% endfor %} </ul> diff --git a/plugins/CoreHome/templates/_dataTableViz_jqplotGraph.twig b/plugins/CoreHome/templates/_dataTableViz_jqplotGraph.twig deleted file mode 100644 index 65e9f7a43c..0000000000 --- a/plugins/CoreHome/templates/_dataTableViz_jqplotGraph.twig +++ /dev/null @@ -1,10 +0,0 @@ -<div class="jqplot-graph"> - <div class="piwik-graph" - style="width: {{ properties.graph_width }}; height: {{ properties.graph_height }};" - data-data="{{ data|e('html') }}" - {% if properties.external_series_toggle is defined and properties.external_series_toggle %} - data-external-series-toggle="{{ properties.external_series_toggle }}" - data-external-series-show-all="{% if properties.external_series_toggle_show_all %}1{% else %}0{% endif %}" - {% endif %}> - </div> -</div>
\ No newline at end of file diff --git a/plugins/CoreHome/templates/_siteSelect.twig b/plugins/CoreHome/templates/_siteSelect.twig index e78b93b0bd..7d3072cddc 100644 --- a/plugins/CoreHome/templates/_siteSelect.twig +++ b/plugins/CoreHome/templates/_siteSelect.twig @@ -24,12 +24,13 @@ </a> </div> {% endset %} -<div class="sites_autocomplete" {% if siteSelectorId is defined %}id="{{ siteSelectorId }}"{% endif %} +<div class="sites_autocomplete {% if sites|length > 1 %}sites_autocomplete--dropdown{% endif %}" + {% if siteSelectorId is defined %}id="{{ siteSelectorId }}"{% endif %} {% if switchSiteOnSelect is not defined or switchSiteOnSelect %}data-switch-site-on-select="1"{% endif %}> <div class="custom_select"> <a href="#" onclick="return false" class="custom_select_main_link" siteid="{% if idSite is defined %}{{ idSite }}{% else %}{{ sites[0].idsite }}{% endif %}"> - {% if siteName is defined %}{{ siteName|raw }}{% else %}{{ sites[0].name|raw }}{% endif %} + <span>{% if siteName is defined %}{{ siteName|raw }}{% else %}{{ sites[0].name|raw }}{% endif %}</span> </a> <div class="custom_select_block"> diff --git a/plugins/CoreHome/templates/_siteSelectHeader.twig b/plugins/CoreHome/templates/_siteSelectHeader.twig new file mode 100644 index 0000000000..a4ab4cf8a0 --- /dev/null +++ b/plugins/CoreHome/templates/_siteSelectHeader.twig @@ -0,0 +1,4 @@ +<div class="top_bar_sites_selector"> + <label>{{ 'General_Website'|translate }}</label> + {% include "@CoreHome/_siteSelect.twig" %} +</div>
\ No newline at end of file diff --git a/plugins/CoreHome/templates/_topBarHelloMenu.twig b/plugins/CoreHome/templates/_topBarHelloMenu.twig index 34503d12bf..7fb0aadb81 100644 --- a/plugins/CoreHome/templates/_topBarHelloMenu.twig +++ b/plugins/CoreHome/templates/_topBarHelloMenu.twig @@ -8,7 +8,12 @@ {% endset %} <span class="topBarElem">{{ 'General_HelloUser'|translate(helloAlias)|raw }}</span> {% if userLogin != 'anonymous' %} - | <span class="topBarElem"><a href='index.php?module=CoreAdminHome'>{{ 'General_Settings'|translate }}</a></span> + | + {% if isAdminLayout is defined %} + <span class="topBarElem topBarElemActive">{{ 'General_Settings'|translate }}</span> + {% else %} + <span class="topBarElem"><a href='index.php?module=CoreAdminHome'>{{ 'General_Settings'|translate }}</a></span> + {% endif %} {% endif %} | <span class="topBarElem"> {% if userLogin == 'anonymous' %} diff --git a/plugins/CoreHome/templates/_topBarTopMenu.twig b/plugins/CoreHome/templates/_topBarTopMenu.twig index 29330720a0..6e7992e7ac 100644 --- a/plugins/CoreHome/templates/_topBarTopMenu.twig +++ b/plugins/CoreHome/templates/_topBarTopMenu.twig @@ -3,7 +3,7 @@ {% if menu._html is defined %} {{ menu._html|raw }} {% elseif (menu._url.module == currentModule and (menu._url.action is empty or menu._url.action == currentAction)) %} - <span class="topBarElem"><b>{{ label|translate }}</b></span> | + <span class="topBarElem topBarElemActive"><b>{{ label|translate }}</b></span> | {% else %} <span class="topBarElem" {% if menu._tooltip is defined %}title="{{ menu._tooltip }}"{% endif %}> <a id="topmenu-{{ menu._url.module|lower }}" href="index.php{{ menu._url|urlRewriteWithParameters }}">{{ label|translate }}</a> diff --git a/plugins/CoreHome/templates/getDefaultIndexView.twig b/plugins/CoreHome/templates/getDefaultIndexView.twig index 0fe04f26de..b9d26c3a7c 100644 --- a/plugins/CoreHome/templates/getDefaultIndexView.twig +++ b/plugins/CoreHome/templates/getDefaultIndexView.twig @@ -2,10 +2,7 @@ {% block content %} -<div class="top_bar_sites_selector"> - <label>{{ 'General_Website'|translate }}</label> - {% include "@CoreHome/_siteSelect.twig" %} -</div> +{% include "@CoreHome/_siteSelectHeader.twig" %} {% if (menu is defined and menu) %} {% include "@CoreHome/_menu.twig" %} diff --git a/plugins/CoreHome/templates/getMultiRowEvolutionPopover.twig b/plugins/CoreHome/templates/getMultiRowEvolutionPopover.twig index 16ef990aa6..c0a043aac8 100644 --- a/plugins/CoreHome/templates/getMultiRowEvolutionPopover.twig +++ b/plugins/CoreHome/templates/getMultiRowEvolutionPopover.twig @@ -1,4 +1,4 @@ -{% set seriesColorCount = constant("Evolution::SERIES_COLOR_COUNT") %} +{% set seriesColorCount = constant("Piwik\\Plugins\\CoreVisualizations\\Visualizations\\JqplotGraph\\Evolution::SERIES_COLOR_COUNT") %} <div class="rowevolution multirowevolution"> <div class="popover-title">{{ 'RowEvolution_MultiRowEvolutionTitle'|translate }}</div> <div class="graph"> diff --git a/plugins/CoreHome/templates/getRowEvolutionPopover.twig b/plugins/CoreHome/templates/getRowEvolutionPopover.twig index fab9fb2437..74b6cbbfe4 100644 --- a/plugins/CoreHome/templates/getRowEvolutionPopover.twig +++ b/plugins/CoreHome/templates/getRowEvolutionPopover.twig @@ -1,4 +1,4 @@ -{% set seriesColorCount = constant("Evolution::SERIES_COLOR_COUNT") %} +{% set seriesColorCount = constant("Piwik\\Plugins\\CoreVisualizations\\Visualizations\\JqplotGraph\\Evolution::SERIES_COLOR_COUNT") %} <div class="rowevolution"> <div class="popover-title">{{ popoverTitle | raw }}</div> <div class="graph"> diff --git a/plugins/CoreUpdater/Controller.php b/plugins/CoreUpdater/Controller.php index 7cb89e9e30..d829734ae3 100644 --- a/plugins/CoreUpdater/Controller.php +++ b/plugins/CoreUpdater/Controller.php @@ -354,7 +354,7 @@ class Controller extends \Piwik\Controller foreach ($componentsWithUpdateFile as $name => $filenames) { try { $this->warningMessages = array_merge($this->warningMessages, $updater->update($name)); - } catch (Updater_UpdateErrorException $e) { + } catch (\Piwik\Updater_UpdateErrorException $e) { $this->errorMessages[] = $e->getMessage(); if ($name == 'core') { $this->coreError = true; diff --git a/plugins/CoreUpdater/templates/layout.twig b/plugins/CoreUpdater/templates/layout.twig index 23aee27884..cf6dd9ae2b 100644 --- a/plugins/CoreUpdater/templates/layout.twig +++ b/plugins/CoreUpdater/templates/layout.twig @@ -3,7 +3,8 @@ <head> <meta charset="utf-8"> <title>Piwik › {{ 'CoreUpdater_UpdateTitle'|translate }}</title> - <link rel="shortcut icon" href="plugins/CoreHome/images/favicon.ico"/> + <meta http-equiv="X-UA-Compatible" content="IE=EDGE,chrome=1"/> + <meta name="viewport" content="initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="libs/jquery/themes/base/jquery-ui.css"/> <link rel="stylesheet" type="text/css" href="plugins/Zeitgeist/stylesheets/base.css" /> @@ -19,6 +20,8 @@ <link rel="stylesheet" type="text/css" href="plugins/Zeitgeist/stylesheets/rtl.css"/> {% endif %} {{ loadJavascriptTranslations(['CoreHome'])|raw }} + + <link rel="shortcut icon" href="plugins/CoreHome/images/favicon.ico"/> </head> <body id="simple"> <div id="contentsimple"> diff --git a/plugins/CoreVisualizations/CoreVisualizations.php b/plugins/CoreVisualizations/CoreVisualizations.php new file mode 100644 index 0000000000..00330377a2 --- /dev/null +++ b/plugins/CoreVisualizations/CoreVisualizations.php @@ -0,0 +1,58 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik_Plugins + * @package Piwik_CoreVisualizations + */ + +use Piwik\Plugin; + +require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/JqplotDataGenerator.php'; +require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/Cloud.php'; +require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/HtmlTable.php'; +require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/JqplotGraph.php'; + +/** + * This plugin contains all core visualizations, such as the normal HTML table and + * jqPlot graphs. + */ +class Piwik_CoreVisualizations extends Plugin +{ + /** + * @see Piwik_Plugin::getListHooksRegistered + */ + public function getListHooksRegistered() + { + return array( + 'AssetManager.getCssFiles' => 'getCssFiles', + 'AssetManager.getJsFiles' => 'getJsFiles', + 'DataTableVisualization.getAvailable' => 'getAvailableDataTableVisualizations', + ); + } + + public function getAvailableDataTableVisualizations(&$visualizations) + { + $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\HtmlTable'; + $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\HtmlTable\\AllColumns'; + $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\HtmlTable\\Goals'; + $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\Cloud'; + $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\JqplotGraph\\Pie'; + $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\JqplotGraph\\Bar'; + $visualizations[] = 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\JqplotGraph\\Evolution'; + } + + public function getCssFiles(&$cssFiles) + { + $cssFiles[] = "plugins/CoreVisualizations/stylesheets/dataTableVisualizations.less"; + $cssFiles[] = "plugins/CoreVisualizations/stylesheets/jqplot.css"; + } + + public function getJsFiles(&$jsFiles) + { + $jsFiles[] = "plugins/CoreVisualizations/javascripts/jqplot.js"; + } +}
\ No newline at end of file diff --git a/core/JqplotDataGenerator.php b/plugins/CoreVisualizations/JqplotDataGenerator.php index 8f9d48baea..3cf09c8581 100644 --- a/core/JqplotDataGenerator.php +++ b/plugins/CoreVisualizations/JqplotDataGenerator.php @@ -9,7 +9,7 @@ * @package Piwik */ -namespace Piwik; +namespace Piwik\Plugins\CoreVisualizations; use Exception; use Piwik\Common; @@ -17,6 +17,8 @@ use Piwik\Metrics; use Piwik\DataTable; use Piwik\Visualization; +require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php'; + /** * Generates JSON data used to configure and populate JQPlot graphs. * @@ -34,7 +36,7 @@ class JqplotDataGenerator /** * This object does most of the work in generating the JQPlot JSON data. * - * @var \Piwik\Visualization\ + * @var Visualization\ */ protected $visualization; @@ -44,7 +46,7 @@ class JqplotDataGenerator * @param string $type 'pie', 'bar', or 'evolution' * @param array $properties The view properties. * @throws \Exception - * @return \Piwik\JqplotDataGenerator + * @return JqplotDataGenerator */ public static function factory($type, $properties) { @@ -82,8 +84,8 @@ class JqplotDataGenerator */ public function generate($dataTable) { - if (!empty($this->properties['graph_limit'])) { - $offsetStartSummary = $this->properties['graph_limit'] - 1; + if (!empty($this->properties['visualization_properties']->max_graph_elements)) { + $offsetStartSummary = $this->properties['visualization_properties']->max_graph_elements - 1; $sortColumn = !empty($this->properties['filter_sort_column']) ? $this->properties['filter_sort_column'] : Metrics::INDEX_NB_VISITS; @@ -95,7 +97,7 @@ class JqplotDataGenerator if ($dataTable->getRowsCount() > 0) { // if addTotalRow was called in GenerateGraphHTML, add a row containing totals of // different metrics - if (!empty($this->properties['add_total_row'])) { + if (!empty($this->properties['visualization_properties']->add_total_row)) { $dataTable->queueFilter('AddSummaryRow', array(0, Piwik_Translate('General_Total'), null, false)); } @@ -107,6 +109,9 @@ class JqplotDataGenerator return $this->visualization->render(); } + /** + * @param DataTable|DataTable\Map $dataTable + */ protected function initChartObjectData($dataTable) { $dataTable->applyQueuedFilters(); @@ -133,10 +138,11 @@ class JqplotDataGenerator $visualization->setAxisYValues($columnNameToValue); $visualization->setAxisYLabels($columnNameToTranslation); $visualization->setAxisYUnit($this->properties['y_axis_unit']); - $visualization->setDisplayPercentageInTooltip($this->properties['display_percentage_in_tooltip']); + $visualization->setDisplayPercentageInTooltip( + $this->properties['visualization_properties']->display_percentage_in_tooltip); // show_all_ticks is not real query param, it is set by GenerateGraphHTML. - if ($this->properties['show_all_ticks']) { + if ($this->properties['visualization_properties']->show_all_ticks) { $visualization->showAllTicks(); } @@ -183,11 +189,12 @@ class JqplotDataGenerator */ protected function addSeriesPickerToView() { - if (count($this->properties['selectable_columns']) - && Common::getRequestVar('showSeriesPicker', 1) == 1 + $defaultShowSeriesPicker = $this->properties['visualization_properties']->show_series_picker; + if (count($this->properties['visualization_properties']->selectable_columns) + && Common::getRequestVar('showSeriesPicker', $defaultShowSeriesPicker) == 1 ) { $selectableColumns = array(); - foreach ($this->properties['selectable_columns'] as $column) { + foreach ($this->properties['visualization_properties']->selectable_columns as $column) { $selectableColumns[] = array( 'column' => $column, 'translation' => @$this->properties['translations'][$column], @@ -196,7 +203,7 @@ class JqplotDataGenerator } $this->visualization->setSelectableColumns( - $selectableColumns, $this->properties['allow_multi_select_series_picker']); + $selectableColumns, $this->properties['visualization_properties']->allow_multi_select_series_picker); } } } diff --git a/core/JqplotDataGenerator/Evolution.php b/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php index ff4daa2bc3..2d4f3e93e1 100644 --- a/core/JqplotDataGenerator/Evolution.php +++ b/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php @@ -8,14 +8,15 @@ * @category Piwik * @package Piwik */ -namespace Piwik\JqplotDataGenerator; +namespace Piwik\Plugins\CoreVisualizations\JqplotDataGenerator; use Piwik\Piwik; use Piwik\Common; use Piwik\DataTable; +use Piwik\DataTable\Row; use Piwik\ViewDataTable; use Piwik\Url; -use Piwik\JqplotDataGenerator; +use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator; /** * Generates JQPlot JSON data/config for evolution graphs. @@ -26,18 +27,24 @@ class Evolution extends JqplotDataGenerator /** * Constructor. + * + * @param array $properties */ public function __construct($properties) { parent::__construct(new \Piwik\Visualization\Chart\Evolution(), $properties); } + /** + * @param DataTable|DataTable\Map $dataTable + */ protected function initChartObjectData($dataTable) { // 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 Set if ($dataTable instanceof DataTable) { - return parent::initChartObjectData($dataTable); + parent::initChartObjectData($dataTable); + return; } $dataTable->applyQueuedFilters(); @@ -58,13 +65,19 @@ class Evolution extends JqplotDataGenerator $yAxisLabelToUnit = array(); $yAxisLabelToValue = array(); foreach ($dataTable->getArray() as $idDataTable => $childTable) { - foreach ($childTable->getRows() as $row) { + if ($childTable->getRowsCount() > 0) { + $rows = $childTable->getRows(); + } else { + $rows = array(new Row()); + } + + foreach ($rows as $row) { $rowLabel = $row->getColumn('label'); // put together configuration for row picker. // do this for every data table in the array because rows do not // have to present for each date. - if ($this->properties['row_picker_mach_rows_by'] !== false) { + if ($this->properties['row_picker_match_rows_by'] !== false) { $rowVisible = $this->handleRowForRowPicker($rowLabel); if (!$rowVisible) { continue; @@ -74,10 +87,9 @@ class Evolution extends JqplotDataGenerator // build data for request columns foreach ($requestedColumnNames as $requestedColumnName) { $yAxisLabel = $this->getSeriesLabel($rowLabel, $requestedColumnName); - if (($columnValue = $row->getColumn($requestedColumnName)) !== false) { - $yAxisLabelToValue[$yAxisLabel][$idDataTable] = $columnValue; - $yAxisLabelToUnit[$yAxisLabel] = $units[$requestedColumnName]; - } + + $yAxisLabelToValue[$yAxisLabel][$idDataTable] = $row->getColumn($requestedColumnName) ?: 0; + $yAxisLabelToUnit[$yAxisLabel] = $units[$requestedColumnName]; } } } @@ -103,6 +115,8 @@ class Evolution extends JqplotDataGenerator $countGraphElements = $dataTable->getRowsCount(); $dataTables = $dataTable->getArray(); $firstDatatable = reset($dataTables); + + /** @var \Piwik\Period $period */ $period = $firstDatatable->getMetadata('period'); $stepSize = $this->getXAxisStepSize($period->getLabel(), $countGraphElements); @@ -138,7 +152,7 @@ class Evolution extends JqplotDataGenerator $this->addSeriesPickerToView(); // configure the row picker - if ($this->properties['row_picker_mach_rows_by'] !== false) { + if ($this->properties['row_picker_match_rows_by'] !== false) { $visualization->setSelectableRows(array_values($this->rowPickerConfig)); } } @@ -154,7 +168,7 @@ class Evolution extends JqplotDataGenerator { // determine whether row is visible $isVisible = true; - if ($this->properties['row_picker_mach_rows_by'] == 'label') { + if ($this->properties['row_picker_match_rows_by'] == 'label') { $isVisible = in_array($rowLabel, $this->properties['row_picker_visible_rows']); } diff --git a/core/Visualization/Cloud.php b/plugins/CoreVisualizations/Visualizations/Cloud.php index 931ada572c..a9a8eb7364 100644 --- a/core/Visualization/Cloud.php +++ b/plugins/CoreVisualizations/Visualizations/Cloud.php @@ -8,11 +8,12 @@ * @category Piwik * @package Piwik */ -namespace Piwik\Visualization; +namespace Piwik\Plugins\CoreVisualizations\Visualizations; use Piwik\Common; use Piwik\View; use Piwik\DataTable; +use Piwik\DataTableVisualization; /** * Generates a tag cloud from a given data array. @@ -23,14 +24,25 @@ use Piwik\DataTable; * @package Piwik * @subpackage Piwik_Visualization */ -class Cloud +class Cloud extends DataTableVisualization { + const ID = 'cloud'; + /** Used by integration tests to make sure output is consistent. */ public static $debugDisableShuffle = false; protected $wordsArray = array(); public $truncatingLimit = 50; + public static function getDefaultPropertyValues() + { + return array( + 'show_offset_information' => false, + 'show_exclude_low_population' => false, + 'display_logo_instead_of_label' => false, + ); + } + /** * Assign word to array * @param string $word @@ -55,7 +67,7 @@ class Cloud */ public function render($dataTable, $properties) { - $view = new View("@CoreHome/_dataTableViz_tagCloud.twig"); + $view = new View("@CoreVisualizations/_dataTableViz_tagCloud.twig"); $view->properties = $properties; $columnToDisplay = $properties['columns_to_display'][1]; diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable.php b/plugins/CoreVisualizations/Visualizations/HtmlTable.php new file mode 100644 index 0000000000..d3c6a61974 --- /dev/null +++ b/plugins/CoreVisualizations/Visualizations/HtmlTable.php @@ -0,0 +1,394 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ +namespace Piwik\Plugins\CoreVisualizations\Visualizations; + +use Piwik\Piwik; +use Piwik\DataTable; +use Piwik\View; +use Piwik\Config; +use Piwik\Common; +use Piwik\Site; +use Piwik\DataTableVisualization; +use Piwik\DataTable\Filter\AddColumnsProcessedMetricsGoal; +use \Piwik_Goals_API; + +require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php'; +require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/HtmlTable/Goals.php'; + +/** + * DataTable visualization that shows DataTable data in an HTML table. + */ +class HtmlTable extends DataTableVisualization +{ + const ID = 'table'; + + /** + * Custom template used if displaying a subtable. + * + * TODO: Should be replaced w/ allowing custom visualization for + * subtables. Should not directly touch template. + */ + const SUBTABLE_TEMPLATE = 'subtable_template'; + + /** + * Controls whether the entire DataTable should be rendered (including subtables) or just one + * specific table in the tree. + */ + const SHOW_EXPANDED = 'show_expanded'; + + /** + * When showing an expanded datatable, this property controls whether rows with subtables are + * replaced with their subtables, or if they are shown alongside their subtables. + */ + const REPLACE_ROW_WITH_SUBTABLE = 'replace_row_with_subtable'; + + /** + * Controls whether any DataTable Row Action icons are shown. If true, no icons are shown. + * + * @see also self::DISABLE_ROW_EVOLUTION + */ + const DISABLE_ROW_ACTIONS = 'disable_row_actions'; + + /** + * Controls whether the row evolution DataTable Row Action icon is shown or not. + * + * @see also self::DISABLE_ROW_ACTIONS + */ + const DISABLE_ROW_EVOLUTION = 'disable_row_evolution'; + + /** + * If true, the 'label', 'nb_visits', 'nb_uniq_visitors' (if present), 'nb_actions', + * 'nb_actions_per_visit', 'avg_time_on_site', 'bounce_rate' and 'conversion_rate' (if + * goals view is not allowed) are displayed. + */ + const SHOW_EXTRA_COLUMNS = 'show_extra_columns'; + + /** + * If true, conversions for each existing goal will be displayed for the visits in + * each row. + */ + const SHOW_GOALS_COLUMNS = 'show_goals_columns'; + + /** + * If true, subtables will not be loaded when rows are clicked, but only if the + * 'show_goals_columns' property is also true. + * + * @see also self::SHOW_GOALS_COLUMNS + */ + const DISABLE_SUBTABLE_IN_GOALS_VIEW = 'disable_subtable_when_show_goals'; + + static public $clientSideParameters = array( + 'search_recursive', + ); + + static public $clientSideProperties = array( + 'show_extra_columns', + 'show_goals_columns', + 'disable_row_evolution', + 'disable_row_actions' + ); + + /** + * Constructor. + */ + public function __construct($view) + { + if (Common::getRequestVar('idSubtable', false) + && $view->visualization_properties->subtable_template + ) { + $view->datatable_template = $view->visualization_properties->subtable_template; + } + + if ($view->visualization_properties->show_extra_columns) { + $this->setShowExtraColumnsProperties($view); + } + + if ($view->visualization_properties->show_goals_columns) { + $this->setShowGoalsColumnsProperties($view); + } + } + + /** + * Renders this visualization. + * + * @param DataTable $dataTable + * @param array $properties View Properties. + * @return string + */ + public function render($dataTable, $properties) // TODO: $properties should be a viewdatatable, I think. + { + $view = new View("@CoreVisualizations/_dataTableViz_htmlTable.twig"); + $view->properties = $properties; + $view->dataTable = $dataTable; + return $view->render(); + } + + public static function getDefaultPropertyValues() + { + $defaults = array( + 'enable_sort' => true, + 'datatable_js_type' => 'dataTable', + 'filter_limit' => Config::getInstance()->General['datatable_default_limit'], + 'visualization_properties' => array( + 'table' => array( + 'disable_row_evolution' => false, + 'disable_row_actions' => false, + 'subtable_template' => "@CoreHome/_dataTable.twig", + 'show_extra_columns' => false, + 'show_goals_columns' => false, + 'disable_subtable_when_show_goals' => false, + ), + ), + ); + + if (Common::getRequestVar('enable_filter_excludelowpop', false) == '1') { + $defaults['filter_excludelowpop'] = 'nb_visits'; + $defaults['filter_excludelowpop_value'] = null; + } + + return $defaults; + } + + private function setShowExtraColumnsProperties($view) + { + $view->filters[] = array('AddColumnsProcessedMetrics', array(), $priority = true); + + $view->filters[] = function ($dataTable, $view) { + $columnsToDisplay = array('label', 'nb_visits'); + + if (in_array('nb_uniq_visitors', $dataTable->getColumns())) { + $columnsToDisplay[] = 'nb_uniq_visitors'; + } + + $columnsToDisplay = array_merge( + $columnsToDisplay, array('nb_actions', 'nb_actions_per_visit', 'avg_time_on_site', 'bounce_rate') + ); + + // only display conversion rate for the plugins that do not provide "per goal" metrics + // otherwise, conversion rate is meaningless as a whole (since we don't process 'cross goals' conversions) + if (!$view->show_goals) { + $columnsToDisplay[] = 'conversion_rate'; + } + + $view->columns_to_display = $columnsToDisplay; + }; + + $prettifyTime = array('\Piwik\Piwik', 'getPrettyTimeFromSeconds'); + $view->filters[] = array('ColumnCallbackReplace', array('avg_time_on_site', $prettifyTime)); + + $view->show_exclude_low_population = true; + + $view->datatable_css_class = 'dataTableVizAllColumns'; + } + + private function setShowGoalsColumnsProperties($view) + { + $view->datatable_css_class = 'dataTableVizGoals'; + $view->show_exclude_low_population = true; + $view->show_goals = true; + $view->translations += array( + 'nb_conversions' => Piwik_Translate('Goals_ColumnConversions'), + 'conversion_rate' => Piwik_Translate('General_ColumnConversionRate'), + 'revenue' => Piwik_Translate('Goals_ColumnRevenue'), + 'revenue_per_visit' => Piwik_Translate('General_ColumnValuePerVisit'), + ); + $view->metrics_documentation['nb_visits'] = Piwik_Translate('Goals_ColumnVisits'); + + if (Common::getRequestVar('documentationForGoalsPage', 0, 'int') == 1) { // TODO: should not use query parameter + $view->documentation = Piwik_Translate('Goals_ConversionByTypeReportDocumentation', + array('<br />', '<br />', '<a href="http://piwik.org/docs/tracking-goals-web-analytics/" target="_blank">', '</a>')); + } + + if (!$view->visualization_properties->disable_subtable_when_show_goals) { + $view->subtable_controller_action = null; + } + + // set view properties based on goal requested + $idSite = Common::getRequestVar('idSite', null, 'int'); + $idGoal = Common::getRequestVar('idGoal', AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW, 'string'); + if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { + $this->setPropertiesForEcommerceView($view); + } else if ($idGoal == AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE) { + $this->setPropertiesForGoals($view, $idSite, 'all'); + } else if ($idGoal == AddColumnsProcessedMetricsGoal::GOALS_OVERVIEW) { + $this->setPropertiesForGoalsOverview($view, $idSite); + } else { + $this->setPropertiesForGoals($view, $idSite, array($idGoal)); + } + + // add goals columns + $view->filters[] = array( + 'AddColumnsProcessedMetricsGoal', array($ignore = true, $idGoal), $priority = true); + + // prettify columns + $setRatePercent = function ($rate, $thang = false) { return $rate == 0 ? "0%" : $rate; }; + foreach ($view->columns_to_display as $columnName) { + if (strpos($columnName, 'conversion_rate') !== false) { + $view->filters[] = array('ColumnCallbackReplace', array($columnName, $setRatePercent)); + } + } + + $formatPercent = function ($value) use($idSite) { + return Piwik::getPrettyMoney(sprintf("%.1f", $value), $idSite); + }; + + foreach ($view->columns_to_display as $columnName) { + if ($this->isRevenueColumn($columnName)) { + $view->filters[] = array('ColumnCallbackReplace', array($columnName, $formatPercent)); + } + } + + // this ensures that the value is set to zero for all rows where the value was not set (no conversion) + $identityFunction = function ($value) { return $value; }; + foreach ($view->columns_to_display as $columnName) { + if (!$this->isRevenueColumn($columnName)) { + $view->filters[] = array('ColumnCallbackReplace', array($columnName, $identityFunction)); + } + } + } + + private function setPropertiesForEcommerceView($view) + { + $view->filter_sort_column = 'goal_ecommerceOrder_revenue'; + $view->filter_sort_order = 'desc'; + + $view->columns_to_display = array( + 'label', 'nb_visits', 'goal_ecommerceOrder_nb_conversions', 'goal_ecommerceOrder_revenue', + 'goal_ecommerceOrder_conversion_rate', 'goal_ecommerceOrder_avg_order_revenue', 'goal_ecommerceOrder_items', + 'goal_ecommerceOrder_revenue_per_visit' + ); + + $view->translations += array( + 'goal_ecommerceOrder_conversion_rate' => Piwik_Translate('Goals_ConversionRate', Piwik_Translate('Goals_EcommerceOrder')), + 'goal_ecommerceOrder_nb_conversions' => Piwik_Translate('General_EcommerceOrders'), + 'goal_ecommerceOrder_revenue' => Piwik_Translate('General_TotalRevenue'), + 'goal_ecommerceOrder_revenue_per_visit' => Piwik_Translate('General_ColumnValuePerVisit'), + 'goal_ecommerceOrder_avg_order_revenue' => Piwik_Translate('General_AverageOrderValue'), + 'goal_ecommerceOrder_items' => Piwik_Translate('General_PurchasedProducts') + ); + + $goalName = Piwik_Translate('General_EcommerceOrders'); + $view->metrics_documentation += array( + 'goal_ecommerceOrder_conversion_rate' => Piwik_Translate('Goals_ColumnConversionRateDocumentation', $goalName), + 'goal_ecommerceOrder_nb_conversions' => Piwik_Translate('Goals_ColumnConversionsDocumentation', $goalName), + 'goal_ecommerceOrder_revenue' => Piwik_Translate('Goals_ColumnRevenueDocumentation', $goalName), + 'goal_ecommerceOrder_revenue_per_visit' => Piwik_Translate('Goals_ColumnAverageOrderRevenueDocumentation', $goalName), + 'goal_ecommerceOrder_avg_order_revenue' => Piwik_Translate('Goals_ColumnAverageOrderRevenueDocumentation', $goalName), + 'goal_ecommerceOrder_items' => Piwik_Translate('Goals_ColumnPurchasedProductsDocumentation', $goalName), + 'revenue_per_visit' => Piwik_Translate('Goals_ColumnRevenuePerVisitDocumentation', $goalName) + ); + } + + private function setPropertiesForGoalsOverview($view, $idSite) + { + $allGoals = $this->getGoals($idSite); + + // set view properties + $view->columns_to_display = array('label', 'nb_visits'); + + foreach ($allGoals as $goal) { + $column = "goal_{$goal['idgoal']}_conversion_rate"; + + $view->columns_to_display[] = $column; + $view->translations[$column] = Piwik_Translate('Goals_ConversionRate', $goal['name']); + $view->metrics_documentation[$column] + = Piwik_Translate('Goals_ColumnConversionRateDocumentation', $goal['quoted_name'] ?: $goal['name']); + } + + $view->columns_to_display[] = 'revenue_per_visit'; + $view->metrics_documentation['revenue_per_visit'] = + Piwik_Translate('Goals_ColumnRevenuePerVisitDocumentation', Piwik_Translate('Goals_EcommerceAndGoalsMenu')); + } + + private function setPropertiesForGoals($view, $idSite, $idGoals) + { + $allGoals = $this->getGoals($idSite); + + if ($idGoals == 'all') { + $idGoals = array_keys($allGoals); + } else { + // only sort by a goal's conversions if not showing all goals (for FULL_REPORT) + $view->filter_sort_column = 'goal_' . reset($idGoals) . '_nb_conversions'; + $view->filter_sort_order = 'desc'; + } + + $view->columns_to_display = array('label', 'nb_visits'); + + $goalColumnTemplates = array( + 'goal_%s_nb_conversions', + 'goal_%s_conversion_rate', + 'goal_%s_revenue', + 'goal_%s_revenue_per_visit', + ); + + // set columns to display (columns of same type but different goals will be next to each other, + // ie, goal_0_nb_conversions, goal_1_nb_conversions, etc.) + foreach ($goalColumnTemplates as $idx => $columnTemplate) { + foreach ($idGoals as $idGoal) { + $column = sprintf($columnTemplate, $idGoal); + $view->columns_to_display[] = $column; + } + } + + // set translations & metric docs for goal specific metrics + foreach ($idGoals as $idGoal) { + $goalName = $allGoals[$idGoal]['name']; + $quotedGoalName = $allGoals[$idGoal]['quoted_name'] ?: $goalName; + + $view->translations += array( + 'goal_' . $idGoal . '_nb_conversions' => Piwik_Translate('Goals_Conversions', $goalName), + 'goal_' . $idGoal . '_conversion_rate' => Piwik_Translate('Goals_ConversionRate', $goalName), + 'goal_' . $idGoal . '_revenue' => + Piwik_Translate('%s ' . Piwik_Translate('Goals_ColumnRevenue'), $goalName), + 'goal_' . $idGoal . '_revenue_per_visit' => + Piwik_Translate('%s ' . Piwik_Translate('General_ColumnValuePerVisit'), $goalName), + ); + + $view->metrics_documentation += array( + 'goal_' . $idGoal . '_nb_conversions' => Piwik_Translate('Goals_ColumnConversionsDocumentation', $quotedGoalName), + 'goal_' . $idGoal . '_conversion_rate' => Piwik_Translate('Goals_ColumnConversionRateDocumentation', $quotedGoalName), + 'goal_' . $idGoal . '_revenue' => Piwik_Translate('Goals_ColumnRevenueDocumentation', $quotedGoalName), + 'goal_' . $idGoal . '_revenue_per_visit' => + Piwik_Translate('Goals_ColumnRevenuePerVisitDocumentation', Piwik_Translate('Goals_EcommerceAndGoalsMenu')), + ); + } + + $view->columns_to_display[] = 'revenue_per_visit'; + } + + private function getGoals($idSite) + { + // get all goals to display info for + $allGoals = array(); + + if (Site::isEcommerceEnabledFor($idSite)) { + $ecommerceGoal = array( + 'idgoal' => Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER, + 'name' => Piwik_Translate('Goals_EcommerceOrder'), + 'quoted_name' => false + ); + $allGoals[$ecommerceGoal['idgoal']] = $ecommerceGoal; + } + + $siteGoals = Piwik_Goals_API::getInstance()->getGoals($idSite); + foreach ($siteGoals as &$goal) { + $goal['quoted_name'] = '"' . $goal['name'] . '"'; + $allGoals[$goal['idgoal']] = $goal; + } + + return $allGoals; + } + + private function isRevenueColumn($name) + { + return strpos($name, '_revenue') !== false || $name == 'revenue_per_visit'; + } +}
\ No newline at end of file diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php new file mode 100644 index 0000000000..43c7f5c72a --- /dev/null +++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php @@ -0,0 +1,34 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ + +namespace Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; + +use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; + +/** + * TODO + */ +class AllColumns extends HtmlTable +{ + const ID = 'tableAllColumns'; + + /** + * Constructor. + * + * @param \Piwik\ViewDataTable $view + */ + public function __construct($view) + { + $view->visualization_properties->show_extra_columns = true; + + parent::__construct($view); + } +}
\ No newline at end of file diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/Goals.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/Goals.php new file mode 100644 index 0000000000..382eeeaadd --- /dev/null +++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/Goals.php @@ -0,0 +1,34 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ + +namespace Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; + +use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; + +/** + * TODO + */ +class Goals extends HtmlTable +{ + const ID = 'tableGoals'; + + /** + * Constructor. + * + * @param \Piwik\ViewDataTable $view + */ + public function __construct($view) + { + $view->visualization_properties->show_goals_columns = true; + + parent::__construct($view); + } +}
\ No newline at end of file diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php new file mode 100644 index 0000000000..a67e8665fd --- /dev/null +++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php @@ -0,0 +1,212 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ +namespace Piwik\Plugins\CoreVisualizations\Visualizations; + +use Piwik\Common; +use Piwik\View; +use Piwik\DataTable; +use Piwik\DataTableVisualization; +use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator; + +require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php'; +require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php'; +require_once PIWIK_INCLUDE_PATH . '/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php'; + +/** + * DataTable visualization that displays DataTable data in a JQPlot graph. + * TODO: should merge all this logic w/ jqplotdatagenerator & 'Chart' visualizations. + */ +class JqplotGraph extends DataTableVisualization +{ + const DEFAULT_GRAPH_HEIGHT = 250; + const ID = 'jqplot_graph'; + + /** + * Whether the series picker should allow picking more than one series or not. + */ + const ALLOW_MULTI_SELECT_SERIES_PICKER = 'allow_multi_select_series_picker'; + + /** + * The maximum number of elements to render when rendering a jqPlot graph. All other elements + * will be aggregated in an 'Others' element. + */ + const MAX_GRAPH_ELEMENTS = 'max_graph_elements'; + + /** + * The name of the JavaScript class to use as this graph's external series toggle. The class + * must be a subclass of JQPlotExternalSeriesToggle. + * + * @see self::EXTERNAL_SERIES_TOGGLE_SHOW_ALL + */ + const EXTERNAL_SERIES_TOGGLE = 'external_series_toggle'; + + /** + * Whether the graph should show all loaded series upon initial display. + * + * @see self::EXTERNAL_SERIES_TOGGLE + */ + const EXTERNAL_SERIES_TOGGLE_SHOW_ALL = 'external_series_toggle_show_all'; + + /** + * Array property that contains the names of columns that can be selected in the Series Picker. + */ + const SELECTABLE_COLUMNS = 'selectable_columns'; + + /** + * Controls whether all ticks & labels are shown on a graph's x-axis or just some. + */ + const SHOW_ALL_TICKS = 'show_all_ticks'; + + /** + * If true, a row with totals of each DataTable column is added. + */ + const ADD_TOTAL_ROW = 'add_total_row'; + + /** + * The CSS width of the graph. (eg, '100px'). + */ + const GRAPH_WIDTH = 'graph_width'; + + /** + * The CSS height of the graph. (eg, '100px'). + */ + const GRAPH_HEIGHT = 'graph_height'; + + /** + * Controls whether the Series Picker is shown or not. The Series Picker allows users to + * choose between displaying data of different columns. + */ + const SHOW_SERIES_PICKER = 'show_series_picker'; + + /** + * Controls whether the percentage of the total is displayed as a tooltip in Jqplot graphs. + * + * NOTE: Sometimes this percentage is meaningless (when the total of the column values is + * not the total number of elements in the set). In this case the tooltip should not be + * displayed. + */ + const DISPLAY_PERCENTAGE_IN_TOOLTIP = 'display_percentage_in_tooltip'; + + /** + * Constructor. + * + * @param \Piwik\ViewDataTable $view + */ + public function __construct($view) + { + // Graphs require the full dataset, so no filters + $this->request_parameters_to_modify['disable_generic_filters'] = true; + + // 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->request_parameters_to_modify['disable_queued_filters'] = true; + + if ($view->show_goals) { + $goalMetrics = array('nb_conversions', 'revenue'); + $view->visualization_properties->selectable_columns = array_merge( + $view->visualization_properties->selectable_columns, $goalMetrics); + + $view->translations['nb_conversions'] = Piwik_Translate('Goals_ColumnConversions'); + $view->translations['revenue'] = Piwik_Translate('General_TotalRevenue'); + } + + // do not sort if sorted column was initially "label" or eg. it would make "Visits by Server time" not pretty + if ($view->filter_sort_column != 'label') { + $columns = $view->columns_to_display; + + $firstColumn = reset($columns); + if ($firstColumn == 'label') { + $firstColumn = next($columns); + } + + $result['filter_sort_column'] = $firstColumn; + $result['filter_sort_order'] = 'desc'; + } + } + + /** + * Returns an array mapping property names with default values for this visualization. + * + * @return array + */ + public static function getDefaultPropertyValues() + { + // selectable columns + $selectableColumns = array('nb_visits', 'nb_actions'); + if (Common::getRequestVar('period', false) == 'day') { // TODO: should depend on columns datatable has. + $selectableColumns[] = 'nb_uniq_visitors'; + } + + return array( + 'show_offset_information' => false, + 'show_pagination_control' => false, + 'show_exclude_low_population' => false, + 'show_search' => false, + 'show_export_as_image_icon' => true, + 'y_axis_unit' => '', + 'row_picker_match_rows_by' => false, + 'row_picker_visible_rows' => array(), + 'visualization_properties' => array( + 'jqplot_graph' => array( + 'add_total_row' => 0, + 'show_all_ticks' => false, + 'allow_multi_select_series_picker' => true, + 'max_graph_elements' => false, + 'selectable_columns' => $selectableColumns, + 'graph_width' => '100%', + 'graph_height' => self::DEFAULT_GRAPH_HEIGHT . 'px', + 'external_series_toggle' => false, + 'external_series_toggle_show_all' => false, + 'show_series_picker' => true, + 'display_percentage_in_tooltip' => true, + ) + ) + ); + } + + /** + * Renders this visualization. + * + * @param DataTable $dataTable + * @param array $properties View Properties. + * @return string + */ + public function render($dataTable, $properties) + { + $view = new View("@CoreVisualizations/_dataTableViz_jqplotGraph.twig"); + $view->properties = $properties; + $view->dataTable = $dataTable; + $view->data = $this->getGraphData($dataTable, $properties); + return $view->render(); + } + + /** + * Generats JQPlot graph data for a DataTable. + */ + private function getGraphData($dataTable, $properties) + { + $properties = array_merge($properties, $properties['request_parameters_to_modify']); + $dataGenerator = $this->makeDataGenerator($properties); + + $jsonData = $dataGenerator->generate($dataTable); + return str_replace(array("\r", "\n"), '', $jsonData); + } + + /** + * Returns a JqplotDataGenerator for the given graph_type in $properties + * @param array $properties + * @return JqplotDataGenerator + */ + protected function makeDataGenerator($properties) + { + return JqplotDataGenerator::factory($properties['graph_type'], $properties); + } +}
\ No newline at end of file diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php new file mode 100644 index 0000000000..4ec94329e2 --- /dev/null +++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Bar.php @@ -0,0 +1,35 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ + +namespace Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph; + +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph; +use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator; + +/** + * Visualization that renders HTML for a Bar graph using jqPlot. + */ +class Bar extends JqplotGraph +{ + const ID = 'graphVerticalBar'; + + public static function getDefaultPropertyValues() + { + $result = parent::getDefaultPropertyValues(); + $result['visualization_properties']['jqplot_graph']['max_graph_elements'] = 6; + return $result; + } + + protected function makeDataGenerator($properties) + { + return JqplotDataGenerator::factory('bar', $properties); + } +}
\ No newline at end of file diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php new file mode 100644 index 0000000000..f403684834 --- /dev/null +++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Evolution.php @@ -0,0 +1,150 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ + +namespace Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph; + +use Piwik\Common; +use Piwik\Site; +use Piwik\Controller; +use Piwik\Period\Range; +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph; +use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator; + +/** + * Visualization that renders HTML for a line graph using jqPlot. + */ +class Evolution extends JqplotGraph +{ + const ID = 'graphEvolution'; + + const GRAPH_HEIGHT = 170; + const SERIES_COLOR_COUNT = 8; + + public function __construct($view) + { + parent::__construct($view); + + // period will be overridden when 'range' is requested in the UI + // but the graph will display for each day of the range. + // Default 'range' behavior is to return the 'sum' for the range + if (Common::getRequestVar('period', false) == 'range') { + $view->request_parameters_to_modify['period'] = 'day'; + } + + $this->calculateEvolutionDateRange($view); + } + + public static function getDefaultPropertyValues() + { + $result = parent::getDefaultPropertyValues(); + $result['show_all_views_icons'] = false; + $result['show_table'] = false; + $result['show_table'] = false; + $result['show_table_all_columns'] = false; + $result['hide_annotations_view'] = false; + $result['visualization_properties']['graphEvolution']['graph_height'] = self::GRAPH_HEIGHT . 'px'; + return $result; + } + + protected function makeDataGenerator($properties) + { + return JqplotDataGenerator::factory('evolution', $properties); + } + + /** + * Based on the period, date and evolution_{$period}_last_n query parameters, + * calculates the date range this evolution chart will display data for. + */ + private function calculateEvolutionDateRange(&$view) + { + $period = Common::getRequestVar('period'); + + $defaultLastN = self::getDefaultLastN($period); + $originalDate = Common::getRequestVar('date', 'last' . $defaultLastN, 'string'); + + if ($period != 'range') { // show evolution limit if the period is not a range + $view->show_limit_control = true; + + // set the evolution_{$period}_last_n query param + if (Range::parseDateRange($originalDate)) { // if a multiple period + // overwrite last_n param using the date range + $oPeriod = new Range($period, $originalDate); + $lastN = count($oPeriod->getSubperiods()); + } else { // if not a multiple period + list($newDate, $lastN) = self::getDateRangeAndLastN($period, $originalDate, $defaultLastN); + $view->request_parameters_to_modify['date'] = $newDate; + $view->custom_parameters['dateUsedInGraph'] = $newDate; + } + $lastNParamName = self::getLastNParamName($period); + $view->custom_parameters[$lastNParamName] = $lastN; + } + } + + /** + * Returns the entire date range and lastN value for the current request, based on + * a period type and end date. + * + * @param string $period The period type, 'day', 'week', 'month' or 'year' + * @param string $endDate The end date. + * @param int|null $defaultLastN The default lastN to use. If null, the result of + * getDefaultLastN is used. + * @return array An array w/ two elements. The first is a whole date range and the second + * is the lastN number used, ie, array('2010-01-01,2012-01-02', 2). + */ + public static function getDateRangeAndLastN($period, $endDate, $defaultLastN = null) + { + if ($defaultLastN === null) { + $defaultLastN = self::getDefaultLastN($period); + } + + $lastNParamName = self::getLastNParamName($period); + $lastN = Common::getRequestVar($lastNParamName, $defaultLastN, 'int'); + + $site = new Site(Common::getRequestVar('idSite')); + + $dateRange = Controller::getDateRangeRelativeToEndDate($period, 'last' . $lastN, $endDate, $site); + + return array($dateRange, $lastN); + } + + /** + * Returns the default last N number of dates to display for a given period. + * + * @param string $period 'day', 'week', 'month' or 'year' + * @return int + */ + public static function getDefaultLastN($period) + { + switch ($period) { + case 'week': + return 26; + case 'month': + return 24; + case 'year': + return 5; + case 'day': + default: + return 30; + } + } + + /** + * Returns the query parameter that stores the lastN number of periods to get for + * the evolution graph. + * + * @param string $period The period type, 'day', 'week', 'month' or 'year'. + * @return string + */ + public static function getLastNParamName($period) + { + return "evolution_{$period}_last_n"; + } +}
\ No newline at end of file diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php new file mode 100644 index 0000000000..a7f62e7dfd --- /dev/null +++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph/Pie.php @@ -0,0 +1,36 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + * @category Piwik + * @package Piwik + */ + +namespace Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph; + +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph; +use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator; + +/** + * Visualization that renders HTML for a Pie graph using jqPlot. + */ +class Pie extends JqplotGraph +{ + const ID = 'graphPie'; + + public static function getDefaultPropertyValues() + { + $result = parent::getDefaultPropertyValues(); + $result['visualization_properties']['jqplot_graph']['max_graph_elements'] = 6; + $result['visualization_properties']['jqplot_graph']['allow_multi_select_series_picker'] = false; + return $result; + } + + protected function makeDataGenerator($properties) + { + return JqplotDataGenerator::factory('pie', $properties); + } +}
\ No newline at end of file diff --git a/plugins/CoreHome/javascripts/jqplot.js b/plugins/CoreVisualizations/javascripts/jqplot.js index d4287a9bec..4d5f80d046 100644 --- a/plugins/CoreHome/javascripts/jqplot.js +++ b/plugins/CoreVisualizations/javascripts/jqplot.js @@ -60,7 +60,7 @@ JQPlot.prototype = { } if (typeof this.params.axes.yaxis.tickOptions == 'undefined') { - this.params.yaxis.tickOptions = { + this.params.axes.yaxis.tickOptions = { formatString: '%d' }; } @@ -68,21 +68,17 @@ JQPlot.prototype = { /** Generic render function */ render: function (targetDivId, lang) { - var type = $('#' + targetDivId).closest('div.dataTable').data('dataTableInstance').param['viewDataTable']; + var dataTableDiv = $('#' + targetDivId).closest('div.dataTable'); // preapare the appropriate chart type - switch (type) {// TODO: should rely on CSS, not viewDataTable. otherwise ecommerceOrder row evolution will fail - case 'graphEvolution': - this.prepareEvolutionChart(targetDivId, lang); - break; - case 'graphVerticalBar': - this.prepareBarChart(targetDivId, lang); - break; - case 'graphPie': - this.preparePieChart(targetDivId, lang); - break; - default: - return; + if (dataTableDiv.hasClass('dataTableVizEvolution')) { + this.prepareEvolutionChart(targetDivId, lang); + } else if (dataTableDiv.hasClass('dataTableVizBar')) { + this.prepareBarChart(targetDivId, lang); + } else if (dataTableDiv.hasClass('dataTableVizPie')) { + this.preparePieChart(targetDivId, lang); + } else { + return; } // handle replot @@ -169,7 +165,7 @@ JQPlot.prototype = { var percentage = ''; if (typeof self.tooltip.percentages != 'undefined') { - var percentage = self.tooltip.percentages[s][i]; + percentage = self.tooltip.percentages[s][i]; percentage = ' (' + percentage + '%)'; } @@ -304,7 +300,7 @@ JQPlot.prototype = { var popover = $(document.createElement('div')); popover.append('<div style="font-size: 13px; margin-bottom: 10px;">' - + lang.exportText + '</div>').append($(img)) + + lang.exportText + '</div>').append($(img)); popover.dialog({ title: lang.exportTitle, @@ -620,7 +616,8 @@ JQPlot.prototype = { var namespace = graphType + '-graph-colors'; - this.params.seriesColors = colorManager.getColors(namespace, seriesColorNames, true); + this.originalData.params.seriesColors = 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'); diff --git a/plugins/CoreVisualizations/stylesheets/dataTableVisualizations.less b/plugins/CoreVisualizations/stylesheets/dataTableVisualizations.less new file mode 100644 index 0000000000..5ae202f36f --- /dev/null +++ b/plugins/CoreVisualizations/stylesheets/dataTableVisualizations.less @@ -0,0 +1,18 @@ +/* container of each table */ +.dataTableVizHtmlTable > .dataTableWrapper { + width: 450px; + /* not more than 450px to make sure 2 tables can fit horizontally on a 1024 screen */ +} + +.dataTableVizAllColumns > .dataTableWrapper { + width: 535px; +} + +.dataTableVizPie > .dataTableWrapper, .dataTableVizBar > .dataTableWrapper { + width: 500px; + min-height: 1px; +} + +.dataTableVizEvolution > .dataTableWrapper { + width: 100%; +}
\ No newline at end of file diff --git a/plugins/CoreHome/stylesheets/jqplot.css b/plugins/CoreVisualizations/stylesheets/jqplot.css index bd5dec8e59..bd5dec8e59 100644 --- a/plugins/CoreHome/stylesheets/jqplot.css +++ b/plugins/CoreVisualizations/stylesheets/jqplot.css diff --git a/plugins/CoreHome/templates/_dataTableViz_htmlTable.twig b/plugins/CoreVisualizations/templates/_dataTableViz_htmlTable.twig index aa3911f628..a5ba98ac72 100644 --- a/plugins/CoreHome/templates/_dataTableViz_htmlTable.twig +++ b/plugins/CoreVisualizations/templates/_dataTableViz_htmlTable.twig @@ -1,13 +1,20 @@ +{%- set subtablesAreDisabled = properties.visualization_properties.show_goals_columns|default(false) + and properties.visualization_properties.disable_subtable_when_show_goals|default(false) -%} <table cellspacing="0" class="dataTable"> {% include "@CoreHome/_dataTableHead.twig" %} <tbody> {% for rowId, row in dataTable.getRows() %} - {%- set rowHasSubtable = row.getIdSubDataTable() and properties.subtable_controller_action is not null -%} + {%- set rowHasSubtable = not subtablesAreDisabled and row.getIdSubDataTable() and properties.subtable_controller_action is not null -%} {%- set shouldHighlightRow = rowId == constant('Piwik\\DataTable::ID_SUMMARY_ROW') and properties.highlight_summary_row -%} - + {# display this row if it doesn't have a subtable or if we don't replace the row with the subtable #} - {% if not rowHasSubtable or not properties.show_expanded|default(false) or not properties.replace_row_with_subtable|default(false) %} + {%- set showRow = subtablesAreDisabled + or not rowHasSubtable + or not properties.visualization_properties.show_expanded|default(false) + or not properties.visualization_properties.replace_row_with_subtable|default(false) -%} + + {% if showRow %} <tr {% if rowHasSubtable %}id="{{ row.getIdSubDataTable() }}"{% endif %} class="{{ row.getMetadata('css_class') }} {% if rowHasSubtable %}subDataTable{% endif %}{% if shouldHighlightRow %} highlight{% endif %}"> {% for column in properties.columns_to_display %} @@ -19,8 +26,8 @@ {% endif %} {# display subtable if present and showing expanded datatable #} - {% if properties.show_expanded|default(false) and rowHasSubtable %} - {% include properties.subtable_template with {'dataTable': row.getSubtable()} %} + {% if properties.visualization_properties.show_expanded|default(false) and rowHasSubtable %} + {% include properties.visualization_properties.subtable_template with {'dataTable': row.getSubtable()} %} {% endif %} {% endfor %} </tbody> diff --git a/plugins/CoreVisualizations/templates/_dataTableViz_jqplotGraph.twig b/plugins/CoreVisualizations/templates/_dataTableViz_jqplotGraph.twig new file mode 100644 index 0000000000..e980275ac6 --- /dev/null +++ b/plugins/CoreVisualizations/templates/_dataTableViz_jqplotGraph.twig @@ -0,0 +1,10 @@ +<div class="jqplot-graph"> + <div class="piwik-graph" + style="width: {{ properties.visualization_properties.graph_width }}; height: {{ properties.visualization_properties.graph_height }};" + data-data="{{ data|e('html') }}" + {% if properties.visualization_properties.external_series_toggle %} + data-external-series-toggle="{{ properties.visualization_properties.external_series_toggle }}" + data-external-series-show-all="{% if properties.visualization_properties.external_series_toggle_show_all %}1{% else %}0{% endif %}" + {% endif %}> + </div> +</div>
\ No newline at end of file diff --git a/plugins/CoreHome/templates/_dataTableViz_tagCloud.twig b/plugins/CoreVisualizations/templates/_dataTableViz_tagCloud.twig index 1513daca34..1513daca34 100644 --- a/plugins/CoreHome/templates/_dataTableViz_tagCloud.twig +++ b/plugins/CoreVisualizations/templates/_dataTableViz_tagCloud.twig diff --git a/plugins/DBStats/DBStats.php b/plugins/DBStats/DBStats.php index 433f682c9f..e3821800cc 100644 --- a/plugins/DBStats/DBStats.php +++ b/plugins/DBStats/DBStats.php @@ -107,7 +107,7 @@ class DBStats extends \Piwik\Plugin $result['show_offset_information'] = false; $result['show_pagination_control'] = false; - $result['show_all_ticks'] = true; + $result['visualization_properties']['jqplot_graph']['show_all_ticks'] = true; // translate the labels themselves $valueToTranslationStr = array( @@ -148,8 +148,8 @@ class DBStats extends \Piwik\Plugin $this->addPresentationFilters($result); $result['title'] = Piwik_Translate('DBStats_MetricTables'); - $result['relatedReports'] = array( - 'DBStats.getMetricDataSummaryByYear' => Piwik_Translate('DBStats_MetricDataByYear') + $result['related_reports'] = array( + 'DBStats.getMetricDataSummaryByYear' => Piwik_Translate('DBStats_MetricDataByYear') ); return $result; @@ -163,8 +163,8 @@ class DBStats extends \Piwik\Plugin $result['translations']['label'] = Piwik_Translate('CoreHome_PeriodYear'); $result['title'] = Piwik_Translate('DBStats_MetricDataByYear'); - $result['relatedReports'] = array( - 'DBStats.getMetricDataSummary' => Piwik_Translate('DBStats_MetricTables') + $result['related_reports'] = array( + 'DBStats.getMetricDataSummary' => Piwik_Translate('DBStats_MetricTables') ); return $result; @@ -177,7 +177,7 @@ class DBStats extends \Piwik\Plugin $this->addPresentationFilters($result); $result['title'] = Piwik_Translate('DBStats_ReportTables'); - $result['relatedReports'] = array( + $result['related_reports'] = array( 'DBStats.getReportDataSummaryByYear' => Piwik_Translate('DBStats_ReportDataByYear') ); @@ -192,8 +192,8 @@ class DBStats extends \Piwik\Plugin $result['translations']['label'] = Piwik_Translate('CoreHome_PeriodYear'); $result['title'] = Piwik_Translate('DBStats_ReportDataByYear'); - $result['relatedReports'] = array( - 'DBStats.getReportDataSummary' => Piwik_Translate('DBStats_ReportTables') + $result['related_reports'] = array( + 'DBStats.getReportDataSummary' => Piwik_Translate('DBStats_ReportTables') ); return $result; @@ -258,7 +258,7 @@ class DBStats extends \Piwik\Plugin $properties['show_tag_cloud'] = false; $properties['show_table_all_columns'] = false; $properties['keep_summary_row'] = true; - $properties['disable_row_evolution'] = true; + $properties['visualization_properties']['table']['disable_row_evolution'] = true; $properties['translations'] = array( 'label' => Piwik_Translate('DBStats_Table'), 'year' => Piwik_Translate('CoreHome_PeriodYear'), diff --git a/plugins/Dashboard/javascripts/dashboard.js b/plugins/Dashboard/javascripts/dashboard.js index e23ff669a4..e2a73be1d3 100644 --- a/plugins/Dashboard/javascripts/dashboard.js +++ b/plugins/Dashboard/javascripts/dashboard.js @@ -12,9 +12,9 @@ function initDashboard(dashboardId, dashboardLayout) { $('#periodString').after($('#dashboardSettings')); var leftMargin = $('#periodString')[0].offsetWidth; - var segmentSelector = $('.segmentationContainer:visible'); + var segmentSelector = $('#segmentEditorPanel:visible'); if(segmentSelector.length) { - segmentSelector = $($('.segmentationContainer:visible')[0]); + segmentSelector = $($('#segmentEditorPanel:visible')[0]); leftMargin = segmentSelector.position().left + segmentSelector.outerWidth(); } $('#dashboardSettings').css({left: leftMargin}); diff --git a/plugins/Dashboard/javascripts/dashboardObject.js b/plugins/Dashboard/javascripts/dashboardObject.js index 67614dd231..a91b9ad46a 100644 --- a/plugins/Dashboard/javascripts/dashboardObject.js +++ b/plugins/Dashboard/javascripts/dashboardObject.js @@ -409,9 +409,7 @@ } //launch 'sortable' property on every dashboard widgets - if ($( "div.col", dashboardElement ).is( ":data('ui-sortable')" )) { - $( "div.col", dashboardElement ).sortable('destroy'); - } + $( "div.col:data('ui-sortable')", dashboardElement ).sortable('destroy'); $('div.col', dashboardElement) .sortable({ diff --git a/plugins/Dashboard/stylesheets/dashboard.less b/plugins/Dashboard/stylesheets/dashboard.less index a287a438fc..f00fe46366 100644 --- a/plugins/Dashboard/stylesheets/dashboard.less +++ b/plugins/Dashboard/stylesheets/dashboard.less @@ -8,9 +8,24 @@ } .top_controls_inner { - position: relative; - height: 32px; - padding-bottom: 20px; + clear: left; + position: relative; + height: 32px; + padding-bottom: 20px; +} + +@media all and (max-width: 749px) { + .top_controls { + height: auto; + } + + .top_controls #periodString, + .top_controls #dashboardSettings, + .top_controls #segmentEditorPanel { + position: static; + margin: 0 0 10px; + float: none; + } } #dashboardWidgetsArea { @@ -43,7 +58,7 @@ } .col.width-33 { - width: 33%; + width: 33.33%; } .col.width-30 { @@ -65,6 +80,7 @@ overflow: hidden; border-radius: 4px; font-size: 14px; + z-index: 1; } .widgetHover { @@ -86,7 +102,7 @@ .widgetContent.loading { opacity: 0.5; - background: url(../../../plugins/Zeitgeist/images/loading-blue.gif) no-repeat top right; + background: url(plugins/Zeitgeist/images/loading-blue.gif) no-repeat top right; } .widget h2 { @@ -95,10 +111,12 @@ font-weight: bold; } +.widget p { + margin-left: 10px; +} + .widgetTop { - background: #b5b0a7 url(../../../plugins/Zeitgeist/images/dashboard_h_bg.png) repeat-x 0 0; - border-radius: 4px 4px 0 0; - width: 100%; + background: #b5b0a7 url(plugins/Zeitgeist/images/dashboard_h_bg.png) repeat-x 0 0; cursor: move; font-size: 10pt; font-weight: bold; @@ -106,7 +124,7 @@ } .widgetTopHover { - background: #B0A798 url(../../../plugins/Zeitgeist/images/dashboard_h_bg_hover.png) repeat-x 0 0; + background: #B0A798 url(plugins/Zeitgeist/images/dashboard_h_bg_hover.png) repeat-x 0 0; } .widgetName { @@ -117,6 +135,11 @@ text-shadow: 1px 1px 2px #7e7363; } +// Overriding some dataTable css for better dashboard display +.widget .dataTableWrapper { + width: 100% !important; +} + .button { cursor: pointer; } @@ -157,7 +180,7 @@ } .ui-dialog-buttonset input[type=button], .ui-dialog-buttonset button{ - background: #B5B0A7 url(../../../plugins/Zeitgeist/images/dashboard_h_bg_hover.png) repeat-x 0 0 !important; + background: #B5B0A7 url(plugins/Zeitgeist/images/dashboard_h_bg_hover.png) repeat-x 0 0 !important; color: #fff !important; border: 0 !important; font-size: 12px !important; @@ -215,6 +238,7 @@ color: #444; font-size: 14px; cursor: pointer; + overflow: hidden; } #dashboardSettings:hover { @@ -223,7 +247,7 @@ } #dashboardSettings > span { - background: url(../../../plugins/Zeitgeist/images/sort_subtable_desc.png) right center no-repeat; + background: url(plugins/Zeitgeist/images/sort_subtable_desc.png) right center no-repeat; padding-right: 20px; display: block; } @@ -358,7 +382,7 @@ ul.widgetpreview-widgetlist li { } .widgetpreview-base li.widgetpreview-choosen { - background: #e4e2d7 url(../../../plugins/Zeitgeist/images/arr_r.png) no-repeat right 6px; + background: #e4e2d7 url(plugins/Zeitgeist/images/arr_r.png) no-repeat right 6px; color: #255792; font-weight: bold; } @@ -487,5 +511,9 @@ div.widgetpreview-preview { .col.width-30, .col.width-25 { width: 100%; + .widget { + margin-right: 0; + } } + }
\ No newline at end of file diff --git a/plugins/Dashboard/templates/index.twig b/plugins/Dashboard/templates/index.twig index cc86a56715..e16fb1955e 100644 --- a/plugins/Dashboard/templates/index.twig +++ b/plugins/Dashboard/templates/index.twig @@ -4,8 +4,9 @@ <div id="Dashboard"> <ul> {% for dashboard in dashboards %} - <li class="dashboardMenuItem" id="Dashboard_embeddedIndex_{{ dashboard.iddashboard }}"><a - href="javascript:$('#dashboardWidgetsArea').dashboard('loadDashboard', {{ dashboard.iddashboard }});">{{ dashboard.name|escape }}</a></li> + <li class="dashboardMenuItem" id="Dashboard_embeddedIndex_{{ dashboard.iddashboard }}"> + <a href="javascript:$('#dashboardWidgetsArea').dashboard('loadDashboard', {{ dashboard.iddashboard }});">{{ dashboard.name|escape }}</a> + </li> {% endfor %} </ul> </div> diff --git a/plugins/DevicesDetection/DevicesDetection.php b/plugins/DevicesDetection/DevicesDetection.php index 2e8902d6cf..d207cdc285 100644 --- a/plugins/DevicesDetection/DevicesDetection.php +++ b/plugins/DevicesDetection/DevicesDetection.php @@ -317,9 +317,9 @@ class DevicesDetection extends \Piwik\Plugin return array( 'show_search' => false, 'show_exclude_low_population' => false, - 'translations' => array('label' => Piwik_Translate("DevicesDetection_dataTableLabelSystemFamily")), - 'title' => Piwik_Translate('DeviceDetection_OperatingSystemFamilies'), - 'relatedReports' => $this->getOsRelatedReports() + 'translations' => array('label' => Piwik_Translate("DevicesDetection_dataTableLabelSystemFamily")), + 'title' => Piwik_Translate('DeviceDetection_OperatingSystemFamilies'), + 'related_reports' => $this->getOsRelatedReports() ); } @@ -328,9 +328,9 @@ class DevicesDetection extends \Piwik\Plugin return array( 'show_search' => false, 'show_exclude_low_population' => false, - 'translations' => array('label' => Piwik_Translate("DevicesDetection_dataTableLabelSystemVersion")), - 'title' => Piwik_Translate('DeviceDetection_OperatingSystemVersions'), - 'relatedReports' => $this->getOsRelatedReports() + 'translations' => array('label' => Piwik_Translate("DevicesDetection_dataTableLabelSystemVersion")), + 'title' => Piwik_Translate('DeviceDetection_OperatingSystemVersions'), + 'related_reports' => $this->getOsRelatedReports() ); } @@ -339,9 +339,9 @@ class DevicesDetection extends \Piwik\Plugin return array( 'show_search' => false, 'show_exclude_low_population' => false, - 'translations' => array('label' => Piwik_Translate("DevicesDetection_dataTableLabelBrowserFamily")), - 'title' => Piwik_Translate('DevicesDetection_BrowsersFamily'), - 'relatedReports' => $this->getBrowserRelatedReports() + 'translations' => array('label' => Piwik_Translate("DevicesDetection_dataTableLabelBrowserFamily")), + 'title' => Piwik_Translate('DevicesDetection_BrowsersFamily'), + 'related_reports' => $this->getBrowserRelatedReports() ); } @@ -350,8 +350,8 @@ class DevicesDetection extends \Piwik\Plugin return array( 'show_search' => false, 'show_exclude_low_population' => false, - 'translations' => array('label' => Piwik_Translate("DevicesDetection_dataTableLabelBrowserVersion")), - 'relatedReports' => $this->getBrowserRelatedReports() + 'translations' => array('label' => Piwik_Translate("DevicesDetection_dataTableLabelBrowserVersion")), + 'related_reports' => $this->getBrowserRelatedReports() ); } @@ -370,4 +370,4 @@ class DevicesDetection extends \Piwik\Plugin 'DevicesDetection.getBrowserVersions' => Piwik_Translate('DevicesDetection_BrowserVersions') ); } -} +}
\ No newline at end of file diff --git a/plugins/DevicesDetection/lang/en.php b/plugins/DevicesDetection/lang/en.php index 93d4504957..7d1d82ae50 100644 --- a/plugins/DevicesDetection/lang/en.php +++ b/plugins/DevicesDetection/lang/en.php @@ -13,15 +13,15 @@ $translations = array( "DevicesDetection_dataTableLabelBrowserFamily" => "Browser family", "DevicesDetection_dataTableLabelBrowserVersion" => "Browser version", // Title translations for reports - "DevicesDetection_DeviceType" => "Device types report", - "DevicesDetection_DeviceBrand" => "Device manufacturers report", - "DevicesDetection_DeviceModel" => "Device model report", +// "DevicesDetection_DeviceType" => "Device types report", +// "DevicesDetection_DeviceBrand" => "Device manufacturers report", +// "DevicesDetection_DeviceModel" => "Device model report", 'DeviceDetection_OperatingSystemVersions' => "Operating System versions", 'DeviceDetection_OperatingSystemFamilies' => "Operating System families", 'DevicesDetection_BrowsersFamily' => 'Browsers families', 'DevicesDetection_BrowserVersions' => 'Browser versions', // Evolution graph title translations - "DevicesDetection_DeviceType" => "Device type", + 'DevicesDetection_DeviceType' => "Device type", 'DevicesDetection_DeviceBrand' => 'Device brand', 'DevicesDetection_DeviceModel' => 'Device model', // 'DevicesDetection_OS' => 'Device operating system', diff --git a/plugins/ExampleRssWidget/Controller.php b/plugins/ExampleRssWidget/Controller.php index 45e5a44cdc..a8a5eb7247 100644 --- a/plugins/ExampleRssWidget/Controller.php +++ b/plugins/ExampleRssWidget/Controller.php @@ -44,6 +44,9 @@ class Controller extends \Piwik\Controller } } + /** + * @param \Exception $e + */ protected function error($e) { echo '<div class="pk-emptyDataTable">' diff --git a/plugins/ExampleUI/Controller.php b/plugins/ExampleUI/Controller.php index 201610f7e7..dc1415b411 100644 --- a/plugins/ExampleUI/Controller.php +++ b/plugins/ExampleUI/Controller.php @@ -26,12 +26,20 @@ class Controller extends \Piwik\Controller $view->translations['label'] = "Hour of day"; $view->filter_sort_column = 'label'; $view->filter_sort_order = 'asc'; - $view->graph_limit = 24; $view->filter_limit = 24; $view->show_exclude_low_population = false; $view->show_table_all_columns = false; - $view->disable_row_evolution = true; $view->y_axis_unit = '°C'; // useful if the user requests the bar graph + $view->visualization_properties->setForVisualization( + 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\HtmlTable', + 'disable_row_evolution', + true + ); + $view->visualization_properties->setForVisualization( + 'Piwik\\Plugins\\CoreVisualizations\\Visualizations\\JqplotGraph', + 'max_graph_elements', + 24 + ); echo $view->render(); } @@ -57,7 +65,7 @@ class Controller extends \Piwik\Controller 'graphVerticalBar', 'ExampleUI.getTemperatures', $controllerAction = 'ExampleUI.barGraph'); $view->translations['value'] = "Temperature"; $view->y_axis_unit = '°C'; - $view->graph_limit = 24; + $view->visualization_properties->max_graph_elements = 24; $view->show_footer = false; echo $view->render(); } @@ -68,7 +76,7 @@ class Controller extends \Piwik\Controller 'graphPie', 'ExampleUI.getPlanetRatios', $controllerAction = 'ExampleUI.pieGraph'); $view->columns_to_display = array('value'); $view->translations['value'] = "times the diameter of Earth"; - $view->graph_limit = 10; + $view->visualization_properties->max_graph_elements = 10; $view->show_footer_icons = false; echo $view->render(); } diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php index c9e10f4074..7cb2353a0b 100644 --- a/plugins/Goals/Controller.php +++ b/plugins/Goals/Controller.php @@ -290,7 +290,7 @@ class Controller extends \Piwik\Controller $view->translations[$columnName] = $columnTranslation; } $view->columns_to_display = $columns; - $view->selectable_columns = $selectableColumns; + $view->visualization_properties->selectable_columns = $selectableColumns; $langString = $idGoal ? 'Goals_SingleGoalOverviewDocumentation' : 'Goals_GoalsOverviewDocumentation'; $view->documentation = Piwik_Translate($langString, '<br />'); diff --git a/plugins/Goals/Goals.php b/plugins/Goals/Goals.php index 2d3bd0de27..f15569affb 100644 --- a/plugins/Goals/Goals.php +++ b/plugins/Goals/Goals.php @@ -88,18 +88,18 @@ class Goals extends \Piwik\Plugin public function getListHooksRegistered() { $hooks = array( - 'AssetManager.getJsFiles' => 'getJsFiles', - 'AssetManager.getCssFiles' => 'getCssFiles', - 'Common.fetchWebsiteAttributes' => 'fetchGoalsFromDb', - 'ArchiveProcessing_Day.compute' => 'archiveDay', - 'ArchiveProcessing_Period.compute' => 'archivePeriod', - 'API.getReportMetadata.end' => 'getReportMetadata', - 'API.getSegmentsMetadata' => 'getSegmentsMetadata', - 'WidgetsList.add' => 'addWidgets', - 'Menu.add' => 'addMenus', - 'SitesManager.deleteSite' => 'deleteSiteGoals', - 'Goals.getReportsWithGoalMetrics' => 'getActualReportsWithGoalMetrics', - 'ViewDataTable.getReportDisplayProperties' => 'getReportDisplayProperties', // TODO: ViewDataTable should get ALL once + 'AssetManager.getJsFiles' => 'getJsFiles', + 'AssetManager.getCssFiles' => 'getCssFiles', + 'Common.fetchWebsiteAttributes' => 'fetchGoalsFromDb', + 'ArchiveProcessing_Day.compute' => 'archiveDay', + 'ArchiveProcessing_Period.compute' => 'archivePeriod', + 'API.getReportMetadata.end' => 'getReportMetadata', + 'API.getSegmentsMetadata' => 'getSegmentsMetadata', + 'WidgetsList.add' => 'addWidgets', + 'Menu.add' => 'addMenus', + 'SitesManager.deleteSite' => 'deleteSiteGoals', + 'Goals.getReportsWithGoalMetrics' => 'getActualReportsWithGoalMetrics', + 'ViewDataTable.getReportDisplayProperties' => 'getReportDisplayProperties', ); return $hooks; } diff --git a/plugins/Goals/templates/_listGoalEdit.twig b/plugins/Goals/templates/_listGoalEdit.twig index c7acc0c553..b8803ff577 100644 --- a/plugins/Goals/templates/_listGoalEdit.twig +++ b/plugins/Goals/templates/_listGoalEdit.twig @@ -51,7 +51,7 @@ "url": "{{ 'Goals_VisitUrl'|translate }}", "title": "{{ 'Goals_VisitPageTitle'|translate }}", "external_website": "{{ 'Goals_ClickOutlink'|translate }}" - } + }; $(document).ready(function () { // translation of the goal "match attribute" to human readable description diff --git a/plugins/Installation/Controller.php b/plugins/Installation/Controller.php index 9160ca4c63..23333872be 100644 --- a/plugins/Installation/Controller.php +++ b/plugins/Installation/Controller.php @@ -623,8 +623,8 @@ class Controller extends \Piwik\Controller\Admin /** * Redirect to next step * - * @param string Current step - * @return none + * @param string $currentStep Current step + * @return void */ protected function redirectToNextStep($currentStep) { @@ -637,7 +637,7 @@ class Controller extends \Piwik\Controller\Admin /** * Skip this step (typically to mark the current function as completed) * - * @param string function name + * @param string $step function name */ protected function skipThisStep($step) { diff --git a/plugins/Installation/FormDatabaseSetup.php b/plugins/Installation/FormDatabaseSetup.php index a1f58c6c78..c67d8b8470 100644 --- a/plugins/Installation/FormDatabaseSetup.php +++ b/plugins/Installation/FormDatabaseSetup.php @@ -52,7 +52,7 @@ class FormDatabaseSetup extends QuickForm2 $user->addRule('required', Piwik_Translate('General_Required', Piwik_Translate('Installation_DatabaseSetupLogin'))); $requiredPrivileges = Rule_checkUserPrivileges::getRequiredPrivilegesPretty(); $user->addRule('checkUserPrivileges', - Piwik_Translate('Installation_InsufficientPrivileges', $requiredPrivileges . '<br/><br/>') . + Piwik_Translate('Installation_InsufficientPrivilegesMain', $requiredPrivileges . '<br/><br/>') . Piwik_Translate('Installation_InsufficientPrivilegesHelp')); $this->addElement('password', 'password') @@ -289,7 +289,7 @@ class Rule_checkUserPrivileges extends HTML_QuickForm2_Rule /** * Drops the tables created by the privilege checking queries, if they exist. * - * @param $db The database object to use. + * @param \Piwik\Db $db The database object to use. */ private function dropExtraTables($db) { diff --git a/plugins/Installation/stylesheets/installation.css b/plugins/Installation/stylesheets/installation.css index 2cdd581b1a..354f74b539 100644 --- a/plugins/Installation/stylesheets/installation.css +++ b/plugins/Installation/stylesheets/installation.css @@ -29,6 +29,10 @@ p { padding: 20px 30px 40px; } +#installationPage #logo { + height: auto; +} + h2 { font-size: 20px; color: #666666; @@ -106,7 +110,7 @@ code { } /* Cadre general */ -#main { +#installationPage { margin: 30px 5px 5px; text-align: left; } diff --git a/plugins/Installation/templates/layout.twig b/plugins/Installation/templates/layout.twig index 705b40d492..d7b8fb4ff5 100644 --- a/plugins/Installation/templates/layout.twig +++ b/plugins/Installation/templates/layout.twig @@ -16,7 +16,7 @@ {% endif %} </head> <body> -<div id="main"> +<div id="installationPage"> <div id="content"> <div id="logo"> <img id="title" width='160' src="plugins/Zeitgeist/images/logo.png"/> <span diff --git a/plugins/Live/API.php b/plugins/Live/API.php index a1d2b9248f..e8fa49ed30 100644 --- a/plugins/Live/API.php +++ b/plugins/Live/API.php @@ -58,6 +58,10 @@ require_once PIWIK_INCLUDE_PATH . '/plugins/Live/Visitor.php'; */ class API { + const VISITOR_PROFILE_MAX_VISITS_TO_AGGREGATE = 100; + const VISITOR_PROFILE_MAX_VISITS_TO_SHOW = 10; + const VISITOR_PROFILE_DATE_FORMAT = '%day% %shortMonth% %longYear%'; + static private $instance = null; /** @@ -161,6 +165,154 @@ class API } /** + * TODO + * TODO: add abandoned cart info. + * TODO: check for most recent vs. first visit + * TODO: make sure ecommerce is enabled for site, check for goals plugin, etc. + */ + public function getVisitorProfile($idSite, $period, $date, $idVisitor, $segment = false) + { + if ($segment !== false) { + $segment .= '&'; + } + $segment .= 'visitorId==' . $idVisitor; // TODO what happens when visitorId is in the segment? + + $visits = $this->getLastVisitsDetails($idSite, $period, $date, $segment, $filter_limit = self::VISITOR_PROFILE_MAX_VISITS_TO_AGGREGATE); + if ($visits->getRowsCount() == 0) { + return array(); + } + + $result = array(); + + // use the most recent visit for IP/browser/OS/etc. info + // TODO: could just do all of this in twig/JS... really need to do it here? + $mostRecentVisit = $visits->getFirstRow(); + $result['latestVisitIp'] = $mostRecentVisit->getColumn('visitIp'); + $result['visitorId'] = $mostRecentVisit->getColumn('visitorId'); + $result['browserCode'] = $mostRecentVisit->getColumn('browserCode'); + $result['browserName'] = Piwik_UserSettings_getBrowserFromBrowserVersion($mostRecentVisit->getColumn('browserName')); + $result['browserLogo'] = $mostRecentVisit->getColumn('browserIcon'); + $result['operatingSystemCode'] = $mostRecentVisit->getColumn('operatingSystemCode'); + $result['operatingSystemShortName'] = $mostRecentVisit->getColumn('operatingSystemShortName'); + $result['operatingSystemLogo'] = $mostRecentVisit->getColumn('operatingSystemIcon'); + $result['resolution'] = $mostRecentVisit->getColumn('resolution'); + $result['customVariables'] = $mostRecentVisit->getColumn('customVariables'); + + // aggregate all requested visits info for total_* info + $result['totalVisits'] = 0; + $result['totalVisitDuration'] = 0; + $result['totalActionCount'] = 0; + $result['totalGoalConversions'] = 0; + $result['totalEcommerceConversions'] = 0; + $result['totalEcommerceRevenue'] = 0; + $result['totalEcommerceItems'] = 0; + $result['totalAbandonedCarts'] = 0; + $result['totalAbandonedCartsRevenue'] = 0; + $result['totalAbandonedCartsItems'] = 0; + foreach ($visits->getRows() as $visit) { + ++$result['totalVisits']; + + $result['totalVisitDuration'] += $visit->getColumn('visitDuration'); + $result['totalActionCount'] += $visit->getColumn('actions'); + $result['totalGoalConversions'] += $visit->getColumn('goalConversions'); + + // individual goal conversions are stored in action details + foreach ($visit->getColumn('actionDetails') as $action) { + if ($action['type'] == 'goal') { // handle goal conversion + $idGoal = $action['goalId']; + + if (!isset($result['totalConversionsByGoal'][$idGoal])) { + $result['totalConversionsByGoal'][$idGoal] = 0; + } + ++$result['totalConversionsByGoal'][$idGoal]; + + if (!empty($action['revenue'])) { + if (!isset($result['totalRevenueByGoal'][$idGoal])) { + $result['totalRevenueByGoal'][$idGoal] = 0; + } + $result['totalRevenueByGoal'][$idGoal] += $action['revenue']; + } + } else if ($action['type'] == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { // handle ecommerce order + ++$result['totalEcommerceConversions']; + $result['totalEcommerceRevenue'] += $action['revenue']; + $result['totalEcommerceItems'] += $action['items']; + } else if ($action['type'] == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART) { // handler abandoned cart + ++$result['totalAbandonedCarts']; + $result['totalAbandonedCartsRevenue'] += $action['revenue']; + $result['totalAbandonedCartsItems'] += $action['items']; + } + } + } + + $result['totalVisitDurationPretty'] = Piwik::getPrettyTimeFromSeconds($result['totalVisitDuration']); + + // use requested visits for first/last visit info + $result['firstVisit'] = $this->getVisitorProfileVisitSummary(end($visits->getRows())); + $result['lastVisit'] = $this->getVisitorProfileVisitSummary(reset($visits->getRows())); + + // use N most recent visits for last_visits + $visits->deleteRowsOffset(self::VISITOR_PROFILE_MAX_VISITS_TO_SHOW); + $result['lastVisits'] = $visits; + + // use the right date format for the pretty server date + $timezone = Site::getTimezoneFor($idSite); + foreach ($result['lastVisits']->getRows() as $visit) { + $dateTimeVisitFirstAction = Date::factory($visit->getColumn('firstActionTimestamp'), $timezone); + $dateTimePretty = $dateTimeVisitFirstAction->getLocalized(self::VISITOR_PROFILE_DATE_FORMAT); + + $visit->setColumn('serverDatePrettyFirstAction', $dateTimePretty); + } + + return $result; + } + + /** + * Returns a summary for an important visit. Used to describe the first & last visits of a visitor. + * + * @param Piwik\DataTable\Row $visit + */ + private function getVisitorProfileVisitSummary($visit) + { + $today = Date::today(); + + $serverDate = $visit->getColumn('serverDate'); + return array( + 'date' => $serverDate, + 'prettyDate' => Date::factory($serverDate)->getLocalized(self::VISITOR_PROFILE_DATE_FORMAT), + 'daysAgo' => (int)Date::secondsToDays($today->getTimestamp() - Date::factory($serverDate)->getTimestamp()), + 'referralSummary' => $this->getReferrerSummaryForVisit($visit), + ); + } + + /** + * Returns a summary for a visit's referral. + * + * @param Piwik\DataTable\Row $visit + */ + private function getReferrerSummaryForVisit($visit) + { + $referrerType = $visit->getColumn('referrerType'); + if ($referrerType === false + || $referrerType == 'direct' + ) { + $result = Piwik_Translate('Referers_DirectEntry'); + } else if ($referrerType == 'search') { + $result = $visit->getColumn('referrerName'); + + $keyword = $visit->getColumn('referrerKeyword'); + if ($keyword !== false) { + $result .= ' (' . $keyword . ')'; + } + } else if ($referrerType == 'campaign') { + $result = Piwik_Translate('Referers_ColumnCampaign') . ' (' . $visit->getColumn('referrerName') . ')'; + } else { + $result = $visit->getColumn('referrerName'); + } + + return $result; + } + + /** * @deprecated */ public function getLastVisits($idSite, $filter_limit = 10, $minTimestamp = false) diff --git a/plugins/Live/Controller.php b/plugins/Live/Controller.php index fd961c923f..a845c468b0 100644 --- a/plugins/Live/Controller.php +++ b/plugins/Live/Controller.php @@ -17,6 +17,7 @@ use Piwik\Config; use Piwik\Plugins\Live\API; use Piwik\ViewDataTable; use Piwik\View; +use Piwik\FrontController; /** * @package Live @@ -101,6 +102,7 @@ class Controller extends \Piwik\Controller */ public function getVisitorLog($fetch = false) { + $test = array(); $str = (string)$test; return $this->getLastVisitsDetails($fetch); } @@ -132,4 +134,37 @@ class Controller extends \Piwik\Controller $view->pisToday = $today['actions']; return $view; } + + /** + * TODO + */ + public function getVisitorProfilePopup() + { + $idSite = Common::getRequestVar('idSite', null, 'int'); + + $view = new View('@Live/getVisitorProfilePopup.twig'); + $view->idSite = $idSite; + $view->goals = Piwik_Goals_API::getInstance()->getGoals($idSite); + $view->visitorData = Request::processRequest('Live.getVisitorProfile'); + $view->userCountryMap = $this->getUserCountryMapForVisitorProfile(); + echo $view->render(); + } + + private function getUserCountryMapForVisitorProfile() + { + if (empty($_GET['segment'])) { + $_GET['segment'] = ''; + $originalSegment = ''; + } else { + $_GET['segment'] .= '&'; + $originalSegment = $_GET['segment']; + } + $_GET['segment'] .= 'visitorId==' . Common::getRequestVar('idVisitor'); + + $result = FrontController::getInstance()->fetchDispatch('UserCountryMap', 'visitorMap', array('fetch' => true)); // TODO: check if plugin is enabled? + + $_GET['segment'] = $originalSegment; + + return $result; + } }
\ No newline at end of file diff --git a/plugins/Live/Live.php b/plugins/Live/Live.php index 7ef67b56b5..bbdd142b43 100644 --- a/plugins/Live/Live.php +++ b/plugins/Live/Live.php @@ -36,6 +36,7 @@ class Live extends \Piwik\Plugin public function getCssFiles(&$cssFiles) { $cssFiles[] = "plugins/Live/stylesheets/live.less"; + $cssFiles[] = "plugins/Live/stylesheets/visitor_profile.less"; } public function getJsFiles(&$jsFiles) @@ -72,18 +73,22 @@ class Live extends \Piwik\Plugin 'filter_limit' => 20, 'show_offset_information' => false, 'show_exclude_low_population' => false, - 'show_all_views_icons' => false, - 'show_table_all_columns' => false, - 'show_export_as_rss_feed' => false, - 'disable_row_actions' => true, - 'documentation' => Piwik_Translate('Live_VisitorLogDocumentation', array('<br />', '<br />')), - 'custom_parameters' => array( + 'show_all_views_icons' => false, + 'show_table_all_columns' => false, + 'show_export_as_rss_feed' => false, + 'documentation' => Piwik_Translate('Live_VisitorLogDocumentation', array('<br />', '<br />')), + 'custom_parameters' => array( // set a very high row count so that the next link in the footer of the data table is always shown 'totalRows' => 10000000, 'filterEcommerce' => Common::getRequestVar('filterEcommerce', 0, 'int'), 'pageUrlNotDefined' => Piwik_Translate('General_NotDefined', Piwik_Translate('Actions_ColumnPageURL')) ), + 'visualization_properties' => array( + 'table' => array( + 'disable_row_actions' => true, + ) + ) ); } -} +}
\ No newline at end of file diff --git a/plugins/Live/images/REMOVE_ME_avatar.jpg b/plugins/Live/images/REMOVE_ME_avatar.jpg Binary files differnew file mode 100644 index 0000000000..dfd7ec81de --- /dev/null +++ b/plugins/Live/images/REMOVE_ME_avatar.jpg diff --git a/plugins/Live/images/REMOVE_ME_chart.png b/plugins/Live/images/REMOVE_ME_chart.png Binary files differnew file mode 100644 index 0000000000..5f8f03ad6a --- /dev/null +++ b/plugins/Live/images/REMOVE_ME_chart.png diff --git a/plugins/Live/images/REMOVE_ME_map.jpg b/plugins/Live/images/REMOVE_ME_map.jpg Binary files differnew file mode 100644 index 0000000000..ffae900c21 --- /dev/null +++ b/plugins/Live/images/REMOVE_ME_map.jpg diff --git a/plugins/Live/images/avatar_frame.png b/plugins/Live/images/avatar_frame.png Binary files differnew file mode 100644 index 0000000000..23eccfd5fb --- /dev/null +++ b/plugins/Live/images/avatar_frame.png diff --git a/plugins/Live/images/paperclip.png b/plugins/Live/images/paperclip.png Binary files differnew file mode 100644 index 0000000000..b38d33caa1 --- /dev/null +++ b/plugins/Live/images/paperclip.png diff --git a/plugins/Live/images/visitor_profile_background.jpg b/plugins/Live/images/visitor_profile_background.jpg Binary files differnew file mode 100644 index 0000000000..082d637dcf --- /dev/null +++ b/plugins/Live/images/visitor_profile_background.jpg diff --git a/plugins/Live/images/visitor_profile_close.png b/plugins/Live/images/visitor_profile_close.png Binary files differnew file mode 100644 index 0000000000..ae132b7b2c --- /dev/null +++ b/plugins/Live/images/visitor_profile_close.png diff --git a/plugins/Live/images/visitor_profile_gradient.png b/plugins/Live/images/visitor_profile_gradient.png Binary files differnew file mode 100644 index 0000000000..ac5068b54d --- /dev/null +++ b/plugins/Live/images/visitor_profile_gradient.png diff --git a/plugins/Live/stylesheets/live.less b/plugins/Live/stylesheets/live.less index 29d4b03e03..4325471bb6 100644 --- a/plugins/Live/stylesheets/live.less +++ b/plugins/Live/stylesheets/live.less @@ -18,7 +18,7 @@ } #visitsLive .country { - background: #FFF url(../../CoreHome/images/bullet1.gif) no-repeat scroll 0 0; + background: #FFF url(plugins/CoreHome/images/bullet1.gif) no-repeat scroll 0 0; } #visitsLive .referer { diff --git a/plugins/Live/stylesheets/visitor_profile.less b/plugins/Live/stylesheets/visitor_profile.less new file mode 100644 index 0000000000..6b94c5ce8a --- /dev/null +++ b/plugins/Live/stylesheets/visitor_profile.less @@ -0,0 +1,367 @@ +// TODO: use less variables for height & width +.visitor-profile { + position:relative; + width:1149px; + height:844px; + border:1px solid #a19e96; + border-radius:5px; + background:url(../images/visitor_profile_background.jpg) repeat; + box-shadow:5px 5px 5px rgba(0,0,0,0.22); + + h1 { + font-size:18px; + color:#7e7363; + text-shadow:0 1px 0 rgba(255,255,255,1); + margin:9px 0 0 0; + padding:0; + + a { + font-size:12px; + margin-left:3px; + } + } + + span, strong { + display:inline-block; + font-size:14px; + color:#5e5e5c; + line-height:19px; + padding-left:4px; + } + + p { + font-size:13px; + color:#5e5e5c; + line-height:20px; + } + + h2 { + display:inline-block; + font-size:14px; + margin:0 0 0 5px; + padding:0; + font-weight:bold; + color:black; + } + + // TODO: iOS icon looks better in mockup + // TODO: remove temporary images +} + +.visitor-profile-close { + position:absolute; + right:-17px; + top:-16px; + height:35px; + width:35px; + background:url(../images/visitor_profile_close.png) no-repeat; +} + +.visitor-profile a { + text-decoration:none; + color:#255792; +} + +.visitor-profile > div { + width:100%; +} + +.visitor-profile-info { + height:791px; + border-top:2px solid #f6f6f6; + border-bottom:1px solid #d1cec8; + border-radius:5px 5px 0 0; + box-shadow:inset 0 25px 15px -10px #e0e0e0, inset 0 -25px 15px -10px #e0e0e0; + + > div { + width:573px; + height:100%; + float:left; + border-left:1px solid #d1cec8; + + > div { + border-bottom:1px solid #d1cec8; + } + } + + > div:first-child { + border-left:none; + } + + > div:last-child { + border-bottom:none; + } +} + +.visitor-profile-avatar > div { + position:relative; + float:left; + height:145px; + margin-right:15px; + padding:12px 0 13px; +} + +.visitor-profile-avatar > div:first-child { + width:166px; + margin-right:0; + padding-left:16px; + + > .visitor-profile-image-frame { + width:149px; + height:154px; + background:url(../images/avatar_frame.png) no-repeat; + + > img { // avatar image + width:122px; + height:120px; + margin:11px 0 0 12px; + } + } + + > img { // paperclip image + position:absolute; + top:-8px; + left:3px; + z-index:2; + } +} + +.visitor-profile-avatar > div:last-child { + margin-right:0; +} + +.visitor-profile-more-info { + height:18px; + border-top:1px solid #fff; + border-radius:0 0 5px 5px; + text-align:center; + padding:20px 0 13px; + + > a { + font-size:14px; + text-decoration:none; + color:#255792; + text-shadow:0 1px 0 rgba(255,255,255,1); + } +} + +.visitor-profile-latest-visit-column { + padding-top:6px; + display:inline-block; + vertical-align:top; +} + +.visitor-profile-browser { + width:75px; + display:inline-block; +} + +.visitor-profile-os { + width:75px; + display:inline-block; +} + +.visitor-profile-latest-visit-column:first-child { + margin-right:9px; +} + +.visitor-profile-avatar ul { + width:178px; +} + +.visitor-profile-avatar ul li { + display:inline-block; + height:24px; + border-bottom:1px solid #d1cec8; + width:100%; +} + +.visitor-profile-avatar ul li:last-child { + border-bottom:none; +} + +.visitor-profile-avatar ul li:first-child { + border-bottom:1px solid #d1cec8; // make sure there is a border if only one item is shown in the list +} + +.visitor-profile-map { + padding:19px 0 18px 19px; +} + +.visitor-profile-map > div { + border-radius:2px; + background-color:#fff; + width:532px; + height:334px; + padding:2px; +} + +.visitor-profile-summary,.visitor-profile-important-visits { + overflow:hidden; + height:116px; + padding:5px 0 0 22px; +} + +.visitor-profile-summary > div { + margin-top:6px; +} + +.visitor-profile-important-visits { + + > div { + float:left; + width:265px; + height:100%; + + > div { + margin-top:13px; + } + } + + span { + padding-left:0; + } +} + +.visitor-profile-location { + padding:10px 0 4px 19px; + + img { + margin-top:-12px; + } +} + +.visitor-profile-pages-visited { + height:42px; + overflow-y:auto; + position:relative; + margin-right:10px; + border-bottom:none!important; + padding:8px 18px 10px 13px; + + h1 { + margin-left:6px; + } +} + +.visitor-profile-actions { + height:550px; + overflow-y:auto; + position:relative; + margin-right:10px; + border-bottom:none!important; + padding:0 18px 0 13px; + + ol { + counter-reset:item; + list-style-type:none; + + > li { + display:block; + font-size:12px; + font-weight:700; + line-height:25px; + padding:0 0 10px 13px; + + span { + font-size:13px; + font-weight:700; + line-height:25px; + padding-left:0; + } + } + + > li:before { + content:counter(item) " "; + counter-increment:item; + } + } + + // TODO: unordered lists no longer used, remove + ol li ul,ol li ol { + border-top:1px solid #d1cec8; + } + + ol li ul { + padding-left:15px; + } + + ol > li > ol > li { + margin-left:-12px; + } + + ol li ul li,ol li ol li { + display:block; + color:#5e5e5c; + font-size:13px; + line-height:22px; + padding-top:1px; + padding-bottom:1px; + } + + ol li ol li { + padding-bottom:4px; + } + + ol li ul li a,ol li ol li a { + display:inline-block; + } + + ol > li ol li span { + padding-left:4px; + } + + ol > li ol li .action-list-url { + margin-left:15px; + line-height:14px; + display:inline-block; + } + + ol > li ol li img { + margin-left:7px; + } + + // overrides for _actionsDetails styles + strong { + font-size:13px; + line-height:25px; + } +} + +.visitor-profile-date { + float:right; + font-size:13px; + line-height:26px; +} + +.visitor-profile-fog { + height:25px; + width:546px; + position:absolute; + bottom:51px; + right:28px; + background:url(../images/visitor_profile_gradient.png) repeat-x; +} + +// popup css +.visitor-profile-popup { + width: 1151px; + height: auto; + padding: 0; + + > .ui-dialog-titlebar { + display: none; + } + + > #Piwik_Popover { + padding: 0; + margin: 0; + overflow: visible; + } +} + +span.visitor-profile-goal-name { + font-weight:bold; + font-style:italic; + font-size:13px; +}
\ No newline at end of file diff --git a/plugins/Live/templates/_actionsList.twig b/plugins/Live/templates/_actionsList.twig new file mode 100644 index 0000000000..9f5bc672e4 --- /dev/null +++ b/plugins/Live/templates/_actionsList.twig @@ -0,0 +1,106 @@ +{% set visitorHasSomeEcommerceActivity %}0{% endset %} +{% for action in actionDetails %} + {% set customVariablesTooltip %} + {% if action.customVariables is defined %} + {{ 'CustomVariables_CustomVariables'|translate }} + {% for id,customVariable in action.customVariables %} + {% set name = 'customVariablePageName' ~ id %} + {% set value = 'customVariablePageValue' ~ id %} + - {{ customVariable[name]|raw }} {% if customVariable[value]|length > 0 %} = {{ customVariable[value]|raw }}{% endif %} + {% endfor %} + {% endif %} + {% endset %} + {% if not javascriptVariablesToSet.filterEcommerce or action.type == 'ecommerceOrder' or action.type == 'ecommerceAbandonedCart' %} + <li class="{% if action.goalName is defined %}goal{% else %}action{% endif %}" + title="{{ action.serverTimePretty }}{% if action.url is defined and action.url|trim|length %} + {{ action.url }}{% endif %} {% if customVariablesTooltip|trim|length %} + + {{ customVariablesTooltip|trim }}{% endif %}{% if action.timeSpentPretty is defined %} + + {{ 'General_TimeOnPage'|translate }}: {{ action.timeSpentPretty|raw }}{% endif %}{% if action.generationTime is defined %} + + {{ 'General_ColumnGenerationTime'|translate }}: {{ action.generationTime|raw }}{% endif %}"> + {% if action.type == 'ecommerceOrder' or action.type == 'ecommerceAbandonedCart' %} + {# Ecommerce Abandoned Cart / Ecommerce Order #} + <img src="{{ action.icon }}"/> + {% if action.type == 'ecommerceOrder' %} + {% set visitorHasSomeEcommerceActivity %}1{% endset %} + <strong>{{ 'Goals_EcommerceOrder'|translate }}</strong> + <span style='color:#666666'>({{ action.orderId }})</span> + {% else %} + <strong>{{'Goals_AbandonedCart'|translate}}</strong> + + {# TODO: would be nice to have the icons Orders / Cart in the ecommerce log footer #} + {% if javascriptVariablesToSet.filterEcommerce == 2 %} + {% set visitorHasSomeEcommerceActivity %}1{% endset %} + {% endif %} + {% endif %} + <br/> + <span {% if not isWidget %}style='margin-left:20px'{% endif %}> + {% if action.type == 'ecommerceOrder' %} + <abbr title=" + {{ 'Live_GoalRevenue'|translate }}: {{ action.revenue|money(javascriptVariablesToSet.idSite)|raw }} + {% if action.revenueSubTotal is not empty %} - {{ 'General_Subtotal'|translate }}: {{ action.revenueSubTotal|money(javascriptVariablesToSet.idSite)|raw }}{% endif %} + {% if action.revenueTax is not empty %} - {{ 'General_Tax'|translate }}: {{ action.revenueTax|money(javascriptVariablesToSet.idSite)|raw }}{% endif %} + {% if action.revenueShipping is not empty %} - {{ 'General_Shipping'|translate }}: {{ action.revenueShipping|money(javascriptVariablesToSet.idSite)|raw }}{% endif %} + {% if action.revenueDiscount is not empty %} - {{ 'General_Discount'|translate }}: {{ action.revenueDiscount|money(javascriptVariablesToSet.idSite)|raw }}{% endif %} + ">{{ 'Live_GoalRevenue'|translate }}: + {% else %} + {% set revenueLeft %}{{ 'Live_GoalRevenue'|translate }}{% endset %} + {{ 'Goals_LeftInCart'|translate(revenueLeft) }}: + {% endif %} + <strong>{{ action.revenue|money(javascriptVariablesToSet.idSite)|raw }}</strong> + {% if action.type == 'ecommerceOrder' %} + </abbr> + {% endif %}, {{ 'General_Quantity'|translate }}: {{ action.items }} + + {# Ecommerce items in Cart/Order #} + {% if action.itemDetails is not empty %} + <ul style='list-style:square;margin-left:{% if isWidget %}15{% else %}50{% endif %}px'> + {% for product in action.itemDetails %} + <li> + {{ product.itemSKU }}{% if product.itemName is not empty %}: {{ product.itemName }}{% endif %} + {% if product.itemCategory is not empty %} ({{ product.itemCategory }}){% endif %} + , + {{ 'General_Quantity'|translate }}: {{ product.quantity }}, + {{ 'General_Price'|translate }}: {{ product.price|money(javascriptVariablesToSet.idSite)|raw }} + </li> + {% endfor %} + </ul> + {% endif %} + </span> + {% elseif action.goalName is not defined%} + {# Page view / Download / Outlink #} + {% if action.pageTitle is defined and action.pageTitle is not empty %} + <span>{{ action.pageTitle|truncate(80) }}</span> + {% endif %} + {% if action.siteSearchKeyword is defined %} + {% if action.type == 'search' %} + <img src='{{ action.icon }}' title='{{ 'Actions_SubmenuSitesearch'|translate }}'> + {% endif %} + {{ action.siteSearchKeyword|truncate(80) }} + {% endif %} + {% if action.url is not empty %} + {% if action.type == 'action' and action.pageTitle is not empty %}<br/>{% endif %} + {% if action.type == 'download' or action.type == 'outlink' %} + <img src='{{ action.icon }}'> + {% endif %} + <a href="{{ action.url }}" target="_blank" class="action-list-url" + {% if overrideLinkStyle is not defined or overrideLinkStyle %}style="{% if action.type=='action' and action.pageTitle is not empty %}margin-left: 25px;{% endif %}text-decoration:underline;"{% endif %}> + {{ action.url|truncate(80) }} + </a> + {% elseif action.type != 'search' %} + <br/> + <span style="margin-left: 25px;">{{ javascriptVariablesToSet.pageUrlNotDefined }}</span> + {% endif %} + {% else %} + {# Goal conversion #} + <img src="{{ action.icon }}" /> + <strong>{{ action.goalName }}</strong> + {% if action.revenue > 0 %}, {{ 'Live_GoalRevenue'|translate }}: + <strong>{{ action.revenue|money(javascriptVariablesToSet.idSite)|raw }}</strong> + {% endif %} + {% endif %} + </li> + {% endif %} +{% endfor %}
\ No newline at end of file diff --git a/plugins/Live/templates/_totalVisitors.twig b/plugins/Live/templates/_totalVisitors.twig index 40d2d1eed0..c1d70c7c2d 100644 --- a/plugins/Live/templates/_totalVisitors.twig +++ b/plugins/Live/templates/_totalVisitors.twig @@ -15,14 +15,14 @@ </thead> <tbody> <tr class=""> - <td class="columnodd">{{ 'Live_LastHours'|translate(24) }}</td> - <td class="columnodd">{{ visitorsCountToday }}</td> - <td class="columnodd">{{ pisToday }}</td> + <td class="column columnodd">{{ 'Live_LastHours'|translate(24) }}</td> + <td class="column columnodd">{{ visitorsCountToday }}</td> + <td class="column columnodd">{{ pisToday }}</td> </tr> <tr class=""> - <td class="columnodd">{{ 'Live_LastMinutes'|translate(30) }}</td> - <td class="columnodd">{{ visitorsCountHalfHour }}</td> - <td class="columnodd">{{ pisHalfhour }}</td> + <td class="column columnodd">{{ 'Live_LastMinutes'|translate(30) }}</td> + <td class="column columnodd">{{ visitorsCountHalfHour }}</td> + <td class="column columnodd">{{ pisHalfhour }}</td> </tr> </tbody> </table> diff --git a/plugins/Live/templates/getVisitorLog.twig b/plugins/Live/templates/getVisitorLog.twig index 9c9a520acc..25dabd971a 100644 --- a/plugins/Live/templates/getVisitorLog.twig +++ b/plugins/Live/templates/getVisitorLog.twig @@ -187,112 +187,7 @@ </strong> <br/> <ol class='visitorLog'> - {% set visitorHasSomeEcommerceActivity %}0{% endset %} - {% for action in visitor.getColumn('actionDetails') %} - {% set customVariablesTooltip %} - {% if action.customVariables is defined %} - {{ 'CustomVariables_CustomVariables'|translate }} - {% for id,customVariable in action.customVariables %} - {% set name = 'customVariablePageName' ~ id %} - {% set value = 'customVariablePageValue' ~ id %} - - {{ customVariable[name]|raw }} {% if customVariable[value]|length > 0 %} = {{ customVariable[value]|raw }}{% endif %} - {% endfor %} - {% endif %} - {% endset %} - {% if not javascriptVariablesToSet.filterEcommerce or action.type == 'ecommerceOrder' or action.type == 'ecommerceAbandonedCart' %} - <li class="{% if action.goalName is defined %}goal{% else %}action{% endif %}" - title="{{ action.serverTimePretty }}{% if action.url is defined and action.url|trim|length %} - {{ action.url }}{% endif %} {% if customVariablesTooltip|trim|length %} - - {{ customVariablesTooltip|trim }}{% endif %}{% if action.timeSpentPretty is defined %} - - {{ 'General_TimeOnPage'|translate }}: {{ action.timeSpentPretty|raw }}{% endif %}{% if action.generationTime is defined %} - - {{ 'General_ColumnGenerationTime'|translate }}: {{ action.generationTime|raw }}{% endif %}"> - {% if action.type == 'ecommerceOrder' or action.type == 'ecommerceAbandonedCart' %} - {# Ecommerce Abandoned Cart / Ecommerce Order #} - <img src="{{ action.icon }}"/> - {% if action.type == 'ecommerceOrder' %} - {% set visitorHasSomeEcommerceActivity %}1{% endset %} - <strong>{{ 'Goals_EcommerceOrder'|translate }}</strong> - <span style='color:#666666'>({{ action.orderId }})</span> - {% else %} - <strong>{{'Goals_AbandonedCart'|translate}}</strong> - - {# TODO: would be nice to have the icons Orders / Cart in the ecommerce log footer #} - {% if javascriptVariablesToSet.filterEcommerce == 2 %} - {% set visitorHasSomeEcommerceActivity %}1{% endset %} - {% endif %} - {% endif %} - <br/> - <span {% if not isWidget %}style='margin-left:20px'{% endif %}> - {% if action.type == 'ecommerceOrder' %} - <abbr title=" - {{ 'Live_GoalRevenue'|translate }}: {{ action.revenue|money(javascriptVariablesToSet.idSite)|raw }} - {% if action.revenueSubTotal is not empty %} - {{ 'General_Subtotal'|translate }}: {{ action.revenueSubTotal|money(javascriptVariablesToSet.idSite)|raw }}{% endif %} - {% if action.revenueTax is not empty %} - {{ 'General_Tax'|translate }}: {{ action.revenueTax|money(javascriptVariablesToSet.idSite)|raw }}{% endif %} - {% if action.revenueShipping is not empty %} - {{ 'General_Shipping'|translate }}: {{ action.revenueShipping|money(javascriptVariablesToSet.idSite)|raw }}{% endif %} - {% if action.revenueDiscount is not empty %} - {{ 'General_Discount'|translate }}: {{ action.revenueDiscount|money(javascriptVariablesToSet.idSite)|raw }}{% endif %} - ">{{ 'Live_GoalRevenue'|translate }}: - {% else %} - {% set revenueLeft %}{{ 'Live_GoalRevenue'|translate }}{% endset %} - {{ 'Goals_LeftInCart'|translate(revenueLeft) }}: - {% endif %} - <strong>{{ action.revenue|money(javascriptVariablesToSet.idSite)|raw }}</strong> - {% if action.type == 'ecommerceOrder' %} - </abbr> - {% endif %}, {{ 'General_Quantity'|translate }}: {{ action.items }} - - {# Ecommerce items in Cart/Order #} - {% if action.itemDetails is not empty %} - <ul style='list-style:square;margin-left:{% if isWidget %}15{% else %}50{% endif %}px'> - {% for product in action.itemDetails %} - <li> - {{ product.itemSKU }}{% if product.itemName is not empty %}: {{ product.itemName }}{% endif %} - {% if product.itemCategory is not empty %} ({{ product.itemCategory }}){% endif %} - , - {{ 'General_Quantity'|translate }}: {{ product.quantity }}, - {{ 'General_Price'|translate }}: {{ product.price|money(javascriptVariablesToSet.idSite)|raw }} - </li> - {% endfor %} - </ul> - {% endif %} - </span> - {% elseif action.goalName is not defined%} - {# Page view / Download / Outlink #} - {% if action.pageTitle is defined %} - {{ action.pageTitle|truncate(80) }} - {% endif %} - {% if action.siteSearchKeyword is defined %} - {% if action.type == 'search' %} - <img src='{{ action.icon }}' title='{{ 'Actions_SubmenuSitesearch'|translate }}'> - {% endif %} - {{ action.siteSearchKeyword|truncate(80) }} - {% endif %} - {% if action.url is not empty %} - {% if action.type == 'action' and action.pageTitle is not empty %}<br/>{% endif %} - {% if action.type == 'download' or action.type == 'outlink' %} - <img src='{{ action.icon }}'> - {% endif %} - <a href="{{ action.url }}" target="_blank" - style="{% if action.type=='action' and action.pageTitle is not empty %}margin-left: 25px;{% endif %}text-decoration:underline;"> - {{ action.url|truncate(80) }} - </a> - {% elseif action.type != 'search' %} - <br/> - <span style="margin-left: 25px;">{{ javascriptVariablesToSet.pageUrlNotDefined }}</span> - {% endif %} - {% else %} - {# Goal conversion #} - <img src="{{ action.icon }}" /> - <strong>{{ action.goalName }}</strong> - {% if action.revenue > 0 %}, {{ 'Live_GoalRevenue'|translate }}: - <strong>{{ action.revenue|money(javascriptVariablesToSet.idSite)|raw }}</strong> - {% endif %} - {% endif %} - </li> - {% endif %} - {% endfor %} + {% include "@Live/_actionsList.twig" with {'actionDetails': visitor.getColumn('actionDetails')} %} </ol> </td> </tr> @@ -314,11 +209,11 @@ {% include "@CoreHome/_dataTableJS.twig" %} <script type="text/javascript" defer="defer"> - var visitorLogTitle = '{{ 'Live_VisitorLog'|translate|e('js') }}'; + var visitorLogTitle = '{{ 'Live_VisitorProfile'|translate|e('js') }}'; function Piwik_Live_LoadVisitorPopover(visitorId) { var startingDate = piwik.minDateYear + '-01-01'; - var url = 'module=Live&action=getVisitorLog&period=range&date=' + startingDate + ',today&show_footer=0&segment=visitorId' + encodeURIComponent('==') + visitorId; - return Piwik_Popover.createPopupAndLoadUrl(url, visitorLogTitle); + var url = 'module=Live&action=getVisitorProfilePopup&period=range&date=' + startingDate + ',today&idVisitor=' + encodeURIComponent(visitorId); + return Piwik_Popover.createPopupAndLoadUrl(url, visitorLogTitle, 'visitor-profile-popup'); } $(document).ready(function () { @@ -332,7 +227,7 @@ $(this).val(counter); var current = $(this).html(); if (current == prevhtml) { - var repeat = prevelement.find(".repeat") + var repeat = prevelement.find(".repeat"); if (repeat.length) { repeat.html((parseInt(repeat.html()) + 1) + "x"); } else { diff --git a/plugins/Live/templates/getVisitorProfilePopup.twig b/plugins/Live/templates/getVisitorProfilePopup.twig new file mode 100644 index 0000000000..c351ecf570 --- /dev/null +++ b/plugins/Live/templates/getVisitorProfilePopup.twig @@ -0,0 +1,127 @@ +<div class="visitor-profile"> + <a href class="visitor-profile-close"></a> + <div class="visitor-profile-info"> + <div> + <div class="visitor-profile-avatar"> + <div> + <div class="visitor-profile-image-frame"><!-- TODO translate --> + <img src="plugins/Live/images/REMOVE_ME_avatar.jpg" alt=""/> + </div> + <img src="plugins/Live/images/paperclip.png" alt=""/> + </div> + <div> + <h1>Visitor profile</h1> + <div> + <div class="visitor-profile-latest-visit-column"> + <ul> + <li><span>IP</span><strong>{{ visitorData.latestVisitIp }}</strong></li> + <li><span>ID</span><strong>{{ visitorData.visitorId }}</strong></li> + <li> + <div class="visitor-profile-browser"> + <img src="{{ visitorData.browserLogo }}"/><span>{{ visitorData.browserName }}</span> + </div> + <div class="visitor-profile-os"> + <img src="{{ visitorData.operatingSystemLogo }}"/><span>{{ visitorData.operatingSystemShortName }}</span> + </div> + </li> + <li><span>Resolution</span><strong>{{ visitorData.resolution }}</strong></li> + </ul> + </div> + <div class="visitor-profile-latest-visit-column"> + <ul> + {% for id,customVariable in visitorData.customVariables %} + {% if loop.index0 < 4 %} + {% set name='customVariableName' ~ id %} + {% set value='customVariableValue' ~ id %} + <li><span>{{ customVariable[name]|truncate(30) }}</span>{% if customVariable[value]|length > 0 %}<strong>{{ customVariable[value]|truncate(50) }}</strong>{% endif %}</li> + {% endif %} + {% endfor %} + {# TODO: Other custom vars go in expanding div. #} + </ul> + </div> + </div> + </div> + <p style="clear:both; border:none!important;"></p> + </div> + <div style="clear:both; border:none!important;"></div> + <div class="visitor-profile-map"> + {{ userCountryMap|raw }} + </div> + <div class="visitor-profile-important-visits"> + <div> + <h1>First visit</h1> + <div> + <p><strong>{{ visitorData.firstVisit.prettyDate }}</strong><span> - {{ visitorData.firstVisit.daysAgo }} days ago</span></p> + <p><span>from:</span> + <strong>{{ visitorData.firstVisit.referralSummary }}</strong></p> + </div> + </div> + <div> + <h1>Last visit</h1> + <div> + <p><strong>{{ visitorData.lastVisit.prettyDate }}</strong><span> - {{ visitorData.lastVisit.daysAgo }} days ago</span></p> + <p><span>from:</span> + <strong>{{ visitorData.lastVisit.referralSummary }}</strong></p> + </div> + </div> + </div> + <div class="visitor-profile-summary"> + <h1>Summary</h1> + <div> + <p>Spent a total of <strong>{{ visitorData.totalVisitDurationPretty|raw }} on the website</strong>, and <strong>viewed {{ visitorData.totalActionCount }} pages in {{ visitorData.totalVisits }} visits.</strong></p> + <p><strong>Converted {{ visitorData.totalGoalConversions }} Goals</strong> ( + {%- for idGoal, totalConversions in visitorData.totalConversionsByGoal -%} + {%- if not loop.first %}, {% endif -%}{{- totalConversions }} <span class="visitor-profile-goal-name">{{ goals[idGoal]['name'] -}}</span> + {%- endfor -%} + ).</p> + <p>Ecommerce: <strong>{{ visitorData.totalEcommerceConversions }} orders for a total of {{ visitorData.totalEcommerceRevenue|money(idSite)|raw }}</strong>, purchased {{ visitorData.totalEcommerceItems }} items.</p> + </div> + </div> + </div> + <div> + <div class="visitor-profile-location"> + <h1>Location</h1> + <img src="plugins/Live/images/REMOVE_ME_chart.png" alt=""/> {# TODO: country & bar graph #} + </div> + <div class="visitor-profile-pages-visited"> + <h1>Visited pages<a href>see all</a></h1> + </div> + <div class="visitor-profile-actions"> + <ol> + {% for visitInfo in visitorData.lastVisits.getRows() %} + <li><h2>Visit</h2><span class="visitor-profile-date">{{ visitInfo.getColumn('serverDatePrettyFirstAction') }}</span> + <ol> + {% include "@Live/_actionsList.twig" with {'actionDetails': visitInfo.getColumn('actionDetails'), + 'javascriptVariablesToSet': { + 'filterEcommerce': false, + 'idSite': idSite + }, + 'overrideLinkStyle': false} %} + </ol> + </li> + {% endfor %} + </ol> + <br/> + </div> + <div class="visitor-profile-fog"></div> + </div> + </div> + <div class="visitor-profile-more-info"> + <a href="#">View more visitor information</a> + </div> +</div> +<script type="text/javascript"> +$(function() { + $('.visitor-profile-actions').jScrollPane({ + showArrows: true, + verticalArrowPositions: 'os', + horizontalArrowPositions: 'os' + }); + + $('.visitor-profile-close').click(function (e) { + e.preventDefault(); + Piwik_Popover.close(); + return false; + }); +}); +</script>
\ No newline at end of file diff --git a/plugins/Login/stylesheets/login.css b/plugins/Login/stylesheets/login.css index 93b594e18a..ab472c11a1 100644 --- a/plugins/Login/stylesheets/login.css +++ b/plugins/Login/stylesheets/login.css @@ -35,8 +35,9 @@ #logo img { border: 0; vertical-align: bottom; - width: 260px; height: auto; + width: 240px; + margin-right: 20px; } #logo .h1 { diff --git a/plugins/Login/templates/login.twig b/plugins/Login/templates/login.twig index aad97579fb..7b1e37e7f7 100644 --- a/plugins/Login/templates/login.twig +++ b/plugins/Login/templates/login.twig @@ -47,11 +47,10 @@ <a href="http://piwik.org" title="{{ linkTitle }}"> {% endif %} {% if hasSVGLogo %} - <img src='{{ logoSVG }}' title="{{ linkTitle }}" alt="Piwik" width="240" style='margin-right: 20px' - class="ie-hide"/> + <img src='{{ logoSVG }}' title="{{ linkTitle }}" alt="Piwik" class="ie-hide"/> <!--[if lt IE 9]> {% endif %} - <img src='{{ logoLarge }}' title="{{ linkTitle }}" alt="Piwik" width="240" style='margin-right:20px'/> + <img src='{{ logoLarge }}' title="{{ linkTitle }}" alt="Piwik" /> {% if hasSVGLogo %}<![endif]-->{% endif %} {% if isCustomLogo %} diff --git a/plugins/MultiSites/API.php b/plugins/MultiSites/API.php index dec284cd3c..6b2381c0d5 100755 --- a/plugins/MultiSites/API.php +++ b/plugins/MultiSites/API.php @@ -402,8 +402,8 @@ class API * Sets the total evolution metadata for a datatable returned by $this->buildDataTable * given data for the last period. * - * @param DataTable $dataTable - * @param DataTable $pastData + * @param DataTable|DataTable\Map $dataTable + * @param DataTable|DataTable\Map $pastData * @param array $apiMetrics Metrics info. */ private function setPastDataMetadata($dataTable, $pastData, $apiMetrics) diff --git a/plugins/MultiSites/javascripts/multiSites.js b/plugins/MultiSites/javascripts/multiSites.js index 15c8aade97..8b004fb769 100644 --- a/plugins/MultiSites/javascripts/multiSites.js +++ b/plugins/MultiSites/javascripts/multiSites.js @@ -174,7 +174,7 @@ function getSparklineImg(id, column, params) { if (token_auth.length) { append = '&token_auth=' + token_auth; } - return '<img class="sparkline" alt="" src="?module=MultiSites&action=getEvolutionGraph&period=' + params['period'] + '&date=' + params['dateSparkline'] + '&evolutionBy=' + params['evolutionBy'] + '&columns=' + column + '&idSite=' + id + '&idsite=' + id + '&viewDataTable=sparkline' + append + '" width="100" height="25" />'; + return '<img alt="" src="?module=MultiSites&action=getEvolutionGraph&period=' + params['period'] + '&date=' + params['dateSparkline'] + '&evolutionBy=' + params['evolutionBy'] + '&columns=' + column + '&idSite=' + id + '&idsite=' + id + '&viewDataTable=sparkline' + append + '&colors=' + encodeURIComponent(JSON.stringify(piwik.getSparklineColors())) + '" width="100" height="25" />'; } function showPagination(allSites, params) { diff --git a/plugins/MultiSites/stylesheets/multiSites.less b/plugins/MultiSites/stylesheets/multiSites.less index 155af00a5c..ffacd8e3ae 100644 --- a/plugins/MultiSites/stylesheets/multiSites.less +++ b/plugins/MultiSites/stylesheets/multiSites.less @@ -13,7 +13,7 @@ } .indicator { - background: url(../images/loading-blue.gif) no-repeat center; + background: url(plugins/MultiSites/images/loading-blue.gif) no-repeat center; height: 20px; width: 60px; margin: auto; @@ -58,24 +58,24 @@ width: 16px; height: 13px; display: inline-block; - background-image: url(../../Zeitgeist/images/sortdesc.png); + background-image: url(plugins/Zeitgeist/images/sortdesc.png); } .multisites_asc { width: 16px; height: 13px; display: inline-block; - background-image: url(../../Zeitgeist/images/sortasc.png); + background-image: url(plugins/Zeitgeist/images/sortasc.png); } #mt thead { line-height: 2.5em; } -#mt thead :first-child { +#mt thead *:first-child { border-top-left-radius: 7px } -#mt thead :last-child { +#mt thead *:last-child { border-top-right-radius: 7px; }
\ No newline at end of file diff --git a/plugins/MultiSites/templates/_siteRow.twig b/plugins/MultiSites/templates/_siteRow.twig index 437db12226..bd4ea54276 100644 --- a/plugins/MultiSites/templates/_siteRow.twig +++ b/plugins/MultiSites/templates/_siteRow.twig @@ -26,7 +26,7 @@ {% endif %} {% if show_sparklines %} <td style="width:180px"> - <div id="sparkline_%idsite%" style="width: 100px; margin: auto"> + <div id="sparkline_%idsite%" class="sparkline" style="width: 100px; margin: auto"> <a target="_blank" href="index.php?module=CoreHome&action=index&date=%date%&period=%period%&idSite=%idsite%" title="{% set dashboardName %}{{ 'Dashboard_DashboardOf'|translate('%name%') }}{% endset %} {{ 'General_GoTo'|translate(dashboardName) }}">%sparkline%</a> </div> diff --git a/plugins/PDFReports/templates/index.twig b/plugins/PDFReports/templates/index.twig index f48038613b..0ee69e28e6 100644 --- a/plugins/PDFReports/templates/index.twig +++ b/plugins/PDFReports/templates/index.twig @@ -2,6 +2,8 @@ {% block content %} +{% include "@CoreHome/_siteSelectHeader.twig" %} + <div class="top_controls_inner"> {% include "@CoreHome/_periodSelect.twig" %} </div> @@ -26,7 +28,7 @@ </div> <script type="text/javascript"> - var ReportPlugin = new Object(); + var ReportPlugin = {}; ReportPlugin.defaultPeriod = '{{ defaultPeriod }}'; ReportPlugin.defaultHour = '{{ defaultHour }}'; ReportPlugin.defaultReportType = '{{ defaultReportType }}'; diff --git a/plugins/PleineLune/plugin.piwik.json b/plugins/PleineLune/plugin.piwik.json index 8e3ca2a21b..d0718e1737 100644 --- a/plugins/PleineLune/plugin.piwik.json +++ b/plugins/PleineLune/plugin.piwik.json @@ -1,4 +1,5 @@ { - "description": "A dark theme for Piwik, ideal to view your analytics reports before sunrise!", + "name": "PleineLune", + "description": "A dark theme for Piwik, ideal to view your analytics reports before sunrise.", "theme": true }
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/_dataTable.less b/plugins/PleineLune/stylesheets/_dataTable.less new file mode 100644 index 0000000000..bff57f2ff2 --- /dev/null +++ b/plugins/PleineLune/stylesheets/_dataTable.less @@ -0,0 +1,182 @@ +/* Header */ +table.dataTable th, +table.dataTable th.columnSorted { + background: @theme-color-background-smallContrast; + color: @theme-color-text-base; + border-left: 0; + vertical-align: bottom; +} + +.sortIconContainer { + float: right; + margin-right: -20px; +} + +.sortIconContainer:after { + content: " \25BC"; + display: inline; +} + +.sortIconContainerAsc:after { + content: " \25B2"; +} + +.sortIconContainer > img { + display: none; +} + +/* Cells */ +table.dataTable td, +table.dataTable td a { + color: @theme-color-text-base; +} + +table.dataTable td, +table.dataTable td.label, +table.dataTable td.column { + background-color: @theme-color-background-base; + background-color: @theme-color-background-base; + border: 1px solid @theme-color-background-smallContrast; +} + +table.dataTable td.column { + border-width: 0 0 1px 1px; +} + +table.dataTable td.label { + border-width: 0 0 1px 0; + background-image: none; +} + +/* SubTable */ +table.dataTable tr:hover > td.cellSubDataTable { + background: transparent; +} + +table.subDataTable thead th { + border: 1px solid @theme-color-background-smallContrast; +} + +table.subDataTable thead th { + border-width: 0 0 1px 1px; +} + +/* Hover state */ +table.dataTable tr:hover > td, +table.dataTable tr:hover > td .dataTableRowActions, +table.dataTable tr.subDataTable:hover > td, +table.dataTable tr.subDataTable:hover > td .dataTableRowActions { + background: transparent; +} + +/* Focus widget */ +.ui-dialog-content, +.widget:hover, +.cellSubDataTable:hover { + + table.dataTable td, + table.dataTable td a { + color: @theme-color-text-lightFocus; + } + + table.dataTable th, + table.dataTable tr:hover > td, + table.dataTable tr:hover > td > a { + color: @theme-color-text-focus; + } + + table.dataTable td.label, + table.dataTable td.column { + border-bottom-color: #404040; + } +} + +/* Footer */ +.dataTableFooterIcons { + border-top: 1px solid @theme-color-background-contrast; +} + +.dataTableNext, +.dataTablePrevious { + color: @theme-color-text-link; +} + +.dataTableNext:hover, +.dataTablePrevious:hover { + text-decoration: underline; + color: @theme-color-text-focus; +} + +.loadingPiwik { + color: @theme-color-text-base; +} + +/* LimitSelection */ +.limitSelection > div { + border-color: @theme-color-background-smallContrast; + border-radius: 0; +} + +.limitSelection > div > span { + color: @theme-color-text-active; +} + +.limitSelection > ul > li { + background: @theme-color-background-base; + border-color: @theme-color-background-smallContrast; +} + +.limitSelection > ul > li.last { + background: @theme-color-background-base; + border-color: @theme-color-background-smallContrast; +} + +.limitSelection > ul > li:hover { + background-color: @theme-color-background-smallContrast; +} + +.limitSelection > ul > li > span { + color: @theme-color-text-link; +} + +.limitSelection > ul > li:hover > span { + color: @theme-color-text-focus; +} + +/* TableConfiguration */ +.tableConfiguration ul { + background-color: @theme-color-background-base; +} + +.tableConfiguration ul li { + background-color: @theme-color-background-base; + border-color: @theme-color-background-smallContrast; +} + +.tableConfiguration ul li.firstDummy, +.tableConfiguration ul li.last { + border-radius: 0; +} + +.tableConfiguration div.configItem { + color: @theme-color-text-base; +} + +.tableConfiguration div.configItem:hover { + background-color: @theme-color-background-smallContrast; +} + +.tableConfiguration div.configItem span.action { + color: @theme-color-text-link; +} + +.tableConfiguration div.configItem:hover span.action { + text-decoration: underline; + color: @theme-color-text-focus; +} + +/* MultiSites */ +#mt thead *:first-child, +#mt thead *:last-child { + border-radius: 0; +}
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/_general.less b/plugins/PleineLune/stylesheets/_general.less index d39b36d4b6..089f49f0dc 100644 --- a/plugins/PleineLune/stylesheets/_general.less +++ b/plugins/PleineLune/stylesheets/_general.less @@ -19,4 +19,11 @@ a:hover, a:focus, a:active { color: @theme-color-text-focus; +} + +select, +[type="text"] { + background: @theme-color-background-lighter; + border: 0 none; + color: @theme-color-background-smallContrast; }
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/_jqplotColors.less b/plugins/PleineLune/stylesheets/_jqplotColors.less new file mode 100644 index 0000000000..ddb9ad3425 --- /dev/null +++ b/plugins/PleineLune/stylesheets/_jqplotColors.less @@ -0,0 +1,86 @@ +// evolution graph colors +.evolution-graph-colors[data-name=grid-background] { + color: @theme-color-background-base; +} + +.evolution-graph-colors[data-name=grid-border] { + color: @theme-color-background-smallContrast; +} + +.evolution-graph-colors[data-name=series1] { + color: @theme-color-highlight1; +} + +.evolution-graph-colors[data-name=series2] { + color: @theme-color-highlight2; +} + +.evolution-graph-colors[data-name=series3] { + color: @theme-color-highlight3; +} + +.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=grid-background] { + color: @theme-color-background-base; +} + +.bar-graph-colors[data-name=grid-border] { + color: #f00; +} + +.bar-graph-colors[data-name=series1] { + color: @theme-color-highlight1; +} + +.bar-graph-colors[data-name=series2] { + color: @theme-color-highlight2; +} + +.bar-graph-colors[data-name=series3] { + color: @theme-color-highlight3; +} + +.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=grid-background] { + color: @theme-color-background-base; +} + +.pie-graph-colors[data-name=grid-border] { + color: @theme-color-background-smallContrast; +} + +.pie-graph-colors[data-name=series1] { + color: @theme-color-highlight1; +} + +.pie-graph-colors[data-name=series2] { + color: @theme-color-highlight2; +} + +.pie-graph-colors[data-name=series3] { + color: @theme-color-highlight3; +} + +.pie-graph-colors[data-name=ticks] { + color: #ccc; +} + +.pie-graph-colors[data-name=single-metric-label] { + color: #666; +} diff --git a/plugins/PleineLune/stylesheets/_layout.less b/plugins/PleineLune/stylesheets/_layout.less index f43d33d1a7..637fd307f6 100644 --- a/plugins/PleineLune/stylesheets/_layout.less +++ b/plugins/PleineLune/stylesheets/_layout.less @@ -26,4 +26,63 @@ #topRightBar .topBarElem { margin-bottom: 5px; -}
\ No newline at end of file +} + +.topBarElemActive { + color: @theme-color-text-active; +} + +.topBarElemActive > b { + font-weight: normal; +} + +#languageSelect { + background: @theme-color-background-base; + border: 1px solid @theme-color-background-contrast !important; +} + +#languageSelect a:hover { + background: @theme-color-background-smallContrast !important; + border: 0; + border-radius: 0; + color: @theme-color-text-focus !important; +} + + +/* Logo */ +#logo { + opacity: 0.5; +} + +#header:hover #logo { + opacity: 1; +} + +@media all and (max-width: 949px) { + #logo { + float: none; + display: block; + text-align: center + } + + #topBars { + float: none; + display: table; + width: 100%; + } + + #topRightBar, + #topLeftBar { + text-align: center; + } +} + +@media all and (min-width: 1250px) { + #logo img { + height: 80px; + } + + #header:after { + clear: right; + } +} diff --git a/plugins/PleineLune/stylesheets/_menuDashboard.less b/plugins/PleineLune/stylesheets/_menuDashboard.less index 47b0aeb955..c5cadb1493 100644 --- a/plugins/PleineLune/stylesheets/_menuDashboard.less +++ b/plugins/PleineLune/stylesheets/_menuDashboard.less @@ -1,45 +1,69 @@ - /* FIRST LEVEL */ -.nav_tab> li { - background: transparent; +.nav_tab { + margin-left: auto; + margin-right: auto; +} + +.nav_tab > li { + background: @theme-color-background-base; border-color: @theme-color-box-border; margin-right: 5px; } -.nav_tab> li:hover, -.nav_tab> li.sfHover{ - background-color: @theme-color-box-active; +.nav_tab a { + padding: 8px 15px 0; } -.nav_tab> li.sfHover > a, -.nav_tab> li.sfActive.sfHover > a { - border-bottom: 1px solid @theme-color-box-active; +.nav_tab > li:hover, +.nav_tab > li.sfHover { + background-color: @theme-color-box-active; } -.nav_tab> li > a, -.nav_tab> li.sfActive > a { +.nav_tab > li > a, +.nav_tab > li.sfActive > a { color: @theme-color-text-base; } -.nav_tab> li.sfHover > a, -.nav_tab> li.sfActive.sfHover > a { +.nav_tab > li:hover > a, +.nav_tab > li.sfHover > a, +.nav_tab > li.sfActive.sfHover > a { + border-bottom: 1px solid @theme-color-box-active; color: @theme-color-text-active; } +.nav_tab > li:hover > a, +.nav_tab > li.sfHover > a, +.nav_tab > li.sfActive.sfHover > a { +} + +.nav_tab > li:hover > a { + text-decoration: none; +} + +.nav_tab > li > a:hover { + text-decoration: underline; +} + /* SECOND LEVEL */ .nav_sep { border-color: @theme-color-box-border; + border-width: 1px 0; + border-radius: 0; background: @theme-color-box-active; + padding: 0 10px; + margin-left: -10px; + width: 100%; } -.nav_tab> li li > a { +.nav_tab > li li > a { color: @theme-color-text-base; } -.nav_tab> li li:hover > a, -.nav_tab> li li:focus > a, -.nav_tab> li li:active > a { - color: @theme-color-text-focus; +.nav_tab > li li:hover > a, +.nav_tab > li li.sfHover > a, +.nav_tab > li li:focus > a, +.nav_tab > li li:active > a { + color: @theme-color-text-active; } /* UNDER THE MENU */ diff --git a/plugins/PleineLune/stylesheets/_sparklineColors.less b/plugins/PleineLune/stylesheets/_sparklineColors.less new file mode 100644 index 0000000000..a8f978c861 --- /dev/null +++ b/plugins/PleineLune/stylesheets/_sparklineColors.less @@ -0,0 +1,14 @@ +// sparkline styles +div.sparkline, +div.sparkline:hover { + border-bottom: 0; +} + +// sparkline colors +.sparkline-colors[data-name=backgroundColor] { + color: @theme-color-background-base; +} + +.sparkline-colors[data-name=lineColor] { + color: @theme-color-highlight1; +} diff --git a/plugins/PleineLune/stylesheets/_transitionColors.less b/plugins/PleineLune/stylesheets/_transitionColors.less new file mode 100644 index 0000000000..f8bd954310 --- /dev/null +++ b/plugins/PleineLune/stylesheets/_transitionColors.less @@ -0,0 +1,46 @@ +.transition-entries[data-name=light], +.transition-entries[data-name=light-highlighted], +.transition-exits[data-name=light], +.transition-exits[data-name=light-highlighted], +.transition-entries[data-name=dark], +.transition-exits[data-name=dark], +.transition-background[data-name=light], +.transition-background[data-name=light-highlighted], +.transition-background[data-name=light], +.transition-background[data-name=light-highlighted], +.transition-background[data-name=dark], +.transition-background[data-name=dark] { + color: @theme-color-background-contrast; +} + +.transition-entries[data-name=dark-highlighted], +.transition-exits[data-name=dark-highlighted], +.transition-background[data-name=dark-highlighted], +.transition-background[data-name=dark-highlighted] { + color: @theme-color-background-smallContrast; +} + +// closed group gradient colors +.transition-closed-group[data-name=dark], +.transition-closed-group[data-name=light], +.transition-closed-group[data-name=light-highlighted] { + color: @theme-color-background-contrast; +} + +.transition-closed-group[data-name=dark-highlighted] { + color: @theme-color-text-active; +} + +// items gradient colors +.transition-items[data-name=light], +.transition-items[data-name=dark], +.transition-others[data-name=light], +.transition-others[data-name=dark] { + color: @theme-color-background-lighter; +} + +// loop gradient colors +.transition-loops[data-name=light], +.transition-loops[data-name=dark] { + color: @theme-color-background-smallContrast; +}
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/_ui.less b/plugins/PleineLune/stylesheets/_ui.less new file mode 100644 index 0000000000..50f4db575e --- /dev/null +++ b/plugins/PleineLune/stylesheets/_ui.less @@ -0,0 +1,23 @@ +/* Dialog */ +.ui-widget-overlay { + opacity: 1; +} + +.ui-dialog { + background: @theme-color-background-base; + border: 1px solid @theme-color-background-contrast; +} + +/* Autocomplete */ +.ui-autocomplete { + background: @theme-color-background-base; + border: 1px solid @theme-color-background-contrast; +} + +.ui-menu .ui-menu-item a { + color: @theme-color-text-link; +} + +.ui-menu .ui-menu-item a.ui-state-focus { + background: @theme-color-background-smallContrast; +}
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/_widget.less b/plugins/PleineLune/stylesheets/_widget.less new file mode 100644 index 0000000000..c7db32550d --- /dev/null +++ b/plugins/PleineLune/stylesheets/_widget.less @@ -0,0 +1,19 @@ +.widget { + border: 1px solid @theme-color-background-contrast; + border-radius: 0; + background: @theme-color-background-base; +} + +.widgetTop { + background: @theme-color-background-smallContrast; +} + +.widgetName { + text-shadow: none; + color: @theme-color-text-base; +} + +.ui-dialog-content .widgetName, +.widget:hover .widgetName { + color: @theme-color-text-lightFocus; +}
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/controls/_headerMessage.less b/plugins/PleineLune/stylesheets/controls/_headerMessage.less new file mode 100644 index 0000000000..a23fb8a80d --- /dev/null +++ b/plugins/PleineLune/stylesheets/controls/_headerMessage.less @@ -0,0 +1,20 @@ +#header_message { + color: @theme-color-text-base; + border-radius: 0; + padding-left: 8px; + right: 0; +} + +#header_message, +#header_message:hover { + background: @theme-color-background-base; + border: 1px solid @theme-color-background-contrast; +} + +.header_info a { + color: @theme-color-text-link; +} + +.header_info a:hover { + color: @theme-color-text-focus; +}
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/controls/_periodSelect.less b/plugins/PleineLune/stylesheets/controls/_periodSelect.less new file mode 100644 index 0000000000..60a89dffe5 --- /dev/null +++ b/plugins/PleineLune/stylesheets/controls/_periodSelect.less @@ -0,0 +1,34 @@ +#periodString { + color: @theme-color-text-base; + border-radius: 0; +} + +#periodString, +#periodString:hover { + background: @theme-color-background-base; + border: 1px solid @theme-color-background-contrast; +} + +#periodString #date { + color: @theme-color-text-active; +} + +#periodString #date:hover { + color: @theme-color-text-focus; +} + +#periodString b { + color: inherit; +} + +#periodString .calendar-icon { + opacity: 0.7; +} + +#periodString label.selected-period-label { + color: @theme-color-text-active; +} + +#periodString label:hover { + color: @theme-color-text-focus; +}
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/controls/_segmentSelect.less b/plugins/PleineLune/stylesheets/controls/_segmentSelect.less new file mode 100644 index 0000000000..ec4c196271 --- /dev/null +++ b/plugins/PleineLune/stylesheets/controls/_segmentSelect.less @@ -0,0 +1,139 @@ + +#segmentEditorPanel { + color: @theme-color-text-base; + border-radius: 0; +} + +#segmentEditorPanel, +#segmentEditorPanel:hover { + background: @theme-color-background-base; + border: 1px solid @theme-color-background-contrast; +} + +#segmentEditorPanel .segmentationTitle, +.segmentationContainer > span > b, + #available_segments a.dropdown { + color: @theme-color-text-active; +} + +#segmentEditorPanel .segmentationTitle:hover { + color: @theme-color-text-focus; +} + +#segmentEditorPanel .submenu ul { + font-size: 13px; +} + +#segmentEditorPanel .submenu ul > li > span { + color: @theme-color-text-link; + font-weight: normal; +} + +#segmentEditorPanel .submenu ul > li:hover { + background: none; + border: 0; + margin: 3px 0 0; +} + +#segmentEditorPanel .submenu ul > li:hover > span { + color: @theme-color-text-focus; + text-decoration: underline; +} + +#segmentEditorPanel .add_new_segment { + width: auto; + text-align: center; +} + +/* Form to create a segment */ +.segment-element { + background: @theme-color-background-base; + border: 1px solid @theme-color-background-contrast; +} + +.segment-element .segment-nav div > ul > li a { + text-shadow: none; + color: @theme-color-text-link; +} + +.segment-element .segment-nav div > ul > li li:hover { + border: 0; + padding: 1px; +} + +.segment-element .segment-nav div > ul > li li:hover a { + background: @theme-color-background-smallContrast; + border: 0; +} + +.segment-element .custom_select_search { + border-color: @theme-color-background-contrast; +} + +.segment-element .custom_select_search input[type="text"], +.segment-element .segment-top { + color: @theme-color-text-base; +} + +.segment-element .segment-content h3 { + text-shadow: none; + color: @theme-color-text-base; +} + +.segment-element .segment-content .segment-add-row, +.segment-element .segment-content .segment-rows { + background: @theme-color-background-smallContrast; + border-color: @theme-color-background-lighter; + box-shadow: none; +} + +.segment-element .segment-content .segment-row, +.segment-element .segment-content .segment-or, +.segment-element .segment-content .segment-and, +.segment-element .segment-content .segment-add-row, +.segment-element .segment-content .segment-add-or { + background-color: @theme-color-background-contrast; + color: @theme-color-background-smallContrast; + text-shadow: none; +} + +.segment-element .segment-content .segment-and:before, +.segment-element .segment-content .segment-and:after { + border-color: @theme-color-background-lighter; + background: @theme-color-background-base; +} +.segment-element .segment-content .segment-or:before, +.segment-element .segment-content .segment-or:after { + bottom: 0; + top: 0; + border: 0; + background: @theme-color-background-smallContrast; +} + +.segment-element .segment-content .segment-add-row > div, +.segment-element .segment-content .segment-add-or > div { + border-color: @theme-color-background-smallContrast; +} + +.segment-element .segment-content .segment-row-inputs .segment-input { + border: 0; +} + +.segment-element .segment-content .segment-input select, +.segment-element .segment-content .segment-input input { + color: @theme-color-background-smallContrast; +} + +.segment-element .segment-content .segment-add-row > div a span, +.segment-element .segment-content .segment-add-or > div a span { + color: @theme-color-text-link; +} + +.segment-element .segment-footer { + background: @theme-color-background-smallContrast; + border-color: @theme-color-background-contrast; +} + +.segment-element .segment-footer button { + text-shadow: none; +}
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/controls/_siteSelect.less b/plugins/PleineLune/stylesheets/controls/_siteSelect.less new file mode 100644 index 0000000000..dd26213b04 --- /dev/null +++ b/plugins/PleineLune/stylesheets/controls/_siteSelect.less @@ -0,0 +1,69 @@ +.top_bar_sites_selector > label { + display: none; +} + +.top_bar_sites_selector > .sites_autocomplete { + padding: 0; +} + +.sites_autocomplete .custom_select_main_link { + background: none; + padding: 0; + font-size: 18px; + line-height: 1; + color: @theme-color-text-base; +} + +.admin .sites_autocomplete .custom_select_main_link, +.sites_autocomplete--dropdown:hover .custom_select_main_link { + color: @theme-color-text-active; +} + +.sites_autocomplete--dropdown .custom_select_main_link:after { + content: " \25BC"; + float: right; + font-size: 0.8em; + margin-top: 0.2em; +} + +.sites_autocomplete .custom_select_main_link > span { + display: inline-block; + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + vertical-align: bottom; + white-space: nowrap; +} + +.sites_autocomplete .custom_select { + background: @theme-color-background-base; + border-color: @theme-color-background-contrast; + border-radius: 4px 4px 0 0; + font-size: 14px; + min-height: 25px; + padding: 8px 15px 0; +} + +.sites_autocomplete .custom_select_ul_list li a, +.sites_autocomplete .custom_select_all a { + color: @theme-color-text-link; +} + +.sites_autocomplete .custom_select_ul_list li a:hover, +.sites_autocomplete .custom_select_all a:hover { + background: @theme-color-background-smallContrast; + color: @theme-color-text-focus; +} + + +@media all and (max-width: 949px) { + .top_bar_sites_selector { + float: none; + text-align: center; + } + .sites_autocomplete .custom_select { + padding-left: 8px; + padding-right: 8px; + border-radius: 0; + } +}
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/controls/_widgetSelect.less b/plugins/PleineLune/stylesheets/controls/_widgetSelect.less new file mode 100644 index 0000000000..8d9baad15a --- /dev/null +++ b/plugins/PleineLune/stylesheets/controls/_widgetSelect.less @@ -0,0 +1,44 @@ +#dashboardSettings { + color: @theme-color-text-base; + border-radius: 0; +} + +#dashboardSettings, +#dashboardSettings:hover { + background: @theme-color-background-base; + border: 1px solid @theme-color-background-contrast; +} + +#dashboardSettings > span { + color: @theme-color-text-active; +} + +#dashboardSettings > span:hover { + color: @theme-color-text-focus; +} + +#dashboardSettings > ul.submenu > li { + color: @theme-color-text-link; +} + +#dashboardSettings > ul.submenu > li:hover { + color: @theme-color-text-focus; +} + +#dashboardSettings .submenu ul li, +ul.widgetpreview-widgetlist, ul.widgetpreview-categorylist { + color: @theme-color-text-base; +} + +#dashboardSettings .submenu ul li:hover, +#dashboardSettings .submenu ul li.widgetpreview-choosen, +#dashboardSettings .widgetpreview-widgetlist li:hover, +#dashboardSettings .widgetpreview-widgetlist li.widgetpreview-choosen, { + color: @theme-color-text-focus; + background: @theme-color-background-smallContrast; +} + +.widgetpreview-base li.widgetpreview-unavailable { + color: @theme-color-text-base; + text-decoration: line-through; +}
\ No newline at end of file diff --git a/plugins/PleineLune/stylesheets/theme.less b/plugins/PleineLune/stylesheets/theme.less index 0e754e96e0..655f9c6c57 100644 --- a/plugins/PleineLune/stylesheets/theme.less +++ b/plugins/PleineLune/stylesheets/theme.less @@ -1,11 +1,32 @@ -@theme-color-text-link: #6C9C50; + +@theme-color-background-base: #141414; +@theme-color-background-contrast: #5F5A60; +@theme-color-background-smallContrast: #202020; +@theme-color-background-lighter: #888; +@theme-color-highlight1: #766F31; +@theme-color-highlight2: #6C9C50; +@theme-color-highlight3: #67E750; + +@theme-color-text-link: @theme-color-highlight2; @theme-color-text-base: #59867D; -@theme-color-text-focus: #67E750; -@theme-color-text-active: #766F31; -@theme-color-box-border: #5F5A60; //#777778; -@theme-color-box-active: #141414; +@theme-color-text-lightFocus: #AAA; +@theme-color-text-focus: @theme-color-highlight3; +@theme-color-text-active: @theme-color-highlight1; +@theme-color-box-border: @theme-color-background-contrast; +@theme-color-box-active: @theme-color-background-smallContrast; @import "_general.less"; @import "_layout.less"; +@import "controls/_periodSelect.less"; +@import "controls/_segmentSelect.less"; +@import "controls/_widgetSelect.less"; +@import "controls/_headerMessage.less"; +@import "controls/_siteSelect.less"; @import "_menuDashboard.less"; -@import "_menuAdmin.less";
\ No newline at end of file +@import "_menuAdmin.less"; +@import "_widget.less"; +@import "_dataTable.less"; +@import "_sparklineColors.less"; +@import "_jqplotColors.less"; +@import "_ui.less"; +@import "../../PleineLune/stylesheets/_transitionColors.less";
\ No newline at end of file diff --git a/plugins/Referers/Controller.php b/plugins/Referers/Controller.php index 672e6c475f..17da96fe90 100644 --- a/plugins/Referers/Controller.php +++ b/plugins/Referers/Controller.php @@ -264,7 +264,7 @@ class Controller extends \Piwik\Controller { $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Referers.getRefererType'); - $view->add_total_row = true; + $view->visualization_properties->add_total_row = true; // configure displayed columns if (empty($columns)) { @@ -280,7 +280,7 @@ class Controller extends \Piwik\Controller } else { $selectable = array('nb_visits', 'nb_actions'); } - $view->selectable_columns = $selectable; + $view->visualization_properties->selectable_columns = $selectable; // configure displayed rows $visibleRows = Common::getRequestVar('rows', false); @@ -300,7 +300,7 @@ class Controller extends \Piwik\Controller $visibleRows = array($label, $total); $view->request_parameters_to_modify['rows'] = $label . ',' . $total; } - $view->row_picker_mach_rows_by = 'label'; + $view->row_picker_match_rows_by = 'label'; $view->row_picker_visible_rows = $visibleRows; $view->documentation = Piwik_Translate('Referers_EvolutionDocumentation') . '<br />' diff --git a/plugins/Referers/Referers.php b/plugins/Referers/Referers.php index 1b1efdc7c4..5f6451548b 100644 --- a/plugins/Referers/Referers.php +++ b/plugins/Referers/Referers.php @@ -329,15 +329,19 @@ class Referers extends \Piwik\Plugin } return array( - 'default_view_type' => 'tableAllColumns', - 'show_search' => false, - 'show_offset_information' => false, - 'show_pagination_control' => false, - 'show_exclude_low_population' => false, - 'disable_subtable_when_show_goals' => true, - 'show_goals' => true, - 'filter_limit' => 10, - 'translations' => array('label' => $labelColumnTitle) + 'default_view_type' => 'tableAllColumns', + 'show_search' => false, + 'show_offset_information' => false, + 'show_pagination_control' => false, + 'show_exclude_low_population' => false, + 'show_goals' => true, + 'filter_limit' => 10, + 'translations' => array('label' => $labelColumnTitle), + 'visualization_properties' => array( + 'table' => array( + 'disable_subtable_when_show_goals' => true, + ) + ), ); } @@ -346,11 +350,15 @@ class Referers extends \Piwik\Plugin $setGetAllHtmlPrefix = array($this, 'setGetAllHtmlPrefix'); return array( 'show_exclude_low_population' => false, - 'translations' => array('label' => Piwik_Translate('Referers_Referrer')), - 'show_goals' => true, - 'filter_limit' => 20, - 'custom_parameters' => array('disable_row_actions' => '1'), - 'filters' => array( + 'translations' => array('label' => Piwik_Translate('Referers_Referrer')), + 'show_goals' => true, + 'filter_limit' => 20, + 'visualization_properties' => array( + 'table' => array( + 'disable_row_actions' => true + ) + ), + 'filters' => array( array('MetadataCallbackAddMetadata', array('referrer_type', 'html_label_prefix', $setGetAllHtmlPrefix)) ) ); @@ -359,12 +367,16 @@ class Referers extends \Piwik\Plugin private function getDisplayPropertiesForGetKeywords() { return array( - 'subtable_controller_action' => 'getSearchEnginesFromKeywordId', - 'show_exclude_low_population' => false, - 'translations' => array('label' => Piwik_Translate('Referers_ColumnKeyword')), - 'show_goals' => true, - 'filter_limit' => 25, - 'disable_subtable_when_show_goals' => true, + 'subtable_controller_action' => 'getSearchEnginesFromKeywordId', + 'show_exclude_low_population' => false, + 'translations' => array('label' => Piwik_Translate('Referers_ColumnKeyword')), + 'show_goals' => true, + 'filter_limit' => 25, + 'visualization_properties' => array( + 'table' => array( + 'disable_subtable_when_show_goals' => true, + ) + ), ); } @@ -380,13 +392,17 @@ class Referers extends \Piwik\Plugin private function getDisplayPropertiesForGetSearchEngines() { return array( - 'subtable_controller_action' => 'getKeywordsFromSearchEngineId', - 'show_search' => false, - 'show_exclude_low_population' => false, - 'show_goals' => true, - 'filter_limit' => 25, - 'disable_subtable_when_show_goals' => true, - 'translations' => array('label' => Piwik_Translate('Referers_ColumnSearchEngine')) + 'subtable_controller_action' => 'getKeywordsFromSearchEngineId', + 'show_search' => false, + 'show_exclude_low_population' => false, + 'show_goals' => true, + 'filter_limit' => 25, + 'translations' => array('label' => Piwik_Translate('Referers_ColumnSearchEngine')), + 'visualization_properties' => array( + 'table' => array( + 'disable_subtable_when_show_goals' => true, + ) + ), ); } @@ -402,25 +418,33 @@ class Referers extends \Piwik\Plugin private function getDisplayPropertiesForGetWebsites() { return array( - 'subtable_controller_action' => 'getUrlsFromWebsiteId', - 'show_exclude_low_population' => false, - 'show_goals' => true, - 'filter_limit' => 25, - 'disable_subtable_when_show_goals' => true, - 'translations' => array('label' => Piwik_Translate('Referers_ColumnWebsite')) + 'subtable_controller_action' => 'getUrlsFromWebsiteId', + 'show_exclude_low_population' => false, + 'show_goals' => true, + 'filter_limit' => 25, + 'translations' => array('label' => Piwik_Translate('Referers_ColumnWebsite')), + 'visualization_properties' => array( + 'table' => array( + 'disable_subtable_when_show_goals' => true, + ) + ), ); } private function getDisplayPropertiesForGetSocials() { $result = array( - 'default_view_type' => 'graphPie', - 'subtable_controller_action' => 'getUrlsForSocial', - 'show_exclude_low_population' => false, - 'filter_limit' => 10, - 'show_goals' => true, - 'disable_subtable_when_show_goals' => true, - 'translations' => array('label' => Piwik_Translate('Referers_ColumnSocial')) + 'default_view_type' => 'graphPie', + 'subtable_controller_action' => 'getUrlsForSocial', + 'show_exclude_low_population' => false, + 'filter_limit' => 10, + 'show_goals' => true, + 'translations' => array('label' => Piwik_Translate('Referers_ColumnSocial')), + 'visualization_properties' => array( + 'table' => array( + 'disable_subtable_when_show_goals' => true, + ) + ), ); $widget = Common::getRequestVar('widget', false); diff --git a/plugins/SecurityInfo/PhpSecInfo/PhpSecInfo.php b/plugins/SecurityInfo/PhpSecInfo/PhpSecInfo.php index acdba6b959..bc4667665d 100644 --- a/plugins/SecurityInfo/PhpSecInfo/PhpSecInfo.php +++ b/plugins/SecurityInfo/PhpSecInfo/PhpSecInfo.php @@ -182,6 +182,7 @@ class PhpSecInfo /** * Constructor * + * @param null|array $opts * @return PhpSecInfo */ function PhpSecInfo($opts = null) @@ -332,6 +333,7 @@ class PhpSecInfo * * @param string $group_name * @param array $group_results + * @return bool */ function _outputRenderTable($group_name, $group_results) { diff --git a/plugins/SecurityInfo/PhpSecInfo/Test/Session/save_path.php b/plugins/SecurityInfo/PhpSecInfo/Test/Session/save_path.php index f04d087802..fa1eeb2353 100644 --- a/plugins/SecurityInfo/PhpSecInfo/Test/Session/save_path.php +++ b/plugins/SecurityInfo/PhpSecInfo/Test/Session/save_path.php @@ -50,7 +50,7 @@ class PhpSecInfo_Test_Session_Save_Path extends PhpSecInfo_Test_Session * We are disabling this function on Windows OSes right now until * we can be certain of the proper way to check world-readability * - * @return unknown + * @return bool */ function isTestable() { diff --git a/plugins/SegmentEditor/SegmentEditor.php b/plugins/SegmentEditor/SegmentEditor.php index cc0146df90..1c588a483d 100644 --- a/plugins/SegmentEditor/SegmentEditor.php +++ b/plugins/SegmentEditor/SegmentEditor.php @@ -102,16 +102,11 @@ class SegmentEditor extends \Piwik\Plugin public function getJsFiles(&$jsFiles) { - $jsFiles[] = "plugins/SegmentEditor/javascripts/jquery.jscrollpane.js"; $jsFiles[] = "plugins/SegmentEditor/javascripts/Segmentation.js"; - $jsFiles[] = "plugins/SegmentEditor/javascripts/jquery.mousewheel.js"; - $jsFiles[] = "plugins/SegmentEditor/javascripts/mwheelIntent.js"; } public function getCssFiles(&$cssFiles) { $cssFiles[] = "plugins/SegmentEditor/stylesheets/segmentation.less"; - $cssFiles[] = "plugins/SegmentEditor/stylesheets/jquery.jscrollpane.css"; - $cssFiles[] = "plugins/SegmentEditor/stylesheets/scroll.less"; } } diff --git a/plugins/SegmentEditor/javascripts/Segmentation.js b/plugins/SegmentEditor/javascripts/Segmentation.js index 8c3029c674..93ec161bb7 100644 --- a/plugins/SegmentEditor/javascripts/Segmentation.js +++ b/plugins/SegmentEditor/javascripts/Segmentation.js @@ -45,14 +45,14 @@ Segmentation = (function($) { return self.currentSegmentStr; } return decodeURIComponent(self.currentSegmentStr); - } + }; var setSegment = function(segmentStr){ if(!$.browser.mozilla) { segmentStr = encodeURIComponent(segmentStr); } self.currentSegmentStr = segmentStr; - } + }; segmentation.prototype.shortenSegmentName = function(name, length){ @@ -74,7 +74,7 @@ Segmentation = (function($) { return name.slice(0,i)+"..."; } return name; - } + }; var markCurrentSegment = function(){ var current = self.getSegment(); @@ -96,35 +96,35 @@ Segmentation = (function($) { else { $(self.content).find(".segmentationTitle").text(self.translations['SegmentEditor_DefaultAllVisits']); } - } + }; var getAndDiv = function(){ if(typeof andDiv === "undefined"){ var andDiv = $("#SegmentEditor > div.segment-and").clone(); } return andDiv.clone(); - } + }; var getOrDiv = function(){ if(typeof orDiv === "undefined"){ var orDiv = $("#SegmentEditor > div.segment-or").clone(); } return orDiv.clone(); - } + }; var getMockedInputSet = function(){ if(typeof mockedInputSet === "undefined"){ var mockedInputSet = $("#SegmentEditor div.segment-row-inputs").clone(); } return mockedInputSet.clone(); - } + }; var getMockedInputRowHtml = function(){ if(typeof mockedInputRow === "undefined"){ var mockedInputRow = '<div class="segment-row"><a class="segment-close" href="#"></a><div class="segment-row-inputs">'+getMockedInputSet().html()+'</div></div>'; } return mockedInputRow; - } + }; var getMockedFormRow = function(){ if(typeof mockedFormRow === "undefined") @@ -133,7 +133,7 @@ Segmentation = (function($) { $(mockedFormRow).find(".segment-row").append(getMockedInputSet()).after(getAddOrBlockButtonHtml).after(getOrDiv()); } return mockedFormRow.clone(); - } + }; var getInitialStateRowsHtml = function(){ if(typeof initialStateRows === "undefined"){ @@ -141,12 +141,12 @@ Segmentation = (function($) { var initialStateRows = $(content).clone(); } return initialStateRows; - } + }; var revokeInitialStateRows = function(){ $(self.form).find(".segment-add-row").remove(); $(self.form).find(".segment-and").remove(); - } + }; var appendSpecifiedRowHtml= function(metric) { $(self.form).find(".segment-content > h3").after(getMockedFormRow()); @@ -154,7 +154,7 @@ Segmentation = (function($) { $(self.form).find(".segment-content").append(getAddNewBlockButtonHtml()); doDragDropBindings(); $(self.form).find(".metricList").val(metric).trigger("change"); - } + }; var appendComplexRowHtml = function(block){ var key; @@ -177,13 +177,13 @@ Segmentation = (function($) { $(newRow).append(getAddOrBlockButtonHtml()); } $(self.form).find(".segment-content").append(newRow).append(getAndDiv()); - } + }; var applyInitialStateModification = function(){ $(self.form).find(".segment-add-row").remove(); $(self.form).find(".segment-content").append(getInitialStateRowsHtml()); doDragDropBindings(); - } + }; var getSegmentFromId = function (id) { if(self.availableSegments.length > 0) { @@ -196,7 +196,7 @@ Segmentation = (function($) { } } return false; - } + }; var getListHtml = function() { var html = $("#SegmentEditor > .listHtml").clone(); @@ -236,7 +236,7 @@ Segmentation = (function($) { $(html).find(".segmentList > ul").append(listHtml); } return html; - } + }; var getFormHtml = function() { var html = $("#SegmentEditor > .segment-element").clone(); @@ -257,7 +257,7 @@ Segmentation = (function($) { } $(html).find(".segment-content > h3").after(getInitialStateRowsHtml()).show(); return html; - } + }; var doListBindings = function() { @@ -273,14 +273,14 @@ Segmentation = (function($) { doDragDropBindings(); }); - } + }; var closeAllOpenLists = function() { $(".segmentationContainer").each(function() { if($(this).hasClass("visible")) $(this).trigger("click"); }); - } + }; var findAndExplodeByMatch = function(metric){ @@ -324,7 +324,7 @@ Segmentation = (function($) { newMetric.value = decodeURIComponent(newMetric.value); return newMetric; - } + }; var parseSegmentStr = function(segmentStr) { @@ -337,7 +337,7 @@ Segmentation = (function($) { } } return blocks; - } + }; var openEditForm = function(segment){ addForm("edit", segment); @@ -361,7 +361,7 @@ Segmentation = (function($) { $(this).trigger("change", true); }); doDragDropBindings(); - } + }; var bindListEvents = function(){ $(self.content).off("click").on("click", function(event){ @@ -420,7 +420,7 @@ Segmentation = (function($) { autoSuggestValues(this, persist); } ); - } + }; // Request auto-suggest values var autoSuggestValues = function(select, persist) { @@ -457,7 +457,7 @@ Segmentation = (function($) { }); ajaxHandler.send(); } - } + }; var alterMatchesList = function(select, persist){ var oldMatch; @@ -479,7 +479,7 @@ Segmentation = (function($) { matchSelector.append(optionsHtml); matchSelector.val(oldMatch); - } + }; var getAddNewBlockButtonHtml = function() { @@ -489,7 +489,7 @@ Segmentation = (function($) { } return addNewBlockButton.clone(); - } + }; var getAddOrBlockButtonHtml = function(){ if(typeof addOrBlockButton === "undefined") @@ -497,7 +497,7 @@ Segmentation = (function($) { var addOrBlockButton = $("#SegmentEditor div.segment-add-or").clone(); } return addOrBlockButton.clone(); - } + }; var placeSegmentationFormControls = function(){ doDragDropBindings(); @@ -507,7 +507,7 @@ Segmentation = (function($) { verticalArrowPositions: 'os', horizontalArrowPositions: 'os' }); - } + }; function openEditFormGivenSegment(option) { var segment = {}; @@ -542,7 +542,7 @@ Segmentation = (function($) { var oldName = $(e.currentTarget).parents("h3").find("span").text(); $(e.currentTarget).parents("h3").find("span").hide(); $(e.currentTarget).hide(); - $(e.currentTarget).before('<input id="edit_segment_name"/>'); + $(e.currentTarget).before('<input id="edit_segment_name" type="text"/>'); $(e.currentTarget).siblings("#edit_segment_name").focus().val(oldName); }); @@ -616,7 +616,7 @@ Segmentation = (function($) { $(self.form).on("click", ".delete", function(){ var segmentName = $(self.form).find(".segment-content > h3 > span").text(); - var segmentId = $(self.form).find("#available_segments_select option:selected").attr("data-idsegment") + var segmentId = $(self.form).find("#available_segments_select option:selected").attr("data-idsegment"); var params = { "idsegment" : segmentId }; @@ -645,7 +645,7 @@ Segmentation = (function($) { bindChangeMetricSelectEvent(); placeSegmentationFormControls(); - } + }; var doDragDropBindings = function(){ $(self.form).find(".segment-nav div > ul > li > ul > li").sortable({ @@ -681,9 +681,7 @@ Segmentation = (function($) { $(this).find("a").trigger("click", [ui.draggable.parent().attr("data-metric")]); } }); - - - } + }; var searchSegments = function(search){ // pre-process search string to normalized form @@ -700,7 +698,7 @@ Segmentation = (function($) { // 1 - do most obvious selection -> mark whole categories matching search string // also expand whole category $(self.form).find('.segment-nav div > ul > li').each( function(){ - curStr = normalizeSearchString($(this).find("a.metric_category").text()) + curStr = normalizeSearchString($(this).find("a.metric_category").text()); if(curStr.indexOf(search) > -1) { $(this).addClass("searchFound"); $(this).find("ul").show(); @@ -736,7 +734,7 @@ Segmentation = (function($) { self.searchAllowed = true; } - } + }; var clearSearchMetricHighlight = function(){ $(self.form).find('.no_results').remove(); @@ -744,7 +742,7 @@ Segmentation = (function($) { $(self.form).find('.segment-nav div > ul > li').removeClass("others").show(); $(self.form).find('.segment-nav div > ul > li > ul > li').show(); $(self.form).find('.segment-nav div > ul > li > ul').hide(); - } + }; var normalizeSearchString = function(search){ search = search.replace(/^\s+|\s+$/g, ''); // trim @@ -760,7 +758,7 @@ Segmentation = (function($) { .replace(/\s+/g, '_') // collapse whitespace and replace by underscore .replace(/-+/g, '-'); // collapse dashes return search; - } + }; var bindSegmentManipulationEvents = function(){ // upon clicking - add new segment block, then bind 'x' action to newly added row @@ -769,7 +767,7 @@ Segmentation = (function($) { if(typeof data !== "undefined"){ $(self.form).find(".metricList:last").val(data); } - $(self.form).find(".metricList:last").trigger('change') + $(self.form).find(".metricList:last").trigger('change'); doDragDropBindings(); }); @@ -807,7 +805,7 @@ Segmentation = (function($) { } } }); - } + }; // Mode = 'new' or 'edit' var addForm = function(mode, segment){ @@ -822,7 +820,6 @@ Segmentation = (function($) { self.form = getFormHtml(); $("#segmentEditorPanel").prepend(self.form); - setLeftMargin('#segmentEditorPanel > .segment-element'); bindFormEvents(); bindSegmentManipulationEvents(); @@ -854,7 +851,7 @@ Segmentation = (function($) { } $("#segmentList").hide(); - } + }; var parseForm = function(){ var segmentStr = ""; @@ -879,7 +876,7 @@ Segmentation = (function($) { segmentStr += subSegmentStr; }); return segmentStr - } + }; var parseFormAndSave = function(){ var segmentName = $(self.form).find(".segment-content > h3 >span").text(); @@ -905,7 +902,7 @@ Segmentation = (function($) { }); self.updateMethod(params); } - } + }; var makeDropList = function(spanId, selectId){ var select = $(self.form).find(selectId).hide(); @@ -954,11 +951,11 @@ Segmentation = (function($) { dropList.autocomplete().autocomplete("close"); } }); - } + }; var setLeftMargin = function(selector) { $(selector).css({left: Math.max($('#periodString')[0].offsetWidth) + 10}); - } + }; function toggleLoadingMessage(segmentIsSet) { if (segmentIsSet) { @@ -980,7 +977,7 @@ Segmentation = (function($) { $("#"+self.targetId).append(html); self.content = $("#"+self.targetId).find(".segmentationContainer"); } - setLeftMargin('.segmentationContainer'); + setLeftMargin('#segmentEditorPanel'); // assign content to object attribute to make it easil accesible through all widget methods bindListEvents(); @@ -989,7 +986,7 @@ Segmentation = (function($) { // Loading message var segmentIsSet = self.getSegment().length; toggleLoadingMessage(segmentIsSet); - } + }; initHtml(); }; @@ -1014,7 +1011,7 @@ $(document).ready( function(){ definition = definition.replace("'", "%29"); definition = definition.replace("&", "%26"); return definition; - } + }; var addSegment = function(params){ var ajaxHandler = new ajaxHelper(); diff --git a/plugins/SegmentEditor/stylesheets/segmentation.less b/plugins/SegmentEditor/stylesheets/segmentation.less index d2ec307deb..ccd34d25a0 100644 --- a/plugins/SegmentEditor/stylesheets/segmentation.less +++ b/plugins/SegmentEditor/stylesheets/segmentation.less @@ -81,13 +81,16 @@ div.scrollable { border: 1px solid #a9a399; background-color: #f1f0eb; padding: 6px 4px; - border-radius: 3px 3px 3px 3px; + border-radius: 3px; + position: absolute; + left: 0; + top: 0; } .segment-element .custom_select_search { width: 146px; height: 21px; - background: url(../images/bg-segment-search.png) 0 10px no-repeat; + background: url(plugins/SegmentEditor/images/bg-segment-search.png) 0 10px no-repeat; padding: 10px 0 0 0; margin: 10px 0 10px 15px; border-top: 1px solid #dcdacf; @@ -109,7 +112,7 @@ div.scrollable { height: 13px; right: 5px; top: 14px; - background: url(../images/reset_search.png); + background: url(plugins/SegmentEditor/images/reset_search.png); } .segment-element .segment-nav { @@ -128,8 +131,8 @@ div.scrollable { } .segment-element .segment-nav h4.visits { - padding-left: 28px; - background: url(../images/icon-users.png) 0 0 no-repeat; + padding-left: 15px; + background: url(plugins/SegmentEditor/images/icon-users.png) 0 0 no-repeat; } .segment-element .segment-nav h4 a { @@ -141,41 +144,40 @@ div.scrollable { padding: 0 0 0 15px; } -.segment-element .segment-nav div > ul > li { +.segment-element .segment-nav div > ul > li { padding: 2px 0; line-height: 14px; } -.segment-element .segment-nav div > ul > li li { +.segment-element .segment-nav div > ul > li li { padding: 1px; border-radius: 3px 3px 3px 3px; } -.segment-element .segment-nav div > ul > li li:hover { +.segment-element .segment-nav div > ul > li li:hover { padding: 0; border: 1px solid #cfccbd; border-bottom: 1px solid #7c7a72; - background-color: #e9e7e3; } -.segment-element .segment-nav div > ul > li li:hover a { +.segment-element .segment-nav div > ul > li li:hover a { cursor: move; padding: 1px 0 2px 8px; border-top: 1px solid #fff; - background: #eae8e3 url(../images/segment-move.png) 100% 50% no-repeat; + background: #eae8e3 url(plugins/SegmentEditor/images/segment-move.png) 100% 50% no-repeat; } -.segment-element .segment-nav div > ul > li li a { +.segment-element .segment-nav div > ul > li li a { padding: 2px 0 2px 8px; font-weight: normal; display: block; } -.segment-element .segment-nav div > ul > li ul { +.segment-element .segment-nav div > ul > li ul { margin: 2px 0 -3px 10px; } -.segment-element .segment-nav div > ul > li a { +.segment-element .segment-nav div > ul > li a { color: #5d5342; font: bold 11px Arial; text-decoration: none; @@ -219,21 +221,21 @@ div.scrollable { position: relative; } -.segment-element .segment-content .segment-add-row > div, -.segment-element .segment-content .segment-add-or > div { +.segment-element .segment-content .segment-add-row > div, +.segment-element .segment-content .segment-add-or > div { border-radius: 4px; border: 2px dashed #fff; padding: 10px 0; } -.segment-element .segment-content .segment-add-row > div a, -.segment-element .segment-content .segment-add-or > div a { +.segment-element .segment-content .segment-add-row > div a, +.segment-element .segment-content .segment-add-or > div a { color: #b9b9b9; text-decoration: none; } -.segment-element .segment-content .segment-add-row > div a span, -.segment-element .segment-content .segment-add-or > div a span { +.segment-element .segment-content .segment-add-row > div a span, +.segment-element .segment-content .segment-add-or > div a span { color: #255792; } @@ -254,7 +256,7 @@ div.scrollable { border-radius: 3px 3px 3px 3px; } -.segment-element .segment-content .segment-add-or > div { +.segment-element .segment-content .segment-add-or > div { border: 2px dashed #EFEFEB; } @@ -274,7 +276,7 @@ div.scrollable { position: absolute; width: 15px; height: 15px; - background: url(../images/segment-close.png) 0 0 no-repeat; + background: url(plugins/SegmentEditor/images/segment-close.png) 0 0 no-repeat; } .segment-element .segment-content .segment-row .segment-loading { @@ -284,7 +286,7 @@ div.scrollable { position: absolute; width: 15px; height: 15px; - background: url(../../MultiSites/images/loading-blue.gif) 0 0 no-repeat; + background: url(plugins/MultiSites/images/loading-blue.gif) 0 0 no-repeat; } .segment-element .segment-content .segment-or { @@ -337,7 +339,7 @@ div.scrollable { .segment-element .segment-content .segment-and:after { content: ''; position: absolute; - background: url(../images/bg-inverted-corners.png); + background: url(plugins/SegmentEditor/images/bg-inverted-corners.png); border: 1px solid #a9a399; width: 10px; top: 0px; @@ -397,7 +399,7 @@ div.scrollable { .segment-element .segment-top a.dropdown { padding: 0 17px 0 0; - background: url(../../Zeitgeist/images/sort_subtable_desc.png) 100% -2px no-repeat; + background: url(plugins/Zeitgeist/images/sort_subtable_desc.png) 100% -2px no-repeat; } .segment-element .segment-footer { @@ -437,9 +439,9 @@ div.scrollable { margin: 0 0 0 15px; } -.segmentationContainer { +#segmentEditorPanel { position: absolute; - z-index: 2; + z-index: 120; /* Should be the same as 'Dashboard widget selector' (z-index: 120) */ background: #f7f7f7; border: 1px solid #e4e5e4; padding: 5px 10px 6px 10px; @@ -448,12 +450,12 @@ div.scrollable { font-size: 14px; } -.segmentationContainer:hover { +#segmentEditorPanel:hover { background: #f1f0eb; border-color: #a9a399; } -.segmentationContainer > span > b { +.segmentationContainer > span > b { color: #255792; } @@ -496,7 +498,7 @@ div.scrollable { float: left; } -.segmentationContainer ul.submenu > li span.editSegment { +.segmentationContainer ul.submenu > li span.editSegment { display: block; float: right; width: 45px; @@ -515,7 +517,7 @@ div.scrollable { .segmentationContainer.visible .add_new_segment { display: block; - background: url("../images/dashboard_h_bg_hover.png") repeat-x scroll 0 0 #847b6d; + background: url("plugins/SegmentEditor/images/dashboard_h_bg_hover.png") repeat-x scroll 0 0 #847b6d; border: 0 none; border-radius: 4px 4px 4px 4px; clear: both; @@ -527,14 +529,14 @@ div.scrollable { width: 130px; } -.segmentationContainer > ul.submenu > li { +.segmentationContainer > ul.submenu > li { padding: 5px 0; clear: both; cursor: pointer; } span.segmentationTitle { - background: url(../../Zeitgeist/images/sort_subtable_desc.png) right center no-repeat !important; + background: url(plugins/Zeitgeist/images/sort_subtable_desc.png) no-repeat right 0; padding-right: 20px !important; width: 160px !important; display: block !important; @@ -545,8 +547,9 @@ span.segmentationTitle { display: none; } -.segmentList { +#segmentList { max-height: 250px; + overflow: hidden; /* Create a BFC */ } .jspVerticalBar { @@ -558,7 +561,7 @@ body > a.ddmetric { display: block; cursor: move; padding: 1px 0 2px 18px; - background: #eae8e3 url(../images/segment-move.png) 100% 50% no-repeat; + background: #eae8e3 url(plugins/SegmentEditor/images/segment-move.png) 100% 50% no-repeat; color: #5d5342; font: normal 11px Arial; text-decoration: none; @@ -616,7 +619,7 @@ a.metric_category { } #available_segments a.dropdown { - background: url("../../Zeitgeist/images/sort_subtable_desc.png") no-repeat scroll 100% -2px transparent !important; + background: url("plugins/Zeitgeist/images/sort_subtable_desc.png") no-repeat scroll 100% -2px transparent !important; padding: 0 17px 0 0 !important; } diff --git a/plugins/SegmentEditor/templates/getSelector.twig b/plugins/SegmentEditor/templates/getSelector.twig index 181c97bd84..2cecd2dd31 100644 --- a/plugins/SegmentEditor/templates/getSelector.twig +++ b/plugins/SegmentEditor/templates/getSelector.twig @@ -137,9 +137,9 @@ </div> </div> -<span id="segmentEditorPanel"> +<div id="segmentEditorPanel"> <div id="segmentList"></div> -</span> +</div> <div class="ui-confirm" id="segment-delete-confirm"> <h2>{{ 'SegmentEditor_AreYouSureDeleteSegment'|translate }}</h2> diff --git a/plugins/SitesManager/javascripts/SitesManager.js b/plugins/SitesManager/javascripts/SitesManager.js index 73000c3969..e3bcd8c516 100644 --- a/plugins/SitesManager/javascripts/SitesManager.js +++ b/plugins/SitesManager/javascripts/SitesManager.js @@ -306,7 +306,7 @@ function SitesManager(_timezones, _currencies, _defaultTimezone, _defaultCurrenc $('#defaultCurrency').html(getCurrencySelector(defaultCurrency)); $('td.editableSite').click(function () { $(this).parent().find('.editSite').click(); }); - } + }; function getSitesearchSelector(contentBefore) { var globalKeywordParameters = $('input#globalSearchKeywordParameters').val().trim(); diff --git a/plugins/SitesManager/stylesheets/SitesManager.less b/plugins/SitesManager/stylesheets/SitesManager.less index 0196289bee..fca6f5d8bf 100644 --- a/plugins/SitesManager/stylesheets/SitesManager.less +++ b/plugins/SitesManager/stylesheets/SitesManager.less @@ -21,7 +21,7 @@ .addRowSite:before { display: inline-block; - content: url(../../UsersManager/images/add.png); + content: url(plugins/UsersManager/images/add.png); vertical-align: middle; } diff --git a/plugins/Transitions/javascripts/transitions.js b/plugins/Transitions/javascripts/transitions.js index da6c8a8bc2..d442a0cf4c 100644 --- a/plugins/Transitions/javascripts/transitions.js +++ b/plugins/Transitions/javascripts/transitions.js @@ -29,7 +29,7 @@ DataTable_RowActions_Transitions.isPageUrlReport = function (module, action) { DataTable_RowActions_Transitions.isPageTitleReport = function (module, action) { return module == 'Actions' && (action == 'getPageTitles' || action == 'getPageTitlesFollowingSiteSearch'); -} +}; DataTable_RowActions_Transitions.prototype.trigger = function (tr, e, subTableLabel) { var link = tr.find('> td:first > a').attr('href'); @@ -808,9 +808,9 @@ Piwik_Transitions_Canvas.prototype.isNarrowMode = function () { /** * Helper to create horizontal gradients * TODO - * @param lightColor - * @param darkColor - * @param position left|right + * @param {String} colorGroup + * @param {String} position left|right + * @param {Boolean} isHighlighted */ Piwik_Transitions_Canvas.prototype.createHorizontalGradient = function (colorGroup, position, isHighlighted) { var fromX, toX, fromColor, toColor, lightColor, darkColor; diff --git a/plugins/Zeitgeist/stylesheets/ui/_transitions.less b/plugins/Transitions/stylesheets/_transitionColors.less index e74d16b341..e74d16b341 100644 --- a/plugins/Zeitgeist/stylesheets/ui/_transitions.less +++ b/plugins/Transitions/stylesheets/_transitionColors.less diff --git a/plugins/Transitions/stylesheets/transitions.less b/plugins/Transitions/stylesheets/transitions.less index 7fc748602b..978ffdd86a 100644 --- a/plugins/Transitions/stylesheets/transitions.less +++ b/plugins/Transitions/stylesheets/transitions.less @@ -1,3 +1,5 @@ +@import "_transitionColors"; + #Transitions_Container { position: relative; z-index: 1500; diff --git a/plugins/UserCountry/GeoIPAutoUpdater.php b/plugins/UserCountry/GeoIPAutoUpdater.php index 6d28c192cd..86383ed4d8 100755 --- a/plugins/UserCountry/GeoIPAutoUpdater.php +++ b/plugins/UserCountry/GeoIPAutoUpdater.php @@ -456,13 +456,14 @@ class GeoIPAutoUpdater * if we can't unzip it... * * @param string $ext The URL file's extension. + * @throws \Exception */ private static function checkForSupportedArchiveType($ext) { if ($ext != 'tar.gz' && $ext != 'gz' ) { - throw new Exception(Piwik_Translate('UserCountry_UnsupportedArchiveType', "'$ext'")); + throw new \Exception(Piwik_Translate('UserCountry_UnsupportedArchiveType', "'$ext'")); } } diff --git a/plugins/UserCountry/LocationProvider.php b/plugins/UserCountry/LocationProvider.php index e26e72934d..946e131f19 100755 --- a/plugins/UserCountry/LocationProvider.php +++ b/plugins/UserCountry/LocationProvider.php @@ -137,7 +137,7 @@ abstract class LocationProvider /** * Returns every available provider instance. * - * @return array + * @return Piwik_UserCountry_LocationProvider[] */ public static function getAllProviders() { diff --git a/plugins/UserCountry/LocationProvider/Default.php b/plugins/UserCountry/LocationProvider/Default.php index dd44183f21..a8eeb1688d 100755 --- a/plugins/UserCountry/LocationProvider/Default.php +++ b/plugins/UserCountry/LocationProvider/Default.php @@ -51,7 +51,7 @@ class DefaultProvider extends LocationProvider * * This implementation is always available. * - * @return true + * @return bool always true */ public function isAvailable() { @@ -63,7 +63,7 @@ class DefaultProvider extends LocationProvider * * This implementation is always working correctly. * - * @return true + * @return bool always true */ public function isWorking() { diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php index 5c7bde67e0..a2fcc00992 100644 --- a/plugins/UserCountry/UserCountry.php +++ b/plugins/UserCountry/UserCountry.php @@ -378,7 +378,7 @@ class UserCountry extends \Piwik\Plugin if (!$self->isGeoIPWorking()) { $params = array('module' => 'UserCountry', 'action' => 'adminIndex'); $footerMessage .= ' ' . Piwik_Translate('UserCountry_NoDataForGeoIPReport2', - array('<a target="_blank" href="' . Piwik_Url::getCurrentQueryStringWithParametersModified($params) . '">', + array('<a target="_blank" href="' . \Piwik\Url::getCurrentQueryStringWithParametersModified($params) . '">', '</a>', '<a target="_blank" href="http://dev.maxmind.com/geoip/geolite?rId=piwik">', '</a>')); diff --git a/plugins/UserCountry/templates/_updaterManage.twig b/plugins/UserCountry/templates/_updaterManage.twig index 27d61283f1..7ed533051a 100755 --- a/plugins/UserCountry/templates/_updaterManage.twig +++ b/plugins/UserCountry/templates/_updaterManage.twig @@ -43,7 +43,7 @@ </td> <td width="164"> {% set lastTimeRunNote %} - {% if lastTimeUpdaterRun is not empty %} + {% if lastTimeUpdaterRun is defined and lastTimeUpdaterRun is not empty %} {{ 'UserCountry_UpdaterWasLastRun'|translate(lastTimeUpdaterRun)|raw }} {% else %} {{ 'UserCountry_UpdaterHasNotBeenRun'|translate }} diff --git a/plugins/UserCountryMap/Controller.php b/plugins/UserCountryMap/Controller.php index 187aeb9302..50ce58e31a 100644 --- a/plugins/UserCountryMap/Controller.php +++ b/plugins/UserCountryMap/Controller.php @@ -30,7 +30,7 @@ class Controller extends \Piwik\Controller // By default plot up to the last 30 days of visitors on the map, for low traffic sites const REAL_TIME_WINDOW = 'last30'; - public function visitorMap() + public function visitorMap($fetch = false) { $this->checkUserCountryPluginEnabled(); @@ -39,6 +39,7 @@ class Controller extends \Piwik\Controller $period = Common::getRequestVar('period'); $date = Common::getRequestVar('date'); + $segment = Common::getRequestVar('segment', '', 'string'); $token_auth = Piwik::getCurrentUserTokenAuth(); $view = new View('@UserCountryMap/visitorMap'); @@ -81,6 +82,7 @@ class Controller extends \Piwik\Controller 'period' => $period, 'idSite' => $idSite, 'date' => $date, + 'segment' => $segment, 'token_auth' => $token_auth, 'enable_filter_excludelowpop' => 1, 'filter_excludelowpop_value' => -1 @@ -92,7 +94,11 @@ class Controller extends \Piwik\Controller $view->config = Common::json_encode($config); $view->noData = empty($config['visitsSummary']['nb_visits']); - echo $view->render(); + if ($fetch) { + return $view->render(); + } else { + echo $view->render(); + } } /** @@ -209,7 +215,7 @@ class Controller extends \Piwik\Controller . "&period=" . $period . "&date=" . $date . "&token_auth=" . $token_auth - . "&segment=" . \Piwik\API\Request::getRawSegmentFromRequest() + . "&segment=" . Common::getRequestVar('segment', '', 'string') . "&enable_filter_excludelowpop=1" . "&showRawMetrics=1"; diff --git a/plugins/UserSettings/UserSettings.php b/plugins/UserSettings/UserSettings.php index f6dd1d8a7e..ba52b97d0d 100644 --- a/plugins/UserSettings/UserSettings.php +++ b/plugins/UserSettings/UserSettings.php @@ -177,107 +177,171 @@ class UserSettings extends \Piwik\Plugin public function getReportDisplayProperties(&$properties) { - $basicUserSettingsProperties = array('show_search' => false, - 'show_exclude_low_population' => false, - 'filter_limit' => 5, - 'graph_limit' => 5); + $properties['UserSettings.getResolution'] = $this->getDisplayPropertiesForGetResolution(); + $properties['UserSettings.getConfiguration'] = $this->getDisplayPropertiesForGetConfiguration(); + $properties['UserSettings.getOS'] = $this->getDisplayPropertiesForGetOS(); + $properties['UserSettings.getOSFamily'] = $this->getDisplayPropertiesForGetOSFamily(); + $properties['UserSettings.getBrowserVersion'] = $this->getDisplayPropertiesForGetBrowserVersion(); + $properties['UserSettings.getBrowser'] = $this->getDisplayPropertiesForGetBrowser(); + $properties['UserSettings.getBrowserType'] = $this->getDisplayPropertiesForGetBrowserType(); + $properties['UserSettings.getWideScreen'] = $this->getDisplayPropertiesForGetWideScreen(); + $properties['UserSettings.getMobileVsDesktop'] = $this->getDisplayPropertiesForGetMobileVsDesktop(); + $properties['UserSettings.getPlugin'] = $this->getDisplayPropertiesForGetPlugin(); + $properties['UserSettings.getLanguage'] = $this->getDisplayPropertiesForGetLanguage(); + } - $osRelatedReports = array( - 'UserSettings.getOSFamily' => Piwik_Translate('UserSettings_OperatingSystemFamily'), - 'UserSettings.getOS' => Piwik_Translate('UserSettings_OperatingSystems') + private function getDisplayPropertiesForGetResolution() + { + return array_merge($this->getBasicUserSettingsDisplayProperties(), array( + 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnResolution')) + )); + } + + private function getDisplayPropertiesForGetConfiguration() + { + return array_merge($this->getBasicUserSettingsDisplayProperties(), array( + 'filter_limit' => 3, + 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnConfiguration')) + )); + } + + private function getDisplayPropertiesForGetOS() + { + return array_merge($this->getBasicUserSettingsDisplayProperties(), array( + 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnOperatingSystem')), + 'title' => Piwik_Translate('UserSettings_OperatingSystems'), + 'related_reports' => $this->getOsRelatedReports() + )); + } + + private function getDisplayPropertiesForGetOSFamily() + { + return array_merge($this->getBasicUserSettingsDisplayProperties(), array( + 'translations' => array('label' => Piwik_Translate('UserSettings_OperatingSystemFamily')), + 'title' => Piwik_Translate('UserSettings_OperatingSystemFamily'), + 'related_reports' => $this->getOsRelatedReports() + )); + } + + private function getDisplayPropertiesForGetBrowserVersion() + { + $result = array_merge($this->getBasicUserSettingsDisplayProperties(), array( + 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnBrowserVersion')), + 'title' => Piwik_Translate('UserSettings_ColumnBrowserVersion'), + 'related_reports' => $this->getBrowserRelatedReports() + )); + $result['visualization_properties']['jqplot_graph']['max_graph_elements'] = 7; + return $result; + } + + private function getDisplayPropertiesForGetBrowser() + { + $result = array_merge($this->getBasicUserSettingsDisplayProperties(), array( + 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnBrowser')), + 'title' => Piwik_Translate('UserSettings_Browsers'), + 'related_reports' => $this->getBrowserRelatedReports() + )); + $result['visualization_properties']['jqplot_graph']['max_graph_elements'] = 7; + return $result; + } + + private function getDisplayPropertiesForGetBrowserType() + { + return array_merge($this->getBasicUserSettingsDisplayProperties(), array( + 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnBrowserFamily')), + 'show_offset_information' => false, + 'show_pagination_control' => false, + 'default_view_type' => 'graphPie', + )); + } + + private function getDisplayPropertiesForGetWideScreen() + { + return array_merge($this->getBasicUserSettingsDisplayProperties(), array( + 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnTypeOfScreen')), + 'show_offset_information' => false, + 'show_pagination_control' => false, + 'title' => Piwik_Translate('UserSettings_ColumnTypeOfScreen'), + 'related_reports' => $this->getWideScreenDeviceTypeRelatedReports() + )); + } + + private function getDisplayPropertiesForGetMobileVsDesktop() + { + return array_merge($this->getBasicUserSettingsDisplayProperties(), array( + 'translations' => array('label' => Piwik_Translate('UserSettings_MobileVsDesktop')), + 'title' => Piwik_Translate('UserSettings_MobileVsDesktop'), + 'related_reports' => $this->getWideScreenDeviceTypeRelatedReports() + )); + } + + private function getDisplayPropertiesForGetPlugin() + { + return array_merge($this->getBasicUserSettingsDisplayProperties(), array( + 'translations' => array( + 'label' => Piwik_Translate('UserSettings_ColumnPlugin'), + 'nb_visits_percentage' => + str_replace(' ', ' ', Piwik_Translate('General_ColumnPercentageVisits')) + ), + 'show_offset_information' => false, + 'show_pagination_control' => false, + 'show_all_views_icons' => false, + 'show_table_all_columns' => false, + 'columns_to_display' => array('label', 'nb_visits_percentage', 'nb_visits'), + 'filter_sort_column' => 'nb_visits_percentage', + 'filter_sort_order' => 'desc', + 'filter_limit' => 10, + 'show_footer_message' => Piwik_Translate('UserSettings_PluginDetectionDoesNotWorkInIE'), + )); + } + + private function getDisplayPropertiesForGetLanguage() + { + return array( + 'translations' => array('label' => Piwik_Translate('General_Language')), + 'filter_sort_column' => 'nb_visits', + 'filter_sort_order' => 'desc', + 'show_search' => false, + 'columns_to_display' => array('label', 'nb_visits'), + 'show_exclude_low_population' => false, + ); + } + + private function getWideScreenDeviceTypeRelatedReports() + { + return array( + 'UserSettings.getMobileVsDesktop' => Piwik_Translate('UserSettings_MobileVsDesktop'), + 'UserSettings.getWideScreen' => Piwik_Translate('UserSettings_ColumnTypeOfScreen') ); + } - $browserRelatedReports = array( - 'UserSettings.getBrowser' => Piwik_Translate('UserSettings_Browsers'), + private function getBrowserRelatedReports() + { + return array( + 'UserSettings.getBrowser' => Piwik_Translate('UserSettings_Browsers'), 'UserSettings.getBrowserVersion' => Piwik_Translate('UserSettings_ColumnBrowserVersion') ); + } - $wideScreenDeviceTypeRelatedReports = array( - 'UserSettings.getMobileVsDesktop' => Piwik_Translate('UserSettings_MobileVsDesktop'), - 'UserSettings.getWideScreen' => Piwik_Translate('UserSettings_ColumnTypeOfScreen') + private function getOsRelatedReports() + { + return array( + 'UserSettings.getOSFamily' => Piwik_Translate('UserSettings_OperatingSystemFamily'), + 'UserSettings.getOS' => Piwik_Translate('UserSettings_OperatingSystems') ); + } - $properties['UserSettings.getResolution'] = array_merge($basicUserSettingsProperties, array( - 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnResolution')) - )); - - $properties['UserSettings.getConfiguration'] = array_merge($basicUserSettingsProperties, array( - 'filter_limit' => 3, - 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnConfiguration')) - )); - - $properties['UserSettings.getOS'] = array_merge($basicUserSettingsProperties, array( - 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnOperatingSystem')), - 'title' => Piwik_Translate('UserSettings_OperatingSystems'), - 'relatedReports' => $osRelatedReports - )); - - $properties['UserSettings.getOSFamily'] = array_merge($basicUserSettingsProperties, array( - 'translations' => array('label' => Piwik_Translate('UserSettings_OperatingSystemFamily')), - 'title' => Piwik_Translate('UserSettings_OperatingSystemFamily'), - 'relatedReports' => $osRelatedReports - )); - - $properties['UserSettings.getBrowserVersion'] = array_merge($basicUserSettingsProperties, array( - 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnBrowserVersion')), - 'graph_limit' => 7, - 'title' => Piwik_Translate('UserSettings_ColumnBrowserVersion'), - 'relatedReports' => $browserRelatedReports - )); - - $properties['UserSettings.getBrowser'] = array_merge($basicUserSettingsProperties, array( - 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnBrowser')), - 'graph_limit' => 7, - 'title' => Piwik_Translate('UserSettings_Browsers'), - 'relatedReports' => $browserRelatedReports - )); - - $properties['UserSettings.getBrowserType'] = array_merge($basicUserSettingsProperties, array( - 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnBrowserFamily')), - 'show_offset_information' => false, - 'show_pagination_control' => false, - 'default_view_type' => 'graphPie', - )); - - $properties['UserSettings.getWideScreen'] = array_merge($basicUserSettingsProperties, array( - 'translations' => array('label' => Piwik_Translate('UserSettings_ColumnTypeOfScreen')), - 'show_offset_information' => false, - 'show_pagination_control' => false, - 'title' => Piwik_Translate('UserSettings_ColumnTypeOfScreen'), - 'relatedReports' => $wideScreenDeviceTypeRelatedReports - )); - - $properties['UserSettings.getMobileVsDesktop'] = array_merge($basicUserSettingsProperties, array( - 'translations' => array('label' => Piwik_Translate('UserSettings_MobileVsDesktop')), - 'title' => Piwik_Translate('UserSettings_MobileVsDesktop'), - 'relatedReports' => $wideScreenDeviceTypeRelatedReports - )); - - $properties['UserSettings.getPlugin'] = array_merge($basicUserSettingsProperties, array( - 'translations' => array( - 'label' => Piwik_Translate('UserSettings_ColumnPlugin'), - 'nb_visits_percentage' => - str_replace(' ', ' ', Piwik_Translate('General_ColumnPercentageVisits')) - ), - 'show_offset_information' => false, - 'show_pagination_control' => false, - 'show_all_views_icons' => false, - 'show_table_all_columns' => false, - 'columns_to_display' => array('label', 'nb_visits_percentage', 'nb_visits'), - 'filter_sort_column' => 'nb_visits_percentage', - 'filter_sort_order' => 'desc', - 'filter_limit' => 10, - 'show_footer_message' => Piwik_Translate('UserSettings_PluginDetectionDoesNotWorkInIE'), - )); - - $properties['UserSettings.getLanguage'] = array( - 'translations' => array('label' => Piwik_Translate('General_Language')), - 'filter_sort_column' => 'nb_visits', - 'filter_sort_order' => 'desc', + private function getBasicUserSettingsDisplayProperties() + { + return array( 'show_search' => false, - 'filter_limit' => false, - 'columns_to_display' => array('label', 'nb_visits'), 'show_exclude_low_population' => false, + 'filter_limit' => 5, + 'visualization_properties' => array( + 'jqplot_graph' => array( + 'max_graph_elements' => 5 + ) + ) ); } @@ -387,4 +451,4 @@ class UserSettings extends \Piwik\Plugin $archiving->archivePeriod(); } } -} +}
\ No newline at end of file diff --git a/plugins/UsersManager/API.php b/plugins/UsersManager/API.php index a960d84762..1649cdaca7 100644 --- a/plugins/UsersManager/API.php +++ b/plugins/UsersManager/API.php @@ -204,7 +204,7 @@ class API * If a user doesn't have any access to the $idSite ('noaccess'), * the user will not be in the returned array. * - * @param int $idSite Website ID + * @param int $idSite website ID * * @return array The returned array has the format * array( diff --git a/plugins/VisitFrequency/API.php b/plugins/VisitFrequency/API.php index f8f433f581..9d10395ba5 100644 --- a/plugins/VisitFrequency/API.php +++ b/plugins/VisitFrequency/API.php @@ -34,6 +34,14 @@ class API return self::$instance; } + /** + * @param int $idSite + * @param string $period + * @param string $date + * @param bool|string $segment + * @param bool|array $columns + * @return mixed + */ public function get($idSite, $period, $date, $segment = false, $columns = false) { $segment = $this->appendReturningVisitorSegment($segment); diff --git a/plugins/VisitTime/VisitTime.php b/plugins/VisitTime/VisitTime.php index 2cd34adc66..8e047803da 100644 --- a/plugins/VisitTime/VisitTime.php +++ b/plugins/VisitTime/VisitTime.php @@ -133,35 +133,45 @@ class VisitTime extends \Piwik\Plugin ); $properties['VisitTime.getVisitInformationPerServerTime'] = array_merge($commonProperties, array( - 'filter_limit' => 24, - 'graph_limit' => null, - 'show_goals' => true, - 'translations' => array('label' => Piwik_Translate('VisitTime_ColumnServerTime')), - - // custom parameter - 'hideFutureHoursWhenToday' => 1, - )); - + 'filter_limit' => 24, + 'show_goals' => true, + 'translations' => array('label' => Piwik_Translate('VisitTime_ColumnServerTime')), + 'request_parameters_to_modify' => array('hideFutureHoursWhenToday' => 1), + 'visualization_properties' => array( + 'jqplot_graph' => array( + 'max_graph_elements' => false, + ) + ) + )); + $properties['VisitTime.getVisitInformationPerLocalTime'] = array_merge($commonProperties, array( - 'filter_limit' => 24, - 'graph_limit' => null, - 'title' => Piwik_Translate('VisitTime_ColumnLocalTime'), - 'translations' => array('label' => Piwik_Translate('VisitTime_LocalTime')), - )); - + 'filter_limit' => 24, + 'title' => Piwik_Translate('VisitTime_ColumnLocalTime'), + 'translations' => array('label' => Piwik_Translate('VisitTime_LocalTime')), + 'visualization_properties' => array( + 'jqplot_graph' => array( + 'max_graph_elements' => false, + ) + ) + )); + $properties['VisitTime.getByDayOfWeek'] = array_merge($commonProperties, array( - 'filter_limit' => 7, - 'graph_limit' => null, - 'enable_sort' => false, - 'show_all_ticks' => true, - 'show_footer_message' => - Piwik_Translate('General_ReportGeneratedFrom', self::getDateRangeForFooterMessage()), - 'translations' => array('label' => Piwik_Translate('VisitTime_DayOfWeek')), - )); + 'filter_limit' => 7, + 'enable_sort' => false, + 'show_footer_message' => + Piwik_Translate('General_ReportGeneratedFrom', self::getDateRangeForFooterMessage()), + 'translations' => array('label' => Piwik_Translate('VisitTime_DayOfWeek')), + 'visualization_properties' => array( + 'jqplot_graph' => array( + 'show_all_ticks' => true, + 'max_graph_elements' => false, + ) + ) + )); // add the visits by day of week as a related report, if the current period is not 'day' if (Common::getRequestVar('period', 'day') != 'day') { - $properties['VisitTime.getVisitInformationPerLocalTime']['relatedReports'] = array( + $properties['VisitTime.getVisitInformationPerLocalTime']['related_reports'] = array( 'VisitTime.getByDayOfWeek' => Piwik_Translate('VisitTime_VisitsByDayOfWeek') ); } @@ -207,4 +217,4 @@ class VisitTime extends \Piwik\Plugin } return $dateRange; } -} +}
\ No newline at end of file diff --git a/plugins/VisitorInterest/VisitorInterest.php b/plugins/VisitorInterest/VisitorInterest.php index a60118961d..0692649e33 100644 --- a/plugins/VisitorInterest/VisitorInterest.php +++ b/plugins/VisitorInterest/VisitorInterest.php @@ -164,34 +164,42 @@ class VisitorInterest extends \Piwik\Plugin private function getDisplayPropertiesForGetNumberOfVisitsPerVisitDuration() { return array( - 'default_view_type' => 'cloud', - 'filter_sort_column' => 'label', - 'filter_sort_order' => 'asc', - 'translations' => array('label' => Piwik_Translate('VisitorInterest_ColumnVisitDuration')), - 'graph_limit' => 10, - 'enable_sort' => false, + 'default_view_type' => 'cloud', + 'filter_sort_column' => 'label', + 'filter_sort_order' => 'asc', + 'translations' => array('label' => Piwik_Translate('VisitorInterest_ColumnVisitDuration')), + 'enable_sort' => false, 'show_exclude_low_population' => false, - 'show_offset_information' => false, - 'show_pagination_control' => false, - 'show_search' => false, - 'show_table_all_columns' => false, + 'show_offset_information' => false, + 'show_pagination_control' => false, + 'show_search' => false, + 'show_table_all_columns' => false, + 'visualization_properties' => array( + 'jqplot_graph' => array( + 'max_graph_elements' => 10 + ) + ) ); } private function getDisplayPropertiesForGetNumberOfVisitsPerPage() { return array( - 'default_view_type' => 'cloud', - 'filter_sort_column' => 'label', - 'filter_sort_order' => 'asc', - 'translations' => array('label' => Piwik_Translate('VisitorInterest_ColumnPagesPerVisit')), - 'graph_limit' => 10, - 'enable_sort' => false, + 'default_view_type' => 'cloud', + 'filter_sort_column' => 'label', + 'filter_sort_order' => 'asc', + 'translations' => array('label' => Piwik_Translate('VisitorInterest_ColumnPagesPerVisit')), + 'enable_sort' => false, 'show_exclude_low_population' => false, - 'show_offset_information' => false, - 'show_pagination_control' => false, - 'show_search' => false, - 'show_table_all_columns' => false, + 'show_offset_information' => false, + 'show_pagination_control' => false, + 'show_search' => false, + 'show_table_all_columns' => false, + 'visualization_properties' => array( + 'jqplot_graph' => array( + 'max_graph_elements' => 10 + ) + ) ); } diff --git a/plugins/Widgetize/Widgetize.php b/plugins/Widgetize/Widgetize.php index 6464807d8c..b47fdf9e21 100644 --- a/plugins/Widgetize/Widgetize.php +++ b/plugins/Widgetize/Widgetize.php @@ -43,7 +43,7 @@ class Widgetize extends \Piwik\Plugin $jsFiles[] = "libs/jquery/jquery.truncate.js"; $jsFiles[] = "libs/jquery/jquery.scrollTo.js"; $jsFiles[] = "plugins/Zeitgeist/javascripts/piwikHelper.js"; - $jsFiles[] = "plugins/CoreHome/javascripts/datatable.js"; + $jsFiles[] = "plugins/CoreHome/javascripts/dataTable.js"; $jsFiles[] = "plugins/Dashboard/javascripts/widgetMenu.js"; $jsFiles[] = "plugins/Widgetize/javascripts/widgetize.js"; } diff --git a/plugins/Widgetize/javascripts/widgetize.js b/plugins/Widgetize/javascripts/widgetize.js index fb65dc7d02..a50dd34630 100644 --- a/plugins/Widgetize/javascripts/widgetize.js +++ b/plugins/Widgetize/javascripts/widgetize.js @@ -10,7 +10,7 @@ function widgetize() { this.getInputFormWithHtml = function (inputId, htmlEmbed) { return '<input class="formEmbedCode" id="' + inputId + '" value="' + htmlEmbed.replace(/"/g, '"') + '" onclick="javascript:document.getElementById(\'' + inputId + '\').focus();document.getElementById(\'' + inputId + '\').select();" readonly="true" type="text" />'; - } + }; this.getEmbedUrl = function (parameters, exportFormat) { var copyParameters = {}; @@ -31,11 +31,11 @@ function widgetize() { "&date=" + broadcast.getValueFromUrl('date') + "&disableLink=1&widget=1"; return sourceUrl; - } + }; this.htmlentities = function (s) { return s.replace(/[<>&]/g, function (m) { return "&" + m.charCodeAt(0) + ";"; }); - } + }; this.callbackAddExportButtonsUnderWidget = function (widgetUniqueId, loadedWidgetElement) { var widget = widgetsHelper.getWidgetObjectFromUniqueId(widgetUniqueId); diff --git a/plugins/Zeitgeist/javascripts/ajaxHelper.js b/plugins/Zeitgeist/javascripts/ajaxHelper.js index 02711b6945..2a50ec2abc 100644 --- a/plugins/Zeitgeist/javascripts/ajaxHelper.js +++ b/plugins/Zeitgeist/javascripts/ajaxHelper.js @@ -10,7 +10,7 @@ * * @type {Array} array holding XhrRequests with automatic cleanup */ -var globalAjaxQueue = new Array(); +var globalAjaxQueue = []; /** * Extend Array.push with automatic cleanup for finished requests diff --git a/plugins/Zeitgeist/stylesheets/base.css b/plugins/Zeitgeist/stylesheets/base.css index 959c4065eb..3eea5ab03a 100644 --- a/plugins/Zeitgeist/stylesheets/base.css +++ b/plugins/Zeitgeist/stylesheets/base.css @@ -1,7 +1,7 @@ /* TO GENERATE: lessc plugins/Zeitgeist/stylesheets/base.less plugins/Zeitgeist/stylesheets/base.css */ /* base.less is a standalone Less file */ /* base.css is automatically generated. DO NOT MODIFY */ -/* Genreral styles */ +/* General styles */ /* reset style */ html, body, diff --git a/plugins/Zeitgeist/stylesheets/base.less b/plugins/Zeitgeist/stylesheets/base.less index cce7c66822..f4afcc6220 100644 --- a/plugins/Zeitgeist/stylesheets/base.less +++ b/plugins/Zeitgeist/stylesheets/base.less @@ -27,11 +27,5 @@ @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/_jqueryUI.less b/plugins/Zeitgeist/stylesheets/general/_jqueryUI.less index bca00bf69d..ea0820c28b 100644 --- a/plugins/Zeitgeist/stylesheets/general/_jqueryUI.less +++ b/plugins/Zeitgeist/stylesheets/general/_jqueryUI.less @@ -72,7 +72,7 @@ div.ui-state-highlight { } .ui-datepicker-header { - background: #847b6d url(../images/dashboard_h_bg_hover.png) repeat-x 0 0 !important; + background: #847b6d url(plugins/Zeitgeist/images/dashboard_h_bg_hover.png) repeat-x 0 0 !important; color: #fff !important; border-radius: 0 !important; } @@ -82,11 +82,11 @@ div.ui-state-highlight { } .ui-datepicker-header .ui-icon-circle-triangle-w { - background: url(../images/datepicker_arr_l.png) no-repeat 5px 4px !important; + background: url(plugins/Zeitgeist/images/datepicker_arr_l.png) no-repeat 5px 4px !important; } .ui-datepicker-header .ui-icon-circle-triangle-e { - background: url(../images/datepicker_arr_r.png) no-repeat 6px 4px !important; + background: url(plugins/Zeitgeist/images/datepicker_arr_r.png) no-repeat 6px 4px !important; } .ui-datepicker .ui-datepicker-next-hover, diff --git a/plugins/Zeitgeist/stylesheets/general/_misc.less b/plugins/Zeitgeist/stylesheets/general/_misc.less index 38ef9f463f..de419973f1 100644 --- a/plugins/Zeitgeist/stylesheets/general/_misc.less +++ b/plugins/Zeitgeist/stylesheets/general/_misc.less @@ -4,4 +4,38 @@ .exception-backtrace { color: #888; +} + +.section-toggler-link { + font-size: .8em; + font-style: italic; + text-decoration: none; +} + +.section-toggler-link:hover { + text-decoration: underline; +} + +.metricEvolution { + display: inline-block; + font-size: 9pt; + opacity: 0.75; +} + +.metricEvolution > .positive-evolution { + color: green; +} + +.metricEvolution > .negative-evolution { + color: #e02a3b; +} + +.reportsByDimensionView > .entityList { + float: left; + width: 220px; + min-height: 450px; +} + +.dimensionCategory { + margin-top: 10px; }
\ No newline at end of file diff --git a/plugins/Zeitgeist/stylesheets/general/_utils.less b/plugins/Zeitgeist/stylesheets/general/_utils.less index 0077685734..cd7faddea2 100644 --- a/plugins/Zeitgeist/stylesheets/general/_utils.less +++ b/plugins/Zeitgeist/stylesheets/general/_utils.less @@ -27,38 +27,4 @@ html.old-ie .ie-hide { margin: auto; text-align: center; padding-bottom: 10px; -} - -.section-toggler-link { - font-size: .8em; - font-style: italic; - text-decoration: none; -} - -.section-toggler-link:hover { - text-decoration: underline; -} - -.metricEvolution { - display: inline-block; - font-size: 9pt; - opacity: 0.75; -} - -.metricEvolution > .positive-evolution { - color: green; -} - -.metricEvolution > .negative-evolution { - color: #e02a3b; -} - -.reportsByDimensionView > .entityList { - float: left; - width: 220px; - min-height: 450px; -} - -.dimensionCategory { - margin-top: 10px; }
\ No newline at end of file diff --git a/plugins/Zeitgeist/stylesheets/ui/_headerMessage.less b/plugins/Zeitgeist/stylesheets/ui/_headerMessage.less index 779e391e70..7941861a90 100644 --- a/plugins/Zeitgeist/stylesheets/ui/_headerMessage.less +++ b/plugins/Zeitgeist/stylesheets/ui/_headerMessage.less @@ -13,6 +13,12 @@ border-radius: 4px; } +@media all and (max-width: 949px) { + #header_message { + display: none; + } +} + #header_message:hover, #header_message.active { width: auto; diff --git a/plugins/Zeitgeist/stylesheets/ui/_languageSelect.less b/plugins/Zeitgeist/stylesheets/ui/_languageSelect.less index b0eafb2707..cbe890246e 100644 --- a/plugins/Zeitgeist/stylesheets/ui/_languageSelect.less +++ b/plugins/Zeitgeist/stylesheets/ui/_languageSelect.less @@ -3,11 +3,8 @@ overflow-y: auto; overflow-x: hidden; padding: 0 !important; - position: absolute; - z-index: 9999; background:#FFF; border: 1px solid #1F447F!important; - position: relative; } #languageSelection > form { @@ -20,7 +17,8 @@ #languageSelection .ui-autocomplete-input:after { display: inline; - content: " \25BC" + content: " \25BC"; + font-size: 0.9em; } #languageSelection .ui-autocomplete-input { text-decoration: underline; @@ -30,12 +28,12 @@ text-decoration: underline; } -#languageSelect a{ +#languageSelect a { text-decoration:none!important; padding: 1px 25px 1px 3px!important; } -#languageSelect a:hover{ +#languageSelect a:hover { background:#176999!important; color:#FFF!important; }
\ No newline at end of file diff --git a/plugins/Zeitgeist/stylesheets/ui/_periodSelect.less b/plugins/Zeitgeist/stylesheets/ui/_periodSelect.less index 30ff58d2d0..3a87f4eb60 100644 --- a/plugins/Zeitgeist/stylesheets/ui/_periodSelect.less +++ b/plugins/Zeitgeist/stylesheets/ui/_periodSelect.less @@ -51,9 +51,11 @@ #periodMore { padding: 6px 0 0 0; display: none; + overflow: hidden; } -#periodString .period-date, #periodString .period-range { +#periodString .period-date, +#periodString .period-range { float: left; padding: 0 16px 0 0; } diff --git a/plugins/Zeitgeist/stylesheets/ui/_siteSelect.less b/plugins/Zeitgeist/stylesheets/ui/_siteSelect.less index 474c43788b..e3c3ca4ff4 100644 --- a/plugins/Zeitgeist/stylesheets/ui/_siteSelect.less +++ b/plugins/Zeitgeist/stylesheets/ui/_siteSelect.less @@ -5,6 +5,7 @@ position: absolute; font-size: 12px; display: inline-block; + max-height: 30px; /* Hack to not push the dashboard widget bellow */ } .top_bar_sites_selector { @@ -40,17 +41,17 @@ } .sites_autocomplete .custom_select_main_link { - padding: 0 20px 0 4px; - display: block; - text-decoration: none; - background: url(plugins/Zeitgeist/images/sort_subtable_desc.png) no-repeat right 0; -} - -.sites_autocomplete .custom_select_main_link.noselect { padding: 0 8px; display: block; text-decoration: none; background: none; + cursor: default; +} + +.sites_autocomplete--dropdown .custom_select_main_link { + padding: 0 20px 0 4px; + background: url(plugins/Zeitgeist/images/sort_subtable_desc.png) no-repeat right 0; + cursor: pointer; } .sites_autocomplete .custom_select_loading { diff --git a/plugins/Zeitgeist/templates/_jsGlobalVariables.twig b/plugins/Zeitgeist/templates/_jsGlobalVariables.twig index 0ec9e5478d..fc60d946f2 100644 --- a/plugins/Zeitgeist/templates/_jsGlobalVariables.twig +++ b/plugins/Zeitgeist/templates/_jsGlobalVariables.twig @@ -34,4 +34,3 @@ piwik.config.action_url_category_delimiter = "{{ config_action_url_category_delimiter }}"; {% endif %} </script> -<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=IE8"/> diff --git a/plugins/Zeitgeist/templates/_sparklineFooter.twig b/plugins/Zeitgeist/templates/_sparklineFooter.twig index b8b864d75c..60664aa216 100644 --- a/plugins/Zeitgeist/templates/_sparklineFooter.twig +++ b/plugins/Zeitgeist/templates/_sparklineFooter.twig @@ -1,5 +1,5 @@ <script type="text/javascript"> - $(document).ready(function () { + $(function () { initializeSparklines(); }); </script> diff --git a/plugins/Zeitgeist/templates/admin.twig b/plugins/Zeitgeist/templates/admin.twig index f9daab8a91..ef0fca6029 100644 --- a/plugins/Zeitgeist/templates/admin.twig +++ b/plugins/Zeitgeist/templates/admin.twig @@ -20,6 +20,7 @@ {% endblock %} </head> <body> + {% set isAdminLayout = true %} {% include "_iframeBuster.twig" %} {% include "@CoreHome/_javaScriptDisabled.twig" %} diff --git a/plugins/Zeitgeist/templates/genericForm.twig b/plugins/Zeitgeist/templates/genericForm.twig index 1c509a9ae5..e506f190aa 100644 --- a/plugins/Zeitgeist/templates/genericForm.twig +++ b/plugins/Zeitgeist/templates/genericForm.twig @@ -4,7 +4,7 @@ <strong>{{ 'Installation_PleaseFixTheFollowingErrors'|translate }}:</strong> <ul> {% for data in form_data.errors %} - <li>{{ data }}</li> + <li>{{ data|raw }}</li> {% endfor %} </ul> </div> diff --git a/tests/PHPUnit/Integration/FlattenReportsTest.php b/tests/PHPUnit/Integration/FlattenReportsTest.php index 48ecdad576..19d9ed1414 100644 --- a/tests/PHPUnit/Integration/FlattenReportsTest.php +++ b/tests/PHPUnit/Integration/FlattenReportsTest.php @@ -88,6 +88,14 @@ class Test_Piwik_Integration_FlattenReports extends IntegrationTestCase 'testSuffix' => '_expandedSubtable', 'otherRequestParameters' => array('expanded' => '1'))); + // test expanded=1 & depth=1 + $return[] = array('Actions.getPageUrls', array('idSite' => $idSite, + 'date' => $dateTime, + 'periods' => array('week'), + 'testSuffix' => '_expandedWithDepth', + 'otherRequestParameters' => array('expanded' => '1', + 'depth' => '1'))); + // test flat=1 w/ filter_pattern_recursive $return[] = array('Actions.getPageUrls', array('idSite' => $idSite, 'date' => $dateTime, diff --git a/tests/PHPUnit/Integration/expected/test_FlattenReports_expandedWithDepth__Actions.getPageUrls_week.xml b/tests/PHPUnit/Integration/expected/test_FlattenReports_expandedWithDepth__Actions.getPageUrls_week.xml new file mode 100644 index 0000000000..3f3d4a7509 --- /dev/null +++ b/tests/PHPUnit/Integration/expected/test_FlattenReports_expandedWithDepth__Actions.getPageUrls_week.xml @@ -0,0 +1,155 @@ +<?xml version="1.0" encoding="utf-8" ?> +<result> + <row> + <label>dir1</label> + <nb_visits>6</nb_visits> + <nb_hits>6</nb_hits> + <sum_time_spent>0</sum_time_spent> + <nb_hits_with_time_generation>6</nb_hits_with_time_generation> + <min_time_generation>0.1</min_time_generation> + <max_time_generation>0.6</max_time_generation> + <entry_nb_visits>2</entry_nb_visits> + <entry_nb_actions>6</entry_nb_actions> + <entry_sum_visit_length>2</entry_sum_visit_length> + <entry_bounce_count>0</entry_bounce_count> + <exit_nb_visits>2</exit_nb_visits> + <avg_time_on_page>0</avg_time_on_page> + <bounce_rate>0%</bounce_rate> + <exit_rate>33%</exit_rate> + <avg_time_generation>0.3</avg_time_generation> + <subtable> + <row> + <label>sub</label> + <nb_visits>6</nb_visits> + <nb_hits>6</nb_hits> + <sum_time_spent>0</sum_time_spent> + <nb_hits_with_time_generation>6</nb_hits_with_time_generation> + <min_time_generation>0.1</min_time_generation> + <max_time_generation>0.6</max_time_generation> + <entry_nb_visits>2</entry_nb_visits> + <entry_nb_actions>6</entry_nb_actions> + <entry_sum_visit_length>2</entry_sum_visit_length> + <entry_bounce_count>0</entry_bounce_count> + <exit_nb_visits>2</exit_nb_visits> + <avg_time_on_page>0</avg_time_on_page> + <bounce_rate>0%</bounce_rate> + <exit_rate>33%</exit_rate> + <avg_time_generation>0.3</avg_time_generation> + </row> + </subtable> + </row> + <row> + <label>dir2</label> + <nb_visits>6</nb_visits> + <nb_hits>6</nb_hits> + <sum_time_spent>0</sum_time_spent> + <nb_hits_with_time_generation>6</nb_hits_with_time_generation> + <min_time_generation>0.2</min_time_generation> + <max_time_generation>1.2</max_time_generation> + <entry_nb_visits>2</entry_nb_visits> + <entry_nb_actions>6</entry_nb_actions> + <entry_sum_visit_length>2</entry_sum_visit_length> + <entry_bounce_count>0</entry_bounce_count> + <exit_nb_visits>2</exit_nb_visits> + <avg_time_on_page>0</avg_time_on_page> + <bounce_rate>0%</bounce_rate> + <exit_rate>33%</exit_rate> + <avg_time_generation>0.6</avg_time_generation> + <subtable> + <row> + <label>sub</label> + <nb_visits>6</nb_visits> + <nb_hits>6</nb_hits> + <sum_time_spent>0</sum_time_spent> + <nb_hits_with_time_generation>6</nb_hits_with_time_generation> + <min_time_generation>0.2</min_time_generation> + <max_time_generation>1.2</max_time_generation> + <entry_nb_visits>2</entry_nb_visits> + <entry_nb_actions>6</entry_nb_actions> + <entry_sum_visit_length>2</entry_sum_visit_length> + <entry_bounce_count>0</entry_bounce_count> + <exit_nb_visits>2</exit_nb_visits> + <avg_time_on_page>0</avg_time_on_page> + <bounce_rate>0%</bounce_rate> + <exit_rate>33%</exit_rate> + <avg_time_generation>0.6</avg_time_generation> + </row> + </subtable> + </row> + <row> + <label>dir3</label> + <nb_visits>6</nb_visits> + <nb_hits>6</nb_hits> + <sum_time_spent>0</sum_time_spent> + <nb_hits_with_time_generation>6</nb_hits_with_time_generation> + <min_time_generation>0.3</min_time_generation> + <max_time_generation>1.8</max_time_generation> + <entry_nb_visits>2</entry_nb_visits> + <entry_nb_actions>6</entry_nb_actions> + <entry_sum_visit_length>2</entry_sum_visit_length> + <entry_bounce_count>0</entry_bounce_count> + <exit_nb_visits>2</exit_nb_visits> + <avg_time_on_page>0</avg_time_on_page> + <bounce_rate>0%</bounce_rate> + <exit_rate>33%</exit_rate> + <avg_time_generation>0.9</avg_time_generation> + <subtable> + <row> + <label>sub</label> + <nb_visits>6</nb_visits> + <nb_hits>6</nb_hits> + <sum_time_spent>0</sum_time_spent> + <nb_hits_with_time_generation>6</nb_hits_with_time_generation> + <min_time_generation>0.3</min_time_generation> + <max_time_generation>1.8</max_time_generation> + <entry_nb_visits>2</entry_nb_visits> + <entry_nb_actions>6</entry_nb_actions> + <entry_sum_visit_length>2</entry_sum_visit_length> + <entry_bounce_count>0</entry_bounce_count> + <exit_nb_visits>2</exit_nb_visits> + <avg_time_on_page>0</avg_time_on_page> + <bounce_rate>0%</bounce_rate> + <exit_rate>33%</exit_rate> + <avg_time_generation>0.9</avg_time_generation> + </row> + </subtable> + </row> + <row> + <label>sub</label> + <nb_visits>1</nb_visits> + <nb_hits>1</nb_hits> + <sum_time_spent>0</sum_time_spent> + <nb_hits_with_time_generation>0</nb_hits_with_time_generation> + <min_time_generation /> + <max_time_generation>0</max_time_generation> + <entry_nb_visits>1</entry_nb_visits> + <entry_nb_actions>1</entry_nb_actions> + <entry_sum_visit_length>0</entry_sum_visit_length> + <entry_bounce_count>1</entry_bounce_count> + <exit_nb_visits>1</exit_nb_visits> + <avg_time_on_page>0</avg_time_on_page> + <bounce_rate>100%</bounce_rate> + <exit_rate>100%</exit_rate> + <avg_time_generation>0</avg_time_generation> + <subtable> + <row> + <label>dir</label> + <nb_visits>1</nb_visits> + <nb_hits>1</nb_hits> + <sum_time_spent>0</sum_time_spent> + <nb_hits_with_time_generation>0</nb_hits_with_time_generation> + <min_time_generation /> + <max_time_generation>0</max_time_generation> + <entry_nb_visits>1</entry_nb_visits> + <entry_nb_actions>1</entry_nb_actions> + <entry_sum_visit_length>0</entry_sum_visit_length> + <entry_bounce_count>1</entry_bounce_count> + <exit_nb_visits>1</exit_nb_visits> + <avg_time_on_page>0</avg_time_on_page> + <bounce_rate>100%</bounce_rate> + <exit_rate>100%</exit_rate> + <avg_time_generation>0</avg_time_generation> + </row> + </subtable> + </row> +</result>
\ No newline at end of file diff --git a/tests/PHPUnit/IntegrationTestCase.php b/tests/PHPUnit/IntegrationTestCase.php index 59c13c82b9..cfcf72c581 100755 --- a/tests/PHPUnit/IntegrationTestCase.php +++ b/tests/PHPUnit/IntegrationTestCase.php @@ -244,9 +244,6 @@ abstract class IntegrationTestCase extends PHPUnit_Framework_TestCase $_GET = $_REQUEST = array(); Translate::getInstance()->unloadEnglishTranslation(); - - // re-enable tag cloud shuffling - Cloud::$debugDisableShuffle = true; } public function setUp() diff --git a/tests/PHPUnit/TestingEnvironment.php b/tests/PHPUnit/TestingEnvironment.php index 6e015ab681..99d2822ef6 100644 --- a/tests/PHPUnit/TestingEnvironment.php +++ b/tests/PHPUnit/TestingEnvironment.php @@ -20,5 +20,8 @@ class Piwik_TestingEnvironment Piwik_AddAction('Config.createConfigSingleton', function($config) { $config->setTestEnvironment(); }); + Piwik_AddAction('FrontController.dispatch', function() { + \Piwik\Plugins\CoreVisualizations\Visualizations\Cloud::$debugDisableShuffle = true; + }); } }
\ No newline at end of file diff --git a/tests/PHPUnit/UI/UIIntegrationTest.php b/tests/PHPUnit/UI/UIIntegrationTest.php index d8399976ba..7d63301b8e 100644 --- a/tests/PHPUnit/UI/UIIntegrationTest.php +++ b/tests/PHPUnit/UI/UIIntegrationTest.php @@ -22,6 +22,7 @@ use Piwik\Plugins\VisitsSummary\API; class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase { const IMAGE_TYPE = 'png'; + const CUTYCAPT_DELAY = 1000; public static $fixture = null; // initialized below class definition private static $useXvfb = false; @@ -90,7 +91,7 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase $urlBase = 'module=CoreHome&action=index&' . $generalParams; $widgetizeParams = "module=Widgetize&action=iframe"; $segment = urlencode("browserCode==FF"); - + return array( // dashboard array('dashboard1', "?$urlBase#$generalParams&module=Dashboard&action=embeddedIndex&idDashboard=1"), @@ -142,6 +143,15 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase array("widgetize_goals_table", "?$widgetizeParams&$generalParams&moduleToWidgetize=UserCountry&actionToWidgetize=getCountry" . "&viewDataTable=tableGoals"), + array("widgetize_goals_table_ecommerce", + "?$widgetizeParams&$generalParams&moduleToWidgetize=UserCountry&actionToWidgetize=getCountry" + . "&viewDataTable=tableGoals&idGoal=ecommerceOrder"), + array("widgetize_goals_table_single", + "?$widgetizeParams&$generalParams&moduleToWidgetize=UserCountry&actionToWidgetize=getCountry" + . "&viewDataTable=tableGoals&idGoal=1"), + array("widgetize_goals_table_full", + "?$widgetizeParams&$generalParams&moduleToWidgetize=UserCountry&actionToWidgetize=getCountry" + . "&viewDataTable=tableGoals&idGoal=0"), array("widgetize_all_columns_table", "?$widgetizeParams&$generalParams&moduleToWidgetize=UserCountry&actionToWidgetize=getCountry" . "&viewDataTable=tableAllColumns"), @@ -195,14 +205,14 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase $this->runCutyCapt($urlQuery, $processedScreenshotPath); // compare processed w/ expected - $this->compareScreenshot($name, $expectedScreenshotPath, $processedScreenshotPath); + $this->compareScreenshot($name, $expectedScreenshotPath, $processedScreenshotPath, $urlQuery); } private function runCutyCapt($urlQuery, $processedPath) { $url = self::getProxyUrl() . $urlQuery; - $cmd = "cutycapt --url=\"$url\" --out=\"$processedPath\" --min-width=1366 --delay=1000 2>&1"; + $cmd = "cutycapt --url=\"$url\" --out=\"$processedPath\" --min-width=1366 --delay=".self::CUTYCAPT_DELAY." 2>&1"; if (self::$useXvfb) { $cmd = 'xvfb-run --server-args="-screen 0, 1024x768x24" ' . $cmd; } @@ -216,7 +226,7 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase return $output; } - private function compareScreenshot($name, $expectedPath, $processedPath) + private function compareScreenshot($name, $expectedPath, $processedPath, $urlQuery) { $processed = file_get_contents($processedPath); @@ -225,6 +235,9 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase } $expected = file_get_contents($expectedPath); + if ($expected != $processed) { + echo "\nFail: '$processedPath' for '$urlQuery'\n"; + } $this->assertTrue($expected == $processed, "screenshot compare failed for '$processedPath'"); } @@ -253,4 +266,3 @@ class Test_Piwik_Integration_UIIntegrationTest extends IntegrationTestCase } Test_Piwik_Integration_UIIntegrationTest::$fixture = new Test_Piwik_Fixture_ManySitesImportedLogsWithXssAttempts(); - diff --git a/tests/PHPUnit/proxy/index.php b/tests/PHPUnit/proxy/index.php index 12f5e0b2a9..14c0d7593d 100644 --- a/tests/PHPUnit/proxy/index.php +++ b/tests/PHPUnit/proxy/index.php @@ -6,7 +6,6 @@ // make sure the test environment is loaded use Piwik\Tracker\Cache; -use Piwik\Visualization\Cloud; // Wrapping the request inside ob_start() calls to ensure that the Test // calling us waits for the full request to process before unblocking @@ -23,8 +22,6 @@ require_once realpath(dirname(__FILE__)) . '/../../../core/functions.php'; require_once realpath(dirname(__FILE__)) . "/../../../tests/PHPUnit/TestingEnvironment.php"; Piwik_TestingEnvironment::addHooks(); -Cloud::$debugDisableShuffle = true; - \Piwik\Tracker::setTestEnvironment(); Cache::deleteTrackerCache(); |