Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthieu Aubry <matt@piwik.org>2015-11-25 04:48:20 +0300
committerMatthieu Aubry <matt@piwik.org>2015-11-25 04:48:20 +0300
commit01137cbe80eab5c6f66cab87b053115a7454d936 (patch)
tree611cc560b99a84e868382185a674b5232e75d0e4 /plugins
parentecb4029437c42ebc7273af284b319265abdb5174 (diff)
parent1a4db22746d6031a54dde64e416cb2a186ba5fd8 (diff)
Merge pull request #9217 from piwik/9129_2
Added feature Custom Dimensions
Diffstat (limited to 'plugins')
-rw-r--r--plugins/API/API.php37
-rw-r--r--plugins/API/ProcessedReport.php10
-rw-r--r--plugins/API/RowEvolution.php14
-rw-r--r--plugins/Actions/Archiver.php8
-rw-r--r--plugins/Actions/Metrics.php12
m---------plugins/AnonymousPiwikUsageMeasurement0
-rw-r--r--plugins/CoreHome/Columns/UserId.php10
-rw-r--r--plugins/CoreHome/javascripts/broadcast.js7
-rw-r--r--plugins/CoreHome/javascripts/dataTable.js6
-rw-r--r--plugins/CoreHome/javascripts/dataTable_rowactions.js5
-rw-r--r--plugins/CoreHome/javascripts/notification.js10
-rw-r--r--plugins/CoreHome/templates/_menu.twig8
-rw-r--r--plugins/CoreHome/tests/Integration/Column/UserIdTest.php12
-rw-r--r--plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php7
-rw-r--r--plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js5
m---------plugins/CustomAlerts0
m---------plugins/CustomDimensions0
-rw-r--r--plugins/CustomVariables/CustomVariables.php2
-rw-r--r--plugins/CustomVariables/Tracker/CustomVariablesRequestProcessor.php22
-rw-r--r--plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.controller.js5
-rw-r--r--plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.directive.html4
-rw-r--r--plugins/CustomVariables/tests/UI/expected-ui-screenshots/CustomVariables_link_in_menu.pngbin5167 -> 6428 bytes
-rw-r--r--plugins/Goals/Controller.php8
-rw-r--r--plugins/Goals/Reports/Base.php2
-rw-r--r--plugins/ImageGraph/API.php13
-rw-r--r--plugins/Insights/Visualizations/Insight.php4
-rw-r--r--plugins/Live/Live.php2
-rw-r--r--plugins/Live/javascripts/rowaction.js6
-rw-r--r--plugins/Monolog/tests/System/TrackerLoggingTest.php6
-rw-r--r--plugins/Overlay/Controller.php108
-rw-r--r--plugins/Overlay/client/client.js9
-rw-r--r--plugins/Overlay/javascripts/Overlay_Helper.js8
-rw-r--r--plugins/Overlay/javascripts/Piwik_Overlay.js31
-rw-r--r--plugins/Overlay/javascripts/rowaction.js33
-rw-r--r--plugins/Overlay/stylesheets/overlay.css12
-rw-r--r--plugins/Overlay/templates/index.twig4
-rw-r--r--plugins/Overlay/templates/index_noframe.twig2
-rw-r--r--plugins/Overlay/templates/renderSidebar.twig5
-rw-r--r--plugins/Overlay/templates/startOverlaySession.twig50
-rw-r--r--plugins/SegmentEditor/SegmentEditor.php6
-rw-r--r--plugins/SegmentEditor/SegmentFormatter.php142
-rw-r--r--plugins/SegmentEditor/SegmentList.php32
-rw-r--r--plugins/SegmentEditor/SegmentSelectorControl.php5
-rw-r--r--plugins/SegmentEditor/javascripts/Segmentation.js2
-rw-r--r--plugins/SegmentEditor/lang/en.json6
-rw-r--r--plugins/SegmentEditor/templates/_segmentSelector.twig2
-rw-r--r--plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php110
-rw-r--r--plugins/SegmentEditor/tests/Integration/SegmentListTest.php74
-rw-r--r--plugins/SitesManager/API.php8
-rw-r--r--plugins/TestRunner/Commands/TestsRunUI.php2
-rw-r--r--plugins/TestRunner/Commands/TestsSetupFixture.php5
-rw-r--r--plugins/Transitions/javascripts/transitions.js59
m---------plugins/TreemapVisualization0
53 files changed, 796 insertions, 144 deletions
diff --git a/plugins/API/API.php b/plugins/API/API.php
index e5d9fbcd2a..2f609b5e8b 100644
--- a/plugins/API/API.php
+++ b/plugins/API/API.php
@@ -22,7 +22,6 @@ use Piwik\Metrics;
use Piwik\Period;
use Piwik\Period\Range;
use Piwik\Piwik;
-use Piwik\Plugin\Dimension\VisitDimension;
use Piwik\Plugins\API\DataTable\MergeDataTables;
use Piwik\Plugins\CoreAdminHome\CustomLogo;
use Piwik\Translation\Translator;
@@ -88,8 +87,9 @@ class API extends \Piwik\Plugin\API
* are not visible in the UI and not present in the API meta data. These columns are
* translated here.
* @return array
+ * @deprecated since Piwik 2.15.1
*/
- public static function getDefaultMetricTranslations()
+ public function getDefaultMetricTranslations()
{
return Metrics::getDefaultMetricTranslations();
}
@@ -102,6 +102,8 @@ class API extends \Piwik\Plugin\API
*/
public function getAvailableMeasurableTypes()
{
+ Piwik::checkUserHasSomeViewAccess();
+
$typeManager = new TypeManager();
$types = $typeManager->getAllTypes();
@@ -120,13 +122,19 @@ class API extends \Piwik\Plugin\API
public function getSegmentsMetadata($idSites = array(), $_hideImplementationData = true)
{
- $isAuthenticatedWithViewAccess = Piwik::isUserHasViewAccess($idSites) && !Piwik::isUserIsAnonymous();
+ if (empty($idSites)) {
+ Piwik::checkUserHasSomeViewAccess();
+ } else {
+ Piwik::checkUserHasViewAccess($idSites);
+ }
+
+ $isNotAnonymous = !Piwik::isUserIsAnonymous();
$segments = array();
foreach (Dimension::getAllDimensions() as $dimension) {
foreach ($dimension->getSegments() as $segment) {
if ($segment->isRequiresAtLeastViewAccess()) {
- $segment->setPermission($isAuthenticatedWithViewAccess);
+ $segment->setPermission($isNotAnonymous);
}
$segments[] = $segment->toArray();
@@ -250,6 +258,7 @@ class API extends \Piwik\Plugin\API
*
* @param bool $pathOnly If true, returns path relative to doc root. Otherwise, returns a URL.
* @return string
+ * @deprecated since Piwik 2.15.1
*/
public function getLogoUrl($pathOnly = false)
{
@@ -262,6 +271,7 @@ class API extends \Piwik\Plugin\API
*
* @param bool $pathOnly If true, returns path relative to doc root. Otherwise, returns a URL.
* @return string
+ * @deprecated since Piwik 2.15.1
*/
public function getHeaderLogoUrl($pathOnly = false)
{
@@ -300,6 +310,8 @@ class API extends \Piwik\Plugin\API
public function getMetadata($idSite, $apiModule, $apiAction, $apiParameters = array(), $language = false,
$period = false, $date = false, $hideMetricsDoc = false, $showSubtableReports = false)
{
+ Piwik::checkUserHasViewAccess($idSite);
+
if ($language) {
/** @var Translator $translator */
$translator = StaticContainer::get('Piwik\Translation\Translator');
@@ -325,6 +337,8 @@ class API extends \Piwik\Plugin\API
public function getReportMetadata($idSites = '', $period = false, $date = false, $hideMetricsDoc = false,
$showSubtableReports = false)
{
+ Piwik::checkUserHasViewAccess($idSites);
+
$reporter = new ProcessedReport();
$metadata = $reporter->getReportMetadata($idSites, $period, $date, $hideMetricsDoc, $showSubtableReports);
return $metadata;
@@ -333,11 +347,13 @@ class API extends \Piwik\Plugin\API
public function getProcessedReport($idSite, $period, $date, $apiModule, $apiAction, $segment = false,
$apiParameters = false, $idGoal = false, $language = false,
$showTimer = true, $hideMetricsDoc = false, $idSubtable = false, $showRawMetrics = false,
- $format_metrics = null)
+ $format_metrics = null, $idDimension = false)
{
+ Piwik::checkUserHasViewAccess($idSite);
+
$reporter = new ProcessedReport();
$processed = $reporter->getProcessedReport($idSite, $period, $date, $apiModule, $apiAction, $segment,
- $apiParameters, $idGoal, $language, $showTimer, $hideMetricsDoc, $idSubtable, $showRawMetrics, $format_metrics);
+ $apiParameters, $idGoal, $language, $showTimer, $hideMetricsDoc, $idSubtable, $showRawMetrics, $format_metrics, $idDimension);
return $processed;
}
@@ -347,6 +363,8 @@ class API extends \Piwik\Plugin\API
*/
public function get($idSite, $period, $date, $segment = false, $columns = false)
{
+ Piwik::checkUserHasViewAccess($idSite);
+
$columns = Piwik::getArrayFromApiParameter($columns);
// build columns map for faster checks later on
@@ -427,13 +445,16 @@ class API extends \Piwik\Plugin\API
* @param bool|int $idGoal
* @param bool|string $legendAppendMetric
* @param bool|string $labelUseAbsoluteUrl
+ * @param bool|int $idDimension
* @return array
*/
- public function getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $column = false, $language = false, $idGoal = false, $legendAppendMetric = true, $labelUseAbsoluteUrl = true)
+ public function getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $column = false, $language = false, $idGoal = false, $legendAppendMetric = true, $labelUseAbsoluteUrl = true, $idDimension = false)
{
+ Piwik::checkUserHasViewAccess($idSite);
+
$rowEvolution = new RowEvolution();
return $rowEvolution->getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label, $segment, $column,
- $language, $idGoal, $legendAppendMetric, $labelUseAbsoluteUrl);
+ $language, $idGoal, $legendAppendMetric, $labelUseAbsoluteUrl, $idDimension);
}
/**
diff --git a/plugins/API/ProcessedReport.php b/plugins/API/ProcessedReport.php
index db87cd19c7..9c6893057d 100644
--- a/plugins/API/ProcessedReport.php
+++ b/plugins/API/ProcessedReport.php
@@ -380,17 +380,25 @@ class ProcessedReport
public function getProcessedReport($idSite, $period, $date, $apiModule, $apiAction, $segment = false,
$apiParameters = false, $idGoal = false, $language = false,
$showTimer = true, $hideMetricsDoc = false, $idSubtable = false, $showRawMetrics = false,
- $formatMetrics = null)
+ $formatMetrics = null, $idDimension = false)
{
$timer = new Timer();
if (empty($apiParameters)) {
$apiParameters = array();
}
+
if (!empty($idGoal)
&& empty($apiParameters['idGoal'])
) {
$apiParameters['idGoal'] = $idGoal;
}
+
+ if (!empty($idDimension)
+ && empty($apiParameters['idDimension'])
+ ) {
+ $apiParameters['idDimension'] = (int) $idDimension;
+ }
+
// Is this report found in the Metadata available reports?
$reportMetadata = $this->getMetadata($idSite, $apiModule, $apiAction, $apiParameters, $language,
$period, $date, $hideMetricsDoc, $showSubtableReports = true);
diff --git a/plugins/API/RowEvolution.php b/plugins/API/RowEvolution.php
index c708608089..711a48316c 100644
--- a/plugins/API/RowEvolution.php
+++ b/plugins/API/RowEvolution.php
@@ -37,7 +37,7 @@ class RowEvolution
'getPageUrl'
);
- public function getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $column = false, $language = false, $idGoal = false, $legendAppendMetric = true, $labelUseAbsoluteUrl = true)
+ public function getRowEvolution($idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $column = false, $language = false, $idGoal = false, $legendAppendMetric = true, $labelUseAbsoluteUrl = true, $idDimension = false)
{
// validation of requested $period & $date
if ($period == 'range') {
@@ -52,9 +52,9 @@ class RowEvolution
$label = DataTablePostProcessor::unsanitizeLabelParameter($label);
$labels = Piwik::getArrayFromApiParameter($label);
- $metadata = $this->getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $language, $idGoal);
+ $metadata = $this->getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $language, $idGoal, $idDimension);
- $dataTable = $this->loadRowEvolutionDataFromAPI($metadata, $idSite, $period, $date, $apiModule, $apiAction, $labels, $segment, $idGoal);
+ $dataTable = $this->loadRowEvolutionDataFromAPI($metadata, $idSite, $period, $date, $apiModule, $apiAction, $labels, $segment, $idGoal, $idDimension);
if (empty($labels)) {
$labels = $this->getLabelsFromDataTable($dataTable, $labels);
@@ -249,7 +249,7 @@ class RowEvolution
* @throws Exception
* @return DataTable\Map|DataTable
*/
- private function loadRowEvolutionDataFromAPI($metadata, $idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $idGoal = false)
+ private function loadRowEvolutionDataFromAPI($metadata, $idSite, $period, $date, $apiModule, $apiAction, $label = false, $segment = false, $idGoal = false, $idDimension = false)
{
if (!is_array($label)) {
$label = array($label);
@@ -266,6 +266,7 @@ class RowEvolution
'serialize' => '0',
'segment' => $segment,
'idGoal' => $idGoal,
+ 'idDimension' => $idDimension,
// data for row evolution should NOT be limited
'filter_limit' => -1,
@@ -310,12 +311,15 @@ class RowEvolution
* @throws Exception
* @return array
*/
- private function getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $language, $idGoal = false)
+ private function getRowEvolutionMetaData($idSite, $period, $date, $apiModule, $apiAction, $language, $idGoal = false, $idDimension = false)
{
$apiParameters = array();
if (!empty($idGoal) && $idGoal > 0) {
$apiParameters = array('idGoal' => $idGoal);
}
+ if (!empty($idDimension) && $idDimension > 0) {
+ $apiParameters = array('idDimension' => (int) $idDimension);
+ }
$reportMetadata = API::getInstance()->getMetadata($idSite, $apiModule, $apiAction, $apiParameters, $language,
$period, $date, $hideMetricsDoc = false, $showSubtableReports = true);
diff --git a/plugins/Actions/Archiver.php b/plugins/Actions/Archiver.php
index 5110130b84..7610e973ef 100644
--- a/plugins/Actions/Archiver.php
+++ b/plugins/Actions/Archiver.php
@@ -149,10 +149,7 @@ class Archiver extends \Piwik\Plugin\Archiver
$select = "log_action.name,
log_action.type,
log_action.idaction,
- log_action.url_prefix,
- count(distinct log_link_visit_action.idvisit) as `" . PiwikMetrics::INDEX_NB_VISITS . "`,
- count(distinct log_link_visit_action.idvisitor) as `" . PiwikMetrics::INDEX_NB_UNIQ_VISITORS . "`,
- count(*) as `" . PiwikMetrics::INDEX_PAGE_NB_HITS . "`";
+ log_action.url_prefix";
$select = $this->addMetricsToSelect($select, $metricsConfig);
@@ -178,8 +175,7 @@ class Archiver extends \Piwik\Plugin\Archiver
$rankingQuery = new RankingQuery($rankingQueryLimit);
$rankingQuery->setOthersLabel(DataTable::LABEL_SUMMARY_ROW);
$rankingQuery->addLabelColumn(array('idaction', 'name'));
- $rankingQuery->addColumn(array('url_prefix', PiwikMetrics::INDEX_NB_UNIQ_VISITORS));
- $rankingQuery->addColumn(array(PiwikMetrics::INDEX_PAGE_NB_HITS, PiwikMetrics::INDEX_NB_VISITS), 'sum');
+ $rankingQuery->addColumn('url_prefix');
if ($this->isSiteSearchEnabled()) {
$rankingQuery->addColumn(PiwikMetrics::INDEX_SITE_SEARCH_HAS_NO_RESULT, 'min');
diff --git a/plugins/Actions/Metrics.php b/plugins/Actions/Metrics.php
index 83b1c7370a..006fd6043d 100644
--- a/plugins/Actions/Metrics.php
+++ b/plugins/Actions/Metrics.php
@@ -50,6 +50,18 @@ class Metrics
public static function getActionMetrics()
{
$metricsConfig = array(
+ PiwikMetrics::INDEX_NB_VISITS => array(
+ 'aggregation' => 'sum',
+ 'query' => "count(distinct log_link_visit_action.idvisit)"
+ ),
+ PiwikMetrics::INDEX_NB_UNIQ_VISITORS => array(
+ 'aggregation' => false,
+ 'query' => "count(distinct log_link_visit_action.idvisitor)"
+ ),
+ PiwikMetrics::INDEX_PAGE_NB_HITS => array(
+ 'aggregation' => 'sum',
+ 'query' => "count(*)"
+ ),
PiwikMetrics::INDEX_PAGE_SUM_TIME_GENERATION => array(
'aggregation' => 'sum',
'query' => "sum(
diff --git a/plugins/AnonymousPiwikUsageMeasurement b/plugins/AnonymousPiwikUsageMeasurement
-Subproject ea51cb5c1a4fe2b46efc862f5b5e7544cf02312
+Subproject 5ba37193bba2be01df462b61c724c212657c449
diff --git a/plugins/CoreHome/Columns/UserId.php b/plugins/CoreHome/Columns/UserId.php
index bbe7e44c8f..a611ca8def 100644
--- a/plugins/CoreHome/Columns/UserId.php
+++ b/plugins/CoreHome/Columns/UserId.php
@@ -11,6 +11,7 @@ namespace Piwik\Plugins\CoreHome\Columns;
use Piwik\Cache;
use Piwik\DataTable;
use Piwik\DataTable\Map;
+use Piwik\Metrics;
use Piwik\Period\Range;
use Piwik\Piwik;
use Piwik\Plugin\Dimension\VisitDimension;
@@ -124,7 +125,14 @@ class UserId extends VisitDimension
return false;
}
- $numUsers = $result->getColumn('nb_users');
+ $firstRow = $result->getFirstRow();
+ if ($firstRow instanceof DataTable\Row && $firstRow->hasColumn(Metrics::INDEX_NB_USERS)) {
+ $metric = Metrics::INDEX_NB_USERS;
+ } else {
+ $metric = 'nb_users';
+ }
+
+ $numUsers = $result->getColumn($metric);
$numUsers = array_sum($numUsers);
return !empty($numUsers);
diff --git a/plugins/CoreHome/javascripts/broadcast.js b/plugins/CoreHome/javascripts/broadcast.js
index 706a8e59d5..c0cc7d81c4 100644
--- a/plugins/CoreHome/javascripts/broadcast.js
+++ b/plugins/CoreHome/javascripts/broadcast.js
@@ -214,6 +214,10 @@ var broadcast = {
currentHashStr = broadcast.updateParamValue('idDashboard=', currentHashStr);
}
+ if (module != 'CustomDimensions') {
+ currentHashStr = broadcast.updateParamValue('idDimension=', currentHashStr);
+ }
+
if (disableHistory) {
var newLocation = window.location.href.split('#')[0] + '#?' + currentHashStr;
// window.location.replace changes the current url without pushing it on the browser's history stack
@@ -420,7 +424,8 @@ var broadcast = {
broadcast.getParamValue('action', urlAjax),
{
idGoal: broadcast.getParamValue('idGoal', urlAjax),
- idDashboard: broadcast.getParamValue('idDashboard', urlAjax)
+ idDashboard: broadcast.getParamValue('idDashboard', urlAjax),
+ idDimension: broadcast.getParamValue('idDimension', urlAjax)
}
);
});
diff --git a/plugins/CoreHome/javascripts/dataTable.js b/plugins/CoreHome/javascripts/dataTable.js
index 0561185de8..0232d91ec6 100644
--- a/plugins/CoreHome/javascripts/dataTable.js
+++ b/plugins/CoreHome/javascripts/dataTable.js
@@ -1069,6 +1069,7 @@ $.extend(DataTable.prototype, UIControl.prototype, {
var segment = self.param.segment;
var label = self.param.label;
var idGoal = self.param.idGoal;
+ var idDimension = self.param.idDimension;
var param_date = self.param.date;
var date = $(this).attr('date');
if (typeof date != 'undefined') {
@@ -1137,6 +1138,11 @@ $.extend(DataTable.prototype, UIControl.prototype, {
&& idGoal != '-1') {
str += '&idGoal=' + idGoal;
}
+ // Export Dimension specific reports
+ if (typeof idDimension != 'undefined'
+ && idDimension != '-1') {
+ str += '&idDimension=' + idDimension;
+ }
if (label) {
label = label.split(',');
diff --git a/plugins/CoreHome/javascripts/dataTable_rowactions.js b/plugins/CoreHome/javascripts/dataTable_rowactions.js
index 004e27e3b6..ab07537e2f 100644
--- a/plugins/CoreHome/javascripts/dataTable_rowactions.js
+++ b/plugins/CoreHome/javascripts/dataTable_rowactions.js
@@ -386,6 +386,11 @@ DataTable_RowActions_RowEvolution.prototype.showRowEvolution = function (apiMeth
requestParams.action = 'getRowEvolutionPopover';
requestParams.colors = JSON.stringify(piwik.getSparklineColors());
+ var idDimension = broadcast.getValueFromHash('idDimension');
+ if (idDimension) {
+ requestParams.idDimension = parseInt(idDimension, 10);
+ }
+
$.extend(requestParams, extraParams);
var ajaxRequest = new ajaxHelper();
diff --git a/plugins/CoreHome/javascripts/notification.js b/plugins/CoreHome/javascripts/notification.js
index e6c3f017f2..527c845d87 100644
--- a/plugins/CoreHome/javascripts/notification.js
+++ b/plugins/CoreHome/javascripts/notification.js
@@ -54,6 +54,16 @@
this.$node = placeNotification(template, options);
};
+ /**
+ * Removes a previously shown notification having the given notification id.
+ *
+ *
+ * @param {string} notificationId The id of a notification that was previously registered.
+ */
+ Notification.prototype.remove = function (notificationId) {
+ $('[piwik-notification][notification-id=' + notificationId + ']').remove();
+ };
+
Notification.prototype.scrollToNotification = function () {
if (this.$node) {
piwikHelper.lazyScrollTo(this.$node, 250);
diff --git a/plugins/CoreHome/templates/_menu.twig b/plugins/CoreHome/templates/_menu.twig
index 4c4643723d..baaa8ab8ca 100644
--- a/plugins/CoreHome/templates/_menu.twig
+++ b/plugins/CoreHome/templates/_menu.twig
@@ -1,6 +1,6 @@
-{% macro submenuItem(name, url, anchorlink) %}
+{% macro submenuItem(name, url, anchorlink, tooltip) %}
{% if name|slice(0,1) != '_' %}
- <li role="menuitem" title="{{ name|translate|e('html_attr') }}">
+ <li role="menuitem" title="{{ tooltip|default(name)|translate|e('html_attr') }}">
<a class="item" href="{% if anchorlink %}#{% else %}index.php?{% endif %}{{ url|urlRewriteWithParameters|slice(1) }}">
{{ name|translate }}
</a>
@@ -14,7 +14,7 @@
{% for item in group.getItems %}
<a class="item menuItem"
href='{% if anchorlink %}#?{% else %}index.php?{% endif %}{{ item.url|urlRewriteWithParameters|slice(1) }}'
- {% if item.tooltip %}title="{{ item.tooltip|e('html_attr') }}"{% endif %}>
+ title="{% if item.tooltip %}{{ item.tooltip|e('html_attr') }}{% else %}{{ item.name|e('html_attr') }}{% endif %}">
{{ item.name|translate }}
</a>
{% endfor %}
@@ -55,7 +55,7 @@
{% if urlParameters._url is defined and urlParameters._url is not iterable %}
{{ _self.groupedItem(name,urlParameters._url, anchorlink) }}
{% elseif name|slice(0,1) != '_' %}
- {{ _self.submenuItem(name,urlParameters._url, anchorlink) }}
+ {{ _self.submenuItem(name,urlParameters._url, anchorlink, urlParameters._tooltip) }}
{% endif %}
{% endfor %}
</ul>
diff --git a/plugins/CoreHome/tests/Integration/Column/UserIdTest.php b/plugins/CoreHome/tests/Integration/Column/UserIdTest.php
index 33c268afae..70715a4dc2 100644
--- a/plugins/CoreHome/tests/Integration/Column/UserIdTest.php
+++ b/plugins/CoreHome/tests/Integration/Column/UserIdTest.php
@@ -12,6 +12,7 @@ use Piwik\Access;
use Piwik\Cache;
use Piwik\DataAccess\ArchiveTableCreator;
use Piwik\Db;
+use Piwik\Metrics;
use Piwik\Plugin\Manager;
use Piwik\Plugins\CoreHome\Columns\UserId;
use Piwik\Tests\Framework\Fixture;
@@ -164,6 +165,17 @@ class UserIdTest extends IntegrationTestCase
$this->assertDataTableHasUsers($this->getDataTableWithUsers());
}
+ public function test_hasDataTableUsers_shouldBeAbleToDetectIfNbUsersMetricIdIsused()
+ {
+ $table = $this->getDataTableWithZeroUsers();
+ $table->renameColumn('nb_users', Metrics::INDEX_NB_USERS);
+ $this->assertNotDataTableHasUsers($table);
+
+ $table = $this->getDataTableWithUsers();
+ $table->renameColumn('nb_users', Metrics::INDEX_NB_USERS);
+ $this->assertDataTableHasUsers($this->getDataTableWithUsers());
+ }
+
private function getDataTableWithoutUsersColumn()
{
$tableWithoutUsers = new DataTable();
diff --git a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
index 1a41a07df3..5acf9b50be 100644
--- a/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
+++ b/plugins/CoreVisualizations/Visualizations/HtmlTable/AllColumns.php
@@ -10,6 +10,7 @@
namespace Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
use Piwik\DataTable;
+use Piwik\Metrics;
use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
use Piwik\View;
@@ -40,11 +41,13 @@ class AllColumns extends HtmlTable
$this->dataTable->filter(function (DataTable $dataTable) use ($properties) {
$columnsToDisplay = array('label', 'nb_visits');
- if (in_array('nb_uniq_visitors', $dataTable->getColumns())) {
+ $columns = $dataTable->getColumns();
+
+ if (in_array('nb_uniq_visitors', $columns)) {
$columnsToDisplay[] = 'nb_uniq_visitors';
}
- if (in_array('nb_users', $dataTable->getColumns())) {
+ if (in_array('nb_users', $columns)) {
$columnsToDisplay[] = 'nb_users';
}
diff --git a/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js b/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js
index 3b62e9197e..2fa3cee126 100644
--- a/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js
+++ b/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js
@@ -94,6 +94,7 @@
var module = broadcast.getValueFromHash('module');
var action = broadcast.getValueFromHash('action');
var idGoal = broadcast.getValueFromHash('idGoal');
+ var idDimension = broadcast.getValueFromHash('idDimension');
var idSite = broadcast.getValueFromUrl('idSite', url);
var period = broadcast.getValueFromUrl('period', url);
var date = broadcast.getValueFromUrl('date', url);
@@ -109,6 +110,10 @@
url += '&idGoal=' + idGoal;
}
+ if (idDimension) {
+ url += '&idDimension=' + idDimension;
+ }
+
if (period) {
url += '&period=' + period;
}
diff --git a/plugins/CustomAlerts b/plugins/CustomAlerts
-Subproject 540f9b3e1e8fbfb7b2268ec4f293532d3f8cf3b
+Subproject f701502e6580c92f0ff356ea5a3f191b1f125cb
diff --git a/plugins/CustomDimensions b/plugins/CustomDimensions
new file mode 160000
+Subproject e67e2ce7908152cb3138af333ed7f015acba8d0
diff --git a/plugins/CustomVariables/CustomVariables.php b/plugins/CustomVariables/CustomVariables.php
index 6f4796b7aa..9059482c33 100644
--- a/plugins/CustomVariables/CustomVariables.php
+++ b/plugins/CustomVariables/CustomVariables.php
@@ -162,6 +162,8 @@ class CustomVariables extends \Piwik\Plugin
$translationKeys[] = 'CustomVariables_CreatingCustomVariableTakesTime';
$translationKeys[] = 'CustomVariables_SlotsReportIsGeneratedOverTime';
$translationKeys[] = 'General_Loading';
+ $translationKeys[] = 'General_TrackingScopeVisit';
+ $translationKeys[] = 'General_TrackingScopePage';
}
public function getStylesheetFiles(&$stylesheets)
diff --git a/plugins/CustomVariables/Tracker/CustomVariablesRequestProcessor.php b/plugins/CustomVariables/Tracker/CustomVariablesRequestProcessor.php
index de1688d3ed..2b068ba03e 100644
--- a/plugins/CustomVariables/Tracker/CustomVariablesRequestProcessor.php
+++ b/plugins/CustomVariables/Tracker/CustomVariablesRequestProcessor.php
@@ -10,6 +10,7 @@ namespace Piwik\Plugins\CustomVariables\Tracker;
use Piwik\Common;
use Piwik\Plugins\CustomVariables\Model;
+use Piwik\Tracker\Action;
use Piwik\Tracker\Request;
use Piwik\Tracker\RequestProcessor;
use Piwik\Tracker\Visit\VisitProperties;
@@ -63,4 +64,25 @@ class CustomVariablesRequestProcessor extends RequestProcessor
$valuesToUpdate = array_merge($valuesToUpdate, $visitCustomVariables);
}
}
+
+ public function afterRequestProcessed(VisitProperties $visitProperties, Request $request)
+ {
+ $action = $request->getMetadata('Actions', 'action');
+
+ if (empty($action) || !($action instanceof Action)) {
+ return;
+ }
+
+ $customVariables = $action->getCustomVariables();
+
+ if (!empty($customVariables)) {
+ Common::printDebug("Page level Custom Variables: ");
+ Common::printDebug($customVariables);
+
+ foreach ($customVariables as $field => $value) {
+ $action->setCustomField($field, $value);
+ }
+ }
+
+ }
}
diff --git a/plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.controller.js b/plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.controller.js
index 4cbc8dc3e8..f8098eb114 100644
--- a/plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.controller.js
+++ b/plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.controller.js
@@ -14,6 +14,9 @@
this.model = manageCustomVarsModel;
this.siteName = piwik.siteName;
- this.scopes = ['visit', 'page'];
+ this.scopes = [
+ {value: 'visit', name: _pk_translate('General_TrackingScopeVisit')},
+ {value: 'page', name: _pk_translate('General_TrackingScopePage')}
+ ];
}
})(); \ No newline at end of file
diff --git a/plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.directive.html b/plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.directive.html
index ccba542a87..6ab9ea6ba6 100644
--- a/plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.directive.html
+++ b/plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.directive.html
@@ -10,7 +10,7 @@
</div>
<div ng-repeat="scope in manageCustomVars.scopes">
- <h2 class="secondary">{{ 'CustomVariables_ScopeX'|translate:(scope|ucfirst) }}</h2>
+ <h2 class="secondary">{{ 'CustomVariables_ScopeX'|translate:(scope.name) }}</h2>
<table class="dataTable entityTable">
<thead>
<tr>
@@ -22,7 +22,7 @@
<tr>
<td colspan="3" ng-show="manageCustomVars.model.isLoading">{{ 'General_Loading'|translate }}</td>
</tr>
- <tr ng-repeat="customVariables in manageCustomVars.model.customVariables|filter:{scope: scope}">
+ <tr ng-repeat="customVariables in manageCustomVars.model.customVariables|filter:{scope: scope.value}">
<td class="index">{{ customVariables.index }}</td>
<td>
<span ng-show="(customVariables.usages|length) === 0"
diff --git a/plugins/CustomVariables/tests/UI/expected-ui-screenshots/CustomVariables_link_in_menu.png b/plugins/CustomVariables/tests/UI/expected-ui-screenshots/CustomVariables_link_in_menu.png
index 208408ad53..39480bbf29 100644
--- a/plugins/CustomVariables/tests/UI/expected-ui-screenshots/CustomVariables_link_in_menu.png
+++ b/plugins/CustomVariables/tests/UI/expected-ui-screenshots/CustomVariables_link_in_menu.png
Binary files differ
diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php
index 15f7b40aab..7a66581c69 100644
--- a/plugins/Goals/Controller.php
+++ b/plugins/Goals/Controller.php
@@ -459,8 +459,14 @@ class Controller extends \Piwik\Plugin\Controller
}
$customParams['viewDataTable'] = $report['viewDataTable'];
+ if (!empty($report['parameters'])) {
+ $params = array_merge($customParams, $report['parameters']);
+ } else {
+ $params = $customParams;
+ }
+
$goalReportsByDimension->addReport(
- $categoryText, $report['name'], $report['module'] . '.' . $report['action'], $customParams);
+ $categoryText, $report['name'], $report['module'] . '.' . $report['action'], $params);
}
}
}
diff --git a/plugins/Goals/Reports/Base.php b/plugins/Goals/Reports/Base.php
index fd732035d3..3db8c4446b 100644
--- a/plugins/Goals/Reports/Base.php
+++ b/plugins/Goals/Reports/Base.php
@@ -33,7 +33,7 @@ abstract class Base extends \Piwik\Plugin\Report
$this->parameters = array('idGoal' => $goal['idgoal']);
$this->order = $this->orderGoal + $goal['idgoal'] * 3;
- $availableReports[] = $this->buildReportMetadata($availableReports, $infos);
+ $availableReports[] = $this->buildReportMetadata();
}
$this->init();
diff --git a/plugins/ImageGraph/API.php b/plugins/ImageGraph/API.php
index 4e7b466b21..ffdd223d46 100644
--- a/plugins/ImageGraph/API.php
+++ b/plugins/ImageGraph/API.php
@@ -122,7 +122,8 @@ class API extends \Piwik\Plugin\API
$gridColor = API::DEFAULT_GRID_COLOR,
$idSubtable = false,
$legendAppendMetric = true,
- $segment = false
+ $segment = false,
+ $idDimension = false
)
{
Piwik::checkUserHasViewAccess($idSite);
@@ -151,6 +152,9 @@ class API extends \Piwik\Plugin\API
if (!empty($idGoal)) {
$apiParameters = array('idGoal' => $idGoal);
}
+ if (!empty($idDimension)) {
+ $apiParameters = array('idDimension' => $idDimension);
+ }
// Fetch the metadata for given api-action
$parameters = array(
'idSite' => $idSite,
@@ -305,6 +309,7 @@ class API extends \Piwik\Plugin\API
'column' => $plottedMetric,
'language' => $languageLoaded,
'idGoal' => $idGoal,
+ 'idDimension' => $idDimension,
'legendAppendMetric' => $legendAppendMetric,
'labelUseAbsoluteUrl' => false
);
@@ -361,6 +366,7 @@ class API extends \Piwik\Plugin\API
'segment' => $segment,
'apiParameters' => false,
'idGoal' => $idGoal,
+ 'idDimension' => $idDimension,
'language' => $languageLoaded,
'showTimer' => true,
'hideMetricsDoc' => false,
@@ -506,7 +512,10 @@ class API extends \Piwik\Plugin\API
if ($idGoal != '') {
$idGoal = '_' . $idGoal;
}
- $fileName = self::$DEFAULT_PARAMETERS[$graphType][self::FILENAME_KEY] . '_' . $apiModule . '_' . $apiAction . $idGoal . ' ' . str_replace(',', '-', $date) . ' ' . $idSite . '.png';
+ if ($idDimension != '') {
+ $idDimension = '__' . $idDimension;
+ }
+ $fileName = self::$DEFAULT_PARAMETERS[$graphType][self::FILENAME_KEY] . '_' . $apiModule . '_' . $apiAction . $idGoal . $idDimension . ' ' . str_replace(',', '-', $date) . ' ' . $idSite . '.png';
$fileName = str_replace(array(' ', '/'), '_', $fileName);
if (!Filesystem::isValidFilename($fileName)) {
diff --git a/plugins/Insights/Visualizations/Insight.php b/plugins/Insights/Visualizations/Insight.php
index 7fe304e5be..91d2c90b63 100644
--- a/plugins/Insights/Visualizations/Insight.php
+++ b/plugins/Insights/Visualizations/Insight.php
@@ -40,6 +40,10 @@ class Insight extends Visualization
$report = $this->requestConfig->apiMethodToRequestDataTable;
$report = str_replace('.', '_', $report);
+ if (!empty($this->requestConfig->request_parameters_to_modify['reportUniqueId'])) {
+ $report = $this->requestConfig->request_parameters_to_modify['reportUniqueId'];
+ }
+
$this->requestConfig->apiMethodToRequestDataTable = 'Insights.getInsights';
$this->requestConfig->request_parameters_to_modify = array(
diff --git a/plugins/Live/Live.php b/plugins/Live/Live.php
index 93e8d67881..1a71aa7b83 100644
--- a/plugins/Live/Live.php
+++ b/plugins/Live/Live.php
@@ -54,5 +54,7 @@ class Live extends \Piwik\Plugin
$translationKeys[] = "Live_RowActionTooltipDefault";
$translationKeys[] = "Live_RowActionTooltipWithDimension";
$translationKeys[] = "Live_SegmentedVisitorLogTitle";
+ $translationKeys[] = "General_Segment";
+ $translationKeys[] = "General_And";
}
} \ No newline at end of file
diff --git a/plugins/Live/javascripts/rowaction.js b/plugins/Live/javascripts/rowaction.js
index 8baba18a2d..5c54e961b5 100644
--- a/plugins/Live/javascripts/rowaction.js
+++ b/plugins/Live/javascripts/rowaction.js
@@ -150,6 +150,12 @@
var segmentName = getDimensionFromApiMethod(apiMethod);
var segmentValue = findTitleOfRowHavingRawSegmentValue(apiMethod, segment);
+ if (!segmentName || (segment && segment.indexOf(';') > 0)) {
+ segmentName = _pk_translate('General_Segment');
+ var segmentParts = segment.split(';');
+ segmentValue = segmentParts.join(' ' + _pk_translate('General_And') + ' ');
+ }
+
segmentName = piwikHelper.escape(segmentName);
segmentName = piwikHelper.htmlEntities(segmentName);
segmentValue = piwikHelper.escape(segmentValue);
diff --git a/plugins/Monolog/tests/System/TrackerLoggingTest.php b/plugins/Monolog/tests/System/TrackerLoggingTest.php
index 70c933d13f..8716229116 100644
--- a/plugins/Monolog/tests/System/TrackerLoggingTest.php
+++ b/plugins/Monolog/tests/System/TrackerLoggingTest.php
@@ -83,10 +83,8 @@ DEBUG: 'apiv' => '1',", $response);
private function setTrackerConfig($trackerConfig)
{
$testingEnvironment = self::$fixture->getTestEnvironment();
- $configOverride = $testingEnvironment->configOverride;
- $configOverride['Tracker'] = $trackerConfig;
- $configOverride['log']['log_writers'] = array('screen');
- $testingEnvironment->configOverride = $configOverride;
+ $testingEnvironment->overrideConfig('Tracker', $trackerConfig);
+ $testingEnvironment->overrideConfig('log', 'log_writers', array('screen'));
$testingEnvironment->save();
}
diff --git a/plugins/Overlay/Controller.php b/plugins/Overlay/Controller.php
index 795d7b991d..2ed50641c5 100644
--- a/plugins/Overlay/Controller.php
+++ b/plugins/Overlay/Controller.php
@@ -16,14 +16,26 @@ use Piwik\Metrics;
use Piwik\Piwik;
use Piwik\Plugin\Report;
use Piwik\Plugins\Actions\ArchivingHelper;
+use Piwik\Plugins\SegmentEditor\SegmentFormatter;
use Piwik\Plugins\SitesManager\API as APISitesManager;
use Piwik\ProxyHttp;
+use Piwik\Segment;
use Piwik\Tracker\Action;
use Piwik\Tracker\PageUrl;
use Piwik\View;
class Controller extends \Piwik\Plugin\Controller
{
+ /**
+ * @var SegmentFormatter
+ */
+ private $segmentFormatter;
+
+ public function __construct(SegmentFormatter $segmentFormatter)
+ {
+ $this->segmentFormatter = $segmentFormatter;
+ parent::__construct();
+ }
/** The index of the plugin */
public function index()
@@ -38,6 +50,7 @@ class Controller extends \Piwik\Plugin\Controller
$view = new View($template);
$this->setGeneralVariablesView($view);
+ $view->segment = Request::getRawSegmentFromRequest();
$view->ssl = ProxyHttp::isHttps();
@@ -52,8 +65,9 @@ class Controller extends \Piwik\Plugin\Controller
$period = Common::getRequestVar('period');
$date = Common::getRequestVar('date');
$currentUrl = Common::getRequestVar('currentUrl');
+ $segment = Request::getRawSegmentFromRequest();
$currentUrl = Common::unsanitizeInputValue($currentUrl);
- $segment = '';
+ $segmentSidebar = '';
$normalizedCurrentUrl = PageUrl::excludeQueryParametersFromUrl($currentUrl, $idSite);
$normalizedCurrentUrl = Common::unsanitizeInputValue($normalizedCurrentUrl);
@@ -63,16 +77,22 @@ class Controller extends \Piwik\Plugin\Controller
$path = ArchivingHelper::getActionExplodedNames($normalizedCurrentUrl, Action::TYPE_PAGE_URL);
$path = array_map('urlencode', $path);
$label = implode('>', $path);
- $request = new Request(
- 'method=Actions.getPageUrls'
- . '&idSite=' . urlencode($idSite)
- . '&date=' . urlencode($date)
- . '&period=' . urlencode($period)
- . '&label=' . urlencode($label)
- . '&format=original'
- . '&format_metrics=0'
+
+ $params = array(
+ 'idSite' => $idSite,
+ 'date' => $date,
+ 'period' => $period,
+ 'label' => $label,
+ 'format' => 'original',
+ 'format_metrics' => 0,
+ 'serialize' => '0'
);
- $dataTable = $request->process();
+
+ if (!empty($segment)) {
+ $params['segment'] = $segment;
+ }
+
+ $dataTable = Request::processRequest('Actions.getPageUrls', $params);
$formatter = new Metrics\Formatter\Html();
@@ -84,7 +104,10 @@ class Controller extends \Piwik\Plugin\Controller
$showMetrics = array('nb_hits', 'nb_visits', 'nb_users', 'nb_uniq_visitors',
'bounce_rate', 'exit_rate', 'avg_time_on_page');
- $segment = $row->getMetadata('segment');
+ $segmentSidebar = $row->getMetadata('segment');
+ if (!empty($segmentSidebar) && !empty($segment)) {
+ $segmentSidebar = $segment . ';' . $segmentSidebar;
+ }
foreach ($showMetrics as $metric) {
$value = $row->getColumn($metric);
@@ -127,7 +150,8 @@ class Controller extends \Piwik\Plugin\Controller
$view->idSite = $idSite;
$view->period = $period;
$view->date = $date;
- $view->segment = $segment;
+ $view->segment = $segmentSidebar;
+ $view->segmentDescription = $this->segmentFormatter->getHumanReadable($segment, $idSite);
$this->outputCORSHeaders();
return $view->render();
@@ -142,64 +166,20 @@ class Controller extends \Piwik\Plugin\Controller
$idSite = Common::getRequestVar('idSite', 0, 'int');
Piwik::checkUserHasViewAccess($idSite);
+ $view = new View('@Overlay/startOverlaySession');
+
$sitesManager = APISitesManager::getInstance();
$site = $sitesManager->getSiteFromId($idSite);
$urls = $sitesManager->getSiteUrlsFromId($idSite);
+ $view->isHttps = ProxyHttp::isHttps();
+ $view->knownUrls = json_encode($urls);
+ $view->mainUrl = $site['main_url'];
+
$this->outputCORSHeaders();
Common::sendHeader('Content-Type: text/html; charset=UTF-8');
- return '
- <html><head><title></title></head><body>
- <script type="text/javascript">
- function handleProtocol(url) {
- if (' . (ProxyHttp::isHttps() ? 'true' : 'false') . ') {
- return url.replace(/http:\/\//i, "https://");
- } else {
- return url.replace(/https:\/\//i, "http://");
- }
- }
-
- function removeUrlPrefix(url) {
- return url.replace(/http(s)?:\/\/(www\.)?/i, "");
- }
-
- if (window.location.hash) {
- var match = false;
-
- var urlToRedirect = window.location.hash.substr(1);
- var urlToRedirectWithoutPrefix = removeUrlPrefix(urlToRedirect);
-
- var knownUrls = ' . json_encode($urls) . ';
- for (var i = 0; i < knownUrls.length; i++) {
- var testUrl = removeUrlPrefix(knownUrls[i]);
- if (urlToRedirectWithoutPrefix.substr(0, testUrl.length) == testUrl) {
- match = true;
- if (navigator.appName == "Microsoft Internet Explorer") {
- // internet explorer loses the referrer if we use window.location.href=X
- var referLink = document.createElement("a");
- referLink.href = handleProtocol(urlToRedirect);
- document.body.appendChild(referLink);
- referLink.click();
- } else {
- window.location.href = handleProtocol(urlToRedirect);
- }
- break;
- }
- }
-
- if (!match) {
- var idSite = window.location.href.match(/idSite=([0-9]+)/i)[1];
- window.location.href = "index.php?module=Overlay&action=showErrorWrongDomain"
- + "&idSite=" + idSite
- + "&url=" + encodeURIComponent(urlToRedirect);
- }
- }
- else {
- window.location.href = handleProtocol("' . $site['main_url'] . '");
- };
- </script>
- </body></html>
- ';
+
+ return $view->render();
}
/**
diff --git a/plugins/Overlay/client/client.js b/plugins/Overlay/client/client.js
index 04b1f88f13..f37b9a0cd3 100644
--- a/plugins/Overlay/client/client.js
+++ b/plugins/Overlay/client/client.js
@@ -10,7 +10,7 @@ var Piwik_Overlay_Client = (function () {
var idSite;
/** The current period and date */
- var period, date;
+ var period, date, segment;
/** Reference to the status bar DOM element */
var statusBar;
@@ -131,11 +131,12 @@ var Piwik_Overlay_Client = (function () {
return {
/** Initialize in-site analytics */
- initialize: function (pPiwikRoot, pIdSite, pPeriod, pDate) {
+ initialize: function (pPiwikRoot, pIdSite, pPeriod, pDate, pSegment) {
piwikRoot = pPiwikRoot;
idSite = pIdSite;
period = pPeriod;
date = pDate;
+ segment = pSegment;
var load = this.loadScript;
var loading = this.loadingNotification;
@@ -193,6 +194,10 @@ var Piwik_Overlay_Client = (function () {
var url = piwikRoot + 'index.php?module=API&method=Overlay.' + method
+ '&idSite=' + idSite + '&period=' + period + '&date=' + date + '&format=JSON&filter_limit=-1';
+ if (segment) {
+ url += '&segment=' + segment;
+ }
+
if (additionalParams) {
url += '&' + additionalParams;
}
diff --git a/plugins/Overlay/javascripts/Overlay_Helper.js b/plugins/Overlay/javascripts/Overlay_Helper.js
index e0681e7b45..42ff388d81 100644
--- a/plugins/Overlay/javascripts/Overlay_Helper.js
+++ b/plugins/Overlay/javascripts/Overlay_Helper.js
@@ -20,11 +20,17 @@ var Overlay_Helper = {
},
/** Get the url to launch overlay */
- getOverlayLink: function (idSite, period, date, link) {
+ getOverlayLink: function (idSite, period, date, segment, link) {
var url = 'index.php?module=Overlay&period=' + encodeURIComponent(period) + '&date=' + encodeURIComponent(date) + '&idSite=' + encodeURIComponent(idSite);
+
+ if (segment) {
+ url += '&segment=' + encodeURIComponent(segment);
+ }
+
if (link) {
url += '#?l=' + Overlay_Helper.encodeFrameUrl(link);
}
+
return url;
}
diff --git a/plugins/Overlay/javascripts/Piwik_Overlay.js b/plugins/Overlay/javascripts/Piwik_Overlay.js
index 4c78080806..d04f8e5fbe 100644
--- a/plugins/Overlay/javascripts/Piwik_Overlay.js
+++ b/plugins/Overlay/javascripts/Piwik_Overlay.js
@@ -10,7 +10,7 @@ var Piwik_Overlay = (function () {
var $body, $iframe, $sidebar, $main, $location, $loading, $errorNotLoading;
var $rowEvolutionLink, $transitionsLink, $fullScreenLink, $visitorLogLink;
- var idSite, period, date;
+ var idSite, period, date, segment;
var iframeSrcBase;
var iframeDomain = '';
@@ -28,13 +28,19 @@ var Piwik_Overlay = (function () {
iframeCurrentPage = currentUrl;
iframeDomain = currentUrl.match(/http(s)?:\/\/(www\.)?([^\/]*)/i)[3];
- globalAjaxQueue.abort();
- var ajaxRequest = new ajaxHelper();
- ajaxRequest.addParams({
+ var params = {
module: 'Overlay',
action: 'renderSidebar',
currentUrl: currentUrl
- }, 'get');
+ };
+
+ if (segment) {
+ params.segment = segment;
+ }
+
+ globalAjaxQueue.abort();
+ var ajaxRequest = new ajaxHelper();
+ ajaxRequest.addParams(params, 'get');
ajaxRequest.setCallback(
function (response) {
hideLoading();
@@ -111,6 +117,16 @@ var Piwik_Overlay = (function () {
$fullScreenLink.show();
}
+ function getOverlaySegment(url) {
+ var location = broadcast.getParamValue('segment', url);
+
+ // angular will encode the value again since it is added as the fragment path, not the fragment query parameter,
+ // so we have to decode it again after getParamValue
+ location = decodeURIComponent(location);
+
+ return location;
+ }
+
function getOverlayLocationFromHash(urlHash) {
var location = broadcast.getParamValue('l', urlHash);
@@ -143,11 +159,12 @@ var Piwik_Overlay = (function () {
return {
/** This method is called when Overlay loads */
- init: function (iframeSrc, pIdSite, pPeriod, pDate) {
+ init: function (iframeSrc, pIdSite, pPeriod, pDate, pSegment) {
iframeSrcBase = iframeSrc;
idSite = pIdSite;
period = pPeriod;
date = pDate;
+ segment = pSegment;
$body = $('body');
$iframe = $('#overlayIframe');
@@ -201,7 +218,7 @@ var Piwik_Overlay = (function () {
if (parts.length == 2) {
period = parts[0];
date = parts[1];
- window.location.href = Overlay_Helper.getOverlayLink(idSite, period, date, iframeCurrentPage);
+ window.location.href = Overlay_Helper.getOverlayLink(idSite, period, date, segment, iframeCurrentPage);
}
});
diff --git a/plugins/Overlay/javascripts/rowaction.js b/plugins/Overlay/javascripts/rowaction.js
index c84e60a33b..8f11c736d0 100644
--- a/plugins/Overlay/javascripts/rowaction.js
+++ b/plugins/Overlay/javascripts/rowaction.js
@@ -19,12 +19,34 @@ DataTable_RowActions_Overlay.prototype.onClick = function (actionA, tr, e) {
if (!actionA.data('overlay-manipulated')) {
actionA.data('overlay-manipulated', 1);
- var link = tr.find('> td:first > a').attr('href');
- link = $('<textarea>').html(link).val(); // remove html entities
+ var segment, link;
+
+ if (DataTable_RowActions_Transitions.isActionCustomDimensionReport(this.dataTable.param)) {
+
+ link = this.getLabelFromTr(tr);
+ if (link && link.substr(0, 1) === '@') {
+ link = link.substr(1);
+ }
+
+ link = 'http://' + unescape(link);
+
+ var subtable = tr.closest('table');
+ if (subtable.is('.subDataTable')) {
+ var prev = subtable.closest('tr').prev();
+ segment = prev.attr('data-segment-filter');
+ }
+ } else {
+
+ link = tr.find('> td:first > a').attr('href');
+ link = $('<textarea>').html(link).val(); // remove html entities
+ }
+
+
+ var href = Overlay_Helper.getOverlayLink(this.dataTable.param.idSite, 'month', 'today', segment, link);
actionA.attr({
target: '_blank',
- href: Overlay_Helper.getOverlayLink(this.dataTable.param.idSite, 'month', 'today', link)
+ href: href
});
}
@@ -54,6 +76,11 @@ DataTable_RowActions_Registry.register({
if (!window.DataTable_RowActions_Transitions) {
return false;
}
+
+ if (DataTable_RowActions_Transitions.isActionCustomDimensionReport(dataTableParams)) {
+ return true;
+ }
+
return DataTable_RowActions_Transitions.isPageUrlReport(dataTableParams.module, dataTableParams.action);
},
diff --git a/plugins/Overlay/stylesheets/overlay.css b/plugins/Overlay/stylesheets/overlay.css
index 4e30660775..a13dd67a46 100644
--- a/plugins/Overlay/stylesheets/overlay.css
+++ b/plugins/Overlay/stylesheets/overlay.css
@@ -35,12 +35,20 @@ a#overlayTitle .icon-help {
margin: 20px 10px;
}
-#overlayLocation {
+#overlayLocation, .overlaySegment {
width: 200px;
- margin: 0 0 30px 10px;
font-size: 12px;
}
+#overlayLocation {
+ margin: 0 0 10px 10px;
+}
+
+.overlaySegment {
+ margin: 0 0 30px 0;
+ word-break: break-all;
+}
+
#overlayLoading {
background: url(../../Morpheus/images/loading-blue.gif) no-repeat center 10px;
width: 190px;
diff --git a/plugins/Overlay/templates/index.twig b/plugins/Overlay/templates/index.twig
index 10a0b40d76..effe5fbade 100644
--- a/plugins/Overlay/templates/index.twig
+++ b/plugins/Overlay/templates/index.twig
@@ -61,8 +61,8 @@
<script type="text/javascript">
broadcast._isInit = true;
$(function () {
- var iframeSrc = 'index.php?module=Overlay&action=startOverlaySession&idSite={{ idSite }}&period={{ period }}&date={{ rawDate }}';
- Piwik_Overlay.init(iframeSrc, '{{ idSite }}', '{{ period }}', '{{ rawDate }}');
+ var iframeSrc = 'index.php?module=Overlay&action=startOverlaySession&idSite={{ idSite }}&period={{ period }}&date={{ rawDate }}&segment={{ segment }}';
+ Piwik_Overlay.init(iframeSrc, '{{ idSite }}', '{{ period }}', '{{ rawDate }}', '{{ segment }}');
window.Piwik_Overlay_Translations = {
domain: "{{ 'Overlay_Domain'|translate }}"
diff --git a/plugins/Overlay/templates/index_noframe.twig b/plugins/Overlay/templates/index_noframe.twig
index 0478715edb..f3c9e61579 100644
--- a/plugins/Overlay/templates/index_noframe.twig
+++ b/plugins/Overlay/templates/index_noframe.twig
@@ -6,7 +6,7 @@
<div id="overlayNoFrame">
<script type="text/javascript">
- var newLocation = 'index.php?module=Overlay&action=startOverlaySession&idSite={{ idSite }}&period={{ period }}&date={{ date }}';
+ var newLocation = 'index.php?module=Overlay&action=startOverlaySession&idSite={{ idSite }}&period={{ period }}&date={{ date }}&segment={{ segment }}';
var locationParts = window.location.href.split('#');
if (locationParts.length > 1) {
diff --git a/plugins/Overlay/templates/renderSidebar.twig b/plugins/Overlay/templates/renderSidebar.twig
index 09d8cf0d40..36ff9c8ba1 100644
--- a/plugins/Overlay/templates/renderSidebar.twig
+++ b/plugins/Overlay/templates/renderSidebar.twig
@@ -8,6 +8,11 @@
</span>
</div>
+ <div class="overlaySegment">
+ <strong>{{ 'General_Segment'|translate }}:</strong>
+ <span>{{ segmentDescription }}</span>
+ </div>
+
{% if data|length > 0 %}
<h2 class="overlayMainMetrics">{{ 'General_MainMetrics'|translate }}</h2>
<ul class="overlayMetrics">
diff --git a/plugins/Overlay/templates/startOverlaySession.twig b/plugins/Overlay/templates/startOverlaySession.twig
new file mode 100644
index 0000000000..b1db8ce5b2
--- /dev/null
+++ b/plugins/Overlay/templates/startOverlaySession.twig
@@ -0,0 +1,50 @@
+<html><head><title></title></head><body>
+<script type="text/javascript">
+ function handleProtocol(url) {
+ if ({% if isHttps %}true{% else %}false{% endif %}) {
+ return url.replace(/http:\/\//i, "https://");
+ } else {
+ return url.replace(/https:\/\//i, "http://");
+ }
+ }
+
+ function removeUrlPrefix(url) {
+ return url.replace(/http(s)?:\/\/(www\.)?/i, "");
+ }
+
+ if (window.location.hash) {
+ var match = false;
+
+ var urlToRedirect = window.location.hash.substr(1);
+ var urlToRedirectWithoutPrefix = removeUrlPrefix(urlToRedirect);
+
+ var knownUrls = {{ knownUrls|raw }};
+ for (var i = 0; i < knownUrls.length; i++) {
+ var testUrl = removeUrlPrefix(knownUrls[i]);
+ if (urlToRedirectWithoutPrefix.substr(0, testUrl.length) == testUrl) {
+ match = true;
+ if (navigator.appName == "Microsoft Internet Explorer") {
+ // internet explorer loses the referrer if we use window.location.href=X
+ var referLink = document.createElement("a");
+ referLink.href = handleProtocol(urlToRedirect);
+ document.body.appendChild(referLink);
+ referLink.click();
+ } else {
+ window.location.href = handleProtocol(urlToRedirect);
+ }
+ break;
+ }
+ }
+
+ if (!match) {
+ var idSite = window.location.href.match(/idSite=([0-9]+)/i)[1];
+ window.location.href = "index.php?module=Overlay&action=showErrorWrongDomain"
+ + "&idSite=" + idSite
+ + "&url=" + encodeURIComponent(urlToRedirect);
+ }
+ }
+ else {
+ window.location.href = handleProtocol("{{ mainUrl|e('js') }}");
+ };
+</script>
+</body></html> \ No newline at end of file
diff --git a/plugins/SegmentEditor/SegmentEditor.php b/plugins/SegmentEditor/SegmentEditor.php
index 9107935e73..a46be068bc 100644
--- a/plugins/SegmentEditor/SegmentEditor.php
+++ b/plugins/SegmentEditor/SegmentEditor.php
@@ -28,6 +28,7 @@ class SegmentEditor extends \Piwik\Plugin
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
'Template.nextToCalendar' => 'getSegmentEditorHtml',
+ 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
);
}
@@ -85,4 +86,9 @@ class SegmentEditor extends \Piwik\Plugin
{
return Config::getInstance()->General['allow_adding_segments_for_all_websites'] == 1;
}
+
+ public function getClientSideTranslationKeys(&$translationKeys)
+ {
+ $translationKeys[] = 'SegmentEditor_CustomSegment';
+ }
}
diff --git a/plugins/SegmentEditor/SegmentFormatter.php b/plugins/SegmentEditor/SegmentFormatter.php
new file mode 100644
index 0000000000..54dcc20c99
--- /dev/null
+++ b/plugins/SegmentEditor/SegmentFormatter.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\SegmentEditor;
+
+use Exception;
+use Piwik\Config;
+use Piwik\Db;
+use Piwik\Piwik;
+use Piwik\Segment;
+use Piwik\Segment\SegmentExpression;
+
+/**
+ */
+class SegmentFormatter
+{
+ /**
+ * @var SegmentList
+ */
+ private $segmentList;
+
+ private $matchesMetric = array(
+ SegmentExpression::MATCH_EQUAL => 'General_OperationEquals',
+ SegmentExpression::MATCH_NOT_EQUAL => 'General_OperationNotEquals',
+ SegmentExpression::MATCH_LESS_OR_EQUAL => 'General_OperationAtMost',
+ SegmentExpression::MATCH_GREATER_OR_EQUAL => 'General_OperationAtLeast',
+ SegmentExpression::MATCH_LESS => 'General_OperationLessThan',
+ SegmentExpression::MATCH_GREATER => 'General_OperationGreaterThan',
+ );
+
+ private $matchesDimension = array(
+ SegmentExpression::MATCH_EQUAL => 'General_OperationIs',
+ SegmentExpression::MATCH_NOT_EQUAL => 'General_OperationIsNot',
+ SegmentExpression::MATCH_CONTAINS => 'General_OperationContains',
+ SegmentExpression::MATCH_DOES_NOT_CONTAIN => 'General_OperationDoesNotContain',
+ SegmentExpression::MATCH_STARTS_WITH => 'General_OperationStartsWith',
+ SegmentExpression::MATCH_ENDS_WITH => 'General_OperationEndsWith'
+ );
+
+ private $operators = array(
+ SegmentExpression::BOOL_OPERATOR_AND => 'General_And',
+ SegmentExpression::BOOL_OPERATOR_OR => 'General_Or',
+ SegmentExpression::BOOL_OPERATOR_END => '',
+ );
+
+ public function __construct(SegmentList $segmentList)
+ {
+ $this->segmentList = $segmentList;
+ }
+
+ public function getHumanReadable($segmentString, $idSite)
+ {
+ if (empty($segmentString)) {
+ return Piwik::translate('SegmentEditor_DefaultAllVisits');
+ }
+
+ $segment = new SegmentExpression($segmentString);
+ $expressions = $segment->parseSubExpressions();
+
+ $readable = '';
+ foreach ($expressions as $expression) {
+ $operator = $expression[SegmentExpression::INDEX_BOOL_OPERATOR];
+ $operand = $expression[SegmentExpression::INDEX_OPERAND];
+ $name = $operand[SegmentExpression::INDEX_OPERAND_NAME];
+
+ $segment = $this->segmentList->findSegment($name, $idSite);
+
+ if (empty($segment)) {
+ throw new Exception(sprintf("The segment '%s' does not exist.", $name));
+ }
+
+ $readable .= $segment['name'] . ' ';
+ $readable .= $this->getTranslationForComparison($operand, $segment['type']) . ' ';
+ $readable .= $this->getFormattedValue($operand);
+ $readable .= $this->getTranslationForBoolOperator($operator) . ' ';
+ }
+
+ $readable = trim($readable);
+
+ return $readable;
+ }
+
+ private function getTranslationForComparison($operand, $segmentType)
+ {
+ $operator = $operand[SegmentExpression::INDEX_OPERAND_OPERATOR];
+
+ $translation = $operator;
+
+ if ($operator === SegmentExpression::MATCH_IS_NULL_OR_EMPTY) {
+ return Piwik::translate('SegmentEditor_SegmentOperatorIsNullOrEmpty');
+ }
+
+ if ($operator === SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY) {
+ return Piwik::translate('SegmentEditor_SegmentOperatorIsNotNullNorEmpty');
+ }
+
+ if ($segmentType === 'dimension' && !empty($this->matchesDimension[$operator])) {
+ $translation = Piwik::translate($this->matchesDimension[$operator]);
+ }
+ if ($segmentType === 'metric' && !empty($this->matchesMetric[$operator])) {
+ $translation = Piwik::translate($this->matchesMetric[$operator]);
+ }
+
+ return strtolower($translation);
+ }
+
+ private function getFormattedValue($operand)
+ {
+ $operator = $operand[SegmentExpression::INDEX_OPERAND_OPERATOR];
+
+ if ($operator === SegmentExpression::MATCH_IS_NULL_OR_EMPTY
+ || $operator === SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY) {
+ return '';
+ }
+
+ $value = $operand[SegmentExpression::INDEX_OPERAND_VALUE];
+
+ if (empty($value)) {
+ $value = '';
+ }
+
+ return '"' . $value . '" ';
+ }
+
+ private function getTranslationForBoolOperator($operator)
+ {
+ $translation = '';
+
+ if (!empty($this->operators[$operator])) {
+ $translation = Piwik::translate($this->operators[$operator]);
+ } elseif (!empty($operator)) {
+ $translation = $operator;
+ }
+
+ return $translation;
+ }
+}
diff --git a/plugins/SegmentEditor/SegmentList.php b/plugins/SegmentEditor/SegmentList.php
new file mode 100644
index 0000000000..e7094d4793
--- /dev/null
+++ b/plugins/SegmentEditor/SegmentList.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\SegmentEditor;
+
+use Piwik\API\Request;
+use Piwik\Config;
+use Piwik\Db;
+
+/**
+ */
+class SegmentList
+{
+ public function findSegment($segmentName, $idSite)
+ {
+ $segments = Request::processRequest('API.getSegmentsMetadata', array(
+ 'idSites' => array($idSite),
+ ));
+
+ foreach ($segments as $segment) {
+ if ($segment['segment'] == $segmentName && !empty($segmentName)) {
+ return $segment;
+ }
+ }
+ }
+
+}
diff --git a/plugins/SegmentEditor/SegmentSelectorControl.php b/plugins/SegmentEditor/SegmentSelectorControl.php
index 9dc2659660..b01018dbcf 100644
--- a/plugins/SegmentEditor/SegmentSelectorControl.php
+++ b/plugins/SegmentEditor/SegmentSelectorControl.php
@@ -8,8 +8,10 @@
*/
namespace Piwik\Plugins\SegmentEditor;
+use Piwik\API\Request;
use Piwik\Common;
use Piwik\Config;
+use Piwik\Container\StaticContainer;
use Piwik\Piwik;
use Piwik\Plugins\API\API as APIMetadata;
use Piwik\View\UIControl;
@@ -37,6 +39,9 @@ class SegmentSelectorControl extends UIControl
$this->selectedSegment = Common::getRequestVar('segment', false, 'string');
+ $formatter = StaticContainer::get('Piwik\Plugins\SegmentEditor\SegmentFormatter');
+ $this->segmentDescription = $formatter->getHumanReadable(Request::getRawSegmentFromRequest(), $this->idSite);
+
$this->isAddingSegmentsForAllWebsitesEnabled = SegmentEditor::isAddingSegmentsForAllWebsitesEnabled();
$segments = APIMetadata::getInstance()->getSegmentsMetadata($this->idSite);
diff --git a/plugins/SegmentEditor/javascripts/Segmentation.js b/plugins/SegmentEditor/javascripts/Segmentation.js
index ec1e8f23b8..2ffd7dac57 100644
--- a/plugins/SegmentEditor/javascripts/Segmentation.js
+++ b/plugins/SegmentEditor/javascripts/Segmentation.js
@@ -85,7 +85,7 @@ Segmentation = (function($) {
var name = $(foundItems).first().find("span.segname").text();
title.text(name);
} else {
- title.text("Custom Segment");
+ title.text(_pk_translate('SegmentEditor_CustomSegment'));
}
segmentationTitle.html(title);
}
diff --git a/plugins/SegmentEditor/lang/en.json b/plugins/SegmentEditor/lang/en.json
index 933ac73884..8651afeecd 100644
--- a/plugins/SegmentEditor/lang/en.json
+++ b/plugins/SegmentEditor/lang/en.json
@@ -7,6 +7,7 @@
"AutoArchivePreProcessed": "segmented reports are pre-processed (faster, requires cron)",
"AutoArchiveRealTime": "segmented reports are processed in real time",
"ChooseASegment": "Choose a segment",
+ "CurrentlySelectedSegment": "Currently selected segment: %s",
"DataAvailableAtLaterDate": "Your segmented analytics reports will be available later. We apologize for the inconvenience.",
"DefaultAllVisits": "All visits",
"DragDropCondition": "Drag & Drop condition",
@@ -27,6 +28,9 @@
"YouMustBeLoggedInToCreateSegments": "You must be logged in to create and edit custom visitor segments.",
"YouDontHaveAccessToCreateSegments": "You don't have the required access level to create and edit segments.",
"AddingSegmentForAllWebsitesDisabled": "Adding segments for all websites has been disabled.",
- "SegmentXIsAUnionOf": "%s is a union of these segments:"
+ "SegmentXIsAUnionOf": "%s is a union of these segments:",
+ "CustomSegment": "Custom Segment",
+ "SegmentOperatorIsNullOrEmpty": "is null or empty",
+ "SegmentOperatorIsNotNullNorEmpty": "is not null nor empty"
}
} \ No newline at end of file
diff --git a/plugins/SegmentEditor/templates/_segmentSelector.twig b/plugins/SegmentEditor/templates/_segmentSelector.twig
index f2d53b60c7..dc269dc8b9 100644
--- a/plugins/SegmentEditor/templates/_segmentSelector.twig
+++ b/plugins/SegmentEditor/templates/_segmentSelector.twig
@@ -1,5 +1,5 @@
<div class="SegmentEditor" style="display:none;">
- <div class="segmentationContainer listHtml" title="{{ 'SegmentEditor_ChooseASegment'|translate|e('html_attr') }}">
+ <div class="segmentationContainer listHtml" title="{{ 'SegmentEditor_ChooseASegment'|translate|e('html_attr') }}. {{ 'SegmentEditor_CurrentlySelectedSegment'|translate(segmentDescription)|e('html_attr') }}">
<a class="title"><span class="icon icon-segment"></span><span class="segmentationTitle"></span></a>
<div class="dropdown dropdown-body">
<div class="segmentFilterContainer">
diff --git a/plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php b/plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php
new file mode 100644
index 0000000000..bc0f206784
--- /dev/null
+++ b/plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\SegmentEditor\tests\Integration;
+
+use Piwik\Plugins\SegmentEditor\SegmentFormatter;
+use Piwik\Plugins\SegmentEditor\SegmentList;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Tests\Framework\Mock\FakeAccess;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+use Piwik\Translate;
+use Exception;
+
+/**
+ * @group SegmentFormatterTest
+ * @group SegmentFormatter
+ * @group SegmentEditor
+ * @group Plugins
+ */
+class SegmentFormatterTest extends IntegrationTestCase
+{
+ /**
+ * @var SegmentFormatter
+ */
+ private $formatter;
+
+ private $idSite;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->idSite = Fixture::createWebsite('2012-01-01 00:00:00');
+ $this->formatter = new SegmentFormatter(new SegmentList());
+
+ Translate::loadAllTranslations();
+ }
+
+ public function tearDown()
+ {
+ Translate::reset();
+ }
+
+ public function test_getHumanReadable_noSegmentGiven_ShouldReturnDefaultSegment()
+ {
+ $readable = $this->formatter->getHumanReadable($segment = '', $this->idSite);
+ $this->assertSame('All visits', $readable);
+ }
+
+ public function test_getHumanReadable_ShouldTranslateAMetric()
+ {
+ $readable = $this->formatter->getHumanReadable($segment = 'visitCount>5', $this->idSite);
+ $this->assertSame('Number of visits greater than "5"', $readable);
+
+ $readable = $this->formatter->getHumanReadable($segment = 'visitCount==5', $this->idSite);
+ $this->assertSame('Number of visits equals "5"', $readable);
+ }
+
+ public function test_getHumanReadable_ShouldTranslateADimension()
+ {
+ $readable = $this->formatter->getHumanReadable($segment = 'resolution=@1024', $this->idSite);
+ $this->assertSame('Resolution contains "1024"', $readable);
+
+ $readable = $this->formatter->getHumanReadable($segment = 'resolution==1024x768', $this->idSite);
+ $this->assertSame('Resolution is "1024x768"', $readable);
+ }
+
+ public function test_getHumanReadable_ShouldCombineMultipleSegmentDefinitionsWithBooleanOperator()
+ {
+ $readable = $this->formatter->getHumanReadable($segment = 'browserVersion!=1.0;browserEngine=$Trident', $this->idSite);
+ $this->assertSame('Browser version is not "1.0" and Browser engine ends with "Trident"', $readable);
+
+ $readable = $this->formatter->getHumanReadable($segment = 'browserVersion!=1.0,browserEngine=$Trident', $this->idSite);
+ $this->assertSame('Browser version is not "1.0" or Browser engine ends with "Trident"', $readable);
+ }
+
+ public function test_getHumanReadable_ShouldHandleAMissingValue()
+ {
+ $readable = $this->formatter->getHumanReadable($segment = 'browserVersion==', $this->idSite);
+ $this->assertSame('Browser version is null or empty', $readable);
+
+ $readable = $this->formatter->getHumanReadable($segment = 'browserVersion!=', $this->idSite);
+ $this->assertSame('Browser version is not null nor empty', $readable);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage The segment 'noTexisTinG' does not exist
+ */
+ public function test_getHumanReadable_ShouldThrowAnException_IfTheGivenSegmentNameDoesNotExist()
+ {
+ $this->formatter->getHumanReadable($segment = 'noTexisTinG==1.0', $this->idSite);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage The segment 'pageUrl=!1.0' is not valid.
+ */
+ public function test_getHumanReadable_ShouldThrowAnException_IfSegmentCannotBeParsedBecauseOfInvalidFormat()
+ {
+ $invalidOperator = '=!';
+ $this->formatter->getHumanReadable($segment = 'pageUrl' . $invalidOperator . '1.0', $this->idSite);
+ }
+
+}
diff --git a/plugins/SegmentEditor/tests/Integration/SegmentListTest.php b/plugins/SegmentEditor/tests/Integration/SegmentListTest.php
new file mode 100644
index 0000000000..3a90bb95ee
--- /dev/null
+++ b/plugins/SegmentEditor/tests/Integration/SegmentListTest.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+namespace Piwik\Plugins\SegmentEditor\tests\Integration;
+
+use Piwik\Plugins\SegmentEditor\SegmentList;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Tests\Framework\Mock\FakeAccess;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+use Exception;
+
+/**
+ * @group SegmentListTest
+ * @group SegmentList
+ * @group SegmentEditor
+ * @group Plugins
+ */
+class SegmentListTest extends IntegrationTestCase
+{
+ /**
+ * @var SegmentList
+ */
+ private $list;
+
+ private $idSite;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->idSite = Fixture::createWebsite('2012-01-01 00:00:00');
+ $this->list = new SegmentList();
+ }
+
+ public function test_findSegment_shouldFindSegmentByName_IfNameExists()
+ {
+ $segmentName = 'pageUrl';
+
+ $segment = $this->list->findSegment($segmentName, $this->idSite);
+ $this->assertInternalType('array', $segment);
+ $this->assertSame($segmentName, $segment['segment']);
+ }
+
+ public function test_findSegment_shouldNotFindSegmentByName_IfNameDoesNotExist()
+ {
+ $segment = $this->list->findSegment('aNyNotExisTinGSegmEnt', $this->idSite);
+ $this->assertNull($segment);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage checkUserHasViewAccess
+ */
+ public function test_findSegment_ShouldThrowException_IfNotEnoughPermission()
+ {
+ FakeAccess::clearAccess($superUser = false, array(1));
+
+ $segment = $this->list->findSegment('pageUrl', 999);
+ $this->assertNull($segment);
+ }
+
+ public function provideContainerConfig()
+ {
+ return array(
+ 'Piwik\Access' => new FakeAccess()
+ );
+ }
+
+}
diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php
index 4a67c45c2c..9a6bf63469 100644
--- a/plugins/SitesManager/API.php
+++ b/plugins/SitesManager/API.php
@@ -585,7 +585,7 @@ class API extends \Piwik\Plugin\API
}
if (!empty($settings)) {
- $this->validateMeasurableSettings($bind['type'], $settings);
+ $this->validateMeasurableSettings(0, $bind['type'], $settings);
}
$idSite = $this->getModel()->createSite($bind);
@@ -611,9 +611,9 @@ class API extends \Piwik\Plugin\API
return (int) $idSite;
}
- private function validateMeasurableSettings($idType, $settings)
+ private function validateMeasurableSettings($idSite, $idType, $settings)
{
- $measurableSettings = new MeasurableSettings(0, $idType);
+ $measurableSettings = new MeasurableSettings($idSite, $idType);
foreach ($measurableSettings->getSettingsForCurrentUser() as $measurableSetting) {
$name = $measurableSetting->getName();
@@ -1184,7 +1184,7 @@ class API extends \Piwik\Plugin\API
}
if (!empty($settings)) {
- $this->validateMeasurableSettings(Site::getTypeFor($idSite), $settings);
+ $this->validateMeasurableSettings($idSite, Site::getTypeFor($idSite), $settings);
}
$this->getModel()->updateSite($bind, $idSite);
diff --git a/plugins/TestRunner/Commands/TestsRunUI.php b/plugins/TestRunner/Commands/TestsRunUI.php
index 4ca7285c1d..3a9a06c080 100644
--- a/plugins/TestRunner/Commands/TestsRunUI.php
+++ b/plugins/TestRunner/Commands/TestsRunUI.php
@@ -26,7 +26,7 @@ class TestsRunUI extends ConsoleCommand
\nRun one spec:
\n./console tests:run-ui UIIntegrationTest
");
- $this->addArgument('specs', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Run only a specific test spec. Separate multiple specs by comma, for instance UIIntegrationTest ', array());
+ $this->addArgument('specs', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'Run only a specific test spec. Separate multiple specs by a space, for instance UIIntegrationTest ', array());
$this->addOption("persist-fixture-data", null, InputOption::VALUE_NONE, "Persist test data in a database and do not execute tear down.");
$this->addOption('keep-symlinks', null, InputOption::VALUE_NONE, "Keep recursive directory symlinks so test pages can be viewed in a browser.");
$this->addOption('print-logs', null, InputOption::VALUE_NONE, "Print webpage logs even if tests succeed.");
diff --git a/plugins/TestRunner/Commands/TestsSetupFixture.php b/plugins/TestRunner/Commands/TestsSetupFixture.php
index baea8f70ff..565a81122a 100644
--- a/plugins/TestRunner/Commands/TestsSetupFixture.php
+++ b/plugins/TestRunner/Commands/TestsSetupFixture.php
@@ -192,10 +192,7 @@ class TestsSetupFixture extends ConsoleCommand
);
foreach ($optionsToOverride as $configOption => $value) {
if ($value) {
- $configOverride = $testingEnvironment->configOverride;
- $configOverride['database_tests'][$configOption] = $configOverride['database'][$configOption] = $value;
- $testingEnvironment->configOverride = $configOverride;
-
+ $testingEnvironment->overrideConfig('database_tests', $configOption, $value);
Config::getInstance()->database[$configOption] = $value;
}
}
diff --git a/plugins/Transitions/javascripts/transitions.js b/plugins/Transitions/javascripts/transitions.js
index cb98e3d045..a11f6860c6 100644
--- a/plugins/Transitions/javascripts/transitions.js
+++ b/plugins/Transitions/javascripts/transitions.js
@@ -30,6 +30,10 @@ DataTable_RowActions_Transitions.isPageTitleReport = function (module, action) {
return module == 'Actions' && (action == 'getPageTitles' || action == 'getPageTitlesFollowingSiteSearch');
};
+DataTable_RowActions_Transitions.isActionCustomDimensionReport = function (params) {
+ return params.module == 'CustomDimensions' && params.action == 'getCustomDimension' && params.scopeOfDimension && params.scopeOfDimension === 'action';
+};
+
DataTable_RowActions_Transitions.prototype.trigger = function (tr, e, subTableLabel) {
var link = tr.find('> td:first > a').attr('href');
link = $('<textarea>').html(link).val(); // remove html entities
@@ -40,6 +44,27 @@ DataTable_RowActions_Transitions.prototype.trigger = function (tr, e, subTableLa
this.openPopover('url:' + link);
} else if (DataTable_RowActions_Transitions.isPageTitleReport(module, action)) {
DataTable_RowAction.prototype.trigger.apply(this, [tr, e, subTableLabel]);
+ } else if (DataTable_RowActions_Transitions.isActionCustomDimensionReport(this.dataTable.param)) {
+
+ var label = this.getLabelFromTr(tr);
+ if (label && label.substr(0, 1) === '@') {
+ label = label.substr(1);
+ }
+
+ var subtable = tr.closest('table');
+ if (subtable.is('.subDataTable')) {
+ var prev = subtable.closest('tr').prev();
+ var segment = prev.attr('data-segment-filter');
+ if (segment) {
+ label = unescape(label);
+ if (this.transitions === null) {
+ this.transitions = new Piwik_Transitions('url', label, this, segment);
+ } else {
+ this.transitions.reset('url', label, segment);
+ }
+ this.transitions.showPopover();
+ }
+ }
} else {
alert('Transitions can\'t be used on this report.');
}
@@ -95,7 +120,8 @@ DataTable_RowActions_Registry.register({
isAvailableOnReport: function (dataTableParams) {
return (
DataTable_RowActions_Transitions.isPageUrlReport(dataTableParams.module, dataTableParams.action) ||
- DataTable_RowActions_Transitions.isPageTitleReport(dataTableParams.module, dataTableParams.action)
+ DataTable_RowActions_Transitions.isPageTitleReport(dataTableParams.module, dataTableParams.action) ||
+ DataTable_RowActions_Transitions.isActionCustomDimensionReport(dataTableParams)
);
},
@@ -109,6 +135,11 @@ DataTable_RowActions_Registry.register({
// not on page url without link (i.e. "Page URL not defined")
return false;
}
+ if (DataTable_RowActions_Transitions.isActionCustomDimensionReport(dataTableParams)
+ && !tr.parents('table').first().hasClass('subDataTable')) {
+ // only show it in subtables of custom dimensions
+ return false;
+ }
return true;
}
@@ -118,8 +149,8 @@ DataTable_RowActions_Registry.register({
// TRANSITIONS IMPLEMENTATION
//
-function Piwik_Transitions(actionType, actionName, rowAction) {
- this.reset(actionType, actionName);
+function Piwik_Transitions(actionType, actionName, rowAction, segment) {
+ this.reset(actionType, actionName, segment);
this.rowAction = rowAction;
this.ajax = new Piwik_Transitions_Ajax();
@@ -129,9 +160,10 @@ function Piwik_Transitions(actionType, actionName, rowAction) {
this.rightGroups = ['followingPages', 'followingSiteSearches', 'downloads', 'outlinks'];
}
-Piwik_Transitions.prototype.reset = function (actionType, actionName) {
+Piwik_Transitions.prototype.reset = function (actionType, actionName, segment) {
this.actionType = actionType;
this.actionName = actionName;
+ this.segment = segment;
this.popover = null;
this.canvas = null;
@@ -179,7 +211,7 @@ Piwik_Transitions.prototype.showPopover = function () {
}
// load the data
- self.model.loadData(self.actionType, self.actionName, function () {
+ self.model.loadData(self.actionType, self.actionName, self.segment, function () {
if (typeof Piwik_Transitions.popoverHtml == 'undefined') {
// html not there yet
callbackForHtml = bothLoaded;
@@ -1249,7 +1281,7 @@ Piwik_Transitions_Model.prototype.htmlLoaded = function () {
};
};
-Piwik_Transitions_Model.prototype.loadData = function (actionType, actionName, callback) {
+Piwik_Transitions_Model.prototype.loadData = function (actionType, actionName, segment, callback) {
var self = this;
this.pageviews = 0;
@@ -1287,11 +1319,16 @@ Piwik_Transitions_Model.prototype.loadData = function (actionType, actionName, c
this.date = '';
- this.ajax.callApi('Transitions.getTransitionsForAction', {
- actionType: actionType,
- actionName: actionName,
- expanded: 1
- },
+ var params = {
+ actionType: actionType,
+ actionName: actionName,
+ expanded: 1
+ };
+ if (segment) {
+ params.segment = segment;
+ }
+
+ this.ajax.callApi('Transitions.getTransitionsForAction', params,
function (report) {
self.date = report.date;
diff --git a/plugins/TreemapVisualization b/plugins/TreemapVisualization
-Subproject a6f46d35e9227c471e0be2c3ae4ae69380049a0
+Subproject e487d14390a4b99504a38ba6237705c10317b12