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-08-27 21:10:20 +0400
committerThomas Steur <thomas.steur@googlemail.com>2014-08-27 21:10:20 +0400
commit10ecff50c3e25cab6501dbc73a1c64131e21db7e (patch)
treeb5c29fb038563d0ec724e8c1f95f07c8350b7f31 /js
parentce8d27ce90be5be96ae540cc5805c34601590260 (diff)
refs #4996 worked on detecting content name, piece and target. Next: Sending the impressions to Piwik via bulk tracking
Diffstat (limited to 'js')
-rw-r--r--js/piwik.js799
1 files changed, 423 insertions, 376 deletions
diff --git a/js/piwik.js b/js/piwik.js
index f265180c75..1e4b3e4825 100644
--- a/js/piwik.js
+++ b/js/piwik.js
@@ -976,6 +976,417 @@ if (typeof Piwik !== 'object') {
}
/************************************************************
+ * Query
+ ************************************************************/
+
+ var query = {
+ find: function(selector)
+ {
+ if (!document.querySelectorAll) {
+ return []; // TODO
+ }
+
+ return document.querySelectorAll(selector);
+ },
+ findMultiple: function(selectors)
+ {
+ var index, j,foundNodes;
+ var nodes = [];
+ for (index = 0; index < selectors.length; index++) {
+ foundNodes = this.find(selectors[index]);
+ if (!foundNodes || !foundNodes.length) {
+ continue;
+ }
+ for (j = 0; j < foundNodes.length; j++) {
+ nodes.push(foundNodes[j]);
+ }
+ }
+
+ nodes = this.makeNodesUnique(nodes);
+
+ return nodes;
+ },
+ makeNodesUnique: function (nodes)
+ {
+ nodes.sort(function (n1, n2) {
+ if (n1 === n2) {
+ return 0;
+ }
+
+ return n1.innerHTML > n2.innerHTML ? 1 : -1;
+ });
+
+ var index = 0;
+ var numDuplicates = 0;
+ var duplicates = [];
+ var node;
+
+ while ((node = nodes[index++])) {
+ if (node === nodes[index]) {
+ numDuplicates = duplicates.push(index);
+ }
+ }
+
+ while (numDuplicates--) {
+ nodes.splice(duplicates[numDuplicates], 1);
+ }
+
+ return nodes;
+ },
+ getAttributeValueFromNode: function (node, attributeName) {
+ if (node && node.getAttribute) {
+ return node.getAttribute(attributeName)
+ }
+
+ if (!node || !node.attributes) {
+ return;
+ }
+
+ if ('undefined' === (typeof node.attributes[attributeName])) {
+ return;
+ }
+
+ if (node.attributes[attributeName].value) {
+ return node.attributes[attributeName].value; // nodeValue is deprecated ie Chrome
+ }
+
+ if (node.attributes[attributeName].nodeValue) {
+ return node.attributes[attributeName].nodeValue;
+ }
+
+ var index;
+ var attrs = node.attributes;
+
+ if (!attrs) {
+ return;
+ }
+
+ for (index = 0; index < attrs.length; index++) {
+ if (attrs[index].nodeName === attributeName) {
+ return attrs[index].nodeValue;
+ }
+ }
+
+ return null;
+ },
+ hasNodeAttributeWithValue: function (node, attributeName) {
+ if (this.hasNodeAttribute(node, attributeName)) {
+ var value = this.getAttributeValueFromNode(node, attributeName);
+
+ if (value) {
+ return value;
+ }
+ }
+ },
+ hasNodeAttribute: function (node, attributeName) {
+ if (node && node.hasAttribute) {
+ return node.hasAttribute(attributeName)
+ }
+
+ if (node && node.attributes) {
+ return 'undefined' !== (typeof node.attributes[attributeName])
+ }
+
+ return false;
+ },
+ hasNodeCssClass: function (node, className) {
+ if (node && node.className) {
+ var classes = node.className.split(' ');
+ if (-1 !== classes.indexOf(className)) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+ findNodesHavingAttribute: function (nodeToSearch, attributeName, nodes) {
+ if (!nodes) {
+ nodes = []
+ }
+
+ if (!nodeToSearch || !nodeToSearch.children) {
+ return nodes;
+ }
+
+ var index, child;
+ for (index = 0; index < nodeToSearch.children.length; index++) {
+ child = nodeToSearch.children[index];
+ if (this.hasNodeAttribute(child, attributeName)) {
+ nodes.push(child);
+ }
+
+ nodes = this.findNodesHavingAttribute(child, attributeName, nodes);
+ }
+
+ return nodes;
+ },
+ findFirstNodeHavingAttribute: function (node, attributeName) {
+ if (this.hasNodeAttribute(node, attributeName)) {
+ return node;
+ }
+
+ var nodes = this.findNodesHavingAttribute(node, attributeName);
+
+ if (nodes && nodes.length) {
+ return nodes[0]; // TODO here we should check whether this node is also present within another nested piece of content and if there are multiple other nodes maybe use the next one
+ }
+ },
+ findFirstNodeHavingAttributeWithValue: function (node, attributeName) {
+ if (this.hasNodeAttributeWithValue(node, attributeName)) {
+ return node;
+ }
+
+ var nodes = this.findNodesHavingAttribute(node, attributeName);
+
+ if (!nodes || !nodes.length) {
+ return;
+ }
+
+ var index;
+ for (index = 0; index < nodes.length; index++) {
+ if (this.getAttributeValueFromNode(nodes[index], attributeName)) {
+ return nodes[index];
+ }
+ }
+ },
+ findNodesHavingCssClass: function (nodeToSearch, className, nodes) {
+ if (!nodes) {
+ nodes = []
+ }
+
+ if (!nodeToSearch) {
+ return nodes;
+ }
+
+ if (nodeToSearch.getElementsByClassName) {
+ return nodeToSearch.getElementsByClassName(className);
+ }
+
+ if (!nodeToSearch.children) {
+ return;
+ }
+
+ var index, child;
+ for (index = 0; index < nodeToSearch.children.length; index++) {
+ child = nodeToSearch.children[index];
+ if (this.hasNodeCssClass(child, className)) {
+ nodes.push(child);
+ }
+
+ nodes = this.findNodesHavingCssClass(child, className, nodes);
+ }
+
+ return nodes;
+ },
+ findFirstNodeHavingClass: function (node, className) {
+ if (this.hasNodeCssClass(node, className)) {
+ return node;
+ }
+
+ var nodes = this.findNodesHavingCssClass(node, className);
+
+ if (nodes && nodes.length) {
+ return nodes[0]; // TODO here we should check whether this node is also present within another nested piece of content and if there are multiple other nodes maybe use the next one
+ }
+ },
+ findFirstLink: function (node) {
+ var linkNodes = node.getElementsByTagName('a');
+
+ if (linkNodes && linkNodes.length) {
+ return linkNodes[0];
+ }
+ }
+ }
+
+ /************************************************************
+ * Content Tracking
+ ************************************************************/
+
+ var content = {
+ CONTENT_ATTR: 'data-track-content',
+ CONTENT_CLASS: 'piwikTrackContent',
+ CONTENT_NAME_ATTR: 'data-content-name',
+ CONTENT_PIECE_ATTR: 'data-content-piece',
+ CONTENT_PIECE_CLASS: 'piwikContentPiece',
+ CONTENT_INTERACTION_ATTR: 'data-content-interaction',
+ CONTENT_INTERACTION_CLASS: 'piwikContentInteraction',
+
+ findPieceNode: function (node) {
+ var contentPiece;
+
+ contentPiece = query.findFirstNodeHavingAttribute(this.CONTENT_NAME_ATTR);
+
+ if (!contentPiece) {
+ contentPiece = query.findFirstNodeHavingClass(this.CONTENT_PIECE_CLASS);
+ }
+
+ if (!contentPiece) {
+ contentPiece = query.findFirstNodeHavingClass(this.CONTENT_INTERACTION_CLASS);
+ }
+
+ if (contentPiece) {
+ return contentPiece;
+ }
+
+ return node;
+ },
+ findTargetNode: function (node)
+ {
+ var target = query.findFirstNodeHavingAttributeWithValue(node, this.CONTENT_INTERACTION_ATTR);
+ if (target) {
+ return target;
+ }
+
+ target = query.findFirstNodeHavingAttribute(node, this.CONTENT_INTERACTION_ATTR);
+ if (target) {
+ return target;
+ }
+
+ target = query.findFirstNodeHavingClass(node, this.CONTENT_INTERACTION_CLASS);
+ if (target) {
+ return target;
+ }
+
+ return node;
+ },
+ findContentName: function (node)
+ {
+ var nameNode = query.findFirstNodeHavingAttributeWithValue(node, this.CONTENT_NAME_ATTR);
+
+ if (nameNode) {
+ return query.getAttributeValueFromNode(nameNode, this.CONTENT_NAME_ATTR);
+ }
+
+ var contentPiece = this.findContentPiece(node);
+ if (contentPiece) {
+ return this.removeDomainIfIsUrl(contentPiece);
+ }
+
+ if (query.hasNodeAttributeWithValue(node, 'title')) {
+ return query.getAttributeValueFromNode(node, 'title');
+ }
+
+ var clickUrlNode = this.findPieceNode(node);
+
+ if (query.hasNodeAttributeWithValue(clickUrlNode, 'title')) {
+ return query.getAttributeValueFromNode(clickUrlNode, 'title');
+ }
+
+ var targetNode = this.findTargetNode(node);
+
+ if (query.hasNodeAttributeWithValue(targetNode, 'title')) {
+ return query.getAttributeValueFromNode(targetNode, 'title');
+ }
+ },
+ findContentPiece: function (node)
+ {
+ var nameNode = query.findFirstNodeHavingAttributeWithValue(node, this.CONTENT_PIECE_ATTR);
+
+ if (nameNode) {
+ return query.getAttributeValueFromNode(nameNode, this.CONTENT_NAME_ATTR);
+ }
+
+ var contentNode = this.findPieceNode(node);
+
+ var media = this.findMediaUrlInNode(contentNode);
+ if (media) {
+ return media;
+ }
+
+ var targetNode = this.findTargetNode(node);
+
+ if (contentNode !== targetNode) {
+ var media = this.findMediaUrlInNode(targetNode);
+ if (media) {
+ return media;
+ }
+ }
+
+ // contentNode.innerText
+
+ return '';
+ },
+ findContentTarget: function (node)
+ {
+ var targetNode = this.findTargetNode(node);
+
+ if (query.hasNodeAttributeWithValue(targetNode, this.CONTENT_INTERACTION_ATTR)) {
+ return query.getAttributeValueFromNode(targetNode, this.CONTENT_INTERACTION_ATTR);
+ }
+
+ if (query.hasNodeAttributeWithValue(targetNode, 'href')) {
+ return query.getAttributeValueFromNode(targetNode, 'href');
+ }
+
+ var contentNode = this.findPieceNode(node);
+
+ if (query.hasNodeAttributeWithValue(contentNode, 'href')) {
+ return query.getAttributeValueFromNode(contentNode, 'href');
+ }
+ },
+ removeDomainIfIsUrl: function (text) {
+ if (text && -1 !== text.search(/^https?:\/\/[^\/]+/)) {
+ text = text.replace(/^.*\/\/[^\/]+/, ''); // TODO only remove if !== location.origin
+ }
+
+ return text;
+ },
+ findMediaUrlInNode: function (node)
+ {
+ if (!node) {
+ return;
+ }
+
+ var mediaElements = ['img', 'embed', 'video', 'audio'];
+ var elementName = node.nodeName.toLowerCase();
+
+ if (-1 !== mediaElements.indexOf(elementName) && query.findFirstNodeHavingAttributeWithValue(node, 'src')) {
+
+ var sourceNode = query.findFirstNodeHavingAttributeWithValue(node, 'src');
+
+ return query.getAttributeValueFromNode(sourceNode, 'src');
+ }
+
+ if (elementName === 'object' && query.hasNodeAttributeWithValue(node, 'data')) {
+
+ return query.getAttributeValueFromNode(node, 'data');
+ }
+
+ },
+ buildContentPiece: function (node)
+ {
+ var name = this.findContentName(node);
+ var piece = this.findContentPiece(node);
+ var target = this.findContentTarget(node);
+
+ return {
+ c_n: name ? name : 'Unknown',
+ c_p: piece ? piece : 'Unknown',
+ c_t: target ? target : ''
+ };
+ },
+ collectContent: function ()
+ {
+ var cssSelector = '.' + this.CONTENT_CLASS;
+ var attrSelector = '[' + this.CONTENT_ATTR + ']';
+ var contentNodes = query.findMultiple([cssSelector, attrSelector]);
+
+ if (!contentNodes || !contentNodes.length) {
+ return;
+ }
+
+ var contents = [];
+
+ var index;
+ for (index = 0; index < contentNodes.length; index++) {
+ contents.push(this.buildContentPiece(contentNodes[index]));
+ }
+
+ return contents;
+ }
+ };
+
+ /************************************************************
* Page Overlay
************************************************************/
@@ -1973,386 +2384,22 @@ if (typeof Piwik !== 'object') {
}
}
- function makeNodesUnique(nodes)
- {
- nodes.sort(function (n1, n2) {
- if (n1 === n2) {
- return 0;
- }
-
- return n1.innerHTML > n2.innerHTML ? 1 : -1;
- });
-
- var index = 0;
- var numDuplicates = 0;
- var duplicates = [];
- var node;
-
- while ((node = nodes[index++])) {
- if (node === nodes[index]) {
- numDuplicates = duplicates.push(index);
- }
- }
-
- while (numDuplicates--) {
- nodes.splice(duplicates[numDuplicates], 1);
- }
-
- return nodes;
- }
-
- function queryDom(selector)
- {
- if (!document.querySelectorAll) {
- return []; // TODO
- }
-
- return document.querySelectorAll(selector);
- }
-
- function queryDomMultiple(selectors)
- {
- var index;
- var nodes = [];
- for (index = 0; index < selectors.length; index++) {
- nodes = nodes.concat(queryDom(selectors[index]));
- }
-
- nodes = makeNodesUnique(nodes);
-
- return nodes;
- }
-
- function findContentName(node)
- {
- /**
- * the Content Name must be memorable and distinguishable from others. Piwik will detect the content name by:
- o TODO what is actually meant by main content element, it is described three times differently here
- o reading the 'data-name' attribute of the main content element: <div data-name="Content name 1" ...>
- o reading the title element of the main content element: <a href="{CLICK_URL}" data-trackclick title="This is used as content name">
- o TODO image hard coded makes no sense, reading the title element of the Image found within this link element and used as content image <a href="{CLICK_URL}" data-trackclick> <img title="This is used as content name" src="{BANNER_IMAGE}"> </a>
- o note: if data-name=" is not found in the data-trackclick element or any children, piwik will also read the title="" and alt="" attributes
- o TODO not possible as well, if no title or alt is found, the Content Image name is used as Content name, eg. "SHOP-new_at_shopi_tile"
- + TOOD everything here is very vague and it is way too complicated for users to understand which value will be used!!!
- */
-
- /**
- * It should be actually
- * Search for data-name attribute where piwik-trackcontent is set // why not let users directly specify `piwik-trackcontent="data name"`???
- * Search for data-name attribute where piwik-clickurl is set
- * Search for any data-name attribute within piwik-trackcontent's children
- * Search for title attribute where piwik-trackcontent is set
- * Search for title attribute where piwik-clickurl is set
- * Search for any title within piwik-clickurl's children
- * Search for any alt within piwik-clickurl's children
- * TODO use 'Unknown'? or ignore content?
- *
- * TODO Actually I think we should read ONLY!!! data-name and maybe title attribute to keep it simple for users! It would end in random content names that change often!!!
- */
-
- /**
- * So better:
- * Search for any data-name attribute within the content (children of piwik-trackcontent)
- * Search for any title attribute within click-url (children of piwik-clickurl)
- * Search for any alt attribute within click-url (children of piwik-clickurl)
- *
- * Maybe we should prefix data-name since it might be used in other components as well!
- */
-
- var name;
- var target = '';
- var clickUrlNode = null;
-
- if (hasNodeAttributeWithValue(node, 'data-name')) {
- return getAttributeValueFromNode(node, 'data-name');
- }
-
- if (hasNodeAttributeWithValue(clickUrlNode, 'data-name')) {
- return getAttributeValueFromNode(clickUrlNode, 'data-name');
- }
-
- name = findFirstNodeHavingAttributeWithValue(node, 'data-name');
-
- if (name) {
- return name;
- }
-
- if (hasNodeAttributeWithValue(node, 'title')) {
- return getAttributeValueFromNode(node, 'title');
- }
-
- if (hasNodeAttributeWithValue(clickUrlNode, 'title')) {
- return getAttributeValueFromNode(clickUrlNode, 'title');
- }
-
- name = findFirstNodeHavingAttributeWithValue(clickUrlNode, 'title');
-
- if (name) {
- return name;
- }
-
- name = findFirstNodeHavingAttributeWithValue(clickUrlNode, 'alt');
-
- if (name) {
- return name;
- }
-
- return 'Unknown';
- }
-
- function findContentPiece(node)
- {
- /**
- * the Content Image is what all visitors see before clicking on the content.
- o by default, Piwik will automatically detect the first image found within the content:
- o alternatively, you may add a CSS class to the image element to use as banner image. <img class="piwik-banner" src="{BANNER_IMAGE}">
- o or add a tag <img data-banner src="{BANNER_IMAGE}">
- */
- return '';
- }
-
- function findContentTarget(node)
- {
- /**
- * the Click URL can be a landing page or a product page. Help Piwik detect this Click URL by tagging your content links elements:
- o by default, Piwik will automatically detect the first link found within the content:
- o you may add a CSS class to the link element to track, <a class="piwik-trackclick" href="{CLICK_URL}">
- o you may add a tag "data-click" to the link element <a data-trackclick href="{CLICK_URL}">
- */
-
- var link;
- var target = '';
-
- link = findFirstNodeHavingAttribute(node, 'data-trackclick');
- // TODO it might be not always 'href' or it may contain javascript so we allow data-trackclick="http://..."?
-
- if (link) {
- target = getAttributeValueFromNode(node, 'data-trackclick');
-
- if (target) {
- return target;
- }
- }
-
-
- if (!link) {
- link = findFirstNodeHavingClass(node, 'piwik-trackclick');
- }
-
- if (!link) {
- link = findFirstLink(node)
- }
-
- if (!link) {
- return;
- }
-
- return getAttributeValueFromNode(node, 'href');
- }
-
- function getAttributeValueFromNode(node, attributeName)
- {
- if (node && node.getAttribute) {
- return node.getAttribute(attributeName)
- }
-
- if (!node || !node.attributes) {
- return;
- }
-
- if ('undefined' === (typeof node.attributes[attributeName])) {
- return;
- }
-
- if (node.attributes[attributeName].value) {
- return node.attributes[attributeName].value; // nodeValue is deprecated ie Chrome
- }
-
- if (node.attributes[attributeName].nodeValue) {
- return node.attributes[attributeName].nodeValue;
- }
-
- var index;
- var attrs = node.attributes;
-
- for (index = 0; index < attrs.length; index++) {
- if (attrs[index].nodeName === attributeName) {
- return attrs[index].nodeValue;
- }
- }
-
- return null;
- }
-
- function hasNodeAttributeWithValue(node, attributeName)
- {
- if (hasNodeAttribute(node, attributeName)) {
- var value = getAttributeValueFromNode(node, attributeName);
-
- if (value) {
- return value;
- }
- }
- }
-
- function hasNodeAttribute(node, attributeName)
- {
- if (node && node.hasAttribute) {
- return node.hasAttribute(attributeName)
- }
-
- if (node && node.attributes) {
- return 'undefined' !== (typeof node.attributes[attributeName])
- }
-
- return false;
- }
-
- function hasNodeCssClass(node, className)
- {
- if (node && node.className) {
- var classes = node.className.split(' ');
- if (-1 !== classes.indexOf(className)) {
- return true;
- }
- }
-
- return false;
- }
-
- function findNodesHavingAttribute(nodeToSearch, attributeName, nodes)
- {
- if (!nodes) {
- nodes = []
- }
-
- if (!nodeToSearch) {
- return nodes;
- }
-
- var index, child;
- for (index = 0; index < nodeToSearch.children.length; index++) {
- child = nodeToSearch.children[index];
- if (hasNodeAttribute(child, attributeName)) {
- nodes.push(child);
- }
-
- nodes = findNodesHavingAttribute(child, attributeName, nodes);
- }
-
- return nodes;
- }
-
- function findNodesHavingCssClass(nodeToSearch, className, nodes)
- {
- if (!nodes) {
- nodes = []
- }
-
- if (!nodeToSearch) {
- return nodes;
- }
-
- if (nodeToSearch.getElementsByClassName) {
- return nodeToSearch.getElementsByClassName(className);
- }
-
- var index, child;
- for (index = 0; index < nodeToSearch.children.length; index++) {
- child = nodeToSearch.children[index];
- if (hasNodeCssClass(child, className)) {
- nodes.push(child);
- }
-
- nodes = findNodesHavingCssClass(child, className, nodes);
- }
-
- return nodes;
- }
-
- function findFirstNodeHavingClass(node, className)
- {
- if (hasNodeCssClass(node, className)) {
- return node;
- }
-
- var nodes = findNodesHavingCssClass(node, className);
-
- if (nodes && nodes.length) {
- return nodes[0]; // TODO here we should check whether this node is also present within another nested piece of content and if there are multiple other nodes maybe use the next one
- }
- }
-
- function findFirstNodeHavingAttributeWithValue(node, attributeName)
- {
- if (hasNodeAttribute(node, attributeName) && getAttributeValueFromNode(node, attributeName)) {
- return node;
- }
-
- var nodes = findNodesHavingAttribute(node, attributeName);
-
- var index;
- for (index = 0; index < nodes.length; index++) {
- if (getAttributeValueFromNode(nodes[index], attributeName)) {
- return nodes[index];
- }
- }
- }
-
- function findFirstNodeHavingAttribute(node, attributeName)
- {
- if (hasNodeAttribute(node, attributeName)) {
- return node;
- }
-
- var nodes = findNodesHavingAttribute(node, attributeName);
-
- if (nodes && nodes.length) {
- return nodes[0]; // TODO here we should check whether this node is also present within another nested piece of content and if there are multiple other nodes maybe use the next one
- }
- }
-
- function findFirstLink(node)
- {
- var linkNodes = node.getElementsByTagName('a');
-
- if (linkNodes && linkNodes.length) {
- return linkNodes[0];
- }
- }
-
- function buildContentPiece(node)
- {
- return {
- c_n: findContentName(node),
- c_p: findContentPiece(node),
- c_t: findContentTarget(node)
- };
- }
-
- function collectContentPieces()
- {
- var contentNodes = queryDomMultiple(['.piwik-trackcontent', '[data-trackcontent]']);
-
- if (!contentNodes.length) {
- return;
- }
-
- var contents = [];
-
- var index;
- for (index = 0; index < contentNodes.length; index++) {
- contents.push(buildContentPiece(contents[index]));
- }
-
- return contents;
- }
-
/*
* Log all content pieces
*/
function logContentPieces() {
- var contents = collectContentPieces();
+ var contents = content.collectContent();
+
+ // sendRequest(request, configTrackerPause);
+ /**
+ * {
+ "requests": [
+ "?idsite=1&url=http://example.org&action_name=Test bulk log Pageview&rec=1",
+ "?idsite=1&url=http://example.net/test.htm&action_name=Another bul k page view&rec=1"
+ ],
+ "token_auth": "33dc3f2536d3025974cccb4b4d2d98f4"
+}
+ */
// send bulk tracking request?
}