Scroller: lots of updates

* Support multiple tbodies. See #906
* Limit horizontal scrollbar to scrolling section
* Removed widthFixed requirement
* Update RTL support
* Fix column alignment. Fixes #913
* Fix mousewheel scrolling in Firefox. See #135
* Fix filter returning zero to few rows
* Integrate with pager. Fixes #884
This commit is contained in:
Mottie 2015-05-28 11:30:49 -05:00
parent a153bea128
commit 7c46c9e02e
2 changed files with 657 additions and 312 deletions

View File

@ -33,7 +33,39 @@
<script src="../js/jquery.tablesorter.widgets.js"></script>
<script src="../js/widgets/widget-scroller.js"></script>
<style id="css">/* OPTIONAL CSS! */
<style id="css">/* Fixed column scroll bar spacer styling */
.tablesorter-scroller-bar-spacer {
background: #eee;
}
/* add border to right side (LTR pages) of fixed column */
.tablesorter-scroller-fixed:after {
content: '';
border-right: 1px solid #444;
width: 1px;
position: absolute;
top: 0;
bottom: 0;
z-index: 2;
/* set to zero for non-jquery ui themes; use "left" here for RTL pages */
right: 0;
/* match the margins set to the table to keep the border the same height as the table */
margin: 10px 0 15px;
}
/* using-x-theme added by the demo code */
.using-jui-theme .tablesorter-scroller-fixed:after {
/* set to -2px for jquery ui themes; use "left" here for RTL pages */
right: -2px;
}
.using-green-theme .tablesorter-scroller-fixed:after,
.using-black-ice-theme .tablesorter-scroller-fixed:after,
.using-dark-theme .tablesorter-scroller-fixed:after,
.using-dropbox-theme .tablesorter-scroller-fixed:after {
/* match the margins set to the table to keep the border the same height as the table */
margin: 0;
}
/* OPTIONAL CSS! */
#fixed-columns-table tbody td {
/* force "Notes" column to not wrap, so we get a horizontal scrolling demo! */
white-space: nowrap;
@ -45,7 +77,6 @@
$('.tablesorter').tablesorter({
theme: 'jui',
// widthFixed: true, // <- now automatically set by the scroller widget
showProcessing: true,
headerTemplate : '{content} {icon}',
widgets: [ 'uitheme', 'zebra', 'filter', 'scroller' ],
@ -69,13 +100,19 @@
headerTemplate : '{content} {icon}',
widgets: [ 'uitheme', 'zebra', 'filter', 'scroller' ],
widgetOptions : {
scroller_jumpToHeader : false,
scroller_upAfterSort : false,
scroller_height : 300,
// set number of columns to fix
scroller_fixedColumns : 2,
// add a fixed column overlay for styling
scroller_addFixedOverlay : false,
// add hover highlighting to the fixed column (disable if it causes slowing)
scroller_rowHighlight : 'hover'
scroller_rowHighlight : 'hover',
// bar width is now calculated; set a value to override
scroller_barWidth : null
}
});
@ -119,6 +156,9 @@ $(function() {
.change(function(){
var theme = $(this).val().toLowerCase();
// add class so the black border fits the theme
$('#main').attr( 'class', 'using-' + theme + '-theme' );
// refresh uitheme widget class names
$('#main .tablesorter').each(function(){
if (this.config) {
@ -170,6 +210,39 @@ $(function() {
<h3><a href="#">Notes</a></h3>
<div>
<ul>
<li>In <span class="version">v2.22.2</span>,
<ul>
<li>Add support for multiple tbodies in fixed columns:
<ul>
<li><span class="label warning">*WARN*</span> <code>colspan</code>s within information only tbodies are still problematic!</li>
<li>If a <code>colspan</code> is to be used with fixed columns, then split it so that the <code>colspan</code> splits at the edge of fixed column; e.g. for a table with 10 columns and 2 fixed columns, split the original table cell with a colspan of 10 into two table cells of that have colspans of 2 and 8.</li>
</ul>
</li>
<li>The horizontal scrollbar no longer appears under the fixed column:
<ul>
<li>There is now a gap visible below the content when scrolled to the bottom.</li>
<li>This gap is filled by a div and can be styled by targeting the <code>tablesorter-scroller-bar-spacer</code> class name. See the css code block for an example.</li>
</ul>
</li>
<li>Removed:
<ul>
<li>The automatic setting of the <code>widthFixed</code> option to <code>true</code>.</li>
<li>Extra <code>colgroup</code> which were copied into each table clone.</li>
<li>Extra hidden elements in the fixed column.</li>
</ul>
</li>
<li>Updated RTL (right-to-left) support:
<ul>
<li>Changed the default class from <code>tablesorter-scroller-rtl</code> to <code>ts-scroller-rtl</code>, which is added to the table element to indicate where the fixed column is placed.</li>
<li>RTL support <em>does require</em> the <code>direction: rtl</code> css setting to be applied to the table wrapper.</li>
</ul>
</li>
<li>Fixed slow mousewheel scrolling when a fixed column is active in Firefox &amp; older versions of Internet Explorer.</li>
<li>Fixed filtering of table content causing the fixed column to misalign; especially when few to no results are found.</li>
<li>The scroller now integrates smoothly with the pager widget.</li>
<li>Thanks to <a href="https://github.com/TheSin-">TheSin-</a> for all the work he put into updating this widget... he really didn't like that scrollbar under the fixed column LOL.</li>
</ul>
</li>
<li>In <span class="version">v2.22.0</span>,
<ul>
<li>Horizontal scrollbar now only appears on overflow.</li>
@ -182,6 +255,12 @@ $(function() {
<li>Refresh column sizes after update.</li>
</ul>
</li>
</ul>
<div class="accordion start-closed">
<h3><a href="#">Older Notes</a></h3>
<div>
<ul>
<li>In <span class="version">v2.21.3</span>
<ul>
<li><span class="label warning">* NOTE *</span> Prior to v2.21.3, this widget would work with jQuery v1.4.4+, now it requires <em>jQuery v1.7+</em>.</li>
@ -221,7 +300,11 @@ $(function() {
<li>Added <code>scroller_upAfterSort</code> option.</li>
</ul>
</li>
<li>This widget can not be applied to the original plugin and requires jQuery version 1.4+ to function properly; if you need to make it work with older versions of jQuery and the plugin, please use <a href="http://tconnell.com/samples/scroller/">this version</a> of the widget.</li>
</ul>
</div>
</div> <!-- end older Notes accordion -->
<ul>
<li>This widget <em>can not</em> be applied to the original plugin and requires jQuery version 1.7+ to function properly; if you need to make it work with older versions of jQuery and the plugin, please use <a href="http://tconnell.com/samples/scroller/">this version</a> of the widget.</li>
<li>This widget was originally written by <a href="http://tconnell.com/samples/scroller/">Connell & Associates, Inc.</a> and is dual-licensed under the MIT and GPL licenses. It has been modified to work with tablesorter version 2.9+.</li>
</ul>
</div>
@ -284,10 +367,11 @@ $(function() {
<tr id="scroller-fixed-columns">
<td><a href="#" class="permalink">scroller_fixedColumns</a></td>
<td>0</td>
<td>This allows setting the number of fixed columns to add to the scroller (<span class="version">v2.21.3</span>).
<td>This allows setting the number of fixed columns to add to the scroller (<span class="version">v2.21.3</span>; <span class="version updated">v2.22.2</span>).
<div class="collapsible">
<p>It's not 100% pixel-perfect in alignment, especially not with a jQuery UI theme, but it looks good with the other themes.</p>
<p>If the content is set a RTL direction, add a class name of <code>tablesorter-scroller-rtl</code> (name set in <code>$.tablesorter.css.scrollerRtl</code>) to the table to align the fixed header on the right.</p>
<p>If the content is set a RTL direction, add a class name of <code>ts-scroller-rtl</code><span class="results">&dagger;</span> (name set in <code>$.tablesorter.css.scrollerRtl</code>) to the table to align the fixed header on the right.</p>
<p><span class="results">&dagger;</span> default value changed in <span class="version updated">v2.22.2</span> because tablesorter is set up to assume a theme name has already been added to the table when it encounters a class name starting with <code>tablesorter-</code>; if the original <code>tablesorter-scroller-rtl</code> class were added, the <code>theme</code> option setting would be ignored (because a theme named <code>scroller-rtl</code> is already set), and would require the developer to add the class name to the table (e.g. <code>tablesorter-blue</code>).</p>
<p> To change this method internally would require a breaking change where all css files would need to be updated and all theme classes would start with <code>tablesorter-theme-</code>; this will be planned for the <a href="https://github.com/tablesort/Abelt">Abelt</a> update.</p>
</div>
</td>
</tr>
@ -315,6 +399,22 @@ $(function() {
}</pre>
<p>* Demos by <a href="https://github.com/TheSin-">TheSin-</a> from <a href="https://github.com/Mottie/tablesorter/issues/887#issuecomment-101862175">issue 887</a>.</p>
<p><span class="label warning">*WARNING*</span> interacting with elements under this overlay requires that the browser supports <a href="http://caniuse.com/#search=pointer-events">pointer-events</a>.</p>
<hr>
<p><span class="label label-info">*NOTE*</span> Personally, I <em>would not recommend</em> setting this option to <code>true</code> because of the interference from the overlay - the following css will add a border to the fixed column using css3 <code>:after</code> to acheive the same effect.</p>
<pre class="prettyprint lang-css locked">/* add border to right side (LTR pages) of fixed column */
.tablesorter-scroller-fixed:after {
content: '';
border-right: 2px solid black;
width: 2px;
position: absolute;
top: 0;
bottom: 0;
z-index: 2;
/* change this to zero for non-jquery ui themes; and use "left" here for RTL pages */
right: -1px;
/* match the margins set to the table to keep the border the same height as the table */
margin: 10px 0 15px;
}</pre>
</div>
</td>
</tr>
@ -381,8 +481,8 @@ $(function() {
</div>
<h1>Demo</h1>
<p><a href="#wide-demo">Full-width</a> | <a href="#narrow-demo">Half-width</a> | <a href="#fixed-demo">Fixed columns</a></p>
<a id="wide-demo"></a>
<p><a href="#fixed-demo">Fixed columns</a> | <a href="#wide-demo">Full-width</a> | <a href="#narrow-demo">Half-width</a></p>
Choose Theme:
<select>
<option value="jui">Jquery UI</option>
@ -393,103 +493,6 @@ $(function() {
<button type="button">Toggle</button> scroller_upAfterSort : <span id="uas">true</span>
<p></p>
<table id="scroller1" class="tablesorter">
<thead>
<tr>
<th class="name">Name</th>
<th class="major">Major</th><th>Sex</th>
<th class="english">English</th>
<th class="japanese">Japanese</th>
<th class="calculus">Calculus</th>
<th class="geometry filter-false sorter-false">Geometry</th>
</tr>
</thead>
<tfoot>
<tr><th>Name</th><th>Major</th><th>Sex</th><th>English</th><th>Japanese</th><th>Calculus</th><th>Geometry</th></tr>
</tfoot>
<tbody>
<tr><td>Student01</td><td>Languages</td><td>male</td><td>80</td><td>70</td><td>75</td><td>80</td></tr>
<tr><td>Student02</td><td>Mathematics</td><td>male</td><td>90</td><td>88</td><td>100</td><td>90</td></tr>
<tr><td>Student03</td><td>Languages</td><td>female</td><td>85</td><td>95</td><td>80</td><td>85</td></tr>
<tr><td>Student04</td><td>Languages</td><td>male</td><td>60</td><td>55</td><td>100</td><td>100</td></tr>
<tr><td>Student05</td><td>Languages</td><td>female</td><td>68</td><td>80</td><td>95</td><td>80</td></tr>
<tr><td>Student06</td><td>Mathematics</td><td>male</td><td>100</td><td>99</td><td>100</td><td>90</td></tr>
<tr><td>Student07</td><td>Mathematics</td><td>male</td><td>85</td><td>68</td><td>90</td><td>90</td></tr>
<tr><td>Student08</td><td>Languages</td><td>male</td><td>100</td><td>90</td><td>90</td><td>85</td></tr>
<tr><td>Student09</td><td>Mathematics</td><td>male</td><td>80</td><td>50</td><td>65</td><td>75</td></tr>
<tr><td>Student10</td><td>Languages</td><td>male</td><td>85</td><td>100</td><td>100</td><td>90</td></tr>
<tr><td>Student11</td><td>Languages</td><td>male</td><td>86</td><td>85</td><td>100</td><td>100</td></tr>
<tr><td>Student12</td><td>Mathematics</td><td>female</td><td>100</td><td>75</td><td>70</td><td>85</td></tr>
<tr><td>Student13</td><td>Languages</td><td>female</td><td>100</td><td>80</td><td>100</td><td>90</td></tr>
<tr><td>Student14</td><td>Languages</td><td>female</td><td>50</td><td>45</td><td>55</td><td>90</td></tr>
<tr><td>Student15</td><td>Languages</td><td>male</td><td>95</td><td>35</td><td>100</td><td>90</td></tr>
<tr><td>Student16</td><td>Languages</td><td>female</td><td>100</td><td>50</td><td>30</td><td>70</td></tr>
<tr><td>Student17</td><td>Languages</td><td>female</td><td>80</td><td>100</td><td>55</td><td>65</td></tr>
<tr><td>Student18</td><td>Mathematics</td><td>male</td><td>30</td><td>49</td><td>55</td><td>75</td></tr>
<tr><td>Student19</td><td>Languages</td><td>male</td><td>68</td><td>90</td><td>88</td><td>70</td></tr>
<tr><td>Student20</td><td>Mathematics</td><td>male</td><td>40</td><td>45</td><td>40</td><td>80</td></tr>
<tr><td>Student21</td><td>Languages</td><td>male</td><td>50</td><td>45</td><td>100</td><td>100</td></tr>
<tr><td>Student22</td><td>Mathematics</td><td>male</td><td>100</td><td>99</td><td>100</td><td>90</td></tr>
<tr><td>Student23</td><td>Languages</td><td>female</td><td>85</td><td>80</td><td>80</td><td>80</td></tr>
<tr><td>student23</td><td>Mathematics</td><td>male</td><td>82</td><td>77</td><td>0</td><td>79</td></tr>
<tr><td>student24</td><td>Languages</td><td>female</td><td>100</td><td>91</td><td>13</td><td>82</td></tr>
<tr><td>student25</td><td>Mathematics</td><td>male</td><td>22</td><td>96</td><td>82</td><td>53</td></tr>
<tr><td>student26</td><td>Languages</td><td>female</td><td>37</td><td>29</td><td>56</td><td>59</td></tr>
<tr><td>student27</td><td>Mathematics</td><td>male</td><td>86</td><td>82</td><td>69</td><td>23</td></tr>
<tr><td>student28</td><td>Languages</td><td>female</td><td>44</td><td>25</td><td>43</td><td>1</td></tr>
<tr><td>student29</td><td>Mathematics</td><td>male</td><td>77</td><td>47</td><td>22</td><td>38</td></tr>
<tr><td>student30</td><td>Languages</td><td>female</td><td>19</td><td>35</td><td>23</td><td>10</td></tr>
<tr><td>student31</td><td>Mathematics</td><td>male</td><td>90</td><td>27</td><td>17</td><td>50</td></tr>
<tr><td>student32</td><td>Languages</td><td>female</td><td>60</td><td>75</td><td>33</td><td>38</td></tr>
<tr><td>student33</td><td>Mathematics</td><td>male</td><td>4</td><td>31</td><td>37</td><td>15</td></tr>
<tr><td>student34</td><td>Languages</td><td>female</td><td>77</td><td>97</td><td>81</td><td>44</td></tr>
<tr><td>student35</td><td>Mathematics</td><td>male</td><td>5</td><td>81</td><td>51</td><td>95</td></tr>
<tr><td>student36</td><td>Languages</td><td>female</td><td>70</td><td>61</td><td>70</td><td>94</td></tr>
<tr><td>student37</td><td>Mathematics</td><td>male</td><td>60</td><td>3</td><td>61</td><td>84</td></tr>
<tr><td>student38</td><td>Languages</td><td>female</td><td>63</td><td>39</td><td>0</td><td>11</td></tr>
<tr><td>student39</td><td>Mathematics</td><td>male</td><td>50</td><td>46</td><td>32</td><td>38</td></tr>
<tr><td>student40</td><td>Languages</td><td>female</td><td>51</td><td>75</td><td>25</td><td>3</td></tr>
<tr><td>student41</td><td>Mathematics</td><td>male</td><td>43</td><td>34</td><td>28</td><td>78</td></tr>
<tr><td>student42</td><td>Languages</td><td>female</td><td>11</td><td>89</td><td>60</td><td>95</td></tr>
<tr><td>student43</td><td>Mathematics</td><td>male</td><td>48</td><td>92</td><td>18</td><td>88</td></tr>
<tr><td>student44</td><td>Languages</td><td>female</td><td>82</td><td>2</td><td>59</td><td>73</td></tr>
<tr><td>student45</td><td>Mathematics</td><td>male</td><td>91</td><td>73</td><td>37</td><td>39</td></tr>
<tr><td>student46</td><td>Languages</td><td>female</td><td>4</td><td>8</td><td>12</td><td>10</td></tr>
<tr><td>student47</td><td>Mathematics</td><td>male</td><td>89</td><td>10</td><td>6</td><td>11</td></tr>
<tr><td>student48</td><td>Languages</td><td>female</td><td>90</td><td>32</td><td>21</td><td>18</td></tr>
<tr><td>student49</td><td>Mathematics</td><td>male</td><td>42</td><td>49</td><td>49</td><td>72</td></tr>
<tr><td>student50</td><td>Languages</td><td>female</td><td>56</td><td>37</td><td>67</td><td>54</td></tr>
</tbody>
</table>
<div id="narrow-demo" class="narrow-block">
<table class="tablesorter">
<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>
<tfoot>
<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>
</tfoot>
<tbody>
<tr><td>A43</td><td>Peter</td><td>Parker</td><td>28</td><td>9.99</td><td>20.3%</td><td>+3</td></tr>
<tr><td>A255</td><td>John</td><td>Hood</td><td>33</td><td>19.99</td><td>25.1%</td><td>-7</td></tr>
<tr><td>A33</td><td>Clark</td><td>Kent</td><td>18</td><td>15.49</td><td>44.2%</td><td>-13</td></tr>
<tr><td>A11</td><td>Bruce</td><td>Almighty</td><td>45</td><td>153.19</td><td>44%</td><td>+19</td></tr>
<tr><td>A102</td><td>Bruce</td><td>Evans</td><td>56</td><td>153.19</td><td>23%</td><td>+9</td></tr>
<tr><td>A23</td><td>Mike</td><td>Peters</td><td>22</td><td>5.69</td><td>20.3%</td><td>+2</td></tr>
<tr><td>A55</td><td>Leslie</td><td>Kent</td><td>33</td><td>15.99</td><td>25.1%</td><td>-3</td></tr>
<tr><td>A3</td><td>Frank</td><td>Mint</td><td>44</td><td>12.59</td><td>44.2%</td><td>-12</td></tr>
<tr><td>A21</td><td>Joe</td><td>Thomas</td><td>45</td><td>15.25</td><td>44%</td><td>+12</td></tr>
<tr><td>A12</td><td>Tess</td><td>Evans</td><td>66</td><td>13.59</td><td>23%</td><td>+4</td></tr>
<tr><td>A21</td><td>Peter</td><td>Dunn</td><td>12</td><td>2.99</td><td>21.1%</td><td>+2</td></tr>
<tr><td>A33</td><td>Harry</td><td>Jones</td><td>13</td><td>19.49</td><td>22.2%</td><td>-6</td></tr>
<tr><td>A13</td><td>John</td><td>James</td><td>16</td><td>13.89</td><td>42.1%</td><td>-13</td></tr>
<tr><td>A71</td><td>Nick</td><td>Parker</td><td>45</td><td>13.89</td><td>44%</td><td>+29</td></tr>
<tr><td>A21</td><td>Charles</td><td>Dunn</td><td>19</td><td>15.49</td><td>22%</td><td>+3</td></tr>
</tbody>
</table>
</div>
<h4 id="fixed-demo">
Fixed Column Demo<br>
<small>(Shrink the browser window if the horizontal scrollbar is not visible)</small>
@ -583,6 +586,105 @@ $(function() {
</tbody>
</table>
<h4 id="wide-demo">Full-width demo</h4>
<table id="scroller1" class="tablesorter">
<thead>
<tr>
<th class="name">Name</th>
<th class="major">Major</th><th>Sex</th>
<th class="english">English</th>
<th class="japanese">Japanese</th>
<th class="calculus">Calculus</th>
<th class="geometry filter-false sorter-false">Geometry</th>
</tr>
</thead>
<tfoot>
<tr><th>Name</th><th>Major</th><th>Sex</th><th>English</th><th>Japanese</th><th>Calculus</th><th>Geometry</th></tr>
</tfoot>
<tbody>
<tr><td>Student01</td><td>Languages</td><td>male</td><td>80</td><td>70</td><td>75</td><td>80</td></tr>
<tr><td>Student02</td><td>Mathematics</td><td>male</td><td>90</td><td>88</td><td>100</td><td>90</td></tr>
<tr><td>Student03</td><td>Languages</td><td>female</td><td>85</td><td>95</td><td>80</td><td>85</td></tr>
<tr><td>Student04</td><td>Languages</td><td>male</td><td>60</td><td>55</td><td>100</td><td>100</td></tr>
<tr><td>Student05</td><td>Languages</td><td>female</td><td>68</td><td>80</td><td>95</td><td>80</td></tr>
<tr><td>Student06</td><td>Mathematics</td><td>male</td><td>100</td><td>99</td><td>100</td><td>90</td></tr>
<tr><td>Student07</td><td>Mathematics</td><td>male</td><td>85</td><td>68</td><td>90</td><td>90</td></tr>
<tr><td>Student08</td><td>Languages</td><td>male</td><td>100</td><td>90</td><td>90</td><td>85</td></tr>
<tr><td>Student09</td><td>Mathematics</td><td>male</td><td>80</td><td>50</td><td>65</td><td>75</td></tr>
<tr><td>Student10</td><td>Languages</td><td>male</td><td>85</td><td>100</td><td>100</td><td>90</td></tr>
<tr><td>Student11</td><td>Languages</td><td>male</td><td>86</td><td>85</td><td>100</td><td>100</td></tr>
<tr><td>Student12</td><td>Mathematics</td><td>female</td><td>100</td><td>75</td><td>70</td><td>85</td></tr>
<tr><td>Student13</td><td>Languages</td><td>female</td><td>100</td><td>80</td><td>100</td><td>90</td></tr>
<tr><td>Student14</td><td>Languages</td><td>female</td><td>50</td><td>45</td><td>55</td><td>90</td></tr>
<tr><td>Student15</td><td>Languages</td><td>male</td><td>95</td><td>35</td><td>100</td><td>90</td></tr>
<tr><td>Student16</td><td>Languages</td><td>female</td><td>100</td><td>50</td><td>30</td><td>70</td></tr>
<tr><td>Student17</td><td>Languages</td><td>female</td><td>80</td><td>100</td><td>55</td><td>65</td></tr>
<tr><td>Student18</td><td>Mathematics</td><td>male</td><td>30</td><td>49</td><td>55</td><td>75</td></tr>
<tr><td>Student19</td><td>Languages</td><td>male</td><td>68</td><td>90</td><td>88</td><td>70</td></tr>
<tr><td>Student20</td><td>Mathematics</td><td>male</td><td>40</td><td>45</td><td>40</td><td>80</td></tr>
<tr><td>Student21</td><td>Languages</td><td>male</td><td>50</td><td>45</td><td>100</td><td>100</td></tr>
<tr><td>Student22</td><td>Mathematics</td><td>male</td><td>100</td><td>99</td><td>100</td><td>90</td></tr>
<tr><td>Student23</td><td>Languages</td><td>female</td><td>85</td><td>80</td><td>80</td><td>80</td></tr>
<tr><td>student23</td><td>Mathematics</td><td>male</td><td>82</td><td>77</td><td>0</td><td>79</td></tr>
<tr><td>student24</td><td>Languages</td><td>female</td><td>100</td><td>91</td><td>13</td><td>82</td></tr>
<tr><td>student25</td><td>Mathematics</td><td>male</td><td>22</td><td>96</td><td>82</td><td>53</td></tr>
<tr><td>student26</td><td>Languages</td><td>female</td><td>37</td><td>29</td><td>56</td><td>59</td></tr>
<tr><td>student27</td><td>Mathematics</td><td>male</td><td>86</td><td>82</td><td>69</td><td>23</td></tr>
<tr><td>student28</td><td>Languages</td><td>female</td><td>44</td><td>25</td><td>43</td><td>1</td></tr>
<tr><td>student29</td><td>Mathematics</td><td>male</td><td>77</td><td>47</td><td>22</td><td>38</td></tr>
<tr><td>student30</td><td>Languages</td><td>female</td><td>19</td><td>35</td><td>23</td><td>10</td></tr>
<tr><td>student31</td><td>Mathematics</td><td>male</td><td>90</td><td>27</td><td>17</td><td>50</td></tr>
<tr><td>student32</td><td>Languages</td><td>female</td><td>60</td><td>75</td><td>33</td><td>38</td></tr>
<tr><td>student33</td><td>Mathematics</td><td>male</td><td>4</td><td>31</td><td>37</td><td>15</td></tr>
<tr><td>student34</td><td>Languages</td><td>female</td><td>77</td><td>97</td><td>81</td><td>44</td></tr>
<tr><td>student35</td><td>Mathematics</td><td>male</td><td>5</td><td>81</td><td>51</td><td>95</td></tr>
<tr><td>student36</td><td>Languages</td><td>female</td><td>70</td><td>61</td><td>70</td><td>94</td></tr>
<tr><td>student37</td><td>Mathematics</td><td>male</td><td>60</td><td>3</td><td>61</td><td>84</td></tr>
<tr><td>student38</td><td>Languages</td><td>female</td><td>63</td><td>39</td><td>0</td><td>11</td></tr>
<tr><td>student39</td><td>Mathematics</td><td>male</td><td>50</td><td>46</td><td>32</td><td>38</td></tr>
<tr><td>student40</td><td>Languages</td><td>female</td><td>51</td><td>75</td><td>25</td><td>3</td></tr>
<tr><td>student41</td><td>Mathematics</td><td>male</td><td>43</td><td>34</td><td>28</td><td>78</td></tr>
<tr><td>student42</td><td>Languages</td><td>female</td><td>11</td><td>89</td><td>60</td><td>95</td></tr>
<tr><td>student43</td><td>Mathematics</td><td>male</td><td>48</td><td>92</td><td>18</td><td>88</td></tr>
<tr><td>student44</td><td>Languages</td><td>female</td><td>82</td><td>2</td><td>59</td><td>73</td></tr>
<tr><td>student45</td><td>Mathematics</td><td>male</td><td>91</td><td>73</td><td>37</td><td>39</td></tr>
<tr><td>student46</td><td>Languages</td><td>female</td><td>4</td><td>8</td><td>12</td><td>10</td></tr>
<tr><td>student47</td><td>Mathematics</td><td>male</td><td>89</td><td>10</td><td>6</td><td>11</td></tr>
<tr><td>student48</td><td>Languages</td><td>female</td><td>90</td><td>32</td><td>21</td><td>18</td></tr>
<tr><td>student49</td><td>Mathematics</td><td>male</td><td>42</td><td>49</td><td>49</td><td>72</td></tr>
<tr><td>student50</td><td>Languages</td><td>female</td><td>56</td><td>37</td><td>67</td><td>54</td></tr>
</tbody>
</table>
<h4 id="narrow-demo">Half-width demo</h4>
<div class="narrow-block">
<table class="tablesorter">
<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>
<tfoot>
<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>
</tfoot>
<tbody>
<tr><td>A43</td><td>Peter</td><td>Parker</td><td>28</td><td>9.99</td><td>20.3%</td><td>+3</td></tr>
<tr><td>A255</td><td>John</td><td>Hood</td><td>33</td><td>19.99</td><td>25.1%</td><td>-7</td></tr>
<tr><td>A33</td><td>Clark</td><td>Kent</td><td>18</td><td>15.49</td><td>44.2%</td><td>-13</td></tr>
<tr><td>A11</td><td>Bruce</td><td>Almighty</td><td>45</td><td>153.19</td><td>44%</td><td>+19</td></tr>
<tr><td>A102</td><td>Bruce</td><td>Evans</td><td>56</td><td>153.19</td><td>23%</td><td>+9</td></tr>
<tr><td>A23</td><td>Mike</td><td>Peters</td><td>22</td><td>5.69</td><td>20.3%</td><td>+2</td></tr>
<tr><td>A55</td><td>Leslie</td><td>Kent</td><td>33</td><td>15.99</td><td>25.1%</td><td>-3</td></tr>
<tr><td>A3</td><td>Frank</td><td>Mint</td><td>44</td><td>12.59</td><td>44.2%</td><td>-12</td></tr>
<tr><td>A21</td><td>Joe</td><td>Thomas</td><td>45</td><td>15.25</td><td>44%</td><td>+12</td></tr>
<tr><td>A12</td><td>Tess</td><td>Evans</td><td>66</td><td>13.59</td><td>23%</td><td>+4</td></tr>
<tr><td>A21</td><td>Peter</td><td>Dunn</td><td>12</td><td>2.99</td><td>21.1%</td><td>+2</td></tr>
<tr><td>A33</td><td>Harry</td><td>Jones</td><td>13</td><td>19.49</td><td>22.2%</td><td>-6</td></tr>
<tr><td>A13</td><td>John</td><td>James</td><td>16</td><td>13.89</td><td>42.1%</td><td>-13</td></tr>
<tr><td>A71</td><td>Nick</td><td>Parker</td><td>45</td><td>13.89</td><td>44%</td><td>+29</td></tr>
<tr><td>A21</td><td>Charles</td><td>Dunn</td><td>19</td><td>15.49</td><td>22%</td><td>+3</td></tr>
</tbody>
</table>
</div>
<div class="halfspacer"></div>
</div>

View File

@ -11,23 +11,22 @@
Resizable scroller widget for the jQuery tablesorter plugin
Version 2.0 - modified by Rob Garrison 4/12/2013; updated 3/5/2015 (v2.21.0)
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_barWidth : 18, // scroll bar width
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
@ -47,8 +46,16 @@ $.extend( ts.css, {
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',
scrollerReset : 'tablesorter-scroller-reset',
scrollerRtl : 'tablesorter-scroller-rtl'
// 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({
@ -56,18 +63,21 @@ ts.addWidget({
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 columns to fix
// 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,
// bar width is now calculated; set a value to override
// 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 ) {
format : function( table, c, wo ) {
if ( !c.isScrolling ) {
// initialize here instead of in widget init to give the
// filter widget time to finish building the filter row
@ -92,47 +102,43 @@ ts.window_resize = function() {
// Add extra scroller css
$( function() {
var style = '<style>' +
/* measure scroll bar width */
'.' + tscss.scrollerWrap + 'Measure { width: 100px; height: 100px; overflow: scroll; position: absolute; top: -9999px; }' +
/* reset width to get accurate measurements after window resize */
'.' + tscss.scrollerReset + ' { width: auto !important; min-width: auto !important; max-width: auto !important; }' +
/* 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 + ' { overflow: hidden; }' +
'.' + 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 + ' { overflow-y: scroll; }' +
'.' + tscss.scrollerTable + ' table.' + tscss.table + ' { border-top: 0; margin-top: 0; margin-bottom: 0; overflow-y: scroll; }' +
/* hide filter row in clones */
'.' + tscss.scrollerTable + ' .' + ( tscss.filterRow || 'tablesorter-filter-row' ) + ',.' + tscss.scrollerFooter + ' .' +
( tscss.filterRow || 'tablesorter-filter-row' ) + ',.' + tscss.scrollerTable + ' tfoot { display: none; }' +
/* visibly hide header rows in clones, so we can still set a width on it and still effect the rest of the column */
'.' + tscss.scrollerTable + ' table.' + tscss.table + ' thead tr.' + tscss.headerRow + ' *, .' + tscss.scrollerFooter +
' table.' + tscss.table + ' thead * { line-height: 0; height: 0; border: none; background-image: none; padding-top: 0;' +
' padding-bottom: 0; margin-top: 0; margin-bottom: 0; overflow: hidden; }' +
/* 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; }' +
/* 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; }' +
'.' + 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-x: auto; }' +
/* need to position the tbody & tfoot absolutely to hide the scrollbar & move the footer below the horizontal scrollbar */
'.' + 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 */
'.' + tscss.scrollerFixed + ' .' + tscss.scrollerTable + ' { position: relative; left: 0; overflow-x: hidden; overflow-y: scroll; -ms-overflow-style: none; }' +
'.' + tscss.scrollerFixed + ' .' + tscss.scrollerTable +
' { position: relative; left: 0; overflow: hidden; -ms-overflow-style: none; }' +
'.' + tscss.scrollerFixed + ' .' + tscss.scrollerTable + '::-webkit-scrollbar { display: none; }' +
/* remove right border of fixed header tables to hide the boundary */
'.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixed + ' table { border-right-color: transparent; padding-right: 0; }' +
'.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixed + '.' + tscss.scrollerRtl + ' table { border-left-color: transparent; padding-left: 0; }' +
/*** fixed column panel ***/
'.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixedPanel + ' { position: absolute; top: 0; bottom: 0; z-index: 2; left: 0; right: 0; } ' +
'.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixedPanel +
' { position: absolute; top: 0; bottom: 0; z-index: 2; left: 0; right: 0; } ' +
'</style>';
$( style ).appendTo( 'body' );
});
@ -143,9 +149,17 @@ ts.scroller = {
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,
// 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 ) {
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 ) {
@ -158,15 +172,23 @@ ts.scroller = {
// modified from http://davidwalsh.name/detect-scrollbar-width
getBarWidth : function() {
var $scrollDiv = $( '<div class="' + tscss.scrollerWrap + 'Measure">' ).appendTo( 'body' ),
div = $scrollDiv[ 0 ],
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;
$scrollDiv.remove();
$div.remove();
return barWidth;
},
setup : function( c, wo ) {
var maxHt, tbHt, $hdr, $t, $hCells, $fCells, $tableWrap,
var maxHt, tbHt, $hdr, $t, $hCells, $fCells, $tableWrap, tmp,
$win = $( window ),
namespace = c.namespace + 'tsscroller',
$foot = $(),
@ -174,6 +196,11 @@ ts.scroller = {
id = c.namespace.slice( 1 ) + 'tsscroller',
$table = c.$table;
// set scrollbar width & allow setting width to zero
wo.scroller_barSetWidth = wo.scroller_barWidth !== null ?
wo.scroller_barWidth :
( ts.scroller.getBarWidth() || 15 );
maxHt = wo.scroller_height || 300;
// sum all tbody heights
tbHt = 0;
@ -181,16 +208,17 @@ ts.scroller = {
tbHt += $( this ).outerHeight();
});
wo.scroller_$header = $hdr = $( '<table class="' + $table.attr( 'class' ) + '" cellpadding=0 cellspacing=0>' +
$table.children( 'thead' )[0].outerHTML +
'</table>' )
.addClass( c.namespace.slice(1) + '_extra_table' );
$hdr = $( '<table class="' + $table.attr( 'class' ) + '" cellpadding=0 cellspacing=0>' +
$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' )
.append( $t.clone( true ) ) // maintain any bindings on the tfoot cells
$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();
}
@ -200,7 +228,8 @@ ts.scroller = {
.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 );
.find( '.' + tscss.filterRow )
.addClass( tscss.filterRowHide );
wo.scroller_$container = $table.parent();
@ -222,19 +251,12 @@ ts.scroller = {
// look for filter widget
if ( $table.hasClass( 'hasFilters' ) ) {
ts.filter.bindSearch( $table, $hdr.find('.' + tscss.filter) );
ts.filter.bindSearch( $table, $hdr.find( '.' + tscss.filter ) );
}
// remove any previous fixed columns ( in case we're updating )
wo.scroller_$container.find( '.' + tscss.scrollerFixed ).remove();
if ( wo.scroller_fixedColumns > 0 ) {
ts.scroller.setupFixed( c, wo );
}
ts.scroller.resize( c, wo );
$table.find( 'thead' ).hide();
$table
.find( 'thead' )
.addClass( tscss.scrollerHideElement );
tbHt = $tableWrap.parent().height();
@ -248,31 +270,42 @@ ts.scroller = {
$win.scrollTop( $hdr.offset().top );
}
}
$hdr.parent().add( $foot.parent() ).scrollLeft( $( this ).scrollLeft() );
$hdr
.parent()
.add( $foot.parent() )
.scrollLeft( $( this ).scrollLeft() );
});
// Sorting, so scroll to top
tmp = 'sortEnd setFixedColumnSize updateComplete pagerComplete pagerInitialized '
.split( ' ' )
.join( namespace + ' ' );
$table
.off( 'sortEnd setFixedColumnSize updateComplete '.split( ' ' ).join( namespace + ' ' ) )
.off( tmp )
.on( 'sortEnd' + namespace, function() {
if ( wo.scroller_upAfterSort ) {
$table.parent().animate({ scrollTop: 0 }, 'fast' );
$table.parent().animate({
scrollTop : 0
}, 'fast' );
}
})
.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
wo.scroller_$container.find( '.' + tscss.scrollerFixed ).remove();
ts.scroller.removeFixed( c, wo );
size = wo.scroller_fixedColumns;
if ( size > 0 && size < c.columns - 1 ) {
ts.scroller.setupFixed( c, wo );
} else {
wo.scroller_$container.removeClass( tscss.scrollerHasFix );
ts.scroller.updateFixed( c, wo );
} else if ( $wrap.hasClass( tscss.scrollerHasFix ) ) {
$wrap.removeClass( tscss.scrollerHasFix );
// resize needed to make tables full width
ts.scroller.resize( c, wo );
}
})
.on( 'updateComplete' + namespace, function() {
.on( 'updateComplete pagerComplete pagerInitialized '.split( ' ' ).join( namespace + ' ' ), function() {
// adjust column sizes after an update
ts.scroller.resize( c, wo );
});
@ -287,44 +320,47 @@ ts.scroller = {
$win.off( 'resize' + namespace, ts.window_resize );
ts.scroller.resize( c, wo );
$win.on( 'resize' + namespace, ts.window_resize );
$tableWrap.trigger( 'scroll' + namespace );
});
// initialization flag
c.isScrolling = true;
ts.scroller.updateFixed( c, wo );
},
resize : function( c, wo ) {
var index, borderWidth, setWidth, $hCells, $bCells, $fCells, $headers, $this,
var index, borderWidth, setWidth, $hCells, $bCells, $fCells, $headers, $this, temp,
$table = c.$table,
$tableWrap = $table.parent(),
$hdr = wo.scroller_$header,
$foot = wo.scroller_$footer,
id = c.namespace.slice( 1 ) + 'tsscroller',
// Hide other scrollers so we can resize
$div = $( 'div.' + tscss.scrollerWrap + '[id != "' + id + '"]' ).hide();
$div = $( 'div.' + tscss.scrollerWrap + '[id!="' + id + '"]' )
.addClass( tscss.scrollerHideElement );
// Remove fixed so we get proper widths and heights
ts.scroller.removeFixed( c, wo );
// show original table thead to get proper alignments
$table.children( 'thead' ).show();
$table.children( 'thead' ).removeClass( tscss.scrollerHideElement );
// Reset sizes so parent can resize.
$table
.addClass( tscss.scrollerReset )
.children( 'thead' )
.find( '.' + tscss.headerIn ).addClass( tscss.scrollerReset ).end()
.find( '.' + tscss.filterRow ).show();
.find( '.' + tscss.headerIn )
.addClass( tscss.scrollerReset )
.end()
.find( '.' + tscss.filterRow )
.removeClass( tscss.scrollerHideElement );
$tableWrap.addClass( tscss.scrollerReset );
// include left & right border widths
borderWidth = parseInt( $table.css( 'border-left-width' ), 10 );
// Shrink a bit to accommodate scrollbar
wo.scroller_barSetWidth = ( wo.scroller_barWidth || ts.scroller.getBarWidth() || 18 ) + borderWidth;
$tableWrap.width( $tableWrap.parent().innerWidth() - ( ts.scroller.hasScrollBar( $tableWrap.parent() ) ? wo.scroller_barSetWidth : 0 ) );
setWidth = $tableWrap.innerWidth() - ( ts.scroller.hasScrollBar( $tableWrap ) ? wo.scroller_barSetWidth : 0 ) + borderWidth;
$hdr.parent().add( $foot.parent() ).width( setWidth );
$hCells = $hdr
.children( 'thead' )
.children( 'tr' )
@ -345,7 +381,11 @@ ts.scroller = {
.filter( ':visible' );
ts.scroller.setWidth( $hCells.add( $bCells ).add( $fCells ), '' );
$headers = $table.children( 'thead' ).children().eq( 0 ).children( 'th, td' );
$headers = $table
.children( 'thead' )
.children()
.eq( 0 )
.children( 'th, td' );
for ( index = 0; index < $headers.length; index++ ) {
$this = $headers.eq( index );
// code from https://github.com/jmosbech/StickyTableHeaders
@ -354,36 +394,49 @@ ts.scroller = {
} else {
if ( $hCells.eq( index ).css( 'border-collapse' ) === 'collapse' ) {
if ( $this.length && window.getComputedStyle ) {
setWidth = parseFloat( window.getComputedStyle( $this[0], null ).width );
setWidth = parseFloat( window.getComputedStyle( $this[ 0 ], null ).width );
} else {
// ie8 only
borderWidth = parseFloat( $this.css( 'border-width' ) ) || 0;
setWidth = $this.outerWidth() - parseFloat( $this.css( 'padding-left' ) ) - parseFloat( $this.css( 'padding-right' ) ) - borderWidth;
setWidth = $this.outerWidth() - parseFloat( $this.css( 'padding-left' ) ) -
parseFloat( $this.css( 'padding-right' ) ) -
( parseFloat( $this.css( 'border-width' ) ) || 0 );
}
} else {
setWidth = $this.width();
}
}
ts.scroller.setWidth( $hCells.eq( index ).add( $bCells.eq( index ) ).add( $fCells.eq( index ) ), setWidth );
temp = $hCells.eq( index )
.add( $bCells.eq( index ) )
.add( $fCells.eq( index ) );
ts.scroller.setWidth( temp, setWidth );
}
temp = $tableWrap.parent().innerWidth() -
( ts.scroller.hasScrollBar( $tableWrap ) ? wo.scroller_barSetWidth : 0 );
$tableWrap.width( temp );
setWidth = $tableWrap.innerWidth() -
( ts.scroller.hasScrollBar( $tableWrap ) ? wo.scroller_barSetWidth : 0 ) + borderWidth;
$hdr
.parent()
.add( $foot.parent() )
.width( setWidth );
wo.scroller_$container
.find( '.' + tscss.scrollerReset )
.removeClass( tscss.scrollerReset );
// update fixed column sizes
if ( wo.scroller_fixedColumns > 0 ) {
ts.scroller.updateFixed( c, wo, true );
}
ts.scroller.updateFixed( c, wo );
// hide original table thead
$table.children( 'thead' ).hide();
$table.children( 'thead' ).addClass( tscss.scrollerHideElement );
$div.show();
$div.removeClass( tscss.scrollerHideElement );
},
// Add fixed (frozen) columns
// Add fixed (frozen) columns (Do not call directly, use updateFixed)
setupFixed : function( c, wo ) {
var index, index2, $el, len, temp, $fixedColumn, $fixedTbody, $fixedContainer,
$table = c.$table,
@ -400,13 +453,15 @@ ts.scroller = {
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', '' );
$fixedTbody = $fixedColumn.find( '.' + tscss.scrollerTable );
$fixedContainer = $fixedTbody.children( 'table' ).children( 'tbody' );
$fixedTbody.children( 'table' ).children( 'thead, tfoot' ).remove();
$fixedTbody
.children( 'table' )
.addClass( c.namespace.slice( 1 ) + '_extra_table' )
.attr( 'id', '' )
.children( 'thead, tfoot' )
.remove();
wo.scroller_$fixedColumns = $fixedColumn;
@ -420,13 +475,22 @@ ts.scroller = {
for ( index = 0; index < len; index++ ) {
$el.eq( index ).children( ':gt(' + ( fixedColumns - 1 ) + ')' ).remove();
}
$fixedColumn.hide().prependTo( $wrapper );
$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 );
$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
@ -441,10 +505,14 @@ ts.scroller = {
c.$table
.add( '.' + tscss.scrollerFooter + ' table' )
.children( 'thead' )
.children( 'tr.' + tscss.headerRow ).children().attr( 'tabindex', -1 );
.children( 'tr.' + tscss.headerRow )
.children()
.attr( 'tabindex', -1 );
$el = wo.scroller_$header
.add( $fixedColumn.find( '.' + tscss.scrollerTable + ' table' ) )
.children( 'thead' ).children( 'tr.' + tscss.headerRow );
.children( 'thead' )
.children( 'tr.' + tscss.headerRow );
len = $el.length;
for ( index = 0; index < len; index++ ) {
temp = $el.eq( index ).children();
@ -458,11 +526,9 @@ ts.scroller = {
/*** Scrollbar hack! Since we can't hide the scrollbar with css ***/
if ( ts.scroller.isFirefox || ts.scroller.isOldIE ) {
$fixedTbody.wrap( '<div class="scroller-scrollbar-hack" style="overflow:hidden;">' );
$fixedTbody.wrap( '<div class="' + tscss.scrollerHack + '" style="overflow:hidden;">' );
}
ts.scroller.updateFixed( c, wo, true );
},
bindFixedColumnEvents : function( c, wo ) {
@ -478,6 +544,7 @@ ts.scroller = {
.off( events )
.on( events, function() {
ts.scroller.updateFixed( c, wo, false );
ts.scroller.resize( c, wo );
})
.parent()
// *** SCROLL *** scroll fixed column along with main
@ -487,7 +554,9 @@ ts.scroller = {
if ( fixedScroll || !ts.scroller.isFirefox ) {
tableScroll = false;
$fixedTbody[0].scrollTop = $( this ).scrollTop();
setTimeout(function(){ tableScroll = true; }, 20);
setTimeout( function() {
tableScroll = true;
}, 20 );
}
});
// scroll main along with fixed column
@ -498,7 +567,9 @@ ts.scroller = {
if ( tableScroll || !ts.scroller.isFirefox ) {
fixedScroll = false;
c.$table.parent()[0].scrollTop = $( this ).scrollTop();
setTimeout(function(){ fixedScroll = true; }, 20);
setTimeout( function() {
fixedScroll = true;
}, 20 );
}
})
.scroll();
@ -511,16 +582,24 @@ ts.scroller = {
.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 )
$fixedTbody
.children( 'table' )
.children( 'tbody' )
.children( 'tr' )
.eq( indx )
.add( this )
.toggleClass( wo.scroller_rowHighlight, event.type === 'mouseover' );
});
$fixedTbody.find( 'table' )
$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 )
c.$table
.children( 'tbody' )
.children( 'tr' )
.eq( indx )
.add( this )
.toggleClass( wo.scroller_rowHighlight, event.type === 'mouseover' );
});
@ -528,59 +607,88 @@ ts.scroller = {
},
updateFixed : function( c, wo ) {
if ( !c.isScrolling ) { return; }
var $wrapper = wo.scroller_$container;
// no idea why this happens, but sometimes the main table wrapper gets the scrollbar width
// subtracted from it on load and on theme change - it can be very sporatic; this fixes it.
c.$table.parent().width( wo.scroller_$container.width() );
if ( wo.scroller_fixedColumns === 0 ) {
ts.scroller.removeFixed( c, wo );
return;
}
if ( !c.isScrolling ) {
return;
}
// 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, widths, $fixHead, $fixBody, $fixFoot,
var index, tbodyIndex, rowIndex, $tbody, $adjCol, $fb, $fixHead, $fixBody, $fixFoot,
totalRows, widths, temp, adj, row,
$table = c.$table,
$wrapper = wo.scroller_$container,
$tableWrap = $table.parent(),
$hdr = wo.scroller_$header,
$foot = wo.scroller_$footer,
// source cells for measurement
$mainTbodies = wo.scroller_$container.children( '.' + tscss.scrollerTable ).children( 'table' ).children( 'tbody' ),
$rows = wo.scroller_$header.children( 'thead' ).children( '.' + tscss.headerRow ), // variable gets redefined
$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.hide(),
$fixedColumn = wo.scroller_$fixedColumns
.addClass( tscss.scrollerHideElement ),
// target cells
$fixedTbodiesTable = $fixedColumn.find( '.' + tscss.scrollerTable ).children( 'table' ),
$fixedTbodies = $fixedTbodiesTable.children( 'tbody' ),
$fixedHeader = $fixedColumn.find( '.' + tscss.scrollerHeader ).children( 'table' ).children( 'thead' ),
$fixedTbodiesTable = $fixedColumn
.find( '.' + tscss.scrollerTable )
.children( 'table' ),
$fixedTbodies = $fixedTbodiesTable
.children( 'tbody' ),
// variables
tsScroller = ts.scroller,
scrollBarWidth = wo.scroller_barSetWidth,
fixedColumns = wo.scroller_fixedColumns,
dir = $table.hasClass( tscss.scrollerRtl ),
// get dimensions
$temp = $table.find( 'tbody td' ),
borderRightWidth = parseInt( $temp.css( 'border-right-width' ), 10 ) || 1,
borderBottomWidth = parseInt( $temp.css( 'border-bottom-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;
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;
// fixed header cell height
$temp = $fixedHeader.children( '.' + tscss.headerRow );
for ( index = 0; index < $temp.length; index++ ) {
$temp.eq( index ).height( $rows.eq( index ).outerHeight() );
}
ts.scroller.removeFixed( c, wo, false );
// body cell dimensions seem to be more accurate *shrug* ( $rows contains table cells in this block )
$rows = c.filteredRows > 0 ? c.$tbodies.children( 'tr:visible' ).children() : $( c.$headerIndexed );
// recalculate widths
widths = $rows.filter( ':lt(' + fixedColumns + ')' ).map( function() {
totalWidth += $( this ).outerWidth() + borderSpacing;
return $( this ).outerWidth();
}).get();
$table.children( 'thead' ).removeClass( tscss.scrollerHideElement );
widths = [];
for ( index = 0; index < c.columns; index++ ) {
temp = c.$headerIndexed[ index ].outerWidth();
totalWidth += index < fixedColumns ? temp + borderSpacing : 0;
widths.push( temp );
}
$table.children( 'thead' ).addClass( tscss.scrollerHideElement );
// set fixed column width
tsScroller.setWidth( $fixedColumn.add( $fixedColumn.children() ), totalWidth + borderRightWidth * 2 - borderSpacing );
tsScroller.setWidth( $fixedColumn.find( 'table' ), totalWidth + borderRightWidth );
totalWidth = totalWidth + borderRightWidth * 2 - borderSpacing;
tsScroller.setWidth( $fixedColumn.add( $fixedColumn.children() ), totalWidth );
tsScroller.setWidth( $fixedColumn.children().children( 'table' ), totalWidth );
// set fixed column height ( changes with filtering )
$fixedColumn.height( $wrapper.height() );
$table.find( '.' + tscss.scrollerSpacerRow ).remove();
row = '<tr class="' + tscss.scrollerSpacerRow + ' ' + c.selectorRemove.slice(1) + '">';
for ( index = 0; index < c.columns; index++ ) {
row += '<td style="padding:0; margin:0;height:0;max-height:0;min-height:0;width:' +
widths[ index ] + 'px;min-width:' + widths[ index ] + 'px;max-width:' +
widths[ index ] + 'px"></td>';
}
c.$tbodies.eq(0).prepend( row += '</tr>' );
// update fixed column tbody content, set row height & set cell widths for first row
for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
@ -589,30 +697,44 @@ ts.scroller = {
// get tbody
$rows = $tbody.children();
totalRows = $rows.length;
$fb = ts.processTbody( $fixedTbodiesTable, $fixedTbodies.eq( tbodyIndex ), true);
$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();
// set row height
$adjCol.children().eq( 0 ).height( $rows.eq( rowIndex ).outerHeight() - ( tsScroller.isFirefox ? borderBottomWidth * 2 : 0 ) );
// still need to adjust tbody cell widths ( the previous row may now be filtered )
if ( rowIndex === 0 ) {
tsScroller.setWidth( $adjCol.children().eq( 0 ), widths[ 0 ] );
}
$adjCol
.children( 'td, th' )
.slice( fixedColumns )
.remove();
$fb.append( $adjCol );
}
// adjust fixed thead/tbody/tfoot cell widths
$fixHead = $fixedColumn.find( 'thead' ).children( 'tr.' + tscss.headerRow ).children();
$fixBody = $fixedColumn.find( 'tbody' ).not('.' + c.cssInfoBlock ).children( 'tr' ).eq( 0 ).children();
$fixFoot = $fixedColumn.find( 'tfoot' ).children( 'tr' ).eq( 0 ).children();
for ( index = 0; index < fixedColumns; index++ ) {
$fixHead = $fixedColumn
.find( 'thead' )
.children( 'tr.' + tscss.headerRow )
.children();
$fixBody = $fixedColumn
.find( tscss.scrollerSpacerRow )
.children();
$fixFoot = $fixedColumn
.find( 'tfoot' )
.children( 'tr' )
.eq( 0 )
.children();
// reusing variables, so ignore the names :P
$adjCol = $hdr.children( 'thead' ).children( 'tr' ).children( 'td, th' );
$rows = $foot.children( 'tfoot' ).children( 'tr' ).children( 'td, th' );
for ( index = 0; index < c.columns; index++ ) {
if ( index < fixedColumns ) {
$temp = $fixHead.eq( index )
.add( $fixBody.eq( index ) )
.add( $fixFoot.eq( index ) );
tsScroller.setWidth( $temp, widths[ index ] );
}
$temp = $adjCol.eq( index )
.add( $rows.eq( index ) );
tsScroller.setWidth( $temp, widths[ index ] );
}
// restore tbody
ts.processTbody( $fixedTbodiesTable, $fb, false );
@ -621,25 +743,138 @@ ts.scroller = {
/*** scrollbar HACK! Since we can't hide the scrollbar with css ***/
if ( tsScroller.isFirefox || tsScroller.isOldIE ) {
$fixedTbodiesTable.parent().css({
'width' : totalWidth + scrollBarWidth + borderRightWidth
$fixedTbodiesTable
.parent()
.css({
'width' : totalWidth
});
}
if ( wo.scroller_$footer.length ) {
// adjust footer row heights (text could wrap on resize)
$temp = $wrapper.children( '.' + tscss.scrollerFooter ).find( 'tfoot tr' );
$rows = $fixedColumn.find( '.' + tscss.scrollerFooter + ' tfoot tr' );
for ( index = 0; index < $rows.length; index++ ) {
$rows.eq( index ).height( $temp.eq( index ).height() );
$fixedColumn.removeClass( tscss.scrollerHideElement );
for ( index = 0; index < fixedColumns; index++ ) {
$wrapper
.children( 'div' )
.children( 'table' )
.find( 'th:nth-child(' + ( index + 1 ) + '), td:nth-child(' + ( index + 1 ) + ')' )
.addClass( tscss.scrollerHideColumn );
}
adj = ts.scroller.hasScrollBar( $tableWrap ) ? scrollBarWidth : 0;
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 );
},
fixHeight : function( $rows, $fixedRows ) {
var index, heightRow, heightFixed, $r, $f,
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( tscss.scrollerAddedHeight ).height( heightRow );
} else if ( heightRow < heightFixed ) {
$r.addClass( tscss.scrollerAddedHeight ).height( heightFixed );
}
}
// leave a gap under the tbody for the horizontal scrollbar
$fixedColumn.find( '.' + tscss.scrollerTable )
.height( $table.parent().height() - scrollBarWidth + borderBottomWidth );
},
$fixedColumn.show();
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 ) {
// 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 ) {
@ -648,10 +883,18 @@ ts.scroller = {
c.$table
.off( namespace )
.insertBefore( $wrap )
.find( 'thead' ).show()
.children( 'tr.' + tscss.headerRow ).children().attr( 'tabindex', 0 )
.find( 'thead' )
.removeClass( tscss.scrollerHideElement )
.children( 'tr.' + tscss.headerRow )
.children()
.attr( 'tabindex', 0 )
.end()
.find( '.' + tscss.filterRow ).show().removeClass( tscss.filterRowHide );
.find( '.' + tscss.filterRow )
.removeClass( tscss.scrollerHideElement + ' ' + tscss.filterRowHide );
c.$table
.find( '.' + tscss.filter )
.not( '.' + tscss.filterDisabled )
.prop( 'disabled', false );
$wrap.remove();
$( window ).off( namespace );
c.isScrolling = false;