diff options
-rw-r--r-- | core/View/ReportsByDimension.php | 107 | ||||
-rwxr-xr-x | plugins/CoreHome/templates/misc.js | 44 | ||||
-rw-r--r-- | plugins/CoreHome/templates/reports_by_dimension.tpl | 27 | ||||
-rw-r--r-- | plugins/Goals/Controller.php | 72 | ||||
-rw-r--r-- | plugins/Goals/templates/goals.css | 8 | ||||
-rw-r--r-- | plugins/Goals/templates/overview.tpl | 11 | ||||
-rw-r--r-- | plugins/Goals/templates/single_goal.tpl | 10 | ||||
-rw-r--r-- | plugins/Goals/templates/table_by_dimension.tpl | 108 | ||||
-rw-r--r-- | themes/default/common.css | 8 |
9 files changed, 272 insertions, 123 deletions
diff --git a/core/View/ReportsByDimension.php b/core/View/ReportsByDimension.php new file mode 100644 index 0000000000..014b8f39ad --- /dev/null +++ b/core/View/ReportsByDimension.php @@ -0,0 +1,107 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * @version $Id$ + * + * @category Piwik + * @package SmartyPlugins + */ + +/** + * A facade that makes it easier to use the 'reports_by_dimension.tpl' template. + * + * This view will output HTML that displays a list of report names by category and + * loads them by AJAX when clicked. The loaded report is displayed to the right + * of the report listing. + */ +class Piwik_View_ReportsByDimension extends Piwik_View +{ + /** + * Constructor. + */ + public function __construct() + { + parent::__construct(PIWIK_INCLUDE_PATH.'/plugins/CoreHome/templates/reports_by_dimension.tpl'); + $this->dimensionCategories = array(); + } + + /** + * Adds a report to the list of reports to display. + * + * @param string $category The report's category. Can be a i18n token. + * @param string $title The report's title. Can be a i18n token. + * @param string $action The controller action used to load the report, ie, Referrers.getAll + * @param array $params The list of query parameters to use when loading the report. + * This list overrides query parameters currently in use. For example, + * array('idSite' => 2, 'viewDataTable' => 'goalsTable') + * would mean the goals report for site w/ ID=2 will always be loaded. + */ + public function addReport( $category, $title, $action, $params = array() ) + { + list($module, $action) = explode('.', $action); + $params = array('module' => $module, 'action' => $action) + $params; + + $categories = $this->dimensionCategories; + $categories[$category][] = array( + 'title' => $title, + 'params' => $params, + 'url' => Piwik_Url::getCurrentQueryStringWithParametersModified($params) + ); + $this->dimensionCategories = $categories; + } + + /** + * Adds a set of reports to the list of reports to display. + * + * @param array $reports An array containing report information. The array requires + * the 'category', 'title', 'action' and 'params' elements. + * For information on what they should contain, @see addReport. + */ + public function addReports( $reports ) + { + foreach ($reports as $report) + { + $this->addReport($report['category'], $report['title'], $report['action'], $report['params']); + } + } + + /** + * Renders this view. + * + * @return string The rendered view. + */ + public function render() + { + $this->firstReport = ""; + + // if there are reports & report categories added, render the first one so we can + // display it initially + $categories = $this->dimensionCategories; + if (!empty($categories)) + { + $firstReportInfo = reset(reset($categories)); + + $oldGet = $_GET; + $oldPost = $_POST; + + foreach ($firstReportInfo['params'] as $key => $value) + { + $_GET[$key] = $value; + } + + $_POST = array(); + + $module = $firstReportInfo['params']['module']; + $action = $firstReportInfo['params']['action']; + $this->firstReport = Piwik_FrontController::getInstance()->fetchDispatch($module, $action); + + $_GET = $oldGet; + $_POST = $oldPost; + } + + return parent::render(); + } +} diff --git a/plugins/CoreHome/templates/misc.js b/plugins/CoreHome/templates/misc.js index 3c8d2a1179..ab542b802f 100755 --- a/plugins/CoreHome/templates/misc.js +++ b/plugins/CoreHome/templates/misc.js @@ -76,6 +76,50 @@ $(document).ready(function() { return false; }); + + // + // reports by dimension list behavior + // + + // when a report dimension is clicked, load the appropriate report + var currentWidgetLoading = null; + $('body').on('click', '.reportDimension', function (e) { + var view = $(this).closest('.reportsByDimensionView'), + report = $('.dimensionReport', view), + loading = $('.loadingPiwik', view); + + // make this dimension the active one + $('.activeDimension', view).removeClass('activeDimension'); + $(this).addClass('activeDimension'); + + // hide the visible report & show the loading elem + report.hide(); + loading.show(); + + // load the report using the data-url attribute (which holds the URL to the report) + var widgetParams = broadcast.getValuesFromUrl($(this).attr('data-url')); + for (var key in widgetParams) + { + widgetParams[key] = decodeURIComponent(widgetParams[key]); + } + + var widgetUniqueId = widgetParams.module + widgetParams.action; + currentWidgetLoading = widgetUniqueId; + + widgetsHelper.loadWidgetAjax(widgetUniqueId, widgetParams, function(response) { + // if the widget that was loaded was not for the latest clicked link, do nothing w/ the response + if (widgetUniqueId != currentWidgetLoading) + { + return; + } + + loading.hide(); + report.html($(response)).css('display', 'inline-block'); + + // scroll to report + piwikHelper.lazyScrollTo(report, 400); + }); + }); }); }(jQuery)); diff --git a/plugins/CoreHome/templates/reports_by_dimension.tpl b/plugins/CoreHome/templates/reports_by_dimension.tpl new file mode 100644 index 0000000000..fd7689138a --- /dev/null +++ b/plugins/CoreHome/templates/reports_by_dimension.tpl @@ -0,0 +1,27 @@ +<div class="reportsByDimensionView"> + +<div class="entityList"> +{foreach from=$dimensionCategories key=category item=dimensions name=dimensionCategories} + <div class='dimensionCategory'> + {$category|translate} + <ul class='listCircle'> + {foreach from=$dimensions key=idx item=dimension} + <li class="reportDimension {if $idx eq 0 && $smarty.foreach.dimensionCategories.index eq 0}activeDimension{/if}" data-url="{$dimension.url}"> + <span class='dimension'>{$dimension.title|translate}</span> + </li> + {/foreach} + </ul> + </div> +{/foreach} +</div> + +<div style="float:left;"> + <div class="loadingPiwik" style="display:none"> + <img src="themes/default/images/loading-blue.gif" alt="" />{'General_LoadingData'|translate} + </div> + + <div class="dimensionReport">{$firstReport}</div> +</div> +<div class="clear"></div> + +</div> diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php index 9af8a8d227..880fdab903 100644 --- a/plugins/Goals/Controller.php +++ b/plugins/Goals/Controller.php @@ -63,7 +63,6 @@ class Piwik_Goals_Controller extends Piwik_Controller { $view = $this->getGoalReportView($idGoal = Piwik_Common::getRequestVar('idGoal', null, 'string')); $view->displayFullReport = true; - $view->goalDimensions = Piwik_Goals::getReportsWithGoalMetrics(); echo $view->render(); } @@ -76,7 +75,6 @@ class Piwik_Goals_Controller extends Piwik_Controller $view = $this->getGoalReportView($idGoal = Piwik_Archive::LABEL_ECOMMERCE_ORDER); $view->displayFullReport = true; - $view->goalDimensions = Piwik_Goals::getReportsWithGoalMetrics(); echo $view->render(); } protected function getItemsView($fetch, $type, $function, $api, $abandonedCart = false) @@ -170,7 +168,7 @@ class Piwik_Goals_Controller extends Piwik_Controller { $goalDefinition['name'] = Piwik_Translate('Goals_Ecommerce'); $goalDefinition['allow_multiple'] = true; - $view->ecommerce = true; + $ecommerce = $view->ecommerce = true; } else { @@ -209,6 +207,8 @@ class Piwik_Goals_Controller extends Piwik_Controller $segment = 'visitorType==new'; $conversionRateNew = Piwik_Goals_API::getInstance()->getConversionRate($this->idSite, Piwik_Common::getRequestVar('period'), Piwik_Common::getRequestVar('date'), $segment, $idGoal); $view->conversion_rate_new = $this->formatConversionRate($conversionRateNew); + $view->goalReportsByDimension = $this->getGoalReportsByDimensionTable( + $view->nb_conversions, isset($ecommerce), !empty($view->cart_nb_conversions)); return $view; } @@ -216,7 +216,6 @@ class Piwik_Goals_Controller extends Piwik_Controller { $view = $this->getOverviewView(); $view->goalsJSON = Piwik_Common::json_encode($this->goals); - $view->goalDimensions = Piwik_Goals::getReportsWithGoalMetrics(); $view->userCanEditGoals = Piwik::isUserHasAdminAccess($this->idSite); $view->ecommerceEnabled = $this->site->isEcommerceEnabled(); $view->displayFullReport = true; @@ -262,6 +261,8 @@ class Piwik_Goals_Controller extends Piwik_Controller $view->goalMetrics = $goalMetrics; $view->goals = $this->goals; + $view->goalReportsByDimension = $this->getGoalReportsByDimensionTable( + $view->nb_conversions, $ecommerce = false, !empty($view->cart_nb_conversions)); return $view; } @@ -504,6 +505,69 @@ class Piwik_Goals_Controller extends Piwik_Controller $view->disableOffsetInformationAndPaginationControls(); return $this->renderView($view, $fetch); } + + /** + * Utility function that returns HTML that displays Goal information for reports. This + * is the HTML that is at the bottom of every goals page. + * + * @param int $conversions The number of conversions for this goal (or all goals + * in case of the overview). + * @param bool $ecommerce Whether to show ecommerce reports or not. + * @param bool $cartNbConversions Whether there are cart conversions or not for this + * goal. + */ + private function getGoalReportsByDimensionTable( $conversions, $ecommerce = false, $cartNbConversions = false ) + { + $preloadAbandonedCart = $cartNbConversions !== false && $conversions == 0; + + $goalReportsByDimension = new Piwik_View_ReportsByDimension(); + + // add ecommerce reports + $ecommerceCustomParams = array(); + if ($ecommerce) + { + if ($preloadAbandonedCart) + { + $ecommerceCustomParams['viewDataTable'] = 'ecommerceAbandonedCart'; + $ecommerceCustomParams['filterEcommerce'] = 2; + } + + $goalReportsByDimension->addReport( + 'Goals_EcommerceReports', 'Goals_ProductSKU', 'Goals.getItemsSku', $ecommerceCustomParams); + $goalReportsByDimension->addReport( + 'Goals_EcommerceReports', 'Goals_ProductName', 'Goals.getItemsName', $ecommerceCustomParams); + $goalReportsByDimension->addReport( + 'Goals_EcommerceReports', 'Goals_ProductCategory', 'Goals.getItemsCategory', $ecommerceCustomParams); + $goalReportsByDimension->addReport( + 'Goals_EcommerceReports', 'Goals_EcommerceLog', 'Goals.getEcommerceLog', $ecommerceCustomParams); + } + + if ($conversions > 0) + { + // for non-Goals reports, we show the goals table + $customParams = $ecommerceCustomParams // TODO: not sure if this is necessary. only here to + // replicate logic of old code in table_by_dimension.tpl + + array('viewDataTable' => 'tableGoals', 'documentationForGoalsPage' => '1'); + + if (Piwik_Common::getRequestVar('idGoal', '') === '') // if no idGoal, use 0 for overview + { + $customParams['idGoal'] = '0'; // NOTE: Must be string! Otherwise Piwik_View_HtmlTable_Goals fails. + } + + $allReports = Piwik_Goals::getReportsWithGoalMetrics(); + foreach ($allReports as $category => $reports) + { + $categoryText = Piwik_Translate('Goals_ViewGoalsBy', $category); + foreach ($reports as $report) + { + $goalReportsByDimension->addReport( + $categoryText, $report['name'], $report['module'].'.'.$report['action'], $customParams); + } + } + } + + return $goalReportsByDimension->render(); + } } diff --git a/plugins/Goals/templates/goals.css b/plugins/Goals/templates/goals.css index 8b781a2c26..b27176beac 100644 --- a/plugins/Goals/templates/goals.css +++ b/plugins/Goals/templates/goals.css @@ -22,11 +22,3 @@ ul.ulGoalTopElements { border-bottom:1px dotted #0033CC; line-height:2em; } -.goalDimensions{ - float: left; - width: 220px; - min-height:450px; -} -.dimensionCategory { - margin-top:10px; -} diff --git a/plugins/Goals/templates/overview.tpl b/plugins/Goals/templates/overview.tpl index 6fd942a6f0..200260f36b 100644 --- a/plugins/Goals/templates/overview.tpl +++ b/plugins/Goals/templates/overview.tpl @@ -32,8 +32,15 @@ {/foreach} {if $displayFullReport} -{assign var=nb_conversions value=$sum_nb_conversions} -{include file="Goals/templates/table_by_dimension.tpl"} +<h2 id='titleGoalsByDimension'> +{if isset($idGoal)} + {'Goals_GoalConversionsBy'|translate:$goalName} +{else} + {'Goals_ConversionsOverviewBy'|translate} +{/if} +</h2> + +{$goalReportsByDimension} {if $userCanEditGoals} {include file="Goals/templates/add_edit_goal.tpl"} diff --git a/plugins/Goals/templates/single_goal.tpl b/plugins/Goals/templates/single_goal.tpl index 4ebba700ea..a65d0a0cdd 100644 --- a/plugins/Goals/templates/single_goal.tpl +++ b/plugins/Goals/templates/single_goal.tpl @@ -31,6 +31,14 @@ $(document).ready( function() { {if $displayFullReport} {if $nb_conversions > 0 || !empty($cart_nb_conversions)} - {include file="Goals/templates/table_by_dimension.tpl"} + <h2 id='titleGoalsByDimension'> + {if isset($idGoal)} + {'Goals_GoalConversionsBy'|translate:$goalName} + {else} + {'Goals_ConversionsOverviewBy'|translate} + {/if} + </h2> + + {$goalReportsByDimension} {/if} {/if} diff --git a/plugins/Goals/templates/table_by_dimension.tpl b/plugins/Goals/templates/table_by_dimension.tpl deleted file mode 100644 index 6add478be0..0000000000 --- a/plugins/Goals/templates/table_by_dimension.tpl +++ /dev/null @@ -1,108 +0,0 @@ -<h2 id='titleGoalsByDimension'>{if isset($idGoal)} - {'Goals_GoalConversionsBy'|translate:$goalName} - {else}{'Goals_ConversionsOverviewBy'|translate}{/if}</h2> - -<div class='entityList goalDimensions'> - {if isset($ecommerce)} - <div class='dimensionCategory'> - {'Goals_EcommerceReports'|translate} - <ul class='listCircle'> - <li class='goalDimension' module='Goals' action='getItemsSku'> - <span class='dimension'>{'Goals_ProductSKU'|translate}</span> - </li> - <li class='goalDimension' module='Goals' action='getItemsName'> - <span class='dimension'>{'Goals_ProductName'|translate}</span> - </li> - </li> - <li class='goalDimension' module='Goals' action='getItemsCategory'> - <span class='dimension'>{'Goals_ProductCategory'|translate}</span> - </li> - <li class='goalDimension' module='Goals' action='getEcommerceLog'> - <span class='dimension'>{'Goals_EcommerceLog'|translate}</span> - </li> - </ul> - </div> - {/if} - {if $nb_conversions > 0 } - {foreach from=$goalDimensions key=dimensionFamilyName item=dimensions} - <div class='dimensionCategory'> - {'Goals_ViewGoalsBy'|translate:$dimensionFamilyName} - <ul class='listCircle'> - {foreach from=$dimensions item=dimension} - <li title='{'Goals_ViewGoalsBy'|translate:$dimension.name}' class='goalDimension' module='{$dimension.module}' action='{$dimension.action}'> - <span class='dimension'>{$dimension.name}</span> - </li> - {/foreach} - </ul> - </div> - {/foreach} - {/if} -</div> - -<div style='float: left;'> - {ajaxLoadingDiv id=tableGoalsLoading} - - <div id='tableGoalsByDimension'></div> -</div> -<div class="clear"></div> -<script type="text/javascript"> -var preloadAbandonedCart = {if !empty($cart_nb_conversions) && $nb_conversions == 0}1{else}0{/if}; -{literal} -$(document).ready( function() { - var countLoaded = 0; - /* - * For each 'dimension' in the list, a click will trigger an ajax request to load the datatable - * showing Goals metrics (conversion, conv. rates, revenue) for this dimension - */ - $('.goalDimension').click( function() { - var self = this; - $('.goalDimension').removeClass('activeDimension'); - $(this).addClass('activeDimension'); - var module = $(this).attr('module'); - var action = $(this).attr('action'); - widgetUniqueId = module+action; - self.expectedWidgetUniqueId = widgetUniqueId; - - var widgetParameters = { - 'module': module, - 'action': action - }; - var idGoal = broadcast.getValueFromHash('idGoal'); - widgetParameters['idGoal'] = idGoal.length ? idGoal : 0; //Piwik_DataTable_Filter_AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE; - - // Loading segment table means loading Goals view for Top Countries/etc. - if(module != 'Goals') { - widgetParameters['viewDataTable'] = 'tableGoals'; - // 0 is Piwik_DataTable_Filter_AddColumnsProcessedMetricsGoal::GOALS_FULL_TABLE - widgetParameters['documentationForGoalsPage'] = 1; - } - - if(preloadAbandonedCart) { - widgetParameters['viewDataTable'] = 'ecommerceAbandonedCart'; - widgetParameters['filterEcommerce'] = 2; - } - var onWidgetLoadedCallback = function (response) { - if(widgetUniqueId != self.expectedWidgetUniqueId) { - return; - } - $('#tableGoalsByDimension').html($(response)); - $('#tableGoalsLoading').hide(); - $('#tableGoalsByDimension').show(); - - countLoaded++; - // only scroll down to the loaded datatable if this is not the first one - // otherwise, screen would jump down to the table when loading the report - if(countLoaded > 1) - { - piwikHelper.lazyScrollTo("#titleGoalsByDimension", 400); - } - }; - $('#tableGoalsByDimension').hide(); - $('#tableGoalsLoading').show(); - - widgetsHelper.loadWidgetAjax(widgetUniqueId, widgetParameters, onWidgetLoadedCallback); - }); - $('.goalDimension').first().click(); -}); -</script> -{/literal} diff --git a/themes/default/common.css b/themes/default/common.css index 8c966df8b5..2a00222315 100644 --- a/themes/default/common.css +++ b/themes/default/common.css @@ -779,3 +779,11 @@ table.entityTable tr td a { opacity:0.75; } +.reportsByDimensionView > .entityList { + float: left; + width: 220px; + min-height:450px; +} +.dimensionCategory { + margin-top:10px; +} |