From 5c4fe06b8158c387054f4aeaaac4dd081f72648e Mon Sep 17 00:00:00 2001 From: Mottie Date: Sun, 31 Mar 2013 12:18:20 -0500 Subject: [PATCH] added widget priorities --- css/theme.default.css | 3 +- docs/example-widget-sticky-header.html | 29 +-- docs/example-widgets.html | 43 ++-- docs/index.html | 18 +- js/jquery.tablesorter.js | 63 +++--- js/jquery.tablesorter.widgets.js | 276 +++++++++++++------------ 6 files changed, 229 insertions(+), 203 deletions(-) diff --git a/css/theme.default.css b/css/theme.default.css index 9efd03e0..4a303572 100644 --- a/css/theme.default.css +++ b/css/theme.default.css @@ -22,7 +22,8 @@ Default Theme border-bottom: #ccc 2px solid; padding: 0; } -.tablesorter-default tfoot th { +.tablesorter-default tfoot th, +.tablesorter-default tfoot td { border: 0; } .tablesorter-default .header, diff --git a/docs/example-widget-sticky-header.html b/docs/example-widget-sticky-header.html index 637d3739..95e203bd 100644 --- a/docs/example-widget-sticky-header.html +++ b/docs/example-widget-sticky-header.html @@ -96,21 +96,19 @@ $(function() { NOTE!

