Add JS files
This commit is contained in:
145
modules/EcmReports/TableSorterNew/js/widgets/widget-alignChar.js
Normal file
145
modules/EcmReports/TableSorterNew/js/widgets/widget-alignChar.js
Normal file
@@ -0,0 +1,145 @@
|
||||
/*! tablesorter Align Character widget - updated 3/12/2014 (core v2.15.8)
|
||||
* Requires tablesorter v2.8+ and jQuery 1.7+
|
||||
* by Rob Garrison
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
var ts = $.tablesorter;
|
||||
|
||||
ts.alignChar = {
|
||||
|
||||
init : function(table, c, wo) {
|
||||
c.$headers.filter('[' + wo.alignChar_charAttrib + ']').each(function(){
|
||||
var $this = $(this),
|
||||
vars = {
|
||||
column : this.column,
|
||||
align : $this.attr(wo.alignChar_charAttrib),
|
||||
alignIndex : parseInt( $this.attr(wo.alignChar_indexAttrib) || 0, 10),
|
||||
adjust : parseFloat($this.attr(wo.alignChar_adjustAttrib)) || 0,
|
||||
};
|
||||
vars.regex = new RegExp('\\' + vars.align, 'g');
|
||||
if (typeof vars.align !== 'undefined') {
|
||||
wo.alignChar_savedVars[this.column] = vars;
|
||||
ts.alignChar.setup(table, c, wo, vars);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setup: function(table, c, wo, v){
|
||||
// do nothing for empty tables
|
||||
if ($.isEmptyObject(c.cache)) { return; }
|
||||
var tbodyIndex, rowIndex, start, end, last, index, rows, val, count,
|
||||
len, wLeft, wRight, alignChar, $row,
|
||||
left = [],
|
||||
right = [];
|
||||
for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++){
|
||||
rows = c.cache[tbodyIndex];
|
||||
len = rows.normalized.length;
|
||||
for (rowIndex = 0; rowIndex < len; rowIndex++) {
|
||||
// set up to work with modified cache v2.16.0+
|
||||
$row = rows.row ? rows.row[rowIndex] : rows.normalized[rowIndex][c.columns].$row;
|
||||
val = $row.find('td').eq(v.column).text().replace(/[ ]/g, "\u00a0");
|
||||
// count how many "align" characters are in the string
|
||||
count = (val.match( v.regex ) || []).length;
|
||||
// set alignment @ alignIndex (one-based index)
|
||||
if (count > 0 && v.alignIndex > 0) {
|
||||
end = Math.min(v.alignIndex, count);
|
||||
start = 0;
|
||||
index = 0;
|
||||
last = 0;
|
||||
// find index of nth align character based on alignIndex (data-align-index)
|
||||
while (start++ < end) {
|
||||
last = val.indexOf(v.align, last + 1);
|
||||
index = last < 0 ? index : last;
|
||||
}
|
||||
} else {
|
||||
index = val.indexOf(v.align);
|
||||
}
|
||||
if ( index >= 0 ) {
|
||||
left.push( val.substring(0, index) || '' );
|
||||
right.push( val.substring(index, val.length) || '' );
|
||||
} else {
|
||||
// no align character found!
|
||||
// put val in right or left based on the align index
|
||||
left.push( (count >= 1 && v.alignIndex >= count) ? '' : val || '' );
|
||||
right.push( (count >= 1 && v.alignIndex >= count) ? val || '' : '' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find widest segments
|
||||
wLeft = ($.extend([], left)).sort(function(a,b){ return b.length - a.length; })[0];
|
||||
wRight = ($.extend([], right)).sort(function(a,b){ return b.length - a.length; })[0];
|
||||
// calculate percentage widths
|
||||
v.width = v.width || ( Math.floor(wLeft.length / (wLeft.length + wRight.length) * 100) + v.adjust );
|
||||
wLeft = 'min-width:' + v.width + '%';
|
||||
wRight = 'min-width:' + (100 - v.width) + '%';
|
||||
|
||||
for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++){
|
||||
rows = c.cache[tbodyIndex];
|
||||
len = rows.normalized.length;
|
||||
for (rowIndex = 0; rowIndex < len; rowIndex++) {
|
||||
alignChar = $(wo.alignChar_wrap).length ? $(wo.alignChar_wrap).html(v.align)[0].outerHTML : v.align;
|
||||
$row = rows.row ? rows.row[rowIndex] : rows.normalized[rowIndex][c.columns].$row;
|
||||
$row.find('td').eq(v.column).html(
|
||||
'<span class="ts-align-wrap"><span class="ts-align-left" style="' + wLeft + '">' + left[rowIndex] + '</span>' +
|
||||
'<span class="ts-align-right" style="' + wRight + '">' + alignChar +
|
||||
right[rowIndex].slice(v.align.length) + '</span></span>'
|
||||
);
|
||||
}
|
||||
}
|
||||
wo.alignChar_initialized = true;
|
||||
|
||||
},
|
||||
remove: function(table, c, column){
|
||||
if ($.isEmptyObject(c.cache)) { return; }
|
||||
var tbodyIndex, rowIndex, len, rows, $row, $cell;
|
||||
for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++){
|
||||
rows = c.cache[tbodyIndex];
|
||||
len = rows.normalized.length;
|
||||
for (rowIndex = 0; rowIndex < len; rowIndex++) {
|
||||
$row = rows.row ? rows.row[rowIndex] : rows.normalized[rowIndex][c.columns].$row;
|
||||
$cell = $row.find('td').eq(column);
|
||||
$cell.html( $cell.text().replace(/\s/g, ' ') );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ts.addWidget({
|
||||
id: 'alignChar',
|
||||
priority: 100,
|
||||
options: {
|
||||
alignChar_wrap : '',
|
||||
alignChar_charAttrib : 'data-align-char',
|
||||
alignChar_indexAttrib : 'data-align-index',
|
||||
alignChar_adjustAttrib : 'data-align-adjust' // percentage width adjustments
|
||||
},
|
||||
init: function(table, thisWidget, c, wo){
|
||||
wo.alignChar_initialized = false;
|
||||
wo.alignChar_savedVars = [];
|
||||
ts.alignChar.init(table, c, wo);
|
||||
c.$table.on('pagerEnd refreshAlign', function(){
|
||||
c.$headers.filter('[' + wo.alignChar_charAttrib + ']').each(function(){
|
||||
ts.alignChar.remove(table, c, this.column);
|
||||
});
|
||||
ts.alignChar.init(table, c, wo);
|
||||
});
|
||||
},
|
||||
format : function(table, c, wo){
|
||||
// reinitialize in case table is empty when first initialized
|
||||
if (!wo.alignChar_initialized) {
|
||||
c.$table.trigger('refreshAlign');
|
||||
}
|
||||
},
|
||||
remove : function(table, c, wo){
|
||||
c.$headers.filter('[' + wo.alignChar_charAttrib + ']').each(function(){
|
||||
ts.alignChar.remove(table, c, this.column);
|
||||
});
|
||||
wo.alignChar_initialized = false;
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,453 @@
|
||||
/*! Build Table widget for tableSorter v2.16.0 (4/23/2014)
|
||||
* by Rob Garrison
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
var ts = $.tablesorter = $.tablesorter || {},
|
||||
|
||||
// build a table from data (requires existing <table> tag)
|
||||
// data.header contains an array of header titles
|
||||
// data.rows contains an array of rows which contains an array of cells
|
||||
bt = ts.buildTable = function(tar, c){
|
||||
// add table if one doesn't exist
|
||||
var $tbl = tar.tagName === 'TABLE' ? $(tar) : $('<table>').appendTo(tar),
|
||||
table = $tbl[0],
|
||||
wo = c.widgetOptions = $.extend( true, {}, bt.defaults, c.widgetOptions ),
|
||||
p = wo.build_processing,
|
||||
typ = wo.build_type,
|
||||
d = wo.build_source || c.data,
|
||||
|
||||
// determine type: html, json, array, csv, object
|
||||
runType = function(d){
|
||||
var t = $.type(d),
|
||||
jq = d instanceof jQuery;
|
||||
// run any processing if set
|
||||
if ( typeof p === 'function' ) { d = p(d, wo); }
|
||||
// store processed data in table.config.data
|
||||
c.data = d;
|
||||
// String (html or unprocessed json) or jQuery object
|
||||
if ( jq || t === 'string' ) {
|
||||
// look for </tr> closing tag, then we have an HTML string
|
||||
if ( jq || /<\s*\/tr\s*>/.test(d) ) {
|
||||
return bt.html( table, d, wo );
|
||||
}
|
||||
try {
|
||||
d = $.parseJSON(d);
|
||||
if (d) {
|
||||
// valid JSON!
|
||||
return bt.object( table, d, wo );
|
||||
}
|
||||
} catch(ignore) {}
|
||||
// fall through in case it's a csv string
|
||||
}
|
||||
// Array
|
||||
if (t === 'array' || t === 'string' || typ === 'array' || typ === 'csv') {
|
||||
// build table using an array (csv & array combined script)
|
||||
return bt.csv( table, d, wo );
|
||||
}
|
||||
// if we got here, it's an object, or nothing
|
||||
return bt.object( table, d, wo );
|
||||
};
|
||||
|
||||
// store config
|
||||
table.config = c;
|
||||
|
||||
// even if wo.build_type is undefined, we can try to figure out the type
|
||||
if ( !ts.buildTable.hasOwnProperty(typ) && typ !== '' ) {
|
||||
if (c.debug) { ts.log('aborting build table widget, incorrect build type'); }
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( d instanceof jQuery ) {
|
||||
// get data from within a jQuery object (csv)
|
||||
runType( $.trim( d.html() ) );
|
||||
} else if ( d && ( d.hasOwnProperty('url') || typ === 'json' ) ) {
|
||||
// load data via ajax
|
||||
$.ajax( wo.build_source )
|
||||
.done(function(data) {
|
||||
runType(data);
|
||||
})
|
||||
.fail(function( jqXHR, textStatus, errorThrown) {
|
||||
if (c.debug) { ts.log('aborting build table widget, failed ajax load'); }
|
||||
$tbl.html('<tr><td class="error">' + jqXHR.status + ' ' + textStatus + '</td></tr>');
|
||||
});
|
||||
} else {
|
||||
runType(d);
|
||||
}
|
||||
};
|
||||
|
||||
bt.defaults = {
|
||||
// *** build widget core ***
|
||||
build_type : '', // array, csv, object, json, html
|
||||
build_source : '', // array, object, jQuery Object or ajaxObject { url: '', dataType: 'json' },
|
||||
build_processing : null, // function that returns a useable build_type (e.g. string to array)
|
||||
build_complete : 'tablesorter-build-complete', // triggered event when build completes
|
||||
|
||||
// *** CSV & Array ***
|
||||
build_headers : {
|
||||
rows : 1, // Number of header rows from the csv
|
||||
classes : [], // Header classes to apply to cells
|
||||
text : [], // Header cell text
|
||||
widths : [] // set header cell widths (set in colgroup)
|
||||
},
|
||||
build_footers : {
|
||||
rows : 1, // Number of header rows from the csv
|
||||
classes : [], // Footer classes to apply to cells
|
||||
text : [] // Footer cell text
|
||||
},
|
||||
build_numbers : {
|
||||
addColumn : false, // include row numbering column?
|
||||
sortable : false // make column sortable?
|
||||
},
|
||||
|
||||
// *** CSV only options ***
|
||||
build_csvStartLine : 0, // line within the csv to start adding to table
|
||||
build_csvSeparator : ",", // csv separator
|
||||
|
||||
// *** build object options ***
|
||||
build_objectRowKey : 'rows', // object key containing table rows
|
||||
build_objectCellKey : 'cells', // object key containing table cells (within the rows object)
|
||||
build_objectHeaderKey : 'headers', // object key containing table headers
|
||||
build_objectFooterKey : 'footers' // object key containing table footers
|
||||
};
|
||||
|
||||
bt.build = {
|
||||
colgroup : function(widths) {
|
||||
var t = '';
|
||||
// add colgroup if widths set
|
||||
if (widths && widths.length) {
|
||||
t += '<colgroup>';
|
||||
$.each(widths, function(i, w){
|
||||
t += '<col' + ( w ? ' style="width:' + w + '"' : '' ) + '>';
|
||||
});
|
||||
t += '</colgroup>';
|
||||
}
|
||||
return t;
|
||||
},
|
||||
// d = cell data; typ = 'th' or 'td'; first = save widths from first header row only
|
||||
cell : function(d, wo, typ, col, first){
|
||||
var j, $td,
|
||||
$col = first ? $('<col>') : '',
|
||||
cls = wo.build_headers.classes,
|
||||
cw = wo.build_headers.widths;
|
||||
// d is just an array
|
||||
if (/string|number/.test(typeof d)) {
|
||||
// add classes from options, but not text
|
||||
$td = $('<' + typ + (cls && cls[col] ? ' class="' + cls[col] + '"' : '') + '>' + d + '</' + typ + '>');
|
||||
// get widths from options (only from first row)
|
||||
if (first && cw && cw[col]) {
|
||||
$col.width(cw[col] || '');
|
||||
}
|
||||
} else {
|
||||
// assume we have an object
|
||||
$td = $('<' + typ + '>');
|
||||
for (j in d) {
|
||||
if (d.hasOwnProperty(j)){
|
||||
if (j === 'text' || j === 'html') {
|
||||
$td[j]( d[j] );
|
||||
} else if (first && j === 'width') {
|
||||
// set column width, but only from first row
|
||||
$col.width(d[j] || '');
|
||||
} else {
|
||||
$td.attr(j, d[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return [ $td, $col ];
|
||||
},
|
||||
// h1 = header text from data
|
||||
header : function(h1, wo){
|
||||
var h2 = wo.build_headers.text,
|
||||
cls = wo.build_headers.classes,
|
||||
t = '<tr>' + (wo.build_numbers.addColumn ? '<th' + (wo.build_numbers.sortable ? '' :
|
||||
' class="sorter-false"') + '>' + wo.build_numbers.addColumn + '</th>' : '');
|
||||
$.each(h1, function(i, h) {
|
||||
if (/<\s*\/t(d|h)\s*>/.test(h)) {
|
||||
t += h;
|
||||
} else {
|
||||
t += '<th' + (cls && cls[i] ? ' class="' + cls[i] + '"' : '') + '>' +
|
||||
(h2 && h2[i] ? h2[i] : h) + '</th>';
|
||||
}
|
||||
});
|
||||
return t + '</tr>';
|
||||
},
|
||||
rows : function(items, txt, c, wo, num, ftr){
|
||||
var h = (ftr ? 'th' : 'td'),
|
||||
t = '<tr>' + (wo.build_numbers.addColumn ? '<' + h + '>' + (ftr ? '' : num) + '</' + h + '>' : '');
|
||||
$.each(items, function(i, item) {
|
||||
// test if HTML is already included; look for closing </td>
|
||||
if (/<\s*\/t(d|h)\s*>/.test(item)) {
|
||||
t += item;
|
||||
} else {
|
||||
t += '<' + (ftr ? h + (c && c[i] ? ' class="' + c[i] + '"' : '') : h) + '>' +
|
||||
(ftr && txt && txt.length && txt[i] ? txt[i] : item) + '</' + h + '>';
|
||||
}
|
||||
});
|
||||
return t + '</tr>';
|
||||
}
|
||||
};
|
||||
|
||||
bt.buildComplete = function(table, wo){
|
||||
$(table).trigger(wo.build_complete);
|
||||
ts.setup(table, table.config);
|
||||
};
|
||||
|
||||
/* ==== Array example ====
|
||||
[
|
||||
[ "header1", "header2", ... "headerN" ],
|
||||
[ "row1cell1", "row1cell2", ... "row1cellN" ],
|
||||
[ "row2cell1", "row2cell2", ... "row2cellN" ],
|
||||
...
|
||||
[ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
|
||||
]
|
||||
*/
|
||||
bt.array = function(table, data, wo) {
|
||||
return bt.csv(table, data, wo);
|
||||
};
|
||||
|
||||
/* ==== CSV example ====
|
||||
ID, Name, Age, Date
|
||||
A42b, Parker, 28, "Jul 6, 2006 8:14 AM"
|
||||
A255, Hood, 33, "Dec 10, 2002 5:14 AM"
|
||||
A33, Kent, 18, "Jan 12, 2003 11:14 AM"
|
||||
A1, Franklin, 45, "Jan 18, 2001 9:12 AM"
|
||||
A102, Evans, 22, "Jan 18, 2007 9:12 AM"
|
||||
A42a, Everet, 22, "Jan 18, 2007 9:12 AM"
|
||||
ID, Name, Age, Date
|
||||
*/
|
||||
// Adapted & modified from csvToTable.js by Steve Sobel
|
||||
// MIT license: https://code.google.com/p/jquerycsvtotable/
|
||||
bt.csv = function(table, data, wo) {
|
||||
var c, h,
|
||||
csv = wo.build_type === 'csv' || typeof data === 'string',
|
||||
$t = $(table),
|
||||
lines = csv ? data.replace('\r','').split('\n') : data,
|
||||
len = lines.length,
|
||||
printedLines = 0,
|
||||
infooter = false,
|
||||
r = wo.build_headers.rows + (csv ? wo.build_csvStartLine : 0),
|
||||
f = wo.build_footers.rows,
|
||||
headerCount = 0,
|
||||
error = '',
|
||||
items,
|
||||
tableHTML = bt.build.colgroup( wo.build_headers.widths ) + '<thead>';
|
||||
|
||||
$.each(lines, function(n, line) {
|
||||
if ( n >= len - f ) { infooter = true; }
|
||||
// build header
|
||||
if ( (csv ? n >= wo.build_csvStartLine : true) && ( n < r ) ) {
|
||||
h = csv ? bt.splitCSV( line, wo.build_csvSeparator ) : line;
|
||||
headerCount = h.length;
|
||||
tableHTML += bt.build.header(h, wo);
|
||||
} else if ( n >= r ) {
|
||||
// build tbody & tfoot rows
|
||||
if (n === r) {
|
||||
tableHTML += '</thead><tbody>';
|
||||
}
|
||||
items = csv ? bt.splitCSV( line, wo.build_csvSeparator ) : line;
|
||||
if (infooter && f > 0) {
|
||||
tableHTML += (n === len - f ? '</tbody><tfoot>' : '') +
|
||||
(n === len ? '</tfoot>' : '');
|
||||
}
|
||||
if (items.length > 1) {
|
||||
printedLines++;
|
||||
if ( items.length !== headerCount ) {
|
||||
error += 'error on line ' + n + ': Item count (' + items.length +
|
||||
') does not match header count (' + headerCount + ') \n';
|
||||
}
|
||||
c = infooter ? wo.build_footers.classes : '';
|
||||
tableHTML += bt.build.rows(items, wo.build_footers.text, c, wo, printedLines, infooter);
|
||||
}
|
||||
}
|
||||
});
|
||||
tableHTML += (f > 0 ? '' : '</tbody>');
|
||||
if (error) {
|
||||
$t.html(error);
|
||||
} else {
|
||||
$t.html(tableHTML);
|
||||
bt.buildComplete(table, wo);
|
||||
}
|
||||
};
|
||||
|
||||
// CSV Parser by Brian Huisman (http://www.greywyvern.com/?post=258)
|
||||
bt.splitCSV = function(str, sep) {
|
||||
var x, tl,
|
||||
thisCSV = $.trim(str).split(sep = sep || ",");
|
||||
for ( x = thisCSV.length - 1; x >= 0; x-- ) {
|
||||
if ( thisCSV[x].replace(/\"\s+$/, '"').charAt(thisCSV[x].length - 1) === '"' ) {
|
||||
if ( (tl = thisCSV[x].replace(/^\s+\"/, '"')).length > 1 && tl.charAt(0) === '"' ) {
|
||||
thisCSV[x] = thisCSV[x].replace(/^\s*"|"\s*$/g, '').replace(/""/g, '"');
|
||||
} else if (x) {
|
||||
thisCSV.splice(x - 1, 2, [thisCSV[x - 1], thisCSV[x]].join(sep));
|
||||
} else {
|
||||
thisCSV = thisCSV.shift().split(sep).concat(thisCSV);
|
||||
}
|
||||
} else {
|
||||
thisCSV[x].replace(/""/g, '"');
|
||||
}
|
||||
}
|
||||
return thisCSV;
|
||||
};
|
||||
|
||||
// data may be a jQuery object after processing
|
||||
bt.html = function(table, data, wo) {
|
||||
var $t = $(table);
|
||||
if ( data instanceof jQuery ) {
|
||||
$t.empty().append(data);
|
||||
} else {
|
||||
$t.html(data);
|
||||
}
|
||||
bt.buildComplete(table, wo);
|
||||
};
|
||||
|
||||
/* ==== Object example ====
|
||||
data : {
|
||||
headers : [
|
||||
[
|
||||
{ text: 'First Name', class: 'fname', width: '20%' }, // row 1 cell 1
|
||||
'Last Name',
|
||||
{ text: 'Age', class: 'age', 'data-sorter' : false },
|
||||
'Total',
|
||||
{ text: 'Discount', class : 'sorter-false' },
|
||||
{ text: 'Date', class : 'date' } // row 1 cell 6
|
||||
]
|
||||
],
|
||||
footers : 'clone', // clone headers or assign array like headers
|
||||
rows : [
|
||||
// TBODY 1
|
||||
[ 'Peter', 'Parker', 28, '$9.99', '20%', 'Jul 6, 2006 8:14 AM' ], // row 1
|
||||
[ 'John', 'Hood', 33, '$19.99', '25%', 'Dec 10, 2002 5:14 AM' ], // row 2
|
||||
[ 'Clark', 'Kent', 18, '$15.89', '44%', 'Jan 12, 2003 11:14 AM' ], // row 3
|
||||
|
||||
// TBODY 2
|
||||
{ newTbody: true, class: 'tablesorter-infoOnly' },
|
||||
{ cells : [ { text: 'Info Row', colSpan: 6 } ] }, // row 4
|
||||
|
||||
// TBODY 3
|
||||
{ newTbody: true },
|
||||
[ 'Bruce', 'Evans', 22, '$13.19', '11%', 'Jan 18, 2007 9:12 AM' ], // row 5
|
||||
[ 'Brice', 'Almighty', 45, '$153.19', '44%', 'Jan 18, 2001 9:12 AM' ], // row 6
|
||||
|
||||
{ class: 'specialRow', // row 7
|
||||
cells: [
|
||||
{ text: 'Fred', class: 'fname' },
|
||||
{ text: 'Smith', class: 'lname' },
|
||||
{ text: 18, class: 'age', 'data-info': 'fake ID!, he is really 16' },
|
||||
{ text: '$22.44', class: 'total' },
|
||||
{ text: '8%', class: 'discount' },
|
||||
{ text: 'Aug 20, 2012 10:15 AM', class: 'date' }
|
||||
],
|
||||
'data-info' : 'This row likes turtles'
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
bt.object = function(table, data, wo) {
|
||||
// "rows"
|
||||
var j, l, t, $c, $t, $tb, $tr,
|
||||
c = table.config,
|
||||
kh = wo.build_objectHeaderKey,
|
||||
kr = wo.build_objectRowKey,
|
||||
h = data.hasOwnProperty(kh) && !$.isEmptyObject(data.kh) ? data.kh : data.hasOwnProperty('headers') ? data.headers : false,
|
||||
r = data.hasOwnProperty(kr) && !$.isEmptyObject(data.kr) ? data.kr : data.hasOwnProperty('rows') ? data.rows : false;
|
||||
|
||||
if (!h || !r || h.length === 0 || r.length === 0) {
|
||||
if (c.debug) { ts.log('aborting build table widget, missing data for object build'); }
|
||||
return false;
|
||||
}
|
||||
|
||||
$c = $('<colgroup>');
|
||||
$t = $('<table><thead/></table>');
|
||||
|
||||
// Build thead
|
||||
// h = [ ['headerRow1Cell1', 'headerRow1Cell2', ... 'headerRow1CellN' ], ['headerRow2Cell1', ... ] ]
|
||||
// or h = [ [ { text: 'firstCell', class: 'fc', width: '20%' }, ..., { text: 'last Cell' } ], [ /* second row */ ] ]
|
||||
$.each(h, function(i, d){
|
||||
$tr = $('<tr>').appendTo( $t.find('thead') );
|
||||
l = d.length; // header row
|
||||
for ( j = 0; j < l; j++ ) {
|
||||
// cell(cellData, widgetOptions, 'th', first row)
|
||||
t = bt.build.cell(d[j], wo, 'th', j, i === 0);
|
||||
if (t[0] && t[0].length) { t[0].appendTo( $tr ); } // add cell
|
||||
if (i === 0 && t[1]) { t[1].appendTo( $c ); } // add col to colgroup
|
||||
}
|
||||
});
|
||||
if ($c.find('col[style]').length) {
|
||||
// add colgroup if it contains col elements
|
||||
$t.prepend( $c );
|
||||
}
|
||||
|
||||
$tb = $('<tbody>');
|
||||
// Build tbody
|
||||
$.each(r, function(i, d){
|
||||
var j;
|
||||
t = $.type(d) === 'object';
|
||||
// add new tbody
|
||||
if (t && d.newTbody) {
|
||||
$tb = $('<tbody>').appendTo( $t );
|
||||
for (j in d) {
|
||||
if (d.hasOwnProperty(j) && j !== 'newTbody'){
|
||||
$tb.attr(j, d[j]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (i === 0) {
|
||||
// add tbody, if the first item in the object isn't a call for a new tbody
|
||||
$tb.appendTo( $t );
|
||||
}
|
||||
|
||||
$tr = $('<tr>').appendTo( $tb );
|
||||
if (t) {
|
||||
// row defined by object
|
||||
for (j in d) {
|
||||
if (d.hasOwnProperty(j) && j !== wo.build_objectCellKey){
|
||||
$tr.attr(j, d[j]);
|
||||
}
|
||||
}
|
||||
if (d.hasOwnProperty(wo.build_objectCellKey)) {
|
||||
// cells contains each cell info
|
||||
d = d.cells;
|
||||
}
|
||||
}
|
||||
|
||||
l = d.length;
|
||||
for ( j = 0; j < l; j++ ) {
|
||||
// cell(cellData, widgetOptions, 'td')
|
||||
$c = bt.build.cell(d[j], wo, 'td', j);
|
||||
if ($c[0] && $c[0].length) { $c[0].appendTo( $tr ); } // add cell
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// add footer
|
||||
if (data.hasOwnProperty(wo.build_objectFooterKey)) {
|
||||
t = data[wo.build_objectFooterKey];
|
||||
if (t === 'clone') {
|
||||
$c = $t.find('thead').html();
|
||||
$t.append('<tfoot>' + $c + '</tfoot>');
|
||||
} else {
|
||||
$c = $('<tfoot>').appendTo( $t );
|
||||
$.each(t, function(i, d) {
|
||||
$tr = $('<tr>').appendTo( $c );
|
||||
l = d.length; // footer cells
|
||||
for ( j = 0; j < l; j++ ) {
|
||||
// cell(cellData, widgetOptions, 'th')
|
||||
$tb = bt.build.cell(d[j], wo, 'th', j);
|
||||
if ($tb[0] && $tb[0].length) { $tb[0].appendTo( $tr ); } // add cell
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(table).html( $t.html() );
|
||||
bt.buildComplete(table, wo);
|
||||
};
|
||||
|
||||
bt.ajax = bt.json = function(table, data, wo) {
|
||||
return bt.object(table, data, wo);
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,317 @@
|
||||
/* Column Selector/Responsive table widget (beta) for TableSorter 5/22/2014 (v2.17.0)
|
||||
* Requires tablesorter v2.8+ and jQuery 1.7+
|
||||
* by Justin Hallett & Rob Garrison
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter,
|
||||
namespace = '.tscolsel',
|
||||
tsColSel = ts.columnSelector = {
|
||||
|
||||
queryAll : '@media only all { [columns] { display: none; } }',
|
||||
queryBreak : '@media all and (min-width: [size]) { [columns] { display: table-cell; } }',
|
||||
|
||||
init: function(table, c, wo) {
|
||||
var $t, colSel;
|
||||
|
||||
// abort if no input is contained within the layout
|
||||
$t = $(wo.columnSelector_layout);
|
||||
if (!$t.find('input').add( $t.filter('input') ).length) {
|
||||
if (c.debug) {
|
||||
ts.log('*** ERROR: Column Selector aborting, no input found in the layout! ***');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// unique table class name
|
||||
c.tableId = 'tablesorter' + new Date().getTime();
|
||||
c.$table.addClass( c.tableId );
|
||||
|
||||
// build column selector/state array
|
||||
colSel = c.selector = { $container : $(wo.columnSelector_container || '<div>') };
|
||||
colSel.$style = $('<style></style>').prop('disabled', true).appendTo('head');
|
||||
colSel.$breakpoints = $('<style></style>').prop('disabled', true).appendTo('head');
|
||||
|
||||
colSel.isInitializing = true;
|
||||
tsColSel.setupSelector(table, c, wo);
|
||||
|
||||
if (wo.columnSelector_mediaquery) {
|
||||
tsColSel.setupBreakpoints(c, wo);
|
||||
}
|
||||
|
||||
colSel.isInitializing = false;
|
||||
if (colSel.$container.length) {
|
||||
tsColSel.updateCols(c, wo);
|
||||
}
|
||||
|
||||
c.$table
|
||||
.off('refreshColumnSelector' + namespace)
|
||||
.on('refreshColumnSelector' + namespace, function(){
|
||||
// make sure we're using current config settings
|
||||
var c = this.config;
|
||||
tsColSel.updateBreakpoints(c, c.widgetOptions);
|
||||
tsColSel.updateCols(c, c.widgetOptions);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
setupSelector: function(table, c, wo) {
|
||||
var name,
|
||||
colSel = c.selector,
|
||||
$container = colSel.$container,
|
||||
useStorage = wo.columnSelector_saveColumns && ts.storage,
|
||||
// get stored column states
|
||||
saved = useStorage ? ts.storage( table, 'tablesorter-columnSelector' ) : [],
|
||||
state = useStorage ? ts.storage( table, 'tablesorter-columnSelector-auto') : {};
|
||||
|
||||
// initial states
|
||||
colSel.auto = $.isEmptyObject(state) || $.type(state.auto) !== "boolean" ? wo.columnSelector_mediaqueryState : state.auto;
|
||||
colSel.states = [];
|
||||
colSel.$column = [];
|
||||
colSel.$wrapper = [];
|
||||
colSel.$checkbox = [];
|
||||
// populate the selector container
|
||||
c.$table.children('thead').find('tr:first th', table).each(function() {
|
||||
var $this = $(this),
|
||||
// if no data-priority is assigned, default to 1, but don't remove it from the selector list
|
||||
priority = $this.attr(wo.columnSelector_priority) || 1,
|
||||
colId = $this.attr('data-column'),
|
||||
state = ts.getData(this, c.headers[colId], 'columnSelector');
|
||||
|
||||
|
||||
// if this column not hidable at all
|
||||
// include getData check (includes "columnSelector-false" class, data attribute, etc)
|
||||
if ( isNaN(priority) && priority.length > 0 || state === 'disable' ||
|
||||
( wo.columnSelector_columns[colId] && wo.columnSelector_columns[colId] === 'disable') ) {
|
||||
return true; // goto next
|
||||
}
|
||||
|
||||
// set default state; storage takes priority
|
||||
colSel.states[colId] = saved && typeof(saved[colId]) !== 'undefined' ?
|
||||
saved[colId] : typeof(wo.columnSelector_columns[colId]) !== 'undefined' ?
|
||||
wo.columnSelector_columns[colId] : (state === 'true' || !(state === 'false'));
|
||||
colSel.$column[colId] = $(this);
|
||||
|
||||
// set default col title
|
||||
name = $this.attr(wo.columnSelector_name) || $this.text();
|
||||
|
||||
if ($container.length) {
|
||||
colSel.$wrapper[colId] = $(wo.columnSelector_layout.replace(/\{name\}/g, name)).appendTo($container);
|
||||
colSel.$checkbox[colId] = colSel.$wrapper[colId]
|
||||
// input may not be wrapped within the layout template
|
||||
.find('input').add( colSel.$wrapper[colId].filter('input') )
|
||||
.attr('data-column', colId)
|
||||
.prop('checked', colSel.states[colId])
|
||||
.on('change', function(){
|
||||
colSel.states[colId] = this.checked;
|
||||
tsColSel.updateCols(c, wo);
|
||||
}).change();
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
setupBreakpoints: function(c, wo){
|
||||
var colSel = c.selector;
|
||||
|
||||
// add responsive breakpoints
|
||||
if (wo.columnSelector_mediaquery) {
|
||||
// used by window resize function
|
||||
colSel.lastIndex = -1;
|
||||
wo.columnSelector_breakpoints.sort();
|
||||
tsColSel.updateBreakpoints(c, wo);
|
||||
c.$table
|
||||
.off('updateAll' + namespace)
|
||||
.on('updateAll' + namespace, function(){
|
||||
tsColSel.updateBreakpoints(c, wo);
|
||||
tsColSel.updateCols(c, wo);
|
||||
});
|
||||
}
|
||||
|
||||
if (colSel.$container.length) {
|
||||
// Add media queries toggle
|
||||
if (wo.columnSelector_mediaquery) {
|
||||
colSel.$auto = $( wo.columnSelector_layout.replace(/\{name\}/g, wo.columnSelector_mediaqueryName) ).prependTo(colSel.$container);
|
||||
colSel.$auto
|
||||
// needed in case the input in the layout is not wrapped
|
||||
.find('input').add( colSel.$auto.filter('input') )
|
||||
.attr('data-column', 'auto')
|
||||
.prop('checked', colSel.auto)
|
||||
.on('change', function(){
|
||||
colSel.auto = this.checked;
|
||||
$.each( colSel.$checkbox, function(i, $cb){
|
||||
if ($cb) {
|
||||
$cb[0].disabled = colSel.auto;
|
||||
colSel.$wrapper[i].toggleClass('disabled', colSel.auto);
|
||||
}
|
||||
});
|
||||
if (wo.columnSelector_mediaquery) {
|
||||
tsColSel.updateBreakpoints(c, wo);
|
||||
}
|
||||
tsColSel.updateCols(c, wo);
|
||||
// copy the column selector to a popup/tooltip
|
||||
if (c.selector.$popup) {
|
||||
c.selector.$popup.find('.tablesorter-column-selector')
|
||||
.html( colSel.$container.html() )
|
||||
.find('input').each(function(){
|
||||
var indx = $(this).attr('data-column');
|
||||
$(this).prop( 'checked', indx === 'auto' ? colSel.auto : colSel.states[indx] );
|
||||
});
|
||||
}
|
||||
if (wo.columnSelector_saveColumns && ts.storage) {
|
||||
ts.storage( c.$table[0], 'tablesorter-columnSelector-auto', { auto : colSel.auto } );
|
||||
}
|
||||
}).change();
|
||||
}
|
||||
// Add a bind on update to re-run col setup
|
||||
c.$table.off('update' + namespace).on('update' + namespace, function() {
|
||||
tsColSel.updateCols(c, wo);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
updateBreakpoints: function(c, wo) {
|
||||
var priority, column, breaks,
|
||||
colSel = c.selector,
|
||||
prefix = '.' + c.tableId,
|
||||
mediaAll = [],
|
||||
breakpts = '';
|
||||
if (wo.columnSelector_mediaquery && !colSel.auto) {
|
||||
colSel.$breakpoints.prop('disabled', true);
|
||||
colSel.$style.prop('disabled', false);
|
||||
return;
|
||||
}
|
||||
|
||||
// only 6 breakpoints (same as jQuery Mobile)
|
||||
for (priority = 0; priority < 6; priority++){
|
||||
/*jshint loopfunc:true */
|
||||
breaks = [];
|
||||
c.$headers.filter('[' + wo.columnSelector_priority + '=' + (priority + 1) + ']').each(function(){
|
||||
column = parseInt($(this).attr('data-column'), 10) + 1;
|
||||
breaks.push(prefix + ' tr th:nth-child(' + column + ')');
|
||||
breaks.push(prefix + ' tr td:nth-child(' + column + ')');
|
||||
});
|
||||
if (breaks.length) {
|
||||
mediaAll = mediaAll.concat( breaks );
|
||||
breakpts += tsColSel.queryBreak
|
||||
.replace(/\[size\]/g, wo.columnSelector_breakpoints[priority])
|
||||
.replace(/\[columns\]/g, breaks.join(','));
|
||||
}
|
||||
}
|
||||
if (colSel.$style) {
|
||||
colSel.$style.prop('disabled', true);
|
||||
}
|
||||
colSel.$breakpoints
|
||||
.prop('disabled', false)
|
||||
.html( tsColSel.queryAll.replace(/\[columns\]/g, mediaAll.join(',')) + breakpts );
|
||||
},
|
||||
|
||||
updateCols: function(c, wo) {
|
||||
if (wo.columnSelector_mediaquery && c.selector.auto || c.selector.isInitializing) {
|
||||
return;
|
||||
}
|
||||
var column,
|
||||
colSel = c.selector,
|
||||
styles = [],
|
||||
prefix = '.' + c.tableId;
|
||||
colSel.$container.find('input[data-column]').filter('[data-column!="auto"]').each(function(){
|
||||
if (!this.checked) {
|
||||
column = parseInt( $(this).attr('data-column'), 10 ) + 1;
|
||||
styles.push(prefix + ' tr th:nth-child(' + column + ')');
|
||||
styles.push(prefix + ' tr td:nth-child(' + column + ')');
|
||||
}
|
||||
});
|
||||
if (wo.columnSelector_mediaquery){
|
||||
colSel.$breakpoints.prop('disabled', true);
|
||||
}
|
||||
if (colSel.$style) {
|
||||
colSel.$style.prop('disabled', false).html( styles.length ? styles.join(',') + ' { display: none; }' : '' );
|
||||
}
|
||||
if (wo.columnSelector_saveColumns && ts.storage) {
|
||||
ts.storage( c.$table[0], 'tablesorter-columnSelector', colSel.states );
|
||||
}
|
||||
},
|
||||
|
||||
attachTo : function(table, elm) {
|
||||
table = $(table)[0];
|
||||
var colSel, wo, indx,
|
||||
c = table.config,
|
||||
$popup = $(elm);
|
||||
if ($popup.length && c) {
|
||||
if (!$popup.find('.tablesorter-column-selector').length) {
|
||||
// add a wrapper to add the selector into, in case the popup has other content
|
||||
$popup.append('<span class="tablesorter-column-selector"></span>');
|
||||
}
|
||||
colSel = c.selector;
|
||||
wo = c.widgetOptions;
|
||||
$popup.find('.tablesorter-column-selector')
|
||||
.html( colSel.$container.html() )
|
||||
.find('input').each(function(){
|
||||
var indx = $(this).attr('data-column');
|
||||
$(this).prop( 'checked', indx === 'auto' ? colSel.auto : colSel.states[indx] );
|
||||
});
|
||||
colSel.$popup = $popup.on('change', 'input', function(){
|
||||
// data input
|
||||
indx = $(this).attr('data-column');
|
||||
// update original popup
|
||||
colSel.$container.find('input[data-column="' + indx + '"]')
|
||||
.prop('checked', this.checked)
|
||||
.trigger('change');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ts.addWidget({
|
||||
id: "columnSelector",
|
||||
priority: 10,
|
||||
options: {
|
||||
// target the column selector markup
|
||||
columnSelector_container : null,
|
||||
// column status, true = display, false = hide
|
||||
// disable = do not display on list
|
||||
columnSelector_columns : {},
|
||||
// remember selected columns
|
||||
columnSelector_saveColumns: true,
|
||||
|
||||
// container layout
|
||||
columnSelector_layout : '<label><input type="checkbox">{name}</label>',
|
||||
// data attribute containing column name to use in the selector container
|
||||
columnSelector_name : 'data-selector-name',
|
||||
|
||||
/* Responsive Media Query settings */
|
||||
// enable/disable mediaquery breakpoints
|
||||
columnSelector_mediaquery: true,
|
||||
// toggle checkbox name
|
||||
columnSelector_mediaqueryName: 'Auto: ',
|
||||
// breakpoints checkbox initial setting
|
||||
columnSelector_mediaqueryState: true,
|
||||
// responsive table hides columns with priority 1-6 at these breakpoints
|
||||
// see http://view.jquerymobile.com/1.3.2/dist/demos/widgets/table-column-toggle/#Applyingapresetbreakpoint
|
||||
// *** set to false to disable ***
|
||||
columnSelector_breakpoints : [ '20em', '30em', '40em', '50em', '60em', '70em' ],
|
||||
// data attribute containing column priority
|
||||
// duplicates how jQuery mobile uses priorities:
|
||||
// http://view.jquerymobile.com/1.3.2/dist/demos/widgets/table-column-toggle/
|
||||
columnSelector_priority : 'data-priority'
|
||||
|
||||
},
|
||||
init: function(table, thisWidget, c, wo) {
|
||||
tsColSel.init(table, c, wo);
|
||||
},
|
||||
remove: function(table, c){
|
||||
var csel = c.selector;
|
||||
csel.$container.empty();
|
||||
if (csel.$popup) { csel.$popup.empty(); }
|
||||
csel.$style.remove();
|
||||
csel.$breakpoints.remove();
|
||||
c.$table.off('updateAll' + namespace + ' update' + namespace);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,70 @@
|
||||
/*! tablesorter CSS Sticky Headers widget - updated 5/5/2014 (v2.16.4)
|
||||
* Requires a modern browser, tablesorter v2.8+
|
||||
*/
|
||||
/*jshint jquery:true, unused:false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
$.tablesorter.addWidget({
|
||||
id: "cssStickyHeaders",
|
||||
priority: 10,
|
||||
options: {
|
||||
cssStickyHeaders_offset : 0,
|
||||
cssStickyHeaders_addCaption : false,
|
||||
cssStickyHeaders_attachTo : null,
|
||||
cssStickyHeaders_filteredToTop : true,
|
||||
cssStickyHeaders_zIndex : 10
|
||||
},
|
||||
init : function(table, thisWidget, c, wo) {
|
||||
var $attach = $(wo.cssStickyHeaders_attachTo),
|
||||
namespace = '.cssstickyheader',
|
||||
$thead = c.$table.children('thead'),
|
||||
$caption = c.$table.find('caption'),
|
||||
$win = $attach.length ? $attach : $(window);
|
||||
$win.bind('scroll resize '.split(' ').join(namespace + ' '), function() {
|
||||
var top = $attach.length ? $attach.offset().top : $win.scrollTop(),
|
||||
// add caption height; include table padding top & border-spacing or text may be above the fold (jQuery UI themes)
|
||||
// border-spacing needed in Firefox, but not webkit... not sure if I should account for that
|
||||
captionTop = wo.cssStickyHeaders_addCaption ? $caption.outerHeight(true) +
|
||||
(parseInt(c.$table.css('padding-top'), 10) || 0) + (parseInt(c.$table.css('border-spacing'), 10) || 0) : 0,
|
||||
bottom = c.$table.height() - $thead.height() - (c.$table.find('tfoot').height() || 0) - captionTop,
|
||||
deltaY = top - $thead.offset().top + (parseInt(c.$table.css('border-top-width'), 10) || 0) +
|
||||
(wo.cssStickyHeaders_offset || 0) + captionTop,
|
||||
finalY = (deltaY > 0 && deltaY <= bottom ? deltaY : 0),
|
||||
// IE can only transform header cells - fixes #447 thanks to @gakreol!
|
||||
$cells = $thead.children().children();
|
||||
if (wo.cssStickyHeaders_addCaption) {
|
||||
$cells = $cells.add($caption);
|
||||
}
|
||||
$cells.css({
|
||||
"position" : "relative",
|
||||
"z-index" : wo.cssStickyHeaders_zIndex,
|
||||
"transform" : finalY === 0 ? "" : "translate(0px," + finalY + "px)",
|
||||
"-ms-transform" : finalY === 0 ? "" : "translate(0px," + finalY + "px)",
|
||||
"-webkit-transform" : finalY === 0 ? "" : "translate(0px," + finalY + "px)"
|
||||
});
|
||||
});
|
||||
c.$table.bind('filterEnd', function() {
|
||||
if (wo.cssStickyHeaders_filteredToTop) {
|
||||
// scroll top of table into view
|
||||
window.scrollTo(0, c.$table.position().top);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
remove: function(table, c, wo){
|
||||
var namespace = '.cssstickyheader';
|
||||
$(window).unbind('scroll resize '.split(' ').join(namespace + ' '));
|
||||
c.$table
|
||||
.unbind('update updateAll '.split(' ').join(namespace + ' '))
|
||||
.children('thead, caption').css({
|
||||
"position" : "",
|
||||
"z-index" : "",
|
||||
"transform" : "",
|
||||
"-ms-transform" : "",
|
||||
"-webkit-transform" : ""
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
200
modules/EcmReports/TableSorterNew/js/widgets/widget-editable.js
Normal file
200
modules/EcmReports/TableSorterNew/js/widgets/widget-editable.js
Normal file
@@ -0,0 +1,200 @@
|
||||
/*! tablesorter Editable Content widget - updated 9/15/2014 (core v2.17.8)
|
||||
* Requires tablesorter v2.8+ and jQuery 1.7+
|
||||
* by Rob Garrison
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
$.tablesorter.addWidget({
|
||||
id: 'editable',
|
||||
options : {
|
||||
editable_columns : [],
|
||||
editable_enterToAccept : true,
|
||||
editable_autoAccept : true,
|
||||
editable_autoResort : false,
|
||||
editable_wrapContent : '<div>', // wrap the cell content... makes this widget work in IE, and with autocomplete
|
||||
editable_trimContent : true, // trim content inside of contenteditable (remove tabs & carriage returns)
|
||||
editable_validate : null, // function(text, originalText){ return text; }
|
||||
editable_focused : null, // function(text, columnIndex, $element) {}
|
||||
editable_blur : null, // function(text, columnIndex, $element) { }
|
||||
editable_selectAll : false, // true/false or function(text, columnIndex, $element) { return true; }
|
||||
editable_noEdit : 'no-edit',
|
||||
editable_editComplete : 'editComplete'
|
||||
},
|
||||
init: function(table, thisWidget, c, wo){
|
||||
if ( !wo.editable_columns.length ) { return; }
|
||||
var indx, tmp, $t,
|
||||
cols = [],
|
||||
editComplete = function($cell, refocus){
|
||||
$cell
|
||||
.removeClass('tseditable-last-edited-cell')
|
||||
.trigger( wo.editable_editComplete, [c] );
|
||||
// restore focus last cell after updating
|
||||
if (refocus) {
|
||||
setTimeout(function(){
|
||||
$cell.focus();
|
||||
}, 50);
|
||||
}
|
||||
},
|
||||
selectAll = function(cell){
|
||||
setTimeout(function(){
|
||||
// select all text in contenteditable
|
||||
// see http://stackoverflow.com/a/6150060/145346
|
||||
var range = document.createRange();
|
||||
range.selectNodeContents(cell);
|
||||
var sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
if ( $.type(wo.editable_columns) === "string" && wo.editable_columns.indexOf('-') >= 0 ) {
|
||||
// editable_columns can contain a range string (i.e. "2-4" )
|
||||
tmp = wo.editable_columns.split('-');
|
||||
indx = parseInt(tmp[0],10) || 0;
|
||||
tmp = parseInt(tmp[1],10) || (c.columns - 1);
|
||||
if ( tmp > c.columns ) { tmp = c.columns - 1; }
|
||||
for ( ; indx <= tmp; indx++ ) {
|
||||
cols.push('td:nth-child(' + (indx + 1) + ')');
|
||||
}
|
||||
} else if ( $.isArray(wo.editable_columns) ) {
|
||||
$.each(wo.editable_columns, function(i, col){
|
||||
if ( col < c.columns ) {
|
||||
cols.push('td:nth-child(' + (col + 1) + ')');
|
||||
}
|
||||
});
|
||||
}
|
||||
tmp = $('<div>').wrapInner(wo.editable_wrapContent).children().length || $.isFunction(wo.editable_wrapContent);
|
||||
// IE does not allow making TR/TH/TD cells directly editable (issue #404)
|
||||
// so add a div or span inside ( it's faster than using wrapInner() )
|
||||
c.$tbodies.find( cols.join(',') ).not( '.' + wo.editable_noEdit ).each(function(){
|
||||
// test for children, if they exist, then make the children editable
|
||||
$t = $(this);
|
||||
|
||||
if (tmp && $t.children().length === 0) {
|
||||
$t.wrapInner( wo.editable_wrapContent );
|
||||
}
|
||||
if ($t.children().length) {
|
||||
// make all children content editable
|
||||
$t.children().not('.' + wo.editable_noEdit).each(function(){
|
||||
var $this = $(this);
|
||||
if (wo.editable_trimContent) {
|
||||
$this.text(function(i, txt){
|
||||
return $.trim(txt);
|
||||
});
|
||||
}
|
||||
$this.prop( 'contenteditable', true );
|
||||
});
|
||||
} else {
|
||||
if (wo.editable_trimContent) {
|
||||
$t.text(function(i, txt){
|
||||
return $.trim(txt);
|
||||
});
|
||||
}
|
||||
$t.prop( 'contenteditable', true );
|
||||
}
|
||||
});
|
||||
c.$tbodies
|
||||
.on('mouseleave.tseditable', function(){
|
||||
if ( c.$table.data('contentFocused') ) {
|
||||
// change to "true" instead of element to allow focusout to process
|
||||
c.$table.data( 'contentFocused', true );
|
||||
$(':focus').trigger('focusout');
|
||||
}
|
||||
})
|
||||
.on('focus.tseditable', '[contenteditable]', function(e){
|
||||
clearTimeout( $(this).data('timer') );
|
||||
c.$table.data( 'contentFocused', e.target );
|
||||
var $this = $(this),
|
||||
selAll = wo.editable_selectAll,
|
||||
column = $this.closest('td').index(),
|
||||
txt = $.trim( $this.text() );
|
||||
if (wo.editable_enterToAccept) {
|
||||
// prevent enter from adding into the content
|
||||
$this.on('keydown.tseditable', function(e){
|
||||
if ( e.which === 13 ) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
$this.data({ before : txt, original: txt });
|
||||
|
||||
if (typeof wo.editable_focused === 'function') {
|
||||
wo.editable_focused( txt, column, $this );
|
||||
}
|
||||
|
||||
if (selAll) {
|
||||
if (typeof selAll === 'function') {
|
||||
if ( selAll( txt, column, $this ) ) {
|
||||
selectAll($this[0]);
|
||||
}
|
||||
} else {
|
||||
selectAll($this[0]);
|
||||
}
|
||||
}
|
||||
})
|
||||
.on('blur focusout keydown '.split(' ').join('.tseditable '), '[contenteditable]', function(e){
|
||||
if ( !c.$table.data('contentFocused') ) { return; }
|
||||
var t, validate,
|
||||
valid = false,
|
||||
$this = $(e.target),
|
||||
txt = $.trim( $this.text() ),
|
||||
column = $this.closest('td').index();
|
||||
if ( e.which === 27 ) {
|
||||
// user cancelled
|
||||
$this.html( $.trim( $this.data('original') ) ).trigger('blur.tseditable');
|
||||
c.$table.data( 'contentFocused', false );
|
||||
return false;
|
||||
}
|
||||
// accept on enter (if set), alt-enter (always) or if autoAccept is set and element is blurred or unfocused
|
||||
t = e.which === 13 && ( wo.editable_enterToAccept || e.altKey ) || wo.editable_autoAccept && e.type !== 'keydown';
|
||||
// change if new or user hits enter (if option set)
|
||||
if ( t && $this.data('before') !== txt ) {
|
||||
|
||||
validate = wo.editable_validate;
|
||||
valid = txt;
|
||||
|
||||
if (typeof(validate) === "function") {
|
||||
valid = validate( txt, $this.data('original'), column, $this );
|
||||
} else if (typeof (validate = $.tablesorter.getColumnData( table, validate, column )) === 'function') {
|
||||
valid = validate( txt, $this.data('original'), column, $this );
|
||||
}
|
||||
|
||||
if ( t && valid !== false ) {
|
||||
c.$table.find('.tseditable-last-edited-cell').removeClass('tseditable-last-edited-cell');
|
||||
$this
|
||||
.addClass('tseditable-last-edited-cell')
|
||||
.html( $.trim( valid ) )
|
||||
.data('before', valid)
|
||||
.data('original', valid)
|
||||
.trigger('change');
|
||||
c.$table.trigger('updateCell', [ $this.closest('td'), false, function(){
|
||||
if (wo.editable_autoResort) {
|
||||
setTimeout(function(){
|
||||
c.$table.trigger("sorton", [ c.sortList, function(){
|
||||
editComplete(c.$table.find('.tseditable-last-edited-cell'), true);
|
||||
}, true ]);
|
||||
}, 10);
|
||||
} else {
|
||||
editComplete(c.$table.find('.tseditable-last-edited-cell'));
|
||||
}
|
||||
} ]);
|
||||
return false;
|
||||
}
|
||||
} else if ( !valid && e.type !== 'keydown' ) {
|
||||
clearTimeout( $this.data('timer') );
|
||||
$this.data('timer', setTimeout(function(){
|
||||
if ($.isFunction(wo.editable_blur)) {
|
||||
wo.editable_blur( $.trim( $this.text() ), column, $this );
|
||||
}
|
||||
}, 100));
|
||||
// restore original content on blur
|
||||
$this.html( $.trim( $this.data('original') ) );
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
249
modules/EcmReports/TableSorterNew/js/widgets/widget-grouping.js
Normal file
249
modules/EcmReports/TableSorterNew/js/widgets/widget-grouping.js
Normal file
@@ -0,0 +1,249 @@
|
||||
/*! tablesorter Grouping widget - updated 3/7/2014 (core v2.15.6)
|
||||
* Requires tablesorter v2.8+ and jQuery 1.7+
|
||||
* by Rob Garrison
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
var ts = $.tablesorter;
|
||||
|
||||
ts.grouping = {
|
||||
|
||||
types : {
|
||||
number : function(c, $column, txt, num, group){
|
||||
var value, word;
|
||||
if (num > 1 && txt !== '') {
|
||||
if ($column.hasClass(ts.css.sortAsc)) {
|
||||
value = Math.floor(parseFloat(txt)/num) * num;
|
||||
return value > parseFloat(group || 0) ? value : parseFloat(group || 0);
|
||||
} else {
|
||||
value = Math.ceil(parseFloat(txt)/num) * num;
|
||||
return value < parseFloat(group || num) - value ? parseFloat(group || num) - value : value;
|
||||
}
|
||||
} else {
|
||||
word = (txt + '').match(/\d+/g);
|
||||
return word && word.length >= num ? word[num - 1] : txt || '';
|
||||
}
|
||||
},
|
||||
separator : function(c, $column, txt, num){
|
||||
var word = (txt + '').split(c.widgetOptions.group_separator);
|
||||
return $.trim(word && num > 0 && word.length >= num ? word[(num || 1) - 1] : '');
|
||||
},
|
||||
word : function(c, $column, txt, num){
|
||||
var word = (txt + ' ').match(/\w+/g);
|
||||
return word && word.length >= num ? word[num - 1] : txt || '';
|
||||
},
|
||||
letter : function(c, $column, txt, num){
|
||||
return txt ? (txt + ' ').substring(0, num) : '';
|
||||
},
|
||||
date : function(c, $column, txt, part, group){
|
||||
var wo = c.widgetOptions,
|
||||
time = new Date(txt || ''),
|
||||
hours = time.getHours();
|
||||
return part === 'year' ? time.getFullYear() :
|
||||
part === 'month' ? wo.group_months[time.getMonth()] :
|
||||
part === 'day' ? wo.group_months[time.getMonth()] + ' ' + time.getDate() :
|
||||
part === 'week' ? wo.group_week[time.getDay()] :
|
||||
part === 'time' ? ('00' + (hours > 12 ? hours - 12 : hours === 0 ? hours + 12 : hours)).slice(-2) + ':' +
|
||||
('00' + time.getMinutes()).slice(-2) + ' ' + ('00' + wo.group_time[hours >= 12 ? 1 : 0]).slice(-2) :
|
||||
wo.group_dateString(time);
|
||||
}
|
||||
},
|
||||
|
||||
update : function(table, c, wo){
|
||||
if ($.isEmptyObject(c.cache)) { return; }
|
||||
var rowIndex, tbodyIndex, currentGroup, $rows, groupClass, grouping, time, cache, saveName, direction,
|
||||
lang = wo.grouping_language,
|
||||
group = '',
|
||||
savedGroup = false,
|
||||
column = c.sortList[0] ? c.sortList[0][0] : -1;
|
||||
c.$table
|
||||
.find('tr.group-hidden').removeClass('group-hidden').end()
|
||||
.find('tr.group-header').remove();
|
||||
if (wo.group_collapsible) {
|
||||
// clear pager saved spacer height (in case the rows are collapsed)
|
||||
c.$table.data('pagerSavedHeight', 0);
|
||||
}
|
||||
if (column >= 0 && !c.$headers.filter('[data-column="' + column + '"]:last').hasClass('group-false')) {
|
||||
if (c.debug){ time = new Date(); }
|
||||
wo.group_currentGroup = ''; // save current groups
|
||||
wo.group_currentGroups = {};
|
||||
|
||||
// group class finds "group-{word/separator/letter/number/date/false}-{optional:#/year/month/day/week/time}"
|
||||
groupClass = (c.$headers.filter('[data-column="' + column + '"]:last').attr('class') || '').match(/(group-\w+(-\w+)?)/g);
|
||||
// grouping = [ 'group', '{word/separator/letter/number/date/false}', '{#/year/month/day/week/time}' ]
|
||||
grouping = groupClass ? groupClass[0].split('-') : ['group','letter',1]; // default to letter 1
|
||||
|
||||
// save current grouping
|
||||
if (wo.group_collapsible && wo.group_saveGroups && ts.storage) {
|
||||
wo.group_currentGroups = ts.storage( table, 'tablesorter-groups' ) || {};
|
||||
// include direction when grouping numbers > 1 (reversed direction shows different range values)
|
||||
direction = (grouping[1] === 'number' && grouping[2] > 1) ? 'dir' + c.sortList[0][1] : '';
|
||||
// combine column, sort direction & grouping as save key
|
||||
saveName = wo.group_currentGroup = '' + column + direction + grouping.join('');
|
||||
if (!wo.group_currentGroups[saveName]) {
|
||||
wo.group_currentGroups[saveName] = [];
|
||||
} else {
|
||||
savedGroup = true;
|
||||
}
|
||||
}
|
||||
for (tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++) {
|
||||
cache = c.cache[tbodyIndex].normalized;
|
||||
group = ''; // clear grouping across tbodies
|
||||
$rows = c.$tbodies.eq(tbodyIndex).children('tr').not('.' + c.cssChildRow);
|
||||
for (rowIndex = 0; rowIndex < $rows.length; rowIndex++) {
|
||||
if ( $rows.eq(rowIndex).is(':visible') ) {
|
||||
// fixes #438
|
||||
if (ts.grouping.types[grouping[1]]) {
|
||||
currentGroup = cache[rowIndex] ?
|
||||
ts.grouping.types[grouping[1]]( c, c.$headers.filter('[data-column="' + column + '"]:last'), cache[rowIndex][column], /date/.test(groupClass) ?
|
||||
grouping[2] : parseInt(grouping[2] || 1, 10) || 1, group, lang ) : currentGroup;
|
||||
if (group !== currentGroup) {
|
||||
group = currentGroup;
|
||||
// show range if number > 1
|
||||
if (grouping[1] === 'number' && grouping[2] > 1 && currentGroup !== '') {
|
||||
currentGroup += ' - ' + (parseInt(currentGroup, 10) +
|
||||
((parseInt(grouping[2],10) - 1) * (c.$headers.filter('[data-column="' + column + '"]:last').hasClass(ts.css.sortAsc) ? 1 : -1)));
|
||||
}
|
||||
if ($.isFunction(wo.group_formatter)) {
|
||||
currentGroup = wo.group_formatter((currentGroup || '').toString(), column, table, c, wo) || currentGroup;
|
||||
}
|
||||
$rows.eq(rowIndex).before('<tr class="group-header ' + c.selectorRemove.slice(1) +
|
||||
'" unselectable="on"><td colspan="' +
|
||||
c.columns + '">' + (wo.group_collapsible ? '<i/>' : '') + '<span class="group-name">' +
|
||||
currentGroup + '</span><span class="group-count"></span></td></tr>');
|
||||
if (wo.group_saveGroups && !savedGroup && wo.group_collapsed && wo.group_collapsible) {
|
||||
// all groups start collapsed
|
||||
wo.group_currentGroups[wo.group_currentGroup].push(currentGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
c.$table.find('tr.group-header')
|
||||
.bind('selectstart', false)
|
||||
.each(function(){
|
||||
var isHidden, $label, name,
|
||||
$row = $(this),
|
||||
$rows = $row.nextUntil('tr.group-header').filter(':visible');
|
||||
if (wo.group_count || $.isFunction(wo.group_callback)) {
|
||||
$label = $row.find('.group-count');
|
||||
if ($label.length) {
|
||||
if (wo.group_count) {
|
||||
$label.html( wo.group_count.replace(/\{num\}/g, $rows.length) );
|
||||
}
|
||||
if ($.isFunction(wo.group_callback)) {
|
||||
wo.group_callback($row.find('td'), $rows, column, table);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wo.group_saveGroups && wo.group_currentGroups[wo.group_currentGroup].length) {
|
||||
name = $row.find('.group-name').text().toLowerCase();
|
||||
isHidden = $.inArray( name, wo.group_currentGroups[wo.group_currentGroup] ) > -1;
|
||||
$row.toggleClass('collapsed', isHidden);
|
||||
$rows.toggleClass('group-hidden', isHidden);
|
||||
} else if (wo.group_collapsed && wo.group_collapsible) {
|
||||
$row.addClass('collapsed');
|
||||
$rows.addClass('group-hidden');
|
||||
}
|
||||
});
|
||||
c.$table.trigger(wo.group_complete);
|
||||
if (c.debug) {
|
||||
$.tablesorter.benchmark("Applying groups widget: ", time);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
bindEvents : function(table, c, wo){
|
||||
if (wo.group_collapsible) {
|
||||
wo.group_currentGroups = [];
|
||||
// .on() requires jQuery 1.7+
|
||||
c.$table.on('click toggleGroup', 'tr.group-header', function(event){
|
||||
event.stopPropagation();
|
||||
var isCollapsed, $groups, indx,
|
||||
$this = $(this),
|
||||
name = $this.find('.group-name').text().toLowerCase();
|
||||
// use shift-click to toggle ALL groups
|
||||
if (event.type === 'click' && event.shiftKey) {
|
||||
$this.siblings('.group-header').trigger('toggleGroup');
|
||||
}
|
||||
$this.toggleClass('collapsed');
|
||||
// nextUntil requires jQuery 1.4+
|
||||
$this.nextUntil('tr.group-header').toggleClass('group-hidden', $this.hasClass('collapsed') );
|
||||
// save collapsed groups
|
||||
if (wo.group_saveGroups && ts.storage) {
|
||||
$groups = c.$table.find('.group-header');
|
||||
isCollapsed = $this.hasClass('collapsed');
|
||||
if (!wo.group_currentGroups[wo.group_currentGroup]) {
|
||||
wo.group_currentGroups[wo.group_currentGroup] = [];
|
||||
}
|
||||
if (isCollapsed && wo.group_currentGroup) {
|
||||
wo.group_currentGroups[wo.group_currentGroup].push( name );
|
||||
} else if (wo.group_currentGroup) {
|
||||
indx = $.inArray( name, wo.group_currentGroups[wo.group_currentGroup] );
|
||||
if (indx > -1) {
|
||||
wo.group_currentGroups[wo.group_currentGroup].splice( indx, 1 );
|
||||
}
|
||||
}
|
||||
ts.storage( table, 'tablesorter-groups', wo.group_currentGroups );
|
||||
}
|
||||
});
|
||||
}
|
||||
$(wo.group_saveReset).on('click', function(){
|
||||
ts.grouping.clearSavedGroups(table);
|
||||
});
|
||||
c.$table.on('pagerChange.tsgrouping', function(){
|
||||
ts.grouping.update(table, c, wo);
|
||||
});
|
||||
},
|
||||
|
||||
clearSavedGroups: function(table){
|
||||
if (table && ts.storage) {
|
||||
ts.storage(table, 'tablesorter-groups', '');
|
||||
ts.grouping.update(table, table.config, table.config.widgetOptions);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ts.addWidget({
|
||||
id: 'group',
|
||||
priority: 100,
|
||||
options: {
|
||||
group_collapsible : true, // make the group header clickable and collapse the rows below it.
|
||||
group_collapsed : false, // start with all groups collapsed
|
||||
group_saveGroups : true, // remember collapsed groups
|
||||
group_saveReset : null, // element to clear saved collapsed groups
|
||||
group_count : ' ({num})', // if not false, the "{num}" string is replaced with the number of rows in the group
|
||||
group_separator : '-', // group name separator; used when group-separator-# class is used.
|
||||
group_formatter : null, // function(txt, column, table, c, wo) { return txt; }
|
||||
group_callback : null, // function($cell, $rows, column, table){}, callback allowing modification of the group header labels
|
||||
group_complete : 'groupingComplete', // event triggered on the table when the grouping widget has finished work
|
||||
|
||||
// change these default date names based on your language preferences
|
||||
group_months : [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ],
|
||||
group_week : [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ],
|
||||
group_time : [ 'AM', 'PM' ],
|
||||
// this function is used when "group-date" is set to create the date string
|
||||
// you can just return date, date.toLocaleString(), date.toLocaleDateString() or d.toLocaleTimeString()
|
||||
// reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Conversion_getter
|
||||
group_dateString : function(date) { return date.toLocaleString(); }
|
||||
},
|
||||
init: function(table, thisWidget, c, wo){
|
||||
ts.grouping.bindEvents(table, c, wo);
|
||||
},
|
||||
format: function(table, c, wo) {
|
||||
ts.grouping.update(table, c, wo);
|
||||
},
|
||||
remove : function(table, c, wo){
|
||||
c.$table
|
||||
.off('click', 'tr.group-header')
|
||||
.off('pagerChange.tsgrouping')
|
||||
.find('.group-hidden').removeClass('group-hidden').end()
|
||||
.find('tr.group-header').remove();
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,91 @@
|
||||
/*! tablesorter headerTitles widget - updated 3/5/2014 (core v2.15.6)
|
||||
* Requires tablesorter v2.8+ and jQuery 1.7+
|
||||
* by Rob Garrison
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
var ts = $.tablesorter;
|
||||
|
||||
ts.addWidget({
|
||||
id: 'headerTitles',
|
||||
options: {
|
||||
// use aria-label text
|
||||
// e.g. "First Name: Ascending sort applied, activate to apply a descending sort"
|
||||
headerTitle_useAria : false,
|
||||
// add tooltip class
|
||||
headerTitle_tooltip : '',
|
||||
// custom titles [ ascending, descending, unsorted ]
|
||||
headerTitle_cur_text : [ ' sort: A - Z', ' sort: Z - A', 'ly unsorted' ],
|
||||
headerTitle_cur_numeric : [ ' sort: 0 - 9', ' sort: 9 - 0', 'ly unsorted' ],
|
||||
headerTitle_nxt_text : [ ' sort: A - Z', ' sort: Z - A', 'remove sort' ],
|
||||
headerTitle_nxt_numeric : [ ' sort: 0 - 9', ' sort: 9 - 0', 'remove sort' ],
|
||||
|
||||
// title display; {prefix} adds above prefix
|
||||
// {type} adds the current sort order from above (text or numeric)
|
||||
// {next} adds the next sort direction using the sort order above
|
||||
headerTitle_output_sorted : 'current{current}; activate to {next}',
|
||||
headerTitle_output_unsorted : 'current{current}; activate to {next} ',
|
||||
headerTitle_output_nosort : 'No sort available',
|
||||
// use this type to override the parser detection result
|
||||
// e.g. use for numerically parsed columns (e.g. dates), but you
|
||||
// want the user to see a text sort, e.g. [ 'text', 'numeric' ]
|
||||
headerTitle_type : [],
|
||||
// manipulate the title as desired
|
||||
headerTitle_callback : null // function($cell, txt) { return txt; }
|
||||
},
|
||||
init: function(table, thisWidget, c, wo){
|
||||
// force refresh
|
||||
c.$table.on('refreshHeaderTitle', function(){
|
||||
thisWidget.format(table, c, wo);
|
||||
});
|
||||
// add tooltip class
|
||||
if ($.isArray(wo.headerTitle_tooltip)) {
|
||||
c.$headers.each(function(){
|
||||
$(this).addClass( wo.headerTitle_tooltip[this.column] || '' );
|
||||
});
|
||||
} else if (wo.headerTitle_tooltip !== '') {
|
||||
c.$headers.addClass( wo.headerTitle_tooltip );
|
||||
}
|
||||
},
|
||||
format: function (table, c, wo) {
|
||||
var txt;
|
||||
c.$headers.each(function(){
|
||||
var t = this,
|
||||
$this = $(this),
|
||||
sortType = wo.headerTitle_type[t.column] || c.parsers[ t.column ].type || 'text',
|
||||
sortDirection = $this.hasClass(ts.css.sortAsc) ? 0 : $this.hasClass(ts.css.sortDesc) ? 1 : 2,
|
||||
sortNext = t.order[(t.count + 1) % (c.sortReset ? 3 : 2)];
|
||||
if (wo.headerTitle_useAria) {
|
||||
txt = $this.hasClass('sorter-false') ? wo.headerTitle_output_nosort : $this.attr('aria-label') || '';
|
||||
} else {
|
||||
txt = (wo.headerTitle_prefix || '') + // now deprecated
|
||||
($this.hasClass('sorter-false') ? wo.headerTitle_output_nosort :
|
||||
ts.isValueInArray( t.column, c.sortList ) >= 0 ? wo.headerTitle_output_sorted : wo.headerTitle_output_unsorted);
|
||||
txt = txt.replace(/\{(current|next|name)\}/gi, function(m){
|
||||
return {
|
||||
'{name}' : $this.text(),
|
||||
'{current}' : wo[ 'headerTitle_cur_' + sortType ][ sortDirection ] || '',
|
||||
'{next}' : wo[ 'headerTitle_nxt_' + sortType ][ sortNext ] || ''
|
||||
}[m.toLowerCase()];
|
||||
});
|
||||
}
|
||||
$this.attr('title', $.isFunction(wo.headerTitle_callback) ? wo.headerTitle_callback($this, txt) : txt);
|
||||
});
|
||||
},
|
||||
remove: function (table, c, wo) {
|
||||
c.$headers.attr('title', '');
|
||||
c.$table.off('refreshHeaderTitle');
|
||||
// remove tooltip class
|
||||
if ($.isArray(wo.headerTitle_tooltip)) {
|
||||
c.$headers.each(function(){
|
||||
$(this).removeClass( wo.headerTitle_tooltip[this.column] || '' );
|
||||
});
|
||||
} else if (wo.headerTitle_tooltip !== '') {
|
||||
c.$headers.removeClass( wo.headerTitle_tooltip );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
413
modules/EcmReports/TableSorterNew/js/widgets/widget-math.js
Normal file
413
modules/EcmReports/TableSorterNew/js/widgets/widget-math.js
Normal file
@@ -0,0 +1,413 @@
|
||||
/*! tablesorter math widget - beta - updated 5/28/2014 (v2.17.1)
|
||||
* Requires tablesorter v2.16+ and jQuery 1.7+
|
||||
* by Rob Garrison
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter,
|
||||
math = {
|
||||
|
||||
// get all of the row numerical values in an arry
|
||||
getRow : function(table, wo, $el, dataAttrib) {
|
||||
var $t, txt,
|
||||
c = table.config,
|
||||
arry = [],
|
||||
$row = $el.closest('tr'),
|
||||
$cells = $row.children();
|
||||
if (!$row.hasClass(wo.filter_filteredRow || 'filtered')) {
|
||||
if (wo.math_ignore.length) {
|
||||
$cells = $cells.not('[' + dataAttrib + '=ignore]').not('[data-column=' + wo.math_ignore.join('],[data-column=') + ']');
|
||||
}
|
||||
arry = $cells.not($el).map(function(){
|
||||
$t = $(this);
|
||||
txt = $t.attr(c.textAttribute);
|
||||
if (typeof txt === "undefined") {
|
||||
txt = this.textContent || $t.text();
|
||||
}
|
||||
txt = ts.formatFloat(txt.replace(/[^\w,. \-()]/g, ""), table);
|
||||
return isNaN(txt) ? 0 : txt;
|
||||
}).get();
|
||||
}
|
||||
return arry;
|
||||
},
|
||||
|
||||
// get all of the column numerical values in an arry
|
||||
getColumn : function(table, wo, $el, type, dataAttrib){
|
||||
var i, txt, $t, len, mathAbove,
|
||||
arry = [],
|
||||
c = table.config,
|
||||
filtered = wo.filter_filteredRow || 'filtered',
|
||||
cIndex = parseInt( $el.attr('data-column'), 10 ),
|
||||
$rows = c.$table.children('tbody').children(),
|
||||
$row = $el.closest('tr');
|
||||
// make sure tfoot rows are AFTER the tbody rows
|
||||
// $rows.add( c.$table.children('tfoot').children() );
|
||||
if (type === 'above') {
|
||||
len = $rows.index($row);
|
||||
i = len;
|
||||
while (i >= 0) {
|
||||
$t = $rows.eq(i).children().filter('[data-column=' + cIndex + ']');
|
||||
mathAbove = $t.filter('[' + dataAttrib + '^=above]').length;
|
||||
// ignore filtered rows & rows with data-math="ignore" (and starting row)
|
||||
if ( ( !$rows.eq(i).hasClass(filtered) && $rows.eq(i).not('[' + dataAttrib + '=ignore]').length && i !== len ) || mathAbove && i !== len ) {
|
||||
// stop calculating "above", when encountering another "above"
|
||||
if (mathAbove) {
|
||||
i = 0;
|
||||
} else if ($t.length) {
|
||||
txt = $t.attr(c.textAttribute);
|
||||
if (typeof txt === "undefined") {
|
||||
txt = $t[0].textContent || $t.text();
|
||||
}
|
||||
txt = ts.formatFloat(txt.replace(/[^\w,. \-()]/g, ""), table);
|
||||
arry.push(isNaN(txt) ? 0 : txt);
|
||||
}
|
||||
}
|
||||
i--;
|
||||
}
|
||||
} else {
|
||||
$rows.each(function(){
|
||||
$t = $(this).children().filter('[data-column=' + cIndex + ']');
|
||||
if (!$(this).hasClass(filtered) && $t.not('[' + dataAttrib + '^=above],[' + dataAttrib + '^=col]').length && !$t.is($el)) {
|
||||
txt = $t.attr(c.textAttribute);
|
||||
if (typeof txt === "undefined") {
|
||||
txt = ($t[0] ? $t[0].textContent : '') || $t.text();
|
||||
}
|
||||
txt = ts.formatFloat(txt.replace(/[^\w,. \-()]/g, ""), table);
|
||||
arry.push(isNaN(txt) ? 0 : txt);
|
||||
}
|
||||
});
|
||||
}
|
||||
return arry;
|
||||
},
|
||||
|
||||
// get all of the column numerical values in an arry
|
||||
getAll : function(table, wo, dataAttrib){
|
||||
var txt, $t, col,
|
||||
arry = [],
|
||||
c = table.config,
|
||||
filtered = wo.filter_filteredRow || 'filtered',
|
||||
$rows = c.$table.children('tbody').children();
|
||||
$rows.each(function(){
|
||||
if (!$(this).hasClass(filtered)) {
|
||||
$(this).children().each(function(){
|
||||
$t = $(this);
|
||||
col = parseInt( $t.attr('data-column'), 10);
|
||||
if (!$t.filter('[' + dataAttrib + ']').length && $.inArray(col, wo.math_ignore) < 0) {
|
||||
txt = $t.attr(c.textAttribute);
|
||||
if (typeof txt === "undefined") {
|
||||
txt = ($t[0] ? $t[0].textContent : '') || $t.text();
|
||||
}
|
||||
txt = ts.formatFloat(txt.replace(/[^\w,. \-()]/g, ""), table);
|
||||
arry.push(isNaN(txt) ? 0 : txt);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return arry;
|
||||
},
|
||||
|
||||
recalculate : function(table, c, wo, init){
|
||||
if (c && (!wo.math_isUpdating || init)) {
|
||||
|
||||
// add data-column attributes to all table cells
|
||||
if (init) {
|
||||
ts.computeColumnIndex( c.$table.children('tbody').children() );
|
||||
}
|
||||
|
||||
// data-attribute name (defaults to data-math)
|
||||
var dataAttrib = 'data-' + (wo.math_data || 'math'),
|
||||
|
||||
// all non-info tbody cells
|
||||
$mathCells = c.$tbodies.find('[' + dataAttrib + ']');
|
||||
math.mathType( table, wo, $mathCells, wo.math_priority, dataAttrib );
|
||||
|
||||
// only info tbody cells
|
||||
$mathCells = c.$table.find('.' + c.cssInfoBlock + ', tfoot').find('[' + dataAttrib + ']');
|
||||
math.mathType( table, wo, $mathCells, wo.math_priority, dataAttrib );
|
||||
|
||||
// find the "all" total
|
||||
math.mathType( table, wo, c.$table.find('[' + dataAttrib + '^=all]'), ['all'], dataAttrib );
|
||||
|
||||
wo.math_isUpdating = true;
|
||||
c.$table.trigger('update');
|
||||
}
|
||||
},
|
||||
|
||||
mathType : function(table, wo, $cells, priority, dataAttrib) {
|
||||
if ($cells.length) {
|
||||
var formula, t, $t, arry, getAll,
|
||||
eq = ts.equations;
|
||||
if (priority[0] === 'all') {
|
||||
// no need to get all cells more than once
|
||||
getAll = math.getAll(table, wo, dataAttrib);
|
||||
}
|
||||
$.each( priority, function(i, type) {
|
||||
$cells.filter('[' + dataAttrib + '^=' + type + ']').each(function(){
|
||||
$t = $(this);
|
||||
formula = ($t.attr(dataAttrib) || '').replace(type + '-', '');
|
||||
arry = (type === "row") ? math.getRow(table, wo, $t, dataAttrib) :
|
||||
(type === "all") ? getAll : math.getColumn(table, wo, $t, type, dataAttrib);
|
||||
if (eq[formula]) {
|
||||
t = eq[formula](arry);
|
||||
if (table.config.debug && console && console.log) {
|
||||
console.log($t.attr(dataAttrib), arry, '=', t);
|
||||
}
|
||||
math.output( $t, wo, t, arry );
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
output : function($cell, wo, value, arry) {
|
||||
// get mask from cell data-attribute: data-math-mask="#,##0.00"
|
||||
var result = ts.formatMask( $cell.attr('data-' + wo.math_data + '-mask') || wo.math_mask, value, wo.math_wrapPrefix, wo.math_wrapSuffix );
|
||||
if ($.isFunction(wo.math_complete)) {
|
||||
result = wo.math_complete($cell, wo, result, value, arry);
|
||||
}
|
||||
if (result !== false) {
|
||||
$cell.html(result);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Modified from https://code.google.com/p/javascript-number-formatter/
|
||||
/**
|
||||
* @preserve IntegraXor Web SCADA - JavaScript Number Formatter
|
||||
* http:// www.integraxor.com/
|
||||
* author: KPL, KHL
|
||||
* (c)2011 ecava
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*/
|
||||
ts.formatMask = function(m, v, tmpPrefix, tmpSuffix){
|
||||
if ( !m || isNaN(+v) ) {
|
||||
return v; // return as it is.
|
||||
}
|
||||
|
||||
var isNegative, result, decimal, group, posLeadZero, posTrailZero, posSeparator, part, szSep,
|
||||
integer, str, offset, i, l, len, start, tmp, end, inv,
|
||||
prefix = '',
|
||||
suffix = '';
|
||||
|
||||
// find prefix/suffix
|
||||
len = m.length;
|
||||
start = m.search( /[0-9\-\+#]/ );
|
||||
tmp = start > 0 ? m.substring(0, start) : '';
|
||||
prefix = tmp;
|
||||
if ( start > 0 && tmpPrefix ) {
|
||||
if ( /\{content\}/.test(tmpPrefix || '') ) {
|
||||
prefix = (tmpPrefix || '').replace(/\{content\}/g, tmp || '');
|
||||
} else {
|
||||
prefix = (tmpPrefix || '') + tmp;
|
||||
}
|
||||
}
|
||||
// reverse string: not an ideal method if there are surrogate pairs
|
||||
inv = m.split('').reverse().join('');
|
||||
end = inv.search( /[0-9\-\+#]/ );
|
||||
i = len - end;
|
||||
i += (m.substring( i, i + 1 ) === '.') ? 1 : 0;
|
||||
tmp = end > 0 ? m.substring( i, len) : '';
|
||||
suffix = tmp;
|
||||
if (tmp !== '' && tmpSuffix) {
|
||||
if ( /\{content\}/.test(tmpSuffix || '') ) {
|
||||
suffix = (tmpSuffix || '').replace(/\{content\}/g, tmp || '');
|
||||
} else {
|
||||
suffix = tmp + (tmpSuffix || '');
|
||||
}
|
||||
}
|
||||
m = m.substring(start, i);
|
||||
|
||||
// convert any string to number according to formation sign.
|
||||
v = m.charAt(0) == '-' ? -v : +v;
|
||||
isNegative = v < 0 ? v = -v : 0; // process only abs(), and turn on flag.
|
||||
|
||||
// search for separator for grp & decimal, anything not digit, not +/- sign, not #.
|
||||
result = m.match( /[^\d\-\+#]/g );
|
||||
decimal = ( result && result[result.length-1] ) || '.'; // treat the right most symbol as decimal
|
||||
group = ( result && result[1] && result[0] ) || ','; // treat the left most symbol as group separator
|
||||
|
||||
// split the decimal for the format string if any.
|
||||
m = m.split( decimal );
|
||||
// Fix the decimal first, toFixed will auto fill trailing zero.
|
||||
v = v.toFixed( m[1] && m[1].length );
|
||||
v = +(v) + ''; // convert number to string to trim off *all* trailing decimal zero(es)
|
||||
|
||||
// fill back any trailing zero according to format
|
||||
posTrailZero = m[1] && m[1].lastIndexOf('0'); // look for last zero in format
|
||||
part = v.split('.');
|
||||
// integer will get !part[1]
|
||||
if ( !part[1] || ( part[1] && part[1].length <= posTrailZero ) ) {
|
||||
v = (+v).toFixed( posTrailZero + 1 );
|
||||
}
|
||||
szSep = m[0].split( group ); // look for separator
|
||||
m[0] = szSep.join(''); // join back without separator for counting the pos of any leading 0.
|
||||
|
||||
posLeadZero = m[0] && m[0].indexOf('0');
|
||||
if ( posLeadZero > -1 ) {
|
||||
while ( part[0].length < ( m[0].length - posLeadZero ) ) {
|
||||
part[0] = '0' + part[0];
|
||||
}
|
||||
} else if ( +part[0] === 0 ) {
|
||||
part[0] = '';
|
||||
}
|
||||
|
||||
v = v.split('.');
|
||||
v[0] = part[0];
|
||||
|
||||
// process the first group separator from decimal (.) only, the rest ignore.
|
||||
// get the length of the last slice of split result.
|
||||
posSeparator = ( szSep[1] && szSep[ szSep.length - 1 ].length );
|
||||
if ( posSeparator ) {
|
||||
integer = v[0];
|
||||
str = '';
|
||||
offset = integer.length % posSeparator;
|
||||
l = integer.length;
|
||||
for ( i = 0; i < l; i++ ) {
|
||||
str += integer.charAt(i); // ie6 only support charAt for sz.
|
||||
// -posSeparator so that won't trail separator on full length
|
||||
/*jshint -W018 */
|
||||
if ( !( ( i - offset + 1 ) % posSeparator ) && i < l - posSeparator ) {
|
||||
str += group;
|
||||
}
|
||||
}
|
||||
v[0] = str;
|
||||
}
|
||||
|
||||
v[1] = ( m[1] && v[1] ) ? decimal + v[1] : "";
|
||||
// put back any negation, combine integer and fraction, and add back prefix & suffix
|
||||
return prefix + ( ( isNegative ? '-' : '' ) + v[0] + v[1] ) + suffix;
|
||||
};
|
||||
|
||||
ts.equations = {
|
||||
count : function(arry) {
|
||||
return arry.length;
|
||||
},
|
||||
sum : function(arry) {
|
||||
var total = 0;
|
||||
$.each( arry, function(i) {
|
||||
total += arry[i];
|
||||
});
|
||||
return total;
|
||||
},
|
||||
mean : function(arry) {
|
||||
var total = ts.equations.sum( arry );
|
||||
return total / arry.length;
|
||||
},
|
||||
median : function(arry) {
|
||||
// https://gist.github.com/caseyjustus/1166258
|
||||
arry.sort( function(a,b){ return a - b; } );
|
||||
var half = Math.floor( arry.length / 2 );
|
||||
return (arry.length % 2) ? arry[half] : ( arry[half - 1] + arry[half] ) / 2.0;
|
||||
},
|
||||
mode : function(arry) {
|
||||
// http://stackoverflow.com/a/3451640/145346
|
||||
if ( arry.length === 0 ) { return 'none'; }
|
||||
var i, el,
|
||||
modeMap = {},
|
||||
maxCount = 1,
|
||||
modes = [arry[0]];
|
||||
for (i = 0; i < arry.length; i++) {
|
||||
el = arry[i];
|
||||
modeMap[el] = modeMap[el] ? modeMap[el] + 1 : 1;
|
||||
if ( modeMap[el] > maxCount ) {
|
||||
modes = [el];
|
||||
maxCount = modeMap[el];
|
||||
} else if (modeMap[el] === maxCount) {
|
||||
modes.push(el);
|
||||
maxCount = modeMap[el];
|
||||
}
|
||||
}
|
||||
// returns arry of modes if there is a tie
|
||||
return modes.sort( function(a,b){ return a - b; } );
|
||||
},
|
||||
max : function(arry) {
|
||||
return Math.max.apply( Math, arry );
|
||||
},
|
||||
min : function(arry) {
|
||||
return Math.min.apply( Math, arry );
|
||||
},
|
||||
range: function(arry) {
|
||||
var v = arry.sort(function(a,b){ return a - b; });
|
||||
return v[ arry.length - 1 ] - v[0];
|
||||
},
|
||||
// common variance equation
|
||||
// (not accessible via data-attribute setting)
|
||||
variance: function(arry, population) {
|
||||
var avg = ts.equations.mean( arry ),
|
||||
v = 0,
|
||||
i = arry.length;
|
||||
while (i--) {
|
||||
v += Math.pow( ( arry[i] - avg ), 2 );
|
||||
}
|
||||
v /= ( arry.length - (population ? 0 : 1) );
|
||||
return v;
|
||||
},
|
||||
// variance (population)
|
||||
varp : function(arry) {
|
||||
return ts.equations.variance(arry, true);
|
||||
},
|
||||
// variance (sample)
|
||||
vars : function(arry) {
|
||||
return ts.equations.variance(arry);
|
||||
},
|
||||
// standard deviation (sample)
|
||||
stdevs : function(arry) {
|
||||
var vars = ts.equations.variance(arry);
|
||||
return Math.sqrt( vars );
|
||||
},
|
||||
// standard deviation (population)
|
||||
stdevp : function(arry){
|
||||
var varp = ts.equations.variance(arry, true);
|
||||
return Math.sqrt( varp );
|
||||
}
|
||||
};
|
||||
|
||||
// add new widget called repeatHeaders
|
||||
// ************************************
|
||||
ts.addWidget({
|
||||
id: "math",
|
||||
priority: 100,
|
||||
options: {
|
||||
math_data : 'math',
|
||||
// column index to ignore
|
||||
math_ignore : [],
|
||||
// mask info: https://code.google.com/p/javascript-number-formatter/
|
||||
math_mask : '#,##0.00',
|
||||
// complete executed after each fucntion
|
||||
math_complete : null, // function($cell, wo, result, value, arry){ return result; },
|
||||
// order of calculation; "all" is last
|
||||
math_priority : [ 'row', 'above', 'col' ],
|
||||
// template for or just prepend the mask prefix & suffix with this HTML
|
||||
// e.g. '<span class="red">{content}</span>'
|
||||
math_prefix : '',
|
||||
math_suffix : ''
|
||||
},
|
||||
init : function(table, thisWidget, c, wo){
|
||||
c.$table
|
||||
.bind('tablesorter-initialized update updateRows addRows updateCell filterReset filterEnd '.split(' ').join('.tsmath '), function(e){
|
||||
var init = e.type === 'tablesorter-initialized';
|
||||
if (!wo.math_isUpdating || init) {
|
||||
math.recalculate( table, c, wo, init );
|
||||
}
|
||||
})
|
||||
.bind('updateComplete.tsmath', function(){
|
||||
setTimeout(function(){
|
||||
wo.math_isUpdating = false;
|
||||
}, 500);
|
||||
});
|
||||
wo.math_isUpdating = false;
|
||||
},
|
||||
// this remove function is called when using the refreshWidgets method or when destroying the tablesorter plugin
|
||||
// this function only applies to tablesorter v2.4+
|
||||
remove: function(table, c, wo){
|
||||
$(table)
|
||||
.unbind('tablesorter-initialized update updateRows addRows updateCell filterReset filterEnd '.split(' ').join('.tsmath '))
|
||||
.find('[data-' + wo.math_data + ']').empty();
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
316
modules/EcmReports/TableSorterNew/js/widgets/widget-output.js
Normal file
316
modules/EcmReports/TableSorterNew/js/widgets/widget-output.js
Normal file
@@ -0,0 +1,316 @@
|
||||
/* Output widget (beta) for TableSorter 7/17/2014 (v2.17.5)
|
||||
* Requires tablesorter v2.8+ and jQuery 1.7+
|
||||
* Modified from:
|
||||
* HTML Table to CSV: http://www.kunalbabre.com/projects/table2CSV.php (License unknown?)
|
||||
* Download-File-JS: https://github.com/PixelsCommander/Download-File-JS (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter,
|
||||
|
||||
output = ts.output = {
|
||||
|
||||
event : 'outputTable',
|
||||
|
||||
// wrap line breaks & tabs in quotes
|
||||
regexQuote : /([\n\t]|<[^<]+>)/, // test
|
||||
regexBR : /(<br([\s\/])?>|\n)/g, // replace
|
||||
regexIMG : /<img[^>]+alt\s*=\s*['"]([^'"]+)['"][^>]*>/i, // match
|
||||
regexHTML : /<[^<]+>/g, // replace
|
||||
|
||||
replaceCR : '\\n',
|
||||
replaceTab : '\\t',
|
||||
|
||||
popupTitle : 'Output',
|
||||
popupStyle : 'width:100%;height:100%;', // for textarea
|
||||
message : 'Your device does not support downloading. Please try again in desktop browser.',
|
||||
|
||||
init : function(c) {
|
||||
c.$table
|
||||
.off(output.event)
|
||||
.on(output.event, function(){
|
||||
// explicitly use table.config.widgetOptions because we want
|
||||
// the most up-to-date values; not the "wo" from initialization
|
||||
output.process(c, c.widgetOptions);
|
||||
});
|
||||
},
|
||||
|
||||
processRow: function(c, $rows, isHeader, isJSON) {
|
||||
var $this, row, col, rowlen, collen, txt,
|
||||
wo = c.widgetOptions,
|
||||
tmpRow = [],
|
||||
dupe = wo.output_duplicateSpans,
|
||||
addSpanIndex = isHeader && isJSON && wo.output_headerRows && $.isFunction(wo.output_callbackJSON),
|
||||
cellIndex = 0;
|
||||
$rows.each(function(rowIndex) {
|
||||
if (!tmpRow[rowIndex]) { tmpRow[rowIndex] = []; }
|
||||
cellIndex = 0;
|
||||
$(this).children().each(function(){
|
||||
$this = $(this);
|
||||
// process rowspans
|
||||
if ($this.filter('[rowspan]').length) {
|
||||
rowlen = parseInt( $this.attr('rowspan'), 10) - 1;
|
||||
txt = output.formatData( wo, $this.attr(wo.output_dataAttrib) || $this.html(), isHeader );
|
||||
for (row = 1; row <= rowlen; row++) {
|
||||
if (!tmpRow[rowIndex + row]) { tmpRow[rowIndex + row] = []; }
|
||||
tmpRow[rowIndex + row][cellIndex] = isHeader ? txt : dupe ? txt : '';
|
||||
}
|
||||
}
|
||||
// process colspans
|
||||
if ($this.filter('[colspan]').length) {
|
||||
collen = parseInt( $this.attr('colspan'), 10) - 1;
|
||||
txt = output.formatData( wo, $this.attr(wo.output_dataAttrib) || $this.html(), isHeader );
|
||||
for (col = 1; col <= collen; col++) {
|
||||
// if we're processing the header & making JSON, the header names need to be unique
|
||||
if ($this.filter('[rowspan]').length) {
|
||||
rowlen = parseInt( $this.attr('rowspan'), 10);
|
||||
for (row = 0; row < rowlen; row++) {
|
||||
if (!tmpRow[rowIndex + row]) { tmpRow[rowIndex + row] = []; }
|
||||
tmpRow[rowIndex + row][cellIndex + col] = addSpanIndex ?
|
||||
wo.output_callbackJSON($this, txt, cellIndex + col) || txt + '(' + (cellIndex + col) + ')' : isHeader ? txt : dupe ? txt : '';
|
||||
}
|
||||
} else {
|
||||
tmpRow[rowIndex][cellIndex + col] = addSpanIndex ?
|
||||
wo.output_callbackJSON($this, txt, cellIndex + col) || txt + '(' + (cellIndex + col) + ')' : isHeader ? txt : dupe ? txt : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't include hidden columns
|
||||
if ( $this.css('display') !== 'none' ) {
|
||||
// skip column if already defined
|
||||
while (typeof tmpRow[rowIndex][cellIndex] !== 'undefined') { cellIndex++; }
|
||||
tmpRow[rowIndex][cellIndex] = tmpRow[rowIndex][cellIndex] ||
|
||||
output.formatData( wo, $this.attr(wo.output_dataAttrib) || $this.html(), isHeader );
|
||||
cellIndex++;
|
||||
}
|
||||
});
|
||||
});
|
||||
return tmpRow;
|
||||
},
|
||||
|
||||
ignoreColumns : function(wo, data) {
|
||||
// ignore columns -> remove data from built array (because we've already processed any rowspan/colspan)
|
||||
$.each( data, function(indx, val){
|
||||
data[indx] = $.grep(val, function(v, cellIndx){
|
||||
return $.inArray(cellIndx, wo.output_ignoreColumns) < 0;
|
||||
});
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
process : function(c, wo) {
|
||||
var mydata, $this, $rows, headers, csvData, len,
|
||||
hasStringify = window.JSON && JSON.hasOwnProperty('stringify'),
|
||||
indx = 0,
|
||||
tmpData = (wo.output_separator || ',').toLowerCase(),
|
||||
outputJSON = tmpData === 'json',
|
||||
outputArray = tmpData === 'array',
|
||||
separator = outputJSON || outputArray ? ',' : wo.output_separator,
|
||||
$el = c.$table;
|
||||
// regex to look for the set separator or HTML
|
||||
wo.output_regex = new RegExp('(' + (/\\/.test(separator) ? '\\' : '' ) + separator + ')' );
|
||||
|
||||
// get header cells
|
||||
$this = $el.find('thead tr:visible').not('.' + (ts.css.filterRow || 'tablesorter-filter-row') );
|
||||
headers = output.processRow(c, $this, true, outputJSON);
|
||||
|
||||
// all tbody rows
|
||||
$rows = $el.children('tbody').children('tr');
|
||||
// get (f)iltered, (v)isible or all rows (look for the first letter only)
|
||||
$rows = /f/.test(wo.output_saveRows) ? $rows.not('.' + (wo.filter_filteredRow || 'filtered') ) :
|
||||
/v/.test(wo.output_saveRows) ? $rows.filter(':visible') : $rows;
|
||||
|
||||
// process to array of arrays
|
||||
csvData = output.processRow(c, $rows);
|
||||
len = headers.length;
|
||||
|
||||
if (wo.output_ignoreColumns.length) {
|
||||
headers = output.ignoreColumns(wo, headers);
|
||||
csvData = output.ignoreColumns(wo, csvData);
|
||||
}
|
||||
|
||||
if (outputJSON) {
|
||||
tmpData = [];
|
||||
$.each( csvData, function(indx, val){
|
||||
// multiple header rows & output_headerRows = true, pick the last row...
|
||||
tmpData.push( output.row2Hash( headers[ (len > 1 && wo.output_headerRows) ? indx % len : len - 1], val ) );
|
||||
});
|
||||
|
||||
// requires JSON stringify; if it doesn't exist, the output will show [object Object],... in the output window
|
||||
mydata = hasStringify ? JSON.stringify(tmpData) : tmpData;
|
||||
} else {
|
||||
tmpData = output.row2CSV(wo, wo.output_headerRows ? headers : [ headers[ (len > 1 && wo.output_headerRows) ? indx % len : len - 1] ], outputArray)
|
||||
.concat( output.row2CSV(wo, csvData, outputArray) );
|
||||
|
||||
// stringify the array; if stringify doesn't exist the array will be flattened
|
||||
mydata = outputArray && hasStringify ? JSON.stringify(tmpData) : tmpData.join('\n');
|
||||
}
|
||||
|
||||
// callback; if true returned, continue processing
|
||||
if ($.isFunction(wo.output_callback) && !wo.output_callback(c, mydata)) { return; }
|
||||
|
||||
if ( /p/.test( (wo.output_delivery || '').toLowerCase() ) ) {
|
||||
output.popup(mydata, wo.output_popupStyle, outputJSON || outputArray);
|
||||
} else {
|
||||
output.download(wo, mydata);
|
||||
}
|
||||
|
||||
}, // end process
|
||||
|
||||
row2CSV : function(wo, tmpRow, outputArray) {
|
||||
var tmp, rowIndex,
|
||||
csvData = [],
|
||||
rowLen = tmpRow.length;
|
||||
for (rowIndex = 0; rowIndex < rowLen; rowIndex++) {
|
||||
// remove any blank rows
|
||||
tmp = tmpRow[rowIndex].join('').replace(/\"/g,'');
|
||||
if (tmpRow[rowIndex].length > 0 && tmp !== '') {
|
||||
csvData[csvData.length] = outputArray ? tmpRow[rowIndex] : tmpRow[rowIndex].join(wo.output_separator);
|
||||
}
|
||||
}
|
||||
return csvData;
|
||||
},
|
||||
|
||||
row2Hash : function(keys, values) {
|
||||
var json = {};
|
||||
$.each(values, function(indx, val) {
|
||||
if ( indx < keys.length ) {
|
||||
json[ keys[indx] ] = val;
|
||||
}
|
||||
});
|
||||
return json;
|
||||
},
|
||||
|
||||
formatData : function(wo, input, isHeader) {
|
||||
var txt,
|
||||
quotes = (wo.output_separator || ',').toLowerCase(),
|
||||
separator = quotes === 'json' || quotes === 'array',
|
||||
// replace " with “ if undefined
|
||||
result = input.replace(/\"/g, wo.output_replaceQuote || '\u201c');
|
||||
// replace line breaks with \\n & tabs with \\t
|
||||
result = result.replace(output.regexBR, output.replaceCR).replace(/\t/g, output.replaceTab);
|
||||
// extract img alt text
|
||||
txt = result.match(output.regexIMG);
|
||||
if (!wo.output_includeHTML && txt !== null) {
|
||||
result = txt[1];
|
||||
}
|
||||
// replace/remove html
|
||||
result = wo.output_includeHTML && !isHeader ? result : result.replace(output.regexHTML, '');
|
||||
result = wo.output_trimSpaces || isHeader ? $.trim(result) : result;
|
||||
// JSON & array outputs don't need quotes
|
||||
quotes = separator ? false : wo.output_wrapQuotes || wo.output_regex.test(result) || output.regexQuote.test(result);
|
||||
return quotes ? '"' + result + '"' : result;
|
||||
},
|
||||
|
||||
popup : function(data, style, wrap) {
|
||||
var generator = window.open('', output.popupTitle, style);
|
||||
generator.document.write(
|
||||
'<html><head><title>' + output.popupTitle + '</title></head><body>' +
|
||||
'<textarea wrap="' + (wrap ? 'on' : 'off') + '" style="' + output.popupStyle + '">' + data + '\n</textarea>' +
|
||||
'</body></html>'
|
||||
);
|
||||
generator.document.close();
|
||||
generator.focus();
|
||||
// select all text and focus within the textarea in the popup
|
||||
// $(generator.document).find('textarea').select().focus();
|
||||
return true;
|
||||
},
|
||||
|
||||
// modified from https://github.com/PixelsCommander/Download-File-JS
|
||||
// & http://html5-demos.appspot.com/static/a.download.html
|
||||
download : function (wo, data){
|
||||
|
||||
var e, blob, gotBlob,
|
||||
nav = window.navigator,
|
||||
link = document.createElement('a');
|
||||
|
||||
// iOS devices do not support downloading. We have to inform user about this.
|
||||
if (/(iP)/g.test(nav.userAgent)) {
|
||||
alert(output.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
// test for blob support
|
||||
try {
|
||||
gotBlob = !!new Blob();
|
||||
} catch (err) {
|
||||
gotBlob = false;
|
||||
}
|
||||
|
||||
// Use HTML5 Blob if browser supports it
|
||||
if ( gotBlob ) {
|
||||
|
||||
window.URL = window.webkitURL || window.URL;
|
||||
blob = new Blob([data], {type: wo.output_encoding});
|
||||
|
||||
if (nav.msSaveBlob) {
|
||||
// IE 10+
|
||||
nav.msSaveBlob(blob, wo.output_saveFileName);
|
||||
} else {
|
||||
// all other browsers
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.download = wo.output_saveFileName;
|
||||
// Dispatching click event; using $(link).trigger() won't work
|
||||
if (document.createEvent) {
|
||||
e = document.createEvent('MouseEvents');
|
||||
// event.initMouseEvent(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
|
||||
e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||||
link.dispatchEvent(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// fallback to force file download (whether supported by server).
|
||||
// not sure if this actually works in IE9 and older...
|
||||
window.open( wo.output_encoding + encodeURIComponent(data) + '?download' , '_self');
|
||||
return true;
|
||||
|
||||
},
|
||||
|
||||
remove : function(c) {
|
||||
c.$table.off(output.event);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ts.addWidget({
|
||||
id: "output",
|
||||
options: {
|
||||
output_separator : ',', // set to "json", "array" or any separator
|
||||
output_ignoreColumns : [], // columns to ignore [0, 1,... ] (zero-based index)
|
||||
output_dataAttrib : 'data-name', // header attrib containing modified header name
|
||||
output_headerRows : false, // if true, include multiple header rows (JSON only)
|
||||
output_delivery : 'popup', // popup, download
|
||||
output_saveRows : 'filtered', // all, visible or filtered
|
||||
output_duplicateSpans: true, // duplicate output data in tbody colspan/rowspan
|
||||
output_replaceQuote : '\u201c;', // left double quote
|
||||
output_includeHTML : false,
|
||||
output_trimSpaces : true,
|
||||
output_wrapQuotes : false,
|
||||
output_popupStyle : 'width=500,height=300',
|
||||
output_saveFileName : 'mytable.csv',
|
||||
// callback executed when processing completes
|
||||
// return true to continue download/output
|
||||
// return false to stop delivery & do something else with the data
|
||||
output_callback : function(config, data){ return true; },
|
||||
// JSON callback executed when a colspan is encountered in the header
|
||||
output_callbackJSON : function($cell, txt, cellIndex) { return txt + '(' + (cellIndex) + ')'; },
|
||||
// the need to modify this for Excel no longer exists
|
||||
output_encoding : 'data:application/octet-stream;charset=utf8,'
|
||||
|
||||
},
|
||||
init: function(table, thisWidget, c) {
|
||||
output.init(c);
|
||||
},
|
||||
remove: function(table, c){
|
||||
output.remove(c);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
975
modules/EcmReports/TableSorterNew/js/widgets/widget-pager.js
Normal file
975
modules/EcmReports/TableSorterNew/js/widgets/widget-pager.js
Normal file
@@ -0,0 +1,975 @@
|
||||
/* Pager widget for TableSorter 9/15/2014 (v2.17.8) */
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
var tsp,
|
||||
ts = $.tablesorter;
|
||||
|
||||
ts.addWidget({
|
||||
id: "pager",
|
||||
priority: 55, // load pager after filter widget
|
||||
options : {
|
||||
// output default: '{page}/{totalPages}'
|
||||
// possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows}
|
||||
pager_output: '{startRow} to {endRow} of {totalRows} rows', // '{page}/{totalPages}'
|
||||
|
||||
// apply disabled classname to the pager arrows when the rows at either extreme is visible
|
||||
pager_updateArrows: true,
|
||||
|
||||
// starting page of the pager (zero based index)
|
||||
pager_startPage: 0,
|
||||
|
||||
// reset pager after filtering; set to desired page #
|
||||
// set to false to not change page at filter start
|
||||
pager_pageReset: 0,
|
||||
|
||||
// Number of visible rows
|
||||
pager_size: 10,
|
||||
|
||||
// Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js)
|
||||
pager_savePages: true,
|
||||
|
||||
//defines custom storage key
|
||||
pager_storageKey: 'tablesorter-pager',
|
||||
|
||||
// if true, the table will remain the same height no matter how many records are displayed. The space is made up by an empty
|
||||
// table row set to a height to compensate; default is false
|
||||
pager_fixedHeight: false,
|
||||
|
||||
// count child rows towards the set page size? (set true if it is a visible table row within the pager)
|
||||
// if true, child row(s) may not appear to be attached to its parent row, may be split across pages or
|
||||
// may distort the table if rowspan or cellspans are included.
|
||||
pager_countChildRows: false,
|
||||
|
||||
// remove rows from the table to speed up the sort of large tables.
|
||||
// setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled.
|
||||
pager_removeRows: false, // removing rows in larger tables speeds up the sort
|
||||
|
||||
// use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}"
|
||||
// where {page} is replaced by the page number, {size} is replaced by the number of records to show,
|
||||
// {sortList:col} adds the sortList to the url into a "col" array, and {filterList:fcol} adds
|
||||
// the filterList to the url into an "fcol" array.
|
||||
// So a sortList = [[2,0],[3,0]] becomes "&col[2]=0&col[3]=0" in the url
|
||||
// and a filterList = [[2,Blue],[3,13]] becomes "&fcol[2]=Blue&fcol[3]=13" in the url
|
||||
pager_ajaxUrl: null,
|
||||
|
||||
// modify the url after all processing has been applied
|
||||
pager_customAjaxUrl: function(table, url) { return url; },
|
||||
|
||||
// modify the $.ajax object to allow complete control over your ajax requests
|
||||
pager_ajaxObject: {
|
||||
dataType: 'json'
|
||||
},
|
||||
|
||||
// set this to false if you want to block ajax loading on init
|
||||
pager_processAjaxOnInit: true,
|
||||
|
||||
// process ajax so that the following information is returned:
|
||||
// [ total_rows (number), rows (array of arrays), headers (array; optional) ]
|
||||
// example:
|
||||
// [
|
||||
// 100, // total rows
|
||||
// [
|
||||
// [ "row1cell1", "row1cell2", ... "row1cellN" ],
|
||||
// [ "row2cell1", "row2cell2", ... "row2cellN" ],
|
||||
// ...
|
||||
// [ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
|
||||
// ],
|
||||
// [ "header1", "header2", ... "headerN" ] // optional
|
||||
// ]
|
||||
pager_ajaxProcessing: function(ajax){ return [ 0, [], null ]; },
|
||||
|
||||
// css class names of pager arrows
|
||||
pager_css: {
|
||||
container : 'tablesorter-pager',
|
||||
errorRow : 'tablesorter-errorRow', // error information row (don't include period at beginning)
|
||||
disabled : 'disabled' // class added to arrows @ extremes (i.e. prev/first arrows "disabled" on first page)
|
||||
},
|
||||
|
||||
// jQuery selectors
|
||||
pager_selectors: {
|
||||
container : '.pager', // target the pager markup
|
||||
first : '.first', // go to first page arrow
|
||||
prev : '.prev', // previous page arrow
|
||||
next : '.next', // next page arrow
|
||||
last : '.last', // go to last page arrow
|
||||
gotoPage : '.gotoPage', // go to page selector - select dropdown that sets the current page
|
||||
pageDisplay : '.pagedisplay', // location of where the "output" is displayed
|
||||
pageSize : '.pagesize' // page size selector - select dropdown that sets the "size" option
|
||||
}
|
||||
},
|
||||
init: function(table){
|
||||
tsp.init(table);
|
||||
},
|
||||
// only update to complete sorter initialization
|
||||
format: function(table, c){
|
||||
if (!(c.pager && c.pager.initialized)){
|
||||
return tsp.initComplete(table, c);
|
||||
}
|
||||
tsp.moveToPage(table, c.pager, false);
|
||||
},
|
||||
remove: function(table, c){
|
||||
tsp.destroyPager(table, c);
|
||||
}
|
||||
});
|
||||
|
||||
/* pager widget functions */
|
||||
tsp = ts.pager = {
|
||||
|
||||
init: function(table) {
|
||||
// check if tablesorter has initialized
|
||||
if (table.hasInitialized && table.config.pager.initialized) { return; }
|
||||
var t,
|
||||
c = table.config,
|
||||
wo = c.widgetOptions,
|
||||
s = wo.pager_selectors,
|
||||
|
||||
// save pager variables
|
||||
p = c.pager = $.extend({
|
||||
totalPages: 0,
|
||||
filteredRows: 0,
|
||||
filteredPages: 0,
|
||||
currentFilters: [],
|
||||
page: wo.pager_startPage,
|
||||
startRow: 0,
|
||||
endRow: 0,
|
||||
ajaxCounter: 0,
|
||||
$size: null,
|
||||
last: {}
|
||||
}, c.pager);
|
||||
|
||||
// pager initializes multiple times before table has completed initialization
|
||||
if (p.isInitializing) { return; }
|
||||
|
||||
p.isInitializing = true;
|
||||
if (c.debug) {
|
||||
ts.log('Pager initializing');
|
||||
}
|
||||
|
||||
p.size = $.data(table, 'pagerLastSize') || wo.pager_size;
|
||||
// added in case the pager is reinitialized after being destroyed.
|
||||
p.$container = $(s.container).addClass(wo.pager_css.container).show();
|
||||
// goto selector
|
||||
p.$goto = p.$container.find(s.gotoPage); // goto is a reserved word #657
|
||||
// page size selector
|
||||
p.$size = p.$container.find(s.pageSize);
|
||||
p.totalRows = c.$tbodies.eq(0).children('tr').not( c.widgetOptions.pager_countChildRows ? '' : '.' + c.cssChildRow ).length;
|
||||
p.oldAjaxSuccess = p.oldAjaxSuccess || wo.pager_ajaxObject.success;
|
||||
c.appender = tsp.appender;
|
||||
if (ts.filter && $.inArray('filter', c.widgets) >= 0) {
|
||||
// get any default filter settings (data-value attribute) fixes #388
|
||||
p.currentFilters = c.$table.data('lastSearch') || ts.filter.setDefaults(table, c, wo) || [];
|
||||
// set, but don't apply current filters
|
||||
ts.setFilters(table, p.currentFilters, false);
|
||||
}
|
||||
if (wo.pager_savePages && ts.storage) {
|
||||
t = ts.storage(table, wo.pager_storageKey) || {}; // fixes #387
|
||||
p.page = isNaN(t.page) ? p.page : t.page;
|
||||
p.size = ( isNaN(t.size) ? p.size : t.size ) || 10;
|
||||
$.data(table, 'pagerLastSize', p.size);
|
||||
}
|
||||
|
||||
// skipped rows
|
||||
p.regexRows = new RegExp('(' + (wo.filter_filteredRow || 'filtered') + '|' + c.selectorRemove.replace(/^(\w+\.)/g,'') + '|' + c.cssChildRow + ')');
|
||||
|
||||
// clear initialized flag
|
||||
p.initialized = false;
|
||||
// before initialization event
|
||||
c.$table.trigger('pagerBeforeInitialized', c);
|
||||
|
||||
tsp.enablePager(table, c, false);
|
||||
|
||||
if ( typeof(wo.pager_ajaxUrl) === 'string' ) {
|
||||
// ajax pager; interact with database
|
||||
p.ajax = true;
|
||||
// When filtering with ajax, allow only custom filtering function, disable default filtering since it will be done server side.
|
||||
wo.filter_serversideFiltering = true;
|
||||
c.serverSideSorting = true;
|
||||
tsp.moveToPage(table, p);
|
||||
} else {
|
||||
p.ajax = false;
|
||||
// Regular pager; all rows stored in memory
|
||||
c.$table.trigger("appendCache", [{}, true]);
|
||||
tsp.hideRowsSetup(table, c);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
initComplete: function(table, c){
|
||||
var p = c.pager;
|
||||
tsp.changeHeight(table, c);
|
||||
tsp.bindEvents(table, c);
|
||||
tsp.setPageSize(table, 0, c); // page size 0 is ignored
|
||||
|
||||
// pager initialized
|
||||
p.initialized = true;
|
||||
p.isInitializing = false;
|
||||
c.$table.trigger('pagerInitialized', c);
|
||||
tsp.updatePageDisplay(table, c);
|
||||
},
|
||||
|
||||
bindEvents: function(table, c){
|
||||
var ctrls, fxn,
|
||||
p = c.pager,
|
||||
wo = c.widgetOptions,
|
||||
s = wo.pager_selectors;
|
||||
|
||||
c.$table
|
||||
.unbind('filterStart filterEnd sortEnd disable enable destroy updateComplete pageSize '.split(' ').join('.pager '))
|
||||
.bind('filterStart.pager', function(e, filters) {
|
||||
p.currentFilters = filters;
|
||||
// don't change page is filters are the same (pager updating, etc)
|
||||
if (wo.pager_pageReset !== false && (c.lastCombinedFilter || '') !== (filters || []).join('')) {
|
||||
p.page = wo.pager_pageReset; // fixes #456 & #565
|
||||
}
|
||||
})
|
||||
// update pager after filter widget completes
|
||||
.bind('filterEnd.pager sortEnd.pager', function() {
|
||||
if (p.initialized) {
|
||||
if (c.delayInit && c.rowsCopy && c.rowsCopy.length === 0) {
|
||||
// make sure we have a copy of all table rows once the cache has been built
|
||||
tsp.updateCache(table);
|
||||
}
|
||||
// update page display first, so we update p.filteredPages
|
||||
tsp.updatePageDisplay(table, c, false);
|
||||
// tsp.moveToPage(table, p, false); <-- called when applyWidgets is triggered
|
||||
c.pager.last.page = -1;
|
||||
c.$table.trigger('applyWidgets');
|
||||
tsp.fixHeight(table, c);
|
||||
}
|
||||
})
|
||||
.bind('disable.pager', function(e){
|
||||
e.stopPropagation();
|
||||
tsp.showAllRows(table, c);
|
||||
})
|
||||
.on('enable.pager', function(e){
|
||||
e.stopPropagation();
|
||||
tsp.enablePager(table, c, true);
|
||||
})
|
||||
.on('destroy.pager', function(e){
|
||||
e.stopPropagation();
|
||||
tsp.destroyPager(table, c);
|
||||
})
|
||||
.on('updateComplete.pager', function(e, table, triggered){
|
||||
e.stopPropagation();
|
||||
// table can be unintentionally undefined in tablesorter v2.17.7 and earlier
|
||||
if (!table || triggered) { return; }
|
||||
tsp.fixHeight(table, c);
|
||||
var $rows = c.$tbodies.eq(0).children('tr').not(c.selectorRemove);
|
||||
p.totalRows = $rows.length - ( c.widgetOptions.pager_countChildRows ? 0 : $rows.filter('.' + c.cssChildRow).length );
|
||||
p.totalPages = Math.ceil( p.totalRows / p.size );
|
||||
if ($rows.length && c.rowsCopy && c.rowsCopy.length === 0) {
|
||||
// make a copy of all table rows once the cache has been built
|
||||
tsp.updateCache(table);
|
||||
}
|
||||
tsp.updatePageDisplay(table, c);
|
||||
tsp.hideRows(table, c);
|
||||
// make sure widgets are applied - fixes #450
|
||||
c.$table.trigger('applyWidgets');
|
||||
})
|
||||
.on('pageSize.pager', function(e,v){
|
||||
e.stopPropagation();
|
||||
tsp.setPageSize(table, parseInt(v, 10) || 10, c);
|
||||
tsp.hideRows(table, c);
|
||||
tsp.updatePageDisplay(table, c, false);
|
||||
if (p.$size.length) { p.$size.val(p.size); } // twice?
|
||||
})
|
||||
.on('pageSet.pager', function(e,v){
|
||||
e.stopPropagation();
|
||||
p.page = (parseInt(v, 10) || 1) - 1;
|
||||
if (p.$goto.length) { p.$goto.val(c.size); } // twice?
|
||||
tsp.moveToPage(table, p, true);
|
||||
tsp.updatePageDisplay(table, c, false);
|
||||
});
|
||||
|
||||
// clicked controls
|
||||
ctrls = [ s.first, s.prev, s.next, s.last ];
|
||||
fxn = [ 'moveToFirstPage', 'moveToPrevPage', 'moveToNextPage', 'moveToLastPage' ];
|
||||
p.$container.find(ctrls.join(','))
|
||||
.attr("tabindex", 0)
|
||||
.unbind('click.pager')
|
||||
.bind('click.pager', function(e){
|
||||
e.stopPropagation();
|
||||
var i,
|
||||
$c = $(this),
|
||||
l = ctrls.length;
|
||||
if ( !$c.hasClass(wo.pager_css.disabled) ) {
|
||||
for (i = 0; i < l; i++) {
|
||||
if ($c.is(ctrls[i])) {
|
||||
tsp[fxn[i]](table, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if ( p.$goto.length ) {
|
||||
p.$goto
|
||||
.unbind('change')
|
||||
.bind('change', function(){
|
||||
p.page = $(this).val() - 1;
|
||||
tsp.moveToPage(table, p, true);
|
||||
tsp.updatePageDisplay(table, c, false);
|
||||
});
|
||||
}
|
||||
|
||||
if ( p.$size.length ) {
|
||||
// setting an option as selected appears to cause issues with initial page size
|
||||
p.$size.find('option').removeAttr('selected');
|
||||
p.$size
|
||||
.unbind('change.pager')
|
||||
.bind('change.pager', function() {
|
||||
p.$size.val( $(this).val() ); // in case there are more than one pagers
|
||||
if ( !$(this).hasClass(wo.pager_css.disabled) ) {
|
||||
tsp.setPageSize(table, parseInt( $(this).val(), 10 ), c);
|
||||
tsp.changeHeight(table, c);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// hide arrows at extremes
|
||||
pagerArrows: function(c, disable) {
|
||||
var p = c.pager,
|
||||
dis = !!disable,
|
||||
first = dis || p.page === 0,
|
||||
tp = Math.min( p.totalPages, p.filteredPages ),
|
||||
last = dis || p.page === tp - 1 || tp === 0,
|
||||
wo = c.widgetOptions,
|
||||
s = wo.pager_selectors;
|
||||
if ( wo.pager_updateArrows ) {
|
||||
p.$container.find(s.first + ',' + s.prev).toggleClass(wo.pager_css.disabled, first).attr('aria-disabled', first);
|
||||
p.$container.find(s.next + ',' + s.last).toggleClass(wo.pager_css.disabled, last).attr('aria-disabled', last);
|
||||
}
|
||||
},
|
||||
|
||||
updatePageDisplay: function(table, c, completed) {
|
||||
var i, pg, s, $out, regex,
|
||||
wo = c.widgetOptions,
|
||||
p = c.pager,
|
||||
f = c.$table.hasClass('hasFilters'),
|
||||
t = [],
|
||||
sz = p.size || 10; // don't allow dividing by zero
|
||||
t = [ wo && wo.filter_filteredRow || 'filtered', c.selectorRemove.replace(/^(\w+\.)/g,'') ];
|
||||
if (wo.pager_countChildRows) { t.push(c.cssChildRow); }
|
||||
regex = new RegExp( '(' + t.join('|') + ')' );
|
||||
p.$size.add(p.$goto).removeClass(wo.pager_css.disabled).removeAttr('disabled').attr('aria-disabled', 'false');
|
||||
if (f && !wo.pager_ajaxUrl) {
|
||||
if ($.isEmptyObject(c.cache)) {
|
||||
// delayInit: true so nothing is in the cache
|
||||
p.filteredRows = p.totalRows = c.$tbodies.eq(0).children('tr').not( c.widgetOptions.pager_countChildRows ? '' : '.' + c.cssChildRow ).length;
|
||||
} else {
|
||||
p.filteredRows = 0;
|
||||
$.each(c.cache[0].normalized, function(i, el) {
|
||||
p.filteredRows += p.regexRows.test(el[c.columns].$row[0].className) ? 0 : 1;
|
||||
});
|
||||
}
|
||||
} else if (!f) {
|
||||
p.filteredRows = p.totalRows;
|
||||
}
|
||||
p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method
|
||||
c.totalRows = p.totalRows;
|
||||
c.filteredRows = p.filteredRows;
|
||||
p.filteredPages = Math.ceil( p.filteredRows / sz ) || 0;
|
||||
if ( Math.min( p.totalPages, p.filteredPages ) >= 0 ) {
|
||||
t = (p.size * p.page > p.filteredRows);
|
||||
p.startRow = (t) ? 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1);
|
||||
p.page = (t) ? 0 : p.page;
|
||||
p.endRow = Math.min( p.filteredRows, p.totalRows, p.size * ( p.page + 1 ) );
|
||||
$out = p.$container.find(wo.pager_selectors.pageDisplay);
|
||||
// form the output string (can now get a new output string from the server)
|
||||
s = ( p.ajaxData && p.ajaxData.output ? p.ajaxData.output || wo.pager_output : wo.pager_output )
|
||||
// {page} = one-based index; {page+#} = zero based index +/- value
|
||||
.replace(/\{page([\-+]\d+)?\}/gi, function(m,n){
|
||||
return p.totalPages ? p.page + (n ? parseInt(n, 10) : 1) : 0;
|
||||
})
|
||||
// {totalPages}, {extra}, {extra:0} (array) or {extra : key} (object)
|
||||
.replace(/\{\w+(\s*:\s*\w+)?\}/gi, function(m){
|
||||
var len, indx,
|
||||
str = m.replace(/[{}\s]/g,''),
|
||||
extra = str.split(':'),
|
||||
data = p.ajaxData,
|
||||
// return zero for default page/row numbers
|
||||
deflt = /(rows?|pages?)$/i.test(str) ? 0 : '';
|
||||
if (/(startRow|page)/.test(extra[0]) && extra[1] === 'input') {
|
||||
len = ('' + (extra[0] === 'page' ? p.totalPages : p.totalRows)).length;
|
||||
indx = extra[0] === 'page' ? p.page + 1 : p.startRow;
|
||||
return '<input type="text" class="ts-' + extra[0] + '" style="max-width:' + len + 'em" value="' + indx + '"/>';
|
||||
}
|
||||
return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt;
|
||||
});
|
||||
if ($out.length) {
|
||||
$out[ ($out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
|
||||
if ( p.$goto.length ) {
|
||||
t = '';
|
||||
pg = Math.min( p.totalPages, p.filteredPages );
|
||||
for ( i = 1; i <= pg; i++ ) {
|
||||
t += '<option>' + i + '</option>';
|
||||
}
|
||||
p.$goto[0].innerHTML = t;
|
||||
p.$goto[0].value = p.page + 1;
|
||||
}
|
||||
// rebind startRow/page inputs
|
||||
$out.find('.ts-startRow, .ts-page').unbind('change').bind('change', function(){
|
||||
var v = $(this).val(),
|
||||
pg = $(this).hasClass('ts-startRow') ? Math.floor( v/p.size ) + 1 : v;
|
||||
c.$table.trigger('pageSet.pager', [ pg ]);
|
||||
});
|
||||
}
|
||||
}
|
||||
tsp.pagerArrows(c);
|
||||
if (p.initialized && completed !== false) {
|
||||
c.$table.trigger('pagerComplete', c);
|
||||
// save pager info to storage
|
||||
if (wo.pager_savePages && ts.storage) {
|
||||
ts.storage(table, wo.pager_storageKey, {
|
||||
page : p.page,
|
||||
size : p.size
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
fixHeight: function(table, c) {
|
||||
var d, h,
|
||||
p = c.pager,
|
||||
wo = c.widgetOptions,
|
||||
$b = c.$tbodies.eq(0);
|
||||
if (wo.pager_fixedHeight) {
|
||||
$b.find('tr.pagerSavedHeightSpacer').remove();
|
||||
h = $.data(table, 'pagerSavedHeight');
|
||||
if (h) {
|
||||
d = h - $b.height();
|
||||
if ( d > 5 && $.data(table, 'pagerLastSize') === p.size && $b.children('tr:visible').length < p.size ) {
|
||||
$b.append('<tr class="pagerSavedHeightSpacer ' + wo.pager_selectors.remove.replace(/^(\w+\.)/g,'') + '" style="height:' + d + 'px;"></tr>');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
changeHeight: function(table, c) {
|
||||
var $b = c.$tbodies.eq(0);
|
||||
$b.find('tr.pagerSavedHeightSpacer').remove();
|
||||
$.data(table, 'pagerSavedHeight', $b.height());
|
||||
tsp.fixHeight(table, c);
|
||||
$.data(table, 'pagerLastSize', c.pager.size);
|
||||
},
|
||||
|
||||
hideRows: function(table, c){
|
||||
if (!c.widgetOptions.pager_ajaxUrl) {
|
||||
var i,
|
||||
lastIndex = 0,
|
||||
p = c.pager,
|
||||
wo = c.widgetOptions,
|
||||
rows = c.$tbodies.eq(0).children('tr'),
|
||||
l = rows.length,
|
||||
s = ( p.page * p.size ),
|
||||
e = s + p.size,
|
||||
f = wo && wo.filter_filteredRow || 'filtered',
|
||||
j = 0; // size counter
|
||||
for ( i = 0; i < l; i++ ){
|
||||
if ( !rows[i].className.match(f) ) {
|
||||
if (j === s && rows[i].className.match(c.cssChildRow)) {
|
||||
// hide child rows @ start of pager (if already visible)
|
||||
rows[i].style.display = 'none';
|
||||
} else {
|
||||
rows[i].style.display = ( j >= s && j < e ) ? '' : 'none';
|
||||
// don't count child rows
|
||||
j += rows[i].className.match(c.cssChildRow + '|' + c.selectorRemove.replace(/^(\w+\.)/g,'')) && !wo.pager_countChildRows ? 0 : 1;
|
||||
if ( j === e && rows[i].style.display !== 'none' && rows[i].className.match(ts.css.cssHasChild) ) {
|
||||
lastIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// add any attached child rows to last row of pager. Fixes part of issue #396
|
||||
if ( lastIndex > 0 && rows[lastIndex].className.match(ts.css.cssHasChild) ) {
|
||||
while ( ++lastIndex < l && rows[lastIndex].className.match(c.cssChildRow) ) {
|
||||
rows[lastIndex].style.display = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
hideRowsSetup: function(table, c){
|
||||
var p = c.pager;
|
||||
p.size = parseInt( p.$size.val(), 10 ) || p.size;
|
||||
$.data(table, 'pagerLastSize', p.size);
|
||||
tsp.pagerArrows(c);
|
||||
if ( !c.widgetOptions.pager_removeRows ) {
|
||||
tsp.hideRows(table, c);
|
||||
c.$table.on('sortEnd.pager filterEnd.pager', function(){
|
||||
tsp.hideRows(table, c);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
renderAjax: function(data, table, c, xhr, exception){
|
||||
var p = c.pager,
|
||||
wo = c.widgetOptions;
|
||||
// process data
|
||||
if ( $.isFunction(wo.pager_ajaxProcessing) ) {
|
||||
// ajaxProcessing result: [ total, rows, headers ]
|
||||
var i, j, t, hsh, $f, $sh, th, d, l, rr_count,
|
||||
$t = c.$table,
|
||||
tds = '',
|
||||
result = wo.pager_ajaxProcessing(data, table, xhr) || [ 0, [] ],
|
||||
hl = $t.find('thead th').length;
|
||||
|
||||
// Clean up any previous error.
|
||||
ts.showError(table);
|
||||
|
||||
if ( exception ) {
|
||||
if (c.debug) {
|
||||
ts.log('Ajax Error', xhr, exception);
|
||||
}
|
||||
ts.showError(table, exception.message + ' (' + xhr.status + ')');
|
||||
c.$tbodies.eq(0).children('tr').detach();
|
||||
p.totalRows = 0;
|
||||
} else {
|
||||
// process ajax object
|
||||
if (!$.isArray(result)) {
|
||||
p.ajaxData = result;
|
||||
c.totalRows = p.totalRows = result.total;
|
||||
c.filteredRows = p.filteredRows = typeof result.filteredRows !== 'undefined' ? result.filteredRows : result.total;
|
||||
th = result.headers;
|
||||
d = result.rows;
|
||||
} else {
|
||||
// allow [ total, rows, headers ] or [ rows, total, headers ]
|
||||
t = isNaN(result[0]) && !isNaN(result[1]);
|
||||
// ensure a zero returned row count doesn't fail the logical ||
|
||||
rr_count = result[t ? 1 : 0];
|
||||
p.totalRows = isNaN(rr_count) ? p.totalRows || 0 : rr_count;
|
||||
// can't set filtered rows when returning an array
|
||||
c.totalRows = c.filteredRows = p.filteredRows = p.totalRows;
|
||||
d = p.totalRows === 0 ? [""] : result[t ? 0 : 1] || []; // row data
|
||||
th = result[2]; // headers
|
||||
}
|
||||
l = d && d.length;
|
||||
if (d instanceof jQuery) {
|
||||
if (wo.pager_processAjaxOnInit) {
|
||||
// append jQuery object
|
||||
c.$tbodies.eq(0).children('tr').detach();
|
||||
c.$tbodies.eq(0).append(d);
|
||||
}
|
||||
} else if (l) {
|
||||
// build table from array
|
||||
for ( i = 0; i < l; i++ ) {
|
||||
tds += '<tr>';
|
||||
for ( j = 0; j < d[i].length; j++ ) {
|
||||
// build tbody cells; watch for data containing HTML markup - see #434
|
||||
tds += /^\s*<td/.test(d[i][j]) ? $.trim(d[i][j]) : '<td>' + d[i][j] + '</td>';
|
||||
}
|
||||
tds += '</tr>';
|
||||
}
|
||||
// add rows to first tbody
|
||||
if (wo.pager_processAjaxOnInit) {
|
||||
c.$tbodies.eq(0).html( tds );
|
||||
}
|
||||
}
|
||||
wo.pager_processAjaxOnInit = true;
|
||||
// only add new header text if the length matches
|
||||
if ( th && th.length === hl ) {
|
||||
hsh = $t.hasClass('hasStickyHeaders');
|
||||
$sh = hsh ? wo.$sticky.children('thead:first').children('tr').children() : '';
|
||||
$f = $t.find('tfoot tr:first').children();
|
||||
// don't change td headers (may contain pager)
|
||||
c.$headers.filter('th').each(function(j){
|
||||
var $t = $(this), icn;
|
||||
// add new test within the first span it finds, or just in the header
|
||||
if ( $t.find('.' + ts.css.icon).length ) {
|
||||
icn = $t.find('.' + ts.css.icon).clone(true);
|
||||
$t.find('.tablesorter-header-inner').html( th[j] ).append(icn);
|
||||
if ( hsh && $sh.length ) {
|
||||
icn = $sh.eq(j).find('.' + ts.css.icon).clone(true);
|
||||
$sh.eq(j).find('.tablesorter-header-inner').html( th[j] ).append(icn);
|
||||
}
|
||||
} else {
|
||||
$t.find('.tablesorter-header-inner').html( th[j] );
|
||||
if (hsh && $sh.length) {
|
||||
$sh.eq(j).find('.tablesorter-header-inner').html( th[j] );
|
||||
}
|
||||
}
|
||||
$f.eq(j).html( th[j] );
|
||||
});
|
||||
}
|
||||
}
|
||||
if (c.showProcessing) {
|
||||
ts.isProcessing(table); // remove loading icon
|
||||
}
|
||||
// make sure last pager settings are saved, prevents multiple server side calls with
|
||||
// the same parameters
|
||||
p.totalPages = Math.ceil( p.totalRows / ( p.size || 10 ) );
|
||||
p.last.totalRows = p.totalRows;
|
||||
p.last.currentFilters = p.currentFilters;
|
||||
p.last.sortList = (c.sortList || []).join(',');
|
||||
tsp.updatePageDisplay(table, c);
|
||||
tsp.fixHeight(table, c);
|
||||
$t.trigger('updateCache', [function(){
|
||||
if (p.initialized) {
|
||||
// apply widgets after table has rendered & after a delay to prevent
|
||||
// multiple applyWidget blocking code from blocking this trigger
|
||||
setTimeout(function(){
|
||||
$t
|
||||
.trigger('applyWidgets')
|
||||
.trigger('pagerChange', p);
|
||||
}, 0);
|
||||
}
|
||||
}]);
|
||||
}
|
||||
if (!p.initialized) {
|
||||
c.$table.trigger('applyWidgets');
|
||||
}
|
||||
},
|
||||
|
||||
getAjax: function(table, c){
|
||||
var counter,
|
||||
url = tsp.getAjaxUrl(table, c),
|
||||
$doc = $(document),
|
||||
wo = c.widgetOptions,
|
||||
p = c.pager;
|
||||
if ( url !== '' ) {
|
||||
if (c.showProcessing) {
|
||||
ts.isProcessing(table, true); // show loading icon
|
||||
}
|
||||
$doc.on('ajaxError.pager', function(e, xhr, settings, exception) {
|
||||
tsp.renderAjax(null, table, c, xhr, exception);
|
||||
$doc.unbind('ajaxError.pager');
|
||||
});
|
||||
counter = ++p.ajaxCounter;
|
||||
wo.pager_ajaxObject.url = url; // from the ajaxUrl option and modified by customAjaxUrl
|
||||
wo.pager_ajaxObject.success = function(data, status, jqxhr) {
|
||||
// Refuse to process old ajax commands that were overwritten by new ones - see #443
|
||||
if (counter < p.ajaxCounter){
|
||||
return;
|
||||
}
|
||||
tsp.renderAjax(data, table, c, jqxhr);
|
||||
$doc.unbind('ajaxError.pager');
|
||||
if (typeof p.oldAjaxSuccess === 'function') {
|
||||
p.oldAjaxSuccess(data);
|
||||
}
|
||||
};
|
||||
if (c.debug) {
|
||||
ts.log('ajax initialized', wo.pager_ajaxObject);
|
||||
}
|
||||
$.ajax(wo.pager_ajaxObject);
|
||||
}
|
||||
},
|
||||
|
||||
getAjaxUrl: function(table, c) {
|
||||
var p = c.pager,
|
||||
wo = c.widgetOptions,
|
||||
url = (wo.pager_ajaxUrl) ? wo.pager_ajaxUrl
|
||||
// allow using "{page+1}" in the url string to switch to a non-zero based index
|
||||
.replace(/\{page([\-+]\d+)?\}/, function(s,n){ return p.page + (n ? parseInt(n, 10) : 0); })
|
||||
.replace(/\{size\}/g, p.size) : '',
|
||||
sl = c.sortList,
|
||||
fl = p.currentFilters || $(table).data('lastSearch') || [],
|
||||
sortCol = url.match(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/),
|
||||
filterCol = url.match(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/),
|
||||
arry = [];
|
||||
if (sortCol) {
|
||||
sortCol = sortCol[1];
|
||||
$.each(sl, function(i,v){
|
||||
arry.push(sortCol + '[' + v[0] + ']=' + v[1]);
|
||||
});
|
||||
// if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col"
|
||||
url = url.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : sortCol );
|
||||
arry = [];
|
||||
}
|
||||
if (filterCol) {
|
||||
filterCol = filterCol[1];
|
||||
$.each(fl, function(i,v){
|
||||
if (v) {
|
||||
arry.push(filterCol + '[' + i + ']=' + encodeURIComponent(v));
|
||||
}
|
||||
});
|
||||
// if the arry is empty, just add the fcol parameter... "&{filterList:fcol}" becomes "&fcol"
|
||||
url = url.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : filterCol );
|
||||
p.currentFilters = fl;
|
||||
}
|
||||
if ( $.isFunction(wo.pager_customAjaxUrl) ) {
|
||||
url = wo.pager_customAjaxUrl(table, url);
|
||||
}
|
||||
if (c.debug) {
|
||||
ts.log('Pager ajax url: ' + url);
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
renderTable: function(table, rows) {
|
||||
var $tb, index, count, added,
|
||||
c = table.config,
|
||||
p = c.pager,
|
||||
wo = c.widgetOptions,
|
||||
f = c.$table.hasClass('hasFilters'),
|
||||
l = rows && rows.length || 0, // rows may be undefined
|
||||
s = ( p.page * p.size ),
|
||||
e = p.size;
|
||||
if ( l < 1 ) {
|
||||
if (c.debug) {
|
||||
ts.log('Pager: no rows for pager to render');
|
||||
}
|
||||
// empty table, abort!
|
||||
return;
|
||||
}
|
||||
if ( p.page >= p.totalPages ) {
|
||||
// lets not render the table more than once
|
||||
return tsp.moveToLastPage(table, p);
|
||||
}
|
||||
p.isDisabled = false; // needed because sorting will change the page and re-enable the pager
|
||||
if (p.initialized) { c.$table.trigger('pagerChange', c); }
|
||||
if ( !wo.pager_removeRows ) {
|
||||
tsp.hideRows(table, c);
|
||||
} else {
|
||||
ts.clearTableBody(table);
|
||||
$tb = ts.processTbody(table, c.$tbodies.eq(0), true);
|
||||
// not filtered, start from the calculated starting point (s)
|
||||
// if filtered, start from zero
|
||||
index = f ? 0 : s;
|
||||
count = f ? 0 : s;
|
||||
added = 0;
|
||||
while (added < e && index < rows.length) {
|
||||
if (!f || !/filtered/.test(rows[index][0].className)){
|
||||
count++;
|
||||
if (count > s && added <= e) {
|
||||
added++;
|
||||
$tb.append(rows[index]);
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
ts.processTbody(table, $tb, false);
|
||||
}
|
||||
|
||||
tsp.updatePageDisplay(table, c);
|
||||
if ( !p.isDisabled ) { tsp.fixHeight(table, c); }
|
||||
|
||||
wo.pager_startPage = p.page;
|
||||
wo.pager_size = p.size;
|
||||
if (table.isUpdating) {
|
||||
c.$table.trigger('updateComplete', [ table, true ]);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
showAllRows: function(table, c){
|
||||
var p = c.pager,
|
||||
wo = c.widgetOptions;
|
||||
if ( p.ajax ) {
|
||||
tsp.pagerArrows(c, true);
|
||||
} else {
|
||||
p.isDisabled = true;
|
||||
$.data(table, 'pagerLastPage', p.page);
|
||||
$.data(table, 'pagerLastSize', p.size);
|
||||
p.page = 0;
|
||||
p.size = p.totalRows;
|
||||
p.totalPages = 1;
|
||||
c.$table
|
||||
.addClass('pagerDisabled')
|
||||
.removeAttr('aria-describedby')
|
||||
.find('tr.pagerSavedHeightSpacer').remove();
|
||||
tsp.renderTable(table, c.rowsCopy);
|
||||
c.$table.trigger('applyWidgets');
|
||||
if (c.debug) {
|
||||
ts.log('pager disabled');
|
||||
}
|
||||
}
|
||||
// disable size selector
|
||||
p.$size.add(p.$goto).each(function(){
|
||||
$(this).attr('aria-disabled', 'true').addClass(wo.pager_css.disabled)[0].disabled = true;
|
||||
});
|
||||
},
|
||||
|
||||
// updateCache if delayInit: true
|
||||
// this is normally done by "appendToTable" function in the tablesorter core AFTER a sort
|
||||
updateCache: function(table) {
|
||||
var c = table.config,
|
||||
p = c.pager;
|
||||
c.$table.trigger('updateCache', [ function(){
|
||||
if ( !$.isEmptyObject(table.config.cache) ) {
|
||||
var i,
|
||||
rows = [],
|
||||
n = table.config.cache[0].normalized;
|
||||
p.totalRows = n.length;
|
||||
for (i = 0; i < p.totalRows; i++) {
|
||||
rows.push(n[i][c.columns].$row);
|
||||
}
|
||||
c.rowsCopy = rows;
|
||||
tsp.moveToPage(table, p, true);
|
||||
// clear out last search to force an update
|
||||
p.last.currentFilters = [' '];
|
||||
}
|
||||
} ]);
|
||||
},
|
||||
|
||||
moveToPage: function(table, p, pageMoved) {
|
||||
if ( p.isDisabled ) { return; }
|
||||
if ( pageMoved !== false && p.initialized && $.isEmptyObject(table.config.cache)) {
|
||||
return tsp.updateCache(table);
|
||||
}
|
||||
var c = table.config,
|
||||
l = p.last,
|
||||
pg = Math.min( p.totalPages, p.filteredPages );
|
||||
if ( p.page < 0 ) { p.page = 0; }
|
||||
if ( p.page > ( pg - 1 ) && pg !== 0 ) { p.page = pg - 1; }
|
||||
// fixes issue where one current filter is [] and the other is ['','',''],
|
||||
// making the next if comparison think the filters as different. Fixes #202.
|
||||
l.currentFilters = (l.currentFilters || []).join('') === '' ? [] : l.currentFilters;
|
||||
p.currentFilters = (p.currentFilters || []).join('') === '' ? [] : p.currentFilters;
|
||||
// don't allow rendering multiple times on the same page/size/totalRows/filters/sorts
|
||||
if ( l.page === p.page && l.size === p.size && l.totalRows === p.totalRows &&
|
||||
(l.currentFilters || []).join(',') === (p.currentFilters || []).join(',') &&
|
||||
l.sortList === (c.sortList || []).join(',') ) {
|
||||
return;
|
||||
}
|
||||
if (c.debug) {
|
||||
ts.log('Pager changing to page ' + p.page);
|
||||
}
|
||||
p.last = {
|
||||
page : p.page,
|
||||
size : p.size,
|
||||
// fixes #408; modify sortList otherwise it auto-updates
|
||||
sortList : (c.sortList || []).join(','),
|
||||
totalRows : p.totalRows,
|
||||
currentFilters : p.currentFilters || []
|
||||
};
|
||||
if (p.ajax) {
|
||||
tsp.getAjax(table, c);
|
||||
} else if (!p.ajax) {
|
||||
tsp.renderTable(table, c.rowsCopy);
|
||||
}
|
||||
$.data(table, 'pagerLastPage', p.page);
|
||||
if (p.initialized && pageMoved !== false) {
|
||||
c.$table
|
||||
.trigger('pageMoved', c)
|
||||
.trigger('applyWidgets');
|
||||
if (!p.ajax && table.isUpdating) {
|
||||
c.$table.trigger('updateComplete', [ table, true ]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setPageSize: function(table, size, c) {
|
||||
var p = c.pager;
|
||||
p.size = size || p.size || 10;
|
||||
p.$size.val(p.size);
|
||||
$.data(table, 'pagerLastPage', p.page);
|
||||
$.data(table, 'pagerLastSize', p.size);
|
||||
p.totalPages = Math.ceil( p.totalRows / p.size );
|
||||
p.filteredPages = Math.ceil( p.filteredRows / p.size );
|
||||
tsp.moveToPage(table, p, true);
|
||||
},
|
||||
|
||||
moveToFirstPage: function(table, p) {
|
||||
p.page = 0;
|
||||
tsp.moveToPage(table, p, true);
|
||||
},
|
||||
|
||||
moveToLastPage: function(table, p) {
|
||||
p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 );
|
||||
tsp.moveToPage(table, p, true);
|
||||
},
|
||||
|
||||
moveToNextPage: function(table, p) {
|
||||
p.page++;
|
||||
if ( p.page >= ( Math.min( p.totalPages, p.filteredPages ) - 1 ) ) {
|
||||
p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 );
|
||||
}
|
||||
tsp.moveToPage(table, p, true);
|
||||
},
|
||||
|
||||
moveToPrevPage: function(table, p) {
|
||||
p.page--;
|
||||
if ( p.page <= 0 ) {
|
||||
p.page = 0;
|
||||
}
|
||||
tsp.moveToPage(table, p, true);
|
||||
},
|
||||
|
||||
destroyPager: function(table, c){
|
||||
var p = c.pager;
|
||||
tsp.showAllRows(table, c);
|
||||
p.$container.hide(); // hide pager
|
||||
c.appender = null; // remove pager appender function
|
||||
p.initialized = false;
|
||||
delete table.config.rowsCopy;
|
||||
c.$table.unbind('destroy.pager sortEnd.pager filterEnd.pager enable.pager disable.pager');
|
||||
if (ts.storage) {
|
||||
ts.storage(table, c.widgetOptions.pager_storageKey, '');
|
||||
}
|
||||
},
|
||||
|
||||
enablePager: function(table, c, triggered){
|
||||
var info, p = c.pager;
|
||||
p.isDisabled = false;
|
||||
p.page = $.data(table, 'pagerLastPage') || p.page || 0;
|
||||
p.size = $.data(table, 'pagerLastSize') || parseInt(p.$size.find('option[selected]').val(), 10) || p.size || 10;
|
||||
p.$size.val(p.size); // set page size
|
||||
p.totalPages = Math.ceil( Math.min( p.totalRows, p.filteredRows ) / p.size );
|
||||
c.$table.removeClass('pagerDisabled');
|
||||
// if table id exists, include page display with aria info
|
||||
if ( table.id ) {
|
||||
info = table.id + '_pager_info';
|
||||
p.$container.find(c.widgetOptions.pager_selectors.pageDisplay).attr('id', info);
|
||||
c.$table.attr('aria-describedby', info);
|
||||
}
|
||||
if ( triggered ) {
|
||||
c.$table.trigger('updateRows');
|
||||
tsp.setPageSize(table, p.size, c);
|
||||
tsp.hideRowsSetup(table, c);
|
||||
tsp.fixHeight(table, c);
|
||||
if (c.debug) {
|
||||
ts.log('pager enabled');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
appender: function(table, rows) {
|
||||
var c = table.config,
|
||||
wo = c.widgetOptions,
|
||||
p = c.pager;
|
||||
if ( !p.ajax ) {
|
||||
c.rowsCopy = rows;
|
||||
p.totalRows = c.widgetOptions.pager_countChildRows ? c.$tbodies.eq(0).children('tr').length : rows.length;
|
||||
p.size = $.data(table, 'pagerLastSize') || p.size || wo.pager_size || 10;
|
||||
p.totalPages = Math.ceil( p.totalRows / p.size );
|
||||
tsp.moveToPage(table, p);
|
||||
// update display here in case all rows are removed
|
||||
tsp.updatePageDisplay(table, c, false);
|
||||
} else {
|
||||
tsp.moveToPage(table, p, true);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// see #486
|
||||
ts.showError = function(table, message){
|
||||
$(table).each(function(){
|
||||
var $row,
|
||||
c = this.config,
|
||||
errorRow = c.pager && c.pager.cssErrorRow || c.widgetOptions.pager_css && c.widgetOptions.pager_css.errorRow || 'tablesorter-errorRow';
|
||||
if (c) {
|
||||
if (typeof message === 'undefined') {
|
||||
c.$table.find('thead').find(c.selectorRemove).remove();
|
||||
} else {
|
||||
$row = ( /tr\>/.test(message) ? $(message) : $('<tr><td colspan="' + c.columns + '">' + message + '</td></tr>') )
|
||||
.click(function(){
|
||||
$(this).remove();
|
||||
})
|
||||
// add error row to thead instead of tbody, or clicking on the header will result in a parser error
|
||||
.appendTo( c.$table.find('thead:first') )
|
||||
.addClass( errorRow + ' ' + c.selectorRemove.replace(/^(\w+\.)/g,'') )
|
||||
.attr({
|
||||
role : 'alert',
|
||||
'aria-live' : 'assertive'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
123
modules/EcmReports/TableSorterNew/js/widgets/widget-print.js
Normal file
123
modules/EcmReports/TableSorterNew/js/widgets/widget-print.js
Normal file
@@ -0,0 +1,123 @@
|
||||
/* Print widget (beta) for TableSorter 6/18/2014 (v2.17.2)
|
||||
* Requires tablesorter v2.8+ and jQuery 1.2.6+
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter,
|
||||
|
||||
printTable = ts.printTable = {
|
||||
|
||||
event : 'printTable',
|
||||
basicStyle : 'table, tr, td, th { border : solid 1px black; border-collapse : collapse; } td, th { padding: 2px; }',
|
||||
|
||||
init : function(c) {
|
||||
c.$table
|
||||
.unbind(printTable.event)
|
||||
.bind(printTable.event, function(){
|
||||
// explicitly use table.config.widgetOptions because we want
|
||||
// the most up-to-date values; not the "wo" from initialization
|
||||
printTable.process(c, c.widgetOptions);
|
||||
});
|
||||
},
|
||||
|
||||
process : function(c, wo) {
|
||||
var $this,
|
||||
$table = $('<div/>').append(c.$table.clone()),
|
||||
printStyle = printTable.basicStyle + 'table { width: 100% }' +
|
||||
// hide filter row
|
||||
'.tablesorter-filter-row { display: none }' +
|
||||
// hide sort arrows
|
||||
'.tablesorter-header { background-image: none !important; }';
|
||||
|
||||
// replace content with data-attribute content
|
||||
$table.find('[' + wo.print_dataAttrib + ']').each(function(){
|
||||
$this = $(this);
|
||||
$this.text( $this.attr(wo.print_dataAttrib) );
|
||||
});
|
||||
|
||||
// === rows ===
|
||||
// Assume "visible" means rows hidden by the pager (rows set to "display:none")
|
||||
// or hidden by a class name which is added to the wo.print_extraCSS definition
|
||||
if (/a/i.test(wo.print_rows)) {
|
||||
// force show of all rows
|
||||
printStyle += 'tbody tr { display: table-row !important; }';
|
||||
} else if (/f/i.test(wo.print_rows)) {
|
||||
// add definition to show all non-filtered rows (cells hidden by the pager)
|
||||
printStyle += 'tbody tr:not(.' + (wo.filter_filteredRow || 'filtered') + ') { display: table-row !important; }';
|
||||
}
|
||||
|
||||
// === columns ===
|
||||
// columnSelector -> c.selector.$style
|
||||
// Assume "visible" means hidden columns have a "display:none" style, or a class name
|
||||
// add the definition to the wo.print_extraCSS option
|
||||
if (/s/i.test(wo.print_columns) && c.selector && c.widgets.indexOf('columnSelector') >= 0) {
|
||||
// show selected (visible) columns; make a copy of the columnSelector widget css (not media queries)
|
||||
printStyle += c.selector.auto ? '' : c.selector.$style.text();
|
||||
} else if (/a/i.test(wo.print_columns)) {
|
||||
// force show all cells
|
||||
printStyle += 'td, th { display: table-cell !important; }';
|
||||
}
|
||||
|
||||
printStyle += wo.print_extraCSS;
|
||||
|
||||
// callback function
|
||||
if ( $.isFunction(wo.print_callback) ) {
|
||||
wo.print_callback( c, $table, printStyle );
|
||||
} else {
|
||||
printTable.printOutput(c, $table.html(), printStyle);
|
||||
}
|
||||
|
||||
}, // end process
|
||||
|
||||
printOutput : function(c, data, style) {
|
||||
var wo = c.widgetOptions,
|
||||
generator = window.open('', wo.print_title, 'width=500,height=300'),
|
||||
t = wo.print_title || c.$table.find('caption').text() || c.$table[0].id || document.title || 'table';
|
||||
generator.document.write(
|
||||
'<html><head><title>' + t + '</title>' +
|
||||
( wo.print_styleSheet ? '<link rel="stylesheet" href="' + wo.print_styleSheet + '">' : '' ) +
|
||||
'<style>' + style + '</style>' +
|
||||
'</head><body>' + data + '</body></html>'
|
||||
);
|
||||
generator.document.close();
|
||||
generator.print();
|
||||
generator.close();
|
||||
return true;
|
||||
},
|
||||
|
||||
remove : function(c) {
|
||||
c.$table.off(printTable.event);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ts.addWidget({
|
||||
id: 'print',
|
||||
options: {
|
||||
print_title : '', // this option > caption > table id > "table"
|
||||
print_dataAttrib : 'data-name', // header attrib containing modified header name
|
||||
print_rows : 'filtered', // (a)ll, (v)isible or (f)iltered
|
||||
print_columns : 'selected', // (a)ll or (s)elected (if columnSelector widget is added)
|
||||
print_extraCSS : '', // add any extra css definitions for the popup window here
|
||||
print_styleSheet : '', // add the url of your print stylesheet
|
||||
// callback executed when processing completes
|
||||
// to continue printing, use the following function:
|
||||
// function( config, $table, printStyle ) {
|
||||
// // do something to the table or printStyle string
|
||||
// $.tablesorter.printTable.printOutput( config, $table.html(), printStyle );
|
||||
// }
|
||||
print_callback : null
|
||||
},
|
||||
init: function(table, thisWidget, c) {
|
||||
printTable.init(c);
|
||||
},
|
||||
remove: function(table, c){
|
||||
printTable.remove(c);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
179
modules/EcmReports/TableSorterNew/js/widgets/widget-reflow.js
Normal file
179
modules/EcmReports/TableSorterNew/js/widgets/widget-reflow.js
Normal file
@@ -0,0 +1,179 @@
|
||||
/* table reflow widget (beta) for TableSorter 3/22/2014 (v2.16.0)
|
||||
* Requires tablesorter v2.8+ and jQuery 1.7+
|
||||
* Also, this widget requires the following default css (modify as desired)
|
||||
|
||||
/ * REQUIRED CSS: change your reflow breakpoint here (35em below) * /
|
||||
@media ( max-width: 35em ) {
|
||||
.ui-table-reflow td,
|
||||
.ui-table-reflow th {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
float: right;
|
||||
/ * if not using the stickyHeaders widget (not the css3 version)
|
||||
* the "!important" flag, and "height: auto" can be removed * /
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
}
|
||||
/ * reflow widget * /
|
||||
.ui-table-reflow tbody td[data-title]:before {
|
||||
color: #469;
|
||||
font-size: .9em;
|
||||
content: attr(data-title);
|
||||
float: left;
|
||||
width: 50%;
|
||||
white-space: pre-wrap;
|
||||
text-align: bottom;
|
||||
display: inline-block;
|
||||
}
|
||||
/ * reflow2 widget * /
|
||||
table.ui-table-reflow .ui-table-cell-label.ui-table-cell-label-top {
|
||||
display: block;
|
||||
padding: .4em 0;
|
||||
margin: .4em 0;
|
||||
text-transform: uppercase;
|
||||
font-size: .9em;
|
||||
font-weight: 400;
|
||||
}
|
||||
table.ui-table-reflow .ui-table-cell-label {
|
||||
padding: .4em;
|
||||
min-width: 30%;
|
||||
display: inline-block;
|
||||
margin: -.4em 1em -.4em -.4em;
|
||||
}
|
||||
}
|
||||
.ui-table-reflow .ui-table-cell-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter,
|
||||
|
||||
tablereflow = {
|
||||
// simple reflow
|
||||
// add data-attribute to each cell which shows when media query is active
|
||||
// this widget DOES NOT WORK on a table with multiple thead rows
|
||||
init : function(table, c, wo) {
|
||||
var $this,
|
||||
title = wo.reflow_dataAttrib,
|
||||
header = wo.reflow_headerAttrib,
|
||||
headers = [];
|
||||
c.$table
|
||||
.addClass(wo.reflow_className)
|
||||
.off('refresh.tsreflow updateComplete.tsreflow2')
|
||||
// emulate jQuery Mobile refresh
|
||||
// https://api.jquerymobile.com/table-reflow/#method-refresh
|
||||
.on('refresh.tsreflow updateComplete.tsreflow2', function(){
|
||||
tablereflow.init(table, c, wo);
|
||||
});
|
||||
c.$headers.each(function(){
|
||||
$this = $(this);
|
||||
headers.push( $this.attr(header) || $this.text() );
|
||||
});
|
||||
c.$tbodies.children().each(function(){
|
||||
$(this).children().each(function(i){
|
||||
$(this).attr(title, headers[i]);
|
||||
});
|
||||
});
|
||||
},
|
||||
init2: function(table, c, wo) {
|
||||
var $this, $tbody, i, $hdr, txt, len,
|
||||
cols = c.columns,
|
||||
header = wo.reflow2_headerAttrib,
|
||||
headers = [];
|
||||
c.$table
|
||||
.addClass(wo.reflow2_className)
|
||||
.off('refresh.tsreflow2 updateComplete.tsreflow2')
|
||||
// emulate jQuery Mobile refresh
|
||||
// https://api.jquerymobile.com/table-reflow/#method-refresh
|
||||
.on('refresh.tsreflow2 updateComplete.tsreflow2', function(){
|
||||
tablereflow.init2(table, c, wo);
|
||||
});
|
||||
|
||||
// add <b> to every table cell with thead cell contents
|
||||
for (i = 0; i < cols; i++) {
|
||||
$hdr = c.$headers.filter('[data-column="' + i + '"]');
|
||||
if ($hdr.length > 1) {
|
||||
txt = [];
|
||||
$hdr.each(function(){
|
||||
$this = $(this);
|
||||
if (!$this.hasClass(wo.reflow2_classIgnore)) {
|
||||
txt.push( $this.attr(header) || $this.text() );
|
||||
}
|
||||
});
|
||||
} else {
|
||||
txt = [ $hdr.attr(header) || $hdr.text() ];
|
||||
}
|
||||
headers.push( txt );
|
||||
}
|
||||
// include "remove-me" class so these additional elements are removed before updating
|
||||
txt = '<b class="' + c.selectorRemove.slice(1) + ' ' + wo.reflow2_labelClass;
|
||||
c.$tbodies.children().each(function(){
|
||||
$tbody = ts.processTbody(table, $(this), true);
|
||||
$tbody.children().each(function(j){
|
||||
$this = $(this);
|
||||
len = headers[j].length
|
||||
i = len - 1;
|
||||
while (i >= 0) {
|
||||
$this.prepend(txt + (i === 0 && len > 1 ? ' ' + wo.reflow2_labelTop : '') + '">' + headers[j][i] + '</b>');
|
||||
i--;
|
||||
}
|
||||
});
|
||||
ts.processTbody(table, $tbody, false);
|
||||
});
|
||||
},
|
||||
remove : function(table, c, wo) {
|
||||
c.$table.removeClass(wo.reflow_className);
|
||||
},
|
||||
remove2 : function(table, c, wo) {
|
||||
c.$table.removeClass(wo.reflow2_className);
|
||||
}
|
||||
};
|
||||
|
||||
ts.addWidget({
|
||||
id: "reflow",
|
||||
options: {
|
||||
// class name added to make it responsive (class name within media query)
|
||||
reflow_className : 'ui-table-reflow',
|
||||
// header attribute containing modified header name
|
||||
reflow_headerAttrib : 'data-name',
|
||||
// data attribute added to each tbody cell
|
||||
reflow_dataAttrib : 'data-title'
|
||||
},
|
||||
init: function(table, thisWidget, c, wo) {
|
||||
tablereflow.init(table, c, wo);
|
||||
},
|
||||
remove: function(table, c, wo){
|
||||
tablereflow.remove(table, c, wo);
|
||||
}
|
||||
});
|
||||
|
||||
ts.addWidget({
|
||||
id: "reflow2",
|
||||
options: {
|
||||
// class name added to make it responsive (class name within media query)
|
||||
reflow2_className : 'ui-table-reflow',
|
||||
// ignore header cell content with this class name
|
||||
reflow2_classIgnore : 'ui-table-reflow-ignore',
|
||||
// header attribute containing modified header name
|
||||
reflow2_headerAttrib : 'data-name',
|
||||
// class name applied to thead labels
|
||||
reflow2_labelClass : 'ui-table-cell-label',
|
||||
// class name applied to first row thead label
|
||||
reflow2_labelTop : 'ui-table-cell-label-top'
|
||||
},
|
||||
init: function(table, thisWidget, c, wo) {
|
||||
tablereflow.init2(table, c, wo);
|
||||
},
|
||||
remove: function(table, c, wo){
|
||||
tablereflow.remove2(table, c, wo);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,50 @@
|
||||
/*! tablesorter repeatHeaders widget - updated 4/12/2013
|
||||
* Requires tablesorter v2.8+ and jQuery 1.7+
|
||||
* Original by Christian Bach from the example-widgets.html demo
|
||||
*/
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
$.tablesorter.addWidget({
|
||||
id: "repeatHeaders",
|
||||
priority: 10,
|
||||
options: {
|
||||
rowsToSkip : 4
|
||||
},
|
||||
// format is called on init and when a sorting has finished
|
||||
format: function(table, c, wo) {
|
||||
var h = '', i, $tr, l, skip;
|
||||
// cache and collect all TH headers
|
||||
if (!wo.repeatHeaders) {
|
||||
h = '<tr class="repeated-header remove-me">';
|
||||
$.each(c.headerContent, function(i,t) {
|
||||
h += '<th>' + t + '</th>';
|
||||
});
|
||||
// "remove-me" class was added in case the table needs to be updated, the "remove-me" rows will be
|
||||
// removed prior to the update to prevent including the rows in the update - see "selectorRemove" option
|
||||
wo.repeatHeaders = h + '</tr>';
|
||||
}
|
||||
|
||||
// number of rows to skip
|
||||
skip = wo && wo.rowsToSkip || 4;
|
||||
|
||||
// remove appended headers by classname
|
||||
c.$table.find("tr.repeated-header").remove();
|
||||
$tr = c.$tbodies.find('tr');
|
||||
l = $tr.length;
|
||||
// loop all tr elements and insert a copy of the "headers"
|
||||
for (i = skip; i < l; i += skip) {
|
||||
// insert a copy of the table head every X rows
|
||||
$tr.eq(i).before(wo.repeatHeaders);
|
||||
}
|
||||
},
|
||||
// this remove function is called when using the refreshWidgets method or when destroying the tablesorter plugin
|
||||
// this function only applies to tablesorter v2.4+
|
||||
remove: function(table, c){
|
||||
c.$table.find("tr.repeated-header").remove();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
218
modules/EcmReports/TableSorterNew/js/widgets/widget-scroller.js
Normal file
218
modules/EcmReports/TableSorterNew/js/widgets/widget-scroller.js
Normal file
@@ -0,0 +1,218 @@
|
||||
/*!
|
||||
Copyright (C) 2011 T. Connell & Associates, Inc.
|
||||
|
||||
Dual-licensed under the MIT and GPL licenses
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Resizable scroller widget for the jQuery tablesorter plugin
|
||||
|
||||
Version 2.0 - modified by Rob Garrison 4/12/2013; updated 6/28/2014 (v2.17.3)
|
||||
Requires jQuery v1.7+
|
||||
Requires the tablesorter plugin, v2.8+, available at http://mottie.github.com/tablesorter/docs/
|
||||
|
||||
Usage:
|
||||
|
||||
$(function() {
|
||||
|
||||
$('table.tablesorter').tablesorter({
|
||||
widgets: ['zebra', 'scroller'],
|
||||
widgetOptions : {
|
||||
scroller_height : 300, // height of scroll window
|
||||
scroller_barWidth : 18, // scroll bar width
|
||||
scroller_jumpToHeader : true, // header snap to browser top when scrolling the tbody
|
||||
scroller_idPrefix : 's_' // cloned thead id prefix (random number added to end)
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Website: www.tconnell.com
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
$.fn.hasScrollBar = function(){
|
||||
return this.get(0).scrollHeight > this.height();
|
||||
};
|
||||
var ts = $.tablesorter;
|
||||
|
||||
ts.window_resize = function(){
|
||||
if (this.resize_timer) {
|
||||
clearTimeout(this.resize_timer);
|
||||
}
|
||||
this.resize_timer = setTimeout(function(){
|
||||
$(this).trigger('resizeEnd');
|
||||
}, 250);
|
||||
};
|
||||
|
||||
// Add extra scroller css
|
||||
$(function(){
|
||||
var s = '<style>' +
|
||||
'.tablesorter-scroller-reset { width: auto !important; } ' +
|
||||
'.tablesorter-scroller { text-align: left; overflow: hidden; }' +
|
||||
'.tablesorter-scroller-header { overflow: hidden; }' +
|
||||
'.tablesorter-scroller-header table.tablesorter { margin-bottom: 0; }' +
|
||||
'.tablesorter-scroller-table { overflow-y: scroll; }' +
|
||||
'.tablesorter-scroller-table table.tablesorter { margin-top: 0; overflow: scroll; } ' +
|
||||
'.tablesorter-scroller-table .tablesorter-filter-row, .tablesorter-scroller-table tfoot { display: none; }' +
|
||||
'.tablesorter-scroller-table table.tablesorter thead tr.tablesorter-headerRow * {' +
|
||||
'line-height:0;height:0;border:none;background-image:none;padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;overflow:hidden;' +
|
||||
'}</style>';
|
||||
$(s).appendTo('body');
|
||||
});
|
||||
|
||||
ts.addWidget({
|
||||
id: 'scroller',
|
||||
priority: 60, // run after the filter widget
|
||||
options: {
|
||||
scroller_height : 300,
|
||||
scroller_barWidth : 18,
|
||||
scroller_jumpToHeader: true,
|
||||
scroller_upAfterSort: true,
|
||||
scroller_idPrefix : 's_'
|
||||
},
|
||||
init: function(table, thisWidget, c, wo){
|
||||
var $win = $(window);
|
||||
// Setup window.resizeEnd event
|
||||
$win
|
||||
.bind('resize', ts.window_resize)
|
||||
.bind('resizeEnd', function() {
|
||||
// init is run before format, so scroller_resizeWidth
|
||||
// won't be defined within the "c" or "wo" parameters
|
||||
if (typeof table.config.widgetOptions.scroller_resizeWidth === 'function') {
|
||||
// IE calls resize when you modify content, so we have to unbind the resize event
|
||||
// so we don't end up with an infinite loop. we can rebind after we're done.
|
||||
$win.unbind('resize', ts.window_resize);
|
||||
table.config.widgetOptions.scroller_resizeWidth();
|
||||
$win.bind('resize', ts.window_resize);
|
||||
}
|
||||
});
|
||||
},
|
||||
format: function(table, c, wo) {
|
||||
var h, $hdr, id, t, resize, $cells,
|
||||
$win = $(window),
|
||||
$tbl = c.$table;
|
||||
|
||||
if (!c.isScrolling) {
|
||||
h = wo.scroller_height || 300;
|
||||
t = $tbl.find('tbody').height();
|
||||
if (t !== 0 && h > t) { h = t + 10; } // Table is less than h px
|
||||
id = wo.scroller_id = wo.scroller_idPrefix + Math.floor(Math.random() * 1001);
|
||||
|
||||
$hdr = $('<table class="' + $tbl.attr('class') + '" cellpadding=0 cellspacing=0><thead>' + $tbl.find('thead:first').html() + '</thead></table>');
|
||||
$tbl
|
||||
.wrap('<div id="' + id + '" class="tablesorter-scroller" />')
|
||||
.before($hdr)
|
||||
.find('.tablesorter-filter-row').addClass('hideme');
|
||||
|
||||
$cells = $hdr
|
||||
.wrap('<div class="tablesorter-scroller-header" style="width:' + $tbl.width() + ';" />')
|
||||
.find('.' + ts.css.header);
|
||||
|
||||
$tbl.wrap('<div class="tablesorter-scroller-table" style="height:' + h + 'px;width:' + $tbl.width() + ';" />');
|
||||
|
||||
// make scroller header sortable
|
||||
ts.bindEvents(table, $cells);
|
||||
|
||||
// look for filter widget
|
||||
if ($tbl.hasClass('hasFilters')) {
|
||||
ts.filter.bindSearch( $tbl, $hdr.find('.' + ts.css.filter) );
|
||||
}
|
||||
|
||||
resize = function(){
|
||||
var d, b, $h, $th, w,
|
||||
// Hide other scrollers so we can resize
|
||||
$div = $('div.scroller[id != "' + id + '"]').hide();
|
||||
|
||||
$tbl.find('thead').show();
|
||||
|
||||
// Reset sizes so parent can resize.
|
||||
$tbl
|
||||
.addClass('tablesorter-scroller-reset')
|
||||
.find('thead').find('.tablesorter-header-inner').addClass('tablesorter-scroller-reset');
|
||||
d = $tbl.parent();
|
||||
d.addClass('tablesorter-scroller-reset');
|
||||
|
||||
d.parent().trigger('resize');
|
||||
|
||||
// Shrink a bit to accommodate scrollbar
|
||||
d.width( d.parent().innerWidth() - ( d.parent().hasScrollBar() ? wo.scroller_barWidth : 0 ) );
|
||||
w = d.innerWidth() - ( d.hasScrollBar() ? wo.scroller_barWidth : 0 );
|
||||
$tbl.width( w );
|
||||
$hdr.width( w );
|
||||
$hdr.parent().width( w );
|
||||
|
||||
$tbl.closest('.tablesorter-scroller').find('.tablesorter-scroller-reset').removeClass('tablesorter-scroller-reset');
|
||||
|
||||
// include left & right border widths
|
||||
b = parseInt( $tbl.css('border-left-width'), 10 ) + parseInt( $tbl.css('border-right-width'), 10 );
|
||||
$h = $hdr.find('thead').children().children();
|
||||
|
||||
// adjust cloned header to match original table width - includes wrappers, headers, and header inner div
|
||||
$tbl.find('thead').children().children().each(function(i, c){
|
||||
$th = $(c).find('.tablesorter-header-inner');
|
||||
if ($th.length) {
|
||||
// I have no idea why this is in here anymore LOL
|
||||
w = parseInt( $th.css('min-width').replace('auto', '0').replace(/(px|em)/, ''), 10 );
|
||||
if ( $th.width() < w ) {
|
||||
$th.width(w);
|
||||
} else {
|
||||
w = $th.width();
|
||||
}
|
||||
$h.eq(i)
|
||||
.find('.tablesorter-header-inner').width(w - b)
|
||||
// set inner width first
|
||||
.parent()
|
||||
.width( $th.parent().width() - b );
|
||||
}
|
||||
});
|
||||
|
||||
$div.show();
|
||||
};
|
||||
|
||||
// Expose to external calls
|
||||
wo.scroller_resizeWidth = resize;
|
||||
|
||||
resize();
|
||||
|
||||
$tbl.find('thead').css('visibility', 'hidden');
|
||||
c.isScrolling = true;
|
||||
|
||||
t = $tbl.parent().parent().height();
|
||||
|
||||
// The header will always jump into view if scrolling the table body
|
||||
$tbl.parent().bind('scroll', function(){
|
||||
if (wo.scroller_jumpToHeader) {
|
||||
var pos = $win.scrollTop() - $hdr.offset().top;
|
||||
if ($(this).scrollTop() !== 0 && pos < t && pos > 0) {
|
||||
$win.scrollTop( $hdr.offset().top );
|
||||
}
|
||||
}
|
||||
$hdr.parent().scrollLeft( $(this).scrollLeft() );
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Sorting, so scroll to top
|
||||
if (wo.scroller_upAfterSort) {
|
||||
$tbl.parent().animate({ scrollTop: 0 }, 'fast');
|
||||
}
|
||||
|
||||
},
|
||||
remove : function(table, c, wo){
|
||||
var $table = c.$table;
|
||||
$table.closest('.tablesorter-scroller').find('.tablesorter-scroller-header').remove();
|
||||
$table
|
||||
.unwrap()
|
||||
.find('.tablesorter-filter-row').removeClass('hideme').end()
|
||||
.find('thead').show().css('visibility', 'visible');
|
||||
c.isScrolling = false;
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
124
modules/EcmReports/TableSorterNew/js/widgets/widget-staticRow.js
Normal file
124
modules/EcmReports/TableSorterNew/js/widgets/widget-staticRow.js
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* StaticRow widget for jQuery TableSorter 2.0
|
||||
* Version 1.2 - modified by Rob Garrison (6/28/2014 for tablesorter v2.16.1-beta+)
|
||||
* Requires:
|
||||
* jQuery v1.4+
|
||||
* tablesorter plugin, v2.8+, available at http://mottie.github.com/tablesorter/docs/
|
||||
*
|
||||
* Copyright (c) 2011 Nils Luxton
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
var ts = $.tablesorter,
|
||||
|
||||
// events triggered on the table that update this widget
|
||||
events = 'staticRowsRefresh updateComplete '.split(' ').join('.tsstaticrows '),
|
||||
|
||||
// add/refresh row indexes
|
||||
addIndexes = function(table){
|
||||
var $tr, wo, v, indx, rows,
|
||||
c = table.config;
|
||||
// "Index" the static rows, saving their current (starting) position in the
|
||||
// table inside a data() param on the <tr> element itself for later use.
|
||||
if (c) {
|
||||
wo = c.widgetOptions;
|
||||
c.$tbodies.each(function(){
|
||||
$tr = $(this).children();
|
||||
rows = $tr.length;
|
||||
$tr.filter(wo.staticRow_class).each(function() {
|
||||
$tr = $(this);
|
||||
indx = $tr.data(wo.staticRow_index);
|
||||
if (typeof indx !== "undefined") {
|
||||
v = parseFloat(indx);
|
||||
// percentage of total rows
|
||||
indx = (/%/.test(indx)) ? Math.round(v/100 * rows) : v;
|
||||
} else {
|
||||
indx = $tr.index();
|
||||
}
|
||||
// row indexing starts over within each tbody
|
||||
$tr.data( wo.staticRow_data, indx );
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
ts.addWidget({
|
||||
// Give the new Widget an ID to be used in the tablesorter() call, as follows:
|
||||
// $('#myElement').tablesorter({ widgets: ['zebra', 'staticRow'] });
|
||||
id: 'staticRow',
|
||||
|
||||
options: {
|
||||
staticRow_class : '.static',
|
||||
staticRow_data : 'static-index',
|
||||
staticRow_index : 'row-index'
|
||||
},
|
||||
|
||||
init: function(table, thisWidget, c, wo){
|
||||
addIndexes(table);
|
||||
// refresh static rows after updates
|
||||
c.$table
|
||||
.unbind(events)
|
||||
.bind(events, function(){
|
||||
addIndexes(table);
|
||||
c.$table.trigger('applyWidgets');
|
||||
});
|
||||
},
|
||||
|
||||
format: function(table, c, wo) {
|
||||
// Loop thru static rows, moving them to their original "indexed" position,
|
||||
// & repeat until no more re-shuffling is needed
|
||||
var targetIndex, $thisRow, indx, numRows, $tbody, hasShuffled, $rows, max;
|
||||
|
||||
c.$tbodies.each(function(){
|
||||
$tbody = $.tablesorter.processTbody(table, $(this), true); // remove tbody
|
||||
hasShuffled = true;
|
||||
indx = 0;
|
||||
$rows = $tbody.children(wo.staticRow_class);
|
||||
numRows = $tbody.children('tr').length - 1;
|
||||
max = $rows.length;
|
||||
|
||||
// don't allow the while loop to cycle more times than the set number of static rows
|
||||
while (hasShuffled && indx < max) {
|
||||
hasShuffled = false;
|
||||
/*jshint loopfunc:true */
|
||||
$rows.each(function() {
|
||||
targetIndex = $(this).data(wo.staticRow_data);
|
||||
// allow setting target index >> num rows to always make a row last
|
||||
targetIndex = targetIndex >= numRows ? numRows : targetIndex < 0 ? 0 : targetIndex;
|
||||
if (targetIndex !== $(this).index()) {
|
||||
hasShuffled = true;
|
||||
$thisRow = $(this).detach();
|
||||
|
||||
if (targetIndex >= numRows) {
|
||||
// Are we trying to be the last row?
|
||||
$thisRow.appendTo( $tbody );
|
||||
} else if (targetIndex === 0) {
|
||||
// Are we trying to be the first row?
|
||||
$thisRow.prependTo( $tbody );
|
||||
} else {
|
||||
// No, we want to be somewhere in the middle!
|
||||
$thisRow.insertBefore( $tbody.find('tr:eq(' + targetIndex + ')') );
|
||||
}
|
||||
}
|
||||
});
|
||||
indx++;
|
||||
}
|
||||
|
||||
$.tablesorter.processTbody(table, $tbody, false); // restore tbody
|
||||
});
|
||||
|
||||
c.$table.trigger('staticRowsComplete', table);
|
||||
},
|
||||
|
||||
remove : function(table, c, wo){
|
||||
c.$table.unbind(events);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
Reference in New Issue
Block a user