PDF rausgenommen
This commit is contained in:
317
msd2/tracking/piwik/plugins/Dashboard/javascripts/dashboard.js
Normal file
317
msd2/tracking/piwik/plugins/Dashboard/javascripts/dashboard.js
Normal file
@ -0,0 +1,317 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
function createDashboard() {
|
||||
$(makeSelectorLastId('createDashboardName')).val('');
|
||||
|
||||
piwikHelper.modalConfirm(makeSelectorLastId('createDashboardConfirm'), {yes: function () {
|
||||
var dashboardName = $(makeSelectorLastId('createDashboardName')).val();
|
||||
var addDefaultWidgets = ($('[id=dashboard_type_empty]:last:checked').length > 0) ? 0 : 1;
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.setLoadingElement();
|
||||
ajaxRequest.withTokenInUrl();
|
||||
ajaxRequest.addParams({
|
||||
module: 'API',
|
||||
method: 'Dashboard.createNewDashboardForUser',
|
||||
format: 'json'
|
||||
}, 'get');
|
||||
ajaxRequest.addParams({
|
||||
dashboardName: encodeURIComponent(dashboardName),
|
||||
addDefaultWidgets: addDefaultWidgets,
|
||||
login: piwik.userLogin
|
||||
}, 'post');
|
||||
ajaxRequest.setCallback(
|
||||
function (response) {
|
||||
var id = response.value;
|
||||
angular.element(document).injector().invoke(function ($location, reportingMenuModel, dashboardsModel) {
|
||||
dashboardsModel.reloadAllDashboards().then(function () {
|
||||
|
||||
$('#dashboardWidgetsArea').dashboard('loadDashboard', id);
|
||||
$('#dashboardWidgetsArea').dashboard('rebuildMenu');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
ajaxRequest.send();
|
||||
}});
|
||||
}
|
||||
|
||||
function makeSelectorLastId(domElementId)
|
||||
{
|
||||
// there can be many elements with this id, we prefer the last one
|
||||
return '[id=' + domElementId + ']:last';
|
||||
}
|
||||
|
||||
function resetDashboard() {
|
||||
piwikHelper.modalConfirm(makeSelectorLastId('resetDashboardConfirm'), {yes:
|
||||
function () { $('#dashboardWidgetsArea').dashboard('resetLayout');
|
||||
}});
|
||||
}
|
||||
|
||||
function renameDashboard() {
|
||||
$(makeSelectorLastId('newDashboardName')).val($('#dashboardWidgetsArea').dashboard('getDashboardName'));
|
||||
|
||||
piwikHelper.modalConfirm(makeSelectorLastId('renameDashboardConfirm'), {yes: function () {
|
||||
var newDashboardName = $(makeSelectorLastId('newDashboardName')).val();
|
||||
$('#dashboardWidgetsArea').dashboard('setDashboardName', newDashboardName);
|
||||
}});
|
||||
}
|
||||
|
||||
function removeDashboard() {
|
||||
$(makeSelectorLastId('removeDashboardConfirm')).find('h2 span').text($('#dashboardWidgetsArea').dashboard('getDashboardName'));
|
||||
|
||||
piwikHelper.modalConfirm(makeSelectorLastId('removeDashboardConfirm'), {yes: function () {
|
||||
$('#dashboardWidgetsArea').dashboard('removeDashboard');
|
||||
}});
|
||||
}
|
||||
|
||||
function showChangeDashboardLayoutDialog() {
|
||||
$('#columnPreview').find('>div').removeClass('choosen');
|
||||
$('#columnPreview').find('>div[layout=' + $('#dashboardWidgetsArea').dashboard('getColumnLayout') + ']').addClass('choosen');
|
||||
|
||||
var id = makeSelectorLastId('changeDashboardLayout');
|
||||
piwikHelper.modalConfirm(id, {yes: function () {
|
||||
var layout = $(id).find('.choosen').attr('layout');
|
||||
$('#dashboardWidgetsArea').dashboard('setColumnLayout', layout);
|
||||
}}, {fixedFooter: true});
|
||||
}
|
||||
|
||||
function showEmptyDashboardNotification() {
|
||||
piwikHelper.modalConfirm(makeSelectorLastId('dashboardEmptyNotification'), {
|
||||
resetDashboard: function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); },
|
||||
addWidget: function () { $('.dashboardSettings > a').trigger('click'); }
|
||||
});
|
||||
}
|
||||
|
||||
function setAsDefaultWidgets() {
|
||||
piwikHelper.modalConfirm(makeSelectorLastId('setAsDefaultWidgetsConfirm'), {
|
||||
yes: function () {
|
||||
$('#dashboardWidgetsArea').dashboard('saveLayoutAsDefaultWidgetLayout');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function copyDashboardToUser() {
|
||||
$(makeSelectorLastId('copyDashboardName')).val($('#dashboardWidgetsArea').dashboard('getDashboardName'));
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'API',
|
||||
method: 'UsersManager.getUsers',
|
||||
format: 'json',
|
||||
filter_limit: '-1'
|
||||
}, 'get');
|
||||
ajaxRequest.setCallback(
|
||||
function (availableUsers) {
|
||||
$(makeSelectorLastId('copyDashboardUser')).empty();
|
||||
$(makeSelectorLastId('copyDashboardUser')).append(
|
||||
$('<option></option>').val(piwik.userLogin).text(piwik.userLogin)
|
||||
);
|
||||
$.each(availableUsers, function (index, user) {
|
||||
if (user.login != 'anonymous' && user.login != piwik.userLogin) {
|
||||
$(makeSelectorLastId('copyDashboardUser')).append(
|
||||
$('<option></option>').val(user.login).text(user.login + ' (' + user.alias + ')')
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
ajaxRequest.send();
|
||||
|
||||
piwikHelper.modalConfirm(makeSelectorLastId('copyDashboardToUserConfirm'), {
|
||||
yes: function () {
|
||||
var copyDashboardName = $(makeSelectorLastId('copyDashboardName')).val();
|
||||
var copyDashboardUser = $(makeSelectorLastId('copyDashboardUser')).val();
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'API',
|
||||
method: 'Dashboard.copyDashboardToUser',
|
||||
format: 'json'
|
||||
}, 'get');
|
||||
ajaxRequest.addParams({
|
||||
dashboardName: encodeURIComponent(copyDashboardName),
|
||||
idDashboard: $('#dashboardWidgetsArea').dashboard('getDashboardId'),
|
||||
copyToUser: encodeURIComponent(copyDashboardUser)
|
||||
}, 'post');
|
||||
ajaxRequest.setCallback(
|
||||
function (response) {
|
||||
$('#alert').find('h2').text(_pk_translate('Dashboard_DashboardCopied'));
|
||||
piwikHelper.modalConfirm('#alert', {});
|
||||
}
|
||||
);
|
||||
ajaxRequest.withTokenInUrl();
|
||||
ajaxRequest.send();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
(function () {
|
||||
var exports = window.require('piwik/UI');
|
||||
var UIControl = exports.UIControl;
|
||||
|
||||
/**
|
||||
* Contains logic common to all dashboard management controls. This is the JavaScript analog of
|
||||
* the DashboardSettingsControlBase PHP class.
|
||||
*
|
||||
* @param {Element} element The HTML element generated by the SegmentSelectorControl PHP class. Should
|
||||
* have the CSS class 'segmentEditorPanel'.
|
||||
* @constructor
|
||||
*/
|
||||
var DashboardSettingsControlBase = function (element) {
|
||||
UIControl.call(this, element);
|
||||
|
||||
// on menu item click, trigger action event on this
|
||||
var self = this;
|
||||
this.$element.on('click', 'ul.submenu li[data-action]', function (e) {
|
||||
if (!$(this).attr('disabled')) {
|
||||
self.$element.removeClass('expanded');
|
||||
$(self).trigger($(this).attr('data-action'));
|
||||
}
|
||||
});
|
||||
|
||||
// open manager on open
|
||||
this.$element.on('click', function (e) {
|
||||
if ($(e.target).is('.dashboardSettings') || $(e.target).closest('.dashboardSettings').length) {
|
||||
self.onOpen();
|
||||
}
|
||||
});
|
||||
|
||||
// handle manager close
|
||||
this.onBodyMouseUp = function (e) {
|
||||
if (!$(e.target).closest('.dashboardSettings').length
|
||||
&& !$(e.target).is('.dashboardSettings')
|
||||
) {
|
||||
self.$element.widgetPreview('reset');
|
||||
self.$element.removeClass('expanded');
|
||||
}
|
||||
};
|
||||
|
||||
$('body').on('mouseup', this.onBodyMouseUp);
|
||||
|
||||
// setup widgetPreview
|
||||
this.$element.widgetPreview({
|
||||
isWidgetAvailable: function (widgetUniqueId) {
|
||||
return self.isWidgetAvailable(widgetUniqueId);
|
||||
},
|
||||
onSelect: function (widgetUniqueId) {
|
||||
widgetsHelper.getWidgetObjectFromUniqueId(widgetUniqueId, function(widget){
|
||||
self.$element.removeClass('expanded');
|
||||
self.widgetSelected(widget);
|
||||
});
|
||||
|
||||
},
|
||||
resetOnSelect: true
|
||||
});
|
||||
|
||||
// on enter widget list category, reset widget preview
|
||||
this.$element.on('mouseenter', '.submenu > li', function (event) {
|
||||
if (!$('.widgetpreview-categorylist', event.target).length) {
|
||||
self.$element.widgetPreview('reset');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.extend(DashboardSettingsControlBase.prototype, UIControl.prototype, {
|
||||
_destroy: function () {
|
||||
UIControl.prototype._destroy.call(this);
|
||||
|
||||
$('body').off('mouseup', null, this.onBodyMouseUp);
|
||||
}
|
||||
});
|
||||
|
||||
exports.DashboardSettingsControlBase = DashboardSettingsControlBase;
|
||||
|
||||
/**
|
||||
* Sets up and handles events for the dashboard manager control.
|
||||
*
|
||||
* @param {Element} element The HTML element generated by the SegmentSelectorControl PHP class. Should
|
||||
* have the CSS class 'segmentEditorPanel'.
|
||||
* @constructor
|
||||
*/
|
||||
var DashboardManagerControl = function (element) {
|
||||
DashboardSettingsControlBase.call(this, element);
|
||||
|
||||
$(this).on('resetDashboard', function () {
|
||||
this.hide();
|
||||
resetDashboard();
|
||||
});
|
||||
|
||||
$(this).on('showChangeDashboardLayoutDialog', function () {
|
||||
this.hide();
|
||||
showChangeDashboardLayoutDialog();
|
||||
});
|
||||
|
||||
$(this).on('renameDashboard', function () {
|
||||
this.hide();
|
||||
renameDashboard();
|
||||
});
|
||||
|
||||
$(this).on('removeDashboard', function () {
|
||||
this.hide();
|
||||
removeDashboard();
|
||||
});
|
||||
|
||||
$(this).on('setAsDefaultWidgets', function () {
|
||||
this.hide();
|
||||
setAsDefaultWidgets();
|
||||
});
|
||||
|
||||
$(this).on('copyDashboardToUser', function () {
|
||||
this.hide();
|
||||
copyDashboardToUser();
|
||||
});
|
||||
|
||||
$(this).on('createDashboard', function () {
|
||||
this.hide();
|
||||
createDashboard();
|
||||
});
|
||||
};
|
||||
|
||||
$.extend(DashboardManagerControl.prototype, DashboardSettingsControlBase.prototype, {
|
||||
onOpen: function () {
|
||||
if ($('#dashboardWidgetsArea').dashboard('isDefaultDashboard')) {
|
||||
$('[data-action=removeDashboard]', this.$element).attr('disabled', 'disabled');
|
||||
$(this.$element).tooltip({
|
||||
items: '[data-action=removeDashboard]',
|
||||
show: false,
|
||||
hide: false,
|
||||
track: true,
|
||||
content: function() {
|
||||
return _pk_translate('Dashboard_RemoveDefaultDashboardNotPossible')
|
||||
},
|
||||
tooltipClass: 'small'
|
||||
});
|
||||
} else {
|
||||
$('[data-action=removeDashboard]', this.$element).removeAttr('disabled');
|
||||
// try to remove tooltip if any
|
||||
try {
|
||||
$(this.$element).tooltip('destroy');
|
||||
} catch (e) { }
|
||||
}
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
this.$element.removeClass('expanded');
|
||||
},
|
||||
|
||||
isWidgetAvailable: function (widgetUniqueId) {
|
||||
return !$('#dashboardWidgetsArea').find('[widgetId="' + widgetUniqueId + '"]').length;
|
||||
},
|
||||
|
||||
widgetSelected: function (widget) {
|
||||
$('#dashboardWidgetsArea').dashboard('addWidget', widget.uniqueId, 1, widget.parameters, true, false);
|
||||
}
|
||||
});
|
||||
|
||||
DashboardManagerControl.initElements = function () {
|
||||
UIControl.initElements(this, '.dashboard-manager');
|
||||
$('.top_controls .dashboard-manager').hide(); // initially hide the manager
|
||||
};
|
||||
|
||||
exports.DashboardManagerControl = DashboardManagerControl;
|
||||
}());
|
@ -0,0 +1,670 @@
|
||||
/*!
|
||||
* 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 layoutColumnSelector = '#dashboardWidgetsArea > .col';
|
||||
|
||||
/**
|
||||
* Current dashboard column layout
|
||||
* @type {object}
|
||||
*/
|
||||
var dashboardLayout = {};
|
||||
/**
|
||||
* Id of current dashboard
|
||||
* @type {int}
|
||||
*/
|
||||
var dashboardId = 1;
|
||||
/**
|
||||
* Name of current dashboard
|
||||
* @type {string}
|
||||
*/
|
||||
var dashboardName = '';
|
||||
/**
|
||||
* Holds a reference to the dashboard element
|
||||
* @type {object}
|
||||
*/
|
||||
var dashboardElement = null;
|
||||
/**
|
||||
* Boolean indicating wether the layout config has been changed or not
|
||||
* @type {boolean}
|
||||
*/
|
||||
var dashboardChanged = false;
|
||||
|
||||
/**
|
||||
* public methods of dashboard plugin
|
||||
* all methods defined here are accessible with $(selector).dashboard('method', param, param, ...)
|
||||
*/
|
||||
var methods = {
|
||||
|
||||
/**
|
||||
* creates a dashboard object
|
||||
*
|
||||
* @param {object} options
|
||||
*/
|
||||
init: function (options) {
|
||||
|
||||
dashboardElement = this;
|
||||
|
||||
if (options.idDashboard) {
|
||||
dashboardId = options.idDashboard;
|
||||
}
|
||||
|
||||
if (options.name) {
|
||||
dashboardName = options.name;
|
||||
}
|
||||
|
||||
if (options.layout) {
|
||||
generateLayout(options.layout);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroys the dashboard object and all its childrens
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
destroy: function () {
|
||||
$(dashboardElement).remove();
|
||||
dashboardElement = null;
|
||||
destroyWidgets();
|
||||
},
|
||||
|
||||
destroyWidgets: destroyWidgets,
|
||||
|
||||
/**
|
||||
* Load dashboard with the given id
|
||||
*
|
||||
* @param {int} dashboardIdToLoad
|
||||
*/
|
||||
loadDashboard: function (dashboardIdToLoad, forceReload) {
|
||||
|
||||
$(dashboardElement).empty();
|
||||
dashboardName = '';
|
||||
dashboardLayout = null;
|
||||
dashboardId = dashboardIdToLoad;
|
||||
|
||||
if (!forceReload && piwikHelper.isAngularRenderingThePage()) {
|
||||
angular.element(document).injector().invoke(function ($location) {
|
||||
$location.search('subcategory', '' + dashboardIdToLoad);
|
||||
});
|
||||
} else {
|
||||
var element = $('[piwik-dashboard]');
|
||||
var scope = angular.element(element).scope();
|
||||
scope.fetchDashboard(dashboardIdToLoad);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Change current column layout to the given one
|
||||
*
|
||||
* @param {String} newLayout
|
||||
*/
|
||||
setColumnLayout: function (newLayout) {
|
||||
adjustDashboardColumns(newLayout);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the current column layout
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
getColumnLayout: function () {
|
||||
return dashboardLayout.config.layout;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the current dashboard name
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
getDashboardName: function () {
|
||||
return dashboardName;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the current dashboard id
|
||||
*
|
||||
* @return {int}
|
||||
*/
|
||||
getDashboardId: function () {
|
||||
return dashboardId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets a new name for the current dashboard
|
||||
*
|
||||
* @param {String} newName
|
||||
*/
|
||||
setDashboardName: function (newName) {
|
||||
dashboardName = newName;
|
||||
dashboardChanged = true;
|
||||
saveLayout();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a new widget to the dashboard
|
||||
*
|
||||
* @param {String} uniqueId
|
||||
* @param {int} columnNumber
|
||||
* @param {object} widgetParameters
|
||||
* @param {boolean} addWidgetOnTop
|
||||
* @param {boolean} isHidden
|
||||
*/
|
||||
addWidget: function (uniqueId, columnNumber, widgetParameters, addWidgetOnTop, isHidden) {
|
||||
addWidgetTemplate(uniqueId, columnNumber, widgetParameters, addWidgetOnTop, isHidden);
|
||||
saveLayout();
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets the current layout to the defaults
|
||||
*/
|
||||
resetLayout: function () {
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: 'resetLayout',
|
||||
idDashboard: dashboardId
|
||||
}, 'get');
|
||||
ajaxRequest.withTokenInUrl();
|
||||
ajaxRequest.setCallback(
|
||||
function () {
|
||||
methods.loadDashboard.apply(this, [dashboardId, true])
|
||||
}
|
||||
);
|
||||
ajaxRequest.setLoadingElement();
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send();
|
||||
},
|
||||
|
||||
rebuildMenu: rebuildMenu,
|
||||
/**
|
||||
* Removes the current dashboard
|
||||
*/
|
||||
removeDashboard: function () {
|
||||
if (dashboardId == 1) {
|
||||
return; // dashboard with id 1 should never be deleted, as it is the default
|
||||
}
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.setLoadingElement();
|
||||
ajaxRequest.addParams({
|
||||
module: 'API',
|
||||
method: 'Dashboard.removeDashboard',
|
||||
idDashboard: dashboardId,
|
||||
login: piwik.userLogin,
|
||||
format: 'json'
|
||||
}, 'get');
|
||||
ajaxRequest.setCallback(
|
||||
function () {
|
||||
methods.loadDashboard.apply(this, [1]);
|
||||
rebuildMenu();
|
||||
}
|
||||
);
|
||||
ajaxRequest.withTokenInUrl();
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send();
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the current layout aus new default widget layout
|
||||
*/
|
||||
saveLayoutAsDefaultWidgetLayout: function () {
|
||||
saveLayout('saveLayoutAsDefault');
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns if the current loaded dashboard is the default dashboard
|
||||
*/
|
||||
isDefaultDashboard: function () {
|
||||
return (dashboardId == 1);
|
||||
}
|
||||
};
|
||||
|
||||
function destroyWidgets()
|
||||
{
|
||||
var widgets = $('[widgetId]');
|
||||
for (var i = 0; i < widgets.length; i++) {
|
||||
$(widgets[i]).dashboardWidget('destroy');
|
||||
}
|
||||
}
|
||||
|
||||
function removeNonExistingWidgets(availableWidgets, layout)
|
||||
{
|
||||
var existingModuleAction = {};
|
||||
$.each(availableWidgets, function (category, widgets) {
|
||||
$.each(widgets, function (index, widget) {
|
||||
existingModuleAction[widget.module + '.' + widget.action] = true;
|
||||
});
|
||||
});
|
||||
|
||||
var columns = [];
|
||||
$.each(layout.columns, function (i, column) {
|
||||
var widgets = [];
|
||||
|
||||
$.each(column, function (j, widget) {
|
||||
if (!widget.parameters || !widget.parameters.module) {
|
||||
return;
|
||||
}
|
||||
|
||||
var method = widget.parameters.module + '.' + widget.parameters.action
|
||||
if (existingModuleAction[method]) {
|
||||
widgets.push(widget);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
columns[i] = widgets;
|
||||
});
|
||||
|
||||
layout.columns = columns;
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the dashboard out of the given layout
|
||||
*
|
||||
* @param {object|string} layout
|
||||
*/
|
||||
function generateLayout(layout) {
|
||||
|
||||
dashboardLayout = parseLayout(layout);
|
||||
|
||||
widgetsHelper.getAvailableWidgets(function (availableWidgets) {
|
||||
dashboardLayout = removeNonExistingWidgets(availableWidgets, dashboardLayout);
|
||||
|
||||
piwikHelper.hideAjaxLoading();
|
||||
adjustDashboardColumns(dashboardLayout.config.layout);
|
||||
|
||||
var dashboardContainsWidgets = false;
|
||||
for (var column = 0; column < dashboardLayout.columns.length; column++) {
|
||||
for (var i in dashboardLayout.columns[column]) {
|
||||
if (typeof dashboardLayout.columns[column][i] != 'object') {
|
||||
// Fix IE8 bug: the "i in" loop contains i="indexOf", which would yield type function.
|
||||
// If we would continue with i="indexOf", an invalid widget would be created.
|
||||
continue;
|
||||
}
|
||||
var widget = dashboardLayout.columns[column][i];
|
||||
dashboardContainsWidgets = true;
|
||||
addWidgetTemplate(widget.uniqueId, column + 1, widget.parameters, false, widget.isHidden)
|
||||
}
|
||||
}
|
||||
|
||||
if (!dashboardContainsWidgets) {
|
||||
$(dashboardElement).trigger('dashboardempty');
|
||||
}
|
||||
|
||||
makeWidgetsSortable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the dashboard columns to fit the new layout
|
||||
* removes or adds new columns if needed and sets the column sizes.
|
||||
*
|
||||
* @param {String} layout new layout in format xx-xx-xx
|
||||
* @return {void}
|
||||
*/
|
||||
function adjustDashboardColumns(layout) {
|
||||
var columnWidth = layout.split('-');
|
||||
var columnCount = columnWidth.length;
|
||||
|
||||
var currentCount = $('> .col', dashboardElement).length;
|
||||
|
||||
if (currentCount < columnCount) {
|
||||
$('.menuClear', dashboardElement).remove();
|
||||
for (var i = currentCount; i < columnCount; i++) {
|
||||
if (dashboardLayout.columns.length < i) {
|
||||
dashboardLayout.columns.push({});
|
||||
}
|
||||
$(dashboardElement).append('<div class="col"> </div>');
|
||||
}
|
||||
$(dashboardElement).append('<div class="menuClear"> </div>');
|
||||
} else if (currentCount > columnCount) {
|
||||
for (var i = columnCount; i < currentCount; i++) {
|
||||
if (dashboardLayout.columns.length >= i) {
|
||||
dashboardLayout.columns.pop();
|
||||
}
|
||||
// move widgets to other columns depending on columns height
|
||||
$('[widgetId]', $(layoutColumnSelector + ':last')).each(function (id, elem) {
|
||||
var cols = $(layoutColumnSelector).slice(0, columnCount);
|
||||
var smallestColumn = $(cols[0]);
|
||||
var smallestColumnHeight = null;
|
||||
cols.each(function (colId, col) {
|
||||
if (smallestColumnHeight == null || smallestColumnHeight > $(col).height()) {
|
||||
smallestColumnHeight = $(col).height();
|
||||
smallestColumn = $(col);
|
||||
}
|
||||
});
|
||||
|
||||
$(elem).appendTo(smallestColumn);
|
||||
});
|
||||
|
||||
$(layoutColumnSelector + ':last').remove();
|
||||
}
|
||||
}
|
||||
|
||||
var $dashboardElement = $(' > .col', dashboardElement);
|
||||
|
||||
if (!$dashboardElement.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (layout) {
|
||||
case '100':
|
||||
$dashboardElement.removeClass().addClass('col s12');
|
||||
break;
|
||||
case '50-50':
|
||||
$dashboardElement.removeClass().addClass('col s12 m6');
|
||||
break;
|
||||
case '67-33':
|
||||
$dashboardElement[0].className = 'col s12 m8';
|
||||
$dashboardElement[1].className = 'col s12 m4';
|
||||
break;
|
||||
case '33-67':
|
||||
$dashboardElement[0].className = 'col s12 m4';
|
||||
$dashboardElement[1].className = 'col s12 m8';
|
||||
break;
|
||||
case '33-33-33':
|
||||
$dashboardElement[0].className = 'col s12 m4';
|
||||
$dashboardElement[1].className = 'col s12 m4';
|
||||
$dashboardElement[2].className = 'col s12 m4';
|
||||
break;
|
||||
case '40-30-30':
|
||||
$dashboardElement[0].className = 'col s12 m6';
|
||||
$dashboardElement[1].className = 'col s12 m3';
|
||||
$dashboardElement[2].className = 'col s12 m3';
|
||||
break;
|
||||
case '30-40-30':
|
||||
$dashboardElement[0].className = 'col s12 m3';
|
||||
$dashboardElement[1].className = 'col s12 m6';
|
||||
$dashboardElement[2].className = 'col s12 m3';
|
||||
break;
|
||||
case '30-30-40':
|
||||
$dashboardElement[0].className = 'col s12 m3';
|
||||
$dashboardElement[1].className = 'col s12 m3';
|
||||
$dashboardElement[2].className = 'col s12 m6';
|
||||
break;
|
||||
case '25-25-25-25':
|
||||
$dashboardElement[0].className = 'col s12 m3';
|
||||
$dashboardElement[1].className = 'col s12 m3';
|
||||
$dashboardElement[2].className = 'col s12 m3';
|
||||
$dashboardElement[3].className = 'col s12 m3';
|
||||
break;
|
||||
}
|
||||
|
||||
makeWidgetsSortable();
|
||||
|
||||
// if dashboard column count is changed (not on initial load)
|
||||
if (currentCount > 0 && dashboardLayout.config.layout != layout) {
|
||||
dashboardChanged = true;
|
||||
dashboardLayout.config.layout = layout;
|
||||
saveLayout();
|
||||
}
|
||||
|
||||
// trigger resize event on all widgets
|
||||
$('.widgetContent').each(function () {
|
||||
$(this).trigger('widget:resize');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given layout as an layout object
|
||||
* Used to parse old layout format into the new syntax
|
||||
*
|
||||
* @param {object} layout layout object or string
|
||||
* @return {object}
|
||||
*/
|
||||
function parseLayout(layout) {
|
||||
|
||||
// Handle layout array used in piwik before 1.7
|
||||
// column count was always 3, so use layout 33-33-33 as default
|
||||
if ($.isArray(layout)) {
|
||||
layout = {
|
||||
config: {layout: '33-33-33'},
|
||||
columns: layout
|
||||
};
|
||||
}
|
||||
|
||||
if (!layout.config.layout) {
|
||||
layout.config.layout = '33-33-33';
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the widget with the given uniqueId
|
||||
*
|
||||
* @param {String|jQuery} $widget
|
||||
*/
|
||||
function reloadWidget($widget) {
|
||||
if (typeof widget === 'string') {
|
||||
$widget = $('[widgetId="' + uniqueId + '"]', dashboardElement);
|
||||
}
|
||||
|
||||
$widget.dashboardWidget('reload', false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an empty widget template to the dashboard in the given column
|
||||
* @param {String} uniqueId
|
||||
* @param {int} columnNumber
|
||||
* @param {object} widgetParameters
|
||||
* @param {boolean} addWidgetOnTop
|
||||
* @param {boolean} isHidden
|
||||
*/
|
||||
function addWidgetTemplate(uniqueId, columnNumber, widgetParameters, addWidgetOnTop, isHidden) {
|
||||
if (!columnNumber) {
|
||||
columnNumber = 1;
|
||||
}
|
||||
|
||||
// do not try to add widget if given column number is to high
|
||||
if (columnNumber > $('> .col', dashboardElement).length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $widgetContent = $('<div class="sortable" widgetId="' + uniqueId + '"></div>');
|
||||
|
||||
if (addWidgetOnTop) {
|
||||
$('> .col:nth-child(' + columnNumber + ')', dashboardElement).prepend($widgetContent);
|
||||
} else {
|
||||
$('> .col:nth-child(' + columnNumber + ')', dashboardElement).append($widgetContent);
|
||||
}
|
||||
|
||||
return $widgetContent.dashboardWidget({
|
||||
uniqueId: uniqueId,
|
||||
widgetParameters: widgetParameters,
|
||||
onChange: function () {
|
||||
saveLayout();
|
||||
},
|
||||
isHidden: isHidden
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Make all widgets on the dashboard sortable
|
||||
*/
|
||||
function makeWidgetsSortable() {
|
||||
function onStart(event, ui) {
|
||||
if (!jQuery.support.noCloneEvent) {
|
||||
$('object', this).hide();
|
||||
}
|
||||
}
|
||||
|
||||
function onStop(event, ui) {
|
||||
$('object', this).show();
|
||||
$('.widgetHover', this).removeClass('widgetHover');
|
||||
$('.widgetTopHover', this).removeClass('widgetTopHover');
|
||||
if ($('.widget:has(".piwik-graph")', ui.item).length) {
|
||||
reloadWidget($('.widget', ui.item).attr('id'));
|
||||
}
|
||||
saveLayout();
|
||||
}
|
||||
|
||||
//launch 'sortable' property on every dashboard widgets
|
||||
$( layoutColumnSelector + ":data('ui-sortable')", dashboardElement ).sortable('destroy');
|
||||
|
||||
$('> .col', dashboardElement)
|
||||
.sortable({
|
||||
items: 'div.sortable',
|
||||
opacity: 0.6,
|
||||
forceHelperSize: true,
|
||||
forcePlaceholderSize: true,
|
||||
placeholder: 'hover',
|
||||
handle: '.widgetTop',
|
||||
helper: 'clone',
|
||||
start: onStart,
|
||||
stop: onStop,
|
||||
connectWith: layoutColumnSelector
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle clicks for menu items for choosing between available dashboards
|
||||
*/
|
||||
function rebuildMenu() {
|
||||
|
||||
if (piwikHelper.isAngularRenderingThePage()) {
|
||||
// dashboard in reporting page (regular Piwik UI)
|
||||
angular.element(document).injector().invoke(function (reportingMenuModel) {
|
||||
reportingMenuModel.reloadMenuItems();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var _self = this;
|
||||
|
||||
// widgetized
|
||||
var success = function (dashboards) {
|
||||
var dashboardMenuList = $('#Dashboard_embeddedIndex_1').closest('ul');
|
||||
var dashboardMenuListItems = dashboardMenuList.find('>li');
|
||||
|
||||
dashboardMenuListItems.filter(function () {
|
||||
return $(this).attr('id').indexOf('Dashboard_embeddedIndex') == 0;
|
||||
}).remove();
|
||||
|
||||
if (dashboards.length === 0) {
|
||||
dashboards = [{iddashboard: 1, name: _pk_translate('Dashboard_Dashboard')}];
|
||||
}
|
||||
|
||||
if (dashboards.length > 1
|
||||
|| dashboardMenuListItems.length >= 1
|
||||
) {
|
||||
var items = [];
|
||||
for (var i = 0; i < dashboards.length; i++) {
|
||||
var $link = $('<a/>').attr('data-iddashboard', dashboards[i].iddashboard).text(dashboards[i].name).addClass('item');
|
||||
var $li = $('<li/>').attr('id', 'Dashboard_embeddedIndex_' + dashboards[i].iddashboard).addClass('dashboardMenuItem').attr('role', 'menuitem').append($link);
|
||||
|
||||
items.push($li);
|
||||
|
||||
if (dashboards[i].iddashboard == dashboardId) {
|
||||
dashboardName = dashboards[i].name;
|
||||
$li.addClass('active');
|
||||
}
|
||||
}
|
||||
dashboardMenuList.prepend(items);
|
||||
}
|
||||
|
||||
dashboardMenuList.find('a[data-iddashboard]').click(function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var idDashboard = $(this).attr('data-iddashboard');
|
||||
|
||||
$('#Dashboard ul li').removeClass('active');
|
||||
|
||||
methods.loadDashboard.apply(_self, [idDashboard]);
|
||||
|
||||
$(this).closest('li').addClass('active');
|
||||
});
|
||||
};
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: 'getAllDashboards',
|
||||
filter_limit: '-1'
|
||||
}, 'get');
|
||||
ajaxRequest.withTokenInUrl();
|
||||
ajaxRequest.setCallback(success);
|
||||
ajaxRequest.send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current layout in database if it has changed
|
||||
* @param {string} [action] action to perform (defaults to saveLayout)
|
||||
*/
|
||||
function saveLayout(action) {
|
||||
var columns = [];
|
||||
|
||||
var columnNumber = 0;
|
||||
|
||||
$(layoutColumnSelector).each(function () {
|
||||
columns[columnNumber] = [];
|
||||
var items = $('[widgetId]', this);
|
||||
for (var j = 0; j < items.length; j++) {
|
||||
columns[columnNumber][j] = $(items[j]).dashboardWidget('getWidgetObject');
|
||||
|
||||
// Do not store segment in the dashboard layout
|
||||
delete columns[columnNumber][j].parameters.segment;
|
||||
|
||||
}
|
||||
columnNumber++;
|
||||
});
|
||||
|
||||
if (JSON.stringify(dashboardLayout.columns) != JSON.stringify(columns) || dashboardChanged || action) {
|
||||
|
||||
dashboardLayout.columns = JSON.parse(JSON.stringify(columns));
|
||||
columns = null;
|
||||
|
||||
if (!action) {
|
||||
action = 'saveLayout';
|
||||
}
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams({
|
||||
module: 'Dashboard',
|
||||
action: action,
|
||||
idDashboard: dashboardId
|
||||
}, 'get');
|
||||
ajaxRequest.addParams({
|
||||
layout: JSON.stringify(dashboardLayout),
|
||||
name: dashboardName
|
||||
}, 'post');
|
||||
ajaxRequest.setCallback(
|
||||
function () {
|
||||
if (dashboardChanged) {
|
||||
dashboardChanged = false;
|
||||
rebuildMenu();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
ajaxRequest.withTokenInUrl();
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make plugin methods available
|
||||
*/
|
||||
$.fn.dashboard = function (method) {
|
||||
if (methods[method]) {
|
||||
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
} else if (typeof method === 'object' || !method) {
|
||||
return methods.init.apply(this, arguments);
|
||||
} else {
|
||||
$.error('Method ' + method + ' does not exist on jQuery.dashboard');
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery);
|
@ -0,0 +1,370 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
$.widget('piwik.dashboardWidget', {
|
||||
|
||||
/**
|
||||
* Boolean indicating wether the widget is currently maximised
|
||||
* @type {Boolean}
|
||||
*/
|
||||
isMaximised: false,
|
||||
/**
|
||||
* Unique Id of the widget
|
||||
* @type {String}
|
||||
*/
|
||||
uniqueId: null,
|
||||
/**
|
||||
* Object holding the widget parameters
|
||||
* @type {Object}
|
||||
*/
|
||||
widgetParameters: {},
|
||||
|
||||
/**
|
||||
* Options available for initialization
|
||||
*/
|
||||
options: {
|
||||
uniqueId: null,
|
||||
isHidden: false,
|
||||
onChange: null,
|
||||
widgetParameters: {},
|
||||
title: null,
|
||||
onRemove: null,
|
||||
onRefresh: null,
|
||||
onMaximise: null,
|
||||
onMinimise: null,
|
||||
autoMaximiseVisualizations: ['tableAllColumns', 'tableGoals']
|
||||
},
|
||||
|
||||
/**
|
||||
* creates a widget object
|
||||
*/
|
||||
_create: function () {
|
||||
|
||||
if (!this.options.uniqueId) {
|
||||
piwikHelper.error('widgets can\'t be created without an uniqueId');
|
||||
return;
|
||||
} else {
|
||||
this.uniqueId = this.options.uniqueId;
|
||||
}
|
||||
|
||||
if (this.options.widgetParameters) {
|
||||
this.widgetParameters = this.options.widgetParameters;
|
||||
}
|
||||
|
||||
this._createDashboardWidget(this.uniqueId);
|
||||
|
||||
var self = this;
|
||||
this.element.on('setParameters.dashboardWidget', function (e, params) { self.setParameters(params); });
|
||||
|
||||
this.reload(true, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Cleanup some events and dialog
|
||||
* Called automatically upon removing the widgets domNode
|
||||
*/
|
||||
destroy: function () {
|
||||
if (this.isMaximised) {
|
||||
$('[widgetId="' + this.uniqueId + '"]').dialog('destroy');
|
||||
}
|
||||
$('*', this.element).off('.dashboardWidget'); // unbind all events
|
||||
$('.widgetContent', this.element).trigger('widget:destroy');
|
||||
require('piwik/UI').UIControl.cleanupUnusedControls();
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the data currently set for the widget
|
||||
* @return {object}
|
||||
*/
|
||||
getWidgetObject: function () {
|
||||
return {
|
||||
uniqueId: this.uniqueId,
|
||||
parameters: this.widgetParameters,
|
||||
isHidden: this.options.isHidden
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the current widget in an ui.dialog
|
||||
*/
|
||||
maximise: function () {
|
||||
this.isMaximised = true;
|
||||
|
||||
if (this.options.onMaximise) {
|
||||
this.options.onMaximise(this.element);
|
||||
} else {
|
||||
this._maximiseImpl();
|
||||
}
|
||||
|
||||
$('.widgetContent', this.element).trigger('widget:maximise');
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reloads the widgets content with the currently set parameters
|
||||
*/
|
||||
reload: function (hideLoading, notJQueryUI, overrideParams) {
|
||||
if (!notJQueryUI) {
|
||||
piwikHelper.log('widget.reload() was called by jquery.ui, ignoring', arguments.callee.caller);
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this, currentWidget = this.element;
|
||||
|
||||
$('.widgetContent', currentWidget).trigger('widget:reload');
|
||||
|
||||
function onWidgetLoadedReplaceElementWithContent(loadedContent) {
|
||||
var $widgetContent = $('.widgetContent', currentWidget);
|
||||
|
||||
$widgetContent.html(loadedContent);
|
||||
|
||||
/* move widget icons into datatable top actions
|
||||
var $buttons = currentWidget.find('.buttons .button');
|
||||
var $controls = currentWidget.find('.dataTableControls .dataTableAction').first();
|
||||
if ($buttons.length && $controls.length) {
|
||||
$buttons.find('.button').addClass('dataTableAction');
|
||||
$buttons.insertBefore($controls);
|
||||
}*/
|
||||
|
||||
if (currentWidget.parents('body').length) {
|
||||
// there might be race conditions, eg widget might be just refreshed while whole dashboard is also
|
||||
// removed from DOM
|
||||
piwikHelper.compileAngularComponents($widgetContent, { forceNewScope: true });
|
||||
}
|
||||
$widgetContent.removeClass('loading');
|
||||
$widgetContent.trigger('widget:create', [self]);
|
||||
|
||||
angular.element(document).injector().invoke(['notifications', function (notifications) {
|
||||
notifications.parseNotificationDivs();
|
||||
}]);
|
||||
}
|
||||
|
||||
// Reading segment from hash tag (standard case) or from the URL (when embedding dashboard)
|
||||
var segment = broadcast.getValueFromHash('segment') || broadcast.getValueFromUrl('segment');
|
||||
if (segment.length) {
|
||||
this.widgetParameters.segment = segment;
|
||||
}
|
||||
|
||||
if (!hideLoading) {
|
||||
$('.widgetContent', currentWidget).addClass('loading');
|
||||
}
|
||||
|
||||
var params = $.extend(this.widgetParameters, overrideParams || {});
|
||||
widgetsHelper.loadWidgetAjax(this.uniqueId, params, onWidgetLoadedReplaceElementWithContent, function (deferred, status) {
|
||||
if (status == 'abort' || !deferred || deferred.status < 400 || deferred.status >= 600) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.widgetContent', currentWidget).removeClass('loading');
|
||||
var errorMessage = _pk_translate('General_ErrorRequest', ['', '']);
|
||||
if ($('#loadingError').html()) {
|
||||
errorMessage = $('#loadingError').html();
|
||||
}
|
||||
|
||||
$('.widgetContent', currentWidget).html('<div class="widgetLoadingError">' + errorMessage + '</div>');
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update widget parameters
|
||||
*
|
||||
* @param {object} parameters
|
||||
*/
|
||||
setParameters: function (parameters) {
|
||||
if (!this.isMaximised
|
||||
&& this.options.autoMaximiseVisualizations.indexOf(parameters.viewDataTable) !== -1
|
||||
) {
|
||||
this.maximise();
|
||||
}
|
||||
for (var name in parameters) {
|
||||
this.widgetParameters[name] = parameters[name];
|
||||
}
|
||||
if (!this.isMaximised) {
|
||||
this.options.onChange();
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get widget parameters
|
||||
*
|
||||
* @param {object} parameters
|
||||
*/
|
||||
getParameters: function () {
|
||||
return $.extend({}, this.widgetParameters);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creaates the widget markup for the given uniqueId
|
||||
*
|
||||
* @param {String} uniqueId
|
||||
*/
|
||||
_createDashboardWidget: function (uniqueId) {
|
||||
|
||||
var self = this;
|
||||
|
||||
widgetsHelper.getWidgetNameFromUniqueId(uniqueId, function(widgetName) {
|
||||
if (!widgetName) {
|
||||
widgetName = _pk_translate('Dashboard_WidgetNotFound');
|
||||
}
|
||||
|
||||
var title = self.options.title === null ? $('<span/>').text(widgetName) : self.options.title;
|
||||
var emptyWidgetContent = require('piwik/UI/Dashboard').WidgetFactory.make(uniqueId, title);
|
||||
self.element.html(emptyWidgetContent);
|
||||
|
||||
var widgetElement = $('[id="' + uniqueId + '"]', self.element);
|
||||
widgetElement
|
||||
.on('mouseenter.dashboardWidget', function () {
|
||||
if (!self.isMaximised) {
|
||||
$(this).addClass('widgetHover');
|
||||
$('.widgetTop', this).addClass('widgetTopHover');
|
||||
}
|
||||
})
|
||||
.on('mouseleave.dashboardWidget', function () {
|
||||
if (!self.isMaximised) {
|
||||
$(this).removeClass('widgetHover');
|
||||
$('.widgetTop', this).removeClass('widgetTopHover');
|
||||
}
|
||||
});
|
||||
|
||||
if (self.options.isHidden) {
|
||||
$('.widgetContent', widgetElement).toggleClass('hidden').closest('.widget').toggleClass('hiddenContent');
|
||||
}
|
||||
|
||||
$('.button#close', widgetElement)
|
||||
.on('click.dashboardWidget', function (ev) {
|
||||
piwikHelper.modalConfirm('#confirm', {yes: function () {
|
||||
if (self.options.onRemove) {
|
||||
self.options.onRemove(self.element);
|
||||
} else {
|
||||
self.element.remove();
|
||||
self.options.onChange();
|
||||
}
|
||||
}});
|
||||
});
|
||||
|
||||
$('.button#maximise', widgetElement)
|
||||
.on('click.dashboardWidget', function (ev) {
|
||||
if (self.options.onMaximise) {
|
||||
self.options.onMaximise(self.element);
|
||||
} else {
|
||||
if ($('.widgetContent', $(this).parents('.widget')).hasClass('hidden')) {
|
||||
self.showContent();
|
||||
} else {
|
||||
self.maximise();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.button#minimise', widgetElement)
|
||||
.on('click.dashboardWidget', function (ev) {
|
||||
if (self.options.onMinimise) {
|
||||
self.options.onMinimise(self.element);
|
||||
} else {
|
||||
if (!self.isMaximised) {
|
||||
self.hideContent();
|
||||
} else {
|
||||
self.element.dialog("close");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.button#refresh', widgetElement)
|
||||
.on('click.dashboardWidget', function (ev) {
|
||||
if (self.options.onRefresh) {
|
||||
self.options.onRefresh(self.element);
|
||||
} else {
|
||||
self.reload(false, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the widget content. Triggers the onChange event.
|
||||
*/
|
||||
hideContent: function () {
|
||||
$('.widgetContent', this.element.find('.widget').addClass('hiddenContent')).addClass('hidden');
|
||||
this.options.isHidden = true;
|
||||
this.options.onChange();
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the widget content. Triggers the onChange event.
|
||||
*/
|
||||
showContent: function () {
|
||||
this.isMaximised = false;
|
||||
this.options.isHidden = false;
|
||||
this.element.find('.widget').removeClass('hiddenContent').find('.widgetContent').removeClass('hidden');
|
||||
this.element.find('.widget').find('div.piwik-graph').trigger('resizeGraph');
|
||||
this.options.onChange();
|
||||
$('.widgetContent', this.element).trigger('widget:minimise');
|
||||
},
|
||||
|
||||
/**
|
||||
* Default maximise behavior. Will create a dialog that is 70% of the document's width,
|
||||
* displaying the widget alone.
|
||||
*/
|
||||
_maximiseImpl: function () {
|
||||
this.detachWidget();
|
||||
|
||||
var width = Math.floor($('body').width() * 0.7);
|
||||
|
||||
var self = this;
|
||||
this.element.dialog({
|
||||
title: '',
|
||||
dialogClass: 'widgetoverlay',
|
||||
modal: true,
|
||||
width: width,
|
||||
position: ['center', 'center'],
|
||||
resizable: true,
|
||||
autoOpen: true,
|
||||
close: function (event, ui) {
|
||||
self.isMaximised = false;
|
||||
$('body').off('.dashboardWidget');
|
||||
$(this).dialog("destroy");
|
||||
$('[id="' + self.uniqueId + '-placeholder"]').replaceWith(this);
|
||||
$(this).removeAttr('style');
|
||||
self.options.onChange();
|
||||
$(this).find('div.piwik-graph').trigger('resizeGraph');
|
||||
$('.widgetContent', self.element).trigger('widget:minimise');
|
||||
}
|
||||
});
|
||||
this.element.find('div.piwik-graph').trigger('resizeGraph');
|
||||
|
||||
var currentWidget = this.element;
|
||||
$('body').on('click.dashboardWidget', function (ev) {
|
||||
if (/ui-widget-overlay/.test(ev.target.className)) {
|
||||
$(currentWidget).dialog("close");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detaches the widget from the DOM and replaces it with a placeholder element.
|
||||
* The placeholder element will have the save dimensions as the widget and will have
|
||||
* the widgetPlaceholder CSS class.
|
||||
*
|
||||
* @return {jQuery} the detached widget
|
||||
*/
|
||||
detachWidget: function () {
|
||||
this.element.before('<div id="' + this.uniqueId + '-placeholder" class="widgetPlaceholder widget"> </div>');
|
||||
var placeholder = $('[id="' + self.uniqueId + '-placeholder"]');
|
||||
|
||||
$('#' + this.uniqueId + '-placeholder').height(this.element.height());
|
||||
$('#' + this.uniqueId + '-placeholder').width(this.element.width() - 16);
|
||||
|
||||
return this.element.detach();
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
508
msd2/tracking/piwik/plugins/Dashboard/javascripts/widgetMenu.js
Normal file
508
msd2/tracking/piwik/plugins/Dashboard/javascripts/widgetMenu.js
Normal file
@ -0,0 +1,508 @@
|
||||
/*!
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
function widgetsHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the available widgets fetched via AJAX (if not already done)
|
||||
*
|
||||
* @return {object} object containing available widgets
|
||||
*/
|
||||
widgetsHelper.getAvailableWidgets = function (callback) {
|
||||
|
||||
function mergeCategoriesAndSubCategories(availableWidgets)
|
||||
{
|
||||
var categorized = {};
|
||||
|
||||
$.each(availableWidgets, function (index, widget) {
|
||||
var category = widget.category.name;
|
||||
|
||||
if (!categorized[category]) {
|
||||
categorized[category] = {'-': []};
|
||||
}
|
||||
|
||||
var subcategory = '-';
|
||||
if (widget.subcategory && widget.subcategory.name) {
|
||||
subcategory = widget.subcategory.name;
|
||||
}
|
||||
|
||||
if (!categorized[category][subcategory]) {
|
||||
categorized[category][subcategory] = [];
|
||||
}
|
||||
|
||||
categorized[category][subcategory].push(widget);
|
||||
});
|
||||
|
||||
var moved = {};
|
||||
|
||||
$.each(categorized, function (category, widgets) {
|
||||
$.each(widgets, function (subcategory, subwidgets) {
|
||||
|
||||
var categoryToUse = category;
|
||||
if (subwidgets.length >= 3 && subcategory !== '-') {
|
||||
categoryToUse = category + ' - ' + subcategory;
|
||||
}
|
||||
|
||||
if (!moved[categoryToUse]) {
|
||||
moved[categoryToUse] = [];
|
||||
}
|
||||
|
||||
$.each(subwidgets, function (index, widget) {
|
||||
moved[categoryToUse].push(widget);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return moved;
|
||||
}
|
||||
|
||||
if (!widgetsHelper.availableWidgets) {
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest._mixinDefaultGetParams = function (params) {
|
||||
return params;
|
||||
};
|
||||
ajaxRequest.addParams({
|
||||
module: 'API',
|
||||
method: 'API.getWidgetMetadata',
|
||||
filter_limit: '-1',
|
||||
format: 'JSON',
|
||||
deep: '1',
|
||||
idSite: piwik.idSite || broadcast.getValueFromUrl('idSite')
|
||||
}, 'get');
|
||||
ajaxRequest.setCallback(
|
||||
function (data) {
|
||||
widgetsHelper.availableWidgets = mergeCategoriesAndSubCategories(data);
|
||||
|
||||
if (callback) {
|
||||
callback(widgetsHelper.availableWidgets);
|
||||
}
|
||||
}
|
||||
);
|
||||
ajaxRequest.setErrorCallback(function (deferred, status) {
|
||||
if (status == 'abort' || !deferred || deferred.status < 400 || deferred.status >= 600) {
|
||||
return;
|
||||
}
|
||||
$('#loadingError').show();
|
||||
});
|
||||
ajaxRequest.send();
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(widgetsHelper.availableWidgets);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines the complete widget object by its unique id and sends it to callback method
|
||||
*
|
||||
* @param {string} uniqueId
|
||||
* @param {function} callback
|
||||
*/
|
||||
widgetsHelper.getWidgetObjectFromUniqueId = function (uniqueId, callback) {
|
||||
widgetsHelper.getAvailableWidgets(function(widgets){
|
||||
for (var widgetCategory in widgets) {
|
||||
var widgetInCategory = widgets[widgetCategory];
|
||||
for (var i in widgetInCategory) {
|
||||
if (widgetInCategory[i]["uniqueId"] == uniqueId) {
|
||||
callback(widgetInCategory[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
callback(false);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines the name of a widget by its unique id and sends it to the callback
|
||||
*
|
||||
* @param {string} uniqueId unique id of the widget
|
||||
* @param {function} callback
|
||||
* @return {string}
|
||||
*/
|
||||
widgetsHelper.getWidgetNameFromUniqueId = function (uniqueId, callback) {
|
||||
this.getWidgetObjectFromUniqueId(uniqueId, function(widget) {
|
||||
if (widget == false) {
|
||||
callback(false);
|
||||
}
|
||||
callback(widget["name"]);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends and ajax request to query for the widgets html
|
||||
*
|
||||
* @param {string} widgetUniqueId unique id of the widget
|
||||
* @param {object} widgetParameters parameters to be used for loading the widget
|
||||
* @param {function} onWidgetLoadedCallback callback to be executed after widget is loaded
|
||||
* @return {object}
|
||||
*/
|
||||
widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWidgetLoadedCallback, onWidgetErrorCallback) {
|
||||
var disableLink = broadcast.getValueFromUrl('disableLink');
|
||||
widgetParameters['disableLink'] = disableLink.length || $('body#standalone').length;
|
||||
|
||||
widgetParameters['widget'] = 1;
|
||||
|
||||
var ajaxRequest = new ajaxHelper();
|
||||
ajaxRequest.addParams(widgetParameters, 'get');
|
||||
ajaxRequest.setCallback(onWidgetLoadedCallback);
|
||||
if (onWidgetErrorCallback) {
|
||||
ajaxRequest.setErrorCallback(onWidgetErrorCallback);
|
||||
}
|
||||
ajaxRequest.setFormat('html');
|
||||
ajaxRequest.send();
|
||||
return ajaxRequest;
|
||||
};
|
||||
|
||||
(function ($, require) {
|
||||
var exports = require('piwik/UI/Dashboard');
|
||||
|
||||
/**
|
||||
* Singleton instance that creates widget elements. Normally not needed even
|
||||
* when embedding/re-using dashboard widgets, but it can be useful when creating
|
||||
* elements with the same look and feel as dashboard widgets, but different
|
||||
* behavior (such as the widget preview in the dashboard manager control).
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
var WidgetFactory = function () {
|
||||
// empty
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an HTML element for displaying a widget.
|
||||
*
|
||||
* @param {string} uniqueId unique id of the widget
|
||||
* @param {string} widgetName name of the widget
|
||||
* @return {Element} the empty widget
|
||||
*/
|
||||
WidgetFactory.prototype.make = function (uniqueId, widgetName) {
|
||||
var $result = this.getWidgetTemplate().clone();
|
||||
$result.attr('id', uniqueId).find('.widgetName').append(widgetName);
|
||||
return $result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the base widget template element. The template is stored in the
|
||||
* element with id == 'widgetTemplate'.
|
||||
*
|
||||
* @return {Element} the widget template
|
||||
*/
|
||||
WidgetFactory.prototype.getWidgetTemplate = function () {
|
||||
if (!this.widgetTemplate) {
|
||||
this.widgetTemplate = $('#widgetTemplate').find('>.widget').detach();
|
||||
}
|
||||
return this.widgetTemplate;
|
||||
};
|
||||
|
||||
exports.WidgetFactory = new WidgetFactory();
|
||||
})(jQuery, require);
|
||||
|
||||
/**
|
||||
* widgetPreview jQuery Extension
|
||||
*
|
||||
* Converts an dom element to a widget preview
|
||||
* Widget preview contains an categorylist, widgetlist and a preview
|
||||
*/
|
||||
(function ($) {
|
||||
$.extend({
|
||||
widgetPreview: new function () {
|
||||
|
||||
/**
|
||||
* Default settings for widgetPreview
|
||||
* @type {object}
|
||||
*/
|
||||
var defaultSettings = {
|
||||
/**
|
||||
* handler called after a widget preview is loaded in preview element
|
||||
* @type {function}
|
||||
*/
|
||||
onPreviewLoaded: function () {},
|
||||
/**
|
||||
* handler called on click on element in widgetlist or widget header
|
||||
* @type {function}
|
||||
*/
|
||||
onSelect: function () {},
|
||||
/**
|
||||
* callback used to determine if a widget is available or not
|
||||
* unavailable widgets aren't chooseable in widgetlist
|
||||
* @type {function}
|
||||
*/
|
||||
isWidgetAvailable: function (widgetUniqueId) { return true; },
|
||||
/**
|
||||
* should the lists and preview be reset on widget selection?
|
||||
* @type {boolean}
|
||||
*/
|
||||
resetOnSelect: false,
|
||||
/**
|
||||
* css classes for various elements
|
||||
* @type {string}
|
||||
*/
|
||||
baseClass: 'widgetpreview-base',
|
||||
categorylistClass: 'widgetpreview-categorylist',
|
||||
widgetlistClass: 'widgetpreview-widgetlist',
|
||||
widgetpreviewClass: 'widgetpreview-preview',
|
||||
choosenClass: 'widgetpreview-choosen',
|
||||
unavailableClass: 'widgetpreview-unavailable'
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the div to show category list in
|
||||
* - if element doesn't exist it will be created and added
|
||||
* - if element already exist it's content will be removed
|
||||
*
|
||||
* @return {$} category list element
|
||||
*/
|
||||
function createWidgetCategoryList(widgetPreview, availableWidgets) {
|
||||
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
if (!$('.' + settings.categorylistClass, widgetPreview).length) {
|
||||
$(widgetPreview).append('<ul class="' + settings.categorylistClass + '"></ul>');
|
||||
} else {
|
||||
$('.' + settings.categorylistClass, widgetPreview).empty();
|
||||
}
|
||||
|
||||
for (var widgetCategory in availableWidgets) {
|
||||
$('.' + settings.categorylistClass, widgetPreview).append($('<li>').text(widgetCategory));
|
||||
}
|
||||
|
||||
return $('.' + settings.categorylistClass, widgetPreview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the div to show widget list in
|
||||
* - if element doesn't exist it will be created and added
|
||||
* - if element already exist it's content will be removed
|
||||
*
|
||||
* @return {$} widget list element
|
||||
*/
|
||||
function createWidgetList(widgetPreview) {
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
if (!$('.' + settings.widgetlistClass, widgetPreview).length) {
|
||||
$(widgetPreview).append('<ul class="' + settings.widgetlistClass + '"></ul>');
|
||||
} else {
|
||||
$('.' + settings.widgetlistClass + ' li', widgetPreview).off('mouseover');
|
||||
$('.' + settings.widgetlistClass + ' li', widgetPreview).off('click');
|
||||
$('.' + settings.widgetlistClass, widgetPreview).empty();
|
||||
}
|
||||
|
||||
if ($('.' + settings.categorylistClass + ' .' + settings.choosenClass, widgetPreview).length) {
|
||||
var position = $('.' + settings.categorylistClass + ' .' + settings.choosenClass, widgetPreview).position().top -
|
||||
$('.' + settings.categorylistClass, widgetPreview).position().top +
|
||||
$('.dashboard-manager .addWidget').outerHeight();
|
||||
|
||||
if (!$('#content.admin').length) {
|
||||
position += 5; // + padding defined in dashboard view
|
||||
}
|
||||
|
||||
$('.' + settings.widgetlistClass, widgetPreview).css('top', position);
|
||||
$('.' + settings.widgetlistClass, widgetPreview).css('marginBottom', position);
|
||||
}
|
||||
|
||||
return $('.' + settings.widgetlistClass, widgetPreview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the given widgets in a widget list
|
||||
*
|
||||
* @param {object} widgets widgets to be displayed
|
||||
* @return {void}
|
||||
*/
|
||||
function showWidgetList(widgets, widgetPreview) {
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
var widgetList = createWidgetList(widgetPreview),
|
||||
widgetPreviewTimer;
|
||||
|
||||
for (var j = 0; j < widgets.length; j++) {
|
||||
var widgetName = widgets[j]["name"];
|
||||
var widgetUniqueId = widgets[j]["uniqueId"];
|
||||
var widgetCategoryId = widgets[j].category ? widgets[j].category.id : null;
|
||||
var widgetClass = '';
|
||||
if (!settings.isWidgetAvailable(widgetUniqueId) && widgetCategoryId !== 'General_Generic') {
|
||||
widgetClass += ' ' + settings.unavailableClass;
|
||||
}
|
||||
|
||||
widgetName = piwikHelper.escape(piwikHelper.htmlEntities(widgetName));
|
||||
|
||||
widgetList.append('<li class="' + widgetClass + '" uniqueid="' + widgetUniqueId + '">' + widgetName + '</li>');
|
||||
}
|
||||
|
||||
// delay widget preview a few millisconds
|
||||
$('li', widgetList).on('mouseenter', function () {
|
||||
var that = this,
|
||||
widgetUniqueId = $(this).attr('uniqueid');
|
||||
clearTimeout(widgetPreview);
|
||||
widgetPreviewTimer = setTimeout(function () {
|
||||
$('li', widgetList).removeClass(settings.choosenClass);
|
||||
$(that).addClass(settings.choosenClass);
|
||||
|
||||
showPreview(widgetUniqueId, widgetPreview);
|
||||
}, 400);
|
||||
});
|
||||
|
||||
// clear timeout after mouse has left
|
||||
$('li:not(.' + settings.unavailableClass + ')', widgetList).on('mouseleave', function () {
|
||||
clearTimeout(widgetPreview);
|
||||
});
|
||||
|
||||
$('li', widgetList).on('click', function () {
|
||||
if (!$('.widgetLoading', widgetPreview).length) {
|
||||
settings.onSelect($(this).attr('uniqueid'));
|
||||
$(widgetPreview).closest('.dashboard-manager').removeClass('expanded');
|
||||
if (settings.resetOnSelect) {
|
||||
resetWidgetPreview(widgetPreview);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the div to show widget preview in
|
||||
* - if element doesn't exist it will be created and added
|
||||
* - if element already exist it's content will be removed
|
||||
*
|
||||
* @return {$} preview element
|
||||
*/
|
||||
function createPreviewElement(widgetPreview) {
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
if (!$('.' + settings.widgetpreviewClass, widgetPreview).length) {
|
||||
$(widgetPreview).append('<div class="' + settings.widgetpreviewClass + '"></div>');
|
||||
} else {
|
||||
$('.' + settings.widgetpreviewClass + ' .widgetTop', widgetPreview).off('click');
|
||||
$('.' + settings.widgetpreviewClass, widgetPreview).empty();
|
||||
}
|
||||
|
||||
return $('.' + settings.widgetpreviewClass, widgetPreview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show widget with the given uniqueId in preview
|
||||
*
|
||||
* @param {string} widgetUniqueId unique id of widget to display
|
||||
* @param widgetPreview
|
||||
* @return {void}
|
||||
*/
|
||||
function showPreview(widgetUniqueId, widgetPreview) {
|
||||
// do not reload id widget already displayed
|
||||
if ($('[id="' + widgetUniqueId + '"]', widgetPreview).length) return;
|
||||
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
var previewElement = createPreviewElement(widgetPreview);
|
||||
|
||||
widgetsHelper.getWidgetObjectFromUniqueId(widgetUniqueId, function(widget) {
|
||||
var widgetParameters = widget['parameters'];
|
||||
|
||||
var emptyWidgetHtml = require('piwik/UI/Dashboard').WidgetFactory.make(
|
||||
widgetUniqueId,
|
||||
$('<span/>')
|
||||
.attr('title', _pk_translate("Dashboard_AddPreviewedWidget"))
|
||||
.text(_pk_translate('Dashboard_WidgetPreview'))
|
||||
);
|
||||
previewElement.html(emptyWidgetHtml);
|
||||
|
||||
var onWidgetLoadedCallback = function (response) {
|
||||
var widgetElement = $(document.getElementById(widgetUniqueId));
|
||||
// document.getElementById needed for widgets with uniqueid like widgetOpens+Contact+Form
|
||||
$('.widgetContent', widgetElement).html($(response));
|
||||
piwikHelper.compileAngularComponents($('.widgetContent', widgetElement), { forceNewScope: true });
|
||||
$('.widgetContent', widgetElement).trigger('widget:create');
|
||||
settings.onPreviewLoaded(widgetUniqueId, widgetElement);
|
||||
$('.' + settings.widgetpreviewClass + ' .widgetTop', widgetPreview).on('click', function () {
|
||||
settings.onSelect(widgetUniqueId);
|
||||
$(widgetPreview).closest('.dashboard-manager').removeClass('expanded');
|
||||
if (settings.resetOnSelect) {
|
||||
resetWidgetPreview(widgetPreview);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
// abort previous sent request
|
||||
if (widgetPreview.widgetAjaxRequest) {
|
||||
widgetPreview.widgetAjaxRequest.abort();
|
||||
}
|
||||
|
||||
widgetPreview.widgetAjaxRequest = widgetsHelper.loadWidgetAjax(widgetUniqueId, widgetParameters, onWidgetLoadedCallback);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset function
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
function resetWidgetPreview(widgetPreview) {
|
||||
var settings = widgetPreview.settings;
|
||||
|
||||
$('.' + settings.categorylistClass + ' li', widgetPreview).removeClass(settings.choosenClass);
|
||||
createWidgetList(widgetPreview);
|
||||
createPreviewElement(widgetPreview);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param {object} userSettings Settings to be used
|
||||
* @return {void}
|
||||
*/
|
||||
this.construct = function (userSettings) {
|
||||
|
||||
if (userSettings == 'reset') {
|
||||
resetWidgetPreview(this);
|
||||
return;
|
||||
}
|
||||
|
||||
this.widgetAjaxRequest = null;
|
||||
|
||||
$(this).addClass('widgetpreview-base');
|
||||
|
||||
this.settings = jQuery.extend({}, defaultSettings, userSettings);
|
||||
|
||||
// set onSelect callback
|
||||
if (typeof this.settings.onSelect == 'function') {
|
||||
this.onSelect = this.settings.onSelect;
|
||||
}
|
||||
|
||||
// set onPreviewLoaded callback
|
||||
if (typeof this.settings.onPreviewLoaded == 'function') {
|
||||
this.onPreviewLoaded = this.settings.onPreviewLoaded;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
widgetsHelper.getAvailableWidgets(function (availableWidgets) {
|
||||
|
||||
var categoryList = createWidgetCategoryList(self, availableWidgets);
|
||||
|
||||
$('li', categoryList).on('mouseover', function () {
|
||||
var category = $(this).text();
|
||||
var widgets = availableWidgets[category];
|
||||
$('li', categoryList).removeClass(self.settings.choosenClass);
|
||||
$(this).addClass(self.settings.choosenClass);
|
||||
showWidgetList(widgets, self);
|
||||
createPreviewElement(self); // empty preview
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Makes widgetPreview available with $().widgetPreview()
|
||||
*/
|
||||
$.fn.extend({
|
||||
widgetPreview: $.widgetPreview.construct
|
||||
})
|
||||
})(jQuery);
|
Reference in New Issue
Block a user