@@ -126,13 +124,8 @@ $(function() {

- - +
Table caption
- - - - diff --git a/docs/example-widgets.html b/docs/example-widgets.html index 18500b1b..2594ba86 100644 --- a/docs/example-widgets.html +++ b/docs/example-widgets.html @@ -26,42 +26,42 @@ // ************************************ $.tablesorter.addWidget({ - // give the widget an id 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, skip; + var h = '', i, $tr, l, skip; // cache and collect all TH headers - if (!this.headers) { - h = this.headers = []; - $("thead th",table).each(function() { - h.push( "" ); + if (!wo.repeatHeaders) { + h = ''; + $.each(c.headerContent, function(i,t) { + h += ''; }); + // "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 + ''; } - // remove appended headers by classname - $(table).find("tr.repeated-header").remove(); - // 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 < table.tBodies[0].rows.length; i += (skip + 1)) { + for (i = skip; i < l; i += skip) { // insert a copy of the table head every X rows - $("tbody tr:eq(" + i + ")",table).before( - // "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 - $("").addClass("repeated-header remove-me").html(this.headers.join("")) - ); + $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, wo){ - $(table).find("tr.repeated-header").remove(); + remove: function(table, c){ + c.$table.find("tr.repeated-header").remove(); } }); @@ -91,6 +91,13 @@ Notes about the addWidget template:
Personal Information for each person (resize the browser to check expanding height)Courses (this is a TD cell)
NameMajorSexEnglishJapaneseCalculusGeometry
" + $(this).text() + "
' + t + '
- + - - - - - - - - + + + + + + + +
Applied OrderNameRequires jQueryLimiting function
Widget PriorityNameRequires jQueryLimiting function
6columnsv1.2.6
5filterv1.4.31.4.3 (nextUntil)
8pagerv1.2.6
4resizablev1.4.1*1.4 (isEmptyObject); 1.4.1 (parseJSON)*
3saveSortv1.4.11.4.1 (parseJSON)*
2stickyHeadersv1.2.6
1uithemev1.2.6
7zebrav1.2.6
60columnsv1.2.6
50filterv1.4.31.4.3 (nextUntil)
Lastpagerv1.2.6
40resizablev1.4.1*1.4 (isEmptyObject); 1.4.1 (parseJSON)*
30saveSortv1.4.11.4.1 (parseJSON)*
20stickyHeadersv1.2.6
10uithemev1.2.6
90zebrav1.2.6
diff --git a/js/jquery.tablesorter.js b/js/jquery.tablesorter.js index fce410c2..e0bb582c 100644 --- a/js/jquery.tablesorter.js +++ b/js/jquery.tablesorter.js @@ -1142,34 +1142,50 @@ }; ts.applyWidget = function(table, init) { - table = $(table)[0]; + table = $(table)[0]; // in case this is called externally var c = table.config, wo = c.widgetOptions, - ws = c.widgets.sort().reverse(), // ensure that widgets are always applied in a certain order - time, i, w, l = ws.length; - // make zebra last - i = $.inArray('zebra', c.widgets); - if (i >= 0) { - c.widgets.splice(i,1); - c.widgets.push('zebra'); - } - if (c.debug) { - time = new Date(); - } - // add selected widgets - for (i = 0; i < l; i++) { - w = ts.getWidgetById(ws[i]); - if ( w ) { - if (init) { - if (w.hasOwnProperty('options')) { $.extend( true, w.options, wo ); } - if (w.hasOwnProperty('init')) { w.init(table, w, c, wo); } - } else if (!init && w.hasOwnProperty('format')) { - w.format(table, c, wo, false); + widgets = [], + time, i, w, wd; + if (c.debug) { time = new Date(); } + if (c.widgets.length) { + // ensure unique widget ids + c.widgets = $.grep(c.widgets, function(v, k){ + return $.inArray(v, c.widgets) === k; + }); + // build widget array & add priority as needed + $.each(c.widgets || [], function(i,n){ + wd = ts.getWidgetById(n); + if (wd && wd.id) { + // set priority to 10 if not defined + if (!wd.priority) { wd.priority = 10; } + widgets[i] = wd; } - } + }); + // sort widgets by priority + widgets.sort(function(a, b){ + return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1; + }); + + // add/update selected widgets + $.each(widgets, function(i,w){ + if (w) { + if (init) { + if (w.hasOwnProperty('options')) { + wo = table.config.widgetOptions = $.extend( true, {}, w.options, wo ); + } + if (w.hasOwnProperty('init')) { + w.init(table, w, c, wo); + } + } else if (!init && w.hasOwnProperty('format')) { + w.format(table, c, wo, false); + } + } + }); } if (c.debug) { - benchmark("Completed " + (init === true ? "initializing" : "applying") + " widgets", time); + w = c.widgets.length; + benchmark("Completed " + (init === true ? "initializing " : "applying ") + w + " widget" + (w !== 1 ? "s" : ""), time); } }; @@ -1409,6 +1425,7 @@ // add default widgets ts.addWidget({ id: "zebra", + priority: 90, format: function(table, c, wo) { var $tb, $tv, $tr, row, even, time, k, l, child = new RegExp(c.cssChildRow, 'i'), diff --git a/js/jquery.tablesorter.widgets.js b/js/jquery.tablesorter.widgets.js index b1e4b86a..c056b75f 100644 --- a/js/jquery.tablesorter.widgets.js +++ b/js/jquery.tablesorter.widgets.js @@ -12,9 +12,9 @@ /*global jQuery: false, localStorage: false, navigator: false */ ;(function($){ "use strict"; -$.tablesorter = $.tablesorter || {}; +var ts = $.tablesorter = $.tablesorter || {}; -$.tablesorter.themes = { +ts.themes = { "bootstrap" : { table : 'table table-bordered table-striped', header : 'bootstrap-header', // give the header a gradient background @@ -66,7 +66,7 @@ $.tablesorter.themes = { val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : ''; alert(val); // "data1" if saved, or "" if not */ -$.tablesorter.storage = function(table, key, val){ +ts.storage = function(table, key, val){ var d, k, ls = false, v = {}, id = table.id || $('.tablesorter').index( $(table) ), url = window.location.pathname; @@ -104,17 +104,19 @@ $.tablesorter.storage = function(table, key, val){ // Widget: General UI theme // "uitheme" option in "widgetOptions" // ************************** -$.tablesorter.addWidget({ +ts.addWidget({ id: "uitheme", - format: function(table){ + priority: 10, + options: { + uitheme : 'jui' + }, + format: function(table, c, wo){ var time, klass, $el, $tar, - t = $.tablesorter.themes, - $t = $(table), - c = table.config, - wo = c.widgetOptions, - theme = c.theme !== 'default' ? c.theme : wo.uitheme || 'jui', // default uitheme is 'jui' + t = ts.themes, + $t = c.$table, + theme = c.theme !== 'default' ? c.theme : wo.uitheme || 'jui', o = t[ t[theme] ? theme : t[wo.uitheme] ? wo.uitheme : 'jui'], - $h = $(c.headerList), + $h = c.$headers, sh = 'tr.' + (wo.stickyHeaders || 'tablesorter-stickyHeader'), rmv = o.sortNone + ' ' + o.sortDesc + ' ' + o.sortAsc; if (c.debug) { time = new Date(); } @@ -168,13 +170,13 @@ $.tablesorter.addWidget({ } }); if (c.debug){ - $.tablesorter.benchmark("Applying " + theme + " theme", time); + ts.benchmark("Applying " + theme + " theme", time); } }, remove: function(table, c, wo){ - var $t = $(table), + var $t = c.$table, theme = typeof wo.uitheme === 'object' ? 'jui' : wo.uitheme || 'jui', - o = typeof wo.uitheme === 'object' ? wo.uitheme : $.tablesorter.themes[ $.tablesorter.themes.hasOwnProperty(theme) ? theme : 'jui'], + o = typeof wo.uitheme === 'object' ? wo.uitheme : ts.themes[ ts.themes.hasOwnProperty(theme) ? theme : 'jui'], $h = $t.children('thead').children(), rmv = o.sortNone + ' ' + o.sortDesc + ' ' + o.sortAsc; $t @@ -192,17 +194,18 @@ $.tablesorter.addWidget({ // "columns", "columns_thead" (true) and // "columns_tfoot" (true) options in "widgetOptions" // ************************** -$.tablesorter.addWidget({ +ts.addWidget({ id: "columns", - format: function(table){ + priority: 60, + options : { + columns : [ "primary", "secondary", "tertiary" ] + }, + format: function(table, c, wo){ var $tb, $tr, $td, $t, time, last, rmv, i, k, l, - $tbl = $(table), - c = table.config, - wo = c.widgetOptions, + $tbl = c.$table, b = c.$tbodies, list = c.sortList, len = list.length, - css = [ "primary", "secondary", "tertiary" ]; // default options // keep backwards compatibility, for now css = (c.widgetColumns && c.widgetColumns.hasOwnProperty('css')) ? c.widgetColumns.css || css : (wo && wo.hasOwnProperty('columns')) ? wo.columns || css : css; @@ -213,7 +216,7 @@ $.tablesorter.addWidget({ } // check if there is a sort (on initialization there may not be one) for (k = 0; k < b.length; k++ ){ - $tb = $.tablesorter.processTbody(table, b.eq(k), true); // detach tbody + $tb = ts.processTbody(table, b.eq(k), true); // detach tbody $tr = $tb.children('tr'); l = $tr.length; // loop through the visible rows @@ -235,7 +238,7 @@ $.tablesorter.addWidget({ } } }); - $.tablesorter.processTbody(table, $tb, false); + ts.processTbody(table, $tb, false); } // add classes to thead and tfoot $tr = wo.columns_thead !== false ? 'thead tr' : ''; @@ -256,7 +259,7 @@ $.tablesorter.addWidget({ } } if (c.debug){ - $.tablesorter.benchmark("Applying Columns widget", time); + ts.benchmark("Applying Columns widget", time); } }, remove: function(table, c, wo){ @@ -264,56 +267,55 @@ $.tablesorter.addWidget({ b = c.$tbodies, rmv = (wo.columns || [ "primary", "secondary", "tertiary" ]).join(' '); c.$headers.removeClass(rmv); - $(table).children('tfoot').children('tr').children('th, td').removeClass(rmv); + c.$table.children('tfoot').children('tr').children('th, td').removeClass(rmv); for (k = 0; k < b.length; k++ ){ - $tb = $.tablesorter.processTbody(table, b.eq(k), true); // remove tbody + $tb = ts.processTbody(table, b.eq(k), true); // remove tbody $tb.children('tr').each(function(){ $(this).children().removeClass(rmv); }); - $.tablesorter.processTbody(table, $tb, false); // restore tbody + ts.processTbody(table, $tb, false); // restore tbody } } }); -/* Widget: filter - widgetOptions: - filter_childRows : false // if true, filter includes child row content in the search - filter_columnFilters : true // if true, a filter will be added to the top of each table column - filter_cssFilter : 'tablesorter-filter' // css class name added to the filter row & each input in the row - filter_formatter : null // add custom filter elements to the filter row - filter_functions : null // add custom filter functions using this option - filter_hideFilters : false // collapse filter row when mouse leaves the area - filter_ignoreCase : true // if true, make all searches case-insensitive - filter_reset : null // jQuery selector string of an element used to reset the filters - filter_searchDelay : 300 // typing delay in milliseconds before starting a search - filter_startsWith : false // if true, filter start from the beginning of the cell contents - filter_useParsedData : false // filter all data using parsed content - filter_serversideFiltering : false // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used. - **************************/ -$.tablesorter.addWidget({ +// Widget: filter +// ************************** +ts.addWidget({ id: "filter", - format: function(table){ - if (table.config.parsers && !$(table).hasClass('hasFilters')){ + priority: 50, + options : { + filter_childRows : false, // if true, filter includes child row content in the search + filter_columnFilters : true, // if true, a filter will be added to the top of each table column + filter_cssFilter : 'tablesorter-filter', // css class name added to the filter row & each input in the row + filter_formatter : null, // add custom filter elements to the filter row + filter_functions : null, // add custom filter functions using this option + filter_hideFilters : false, // collapse filter row when mouse leaves the area + filter_ignoreCase : true, // if true, make all searches case-insensitive + filter_reset : null, // jQuery selector string of an element used to reset the filters + filter_searchDelay : 300, // typing delay in milliseconds before starting a search + filter_startsWith : false, // if true, filter start from the beginning of the cell contents + filter_useParsedData : false, // filter all data using parsed content + filter_serversideFiltering : false, // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used. + filter_regex : { // regex used in filter "check" functions + "regex" : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // regex to test for regex + "child" : /tablesorter-childRow/, // child row class name; this gets updated in the script + "type" : /undefined|number/, // check type + "exact" : /(^[\"|\'|=])|([\"|\'|=]$)/g, // exact match + "nondigit" : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser) + "operators" : /[<>=]/g // replace operators + } + }, + format: function(table, c, wo){ + if (c.parsers && !c.$table.hasClass('hasFilters')){ var i, j, k, l, val, ff, x, xi, st, sel, str, ft, ft2, $th, $fr, rg, s, t, dis, col, - fmt = $.tablesorter.formatFloat, + fmt = ts.formatFloat, last = '', // save last filter search - ts = $.tablesorter, - c = table.config, - $ths = $(c.headerList), - wo = c.widgetOptions, + $ths = c.$headers, css = wo.filter_cssFilter || 'tablesorter-filter', - $t = $(table).addClass('hasFilters'), + $t = c.$table.addClass('hasFilters'), b = $t.find('tbody'), cols = c.parsers.length, - reg = { // regex used in filter "check" functions - "regex" : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // regex to test for regex - "child" : new RegExp(c.cssChildRow), // child row - "type" : /undefined|number/, // check type - "exact" : /(^[\"|\'|=])|([\"|\'|=]$)/g, // exact match - "nondigit" : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser) - "operators" : /[<>=]/g // replace operators - }, parsed, time, timer, // dig fer gold @@ -332,7 +334,7 @@ $.tablesorter.addWidget({ $(el).val(filter[i] || ''); }); } - if (wo.filter_hideFilters === true){ + if (wo.filter_hideFilters){ // show/hide filter row as needed $t.find('.tablesorter-filter-row').trigger( cv === '' ? 'mouseleave' : 'mouseenter' ); } @@ -357,7 +359,7 @@ $.tablesorter.addWidget({ for (k = 0; k < b.length; k++ ){ if (b.eq(k).hasClass(c.cssInfoBlock)) { continue; } // ignore info blocks, issue #264 - $tb = $.tablesorter.processTbody(table, b.eq(k), true); + $tb = ts.processTbody(table, b.eq(k), true); $tr = $tb.children('tr'); l = $tr.length; if (cv === '' || wo.filter_serversideFiltering){ @@ -366,14 +368,13 @@ $.tablesorter.addWidget({ // loop through the rows for (j = 0; j < l; j++){ // skip child rows - if (reg.child.test($tr[j].className)) { continue; } + if (wo.filter_regex.child.test($tr[j].className)) { continue; } r = true; cr = $tr.eq(j).nextUntil('tr:not(.' + c.cssChildRow + ')'); // so, if "table.config.widgetOptions.filter_childRows" is true and there is // a match anywhere in the child row, then it will make the row visible // checked here so the option can be changed dynamically - t = (cr.length && (wo && wo.hasOwnProperty('filter_childRows') && - typeof wo.filter_childRows !== 'undefined' ? wo.filter_childRows : true)) ? cr.text() : ''; + t = (cr.length && wo.filter_childRows) ? cr.text() : ''; t = wo.filter_ignoreCase ? t.toLocaleLowerCase() : t; $td = $tr.eq(j).children('td'); for (i = 0; i < cols; i++){ @@ -386,7 +387,7 @@ $.tablesorter.addWidget({ // using older or original tablesorter x = $.trim($td.eq(i).text()); } - xi = !reg.type.test(typeof x) && wo.filter_ignoreCase ? x.toLocaleLowerCase() : x; + xi = !wo.filter_regex.type.test(typeof x) && wo.filter_ignoreCase ? x.toLocaleLowerCase() : x; ff = r; // if r is true, show that row // val = case insensitive, v[i] = case sensitive val = wo.filter_ignoreCase ? v[i].toLocaleLowerCase() : v[i]; @@ -402,8 +403,8 @@ $.tablesorter.addWidget({ ff = wo.filter_functions[i][v[i]](x, c.cache[k].normalized[j][i], v[i], i); } // Look for regex - } else if (reg.regex.test(val)){ - rg = reg.regex.exec(val); + } else if (wo.filter_regex.regex.test(val)){ + rg = wo.filter_regex.regex.exec(val); try { ff = new RegExp(rg[1], rg[2]).test(xi); } catch (err){ @@ -411,7 +412,7 @@ $.tablesorter.addWidget({ } // Look for quotes or equals to get an exact match; ignore type since xi could be numeric /*jshint eqeqeq:false */ - } else if (val.replace(reg.exact, '') == xi){ + } else if (val.replace(wo.filter_regex.exact, '') == xi){ ff = true; // Look for a not match } else if (/^\!/.test(val)){ @@ -421,8 +422,8 @@ $.tablesorter.addWidget({ // Look for operators >, >=, < or <= } else if (/^[<>]=?/.test(val)){ // xi may be numeric - see issue #149 - rg = isNaN(xi) ? fmt(xi.replace(reg.nondigit, ''), table) : fmt(xi, table); - s = fmt(val.replace(reg.nondigit, '').replace(reg.operators,''), table); + rg = isNaN(xi) ? fmt(xi.replace(wo.filter_regex.nondigit, ''), table) : fmt(xi, table); + s = fmt(val.replace(wo.filter_regex.nondigit, '').replace(wo.filter_regex.operators,''), table); if (/>/.test(val)) { ff = />=/.test(val) ? rg >= s : rg > s; } if (/ r2) { ff = r1; r1 = r2; r2 = ff; } // swap ff = (rg >= r1 && rg <= r2) || (r1 === '' || r2 === '') ? true : false; // Look for wild card: ? = single, * = multiple, or | = logical OR @@ -459,7 +460,7 @@ $.tablesorter.addWidget({ if (cr.length) { cr[r ? 'show' : 'hide'](); } } } - $.tablesorter.processTbody(table, $tb, false); + ts.processTbody(table, $tb, false); } last = cv; // save last search @@ -494,9 +495,9 @@ $.tablesorter.addWidget({ // if $.tablesorter.sortText exists (not in the original tablesorter), // then natural sort the list otherwise use a basic sort arry = $.grep(arry, function(v, k){ - return $.inArray(v ,arry) === k; + return $.inArray(v, arry) === k; }); - arry = (ts.sortText) ? arry.sort(function(a,b){ return ts.sortText(table, a, b, i); }) : arry.sort(true); + arry = (ts.sortText) ? arry.sort(function(a, b){ return ts.sortText(table, a, b, i); }) : arry.sort(true); // build option list for (k = 0; k < arry.length; k++){ @@ -520,8 +521,7 @@ $.tablesorter.addWidget({ if (c.debug){ time = new Date(); } - wo.filter_ignoreCase = wo.filter_ignoreCase !== false; // set default filter_ignoreCase to true - wo.filter_useParsedData = wo.filter_useParsedData === true; // default is false + wo.filter_regex.child = new RegExp(c.cssChildRow); // don't build filter row if columnFilters is false or all columns are set to "filter-false" - issue #156 if (wo.filter_columnFilters !== false && $ths.filter('.filter-false').length !== $ths.length){ // build filter row @@ -595,7 +595,7 @@ $.tablesorter.addWidget({ clearTimeout(timer); timer = setTimeout(function(){ checkFilters(false); - }, wo.filter_searchDelay || 300); + }, wo.filter_searchDelay); return false; }); @@ -639,7 +639,7 @@ $.tablesorter.addWidget({ checkFilters(); }); - if (wo.filter_hideFilters === true){ + if (wo.filter_hideFilters){ $t .find('.tablesorter-filter-row') .addClass('hideme') @@ -656,7 +656,7 @@ $.tablesorter.addWidget({ // $(':focus') needs jQuery 1.6+ if ($(document.activeElement).closest('tr')[0] !== ft[0]){ // get all filter values - all = $t.find('.' + (wo.filter_cssFilter || 'tablesorter-filter')).map(function(){ + all = $t.find('.' + wo.filter_cssFilter).map(function(){ return $(this).val() || ''; }).get().join(''); // don't hide row if any filter has a value @@ -672,7 +672,7 @@ $.tablesorter.addWidget({ clearTimeout(st); st = setTimeout(function(){ // don't hide row if any filter has a value - if ($t.find('.' + (wo.filter_cssFilter || 'tablesorter-filter')).map(function(){ return $(this).val() || ''; }).get().join('') === ''){ + if ($t.find('.' + wo.filter_cssFilter).map(function(){ return $(this).val() || ''; }).get().join('') === ''){ ft2[ e.type === 'focus' ? 'removeClass' : 'addClass']('hideme'); } }, 200); @@ -699,7 +699,7 @@ $.tablesorter.addWidget({ }, remove: function(table, c, wo){ var k, $tb, - $t = $(table), + $t = c.$table, b = c.$tbodies; $t .removeClass('hasFilters') @@ -707,9 +707,9 @@ $.tablesorter.addWidget({ .unbind('addRows updateCell update updateComplete appendCache search filterStart filterEnd '.split(' ').join('.tsfilter ')) .find('.tablesorter-filter-row').remove(); for (k = 0; k < b.length; k++ ){ - $tb = $.tablesorter.processTbody(table, b.eq(k), true); // remove tbody + $tb = ts.processTbody(table, b.eq(k), true); // remove tbody $tb.children().removeClass('filtered').show(); - $.tablesorter.processTbody(table, $tb, false); // restore tbody + ts.processTbody(table, $tb, false); // restore tbody } if (wo.filterreset) { $(wo.filter_reset).unbind('click.tsfilter'); } } @@ -720,24 +720,26 @@ $.tablesorter.addWidget({ // http://css-tricks.com/13465-persistent-headers/ // and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech // ************************** -$.tablesorter.addWidget({ +ts.addWidget({ id: "stickyHeaders", - format: function(table){ - if ($(table).hasClass('hasStickyHeaders')) { return; } - var $table = $(table).addClass('hasStickyHeaders'), - c = table.config, - wo = c.widgetOptions, + priority: 20, + options: { + stickyHeaders: 'tablesorter-stickyHeader', + stickyHeaders_cloneId: '-sticky', // added to table ID, if it exists + }, + format: function(table, c, wo){ + if (c.$table.hasClass('hasStickyHeaders')) { return; } + var $table = c.$table.addClass('hasStickyHeaders'), win = $(window), - header = $(table).children('thead:first'), //.add( $(table).find('caption') ), + header = c.$table.children('thead:first'), //.add( c.$table.find('caption') ), hdrCells = header.children('tr:not(.sticky-false)').children(), - css = wo.stickyHeaders || 'tablesorter-stickyHeader', innr = '.tablesorter-header-inner', firstRow = hdrCells.eq(0).parent(), tfoot = $table.find('tfoot'), - t2 = wo.$sticky = $table.clone(), // clone table, but don't remove id... the table might be styled by css + t2 = wo.$sticky = $table.clone(), // clone the entire thead - seems to work in IE8+ stkyHdr = t2.children('thead:first') - .addClass(css) + .addClass(wo.stickyHeaders) .css({ width : header.outerWidth(true), position : 'fixed', @@ -777,8 +779,10 @@ $.tablesorter.addWidget({ $(this).width(w); }); }; + // fix clone ID, if it exists - fixes #271 + if (t2.attr('id')) { t2[0].id += wo.stickyHeaders_cloneId; } // clear out cloned table, except for sticky header - t2.find('thead:gt(0),tr.sticky-false,tbody,tfoot,caption').remove(); + t2.find('thead:gt(0), tr.sticky-false, tbody, tfoot, caption').remove(); t2.css({ height:0, width:0, padding:0, margin:0, border:0 }); // remove rows you don't want to be sticky stkyHdr.find('tr.sticky-false').remove(); @@ -823,8 +827,7 @@ $.tablesorter.addWidget({ sTop = win.scrollTop(), tableHt = $table.height() - (stkyHdr.height() + (tfoot.height() || 0)), vis = (sTop > offset.top) && (sTop < offset.top + tableHt) ? 'visible' : 'hidden'; - stkyHdr - .css({ + stkyHdr.css({ // adjust when scrolling horizontally - fixes issue #143 left : header.offset().left - win.scrollLeft() - spacing, visibility : vis @@ -840,12 +843,10 @@ $.tablesorter.addWidget({ }); }, remove: function(table, c, wo){ - var $t = $(table), - css = wo.stickyHeaders || 'tablesorter-stickyHeader'; - $t + c.$table .removeClass('hasStickyHeaders') .unbind('sortEnd.tsSticky pagerComplete.tsSticky') - .find('.' + css).remove(); + .find('.' + wo.stickyHeaders).remove(); if (wo.$sticky) { wo.$sticky.remove(); } // remove cloned thead $(window).unbind('scroll.tsSticky resize.tsSticky'); } @@ -855,39 +856,42 @@ $.tablesorter.addWidget({ // this widget saves the column widths if // $.tablesorter.storage function is included // ************************** -$.tablesorter.addWidget({ +ts.addWidget({ id: "resizable", - format: function(table){ - if ($(table).hasClass('hasResizable')) { return; } - $(table).addClass('hasResizable'); - var $t, t, i, j, s, $c, $cols, w, tw, - $tbl = $(table), - c = table.config, - wo = c.widgetOptions, + priority: 40, + options: { + resizable : true, + resizable_addLastColumn : false + }, + format: function(table, c, wo){ + if (c.$table.hasClass('hasResizable')) { return; } + c.$table.addClass('hasResizable'); + var $t, t, i, j, s = {}, $c, $cols, w, tw, + $tbl = c.$table, position = 0, $target = null, $next = null, fullWidth = Math.abs($tbl.parent().width() - $tbl.width()) < 20, stopResize = function(){ - if ($.tablesorter.storage && $target){ + if (ts.storage && $target){ s[$target.index()] = $target.width(); s[$next.index()] = $next.width(); $target.width( s[$target.index()] ); $next.width( s[$next.index()] ); if (wo.resizable !== false){ - $.tablesorter.storage(table, 'tablesorter-resizable', s); + ts.storage(table, 'tablesorter-resizable', s); } } position = 0; $target = $next = null; $(window).trigger('resize'); // will update stickyHeaders, just in case }; - s = ($.tablesorter.storage && wo.resizable !== false) ? $.tablesorter.storage(table, 'tablesorter-resizable') : {}; + s = (ts.storage && wo.resizable !== false) ? ts.storage(table, 'tablesorter-resizable') : {}; // process only if table ID or url match if (s){ for (j in s){ - if (!isNaN(j) && j < c.headerList.length){ - $(c.headerList[j]).width(s[j]); // set saved resizable widths + if (!isNaN(j) && j < c.$headers.length){ + c.$headers.eq(j).width(s[j]); // set saved resizable widths } } } @@ -896,7 +900,7 @@ $.tablesorter.addWidget({ $t.children().each(function(){ t = $(this); i = t.attr('data-column'); - j = $.tablesorter.getData( t, c.headers[i], 'resizable') === "false"; + j = ts.getData( t, c.headers[i], 'resizable') === "false"; $t.children().filter('[data-column="' + i + '"]').toggleClass('resizable-false', j); }); // add wrapper inside each cell to allow for positioning of the resizable target block @@ -951,15 +955,15 @@ $.tablesorter.addWidget({ }) // right click to reset columns to default widths .bind('contextmenu.tsresize', function(){ - $.tablesorter.resizableReset(table); + ts.resizableReset(table); // $.isEmptyObject() needs jQuery 1.4+ var rtn = $.isEmptyObject ? $.isEmptyObject(s) : s === {}; // allow right click if already reset s = {}; return rtn; }); }, - remove: function(table){ - $(table) + remove: function(table, c, wo){ + c.$table .removeClass('hasResizable') .find('thead') .unbind('mouseup.tsresize mouseleave.tsresize contextmenu.tsresize') @@ -967,12 +971,12 @@ $.tablesorter.addWidget({ .unbind('mousemove.tsresize mouseup.tsresize') // don't remove "tablesorter-wrapper" as uitheme uses it too .find('.tablesorter-resizer,.tablesorter-resizer-grip').remove(); - $.tablesorter.resizableReset(table); + ts.resizableReset(table); } }); -$.tablesorter.resizableReset = function(table){ - $(table.config.headerList).filter(':not(.resizable-false)').css('width',''); - if ($.tablesorter.storage) { $.tablesorter.storage(table, 'tablesorter-resizable', {}); } +ts.resizableReset = function(table){ + table.config.$headers.filter(':not(.resizable-false)').css('width',''); + if (ts.storage) { ts.storage(table, 'tablesorter-resizable', {}); } }; // Save table sort widget @@ -980,27 +984,29 @@ $.tablesorter.resizableReset = function(table){ // saveSort widget option is true AND the // $.tablesorter.storage function is included // ************************** -$.tablesorter.addWidget({ +ts.addWidget({ id: 'saveSort', + priority: 30, + options: { + saveSort : true + }, init: function(table, thisWidget, c, wo){ // run widget format before all other widgets are applied to the table thisWidget.format(table, c, wo, true); }, format: function(table, c, wo, init){ - // redefining c & wo for backwards compatibility - c = table.config; - wo = c.widgetOptions; - var sl, time, $t = $(table), + var sl, time, + $t = c.$table, ss = wo.saveSort !== false, // make saveSort active/inactive; default to true sortList = { "sortList" : c.sortList }; if (c.debug){ time = new Date(); } if ($t.hasClass('hasSaveSort')){ - if (ss && table.hasInitialized && $.tablesorter.storage){ - $.tablesorter.storage( table, 'tablesorter-savesort', sortList ); + if (ss && table.hasInitialized && ts.storage){ + ts.storage( table, 'tablesorter-savesort', sortList ); if (c.debug){ - $.tablesorter.benchmark('saveSort widget: Saving last sort: ' + c.sortList, time); + ts.benchmark('saveSort widget: Saving last sort: ' + c.sortList, time); } } } else { @@ -1008,15 +1014,15 @@ $.tablesorter.addWidget({ $t.addClass('hasSaveSort'); sortList = ''; // get data - if ($.tablesorter.storage){ - sl = $.tablesorter.storage( table, 'tablesorter-savesort' ); + if (ts.storage){ + sl = ts.storage( table, 'tablesorter-savesort' ); sortList = (sl && sl.hasOwnProperty('sortList') && $.isArray(sl.sortList)) ? sl.sortList : ''; if (c.debug){ - $.tablesorter.benchmark('saveSort: Last sort loaded: "' + sortList + '"', time); + ts.benchmark('saveSort: Last sort loaded: "' + sortList + '"', time); } $t.bind('saveSortReset', function(e){ e.stopPropagation(); - $.tablesorter.storage( table, 'tablesorter-savesort', '' ); + ts.storage( table, 'tablesorter-savesort', '' ); }); } // init is true when widget init is run, this will run this widget before all other widgets have initialized @@ -1031,7 +1037,7 @@ $.tablesorter.addWidget({ }, remove: function(table){ // clear storage - if ($.tablesorter.storage) { $.tablesorter.storage( table, 'tablesorter-savesort', '' ); } + if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); } } });