Skip to content

Commit

Permalink
Refs #3089, #4116, display visitor profile popup when visit in realti…
Browse files Browse the repository at this point in the history
…me map is clicked.

Notes:
  - Includes new UIControl base type.
  - Fixes cleanup bugs in realtime map and popover closing.
  - Refactored realtime map so as little JavaScript as possible is included in HTML fragments.
  - Allow more than one realtime map to exist on a single page.
  • Loading branch information
Benaka Moorthi committed Sep 11, 2013
1 parent 94eff35 commit 6d884e1
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 105 deletions.
1 change: 1 addition & 0 deletions plugins/CoreHome/CoreHome.php
Expand Up @@ -72,6 +72,7 @@ public function getJsFiles(&$jsFiles)
$jsFiles[] = "plugins/Zeitgeist/javascripts/piwikHelper.js";
$jsFiles[] = "plugins/Zeitgeist/javascripts/ajaxHelper.js";
$jsFiles[] = "plugins/CoreHome/javascripts/require.js";
$jsFiles[] = "plugins/CoreHome/javascripts/uiControl.js";
$jsFiles[] = "plugins/CoreHome/javascripts/dataTable.js";
$jsFiles[] = "plugins/CoreHome/javascripts/dataTable_rowactions.js";
$jsFiles[] = "plugins/CoreHome/javascripts/popover.js";
Expand Down
3 changes: 3 additions & 0 deletions plugins/CoreHome/javascripts/broadcast.js
Expand Up @@ -130,6 +130,9 @@ var broadcast = {
// make sure the "Widgets & Dashboard" is deleted on reload
$('#dashboardSettings').remove();
$('#dashboardWidgetsArea').dashboard('destroy');

// remove unused controls
require('piwik/UI').UIControl.cleanupUnusedControls();
}
}

Expand Down
1 change: 1 addition & 0 deletions plugins/CoreHome/javascripts/popover.js
Expand Up @@ -45,6 +45,7 @@ var Piwik_Popover = (function () {
$('.ui-widget-overlay').off('click.popover');
isOpen = false;
broadcast.propagateNewPopoverParameter(false);
require('piwik/UI').UIControl.cleanupUnusedControls();
if (typeof closeCallback == 'function') {
closeCallback();
closeCallback = false;
Expand Down
75 changes: 75 additions & 0 deletions plugins/CoreHome/javascripts/uiControl.js
@@ -0,0 +1,75 @@
/**
* Piwik - Web Analytics
*
* Visitor profile popup control.
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/

(function ($, require) {

var exports = require('piwik/UI');

/**
* Base type for Piwik UI controls. Provides functionality that all controls need (such as
* cleanup on destruction).
*
* @param {Element} element The root element of the control.
*/
var UIControl = function (element) {
this._controlIndex = UIControl._controls.length;
UIControl._controls.push(this);

var $element = this.$element = $(element);
$element.data('uiControlObject', this);
};

/**
* Contains all active control instances.
*/
UIControl._controls = [];

/**
* Utility method that will clean up all piwik UI controls whose elements are not attached
* to the DOM.
*
* TODO: instead of having other pieces of the UI manually calling cleanupUnusedControls,
* MutationObservers should be called
*/
UIControl.cleanupUnusedControls = function () {
var controls = UIControl._controls;

for (var i = 0; i != controls.length; ++i) {
var control = controls[i];
if (control.$element
&& !$.contains(document.documentElement, control.$element[0])
) {
controls[i] = null;
control._destroy();

if (!control._baseDestroyCalled) {
throw new Error("Error: " + control.constructor.name + "'s destroy method does not call " +
"UIControl.destroy. You may have a memory leak.");
}
}
}
};

UIControl.prototype = {

/**
* Perform cleanup. Called when the control has been removed from the DOM. Derived
* classes should overload this function to perform their own cleanup.
*/
_destroy: function () {
this.$element.removeData('uiControlObject');
delete this.$element;

this._baseDestroyCalled = true;
},
};

exports.UIControl = UIControl;

})(jQuery, require);
1 change: 1 addition & 0 deletions plugins/Dashboard/javascripts/dashboardWidget.js
Expand Up @@ -68,6 +68,7 @@
}
$('*', this.element).off('.dashboardWidget'); // unbind all events
$('.widgetContent', this.element).trigger('widget:destroy');
require('piwik/UI').UIControl.cleanupUnusedControls();
return this;
},

