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
path: root/js
diff options
context:
space:
mode:
authorThomas Steur <thomas.steur@googlemail.com>2014-09-10 16:25:08 +0400
committerThomas Steur <thomas.steur@googlemail.com>2014-09-10 16:25:08 +0400
commitdf65e0dd10f12e11990665971e5f7e019168fd39 (patch)
tree3d24bb805a37e4dde51ae8de10884e821b501338 /js
parent7ad02af8bef3eff12624925c4521feaab9f98aae (diff)
refs #4996 many new tests and many bugfixes. Tests should be done now except for cross browser support. I fixed many issues as I did not consider that link tracking may be disabled or enabled and the behavior should be different in such a case.
Diffstat (limited to 'js')
-rw-r--r--js/piwik.js206
1 files changed, 168 insertions, 38 deletions
diff --git a/js/piwik.js b/js/piwik.js
index 10ef6a6533..f9309c217f 100644
--- a/js/piwik.js
+++ b/js/piwik.js
@@ -452,7 +452,9 @@ if (typeof JSON2 !== 'object') {
contentInteractionTrackingSetupDone, contains, match, pathname, piece, trackContentInteractionNode,
trackContentInteractionNode, trackContentImpressionsWithinNode, trackContentImpression,
enableTrackOnlyVisibleContent, trackContentInteraction, clearEnableTrackOnlyVisibleContent,
- trackVisibleContentImpressions, isTrackOnlyVisibleContentEnabled, port
+ trackVisibleContentImpressions, isTrackOnlyVisibleContentEnabled, port, isUrlToCurrentDomain,
+ isNodeAuthorizedToTriggerInteraction, replaceHrefIfInternalLink, getConfigDownloadExtensions, disableLinkTracking,
+ substr, setAnyAttribute
*/
/*global _paq:true */
/*members push */
@@ -1412,6 +1414,18 @@ if (typeof Piwik !== 'object') {
var pos = linkElementNames.indexOf(elementName);
return pos !== -1;
+ },
+ setAnyAttribute: function (node, attrName, attrValue)
+ {
+ if (!node || !attrName) {
+ return;
+ }
+
+ if (node.setAttribute) {
+ node.setAttribute(attrName, attrValue);
+ } else {
+ node[attrName] = attrValue;
+ }
}
};
@@ -1866,17 +1880,36 @@ if (typeof Piwik !== 'object') {
var base = this.getLocation().origin + this.getLocation().pathname.match(new RegExp(regexMatchDir))[0];
return base + url;
},
+ isUrlToCurrentDomain: function (url) {
+
+ var absoluteUrl = this.toAbsoluteUrl(url);
+
+ if (!absoluteUrl) {
+ return false;
+ }
+
+ var origin = this.getLocation().origin;
+ if (origin === absoluteUrl) {
+ return true;
+ }
+
+ if (0 === String(absoluteUrl).indexOf(origin)) {
+ if (':' === String(absoluteUrl).substr(origin.length, 1)) {
+ return false; // url has port whereas origin has not => different URL
+ }
+
+ return true;
+ }
+
+ return false;
+ },
setHrefAttribute: function (node, url)
{
if (!node || !url) {
return;
}
- if (node.setAttribute) {
- node.setAttribute('href', url);
- } else {
- node.href = url;
- }
+ query.setAnyAttribute(node, 'href', url);
},
shouldIgnoreInteraction: function (targetNode)
{
@@ -2937,6 +2970,10 @@ if (typeof Piwik !== 'object') {
* Link or Download?
*/
function getLinkType(className, href, isInLink) {
+ if (configTrackerUrl && href && 0 === String(href).indexOf(configTrackerUrl)) {
+ return 0;
+ }
+
// does class indicate whether it is an (explicit/forced) outlink or a download?
var downloadPattern = getClassesRegExp(configDownloadClasses, 'download'),
linkPattern = getClassesRegExp(configLinkClasses, 'link'),
@@ -2990,6 +3027,12 @@ if (typeof Piwik !== 'object') {
return;
}
+ var href = query.getAttributeValueFromNode(sourceElement, 'href');
+
+ if (configTrackerUrl && href && 0 === String(href).indexOf(configTrackerUrl)) {
+ return;
+ }
+
// browsers, such as Safari, don't downcase hostname and href
var originalSourceHostName = sourceElement.hostname || getHostName(sourceElement.href);
var sourceHostName = originalSourceHostName.toLowerCase();
@@ -3044,34 +3087,47 @@ if (typeof Piwik !== 'object') {
return configTrackerUrl + separator + request;
}
- function getContentInteractionToRequestIfPossible (anyNode, interaction, fallbackTarget)
+ function isNodeAuthorizedToTriggerInteraction(contentNode, interactedNode)
{
- if (!anyNode) {
- return;
- }
-
- var contentNode = content.findParentContentNode(anyNode);
-
- if (!contentNode) {
- // we are not within a content block
- return;
+ if (!contentNode || !interactedNode) {
+ return false;
}
var targetNode = content.findTargetNode(contentNode);
if (content.shouldIgnoreInteraction(targetNode)) {
// interaction should be ignored
- return;
+ return false;
}
targetNode = content.findTargetNodeNoDefault(contentNode);
- if (targetNode && !targetNode.contains(anyNode)) {
+ if (targetNode && !targetNode.contains(interactedNode)) {
/**
* There is a target node defined but the clicked element is not within the target node. example:
* <div data-track-content><a href="Y" data-content-target>Y</a><img src=""/><a href="Z">Z</a></div>
*
* The user clicked in this case on link Z and not on target Y
*/
+ return false;
+ }
+
+ return true;
+ }
+
+ function getContentInteractionToRequestIfPossible (anyNode, interaction, fallbackTarget)
+ {
+ if (!anyNode) {
+ return;
+ }
+
+ var contentNode = content.findParentContentNode(anyNode);
+
+ if (!contentNode) {
+ // we are not within a content block
+ return;
+ }
+
+ if (!isNodeAuthorizedToTriggerInteraction(contentNode, anyNode)) {
return;
}
@@ -3110,43 +3166,109 @@ if (typeof Piwik !== 'object') {
return false;
}
- function trackContentImpressionClickInteraction (targetNode)
+ function replaceHrefIfInternalLink(contentBlock)
{
- return function () {
+ if (!contentBlock) {
+ return false;
+ }
- if (!targetNode || content.shouldIgnoreInteraction(targetNode)) {
- return;
- }
+ var targetNode = content.findTargetNode(contentBlock);
- var link = getLinkIfShouldBeProcessed(targetNode);
+ if (!targetNode || content.shouldIgnoreInteraction(targetNode)) {
+ return false;
+ }
- if (link && link.type) {
- // click ignore, will be tracked via processClick, we do not want to track it twice
+ var link = getLinkIfShouldBeProcessed(targetNode);
+ if (linkTrackingInstalled && link && link.type) {
- return link.type;
+ return false; // it is an outlink or download.
+ }
+
+ if (query.isLinkElement(targetNode) &&
+ query.hasNodeAttributeWithValue(targetNode, 'href')) {
+ var url = String(query.getAttributeValueFromNode(targetNode, 'href'));
+
+ if (0 === url.indexOf('#')) {
+ return false;
+ }
+
+ if (configTrackerUrl && 0 === url.indexOf(configTrackerUrl)) {
+ return true;
+ }
+
+ if (!content.isUrlToCurrentDomain(url)) {
+ return false;
}
- var contentBlock = content.findParentContentNode(targetNode);
var contentName = content.findContentName(contentBlock);
var contentPiece = content.findContentPiece(contentBlock);
var contentTarget = content.findContentTarget(contentBlock);
- if (query.isLinkElement(targetNode) &&
- query.hasNodeAttributeWithValue(targetNode, 'href')) {
- var url = query.getAttributeValueFromNode(targetNode, 'href');
+ var targetUrl = buildContentInteractionTrackingRedirectUrl(url, 'click', contentName, contentPiece, contentTarget);
- if (0 !== String(url).indexOf('#')) {
+ // make sure we still track the correct content target when an interaction is happening
+ if (!query.hasNodeAttributeWithValue(targetNode, content.CONTENT_TARGET_ATTR)) {
+ query.setAnyAttribute(targetNode, content.CONTENT_TARGET_ATTR, content.toAbsoluteUrl(url));
+ }
+ // location.href does not respect target=_blank so we prefer to use this
+ content.setHrefAttribute(targetNode, targetUrl);
- var targetUrl = buildContentInteractionTrackingRedirectUrl(url, 'click', contentName, contentPiece, contentTarget);
+ return true;
+ }
- // location.href does not respect target=_blank so we prefer to use this
- content.setHrefAttribute(targetNode, targetUrl);
+ return false;
+ }
- return 'href';
- }
+ function replaceHrefsIfInternalLink(contentNodes)
+ {
+ if (!contentNodes || !contentNodes.length) {
+ return;
+ }
+ var index;
+ for (index = 0; index < contentNodes.length; index++) {
+ replaceHrefIfInternalLink(contentNodes[index]);
+ }
+ }
+
+ function trackContentImpressionClickInteraction (targetNode)
+ {
+ return function (event) {
+
+ if (!targetNode) {
+ return;
+ }
+
+ var contentBlock = content.findParentContentNode(targetNode);
+
+ var interactedElement;
+ if (event) {
+ interactedElement = event.target || event.srcElement;
+ }
+ if (!interactedElement) {
+ interactedElement = targetNode;
+ }
+
+ if (!isNodeAuthorizedToTriggerInteraction(contentBlock, interactedElement)) {
+ return;
}
+ var link = getLinkIfShouldBeProcessed(targetNode);
+
+ if (linkTrackingInstalled && link && link.type) {
+ // click ignore, will be tracked via processClick, we do not want to track it twice
+
+ return link.type;
+ }
+
+ if (replaceHrefIfInternalLink(contentBlock)) {
+ return 'href';
+ }
+
+ var contentName = content.findContentName(contentBlock);
+ var contentPiece = content.findContentPiece(contentBlock);
+ var contentTarget = content.findContentTarget(contentBlock);
+
// click on any non link element, or on a link element that has not an href attribute or on an anchor
var request = buildContentInteractionRequest('click', contentName, contentPiece, contentTarget);
sendRequest(request, configTrackerPause);
@@ -3171,7 +3293,6 @@ if (typeof Piwik !== 'object') {
addEventListener(targetNode, 'click', trackContentImpressionClickInteraction(targetNode));
}
-
}
}
@@ -3200,6 +3321,7 @@ if (typeof Piwik !== 'object') {
return [];
}
+ replaceHrefsIfInternalLink(contentNodes);
setupInteractionsTracking(contentNodes);
var requests = [];
@@ -3708,6 +3830,11 @@ if (typeof Piwik !== 'object') {
setupInteractionsTracking: setupInteractionsTracking,
trackContentImpressionClickInteraction: trackContentImpressionClickInteraction,
internalIsNodeVisible: isVisible,
+ isNodeAuthorizedToTriggerInteraction: isNodeAuthorizedToTriggerInteraction,
+ replaceHrefIfInternalLink: replaceHrefIfInternalLink,
+ getConfigDownloadExtensions: function () {
+ return configDownloadExtensions;
+ },
enableTrackOnlyVisibleContent: function (checkOnScroll, timeIntervalInMs) {
return enableTrackOnlyVisibleContent(checkOnScroll, timeIntervalInMs, this);
},
@@ -3723,6 +3850,9 @@ if (typeof Piwik !== 'object') {
clearEnableTrackOnlyVisibleContent: function () {
isTrackOnlyVisibleContentEnabled = false;
},
+ disableLinkTracking: function () {
+ linkTrackingInstalled = false;
+ },
/*</DEBUG>*/
/**