Newer
Older
* Piwik - Web Analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//A list of all our DataTables
//Test if the object have already been initialized (multiple includes)
if(typeof dataTables == "undefined")
var dataTables = {};
//DataTable constructor
function dataTable()
{
this.param = {};
}
//Prototype of the DataTable object
dataTable.prototype =
{
//initialisation function
init: function(workingDivId, domElem)
{
if(typeof domElem == "undefined")
{
domElem = $('#'+workingDivId);
}
this.workingDivId = workingDivId;
this.loadedSubDataTable = {};
this.bindEventsAndApplyStyle(domElem);
this.initialized = true;
},
//function triggered when user click on column sort
onClickSort: function(domElem)
{
var self = this;
var newColumnToSort = $(domElem).attr('id');
// we lookup if the column to sort was already this one, if it is the case then we switch from desc <-> asc
if(self.param.filter_sort_column == newColumnToSort)
{
// toggle the sorted order
if(this.param.filter_sort_order == 'asc')
{
self.param.filter_sort_order = 'desc';
}
else
{
self.param.filter_sort_order = 'asc';
}
}
self.param.filter_offset = 0;
self.param.filter_sort_column = newColumnToSort;
self.reloadAjaxDataTable();
},
setGraphedColumn: function( columnName )
{
this.param.columns = columnName;
},
//Reset DataTable filters (used before a reload or view change)
resetAllFilters: function()
{
var self = this;
var FiltersToRestore = new Array();
filters = [
'filter_column',
'filter_pattern',
'filter_column_recursive',
'filter_pattern_recursive',
'enable_filter_excludelowpop',
'filter_offset',
'filter_sort_column',
'filter_sort_order',
'disable_generic_filters',
'columns',
'flat',
'include_aggregate_rows'
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
];
for(var key in filters)
{
var value = filters[key];
FiltersToRestore[value] = self.param[value];
delete self.param[value];
}
return FiltersToRestore;
},
//Restores the filters to the values given in the array in parameters
restoreAllFilters: function(FiltersToRestore)
{
var self = this;
for(key in FiltersToRestore)
{
self.param[key] = FiltersToRestore[key];
}
},
//Translate string parameters to javascript builtins
//'true' -> true, 'false' -> false
//it simplifies condition tests in the code
cleanParams: function()
{
var self = this;
for(var key in self.param)
{
if(self.param[key] == 'true') self.param[key]=true;
if(self.param[key] == 'false') self.param[key]=false;
}
},
// Returns the standard Ajax request object used by the Jquery .ajax method
buildAjaxRequest: function(callbackSuccess)
{
var self = this;
//prepare the ajax request
var ajaxRequest =
{
type: 'GET',
url: 'index.php',
dataType: 'html',
async: true,
error: piwikHelper.ajaxHandleError, // Callback when the request fails
success: callbackSuccess, // Callback when the request succeeds
data: new Object
};
//Extract the configuration from the datatable and pass it to the API
for(var key in self.param)
{
if(typeof self.param[key] != "undefined")
ajaxRequest.data[key] = self.param[key];
}
return ajaxRequest;
},
// Function called to trigger the AJAX request
// The ajax request contains the function callback to trigger if the request is successful or failed
// displayLoading = false When we don't want to display the Loading... DIV .loadingPiwik
// for example when the script add a Loading... it self and doesn't want to display the generic Loading
reloadAjaxDataTable: function(displayLoading, callbackSuccess)
{
var self = this;
if (typeof displayLoading == "undefined")
{
displayLoading = true;
}
if (typeof callbackSuccess == "undefined")
{
callbackSuccess = self.dataTableLoaded;
}
if(displayLoading)
{
$('#'+self.workingDivId+' .loadingPiwik').last().css('display','block');
}
var container = $('#'+self.workingDivId+' .piwik-graph');
piwikHelper.queueAjaxRequest($.ajax(self.buildAjaxRequest(function(response) {
container.trigger('piwikDestroyPlot');
container.off('piwikDestroyPlot');
callbackSuccess(response);
})));
},
// Function called when the AJAX request is successful
// it looks for the ID of the response and replace the very same ID
// in the current page with the AJAX response
dataTableLoaded: function(response)
{
var content = $(response);
var idToReplace = $(content).attr('id');
var dataTableSel = $('#'+idToReplace);
table = $(content).parents('table.dataTable');
if(dataTableSel.parents('.dataTable').is('table'))
{
// we add class to the table so that we can give a different style to the subtable
$(content).find('table.dataTable').addClass('subDataTable');
//we force the initialisation of subdatatables
}
else
{
dataTableSel.find('object').remove();
}
piwikHelper.lazyScrollTo(dataTableSel[0], 400);
},
/* This method is triggered when a new DIV is loaded, which happens
- at the first loading of the page
- after any AJAX loading of a DataTable
This method basically add features to the DataTable,
- such as column sorting, searching in the rows, displaying Next / Previous links, etc.
- add styles to the cells and rows (odd / even styles)
- modify some rows to add images if a span img is found, or add a link if a span urlLink is found
or truncate the labels when they are too big
- bind new events onclick / hover / etc. to trigger AJAX requests,
nice hovertip boxes for truncated cells
*/
bindEventsAndApplyStyle: function(domElem)
{
var self = this;
self.cleanParams();
self.handleSort(domElem);
self.handleLimit(domElem);
self.handleSearchBox(domElem);
self.handleOffsetInformation(domElem);
self.handleExportBox(domElem);
self.applyCosmetics(domElem);
self.handleSubDataTable(domElem);
self.handleConfigurationBox(domElem);
self.handleColumnDocumentation(domElem);
self.handleReportDocumentation(domElem);
self.handleRowActions(domElem);
},
handleLimit: function(domElem)
{
var self = this;
$('.limitSelection', domElem).remove();
$('.limitSelection', domElem).append('<div><span>'+self.param.filter_limit+'</span></div><ul></ul>');
mattpiwik
a validé
if(self.param.viewDataTable == 'table' || self.param.viewDataTable == 'tableAllColumns' || self.param.viewDataTable == 'tableGoals' || self.param.viewDataTable == 'ecommerceOrder' || self.param.viewDataTable == 'ecommerceAbandonedCart') {
$('.limitSelection ul', domElem).hide();
for(var i=0; i<numbers.length; i++) {
$('.limitSelection ul', domElem).append('<li value="'+numbers[i]+'"><span>'+numbers[i]+'</span></li>');
}
$('.limitSelection ul li:last', domElem).addClass('last');
if(self.param.totalRows > 0) {
$('.limitSelection div', domElem).on('click', function(){
$('.limitSelection ul', domElem).toggle();
$('.limitSelection', domElem).toggleClass('visible');
});
$('.limitSelection ul li', domElem).on('click', function(event){
var limit = parseInt($(event.target).text());
$('.limitSelection', domElem).removeClass('visible');
$('.limitSelection ul', domElem).hide();
if(limit != self.param.filter_limit) {
self.param.filter_limit = limit;
self.param.filter_offset = 0;
// Hack for Visitor Log to not pass the maxIdVisit parameter when limit is changed
delete self.param.maxIdVisit;
$('.limitSelection>div>span', domElem).text(self.param.filter_limit);
self.reloadAjaxDataTable();
self.notifyWidgetParametersChange(domElem, {'filter_limit': self.param.filter_limit});
}
});
$('body').on('mouseup',function(e){
if(!$(e.target).parents('.limitSelection').length && !$(e.target).is('.limitSelection')) {
$('.limitSelection', domElem).removeClass('visible');
$('.limitSelection ul', domElem).hide();
}
});
} else {
$('.limitSelection', domElem).toggleClass('disabled');
}
} else {
$('.limitSelection', domElem).hide();
}
},
// if sorting the columns is enabled, when clicking on a column,
// - if this column was already the one used for sorting, we revert the order desc<->asc
// - we send the ajax request with the new sorting information
handleSort: function(domElem)
{
var self = this;
if( self.param.enable_sort )
{
$('.sortable', domElem).click(
function()
{
$(this).off('click');
self.onClickSort(this);
}
);
if (self.param.filter_sort_column != '')
{
// are we in a subdatatable?
var currentIsSubDataTable = $(domElem).parent().hasClass('cellSubDataTable');
var prefixSortIcon = '';
if(currentIsSubDataTable)
{
prefixSortIcon = '_subtable_';
}
var imageSortWidth = 16;
var imageSortHeight = 16;
// we change the style of the column currently used as sort column
// adding an image and the class columnSorted to the TD
$(".sortable#"+self.param.filter_sort_column+' #thDIV', domElem).parent()
.addClass('columnSorted')
.prepend('<div id="sortIconContainer"><img id="sortIcon" width="'+imageSortWidth+'" height="'+imageSortHeight+'" src="themes/default/images/sort'+prefixSortIcon+ self.param.filter_sort_order+'.png" /></div>');
}
},
//behaviour for the DataTable 'search box'
handleSearchBox: function(domElem, callbackSuccess)
{
var self = this;
var currentPattern = self.param.filter_pattern;
if(typeof self.param.filter_pattern != "undefined"
&& self.param.filter_pattern.length > 0)
{
currentPattern = self.param.filter_pattern;
}
else if(typeof self.param.filter_pattern_recursive != "undefined"
&& self.param.filter_pattern_recursive.length > 0)
{
currentPattern = self.param.filter_pattern_recursive;
}
else
{
currentPattern = '';
}
.show()
.each(function(){
// when enter is pressed in the input field we submit the form
$('#keyword', this)
{
if(isEnterKey(e))
{
}
}
)
.val(currentPattern)
;
$(':submit', this).submit(
function()
{
var keyword = $(this).siblings('#keyword').val();
self.param.filter_offset = 0;
if(self.param.search_recursive)
{
self.param.filter_column_recursive = 'label';
self.param.filter_pattern_recursive = keyword;
}
else
{
self.param.filter_column = 'label';
self.param.filter_pattern = keyword;
}
self.reloadAjaxDataTable(true, callbackSuccess);
}
$(':submit', this)
.click( function(){ $(this).submit(); })
;
// in the case there is a searched keyword we display the RESET image
if(currentPattern)
{
var target = this;
var clearImg = $('<span style="position: relative;">\
<img src="plugins/CoreHome/templates/images/reset_search.png" style="position: absolute; top: 4px; left: -15px; cursor: pointer; display: inline;" title="Clear" />\
</span>')
.click( function() {
$('#keyword', target).val('');
$(':submit', target).submit();
});
$('#keyword',this).after(clearImg);
}
}
);
},
//behaviour for '< prev' 'next >' links and page count
handleOffsetInformation: function(domElem)
{
var self = this;
function(){
var offset = 1+Number(self.param.filter_offset);
var offsetEnd = Number(self.param.filter_offset) + Number(self.param.filter_limit);
var totalRows = Number(self.param.totalRows);
offsetEndDisp = offsetEnd;
if(offsetEnd > totalRows) offsetEndDisp = totalRows;
// only show this string if there is some rows in the datatable
if(totalRows != 0)
{
var str = sprintf(_pk_translate('CoreHome_PageOf_js'),offset + '-' + offsetEndDisp,totalRows);
}
}
);
// Display the next link if the total Rows is greater than the current end row
.each(function(){
var offsetEnd = Number(self.param.filter_offset)
+ Number(self.param.filter_limit);
var totalRows = Number(self.param.totalRows);
if(offsetEnd < totalRows)
{
$(this).css('display','inline');
}
})
// bind the click event to trigger the ajax request with the new offset
.click(function(){
$(this).off('click');
self.param.filter_offset = Number(self.param.filter_offset) + Number(self.param.filter_limit);
self.reloadAjaxDataTable();
})
;
// Display the previous link if the current offset is not zero
.each(function(){
var offset = 1+Number(self.param.filter_offset);
if(offset != 1)
{
$(this).css('display','inline');
}
}
)
// bind the click event to trigger the ajax request with the new offset
// take care of the negative offset, we setup 0
.click(
function(){
$(this).off('click');
var offset = Number(self.param.filter_offset) - Number(self.param.filter_limit);
if(offset < 0) { offset = 0; }
self.param.filter_offset = offset;
self.param.previous = 1;
self.reloadAjaxDataTable();
},
// DataTable view box (simple table, all columns table, Goals table, pie graph, tag cloud, graph, ...)
handleExportBox: function(domElem)
{
var self = this;
if( self.param.idSubtable )
return;
}
// When the (+) image is hovered, the export buttons are displayed
.show()
.hover( function() {
$(this).fadeOut('slow');
}, function(){}
);
self.jsViewDataTable=$('.dataTableFooterWrap', domElem).attr('var');
$('.tableAllColumnsSwitch a', domElem)
.show()
.click(
function(){
// we only reset the limit filter, in case switch to table view from cloud view where limit is custom set to 30
// this value is stored in config file General->datatable_default_limit but this is more an edge case so ok to set it to 10
self.setActiveIcon(this, domElem);
var viewDataTable = $(this).attr('format');
self.param.viewDataTable = viewDataTable;
//self.resetAllFilters();
// when switching to display simple table, do not exclude low pop by default
delete self.param.enable_filter_excludelowpop;
delete self.param.filter_sort_column;
delete self.param.filter_sort_order;
delete columns;
self.reloadAjaxDataTable();
self.notifyWidgetParametersChange($(this), {viewDataTable: self.param.viewDataTable});
)
$('.tableGraphViews a', domElem)
.click(function(){
var viewDataTable = $(this).attr('format');
self.setActiveIcon(this, domElem);
var filters = self.resetAllFilters();
self.param.flat = filters.flat;
self.param.columns = filters.columns;
self.param.viewDataTable = viewDataTable;
self.reloadAjaxDataTable();
self.notifyWidgetParametersChange($(this), {viewDataTable: self.param.viewDataTable});
});
//Graph icon Collapsed functionality
self.currentGraphViewIcon=0;
self.graphViewEnabled=0;
self.graphViewStartingThreads=0;
self.graphViewStartingKeep=false; //show keep flag
//define collapsed icons
$('.tableGraphCollapsed a', domElem)
.each(function(i){
if(self.jsViewDataTable==$(this).attr('var')){
self.currentGraphViewIcon=i;
self.graphViewEnabled=true;
}
})
.each(function(i){
if(self.currentGraphViewIcon!=i) $(this).hide();
});
$('.tableGraphCollapsed', domElem).hover(
function(){
//Graph icon onmouseover
if(self.graphViewStartingThreads>0) return self.graphViewStartingKeep=true; //exit if animation is not finished
$(this).addClass('tableIconsGroupActive');
$('a', this).each(function(i){
if(self.currentGraphViewIcon!=i || self.graphViewEnabled){
self.graphViewStartingThreads++;
}
if(self.currentGraphViewIcon!=i){
//show other icons
$(this).show('fast', function(){self.graphViewStartingThreads--});
}
else if (self.graphViewEnabled){
//set footer arrow position
$('.dataTableFooterActiveItem', domElem).animate({left:$(this).parent().position().left+i*(this.offsetWidth+1)}, "fast", function(){self.graphViewStartingThreads--});
}
});
self.exportToFormatHide(domElem);
},
function(){
//Graph icon onmouseout
if(self.graphViewStartingKeep) return self.graphViewStartingKeep=false; //exit while icons animate
$('a', this).each(function(i){
if(self.currentGraphViewIcon!=i){
//hide other icons
$(this).hide('fast');
}
else if (self.graphViewEnabled){
//set footer arrow position
$('.dataTableFooterActiveItem', domElem).animate({left:$(this).parent().position().left}, "fast");
}
});
$(this).removeClass('tableIconsGroupActive');
}
);
self.exportToFormat=null;
$('.exportToFormatIcons a', domElem).click(function(){
self.exportToFormat={};
self.exportToFormat.lastActiveIcon=self.setActiveIcon(this, domElem);
self.exportToFormat.target=$(this).parent().siblings('.exportToFormatItems').show('fast');
self.exportToFormat.obj=$(this).hide();
});
$('body').on('mouseup',function(e){
if(self.exportToFormat){
self.exportToFormatHide(domElem);
}
});
$('.exportToFormatItems a', domElem)
// prevent click jacking attacks by dynamically adding the token auth when the link is clicked
.click( function() {
$(this).attr('href', function() {
return $(this).attr('href') +'&token_auth='+piwik.token_auth;
})
})
.attr( 'href', function(){
var format = $(this).attr('format');
var method = $(this).attr('methodToCall');
var filter_limit = $(this).attr('filter_limit');
var label = self.param.label;
mattpiwik
a validé
var idGoal = self.param.idGoal;
var param_date = self.param.date;
var date = $(this).attr('date');
if(typeof date != 'undefined') {
param_date = date;
}
mattpiwik
a validé
var period = self.param.period;
// RSS does not work for period=range
if(format == 'RSS'
&& self.param.period == 'range') {
period = 'day';
}
var str = 'index.php?module=API'
+'&method='+method
+'&format='+format
+'&idSite='+self.param.idSite
mattpiwik
a validé
+'&period='+period
+'&date='+param_date
+ ( typeof self.param.filter_pattern != "undefined" ? '&filter_pattern=' + self.param.filter_pattern : '')
+ ( typeof self.param.filter_pattern_recursive != "undefined" ? '&filter_pattern_recursive=' + self.param.filter_pattern_recursive : '');
if (typeof self.param.flat != "undefined" && self.param.flat) {
str += '&flat=1';
if (typeof self.param.include_aggregate_rows != "undefined" && self.param.include_aggregate_rows) {
}
if (format == 'CSV' || format == 'TSV' || format == 'RSS') {
str += '&translateColumnNames=1&language='+piwik.language;
if(typeof segment != 'undefined') {
str += '&segment='+segment;
}
mattpiwik
a validé
// Export Goals specific reports
if(typeof idGoal != 'undefined'
&& idGoal != '-1') {
mattpiwik
a validé
str += '&idGoal='+idGoal;
}
{
str += '&filter_limit='+filter_limit;
}
if(label)
{
str += '&label='+encodeURIComponent(label);
}
return str;
}
);
$('.dataTableFooterWrap a.tableIcon', domElem).each(function(){
if(self.jsViewDataTable==$(this).attr('var')) self.setActiveIcon(this, domElem);
});
},
{
var self=this;
if(self.exportToFormat){
self.setActiveIcon(self.exportToFormat.lastActiveIcon, domElem);
var animationSpeed = noAnimation ? 0 : 'fast';
self.exportToFormat.target.hide(animationSpeed);
self.exportToFormat.obj.show(animationSpeed);
self.exportToFormat=null;
}
},
handleConfigurationBox: function(domElem, callbackSuccess)
{
var self = this;
if (typeof self.parentId != "undefined" && self.parentId != '')
{
// no manipulation when loading subtables
return;
}
if ((typeof self.numberOfSubtables == 'undefined' || self.numberOfSubtables == 0)
&& (typeof self.param.flat == 'undefined' || self.param.flat != 1))
{
// if there are no subtables, remove the flatten action
$('.dataTableFlatten', domElem).parent().remove();
}
var ul = $('div.tableConfiguration ul', domElem);
if (ul.find('li').size() == 0 ||
!(self.param.viewDataTable == 'table' || self.param.viewDataTable == 'tableAllColumns'
|| self.param.viewDataTable == 'tableGoals'))
// hide the icon when there are no actions available or we're not in a table view
$('div.tableConfiguration', domElem).remove();
return;
}
var icon = $('a.tableConfigurationIcon', domElem);
icon.click(function() { return false; });
var iconHighlighted = false;
ul.find('li:first').addClass('first');
ul.find('li:last').addClass('last');
ul.prepend('<li class="firstDummy"></li>');
// open and close the box
ul.addClass('open');
icon.css('opacity', 1);
};
ul.removeClass('open');
icon.css('opacity', icon.hasClass('highlighted') ? .85 : .6);
};
var generateClickCallback = function(paramName, callbackAfterToggle)
{
return function()
{
close();
self.param[paramName] = 1 - self.param[paramName];
self.param.filter_offset = 0;
if (callbackAfterToggle) callbackAfterToggle();
self.reloadAjaxDataTable(true, callbackSuccess);
var data = {};
data[paramName] = self.param[paramName];
self.notifyWidgetParametersChange(domElem, data);
};
};
var getText = function(text, addDefault)
{
text = _pk_translate(text);
if (text.indexOf('%s') > 0)
{
text = text.replace('%s', '<br /><span class="action">» ');
if (addDefault) text += ' (' + _pk_translate('CoreHome_Default_js') + ')';
var setText = function(el, paramName, textA, textB)
{
if (typeof self.param[paramName] != 'undefined' && self.param[paramName] == 1)
{
$(el).html(getText(textA, true));
iconHighlighted = true;
}
else
{
self.param[paramName] = 0;
}
};
// handle low population
$('.dataTableExcludeLowPopulation', domElem)
.each(function()
{
// Set the text, either "Exclude low pop" or "Include all"
if(typeof self.param.enable_filter_excludelowpop == 'undefined')
{
self.param.enable_filter_excludelowpop = 0;
}
if(Number(self.param.enable_filter_excludelowpop) != 0)
{
string = getText('CoreHome_IncludeRowsWithLowPopulation_js', true);
self.param.enable_filter_excludelowpop = 1;
iconHighlighted = true;
}
else
{
self.param.enable_filter_excludelowpop = 0;
}
$(this).html(string);
})
.click( generateClickCallback('enable_filter_excludelowpop') );
// handle flatten
$('.dataTableFlatten', domElem)
.each( function() {
setText(this, 'flat', 'CoreHome_UnFlattenDataTable_js', 'CoreHome_FlattenDataTable_js');
})
.click( generateClickCallback('flat') );
$('.dataTableIncludeAggregateRows', domElem)
.each( function() {
setText(this, 'include_aggregate_rows', 'CoreHome_DataTableExcludeAggregateRows_js',
'CoreHome_DataTableIncludeAggregateRows_js');
})
.click( generateClickCallback('include_aggregate_rows', function() {
if (self.param.include_aggregate_rows == 1)
{
// when including aggregate rows is enabled, we remove the sorting
// this way, the aggregate rows appear directly before their children
self.param.filter_sort_column = '';
self.notifyWidgetParametersChange(domElem, {filter_sort_column: ''});
}
}));
// handle highlighted icon
if (iconHighlighted)
{
icon.addClass('highlighted');
}
close();
// fix a css bug of ie7
if (document.all && !window.opera && window.XMLHttpRequest)
{
window.setTimeout(function() {
open();
var width = 0;
ul.find('li').each(function() {
width = Math.max(width, $(this).width());
}).width(width);
close();
}, 400);
}
},
setActiveIcon: function(obj, domElem)
{
if(!obj) return false;
var lastActiveIcon=this.lastActiveIcon;
if(lastActiveIcon){
$(lastActiveIcon).removeClass("activeIcon");
}
$(obj).addClass("activeIcon");
this.lastActiveIcon=obj;
var target=$('.dataTableFooterActiveItem', domElem);
//set arrow position with delay (for ajax widget loading)
setTimeout(function(){
},100);
return lastActiveIcon;
},
// Tell parent widget that the parameters of this table was updated,
notifyWidgetParametersChange: function(domWidget, parameters)
{
var widget = $(domWidget).parents('[widgetId]');
// trigger setParameters event on base element
widget.trigger('setParameters', parameters);
},
truncate: function(domElemToTruncate, truncationOffset)
{
var self = this;
domElemToTruncate = $(domElemToTruncate);
if (typeof domElemToTruncate.data('originalText') != 'undefined')
{
// truncate only once. otherwise, the tooltip will show the truncated text as well.
return;
}
// make the original text (before truncation) available for others.
// the .truncate plugins adds a title to the dom element but the .tooltip
// plugin removes that again.
domElemToTruncate.data('originalText', domElemToTruncate.text());
if (typeof truncationOffset == 'undefined')
{
truncationOffset = 0;
}
if (typeof self.param.idSubtable == 'undefined'
&& self.param.viewDataTable == 'tableAllColumns')
{
// when showing all columns in a subtable, space is restricted
truncationLimit = 25;
}
domElemToTruncate.truncate(truncationLimit);
},
//Apply some miscelleaneous style to the DataTable
applyCosmetics: function(domElem)
{
var self = this;
// Add some styles on the cells even/odd
// label (first column of a data row) or not
$("th:first-child", domElem).addClass('label');
$("td:first-child:odd", domElem).addClass('label labeleven');
$("td:first-child:even", domElem).addClass('label labelodd');
$("tr:odd td", domElem).slice(1).addClass('columnodd');
$("tr:even td", domElem).slice(1).addClass('columneven');
$('td span.label', domElem).each(function(){ self.truncate($(this)); } );
},
//behaviour for 'nested DataTable' (DataTable loaded on a click on a row)
handleSubDataTable: function(domElem)
{
var self = this;
// When the TR has a subDataTable class it means that this row has a link to a subDataTable
this.numberOfSubtables = $('tr.subDataTable', domElem)
.click(
function()
{
// get the idSubTable
var idSubTable = $(this).attr('id');
var divIdToReplaceWithSubTable = 'subDataTable_'+idSubTable;
// if the subDataTable is not already loaded
if (typeof self.loadedSubDataTable[divIdToReplaceWithSubTable] == "undefined")
{
var numberOfColumns = $(this).children().length;
// at the end of the query it will replace the ID matching the new HTML table #ID
// we need to create this ID first
$(this).after(
'<tr>'+
'<td colspan="'+numberOfColumns+'" class="cellSubDataTable">'+
'<div id="'+divIdToReplaceWithSubTable+'">'+
'<span class="loadingPiwik" style="display:inline"><img src="themes/default/images/loading-blue.gif" />'+ _pk_translate('General_Loading_js') +'</span>'+
'</div>'+
'</td>'+
'</tr>'
);
var savedActionVariable = self.param.action;
// reset all the filters from the Parent table
var filtersToRestore = self.resetAllFilters();
mattpiwik
a validé
// do not ignore the exclude low population click
self.param.enable_filter_excludelowpop = filtersToRestore.enable_filter_excludelowpop;
self.param.idSubtable = idSubTable;
self.param.action = self.param.controllerActionCalledWhenRequestSubTable;
self.reloadAjaxDataTable(false);
self.param.action = savedActionVariable;
delete self.param.idSubtable;
self.restoreAllFilters(filtersToRestore);
self.loadedSubDataTable[divIdToReplaceWithSubTable] = true;
$(this).next().toggle();
// when "loading..." is displayed, hide actions
// repositioning after loading is not easily possible
$(this).find('div.dataTableRowActions').hide();
}
$(this).next().toggle();
self.repositionRowActions($(this));
}
).size();
},
// tooltip for column documentation
handleColumnDocumentation: function(domElem)
{
if ($('#dashboard').size() > 0) {
// don't display column documentation in dashboard
// it causes trouble in full screen view
return;
}