Dragtable: make compatible with other widgets

This commit is contained in:
Mottie 2015-02-03 12:58:41 -06:00
parent 5e0717c466
commit 485b515066
9 changed files with 643 additions and 149 deletions

View File

@ -1,40 +1,64 @@
/*
* dragtable
*
* @Version 2.0.14
*
* @Version 2.0.14 MOD
* default css
*
*/
/*##### the dragtable stuff #####*/
.dragtable-sortable {
list-style-type: none; margin: 0; padding: 0; -moz-user-select: none;
list-style-type: none;
margin: 0;
padding: 0;
-moz-user-select: none;
z-index: 10;
}
.dragtable-sortable li {
margin: 0; padding: 0; float: left; font-size: 1em; background: white;
margin: 0;
padding: 0;
float: left;
font-size: 1em;
}
.dragtable-sortable th, .dragtable-sortable td{
border-left: 0px;
.dragtable-sortable table {
margin-top: 0;
}
.dragtable-sortable th, .dragtable-sortable td {
border-left: 0px;
}
.dragtable-sortable li:first-child th, .dragtable-sortable li:first-child td {
border-left: 1px solid #CCC;
border-left: 1px solid #CCC;
}
.dragtable-handle-selected {
/* table-handle class while actively dragging a column */
}
.ui-sortable-helper {
opacity: 0.7;filter: alpha(opacity=70);
opacity: 0.7;
filter: alpha(opacity=70);
}
.ui-sortable-placeholder {
-moz-box-shadow: 4px 5px 4px #C6C6C6 inset;
-webkit-box-shadow: 4px 5px 4px #C6C6C6 inset;
box-shadow: 4px 5px 4px #C6C6C6 inset;
border-bottom: 1px solid #CCCCCC;
border-top: 1px solid #CCCCCC;
visibility: visible !important;
background: #EFEFEF !important;
visibility: visible !important;
-moz-box-shadow: 4px 5px 4px rgba(0,0,0,0.2) inset;
-webkit-box-shadow: 4px 5px 4px rgba(0,0,0,0.2) inset;
box-shadow: 4px 5px 4px rgba(0,0,0,0.2) inset;
border-bottom: 1px solid rgba(0,0,0,0.2);
border-top: 1px solid rgba(0,0,0,0.2);
visibility: visible !important;
/* change the background color here to match the tablesorter theme */
background: #EFEFEF;
}
.ui-sortable-placeholder * {
opacity: 0.0; visibility: hidden;
opacity: 0.0;
visibility: hidden;
}
.table-handle, .table-handle-disabled {
/* background-image: url(images/dragtable-handle.png); */
/* background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAANAQMAAAC5Li2yAAAABlBMVEUAAAAzMzPI8eYgAAAAAnRSTlMAzORBQ6MAAAAOSURBVAjXYwABByyYAQAQWgFBLN2RnwAAAABJRU5ErkJggg=='); */
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyIiBoZWlnaHQ9IjEzIj48cmVjdCBzdHlsZT0iZmlsbDojMzMzO2ZpbGwtb3BhY2l0eTouODsiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHg9IjEiIHk9IjIiLz4JPHJlY3Qgc3R5bGU9ImZpbGw6IzMzMztmaWxsLW9wYWNpdHk6Ljg7IiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4PSIxIiB5PSI0Ii8+CTxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iNiIvPjxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iOCIvPjxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iMTAiLz48L3N2Zz4=);
background-repeat: repeat-x;
height: 13px;
margin: 0 1px;
cursor: move;
}
.table-handle-disabled {
opacity: 0;
cursor: not-allowed;
}
.dragtable-sortable table {
margin-bottom: 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2" height="13">
<rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="2"/>
<rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="4"/>
<rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="6"/>
<rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="8"/>
<rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="10"/>
</svg>

After

Width:  |  Height:  |  Size: 455 B

View File

@ -83,6 +83,8 @@ span.alert { padding: 1px 3px; }
.fade { opacity: 0.5; }
.results { color: red; }
.clear { clear: both; }
.good { color: #080; }
.bad { color: #800; }
.bootstrap_buttons button { margin: 5px 0 0 0; }
#main .ui-accordion-header a, #main .ui-accordion-content { font-size: 14px; }
#banner small { font-size: 16px; vertical-align: super; }

245
docs/example-dragtable.html Normal file
View File

@ -0,0 +1,245 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jQuery plugin: Tablesorter 2.0 - Dragtable Mod (beta)</title>
<!-- jQuery -->
<script src="js/jquery-latest.min.js"></script>
<script src="js/jquery-ui-latest.min.js"></script>
<!-- Demo stuff -->
<link class="ui-theme" rel="stylesheet" href="css/jquery-ui.min.css">
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/jq.css">
<link href="css/prettify.css" rel="stylesheet">
<script src="js/prettify.js"></script>
<script src="js/docs.js"></script>
<style>
/* override jQuery UI overriding Bootstrap */
.accordion .ui-widget-content a {
color: #337ab7;
}
</style>
<!-- Tablesorter: theme -->
<link class="theme" rel="stylesheet" href="../css/theme.blue.css">
<link rel="stylesheet" href="../css/dragtable.mod.css">
<!-- Tablesorter script: required -->
<script src="../js/jquery.tablesorter.js"></script>
<script src="../js/jquery.tablesorter.widgets.js"></script>
<script src="../js/extras/jquery.dragtable.mod.js"></script>
<style id="css">/* optional styling */
caption {
/* override bootstrap adding 8px to the top & bottom of the caption */
padding: 0;
}
.ui-sortable-placeholder {
/* change placeholder (seen while dragging) background color */
background: #ddd;
}
div.table-handle-disabled {
/* optional red background color indicating a disabled drag handle */
background-color: rgba(255,128,128,0.5);
/* opacity set to zero for disabled handles in the dragtable.mod.css file */
opacity: 0.7;
}
/* fix cursor */
.tablesorter-blue .tablesorter-header {
cursor: default;
}
.sorter {
cursor: pointer;
}</style>
<script id="js">$(function () {
$('table')
// initialize dragtable FIRST!
.dragtable({
// *** new dragtable mod options ***
// this option MUST match the tablesorter selectorSort option!
sortClass: '.sorter',
// this function is called after everything has been updated
tablesorterComplete: function(table){},
// *** original dragtable settings (non-default) ***
dragaccept: '.drag-enable', // class name of draggable cols -> default null = all columns draggable
// *** original dragtable settings (default values) ***
revert: false, // smooth revert
dragHandle: '.table-handle', // handle for moving cols, if not exists the whole 'th' is the handle
maxMovingRows: 40, // 1 -> only header. 40 row should be enough, the rest is usually not in the viewport
excludeFooter: false, // excludes the footer row(s) while moving other columns. Make sense if there is a footer with a colspan. */
onlyHeaderThreshold: 100, // TODO: not implemented yet, switch automatically between entire col moving / only header moving
persistState: null, // url or function -> plug in your custom persistState function right here. function call is persistState(originalTable)
restoreState: null, // JSON-Object or function: some kind of experimental aka Quick-Hack TODO: do it better
exact: true, // removes pixels, so that the overlay table width fits exactly the original table width
clickDelay: 10, // ms to wait before rendering sortable list and delegating click event
containment: null, // @see http://api.jqueryui.com/sortable/#option-containment, use it if you want to move in 2 dimesnions (together with axis: null)
cursor: 'move', // @see http://api.jqueryui.com/sortable/#option-cursor
cursorAt: false, // @see http://api.jqueryui.com/sortable/#option-cursorAt
distance: 0, // @see http://api.jqueryui.com/sortable/#option-distance, for immediate feedback use "0"
tolerance: 'pointer', // @see http://api.jqueryui.com/sortable/#option-tolerance
axis: 'x', // @see http://api.jqueryui.com/sortable/#option-axis, Only vertical moving is allowed. Use 'x' or null. Use this in conjunction with the 'containment' setting
beforeStart: $.noop, // returning FALSE will stop the execution chain.
beforeMoving: $.noop,
beforeReorganize: $.noop,
beforeStop: $.noop
})
// initialize tablesorter
.tablesorter({
theme: 'blue',
// this option MUST match the dragtable sortClass option!
selectorSort: '.sorter',
widgets: ['zebra', 'filter', 'columns']
});
});</script>
</head>
<body>
<div id="banner">
<h1>table<em>sorter</em></h1>
<h2>Dragtable Mod (beta)</h2>
<h3>Flexible client-side table sorting</h3>
<a href="index.html">Back to documentation</a>
</div>
<div id="main">
<p></p>
<br>
<div id="root" class="accordion">
<h3 id="notes"><a href="#">Notes</a></h3>
<div>
<ul>
<li>This demo uses a modified version of the <a href="http://akottr.github.io/dragtable/">jQuery UI Dragtable widget</a> (beta) to work with tablesorter.</li>
<li>This mod <strong>has been</strong> tested with the following widgets: <span class="good">alignChar</span>, <span class="good">columns</span>, <span class="good">cssStickyHeaders</span>, <span class="good">editable</span>, <span class="good">filter</span>, <span class="good">grouping</span>, <span class="good">headerTitles</span>, <span class="good">math</span>, <span class="good">output</span>, <span class="good">pager</span> <span class="good">print</span>, <span class="good">reflow</span>, <span class="good">resizable</span>, <span class="good">repeatHeaders</span>, <span class="good">staticRow</span>, <span class="good">uitheme</span> &amp; <span class="good">zebra</span>.</li>
<li>This mod <strong><em>does not</em></strong> currently work with the following widgets:
<ul>
<li><span class="bad">chart</span> - needs more work to be compatible.</li>
<li><span class="bad">columnSelector</span> - needs more work - making this compatible will require significant changes to the dragtable core.</li>
<li><span class="bad">saveSort</span> - this saves the newly moved sorted column properly, but on page reload the column order is restored so it sorts the incorrect column.</li>
<li><span class="bad">scroller</span> - way too much work to make this compatible.</li>
<li><span class="bad">stickyHeaders</span> - needs more work - can't get the drag handle in the cloned sticky header from passing the mousedown on to the original drag handle.</li>
</ul>
</li>
<li>Any widgets not listed above can be assumed to be incompatible, for now.</li>
</ul>
</div>
<h3 id="setup"><a href="#">Tablesorter setup</a></h3>
<div>
A complete javascript example can be found in the demo section, below the table.
<p></p>
To use this mod:
<ul>
<li>Initialize the dragtable mod script first, then initialize tablesorter.</li>
<li><span class="label label-warning">Warning!</span> When setting up the initialization code, make sure that the dragtable <code>sortClass</code> option <em>exactly matches</em> the tablesorter <code>selectorSort</code> option, or the table will be unsortable.
<pre class="prettyprint lang-js">$('table')
.dragtable({ sortClass: '.sorter' }) // this is already the default value
.tablesorter({ selectorSort: '.sorter' }); // this default value is 'th, td'</pre></li>
<li><span class="label warning">Warning!</span> Do not reference a column using jQuery data (e.g. <code>$('th:contains(Name)').data('sorter', 'text');</code>) or by it's zero-based index<sup class="bright">(1)</sup> because these references do not get updated after a column move!
<p></p>
Instead, use one of the following methods (these examples set the column parser):
<h4>Set parser by data-attribute or header class</h4>
<pre class="prettyprint lang-html">&lt;tr&gt;
&lt;th class="col-id" data-sorter="digit"&gt;...&lt;/th&gt; &lt;!-- parser set by data-attribute --&gt;
&lt;th class="col-name drag-enable sorter-text"&gt;...&lt;/th&gt; &lt;!-- parser set by header class --&gt;
&lt;th class="col-date drag-enable"&gt;...&lt;/th&gt; &lt;!-- parser set by headers option (see below) --&gt;
&lt;/tr&gt;</pre>
<h4>Or, set parser by <code>headers</code> option</h4>
<pre class="prettyprint lang-js">$('table').tablesorter({
headers : {
'.col-date' : { sorter : 'shortDate' }
}
});</pre></li>
<li>In order to get dragtable to work, the mod will add a div to act as a dragable handle and wrap the header text in a div<sup class="bright">(2)</sup> which needs to be targeted by the <code>selectorSort</code> option to make it clickable for sorting.
<p></p>
The <em>resulting HTML</em> may look like this:
<pre class="prettyprint lang-html">&lt;tr&gt;
&lt;th class="col-id" data-sorter="digit"&gt;
&lt;div class="table-handle-disabled"&gt;&lt;/div&gt;
&lt;!-- clicking on the "sort" wrapper below will not trigger a sort, because the cell is not set to sort --&gt;
&lt;div class="sorter"&gt;9999&lt;/div&gt;
&lt;/th&gt;
&lt;th class="col-name sorter-text drag-enable"&gt;
&lt;div class="table-handle"&gt;&lt;/div&gt;
&lt;div class="sorter"&gt;Name&lt;/div&gt;
&lt;/th&gt;
&lt;th class="col-date drag-enable"&gt;
&lt;div class="table-handle"&gt;&lt;/div&gt;
&lt;div class="sorter"&gt;1/1/2015&lt;/div&gt;
&lt;/th&gt;
&lt;/tr&gt;</pre>
</li>
</ul>
<span class="bright">(1)</span> Options that use a column index (such as the <code>sortList</code>), or an array of settings (like the <code>resizable_widths</code> option) are updated internally by the mod.
<p></p>
<span class="bright">(2)</span> The class name for the dragable handle is set by the dragtable <code>dragHandle</code> option &amp; the class name for the clickable div wrapping the header text is set by the dragtable <code>sortClass</code> option.
</div>
</div>
<h1>Demo</h1>
<div id="demo"><table class="tablesorter">
<caption>Student Grades</caption>
<thead>
<tr>
<th>Name (0)</th> <!-- disable dragtable on this column -->
<th class="drag-enable">Major (1)</th>
<th class="drag-enable">Sex (2)</th>
<th class="drag-enable">English (3)</th>
<th class="drag-enable">Japanese (4)</th>
<th class="drag-enable">Calculus (5)</th>
<th class="drag-enable">Geometry (6)</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 (0)</td><td>Languages (1)</td><td>male (2)</td><td>80 (3)</td><td>70 (4)</td><td>75 (5)</td><td>80 (6)</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>
</tbody>
</table></div>
<h1>HTML</h1>
<div id="html">
<pre class="prettyprint lang-html"></pre>
</div>
<h1>Javascript</h1>
<div id="javascript">
<pre class="prettyprint lang-javascript"></pre>
</div>
<h1>Optional CSS</h1>
<div id="css">
<pre class="prettyprint lang-css"></pre>
</div>
</div>
</body>
</html>

View File

@ -473,6 +473,7 @@
<li><span class="results">&dagger;</span> <a href="example-widget-columns.html">Columns Highlight widget</a> (v2.0.17)</li>
<li><span class="label label-info">Beta</span> <a href="example-widget-column-selector.html">Column Selector widget</a> (<span class="version">v2.15</span>; <span class="version updated">v2.18.5</span>).</li>
<li><a href="example-widget-editable.html">Content Editable widget</a> (v2.9; <span class="version updated">v2.18.0</span>).</li>
<li><span class="label label-info">Beta</span> <a href="example-dragtable.html">Dragtable mod</a> - (jQuery UI widget for column reordering [<a href="http://stackoverflow.com/a/27770224/145346">ref</a>]; <span class="version">v2.18.5</span>).</li>
<li><span class="results">&dagger;</span> Filter Widget (<span class="version updated">v2.17.4</span>):
<ul>
<li><a href="example-widget-filter.html">basic</a> (v2.0.18; <span class="version updated">v2.18.1</span>)</li>
@ -484,7 +485,7 @@
<li>formatter: <a href="example-widget-filter-formatter-select2.html">select2</a> (<span class="version">v2.16.0</span>; <span class="version updated">v2.18.5</span>)</li>
</ul>
</li>
<li><a href="example-widget-formatter.html">Formatter widget</a> (<span class="version">v2.18.5</span>).</li>
<li><span class="label label-info">Beta</span> <a href="example-widget-formatter.html">Formatter widget</a> (<span class="version">v2.18.5</span>).</li>
<li>Grouping rows widget:
<ul>
<li><a href="example-widget-grouping.html">basic</a> (v2.8; <span class="version updated">v2.18.0</span>).</li>
@ -542,7 +543,7 @@
<ul>
<li><span class="label label-info">Beta</span> <a href="../beta-testing/example-pager-custom-controls.html">Custom pager control script</a> (<span class="version updated">v2.17.1</span>)</li>
<li><span class="label label-info">Alpha</span> <a href="../beta-testing/example-widget-column-reorder.html">Column reorder widget</a> - not working 100% with sticky headers</li>
<li><span class="label label-info">Beta</span> Column reorder using the <a href="http://stackoverflow.com/a/27770224/145346">dragtable widget</a>.</li>
<li><span class="label label-info">Alpha</span> Column reorder using the <a href="http://stackoverflow.com/a/27770224/145346">dragtable widget</a> (non-mod version).</li>
</ul>
</div>

View File

@ -1,7 +1,211 @@
/*! Dragtable Mod for TableSorter - 1/14/2015 (v2.18.5) *//*
* Requires
* tablesorter v2.8+
* jQuery 1.7+
* jQuery UI (Core, Widget, Mouse & Sortable)
* Dragtable by Akottr (https://github.com/akottr) modified by Rob Garrison
*/
/*jshint browser:true, jquery:true, unused:false */
/*global jQuery: false */
;(function( $ ) {
'use strict';
var undef,
ts = $.tablesorter;
ts.dragtable = {
create : function( _this ) {
var hasAccept,
$table = _this.originalTable.el,
handle = _this.options.dragHandle.replace('.', '');
$table.children('thead').children().children('th,td').each(function(){
var $this = $(this);
if ( !$this.find( _this.options.dragHandle + ',.' + handle + '-disabled' ).length ) {
hasAccept = _this.options.dragaccept ? $this.hasClass( _this.options.dragaccept.replace('.', '') ) : true;
$this
// sortClass includes a "." to match the tablesorter selectorSort option - for consistency
.wrapInner('<div class="' + _this.options.sortClass.replace('.', '') + '"/>')
// add handle class + "-disabled" to drag-disabled columns
.prepend('<div class="' + handle + ( hasAccept ? '' : '-disabled' ) + '"></div>');
}
});
},
start : function( table ) {
table = $( table )[0];
if ( table && table.config ) {
table.config.widgetOptions.dragtableLast = {
search : $( table ).data( 'lastSearch' ),
order : ts.dragtable.getOrder( table )
};
}
},
update : function( _this ) {
var t, list, val,
dragTable = _this.originalTable,
table = dragTable.el[ 0 ],
$table = $( table ),
c = table.config,
wo = c && c.widgetOptions,
startIndex = dragTable.startIndex - 1,
endIndex = dragTable.endIndex - 1,
columnOrder = ts.dragtable.getOrder( table ) || [],
hasFilters = ts.hasWidget( $table, 'filter' ) || false,
last = wo && wo.dragtableLast || {},
// update moved filters
filters = [];
// only trigger updateAll if column order changed
if ( ( last.order || [] ).join( '' ) !== columnOrder.join( '' ) ) {
if ( c.sortList.length ) {
// must deep extend (nested arrays) to prevent list from changing with c.sortList
list = $.extend( true, [], c.sortList );
$.each( columnOrder, function( indx, value ) {
val = ts.isValueInArray( parseInt( value, 10 ), list );
if ( value !== last.order[ indx ] && val >= 0 ) {
c.sortList[ val ][ 0 ] = indx;
}
});
}
// update filter widget
if ( hasFilters ) {
$.each( last.search || [], function( indx ) {
filters[ indx ] = last.search[ columnOrder[ indx ] ];
});
}
// update preset editable widget columns
t = ( ts.hasWidget( c.$table, 'editable' ) || false ) ? wo.editable_columnsArray : false;
if ( t ) {
c.widgetOptions.editable_columnsArray = ts.dragtable.reindexArrayItem( t, startIndex, endIndex );
}
// update ignore math columns
t = ( ts.hasWidget( c.$table, 'math' ) || false ) ? wo.math_ignore : false;
if ( t ) {
c.widgetOptions.math_ignore = ts.dragtable.reindexArrayItem( t, startIndex, endIndex );
}
// update preset resizable widget widths
t = ( ts.hasWidget( c.$table, 'resizable' ) || false ) ? wo.resizable_widths : false;
if ( t ) {
// use zero-based indexes in the array
wo.resizable_widths = ts.dragtable.moveArrayItem( t, startIndex, endIndex );
}
/*
// chart widget WIP - there are other options that need to be rearranged!
t = ( ts.hasWidget( c.$table, 'chart' ) || false ) ? wo.chart_ignoreColumns : false;
if ( t ) {
// use zero-based indexes in the array
wo.chart_ignoreColumns = ts.dragtable.moveArrayItem( t, startIndex, endIndex );
}
*/
$table.trigger('updateAll', [ false, function() {
if ( hasFilters ) {
setTimeout( function() {
// just update the filter values
c.lastCombinedFilter = null;
c.$table.data('lastSearch', filters);
ts.setFilters( $table, filters );
if ($.isFunction(_this.options.tablesorterComplete)) {
_this.options.tablesorterComplete( c.table );
}
}, 10 );
}
} ]);
}
},
getOrder : function( table ) {
return $( table ).children( 'thead' ).children( '.' + ts.css.headerRow ).children().map( function() {
return $( this ).attr( 'data-column' );
}).get() || [];
},
// bubble the moved col left or right
startColumnMove : function( dragTable ) {
var $cols,
c = dragTable.el[ 0 ].config,
startIndex = dragTable.startIndex - 1,
endIndex = dragTable.endIndex - 1,
cols = c.columns - 1,
pos = endIndex === cols ? false : endIndex <= startIndex,
$rows = c.$table.children().children( 'tr' );
if ( c.debug ) {
ts.log( 'Inserting column ' + startIndex + ( pos ? ' before' : ' after' ) + ' column ' + endIndex );
}
$rows.each( function() {
$cols = $( this ).children();
$cols.eq( startIndex )[ pos ? 'insertBefore' : 'insertAfter' ]( $cols.eq( endIndex ) );
});
// rearrange col in colgroup
$cols = c.$table.children( 'colgroup' ).children();
$cols.eq( startIndex )[ pos ? 'insertBefore' : 'insertAfter' ]( $cols.eq( endIndex ) );
},
swapNodes : function( a, b ) {
var indx, aparent, asibling,
len = a.length;
for ( indx = 0; indx < len; indx++ ) {
aparent = a[ indx ].parentNode;
asibling = a[ indx ].nextSibling === b[ indx ] ? a[ indx ] : a[ indx ].nextSibling;
b[ indx ].parentNode.insertBefore( a[ indx ], b[ indx ] );
aparent.insertBefore( b[ indx ], asibling );
}
},
// http://stackoverflow.com/a/5306832/145346
moveArrayItem : function( array, oldIndex, newIndex ) {
var indx, len = array.length;
if ( newIndex >= len ) {
indx = newIndex - len;
while ( ( indx-- ) + 1 ) {
array.push( undef );
}
}
array.splice( newIndex, 0, array.splice( oldIndex, 1 )[ 0 ] );
return array;
},
reindexArrayItem : function( array, oldIndex, newIndex ) {
var nIndx = $.inArray( newIndex, array ),
oIndx = $.inArray( oldIndex, array ),
max = Math.max.apply( Math, array ),
arry = [];
// columns in the array were swapped so return original array
if ( nIndx >= 0 && oIndx >= 0 ) {
return array;
}
// columns not in the array were moved
$.each( array, function( indx, value ) {
// column (not in array) inserted between indexes
if ( newIndex < oldIndex ) {
// ( [ 0,1,2,3 ], 5, 1 ) -> column inserted between 0 & 1 => [ 0,2,3,4 ]
if ( value >= newIndex ) {
// 5 -> 1 [ 0, 2, 3 ] then 1 -> 0 [ 1, 2, 3 ]
arry.push( value + ( value < oldIndex ? 1 : 0 ) );
} else {
arry.push( value );
}
} else if ( newIndex > oldIndex ) {
// ( [ 0,1,2,3 ], 1, 5 ) -> column in array moved outside => [ 0,1,2,5 ]
if ( value === oldIndex ) {
arry.push( newIndex );
} else if ( value < newIndex && value >= oldIndex ) {
arry.push( value - 1 );
} else if ( value <= newIndex ) {
arry.push( value );
} else if ( value > oldIndex ) {
arry.push( value + ( value < newIndex ? 0 : 1 ) );
}
}
});
return arry.sort();
}
};
/*!
* dragtable
* _____ _
* | |___ _| |
* | | | | . | . |
* |_|_|_|___|___|
*
* @Version 2.0.14
* @Version 2.0.14 MOD
*
* Copyright (c) 2010-2013, Andres akottr@gmail.com
* Dual licensed under the MIT (MIT-LICENSE.txt)
@ -52,7 +256,6 @@
* Special thx to all pull requests comitters
*/
(function($) {
$.widget("akottr.dragtable", {
options: {
revert: false, // smooth revert
@ -74,7 +277,10 @@
beforeStart: $.noop, // returning FALSE will stop the execution chain.
beforeMoving: $.noop,
beforeReorganize: $.noop,
beforeStop: $.noop
beforeStop: $.noop,
// new options
tablesorterComplete: null,
sortClass : '.sorter'
},
originalTable: {
el: null,
@ -108,44 +314,16 @@
*/
_restoreState: function(persistObj) {
for (var n in persistObj) {
this.originalTable.startIndex = $('#' + n).closest('th').prevAll().size() + 1;
this.originalTable.endIndex = parseInt(persistObj[n], 10) + 1;
this._bubbleCols();
if (n in persistObj) {
this.originalTable.startIndex = $('#' + n).closest('th').prevAll().length + 1;
this.originalTable.endIndex = parseInt(persistObj[n], 10) + 1;
this._bubbleCols();
}
}
},
// bubble the moved col left or right
_bubbleCols: function() {
var i, j, col1, col2;
var from = this.originalTable.startIndex;
var to = this.originalTable.endIndex;
/* Find children thead and tbody.
* Only to process the immediate tr-children. Bugfix for inner tables
*/
var thtb = this.originalTable.el.children();
if (this.options.excludeFooter) {
thtb = thtb.not('tfoot');
}
if (from < to) {
for (i = from; i < to; i++) {
col1 = thtb.find('> tr > td:nth-child(' + i + ')')
.add(thtb.find('> tr > th:nth-child(' + i + ')'));
col2 = thtb.find('> tr > td:nth-child(' + (i + 1) + ')')
.add(thtb.find('> tr > th:nth-child(' + (i + 1) + ')'));
for (j = 0; j < col1.length; j++) {
swapNodes(col1[j], col2[j]);
}
}
} else {
for (i = from; i > to; i--) {
col1 = thtb.find('> tr > td:nth-child(' + i + ')')
.add(thtb.find('> tr > th:nth-child(' + i + ')'));
col2 = thtb.find('> tr > td:nth-child(' + (i - 1) + ')')
.add(thtb.find('> tr > th:nth-child(' + (i - 1) + ')'));
for (j = 0; j < col1.length; j++) {
swapNodes(col1[j], col2[j]);
}
}
}
ts.dragtable.startColumnMove(this.originalTable);
},
_rearrangeTableBackroundProcessing: function() {
var _this = this;
@ -154,10 +332,14 @@
_this.options.beforeStop(_this.originalTable);
_this.sortableTable.el.remove();
restoreTextSelection();
ts.dragtable.update(_this);
// persist state if necessary
if (_this.options.persistState !== null) {
$.isFunction(_this.options.persistState) ? _this.options.persistState(_this.originalTable) : _this.persistState();
if ($.isFunction(_this.options.persistState)) {
_this.options.persistState(_this.originalTable);
} else {
_this.persistState();
}
};
},
_rearrangeTable: function() {
@ -171,7 +353,7 @@
_this.options.beforeReorganize(_this.originalTable, _this.sortableTable);
// do reorganisation asynchronous
// for chrome a little bit more than 1 ms because we want to force a rerender
_this.originalTable.endIndex = _this.sortableTable.movingRow.prevAll().size() + 1;
_this.originalTable.endIndex = _this.sortableTable.movingRow.prevAll().length + 1;
setTimeout(_this._rearrangeTableBackroundProcessing(), 50);
};
},
@ -181,28 +363,33 @@
* each li with a separate table representig a single col of the original table.
*/
_generateSortable: function(e) {
!e.cancelBubble && (e.cancelBubble = true);
if (e.cancelBubble) {
e.cancelBubble = true;
} else {
e.stopPropagation();
}
var _this = this;
// table attributes
var attrs = this.originalTable.el[0].attributes;
var attrsString = '';
var tableAttrsString = '';
for (var i = 0; i < attrs.length; i++) {
if (attrs[i].nodeValue && attrs[i].nodeName != 'id' && attrs[i].nodeName != 'width') {
attrsString += attrs[i].nodeName + '="' + attrs[i].nodeValue + '" ';
if ( (attrs[i].value || attrs[i].nodeValue) && attrs[i].nodeName != 'id' && attrs[i].nodeName != 'width') {
tableAttrsString += attrs[i].nodeName + '="' + ( attrs[i].value || attrs[i].nodeValue ) + '" ';
}
}
// row attributes
var rowAttrsArr = [];
//compute height, special handling for ie needed :-(
var heightArr = [];
this.originalTable.el.find('tr').slice(0, this.options.maxMovingRows).each(function(i, v) {
// don't save tfoot attributes because it messes up indexing
_this.originalTable.el.children('thead, tbody').children('tr:visible').slice(0, _this.options.maxMovingRow).each(function() {
// row attributes
var attrs = this.attributes;
var attrsString = "";
var attrsString = '';
for (var j = 0; j < attrs.length; j++) {
if (attrs[j].nodeValue && attrs[j].nodeName != 'id') {
attrsString += " " + attrs[j].nodeName + '="' + attrs[j].nodeValue + '"';
if ( (attrs[j].value || attrs[j].nodeValue ) && attrs[j].nodeName != 'id') {
attrsString += ' ' + attrs[j].nodeName + '="' + ( attrs[j].value || attrs[j].nodeValue ) + '"';
}
}
rowAttrsArr.push(attrsString);
@ -217,47 +404,72 @@
* Only to process the immediate tr-children. Bugfix for inner tables
*/
var thtb = _this.originalTable.el.children();
if (this.options.excludeFooter) {
thtb = thtb.not('tfoot');
}
thtb.find('> tr > th').each(function(i, v) {
var headerRows = thtb.filter('thead').children('tr:visible');
var visibleRows = thtb.filter('tbody').children('tr:visible');
headerRows.eq(0).children('th, td').filter(':visible').each(function() {
var w = $(this).outerWidth();
widthArr.push(w);
totalWidth += w;
});
if(_this.options.exact) {
var difference = totalWidth - _this.originalTable.el.outerWidth();
widthArr[0] -= difference;
var difference = totalWidth - _this.originalTable.el.outerWidth();
widthArr[0] -= difference;
}
// one extra px on right and left side
totalWidth += 2
totalWidth += 2;
var captionHeight = 0;
thtb.filter('caption').each(function(){
captionHeight += $(this).outerHeight();
});
var sortableHtml = '<ul class="dragtable-sortable" style="position:absolute; width:' + totalWidth + 'px;">';
var sortableColumn = [];
// assemble the needed html
thtb.find('> tr > th').each(function(i, v) {
var width_li = $(this).outerWidth();
sortableHtml += '<li style="width:' + width_li + 'px;">';
sortableHtml += '<table ' + attrsString + '>';
var row = thtb.find('> tr > th:nth-child(' + (i + 1) + ')');
if (_this.options.maxMovingRows > 1) {
row = row.add(thtb.find('> tr > td:nth-child(' + (i + 1) + ')').slice(0, _this.options.maxMovingRows - 1));
// build list
var rowIndex,
columns = headerRows.eq(0).children('th, td').length;
/*jshint loopfunc:true */
for (i = 0; i < columns; i++) {
var row = headerRows.children(':nth-child(' + (i + 1) + ')');
if (row.is(':visible')) {
rowIndex = 0;
sortableColumn[i] = '<li style="width:' + row.outerWidth() + 'px;">' +
'<table ' + tableAttrsString + '>' +
( captionHeight ? '<caption style="height:' + captionHeight + 'px;"></caption>' : '' ) +
'<thead>';
// thead
headerRows.each(function(j){
sortableColumn[i] += '<tr ' + rowAttrsArr[rowIndex++] +
( heightArr[j] ? ' style="height:' + heightArr[j] + 'px;"' : '' ) + '>' +
row[j].outerHTML + '</tr>';
});
sortableColumn[i] += '</thead><tbody>';
// tbody
row = visibleRows.children(':nth-child(' + (i + 1) + ')');
if (_this.options.maxMovingRows > 1) {
row = row.add(visibleRows.children(':nth-child(' + (i + 1) + ')').slice(0, _this.options.maxMovingRows - 1));
}
row.each(function(j) {
sortableColumn[i] += '<tr ' + rowAttrsArr[rowIndex++] +
( heightArr[j] ? ' style="height:' + heightArr[j] + 'px;"' : '' ) + '>' +
this.outerHTML + '</tr>';
});
sortableColumn[i] += '</tbody>';
// add footer to end of max Rows
if (!_this.options.excludeFooter) {
sortableColumn[i] += '<tfoot><tr ' + rowAttrsArr[rowIndex++] + '>' +
thtb.filter('tfoot').children('tr:visible').children()[i].outerHTML + '</tr></tfoot>';
}
sortableColumn[i] += '</table></li>';
}
row.each(function(j) {
// TODO: May cause duplicate style-Attribute
var row_content = $(this).clone().wrap('<div></div>').parent().html();
if (row_content.toLowerCase().indexOf('<th') === 0) sortableHtml += "<thead>";
sortableHtml += '<tr ' + rowAttrsArr[j] + '" style="height:' + heightArr[j] + 'px;">';
sortableHtml += row_content;
if (row_content.toLowerCase().indexOf('<th') === 0) sortableHtml += "</thead>";
sortableHtml += '</tr>';
});
sortableHtml += '</table>';
sortableHtml += '</li>';
});
sortableHtml += '</ul>';
}
sortableHtml += sortableColumn.join('') + '</ul>';
this.sortableTable.el = this.originalTable.el.before(sortableHtml).prev();
// set width if necessary
this.sortableTable.el.find('> li > table').each(function(i, v) {
this.sortableTable.el.find('> li > table').each(function(i) {
$(this).css('width', widthArr[i] + 'px');
});
@ -279,11 +491,10 @@
});
// assign start index
this.originalTable.startIndex = $(e.target).closest('th').prevAll().size() + 1;
this.originalTable.startIndex = $(e.target).closest('th,td').prevAll().length + 1;
this.options.beforeMoving(this.originalTable, this.sortableTable);
// Start moving by delegating the original event to the new sortable table
this.sortableTable.movingRow = this.sortableTable.el.find('> li:nth-child(' + this.originalTable.startIndex + ')');
this.sortableTable.movingRow = this.sortableTable.el.children('li:nth-child(' + this.originalTable.startIndex + ')');
// prevent the user from drag selecting "highlighting" surrounding page elements
disableTextSelection();
@ -300,7 +511,7 @@
// Some inner divs to deliver the posibillity to style the placeholder more sophisticated
var placeholder = this.sortableTable.el.find('.ui-sortable-placeholder');
if(!placeholder.height() <= 0) {
if(placeholder.height() > 0) {
placeholder.css('height', this.sortableTable.el.find('.ui-sortable-helper').height());
}
@ -308,42 +519,42 @@
},
bindTo: {},
_create: function() {
this.originalTable = {
el: this.element,
var _this = this;
_this.originalTable = {
el: _this.element,
selectedHandle: $(),
sortOrder: {},
startIndex: 0,
endIndex: 0
};
// bind draggable to 'th' by default
this.bindTo = this.originalTable.el.find('th');
ts.dragtable.create( _this );
// filter only the cols that are accepted
if (this.options.dragaccept) {
this.bindTo = this.bindTo.filter(this.options.dragaccept);
}
_this.bindTo = '> thead > tr > ' + ( _this.options.dragaccept || 'th, td' );
// bind draggable to handle if exists
if (this.bindTo.find(this.options.dragHandle).size() > 0) {
this.bindTo = this.bindTo.find(this.options.dragHandle);
if (_this.element.find(_this.bindTo).find(_this.options.dragHandle).length) {
_this.bindTo += ' ' + _this.options.dragHandle;
}
// restore state if necessary
if (this.options.restoreState !== null) {
$.isFunction(this.options.restoreState) ? this.options.restoreState(this.originalTable) : this._restoreState(this.options.restoreState);
if ($.isFunction(_this.options.restoreState)) {
_this.options.restoreState(_this.originalTable);
} else {
_this._restoreState(_this.options.restoreState);
}
var _this = this;
this.bindTo.mousedown(function(evt) {
_this.originalTable.el.on( 'mousedown.dragtable', _this.bindTo, function(evt) {
// listen only to left mouse click
if(evt.which!==1) return;
if (evt.which!==1) return;
ts.dragtable.start( _this.originalTable.el );
if (_this.options.beforeStart(_this.originalTable) === false) {
return;
}
clearTimeout(this.downTimer);
this.downTimer = setTimeout(function() {
_this.originalTable.selectedHandle = $(this);
clearTimeout(_this.downTimer);
_this.downTimer = setTimeout(function() {
_this.originalTable.selectedHandle = $(_this);
_this.originalTable.selectedHandle.addClass('dragtable-handle-selected');
_this._generateSortable(evt);
}, _this.options.clickDelay);
}).mouseup(function(evt) {
clearTimeout(this.downTimer);
}).on( 'mouseup.dragtable', _this.options.dragHandle,function() {
clearTimeout(_this.downTimer);
});
},
redraw: function(){
@ -351,20 +562,18 @@
this._create();
},
destroy: function() {
this.bindTo.unbind('mousedown');
_this.originalTable.el.off('mousedown.dragtable mouseup.dragtable', _this.bindTo);
$.Widget.prototype.destroy.apply(this, arguments); // default destroy
// now do other stuff particular to this widget
}
});
/** closure-scoped "private" functions **/
var body_onselectstart_save = $(document.body).attr('onselectstart'),
body_unselectable_save = $(document.body).attr('unselectable');
body_unselectable_save = $(document.body).attr('unselectable');
// css properties to disable user-select on the body tag by appending a <style> tag to the <head>
// remove any current document selections
function disableTextSelection() {
// jQuery doesn't support the element.text attribute in MSIE 8
// http://stackoverflow.com/questions/2692770/style-style-textcss-appendtohead-does-not-work-in-ie
@ -379,7 +588,6 @@
}
// remove the <style> tag, and restore the original <body> onselectstart attribute
function restoreTextSelection() {
$('#__dragtable_disable_text_selection__').remove();
if (body_onselectstart_save) {
@ -394,10 +602,4 @@
}
}
function swapNodes(a, b) {
var aparent = a.parentNode;
var asibling = a.nextSibling === b ? a : a.nextSibling;
b.parentNode.insertBefore(a, b);
aparent.insertBefore(b, asibling);
}
})(jQuery);

View File

@ -35,9 +35,9 @@ var tse = $.tablesorter.editable = {
update: function( c, wo ) {
var indx, tmp, $t,
colIndex = [],
cols = [];
if ( $.type( wo.editable_columns ) === 'string' && wo.editable_columns.indexOf( '-' ) >= 0 ) {
if ( !wo.editable_columnsArray && $.type( wo.editable_columns ) === 'string' && wo.editable_columns.indexOf( '-' ) >= 0 ) {
// editable_columns can contain a range string ( i.e. '2-4' )
tmp = wo.editable_columns.split( /\s*-\s*/ );
indx = parseInt( tmp[ 0 ], 10 ) || 0;
@ -46,15 +46,21 @@ var tse = $.tablesorter.editable = {
tmp = c.columns - 1;
}
for ( ; indx <= tmp; indx++ ) {
colIndex.push( indx );
cols.push( 'td:nth-child(' + ( indx + 1 ) + ')' );
}
} else if ( $.isArray( wo.editable_columns ) ) {
$.each( wo.editable_columns, function( i, col ) {
$.each( wo.editable_columnsArray || wo.editable_columns, function( i, col ) {
if ( col < c.columns ) {
colIndex.push( col );
cols.push( 'td:nth-child(' + ( col + 1 ) + ')' );
}
});
}
if ( !wo.editable_columnsArray ) {
wo.editable_columnsArray = colIndex;
wo.editable_columnsArray.sort(function(a,b){ return a - b; });
}
tmp = $( '<div>' ).wrapInner( wo.editable_wrapContent ).children().length || $.isFunction( wo.editable_wrapContent );
// IE does not allow making TR/TH/TD cells directly editable ( issue #404 )
// so add a div or span inside ( it's faster than using wrapInner() )
@ -91,7 +97,7 @@ var tse = $.tablesorter.editable = {
c.$table
.off( 'updateComplete pagerComplete '.split( ' ' ).join( '.tseditable' ) )
.on( 'updateComplete pagerComplete '.split( ' ' ).join( '.tseditable' ), function() {
tse.update( c, wo );
tse.update( c, c.widgetOptions );
});
c.$tbodies

View File

@ -8,6 +8,8 @@
"use strict";
var ts = $.tablesorter,
events = ( 'tablesorter-initialized update updateAll updateRows addRows updateCell ' +
'filterReset filterEnd recalculate ' ).split(' ').join('.tsmath '),
math = {
// get all of the row numerical values in an arry
@ -183,7 +185,7 @@
* (c)2011 ecava
* Dual licensed under the MIT or GPL Version 2 licenses.
*/
ts.formatMask = function(m, v, tmpPrefix, tmpSuffix){
ts.formatMask = function(m, v, tmpPrefix, tmpSuffix) {
if ( !m || isNaN(+v) ) {
return v; // return as it is.
}
@ -388,9 +390,13 @@
},
init : function(table, thisWidget, c, wo){
c.$table
.bind('tablesorter-initialized update updateRows addRows updateCell filterReset filterEnd '.split(' ').join('.tsmath '), function(e){
.unbind(events + ' updateComplete.tsmath')
.bind(events, function(e){
var init = e.type === 'tablesorter-initialized';
if (!wo.math_isUpdating || init) {
if (e.type === 'updateAll') {
// redo data-column indexes in case columns were rearranged
ts.computeColumnIndex( c.$table.children('tbody').children() );
} else if (!wo.math_isUpdating || init) {
math.recalculate( table, c, wo, init );
}
})
@ -403,9 +409,10 @@
},
// this remove function is called when using the refreshWidgets method or when destroying the tablesorter plugin
// this function only applies to tablesorter v2.4+
remove: function(table, c, wo){
remove: function(table, c, wo, refreshing){
if (refreshing) { return; }
$(table)
.unbind('tablesorter-initialized update updateRows addRows updateCell filterReset filterEnd '.split(' ').join('.tsmath '))
.unbind(events + ' updateComplete.tsmath')
.find('[data-' + wo.math_data + ']').empty();
}
});