PDF rausgenommen
This commit is contained in:
770
msd2/tracking/piwik/plugins/CoreHome/javascripts/broadcast.js
Normal file
770
msd2/tracking/piwik/plugins/CoreHome/javascripts/broadcast.js
Normal file
@ -0,0 +1,770 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* broadcast object is to help maintain a hash for link clicks and ajax calls
|
||||
* so we can have back button and refresh button working.
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var broadcast = {
|
||||
|
||||
/**
|
||||
* Initialisation state
|
||||
* @type {Boolean}
|
||||
*/
|
||||
_isInit: false,
|
||||
|
||||
/**
|
||||
* Last known hash url without popover parameter
|
||||
*/
|
||||
currentHashUrl: false,
|
||||
|
||||
/**
|
||||
* Last known popover parameter
|
||||
*/
|
||||
currentPopoverParameter: false,
|
||||
|
||||
/**
|
||||
* Callbacks for popover parameter change
|
||||
*/
|
||||
popoverHandlers: [],
|
||||
|
||||
/**
|
||||
* Holds the stack of popovers opened in sequence. When closing a popover, the last popover in the stack
|
||||
* is opened (if any).
|
||||
*/
|
||||
popoverParamStack: [],
|
||||
|
||||
/**
|
||||
* Force reload once
|
||||
*/
|
||||
forceReload: false,
|
||||
|
||||
/**
|
||||
* Suppress content update on hash changing
|
||||
*/
|
||||
updateHashOnly: false,
|
||||
|
||||
/**
|
||||
* Initializes broadcast object
|
||||
*
|
||||
* @deprecated in 3.2.2, will be removed in Piwik 4
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
init: function (noLoadingMessage) {
|
||||
if (broadcast._isInit) {
|
||||
return;
|
||||
}
|
||||
broadcast._isInit = true;
|
||||
|
||||
angular.element(document).injector().invoke(function (historyService) {
|
||||
historyService.init();
|
||||
});
|
||||
|
||||
if(noLoadingMessage != true) {
|
||||
piwikHelper.showAjaxLoading();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* ========== PageLoad function =================
|
||||
* This function is called when:
|
||||
* 1. after calling $.history.init();
|
||||
* 2. after calling $.history.load(); //look at broadcast.changeParameter();
|
||||
* 3. after pushing "Go Back" button of a browser
|
||||
*
|
||||
* * Note: the method is manipulated in Overlay/javascripts/Piwik_Overlay.js - keep this in mind when making changes.
|
||||
*
|
||||
* @deprecated since 3.2.2, will be removed in Piwik 4
|
||||
*
|
||||
* @param {string} hash to load page with
|
||||
* @return {void}
|
||||
*/
|
||||
pageload: function (hash) {
|
||||
broadcast.init();
|
||||
|
||||
// Unbind any previously attached resize handlers
|
||||
$(window).off('resize');
|
||||
|
||||
// do not update content if it should be suppressed
|
||||
if (broadcast.updateHashOnly) {
|
||||
broadcast.updateHashOnly = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// hash doesn't contain the first # character.
|
||||
if (hash && 0 === (''+hash).indexOf('/')) {
|
||||
hash = (''+hash).substr(1);
|
||||
}
|
||||
|
||||
|
||||
if (hash) {
|
||||
|
||||
if (/^popover=/.test(hash)) {
|
||||
var hashParts = [
|
||||
'',
|
||||
hash.replace(/^popover=/, '')
|
||||
];
|
||||
} else {
|
||||
var hashParts = hash.split('&popover=');
|
||||
}
|
||||
var hashUrl = hashParts[0];
|
||||
var popoverParam = '';
|
||||
if (hashParts.length > 1) {
|
||||
popoverParam = hashParts[1];
|
||||
// in case the $ was encoded (e.g. when using copy&paste on urls in some browsers)
|
||||
popoverParam = decodeURIComponent(popoverParam);
|
||||
// revert special encoding from broadcast.propagateNewPopoverParameter()
|
||||
popoverParam = popoverParam.replace(/\$/g, '%');
|
||||
popoverParam = decodeURIComponent(popoverParam);
|
||||
}
|
||||
|
||||
var pageUrlUpdated = (popoverParam == '' ||
|
||||
(broadcast.currentHashUrl !== false && broadcast.currentHashUrl != hashUrl));
|
||||
|
||||
var popoverParamUpdated = (popoverParam != '' && hashUrl == broadcast.currentHashUrl);
|
||||
|
||||
if (broadcast.currentHashUrl === false) {
|
||||
// new page load
|
||||
pageUrlUpdated = true;
|
||||
popoverParamUpdated = (popoverParam != '');
|
||||
}
|
||||
|
||||
if (!broadcast.isWidgetizedDashboard() && (pageUrlUpdated || broadcast.forceReload)) {
|
||||
Piwik_Popover.close();
|
||||
|
||||
if (hashUrl != broadcast.currentHashUrl || broadcast.forceReload) {
|
||||
// restore ajax loaded state
|
||||
broadcast.loadAjaxContent(hashUrl);
|
||||
|
||||
// make sure the "Widgets & Dashboard" is deleted on reload
|
||||
$('.top_controls .dashboard-manager').hide();
|
||||
$('#dashboardWidgetsArea').dashboard('destroy');
|
||||
|
||||
// remove unused controls
|
||||
require('piwik/UI').UIControl.cleanupUnusedControls();
|
||||
}
|
||||
}
|
||||
|
||||
broadcast.forceReload = false;
|
||||
broadcast.currentHashUrl = hashUrl;
|
||||
broadcast.currentPopoverParameter = popoverParam;
|
||||
|
||||
Piwik_Popover.close();
|
||||
|
||||
if (popoverParamUpdated) {
|
||||
var popoverParamParts = popoverParam.split(':');
|
||||
var handlerName = popoverParamParts[0];
|
||||
popoverParamParts.shift();
|
||||
var param = popoverParamParts.join(':');
|
||||
if (typeof broadcast.popoverHandlers[handlerName] != 'undefined' && !broadcast.isLoginPage()) {
|
||||
broadcast.popoverHandlers[handlerName](param);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// start page
|
||||
Piwik_Popover.close();
|
||||
if (!broadcast.isWidgetizedDashboard()) {
|
||||
$('.pageWrap #content:not(.admin)').empty();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isWidgetizedDashboard: function() {
|
||||
return broadcast.getValueFromUrl('module') == 'Widgetize' && broadcast.getValueFromUrl('moduleToWidgetize') == 'Dashboard';
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns if the current page is the login page
|
||||
* @return {boolean}
|
||||
*/
|
||||
isLoginPage: function() {
|
||||
return !!$('body#loginPage').length;
|
||||
},
|
||||
|
||||
/**
|
||||
* propagateAjax -- update hash values then make ajax calls.
|
||||
* example :
|
||||
* 1) <a href="javascript:broadcast.propagateAjax('module=Referrers&action=getKeywords')">View keywords report</a>
|
||||
* 2) Main menu li also goes through this function.
|
||||
*
|
||||
* Will propagate your new value into the current hash string and make ajax calls.
|
||||
*
|
||||
* NOTE: this method will only make ajax call and replacing main content.
|
||||
*
|
||||
* @deprecated in 3.2.2, will be removed in Piwik 4.
|
||||
*
|
||||
* @param {string} ajaxUrl querystring with parameters to be updated
|
||||
* @param {boolean} [disableHistory] the hash change won't be available in the browser history
|
||||
* @return {void}
|
||||
*/
|
||||
propagateAjax: function (ajaxUrl, disableHistory) {
|
||||
broadcast.init();
|
||||
|
||||
// abort all existing ajax requests
|
||||
globalAjaxQueue.abort();
|
||||
|
||||
// available in global scope
|
||||
var currentHashStr = broadcast.getHash();
|
||||
|
||||
ajaxUrl = ajaxUrl.replace(/^\?|&#/, '');
|
||||
|
||||
var params_vals = ajaxUrl.split("&");
|
||||
for (var i = 0; i < params_vals.length; i++) {
|
||||
currentHashStr = broadcast.updateParamValue(params_vals[i], currentHashStr);
|
||||
}
|
||||
|
||||
// if the module is not 'Goals', we specifically unset the 'idGoal' parameter
|
||||
// this is to ensure that the URLs are clean (and that clicks on graphs work as expected - they are broken with the extra parameter)
|
||||
var action = broadcast.getParamValue('action', currentHashStr);
|
||||
if (action != 'goalReport'
|
||||
&& action != 'ecommerceReport'
|
||||
&& action != 'products'
|
||||
&& action != 'sales'
|
||||
&& (''+ ajaxUrl).indexOf('&idGoal=') === -1) {
|
||||
currentHashStr = broadcast.updateParamValue('idGoal=', currentHashStr);
|
||||
}
|
||||
// unset idDashboard if use doesn't display a dashboard
|
||||
var module = broadcast.getParamValue('module', currentHashStr);
|
||||
if (module != 'Dashboard') {
|
||||
currentHashStr = broadcast.updateParamValue('idDashboard=', currentHashStr);
|
||||
}
|
||||
|
||||
if (module != 'CustomDimensions') {
|
||||
currentHashStr = broadcast.updateParamValue('idDimension=', currentHashStr);
|
||||
}
|
||||
|
||||
if (disableHistory) {
|
||||
var newLocation = window.location.href.split('#')[0] + '#?' + currentHashStr;
|
||||
// window.location.replace changes the current url without pushing it on the browser's history stack
|
||||
window.location.replace(newLocation);
|
||||
}
|
||||
else {
|
||||
// Let history know about this new Hash and load it.
|
||||
broadcast.forceReload = true;
|
||||
angular.element(document).injector().invoke(function (historyService) {
|
||||
historyService.load(currentHashStr);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the current hash with updated parameters that were provided in ajaxUrl
|
||||
*
|
||||
* Parameters like idGoal and idDashboard will be automatically reset if the won't be relevant anymore
|
||||
*
|
||||
* NOTE: this method does not issue any ajax call, but returns the hash instead
|
||||
*
|
||||
* @param {string} ajaxUrl querystring with parameters to be updated
|
||||
* @return {string} current hash with updated parameters
|
||||
*/
|
||||
buildReportingUrl: function (ajaxUrl) {
|
||||
|
||||
// available in global scope
|
||||
var currentHashStr = broadcast.getHash();
|
||||
|
||||
ajaxUrl = ajaxUrl.replace(/^\?|&#/, '');
|
||||
|
||||
var params_vals = ajaxUrl.split("&");
|
||||
for (var i = 0; i < params_vals.length; i++) {
|
||||
currentHashStr = broadcast.updateParamValue(params_vals[i], currentHashStr);
|
||||
}
|
||||
|
||||
// if the module is not 'Goals', we specifically unset the 'idGoal' parameter
|
||||
// this is to ensure that the URLs are clean (and that clicks on graphs work as expected - they are broken with the extra parameter)
|
||||
var action = broadcast.getParamValue('action', currentHashStr);
|
||||
if (action != 'goalReport' && action != 'ecommerceReport' && action != 'products' && action != 'sales') {
|
||||
currentHashStr = broadcast.updateParamValue('idGoal=', currentHashStr);
|
||||
}
|
||||
// unset idDashboard if use doesn't display a dashboard
|
||||
var module = broadcast.getParamValue('module', currentHashStr);
|
||||
if (module != 'Dashboard') {
|
||||
currentHashStr = broadcast.updateParamValue('idDashboard=', currentHashStr);
|
||||
}
|
||||
|
||||
return '#' + currentHashStr;
|
||||
},
|
||||
|
||||
/**
|
||||
* propagateNewPage() -- update url value and load new page,
|
||||
* Example:
|
||||
* 1) We want to update idSite to both search query and hash then reload the page,
|
||||
* 2) update period to both search query and hash then reload page.
|
||||
*
|
||||
* Expecting:
|
||||
* str = "param1=newVal1¶m2=newVal2";
|
||||
*
|
||||
* NOTE: This method will refresh the page with new values.
|
||||
*
|
||||
* @param {string} str url with parameters to be updated
|
||||
* @param {boolean} [showAjaxLoading] whether to show the ajax loading gif or not.
|
||||
* @param {string} strHash additional parameters that should be updated on the hash
|
||||
* @return {void}
|
||||
*/
|
||||
propagateNewPage: function (str, showAjaxLoading, strHash) {
|
||||
// abort all existing ajax requests
|
||||
globalAjaxQueue.abort();
|
||||
|
||||
if (typeof showAjaxLoading === 'undefined' || showAjaxLoading) {
|
||||
piwikHelper.showAjaxLoading();
|
||||
}
|
||||
|
||||
var params_vals = str.split("&");
|
||||
|
||||
// available in global scope
|
||||
var currentSearchStr = window.location.search;
|
||||
var currentHashStr = broadcast.getHashFromUrl();
|
||||
|
||||
if (!currentSearchStr) {
|
||||
currentSearchStr = '?';
|
||||
}
|
||||
|
||||
var oldUrl = currentSearchStr + currentHashStr;
|
||||
|
||||
for (var i = 0; i < params_vals.length; i++) {
|
||||
|
||||
if(params_vals[i].length == 0) {
|
||||
continue; // updating with empty string would destroy some values
|
||||
}
|
||||
|
||||
// update both the current search query and hash string
|
||||
currentSearchStr = broadcast.updateParamValue(params_vals[i], currentSearchStr);
|
||||
|
||||
if (currentHashStr.length != 0) {
|
||||
currentHashStr = broadcast.updateParamValue(params_vals[i], currentHashStr);
|
||||
}
|
||||
}
|
||||
|
||||
var updatedUrl = new RegExp('&updated=([0-9]+)');
|
||||
var updatedCounter = updatedUrl.exec(currentSearchStr);
|
||||
if (!updatedCounter) {
|
||||
currentSearchStr += '&updated=1';
|
||||
} else {
|
||||
updatedCounter = 1 + parseInt(updatedCounter[1]);
|
||||
currentSearchStr = currentSearchStr.replace(new RegExp('(&updated=[0-9]+)'), '&updated=' + updatedCounter);
|
||||
}
|
||||
|
||||
if (strHash && currentHashStr.length != 0) {
|
||||
var params_hash_vals = strHash.split("&");
|
||||
for (var i = 0; i < params_hash_vals.length; i++) {
|
||||
currentHashStr = broadcast.updateParamValue(params_hash_vals[i], currentHashStr);
|
||||
}
|
||||
}
|
||||
|
||||
// Now load the new page.
|
||||
var newUrl = currentSearchStr + currentHashStr;
|
||||
|
||||
var $rootScope = piwikHelper.getAngularDependency('$rootScope');
|
||||
if ($rootScope) {
|
||||
$rootScope.$on('$locationChangeStart', function (event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (oldUrl == newUrl) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
this.forceReload = true;
|
||||
window.location.href = newUrl;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/*************************************************
|
||||
*
|
||||
* Broadcast Supporter Methods:
|
||||
*
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* updateParamValue(newParamValue,urlStr) -- Helping propagate functions to update value to url string.
|
||||
* eg. I want to update date value to search query or hash query
|
||||
*
|
||||
* Expecting:
|
||||
* urlStr : A Hash or search query string. e.g: module=whatever&action=index=date=yesterday
|
||||
* newParamValue : A param value pair: e.g: date=2009-05-02
|
||||
*
|
||||
* Return module=whatever&action=index&date=2009-05-02
|
||||
*
|
||||
* @param {string} newParamValue param to be updated
|
||||
* @param {string} urlStr url to be updated
|
||||
* @return {string} urlStr with updated param
|
||||
*/
|
||||
updateParamValue: function (newParamValue, urlStr) {
|
||||
var p_v = newParamValue.split("=");
|
||||
|
||||
var paramName = p_v[0];
|
||||
var valFromUrl = broadcast.getParamValue(paramName, urlStr);
|
||||
// if set 'idGoal=' then we remove the parameter from the URL automatically (rather than passing an empty value)
|
||||
var paramValue = p_v[1];
|
||||
if (paramValue == '') {
|
||||
newParamValue = '';
|
||||
}
|
||||
var getQuotedRegex = function(str) {
|
||||
return (str+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
|
||||
};
|
||||
|
||||
if (valFromUrl != '') {
|
||||
// replacing current param=value to newParamValue;
|
||||
valFromUrl = getQuotedRegex(valFromUrl);
|
||||
var regToBeReplace = new RegExp(paramName + '=' + valFromUrl, 'ig');
|
||||
if (newParamValue == '') {
|
||||
// if new value is empty remove leading &, as well
|
||||
regToBeReplace = new RegExp('[\&]?' + paramName + '=' + valFromUrl, 'ig');
|
||||
}
|
||||
urlStr = urlStr.replace(regToBeReplace, newParamValue);
|
||||
} else if (newParamValue != '') {
|
||||
urlStr += (urlStr == '') ? newParamValue : '&' + newParamValue;
|
||||
}
|
||||
|
||||
return urlStr;
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads a popover by adding a 'popover' query parameter to the current URL and
|
||||
* indirectly executing the popover handler.
|
||||
*
|
||||
* This function should be called to open popovers that can be opened by URL alone.
|
||||
* That is, if you want users to be able to copy-paste the URL displayed when a popover
|
||||
* is open into a new browser window/tab and have the same popover open, you should
|
||||
* call this function.
|
||||
*
|
||||
* In order for this function to open a popover, there must be a popover handler
|
||||
* associated with handlerName. To associate one, call broadcast.addPopoverHandler.
|
||||
*
|
||||
* @param {String} handlerName The name of the popover handler.
|
||||
* @param {String} value The String value that should be passed to the popover
|
||||
* handler.
|
||||
*/
|
||||
propagateNewPopoverParameter: function (handlerName, value) {
|
||||
|
||||
var $location = angular.element(document).injector().get('$location');
|
||||
|
||||
var popover = '';
|
||||
if (handlerName && '' != value && 'undefined' != typeof value) {
|
||||
popover = handlerName + ':' + value;
|
||||
|
||||
// between jquery.history and different browser bugs, it's impossible to ensure
|
||||
// that the parameter is en- and decoded the same number of times. in order to
|
||||
// make sure it doesn't change, we have to manipulate the url encoding a bit.
|
||||
popover = encodeURIComponent(popover);
|
||||
popover = popover.replace(/%/g, '\$');
|
||||
|
||||
broadcast.popoverParamStack.push(popover);
|
||||
} else {
|
||||
broadcast.popoverParamStack.pop();
|
||||
if (broadcast.popoverParamStack.length) {
|
||||
popover = broadcast.popoverParamStack[broadcast.popoverParamStack.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
$location.search('popover', popover);
|
||||
|
||||
setTimeout(function () {
|
||||
angular.element(document).injector().get('$rootScope').$apply();
|
||||
}, 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets the popover param stack ensuring when a popover is closed, no new popover will
|
||||
* be loaded.
|
||||
*/
|
||||
resetPopoverStack: function () {
|
||||
broadcast.popoverParamStack = [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a handler for the 'popover' query parameter.
|
||||
*
|
||||
* @see broadcast#propagateNewPopoverParameter
|
||||
*
|
||||
* @param {String} handlerName The handler name, eg, 'visitorProfile'. Should identify
|
||||
* the popover that the callback will open up.
|
||||
* @param {Function} callback This function should open the popover. It should take
|
||||
* one string parameter.
|
||||
*/
|
||||
addPopoverHandler: function (handlerName, callback) {
|
||||
broadcast.popoverHandlers[handlerName] = callback;
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads the given url with ajax and replaces the content
|
||||
*
|
||||
* Note: the method is replaced in Overlay/javascripts/Piwik_Overlay.js - keep this in mind when making changes.
|
||||
*
|
||||
* @param {string} urlAjax url to load
|
||||
* @return {Boolean}
|
||||
*/
|
||||
loadAjaxContent: function (urlAjax) {
|
||||
if(broadcast.getParamValue('module', urlAjax) == 'API') {
|
||||
broadcast.lastUrlRequested = null;
|
||||
$('#content').html("Loading content from the API and displaying it within Piwik is not allowed.");
|
||||
piwikHelper.hideAjaxLoading();
|
||||
return false;
|
||||
}
|
||||
|
||||
piwikHelper.hideAjaxError('loadingError');
|
||||
piwikHelper.showAjaxLoading();
|
||||
$('#content').empty();
|
||||
$("object").remove();
|
||||
|
||||
urlAjax = urlAjax.match(/^\?/) ? urlAjax : "?" + urlAjax;
|
||||
broadcast.lastUrlRequested = urlAjax;
|
||||
|
||||
function sectionLoaded(content, status, request) {
|
||||
if (request) {
|
||||
var responseHeader = request.getResponseHeader('Content-Type');
|
||||
if (responseHeader && 0 <= responseHeader.toLowerCase().indexOf('json')) {
|
||||
var message = 'JSON cannot be displayed for';
|
||||
if (this.getParams && this.getParams['module']) {
|
||||
message += ' module=' + this.getParams['module'];
|
||||
}
|
||||
if (this.getParams && this.getParams['action']) {
|
||||
message += ' action=' + this.getParams['action'];
|
||||
}
|
||||
$('#content').text(message);
|
||||
piwikHelper.hideAjaxLoading();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if content is whole HTML document, do not show it, otherwise recursive page load could occur
|
||||
var htmlDocType = '<!DOCTYPE';
|
||||
if (content.substring(0, htmlDocType.length) == htmlDocType) {
|
||||
// if the content has an error message, display it
|
||||
if ($(content).filter('title').text() == 'Piwik › Error') {
|
||||
content = $(content).filter('#contentsimple');
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (urlAjax == broadcast.lastUrlRequested) {
|
||||
$('#content').html(content).show();
|
||||
$(broadcast).trigger('locationChangeSuccess', {element: $('#content'), content: content});
|
||||
piwikHelper.hideAjaxLoading();
|
||||
broadcast.lastUrlRequested = null;
|
||||
|
||||
piwikHelper.compileAngularComponents('#content');
|
||||
}
|
||||
|
||||
initTopControls();
|
||||
}
|
||||
|
||||
var ajax = new ajaxHelper();
|
||||
ajax.setUrl(urlAjax);
|
||||
ajax._getDefaultPostParams = function () {
|
||||
return {};
|
||||
};
|
||||
ajax.setErrorCallback(broadcast.customAjaxHandleError);
|
||||
ajax.setCallback(sectionLoaded);
|
||||
ajax.setFormat('html');
|
||||
ajax.send();
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to handle ajax errors
|
||||
* @param {XMLHttpRequest} deferred
|
||||
* @param {string} status
|
||||
* @return {void}
|
||||
*/
|
||||
customAjaxHandleError: function (deferred, status) {
|
||||
broadcast.lastUrlRequested = null;
|
||||
|
||||
piwikHelper.hideAjaxLoading();
|
||||
|
||||
// do not display error message if request was aborted
|
||||
if(status == 'abort') {
|
||||
return;
|
||||
}
|
||||
|
||||
$('#loadingError').show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Return hash string if hash exists on address bar.
|
||||
* else return false;
|
||||
*
|
||||
* @return {string|boolean} current hash or false if it is empty
|
||||
*/
|
||||
isHashExists: function () {
|
||||
var hashStr = broadcast.getHashFromUrl();
|
||||
|
||||
if (hashStr != "") {
|
||||
return hashStr;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get Hash from given url or from current location.
|
||||
* return empty string if no hash present.
|
||||
*
|
||||
* @param {string} [url] url to get hash from (defaults to current location)
|
||||
* @return {string} the hash part of the given url
|
||||
*/
|
||||
getHashFromUrl: function (url) {
|
||||
var hashStr = "";
|
||||
// If url provided, give back the hash from url, else get hash from current address.
|
||||
if (url && url.match('#')) {
|
||||
hashStr = url.substring(url.indexOf("#"), url.length);
|
||||
}
|
||||
else {
|
||||
locationSplit = location.href.split('#');
|
||||
if(typeof locationSplit[1] != 'undefined') {
|
||||
hashStr = '#' + locationSplit[1];
|
||||
}
|
||||
}
|
||||
|
||||
return hashStr;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get search query from given url or from current location.
|
||||
* return empty string if no search query present.
|
||||
*
|
||||
* @param {string} url
|
||||
* @return {string} the query part of the given url
|
||||
*/
|
||||
getSearchFromUrl: function (url) {
|
||||
var searchStr = "";
|
||||
// If url provided, give back the query string from url, else get query string from current address.
|
||||
if (url && url.match(/\?/)) {
|
||||
searchStr = url.substring(url.indexOf("?"), url.length);
|
||||
} else {
|
||||
searchStr = location.search;
|
||||
}
|
||||
|
||||
return searchStr;
|
||||
},
|
||||
|
||||
/**
|
||||
* Extracts from a query strings, the request array
|
||||
* @param queryString
|
||||
* @returns {object}
|
||||
*/
|
||||
extractKeyValuePairsFromQueryString: function (queryString) {
|
||||
var pairs = queryString.split('&');
|
||||
var result = {};
|
||||
for (var i = 0; i != pairs.length; ++i) {
|
||||
// attn: split with regex has bugs in several browsers such as IE 8
|
||||
// so we need to split, use the first part as key and rejoin the rest
|
||||
var pair = pairs[i].split('=');
|
||||
var key = pair.shift();
|
||||
result[key] = pair.join('=');
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns all key-value pairs in query string of url.
|
||||
*
|
||||
* @param {string} url url to check. if undefined, null or empty, current url is used.
|
||||
* @return {object} key value pair describing query string parameters
|
||||
*/
|
||||
getValuesFromUrl: function (url) {
|
||||
var searchString = this._removeHashFromUrl(url).split('?')[1] || '';
|
||||
return this.extractKeyValuePairsFromQueryString(searchString);
|
||||
},
|
||||
|
||||
/**
|
||||
* help to get param value for any given url string with provided param name
|
||||
* if no url is provided, it will get param from current address.
|
||||
* return:
|
||||
* Empty String if param is not found.
|
||||
*
|
||||
* @param {string} param parameter to search for
|
||||
* @param {string} [url] url to check, defaults to current location
|
||||
* @return {string} value of the given param within the given url
|
||||
*/
|
||||
getValueFromUrl: function (param, url) {
|
||||
var searchString = this._removeHashFromUrl(url);
|
||||
return broadcast.getParamValue(param, searchString);
|
||||
},
|
||||
|
||||
/**
|
||||
* NOTE: you should probably be using broadcast.getValueFromUrl instead!
|
||||
*
|
||||
* @param {string} param parameter to search for
|
||||
* @param {string} [url] url to check
|
||||
* @return {string} value of the given param within the hash part of the given url
|
||||
*/
|
||||
getValueFromHash: function (param, url) {
|
||||
var hashStr = broadcast.getHashFromUrl(url);
|
||||
if (hashStr.substr(0, 1) == '#') {
|
||||
hashStr = hashStr.substr(1);
|
||||
}
|
||||
hashStr = hashStr.split('#')[0];
|
||||
|
||||
return broadcast.getParamValue(param, hashStr);
|
||||
},
|
||||
|
||||
/**
|
||||
* return value for the requested param, will return the first match.
|
||||
* out side of this class should use getValueFromHash() or getValueFromUrl() instead.
|
||||
* return:
|
||||
* Empty String if param is not found.
|
||||
*
|
||||
* @param {string} param parameter to search for
|
||||
* @param {string} url url to check
|
||||
* @return {string} value of the given param within the given url
|
||||
*/
|
||||
getParamValue: function (param, url) {
|
||||
var lookFor = param + '=';
|
||||
var startStr = url.indexOf(lookFor);
|
||||
|
||||
if (startStr >= 0) {
|
||||
var endStr = url.indexOf("&", startStr);
|
||||
if (endStr == -1) {
|
||||
endStr = url.length;
|
||||
}
|
||||
var value = url.substring(startStr + param.length + 1, endStr);
|
||||
|
||||
// we sanitize values to add a protection layer against XSS
|
||||
// &segment= value is not sanitized, since segments are designed to accept any user input
|
||||
if(param != 'segment') {
|
||||
value = value.replace(/[^_%~\*\+\-\<\>!@\$\.()=,;0-9a-zA-Z]/gi, '');
|
||||
}
|
||||
return value;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the hash without the starting #
|
||||
* @return {string} hash part of the current url
|
||||
*/
|
||||
getHash: function () {
|
||||
return broadcast.getHashFromUrl().replace(/^#/, '').split('#')[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the hash portion of a URL and returns the rest.
|
||||
*
|
||||
* @param {string} url
|
||||
* @return {string} url w/o hash
|
||||
*/
|
||||
_removeHashFromUrl: function (url) {
|
||||
var searchString = '';
|
||||
if (url) {
|
||||
var urlParts = url.split('#');
|
||||
searchString = urlParts[0];
|
||||
} else {
|
||||
searchString = location.search;
|
||||
}
|
||||
return searchString;
|
||||
}
|
||||
};
|
92
msd2/tracking/piwik/plugins/CoreHome/javascripts/calendar.js
Normal file
92
msd2/tracking/piwik/plugins/CoreHome/javascripts/calendar.js
Normal file
@ -0,0 +1,92 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
(function ($) {
|
||||
// min/max date for picker
|
||||
var piwikMinDate = new Date(piwik.minDateYear, piwik.minDateMonth - 1, piwik.minDateDay),
|
||||
piwikMaxDate = new Date(piwik.maxDateYear, piwik.maxDateMonth - 1, piwik.maxDateDay);
|
||||
|
||||
piwik.getBaseDatePickerOptions = function (defaultDate) {
|
||||
return {
|
||||
showOtherMonths: false,
|
||||
dateFormat: 'yy-mm-dd',
|
||||
firstDay: 1,
|
||||
minDate: piwikMinDate,
|
||||
maxDate: piwikMaxDate,
|
||||
prevText: "",
|
||||
nextText: "",
|
||||
currentText: "",
|
||||
defaultDate: defaultDate,
|
||||
changeMonth: true,
|
||||
changeYear: true,
|
||||
stepMonths: 1,
|
||||
// jquery-ui-i18n 1.7.2 lacks some translations, so we use our own
|
||||
dayNamesMin: [
|
||||
_pk_translate('Intl_Day_Min_StandAlone_7'),
|
||||
_pk_translate('Intl_Day_Min_StandAlone_1'),
|
||||
_pk_translate('Intl_Day_Min_StandAlone_2'),
|
||||
_pk_translate('Intl_Day_Min_StandAlone_3'),
|
||||
_pk_translate('Intl_Day_Min_StandAlone_4'),
|
||||
_pk_translate('Intl_Day_Min_StandAlone_5'),
|
||||
_pk_translate('Intl_Day_Min_StandAlone_6')],
|
||||
dayNamesShort: [
|
||||
_pk_translate('Intl_Day_Short_StandAlone_7'), // start with sunday
|
||||
_pk_translate('Intl_Day_Short_StandAlone_1'),
|
||||
_pk_translate('Intl_Day_Short_StandAlone_2'),
|
||||
_pk_translate('Intl_Day_Short_StandAlone_3'),
|
||||
_pk_translate('Intl_Day_Short_StandAlone_4'),
|
||||
_pk_translate('Intl_Day_Short_StandAlone_5'),
|
||||
_pk_translate('Intl_Day_Short_StandAlone_6')],
|
||||
dayNames: [
|
||||
_pk_translate('Intl_Day_Long_StandAlone_7'), // start with sunday
|
||||
_pk_translate('Intl_Day_Long_StandAlone_1'),
|
||||
_pk_translate('Intl_Day_Long_StandAlone_2'),
|
||||
_pk_translate('Intl_Day_Long_StandAlone_3'),
|
||||
_pk_translate('Intl_Day_Long_StandAlone_4'),
|
||||
_pk_translate('Intl_Day_Long_StandAlone_5'),
|
||||
_pk_translate('Intl_Day_Long_StandAlone_6')],
|
||||
monthNamesShort: [
|
||||
_pk_translate('Intl_Month_Short_StandAlone_1'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_2'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_3'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_4'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_5'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_6'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_7'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_8'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_9'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_10'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_11'),
|
||||
_pk_translate('Intl_Month_Short_StandAlone_12')],
|
||||
monthNames: [
|
||||
_pk_translate('Intl_Month_Long_StandAlone_1'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_2'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_3'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_4'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_5'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_6'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_7'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_8'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_9'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_10'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_11'),
|
||||
_pk_translate('Intl_Month_Long_StandAlone_12')]
|
||||
};
|
||||
};
|
||||
|
||||
piwikHelper.registerShortcut('d', _pk_translate('CoreHome_ShortcutCalendar'), function(event) {
|
||||
if (event.altKey) {
|
||||
return;
|
||||
}
|
||||
if (event.preventDefault) {
|
||||
event.preventDefault();
|
||||
} else {
|
||||
event.returnValue = false; // IE
|
||||
}
|
||||
$('#periodString .title').trigger('click').focus();
|
||||
});
|
||||
|
||||
}(jQuery));
|
@ -0,0 +1,225 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
var colorNames = {"aliceblue":"#f0f8ff","antiquewhite":"#faebd7","aqua":"#00ffff","aquamarine":"#7fffd4","azure":"#f0ffff",
|
||||
"beige":"#f5f5dc","bisque":"#ffe4c4","black":"#000000","blanchedalmond":"#ffebcd","blue":"#0000ff","blueviolet":"#8a2be2","brown":"#a52a2a","burlywood":"#deb887",
|
||||
"cadetblue":"#5f9ea0","chartreuse":"#7fff00","chocolate":"#d2691e","coral":"#ff7f50","cornflowerblue":"#6495ed","cornsilk":"#fff8dc","crimson":"#dc143c","cyan":"#00ffff",
|
||||
"darkblue":"#00008b","darkcyan":"#008b8b","darkgoldenrod":"#b8860b","darkgray":"#a9a9a9","darkgreen":"#006400","darkkhaki":"#bdb76b","darkmagenta":"#8b008b","darkolivegreen":"#556b2f",
|
||||
"darkorange":"#ff8c00","darkorchid":"#9932cc","darkred":"#8b0000","darksalmon":"#e9967a","darkseagreen":"#8fbc8f","darkslateblue":"#483d8b","darkslategray":"#2f4f4f","darkturquoise":"#00ced1",
|
||||
"darkviolet":"#9400d3","deeppink":"#ff1493","deepskyblue":"#00bfff","dimgray":"#696969","dodgerblue":"#1e90ff",
|
||||
"firebrick":"#b22222","floralwhite":"#fffaf0","forestgreen":"#228b22","fuchsia":"#ff00ff","gainsboro":"#dcdcdc","ghostwhite":"#f8f8ff","gold":"#ffd700","goldenrod":"#daa520","gray":"#808080","green":"#43a047","greenyellow":"#adff2f",
|
||||
"honeydew":"#f0fff0","hotpink":"#ff69b4","indianred ":"#cd5c5c","indigo ":"#4b0082","ivory":"#fffff0","khaki":"#f0e68c",
|
||||
"lavender":"#e6e6fa","lavenderblush":"#fff0f5","lawngreen":"#7cfc00","lemonchiffon":"#fffacd","lightblue":"#add8e6","lightcoral":"#f08080","lightcyan":"#e0ffff","lightgoldenrodyellow":"#fafad2",
|
||||
"lightgrey":"#d3d3d3","lightgreen":"#90ee90","lightpink":"#ffb6c1","lightsalmon":"#ffa07a","lightseagreen":"#20b2aa","lightskyblue":"#87cefa","lightslategray":"#778899","lightsteelblue":"#b0c4de",
|
||||
"lightyellow":"#ffffe0","lime":"#00ff00","limegreen":"#32cd32","linen":"#faf0e6","magenta":"#ff00ff","maroon":"#800000","mediumaquamarine":"#66cdaa","mediumblue":"#0000cd","mediumorchid":"#ba55d3","mediumpurple":"#9370d8","mediumseagreen":"#3cb371","mediumslateblue":"#7b68ee",
|
||||
"mediumspringgreen":"#00fa9a","mediumturquoise":"#48d1cc","mediumvioletred":"#c71585","midnightblue":"#191970","mintcream":"#f5fffa","mistyrose":"#ffe4e1","moccasin":"#ffe4b5",
|
||||
"navajowhite":"#ffdead","navy":"#000080","oldlace":"#fdf5e6","olive":"#808000","olivedrab":"#6b8e23","orange":"#ffa500","orangered":"#ff4500","orchid":"#da70d6",
|
||||
"palegoldenrod":"#eee8aa","palegreen":"#98fb98","paleturquoise":"#afeeee","palevioletred":"#d87093","papayawhip":"#ffefd5","peachpuff":"#ffdab9","peru":"#cd853f","pink":"#ffc0cb","plum":"#dda0dd","powderblue":"#b0e0e6","purple":"#800080",
|
||||
"red":"#ff0000","rosybrown":"#bc8f8f","royalblue":"#4169e1","saddlebrown":"#8b4513","salmon":"#fa8072","sandybrown":"#f4a460","seagreen":"#2e8b57","seashell":"#fff5ee","sienna":"#a0522d","silver":"#c0c0c0","skyblue":"#87ceeb","slateblue":"#6a5acd","slategray":"#708090","snow":"#fffafa","springgreen":"#00ff7f","steelblue":"#4682b4",
|
||||
"tan":"#d2b48c","teal":"#008080","thistle":"#d8bfd8","tomato":"#ff6347","turquoise":"#40e0d0","violet":"#ee82ee","wheat":"#f5deb3","white":"#ffffff","whitesmoke":"#f5f5f5","yellow":"#ffff00","yellowgreen":"#9acd32"};
|
||||
|
||||
/**
|
||||
* The ColorManager class allows JS code to grab colors defined in CSS for
|
||||
* components that don't manage HTML (like jqPlot or sparklines). Such components
|
||||
* can't use CSS colors directly since the colors are used to generate images
|
||||
* or by <canvas> elements.
|
||||
*
|
||||
* Colors obtained via ColorManager are defined in CSS like this:
|
||||
*
|
||||
* .my-color-namespace[data-name=color-name] {
|
||||
* color: #fff
|
||||
* }
|
||||
*
|
||||
* and can be accessed in JavaScript like this:
|
||||
*
|
||||
* piwik.ColorManager.getColor("my-color-namespace", "color-name");
|
||||
*
|
||||
* The singleton instance of this class can be accessed via piwik.ColorManager.
|
||||
*/
|
||||
var ColorManager = function () {
|
||||
// empty
|
||||
};
|
||||
|
||||
ColorManager.prototype = {
|
||||
|
||||
/**
|
||||
* Returns the color for a namespace and name.
|
||||
*
|
||||
* @param {String} namespace The string identifier that groups related colors
|
||||
* together. For example, 'sparkline-colors'.
|
||||
* @param {String} name The name of the color to retrieve. For example, 'lineColor'.
|
||||
* @return {String} A hex color, eg, '#fff'.
|
||||
*/
|
||||
getColor: function (namespace, name) {
|
||||
var element = this._getElement();
|
||||
|
||||
element.attr('class', 'color-manager ' + namespace).attr('data-name', name);
|
||||
|
||||
return this._normalizeColor(element.css('color'));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the colors for a namespace and a list of names.
|
||||
*
|
||||
* @param {String} namespace The string identifier that groups related colors
|
||||
* together. For example, 'sparkline-colors'.
|
||||
* @param {Array} names An array of color names to retrieve.
|
||||
* @param {Boolean} asArray Whether the result should be an array or an object.
|
||||
* @return {Object|Array} An object mapping color names with color values or an
|
||||
* array of colors.
|
||||
*/
|
||||
getColors: function (namespace, names, asArray) {
|
||||
var colors = asArray ? [] : {};
|
||||
for (var i = 0; i != names.length; ++i) {
|
||||
var name = names[i],
|
||||
color = this.getColor(namespace, name);
|
||||
if (color) {
|
||||
if (asArray) {
|
||||
colors.push(color);
|
||||
} else {
|
||||
colors[name] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
return colors;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a color that is N % between two other colors.
|
||||
*
|
||||
* @param {String|Array} spectrumStart The start color. If percentFromStart is 0, this color will
|
||||
* be returned. Can be either a hex color or RGB array.
|
||||
* It will be converted to an RGB array if a hex color is supplied.
|
||||
* @param {String|Array} spectrumEnd The end color. If percentFromStart is 1, this color will be
|
||||
* returned. Can be either a hex color or RGB array. It will be
|
||||
* converted to an RGB array if a hex color is supplied.
|
||||
* @param {Number} percentFromStart The percent from spectrumStart and twoard spectrumEnd that the
|
||||
* result color should be. Must be a value between 0.0 & 1.0.
|
||||
* @return {String} A hex color.
|
||||
*/
|
||||
getSingleColorFromGradient: function (spectrumStart, spectrumEnd, percentFromStart) {
|
||||
if (!(spectrumStart instanceof Array)) {
|
||||
spectrumStart = this.getRgb(spectrumStart);
|
||||
}
|
||||
|
||||
if (!(spectrumEnd instanceof Array)) {
|
||||
spectrumEnd = this.getRgb(spectrumEnd);
|
||||
}
|
||||
|
||||
var result = [];
|
||||
for (var channel = 0; channel != spectrumStart.length; ++channel) {
|
||||
var delta = (spectrumEnd[channel] - spectrumStart[channel]) * percentFromStart;
|
||||
|
||||
result[channel] = Math.floor(spectrumStart[channel] + delta);
|
||||
}
|
||||
|
||||
return this.getHexColor(result);
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility function that converts a hex color (ie, #fff or #1a1a1a) to an array of
|
||||
* RGB values.
|
||||
*
|
||||
* @param {String} hexColor The color to convert.
|
||||
* @return {Array} An array with three integers between 0 and 255.
|
||||
*/
|
||||
getRgb: function (hexColor) {
|
||||
if (hexColor[0] == '#') {
|
||||
hexColor = hexColor.substring(1);
|
||||
}
|
||||
|
||||
if (hexColor.length == 3) {
|
||||
return [
|
||||
parseInt(hexColor[0], 16),
|
||||
parseInt(hexColor[1], 16),
|
||||
parseInt(hexColor[2], 16)
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
parseInt(hexColor.substring(0,2), 16),
|
||||
parseInt(hexColor.substring(2,4), 16),
|
||||
parseInt(hexColor.substring(4,6), 16)
|
||||
];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility function that converts an RGB array to a hex color.
|
||||
*
|
||||
* @param {Array} rgbColor An array with three integers between 0 and 255.
|
||||
* @return {String} The hex color, eg, #1a1a1a.
|
||||
*/
|
||||
getHexColor: function (rgbColor) {
|
||||
// convert channels to hex with one leading 0
|
||||
for (var i = 0; i != rgbColor.length; ++i) {
|
||||
rgbColor[i] = ("00" + rgbColor[i].toString(16)).slice(-2);
|
||||
}
|
||||
|
||||
// create hex string
|
||||
return '#' + rgbColor.join('');
|
||||
},
|
||||
|
||||
/**
|
||||
* Turns a color string that might be an rgb value rgb(12, 34, 56) into
|
||||
* a hex color string.
|
||||
*/
|
||||
_normalizeColor: function (color) {
|
||||
if (color == this._getTransparentColor()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (color && colorNames[color]) {
|
||||
return colorNames[color];
|
||||
}
|
||||
|
||||
if (color
|
||||
&& color[0] != '#'
|
||||
) {
|
||||
// parse rgb(#, #, #) and get rgb numbers
|
||||
var parts = color.split(/[()rgb,\s]+/);
|
||||
parts = [+parts[1], +parts[2], +parts[3]];
|
||||
|
||||
// convert to hex
|
||||
color = this.getHexColor(parts);
|
||||
}
|
||||
return color;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the manufactured <div> element used to obtain color data. When
|
||||
* getting color data the class and data-name attribute of this element are
|
||||
* changed.
|
||||
*/
|
||||
_getElement: function () {
|
||||
if (!this.$element) {
|
||||
$('body').append('<div id="color-manager"></div>');
|
||||
this.$element = $('#color-manager');
|
||||
}
|
||||
|
||||
return this.$element;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns this browser's representation of the 'transparent' color. Used to
|
||||
* compare against colors obtained in getColor. If a color is 'transparent'
|
||||
* it means there's no color for that namespace/name combination.
|
||||
*/
|
||||
_getTransparentColor: function () {
|
||||
if (!this.transparentColor) {
|
||||
this.transparentColor =
|
||||
$('<div style="color:transparent;display:none;"></div>').appendTo($('body')).css('color');
|
||||
}
|
||||
|
||||
return this.transparentColor;
|
||||
}
|
||||
};
|
||||
|
||||
piwik.ColorManager = new ColorManager();
|
||||
|
||||
}(jQuery));
|
130
msd2/tracking/piwik/plugins/CoreHome/javascripts/corehome.js
Normal file
130
msd2/tracking/piwik/plugins/CoreHome/javascripts/corehome.js
Normal file
@ -0,0 +1,130 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
$(function () {
|
||||
|
||||
//
|
||||
// 'check for updates' behavior
|
||||
//
|
||||
|
||||
var headerMessageParent = $('#header_message').parent();
|
||||
|
||||
initTopControls();
|
||||
|
||||
// when 'check for updates...' link is clicked, force a check & display the result
|
||||
headerMessageParent.on('click', '#updateCheckLinkContainer', function (e) {
|
||||
var headerMessage = $(this).closest('#header_message');
|
||||
|
||||
var $titleElement = headerMessage.find('.title');
|
||||
if ($titleElement.attr('target')) { // if this is an external link, internet access is not available on the server
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.setLoadingElement('#header_message .loadingPiwik');
|
||||
ajaxRequest.addParams({
|
||||
module: 'CoreHome',
|
||||
action: 'checkForUpdates'
|
||||
}, 'get');
|
||||
|
||||
ajaxRequest.withTokenInUrl();
|
||||
|
||||
$titleElement.addClass('activityIndicator');
|
||||
|
||||
ajaxRequest.setCallback(function (response) {
|
||||
headerMessage.fadeOut('slow', function () {
|
||||
response = $('#header_message', $('<div>' + response + '</div>'));
|
||||
|
||||
$titleElement.removeClass('activityIndicator');
|
||||
|
||||
var newVersionAvailable = response.hasClass('update_available');
|
||||
if (newVersionAvailable) {
|
||||
headerMessage.replaceWith(response);
|
||||
headerMessage.show();
|
||||
}
|
||||
else {
|
||||
headerMessage.find('.title').html(_pk_translate('CoreHome_YouAreUsingTheLatestVersion'));
|
||||
headerMessage.show();
|
||||
setTimeout(function () {
|
||||
headerMessage.fadeOut('slow', function () {
|
||||
headerMessage.replaceWith(response);
|
||||
});
|
||||
}, 4000);
|
||||
}
|
||||
});
|
||||
});
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send();
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// when clicking the header message, show the long message w/o needing to hover
|
||||
headerMessageParent.on('click', '#header_message', function (e) {
|
||||
if (e.target.tagName.toLowerCase() != 'a') {
|
||||
$(this).toggleClass('expanded');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}(jQuery));
|
||||
|
||||
|
||||
$( document ).ready(function() {
|
||||
$('.accessibility-skip-to-content').click(function(e){
|
||||
$('a[name="main"]').attr('tabindex', -1).focus();
|
||||
$(window).scrollTo($('a[name="main"]'));
|
||||
});
|
||||
|
||||
$("nav .activateTopMenu").sideNav({
|
||||
closeOnClick: true,
|
||||
edge: 'right'
|
||||
});
|
||||
|
||||
$('select').material_select();
|
||||
|
||||
piwikHelper.registerShortcut('?', _pk_translate('CoreHome_ShortcutHelp') , function (event) {
|
||||
// don't open if an modal is already shown
|
||||
if (event.altKey || $('.modal.open').length) {
|
||||
return;
|
||||
}
|
||||
if (event.preventDefault) {
|
||||
event.preventDefault();
|
||||
} else {
|
||||
event.returnValue = false; // IE
|
||||
}
|
||||
|
||||
var list = $('#shortcuthelp dl');
|
||||
list.empty();
|
||||
|
||||
var keys = Object.keys(piwikHelper.shortcuts).sort();
|
||||
|
||||
jQuery.each(keys, function(i, key) {
|
||||
if (piwikHelper.shortcuts.hasOwnProperty(key)) {
|
||||
list.append($('<dt />').append($('<kbd />').text(key)));
|
||||
list.append($('<dd />').text(piwikHelper.shortcuts[key]));
|
||||
}
|
||||
});
|
||||
|
||||
var isMac = navigator.userAgent.indexOf('Mac OS X') != -1;
|
||||
|
||||
list.append($('<dt />').append($('<kbd />').text(_pk_translate(isMac ? "CoreHome_MacPageUp" : "CoreHome_HomeShortcut"))));
|
||||
|
||||
list.append($('<dd />').text(_pk_translate('CoreHome_PageUpShortcutDescription')));
|
||||
|
||||
list.append($('<dt />').append($('<kbd />').text(_pk_translate(isMac ? "CoreHome_MacPageDown" : "CoreHome_EndShortcut"))));
|
||||
|
||||
list.append($('<dd />').text(_pk_translate('CoreHome_PageDownShortcutDescription')));
|
||||
|
||||
piwikHelper.modalConfirm('#shortcuthelp');
|
||||
});
|
||||
});
|
2005
msd2/tracking/piwik/plugins/CoreHome/javascripts/dataTable.js
Normal file
2005
msd2/tracking/piwik/plugins/CoreHome/javascripts/dataTable.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,431 @@
|
||||
/**
|
||||
* Registry for row actions
|
||||
*
|
||||
* Plugins can call DataTable_RowActions_Registry.register() from their JS
|
||||
* files in order to add new actions to arbitrary data tables. The register()
|
||||
* method takes an object containing:
|
||||
* - name: string identifying the action. must be short, no spaces.
|
||||
* - dataTableIcon: path to the icon for the action
|
||||
* - createInstance: a factory method to create an instance of the appropriate
|
||||
* subclass of DataTable_RowAction
|
||||
* - isAvailable: a method to determine whether the action is available in a
|
||||
* given row of a data table
|
||||
*/
|
||||
var DataTable_RowActions_Registry = {
|
||||
|
||||
registry: [],
|
||||
|
||||
register: function (action) {
|
||||
var createInstance = action.createInstance;
|
||||
action.createInstance = function (dataTable, param) {
|
||||
var instance = createInstance(dataTable, param);
|
||||
instance.actionName = action.name;
|
||||
return instance;
|
||||
};
|
||||
|
||||
this.registry.push(action);
|
||||
},
|
||||
|
||||
getAvailableActionsForReport: function (dataTableParams, tr) {
|
||||
if (dataTableParams.disable_row_actions == '1') {
|
||||
return [];
|
||||
}
|
||||
|
||||
var available = [];
|
||||
for (var i = 0; i < this.registry.length; i++) {
|
||||
if (this.registry[i].isAvailableOnReport(dataTableParams, tr)) {
|
||||
available.push(this.registry[i]);
|
||||
}
|
||||
}
|
||||
available.sort(function (a, b) {
|
||||
return b.order - a.order;
|
||||
});
|
||||
return available;
|
||||
},
|
||||
|
||||
getActionByName: function (name) {
|
||||
for (var i = 0; i < this.registry.length; i++) {
|
||||
if (this.registry[i].name == name) {
|
||||
return this.registry[i];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Register Row Evolution (also servers as example)
|
||||
DataTable_RowActions_Registry.register({
|
||||
|
||||
name: 'RowEvolution',
|
||||
|
||||
dataTableIcon: 'icon-evolution',
|
||||
|
||||
order: 50,
|
||||
|
||||
dataTableIconTooltip: [
|
||||
_pk_translate('General_RowEvolutionRowActionTooltipTitle'),
|
||||
_pk_translate('General_RowEvolutionRowActionTooltip')
|
||||
],
|
||||
|
||||
createInstance: function (dataTable, param) {
|
||||
if (dataTable !== null && typeof dataTable.rowEvolutionActionInstance != 'undefined') {
|
||||
return dataTable.rowEvolutionActionInstance;
|
||||
}
|
||||
|
||||
if (dataTable === null && param) {
|
||||
// when row evolution is triggered from the url (not a click on the data table)
|
||||
// we look for the data table instance in the dom
|
||||
var report = param.split(':')[0];
|
||||
var div = $(require('piwik/UI').DataTable.getDataTableByReport(report));
|
||||
if (div.length && div.data('uiControlObject')) {
|
||||
dataTable = div.data('uiControlObject');
|
||||
if (typeof dataTable.rowEvolutionActionInstance != 'undefined') {
|
||||
return dataTable.rowEvolutionActionInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var instance = new DataTable_RowActions_RowEvolution(dataTable);
|
||||
if (dataTable !== null) {
|
||||
dataTable.rowEvolutionActionInstance = instance;
|
||||
}
|
||||
return instance;
|
||||
},
|
||||
|
||||
isAvailableOnReport: function (dataTableParams) {
|
||||
return (
|
||||
typeof dataTableParams.disable_row_evolution == 'undefined'
|
||||
|| dataTableParams.disable_row_evolution == "0"
|
||||
);
|
||||
},
|
||||
|
||||
isAvailableOnRow: function (dataTableParams, tr) {
|
||||
return !tr.hasClass('totalsRow');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* DataTable Row Actions
|
||||
*
|
||||
* The lifecycle of an action is as follows:
|
||||
* - for each data table, a new instance of the action is created using the factory
|
||||
* - when the table is loaded, initTr is called for each tr
|
||||
* - when the action icon is clicked, trigger is called
|
||||
* - the label is put together and performAction is called
|
||||
* - performAction must call openPopover on the base class
|
||||
* - openPopover calls back doOpenPopover after doing general stuff
|
||||
*
|
||||
* The two template methods are performAction and doOpenPopover
|
||||
*/
|
||||
|
||||
//
|
||||
// BASE CLASS
|
||||
//
|
||||
|
||||
function DataTable_RowAction(dataTable) {
|
||||
this.dataTable = dataTable;
|
||||
|
||||
// has to be overridden in subclasses
|
||||
this.trEventName = 'piwikTriggerRowAction';
|
||||
|
||||
// set in registry
|
||||
this.actionName = 'RowAction';
|
||||
}
|
||||
|
||||
/** Initialize a row when the table is loaded */
|
||||
DataTable_RowAction.prototype.initTr = function (tr) {
|
||||
var self = this;
|
||||
|
||||
// For subtables, we need to make sure that the actions are always triggered on the
|
||||
// action instance connected to the root table. Otherwise sharing data (e.g. for
|
||||
// for multi-row evolution) wouldn't be possible. Also, sub-tables might have different
|
||||
// API actions. For the label filter to work, we need to use the parent action.
|
||||
// We use jQuery events to let subtables access their parents.
|
||||
tr.bind(self.trEventName, function (e, params) {
|
||||
self.trigger($(this), params.originalEvent, params.label);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This method is called from the click event and the tr event (see this.trEventName).
|
||||
* It derives the label and calls performAction.
|
||||
*/
|
||||
DataTable_RowAction.prototype.trigger = function (tr, e, subTableLabel) {
|
||||
var label = this.getLabelFromTr(tr);
|
||||
|
||||
// if we have received the event from the sub table, add the label
|
||||
if (subTableLabel) {
|
||||
var separator = ' > '; // LabelFilter::SEPARATOR_RECURSIVE_LABEL
|
||||
label += separator + subTableLabel;
|
||||
}
|
||||
|
||||
// handle sub tables in nested reports: forward to parent
|
||||
var subtable = tr.closest('table');
|
||||
if (subtable.is('.subDataTable')) {
|
||||
subtable.closest('tr').prev().trigger(this.trEventName, {
|
||||
label: label,
|
||||
originalEvent: e
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// ascend in action reports
|
||||
if (subtable.closest('div.dataTableActions').length) {
|
||||
var allClasses = tr.attr('class');
|
||||
var matches = allClasses.match(/level[0-9]+/);
|
||||
var level = parseInt(matches[0].substring(5, matches[0].length), 10);
|
||||
if (level > 0) {
|
||||
// .prev(.levelX) does not work for some reason => do it "by hand"
|
||||
var findLevel = 'level' + (level - 1);
|
||||
var ptr = tr;
|
||||
while ((ptr = ptr.prev()).length) {
|
||||
if (!ptr.hasClass(findLevel) || ptr.hasClass('nodata')) {
|
||||
continue;
|
||||
}
|
||||
ptr.trigger(this.trEventName, {
|
||||
label: label,
|
||||
originalEvent: e
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.performAction(label, tr, e);
|
||||
};
|
||||
|
||||
/** Get the label string from a tr dom element */
|
||||
DataTable_RowAction.prototype.getLabelFromTr = function (tr) {
|
||||
var label = tr.find('span.label');
|
||||
|
||||
// handle truncation
|
||||
var value = label.data('originalText');
|
||||
|
||||
if (!value) {
|
||||
value = label.text();
|
||||
}
|
||||
value = value.trim();
|
||||
value = encodeURIComponent(value);
|
||||
|
||||
// if tr is a terminal node, we use the @ operator to distinguish it from branch nodes w/ the same name
|
||||
if (!tr.hasClass('subDataTable')) {
|
||||
value = '@' + value;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
/** Get row metadata object */
|
||||
DataTable_RowAction.prototype.getRowMetadata = function (tr) {
|
||||
return tr.data('row-metadata') || {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Base method for opening popovers.
|
||||
* This method will remember the parameter in the url and call doOpenPopover().
|
||||
*/
|
||||
DataTable_RowAction.prototype.openPopover = function (parameter) {
|
||||
broadcast.propagateNewPopoverParameter('RowAction', this.actionName + ':' + parameter);
|
||||
};
|
||||
|
||||
broadcast.addPopoverHandler('RowAction', function (param) {
|
||||
var paramParts = param.split(':');
|
||||
var rowActionName = paramParts[0];
|
||||
paramParts.shift();
|
||||
param = paramParts.join(':');
|
||||
|
||||
var rowAction = DataTable_RowActions_Registry.getActionByName(rowActionName);
|
||||
if (rowAction) {
|
||||
rowAction.createInstance(null, param).doOpenPopover(param);
|
||||
}
|
||||
});
|
||||
|
||||
/** To be overridden */
|
||||
DataTable_RowAction.prototype.performAction = function (label, tr, e) {
|
||||
};
|
||||
DataTable_RowAction.prototype.doOpenPopover = function (parameter) {
|
||||
};
|
||||
|
||||
//
|
||||
// ROW EVOLUTION
|
||||
//
|
||||
|
||||
function DataTable_RowActions_RowEvolution(dataTable) {
|
||||
this.dataTable = dataTable;
|
||||
this.trEventName = 'piwikTriggerRowEvolution';
|
||||
|
||||
/** The rows to be compared in multi row evolution */
|
||||
this.multiEvolutionRows = [];
|
||||
}
|
||||
|
||||
/** Static helper method to launch row evolution from anywhere */
|
||||
DataTable_RowActions_RowEvolution.launch = function (apiMethod, label) {
|
||||
var param = 'RowEvolution:' + apiMethod + ':0:' + label;
|
||||
broadcast.propagateNewPopoverParameter('RowAction', param);
|
||||
};
|
||||
|
||||
DataTable_RowActions_RowEvolution.prototype = new DataTable_RowAction;
|
||||
|
||||
DataTable_RowActions_RowEvolution.prototype.performAction = function (label, tr, e) {
|
||||
if (e.shiftKey) {
|
||||
// only mark for multi row evolution if shift key is pressed
|
||||
this.addMultiEvolutionRow(label);
|
||||
return;
|
||||
}
|
||||
|
||||
this.addMultiEvolutionRow(label);
|
||||
|
||||
// check whether we have rows marked for multi row evolution
|
||||
var extraParams = {};
|
||||
if (this.multiEvolutionRows.length > 1) {
|
||||
extraParams.action = 'getMultiRowEvolutionPopover';
|
||||
label = this.multiEvolutionRows.join(',');
|
||||
}
|
||||
|
||||
$.each(this.dataTable.param, function (index, value) {
|
||||
// we automatically add fields like idDimension, idGoal etc.
|
||||
if (index !== 'idSite' && index.indexOf('id') === 0 && $.isNumeric(value)) {
|
||||
extraParams[index] = value;
|
||||
}
|
||||
});
|
||||
|
||||
// check if abandonedCarts is in the dataTable params and if so, propagate to row evolution request
|
||||
if (this.dataTable.param.abandonedCarts !== undefined) {
|
||||
extraParams['abandonedCarts'] = this.dataTable.param.abandonedCarts;
|
||||
}
|
||||
|
||||
if (this.dataTable.param.flat !== undefined) {
|
||||
extraParams['flat'] = this.dataTable.param.flat;
|
||||
}
|
||||
|
||||
var apiMethod = this.dataTable.param.module + '.' + this.dataTable.param.action;
|
||||
this.openPopover(apiMethod, extraParams, label);
|
||||
};
|
||||
|
||||
DataTable_RowActions_RowEvolution.prototype.addMultiEvolutionRow = function (label) {
|
||||
if ($.inArray(label, this.multiEvolutionRows) == -1) {
|
||||
this.multiEvolutionRows.push(label);
|
||||
}
|
||||
};
|
||||
|
||||
DataTable_RowActions_RowEvolution.prototype.openPopover = function (apiMethod, extraParams, label) {
|
||||
var urlParam = apiMethod + ':' + encodeURIComponent(JSON.stringify(extraParams)) + ':' + label;
|
||||
DataTable_RowAction.prototype.openPopover.apply(this, [urlParam]);
|
||||
};
|
||||
|
||||
DataTable_RowActions_RowEvolution.prototype.doOpenPopover = function (urlParam) {
|
||||
var urlParamParts = urlParam.split(':');
|
||||
|
||||
var apiMethod = urlParamParts.shift();
|
||||
|
||||
var extraParamsString = urlParamParts.shift(),
|
||||
extraParams = {}; // 0/1 or "0"/"1"
|
||||
try {
|
||||
extraParams = JSON.parse(decodeURIComponent(extraParamsString));
|
||||
} catch (e) {
|
||||
// assume the parameter is an int/string describing whether to use multi row evolution
|
||||
if (extraParamsString == '1') {
|
||||
extraParams.action = 'getMultiRowEvolutionPopover';
|
||||
} else if (extraParamsString != '0') {
|
||||
extraParams.action = 'getMultiRowEvolutionPopover';
|
||||
extraParams.column = extraParamsString;
|
||||
}
|
||||
}
|
||||
|
||||
var label = urlParamParts.join(':');
|
||||
|
||||
this.showRowEvolution(apiMethod, label, extraParams);
|
||||
};
|
||||
|
||||
/** Open the row evolution popover */
|
||||
DataTable_RowActions_RowEvolution.prototype.showRowEvolution = function (apiMethod, label, extraParams) {
|
||||
|
||||
var self = this;
|
||||
|
||||
// open the popover
|
||||
var box = Piwik_Popover.showLoading('Row Evolution');
|
||||
box.addClass('rowEvolutionPopover');
|
||||
|
||||
// prepare loading the popover contents
|
||||
var requestParams = {
|
||||
apiMethod: apiMethod,
|
||||
label: label,
|
||||
disableLink: 1
|
||||
};
|
||||
|
||||
var callback = function (html) {
|
||||
Piwik_Popover.setContent(html);
|
||||
|
||||
// use the popover title returned from the server
|
||||
var title = box.find('div.popover-title');
|
||||
if (title.length) {
|
||||
Piwik_Popover.setTitle(title.html());
|
||||
title.remove();
|
||||
}
|
||||
|
||||
Piwik_Popover.onClose(function () {
|
||||
// reset rows marked for multi row evolution on close
|
||||
self.multiEvolutionRows = [];
|
||||
});
|
||||
|
||||
if (self.dataTable !== null) {
|
||||
// remember label for multi row evolution
|
||||
box.find('.rowevolution-startmulti').click(function () {
|
||||
Piwik_Popover.onClose(false); // unbind listener that resets multiEvolutionRows
|
||||
broadcast.propagateNewPopoverParameter(false);
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
// when the popover is launched by copy&pasting a url, we don't have the data table.
|
||||
// in this case, we can't remember the row marked for multi row evolution so
|
||||
// we disable the picker.
|
||||
box.find('.compare-container, .rowevolution-startmulti').remove();
|
||||
}
|
||||
|
||||
// switch metric in multi row evolution
|
||||
box.find('select.multirowevoltion-metric').change(function () {
|
||||
var metric = $(this).val();
|
||||
Piwik_Popover.onClose(false); // unbind listener that resets multiEvolutionRows
|
||||
var extraParams = {action: 'getMultiRowEvolutionPopover', column: metric};
|
||||
self.openPopover(apiMethod, extraParams, label);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
requestParams.module = 'CoreHome';
|
||||
requestParams.action = 'getRowEvolutionPopover';
|
||||
requestParams.colors = JSON.stringify(piwik.getSparklineColors());
|
||||
|
||||
var idDimension;
|
||||
|
||||
if (broadcast.getValueFromUrl('module') === 'Widgetize') {
|
||||
idDimension = broadcast.getValueFromUrl('subcategory');
|
||||
} else {
|
||||
idDimension = broadcast.getValueFromHash('subcategory');
|
||||
}
|
||||
|
||||
if (idDimension && ('' + idDimension).indexOf('customdimension') === 0) {
|
||||
idDimension = ('' + idDimension).replace('customdimension', '');
|
||||
idDimension = parseInt(idDimension, 10);
|
||||
if (idDimension > 0) {
|
||||
requestParams.idDimension = idDimension;
|
||||
}
|
||||
}
|
||||
|
||||
if (self.dataTable && self.dataTable.jsViewDataTable === 'tableGoals') {
|
||||
// remove idGoal param, when it's set for goal visualizations
|
||||
if (extraParams['idGoal']) {
|
||||
delete(extraParams['idGoal']);
|
||||
}
|
||||
}
|
||||
|
||||
$.extend(requestParams, extraParams);
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams(requestParams, 'get');
|
||||
ajaxRequest.setCallback(callback);
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send();
|
||||
};
|
142
msd2/tracking/piwik/plugins/CoreHome/javascripts/donate.js
Normal file
142
msd2/tracking/piwik/plugins/CoreHome/javascripts/donate.js
Normal file
@ -0,0 +1,142 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
var donateAmounts = [0, 30, 60, 90, 120];
|
||||
|
||||
// returns the space between each donation amount in the donation slider
|
||||
var getTickWidth = function (slider) {
|
||||
var effectiveSliderWidth = $('.slider-range', slider).width() - $('.slider-position', slider).width();
|
||||
return effectiveSliderWidth / (donateAmounts.length - 1);
|
||||
};
|
||||
|
||||
// returns the position index on a slider based on a x coordinate value
|
||||
var getPositionFromPageCoord = function (slider, pageX) {
|
||||
return Math.round((pageX - $('.slider-range', slider).offset().left) / getTickWidth(slider));
|
||||
};
|
||||
|
||||
// set's the correct amount text & smiley face image based on the position of the slider
|
||||
var setSmileyFaceAndAmount = function (slider, pos) {
|
||||
// set text yearly amount
|
||||
$('.slider-donate-amount', slider).text('$' + donateAmounts[pos] + '/' + _pk_translate('Intl_Year_Short'));
|
||||
|
||||
// set the right smiley face
|
||||
$('.slider-smiley-face').attr('src', 'plugins/Morpheus/images/smileyprog_' + pos + '.png');
|
||||
|
||||
// set the hidden option input for paypal
|
||||
var option = Math.max(1, pos);
|
||||
$('.piwik-donate-call input[name=os0]').val("Option " + option);
|
||||
};
|
||||
|
||||
// move's a slider's position to a specific spot
|
||||
var moveSliderPosition = function (slider, to) {
|
||||
// make sure 'to' is valid
|
||||
if (to < 0) {
|
||||
to = 0;
|
||||
}
|
||||
else if (to >= donateAmounts.length) {
|
||||
to = donateAmounts.length - 1;
|
||||
}
|
||||
|
||||
// set the slider position
|
||||
var left = to * getTickWidth(slider);
|
||||
if (left == 0) {
|
||||
left = -1; // at position 0 we move one pixel left to cover up some of slider bar
|
||||
}
|
||||
|
||||
$('.slider-position', slider).css({
|
||||
left: left + 'px'
|
||||
});
|
||||
|
||||
// reset the smiley face & amount based on the new position
|
||||
setSmileyFaceAndAmount(slider, to);
|
||||
};
|
||||
|
||||
// when a slider is clicked, set the amount & smiley face appropriately
|
||||
$('body').on('click', '.piwik-donate-slider>.slider-range', function (e) {
|
||||
var slider = $(this).parent(),
|
||||
currentPageX = $('.slider-position', this).offset().left,
|
||||
currentPos = getPositionFromPageCoord(slider, currentPageX),
|
||||
pos = getPositionFromPageCoord(slider, e.pageX);
|
||||
|
||||
// if the closest position is the current one, use the other position since
|
||||
// the user obviously wants to move the slider.
|
||||
if (currentPos == pos) {
|
||||
// if click is to right, go forward one, else backwards one
|
||||
if (e.pageX > currentPageX) {
|
||||
++pos;
|
||||
}
|
||||
else {
|
||||
--pos;
|
||||
}
|
||||
}
|
||||
|
||||
moveSliderPosition(slider, pos);
|
||||
});
|
||||
|
||||
// when the smiley icon is clicked, move the position up one to demonstrate how to use the slider
|
||||
$('body').on('click', '.piwik-donate-slider .slider-smiley-face,.piwik-donate-slider .slider-donate-amount',
|
||||
function (e) {
|
||||
var slider = $(this).closest('.piwik-donate-slider'),
|
||||
currentPageX = $('.slider-position', slider).offset().left,
|
||||
currentPos = getPositionFromPageCoord(slider, currentPageX);
|
||||
|
||||
moveSliderPosition(slider, currentPos + 1);
|
||||
}
|
||||
);
|
||||
|
||||
// stores the current slider being dragged
|
||||
var draggingSlider = false;
|
||||
|
||||
// start dragging on mousedown for a slider's position bar
|
||||
$('body').on('mousedown', '.piwik-donate-slider .slider-position', function () {
|
||||
draggingSlider = $(this).parent().parent();
|
||||
});
|
||||
|
||||
// move the slider position if currently dragging when the mouse moves anywhere over the entire page
|
||||
$('body').on('mousemove', function (e) {
|
||||
if (draggingSlider) {
|
||||
var slider = draggingSlider.find('.slider-range'),
|
||||
sliderPos = slider.find('.slider-position'),
|
||||
left = e.pageX - slider.offset().left;
|
||||
|
||||
// only move slider if the mouse x-coord is still on the slider (w/ some padding for borders)
|
||||
if (left <= slider.width() - sliderPos.width() + 2
|
||||
&& left >= -2) {
|
||||
sliderPos.css({left: left + 'px'});
|
||||
|
||||
var closestPos = Math.round(left / getTickWidth(draggingSlider));
|
||||
setSmileyFaceAndAmount(draggingSlider, closestPos);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// stop dragging and normalize a slider's position on mouseup over the entire page
|
||||
$('body').on('mouseup', function () {
|
||||
if (draggingSlider) {
|
||||
var sliderPos = $('.slider-position', draggingSlider),
|
||||
slider = sliderPos.parent();
|
||||
|
||||
if (sliderPos.length) {
|
||||
// move the slider to the nearest donation amount position
|
||||
var pos = getPositionFromPageCoord(draggingSlider, sliderPos.offset().left);
|
||||
moveSliderPosition(draggingSlider, pos);
|
||||
}
|
||||
|
||||
draggingSlider = false; // stop dragging
|
||||
}
|
||||
});
|
||||
|
||||
// event for programatically changing the position
|
||||
$('body').on('piwik:changePosition', '.piwik-donate-slider', function (e, data) {
|
||||
moveSliderPosition(this, data.position);
|
||||
});
|
||||
});
|
||||
|
||||
}(jQuery));
|
9
msd2/tracking/piwik/plugins/CoreHome/javascripts/iframeResizer.min.js
vendored
Normal file
9
msd2/tracking/piwik/plugins/CoreHome/javascripts/iframeResizer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,48 @@
|
||||
{
|
||||
"short_name": "Matomo",
|
||||
"name": "Matomo - Open Source Analytics",
|
||||
"icons": [
|
||||
{
|
||||
"src": "../images/applogo_32.png",
|
||||
"sizes": "32x32",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "../images/applogo_72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "../images/applogo_128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "../images/applogo_144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "../images/applogo_192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "../images/applogo_256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"start_url": "../../../",
|
||||
"display": "standalone",
|
||||
"orientation": "portrait",
|
||||
"background_color": "#edecec",
|
||||
"theme_color": "#3450A3",
|
||||
"prefer_related_applications": true,
|
||||
"related_applications": [
|
||||
{
|
||||
"platform": "play",
|
||||
"id": "org.piwik.mobile2"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
$(function () {
|
||||
if ($.browser.msie && parseInt($.browser.version) === 10) {
|
||||
$(document).on('click', 'a[rel~="noreferrer"]', function (event) {
|
||||
event.preventDefault();
|
||||
var a = event.currentTarget;
|
||||
var w = window.open(a.href, a.target || '_self');
|
||||
if (/\bnoopener\b/.test(a.rel)) {
|
||||
w.opener = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
204
msd2/tracking/piwik/plugins/CoreHome/javascripts/notification.js
Normal file
204
msd2/tracking/piwik/plugins/CoreHome/javascripts/notification.js
Normal file
@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
(function ($, require) {
|
||||
|
||||
var exports = require('piwik/UI');
|
||||
|
||||
/**
|
||||
* Creates a new notifications.
|
||||
*
|
||||
* Example:
|
||||
* var UI = require('piwik/UI');
|
||||
* var notification = new UI.Notification();
|
||||
* notification.show('My Notification Message', {title: 'Low space', context: 'warning'});
|
||||
*/
|
||||
var Notification = function () {
|
||||
this.$node = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes the notification visible.
|
||||
*
|
||||
* @param {string} message The actual message that will be displayed. Must be set.
|
||||
* @param {Object} [options]
|
||||
* @param {string} [options.id] Only needed for persistent notifications. The id will be sent to the
|
||||
* frontend once the user closes the notifications. The notification has to
|
||||
* be registered/notified under this name
|
||||
* @param {string} [options.title] The title of the notification. For instance the plugin name.
|
||||
* @param {bool} [options.animate=true] If enabled, the notification will be faded in.
|
||||
* @param {string} [options.context=warning] Context of the notification: 'info', 'warning', 'success' or
|
||||
* 'error'
|
||||
* @param {string} [options.type=transient] The type of the notification: Either 'toast' or 'transitent'
|
||||
* @param {bool} [options.noclear=false] If set, the close icon is not displayed.
|
||||
* @param {object} [options.style] Optional style/css dictionary. For instance {'display': 'inline-block'}
|
||||
* @param {string} [options.placeat] By default, the notification will be displayed in the "stats bar".
|
||||
* You can specify any other CSS selector to place the notifications
|
||||
* wherever you want.
|
||||
*/
|
||||
Notification.prototype.show = function (message, options) {
|
||||
checkMessage(message);
|
||||
options = checkOptions(options);
|
||||
|
||||
var template = generateNotificationHtmlMarkup(options, message);
|
||||
this.$node = placeNotification(template, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a previously shown notification having the given notification id.
|
||||
*
|
||||
*
|
||||
* @param {string} notificationId The id of a notification that was previously registered.
|
||||
*/
|
||||
Notification.prototype.remove = function (notificationId) {
|
||||
$('[piwik-notification][notification-id=' + notificationId + ']').remove();
|
||||
};
|
||||
|
||||
Notification.prototype.scrollToNotification = function () {
|
||||
if (this.$node) {
|
||||
piwikHelper.lazyScrollTo(this.$node, 250);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows a notification at a certain point with a quick upwards animation.
|
||||
*
|
||||
* TODO: if the materializecss version matomo uses is updated, should use their toasts.
|
||||
*
|
||||
* @type {Notification}
|
||||
* @param {string} message The actual message that will be displayed. Must be set.
|
||||
* @param {Object} options
|
||||
* @param {string} options.placeat Where to place the notification. Required.
|
||||
* @param {string} [options.id] Only needed for persistent notifications. The id will be sent to the
|
||||
* frontend once the user closes the notifications. The notification has to
|
||||
* be registered/notified under this name
|
||||
* @param {string} [options.title] The title of the notification. For instance the plugin name.
|
||||
* @param {string} [options.context=warning] Context of the notification: 'info', 'warning', 'success' or
|
||||
* 'error'
|
||||
* @param {string} [options.type=transient] The type of the notification: Either 'toast' or 'transitent'
|
||||
* @param {bool} [options.noclear=false] If set, the close icon is not displayed.
|
||||
* @param {object} [options.style] Optional style/css dictionary. For instance {'display': 'inline-block'}
|
||||
*/
|
||||
Notification.prototype.toast = function (message, options) {
|
||||
checkMessage(message);
|
||||
options = checkOptions(options);
|
||||
|
||||
var $placeat = $(options.placeat);
|
||||
if (!$placeat.length) {
|
||||
throw new Error("A valid selector is required for the placeat option when using Notification.toast().");
|
||||
}
|
||||
|
||||
var $template = $(generateNotificationHtmlMarkup(options, message)).hide();
|
||||
$('body').append($template);
|
||||
|
||||
compileNotification($template);
|
||||
|
||||
$template.css({
|
||||
position: 'absolute',
|
||||
left: $placeat.offset().left,
|
||||
top: $placeat.offset().top
|
||||
});
|
||||
setTimeout(function () {
|
||||
$template.animate(
|
||||
{
|
||||
top: $placeat.offset().top - $template.height()
|
||||
},
|
||||
{
|
||||
duration: 300,
|
||||
start: function () {
|
||||
$template.show();
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
exports.Notification = Notification;
|
||||
|
||||
function generateNotificationHtmlMarkup(options, message) {
|
||||
var attributeMapping = {
|
||||
id: 'notification-id',
|
||||
title: 'notification-title',
|
||||
context: 'context',
|
||||
type: 'type',
|
||||
noclear: 'noclear',
|
||||
class: 'class',
|
||||
toastLength: 'toast-length'
|
||||
},
|
||||
html = '<div piwik-notification';
|
||||
|
||||
for (var key in attributeMapping) {
|
||||
if (attributeMapping.hasOwnProperty(key)
|
||||
&& options[key]
|
||||
) {
|
||||
html += ' ' + attributeMapping[key] + '="' + options[key].toString().replace(/"/g, """) + '"';
|
||||
}
|
||||
}
|
||||
|
||||
html += '>' + message + '</div>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function compileNotification($node) {
|
||||
angular.element(document).injector().invoke(function ($compile, $rootScope) {
|
||||
$compile($node)($rootScope.$new(true));
|
||||
});
|
||||
}
|
||||
|
||||
function placeNotification(template, options) {
|
||||
var $notificationNode = $(template);
|
||||
|
||||
// compile the template in angular
|
||||
compileNotification($notificationNode);
|
||||
|
||||
if (options.style) {
|
||||
$notificationNode.css(options.style);
|
||||
}
|
||||
|
||||
var notificationPosition = '#notificationContainer';
|
||||
var method = 'append';
|
||||
if (options.placeat) {
|
||||
notificationPosition = options.placeat;
|
||||
} else {
|
||||
// If a modal is open, we want to make sure the error message is visible and therefore show it within the opened modal
|
||||
var modalSelector = '.modal.open .modal-content';
|
||||
var modalOpen = $(modalSelector);
|
||||
if (modalOpen.length) {
|
||||
notificationPosition = modalSelector;
|
||||
method = 'prepend';
|
||||
}
|
||||
}
|
||||
|
||||
$notificationNode = $notificationNode.hide();
|
||||
$(notificationPosition)[method]($notificationNode);
|
||||
|
||||
if (false === options.animate) {
|
||||
$notificationNode.show();
|
||||
} else {
|
||||
$notificationNode.fadeIn(1000);
|
||||
}
|
||||
|
||||
return $notificationNode;
|
||||
}
|
||||
|
||||
function checkMessage(message) {
|
||||
if (!message) {
|
||||
throw new Error('No message given, cannot display notification');
|
||||
}
|
||||
}
|
||||
|
||||
function checkOptions(options) {
|
||||
if (options && !$.isPlainObject(options)) {
|
||||
throw new Error('Options has the wrong format, cannot display notification');
|
||||
} else if (!options) {
|
||||
options = {};
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
})(jQuery, require);
|
@ -0,0 +1,143 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Number Formatter for formatting numbers, percent and currencies values
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
var NumberFormatter = (function () {
|
||||
|
||||
var minimumFractionDigits = 0;
|
||||
var maximumFractionDigits = 2;
|
||||
|
||||
/**
|
||||
* Formats the given numeric value with the given pattern
|
||||
*
|
||||
* @param value
|
||||
* @param pattern
|
||||
* @returns {string}
|
||||
*/
|
||||
function format(value, pattern) {
|
||||
|
||||
if (!$.isNumeric(value)) {
|
||||
return value;
|
||||
}
|
||||
pattern = pattern || piwik.numbers.patternNumber;
|
||||
|
||||
var patterns = pattern.split(';');
|
||||
if (patterns.length == 1) {
|
||||
// No explicit negative pattern was provided, construct it.
|
||||
patterns.push('-' + patterns[0])
|
||||
}
|
||||
|
||||
// Ensure that the value is positive and has the right number of digits.
|
||||
var negative = value < 0;
|
||||
pattern = negative ? patterns[1] : patterns[0];
|
||||
|
||||
var usesGrouping = (pattern.indexOf(',') != -1);
|
||||
// if pattern has number groups, parse them.
|
||||
if (usesGrouping) {
|
||||
var primaryGroupMatches = pattern.match(/#+0/);
|
||||
var primaryGroupSize = primaryGroupMatches[0].length;
|
||||
var secondaryGroupSize = primaryGroupMatches[0].length;
|
||||
var numberGroups = pattern.split(',');
|
||||
// check for distinct secondary group size.
|
||||
if (numberGroups.length > 2) {
|
||||
secondaryGroupSize = numberGroups[1].length;
|
||||
}
|
||||
}
|
||||
|
||||
var signMultiplier = negative ? '-1' : '1';
|
||||
value = value * signMultiplier;
|
||||
// Split the number into major and minor digits.
|
||||
var valueParts = value.toString().split('.');
|
||||
var majorDigits = valueParts[0];
|
||||
// Account for maximumFractionDigits = 0, where the number won't
|
||||
// have a decimal point, and $valueParts[1] won't be set.
|
||||
minorDigits = valueParts[1] || '';
|
||||
if (usesGrouping) {
|
||||
// Reverse the major digits, since they are grouped from the right.
|
||||
majorDigits = majorDigits.split('').reverse();
|
||||
// Group the major digits.
|
||||
var groups = [];
|
||||
groups.push(majorDigits.splice(0, primaryGroupSize).reverse().join(''));
|
||||
while (majorDigits.length) {
|
||||
groups.push(majorDigits.splice(0, secondaryGroupSize).reverse().join(''));
|
||||
}
|
||||
// Reverse the groups and the digits inside of them.
|
||||
groups = groups.reverse();
|
||||
// Reconstruct the major digits.
|
||||
majorDigits = groups.join(',');
|
||||
}
|
||||
if (minimumFractionDigits < maximumFractionDigits) {
|
||||
// Strip any trailing zeroes.
|
||||
var minorDigits = minorDigits.replace(/0+$/,'');
|
||||
if (minorDigits.length < minimumFractionDigits) {
|
||||
// Now there are too few digits, re-add trailing zeroes
|
||||
// until the desired length is reached.
|
||||
var neededZeroes = minimumFractionDigits - minorDigits.length;
|
||||
minorDigits += (new Array(neededZeroes+1)).join('0');
|
||||
}
|
||||
}
|
||||
// Assemble the final number and insert it into the pattern.
|
||||
value = minorDigits ? majorDigits + '.' + minorDigits : majorDigits;
|
||||
value = pattern.replace(/#(?:[\.,]#+)*0(?:[,\.][0#]+)*/, value);
|
||||
// Localize the number.
|
||||
return replaceSymbols(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the placeholders with real symbols
|
||||
*
|
||||
* @param value
|
||||
* @returns {string}
|
||||
*/
|
||||
function replaceSymbols(value) {
|
||||
var replacements = {
|
||||
'.': piwik.numbers.symbolDecimal,
|
||||
',': piwik.numbers.symbolGroup,
|
||||
'+': piwik.numbers.symbolPlus,
|
||||
'-': piwik.numbers.symbolMinus,
|
||||
'%': piwik.numbers.symbolPercent
|
||||
};
|
||||
|
||||
var newValue = '';
|
||||
var valueParts = value.split('');
|
||||
|
||||
$.each(valueParts, function(index, value) {
|
||||
$.each(replacements, function(char, replacement) {
|
||||
if (value.indexOf(char) != -1) {
|
||||
value = value.replace(char, replacement);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
newValue += value;
|
||||
});
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public available methods
|
||||
*/
|
||||
return {
|
||||
|
||||
formatNumber: function (value) {
|
||||
return format(value, piwik.numbers.patternNumber);
|
||||
},
|
||||
|
||||
formatPercent: function (value) {
|
||||
return format(value, piwik.numbers.patternPercent);
|
||||
},
|
||||
|
||||
formatCurrency: function (value, currency) {
|
||||
var formatted = format(value, piwik.numbers.patternCurrency);
|
||||
return formatted.replace('¤', currency);
|
||||
}
|
||||
}
|
||||
})();
|
301
msd2/tracking/piwik/plugins/CoreHome/javascripts/popover.js
Normal file
301
msd2/tracking/piwik/plugins/CoreHome/javascripts/popover.js
Normal file
@ -0,0 +1,301 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
var Piwik_Popover = (function () {
|
||||
|
||||
var container = false;
|
||||
var isOpen = false;
|
||||
var closeCallback = false;
|
||||
var isProgrammaticClose = false;
|
||||
|
||||
var createContainer = function () {
|
||||
if (container === false) {
|
||||
container = $(document.createElement('div')).attr('id', 'Piwik_Popover');
|
||||
}
|
||||
};
|
||||
|
||||
var openPopover = function (title, dialogClass) {
|
||||
createContainer();
|
||||
|
||||
var options =
|
||||
{
|
||||
title: title,
|
||||
modal: true,
|
||||
width: '1050px',
|
||||
position: ['center', 'center'],
|
||||
resizable: false,
|
||||
autoOpen: true,
|
||||
open: function (event, ui) {
|
||||
if (dialogClass) {
|
||||
$(this).parent().addClass(dialogClass).attr('style', '');
|
||||
}
|
||||
|
||||
$('.ui-widget-overlay').on('click.popover', function () {
|
||||
container.dialog('close');
|
||||
});
|
||||
|
||||
// sometimes the modal can be displayed outside of the current viewport, in this case
|
||||
// we scroll to it to make sure it's visible. this isn't a perfect workaround, since it
|
||||
// doesn't center the modal.g
|
||||
var self = this;
|
||||
setTimeout(function () {
|
||||
piwikHelper.lazyScrollTo(self, 0);
|
||||
}, 0);
|
||||
},
|
||||
close: function (event, ui) {
|
||||
// if clicking outside of the dialog, close entire stack
|
||||
if (!event.currentTarget && !$(event.currentTarget).is('button')) {
|
||||
broadcast.resetPopoverStack();
|
||||
}
|
||||
|
||||
container.find('div.jqplot-target').trigger('piwikDestroyPlot');
|
||||
container[0].innerHTML = '';
|
||||
container.dialog('destroy').remove();
|
||||
globalAjaxQueue.abort();
|
||||
$('.ui-widget-overlay').off('click.popover');
|
||||
isOpen = false;
|
||||
require('piwik/UI').UIControl.cleanupUnusedControls();
|
||||
if (typeof closeCallback == 'function') {
|
||||
closeCallback();
|
||||
closeCallback = false;
|
||||
}
|
||||
|
||||
// just to avoid any annoying race conditions that cause tooltips to remain on the screen permanently,
|
||||
// remove any that still exist
|
||||
$('body > .ui-tooltip').remove();
|
||||
|
||||
// if we were not called by Piwik_Popover.close(), then the user clicked the close button or clicked
|
||||
// the overlay, in which case we want to handle the popover URL as well as the actual modal.
|
||||
if (!isProgrammaticClose) {
|
||||
broadcast.propagateNewPopoverParameter(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
container.dialog(options);
|
||||
|
||||
// override the undocumented _title function to ensure that the title attribute is not escaped (according to jQueryUI bug #6016)
|
||||
container.data( "uiDialog" )._title = function(title) {
|
||||
title.html( this.options.title );
|
||||
};
|
||||
|
||||
isOpen = true;
|
||||
};
|
||||
|
||||
var centerPopover = function () {
|
||||
if (container !== false) {
|
||||
container.dialog({position: ['center', 'center']});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* Open the popover with a loading message
|
||||
*
|
||||
* @param {string} popoverName name of the popover
|
||||
* @param {string} [popoverSubject] subject of the popover (e.g. url, optional)
|
||||
* @param {int} [height] height of the popover in px (optional)
|
||||
* @param {string} [dialogClass] css class to add to dialog
|
||||
*/
|
||||
showLoading: function (popoverName, popoverSubject, height, dialogClass) {
|
||||
var loading = $(document.createElement('div')).addClass('Piwik_Popover_Loading');
|
||||
|
||||
var loadingMessage = popoverSubject ? translations.General_LoadingPopoverFor :
|
||||
translations.General_LoadingPopover;
|
||||
|
||||
loadingMessage = sprintf(loadingMessage, popoverName);
|
||||
|
||||
var p1 = $(document.createElement('p')).addClass('Piwik_Popover_Loading_Name');
|
||||
loading.append(p1.text(loadingMessage));
|
||||
|
||||
var p2;
|
||||
if (popoverSubject) {
|
||||
popoverSubject = piwikHelper.addBreakpointsToUrl(popoverSubject);
|
||||
p1.addClass('Piwik_Popover_Loading_NameWithSubject');
|
||||
p2 = $(document.createElement('p')).addClass('Piwik_Popover_Loading_Subject');
|
||||
loading.append(p2.html(popoverSubject));
|
||||
}
|
||||
|
||||
if (height) {
|
||||
loading.height(height);
|
||||
}
|
||||
|
||||
if (!isOpen) {
|
||||
openPopover(null, dialogClass);
|
||||
}
|
||||
|
||||
this.setContent(loading);
|
||||
this.setTitle('');
|
||||
|
||||
if (height) {
|
||||
var offset = loading.height() - p1.outerHeight();
|
||||
if (popoverSubject) {
|
||||
offset -= p2.outerHeight();
|
||||
}
|
||||
var spacingEl = $(document.createElement('div'));
|
||||
spacingEl.height(Math.round(offset / 2));
|
||||
loading.prepend(spacingEl);
|
||||
}
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a help button to the current popover
|
||||
*
|
||||
* @param {string} helpUrl
|
||||
*/
|
||||
addHelpButton: function (helpUrl) {
|
||||
if (!isOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
var titlebar = container.parent().find('.ui-dialog-titlebar');
|
||||
|
||||
var button = $(document.createElement('a')).addClass('ui-dialog-titlebar-help');
|
||||
button.attr({href: helpUrl, target: '_blank'});
|
||||
|
||||
titlebar.append(button);
|
||||
},
|
||||
|
||||
/** Set the title of the popover */
|
||||
setTitle: function (titleHtml) {
|
||||
var titleText = piwikHelper.htmlDecode(titleHtml);
|
||||
if (titleText.length > 60) {
|
||||
titleHtml = $('<span>').attr('class', 'tooltip').attr('title', titleText).html(titleHtml);
|
||||
}
|
||||
container.dialog('option', 'title', titleHtml);
|
||||
try {
|
||||
$('.tooltip', container.parentNode).tooltip('destroy');
|
||||
} catch (e) {}
|
||||
if (titleText.length > 60) {
|
||||
$('.tooltip', container.parentNode).tooltip({track: true, items: '.tooltip'});
|
||||
}
|
||||
},
|
||||
|
||||
/** Set inner HTML of the popover */
|
||||
setContent: function (html) {
|
||||
if (typeof closeCallback == 'function') {
|
||||
closeCallback();
|
||||
closeCallback = false;
|
||||
}
|
||||
|
||||
container.html(html);
|
||||
|
||||
container.children().each(function (i, childNode) {
|
||||
piwikHelper.compileAngularComponents(childNode);
|
||||
})
|
||||
centerPopover();
|
||||
},
|
||||
|
||||
/**
|
||||
* Show an error message. All params are HTML!
|
||||
*
|
||||
* @param {string} title
|
||||
* @param {string} [message]
|
||||
* @param {string} [backLabel]
|
||||
*/
|
||||
showError: function (title, message, backLabel) {
|
||||
var error = $(document.createElement('div')).addClass('Piwik_Popover_Error');
|
||||
|
||||
var p = $(document.createElement('p')).addClass('Piwik_Popover_Error_Title');
|
||||
error.append(p.html(title));
|
||||
|
||||
if (message) {
|
||||
p = $(document.createElement('p')).addClass('Piwik_Popover_Error_Message');
|
||||
error.append(p.html(message));
|
||||
}
|
||||
|
||||
if (backLabel) {
|
||||
var back = $(document.createElement('a')).addClass('Piwik_Popover_Error_Back');
|
||||
back.attr('href', '#').click(function () {
|
||||
history.back();
|
||||
return false;
|
||||
});
|
||||
error.append(back.html(backLabel));
|
||||
}
|
||||
|
||||
if (!isOpen) {
|
||||
openPopover();
|
||||
}
|
||||
|
||||
this.setContent(error);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a callback for the next time the popover is closed or the content changes
|
||||
*
|
||||
* @param {function} callback
|
||||
*/
|
||||
onClose: function (callback) {
|
||||
closeCallback = callback;
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the popover.
|
||||
*
|
||||
* Note: this method shouldn't normally be used to close a popover, instead
|
||||
* `broadcast.propagateNewPopoverHandler(false)` should be used.
|
||||
*/
|
||||
close: function () {
|
||||
if (isOpen) {
|
||||
isProgrammaticClose = true;
|
||||
container.dialog('close');
|
||||
isProgrammaticClose = false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a Popover and load the specified URL in it.
|
||||
*
|
||||
* Note: If you want the popover to be persisted in the URL (so if the URL is copy/pasted
|
||||
* to a new window/tab it will be opened there), use broadcast.propagateNewPopoverParameter
|
||||
* with a popover handler function that calls this one.
|
||||
*
|
||||
* @param {string} url
|
||||
* @param {string} loadingName
|
||||
* @param {string} [dialogClass] css class to add to dialog
|
||||
* @param {object} [ajaxRequest] optional instance of ajaxHelper
|
||||
*/
|
||||
createPopupAndLoadUrl: function (url, loadingName, dialogClass, ajaxRequest) {
|
||||
// make sure the minimum top position of the popover is 15px
|
||||
var ensureMinimumTop = function () {
|
||||
var popoverContainer = $('#Piwik_Popover').parent();
|
||||
if (popoverContainer.position().top < 106) {
|
||||
popoverContainer.css('top', '15px');
|
||||
}
|
||||
};
|
||||
|
||||
// open the popover
|
||||
var box = Piwik_Popover.showLoading(loadingName, null, null, dialogClass);
|
||||
ensureMinimumTop();
|
||||
|
||||
var callback = function (html) {
|
||||
function setPopoverTitleIfOneFoundInContainer() {
|
||||
var title = $('h1,h2', container);
|
||||
if (title.length == 1) {
|
||||
Piwik_Popover.setTitle(title.text());
|
||||
$(title).hide();
|
||||
}
|
||||
}
|
||||
|
||||
Piwik_Popover.setContent(html);
|
||||
setPopoverTitleIfOneFoundInContainer();
|
||||
ensureMinimumTop();
|
||||
};
|
||||
|
||||
if ('undefined' === typeof ajaxRequest) {
|
||||
ajaxRequest = new ajaxHelper();
|
||||
}
|
||||
ajaxRequest.addParams(piwikHelper.getArrayFromQueryString(url), 'get');
|
||||
ajaxRequest.setCallback(callback);
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send();
|
||||
}
|
||||
};
|
||||
})();
|
39
msd2/tracking/piwik/plugins/CoreHome/javascripts/require.js
Normal file
39
msd2/tracking/piwik/plugins/CoreHome/javascripts/require.js
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* Module creation & inclusion for Piwik.
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
(function (window) {
|
||||
|
||||
var MODULE_SPLIT_REGEX = /[\/.\\]/;
|
||||
|
||||
/**
|
||||
* Returns a module for its ID. Empty modules are created if they does not exist.
|
||||
*
|
||||
* Modules are currently stored in the window object.
|
||||
*
|
||||
* @param {String} moduleId e.g. 'piwik/UserCountryMap' or 'myPlugin/Widgets/FancySchmancyThing'.
|
||||
* The following characters can be used to separate individual modules:
|
||||
* '/', '.' or '\'.
|
||||
* @return {Object} The module object.
|
||||
*/
|
||||
window.require = function (moduleId) {
|
||||
var parts = moduleId.split(MODULE_SPLIT_REGEX);
|
||||
|
||||
// TODO: we use window objects for backwards compatibility. when rest of Piwik is rewritten to use
|
||||
// require, we can switch simply holding the modules in a private variable.
|
||||
var currentModule = window;
|
||||
for (var i = 0; i != parts.length; ++i) {
|
||||
var part = parts[i];
|
||||
|
||||
currentModule[part] = currentModule[part] || {};
|
||||
currentModule = currentModule[part];
|
||||
}
|
||||
return currentModule;
|
||||
};
|
||||
|
||||
})(window);
|
115
msd2/tracking/piwik/plugins/CoreHome/javascripts/sparkline.js
Normal file
115
msd2/tracking/piwik/plugins/CoreHome/javascripts/sparkline.js
Normal file
@ -0,0 +1,115 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
var sparklineColorNames = ['backgroundColor', 'lineColor', 'minPointColor', 'maxPointColor', 'lastPointColor', 'fillColor'];
|
||||
|
||||
var sparklineDisplayHeight = 25;
|
||||
var sparklineDisplayWidth = 100;
|
||||
|
||||
piwik.getSparklineColors = function () {
|
||||
return piwik.ColorManager.getColors('sparkline-colors', sparklineColorNames);
|
||||
};
|
||||
|
||||
// initializes each sparkline so they use colors defined in CSS
|
||||
piwik.initSparklines = function() {
|
||||
$('.sparkline > img').each(function () {
|
||||
var $self = $(this);
|
||||
|
||||
if ($self.attr('src')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var colors = JSON.stringify(piwik.getSparklineColors());
|
||||
var appendToSparklineUrl = '&colors=' + encodeURIComponent(colors);
|
||||
|
||||
// Append the token_auth to the URL if it was set (eg. embed dashboard)
|
||||
var token_auth = broadcast.getValueFromUrl('token_auth');
|
||||
if (token_auth.length && piwik.shouldPropagateTokenAuth) {
|
||||
appendToSparklineUrl += '&token_auth=' + token_auth;
|
||||
}
|
||||
$self.attr('width', sparklineDisplayWidth);
|
||||
$self.attr('height', sparklineDisplayHeight);
|
||||
$self.attr('src', $self.attr('data-src') + appendToSparklineUrl);
|
||||
});
|
||||
};
|
||||
|
||||
window.initializeSparklines = function () {
|
||||
var sparklineUrlParamsToIgnore = ['module', 'action', 'idSite', 'period', 'date', 'showtitle', 'viewDataTable', 'forceView', 'random'];
|
||||
|
||||
$('.dataTableVizEvolution[data-report]').each(function () {
|
||||
var graph = $(this);
|
||||
|
||||
// we search for .widget to make sure eg in the Dashboard to not update any graph of another report
|
||||
var selectorsToFindParent = ['.widget', '[piwik-widget-container]', '.reporting-page', 'body'];
|
||||
var index = 0, selector, parent;
|
||||
for (index; index < selectorsToFindParent.length; index++) {
|
||||
selector = selectorsToFindParent[index];
|
||||
parent = graph.parents(selector).first();
|
||||
if (parent && parent.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!parent || !parent.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var sparklines = parent.find('div.sparkline:not(.notLinkable)');
|
||||
|
||||
// try to find sparklines and add them clickable behaviour
|
||||
sparklines.each(function () {
|
||||
// find the sparkline and get it's src attribute
|
||||
var sparklineUrl = $('img', this).attr('data-src');
|
||||
|
||||
var $this = $(this);
|
||||
|
||||
if (sparklineUrl != "") {
|
||||
|
||||
$this.addClass('linked');
|
||||
|
||||
var params = broadcast.getValuesFromUrl(sparklineUrl);
|
||||
for (var i = 0; i != sparklineUrlParamsToIgnore.length; ++i) {
|
||||
delete params[sparklineUrlParamsToIgnore[i]];
|
||||
}
|
||||
for (var key in params) {
|
||||
if (typeof params[key] == 'undefined') {
|
||||
// this happens for example with an empty segment parameter
|
||||
delete params[key];
|
||||
} else {
|
||||
params[key] = decodeURIComponent(params[key]);
|
||||
}
|
||||
}
|
||||
|
||||
// on click, reload the graph with the new url
|
||||
$this.off('click.sparkline');
|
||||
$this.on('click.sparkline', function () {
|
||||
var reportId = graph.attr('data-report'),
|
||||
dataTable = graph;
|
||||
|
||||
// when the metrics picker is used, the id of the data table might be updated (which is correct behavior).
|
||||
// for example, in goal reports it might change from GoalsgetEvolutionGraph to GoalsgetEvolutionGraph1.
|
||||
// if this happens, we can't find the graph using $('#'+idDataTable+"Chart");
|
||||
// instead, we just use the first evolution graph we can find.
|
||||
if (dataTable.length == 0) {
|
||||
if ($(this).closest('.widget').length) {
|
||||
dataTable = $(this).closest('.widget').find('div.dataTableVizEvolution');
|
||||
} else {
|
||||
dataTable = $('div.dataTableVizEvolution');
|
||||
}
|
||||
}
|
||||
|
||||
// reload the datatable w/ a new column & scroll to the graph
|
||||
dataTable.trigger('reload', params);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
}(jQuery));
|
110
msd2/tracking/piwik/plugins/CoreHome/javascripts/top_controls.js
Normal file
110
msd2/tracking/piwik/plugins/CoreHome/javascripts/top_controls.js
Normal file
@ -0,0 +1,110 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
function initTopControls() {
|
||||
function getOverlap(element1, element2)
|
||||
{
|
||||
if (!element1 || !element1.getBoundingClientRect || !element2 || !element2.getBoundingClientRect) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var rect1 = element1.getBoundingClientRect();
|
||||
var rect2 = element2.getBoundingClientRect();
|
||||
|
||||
var doOverlap = !(rect1.right < rect2.left || rect1.left > rect2.right);
|
||||
|
||||
if (doOverlap) {
|
||||
return rect1.left - rect2.right;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
var $topControlsContainer = $('.top_controls');
|
||||
|
||||
var allRendered = true;
|
||||
|
||||
if ($topControlsContainer.length) {
|
||||
$topControlsContainer.find('.piwikTopControl').each(function () {
|
||||
var $control = $(this);
|
||||
if ($control.css('display') == 'none') {
|
||||
return;
|
||||
}
|
||||
|
||||
var width = $control.outerWidth(true);
|
||||
|
||||
var isControlFullyRendered = width >= 30;
|
||||
if (!isControlFullyRendered) {
|
||||
allRendered = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (allRendered) {
|
||||
// we make top controls visible only after all selectors are rendered
|
||||
$('.top_controls').css('visibility', 'visible');
|
||||
$('.top_controls').css('opacity', '1');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Keyboard controls for Top Controls Calendar through tab and enter.
|
||||
$( document ).ready(function() {
|
||||
$('.periodSelector').keydown(function(e){
|
||||
toggleCalendar(e);
|
||||
})
|
||||
|
||||
blockPropegation();
|
||||
|
||||
$('.periodSelector .form-radio').keydown(function(e){
|
||||
e.stopPropagation();
|
||||
if(e.which==13){
|
||||
selectPeriodRadioButton($(this));
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
//Keyboard controls for Top Controls Calendar through tab and enter.
|
||||
$( document ).ready(function() {
|
||||
$('.periodSelector').keydown(function(e){
|
||||
toggleCalendar(e);
|
||||
})
|
||||
|
||||
blockPropegation();
|
||||
|
||||
$('.periodSelector .form-radio').keydown(function(e){
|
||||
e.stopPropagation();
|
||||
if(e.which==13){
|
||||
selectPeriodRadioButton($(this));
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
function toggleCalendar(e){
|
||||
var calendarOpen = $('.periodSelector').hasClass('expanded');
|
||||
|
||||
if(e.which==13){
|
||||
if(calendarOpen){
|
||||
$('.periodSelector').removeClass('expanded');
|
||||
}else{
|
||||
$('.periodSelector').addClass('expanded');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function selectPeriodRadioButton(button){
|
||||
$('.periodSelector .form-radio').removeClass('checked');
|
||||
button.addClass('checked');
|
||||
button.find('input').click();
|
||||
|
||||
blockPropegation();
|
||||
}
|
||||
|
||||
function blockPropegation(){
|
||||
$('.ui-datepicker-month, .ui-datepicker-year, .periodSelector td a').keydown(function(e){
|
||||
e.stopPropagation();
|
||||
})
|
||||
}
|
124
msd2/tracking/piwik/plugins/CoreHome/javascripts/uiControl.js
Normal file
124
msd2/tracking/piwik/plugins/CoreHome/javascripts/uiControl.js
Normal file
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* Visitor profile popup control.
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
(function ($, require) {
|
||||
|
||||
var exports = require('piwik/UI');
|
||||
|
||||
/**
|
||||
* Base type for Piwik UI controls. Provides functionality that all controls need (such as
|
||||
* cleanup on destruction).
|
||||
*
|
||||
* @param {Element} element The root element of the control.
|
||||
*/
|
||||
var UIControl = function (element) {
|
||||
if (!element) {
|
||||
throw new Error("no element passed to UIControl constructor");
|
||||
}
|
||||
|
||||
this._controlId = UIControl._nextControlId++;
|
||||
UIControl._controls.push(this);
|
||||
|
||||
var $element = this.$element = $(element);
|
||||
$element.data('uiControlObject', this);
|
||||
|
||||
var params = JSON.parse($element.attr('data-params') || '{}');
|
||||
for (var key in params) { // convert values in params that are arrays to comma separated string lists
|
||||
if (params[key] instanceof Array) {
|
||||
params[key] = params[key].join(',');
|
||||
}
|
||||
}
|
||||
this.param = params;
|
||||
|
||||
this.props = JSON.parse($element.attr('data-props') || '{}');
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains all active control instances.
|
||||
*/
|
||||
UIControl._controls = [];
|
||||
|
||||
/**
|
||||
* Specifies the next unique control ID to use.
|
||||
*/
|
||||
UIControl._nextControlId = 0;
|
||||
|
||||
/**
|
||||
* Utility method that will clean up all piwik UI controls whose elements are not attached
|
||||
* to the DOM.
|
||||
*
|
||||
* TODO: instead of having other pieces of the UI manually calling cleanupUnusedControls,
|
||||
* MutationObservers should be used
|
||||
*/
|
||||
UIControl.cleanupUnusedControls = function () {
|
||||
var controls = UIControl._controls;
|
||||
// reset _controls; we will repopulate it with only active
|
||||
// controls in the loop below.
|
||||
var activeControls = UIControl._controls = [];
|
||||
|
||||
for (var i = 0; i != controls.length; ++i) {
|
||||
var control = controls[i];
|
||||
if (control
|
||||
&& control.$element
|
||||
&& !$.contains(document.documentElement, control.$element[0])
|
||||
) {
|
||||
controls[i] = null;
|
||||
control._destroy();
|
||||
|
||||
if (!control._baseDestroyCalled) {
|
||||
throw new Error("Error: " + control.constructor.name + "'s destroy method does not call " +
|
||||
"UIControl.destroy. You may have a memory leak.");
|
||||
}
|
||||
} else {
|
||||
// Control is still active / used.
|
||||
activeControls.push(control);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
UIControl.initElements = function (klass, selector) {
|
||||
$(selector).each(function () {
|
||||
if (!$(this).attr('data-inited')) {
|
||||
var control = new klass(this);
|
||||
$(this).attr('data-inited', 1);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
UIControl.prototype = {
|
||||
|
||||
/**
|
||||
* Perform cleanup. Called when the control has been removed from the DOM. Derived
|
||||
* classes should overload this function to perform their own cleanup.
|
||||
*/
|
||||
_destroy: function () {
|
||||
this.$element.removeData('uiControlObject');
|
||||
delete this.$element;
|
||||
|
||||
this._baseDestroyCalled = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle the widget resize event, if we're currently in a widget.
|
||||
*
|
||||
* TODO: should use proper resize detection (see
|
||||
* http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/ )
|
||||
* with timeouts (since resizing widgets can be expensive)
|
||||
*/
|
||||
onWidgetResize: function (handler) {
|
||||
var $widget = this.$element.closest('.widgetContent');
|
||||
$widget.on('widget:maximise', handler)
|
||||
.on('widget:minimise', handler)
|
||||
.on('widget:resize', handler);
|
||||
}
|
||||
};
|
||||
|
||||
exports.UIControl = UIControl;
|
||||
|
||||
})(jQuery, require);
|
36
msd2/tracking/piwik/plugins/CoreHome/javascripts/zen-mode.js
Normal file
36
msd2/tracking/piwik/plugins/CoreHome/javascripts/zen-mode.js
Normal file
@ -0,0 +1,36 @@
|
||||
$(function () {
|
||||
|
||||
angular.element(document).injector().invoke(handleZenMode);
|
||||
|
||||
function handleZenMode ($rootElement, $cookies) {
|
||||
var zenMode = !!parseInt($cookies.get('zenMode'), 10);
|
||||
var iconSwitcher = $('.top_controls .icon-arrowup');
|
||||
|
||||
iconSwitcher.click(function(event) {
|
||||
Mousetrap.trigger('z')
|
||||
});
|
||||
|
||||
function updateZenMode() {
|
||||
if (zenMode) {
|
||||
$('body').addClass('zenMode');
|
||||
iconSwitcher.addClass('icon-arrowdown').removeClass('icon-arrowup');
|
||||
iconSwitcher.prop('title', _pk_translate('CoreHome_ExitZenMode'));
|
||||
} else {
|
||||
$('body').removeClass('zenMode');
|
||||
iconSwitcher.removeClass('icon-arrowdown').addClass('icon-arrowup');
|
||||
iconSwitcher.prop('title', _pk_translate('CoreHome_EnterZenMode'));
|
||||
}
|
||||
}
|
||||
|
||||
piwikHelper.registerShortcut('z', _pk_translate('CoreHome_ShortcutZenMode'), function (event) {
|
||||
if (event.altKey) {
|
||||
return;
|
||||
}
|
||||
zenMode = !zenMode;
|
||||
$cookies.put('zenMode', zenMode ? '1' : '0');
|
||||
updateZenMode();
|
||||
});
|
||||
|
||||
updateZenMode();
|
||||
}
|
||||
});
|
Reference in New Issue
Block a user