site-accueil-insa/matomo/plugins/Transitions/javascripts/transitions.js

1704 lines
61 KiB
JavaScript

/*!
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
//
// TRANSITIONS ROW ACTION FOR DATA TABLES
//
function DataTable_RowActions_Transitions(dataTable) {
this.dataTable = dataTable;
this.transitions = null;
}
DataTable_RowActions_Transitions.prototype = new DataTable_RowAction;
/** Static helper method to launch transitions from anywhere */
DataTable_RowActions_Transitions.launchForUrl = function (url, segment) {
var value = 'Transitions:url:' + url;
if (segment) {
value += ':segment:' + segment;
}
broadcast.propagateNewPopoverParameter('RowAction', value);
};
DataTable_RowActions_Transitions.isPageUrlReport = function (module, action) {
return module == 'Actions' &&
(action == 'getPageUrls' || action == 'getEntryPageUrls' || action == 'getExitPageUrls' || action == 'getPageUrlsFollowingSiteSearch');
};
DataTable_RowActions_Transitions.isPageTitleReport = function (module, action) {
return module == 'Actions' && (action == 'getPageTitles' || action == 'getPageTitlesFollowingSiteSearch');
};
DataTable_RowActions_Transitions.registeredReports = [];
DataTable_RowActions_Transitions.registerReport = function (handler) {
DataTable_RowActions_Transitions.registeredReports.push(handler);
}
DataTable_RowActions_Transitions.prototype.trigger = function (tr, e, subTableLabel) {
var i = 0;
for (i; i < DataTable_RowActions_Transitions.registeredReports.length; i++) {
var report = DataTable_RowActions_Transitions.registeredReports[i];
if (report
&& report.trigger
&& report.isAvailableOnReport
&& report.isAvailableOnReport(this.dataTable.param)) {
report.trigger.apply(this, arguments);
return;
}
}
alert('Transitions can\'t be used on this report.');
};
DataTable_RowActions_Transitions.prototype.performAction = function (label, tr, e) {
var separator = ' > '; // LabelFilter::SEPARATOR_RECURSIVE_LABEL
var labelParts = label.split(separator);
for (var i = 0; i < labelParts.length; i++) {
var labelPart = labelParts[i].replace('@', '');
labelParts[i] = $.trim(decodeURIComponent(labelPart));
}
var delimiter = piwik.config.action_url_category_delimiter;
if(this.dataTable.param.action.indexOf('PageTitles') !== false) {
delimiter = piwik.config.action_title_category_delimiter;
}
label = labelParts.join(delimiter);
this.openPopover('title:' + label);
};
DataTable_RowActions_Transitions.prototype.doOpenPopover = function (link) {
var ALLOWED_OVERRIDE_PARAMS = ['segment', 'date', 'period', 'idSite'];
var parts = link.split(':');
var overrideParams = {};
var i = 0;
while (i < parts.length) {
var paramName = decodeURIComponent(parts[i]);
if (ALLOWED_OVERRIDE_PARAMS.indexOf(paramName) === -1) {
i += 1;
continue;
}
overrideParams[paramName] = decodeURIComponent(parts[i + 1]);
parts.splice(i, 2);
}
if (parts.length < 2) {
return;
}
var actionType = parts[0];
parts.shift();
var actionName = parts.join(':');
if (this.transitions === null) {
this.transitions = new Piwik_Transitions(actionType, actionName, this, overrideParams);
} else {
this.transitions.reset(actionType, actionName, segment);
}
this.transitions.showPopover();
};
DataTable_RowActions_Registry.register({
name: 'Transitions',
dataTableIcon: 'icon-transition',
order: 20,
dataTableIconTooltip: [
_pk_translate('General_TransitionsRowActionTooltipTitle'),
_pk_translate('General_TransitionsRowActionTooltip')
],
createInstance: function (dataTable) {
return new DataTable_RowActions_Transitions(dataTable);
},
isAvailableOnReport: function (dataTableParams) {
if (piwik.transitionsMaxPeriodAllowed && dataTableParams['period']) {
if (dataTableParams['period'] === 'range') {
var piwikPeriods = piwikHelper.getAngularDependency('piwikPeriods');
if (piwikPeriods) {
var range = piwikPeriods.parse(dataTableParams['period'], dataTableParams['date']);
if (range) {
var rangeDays = range.getDayCount();
if ((piwik.transitionsMaxPeriodAllowed === 'day' && rangeDays > 1) ||
(piwik.transitionsMaxPeriodAllowed === 'week' && rangeDays > 7) ||
(piwik.transitionsMaxPeriodAllowed === 'month' && rangeDays > 31) ||
(piwik.transitionsMaxPeriodAllowed === 'year' && rangeDays > 365))
{
return false;
}
}
}
} else {
if (piwik.transitionsMaxPeriodAllowed === 'day' && dataTableParams['period'] !== 'day') {
return false;
}
if (piwik.transitionsMaxPeriodAllowed === 'week' && dataTableParams['period'] !== 'day'
&& dataTableParams['period'] !== 'week') {
return false;
}
if (piwik.transitionsMaxPeriodAllowed === 'month' && dataTableParams['period'] !== 'day'
&& dataTableParams['period'] !== 'week' && dataTableParams['period'] !== 'month') {
return false;
}
if (piwik.transitionsMaxPeriodAllowed === 'year' && dataTableParams['period'] !== 'day'
&& dataTableParams['period'] !== 'week' && dataTableParams['period'] !== 'month'
&& dataTableParams['period'] !== 'year'
) {
return false;
}
}
}
var i = 0;
for (i; i < DataTable_RowActions_Transitions.registeredReports.length; i++) {
var report = DataTable_RowActions_Transitions.registeredReports[i];
if (report
&& report.isAvailableOnReport
&& report.isAvailableOnReport(dataTableParams)) {
return true;
}
}
return false;
},
isAvailableOnRow: function (dataTableParams, tr) {
if (tr.hasClass('subDataTable') || tr.hasClass('totalsRow')) {
// not available on groups (i.e. folders)
return false;
}
var i = 0;
for (i; i < DataTable_RowActions_Transitions.registeredReports.length; i++) {
var report = DataTable_RowActions_Transitions.registeredReports[i];
if (report
&& report.isAvailableOnRow
&& report.isAvailableOnReport
&& report.isAvailableOnReport(dataTableParams)) {
return report.isAvailableOnRow(dataTableParams, tr);
}
}
return true;
}
});
//
// TRANSITIONS IMPLEMENTATION
//
function Piwik_Transitions(actionType, actionName, rowAction, overrideParams) {
this.reset(actionType, actionName, overrideParams);
this.rowAction = rowAction;
this.ajax = new Piwik_Transitions_Ajax();
this.model = new Piwik_Transitions_Model(this.ajax);
this.leftGroups = ['previousPages', 'previousSiteSearches', 'searchEngines', 'socialNetworks', 'websites', 'campaigns'];
this.rightGroups = ['followingPages', 'followingSiteSearches', 'downloads', 'outlinks'];
}
Piwik_Transitions.prototype.reset = function (actionType, actionName, overrideParams) {
this.actionType = actionType;
this.actionName = actionName;
this.overrideParams = overrideParams;
this.popover = null;
this.canvas = null;
this.centerBox = null;
this.leftOpenGroup = 'previousPages';
this.rightOpenGroup = 'followingPages';
this.highlightedGroup = false;
this.highlightedGroupSide = false;
this.highlightedGroupCenterEl = false;
};
/** Open the popover */
Piwik_Transitions.prototype.showPopover = function (showEmbeddedInReport) {
var self = this;
this.showEmbeddedInReport = showEmbeddedInReport;
$('#transitions_report .popoverContainer').hide();
if (showEmbeddedInReport) {
this.popover = $('#transitions_report');
$('#Transitions_Error_Container').hide();
$('#transitions_inline_loading').show();
} else {
this.popover = Piwik_Popover.showLoading('Transitions', self.actionName, 550);
Piwik_Popover.addHelpButton('https://matomo.org/docs/transitions');
}
var bothLoaded = function () {
if (!showEmbeddedInReport) {
Piwik_Popover.setContent(Piwik_Transitions.popoverHtml);
} else {
$('#transitions_inline_loading').hide();
$('#transitions_report .popoverContainer').html(Piwik_Transitions.popoverHtml);
$('#transitions_report .popoverContainer').show();
}
self.preparePopover();
self.model.htmlLoaded();
if (self.model.searchEnginesNbTransitions > 0 && self.model.websitesNbTransitions > 0 && self.model.socialNetworksNbTransitions > 0
&& self.model.campaignsNbTransitions > 0) {
self.canvas.narrowMode();
}
self.render();
self.canvas.truncateVisibleBoxTexts();
};
// load the popover HTML (only done once)
var callbackForHtml = false;
if (typeof Piwik_Transitions.popoverHtml == 'undefined') {
this.ajax.callTransitionsController('renderPopover', function (html) {
Piwik_Transitions.popoverHtml = html;
if (callbackForHtml !== false) {
callbackForHtml();
}
});
}
// load the data
self.model.loadData(self.actionType, self.actionName, self.overrideParams, function () {
if (typeof Piwik_Transitions.popoverHtml == 'undefined') {
// html not there yet
callbackForHtml = bothLoaded;
} else {
// html already loaded
bothLoaded();
}
});
};
/** Prepare the popover with the basic DOM to add data later. */
Piwik_Transitions.prototype.preparePopover = function () {
var self = this;
var width = 900;
var height = 550;
var canvasBgLeft = self.prepareCanvas('Background_Left', width, height);
var canvasBgRight = self.prepareCanvas('Background_Right', width, height);
var canvasLeft = self.prepareCanvas('Left', width, height);
var canvasRight = self.prepareCanvas('Right', width, height);
var canvasLoops = self.prepareCanvas('Loops', width, height);
self.canvas = new Piwik_Transitions_Canvas(canvasBgLeft, canvasBgRight, canvasLeft, canvasRight,
canvasLoops, width, height);
self.centerBox = self.popover.find('#Transitions_CenterBox');
var title = self.actionName;
if (self.actionType == 'url') {
title = Piwik_Transitions_Util.shortenUrl(title, true);
}
var h2 = self.centerBox.find('h2');
var textContainer = h2;
if (self.actionType == 'url') {
var a = $(document.createElement('a'));
a.attr('href', self.actionName);
a.attr('rel', 'noreferrer noopener');
a.attr('target', '_blank');
h2.append(a);
textContainer = a;
}
textContainer.addClass('Transitions_ApplyTextAndTruncate')
.data('text', title)
.data('maxLines', 3);
var element = textContainer.add(self.popover.find('p.Transitions_Pageviews'));
element.tooltip({
track: true,
content: function () {
var totalNbPageviews = self.model.getTotalNbPageviews();
if (totalNbPageviews > 0) {
var share = NumberFormatter.formatPercent(Math.round(self.model.pageviews / totalNbPageviews * 1000) / 10);
var text = Piwik_Transitions_Translations.ShareOfAllPageviews;
text = sprintf(text, NumberFormatter.formatNumber(self.model.pageviews), share);
text += '<br /><em>' + Piwik_Transitions_Translations.DateRange + ' ' + self.model.date + '</em>';
var title = '<h3>' + piwikHelper.addBreakpointsToUrl(self.actionName) + '</h3>';
return title + text;
}
return false;
},
items: '*',
tooltipClass: 'Transitions_Tooltip_Small',
show: false,
hide: false
});
};
Piwik_Transitions.prototype.prepareCanvas = function (canvasId, width, height) {
canvasId = 'Transitions_Canvas_' + canvasId;
var div = $('#' + canvasId).width(width).height(height);
var canvas;
if (typeof Piwik_Transitions.canvasCache == 'undefined'
|| typeof window.G_vmlCanvasManager != "undefined") {
// no recycling for excanvas because they are disposed properly anyway and
// recycling doesn't work this way in IE8
Piwik_Transitions.canvasCache = {};
}
if (typeof Piwik_Transitions.canvasCache[canvasId] == 'undefined') {
Piwik_Transitions.canvasCache[canvasId] = document.createElement('canvas');
canvas = Piwik_Transitions.canvasCache[canvasId];
canvas.width = width;
canvas.height = height;
} else {
canvas = Piwik_Transitions.canvasCache[canvasId];
canvas.getContext('2d').clearRect(0, 0, width, height);
}
div.append(canvas);
return canvas;
};
/** Render the popover content */
Piwik_Transitions.prototype.render = function () {
this.renderCenterBox();
this.renderLeftSide();
this.renderRightSide();
this.renderLoops();
var $rootScope = piwikHelper.getAngularDependency('$rootScope');
if ($rootScope) {
$rootScope.$emit('Transitions.dataChanged', {'actionType': this.actionType, 'actionName': this.actionName});
}
};
/** Render left side: referrer groups & direct entries */
Piwik_Transitions.prototype.renderLeftSide = function (onlyBg) {
this.renderGroups(this.leftGroups, this.leftOpenGroup, 'left', onlyBg);
this.renderEntries(onlyBg);
this.reRenderIfNeededToCenter('left', onlyBg);
};
/** Render right side: following pages & exits */
Piwik_Transitions.prototype.renderRightSide = function (onlyBg) {
this.renderGroups(this.rightGroups, this.rightOpenGroup, 'right', onlyBg);
this.renderExits(onlyBg);
this.reRenderIfNeededToCenter('right', onlyBg);
};
/** Helper method to render open and closed groups for both sides */
Piwik_Transitions.prototype.renderGroups = function (groups, openGroup, side, onlyBg) {
for (var i = 0; i < groups.length; i++) {
var groupName = groups[i];
if (groupName == openGroup) {
if (i != 0) {
var spacing = this.canvas.isNarrowMode() ? 7 : 13;
this.canvas.addBoxSpacing(spacing, side);
}
this.renderOpenGroup(groupName, side, onlyBg);
} else {
this.renderClosedGroup(groupName, side, onlyBg);
}
}
this.canvas.addBoxSpacing(13, side);
};
/**
* If one side doesn't have much information, it doesn't look good to start from y=0.
* In this case, add some spacing on top and redraw.
*/
Piwik_Transitions.prototype.reRenderIfNeededToCenter = function (side, onlyBg) {
var height = (side == 'left' ? this.canvas.leftBoxPositionY : this.canvas.rightBoxPositionY) - 20;
if (height < 460 && !this.reRendering) {
var yOffset = (460 - height) / 2;
this.canvas.clearSide(side, onlyBg);
this.canvas.addBoxSpacing(yOffset, side);
this.reRendering = true;
side == 'left' ? this.renderLeftSide(onlyBg) : this.renderRightSide(onlyBg);
this.reRendering = false;
}
};
/** Render the center box with the main metrics */
Piwik_Transitions.prototype.renderCenterBox = function () {
var box = this.centerBox;
Piwik_Transitions_Util.replacePlaceholderInHtml(
box.find('.Transitions_Pageviews'), NumberFormatter.formatNumber(this.model.pageviews));
var self = this;
var showMetric = function (cssClass, modelProperty, highlightCurveOnSide, groupCanBeExpanded) {
var el = box.find('.Transitions_' + cssClass);
Piwik_Transitions_Util.replacePlaceholderInHtml(el, NumberFormatter.formatNumber(self.model[modelProperty]));
if (self.model[modelProperty] == 0) {
el.addClass('Transitions_Value0');
} else {
self.addTooltipShowingPercentageOfAllPageviews(el, modelProperty);
var groupName = cssClass.charAt(0).toLowerCase() + cssClass.slice(1);
el.hover(function () {
self.highlightGroup(groupName, highlightCurveOnSide);
}, function () {
self.unHighlightGroup(groupName, highlightCurveOnSide);
});
if (groupCanBeExpanded) {
el.click(function () {
self.openGroup(highlightCurveOnSide, groupName);
}).css('cursor', 'pointer');
}
}
};
showMetric('DirectEntries', 'directEntries', 'left', false);
showMetric('PreviousSiteSearches', 'previousSiteSearchesNbTransitions', 'left', true);
showMetric('PreviousPages', 'previousPagesNbTransitions', 'left', true);
showMetric('SearchEngines', 'searchEnginesNbTransitions', 'left', true);
showMetric('SocialNetworks', 'socialNetworksNbTransitions', 'left', true);
showMetric('Websites', 'websitesNbTransitions', 'left', true);
showMetric('Campaigns', 'campaignsNbTransitions', 'left', true);
showMetric('FollowingPages', 'followingPagesNbTransitions', 'right', true);
showMetric('FollowingSiteSearches', 'followingSiteSearchesNbTransitions', 'right', true);
showMetric('Outlinks', 'outlinksNbTransitions', 'right', true);
showMetric('Downloads', 'downloadsNbTransitions', 'right', true);
showMetric('Exits', 'exits', 'right', false);
box.find('.Transitions_CenterBoxMetrics').show();
};
Piwik_Transitions.prototype.addTooltipShowingPercentageOfAllPageviews = function (element, metric) {
var tip = Piwik_Transitions_Translations.XOfAllPageviews;
var percentage = this.model.getPercentage(metric, true);
tip = sprintf(tip, '<strong>' + percentage + '</strong>');
element.tooltip({
track: true,
content: tip,
items: '*',
tooltipClass: 'Transitions_Tooltip_Small',
show: false,
hide: false
});
};
/** Render the loops (i.e. page reloads) */
Piwik_Transitions.prototype.renderLoops = function () {
if (this.model.loops == 0) {
return;
}
var loops = this.popover.find('#Transitions_Loops').show();
Piwik_Transitions_Util.replacePlaceholderInHtml(loops, NumberFormatter.formatNumber(this.model.loops));
this.addTooltipShowingPercentageOfAllPageviews(loops, 'loops');
this.canvas.renderLoops(this.model.getPercentage('loops'));
};
Piwik_Transitions.prototype.renderEntries = function (onlyBg) {
if (this.model.directEntries > 0) {
var self = this;
var isHighlighted = this.highlightedGroup == 'directEntries';
var gradient = this.canvas.createHorizontalGradient('entries', 'left', isHighlighted);
this.canvas.renderBox({
side: 'left',
onlyBg: onlyBg,
share: this.model.getPercentage('directEntries'),
gradient: gradient,
boxText: Piwik_Transitions_Translations.directEntries,
boxTextNumLines: 1,
boxTextCssClass: 'SingleLine',
smallBox: true,
onMouseOver: function () {
self.highlightGroup('directEntries', 'left');
},
onMouseOut: function () {
self.unHighlightGroup('directEntries', 'left');
}
});
this.canvas.addBoxSpacing(20, 'left');
}
};
Piwik_Transitions.prototype.renderExits = function (onlyBg) {
if (this.model.exits > 0) {
var self = this;
var isHighlighted = this.highlightedGroup == 'exits';
var gradient = this.canvas.createHorizontalGradient('exits', 'right', isHighlighted);
this.canvas.renderBox({
side: 'right',
onlyBg: onlyBg,
share: this.model.getPercentage('exits'),
gradient: gradient,
boxText: Piwik_Transitions_Translations.exits,
boxTextNumLines: 1,
boxTextCssClass: 'SingleLine',
smallBox: true,
onMouseOver: function () {
self.highlightGroup('exits', 'right');
},
onMouseOut: function () {
self.unHighlightGroup('exits', 'right');
}
});
this.canvas.addBoxSpacing(20, 'right');
}
};
/** Render the open group with the detailed data */
Piwik_Transitions.prototype.renderOpenGroup = function (groupName, side, onlyBg) {
var self = this;
// get data from the model
var nbTransitionsVarName = groupName + 'NbTransitions';
var nbTransitions = self.model[nbTransitionsVarName];
if (nbTransitions == 0) {
return;
}
var totalShare = this.model.getPercentage(nbTransitionsVarName);
var details = self.model.getDetailsForGroup(groupName);
// prepare gradients
var gradientItems = this.canvas.createHorizontalGradient('items', side);
var gradientOthers = this.canvas.createHorizontalGradient('others', side);
var gradientBackground =
this.canvas.createHorizontalGradient('background', side, groupName == this.highlightedGroup);
// remember current offsets to reset them later for drawing the background
var boxPositionBefore, curvePositionBefore;
if (side == 'left') {
boxPositionBefore = this.canvas.leftBoxPositionY;
curvePositionBefore = this.canvas.leftCurvePositionY;
} else {
boxPositionBefore = this.canvas.rightBoxPositionY;
curvePositionBefore = this.canvas.rightCurvePositionY;
}
// headline of the open group
var titleX, titleClass;
if (side == 'left') {
titleX = this.canvas.leftBoxBeginX + 10;
titleClass = 'BoxTextLeft';
} else {
titleX = this.canvas.rightBoxBeginX - 1;
titleClass = 'BoxTextRight';
}
if (!onlyBg) {
var groupTitle = self.model.getGroupTitle(groupName);
var titleEl = this.canvas.renderText(groupTitle, titleX, boxPositionBefore + 11,
[titleClass, 'TitleOfOpenGroup']);
titleEl.hover(function () {
self.highlightGroup(groupName, side);
}, function () {
self.unHighlightGroup(groupName, side);
});
}
this.canvas.addBoxSpacing(34, side);
// draw detail boxes
for (var i = 0; i < details.length; i++) {
var data = details[i];
var label = (typeof data.url != 'undefined' ? data.url : data.label);
label = (typeof label != 'undefined' && label !== null ? label : '');
var isOthers = (label == 'Others');
var onClick = false;
if (!isOthers && (groupName == 'previousPages' || groupName == 'followingPages')) {
if (this.showEmbeddedInReport) {
onClick = (function (url) {
return function () {
var $rootScope = piwikHelper.getAngularDependency('$rootScope');
if ($rootScope) {
$rootScope.$emit('Transitions.switchTransitionsUrl', {
url:url
});
}
};
})(label);
} else {
onClick = (function (url) {
return function () {
if (self.actionType == 'url') {
url = url.replace(/^(?!http)/, 'http://');
}
self.reloadPopover(url);
};
})(label);
}
} else if (!isOthers && (groupName == 'outlinks' || groupName == 'websites' || groupName == 'downloads')) {
onClick = label
}
var tooltip = Piwik_Transitions_Translations.XOfY;
tooltip = '<strong>' + sprintf(tooltip, data.referrals, nbTransitions) + '</strong>';
tooltip = this.model.getShareInGroupTooltip(tooltip, groupName);
var fullLabel = label;
var shortened = false;
if ((this.actionType == 'url' && (groupName == 'previousPages' || groupName == 'followingPages'))
|| groupName == 'downloads') {
// remove http + www + domain for internal URLs
label = Piwik_Transitions_Util.shortenUrl(label, true);
shortened = true;
} else if (groupName == 'outlinks' || groupName == 'websites') {
// remove http + www for external URLs
label = Piwik_Transitions_Util.shortenUrl(label);
shortened = true;
}
this.canvas.renderBox({
side: side,
onlyBg: onlyBg,
share: data.percentage / 100 * totalShare,
gradient: isOthers ? gradientOthers : gradientItems,
boxText: label,
boxTextTooltip: isOthers || !shortened ? false : fullLabel,
boxTextNumLines: 3,
curveText: NumberFormatter.formatPercent(data.percentage),
curveTextTooltip: tooltip,
onClick: onClick
});
}
// draw background
var boxPositionAfter, curvePositionAfter;
if (side == 'left') {
boxPositionAfter = this.canvas.leftBoxPositionY;
curvePositionAfter = this.canvas.leftCurvePositionY;
this.canvas.leftBoxPositionY = boxPositionBefore;
this.canvas.leftCurvePositionY = curvePositionBefore;
} else {
boxPositionAfter = this.canvas.rightBoxPositionY;
curvePositionAfter = this.canvas.rightCurvePositionY;
this.canvas.rightBoxPositionY = boxPositionBefore;
this.canvas.rightCurvePositionY = curvePositionBefore;
}
this.canvas.renderBox({
side: side,
boxHeight: boxPositionAfter - boxPositionBefore - this.canvas.boxSpacing - 2,
curveHeight: curvePositionAfter - curvePositionBefore - this.canvas.curveSpacing,
gradient: gradientBackground,
bgCanvas: true
});
var spacing = this.canvas.isNarrowMode() ? 8 : 15;
this.canvas.addBoxSpacing(spacing, side);
};
/** Render a closed group without detailed data, only one box for the sum */
Piwik_Transitions.prototype.renderClosedGroup = function (groupName, side, onlyBg) {
var self = this;
var isHighlighted = groupName == this.highlightedGroup;
var gradient = this.canvas.createHorizontalGradient('closed-group', side, isHighlighted);
var nbTransitionsVarName = groupName + 'NbTransitions';
if (self.model[nbTransitionsVarName] == 0) {
return;
}
self.canvas.renderBox({
side: side,
onlyBg: onlyBg,
share: self.model.getPercentage(nbTransitionsVarName),
gradient: gradient,
boxText: self.model.getGroupTitle(groupName),
boxTextNumLines: 1,
boxTextCssClass: 'SingleLine',
boxIcon: 'plugins/Morpheus/images/plus_blue.png',
smallBox: true,
onClick: function () {
self.unHighlightGroup(groupName, side);
self.openGroup(side, groupName);
},
onMouseOver: function () {
self.highlightGroup(groupName, side);
},
onMouseOut: function () {
self.unHighlightGroup(groupName, side);
}
});
};
/** Reload the entire popover for a different URL */
Piwik_Transitions.prototype.reloadPopover = function (url) {
if (this.rowAction) {
this.rowAction.openPopover(this.actionType + ':' + url);
} else {
this.reset(this.actionType, url);
this.showPopover();
}
};
/** Redraw the left or right sides with a different group opened */
Piwik_Transitions.prototype.openGroup = function (side, groupName) {
this.canvas.clearSide(side);
if (side == 'left') {
this.leftOpenGroup = groupName;
this.renderLeftSide();
} else {
this.rightOpenGroup = groupName;
this.renderRightSide();
}
this.renderLoops();
this.canvas.truncateVisibleBoxTexts();
};
/** Highlight a group: change curve color and highlight metric in the center box */
Piwik_Transitions.prototype.highlightGroup = function (groupName, side) {
if (this.highlightedGroup == groupName) {
return;
}
if (this.highlightedGroup !== false) {
this.unHighlightGroup(this.highlightedGroup, this.highlightedGroupSide);
}
this.highlightedGroup = groupName;
this.highlightedGroupSide = side;
var cssClass = 'Transitions_' + groupName.charAt(0).toUpperCase() + groupName.slice(1);
this.highlightedGroupCenterEl = this.canvas.container.find('.' + cssClass);
this.highlightedGroupCenterEl.addClass('Transitions_Highlighted');
this.canvas.clearSide(side, true);
if (side == 'left') {
this.renderLeftSide(true);
} else {
this.renderRightSide(true);
}
this.renderLoops();
};
/** Remove highlight after using highlightGroup() */
Piwik_Transitions.prototype.unHighlightGroup = function (groupName, side) {
if (this.highlightedGroup === false) {
return;
}
this.highlightedGroupCenterEl.removeClass('Transitions_Highlighted');
this.highlightedGroup = false;
this.highlightedGroupSide = false;
this.highlightedGroupCenterEl = false;
this.canvas.clearSide(side, true);
if (side == 'left') {
this.renderLeftSide(true);
} else {
this.renderRightSide(true);
}
this.renderLoops();
};
// --------------------------------------
// CANVAS
// --------------------------------------
function Piwik_Transitions_Canvas(canvasBgLeft, canvasBgRight, canvasLeft, canvasRight, canvasLoops, width, height) {
if (typeof window.G_vmlCanvasManager != "undefined") {
window.G_vmlCanvasManager.initElement(canvasBgLeft);
window.G_vmlCanvasManager.initElement(canvasBgRight);
window.G_vmlCanvasManager.initElement(canvasLeft);
window.G_vmlCanvasManager.initElement(canvasRight);
window.G_vmlCanvasManager.initElement(canvasLoops);
}
if (!canvasBgLeft.getContext) {
alert('Your browser is not supported.');
return;
}
/** DOM element that contains the canvas */
this.container = $(canvasBgLeft).parent().parent();
/** Drawing context of the canvases */
this.contextBgLeft = canvasBgLeft.getContext('2d');
this.contextBgRight = canvasBgRight.getContext('2d');
this.contextLeft = canvasLeft.getContext('2d');
this.contextRight = canvasRight.getContext('2d');
this.contextLoops = canvasLoops.getContext('2d');
/** Width of the entire canvas */
this.width = width;
/** Height of the entire canvas */
this.height = height;
/** Current Y positions */
this.leftBoxPositionY = this.originalBoxPositionY = 0;
this.leftCurvePositionY = this.originalCurvePositionY = 110;
this.rightBoxPositionY = this.originalBoxPositionY;
this.rightCurvePositionY = this.originalCurvePositionY;
/** Width of the rectangular box */
this.boxWidth = 175;
/** Height of the rectangular box */
this.boxHeight = 53;
/** Height of a smaller rectangular box */
this.smallBoxHeight = 30;
/** Width of the curve that connects the boxes to the center */
this.curveWidth = 170;
/** Line-height of the text */
this.lineHeight = 14;
/** Spacing between rectangular boxes */
this.boxSpacing = 7;
/** Spacing between the curves where they connect to the center */
this.curveSpacing = 1.5;
/** The total net height (without curve spacing) of the curves as they connect to the center */
this.totalHeightOfConnections = 205;
/** X positions of the left box - begin means left, end means right */
this.leftBoxBeginX = 0;
this.leftCurveBeginX = this.leftBoxBeginX + this.boxWidth;
this.leftCurveEndX = this.leftCurveBeginX + this.curveWidth;
/** X positions of the right box - begin means left, end means right */
this.rightBoxEndX = this.width;
this.rightBoxBeginX = this.rightCurveEndX = this.rightBoxEndX - this.boxWidth;
this.rightCurveBeginX = this.rightCurveEndX - this.curveWidth;
// load gradient colors from CSS
this.colors = {};
var transitionsColorNamespaces = ['entries', 'exits', 'background', 'closed-group', 'items', 'others', 'loops'];
var gradientColorNames = ['light', 'dark', 'light-highlighted', 'dark-highlighted'];
for (var i = 0; i != transitionsColorNamespaces.length; ++i) {
var namespace = 'transition-' + transitionsColorNamespaces[i];
this.colors[namespace] = piwik.ColorManager.getColors(namespace, gradientColorNames);
}
}
/**
* Activate narrow mode: draw groups a bit more compact in order to save space
* for more than 3 referrer groups.
*/
Piwik_Transitions_Canvas.prototype.narrowMode = function () {
this.smallBoxHeight = 26;
this.boxSpacing = 4;
this.narrowMode = true;
};
Piwik_Transitions_Canvas.prototype.isNarrowMode = function () {
return typeof this.narrowMode != 'undefined';
};
/**
* Helper to create horizontal gradients
*
* @param {String} colorGroup
* @param {String} position left|right
* @param {Boolean} isHighlighted
*/
Piwik_Transitions_Canvas.prototype.createHorizontalGradient = function (colorGroup, position, isHighlighted) {
var fromX, toX, fromColor, toColor, lightColor, darkColor;
colorGroup = 'transition-' + colorGroup;
if (isHighlighted) {
lightColor = this.colors[colorGroup]['light-highlighted'];
darkColor = this.colors[colorGroup]['dark-highlighted'];
} else {
lightColor = this.colors[colorGroup]['light'];
darkColor = this.colors[colorGroup]['dark'];
}
if (position == 'left') {
// gradient is used to fill a box on the left
fromX = this.leftBoxBeginX + 50;
toX = this.leftCurveEndX - 20;
fromColor = lightColor;
toColor = darkColor;
} else {
// gradient is used to fill a box on the right
fromX = this.rightCurveBeginX + 20;
toX = this.rightBoxEndX - 50;
fromColor = darkColor;
toColor = lightColor;
}
var gradient = this.contextBgLeft.createLinearGradient(fromX, 0, toX, 0);
gradient.addColorStop(0, fromColor);
gradient.addColorStop(1, toColor);
return gradient;
};
/** Render text using a div inside the container */
Piwik_Transitions_Canvas.prototype.renderText = function (text, x, y, cssClass, onClick, icon, maxLines) {
var div = this.addDomElement('div', 'Text');
div.css({
left: x + 'px',
top: y + 'px'
});
if (icon) {
div.addClass('Transitions_HasBackground');
div.css({backgroundImage: 'url(' + icon + ')'});
}
if (cssClass) {
if (typeof cssClass == 'object') {
for (var i = 0; i < cssClass.length; i++) {
div.addClass('Transitions_' + cssClass[i]);
}
} else {
div.addClass('Transitions_' + cssClass);
}
}
var textContainer = div;
if (onClick) {
if (typeof onClick == 'function') {
div.css('cursor', 'pointer').hover(function () {
$(this).addClass('Transitions_Hover');
},function () {
$(this).removeClass('Transitions_Hover');
}).click(onClick);
} else {
var a = $(document.createElement('a'));
a.attr('href', onClick);
a.attr('rel', 'noreferrer noopener');
a.attr('target', '_blank');
div.append(a);
textContainer = a;
}
}
if (maxLines) {
textContainer.addClass('Transitions_ApplyTextAndTruncate').data('text', text);
} else {
textContainer.html(text);
}
return div;
};
/** Add a DOM element inside the container (as a sibling of the canvas) */
Piwik_Transitions_Canvas.prototype.addDomElement = function (tagName, cssClass) {
var el = $(document.createElement('div')).addClass('Transitions_' + cssClass);
this.container.append(el);
return el;
};
/**
* Truncate box texts by replacing the middle part with ...
* This method looks for the class Transitions_ApplyTextAndTruncate.
* It then looks up data-text and truncates it until it fits.
*/
Piwik_Transitions_Canvas.prototype.truncateVisibleBoxTexts = function () {
this.container.find('.Transitions_ApplyTextAndTruncate').each(function () {
var container = $(this).html('<span>');
var span = container.find('span');
var text = container.data('text');
span.html(piwikHelper.addBreakpointsToUrl(text));
var divHeight = container.innerHeight();
if (container.data('maxLines')) {
divHeight = container.data('maxLines') * (parseInt(container.css('lineHeight'), 10) + .2);
}
var leftPart = false;
var rightPart = false;
while (divHeight < span.outerHeight()) {
if (leftPart === false) {
var middle = Math.round(text.length / 2);
leftPart = text.substring(0, middle);
rightPart = text.substring(middle, text.length);
}
leftPart = leftPart.substring(0, leftPart.length - 2);
rightPart = rightPart.substring(2, rightPart.length);
text = leftPart + '...' + rightPart;
span.html(piwikHelper.addBreakpointsToUrl(text));
}
span.removeClass('Transitions_Truncate');
});
};
/**
* Render a box.
* This method automatically keeps track of the current position.
*
* PARAMS (pass as object):
* side: left or right
* share: of the box in the total amount of incoming transitions
* gradient: for filling the box
* boxText: to be placed inside the box (optional)
* boxTextNumLines: the number of lines to be placed in the box (optional)
* boxTextCssClass: for divs containing the texts (optional)
* boxTextTooltip: text for a tooltip this is when hovering the box text (optional)
* curveText: to be placed where the curve begins (optional)
* curveTextTooltip: text for a tooltip that is shown when hovering the curve text (optional)
* smallBox: use this.smallBoxHeight instead of this.boxHeight (optional)
* boxIcon: path to an icon that is put in front of the text (optional)
* onClick: click callback for the text in the box (optional)
* onMouseOver: mouse over callback for the text in the box (optional)
* onMouseOut: mouse over callback for the text in the box (optional)
* onlyBg: render only the background, not the text; used for highlighting (optional)
*
* Only used for background:
* curveHeight: fix height in px instead of share
* boxHeight: fix box height in px
* bgCanvas: true to draw on background canvas
*/
Piwik_Transitions_Canvas.prototype.renderBox = function (params) {
var curveHeight = params.curveHeight ? params.curveHeight :
Math.round(this.totalHeightOfConnections * params.share);
curveHeight = Math.max(curveHeight, 1);
var boxHeight = this.boxHeight;
if (params.smallBox) {
boxHeight = this.smallBoxHeight;
}
if (params.boxHeight) {
boxHeight = params.boxHeight;
}
var context;
if (params.bgCanvas) {
context = params.side == 'left' ? this.contextBgLeft : this.contextBgRight;
} else {
context = params.side == 'left' ? this.contextLeft : this.contextRight;
}
// background
context.fillStyle = params.gradient;
context.beginPath();
if (params.side == 'left') {
this.renderLeftBoxBg(context, boxHeight, curveHeight);
} else {
this.renderRightBoxBg(context, boxHeight, curveHeight);
}
if (typeof context.endPath == 'function') {
context.endPath();
}
// text inside the box
if (params.boxText && !params.onlyBg) {
var onClick = params.onClick;
var boxTextLeft, boxTextTop, el;
if (params.side == 'left') {
boxTextLeft = this.leftBoxBeginX + 10;
boxTextTop = this.leftBoxPositionY + boxHeight / 2 - params.boxTextNumLines * this.lineHeight / 2;
el = this.renderText(params.boxText, boxTextLeft, boxTextTop, 'BoxTextLeft', onClick, params.boxIcon,
params.boxTextNumLines);
} else {
boxTextLeft = this.rightBoxBeginX;
boxTextTop = this.rightBoxPositionY + boxHeight / 2 - params.boxTextNumLines * this.lineHeight / 2;
el = this.renderText(params.boxText, boxTextLeft, boxTextTop, 'BoxTextRight', onClick, params.boxIcon,
params.boxTextNumLines);
}
if (params.boxTextCssClass) {
el.addClass('Transitions_' + params.boxTextCssClass);
}
// tooltip
if (params.boxTextTooltip) {
var tip = piwikHelper.addBreakpointsToUrl(params.boxTextTooltip);
el.tooltip({
track: true,
content: tip,
items: '*',
tooltipClass: 'Transitions_Tooltip_Small',
show: false,
hide: false
});
}
if (typeof params.onMouseOver == 'function') {
el.mouseenter(params.onMouseOver);
}
if (typeof params.onMouseOut == 'function') {
el.mouseleave(params.onMouseOut);
}
}
// text at the beginning of the curve
if (params.curveText && !params.onlyBg) {
var curveTextLeft, curveTextTop;
if (params.side == 'left') {
curveTextLeft = this.leftBoxBeginX + this.boxWidth + 3;
curveTextTop = this.leftBoxPositionY + boxHeight / 2 - this.lineHeight / 2;
} else {
curveTextLeft = this.rightBoxBeginX - 37;
curveTextTop = this.rightBoxPositionY + boxHeight / 2 - this.lineHeight / 2;
}
var textDiv = this.renderText(params.curveText, curveTextLeft, curveTextTop,
params.side == 'left' ? 'CurveTextLeft' : 'CurveTextRight');
// tooltip
if (params.curveTextTooltip) {
textDiv.tooltip({
track: true,
content: params.curveTextTooltip,
items: '*',
tooltipClass: 'Transitions_Tooltip_Small',
show: false,
hide: false
});
}
}
if (params.side == 'left') {
this.leftBoxPositionY += boxHeight + this.boxSpacing;
this.leftCurvePositionY += curveHeight + this.curveSpacing;
} else {
this.rightBoxPositionY += boxHeight + this.boxSpacing;
this.rightCurvePositionY += curveHeight + this.curveSpacing;
}
};
Piwik_Transitions_Canvas.prototype.renderLeftBoxBg = function (context, boxHeight, curveHeight) {
// derive coordinates for ths curve
var leftUpper = {x: this.leftCurveBeginX, y: this.leftBoxPositionY};
var leftLower = {x: this.leftCurveBeginX, y: this.leftBoxPositionY + boxHeight};
var rightUpper = {x: this.leftCurveEndX, y: this.leftCurvePositionY};
var rightLower = {x: this.leftCurveEndX, y: this.leftCurvePositionY + curveHeight};
// derive control points for bezier curve
var center = (this.leftCurveBeginX + this.leftCurveEndX) / 2;
var cp1Upper = {x: center, y: leftUpper.y};
var cp2Upper = {x: center, y: rightUpper.y};
var cp1Lower = {x: center, y: rightLower.y};
var cp2Lower = {x: center, y: leftLower.y};
// the flow
context.moveTo(leftUpper.x, leftUpper.y);
context.bezierCurveTo(cp1Upper.x, cp1Upper.y, cp2Upper.x, cp2Upper.y, rightUpper.x, rightUpper.y);
context.lineTo(rightLower.x, rightLower.y);
context.bezierCurveTo(cp1Lower.x, cp1Lower.y, cp2Lower.x, cp2Lower.y, leftLower.x, leftLower.y);
// the box
context.lineTo(leftLower.x - this.boxWidth + 2, leftLower.y);
context.lineTo(leftLower.x - this.boxWidth, leftUpper.y);
context.lineTo(leftUpper.x, leftUpper.y);
context.fill();
};
Piwik_Transitions_Canvas.prototype.renderRightBoxBg = function (context, boxHeight, curveHeight) {
// derive coordinates for curve
var leftUpper = {x: this.rightCurveBeginX, y: this.rightCurvePositionY};
var leftLower = {x: this.rightCurveBeginX, y: this.rightCurvePositionY + curveHeight};
var rightUpper = {x: this.rightCurveEndX, y: this.rightBoxPositionY};
var rightLower = {x: this.rightCurveEndX, y: this.rightBoxPositionY + boxHeight};
// derive control points for bezier curve
var center = (this.rightCurveBeginX + this.rightCurveEndX) / 2;
var cp1Upper = {x: center, y: leftUpper.y};
var cp2Upper = {x: center, y: rightUpper.y};
var cp1Lower = {x: center, y: rightLower.y};
var cp2Lower = {x: center, y: leftLower.y};
// the flow part 1
context.moveTo(leftUpper.x, leftUpper.y);
context.bezierCurveTo(cp1Upper.x, cp1Upper.y, cp2Upper.x, cp2Upper.y, rightUpper.x, rightUpper.y);
// the box
context.lineTo(rightUpper.x + this.boxWidth, rightUpper.y);
context.lineTo(rightLower.x + this.boxWidth - 2, rightLower.y);
context.lineTo(rightLower.x, rightLower.y);
// the flow part 2
context.bezierCurveTo(cp1Lower.x, cp1Lower.y, cp2Lower.x, cp2Lower.y, leftLower.x, leftLower.y);
context.lineTo(leftUpper.x, leftUpper.y);
context.fill();
};
/** Add spacing after the current box */
Piwik_Transitions_Canvas.prototype.addBoxSpacing = function (spacing, side) {
if (side == 'left') {
this.leftBoxPositionY += spacing;
} else {
this.rightBoxPositionY += spacing;
}
};
Piwik_Transitions_Canvas.prototype.renderLoops = function (share) {
var curveHeight = Math.round(this.totalHeightOfConnections * share);
curveHeight = Math.max(curveHeight, 1);
// create gradient
var gradient = this.contextLoops.createLinearGradient(this.leftCurveEndX - 50, 0, this.rightCurveBeginX + 50, 0);
var light = this.colors['transition-loops']['light'];
var dark = this.colors['transition-loops']['dark'];
gradient.addColorStop(0, dark);
gradient.addColorStop(.5, light);
gradient.addColorStop(1, dark);
this.contextLoops.fillStyle = gradient;
this.contextLoops.beginPath();
// curve from the upper left connection to the center box to the lower left connection to the text box
var point1 = {x: this.leftCurveEndX, y: this.leftCurvePositionY};
var point2 = {x: this.leftCurveEndX, y: 470};
var cpLeftX = (this.leftCurveBeginX + this.leftCurveEndX) / 2 + 30;
var cp1 = {x: cpLeftX, y: point1.y};
var cp2 = {x: cpLeftX, y: point2.y};
this.contextLoops.moveTo(point1.x, point1.y);
this.contextLoops.bezierCurveTo(cp1.x, cp1.y, cp2.x, cp2.y, point2.x, point2.y);
// lower line of text box
var point3 = {x: this.rightCurveBeginX, y: point2.y};
this.contextLoops.lineTo(point3.x, point3.y);
// curve to upper right connection to the center box
var point4 = {x: this.rightCurveBeginX, y: this.rightCurvePositionY};
var cpRightX = (this.rightCurveBeginX + this.rightCurveEndX) / 2 - 30;
var cp3 = {x: cpRightX, y: point3.y};
var cp4 = {x: cpRightX, y: point4.y};
this.contextLoops.bezierCurveTo(cp3.x, cp3.y, cp4.x, cp4.y, point4.x, point4.y);
// line to lower right connection to the center box
var point5 = {x: point4.x, y: point4.y + curveHeight};
this.contextLoops.lineTo(point5.x, point5.y);
// curve to upper right connection to the text box
var point6 = {x: point5.x, y: point2.y - 25};
cpRightX -= 30;
var cp5 = {x: cpRightX, y: point5.y};
var cp6 = {x: cpRightX, y: point6.y};
this.contextLoops.bezierCurveTo(cp5.x, cp5.y, cp6.x, cp6.y, point6.x, point6.y);
// upper line of the text box
var point7 = {x: point1.x, y: point6.y};
this.contextLoops.lineTo(point7.x, point7.y);
// line to lower left connection to the center box
var point8 = {x: point1.x, y: point1.y + curveHeight};
cpLeftX += 30;
var cp7 = {x: cpLeftX, y: point7.y};
var cp8 = {x: cpLeftX, y: point8.y};
this.contextLoops.bezierCurveTo(cp7.x, cp7.y, cp8.x, cp8.y, point8.x, point8.y);
this.contextLoops.fill();
if (typeof this.contextLoops.endPath == 'function') {
this.contextLoops.endPath();
}
};
/** Clear one side for redrawing */
Piwik_Transitions_Canvas.prototype.clearSide = function (side, onlyBg) {
if (side == 'left') {
this.contextBgLeft.clearRect(0, 0, this.width, this.height);
this.contextLeft.clearRect(0, 0, this.width, this.height);
} else {
this.contextBgRight.clearRect(0, 0, this.width, this.height);
this.contextRight.clearRect(0, 0, this.width, this.height);
}
this.contextLoops.clearRect(0, 0, this.width, this.height);
if (side == 'left') {
if (!onlyBg) {
this.container.find('.Transitions_BoxTextLeft').remove();
this.container.find('.Transitions_CurveTextLeft').remove();
}
this.leftBoxPositionY = this.originalBoxPositionY;
this.leftCurvePositionY = this.originalCurvePositionY;
} else {
if (!onlyBg) {
this.container.find('.Transitions_BoxTextRight').remove();
this.container.find('.Transitions_CurveTextRight').remove();
}
this.rightBoxPositionY = this.originalBoxPositionY;
this.rightCurvePositionY = this.originalCurvePositionY;
}
};
// --------------------------------------
// MODEL
// --------------------------------------
function Piwik_Transitions_Model(ajax) {
this.ajax = ajax;
this.groupTitles = {};
}
Piwik_Transitions_Model.prototype.htmlLoaded = function () {
this.groupTitles.previousPages = Piwik_Transitions_Translations.fromPreviousPages;
this.groupTitles.previousSiteSearches = Piwik_Transitions_Translations.fromPreviousSiteSearches;
this.groupTitles.followingPages = Piwik_Transitions_Translations.toFollowingPages;
this.groupTitles.followingSiteSearches = Piwik_Transitions_Translations.toFollowingSiteSearches;
this.groupTitles.outlinks = Piwik_Transitions_Translations.outlinks;
this.groupTitles.downloads = Piwik_Transitions_Translations.downloads;
this.shareInGroupTexts = {
previousPages: Piwik_Transitions_Translations.fromPreviousPagesInline,
previousSiteSearches: Piwik_Transitions_Translations.fromPreviousSiteSearchesInline,
followingPages: Piwik_Transitions_Translations.toFollowingPagesInline,
followingSiteSearches: Piwik_Transitions_Translations.toFollowingSiteSearchesInline,
searchEngines: Piwik_Transitions_Translations.fromSearchEnginesInline,
socialNetworks: Piwik_Transitions_Translations.fromSocialNetworksInline,
websites: Piwik_Transitions_Translations.fromWebsitesInline,
campaigns: Piwik_Transitions_Translations.fromCampaignsInline,
outlinks: Piwik_Transitions_Translations.outlinksInline,
downloads: Piwik_Transitions_Translations.downloadsInline
};
};
Piwik_Transitions_Model.prototype.loadData = function (actionType, actionName, overrideParams, callback) {
var self = this;
this.pageviews = 0;
this.exits = 0;
this.loops = 0;
this.directEntries = 0;
this.searchEnginesNbTransitions = 0;
this.searchEngines = [];
this.socialNetworksNbTransitions = 0;
this.socialNetworks = [];
this.websitesNbTransitions = 0;
this.websites = [];
this.campaignsNbTransitions = 0;
this.campaigns = [];
this.previousPagesNbTransitions = 0;
this.previousPages = [];
this.followingPagesNbTransitions = 0;
this.followingPages = [];
this.downloadsNbTransitions = 0;
this.downloads = [];
this.outlinksNbTransitions = 0;
this.outlinks = [];
this.previousSiteSearchesNbTransitions = 0;
this.previousSiteSearches = [];
this.followingSiteSearchesNbTransitions = 0;
this.followingSiteSearches = [];
this.date = '';
var params = {
actionType: actionType,
actionName: actionName,
expanded: 1
};
if (overrideParams) {
$.extend(params, overrideParams);
}
this.ajax.callApi('Transitions.getTransitionsForAction', params,
function (report) {
self.date = report.date;
// load page metrics
self.pageviews = report.pageMetrics.pageviews;
self.loops = report.pageMetrics.loops;
self.exits = report.pageMetrics.exits;
// load referrers: split direct entries and others
for (var i = 0; i < report.referrers.length; i++) {
var referrer = report.referrers[i];
if (referrer.shortName == 'direct') {
self.directEntries = referrer.visits;
} else if (referrer.shortName == 'search') {
self.searchEnginesNbTransitions = referrer.visits;
self.searchEngines = referrer.details;
self.groupTitles.searchEngines = referrer.label;
} else if (referrer.shortName == 'social') {
self.socialNetworksNbTransitions = referrer.visits;
self.socialNetworks = referrer.details;
self.groupTitles.socialNetworks = referrer.label;
} else if (referrer.shortName == 'website') {
self.websitesNbTransitions = referrer.visits;
self.websites = referrer.details;
self.groupTitles.websites = referrer.label;
} else if (referrer.shortName == 'campaign') {
self.campaignsNbTransitions = referrer.visits;
self.campaigns = referrer.details;
self.groupTitles.campaigns = referrer.label;
}
}
self.loadAndSumReport(report, 'previousPages');
self.loadAndSumReport(report, 'previousSiteSearches');
self.loadAndSumReport(report, 'followingPages');
self.loadAndSumReport(report, 'followingSiteSearches');
self.loadAndSumReport(report, 'downloads');
self.loadAndSumReport(report, 'outlinks');
if (typeof Piwik_Transitions_Model.totalNbPageviews == 'undefined') {
Piwik_Transitions_Model.totalNbPageviews = false;
self.ajax.loadTotalNbPageviews(function (nbPageviews) {
Piwik_Transitions_Model.totalNbPageviews = nbPageviews;
});
}
callback();
});
};
Piwik_Transitions_Model.prototype.loadAndSumReport = function (apiData, reportName) {
var data = this[reportName] = apiData[reportName];
var sumVarName = reportName + 'NbTransitions';
this[sumVarName] = 0;
for (var i = 0; i < data.length; i++) {
this[sumVarName] += data[i].referrals;
}
};
Piwik_Transitions_Model.prototype.getTotalNbPageviews = function () {
if (typeof Piwik_Transitions_Model.totalNbPageviews == 'undefined') {
return false;
}
return Piwik_Transitions_Model.totalNbPageviews;
};
Piwik_Transitions_Model.prototype.getGroupTitle = function (groupName) {
if (typeof this.groupTitles[groupName] != 'undefined') {
return this.groupTitles[groupName];
}
return groupName;
};
Piwik_Transitions_Model.prototype.getShareInGroupTooltip = function (share, groupName) {
var tip = this.shareInGroupTexts[groupName];
return sprintf(tip, share);
};
Piwik_Transitions_Model.prototype.getDetailsForGroup = function (groupName) {
return this.addPercentagesToData(this[groupName]);
};
Piwik_Transitions_Model.prototype.getPercentage = function (metric, formatted) {
var percentage = (this.pageviews == 0 ? 0 : this[metric] / this.pageviews);
if (formatted) {
percentage = this.roundPercentage(percentage);
return NumberFormatter.formatPercent(percentage);
}
return percentage;
};
Piwik_Transitions_Model.prototype.addPercentagesToData = function (data) {
var total = 0;
for (var i = 0; i < data.length; i++) {
total += parseInt(data[i].referrals, 10);
}
for (i = 0; i < data.length; i++) {
data[i].percentage = this.roundPercentage(data[i].referrals / total);
}
return data;
};
Piwik_Transitions_Model.prototype.roundPercentage = function (value) {
if (value < .1) {
return Math.round(value * 1000) / 10.0;
} else {
return Math.round(value * 100);
}
};
// --------------------------------------
// AJAX
// --------------------------------------
function Piwik_Transitions_Ajax() {
}
Piwik_Transitions_Ajax.prototype.loadTotalNbPageviews = function (callback) {
this.callApi('Actions.get', {
columns: 'nb_pageviews'
}, function (response) {
var value = typeof response.value != 'undefined' ? response.value : false;
callback(value);
});
};
Piwik_Transitions_Ajax.prototype.callTransitionsController = function (action, callback) {
var ajaxRequest = new ajaxHelper();
ajaxRequest.addParams({
module: 'Transitions',
action: action
}, 'get');
ajaxRequest.setCallback(callback);
ajaxRequest.setFormat('html');
ajaxRequest.send();
};
Piwik_Transitions_Ajax.prototype.callApi = function (method, params, callback) {
var self = this;
params.format = 'JSON';
params.module = 'API';
params.method = method;
params.filter_limit = '-1';
var ajaxRequest = new ajaxHelper();
ajaxRequest.addParams(params, 'get');
ajaxRequest.useCallbackInCaseOfError();
ajaxRequest.setCallback(
function (result) {
if (typeof result.result != 'undefined' && result.result == 'error') {
var errorName = result.message;
var showError = function () {
var errorTitle, errorMessage, errorBack;
if (typeof Piwik_Transitions_Translations[errorName] == 'undefined') {
errorTitle = 'Exception';
errorMessage = errorName;
errorBack = '<<<';
} else {
errorTitle = Piwik_Transitions_Translations[errorName];
errorMessage = Piwik_Transitions_Translations[errorName + 'Details'];
errorBack = Piwik_Transitions_Translations[errorName + 'Back'];
}
if (typeof params.actionName != 'undefined') {
var url = params.actionName;
url = piwikHelper.addBreakpointsToUrl(url);
errorTitle = sprintf(errorTitle, '<span>' + url + '</span>');
}
errorMessage = sprintf(errorMessage, '<br />');
var inlineErrorNode = $('#Transitions_Error_Container');
if (inlineErrorNode.length) {
// viewing it as report, not popover
inlineErrorNode.html('');
var theContentNode = $(document.createElement('div')).addClass('Piwik_Popover_Error');
var p = $(document.createElement('p')).addClass('Piwik_Popover_Error_Title');
theContentNode.append(p.html(errorTitle));
if (errorMessage) {
p = $(document.createElement('p')).addClass('Piwik_Popover_Error_Message');
theContentNode.append(p.html(errorMessage));
}
inlineErrorNode.append(theContentNode);
inlineErrorNode.show();
$('#transitions_report .popoverContainer').hide();
} else {
Piwik_Popover.showError(errorTitle, errorMessage, errorBack);
}
$('#transitions_inline_loading').hide();
};
if (typeof Piwik_Transitions_Translations == 'undefined') {
self.callApi('Transitions.getTranslations', {}, function (response) {
if (typeof response == 'object') {
Piwik_Transitions_Translations = response;
} else {
Piwik_Transitions_Translations = {};
}
showError();
});
} else {
showError();
}
}
else {
callback(result);
}
}
);
ajaxRequest.send();
};
// --------------------------------------
// STATIC UTIL FUNCTIONS
// --------------------------------------
Piwik_Transitions_Util = {
/**
* Removes protocol, www and trailing slashes from a URL.
* If removeDomain is set, the domain is removed as well.
*/
shortenUrl: function (url, removeDomain) {
if (url == 'Others') {
return url;
}
var urlBackup = url;
url = url.replace(/http(s)?:\/\/(www\.)?/, '');
if (urlBackup == url) {
return url;
}
if (removeDomain) {
url = url.replace(/[^\/]*/, '');
if (url == '/') {
url = urlBackup;
}
}
url = url.replace(/\/$/, '');
return url;
},
/**
* Replaces a %s placeholder in the HTML.
* The special feature is that it can be called multiple times, replacing the already
* replaced placeholder again. It creates a span that can be assigned a class using the
* spanClass parameter. The default class is 'Transitions_Metric'.
*/
replacePlaceholderInHtml: function (container, value, spanClass) {
var span = container.find('span');
if (!span.length) {
var html = container.html().replace(/%s/, '<span></span>');
span = container.html(html).find('span');
if (!spanClass) {
spanClass = 'Transitions_Metric';
}
span.addClass(spanClass);
}
if ($.browser.msie && parseFloat($.browser.version) < 8) {
// ie7 fix
value += '&nbsp;';
}
span.html(value);
}
};