Expand Down
12 changes: 8 additions & 4 deletions plugins/Live/javascripts/visitorProfile.js
Expand Up @@ -10,7 +10,8 @@
(function ($, require) {

var piwik = require('piwik'),
exports = require('piwik/UI');
exports = require('piwik/UI'),
UIControl = exports.UIControl;

/**
* Sets up and handles events for the visitor profile popup.
Expand All @@ -20,7 +21,7 @@
* @constructor
*/
var VisitorProfileControl = function (element) {
this.$element = $(element).focus();
UIControl.call(this, element);
this._setupControl();
this._bindEventCallbacks();
};
Expand Down Expand Up @@ -53,9 +54,12 @@
Piwik_Popover.createPopupAndLoadUrl(url, '', 'visitor-profile-popup');
};

VisitorProfileControl.prototype = {
$.extend(VisitorProfileControl.prototype, UIControl.prototype, {

_setupControl: function () {
// focus the popup so it will accept key events
this.$element.focus();

// highlight the first visit
$('.visitor-profile-visits>li:first-child', this.$element).addClass('visitor-profile-current-visit');
},
Expand Down Expand Up @@ -232,7 +236,7 @@
_inWidget: function () {
return !! this.$element.closest('.widget').length;
}
};
});

exports.VisitorProfileControl = VisitorProfileControl;

Expand Down
67 changes: 40 additions & 27 deletions plugins/UserCountryMap/Controller.php
Expand Up @@ -131,40 +131,50 @@ public function realtimeMap($standalone = false, $fetch = false, $segmentOverrid

$view->metrics = $this->getMetrics($idSite, 'range', self::REAL_TIME_WINDOW, $token_auth);
$view->defaultMetric = 'nb_visits';
$view->liveRefreshAfterMs = (int)Config::getInstance()->General['live_widget_refresh_after_seconds'] * 1000;
$liveRefreshAfterMs = (int)Config::getInstance()->General['live_widget_refresh_after_seconds'] * 1000;

$goals = API::getInstance()->getGoals($idSite);
$site = new Site($idSite);
$view->hasGoals = !empty($goals) || $site->isEcommerceEnabled() ? 'true' : 'false';
$hasGoals = !empty($goals) || $site->isEcommerceEnabled();

// maximum number of visits to be displayed in the map
$view->maxVisits = Common::getRequestVar('format_limit', 100, 'int');
$maxVisits = Common::getRequestVar('format_limit', 100, 'int');

// some translations
$view->localeJSON = json_encode(array(
'nb_actions' => Piwik_Translate('VisitsSummary_NbActionsDescription'),
'local_time' => Piwik_Translate('VisitTime_ColumnLocalTime'),
'from' => Piwik_Translate('General_FromReferrer'),
'seconds' => Piwik_Translate('UserCountryMap_Seconds'),
'seconds_ago' => Piwik_Translate('UserCountryMap_SecondsAgo'),
'minutes' => Piwik_Translate('UserCountryMap_Minutes'),
'minutes_ago' => Piwik_Translate('UserCountryMap_MinutesAgo'),
'hours' => Piwik_Translate('UserCountryMap_Hours'),
'hours_ago' => Piwik_Translate('UserCountryMap_HoursAgo'),
'days_ago' => Piwik_Translate('UserCountryMap_DaysAgo'),
'actions' => Piwik_Translate('VisitsSummary_NbPageviewsDescription'),
'searches' => Piwik_Translate('UserCountryMap_Searches'),
'goal_conversions' => Piwik_Translate('UserCountryMap_GoalConversions'),
));
$locale = array(
'nb_actions' => Piwik_Translate('VisitsSummary_NbActionsDescription'),
'local_time' => Piwik_Translate('VisitTime_ColumnLocalTime'),
'from' => Piwik_Translate('General_FromReferrer'),
'seconds' => Piwik_Translate('UserCountryMap_Seconds'),
'seconds_ago' => Piwik_Translate('UserCountryMap_SecondsAgo'),
'minutes' => Piwik_Translate('UserCountryMap_Minutes'),
'minutes_ago' => Piwik_Translate('UserCountryMap_MinutesAgo'),
'hours' => Piwik_Translate('UserCountryMap_Hours'),
'hours_ago' => Piwik_Translate('UserCountryMap_HoursAgo'),
'days_ago' => Piwik_Translate('UserCountryMap_DaysAgo'),
'actions' => Piwik_Translate('VisitsSummary_NbPageviewsDescription'),
'searches' => Piwik_Translate('UserCountryMap_Searches'),
'goal_conversions' => Piwik_Translate('UserCountryMap_GoalConversions'),
);

$segment = $segmentOverride ?: Request::getRawSegmentFromRequest() ?: '';
$view->reqParamsJSON = $this->getEnrichedRequest(array(
'period' => 'range',
'idSite' => $idSite,
'date' => self::REAL_TIME_WINDOW,
'segment' => $segment,
'token_auth' => $token_auth,
));
$reqParams = $this->getEnrichedRequest(array(
'period' => 'range',
'idSite' => $idSite,
'date' => self::REAL_TIME_WINDOW,
'segment' => $segment,
'token_auth' => $token_auth,
), $encode = false);

$view->config = array(
'metrics' => array(),
'svgBasePath' => $view->piwikUrl . 'plugins/UserCountryMap/svg/',
'liveRefreshAfterMs' => $liveRefreshAfterMs,
'_' => $locale,
'reqParams' => $reqParams,
'siteHasGoals' => $hasGoals,
'maxVisits' => $maxVisits
);

if ($fetch) {
return $view->render();
Expand All @@ -173,7 +183,7 @@ public function realtimeMap($standalone = false, $fetch = false, $segmentOverrid
}
}

private function getEnrichedRequest($params)
private function getEnrichedRequest($params, $encode = true)
{
$params['format'] = 'json';
$params['showRawMetrics'] = 1;
Expand All @@ -184,7 +194,10 @@ private function getEnrichedRequest($params)
}
}

return Common::json_encode($params);
if ($encode) {
$params = Common::json_encode($params);
}
return $params;
}

private function checkUserCountryPluginEnabled()
Expand Down

0 comments on commit 6d884e1

Please sign in to comment.