PDF rausgenommen
This commit is contained in:
565
msd2/tracking/piwik/plugins/Morpheus/javascripts/ajaxHelper.js
Normal file
565
msd2/tracking/piwik/plugins/Morpheus/javascripts/ajaxHelper.js
Normal file
@ -0,0 +1,565 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* global ajax queue
|
||||
*
|
||||
* @type {Array} array holding XhrRequests with automatic cleanup
|
||||
*/
|
||||
var globalAjaxQueue = [];
|
||||
globalAjaxQueue.active = 0;
|
||||
|
||||
/**
|
||||
* Removes all finished requests from the queue.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
globalAjaxQueue.clean = function () {
|
||||
for (var i = this.length; i--;) {
|
||||
if (!this[i] || this[i].readyState == 4) {
|
||||
this.splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extend Array.push with automatic cleanup for finished requests
|
||||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
globalAjaxQueue.push = function () {
|
||||
this.active += arguments.length;
|
||||
|
||||
// cleanup ajax queue
|
||||
this.clean();
|
||||
|
||||
// call original array push
|
||||
return Array.prototype.push.apply(this, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Extend with abort function to abort all queued requests
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
globalAjaxQueue.abort = function () {
|
||||
// abort all queued requests
|
||||
for (var i = this.length; i--;) {
|
||||
this[i] && this[i].abort && this[i].abort(); // abort if possible
|
||||
}
|
||||
// remove all elements from array
|
||||
this.splice(0, this.length);
|
||||
|
||||
this.active = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Global ajax helper to handle requests within piwik
|
||||
*
|
||||
* @type {Object}
|
||||
* @constructor
|
||||
*/
|
||||
function ajaxHelper() {
|
||||
|
||||
/**
|
||||
* Format of response
|
||||
* @type {String}
|
||||
*/
|
||||
this.format = 'json';
|
||||
|
||||
/**
|
||||
* Should ajax request be asynchronous
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.async = true;
|
||||
|
||||
/**
|
||||
* A timeout for the request which will override any global timeout
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.timeout = null;
|
||||
|
||||
/**
|
||||
* Callback function to be executed on success
|
||||
*/
|
||||
this.callback = function () {};
|
||||
|
||||
/**
|
||||
* Use this.callback if an error is returned
|
||||
* @type {Boolean}
|
||||
*/
|
||||
this.useRegularCallbackInCaseOfError = false;
|
||||
|
||||
/**
|
||||
* Callback function to be executed on error
|
||||
*/
|
||||
this.errorCallback = this.defaultErrorCallback;
|
||||
|
||||
this.withToken = false;
|
||||
|
||||
/**
|
||||
* Callback function to be executed on complete (after error or success)
|
||||
*/
|
||||
this.completeCallback = function () {};
|
||||
|
||||
/**
|
||||
* Params to be passed as GET params
|
||||
* @type {Object}
|
||||
* @see ajaxHelper._mixinDefaultGetParams
|
||||
*/
|
||||
this.getParams = {};
|
||||
|
||||
/**
|
||||
* Base URL used in the AJAX request. Can be set by setUrl.
|
||||
*
|
||||
* It is set to '?' rather than 'index.php?' to increase chances that it works
|
||||
* including for users who have an automatic 301 redirection from index.php? to ?
|
||||
* POST values are missing when there is such 301 redirection. So by by-passing
|
||||
* this 301 redirection, we avoid this issue.
|
||||
*
|
||||
* @type {String}
|
||||
* @see ajaxHelper.setUrl
|
||||
*/
|
||||
this.getUrl = '?';
|
||||
|
||||
/**
|
||||
* Params to be passed as GET params
|
||||
* @type {Object}
|
||||
* @see ajaxHelper._mixinDefaultPostParams
|
||||
*/
|
||||
this.postParams = {};
|
||||
|
||||
/**
|
||||
* Element to be displayed while loading
|
||||
* @type {String}
|
||||
*/
|
||||
this.loadingElement = null;
|
||||
|
||||
/**
|
||||
* Element to be displayed on error
|
||||
* @type {String}
|
||||
*/
|
||||
this.errorElement = '#ajaxError';
|
||||
|
||||
/**
|
||||
* Handle for current request
|
||||
* @type {XMLHttpRequest}
|
||||
*/
|
||||
this.requestHandle = null;
|
||||
|
||||
this.defaultParams = ['idSite', 'period', 'date', 'segment'];
|
||||
|
||||
/**
|
||||
* Adds params to the request.
|
||||
* If params are given more then once, the latest given value is used for the request
|
||||
*
|
||||
* @param {object} params
|
||||
* @param {string} type type of given parameters (POST or GET)
|
||||
* @return {void}
|
||||
*/
|
||||
this.addParams = function (params, type) {
|
||||
if (typeof params == 'string') {
|
||||
params = broadcast.getValuesFromUrl(params);
|
||||
}
|
||||
|
||||
for (var key in params) {
|
||||
if(type.toLowerCase() == 'get') {
|
||||
this.getParams[key] = params[key];
|
||||
} else if(type.toLowerCase() == 'post') {
|
||||
this.postParams[key] = params[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.withTokenInUrl = function () {
|
||||
this.withToken = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the base URL to use in the AJAX request.
|
||||
*
|
||||
* @param {string} url
|
||||
*/
|
||||
this.setUrl = function (url) {
|
||||
this.addParams(broadcast.getValuesFromUrl(url), 'GET');
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets this helper instance ready to send a bulk request. Each argument to this
|
||||
* function is a single request to use.
|
||||
*/
|
||||
this.setBulkRequests = function () {
|
||||
var urls = [];
|
||||
for (var i = 0; i != arguments.length; ++i) {
|
||||
urls.push($.param(arguments[i]));
|
||||
}
|
||||
|
||||
this.addParams({
|
||||
module: 'API',
|
||||
method: 'API.getBulkRequest',
|
||||
urls: urls,
|
||||
format: 'json'
|
||||
}, 'post');
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a timeout (in milliseconds) for the request. This will override any global timeout.
|
||||
*
|
||||
* @param {integer} timeout Timeout in milliseconds
|
||||
* @return {void}
|
||||
*/
|
||||
this.setTimeout = function (timeout) {
|
||||
this.timeout = timeout;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the callback called after the request finishes
|
||||
*
|
||||
* @param {function} callback Callback function
|
||||
* @return {void}
|
||||
*/
|
||||
this.setCallback = function (callback) {
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set that the callback passed to setCallback() should be used if an application error (i.e. an
|
||||
* Exception in PHP) is returned.
|
||||
*/
|
||||
this.useCallbackInCaseOfError = function () {
|
||||
this.useRegularCallbackInCaseOfError = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set callback to redirect on success handler
|
||||
* &update=1(+x) will be appended to the current url
|
||||
*
|
||||
* @param {object} [params] to modify in redirect url
|
||||
* @return {void}
|
||||
*/
|
||||
this.redirectOnSuccess = function (params) {
|
||||
this.setCallback(function() {
|
||||
piwikHelper.redirect(params);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the callback called in case of an error within the request
|
||||
*
|
||||
* @param {function} callback Callback function
|
||||
* @return {void}
|
||||
*/
|
||||
this.setErrorCallback = function (callback) {
|
||||
this.errorCallback = callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the complete callback which is called after an error or success callback.
|
||||
*
|
||||
* @param {function} callback Callback function
|
||||
* @return {void}
|
||||
*/
|
||||
this.setCompleteCallback = function (callback) {
|
||||
this.completeCallback = callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* error callback to use by default
|
||||
*
|
||||
* @param deferred
|
||||
* @param status
|
||||
*/
|
||||
this.defaultErrorCallback = function(deferred, status)
|
||||
{
|
||||
// do not display error message if request was aborted
|
||||
if(status == 'abort') {
|
||||
return;
|
||||
}
|
||||
$('#loadingError').show();
|
||||
setTimeout( function(){
|
||||
$('#loadingError').fadeOut('slow');
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the response format for the request
|
||||
*
|
||||
* @param {string} format response format (e.g. json, html, ...)
|
||||
* @return {void}
|
||||
*/
|
||||
this.setFormat = function (format) {
|
||||
this.format = format;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the div element to show while request is loading
|
||||
*
|
||||
* @param {String} [element] selector for the loading element
|
||||
*/
|
||||
this.setLoadingElement = function (element) {
|
||||
if (!element) {
|
||||
element = '#ajaxLoadingDiv';
|
||||
}
|
||||
this.loadingElement = element;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the div element to show on error
|
||||
*
|
||||
* @param {String} element selector for the error element
|
||||
*/
|
||||
this.setErrorElement = function (element) {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
this.errorElement = element;
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect whether are allowed to use the given default parameter or not
|
||||
* @param string parameter
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
this._useGETDefaultParameter = function (parameter) {
|
||||
if (parameter && this.defaultParams) {
|
||||
var i;
|
||||
for (i = 0; i < this.defaultParams.length; i++) {
|
||||
if (this.defaultParams[i] === parameter) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a default parameter that is usually send automatically along the request.
|
||||
*
|
||||
* @param {String} parameter A name such as "period", "date", "segment".
|
||||
*/
|
||||
this.removeDefaultParameter = function (parameter) {
|
||||
if (parameter && this.defaultParams) {
|
||||
|
||||
var i;
|
||||
for (i = 0; i < this.defaultParams.length; i++) {
|
||||
if (this.defaultParams[i] === parameter) {
|
||||
this.defaultParams.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the request
|
||||
*
|
||||
* Note: Sending synchronous requests will be removed in Matomo 4
|
||||
*
|
||||
* @param {Boolean} [sync] indicates if the request should be synchronous (defaults to false)
|
||||
* @return {void}
|
||||
*/
|
||||
this.send = function (sync) {
|
||||
if (sync === true) {
|
||||
this.async = false;
|
||||
}
|
||||
|
||||
if ($(this.errorElement).length) {
|
||||
$(this.errorElement).hide();
|
||||
}
|
||||
|
||||
if (this.loadingElement) {
|
||||
$(this.loadingElement).fadeIn();
|
||||
}
|
||||
|
||||
this.requestHandle = this._buildAjaxCall();
|
||||
globalAjaxQueue.push(this.requestHandle);
|
||||
};
|
||||
|
||||
/**
|
||||
* Aborts the current request if it is (still) running
|
||||
* @return {void}
|
||||
*/
|
||||
this.abort = function () {
|
||||
if (this.requestHandle && typeof this.requestHandle.abort == 'function') {
|
||||
this.requestHandle.abort();
|
||||
this.requestHandle = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds and sends the ajax requests
|
||||
* @return {XMLHttpRequest}
|
||||
* @private
|
||||
*/
|
||||
this._buildAjaxCall = function () {
|
||||
var that = this;
|
||||
|
||||
var parameters = this._mixinDefaultGetParams(this.getParams);
|
||||
|
||||
var url = this.getUrl;
|
||||
if (url[url.length - 1] != '?') {
|
||||
url += '&';
|
||||
}
|
||||
|
||||
// we took care of encoding &segment properly already, so we don't use $.param for it ($.param URL encodes the values)
|
||||
if(parameters['segment']) {
|
||||
url += 'segment=' + parameters['segment'] + '&';
|
||||
delete parameters['segment'];
|
||||
}
|
||||
if(parameters['date']) {
|
||||
url += 'date=' + decodeURIComponent(parameters['date']) + '&';
|
||||
delete parameters['date'];
|
||||
}
|
||||
url += $.param(parameters);
|
||||
var ajaxCall = {
|
||||
type: 'POST',
|
||||
async: this.async !== false,
|
||||
url: url,
|
||||
dataType: this.format || 'json',
|
||||
complete: this.completeCallback,
|
||||
error: function () {
|
||||
--globalAjaxQueue.active;
|
||||
|
||||
if (that.errorCallback) {
|
||||
that.errorCallback.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
success: function (response, status, request) {
|
||||
if (that.loadingElement) {
|
||||
$(that.loadingElement).hide();
|
||||
}
|
||||
|
||||
if (response && response.result == 'error' && !that.useRegularCallbackInCaseOfError) {
|
||||
|
||||
var placeAt = null;
|
||||
var type = 'toast';
|
||||
if ($(that.errorElement).length && response.message) {
|
||||
$(that.errorElement).show();
|
||||
placeAt = that.errorElement;
|
||||
type = null;
|
||||
}
|
||||
|
||||
if (response.message) {
|
||||
|
||||
var UI = require('piwik/UI');
|
||||
var notification = new UI.Notification();
|
||||
notification.show(response.message, {
|
||||
placeat: placeAt,
|
||||
context: 'error',
|
||||
type: type,
|
||||
id: 'ajaxHelper'
|
||||
});
|
||||
notification.scrollToNotification();
|
||||
}
|
||||
|
||||
} else {
|
||||
that.callback(response, status, request);
|
||||
}
|
||||
|
||||
--globalAjaxQueue.active;
|
||||
var piwik = window.piwik;
|
||||
if (piwik
|
||||
&& piwik.ajaxRequestFinished
|
||||
) {
|
||||
piwik.ajaxRequestFinished();
|
||||
}
|
||||
},
|
||||
data: this._mixinDefaultPostParams(this.postParams)
|
||||
};
|
||||
|
||||
if (this.timeout !== null) {
|
||||
ajaxCall.timeout = this.timeout;
|
||||
}
|
||||
|
||||
return $.ajax(ajaxCall);
|
||||
};
|
||||
|
||||
this._isRequestToApiMethod = function () {
|
||||
return (this.getParams && this.getParams['module'] === 'API' && this.getParams['method']) ||
|
||||
(this.postParams && this.postParams['module'] === 'API' && this.postParams['method']);
|
||||
};
|
||||
|
||||
this._isWidgetizedRequest = function () {
|
||||
return (broadcast.getValueFromUrl('module') == 'Widgetize');
|
||||
};
|
||||
|
||||
this._getDefaultPostParams = function () {
|
||||
if (this.withToken || this._isRequestToApiMethod() || piwik.shouldPropagateTokenAuth) {
|
||||
return {
|
||||
token_auth: piwik.token_auth
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Mixin the default parameters to send as POST
|
||||
*
|
||||
* @param {object} params parameter object
|
||||
* @return {object}
|
||||
* @private
|
||||
*/
|
||||
this._mixinDefaultPostParams = function (params) {
|
||||
|
||||
var defaultParams = this._getDefaultPostParams();
|
||||
|
||||
for (var index in defaultParams) {
|
||||
|
||||
if (!params[index]) {
|
||||
|
||||
params[index] = defaultParams[index];
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mixin the default parameters to send as GET
|
||||
*
|
||||
* @param {object} params parameter object
|
||||
* @return {object}
|
||||
* @private
|
||||
*/
|
||||
this._mixinDefaultGetParams = function (params) {
|
||||
|
||||
if (window.location.hash) {
|
||||
var segment = broadcast.getValueFromHash('segment', window.location.href.split('#')[1]);
|
||||
} else {
|
||||
var segment = broadcast.getValueFromUrl('segment');
|
||||
}
|
||||
|
||||
var defaultParams = {
|
||||
idSite: piwik.idSite || broadcast.getValueFromUrl('idSite'),
|
||||
period: piwik.period || broadcast.getValueFromUrl('period'),
|
||||
segment: segment
|
||||
};
|
||||
|
||||
// never append token_auth to url
|
||||
if (params.token_auth) {
|
||||
params.token_auth = null;
|
||||
delete params.token_auth;
|
||||
}
|
||||
|
||||
for (var key in defaultParams) {
|
||||
if (this._useGETDefaultParameter(key) && !params[key] && !this.postParams[key] && defaultParams[key]) {
|
||||
params[key] = defaultParams[key];
|
||||
}
|
||||
}
|
||||
|
||||
// handle default date & period if not already set
|
||||
if (this._useGETDefaultParameter('date') && !params.date && !this.postParams.date) {
|
||||
params.date = piwik.currentDateString;
|
||||
}
|
||||
|
||||
return params;
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
23
msd2/tracking/piwik/plugins/Morpheus/javascripts/layout.js
Normal file
23
msd2/tracking/piwik/plugins/Morpheus/javascripts/layout.js
Normal file
@ -0,0 +1,23 @@
|
||||
/*!
|
||||
* 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 adjustSize(content)
|
||||
{
|
||||
var width = $('body').width() - content.offset().left - 16;
|
||||
content.css('width', width + 'px');
|
||||
}
|
||||
|
||||
var contentAdmin = $('#content.admin');
|
||||
|
||||
if (contentAdmin.length) {
|
||||
adjustSize(contentAdmin);
|
||||
$(window).resize(function () {
|
||||
adjustSize(contentAdmin);
|
||||
});
|
||||
}
|
||||
});
|
630
msd2/tracking/piwik/plugins/Morpheus/javascripts/piwikHelper.js
Normal file
630
msd2/tracking/piwik/plugins/Morpheus/javascripts/piwikHelper.js
Normal file
@ -0,0 +1,630 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
function _pk_translate(translationStringId, values) {
|
||||
|
||||
if( typeof(piwik_translations[translationStringId]) != 'undefined' ){
|
||||
var translation = piwik_translations[translationStringId];
|
||||
if (typeof values != 'undefined' && values && values.length) {
|
||||
values.unshift(translation);
|
||||
return sprintf.apply(null, values);
|
||||
}
|
||||
|
||||
return translation;
|
||||
}
|
||||
|
||||
return "The string "+translationStringId+" was not loaded in javascript. Make sure it is added in the Translate.getClientSideTranslationKeys hook.";
|
||||
}
|
||||
|
||||
var piwikHelper = {
|
||||
|
||||
htmlDecode: function(value)
|
||||
{
|
||||
var textArea = document.createElement('textarea');
|
||||
textArea.innerHTML = value;
|
||||
return textArea.value;
|
||||
},
|
||||
|
||||
sendContentAsDownload: function (filename, content, mimeType) {
|
||||
if (!mimeType) {
|
||||
mimeType = 'text/plain';
|
||||
}
|
||||
function downloadFile(content)
|
||||
{
|
||||
var node = document.createElement('a');
|
||||
node.style.display = 'none';
|
||||
if ('string' === typeof content) {
|
||||
node.setAttribute('href', 'data:' + mimeType + ';charset=utf-8,' + encodeURIComponent(content));
|
||||
} else {
|
||||
node.href = window.URL.createObjectURL(blob);
|
||||
}
|
||||
node.setAttribute('download', filename);
|
||||
document.body.appendChild(node);
|
||||
node.click();
|
||||
document.body.removeChild(node);
|
||||
}
|
||||
|
||||
var node;
|
||||
if ('function' === typeof Blob) {
|
||||
// browser supports blob
|
||||
try {
|
||||
var blob = new Blob([content], {type: mimeType});
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
window.navigator.msSaveBlob(blob, filename);
|
||||
return;
|
||||
} else {
|
||||
downloadFile(blob);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
downloadFile(content);
|
||||
}
|
||||
}
|
||||
downloadFile(content);
|
||||
},
|
||||
|
||||
/**
|
||||
* a nice cross-browser logging function
|
||||
*/
|
||||
log: function() {
|
||||
try {
|
||||
console.log.apply(console, arguments); // Firefox, Chrome
|
||||
} catch (e) {
|
||||
try {
|
||||
opera.postError.apply(opera, arguments); // Opera
|
||||
} catch (f) {
|
||||
// don't alert as log is not considered to be important enough
|
||||
// (as opposed to piwikHelper.error)
|
||||
//alert(Array.prototype.join.call(arguments, ' ')); // MSIE
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
error: function() {
|
||||
try {
|
||||
console.error.apply(console, arguments); // Firefox, Chrome
|
||||
} catch (e) {
|
||||
try {
|
||||
opera.postError.apply(opera, arguments); // Opera
|
||||
} catch (f) {
|
||||
alert(Array.prototype.join.call(arguments, ' ')); // MSIE
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
htmlEntities: function(value)
|
||||
{
|
||||
if (!value) {
|
||||
return value;
|
||||
}
|
||||
var findReplace = [[/&/g, "&"], [/</g, "<"], [/>/g, ">"], [/"/g, """], [/{{/g, '{⁣{']];
|
||||
for(var item in findReplace) {
|
||||
value = value.replace(findReplace[item][0], findReplace[item][1]);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
escape: function (value)
|
||||
{
|
||||
var escape = angular.element(document).injector().get('$sanitize');
|
||||
|
||||
return escape(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add break points to a string so that it can be displayed more compactly
|
||||
*/
|
||||
addBreakpoints: function(text, breakpointMarkup)
|
||||
{
|
||||
return text.replace(/([\/&=?\.%#:_-])/g, '$1' +
|
||||
(typeof breakpointMarkup == 'undefined' ? '<wbr>​' : breakpointMarkup));
|
||||
// ​ is for internet explorer
|
||||
},
|
||||
|
||||
/**
|
||||
* Add breakpoints to a URL
|
||||
* urldecodes and encodes htmlentities to display utf8 urls without XSS vulnerabilities
|
||||
*/
|
||||
addBreakpointsToUrl: function(url)
|
||||
{
|
||||
try {
|
||||
url = decodeURIComponent(url);
|
||||
} catch (e) {
|
||||
// might throw "URI malformed"
|
||||
}
|
||||
url = piwikHelper.addBreakpoints(url, '|||');
|
||||
url = $(document.createElement('p')).text(url).html();
|
||||
url = url.replace(/\|\|\|/g, '<wbr />​'); // ​ is for internet explorer
|
||||
return url;
|
||||
},
|
||||
|
||||
getAngularDependency: function (dependency) {
|
||||
return angular.element(document).injector().get(dependency);
|
||||
},
|
||||
|
||||
/**
|
||||
* As we still have a lot of old jQuery code and copy html from node to node we sometimes have to trigger the
|
||||
* compiling of angular components manually.
|
||||
*
|
||||
* @param selector
|
||||
* @param {object} options
|
||||
* @param {object} options.scope if supplied, the given scope will be used when compiling the template. Shouldn't
|
||||
* be a plain object but an actual angular scope.
|
||||
* @param {object} options.params if supplied, the properties in this object are
|
||||
* added to the new scope.
|
||||
*/
|
||||
compileAngularComponents: function (selector, options) {
|
||||
options = options || {};
|
||||
|
||||
var $element = $(selector);
|
||||
|
||||
if (!$element.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
angular.element(document).injector().invoke(function($compile, $rootScope) {
|
||||
var scope = null;
|
||||
if (options.scope) {
|
||||
scope = options.scope;
|
||||
} else if (!options.forceNewScope) { // TODO: docs
|
||||
scope = angular.element($element).scope();
|
||||
}
|
||||
if (!scope) {
|
||||
scope = $rootScope.$new(true);
|
||||
}
|
||||
|
||||
if (options.params) {
|
||||
$.extend(scope, options.params);
|
||||
}
|
||||
|
||||
$compile($element)(scope);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detection works currently only for directives defining an isolated scope. Functionality might need to be
|
||||
* extended if needed. Under circumstances you might call this method before calling compileAngularComponents()
|
||||
* to avoid compiling the same element twice.
|
||||
* @param selector
|
||||
*/
|
||||
isAlreadyCompiledAngularComponent: function (selector) {
|
||||
var $element = $(selector);
|
||||
|
||||
return ($element.length && $element.hasClass('ng-isolate-scope'));
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects whether angular is rendering the page. If so, the page will be reloaded automatically
|
||||
* via angular as soon as it detects a $locationChange
|
||||
*
|
||||
* @returns {number|jQuery}
|
||||
*/
|
||||
isAngularRenderingThePage: function ()
|
||||
{
|
||||
return $('[piwik-reporting-page]').length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves an element further to the left by changing the left margin to make sure as much as possible of an element
|
||||
* is visible in the current viewport. The top position keeps unchanged.
|
||||
* @param elementToPosition
|
||||
*/
|
||||
setMarginLeftToBeInViewport: function (elementToPosition) {
|
||||
var availableWidth = $(window).width();
|
||||
$(elementToPosition).css('marginLeft', '0px');
|
||||
var offset = $(elementToPosition).offset();
|
||||
if (!offset) {
|
||||
return;
|
||||
}
|
||||
var leftPos = offset.left;
|
||||
if (leftPos < 0) {
|
||||
leftPos = 0;
|
||||
}
|
||||
var widthSegmentForm = $(elementToPosition).outerWidth();
|
||||
if (leftPos + widthSegmentForm > availableWidth) {
|
||||
var extraSpaceForMoreBeauty = 16;
|
||||
var newLeft = availableWidth - widthSegmentForm - extraSpaceForMoreBeauty;
|
||||
if (newLeft < extraSpaceForMoreBeauty) {
|
||||
newLeft = extraSpaceForMoreBeauty;
|
||||
}
|
||||
var marginLeft = Math.abs(leftPos - newLeft);
|
||||
if (marginLeft > extraSpaceForMoreBeauty) {
|
||||
// we only move it further to the left if it is actually more than 16px to the left.
|
||||
// otherwise it is not really worth it and doesn't look as good.
|
||||
$(elementToPosition).css('marginLeft', (parseInt(marginLeft, 10) * -1) + 'px');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays a Modal dialog. Text will be taken from the DOM node domSelector.
|
||||
* Given callback handles will be mapped to the buttons having a role attribute
|
||||
*
|
||||
* Dialog will be closed when a button is clicked and callback handle will be
|
||||
* called, if one was given for the clicked role
|
||||
*
|
||||
* @param {string} domSelector domSelector for modal window
|
||||
* @param {object} handles callback functions for available roles
|
||||
* @param {object} options options for modal
|
||||
* @return {void}
|
||||
*/
|
||||
modalConfirm: function(domSelector, handles, options)
|
||||
{
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
var domElem = $(domSelector);
|
||||
var buttons = [];
|
||||
|
||||
var content = '<div class="modal"><div class="modal-content"></div>';
|
||||
content += '<div class="modal-footer"></div></div>';
|
||||
|
||||
var $content = $(content).hide();
|
||||
var $footer = $content.find('.modal-footer');
|
||||
|
||||
$('[role]', domElem).each(function(){
|
||||
var $button = $(this);
|
||||
var role = $button.attr('role');
|
||||
var title = $button.attr('title');
|
||||
var text = $button.val();
|
||||
$button.hide();
|
||||
|
||||
var button = $('<a href="javascript:;" class="modal-action modal-close waves-effect waves-light btn-flat "></a>');
|
||||
button.text(text);
|
||||
if (title) {
|
||||
button.attr('title', title);
|
||||
}
|
||||
|
||||
if (typeof handles !== 'undefined' && typeof handles[role] == 'function') {
|
||||
button.on('click', function(){
|
||||
handles[role].apply()
|
||||
});
|
||||
}
|
||||
if (typeof $button.data('href') !== 'undefined') {
|
||||
button.on('click', function () {
|
||||
window.location.href = $button.data('href');
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
$footer.append(button);
|
||||
});
|
||||
|
||||
$('body').append($content);
|
||||
$content.find('.modal-content').append(domElem);
|
||||
|
||||
if (options && options.fixedFooter) {
|
||||
$content.addClass('modal-fixed-footer');
|
||||
delete options.fixedFooter;
|
||||
}
|
||||
|
||||
if (options && options.extraWide) {
|
||||
// if given, the modal will be shown larger than usual and almost consume the full width.
|
||||
$content.addClass('modal-extra-wide');
|
||||
delete options.extraWide;
|
||||
}
|
||||
|
||||
if (options && !options.ready) {
|
||||
options.ready = function () {
|
||||
$(".modal.open a").focus();
|
||||
var modalContent = $(".modal.open");
|
||||
if (modalContent && modalContent[0]) {
|
||||
// make sure to scroll to the top of the content
|
||||
modalContent[0].scrollTop = 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
domElem.show();
|
||||
$content.openModal(options);
|
||||
},
|
||||
|
||||
getQueryStringWithParametersModified: function (queryString, newParameters) {
|
||||
if (queryString != '') {
|
||||
var r, i, keyvalue, keysvalues = newParameters.split('&');
|
||||
var appendUrl = '';
|
||||
for (i = 0; i < keysvalues.length; i++) {
|
||||
keyvalue = keysvalues[i].split('=');
|
||||
r = new RegExp('(^|[?&])' + keyvalue[0] + '=[^&]*');
|
||||
queryString = queryString.replace(r, '');
|
||||
|
||||
// empty value, eg. &segment=, we remove the parameter from URL entirely
|
||||
if (keyvalue[1].length == 0) {
|
||||
continue;
|
||||
}
|
||||
appendUrl += '&' + keyvalue[0] + '=' + keyvalue[1];
|
||||
}
|
||||
queryString += appendUrl;
|
||||
if (queryString[0] == '&') {
|
||||
queryString = '?' + queryString.substring(1);
|
||||
}
|
||||
} else {
|
||||
queryString = '?' + newParameters;
|
||||
}
|
||||
|
||||
return queryString;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the current query string with the given parameters modified
|
||||
* @param {String} newparams parameters to be modified
|
||||
* @return {String}
|
||||
*/
|
||||
getCurrentQueryStringWithParametersModified: function(newparams)
|
||||
{
|
||||
var queryString = String(window.location.search);
|
||||
if (newparams) {
|
||||
queryString = this.getQueryStringWithParametersModified(queryString, newparams);
|
||||
}
|
||||
return String(window.location.pathname) + queryString;
|
||||
},
|
||||
|
||||
/**
|
||||
* Given param1=v1¶m2=k2
|
||||
* returns: { "param1": "v1", "param2": "v2" }
|
||||
*
|
||||
* @param query string
|
||||
* @return {Object}
|
||||
*/
|
||||
getArrayFromQueryString: function (query) {
|
||||
var params = {};
|
||||
var vars = query.split("&");
|
||||
for (var i=0;i<vars.length;i++) {
|
||||
var keyValue = vars[i].split("=");
|
||||
// Jquery will urlencode these, but we wish to keep the current raw value
|
||||
// use case: &segment=visitorId%3D%3Dabc...
|
||||
params[keyValue[0]] = decodeURIComponent(keyValue[1]);
|
||||
}
|
||||
return params;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns query string for an object of key,values
|
||||
* Note: we don't use $.param from jquery as it doesn't return array values the PHP way (returns a=v1&a=v2 instead of a[]=v1&a[]=v2)
|
||||
* Example:
|
||||
* piwikHelper.getQueryStringFromParameters({"a":"va","b":["vb","vc"],"c":1})
|
||||
* Returns:
|
||||
* a=va&b[]=vb&b[]=vc&c=1
|
||||
* @param {object} parameters
|
||||
* @return {string}
|
||||
*/
|
||||
getQueryStringFromParameters: function(parameters)
|
||||
{
|
||||
var queryString = '';
|
||||
if(!parameters || parameters.length==0) {
|
||||
return queryString;
|
||||
}
|
||||
for(var name in parameters) {
|
||||
var value = parameters[name];
|
||||
if(typeof value == 'object') {
|
||||
for(var i in value) {
|
||||
queryString += name + '[]=' + value[i] + '&';
|
||||
}
|
||||
} else {
|
||||
queryString += name + '=' + value + '&';
|
||||
}
|
||||
}
|
||||
return queryString.substring(0, queryString.length-1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the given ajax error message within the given id element
|
||||
* @param {string} message error message
|
||||
* @param {string} errorDivID id of the domNode (defaults to ajaxError)
|
||||
* @return {void}
|
||||
*/
|
||||
showAjaxError: function( message, errorDivID )
|
||||
{
|
||||
errorDivID = errorDivID || 'ajaxError';
|
||||
$('#'+errorDivID).html(message).show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides the error message with the given id
|
||||
* @param {string} [errorDivID] id of the domNode (defaults to ajaxError)
|
||||
* @return {void}
|
||||
*/
|
||||
hideAjaxError: function(errorDivID)
|
||||
{
|
||||
errorDivID = errorDivID || 'ajaxError';
|
||||
$('#'+errorDivID).hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the loading message with the given Id
|
||||
* @param {string} [loadingDivID] id of the domNode (defaults to ajaxLoading)
|
||||
* @return {void}
|
||||
*/
|
||||
showAjaxLoading: function(loadingDivID)
|
||||
{
|
||||
loadingDivID = loadingDivID || 'ajaxLoadingDiv';
|
||||
$('#'+loadingDivID).show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides the loading message with the given id
|
||||
* @param {string} [loadingDivID] id of the domNode (defaults to ajaxLoading)
|
||||
* @return {void}
|
||||
*/
|
||||
hideAjaxLoading: function(loadingDivID)
|
||||
{
|
||||
loadingDivID = loadingDivID || 'ajaxLoadingDiv';
|
||||
$('#'+loadingDivID).hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Reloads the page after the given period
|
||||
* @param {int} timeoutPeriod
|
||||
* @return void
|
||||
*/
|
||||
refreshAfter: function(timeoutPeriod)
|
||||
{
|
||||
if(timeoutPeriod == 0) {
|
||||
location.reload();
|
||||
} else {
|
||||
setTimeout("location.reload();",timeoutPeriod);
|
||||
}
|
||||
},
|
||||
|
||||
redirect: function (params) {
|
||||
// add updated=X to the URL so that a "Your changes have been saved" message is displayed
|
||||
if (typeof params == 'object') {
|
||||
params = this.getQueryStringFromParameters(params);
|
||||
}
|
||||
var urlToRedirect = this.getCurrentQueryStringWithParametersModified(params);
|
||||
var updatedUrl = new RegExp('&updated=([0-9]+)');
|
||||
var updatedCounter = updatedUrl.exec(urlToRedirect);
|
||||
if (!updatedCounter) {
|
||||
urlToRedirect += '&updated=1';
|
||||
} else {
|
||||
updatedCounter = 1 + parseInt(updatedCounter[1]);
|
||||
urlToRedirect = urlToRedirect.replace(new RegExp('(&updated=[0-9]+)'), '&updated=' + updatedCounter);
|
||||
}
|
||||
var currentHashStr = window.location.hash;
|
||||
if(currentHashStr.length > 0) {
|
||||
urlToRedirect += currentHashStr;
|
||||
}
|
||||
this.redirectToUrl(urlToRedirect);
|
||||
},
|
||||
|
||||
/**
|
||||
* Redirect to the given url
|
||||
* @param {string} url
|
||||
*/
|
||||
redirectToUrl: function(url)
|
||||
{
|
||||
window.location = url;
|
||||
},
|
||||
|
||||
lazyScrollToContent: function () {
|
||||
this.lazyScrollTo('#content', 250);
|
||||
},
|
||||
|
||||
/**
|
||||
* Scrolls the window to the jquery element 'elem'
|
||||
* if the top of the element is not currently visible on screen
|
||||
* @param {string} elem Selector for the DOM node to scroll to, eg. '#myDiv'
|
||||
* @param {int} [time] Specifies the duration of the animation in ms
|
||||
* @param {boolean} [forceScroll] Whether to force scroll to an element.
|
||||
* @return {void}
|
||||
*/
|
||||
lazyScrollTo: function(elem, time, forceScroll)
|
||||
{
|
||||
var $elem = $(elem);
|
||||
if (!$elem.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var elemTop = $elem.offset().top;
|
||||
// only scroll the page if the graph is not visible
|
||||
if (elemTop < $(window).scrollTop()
|
||||
|| elemTop > $(window).scrollTop()+$(window).height()
|
||||
|| forceScroll
|
||||
) {
|
||||
// scroll the page smoothly to the graph
|
||||
$.scrollTo(elem, time);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the filtered/converted content of a textarea to be used for api requests
|
||||
* @param {string} textareaContent
|
||||
* @return {string}
|
||||
*/
|
||||
getApiFormatTextarea: function (textareaContent) {
|
||||
if (typeof textareaContent == 'undefined') {
|
||||
return '';
|
||||
}
|
||||
return textareaContent.trim().split("\n").join(',');
|
||||
},
|
||||
|
||||
shortcuts: {},
|
||||
|
||||
/**
|
||||
* Register a shortcut
|
||||
*
|
||||
* @param {string} key key-stroke to be registered for this shortcut
|
||||
* @param {string } description description to be shown in summary
|
||||
* @param callback method called when pressing the key
|
||||
*/
|
||||
registerShortcut: function(key, description, callback) {
|
||||
|
||||
piwikHelper.shortcuts[key] = description;
|
||||
|
||||
Mousetrap.bind(key, callback);
|
||||
},
|
||||
|
||||
calculateEvolution: function (currentValue, pastValue) {
|
||||
var dividend = currentValue - pastValue;
|
||||
var divisor = pastValue;
|
||||
|
||||
if (dividend == 0) {
|
||||
return 0;
|
||||
} else if (divisor == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return Math.round((dividend / divisor) * 1000) / 1000;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (typeof String.prototype.trim !== 'function') {
|
||||
String.prototype.trim = function() {
|
||||
return this.replace(/^\s+|\s+$/g,"");
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Returns true if the event keypress passed in parameter is the ENTER key
|
||||
* @param {Event} e current window event
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isEnterKey(e)
|
||||
{
|
||||
return (window.event?window.event.keyCode:e.which)==13;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the event keypress passed in parameter is the ESCAPE key
|
||||
* @param {Event} e current window event
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isEscapeKey(e)
|
||||
{
|
||||
return (window.event?window.event.keyCode:e.which)==27;
|
||||
}
|
||||
|
||||
// workarounds
|
||||
(function($){
|
||||
try {
|
||||
// this code is not vital, so we make sure any errors are ignored
|
||||
|
||||
//--------------------------------------
|
||||
//
|
||||
// monkey patch that works around bug in arc function of some browsers where
|
||||
// nothing gets drawn if angles are 2 * PI apart and in counter-clockwise direction.
|
||||
// affects some versions of chrome & IE 8
|
||||
//
|
||||
//--------------------------------------
|
||||
var oldArc = CanvasRenderingContext2D.prototype.arc;
|
||||
CanvasRenderingContext2D.prototype.arc = function(x, y, r, sAngle, eAngle, clockwise) {
|
||||
if (Math.abs(eAngle - sAngle - Math.PI * 2) < 0.000001 && !clockwise)
|
||||
eAngle -= 0.000001;
|
||||
oldArc.call(this, x, y, r, sAngle, eAngle, clockwise);
|
||||
};
|
||||
|
||||
// Fix jQuery UI dialogs scrolling when click on links with tooltips
|
||||
jQuery.ui.dialog.prototype._focusTabbable = $.noop;
|
||||
|
||||
// Fix jQuery UI tooltip displaying when dialog is closed by Esc key
|
||||
jQuery(document).keyup(function(e) {
|
||||
if (e.keyCode == 27) {
|
||||
$('.ui-tooltip').hide();
|
||||
}
|
||||
});
|
||||
|
||||
} catch (e) {}
|
||||
}(jQuery));
|
Reference in New Issue
Block a user