PDF rausgenommen
This commit is contained in:
145
msd2/tracking/piwik/plugins/Overlay/client/client.css
Normal file
145
msd2/tracking/piwik/plugins/Overlay/client/client.css
Normal file
@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Reset styles
|
||||
*/
|
||||
|
||||
#PIS_StatusBar,
|
||||
#PIS_StatusBar .PIS_Item,
|
||||
#PIS_StatusBar .PIS_Loading,
|
||||
.PIS_LinkTag,
|
||||
.PIS_LinkHighlightBoxTop,
|
||||
.PIS_LinkHighlightBoxRight,
|
||||
.PIS_LinkHighlightBoxLeft,
|
||||
.PIS_LinkHighlightBoxText {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 11px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
vertical-align: baseline;
|
||||
line-height: 1.4em;
|
||||
text-indent: 0;
|
||||
text-decoration: none;
|
||||
text-transform: none;
|
||||
cursor: default;
|
||||
text-align: left;
|
||||
float: none;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link Tags
|
||||
*/
|
||||
|
||||
.PIS_LinkTag {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999999;
|
||||
width: 36px;
|
||||
height: 21px;
|
||||
text-align: left;
|
||||
background: url(./linktags_lessshadow.png) no-repeat 0 -21px;
|
||||
overflow: hidden;
|
||||
transform-origin: 100% 50%;
|
||||
transition: 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.PIS_LinkTag span {
|
||||
position: absolute;
|
||||
width: 31px;
|
||||
height: 14px;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
line-height: 14px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Highlighted {
|
||||
z-index: 1000002;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Highlighted span {
|
||||
color: #E87500;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Right {
|
||||
background-position: -36px -21px;
|
||||
transform-origin: 0% 50%;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Right span,
|
||||
.PIS_LinkTag.PIS_BottomRight span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Bottom {
|
||||
background-position: 0 0;
|
||||
transform-origin: 100% 50%;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_Bottom span,
|
||||
.PIS_LinkTag.PIS_BottomRight span {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.PIS_LinkTag.PIS_BottomRight {
|
||||
background-position: -36px 0;
|
||||
transform-origin: 0% 50%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link Highlights
|
||||
*/
|
||||
|
||||
.PIS_LinkHighlightBoxTop,
|
||||
.PIS_LinkHighlightBoxRight,
|
||||
.PIS_LinkHighlightBoxText,
|
||||
.PIS_LinkHighlightBoxLeft {
|
||||
position: absolute;
|
||||
z-index: 1000001;
|
||||
overflow: hidden;
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
background: #E87500;
|
||||
}
|
||||
|
||||
.PIS_LinkHighlightBoxText {
|
||||
line-height: 20px;
|
||||
height: 20px;
|
||||
font-size: 11px;
|
||||
color: white;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status bar
|
||||
*/
|
||||
|
||||
#PIS_StatusBar {
|
||||
padding: 10px 0;
|
||||
position: fixed;
|
||||
z-index: 1000020;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-top: 1px solid #ccc;
|
||||
border-left: 1px solid #ccc;
|
||||
background: #fbfbfb;
|
||||
border-radius: 6px 0 0;
|
||||
}
|
||||
|
||||
#PIS_StatusBar .PIS_Item {
|
||||
text-align: right;
|
||||
padding: 3px 5px 0 0;
|
||||
margin: 0 15px 0 20px;
|
||||
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#PIS_StatusBar .PIS_Loading {
|
||||
background: url(./loading.gif) no-repeat right center;
|
||||
padding-right: 30px;
|
||||
}
|
258
msd2/tracking/piwik/plugins/Overlay/client/client.js
Normal file
258
msd2/tracking/piwik/plugins/Overlay/client/client.js
Normal file
@ -0,0 +1,258 @@
|
||||
var Piwik_Overlay_Client = (function () {
|
||||
|
||||
var DOMAIN_PARSE_REGEX = /^http(s)?:\/\/(www\.)?([^\/]*)/i;
|
||||
|
||||
/** jQuery */
|
||||
var $;
|
||||
|
||||
/** Url of the Piwik root */
|
||||
var piwikRoot;
|
||||
|
||||
/** protocol and domain of Piwik root */
|
||||
var piwikOrigin;
|
||||
|
||||
/** Piwik idsite */
|
||||
var idSite;
|
||||
|
||||
/** The current period and date */
|
||||
var period, date, segment;
|
||||
|
||||
/** Reference to the status bar DOM element */
|
||||
var statusBar;
|
||||
|
||||
/** Counter for request IDs for postMessage based API requests. */
|
||||
var lastRequestId = 0;
|
||||
|
||||
/** Map of callbacks for postMessage based API requests. */
|
||||
var requestCallbacks = {};
|
||||
|
||||
/** Load the client CSS */
|
||||
function loadCss() {
|
||||
var css = c('link').attr({
|
||||
rel: 'stylesheet',
|
||||
type: 'text/css',
|
||||
href: piwikRoot + '/plugins/Overlay/client/client.css'
|
||||
});
|
||||
$('head').append(css);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loads jQuery, if it is not there yet.
|
||||
* The callback is triggered after jQuery is loaded.
|
||||
*/
|
||||
function loadJQuery(callback) {
|
||||
if (typeof jQuery != 'undefined') {
|
||||
$ = jQuery;
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
Piwik_Overlay_Client.loadScript('libs/bower_components/jquery/dist/jquery.min.js', function () {
|
||||
$ = jQuery;
|
||||
jQuery.noConflict();
|
||||
callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify Piwik of the current iframe location.
|
||||
* This way, we can display additional metrics on the side of the iframe.
|
||||
*/
|
||||
function notifyPiwikOfLocation() {
|
||||
// check whether the session has been opened in a new tab (instead of an iframe)
|
||||
if (window != window.top) {
|
||||
var iframe = c('iframe', false, {
|
||||
src: piwikRoot + '/index.php?module=Overlay&action=notifyParentIframe#' + window.location.href
|
||||
}).css({width: 0, height: 0, border: 0});
|
||||
|
||||
$('body').append(iframe);
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a jqueryfied DOM element */
|
||||
function c(tagName, className, attributes) {
|
||||
var el = $(document.createElement(tagName));
|
||||
|
||||
if (className) {
|
||||
if (className.substring(0, 1) == '#') {
|
||||
var id = className.substring(1, className.length);
|
||||
id = 'PIS_' + id;
|
||||
el.attr('id', id);
|
||||
}
|
||||
else {
|
||||
className = 'PIS_' + className;
|
||||
el.addClass(className);
|
||||
}
|
||||
}
|
||||
|
||||
if (attributes) {
|
||||
el.attr(attributes);
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
function nextRequestId() {
|
||||
var nextId = lastRequestId + 1;
|
||||
lastRequestId = nextId;
|
||||
return nextId;
|
||||
}
|
||||
|
||||
function handlePostMessages() {
|
||||
window.addEventListener("message", function (event) {
|
||||
if (event.origin !== piwikOrigin) {
|
||||
return;
|
||||
}
|
||||
|
||||
var strData = event.data.split(':', 3);
|
||||
if (strData[0] !== 'overlay.response') {
|
||||
return;
|
||||
}
|
||||
|
||||
var requestId = strData[1];
|
||||
if (!requestCallbacks[requestId]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var callback = requestCallbacks[requestId];
|
||||
delete requestCallbacks[requestId];
|
||||
|
||||
var data = JSON.parse(decodeURIComponent(strData[2]));
|
||||
if (typeof data.result !== 'undefined'
|
||||
&& data.result === 'error'
|
||||
) {
|
||||
alert('Error: ' + data.message);
|
||||
} else {
|
||||
callback(data);
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
/** Initialize in-site analytics */
|
||||
initialize: function (pPiwikRoot, pIdSite, pPeriod, pDate, pSegment) {
|
||||
piwikRoot = pPiwikRoot;
|
||||
piwikOrigin = piwikRoot.match(DOMAIN_PARSE_REGEX)[0];
|
||||
idSite = pIdSite;
|
||||
period = pPeriod;
|
||||
date = pDate;
|
||||
segment = pSegment;
|
||||
|
||||
var load = this.loadScript;
|
||||
var loading = this.loadingNotification;
|
||||
|
||||
loadJQuery(function () {
|
||||
handlePostMessages();
|
||||
notifyPiwikOfLocation();
|
||||
loadCss();
|
||||
|
||||
// translations
|
||||
load('plugins/Overlay/client/translations.js', function () {
|
||||
Piwik_Overlay_Translations.initialize(function () {
|
||||
// following pages
|
||||
var finishPages = loading('Loading following pages');
|
||||
load('plugins/Overlay/client/followingpages.js', function () {
|
||||
Piwik_Overlay_FollowingPages.initialize(finishPages);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/** Create a jqueryfied DOM element */
|
||||
createElement: function (tagName, className, attributes) {
|
||||
return c(tagName, className, attributes);
|
||||
},
|
||||
|
||||
/** Load a script and wait for it to be loaded */
|
||||
loadScript: function (relativePath, callback) {
|
||||
var loaded = false;
|
||||
var onLoad = function () {
|
||||
if (!loaded) {
|
||||
loaded = true;
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
|
||||
script.onreadystatechange = function () {
|
||||
if (this.readyState == 'loaded' || this.readyState == 'complete') {
|
||||
onLoad();
|
||||
}
|
||||
};
|
||||
script.onload = onLoad;
|
||||
|
||||
script.src = piwikRoot + '/' + relativePath + '?v=1';
|
||||
head.appendChild(script);
|
||||
},
|
||||
|
||||
/** Piwik Overlay API Request */
|
||||
api: function (method, callback, additionalParams) {
|
||||
var url = piwikRoot + '/index.php?module=API&method=Overlay.' + method
|
||||
+ '&idSite=' + idSite + '&period=' + period + '&date=' + date + '&format=JSON&filter_limit=-1';
|
||||
|
||||
if (segment) {
|
||||
url += '&segment=' + segment;
|
||||
}
|
||||
|
||||
if (additionalParams) {
|
||||
url += '&' + additionalParams;
|
||||
}
|
||||
|
||||
var requestId = nextRequestId();
|
||||
requestCallbacks[requestId] = callback;
|
||||
|
||||
var matomoFrame = window.parent;
|
||||
matomoFrame.postMessage('overlay.call:' + requestId + ':' + encodeURIComponent(url), piwikOrigin);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize a notification
|
||||
* To hide the notification use the returned callback
|
||||
*/
|
||||
notification: function (message, addClass) {
|
||||
if (!statusBar) {
|
||||
statusBar = c('div', '#StatusBar').css('opacity', .8);
|
||||
$('body').prepend(statusBar);
|
||||
}
|
||||
|
||||
var item = c('div', 'Item').html(message);
|
||||
|
||||
if (addClass) {
|
||||
item.addClass('PIS_' + addClass);
|
||||
}
|
||||
|
||||
statusBar.show().append(item);
|
||||
|
||||
return function () {
|
||||
item.remove();
|
||||
if (!statusBar.children().length) {
|
||||
statusBar.hide();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/** Hide all notifications with a certain class */
|
||||
hideNotifications: function (className) {
|
||||
statusBar.find('.PIS_' + className).remove();
|
||||
if (!statusBar.children().length) {
|
||||
statusBar.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize a loading notification
|
||||
* To hide the notification use the returned callback
|
||||
*/
|
||||
loadingNotification: function (message) {
|
||||
return Piwik_Overlay_Client.notification(message, 'Loading');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
BIN
msd2/tracking/piwik/plugins/Overlay/client/close.png
Normal file
BIN
msd2/tracking/piwik/plugins/Overlay/client/close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 655 B |
561
msd2/tracking/piwik/plugins/Overlay/client/followingpages.js
Normal file
561
msd2/tracking/piwik/plugins/Overlay/client/followingpages.js
Normal file
@ -0,0 +1,561 @@
|
||||
var Piwik_Overlay_FollowingPages = (function () {
|
||||
|
||||
/** jQuery */
|
||||
var $ = jQuery;
|
||||
|
||||
/** Info about the following pages */
|
||||
var followingPages = [];
|
||||
|
||||
/** List of excluded get parameters */
|
||||
var excludedParams = [];
|
||||
|
||||
/** Index of the links on the page */
|
||||
var linksOnPage = {};
|
||||
|
||||
/** Reference to create element function */
|
||||
var c;
|
||||
|
||||
/** Counter for the largest clickRate on the page */
|
||||
var maxClickRate = 0;
|
||||
|
||||
/** Load the following pages */
|
||||
function load(callback) {
|
||||
// normalize current location
|
||||
var location = window.location.href;
|
||||
location = Piwik_Overlay_UrlNormalizer.normalize(location);
|
||||
location = (("https:" == document.location.protocol) ? 'https' : 'http') + '://' + location;
|
||||
|
||||
var excludedParamsLoaded = false;
|
||||
var followingPagesLoaded = false;
|
||||
|
||||
// load excluded params
|
||||
Piwik_Overlay_Client.api('getExcludedQueryParameters', function (data) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (typeof data[i] == 'object') {
|
||||
data[i] = data[i][0];
|
||||
}
|
||||
}
|
||||
excludedParams = data;
|
||||
|
||||
excludedParamsLoaded = true;
|
||||
if (followingPagesLoaded) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
// load following pages
|
||||
Piwik_Overlay_Client.api('getFollowingPages', function (data) {
|
||||
followingPages = data;
|
||||
processFollowingPages();
|
||||
|
||||
followingPagesLoaded = true;
|
||||
if (excludedParamsLoaded) {
|
||||
callback();
|
||||
}
|
||||
}, 'url=' + encodeURIComponent(location));
|
||||
}
|
||||
|
||||
/** Normalize the URLs of following pages and aggregate some stats */
|
||||
function processFollowingPages() {
|
||||
var totalClicks = 0;
|
||||
for (var i = 0; i < followingPages.length; i++) {
|
||||
var page = followingPages[i];
|
||||
// though the following pages are returned without the prefix, downloads
|
||||
// and outlinks still have it.
|
||||
page.label = Piwik_Overlay_UrlNormalizer.removeUrlPrefix(page.label);
|
||||
totalClicks += followingPages[i].referrals;
|
||||
}
|
||||
for (i = 0; i < followingPages.length; i++) {
|
||||
var clickRate = followingPages[i].referrals / totalClicks * 100;
|
||||
followingPages[i].clickRate = clickRate;
|
||||
if (clickRate > maxClickRate) maxClickRate = clickRate;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an index of links on the page.
|
||||
* This function is passed to $('a').each()
|
||||
*/
|
||||
var processLinkDelta = false;
|
||||
|
||||
function processLink() {
|
||||
var a = $(this);
|
||||
a[0].piwikDiscovered = true;
|
||||
|
||||
var href = a.attr('href');
|
||||
href = Piwik_Overlay_UrlNormalizer.normalize(href);
|
||||
|
||||
if (href) {
|
||||
if (typeof linksOnPage[href] == 'undefined') {
|
||||
linksOnPage[href] = [a];
|
||||
}
|
||||
else {
|
||||
linksOnPage[href].push(a);
|
||||
}
|
||||
}
|
||||
|
||||
if (href && processLinkDelta !== false) {
|
||||
if (typeof processLinkDelta[href] == 'undefined') {
|
||||
processLinkDelta[href] = [a];
|
||||
}
|
||||
else {
|
||||
processLinkDelta[href].push(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var repositionTimeout = false;
|
||||
var resizeTimeout = false;
|
||||
|
||||
function build(callback) {
|
||||
// build an index of all links on the page
|
||||
$('a').each(processLink);
|
||||
|
||||
// add tags to known following pages
|
||||
createLinkTags(linksOnPage);
|
||||
|
||||
// position the tags
|
||||
positionLinkTags();
|
||||
|
||||
callback();
|
||||
|
||||
// check on a regular basis whether new links have appeared.
|
||||
// we use a timeout instead of an interval to make sure one call is done before
|
||||
// the next one is triggered
|
||||
var repositionAfterTimeout;
|
||||
repositionAfterTimeout = function () {
|
||||
repositionTimeout = window.setTimeout(function () {
|
||||
findNewLinks();
|
||||
positionLinkTags(repositionAfterTimeout);
|
||||
}, 1800);
|
||||
};
|
||||
repositionAfterTimeout();
|
||||
|
||||
// reposition link tags on window resize
|
||||
$(window).resize(function () {
|
||||
if (repositionTimeout) {
|
||||
window.clearTimeout(repositionTimeout);
|
||||
}
|
||||
if (resizeTimeout) {
|
||||
window.clearTimeout(resizeTimeout);
|
||||
}
|
||||
resizeTimeout = window.setTimeout(function () {
|
||||
positionLinkTags();
|
||||
repositionAfterTimeout();
|
||||
}, 70);
|
||||
});
|
||||
}
|
||||
|
||||
/** Create a batch of link tags */
|
||||
function createLinkTags(links) {
|
||||
var body = $('body');
|
||||
for (var i = 0; i < followingPages.length; i++) {
|
||||
var url = followingPages[i].label;
|
||||
if (typeof links[url] != 'undefined') {
|
||||
for (var j = 0; j < links[url].length; j++) {
|
||||
createLinkTag(links[url][j], url, followingPages[i], body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Create the link tag element */
|
||||
function createLinkTag(linkTag, linkUrl, data, body) {
|
||||
if (typeof linkTag[0].piwikTagElement != 'undefined' && linkTag[0].piwikTagElement !== null) {
|
||||
// this link tag already has a tag element. happens in rare cases.
|
||||
return;
|
||||
}
|
||||
|
||||
linkTag[0].piwikTagElement = true;
|
||||
|
||||
var rate = data.clickRate;
|
||||
|
||||
if( rate < 0.001 ) {
|
||||
rate = '<0.001';
|
||||
} else if (rate < 10) {
|
||||
rate = Math.round(rate * 10) / 10;
|
||||
} else {
|
||||
rate = Math.round(rate);
|
||||
}
|
||||
|
||||
var span = c('span').html(rate + '%');
|
||||
var tagElement = c('div', 'LinkTag').append(span).hide();
|
||||
|
||||
tagElement.attr({'data-rateofmax': Math.round(100 * rate/maxClickRate)/100});
|
||||
|
||||
body.prepend(tagElement);
|
||||
|
||||
linkTag.add(tagElement).hover(function () {
|
||||
highlightLink(linkTag, linkUrl, data);
|
||||
}, function () {
|
||||
unHighlightLink(linkTag, linkUrl);
|
||||
});
|
||||
|
||||
// attach the tag element to the link element. we can't use .data() because jquery
|
||||
// would remove it when removing the link from the dom. but we still need to find
|
||||
// the tag element to remove it as well.
|
||||
linkTag[0].piwikTagElement = tagElement;
|
||||
}
|
||||
|
||||
/** Position the link tags next to the links */
|
||||
function positionLinkTags(callback) {
|
||||
var url, linkTag, tagElement, offset, top, left, isRight, hasOneChild, inlineChild;
|
||||
var tagWidth = 36, tagHeight = 21;
|
||||
var tagsToRemove = [];
|
||||
|
||||
for (var i = 0; i < followingPages.length; i++) {
|
||||
url = followingPages[i].label;
|
||||
if (typeof linksOnPage[url] != 'undefined') {
|
||||
for (var j = 0; j < linksOnPage[url].length; j++) {
|
||||
linkTag = linksOnPage[url][j];
|
||||
tagElement = linkTag[0].piwikTagElement;
|
||||
|
||||
if (linkTag.closest('html').length == 0 || !tagElement) {
|
||||
// the link has been removed from the dom
|
||||
if (tagElement) {
|
||||
tagElement.hide();
|
||||
}
|
||||
// mark for deletion. don't delete it now because we
|
||||
// are iterating of the array it's in. it will be deleted
|
||||
// below this for loop.
|
||||
tagsToRemove.push({
|
||||
index1: url,
|
||||
index2: j
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
hasOneChild = checkHasOneChild(linkTag);
|
||||
inlineChild = false;
|
||||
if (hasOneChild && linkTag.css('display') != 'block') {
|
||||
inlineChild = linkTag.children().eq(0);
|
||||
}
|
||||
|
||||
if (getVisibility(linkTag) == 'hidden' || (
|
||||
// in case of hasOneChild: jquery always returns linkTag.is(':visible')=false
|
||||
!linkTag.is(':visible') && !(hasOneChild && inlineChild && inlineChild.is(':visible'))
|
||||
)) {
|
||||
// link is not visible
|
||||
tagElement.hide();
|
||||
continue;
|
||||
}
|
||||
|
||||
tagElement.attr('class', 'PIS_LinkTag'); // reset class
|
||||
if (tagElement[0].piwikHighlighted) {
|
||||
tagElement.addClass('PIS_Highlighted');
|
||||
}
|
||||
|
||||
// see comment in highlightLink()
|
||||
if (hasOneChild && linkTag.find('> img').length === 1) {
|
||||
offset = linkTag.find('> img').offset();
|
||||
if (offset.left == 0 && offset.top == 0) {
|
||||
offset = linkTag.offset();
|
||||
}
|
||||
} else if (inlineChild !== false) {
|
||||
offset = inlineChild.offset();
|
||||
} else {
|
||||
offset = linkTag.offset();
|
||||
}
|
||||
|
||||
var zoomFactor = 1 + +tagElement.attr('data-rateofmax');
|
||||
top = offset.top - tagHeight + 6;
|
||||
left = offset.left - tagWidth + 10;
|
||||
|
||||
if (isRight = (left < zoomFactor * tagWidth - tagWidth ) ) {
|
||||
tagElement.addClass('PIS_Right');
|
||||
left = offset.left + linkTag.outerWidth() - 10;
|
||||
}
|
||||
|
||||
if (top < zoomFactor * tagHeight - tagHeight ) {
|
||||
tagElement.addClass(isRight ? 'PIS_BottomRight' : 'PIS_Bottom');
|
||||
top = offset.top + linkTag.outerHeight() - 6;
|
||||
}
|
||||
|
||||
tagElement.css({
|
||||
'-webkit-transform': 'translate(' + left + 'px, ' + top + 'px) scale(' + zoomFactor + ')',
|
||||
'-moz-transform': 'translate(' + left + 'px, ' + top + 'px) scale(' + zoomFactor + ')',
|
||||
'-ms-transform': 'translate(' + left + 'px, ' + top + 'px) scale(' + zoomFactor + ')',
|
||||
'-o-transform': 'translate(' + left + 'px, ' + top + 'px) scale(' + zoomFactor + ')',
|
||||
'transform': 'translate(' + left + 'px, ' + top + 'px) scale(' + zoomFactor + ')',
|
||||
'opacity': zoomFactor/2
|
||||
});
|
||||
|
||||
tagElement.show();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// walk tagsToRemove from back to front because it contains the indexes in ascending
|
||||
// order. removing something from the front will impact the indexes that come after-
|
||||
// wards. this can be avoided by starting in the back.
|
||||
for (var k = tagsToRemove.length - 1; k >= 0; k--) {
|
||||
var tagToRemove = tagsToRemove[k];
|
||||
linkTag = linksOnPage[tagToRemove.index1][tagToRemove.index2];
|
||||
// remove the tag element from the dom
|
||||
if (linkTag && linkTag[0] && linkTag[0].piwikTagElement) {
|
||||
tagElement = linkTag[0].piwikTagElement;
|
||||
if (tagElement[0].piwikHighlighted) {
|
||||
unHighlightLink(linkTag, tagToRemove.index1);
|
||||
}
|
||||
tagElement.remove();
|
||||
linkTag[0].piwikTagElement = null;
|
||||
}
|
||||
// remove the link from the index
|
||||
linksOnPage[tagToRemove.index1].splice(tagToRemove.index2, 1);
|
||||
if (linksOnPage[tagToRemove.index1].length == 0) {
|
||||
delete linksOnPage[tagToRemove.index1];
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof callback == 'function') {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the visibility of an element */
|
||||
function getVisibility(el) {
|
||||
var visibility = el.css('visibility');
|
||||
if (visibility == 'inherit') {
|
||||
el = el.parent();
|
||||
if (el.length) {
|
||||
return getVisibility(el);
|
||||
}
|
||||
}
|
||||
return visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out whether a link has only one child. Using .children().length === 1 doesn't work
|
||||
* because it doesn't take additional text nodes into account.
|
||||
*/
|
||||
function checkHasOneChild(linkTag) {
|
||||
var hasOneChild = (linkTag.children().length === 1);
|
||||
if (hasOneChild) {
|
||||
// if the element contains one tag and some text, hasOneChild is set incorrectly
|
||||
var contents = linkTag.contents();
|
||||
if (contents.length > 1) {
|
||||
// find non-empty text nodes
|
||||
contents = contents.filter(function () {
|
||||
return this.nodeType == 3 && // text node
|
||||
$.trim(this.data).length > 0; // contains more than whitespaces
|
||||
});
|
||||
if (contents.length) {
|
||||
hasOneChild = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasOneChild;
|
||||
}
|
||||
|
||||
/** Check whether new links have been added to the dom */
|
||||
function findNewLinks() {
|
||||
var newLinks = $('a').filter(function () {
|
||||
return typeof this.piwikDiscovered == 'undefined' || this.piwikDiscovered === null;
|
||||
});
|
||||
|
||||
if (!newLinks.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
processLinkDelta = {};
|
||||
newLinks.each(processLink);
|
||||
createLinkTags(processLinkDelta);
|
||||
processLinkDelta = false;
|
||||
}
|
||||
|
||||
/** Dom elements used for drawing a box around the link */
|
||||
var highlightElements = [];
|
||||
|
||||
/** Highlight a link on hover */
|
||||
function highlightLink(linkTag, linkUrl, data) {
|
||||
if (highlightElements.length == 0) {
|
||||
highlightElements.push(c('div', 'LinkHighlightBoxTop'));
|
||||
highlightElements.push(c('div', 'LinkHighlightBoxRight'));
|
||||
highlightElements.push(c('div', 'LinkHighlightBoxLeft'));
|
||||
|
||||
highlightElements.push(c('div', 'LinkHighlightBoxText'));
|
||||
|
||||
var body = $('body');
|
||||
for (var i = 0; i < highlightElements.length; i++) {
|
||||
body.prepend(highlightElements[i].css({display: 'none'}));
|
||||
}
|
||||
}
|
||||
|
||||
var width = linkTag.outerWidth();
|
||||
|
||||
var offset, height;
|
||||
var hasOneChild = checkHasOneChild(linkTag);
|
||||
if (hasOneChild && linkTag.find('img').length === 1) {
|
||||
// if the <a> tag contains only an <img>, the offset and height methods don't work properly.
|
||||
// as a result, the box around the image link would be wrong. we use the image to derive
|
||||
// the offset and height instead of the link to get correct values.
|
||||
var img = linkTag.find('img');
|
||||
offset = img.offset();
|
||||
height = img.outerHeight();
|
||||
}
|
||||
if (hasOneChild && linkTag.css('display') != 'block') {
|
||||
// if the <a> tag is not displayed as block and has only one child, using the child to
|
||||
// derive the offset and dimensions is more robust.
|
||||
var child = linkTag.children().eq(0);
|
||||
offset = child.offset();
|
||||
height = child.outerHeight();
|
||||
width = child.outerWidth();
|
||||
} else {
|
||||
offset = linkTag.offset();
|
||||
height = linkTag.outerHeight();
|
||||
}
|
||||
|
||||
var numLinks = linksOnPage[linkUrl].length;
|
||||
|
||||
putBoxAroundLink(offset, width, height, numLinks, data.referrals);
|
||||
|
||||
// highlight tags
|
||||
for (var j = 0; j < numLinks; j++) {
|
||||
var tag = linksOnPage[linkUrl][j][0].piwikTagElement;
|
||||
tag.addClass('PIS_Highlighted');
|
||||
tag[0].piwikHighlighted = true;
|
||||
}
|
||||
|
||||
// Sometimes it fails to remove the notification when the hovered element is removed.
|
||||
// To make sure we don't display more than one location at a time, we hide all before showing the new one.
|
||||
Piwik_Overlay_Client.hideNotifications('LinkLocation');
|
||||
|
||||
// we don't use .data() because jquery would remove the callback when the link tag is removed
|
||||
linkTag[0].piwikHideNotification = Piwik_Overlay_Client.notification(
|
||||
Piwik_Overlay_Translations.get('link') + ': ' + linkUrl, 'LinkLocation');
|
||||
}
|
||||
|
||||
function putBoxAroundLink(offset, width, height, numLinks, numReferrals) {
|
||||
var borderWidth = 2;
|
||||
var padding = 4; // the distance between the link and the border
|
||||
|
||||
// top border
|
||||
highlightElements[0]
|
||||
.width(width + 2 * padding)
|
||||
.css({
|
||||
top: offset.top - borderWidth - padding,
|
||||
left: offset.left - padding
|
||||
}).show();
|
||||
|
||||
// right border
|
||||
highlightElements[1]
|
||||
.height(height + 2 * borderWidth + 2 * padding)
|
||||
.css({
|
||||
top: offset.top - borderWidth - padding,
|
||||
left: offset.left + width + padding
|
||||
}).show();
|
||||
|
||||
// left border
|
||||
highlightElements[2]
|
||||
.height(height + 2 * borderWidth + 2 * padding)
|
||||
.css({
|
||||
top: offset.top - borderWidth - padding,
|
||||
left: offset.left - borderWidth - padding
|
||||
}).show();
|
||||
|
||||
// bottom box text
|
||||
var text;
|
||||
if (numLinks > 1) {
|
||||
text = Piwik_Overlay_Translations.get('clicksFromXLinks')
|
||||
.replace(/%1\$s/, numReferrals)
|
||||
.replace(/%2\$s/, numLinks);
|
||||
} else if (numReferrals == 1) {
|
||||
text = Piwik_Overlay_Translations.get('oneClick');
|
||||
} else {
|
||||
text = Piwik_Overlay_Translations.get('clicks')
|
||||
.replace(/%s/, numReferrals);
|
||||
}
|
||||
|
||||
// bottom box position and dimension
|
||||
var textPadding = ' ';
|
||||
highlightElements[3].html(textPadding + text + textPadding).css({
|
||||
width: 'auto',
|
||||
top: offset.top + height + padding,
|
||||
left: offset.left - borderWidth - padding
|
||||
}).show();
|
||||
|
||||
var minBoxWidth = width + 2 * borderWidth + 2 * padding;
|
||||
if (highlightElements[3].width() < minBoxWidth) {
|
||||
// we cannot use minWidth because of IE7
|
||||
highlightElements[3].width(minBoxWidth);
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove highlight from link */
|
||||
function unHighlightLink(linkTag, linkUrl) {
|
||||
for (var i = 0; i < highlightElements.length; i++) {
|
||||
highlightElements[i].hide();
|
||||
}
|
||||
|
||||
var numLinks = linksOnPage[linkUrl].length;
|
||||
for (var j = 0; j < numLinks; j++) {
|
||||
var tag = linksOnPage[linkUrl][j][0].piwikTagElement;
|
||||
if (tag) {
|
||||
tag.removeClass('PIS_Highlighted');
|
||||
tag[0].piwikHighlighted = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((typeof linkTag[0].piwikHideNotification) == 'function') {
|
||||
linkTag[0].piwikHideNotification();
|
||||
linkTag[0].piwikHideNotification = null;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* The main method
|
||||
*/
|
||||
initialize: function (finishCallback) {
|
||||
c = Piwik_Overlay_Client.createElement;
|
||||
Piwik_Overlay_Client.loadScript('plugins/Overlay/client/urlnormalizer.js', function () {
|
||||
Piwik_Overlay_UrlNormalizer.initialize();
|
||||
load(function () {
|
||||
Piwik_Overlay_UrlNormalizer.setExcludedParameters(excludedParams);
|
||||
build(function () {
|
||||
finishCallback();
|
||||
})
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove everything from the dom and terminate timeouts.
|
||||
* This can be used from the console in order to load a new implementation for debugging afterwards.
|
||||
* If you add `Piwik_Overlay_FollowingPages.remove();` to the beginning and
|
||||
* `Piwik_Overlay_FollowingPages.initialize(function(){});` to the end of this file, you can just
|
||||
* paste it into the console to inject the new implementation.
|
||||
*/
|
||||
remove: function () {
|
||||
for (var i = 0; i < followingPages.length; i++) {
|
||||
var url = followingPages[i].label;
|
||||
if (typeof linksOnPage[url] != 'undefined') {
|
||||
for (var j = 0; j < linksOnPage[url].length; j++) {
|
||||
var linkTag = linksOnPage[url][j];
|
||||
var tagElement = linkTag[0].piwikTagElement;
|
||||
if (tagElement) {
|
||||
tagElement.remove();
|
||||
}
|
||||
linkTag[0].piwikTagElement = null;
|
||||
|
||||
$(linkTag).unbind('mouseenter').unbind('mouseleave');
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < highlightElements.length; i++) {
|
||||
highlightElements[i].remove();
|
||||
}
|
||||
if (repositionTimeout) {
|
||||
window.clearTimeout(repositionTimeout);
|
||||
}
|
||||
if (resizeTimeout) {
|
||||
window.clearTimeout(resizeTimeout);
|
||||
}
|
||||
$(window).unbind('resize');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
BIN
msd2/tracking/piwik/plugins/Overlay/client/linktags.png
Normal file
BIN
msd2/tracking/piwik/plugins/Overlay/client/linktags.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
BIN
msd2/tracking/piwik/plugins/Overlay/client/linktags_noshadow.png
Normal file
BIN
msd2/tracking/piwik/plugins/Overlay/client/linktags_noshadow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
msd2/tracking/piwik/plugins/Overlay/client/loading.gif
Normal file
BIN
msd2/tracking/piwik/plugins/Overlay/client/loading.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 723 B |
30
msd2/tracking/piwik/plugins/Overlay/client/translations.js
Normal file
30
msd2/tracking/piwik/plugins/Overlay/client/translations.js
Normal file
@ -0,0 +1,30 @@
|
||||
var Piwik_Overlay_Translations = (function () {
|
||||
|
||||
/** Translations strings */
|
||||
var translations = [];
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* Initialize translations module.
|
||||
* Callback is triggered when data is available.
|
||||
*/
|
||||
initialize: function (callback) {
|
||||
// Load translation data
|
||||
Piwik_Overlay_Client.api('getTranslations', function (data) {
|
||||
translations = data[0];
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
/** Get translation string */
|
||||
get: function (identifier) {
|
||||
if (typeof translations[identifier] == 'undefined') {
|
||||
return identifier;
|
||||
}
|
||||
return translations[identifier];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
200
msd2/tracking/piwik/plugins/Overlay/client/urlnormalizer.js
Normal file
200
msd2/tracking/piwik/plugins/Overlay/client/urlnormalizer.js
Normal file
@ -0,0 +1,200 @@
|
||||
/**
|
||||
* URL NORMALIZER
|
||||
* This utility preprocesses both the URLs in the document and
|
||||
* from the Piwik logs in order to make matching possible.
|
||||
*/
|
||||
var Piwik_Overlay_UrlNormalizer = (function () {
|
||||
|
||||
/** Base href of the current document */
|
||||
var baseHref = false;
|
||||
|
||||
/** Url of current folder */
|
||||
var currentFolder;
|
||||
|
||||
/** The current domain */
|
||||
var currentDomain;
|
||||
|
||||
/** Regular expressions for parameters to be excluded when matching links on the page */
|
||||
var excludedParamsRegEx = [];
|
||||
|
||||
/**
|
||||
* Basic normalizations for domain names
|
||||
* - remove protocol and www from absolute urls
|
||||
* - add a trailing slash to urls without a path
|
||||
*
|
||||
* Returns array
|
||||
* 0: normalized url
|
||||
* 1: true, if url was absolute (if not, no normalization was performed)
|
||||
*/
|
||||
function normalizeDomain(url) {
|
||||
if (url === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var absolute = false;
|
||||
|
||||
// remove protocol
|
||||
if (url.substring(0, 7) == 'http://') {
|
||||
absolute = true;
|
||||
url = url.substring(7, url.length);
|
||||
} else if (url.substring(0, 8) == 'https://') {
|
||||
absolute = true;
|
||||
url = url.substring(8, url.length);
|
||||
}
|
||||
|
||||
if (absolute) {
|
||||
// remove www.
|
||||
url = removeWww(url);
|
||||
|
||||
// add slash to domain names
|
||||
if (url.indexOf('/') == -1) {
|
||||
url += '/';
|
||||
}
|
||||
}
|
||||
|
||||
return [url, absolute];
|
||||
}
|
||||
|
||||
/** Remove www. from a domain */
|
||||
function removeWww(domain) {
|
||||
if (domain.substring(0, 4) == 'www.') {
|
||||
return domain.substring(4, domain.length);
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
initialize: function () {
|
||||
this.setCurrentDomain(document.location.host);
|
||||
this.setCurrentUrl(window.location.href);
|
||||
|
||||
var head = document.getElementsByTagName('head');
|
||||
if (head.length) {
|
||||
var base = head[0].getElementsByTagName('base');
|
||||
if (base.length && base[0].href) {
|
||||
this.setBaseHref(base[0].href);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Explicitly set domain (for testing)
|
||||
*/
|
||||
setCurrentDomain: function (pCurrentDomain) {
|
||||
currentDomain = removeWww(pCurrentDomain);
|
||||
},
|
||||
|
||||
/**
|
||||
* Explicitly set current url (for testing)
|
||||
*/
|
||||
setCurrentUrl: function (url) {
|
||||
var index = url.lastIndexOf('/');
|
||||
if (index != url.length - 1) {
|
||||
currentFolder = url.substring(0, index + 1);
|
||||
} else {
|
||||
currentFolder = url;
|
||||
}
|
||||
currentFolder = normalizeDomain(currentFolder)[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Explicitly set base href (for testing)
|
||||
*/
|
||||
setBaseHref: function (pBaseHref) {
|
||||
if (!pBaseHref) {
|
||||
baseHref = false;
|
||||
} else {
|
||||
baseHref = normalizeDomain(pBaseHref)[0];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the parameters to be excluded when matching links on the page
|
||||
*/
|
||||
setExcludedParameters: function (pExcludedParams) {
|
||||
excludedParamsRegEx = [];
|
||||
for (var i = 0; i < pExcludedParams.length; i++) {
|
||||
var paramString = pExcludedParams[i];
|
||||
excludedParamsRegEx.push(new RegExp('&' + paramString + '=([^&#]*)', 'ig'));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the protocol and the prefix of a URL
|
||||
*/
|
||||
removeUrlPrefix: function (url) {
|
||||
return normalizeDomain(url)[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Normalize URL
|
||||
* Can be an absolute or a relative URL
|
||||
*/
|
||||
normalize: function (url) {
|
||||
if (!url) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// ignore urls starting with #
|
||||
if (url.substring(0, 1) == '#') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// basic normalizations for absolute urls
|
||||
var normalized = normalizeDomain(url);
|
||||
url = normalized[0];
|
||||
|
||||
var absolute = normalized[1];
|
||||
|
||||
if (!absolute) {
|
||||
/** relative url */
|
||||
if (url.substring(0, 1) == '/') {
|
||||
// relative to domain root
|
||||
url = currentDomain + url;
|
||||
} else if (baseHref) {
|
||||
// relative to base href
|
||||
url = baseHref + url;
|
||||
} else {
|
||||
// relative to current folder
|
||||
url = currentFolder + url;
|
||||
}
|
||||
}
|
||||
|
||||
// replace multiple / with a single /
|
||||
url = url.replace(/\/\/+/g, '/');
|
||||
|
||||
// handle ./ and ../
|
||||
var parts = url.split('/');
|
||||
var urlArr = [];
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
if (parts[i] == '.') {
|
||||
// ignore
|
||||
}
|
||||
else if (parts[i] == '..') {
|
||||
urlArr.pop();
|
||||
}
|
||||
else {
|
||||
urlArr.push(parts[i]);
|
||||
}
|
||||
}
|
||||
url = urlArr.join('/');
|
||||
|
||||
// remove ignored parameters
|
||||
url = url.replace(/\?/, '?&');
|
||||
for (i = 0; i < excludedParamsRegEx.length; i++) {
|
||||
var regEx = excludedParamsRegEx[i];
|
||||
url = url.replace(regEx, '');
|
||||
}
|
||||
url = url.replace(/\?&/, '?');
|
||||
url = url.replace(/\?#/, '#');
|
||||
url = url.replace(/\?$/, '');
|
||||
url = url.replace(/%5B/gi, '[');
|
||||
url = url.replace(/%5D/gi, ']');
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})();
|
Reference in New Issue
Block a user