StickyHeaders: works with nested tables & modified options. Fixes #724

This commit is contained in:
Mottie 2014-10-09 16:04:28 -05:00
parent 2c849fe4c0
commit 3e42e8bb74
6 changed files with 785 additions and 176 deletions

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta charset="utf-8">
<title>jQuery plugin: Tablesorter 2.0 - CSS Sticky Header Widget</title>
<!-- jQuery -->
@ -41,9 +41,8 @@
<script id="js">$(function(){
var options = {
$("#table1, .nested, #table3").tablesorter({
widthFixed : true,
showProcessing: true,
headerTemplate: '{content} {icon}', // Add icon for jui theme; new in v2.7!
widgets: [ 'zebra', 'cssStickyHeaders', 'filter' ],
@ -51,18 +50,26 @@
widgetOptions: {
cssStickyHeaders_offset : 0,
cssStickyHeaders_addCaption : true,
// jQuery selector or object to attach sticky header to
cssStickyHeaders_attachTo : null,
cssStickyHeaders_filteredToTop : true,
cssStickyHeaders_zIndex : 10
}
};
});
$("#table1").tablesorter(options);
$("#table2").tablesorter({
widthFixed : true,
headerTemplate: '{content} {icon}', // Add icon for jui theme; new in v2.7!
/* make second table scroll within its wrapper */
options.widgetOptions.cssStickyHeaders_attachTo = '.wrapper' // or $('.wrapper')
$("#table2").tablesorter(options);
widgets: [ 'zebra', 'cssStickyHeaders', 'filter' ],
widgetOptions: {
cssStickyHeaders_attachTo : '.wrapper', // or $('.wrapper')
cssStickyHeaders_addCaption : true
}
});
});</script>
<script>
@ -72,7 +79,7 @@ $(function() {
var themes = 'default blue green grey ice black-ice dark dropbox',
i, o = '', t = themes.split(' ');
for (i = 0; i < t.length; i++) {
o += '<option>' + t[i] + '</option>';
o += '<option value="' + t[i] + '">' + t[i] + '</option>';
}
$('select:first')
@ -87,7 +94,7 @@ $(function() {
});
$('table')
.removeClass('tablesorter-' + t.join(' tablesorter-') + ' tablesorter-jui')
.addClass('tablesorter-' + theme.replace(/-/,''));
.addClass('tablesorter-' + (theme === 'black-ice' ? 'blackice' : theme) );
}).change();
});
</script>
@ -111,23 +118,55 @@ $(function() {
<h3><a href="#">Notes</a></h3>
<div>
<ul>
<li>This demo uses the CSS Sticky Headers widget which uses CSS transforms to reposition the table head.</li>
<li><a href="http://caniuse.com/#search=transform">CSS transforms</a> are supported by most modern browsers (not IE8 and older).</li>
<li>The jQuery UI themed table does not stick to the top of the page due to the extra padding. Adjust the <code>cssStickyHeaders_offset</code> option as desired. I didn't bother in this demo because it includes more than just the jQuery UI theme.</li>
<li>This widget <em>will not work</em> with the original tablesorter, but works optimally with tablesorter v2.8+ (Added <span class="version">v2.14.2</span>; Updated <span class="version updated">v2.14.4</span>)</li>
<li>In <span class="version">v2.18.0</span>
<ul>
<li>Nested tables with CSS sticky headers now stack; <strong class="results">except in Internet Explorer (IE)</strong>!
<ul>
<li>In IE, the widget only correctly calculates the sticky header position of the <em>first</em> nested table; it's an elusive bug and may take some time to fix it.</li>
<li>In IE, sometimes the entire nested table shrinks or expands when the sticky header becomes fixed.</li>
<li>Currently, <strong>I would <em>not</em> recommend using this css widget for <em>nested tables</em> in IE until this problem is resolved</strong>.<br></li>
</ul>
</li>
<li>Removed <code>cssStickyHeaders_zIndex</code> option since it's not doing anything anymore; the <code>position: relative</code> setting is not required (maybe even ignored) when the transform is applied.</li>
</ul>
</li>
<li>This demo uses the CSS Sticky Headers widget which uses <em>CSS transforms</em> to reposition the table head.</li>
<li><a href="http://caniuse.com/#search=transform">CSS transforms</a> are supported by most modern browsers (<strong>not IE8 and older</strong>).</li>
<li>The jQuery UI themed table does not stick to the top of the page due to the extra padding. Adjust the <code>cssStickyHeaders_offset</code> option as desired. I didn't bother in this demo because it includes more than just the jQuery UI theme.<br><br></li>
<li>This widget <em>will not work</em> with the original tablesorter, but works optimally with tablesorter v2.8+ (Added <span class="version">v2.14.1</span>; Updated <span class="version updated">v2.18.0</span>)</li>
</ul>
</div>
<h3><a href="#">Change log</a></h3>
<div>
<ul>
<li>In <span class="version">v2.16.4</span>, added the <code>cssStickyHeaders_filteredToTop</code> option. When <code>true</code> the table top will scroll into view after being filtered. This is done because if the sticky header is active, and a filter results in say only one row, the table will scroll up out of the browser viewport. If setn to <code>false</code>, no scrolling is done.</li>
<li>In <span class="version">v2.14.4</span>:
<li><span class="version">v2.18.0</span>:
<ul>
<li>Nested css sticky headers now stack; except in IE</li>
<li>Removed <code>cssStickyHeaders_zIndex</code> because the headers are not positioned.</li>
</ul>
</li>
<li><span class="version">v2.16.4</span>:
<ul>
<li>Added the <code>cssStickyHeaders_filteredToTop</code> option.
<ul>
<li>When <code>true</code> the table top will scroll into view after being filtered.</li>
<li>This is done because if the sticky header is active, and a filter results in say only one row, the table will scroll up out of the browser viewport.</li>
<li>If set to <code>false</code>, no scrolling is done.</li>
</ul>
</li>
</ul>
</li>
<li><span class="version">v2.14.4</span>:
<ul>
<li>Added <code>cssStickyHeaders_attachTo</code> (default set to <code>null</code>). Setting this option with either a jQuery selector string (<code>&quot;.wrapper&quot;</code>) or jQuery object (<code>$(&quot;.wrapper&quot;)</code>) to attach the sticky header to this element - see the second example below.</li>
<li>Removed <code>cssStickyHeaders_offsetX</code> option &amp; renamed <code>cssStickyHeaders_offsetY</code> to <code>cssStickyHeaders_offset</code> as the horizontal offset is not required.</li>
</ul><br>
<li>Removed <code>cssStickyHeaders_offsetX</code> option.</li>
<li>Renamed <code>cssStickyHeaders_offsetY</code> to <code>cssStickyHeaders_offset</code> as the horizontal offset is not required.</li>
</ul>
</li>
<li>v2.14.1: Created css Sticky Headers widget</li>
</ul>
</div>
@ -238,6 +277,136 @@ $(function() {
</tbody>
</table>
</div>
<table id="table3" class="tablesorter">
<thead>
<tr>
<th>Main table header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Main table - row 1</td>
</tr>
<tr>
<td>Main table - row 2</td>
</tr>
<tr>
<td>
<table id="nested1" class="nested">
<thead>
<tr>
<th>Header for the nested table 1</th>
</tr>
<tr>
<th class="sorter-false">Second header row for nested table 1</th>
</tr>
</thead>
<tbody>
<tr><td>data in the nested table 1 - row 1</td></tr>
<tr><td>data in the nested table 1 - row 2</td></tr>
<tr><td>data in the nested table 1 - row 3</td></tr>
<tr><td>data in the nested table 1 - row 4</td></tr>
<tr><td>data in the nested table 1 - row 5</td></tr>
<tr>
<td>
<table id="nested2" class="nested">
<caption class="dark-row">Nested table 2 caption</caption>
<thead>
<tr>
<th>Header for the nested table 2</th>
</tr>
<tr>
<th class="sorter-false">Second header row for nested table 2</th>
</tr>
</thead>
<tbody>
<tr><td>data in the nested table 2 - row 1</td></tr>
<tr><td>data in the nested table 2 - row 2</td></tr>
<tr><td>data in the nested table 2 - row 3</td></tr>
<tr><td>data in the nested table 2 - row 4</td></tr>
<tr><td>data in the nested table 2 - row 5</td></tr>
<tr><td>data in the nested table 2 - row 6</td></tr>
<tr><td>data in the nested table 2 - row 7</td></tr>
<tr><td>data in the nested table 2 - row 8</td></tr>
<tr><td>data in the nested table 2 - row 9</td></tr>
<tr><td>data in the nested table 2 - row 10</td></tr>
<tr><td>data in the nested table 2 - row 11</td></tr>
<tr><td>data in the nested table 2 - row 12</td></tr>
<tr><td>data in the nested table 2 - row 13</td></tr>
<tr><td>data in the nested table 2 - row 14</td></tr>
<tr><td>data in the nested table 2 - row 15</td></tr>
<tr><td>data in the nested table 2 - row 16</td></tr>
<tr><td>data in the nested table 2 - row 17</td></tr>
<tr><td>data in the nested table 2 - row 18</td></tr>
<tr><td>data in the nested table 2 - row 19</td></tr>
<tr><td>data in the nested table 2 - row 20</td></tr>
</tbody>
</table>
</td>
</tr>
<tr><td>data in the nested table 1 - row 6</td></tr>
<tr><td>data in the nested table 1 - row 7</td></tr>
<tr><td>data in the nested table 1 - row 8</td></tr>
<tr><td>data in the nested table 1 - row 9</td></tr>
<tr><td>data in the nested table 1 - row 10</td></tr>
<tr><td>data in the nested table 1 - row 11</td></tr>
<tr><td>data in the nested table 1 - row 12</td></tr>
<tr><td>data in the nested table 1 - row 13</td></tr>
<tr><td>data in the nested table 1 - row 14</td></tr>
<tr><td>data in the nested table 1 - row 15</td></tr>
<tr><td>data in the nested table 1 - row 16</td></tr>
<tr><td>data in the nested table 1 - row 17</td></tr>
<tr><td>data in the nested table 1 - row 18</td></tr>
<tr><td>data in the nested table 1 - row 19</td></tr>
<tr><td>data in the nested table 1 - row 20</td></tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>Main table - row 3</td>
</tr>
<tr>
<td>
<table id="nested3" class="nested">
<caption class="dark-row">Nested table 3 caption</caption>
<thead>
<tr>
<th>Header for the nested table 3</th>
</tr>
</thead>
<tbody>
<tr><td>data in the nested table 3 - row 1</td></tr>
<tr><td>data in the nested table 3 - row 2</td></tr>
<tr><td>data in the nested table 3 - row 3</td></tr>
<tr><td>data in the nested table 3 - row 4</td></tr>
<tr><td>data in the nested table 3 - row 5</td></tr>
<tr><td>data in the nested table 3 - row 6</td></tr>
<tr><td>data in the nested table 3 - row 7</td></tr>
<tr><td>data in the nested table 3 - row 8</td></tr>
<tr><td>data in the nested table 3 - row 9</td></tr>
<tr><td>data in the nested table 3 - row 10</td></tr>
<tr><td>data in the nested table 3 - row 11</td></tr>
<tr><td>data in the nested table 3 - row 12</td></tr>
<tr><td>data in the nested table 3 - row 13</td></tr>
<tr><td>data in the nested table 3 - row 14</td></tr>
<tr><td>data in the nested table 3 - row 15</td></tr>
<tr><td>data in the nested table 3 - row 16</td></tr>
<tr><td>data in the nested table 3 - row 17</td></tr>
<tr><td>data in the nested table 3 - row 18</td></tr>
<tr><td>data in the nested table 3 - row 19</td></tr>
<tr><td>data in the nested table 3 - row 20</td></tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>Main table - row 4</td>
</tr>
</tbody>
</table>
<div class="spacer"></div>
</div>

View File

@ -65,7 +65,7 @@ $(function() {
themes = 'default blue green grey ice black-ice dark dropbox',
i, o = '', t = themes.split(' ');
for (i = 0; i < t.length; i++) {
o += '<option>' + t[i] + '</option>';
o += '<option value="' + t[i] + '">' + t[i] + '</option>';
}
$('select')
@ -82,7 +82,7 @@ $(function() {
});
$('table')
.removeClass('tablesorter-' + t.join(' tablesorter-') + ' tablesorter-jui')
.addClass('tablesorter-' + theme.replace(/-/,''));
.addClass('tablesorter-' + (theme === 'black-ice' ? 'blackice' : theme) );
// make sure columns align
$(window).trigger('resize');
}).change();

View File

@ -1,21 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta charset="utf-8">
<title>jQuery plugin: Tablesorter 2.0 - Sticky Header Widget</title>
<!-- jQuery -->
<script src="js/jquery-1.4.4.min.js"></script>
<script src="js/jquery-ui-latest.min.js"></script>
<!-- Demo stuff -->
<link rel="stylesheet" href="css/jq.css">
<link href="css/prettify.css" rel="stylesheet">
<link rel="stylesheet" href="css/jquery-ui.min.css">
<script src="js/prettify.js"></script>
<script src="js/docs.js"></script>
<!-- Tablesorter: theme -->
<link class="ui-theme" rel="stylesheet" href="css/jquery-ui.min.css">
<link class="ui-theme" rel="stylesheet" href="../css/theme.jui.css">
<link class="theme default" rel="stylesheet" href="../css/theme.default.css">
<link class="theme blue" rel="stylesheet" href="../css/theme.blue.css">
<link class="theme green" rel="stylesheet" href="../css/theme.green.css">
@ -38,14 +38,23 @@
<script src="../js/jquery.tablesorter.js"></script>
<script src="../js/jquery.tablesorter.widgets.js"></script>
<script>
$(function(){
$('.options').tablesorter({
widthFixed: true,
widgets: ['stickyHeaders']
});
});
</script>
<script id="js">$(function(){
var options = {
$("#table1, .nested, #table3").tablesorter({
widthFixed : true,
showProcessing: true,
headerTemplate : '{content} {icon}', // Add icon for jui theme; new in v2.7!
headerTemplate : '{content} {icon}', // Add icon for various themes
widgets: [ 'uitheme', 'zebra', 'stickyHeaders', 'filter' ],
widgets: [ 'zebra', 'stickyHeaders', 'filter' ],
widgetOptions: {
@ -63,50 +72,63 @@
stickyHeaders_zIndex : 2,
// jQuery selector or object to attach sticky header to
stickyHeaders_attachTo : null,
// scroll table top into view after filtering
stickyHeaders_filteredToTop: true,
// jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
stickyHeaders_xScroll : null,
// jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
stickyHeaders_yScroll : null,
// scroll table top into view after filtering
stickyHeaders_filteredToTop: true
// *** REMOVED jQuery UI theme due to adding an accordion on this demo page ***
// adding zebra striping, using content and default styles - the ui css removes the background from default
// even and odd class names included for this demo to allow switching themes
zebra : ["ui-widget-content even", "ui-state-default odd"],
// , zebra : ["ui-widget-content even", "ui-state-default odd"]
// use uitheme widget to apply defauly jquery ui (jui) class names
// see the uitheme demo for more details on how to change the class names
uitheme : 'jui'
// , uitheme : 'jui'
}
};
$("#table1").tablesorter(options);
});
/* make second table scroll within its wrapper */
options.widgetOptions.stickyHeaders_attachTo = '.wrapper'; // or $('.wrapper')
$("#table2").tablesorter(options);
$("#table2").tablesorter({
widthFixed : true,
headerTemplate : '{content} {icon}', // Add icon for various themes
widgets: [ 'zebra', 'stickyHeaders', 'filter' ],
widgetOptions: {
// jQuery selector or object to attach sticky header to
stickyHeaders_attachTo : '.wrapper' // or $('.wrapper')
}
});
});</script>
<script>
$(function() {
$('link.theme, link.ui-theme').each(function(){ this.disabled = true; });
// removed jQuery UI theme because of the accordion!
$('link.theme').each(function(){ this.disabled = true; });
var themes = 'default blue green grey ice black-ice dark dropbox',
var themes = 'blue default green grey ice black-ice dark dropbox metro-dark',
i, o = '', t = themes.split(' ');
for (i = 0; i < t.length; i++) {
o += '<option>' + t[i] + '</option>';
o += '<option value="' + t[i] + '">' + t[i] + '</option>';
}
$('select:first')
.append(o)
.change(function(){
var theme = $(this).val().toLowerCase(),
name = theme === 'jui' ? 'ui-theme' : theme,
// ui-theme is added by the themeswitcher
files = $('link.theme, link.ui-theme').each(function(){
files = $('link.theme').each(function(){
this.disabled = true;
})
files.filter('.' + name).each(function(){
files.filter('.' + theme).each(function(){
this.disabled = false;
});
$('table')
.removeClass('tablesorter-' + t.join(' tablesorter-') + ' tablesorter-jui')
.addClass('tablesorter-' + theme.replace(/-/,''));
.removeClass('tablesorter-' + t.join(' tablesorter-'))
.addClass('tablesorter-' + (theme === 'black-ice' ? 'blackice' : theme) );
}).change();
});
</script>
@ -122,34 +144,203 @@ $(function() {
<div id="main">
<p class="tip">
<em>NOTE!</em>
<ul>
<li>In <span class="version updated">v2.16.2</span>, added a <code>stickyHeaders_filteredToTop</code> option which when <code>true</code> will scroll table top into view after filtering</li>
<li>As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8.</li>
<li>Added <code>cssStickyHeaders_attachTo</code> option (default set to <code>null</code>) in <span class="version">v2.14.4</span>.
<ul>
<li>Setting this option with either a jQuery selector string (<code>&quot;.wrapper&quot;</code>) or jQuery object (<code>$(&quot;.wrapper&quot;)</code>).</li>
<li>This option contains the target to which the sticky header will attach - see the <a href="#table2">second example</a> below.</li>
</ul>
</li>
<li>Added a widget option named <code>stickyHeaders_cloneId</code> (<span class="version">v2.9</span>)
<ul>
<li>It contains a suffix to add to any table id.</li>
<li>Its default value is <code>-sticky</code> </li>
</ul>
</li>
<li>To access the added sticky table content from your code without worrying about using the ID, you can use <code>table.config.widgetOptions.$sticky</code>.</li>
<li>Table captions and any additional rows (filter widget row) will also be included in the sticky header (<span class="version">v2.9</span>).</li>
<li>You will need to modify the <code>headerTemplate</code> option to include the jQuery UI icon! See the example in the code (v2.7).</li>
<li>Scroll down the page to see the headers stick. Then sort the columns using the sticky headers!</li>
<li>Added a widget option named <code>stickyHeaders</code> option which contains the css class name applied to the actual sticky header (v2.1). Modified in <span class="version">v2.11</span> so that "tablesorter-stickyHeader" class is always added and this option only adds additional classes.</li>
<li>Multiple rows in the header will become sticky (v2.1.17).</li>
<li>The filter widget adds a row to the table header, but that row will not be included in the sticky header.</li>
<li>Add the class name <code>sticky-false</code> to any header rows you don't want to become sticky (v2.1.18).</li>
<li>Because of the limitations of Internet Explorer version 7 and older, this widget will not work.</li>
</ul>
<p>
<p></p>
<br>
<div id="root" class="accordion">
<h3><a href="#">Notes</a></h3>
<div>
<ul>
<li>In <span class="version">v2.18.0</span>,
<ul>
<li>Nested tables with sticky headers now stack properly. See the new example added to the bottom of this demo page.</li>
<li>Added <code>stickyHeaders_xScroll</code> and <code>stickyHeaders_yScroll</code> widget options.</li>
<li>Any defined <a href="index.html#onrenderheader"><code>onRenderHeader</code></a> function is now executed on the cloned sticky header table cells; the <a href="index.html#onrendertemplate"><code>onRenderTemplate</code></a> function is <em>not</em>! See the change log section for more details.</li>
</ul>
<br>
</li>
<li><span class="label label-info">Note</span> To access the added sticky table content from your code without worrying about using the ID, you can use <code>table.config.widgetOptions.$sticky</code>.</li>
<li><span class="label label-info">Note</span> Add the class name <code>sticky-false</code> to any header rows you don't want to become sticky (v2.1.18).<p></p></li>
<li>You will need to modify the <code>headerTemplate</code> option to include the jQuery UI icon! See the example in the code (v2.7).</li>
<li>Scroll down the page to see the headers stick. Then sort the columns using the sticky headers!</li>
<li>Multiple rows in the header, including the filter row, will become sticky.</li>
<li><strong>As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8</strong>.</li>
<li><strong>Because of the limitations of Internet Explorer version 7 and older, this widget will not work</strong>.</li>
</ul>
</div>
<h3><a href="#">Options</a></h3>
<div>
<h4>stickyHeaders widget defaults (added inside of tablesorter <code>widgetOptions</code>)</h4>
<div>
<span class="label label-info">TIP!</span> Click on the link in the function column to reveal full details (or <a href="#" class="toggleAll">toggle</a>|<a href="#" class="showAll">show</a>|<a href="#" class="hideAll">hide</a> all) or double click to update the browser location.
</div>
<table class="options tablesorter-blue" data-sortlist="[[0,0]]">
<thead>
<tr><th>Option</th><th>Default</th><th class="sorter-false">Description</th></tr>
</thead>
<tbody>
<tr id="stickyheaders">
<td><a href="#" class="permalink">stickyHeaders</a></td>
<td>''</td>
<td>Include any extra class name to be added to the sticky header table (v2.1; <span class="version updated">v2.18.0</span>)
<div class="collapsible">
<br>
<span class="label warning">Note</span> prior to v2.18.0, this class was applied to the sticky table <code>thead</code>; after v2.18.0, the <code>thead</code> and <code>caption</code> are wrapped in a div that is made sticky, with this class name.<br>
<br>
Modified in <span class="version">v2.11</span> so that "tablesorter-stickyHeader" class is always added and this option only adds additional classes.
</div>
</td>
</tr>
<tr id="stickyheaders-offset">
<td><span class="permalink">stickyHeaders_offset</span></td>
<td>0</td>
<td>Set this to a number (in pixels) or jquery selector targeting the <code>position:fixed</code> element in which to place the sticky header below while scrolling.</td>
</tr>
<tr id="stickyheaders-cloneid">
<td><a href="#" class="permalink">stickyHeaders_cloneId</a></td>
<td>'-sticky'</td>
<td>If the original table has an ID, then the value from this option is added to the end of the cloned table to maintain a unique ID (<span class="version">v2.9</span>).
<div class="collapsible">
<ul>
<li>It contains a suffix to add to any table id.</li>
<li>Its default value is <code>-sticky</code> </li>
</ul>
</div>
</td>
</tr>
<tr id="stickyheaders-addresizeevent">
<td><span class="permalink">stickyHeaders_addResizeEvent</span></td>
<td>true</td>
<td>When <code>true</code>, the <a href="index.html#function-resizeevent"><code>$.tablesorter.addHeaderResizeEvent</code></a> function is applied to the table header cells so a "resize" event is triggered and the sticky headers widget can then properly resize the cloned table header cells to match the originals.</td>
</tr>
<tr id="stickyheaders-includecaption">
<td><span class="permalink">stickyHeaders_includeCaption</span></td>
<td>true</td>
<td>If <code>false</code> and a table caption exist, it won't be included in the sticky header.</td>
</tr>
<tr id="stickyheaders-zindex">
<td><span class="permalink">stickyHeaders_zIndex</span></td>
<td>2</td>
<td>Adjust the zIndex of the stickyHeaders element as desired.</td>
</tr>
<tr id="stickyheaders-attachto">
<td><a href="#" class="permalink">stickyHeaders_attachTo</a></td>
<td>null</td>
<td>Set this option as a jQuery selector or object where the sticky header will be attached (<span class="version">v2.14.4</span>).
<div class="collapsible">
<ul>
<li>Setting this option with either a jQuery selector string (<code>&quot;.wrapper&quot;</code>) or jQuery object (<code>$(&quot;.wrapper&quot;)</code>).</li>
<li>This option contains the target to which the sticky header will attach - see the <a href="#table2">second example</a> below.</li>
</ul>
</div>
</td>
</tr>
<tr id="stickyheaders-filteredtotop">
<td><a href="#" class="permalink">stickyHeaders_filteredToTop</a></td>
<td>true</td>
<td>Scroll table top into view after filtering (<span class="version updated">v2.16.2</span>)
<div class="collapsible">
<br>
This is needed when the user choses to filter the table which results in fewer rows than are currently visible in the browser viewport. So, the sticky header may still exist, but the table body may not be seen. Setting this option to <code>true</code> forces the original table header to scroll back into view.
</div>
</td>
</tr>
<tr id="stickyheaders-xscroll">
<td><a href="#" class="permalink">stickyHeaders_xScroll</a></td>
<td>null</td>
<td>jQuery selector or object that will be used to monitor horizontal scroll position(<span class="version">v2.18.0</span>)
<div class="collapsible">
<br>
Defaults: xScroll > attachTo > window<br>
<br>
Indicate the element (jQuery selector or obect) in which to monitor for changes in scroll position; If undefined (<code>null</code> by default), the window is monitored.
</div>
</td>
</tr>
<tr id="stickyheaders-yscroll">
<td><a href="#" class="permalink">stickyHeaders_yScroll</a></td>
<td>null</td>
<td>jQuery selector or object that will be used to monitor vertical scroll position (<span class="version">v2.18.0</span>)
<div class="collapsible">
<br>
Defaults: yScroll > attachTo > window<br>
<br>
Indicate the element (jQuery selector or obect) in which to monitor for changes in scroll position; If undefined (<code>null</code> by default), the window is monitored.
</div>
</td>
</tr>
</tbody>
</table>
</div>
<h3><a href="#">Change log</a></h3>
<div>
<ul>
<li><span class="version">v2.18.0</span>:
<ul>
<li>Nested tables with sticky headers now stack properly. See the new example added to the bottom of this demo page.</li>
<li>Added <code>stickyHeaders_xScroll</code> and <code>stickyHeaders_yScroll</code> options to indicate the element (jQuery selector or obect) in which to monitor for changes in scroll position; If undefined (<code>null</code> by default), the window is monitored.</li>
<li>Any defined <a href="index.html#onrenderheader"><code>onRenderHeader</code></a> function is now executed on the cloned sticky header table cells. There are now 3 parameters available to this function:
<ul>
<li><code>index</code> - header cell index; this is <em>not</em> the column index!</li>
<li><code>config</code> - the <code>table.config</code> settings for the table.</li>
<li><code>$table</code> - the target of this parameter changes:
<ul>
<li>For the original table header cells, this parameter is a jQuery object pointing to the original table; this table has the class name <code>hasStickyHeaders</code>.</li>
<li>When the sticky table header cells are processed, this parameter is a jQuery object pointing to a copy of the table that is used as a sticky header; this table has the class name <code>containsStickyHeaders</code>.</li>
</ul>
</li>
</ul>
<span class="label label-info">Note</span> Any defined <a href="index.html#onrendertemplate"><code>onRenderTemplate</code></a> function is <em>not</em> called on the sticky header because it is a clone of the already rendered header cell; instead use <code>onRenderHeader</code> to attach event listeners, etc.
</li>
<li>Removed jQuery UI theme from the theme selector in this demo to accomodate adding the accordion. With the current setup, changing the table theme would continue to show the jQuery UI class names on the table (uitheme is not removed when switching themes), so the tables became a chimera of jQuery UI and the selected theme, and the accordion would become un-styled; it was a real mess.<br>
<br>
</li>
</ul>
</li>
<li><span class="version">v2.14.4</span>: Added <code>cssStickyHeaders_attachTo</code> option (default set to <code>null</code>).
<ul>
<li>Setting this option with either a jQuery selector string (<code>&quot;.wrapper&quot;</code>) or jQuery object (<code>$(&quot;.wrapper&quot;)</code>).</li>
<li>This option contains the target to which the sticky header will attach - see the <a href="#table2">second example</a> below.</li>
</ul>
</li>
<li>v2.9:
<ul>
<li><strong>As of tablesorter version 2.9+, this widget can no longer be applied to versions of tablesorter prior to version 2.8</strong>.</li>
<li>Added a widget option named <code>stickyHeaders_cloneId</code>
<ul>
<li>It contains a suffix to add to any table id.</li>
<li>Its default value is <code>-sticky</code> </li>
</ul>
</li>
<li>Table captions and any additional rows (filter widget row) will also be included in the sticky header.</li>
</ul>
</li>
<li>v2.7: You will need to modify the <code>headerTemplate</code> option to include the jQuery UI icon! See the example in the code.</li>
<li>v2.1.18: Add the class name <code>sticky-false</code> to any header rows you don't want to become sticky.</li>
<li>v2.1.17: Multiple rows in the header will become sticky.</li>
<li>v2.1 (updated v2.11): Added a widget option named <code>stickyHeaders</code> option which contains the css class name applied to the actual sticky header. Modified in <span class="version">v2.11</span> so that "tablesorter-stickyHeader" class is always added and this option only adds additional classes.</li>
</ul>
</div>
</div>
<h1>CSS</h1>
<div id="css">
@ -163,13 +354,11 @@ $(function() {
<h1>Demo</h1>
Choose Theme:
<select>
<option value="jui">Jquery UI</option>
</select>
<select></select>
<br><br>
<table id="table1" class="tablesorter">
<caption>Student Grades</caption>
<caption class="dark-row">Student Grades</caption> <!-- dark-row used by metro-dark theme to make the header row darker -->
<thead>
<tr><th>Name</th><th>Major</th><th>Sex</th><th>English</th><th>Japanese</th><th>Calculus</th><th class="filter-false sorter-false">Geometry</th></tr>
</thead>
@ -233,7 +422,7 @@ $(function() {
<div class="narrow-block wrapper">
<table id="table2" class="tablesorter">
<caption>Student Grades</caption>
<caption class="dark-row">Student Grades</caption>
<thead>
<tr><th>Account #</th><th>First Name</th><th>Last Name</th><th>Age</th><th>Total</th><th>Discount</th><th>Diff</th></tr>
</thead>
@ -257,6 +446,135 @@ $(function() {
</table>
</div>
<table id="table3" class="tablesorter">
<thead>
<tr>
<th>Main table header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Main table - row 1</td>
</tr>
<tr>
<td>Main table - row 2</td>
</tr>
<tr>
<td>
<table id="nested1" class="nested">
<thead>
<tr>
<th>Header for the nested table 1</th>
</tr>
<tr>
<th class="sorter-false">Second header row for nested table 1</th>
</tr>
</thead>
<tbody>
<tr><td>data in the nested table 1 - row 1</td></tr>
<tr><td>data in the nested table 1 - row 2</td></tr>
<tr><td>data in the nested table 1 - row 3</td></tr>
<tr><td>data in the nested table 1 - row 4</td></tr>
<tr><td>data in the nested table 1 - row 5</td></tr>
<tr>
<td>
<table id="nested2" class="nested">
<caption class="dark-row">Nested table 2 caption</caption>
<thead>
<tr>
<th>Header for the nested table 2</th>
</tr>
<tr">
<th class="sorter-false">Second header row for nested table 2</th>
</tr>
</thead>
<tbody>
<tr><td>data in the nested table 2 - row 1</td></tr>
<tr><td>data in the nested table 2 - row 2</td></tr>
<tr><td>data in the nested table 2 - row 3</td></tr>
<tr><td>data in the nested table 2 - row 4</td></tr>
<tr><td>data in the nested table 2 - row 5</td></tr>
<tr><td>data in the nested table 2 - row 6</td></tr>
<tr><td>data in the nested table 2 - row 7</td></tr>
<tr><td>data in the nested table 2 - row 8</td></tr>
<tr><td>data in the nested table 2 - row 9</td></tr>
<tr><td>data in the nested table 2 - row 10</td></tr>
<tr><td>data in the nested table 2 - row 11</td></tr>
<tr><td>data in the nested table 2 - row 12</td></tr>
<tr><td>data in the nested table 2 - row 13</td></tr>
<tr><td>data in the nested table 2 - row 14</td></tr>
<tr><td>data in the nested table 2 - row 15</td></tr>
<tr><td>data in the nested table 2 - row 16</td></tr>
<tr><td>data in the nested table 2 - row 17</td></tr>
<tr><td>data in the nested table 2 - row 18</td></tr>
<tr><td>data in the nested table 2 - row 19</td></tr>
<tr><td>data in the nested table 2 - row 20</td></tr>
</tbody>
</table>
</td>
</tr>
<tr><td>data in the nested table 1 - row 6</td></tr>
<tr><td>data in the nested table 1 - row 7</td></tr>
<tr><td>data in the nested table 1 - row 8</td></tr>
<tr><td>data in the nested table 1 - row 9</td></tr>
<tr><td>data in the nested table 1 - row 10</td></tr>
<tr><td>data in the nested table 1 - row 11</td></tr>
<tr><td>data in the nested table 1 - row 12</td></tr>
<tr><td>data in the nested table 1 - row 13</td></tr>
<tr><td>data in the nested table 1 - row 14</td></tr>
<tr><td>data in the nested table 1 - row 15</td></tr>
<tr><td>data in the nested table 1 - row 16</td></tr>
<tr><td>data in the nested table 1 - row 17</td></tr>
<tr><td>data in the nested table 1 - row 18</td></tr>
<tr><td>data in the nested table 1 - row 19</td></tr>
<tr><td>data in the nested table 1 - row 20</td></tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>Main table - row 3</td>
</tr>
<tr>
<td>
<table id="nested3" class="nested">
<caption class="dark-row">Nested table 3 caption</caption>
<thead>
<tr>
<th>Header for the nested table 3</th>
</tr>
</thead>
<tbody>
<tr><td>data in the nested table 3 - row 1</td></tr>
<tr><td>data in the nested table 3 - row 2</td></tr>
<tr><td>data in the nested table 3 - row 3</td></tr>
<tr><td>data in the nested table 3 - row 4</td></tr>
<tr><td>data in the nested table 3 - row 5</td></tr>
<tr><td>data in the nested table 3 - row 6</td></tr>
<tr><td>data in the nested table 3 - row 7</td></tr>
<tr><td>data in the nested table 3 - row 8</td></tr>
<tr><td>data in the nested table 3 - row 9</td></tr>
<tr><td>data in the nested table 3 - row 10</td></tr>
<tr><td>data in the nested table 3 - row 11</td></tr>
<tr><td>data in the nested table 3 - row 12</td></tr>
<tr><td>data in the nested table 3 - row 13</td></tr>
<tr><td>data in the nested table 3 - row 14</td></tr>
<tr><td>data in the nested table 3 - row 15</td></tr>
<tr><td>data in the nested table 3 - row 16</td></tr>
<tr><td>data in the nested table 3 - row 17</td></tr>
<tr><td>data in the nested table 3 - row 18</td></tr>
<tr><td>data in the nested table 3 - row 19</td></tr>
<tr><td>data in the nested table 3 - row 20</td></tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>Main table - row 4</td>
</tr>
</tbody>
</table>
<div class="spacer"></div>
<div class="next-up">
<hr />

View File

@ -510,9 +510,9 @@
<li><span class="results">&dagger;</span> <a href="example-widget-savesort.html">Save sort widget</a> (v2.0.27)</li>
<li><a href="example-widget-scroller.html">Scroller widget</a> (<span class="version">v2.9</span>; <span class="version updated">v2.17.3</span>).</li>
<li><span class="label label-info">Beta</span> <a href="example-widget-static-row.html">StaticRow widget</a> (<span class="version">v2.16</span>; <span class="version updated">v2.17.3</span>).</li>
<li><span class="results">&dagger;</span> <a href="example-widget-sticky-header.html">Sticky header widget</a> (v2.0.21.1; <span class="version updated">v2.16.2</span>)</li>
<li><a href="example-widget-css-sticky-header.html">Sticky header (css3) widget</a> (<span class="version">v2.14.2</span>; <span class="version updated">v2.16.4</span>).</li>
<li><span class="results">&dagger;</span> UITheme widget (<span class="version updated">v2.17.4</span>):
<li><span class="results">&dagger;</span> <a href="example-widget-sticky-header.html">Sticky header widget</a> (v2.0.21.1; <span class="version updated">v2.18.0</span>)</li>
<li><a href="example-widget-css-sticky-header.html">Sticky header (css3) widget</a> (<span class="version">v2.14.2</span>; <span class="version updated">v2.18.0</span>).</li>
<li><span class="results">&dagger;</span> UITheme widget (<span class="version updated">v2.17.4</span>; <span class="version updated">v2.18.0</span>):
<ul>
<li><a href="example-widget-ui-theme.html">jQuery UI theme</a> (v2.0.9)</li>
<li><a href="example-widget-bootstrap-theme.html">Bootstrap</a> (v2.4)</li>
@ -1413,7 +1413,7 @@ From the example function above, you'll end up with something similar to this HT
<td><a href="#" class="permalink">theme</a></td>
<td>String</td>
<td>&quot;default&quot;</td>
<td>This option will add a theme css class name to the table <code>&quot;tablesorter-{theme}&quot;</code> for styling (v2.4; <span class="version updated">v2.16.4</span>).
<td>This option will add a theme css class name to the table <code>&quot;tablesorter-{theme}&quot;</code> for styling (v2.4; <span class="version updated">v2.18.0</span>).
<div class="collapsible">
<br>When changing this theme option, make sure that the appropriate css theme file has also been loaded. Included theme files include:
<a href="themes.html" target="_blank" title="open themes in a new window">see all themes</a><br>
@ -1724,7 +1724,11 @@ $(function(){
// extra class name added to the sticky header row
stickyHeaders : '',
// jQuery selector or object to attach sticky header to
stickyHeaders_attachTo : null
stickyHeaders_attachTo : null,
// jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
stickyHeaders_xScroll : null,
// jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
stickyHeaders_yScroll : null,
// number or jquery selector targeting the position:fixed element
stickyHeaders_offset : 0,
// scroll table top into view after filtering
@ -1736,7 +1740,7 @@ $(function(){
// if false and a caption exist, it won't be included in the sticky header
stickyHeaders_includeCaption : true,
// The zIndex of the stickyHeaders, allows the user to adjust this to their needs
stickyHeaders_zIndex : 2
stickyHeaders_zIndex : 2,
// *** resizable widget ***
// if false, resized columns are not saved for next page reload
@ -2971,6 +2975,54 @@ $('table').trigger('search', false);</pre></div>
<td><a href="example-widget-sticky-header.html">Example</a></td>
</tr>
<tr id="widget-sticky-headers-xscroll">
<td><a href="#" class="permalink">stickyHeaders_xScroll</a></td>
<td>String</td>
<td>null</td>
<td>
Sticky Headers widget: points to the element in which to monitor for horizontal scrolling (<span class="version">v2.18.0</span>).
<div class="collapsible">
<br>
If undefined (or <code>null</code>), the window element will be monitored.<br>
<br>
Use the <a href="#widget-sticky-headers-xscroll"><code>stickyHeaders_xScroll</code></a> option as follows:<br>
<pre class="prettyprint lang-js">$(function(){
$("table").tablesorter({
widgets: ["stickyHeaders"],
widgetOptions : {
// jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
stickyHeaders_xScroll : '.wrapper' // $('.wrapper') jQuery object can also be used
}
});
});</pre></div>
</td>
<td><a href="example-widget-sticky-header.html">Example</a></td>
</tr>
<tr id="widget-sticky-headers-yscroll">
<td><a href="#" class="permalink">stickyHeaders_yScroll</a></td>
<td>String</td>
<td>null</td>
<td>
Sticky Headers widget: points to the element in which to monitor for vertical scrolling (<span class="version">v2.18.0</span>).
<div class="collapsible">
<br>
If undefined (or <code>null</code>), the window element will be monitored.<br>
<br>
Use the <a href="#widget-sticky-headers-yscroll"><code>stickyHeaders_yScroll</code></a> option as follows:<br>
<pre class="prettyprint lang-js">$(function(){
$("table").tablesorter({
widgets: ["stickyHeaders"],
widgetOptions : {
// jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
stickyHeaders_yScroll : '.wrapper' // $('.wrapper') jQuery object can also be used
}
});
});</pre></div>
</td>
<td><a href="example-widget-sticky-header.html">Example</a></td>
</tr>
<tr id="widget-sticky-headers-offset">
<td><a href="#" class="permalink">stickyHeaders_offset</a></td>
<td>Multiple</td>

View File

@ -9,8 +9,8 @@
* [ "columns", "filter", "resizable", "stickyHeaders", "uitheme", "saveSort" ]
*/
/*jshint browser:true, jquery:true, unused:false, loopfunc:true */
/*global jQuery: false, localStorage: false, navigator: false */
;(function($) {
/*global jQuery: false, localStorage: false */
;(function ($, window) {
"use strict";
var ts = $.tablesorter = $.tablesorter || {};
@ -55,7 +55,8 @@ $.extend(ts.css, {
wrapper : 'tablesorter-wrapper', // ui theme & resizable
resizer : 'tablesorter-resizer', // resizable
sticky : 'tablesorter-stickyHeader', // stickyHeader
stickyVis : 'tablesorter-sticky-visible'
stickyVis : 'tablesorter-sticky-visible',
stickyWrap: 'tablesorter-sticky-wrapper'
});
// *** Store data in local storage, with a cookie fallback ***
@ -1536,6 +1537,8 @@ ts.addWidget({
options: {
stickyHeaders : '', // extra class name added to the sticky header row
stickyHeaders_attachTo : null, // jQuery selector or object to attach sticky header to
stickyHeaders_xScroll : null, // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
stickyHeaders_yScroll : null, // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
stickyHeaders_offset : 0, // number or jquery selector targeting the position:fixed element
stickyHeaders_filteredToTop: true, // scroll table top into view after filtering
stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists
@ -1549,54 +1552,74 @@ ts.addWidget({
return;
}
var $table = c.$table,
$attach = $(wo.stickyHeaders_attachTo || 'window'),
$attach = $(wo.stickyHeaders_attachTo),
namespace = c.namespace + 'stickyheaders ',
// element to watch for the scroll event
$yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window),
$xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window),
$thead = $table.children('thead:first'),
$win = $attach.length ? $attach : $(window),
$header = $thead.children('tr').not('.sticky-false').children(),
innerHeader = '.' + ts.css.headerIn,
$tfoot = $table.find('tfoot'),
$tfoot = $table.children('tfoot'),
$stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '',
stickyOffset = $attach.length ? 0 : $stickyOffset.length ?
$stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0,
// is this table nested? If so, find parent sticky header wrapper (div, not table)
$nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ?
$table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [],
nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0,
// clone table, then wrap to make sticky header
$stickyTable = wo.$sticky = $table.clone()
.addClass('containsStickyHeaders')
.css({
position : $attach.length ? 'absolute' : 'fixed',
margin : 0,
top : stickyOffset,
left : 0,
visibility : 'hidden',
zIndex : wo.stickyHeaders_zIndex ? wo.stickyHeaders_zIndex : 2
}),
$stickyThead = $stickyTable.children('thead:first').addClass(ts.css.sticky + ' ' + wo.stickyHeaders),
.addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders)
.wrap('<div class="' + ts.css.stickyWrap + '">'),
$stickyWrap = $stickyTable.parent().css({
position : $attach.length ? 'absolute' : 'fixed',
margin : 0,
top : stickyOffset + nestedStickyTop,
left : 0,
visibility : 'hidden',
zIndex : wo.stickyHeaders_zIndex || 2
}),
$stickyThead = $stickyTable.children('thead:first'),
$stickyCells,
laststate = '',
spacing = 0,
nonwkie = $table.css('border-collapse') !== 'collapse' && !/(webkit|msie)/i.test(navigator.userAgent),
setWidth = function($orig, $clone){
$orig.filter(':visible').each(function(i) {
var width, border,
$cell = $clone.filter(':visible').eq(i),
$this = $(this);
// code from https://github.com/jmosbech/StickyTableHeaders
if ($this.css('box-sizing') === 'border-box') {
width = $this.outerWidth();
} else {
if ($cell.css('border-collapse') === 'collapse') {
if (window.getComputedStyle) {
width = parseFloat( window.getComputedStyle(this, null).width );
} else {
// ie8 only
border = parseFloat( $this.css('border-width') );
width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border;
}
} else {
width = $this.width();
}
}
$cell.css({
'min-width': width,
'max-width': width
});
});
},
resizeHeader = function() {
stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0;
spacing = 0;
// yes, I dislike browser sniffing, but it really is needed here :(
// webkit automatically compensates for border spacing
if (nonwkie) {
// Firefox & Opera use the border-spacing
// update border-spacing here because of demos that switch themes
spacing = parseInt($header.eq(0).css('border-left-width'), 10) * 2;
}
$stickyTable.css({
left : $attach.length ? (parseInt($attach.css('padding-left'), 10) || 0) + parseInt(c.$table.css('padding-left'), 10) +
parseInt(c.$table.css('margin-left'), 10) + parseInt($table.css('border-left-width'), 10) :
$thead.offset().left - $win.scrollLeft() - spacing,
width: $table.width()
});
$stickyCells.filter(':visible').each(function(i) {
var $cell = $header.filter(':visible').eq(i),
// some wibbly-wobbly... timey-wimey... stuff, to make columns line up in Firefox
offset = nonwkie && $(this).attr('data-column') === ( '' + parseInt(c.columns/2, 10) ) ? 1 : 0;
$(this)
.css({ width: $cell.width() - spacing })
.find(innerHeader).width( $cell.find(innerHeader).width() - offset );
$stickyWrap.css({
left : $attach.length ? parseInt($attach.css('padding-left'), 10) || 0 :
$table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing,
width: $table.outerWidth()
});
setWidth( $table, $stickyTable );
setWidth( $header, $stickyCells );
};
// fix clone ID, if it exists - fixes #271
if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.stickyHeaders_cloneId; }
@ -1606,42 +1629,60 @@ ts.addWidget({
$stickyTable.find('tbody, tfoot').remove();
if (!wo.stickyHeaders_includeCaption) {
$stickyTable.find('caption').remove();
} else {
$stickyTable.find('caption').css( 'margin-left', '-1px' );
}
// issue #172 - find td/th in sticky header
$stickyCells = $stickyThead.children().children();
$stickyTable.css({ height:0, width:0, padding:0, margin:0, border:0 });
$stickyTable.css({ height:0, width:0, margin: 0 });
// remove resizable block
$stickyCells.find('.' + ts.css.resizer).remove();
// update sticky header class names to match real header after sorting
$table
.addClass('hasStickyHeaders')
.bind('pagerComplete.tsSticky', function() {
.bind('pagerComplete' + namespace, function() {
resizeHeader();
});
ts.bindEvents(table, $stickyThead.children().children('.tablesorter-header'));
// add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned.
$table.after( $stickyTable );
$table.after( $stickyWrap );
// onRenderHeader is defined, we need to do something about it (fixes #641)
if (c.onRenderHeader) {
$stickyThead.children('tr').children().each(function(index){
// send second parameter
c.onRenderHeader.apply( $(this), [ index, c, $stickyTable ] );
});
}
// make it sticky!
$win.bind('scroll.tsSticky resize.tsSticky', function(event) {
$xScroll.add($yScroll)
.unbind('scroll resize '.split(' ').join( namespace ) )
.bind('scroll resize '.split(' ').join( namespace ), function(event) {
if (!$table.is(':visible')) { return; } // fixes #278
// Detect nested tables - fixes #724
nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
var prefix = 'tablesorter-sticky-',
offset = $table.offset(),
captionHeight = (wo.stickyHeaders_includeCaption ? 0 : $table.find('caption').outerHeight(true)),
scrollTop = ($attach.length ? $attach.offset().top : $win.scrollTop()) + stickyOffset - captionHeight,
tableHeight = $table.height() - ($stickyTable.height() + ($tfoot.height() || 0)),
isVisible = (scrollTop > offset.top) && (scrollTop < offset.top + tableHeight) ? 'visible' : 'hidden',
yWindow = $.isWindow( $yScroll[0] ),
xWindow = $.isWindow( $xScroll[0] ),
// scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)),
isVisible = ( scrollTop > offset.top) && (scrollTop < offset.top + tableHeight) ? 'visible' : 'hidden',
cssSettings = { visibility : isVisible };
if ($attach.length) {
cssSettings.top = $attach.scrollTop();
} else {
// adjust when scrolling horizontally - fixes issue #143
cssSettings.left = $thead.offset().left - $win.scrollLeft() - spacing;
cssSettings.top = yWindow ? scrollTop : $attach.scrollTop();
}
$stickyTable
if (xWindow) {
// adjust when scrolling horizontally - fixes issue #143
cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing;
}
if ($nestedSticky.length) {
cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
}
$stickyWrap
.removeClass(prefix + 'visible ' + prefix + 'hidden')
.addClass(prefix + isVisible)
.css(cssSettings);
@ -1656,14 +1697,14 @@ ts.addWidget({
}
// look for filter widget
if ($table.hasClass('hasFilters')) {
if ($table.hasClass('hasFilters') && wo.filter_columnFilters) {
// scroll table into view after filtering, if sticky header is active - #482
$table.bind('filterEnd', function() {
$table.bind('filterEnd' + namespace, function() {
// $(':focus') needs jQuery 1.6+
var $td = $(document.activeElement).closest('td'),
column = $td.parent().children().index($td);
// only scroll if sticky header is active
if ($stickyTable.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) {
if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) {
// scroll to original table (not sticky clone)
window.scrollTo(0, $table.position().top);
// give same input/select focus; check if c.$filters exists; fixes #594
@ -1683,14 +1724,16 @@ ts.addWidget({
},
remove: function(table, c, wo) {
var namespace = c.namespace + 'stickyheaders ';
c.$table
.removeClass('hasStickyHeaders')
.unbind('pagerComplete.tsSticky')
.find('.' + ts.css.sticky).remove();
.unbind( 'pagerComplete filterEnd '.split(' ').join(namespace) )
.next('.' + ts.css.stickyWrap).remove();
if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
// don't unbind if any table on the page still has stickyheaders applied
if (!$('.hasStickyHeaders').length) {
$(window).unbind('scroll.tsSticky resize.tsSticky');
$(window).add(wo.stickyHeaders_xScroll).add(wo.stickyHeaders_yScroll).add(wo.stickyHeaders_attachTo)
.unbind( 'scroll resize '.split(' ').join(namespace) );
}
ts.addHeaderResizeEvent(table, false);
}
@ -1925,4 +1968,4 @@ ts.addWidget({
}
});
})(jQuery);
})(jQuery, window);

View File

@ -3,66 +3,93 @@
*/
/*jshint jquery:true, unused:false */
;(function($){
"use strict";
'use strict';
$.tablesorter.addWidget({
id: "cssStickyHeaders",
var ts = $.tablesorter;
ts.addWidget({
id: 'cssStickyHeaders',
priority: 10,
options: {
cssStickyHeaders_offset : 0,
cssStickyHeaders_addCaption : false,
// jQuery selector or object to attach sticky header to
cssStickyHeaders_attachTo : null,
cssStickyHeaders_filteredToTop : true,
cssStickyHeaders_zIndex : 10
cssStickyHeaders_filteredToTop : true
},
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 isIE = 'ActiveXObject' in window, // target all versions of IE
$table = c.$table,
$attach = $(wo.cssStickyHeaders_attachTo),
namespace = c.namespace + 'cssstickyheader ',
$thead = $table.children('thead'),
$caption = $table.children('caption'),
$win = $attach.length ? $attach : $(window),
$parent = $table.parent().closest('table.' + ts.css.table),
$parentThead = $parent.length && ts.hasWidget($parent[0], 'cssStickyHeaders') ? $parent.children('thead') : [];
$win
.unbind('scroll resize '.split(' ').join(namespace))
.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();
captionHeight = wo.cssStickyHeaders_addCaption ? ( $caption.outerHeight(true) || 0 ) +
( parseInt( $table.css('padding-top'), 10 ) || 0 ) + ( parseInt( $table.css('border-spacing'), 10 ) || 0 ) : 0,
bottom = $table.height() - $thead.height() - ( $table.children('tfoot').height() || 0 ) - captionHeight,
// get bottom of nested sticky headers
nestedStickyTop = $parentThead.length ? ( isIE ? $parent.data('cssStickyHeaderTop') : $parentThead.offset().top ) +
$parentThead.height() - $win.scrollTop() : 0,
// Detect nested tables - fixes #724
deltaY = top - $table.offset().top + nestedStickyTop + ( parseInt( $table.css('border-top-width'), 10 ) || 0 ) +
// Again, I dislike browser sniffing... but I have no idea why I need to include a captionHeight
// for Firefox here and not for Chrome. Even IE behaves, sorta!
( wo.cssStickyHeaders_offset || 0 ) + ( navigator.userAgent.toLowerCase().indexOf('firefox') > -1 ? captionHeight : 0 ),
finalY = deltaY > 0 && deltaY <= bottom ? deltaY : 0,
// All IE (even IE11) can only transform header cells - fixes #447 thanks to @gakreol!
$cells = isIE ? $thead.children().children() : $thead;
// more crazy IE stuff.. somehow the second nested table is completely ignored
if (isIE) {
c.$table.data('cssStickyHeaderTop', finalY - ( $parentThead.length ? $parentThead.height() : 0 ));
if ($parentThead.length) {
top = $parent.data('cssStickyHeaderTop') - $parentThead.height();
finalY = top > 0 && top <= bottom ? top : 0;
}
}
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)"
'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() {
$table.unbind('filterEnd' + namespace).bind('filterEnd' + namespace, function() {
if (wo.cssStickyHeaders_filteredToTop) {
// scroll top of table into view
window.scrollTo(0, c.$table.position().top);
window.scrollTo(0, $table.position().top);
}
});
},
remove: function(table, c, wo){
var namespace = '.cssstickyheader';
$(window).unbind('scroll resize '.split(' ').join(namespace + ' '));
var namespace = c.namespace + 'cssstickyheader ';
$(window).unbind('scroll resize '.split(' ').join(namespace));
c.$table
.unbind('update updateAll '.split(' ').join(namespace + ' '))
.unbind('filterEnd scroll resize '.split(' ').join(namespace))
.add( c.$table.children('thead').children().children() )
.children('thead, caption').css({
"position" : "",
"z-index" : "",
"transform" : "",
"-ms-transform" : "",
"-webkit-transform" : ""
'transform' : '',
'-ms-transform' : '',
'-webkit-transform' : ''
});
}
});