Add JS files
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
/* jQuery Quicksearch plugin
|
||||
by riklomas https://github.com/riklomas/quicksearch
|
||||
Modified to include childRows (for tablesorter)
|
||||
|
||||
See http://stackoverflow.com/q/20342203/145346 for
|
||||
more details
|
||||
*/
|
||||
(function($, window, document, undefined) {
|
||||
$.fn.quicksearch = function (target, opt) {
|
||||
|
||||
var timeout, cache, rowcache, jq_results, val = '', e = this, options = $.extend({
|
||||
delay: 100,
|
||||
selector: null,
|
||||
stripeRows: null,
|
||||
loader: null,
|
||||
noResults: '',
|
||||
childRow: 'tablesorter-childRow', // include child row with search results
|
||||
matchedResultsCount: 0,
|
||||
bind: 'keyup',
|
||||
onBefore: function () {
|
||||
return;
|
||||
},
|
||||
onAfter: function () {
|
||||
return;
|
||||
},
|
||||
show: function () {
|
||||
this.style.display = "";
|
||||
},
|
||||
hide: function () {
|
||||
this.style.display = "none";
|
||||
},
|
||||
prepareQuery: function (val) {
|
||||
return val.toLowerCase().split(' ');
|
||||
},
|
||||
testQuery: function (query, txt, _row) {
|
||||
for (var i = 0; i < query.length; i += 1) {
|
||||
if (txt.indexOf(query[i]) === -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}, opt);
|
||||
|
||||
this.go = function () {
|
||||
|
||||
var i = 0,
|
||||
numMatchedRows = 0,
|
||||
noresults = true,
|
||||
query = options.prepareQuery(val),
|
||||
val_empty = (val.replace(' ', '').length === 0);
|
||||
|
||||
for (var i = 0, len = rowcache.length; i < len; i++) {
|
||||
if (val_empty || options.testQuery(query, cache[i], rowcache[i]) ||
|
||||
($(rowcache[i]).hasClass(options.childRow) && $(rowcache[i > 1 ? i - 1 : 0]).is(':visible'))) {
|
||||
options.show.apply(rowcache[i]);
|
||||
noresults = false;
|
||||
numMatchedRows++;
|
||||
} else {
|
||||
options.hide.apply(rowcache[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (noresults) {
|
||||
this.results(false);
|
||||
} else {
|
||||
this.results(true);
|
||||
this.stripe();
|
||||
}
|
||||
|
||||
this.matchedResultsCount = numMatchedRows;
|
||||
this.loader(false);
|
||||
options.onAfter();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/*
|
||||
* External API so that users can perform search programatically.
|
||||
* */
|
||||
this.search = function (submittedVal) {
|
||||
val = submittedVal;
|
||||
e.trigger();
|
||||
};
|
||||
|
||||
/*
|
||||
* External API to get the number of matched results as seen in
|
||||
* https://github.com/ruiz107/quicksearch/commit/f78dc440b42d95ce9caed1d087174dd4359982d6
|
||||
* */
|
||||
this.currentMatchedResults = function() {
|
||||
return this.matchedResultsCount;
|
||||
};
|
||||
|
||||
this.stripe = function () {
|
||||
|
||||
if (typeof options.stripeRows === "object" && options.stripeRows !== null)
|
||||
{
|
||||
var joined = options.stripeRows.join(' ');
|
||||
var stripeRows_length = options.stripeRows.length;
|
||||
|
||||
jq_results.not(':hidden').each(function (i) {
|
||||
$(this).removeClass(joined).addClass(options.stripeRows[i % stripeRows_length]);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.strip_html = function (input) {
|
||||
var output = input.replace(new RegExp('<[^<]+\>', 'g'), "");
|
||||
output = $.trim(output.toLowerCase());
|
||||
return output;
|
||||
};
|
||||
|
||||
this.results = function (bool) {
|
||||
if (typeof options.noResults === "string" && options.noResults !== "") {
|
||||
if (bool) {
|
||||
$(options.noResults).hide();
|
||||
} else {
|
||||
$(options.noResults).show();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
this.loader = function (bool) {
|
||||
if (typeof options.loader === "string" && options.loader !== "") {
|
||||
(bool) ? $(options.loader).show() : $(options.loader).hide();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
this.cache = function () {
|
||||
|
||||
jq_results = $(target);
|
||||
|
||||
if (typeof options.noResults === "string" && options.noResults !== "") {
|
||||
jq_results = jq_results.not(options.noResults);
|
||||
}
|
||||
|
||||
var t = (typeof options.selector === "string") ?
|
||||
jq_results.find(options.selector) : $(target).not(options.noResults);
|
||||
cache = t.map(function () {
|
||||
return e.strip_html(this.innerHTML);
|
||||
});
|
||||
|
||||
rowcache = jq_results.map(function () {
|
||||
return this;
|
||||
});
|
||||
|
||||
/*
|
||||
* Modified fix for sync-ing "val".
|
||||
* Original fix https://github.com/michaellwest/quicksearch/commit/4ace4008d079298a01f97f885ba8fa956a9703d1
|
||||
* */
|
||||
val = val || this.val() || "";
|
||||
|
||||
return this.go();
|
||||
};
|
||||
|
||||
this.trigger = function () {
|
||||
this.loader(true);
|
||||
options.onBefore();
|
||||
|
||||
window.clearTimeout(timeout);
|
||||
timeout = window.setTimeout(function () {
|
||||
e.go();
|
||||
}, options.delay);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.cache();
|
||||
this.results(true);
|
||||
this.stripe();
|
||||
this.loader(false);
|
||||
|
||||
return this.each(function () {
|
||||
|
||||
/*
|
||||
* Changed from .bind to .on.
|
||||
* */
|
||||
$(this).on(options.bind, function () {
|
||||
|
||||
val = $(this).val();
|
||||
e.trigger();
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
}(jQuery, this, document));
|
||||
1026
modules/EcmReports/TableSorterNew/js/extras/semver-mod.js
Normal file
1026
modules/EcmReports/TableSorterNew/js/extras/semver-mod.js
Normal file
File diff suppressed because it is too large
Load Diff
1011
modules/EcmReports/TableSorterNew/js/extras/semver.js
Normal file
1011
modules/EcmReports/TableSorterNew/js/extras/semver.js
Normal file
File diff suppressed because it is too large
Load Diff
116
modules/EcmReports/TableSorterNew/js/jquery.metadata.js
Normal file
116
modules/EcmReports/TableSorterNew/js/jquery.metadata.js
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Metadata - jQuery plugin for parsing metadata from elements
|
||||
*
|
||||
* Copyright (c) 2006 John Resig, Yehuda Katz, Jörn Zaefferer, Paul McLanahan
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the type of metadata to use. Metadata is encoded in JSON, and each property
|
||||
* in the JSON will become a property of the element itself.
|
||||
*
|
||||
* There are three supported types of metadata storage:
|
||||
*
|
||||
* attr: Inside an attribute. The name parameter indicates *which* attribute.
|
||||
*
|
||||
* class: Inside the class attribute, wrapped in curly braces: { }
|
||||
*
|
||||
* elem: Inside a child element (e.g. a script tag). The
|
||||
* name parameter indicates *which* element.
|
||||
*
|
||||
* The metadata for an element is loaded the first time the element is accessed via jQuery.
|
||||
*
|
||||
* As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
|
||||
* matched by expr, then redefine the metadata type and run another $(expr) for other elements.
|
||||
*
|
||||
* @name $.metadata.setType
|
||||
*
|
||||
* @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
|
||||
* @before $.metadata.setType("class")
|
||||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||||
* @desc Reads metadata from the class attribute
|
||||
*
|
||||
* @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
|
||||
* @before $.metadata.setType("attr", "data")
|
||||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||||
* @desc Reads metadata from a "data" attribute
|
||||
*
|
||||
* @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
|
||||
* @before $.metadata.setType("elem", "script")
|
||||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||||
* @desc Reads metadata from a nested script element
|
||||
*
|
||||
* @param String type The encoding type
|
||||
* @param String name The name of the attribute to be used to get metadata (optional)
|
||||
* @cat Plugins/Metadata
|
||||
* @descr Sets the type of encoding to be used when loading metadata for the first time
|
||||
* @type undefined
|
||||
* @see metadata()
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
$.extend({
|
||||
metadata : {
|
||||
defaults : {
|
||||
type: 'class',
|
||||
name: 'metadata',
|
||||
cre: /(\{.*\})/,
|
||||
single: 'metadata'
|
||||
},
|
||||
setType: function( type, name ){
|
||||
this.defaults.type = type;
|
||||
this.defaults.name = name;
|
||||
},
|
||||
get: function( elem, opts ){
|
||||
var data, m, e, attr,
|
||||
settings = $.extend({},this.defaults,opts);
|
||||
// check for empty string in single property
|
||||
if ( !settings.single.length ) { settings.single = 'metadata'; }
|
||||
|
||||
data = $.data(elem, settings.single);
|
||||
// returned cached data if it already exists
|
||||
if ( data ) { return data; }
|
||||
|
||||
data = "{}";
|
||||
|
||||
if ( settings.type === "class" ) {
|
||||
m = settings.cre.exec( elem.className );
|
||||
if ( m ) { data = m[1]; }
|
||||
} else if ( settings.type === "elem" ) {
|
||||
if( !elem.getElementsByTagName ) { return undefined; }
|
||||
e = elem.getElementsByTagName(settings.name);
|
||||
if ( e.length ) { data = $.trim(e[0].innerHTML); }
|
||||
} else if ( elem.getAttribute !== undefined ) {
|
||||
attr = elem.getAttribute( settings.name );
|
||||
if ( attr ) { data = attr; }
|
||||
}
|
||||
|
||||
if ( data.indexOf( '{' ) <0 ) { data = "{" + data + "}"; }
|
||||
|
||||
data = eval("(" + data + ")");
|
||||
|
||||
$.data( elem, settings.single, data );
|
||||
return data;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the metadata object for the first member of the jQuery object.
|
||||
*
|
||||
* @name metadata
|
||||
* @descr Returns element's metadata object
|
||||
* @param Object opts An object contianing settings to override the defaults
|
||||
* @type jQuery
|
||||
* @cat Plugins/Metadata
|
||||
*/
|
||||
$.fn.metadata = function( opts ){
|
||||
return $.metadata.get( this[0], opts );
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
1901
modules/EcmReports/TableSorterNew/js/jquery.tablesorter.js
Normal file
1901
modules/EcmReports/TableSorterNew/js/jquery.tablesorter.js
Normal file
File diff suppressed because it is too large
Load Diff
5
modules/EcmReports/TableSorterNew/js/jquery.tablesorter.min.js
vendored
Normal file
5
modules/EcmReports/TableSorterNew/js/jquery.tablesorter.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,138 @@
|
||||
/*! Filter widget select2 formatter function - updated 7/17/2014 (v2.17.5)
|
||||
* requires: jQuery 1.7.2+, tableSorter 2.16+, filter widget 2.16+ and select2 v3.4.6+ plugin
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter || {};
|
||||
ts.filterFormatter = ts.filterFormatter || {};
|
||||
|
||||
/************************\
|
||||
Select2 Filter Formatter
|
||||
\************************/
|
||||
ts.filterFormatter.select2 = function($cell, indx, select2Def) {
|
||||
var o = $.extend({
|
||||
// select2 filter formatter options
|
||||
cellText : '', // Text (wrapped in a label element)
|
||||
match : true, // adds "filter-match" to header
|
||||
value : '',
|
||||
// include ANY select2 options below
|
||||
multiple : true,
|
||||
width : '100%'
|
||||
|
||||
}, select2Def ),
|
||||
arry, data,
|
||||
c = $cell.closest('table')[0].config,
|
||||
wo = c.widgetOptions,
|
||||
// Add a hidden input to hold the range values
|
||||
$input = $('<input class="filter" type="hidden">')
|
||||
.appendTo($cell)
|
||||
// hidden filter update namespace trigger by filter widget
|
||||
.bind('change' + c.namespace + 'filter', function(){
|
||||
var val = this.value;
|
||||
val = val.replace(/[/()$^]/g, '').split('|');
|
||||
$cell.find('.select2').select2('val', val);
|
||||
updateSelect2();
|
||||
}),
|
||||
$header = c.$headers.filter('[data-column="' + indx + '"]:last'),
|
||||
onlyAvail = $header.hasClass(wo.filter_onlyAvail),
|
||||
$shcell = [],
|
||||
matchPrefix = o.match ? '' : '^',
|
||||
matchSuffix = o.match ? '' : '$',
|
||||
|
||||
// this function updates the hidden input and adds the current values to the header cell text
|
||||
updateSelect2 = function() {
|
||||
var v = $cell.find('.select2').select2('val') || o.value || '';
|
||||
$input
|
||||
// add regex, so we filter exact numbers
|
||||
.val( $.isArray(v) && v.length && v.join('') !== '' ? '/(' + matchPrefix + (v || []).join(matchSuffix + '|' + matchPrefix) + matchSuffix + ')/' : '' )
|
||||
.trigger('search').end()
|
||||
.find('.select2').select2('val', v);
|
||||
// update sticky header cell
|
||||
if ($shcell.length) {
|
||||
$shcell
|
||||
.find('.select2').select2('val', v);
|
||||
}
|
||||
},
|
||||
|
||||
// get options from table cell content or filter_selectSource (v2.16)
|
||||
updateOptions = function(){
|
||||
data = [];
|
||||
arry = ts.filter.getOptionSource(c.$table[0], indx, onlyAvail) || [];
|
||||
// build select2 data option
|
||||
$.each(arry, function(i,v){
|
||||
data.push({id: v, text: v});
|
||||
});
|
||||
o.data = data;
|
||||
};
|
||||
|
||||
// get filter-match class from option
|
||||
$header.toggleClass('filter-match', o.match);
|
||||
if (o.cellText) {
|
||||
$cell.prepend('<label>' + o.cellText + '</label>');
|
||||
}
|
||||
|
||||
// don't add default in table options if either ajax or
|
||||
// data options are already defined
|
||||
if (!(o.ajax && !$.isEmptyObject(o.ajax)) && !o.data) {
|
||||
updateOptions();
|
||||
if (onlyAvail) {
|
||||
c.$table.bind('filterEnd', function(){
|
||||
updateOptions();
|
||||
$cell.add($shcell).find('.select2').select2(o);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// add a select2 hidden input!
|
||||
$('<input class="select2 select2-' + indx + '" type="hidden" />')
|
||||
.val(o.value)
|
||||
.appendTo($cell)
|
||||
.select2(o)
|
||||
.bind('change', function(){
|
||||
updateSelect2();
|
||||
});
|
||||
|
||||
// update select2 from filter hidden input, in case of saved filters
|
||||
c.$table.bind('filterFomatterUpdate', function(){
|
||||
// value = '/(^x$|^y$)/' => 'x,y'
|
||||
var val = c.$table.data('lastSearch')[indx] || '';
|
||||
val = val.replace(/[/()$^]/g, '').split('|');
|
||||
$cell.find('.select2').select2('val', val);
|
||||
updateSelect2();
|
||||
ts.filter.formatterUpdated($cell, indx);
|
||||
});
|
||||
|
||||
// has sticky headers?
|
||||
c.$table.bind('stickyHeadersInit', function(){
|
||||
$shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty();
|
||||
// add a select2!
|
||||
$('<input class="select2 select2-' + indx + '" type="hidden">')
|
||||
.val(o.value)
|
||||
.appendTo($shcell)
|
||||
.select2(o)
|
||||
.bind('change', function(){
|
||||
$cell.find('.select2').select2('val', $shcell.find('.select2').select2('val') );
|
||||
updateSelect2();
|
||||
});
|
||||
if (o.cellText) {
|
||||
$shcell.prepend('<label>' + o.cellText + '</label>');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// on reset
|
||||
c.$table.bind('filterReset', function(){
|
||||
$cell.find('.select2').select2('val', o.value || '');
|
||||
setTimeout(function(){
|
||||
updateSelect2();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
updateSelect2();
|
||||
return $input;
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
File diff suppressed because it is too large
Load Diff
6
modules/EcmReports/TableSorterNew/js/jquery.tablesorter.widgets-filter-formatter.min.js
vendored
Normal file
6
modules/EcmReports/TableSorterNew/js/jquery.tablesorter.widgets-filter-formatter.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1912
modules/EcmReports/TableSorterNew/js/jquery.tablesorter.widgets.js
Normal file
1912
modules/EcmReports/TableSorterNew/js/jquery.tablesorter.widgets.js
Normal file
File diff suppressed because it is too large
Load Diff
17
modules/EcmReports/TableSorterNew/js/jquery.tablesorter.widgets.min.js
vendored
Normal file
17
modules/EcmReports/TableSorterNew/js/jquery.tablesorter.widgets.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,81 @@
|
||||
/*!
|
||||
* Extract out date parsers
|
||||
*/
|
||||
/*jshint jquery:true */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
/*! extract US Long Date (ignore any other text)
|
||||
* e.g. "Sue's Birthday! Jun 26, 2004 7:22 AM (8# 2oz)"
|
||||
* demo: http://jsfiddle.net/abkNM/2293/
|
||||
*/
|
||||
$.tablesorter.addParser({
|
||||
id: "extractUSLongDate",
|
||||
is: function (s) {
|
||||
// don't auto detect this parser
|
||||
return false;
|
||||
},
|
||||
format: function (s, table) {
|
||||
var date = s.match(/[A-Z]{3,10}\.?\s+\d{1,2},?\s+(?:\d{4})(?:\s+\d{1,2}:\d{2}(?::\d{2})?(?:\s+[AP]M)?)?/i);
|
||||
return date ? $.tablesorter.formatFloat((new Date(date[0]).getTime() || ''), table) || s : s;
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
/*! extract MMDDYYYY (ignore any other text)
|
||||
* demo: http://jsfiddle.net/Mottie/abkNM/2418/
|
||||
*/
|
||||
$.tablesorter.addParser({
|
||||
id: "extractMMDDYYYY",
|
||||
is: function (s) {
|
||||
// don't auto detect this parser
|
||||
return false;
|
||||
},
|
||||
format: function (s, table) {
|
||||
var date = s.replace(/\s+/g," ").replace(/[\-.,]/g, "/").match(/(\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i);
|
||||
return date ? $.tablesorter.formatFloat((new Date(date[0]).getTime() || ''), table) || s : s;
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
/*! extract DDMMYYYY (ignore any other text)
|
||||
* demo: http://jsfiddle.net/Mottie/abkNM/2419/
|
||||
*/
|
||||
$.tablesorter.addParser({
|
||||
id: "extractDDMMYYYY",
|
||||
is: function (s) {
|
||||
// don't auto detect this parser
|
||||
return false;
|
||||
},
|
||||
format: function (s, table) {
|
||||
var date = s.replace(/\s+/g," ").replace(/[\-.,]/g, "/").match(/(\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i);
|
||||
if (date) {
|
||||
date = date[0].replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$2/$1/$3");
|
||||
return $.tablesorter.formatFloat((new Date(date).getTime() || ''), table) || s;
|
||||
}
|
||||
return s;
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
/*! extract YYYYMMDD (ignore any other text)
|
||||
* demo: http://jsfiddle.net/Mottie/abkNM/2420/
|
||||
*/
|
||||
$.tablesorter.addParser({
|
||||
id: "extractYYYYMMDD",
|
||||
is: function (s) {
|
||||
// don't auto detect this parser
|
||||
return false;
|
||||
},
|
||||
format: function (s, table) {
|
||||
var date = s.replace(/\s+/g," ").replace(/[\-.,]/g, "/").match(/(\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i);
|
||||
if (date) {
|
||||
date = date[0].replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, "$2/$3/$1");
|
||||
return $.tablesorter.formatFloat((new Date(date).getTime() || ''), table) || s;
|
||||
}
|
||||
return s;
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,34 @@
|
||||
/*! ISO-8601 date parser
|
||||
* This parser will work with dates in ISO8601 format
|
||||
* 2013-02-18T18:18:44+00:00
|
||||
* Written by Sean Ellingham :https://github.com/seanellingham
|
||||
* See https://github.com/Mottie/tablesorter/issues/247
|
||||
*/
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var iso8601date = /^([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/;
|
||||
$.tablesorter.addParser({
|
||||
id : 'iso8601date',
|
||||
is : function(s) {
|
||||
return s.match(iso8601date);
|
||||
},
|
||||
format : function(s) {
|
||||
var result = s.match(iso8601date);
|
||||
if (result) {
|
||||
var date = new Date(result[1], 0, 1);
|
||||
if (result[3]) { date.setMonth(result[3] - 1); }
|
||||
if (result[5]) { date.setDate(result[5]); }
|
||||
if (result[7]) { date.setHours(result[7]); }
|
||||
if (result[8]) { date.setMinutes(result[8]); }
|
||||
if (result[10]) { date.setSeconds(result[10]); }
|
||||
if (result[12]) { date.setMilliseconds(Number('0.' + result[12]) * 1000); }
|
||||
return date;
|
||||
}
|
||||
return s;
|
||||
},
|
||||
type : 'numeric'
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,33 @@
|
||||
/*! Month parser
|
||||
* Demo: http://jsfiddle.net/Mottie/abkNM/477/
|
||||
*/
|
||||
/*jshint jquery:true */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter;
|
||||
ts.dates = $.extend({}, ts.dates, {
|
||||
// *** modify this array to change match the language ***
|
||||
monthCased : [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
|
||||
});
|
||||
ts.dates.monthLower = ts.dates.monthCased.join(',').toLocaleLowerCase().split(',');
|
||||
|
||||
ts.addParser({
|
||||
id: "month",
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s, table) {
|
||||
var j = -1, c = table.config,
|
||||
n = c.ignoreCase ? s.toLocaleLowerCase() : s;
|
||||
$.each(ts.dates[ 'month' + (c.ignoreCase ? 'Lower' : 'Cased') ], function(i,v){
|
||||
if (j < 0 && n.match(v)) { j = i; }
|
||||
});
|
||||
// return s (original string) if there isn't a match
|
||||
// (non-weekdays will sort separately and empty cells will sort as expected)
|
||||
return j < 0 ? s : j;
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,74 @@
|
||||
/*! Two digit year parser
|
||||
* Demo: http://jsfiddle.net/Mottie/abkNM/427/
|
||||
*/
|
||||
/*jshint jquery:true */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter,
|
||||
|
||||
// Make the date be within +/- range of the 2 digit year
|
||||
// so if the current year is 2020, and the 2 digit year is 80 (2080 - 2020 > 50), it becomes 1980
|
||||
// if the 2 digit year is 50 (2050 - 2020 < 50), then it becomes 2050.
|
||||
range = 50;
|
||||
|
||||
ts.dates = $.extend({}, ts.dates, {
|
||||
regxxxxyy: /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{2})/,
|
||||
regyyxxxx: /(\d{2})[\/\s](\d{1,2})[\/\s](\d{1,2})/
|
||||
});
|
||||
|
||||
ts.formatDate = function(s, regex, format, table){
|
||||
var n = s
|
||||
// replace separators
|
||||
.replace(/\s+/g," ").replace(/[-.,]/g, "/")
|
||||
// reformat xx/xx/xx to mm/dd/19yy;
|
||||
.replace(regex, format),
|
||||
d = new Date(n),
|
||||
y = d.getFullYear(),
|
||||
rng = table && table.config.dateRange || range,
|
||||
now = new Date().getFullYear();
|
||||
// if date > 50 years old (set range), add 100 years
|
||||
// this will work when people start using "50" and mean "2050"
|
||||
while (now - y > rng) {
|
||||
y += 100;
|
||||
}
|
||||
return d.setFullYear(y) || s;
|
||||
};
|
||||
|
||||
$.tablesorter.addParser({
|
||||
id: "ddmmyy",
|
||||
is: function() {
|
||||
return false;
|
||||
},
|
||||
format: function(s, table) {
|
||||
// reformat dd/mm/yy to mm/dd/19yy;
|
||||
return ts.formatDate(s, ts.dates.regxxxxyy, "$2/$1/19$3", table);
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
$.tablesorter.addParser({
|
||||
id: "mmddyy",
|
||||
is: function() {
|
||||
return false;
|
||||
},
|
||||
format: function(s, table) {
|
||||
// reformat mm/dd/yy to mm/dd/19yy
|
||||
return ts.formatDate(s, ts.dates.regxxxxyy, "$1/$2/19$3", table);
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
$.tablesorter.addParser({
|
||||
id: "yymmdd",
|
||||
is: function() {
|
||||
return false;
|
||||
},
|
||||
format: function(s, table) {
|
||||
// reformat yy/mm/dd to mm/dd/19yy
|
||||
return ts.formatDate(s, ts.dates.regyyxxxx, "$2/$3/19$1", table);
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,33 @@
|
||||
/*! Weekday parser
|
||||
* Demo: http://jsfiddle.net/Mottie/abkNM/477/
|
||||
*/
|
||||
/*jshint jquery:true */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter;
|
||||
ts.dates = $.extend({}, ts.dates, {
|
||||
// *** modify this array to change match the language ***
|
||||
weekdayCased : [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]
|
||||
});
|
||||
ts.dates.weekdayLower = ts.dates.weekdayCased.join(',').toLocaleLowerCase().split(',');
|
||||
|
||||
ts.addParser({
|
||||
id: "weekday",
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s, table) {
|
||||
var j = -1, c = table.config;
|
||||
s = c.ignoreCase ? s.toLocaleLowerCase() : s;
|
||||
$.each(ts.dates[ 'weekday' + (c.ignoreCase ? 'Lower' : 'Cased') ], function(i,v){
|
||||
if (j < 0 && s.match(v)) { j = i; }
|
||||
});
|
||||
// return s (original string) if there isn't a match
|
||||
// (non-weekdays will sort separately and empty cells will sort as expected)
|
||||
return j < 0 ? s : j;
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
36
modules/EcmReports/TableSorterNew/js/parsers/parser-date.js
Normal file
36
modules/EcmReports/TableSorterNew/js/parsers/parser-date.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/*!
|
||||
* Extract dates using popular natural language date parsers
|
||||
*/
|
||||
/*jshint jquery:true */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
/*! Sugar (http://sugarjs.com/dates#comparing_dates)
|
||||
* demo: http://jsfiddle.net/Mottie/abkNM/551/
|
||||
*/
|
||||
$.tablesorter.addParser({
|
||||
id: "sugar",
|
||||
is: function() {
|
||||
return false;
|
||||
},
|
||||
format: function(s) {
|
||||
return Date.create ? Date.create(s).getTime() || s : new Date(s).getTime() || s;
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
/*! Datejs (http://www.datejs.com/)
|
||||
* demo: http://jsfiddle.net/Mottie/abkNM/550/
|
||||
*/
|
||||
$.tablesorter.addParser({
|
||||
id: "datejs",
|
||||
is: function() {
|
||||
return false;
|
||||
},
|
||||
format: function(s) {
|
||||
return Date.parse && Date.parse(s) || s;
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,40 @@
|
||||
/*! Duration parser
|
||||
*/
|
||||
/*jshint jquery:true, unused:false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
// If any number > 9999, then set table.config.durationLength = 5
|
||||
// The below regex matches this duration example: 1y 23d 12h 44m 9s
|
||||
$.tablesorter.addParser({
|
||||
id: "duration",
|
||||
is: function() {
|
||||
return false;
|
||||
},
|
||||
format: function(s, table) {
|
||||
var i, time,
|
||||
c = table.config,
|
||||
t = '',
|
||||
duration = '',
|
||||
len = c.durationLength || 4,
|
||||
str = new Array(len + 1).join('0'),
|
||||
labels = (c.durationLabels || '(?:years|year|y),(?:days|day|d),(?:hours|hour|h),(?:minutes|minute|min|m),(?:seconds|second|sec|s)').split(/\s*,\s*/),
|
||||
llen = labels.length;
|
||||
// build regex
|
||||
if (!c.durationRegex) {
|
||||
for (i = 0; i < llen; i++) {
|
||||
t += '(?:(\\d+)\\s*' + labels[i] + '\\s*)?';
|
||||
}
|
||||
c.durationRegex = new RegExp(t, 'i');
|
||||
}
|
||||
// remove commas from value
|
||||
time = ( c.usNumberFormat ? s.replace(/,/g, '') : s.replace( /(\d)(?:\.|\s*)(\d)/g, '$1$2') ).match(c.durationRegex);
|
||||
for (i = 1; i < llen + 1; i++) {
|
||||
duration += ( str + ( time[i] || 0 ) ).slice(-len);
|
||||
}
|
||||
return duration;
|
||||
},
|
||||
type: "text"
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,63 @@
|
||||
/*! Distance parser
|
||||
* This parser will parser numbers like 5'10" (5 foot 10 inches)
|
||||
* and 31½ into sortable values.
|
||||
* Demo: http://jsfiddle.net/Mottie/abkNM/154/
|
||||
*/
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter;
|
||||
ts.symbolRegex = /[\u215b\u215c\u215d\u215e\u00bc\u00bd\u00be]/g;
|
||||
ts.processFractions = function(n, table) {
|
||||
if (n) {
|
||||
var t, p = 0;
|
||||
n = $.trim(n.replace(/\"/,''));
|
||||
// look for a space in the first part of the number: "10 3/4" and save the "10"
|
||||
if (/\s/.test(n)) {
|
||||
p = ts.formatFloat(n.split(' ')[0], table);
|
||||
// remove stuff to the left of the space
|
||||
n = $.trim(n.substring(n.indexOf(' '), n.length));
|
||||
}
|
||||
// look for a "/" to calculate fractions
|
||||
if (/\//g.test(n)) {
|
||||
t = n.split('/');
|
||||
// turn 3/4 into .75; make sure we don't divide by zero
|
||||
n = p + parseInt(t[0], 10) / parseInt(t[1] || 1, 10);
|
||||
// look for fraction symbols
|
||||
} else if (ts.symbolRegex.test(n)) {
|
||||
n = p + n.replace(ts.symbolRegex, function(m){
|
||||
return {
|
||||
'\u215b' : '.125', // 1/8
|
||||
'\u215c' : '.375', // 3/8
|
||||
'\u215d' : '.625', // 5/8
|
||||
'\u215e' : '.875', // 7/8
|
||||
'\u00bc' : '.25', // 1/4
|
||||
'\u00bd' : '.5', // 1/2
|
||||
'\u00be' : '.75' // 3/4
|
||||
}[m];
|
||||
});
|
||||
}
|
||||
}
|
||||
return n || 0;
|
||||
};
|
||||
|
||||
$.tablesorter.addParser({
|
||||
id: 'distance',
|
||||
is: function() {
|
||||
// return false so this parser is not auto detected
|
||||
return false;
|
||||
},
|
||||
format: function(s, table) {
|
||||
if (s === '') { return ''; }
|
||||
// look for feet symbol = '
|
||||
// very generic test to catch 1.1', 1 1/2' and 1½'
|
||||
var d = (/^\s*\S*(\s+\S+)?\s*\'/.test(s)) ? s.split("'") : [0,s],
|
||||
f = ts.processFractions(d[0], table), // feet
|
||||
i = ts.processFractions(d[1], table); // inches
|
||||
return (/[\'\"]/).test(s) ? parseFloat(f) + (parseFloat(i)/12 || 0) : parseFloat(f) + parseFloat(i);
|
||||
},
|
||||
type: 'numeric'
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,73 @@
|
||||
/*! File Type parser
|
||||
* When a file type extension is found, the equivalent name is
|
||||
* prefixed into the parsed data, so sorting occurs in groups
|
||||
*/
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
// basic list from http://en.wikipedia.org/wiki/List_of_file_formats
|
||||
// To add a custom equivalent, define:
|
||||
// $.tablesorter.fileTypes.equivalents['xx'] = "A|B|C";
|
||||
$.tablesorter.fileTypes = {
|
||||
// divides filetype extensions in the equivalent list below
|
||||
separator : '|',
|
||||
equivalents : {
|
||||
"3D Image" : "3dm|3ds|dwg|max|obj",
|
||||
"Audio" : "aif|aac|ape|flac|la|m4a|mid|midi|mp2|mp3|ogg|ra|raw|rm|wav|wma",
|
||||
"Compressed" : "7z|bin|cab|cbr|gz|gzip|iso|lha|lz|rar|tar|tgz|zip|zipx|zoo",
|
||||
"Database" : "csv|dat|db|dbf|json|ldb|mdb|myd|pdb|sql|tsv|wdb|wmdb|xlr|xls|xlsx|xml",
|
||||
"Development" : "asm|c|class|cls|cpp|cc|cs|cxx|cbp|cs|dba|fla|h|java|lua|pl|py|pyc|pyo|sh|sln|r|rb|vb",
|
||||
"Document" : "doc|docx|odt|ott|pages|pdf|rtf|tex|wpd|wps|wrd|wri",
|
||||
"Executable" : "apk|app|com|exe|gadget|lnk|msi",
|
||||
"Fonts" : "eot|fnt|fon|otf|ttf|woff",
|
||||
"Icons" : "ani|cur|icns|ico",
|
||||
"Images" : "bmp|gif|jpg|jpeg|jpe|jp2|pic|png|psd|tga|tif|tiff|wmf|webp",
|
||||
"Presentation" : "pps|ppt",
|
||||
"Published" : "chp|epub|lit|pub|ppp|fm|mobi",
|
||||
"Script" : "as|bat|cgi|cmd|jar|js|lua|scpt|scptd|sh|vbs|vb|wsf",
|
||||
"Styles" : "css|less|sass",
|
||||
"Text" : "info|log|md|markdown|nfo|tex|text|txt",
|
||||
"Vectors" : "awg|ai|eps|cdr|ps|svg",
|
||||
"Video" : "asf|avi|flv|m4v|mkv|mov|mp4|mpe|mpeg|mpg|ogg|rm|rv|swf|vob|wmv",
|
||||
"Web" : "asp|aspx|cer|cfm|htm|html|php|url|xhtml"
|
||||
}
|
||||
};
|
||||
|
||||
$.tablesorter.addParser({
|
||||
id: 'filetype',
|
||||
is: function() {
|
||||
return false;
|
||||
},
|
||||
format: function(s, table) {
|
||||
var t,
|
||||
c = table.config,
|
||||
wo = c.widgetOptions,
|
||||
i = s.lastIndexOf('.'),
|
||||
sep = $.tablesorter.fileTypes.separator,
|
||||
m = $.tablesorter.fileTypes.matching,
|
||||
types = $.tablesorter.fileTypes.equivalents;
|
||||
if (!m) {
|
||||
// make a string to "quick" match the existing equivalents
|
||||
var t = [];
|
||||
$.each(types, function(i,v){
|
||||
t.push(v);
|
||||
});
|
||||
m = $.tablesorter.fileTypes.matching = sep + t.join(sep) + sep;
|
||||
}
|
||||
if (i >= 0) {
|
||||
t = sep + s.substring(i + 1, s.length) + sep;
|
||||
if (m.indexOf(t) >= 0) {
|
||||
for (i in types) {
|
||||
if ((sep + types[i] + sep).indexOf(t) >= 0) {
|
||||
return i + (wo.group_separator ? wo.group_separator : '-') + s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
},
|
||||
type: 'text'
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,61 @@
|
||||
/*! Title parser - updated 9/15/2014 (v2.17.8)
|
||||
* This parser will remove "The", "A" and "An" from the beginning of a book
|
||||
* or movie title, so it sorts by the second word or number
|
||||
* Demo: http://jsfiddle.net/Mottie/abkNM/5/
|
||||
*/
|
||||
/*jshint browser: true, jquery:true, unused:false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter;
|
||||
|
||||
// basic list from http://en.wikipedia.org/wiki/Article_%28grammar%29
|
||||
ts.ignoreArticles = {
|
||||
"en" : "the, a, an",
|
||||
"de" : "der, die, das, des, dem, den, ein, eine, einer, eines, einem, einen",
|
||||
"nl" : "de, het, de, een",
|
||||
"es" : "el, la, lo, los, las, un, una, unos, unas",
|
||||
"pt" : "o, a, os, as, um, uma, uns, umas",
|
||||
"fr" : "le, la, l'_, les, un, une, des",
|
||||
"it" : "il, lo, la, l'_, i, gli, le, un', uno, una, un",
|
||||
"hu" : "a, az, egy"
|
||||
};
|
||||
|
||||
// To add a custom parser, define:
|
||||
// $.tablesorter.ignoreArticles['xx'] = "A, B, C";
|
||||
// and then set the language id 'xx' in the headers option
|
||||
// ignoreArticles : 'xx'
|
||||
|
||||
ts.addParser({
|
||||
id: 'ignoreArticles',
|
||||
is: function() {
|
||||
return false;
|
||||
},
|
||||
format: function(s, table, cell, cellIndex) {
|
||||
var art, ignore, lang,
|
||||
c = table.config,
|
||||
str = s || '';
|
||||
if ( !(c.headers && c.headers[cellIndex] && c.headers[cellIndex].ignoreArticlesRegex) ) {
|
||||
// initialize - save regex in c.headers[cellIndex].ignoreArticlesRegex
|
||||
if (!c.headers) { c.headers = {}; }
|
||||
if (!c.headers[cellIndex]) { c.headers[cellIndex] = {}; }
|
||||
lang = ts.getData( c.$headers.eq(cellIndex), ts.getColumnData( table, c.headers, cellIndex ), 'ignoreArticles' );
|
||||
art = (ts.ignoreArticles[lang] || "the, a, an" ) + "";
|
||||
c.headers[cellIndex].ignoreArticlesRegex = new RegExp('^(' + $.trim( art.split(/\s*\,\s*/).join('\\s|') + "\\s" ).replace("_\\s","") + ')', 'i');
|
||||
// exception regex stored in c.headers[cellIndex].ignoreArticlesRegex2
|
||||
ignore = ts.getData( c.$headers.eq(cellIndex), ts.getColumnData( table, c.headers, cellIndex ), 'ignoreArticlesExcept' );
|
||||
c.headers[cellIndex].ignoreArticlesRegex2 = ignore !== '' ? new RegExp('^(' + ignore.replace(/\s/g, "\\s") + ')', 'i') : '';
|
||||
}
|
||||
art = c.headers[cellIndex].ignoreArticlesRegex;
|
||||
if (art.test(str)) {
|
||||
ignore = c.headers[cellIndex].ignoreArticlesRegex2;
|
||||
if ( !(ignore && ignore.test(str)) ) {
|
||||
return str.replace(art, '');
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
type: 'text'
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
20
modules/EcmReports/TableSorterNew/js/parsers/parser-image.js
Normal file
20
modules/EcmReports/TableSorterNew/js/parsers/parser-image.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/*! image alt attribute parser for jQuery 1.7+ & tablesorter 2.7.11+
|
||||
* New 7/17/2014 (v2.17.5)
|
||||
*/
|
||||
/*jshint jquery:true, unused:false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
$.tablesorter.addParser({
|
||||
id: "image",
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s, table, cell) {
|
||||
return $(cell).find('img').attr(table.config.imgAttr || 'alt') || s;
|
||||
},
|
||||
parsed : true, // filter widget flag
|
||||
type: "text"
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,161 @@
|
||||
/*! input & select parsers for jQuery 1.7+ & tablesorter 2.7.11+
|
||||
* Updated 9/15/2014 (v2.17.8)
|
||||
* Demo: http://mottie.github.com/tablesorter/docs/example-widget-grouping.html
|
||||
*/
|
||||
/*jshint browser: true, jquery:true, unused:false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var resort = true, // resort table after update
|
||||
updateServer = function(event, $table, $input){
|
||||
// do something here to update your server, if needed
|
||||
// event = change event object
|
||||
// $table = jQuery object of the table that was just updated
|
||||
// $input = jQuery object of the input or select that was modified
|
||||
};
|
||||
|
||||
// Custom parser for parsing input values
|
||||
// updated dynamically using the "change" function below
|
||||
$.tablesorter.addParser({
|
||||
id: "inputs",
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s, table, cell) {
|
||||
return $(cell).find('input').val() || s;
|
||||
},
|
||||
parsed : true, // filter widget flag
|
||||
type: "text"
|
||||
});
|
||||
|
||||
// Custom parser for including checkbox status if using the grouping widget
|
||||
// updated dynamically using the "change" function below
|
||||
$.tablesorter.addParser({
|
||||
id: "checkbox",
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s, table, cell, cellIndex) {
|
||||
var $c = $(cell),
|
||||
$input = $c.find('input[type="checkbox"]'),
|
||||
isChecked = $input.length ? $input[0].checked : '';
|
||||
// adding class to row, indicating that a checkbox is checked; includes
|
||||
// a column index in case more than one checkbox happens to be in a row
|
||||
$c.closest('tr').toggleClass('checked-' + cellIndex, isChecked);
|
||||
// returning plain language here because this is what is shown in the
|
||||
// group headers - change it as desired
|
||||
return $input.length ? isChecked ? 'checked' : 'unchecked' : s;
|
||||
},
|
||||
parsed : true, // filter widget flag
|
||||
type: "text"
|
||||
});
|
||||
|
||||
// Custom parser which returns the currently selected options
|
||||
// updated dynamically using the "change" function below
|
||||
$.tablesorter.addParser({
|
||||
id: "select",
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s, table, cell) {
|
||||
return $(cell).find('select').val() || s;
|
||||
},
|
||||
parsed : true, // filter widget flag
|
||||
type: "text"
|
||||
});
|
||||
|
||||
// Select parser to get the selected text
|
||||
$.tablesorter.addParser({
|
||||
id: "select-text",
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s, table, cell) {
|
||||
var $s = $(cell).find('select');
|
||||
return $s.length ? $s.find('option:selected').text() || '' : s;
|
||||
},
|
||||
parsed : true, // filter widget flag
|
||||
type: "text"
|
||||
});
|
||||
|
||||
// Custom parser for parsing textarea values
|
||||
// updated dynamically using the "change" function below
|
||||
$.tablesorter.addParser({
|
||||
id: "textarea",
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s, table, cell) {
|
||||
return $(cell).find('textarea').val() || s;
|
||||
},
|
||||
parsed : true, // filter widget flag
|
||||
type: "text"
|
||||
});
|
||||
|
||||
// update select and all input types in the tablesorter cache when the change event fires.
|
||||
// This method only works with jQuery 1.7+
|
||||
// you can change it to use delegate (v1.4.3+) or live (v1.3+) as desired
|
||||
// if this code interferes somehow, target the specific table $('#mytable'), instead of $('table')
|
||||
$(function(){
|
||||
$('table').on('tablesorter-initialized', function(){
|
||||
// this flag prevents the updateCell event from being spammed
|
||||
// it happens when you modify input text and hit enter
|
||||
var focused = false,
|
||||
restoreValue = function(isTbody){
|
||||
// focused = false; // uncomment this line to prevent auto-accepting changes
|
||||
// make sure we restore original values
|
||||
// isTbody is needed to prevent the select from closing in IE
|
||||
// see https://connect.microsoft.com/IE/feedbackdetail/view/962618/
|
||||
if (isTbody) {
|
||||
$(':focus').blur();
|
||||
}
|
||||
return;
|
||||
};
|
||||
// bind to .tablesorter (default class name)
|
||||
$(this).children('tbody')
|
||||
.on('mouseleave', function(e){
|
||||
restoreValue(e.target.tagName === 'TBODY');
|
||||
})
|
||||
.on('focus', 'select, input, textarea', function(){
|
||||
focused = true;
|
||||
$(this).data('ts-original-value', this.value);
|
||||
})
|
||||
.on('blur', 'input, textarea', function(){
|
||||
// restore input value;
|
||||
// "change" is triggered before "blur" so this doesn't replace the new update with the original
|
||||
this.value = $(this).data('ts-original-value');
|
||||
})
|
||||
.on('change keyup', 'select, input, textarea', function(e){
|
||||
if ( e.which === 27 ) {
|
||||
// escape: restore original value
|
||||
this.value = $(this).data('ts-original-value');
|
||||
return;
|
||||
}
|
||||
// Update cell cache using... select: change, input: enter or textarea: alt + enter
|
||||
if ( ( e.type === 'change' && focused ) ||
|
||||
( e.type === 'keyup' && e.which === 13 && ( e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' && e.altKey ) ) ) {
|
||||
var $tar = $(e.target),
|
||||
$cell = $tar.closest('td'),
|
||||
$table = $cell.closest('table'),
|
||||
indx = $cell[0].cellIndex,
|
||||
c = $table[0].config || false,
|
||||
$hdr = c && c.$headers && c.$headers.eq(indx);
|
||||
// abort if not a tablesorter table, or
|
||||
// don't use updateCell if column is set to "sorter-false" and "filter-false", or column is set to "parser-false"
|
||||
if ( !c || ( $hdr && $hdr.length && ( $hdr.hasClass('parser-false') || ( $hdr.hasClass('sorter-false') && $hdr.hasClass('filter-false') ) ) ) ) {
|
||||
return restoreValue();
|
||||
}
|
||||
// ignore change event if nothing changed
|
||||
if ($tar.val() !== $tar.data('ts-original-value')) {
|
||||
$tar.data('ts-original-value', $tar.val());
|
||||
$table.trigger('updateCell', [ $tar.closest('td'), resort, function(){
|
||||
updateServer(e, $table, $tar);
|
||||
setTimeout(function(){ focused = false; }, 10);
|
||||
} ]);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
76
modules/EcmReports/TableSorterNew/js/parsers/parser-ipv6.js
Normal file
76
modules/EcmReports/TableSorterNew/js/parsers/parser-ipv6.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/*! IPv6 Address parser (WIP)
|
||||
* IPv6 Address (ffff:0000:0000:0000:0000:0000:0000:0000)
|
||||
* needs to support short versions like "::8" or "1:2::7:8"
|
||||
* and "::00:192.168.10.184" (embedded IPv4 address)
|
||||
* see http://www.intermapper.com/support/tools/IPV6-Validator.aspx
|
||||
*/
|
||||
/*global jQuery: false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var ts = $.tablesorter;
|
||||
|
||||
$.extend( ts.regex, {}, {
|
||||
ipv4Validate : /((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})/,
|
||||
ipv4Extract : /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/,
|
||||
|
||||
// simplified regex from http://www.intermapper.com/support/tools/IPV6-Validator.aspx
|
||||
// (specifically from http://download.dartware.com/thirdparty/ipv6validator.js)
|
||||
ipv6Validate : /^\s*((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/i
|
||||
});
|
||||
|
||||
ts.addParser({
|
||||
id: "ipv6Address",
|
||||
is: function(s) {
|
||||
return ts.regex.ipv6Validate.test(s);
|
||||
},
|
||||
format: function(address, table) {
|
||||
// code modified from http://forrst.com/posts/JS_Expand_Abbreviated_IPv6_Addresses-1OR
|
||||
var i, t, sides, groups, groupsPresent,
|
||||
hex = table ? (typeof table === "boolean" ? table : table && table.config.ipv6HexFormat || false) : false,
|
||||
fullAddress = '',
|
||||
expandedAddress = '',
|
||||
validGroupCount = 8,
|
||||
validGroupSize = 4;
|
||||
// remove any extra spaces
|
||||
address = address.replace(/\s*/g, '');
|
||||
// look for embedded ipv4
|
||||
if (ts.regex.ipv4Validate.test(address)) {
|
||||
groups = address.match(ts.regex.ipv4Extract);
|
||||
t = '';
|
||||
for (i = 1; i < groups.length; i++){
|
||||
t += ('00' + (parseInt(groups[i], 10).toString(16)) ).slice(-2) + ( i === 2 ? ':' : '' );
|
||||
}
|
||||
address = address.replace( ts.regex.ipv4Extract, t );
|
||||
}
|
||||
|
||||
if (address.indexOf("::") == -1) {
|
||||
// All eight groups are present
|
||||
fullAddress = address;
|
||||
} else {
|
||||
// Consecutive groups of zeroes have been collapsed with "::".
|
||||
sides = address.split("::");
|
||||
groupsPresent = 0;
|
||||
for (i = 0; i < sides.length; i++) {
|
||||
groupsPresent += sides[i].split(":").length;
|
||||
}
|
||||
fullAddress += sides[0] + ":";
|
||||
for (i = 0; i < validGroupCount - groupsPresent; i++) {
|
||||
fullAddress += "0000:";
|
||||
}
|
||||
fullAddress += sides[1];
|
||||
}
|
||||
groups = fullAddress.split(":");
|
||||
for (i = 0; i < validGroupCount; i++) {
|
||||
// it's fastest & easiest for tablesorter to sort decimal values (vs hex)
|
||||
groups[i] = hex ? ('0000' + groups[i]).slice(-4) :
|
||||
('00000' + (parseInt(groups[i], 16) || 0)).slice(-5);
|
||||
expandedAddress += ( i != validGroupCount-1) ? groups[i] + ':' : groups[i];
|
||||
}
|
||||
return hex ? expandedAddress : expandedAddress.replace(/:/g, '');
|
||||
},
|
||||
// uses natural sort hex compare
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,77 @@
|
||||
/*! Metric parser
|
||||
* Demo: http://jsfiddle.net/Mottie/abkNM/382/
|
||||
* Set the metric name in the header (defaults to "m|meter"), e.g.
|
||||
* <th data-metric-name="b|byte">HDD Size</th>
|
||||
* <th data-metric-name="m|meter">Distance</th>
|
||||
*/
|
||||
/*jshint jquery:true */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
var prefixes = {
|
||||
// "prefix" : [ base 10, base 2 ]
|
||||
// skipping IEEE 1541 defined prefixes: kibibyte, mebibyte, etc, for now.
|
||||
"Y|Yotta|yotta" : [ 1e24, Math.pow(1024, 8) ], // 1024^8
|
||||
"Z|Zetta|zetta" : [ 1e21, Math.pow(1024, 7) ], // 1024^7
|
||||
"E|Exa|exa" : [ 1e18, Math.pow(1024, 6) ], // 1024^6
|
||||
"P|Peta|peta" : [ 1e15, Math.pow(1024, 5) ], // 1024^5
|
||||
"T|Tera|tera" : [ 1e12, Math.pow(1024, 4) ], // 1024^4
|
||||
"G|Giga|giga" : [ 1e9, Math.pow(1024, 3) ], // 1024^3
|
||||
"M|Mega|mega" : [ 1e6, Math.pow(1024, 2) ], // 1024^2
|
||||
"k|Kilo|kilo" : [ 1e3, 1024 ], // 1024
|
||||
// prefixes below here are rarely, if ever, used in binary
|
||||
"h|hecto" : [ 1e2, 1e2 ],
|
||||
"da|deka" : [ 1e1, 1e1 ],
|
||||
"d|deci" : [ 1e-1, 1e-1 ],
|
||||
"c|centi" : [ 1e-2, 1e-2],
|
||||
"m|milli" : [ 1e-3, 1e-3 ],
|
||||
"µ|micro" : [ 1e-6, 1e-6 ],
|
||||
"n|nano" : [ 1e-9, 1e-9 ],
|
||||
"p|pico" : [ 1e-12, 1e-12 ],
|
||||
"f|femto" : [ 1e-15, 1e-15 ],
|
||||
"a|atto" : [ 1e-18, 1e-18 ],
|
||||
"z|zepto" : [ 1e-21, 1e-21 ],
|
||||
"y|yocto" : [ 1e-24, 1e-24 ]
|
||||
},
|
||||
// the \\d+ will not catch digits with spaces, commas or decimals; so use the value from n instead
|
||||
RegLong = "(\\d+)(\\s+)?([Zz]etta|[Ee]xa|[Pp]eta|[Tt]era|[Gg]iga|[Mm]ega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)(",
|
||||
RegAbbr = "(\\d+)(\\s+)?(Z|E|P|T|G|M|k|h|da|d|c|m|µ|n|p|f|a|z|y)(";
|
||||
|
||||
$.tablesorter.addParser({
|
||||
id: 'metric',
|
||||
is: function() {
|
||||
return false;
|
||||
},
|
||||
format: function(s, table, cell, cellIndex) {
|
||||
var v = 'm|meter',
|
||||
b, t,
|
||||
// process number here to get a numerical format (us or eu)
|
||||
n = $.tablesorter.formatFloat(s.replace(/[^\w,. \-()]/g, ""), table),
|
||||
$t = table.config.$headers.filter('[data-column="' + cellIndex + '"]'),
|
||||
m = $t.data('metric');
|
||||
if (!m) {
|
||||
// stored values
|
||||
t = ($t.attr('data-metric-name') || v).split('|');
|
||||
m = [ t[1] || t[0].substring(1), t[0] ];
|
||||
m[2] = new RegExp(RegLong + m[0] + "|" + m[1] + ")");
|
||||
m[3] = new RegExp(RegAbbr + m[1] + ")");
|
||||
$t.data('metric', m);
|
||||
}
|
||||
// find match to full name or abbreviation
|
||||
t = s.match(m[2]) || s.match(m[3]);
|
||||
if (t) {
|
||||
for (v in prefixes) {
|
||||
if (t[3].match(v)) {
|
||||
// exception when using binary prefix
|
||||
// change base for binary use
|
||||
b = /^[b|bit|byte|o|octet]/.test(t[4]) ? 1 : 0;
|
||||
return n * prefixes[v][b];
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
},
|
||||
type: 'numeric'
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
117
modules/EcmReports/TableSorterNew/js/parsers/parser-roman.js
Normal file
117
modules/EcmReports/TableSorterNew/js/parsers/parser-roman.js
Normal file
@@ -0,0 +1,117 @@
|
||||
/*! Roman numeral parsers
|
||||
* code modified from both:
|
||||
* Steven Levithan @ http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter
|
||||
* Jonathan Snook comment @ http://blog.stevenlevithan.com/archives/javascript-roman-numeral-converter#comment-16140
|
||||
*/
|
||||
/*jshint jquery:true, unused:false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
|
||||
// allow lower case roman numerals, since lists use i, ii, iii, etc.
|
||||
var validator = /^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/i,
|
||||
matcher = /\b([MCDLXVI]+\b)/gi,
|
||||
lookup = { I:1, V:5, X:10, L:50, C:100, D:500, M:1000 };
|
||||
|
||||
$.tablesorter.addParser({
|
||||
id: 'roman',
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s) {
|
||||
var val,
|
||||
roman = s.toUpperCase().split(''),
|
||||
num = 0;
|
||||
|
||||
// roman numerals not found!
|
||||
if ( !(s && validator.test(s)) ) {
|
||||
return s;
|
||||
}
|
||||
|
||||
while (roman.length) {
|
||||
val = lookup[roman.shift()];
|
||||
num += val * (val < lookup[roman[0]] ? -1 : 1);
|
||||
}
|
||||
|
||||
return num;
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
$.tablesorter.addParser({
|
||||
id: 'roman-ignore',
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s, table, cell, column) {
|
||||
var val, orig,
|
||||
c = table.config,
|
||||
ignore = $.isArray(c.roman_ignore) ? c.roman_ignore[column] : 0,
|
||||
// find roman numerals
|
||||
roman = ( isNaN(ignore) ?
|
||||
// ignore can be a regex or string
|
||||
$.trim( s.replace(ignore, '') ) :
|
||||
// or a number to ignore the last x letters...
|
||||
$.trim( s.substring(0, s.length - ignore) )
|
||||
).match(matcher),
|
||||
v = validator.test(roman),
|
||||
num = 0;
|
||||
|
||||
// roman numerals not found!
|
||||
if ( !(v) ) {
|
||||
return s;
|
||||
}
|
||||
|
||||
// save roman numeral for replacement
|
||||
orig = roman[0];
|
||||
roman = orig.toUpperCase().split('');
|
||||
|
||||
while (roman.length) {
|
||||
val = lookup[roman.shift()];
|
||||
// ignore non-roman numerals
|
||||
if (val) {
|
||||
num += val * (val < lookup[roman[0]] ? -1 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
return num ? s.replace(orig, num) : s;
|
||||
},
|
||||
type: "text"
|
||||
});
|
||||
|
||||
$.tablesorter.addParser({
|
||||
id: 'roman-extract',
|
||||
is: function(){
|
||||
return false;
|
||||
},
|
||||
format: function(s) {
|
||||
var val,
|
||||
// find roman numerals
|
||||
roman = $.grep(s.split(/\b/), function(v, i){
|
||||
return validator.test(v) ? v : '';
|
||||
}).join('').match(matcher),
|
||||
|
||||
v = roman ? validator.test(roman) : 0,
|
||||
num = 0;
|
||||
|
||||
// roman numerals not found!
|
||||
if ( !(v) ) {
|
||||
return s;
|
||||
}
|
||||
|
||||
// save roman numeral for replacement
|
||||
roman = roman[0].toUpperCase().split('');
|
||||
|
||||
while (roman.length) {
|
||||
val = lookup[roman.shift()];
|
||||
// ignore non-roman numerals
|
||||
if (val) {
|
||||
num += val * (val < lookup[roman[0]] ? -1 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
return num ? num : s;
|
||||
},
|
||||
type: "numeric"
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
957
modules/EcmReports/TableSorterNew/js/widget-scroller.js
Normal file
957
modules/EcmReports/TableSorterNew/js/widget-scroller.js
Normal file
@@ -0,0 +1,957 @@
|
||||
/*! Widget: scroller - updated 4/18/2017 (v2.28.8) *//*
|
||||
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 3/5/2015 (v2.22.2) with lots of help from TheSin-
|
||||
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_jumpToHeader : true, // header snap to browser top when scrolling the tbody
|
||||
scroller_upAfterSort : true, // scroll tbody to top after sorting
|
||||
scroller_fixedColumns : 0 // set number of fixed columns
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Website: www.tconnell.com
|
||||
*/
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
;( function( $, window ) {
|
||||
'use strict';
|
||||
|
||||
var ts = $.tablesorter,
|
||||
tscss = ts.css;
|
||||
|
||||
$.extend( ts.css, {
|
||||
scrollerWrap : 'tablesorter-scroller',
|
||||
scrollerHeader : 'tablesorter-scroller-header',
|
||||
scrollerTable : 'tablesorter-scroller-table',
|
||||
scrollerFooter : 'tablesorter-scroller-footer',
|
||||
scrollerFixed : 'tablesorter-scroller-fixed',
|
||||
scrollerFixedPanel : 'tablesorter-scroller-fixed-panel',
|
||||
scrollerHasFix : 'tablesorter-scroller-has-fixed-columns',
|
||||
scrollerHideColumn : 'tablesorter-scroller-hidden-column',
|
||||
scrollerHideElement : 'tablesorter-scroller-hidden',
|
||||
scrollerSpacerRow : 'tablesorter-scroller-spacer',
|
||||
scrollerBarSpacer : 'tablesorter-scroller-bar-spacer',
|
||||
scrollerAddedHeight : 'tablesorter-scroller-added-height',
|
||||
scrollerHack : 'tablesorter-scroller-scrollbar-hack',
|
||||
// class name on table cannot start with 'tablesorter-' or the
|
||||
// suffix 'scroller-rtl' will match as a theme name
|
||||
scrollerRtl : 'ts-scroller-rtl'
|
||||
});
|
||||
|
||||
ts.addWidget({
|
||||
id : 'scroller',
|
||||
priority : 60, // run after the filter widget
|
||||
options : {
|
||||
scroller_height : 300,
|
||||
// pop table header into view while scrolling up the page
|
||||
scroller_jumpToHeader : true,
|
||||
// scroll tbody to top after sorting
|
||||
scroller_upAfterSort : true,
|
||||
// set number of fixed columns
|
||||
scroller_fixedColumns : 0,
|
||||
// add hover highlighting to the fixed column (disable if it causes slowing)
|
||||
scroller_rowHighlight : 'hover',
|
||||
// add a fixed column overlay for styling
|
||||
scroller_addFixedOverlay : false,
|
||||
// In tablesorter v2.19.0 the scroll bar width is auto-detected
|
||||
// add a value here to override the auto-detected setting
|
||||
scroller_barWidth : null
|
||||
},
|
||||
format : function( table, c, wo ) {
|
||||
if ( c.isScrolling ) {
|
||||
ts.scroller.resize( c, wo );
|
||||
} else {
|
||||
// initialize here instead of in widget init to give the
|
||||
// filter widget time to finish building the filter row
|
||||
ts.scroller.setup( c, wo );
|
||||
}
|
||||
},
|
||||
remove : function( table, c, wo ) {
|
||||
ts.scroller.remove( c, wo );
|
||||
}
|
||||
});
|
||||
|
||||
/* Add window resizeEnd event (also used by columnSelector widget) */
|
||||
ts.window_resize = function() {
|
||||
if ( ts.timer_resize ) {
|
||||
clearTimeout( ts.timer_resize );
|
||||
}
|
||||
ts.timer_resize = setTimeout( function() {
|
||||
$( window ).trigger( 'resizeEnd' );
|
||||
}, 250 );
|
||||
};
|
||||
|
||||
// Add extra scroller css
|
||||
$( function() {
|
||||
var style = '<style>' +
|
||||
/* overall wrapper & table section wrappers */
|
||||
'.' + tscss.scrollerWrap + ' { position: relative; overflow: hidden; }' +
|
||||
/* add border-box sizing to all scroller widget tables; see #135 */
|
||||
'.' + tscss.scrollerWrap + ' * { box-sizing: border-box; }' +
|
||||
'.' + tscss.scrollerHeader + ', .' + tscss.scrollerFooter + ' { position: relative; overflow: hidden; }' +
|
||||
'.' + tscss.scrollerHeader + ' table.' + tscss.table + ' { margin-bottom: 0; }' +
|
||||
/* always leave the scroll bar visible for tbody, or table overflows into the scrollbar
|
||||
when height < max height (filtering) */
|
||||
'.' + tscss.scrollerTable + ' { position: relative; overflow: auto; }' +
|
||||
'.' + tscss.scrollerTable + ' table.' + tscss.table +
|
||||
' { border-top: 0; margin-top: 0; margin-bottom: 0; overflow: hidden; max-width: initial; }' +
|
||||
/* hide footer in original table */
|
||||
'.' + tscss.scrollerTable + ' tfoot, .' + tscss.scrollerHideElement + ', .' + tscss.scrollerHideColumn +
|
||||
' { display: none; }' +
|
||||
|
||||
/*** fixed column ***/
|
||||
/* disable pointer-events on fixed column wrapper or the user can't interact with the horizontal scrollbar */
|
||||
'.' + tscss.scrollerFixed + ', .' + tscss.scrollerFixed + ' .' + tscss.scrollerFixedPanel +
|
||||
' { pointer-events: none; }' +
|
||||
/* enable pointer-events for fixed column children; see #135 & #878 */
|
||||
'.' + tscss.scrollerFixed + ' > div { pointer-events: all; }' +
|
||||
'.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixed + ' { position: absolute; top: 0; z-index: 1; left: 0 } ' +
|
||||
'.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixed + '.' + tscss.scrollerRtl + ' { left: auto; right: 0 } ' +
|
||||
/* add horizontal scroll bar; set to 'auto', see #135 */
|
||||
'.' + tscss.scrollerWrap + '.' + tscss.scrollerHasFix + ' > .' + tscss.scrollerTable + ' { overflow: auto; }' +
|
||||
/* need to position the tbody & tfoot absolutely to hide the scrollbar & move the footer
|
||||
below the horizontal scrollbar */
|
||||
'.' + tscss.scrollerFixed + ' .' + tscss.scrollerFooter + ' { position: absolute; bottom: 0; }' +
|
||||
/* hide fixed tbody scrollbar - see http://goo.gl/VsLe6n - set overflow to auto here for mousewheel scroll */
|
||||
'.' + tscss.scrollerFixed + ' .' + tscss.scrollerTable +
|
||||
' { position: relative; left: 0; overflow: auto; -ms-overflow-style: none; }' +
|
||||
'.' + tscss.scrollerFixed + ' .' + tscss.scrollerTable + '::-webkit-scrollbar { display: none; }' +
|
||||
/*** fixed column panel ***/
|
||||
'.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixedPanel +
|
||||
' { position: absolute; top: 0; bottom: 0; z-index: 2; left: 0; right: 0; } ' +
|
||||
'</style>';
|
||||
$( 'head' ).append( style );
|
||||
});
|
||||
|
||||
ts.scroller = {
|
||||
|
||||
// Ugh.. Firefox misbehaves, so it needs to be detected
|
||||
isFirefox : navigator.userAgent.toLowerCase().indexOf( 'firefox' ) > -1,
|
||||
// old IE needs a wrap to hide the fixed column scrollbar; http://stackoverflow.com/a/24408672/145346
|
||||
isOldIE : document.all && !window.atob,
|
||||
isIE : ( document.all && !window.atob ) || navigator.appVersion.indexOf( 'Trident/' ) > 0,
|
||||
// http://stackoverflow.com/questions/7944460/detect-safari-browser - needed to position scrolling body
|
||||
// when the table is set up in RTL direction
|
||||
isSafari : navigator.userAgent.toLowerCase().indexOf( 'safari' ) > -1 &&
|
||||
navigator.userAgent.toLowerCase().indexOf( 'chrome' ) === -1,
|
||||
|
||||
hasScrollBar : function( $target, checkWidth ) {
|
||||
if ( checkWidth ) {
|
||||
return $target.get(0).scrollWidth > $target.width();
|
||||
} else {
|
||||
return $target.get(0).scrollHeight > $target.height();
|
||||
}
|
||||
},
|
||||
|
||||
setWidth : function( $el, width ) {
|
||||
$el.css({
|
||||
'width' : width,
|
||||
'min-width' : width,
|
||||
'max-width' : width
|
||||
});
|
||||
},
|
||||
|
||||
// modified from http://davidwalsh.name/detect-scrollbar-width
|
||||
getBarWidth : function() {
|
||||
var $div = $( '<div>' ).css({
|
||||
'position' : 'absolute',
|
||||
'top' : '-9999px',
|
||||
'left' : 0,
|
||||
'width' : '100px',
|
||||
'height' : '100px',
|
||||
'overflow' : 'scroll',
|
||||
'visibility' : 'hidden'
|
||||
}).appendTo( 'body' ),
|
||||
div = $div[0],
|
||||
barWidth = div.offsetWidth - div.clientWidth;
|
||||
$div.remove();
|
||||
return barWidth;
|
||||
},
|
||||
|
||||
setup : function( c, wo ) {
|
||||
var tbHt, $hdr, $t, $hCells, $fCells, $tableWrap, events, tmp, detectedWidth,
|
||||
$win = $( window ),
|
||||
tsScroller = ts.scroller,
|
||||
namespace = c.namespace + 'tsscroller',
|
||||
$foot = $(),
|
||||
// c.namespace contains a unique tablesorter ID, per table
|
||||
id = c.namespace.slice( 1 ) + 'tsscroller',
|
||||
$table = c.$table;
|
||||
|
||||
// force config.widthFixed option - this helps maintain proper alignment across cloned tables
|
||||
c.widthFixed = true;
|
||||
|
||||
wo.scroller_calcWidths = [];
|
||||
wo.scroller_saved = [ 0, 0 ];
|
||||
wo.scroller_isBusy = true;
|
||||
|
||||
// set scrollbar width to one of the following (1) explicitly set scroller_barWidth option,
|
||||
// (2) detected scrollbar width or (3) fallback of 15px
|
||||
if ( wo.scroller_barWidth !== null ) {
|
||||
wo.scroller_barSetWidth = wo.scroller_barWidth;
|
||||
} else {
|
||||
detectedWidth = tsScroller.getBarWidth();
|
||||
wo.scroller_barSetWidth = detectedWidth !== null ? detectedWidth : 15;
|
||||
}
|
||||
|
||||
tmp = $table.children( 'caption' );
|
||||
|
||||
$hdr = $( '<table class="' + $table.attr( 'class' ) + '" cellpadding=0 cellspacing=0>' +
|
||||
( tmp.length ? tmp[ 0 ].outerHTML : '' ) +
|
||||
$table.children( 'thead' )[ 0 ].outerHTML + '</table>' );
|
||||
wo.scroller_$header = $hdr.addClass( c.namespace.slice( 1 ) + '_extra_table' );
|
||||
|
||||
$t = $table.children( 'tfoot' );
|
||||
if ( $t.length ) {
|
||||
$foot = $( '<table class="' + $table.attr( 'class' ) +
|
||||
'" cellpadding=0 cellspacing=0 style="margin-top:0"></table>' )
|
||||
.addClass( c.namespace.slice( 1 ) + '_extra_table' )
|
||||
// maintain any bindings on the tfoot cells
|
||||
.append( $t.clone( true ) )
|
||||
.wrap( '<div class="' + tscss.scrollerFooter + '"/>' );
|
||||
$fCells = $foot.children( 'tfoot' ).eq( 0 ).children( 'tr' ).children();
|
||||
}
|
||||
wo.scroller_$footer = $foot;
|
||||
|
||||
$table
|
||||
.wrap( '<div id="' + id + '" class="' + tscss.scrollerWrap + '" />' )
|
||||
.before( $hdr )
|
||||
// shrink filter row but don't completely hide it because the inputs/selectors may distort the columns
|
||||
.find( '.' + tscss.filterRow )
|
||||
.addClass( tscss.filterRowHide );
|
||||
|
||||
wo.scroller_$container = $table.parent();
|
||||
|
||||
if ( $foot.length ) {
|
||||
// $foot.parent() to include <div> wrapper
|
||||
$table.after( $foot.parent() );
|
||||
}
|
||||
|
||||
$hCells = $hdr
|
||||
.wrap( '<div class="' + tscss.scrollerHeader + '" />' )
|
||||
.find( '.' + tscss.header );
|
||||
|
||||
// if max-height is greater than 0 use max-height, so the height resizes dynamically while filtering
|
||||
// else let the table not have a vertical scroll
|
||||
$table.wrap( '<div class="' + tscss.scrollerTable +
|
||||
( wo.scroller_height > 0 ? '" style="max-height:' + wo.scroller_height + 'px;">' : '">' ) );
|
||||
$tableWrap = $table.parent();
|
||||
|
||||
// make scroller header sortable
|
||||
ts.bindEvents( c.table, $hCells );
|
||||
|
||||
// look for filter widget
|
||||
if ( $table.hasClass( 'hasFilters' ) ) {
|
||||
ts.filter.bindSearch( $table, $hdr.find( '.' + tscss.filter ) );
|
||||
}
|
||||
|
||||
$table
|
||||
.children( 'thead, caption' )
|
||||
.addClass( tscss.scrollerHideElement );
|
||||
tbHt = $tableWrap.parent().height();
|
||||
|
||||
// The header will always jump into view if scrolling the table body
|
||||
$tableWrap
|
||||
.off( 'scroll' + namespace )
|
||||
.on( 'scroll' + namespace, function() {
|
||||
if ( wo.scroller_jumpToHeader ) {
|
||||
var pos = $win.scrollTop() - $hdr.offset().top;
|
||||
if ( $( this ).scrollTop() !== 0 && pos < tbHt && pos > 0 ) {
|
||||
$win.scrollTop( $hdr.offset().top );
|
||||
}
|
||||
}
|
||||
$hdr
|
||||
.parent()
|
||||
.add( $foot.parent() )
|
||||
.scrollLeft( $( this ).scrollLeft() );
|
||||
});
|
||||
|
||||
// resize/update events - filterEnd fires after "tablesorter-initialized" and "updateComplete"
|
||||
events = ( ( ts.hasWidget( c.table, 'filter' ) ? 'filterEnd' : 'tablesorter-initialized updateComplete' ) +
|
||||
' sortEnd pagerComplete columnUpdate ' ).split( ' ' ).join( namespace + ' ' );
|
||||
|
||||
$table
|
||||
.off( namespace )
|
||||
.on( 'sortEnd filterEnd'.split( ' ' ).join( namespace + ' ' ), function( event ) {
|
||||
// Sorting, so scroll to top
|
||||
if ( event.type === 'sortEnd' && wo.scroller_upAfterSort ) {
|
||||
$tableWrap.animate({
|
||||
scrollTop : 0
|
||||
}, 'fast' );
|
||||
} else if ( wo.scroller_fixedColumns ) {
|
||||
setTimeout( function() {
|
||||
// restore previous scroll position
|
||||
$tableWrap
|
||||
.scrollTop( wo.scroller_saved[1] )
|
||||
.scrollLeft( wo.scroller_saved[0] );
|
||||
tsScroller.updateFixed( c, wo );
|
||||
}, 0 );
|
||||
}
|
||||
})
|
||||
.on( 'setFixedColumnSize' + namespace, function( event, size ) {
|
||||
var $wrap = wo.scroller_$container;
|
||||
if ( typeof size !== 'undefined' && !isNaN( size ) ) {
|
||||
wo.scroller_fixedColumns = parseInt( size, 10 );
|
||||
}
|
||||
// remove fixed columns
|
||||
tsScroller.removeFixed( c, wo );
|
||||
size = wo.scroller_fixedColumns;
|
||||
if ( size > 0 && size < c.columns - 1 ) {
|
||||
tsScroller.updateFixed( c, wo );
|
||||
} else if ( $wrap.hasClass( tscss.scrollerHasFix ) ) {
|
||||
$wrap.removeClass( tscss.scrollerHasFix );
|
||||
// resize needed to make tables full width
|
||||
tsScroller.resize( c, wo );
|
||||
}
|
||||
})
|
||||
.on( events, function( event ) {
|
||||
// Stop from running twice with pager
|
||||
if ( ts.hasWidget( 'pager' ) && event.type === 'updateComplete' ) {
|
||||
return;
|
||||
}
|
||||
if ( wo.scroller_fixedColumns > 0 ) {
|
||||
tsScroller.updateFixed( c, wo );
|
||||
}
|
||||
// adjust column sizes after an update
|
||||
tsScroller.resize( c, wo );
|
||||
});
|
||||
|
||||
// Setup window.resizeEnd event
|
||||
$win
|
||||
.off( 'resize resizeEnd '.split( ' ' ).join( namespace + ' ' ) )
|
||||
.on( 'resize' + namespace, ts.window_resize )
|
||||
.on( 'resizeEnd' + namespace, 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.off( 'resize' + namespace, ts.window_resize );
|
||||
tsScroller.resize( c, wo );
|
||||
$win.on( 'resize' + namespace, ts.window_resize );
|
||||
$tableWrap.trigger( 'scroll' + namespace );
|
||||
});
|
||||
|
||||
// initialization flag
|
||||
c.isScrolling = true;
|
||||
|
||||
tsScroller.updateFixed( c, wo );
|
||||
|
||||
// updateAll called - need to give the browser time to adjust the layout
|
||||
// before calculating fix column widths
|
||||
if ( c.table.hasInitialized && c.isScrolling ) {
|
||||
setTimeout(function(){
|
||||
ts.scroller.resize( c, wo );
|
||||
}, 50);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
resize : function( c, wo ) {
|
||||
if ( wo.scroller_isBusy ) { return; }
|
||||
var index, borderWidth, setWidth, $headers, $this,
|
||||
tsScroller = ts.scroller,
|
||||
$container = wo.scroller_$container,
|
||||
$table = c.$table,
|
||||
$tableWrap = $table.parent(),
|
||||
$hdr = wo.scroller_$header,
|
||||
$foot = wo.scroller_$footer,
|
||||
$win = $(window),
|
||||
position = [ $win.scrollLeft(), $win.scrollTop() ],
|
||||
id = c.namespace.slice( 1 ) + 'tsscroller',
|
||||
// Hide other scrollers so we can resize
|
||||
$div = $( 'div.' + tscss.scrollerWrap + '[id!="' + id + '"]' )
|
||||
.addClass( tscss.scrollerHideElement ),
|
||||
temp = 'padding:0;margin:0;border:0;height:0;max-height:0;min-height:0;',
|
||||
row = '<tr class="' + tscss.scrollerSpacerRow + ' ' + c.selectorRemove.slice(1) +
|
||||
'" style="' + temp + '">';
|
||||
|
||||
wo.scroller_calcWidths = [];
|
||||
|
||||
// Remove fixed so we get proper widths and heights
|
||||
tsScroller.removeFixed( c, wo );
|
||||
$container.find( '.' + tscss.scrollerSpacerRow ).remove();
|
||||
// remove ts added colgroups
|
||||
$container.find( '.' + ts.css.colgroup ).remove();
|
||||
|
||||
// show original table elements to get proper alignment
|
||||
$table
|
||||
.find( '.' + tscss.scrollerHideElement )
|
||||
.removeClass( tscss.scrollerHideElement );
|
||||
|
||||
// include left & right border widths
|
||||
borderWidth = parseInt( $table.css( 'border-left-width' ), 10 );
|
||||
|
||||
$headers = c.$headerIndexed;
|
||||
|
||||
for ( index = 0; index < c.columns; index++ ) {
|
||||
$this = $headers[ index ];
|
||||
// code from https://github.com/jmosbech/StickyTableHeaders
|
||||
if ( $this.css( 'box-sizing' ) === 'border-box' ) {
|
||||
setWidth = $this.outerWidth();
|
||||
} else {
|
||||
if ( $this.css( 'border-collapse' ) === 'collapse' ) {
|
||||
if ( $this.length && window.getComputedStyle ) {
|
||||
setWidth = parseFloat( window.getComputedStyle( $this[ 0 ], null ).width );
|
||||
} else {
|
||||
// ie8 only
|
||||
setWidth = $this.outerWidth() - parseFloat( $this.css( 'padding-left' ) ) -
|
||||
parseFloat( $this.css( 'padding-right' ) ) -
|
||||
( parseFloat( $this.css( 'border-width' ) ) || 0 );
|
||||
}
|
||||
} else {
|
||||
setWidth = $this.width();
|
||||
}
|
||||
}
|
||||
row += '<td data-column="' + index + '" style="' + temp + 'width:' + setWidth +
|
||||
'px;min-width:' + setWidth + 'px;max-width:' + setWidth + 'px"></td>';
|
||||
|
||||
// save current widths
|
||||
wo.scroller_calcWidths[ index ] = setWidth;
|
||||
}
|
||||
row += '</tr>';
|
||||
c.$tbodies.eq(0).append( row ); // tbody
|
||||
$hdr.children( 'thead' ).append( row );
|
||||
$foot.children( 'tfoot' ).append( row );
|
||||
|
||||
// include colgroup or alignment is off
|
||||
ts.fixColumnWidth( c.table );
|
||||
row = c.$table.children( 'colgroup' )[0].outerHTML;
|
||||
$hdr.append( row );
|
||||
$foot.append( row );
|
||||
|
||||
temp = $tableWrap.parent().innerWidth() -
|
||||
( tsScroller.hasScrollBar( $tableWrap ) ? wo.scroller_barSetWidth : 0 );
|
||||
$tableWrap.width( temp );
|
||||
|
||||
temp = ( tsScroller.hasScrollBar( $tableWrap ) ? wo.scroller_barSetWidth : 0 ) + borderWidth;
|
||||
setWidth = $tableWrap.innerWidth() - temp;
|
||||
|
||||
$hdr
|
||||
.parent()
|
||||
.add( $foot.parent() )
|
||||
.width( setWidth );
|
||||
|
||||
$tableWrap
|
||||
.width( setWidth + temp );
|
||||
|
||||
// hide original table thead
|
||||
$table.children( 'thead, caption' ).addClass( tscss.scrollerHideElement );
|
||||
|
||||
// update fixed column sizes
|
||||
tsScroller.updateFixed( c, wo );
|
||||
|
||||
$div.removeClass( tscss.scrollerHideElement );
|
||||
|
||||
// restore scrollTop - fixes #926
|
||||
$tableWrap.scrollTop( wo.scroller_saved[1] );
|
||||
wo.scroller_$container
|
||||
.find( '.' + tscss.scrollerFixed )
|
||||
.find( '.' + tscss.scrollerTable )
|
||||
.scrollTop( wo.scroller_saved[1] );
|
||||
$win.scrollLeft( position[0] );
|
||||
$win.scrollTop( position[1] );
|
||||
|
||||
// update resizable widget handles
|
||||
setTimeout( function() {
|
||||
c.$table.triggerHandler( 'resizableUpdate' );
|
||||
c.$table.triggerHandler( 'scrollerComplete' );
|
||||
}, 100 );
|
||||
|
||||
},
|
||||
|
||||
// Add fixed (frozen) columns (Do not call directly, use updateFixed)
|
||||
setupFixed : function( c, wo ) {
|
||||
var index, index2, $el, len, temp, $fixedColumn, $fixedTbody,
|
||||
$table = c.$table,
|
||||
$wrapper = wo.scroller_$container,
|
||||
fixedColumns = wo.scroller_fixedColumns;
|
||||
|
||||
$fixedColumn = $wrapper
|
||||
.addClass( tscss.scrollerHasFix )
|
||||
.clone()
|
||||
.addClass( tscss.scrollerFixed )
|
||||
.removeClass( tscss.scrollerWrap )
|
||||
.attr( 'id', '' );
|
||||
|
||||
$fixedColumn.find('caption').html(' ');
|
||||
|
||||
if ( wo.scroller_addFixedOverlay ) {
|
||||
$fixedColumn.append( '<div class="' + tscss.scrollerFixedPanel + '">' );
|
||||
}
|
||||
|
||||
$fixedTbody = $fixedColumn.find( '.' + tscss.scrollerTable );
|
||||
$fixedTbody
|
||||
.children( 'table' )
|
||||
.addClass( c.namespace.slice( 1 ) + '_extra_table' )
|
||||
.attr( 'id', '' )
|
||||
.children( 'thead, tfoot' )
|
||||
.remove();
|
||||
|
||||
wo.scroller_$fixedColumns = $fixedColumn;
|
||||
|
||||
// RTL support (fixes column on right)
|
||||
if ( $table.hasClass( tscss.scrollerRtl ) ) {
|
||||
$fixedColumn.addClass( tscss.scrollerRtl );
|
||||
}
|
||||
|
||||
$el = $fixedColumn.find( 'tr' );
|
||||
len = $el.length;
|
||||
for ( index = 0; index < len; index++ ) {
|
||||
$el.eq( index ).children( ':gt(' + ( fixedColumns - 1 ) + ')' ).remove();
|
||||
}
|
||||
$fixedColumn
|
||||
.addClass( tscss.scrollerHideElement )
|
||||
.prependTo( $wrapper );
|
||||
|
||||
// look for filter widget
|
||||
if ( c.$table.hasClass( 'hasFilters' ) ) {
|
||||
// make sure fixed column filters aren't disabled
|
||||
$el = $fixedColumn
|
||||
.find( '.' + tscss.filter )
|
||||
.not( '.' + tscss.filterDisabled )
|
||||
.prop( 'disabled', false );
|
||||
ts.filter.bindSearch( $table, $fixedColumn.find( '.' + tscss.filter ) );
|
||||
// disable/enable filters behind fixed column
|
||||
$el = $wrapper
|
||||
.children( '.' + tscss.scrollerHeader )
|
||||
.find( '.' + tscss.filter );
|
||||
len = $el.length;
|
||||
for ( index = 0; index < len; index++ ) {
|
||||
// previously disabled filter; don't mess with it! filterDisabled class added by filter widget
|
||||
if ( !$el.eq( index ).hasClass( tscss.filterDisabled || 'disabled' ) ) {
|
||||
// disable filters behind fixed column; don't disable visible filters
|
||||
$el.eq( index ).prop( 'disabled', index < fixedColumns );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// disable/enable tab indexes behind fixed column
|
||||
c.$table
|
||||
.add( '.' + tscss.scrollerFooter + ' table' )
|
||||
.children( 'thead' )
|
||||
.children( 'tr.' + tscss.headerRow )
|
||||
.children()
|
||||
.attr( 'tabindex', -1 );
|
||||
|
||||
$el = wo.scroller_$header
|
||||
.add( $fixedColumn.find( '.' + tscss.scrollerTable + ' table' ) )
|
||||
.children( 'thead' )
|
||||
.children( 'tr.' + tscss.headerRow );
|
||||
len = $el.length;
|
||||
for ( index = 0; index < len; index++ ) {
|
||||
temp = $el.eq( index ).children();
|
||||
for ( index2 = 0; index2 < temp.length; index2++ ) {
|
||||
temp.eq( index2 ).attr( 'tabindex', index2 < fixedColumns ? -1 : 0 );
|
||||
}
|
||||
}
|
||||
|
||||
ts.bindEvents( c.table, $fixedColumn.find( '.' + tscss.header ) );
|
||||
ts.scroller.bindFixedColumnEvents( c, wo );
|
||||
|
||||
/*** Scrollbar hack! Since we can't hide the scrollbar with css ***/
|
||||
if ( ts.scroller.isFirefox || ts.scroller.isOldIE ) {
|
||||
$fixedTbody.wrap( '<div class="' + tscss.scrollerHack + '" style="overflow:hidden;">' );
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// https://remysharp.com/2010/07/21/throttling-function-calls
|
||||
throttle : function(fn, threshhold, scope) {
|
||||
threshhold = threshhold || 50;
|
||||
var last, deferTimer;
|
||||
return function() {
|
||||
var context = scope || this,
|
||||
now = +(new Date()),
|
||||
args = arguments;
|
||||
if (last && now < last + threshhold) {
|
||||
// hold on to it
|
||||
clearTimeout(deferTimer);
|
||||
deferTimer = setTimeout(function() {
|
||||
last = now;
|
||||
fn.apply(context, args);
|
||||
}, threshhold);
|
||||
} else {
|
||||
last = now;
|
||||
fn.apply(context, args);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
bindFixedColumnEvents : function( c, wo ) {
|
||||
// update thead & tbody in fixed column
|
||||
var tsScroller = ts.scroller,
|
||||
namespace = c.namespace + 'tsscrollerFixed',
|
||||
events = 'scroll' + namespace,
|
||||
$fixedTbody = wo.scroller_$fixedColumns.find( '.' + tscss.scrollerTable ),
|
||||
fixedScroll = true,
|
||||
tableScroll = true;
|
||||
|
||||
c.$table
|
||||
.parent()
|
||||
// *** SCROLL *** scroll fixed column along with main
|
||||
.off( events )
|
||||
.on( events, tsScroller.throttle(function() {
|
||||
// using flags to prevent firing the scroll event excessively leading to slow scrolling in Firefox
|
||||
if ( !wo.scroller_isBusy && fixedScroll ) {
|
||||
tableScroll = false;
|
||||
var $this = $( this );
|
||||
$fixedTbody[0].scrollTop = wo.scroller_saved[1] = $this.scrollTop();
|
||||
wo.scroller_saved[0] = $this.scrollLeft();
|
||||
setTimeout( function() {
|
||||
tableScroll = true;
|
||||
}, 20 );
|
||||
}
|
||||
}));
|
||||
// scroll main along with fixed column
|
||||
$fixedTbody
|
||||
.off( events )
|
||||
.on( events, tsScroller.throttle(function() {
|
||||
// using flags to prevent firing the scroll event excessively leading to slow scrolling in Firefox
|
||||
if ( !wo.scroller_isBusy && tableScroll ) {
|
||||
fixedScroll = false;
|
||||
c.$table.parent()[0].scrollTop = wo.scroller_saved[1] = $( this ).scrollTop();
|
||||
setTimeout( function() {
|
||||
fixedScroll = true;
|
||||
}, 20 );
|
||||
}
|
||||
}))
|
||||
.scroll();
|
||||
|
||||
// *** ROW HIGHLIGHT ***
|
||||
if ( wo.scroller_rowHighlight !== '' ) {
|
||||
events = 'mouseover mouseleave '.split( ' ' ).join( namespace + ' ' );
|
||||
// can't use c.$tbodies because it doesn't include info-only tbodies
|
||||
c.$table
|
||||
.off( events, 'tbody > tr' )
|
||||
.on( events, 'tbody > tr', function( event ) {
|
||||
var indx = c.$table.children( 'tbody' ).children( 'tr' ).index( this );
|
||||
$fixedTbody
|
||||
.children( 'table' )
|
||||
.children( 'tbody' )
|
||||
.children( 'tr' )
|
||||
.eq( indx )
|
||||
.add( this )
|
||||
.toggleClass( wo.scroller_rowHighlight, event.type === 'mouseover' );
|
||||
});
|
||||
$fixedTbody
|
||||
.find( 'table' )
|
||||
.off( events, 'tbody > tr' )
|
||||
.on( events, 'tbody > tr', function( event ) {
|
||||
var $fixed = $fixedTbody.children( 'table' ).children( 'tbody' ).children( 'tr' ),
|
||||
indx = $fixed.index( this );
|
||||
c.$table
|
||||
.children( 'tbody' )
|
||||
.children( 'tr' )
|
||||
.eq( indx )
|
||||
.add( this )
|
||||
.toggleClass( wo.scroller_rowHighlight, event.type === 'mouseover' );
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
adjustWidth : function( c, wo, totalWidth, adj, dir ) {
|
||||
var $wrapper = wo.scroller_$container;
|
||||
|
||||
// RTL support (fixes column on right)
|
||||
$wrapper
|
||||
.children( '.' + tscss.scrollerTable )
|
||||
.css( dir ? 'right' : 'left', totalWidth );
|
||||
$wrapper
|
||||
.children( '.' + tscss.scrollerHeader + ', .' + tscss.scrollerFooter )
|
||||
// Safari needs a scrollbar width of extra adjusment to align the fixed & scrolling columns
|
||||
.css( dir ? 'right' : 'left', totalWidth + ( dir && ts.scroller.isSafari ? adj : 0 ) );
|
||||
},
|
||||
|
||||
updateFixed : function( c, wo ) {
|
||||
var temp, adj,
|
||||
$wrapper = wo.scroller_$container,
|
||||
$hdr = wo.scroller_$header,
|
||||
$foot = wo.scroller_$footer,
|
||||
$table = c.$table,
|
||||
$tableWrap = $table.parent(),
|
||||
scrollBarWidth = wo.scroller_barSetWidth,
|
||||
dir = $table.hasClass( tscss.scrollerRtl );
|
||||
|
||||
if ( wo.scroller_fixedColumns === 0 ) {
|
||||
wo.scroller_isBusy = false;
|
||||
ts.scroller.removeFixed( c, wo );
|
||||
temp = $wrapper.width();
|
||||
$tableWrap.width( temp );
|
||||
adj = ts.scroller.hasScrollBar( $tableWrap ) ? scrollBarWidth : 0;
|
||||
$hdr
|
||||
.parent()
|
||||
.add( $foot.parent() )
|
||||
.width( temp - adj );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !c.isScrolling ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wo.scroller_isBusy = true;
|
||||
|
||||
// Make sure the wo.scroller_$fixedColumns container exists, if not build it
|
||||
if ( !$wrapper.find( '.' + tscss.scrollerFixed ).length ) {
|
||||
ts.scroller.setupFixed( c, wo );
|
||||
}
|
||||
|
||||
// scroller_fixedColumns
|
||||
var index, tbodyIndex, rowIndex, $tbody, $adjCol, $fb, totalRows,
|
||||
|
||||
// source cells for measurement
|
||||
$mainTbodies = wo.scroller_$container
|
||||
.children( '.' + tscss.scrollerTable )
|
||||
.children( 'table' )
|
||||
.children( 'tbody' ),
|
||||
// variable gets redefined
|
||||
$rows = wo.scroller_$header
|
||||
.children( 'thead' )
|
||||
.children( '.' + tscss.headerRow ),
|
||||
|
||||
// hide fixed column during resize, or we get a FOUC
|
||||
$fixedColumn = wo.scroller_$fixedColumns
|
||||
.addClass( tscss.scrollerHideElement ),
|
||||
|
||||
// target cells
|
||||
$fixedTbodiesTable = $fixedColumn
|
||||
.find( '.' + tscss.scrollerTable )
|
||||
.children( 'table' ),
|
||||
$fixedTbodies = $fixedTbodiesTable
|
||||
.children( 'tbody' ),
|
||||
// variables
|
||||
tsScroller = ts.scroller,
|
||||
fixedColumns = wo.scroller_fixedColumns,
|
||||
// get dimensions
|
||||
$temp = $table.find( 'tbody td' ),
|
||||
borderRightWidth = parseInt( $temp.css( 'border-right-width' ), 10 ) || 1,
|
||||
borderSpacing = parseInt( ( $temp.css( 'border-spacing' ) || '' ).split( /\s/ )[ 0 ], 10 ) / 2 || 0,
|
||||
totalWidth = parseInt( $table.css( 'padding-left' ), 10 ) +
|
||||
parseInt( $table.css( 'padding-right' ), 10 ) -
|
||||
borderRightWidth,
|
||||
widths = wo.scroller_calcWidths;
|
||||
|
||||
ts.scroller.removeFixed( c, wo, false );
|
||||
|
||||
// calculate fixed column width
|
||||
for ( index = 0; index < fixedColumns; index++ ) {
|
||||
totalWidth += widths[ index ] + borderSpacing;
|
||||
}
|
||||
|
||||
// set fixed column width
|
||||
totalWidth = totalWidth + borderRightWidth * 2 - borderSpacing;
|
||||
tsScroller.setWidth( $fixedColumn.add( $fixedColumn.children() ), totalWidth );
|
||||
tsScroller.setWidth( $fixedColumn.children().children( 'table' ), totalWidth );
|
||||
|
||||
// update fixed column tbody content, set cell widths on hidden row
|
||||
for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
|
||||
$tbody = $mainTbodies.eq( tbodyIndex );
|
||||
if ( $tbody.length ) {
|
||||
// get tbody
|
||||
$rows = $tbody.children();
|
||||
totalRows = $rows.length;
|
||||
$fb = ts.processTbody( $fixedTbodiesTable, $fixedTbodies.eq( tbodyIndex ), true );
|
||||
$fb.empty();
|
||||
// update tbody cells after sort/filtering
|
||||
for ( rowIndex = 0; rowIndex < totalRows; rowIndex++ ) {
|
||||
$adjCol = $( $rows[ rowIndex ].outerHTML );
|
||||
$adjCol
|
||||
.children( 'td, th' )
|
||||
.slice( fixedColumns )
|
||||
.remove();
|
||||
$fb.append( $adjCol );
|
||||
}
|
||||
|
||||
// restore tbody
|
||||
ts.processTbody( $fixedTbodiesTable, $fb, false );
|
||||
}
|
||||
}
|
||||
|
||||
adj = ts.scroller.hasScrollBar( $tableWrap ) ? scrollBarWidth : 0;
|
||||
|
||||
/*** scrollbar HACK! Since we can't hide the scrollbar with css ***/
|
||||
if ( tsScroller.isFirefox || tsScroller.isOldIE ) {
|
||||
$fixedTbodiesTable
|
||||
.css( 'width', totalWidth )
|
||||
.parent()
|
||||
.css( 'width', totalWidth + adj );
|
||||
}
|
||||
|
||||
$fixedColumn.removeClass( tscss.scrollerHideElement );
|
||||
for ( index = 0; index < fixedColumns; index++ ) {
|
||||
temp = ':nth-child(' + ( index + 1 ) + ')';
|
||||
$wrapper
|
||||
.children( 'div' )
|
||||
.children( 'table' )
|
||||
.find( 'th' + temp + ', td' + temp + ', col' + temp )
|
||||
.addClass( tscss.scrollerHideColumn );
|
||||
}
|
||||
|
||||
totalWidth = totalWidth - borderRightWidth;
|
||||
temp = $tableWrap.parent().innerWidth() - totalWidth;
|
||||
$tableWrap.width( temp );
|
||||
// RTL support (fixes column on right)
|
||||
$wrapper
|
||||
.children( '.' + tscss.scrollerTable )
|
||||
.css( dir ? 'right' : 'left', totalWidth );
|
||||
$wrapper
|
||||
.children( '.' + tscss.scrollerHeader + ', .' + tscss.scrollerFooter )
|
||||
// Safari needs a scrollbar width of extra adjusment to align the fixed & scrolling columns
|
||||
.css( dir ? 'right' : 'left', totalWidth + ( dir && ts.scroller.isSafari ? adj : 0 ) );
|
||||
|
||||
$hdr
|
||||
.parent()
|
||||
.add( $foot.parent() )
|
||||
.width( temp - adj );
|
||||
|
||||
// fix gap under the tbody for the horizontal scrollbar
|
||||
temp = ts.scroller.hasScrollBar( $tableWrap, true );
|
||||
adj = temp ? scrollBarWidth : 0;
|
||||
if ( !$fixedColumn.find( '.' + tscss.scrollerBarSpacer ).length && temp ) {
|
||||
$temp = $( '<div class="' + tscss.scrollerBarSpacer + '">' )
|
||||
.css( 'height', adj + 'px' );
|
||||
$fixedColumn.find( '.' + tscss.scrollerTable ).append( $temp );
|
||||
} else if ( !temp ) {
|
||||
$fixedColumn.find( '.' + tscss.scrollerBarSpacer ).remove();
|
||||
}
|
||||
|
||||
ts.scroller.updateRowHeight( c, wo );
|
||||
// set fixed column height (changes with filtering)
|
||||
$fixedColumn.height( $wrapper.height() );
|
||||
|
||||
$fixedColumn.removeClass( tscss.scrollerHideElement );
|
||||
|
||||
// adjust caption height, see #1202
|
||||
$fixedColumn.find('caption').height( wo.scroller_$header.find( 'caption' ).height() );
|
||||
|
||||
wo.scroller_isBusy = false;
|
||||
|
||||
},
|
||||
|
||||
fixHeight : function( $rows, $fixedRows ) {
|
||||
var index, heightRow, heightFixed, $r, $f,
|
||||
addedHt = tscss.scrollerAddedHeight,
|
||||
len = $rows.length;
|
||||
for ( index = 0; index < len; index++ ) {
|
||||
$r = $rows.eq( index );
|
||||
$f = $fixedRows.eq( index );
|
||||
heightRow = $r.height();
|
||||
heightFixed = $f.height();
|
||||
if ( heightRow > heightFixed ) {
|
||||
$f.addClass( addedHt ).height( heightRow );
|
||||
} else if ( heightRow < heightFixed ) {
|
||||
$r.addClass( addedHt ).height( heightFixed );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateRowHeight : function( c, wo ) {
|
||||
var $rows, $fixed,
|
||||
$fixedColumns = wo.scroller_$fixedColumns;
|
||||
|
||||
wo.scroller_$container
|
||||
.find( '.' + tscss.scrollerAddedHeight )
|
||||
.removeClass( tscss.scrollerAddedHeight )
|
||||
.height( '' );
|
||||
|
||||
$rows = wo.scroller_$header
|
||||
.children( 'thead' )
|
||||
.children( 'tr' );
|
||||
$fixed = $fixedColumns
|
||||
.children( '.' + tscss.scrollerHeader )
|
||||
.children( 'table' )
|
||||
.children( 'thead' )
|
||||
.children( 'tr' );
|
||||
ts.scroller.fixHeight( $rows, $fixed );
|
||||
|
||||
$rows = wo.scroller_$footer
|
||||
.children( 'tfoot' )
|
||||
.children( 'tr' );
|
||||
$fixed = $fixedColumns
|
||||
.children( '.' + tscss.scrollerFooter )
|
||||
.children( 'table' )
|
||||
.children( 'tfoot' )
|
||||
.children( 'tr' );
|
||||
ts.scroller.fixHeight( $rows, $fixed );
|
||||
|
||||
if ( ts.scroller.isFirefox || ts.scroller.isOldIE ) {
|
||||
// Firefox/Old IE scrollbar hack (wraps table to hide the scrollbar)
|
||||
$fixedColumns = $fixedColumns.find( '.' + tscss.scrollerHack );
|
||||
}
|
||||
$rows = c.$table
|
||||
.children( 'tbody' )
|
||||
.children( 'tr' );
|
||||
$fixed = $fixedColumns
|
||||
.children( '.' + tscss.scrollerTable )
|
||||
.children( 'table' )
|
||||
.children( 'tbody' )
|
||||
.children( 'tr' );
|
||||
ts.scroller.fixHeight( $rows, $fixed );
|
||||
|
||||
},
|
||||
|
||||
removeFixed : function( c, wo, removeIt ) {
|
||||
var $table = c.$table,
|
||||
$wrapper = wo.scroller_$container,
|
||||
dir = $table.hasClass( tscss.scrollerRtl );
|
||||
|
||||
// remove fixed columns
|
||||
if ( removeIt || typeof removeIt === 'undefined' ) {
|
||||
$wrapper.find( '.' + tscss.scrollerFixed ).remove();
|
||||
}
|
||||
|
||||
$wrapper
|
||||
.find( '.' + tscss.scrollerHideColumn )
|
||||
.removeClass( tscss.scrollerHideColumn );
|
||||
|
||||
// RTL support ( fixes column on right )
|
||||
$wrapper
|
||||
.children( ':not(.' + tscss.scrollerFixed + ')' )
|
||||
.css( dir ? 'right' : 'left', 0 );
|
||||
},
|
||||
|
||||
remove : function( c, wo ) {
|
||||
var $wrap = wo.scroller_$container,
|
||||
namespace = c.namespace + 'tsscroller';
|
||||
c.$table.off( namespace );
|
||||
$( window ).off( namespace );
|
||||
if ( $wrap ) {
|
||||
c.$table
|
||||
.insertBefore( $wrap )
|
||||
.find( 'thead' )
|
||||
.removeClass( tscss.scrollerHideElement )
|
||||
.children( 'tr.' + tscss.headerRow )
|
||||
.children()
|
||||
.attr( 'tabindex', 0 )
|
||||
.end()
|
||||
.find( '.' + tscss.filterRow )
|
||||
.removeClass( tscss.scrollerHideElement + ' ' + tscss.filterRowHide );
|
||||
c.$table
|
||||
.find( '.' + tscss.filter )
|
||||
.not( '.' + tscss.filterDisabled )
|
||||
.prop( 'disabled', false );
|
||||
$wrap.remove();
|
||||
c.isScrolling = false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})( jQuery, window );
|
||||
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