PluginProbe
Contact Forms by Cimatti / 1.0
Contact Forms by Cimatti v1.0
2.3.6 2.3.5 2.3.0 2.2.32 2.2.4 2.2.0 2.1.2 2.1.1 trunk 1.0 1.1 1.2 1.2.1 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 All 62 releases
contact-forms / dragtable / jquery.dragtable.js

jquery.dragtable.js in Contact Forms by Cimatti 1.0, at dragtable/jquery.dragtable.js

332 lines 13.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*!
2 * dragtable
3 *
4 * @Version 1.1.0
5 *
6 * Copyright (c) 2010, Andres Koetter akottr@gmail.com
7 * Dual licensed under the MIT (MIT-LICENSE.txt)
8 * and GPL (GPL-LICENSE.txt) licenses.
9 *
10 * Inspired by the the dragtable from Dan Vanderkam (danvk.org/dragtable/)
11 * Thanks to the jquery and jqueryui comitters
12 *
13 * Any comment, bug report, feature-request is welcome
14 * Feel free to contact me.
15 */
16
17 /* TOKNOW:
18 * For IE7 you need this css rule:
19 * table {
20 * border-collapse: collapse;
21 * }
22 * Or take a clean reset.css (see http://meyerweb.com/eric/tools/css/reset/)
23 */
24
25 /* TODO: investigate
26 * Does not work properly with css rule:
27 * html {
28 * overflow: -moz-scrollbars-vertical;
29 * }
30 * Workaround:
31 * Fixing Firefox issues by scrolling down the page
32 * http://stackoverflow.com/questions/2451528/jquery-ui-sortable-scroll-helper-element-offset-firefox-issue
33 *
34 * var start = $.noop;
35 * var beforeStop = $.noop;
36 * if($.browser.mozilla) {
37 * var start = function (event, ui) {
38 * if( ui.helper !== undefined )
39 * ui.helper.css('position','absolute').css('margin-top', $(window).scrollTop() );
40 * }
41 * var beforeStop = function (event, ui) {
42 * if( ui.offset !== undefined )
43 * ui.helper.css('margin-top', 0);
44 * }
45 * }
46 *
47 * and pass this as start and stop function to the sortable initialisation
48 * start: start,
49 * beforeStop: beforeStop
50 */
51
52 /* TODO: fix it
53 * jqueryui sortable Ticket #4482
54 * Hotfixed it, but not very nice (deprecated api)
55 * if(!p.height() || (jQuery.browser.msie && jQuery.browser.version.match('^7|^6'))) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); };
56 * if(!p.width() || (jQuery.browser.msie && jQuery.browser.version.match('^7|^6'))) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); };
57 */
58
59 /* TODO: support colgroups
60 */
61
62 (function($) {
63 $.fn.dragtable = function(options) {
64 var defaults = {
65 revert:true, // smooth revert
66 dragHandle:'.table-handle', // handle for moving cols, if not exists the whole 'th' is the handle
67 maxMovingRows:40, // 1 -> only header. 40 row should be enough, the rest is usually not in the viewport
68 onlyHeaderThreshold:100, // TODO: not implemented yet, switch automatically between entire col moving / only header moving
69 dragaccept:null, // draggable cols -> default all
70 persistState:null, // url or function -> plug in your custom persistState function right here. function call is persistState(originalTable)
71 restoreState:null, // JSON-Object or function: some kind of experimental aka Quick-Hack TODO: do it better
72 beforeStart:$.noop,
73 beforeMoving:$.noop,
74 beforeReorganize:$.noop,
75 beforeStop:$.noop
76 };
77 var opts = $.extend(defaults, options);
78
79 // here comes the logic. Why var-name _D? My laziness is the culprit!
80 var _D = {
81 // this is the underlying -original- table
82 originalTable:{
83 el:$(),
84 selectedHandle:$(),
85 sortOrder:{},
86 startIndex:0,
87 endIndex:0
88 },
89 // this the sortable table on the layer above the original table
90 sortableTable:{
91 el:$(),
92 selectedHandle:$(),
93 movingRow:$()
94 },
95 swapNodes: function(a, b) {
96 var aparent= a.parentNode;
97 var asibling= a.nextSibling===b? a : a.nextSibling;
98 b.parentNode.insertBefore(a, b);
99 aparent.insertBefore(b, asibling);
100 },
101 // send ids=index as req-param to server
102 persistState: function() {
103 _D.originalTable.el.find('th').each(function(i) {
104 if(this.id != '') {_D.originalTable.sortOrder[this.id]=i;}
105 });
106 $.ajax({url: opts.persistState,
107 data: _D.originalTable.sortOrder});
108 },
109 /*
110 * persistObj looks like
111 * {'id1','2','id3':'3','id2':'1'}
112 * table looks like
113 * | id2 | id1 | id3 |
114 */
115 restoreState: function(persistObj) {;
116 for(n in persistObj) {
117 _D.originalTable.startIndex = $('#'+n).closest('th').prevAll().size() + 1;
118 _D.originalTable.endIndex = parseInt(persistObj[n] + 1);
119 _D.bubbleCols();
120 }
121 },
122 // bubble the moved col left or right
123 bubbleCols: function() {
124 var from = _D.originalTable.startIndex;
125 var to = _D.originalTable.endIndex;
126 if(from < to) {
127 for(var i = from; i < to; i++) {
128 var row1 = _D.originalTable.el.find('tr > td:nth-child('+i+')')
129 .add(_D.originalTable.el.find('tr > th:nth-child('+i+')'));
130 var row2 = _D.originalTable.el.find('tr > td:nth-child('+(i+1)+')')
131 .add(_D.originalTable.el.find('tr > th:nth-child('+(i+1)+')'));
132 for(var j = 0; j < row1.length; j++) {
133 _D.swapNodes(row1[j],row2[j]);
134 }
135 }
136 }
137 else {
138 for(var i = from; i > to; i--) {
139 var row1 = _D.originalTable.el.find('tr > td:nth-child('+i+')')
140 .add(_D.originalTable.el.find('tr > th:nth-child('+i+')'));
141 var row2 = _D.originalTable.el.find('tr > td:nth-child('+(i-1)+')')
142 .add(_D.originalTable.el.find('tr > th:nth-child('+(i-1)+')'));
143 for(var j = 0; j < row1.length; j++) {
144 _D.swapNodes(row1[j],row2[j]);
145 }
146 }
147 }
148 },
149 rearrangeTableBackroundProcessing: function() {
150 return function() {
151 _D.bubbleCols();
152 opts.beforeStop(_D.originalTable);
153 _D.sortableTable.el.remove();
154 // persist state if necessary
155 if(opts.persistState !== null) {
156 $.isFunction(opts.persistState) ? opts.persistState(_D.originalTable) : _D.persistState();
157 }
158 };
159 },
160 rearrangeTable: function() {
161 // remove handler-class -> handler is now finished
162 _D.originalTable.selectedHandle.removeClass('dragtable-handle-selected');
163 // add disabled class -> reorgorganisation starts soon
164 _D.sortableTable.el.sortable("disable");
165 _D.sortableTable.el.addClass('dragtable-disabled');
166 opts.beforeReorganize(_D.originalTable,_D.sortableTable);
167 // do reorganisation asynchronous
168 // for chrome a little bit more than 1 ms because we want to force a rerender
169 _D.originalTable.endIndex = _D.sortableTable.movingRow.prevAll().size() + 1;
170 setTimeout(_D.rearrangeTableBackroundProcessing(),50);
171 },
172 /*
173 * Disrupts the table. The original table stays the same.
174 * But on a layer above the original table we are constructing a list (ul > li)
175 * each li with a separate table representig a single col of the original table.
176 */
177 generateSortable:function(e) {
178 // table attributes
179 var attrs = _D.originalTable.el[0].attributes;
180 var attrsString = '';
181 for(var i=0; i < attrs.length;i++) {
182 if(attrs[i].nodeValue) {
183 attrsString += attrs[i].nodeName + '="' + attrs[i].nodeValue+'" ';
184 }
185 }
186
187 // row attributes
188 var rowAttrsArr = [];
189 //compute height, special handling for ie needed :-(
190 var heightArr = [];
191 _D.originalTable.el.find('tr').slice(0,opts.maxMovingRows).each(function(i,v) {
192 // row attributes
193 var attrs = this.attributes;
194 var attrsString = "";
195 for(var j=0; j < attrs.length;j++) {
196 if(attrs[j].nodeValue) {
197 attrsString += " " + attrs[j].nodeName + '="' + attrs[j].nodeValue+'"';
198 }
199 }
200 rowAttrsArr.push(attrsString);
201 /* the not so easy way */
202 if(jQuery.browser.msie && jQuery.browser.version.match('^7|^6')) {
203 var maxCellHeight = null;
204 $(this).children().each(function() {
205 var tmp = $(this).height();
206 if(maxCellHeight == null || tmp > maxCellHeight) {maxCellHeight = tmp;}
207 });
208 heightArr.push(maxCellHeight);
209 }
210 /* the easy way, but does not work very good in IE < 8 */
211 else {
212 heightArr.push($(this).height());
213 }
214 });
215
216 // compute width, no special handling for ie needed :-)
217 var widthArr = [];
218 // compute total width, needed for not wrapping around after the screen ends (floating)
219 var totalWidth=0;
220 _D.originalTable.el.find('tr > th').each(function(i,v) {
221 // one extra px on right and left side
222 totalWidth+=$(this).outerWidth()+2;
223 widthArr.push($(this).width());
224 });
225
226 var sortableHtml = '<ul class="dragtable-sortable" style="position:absolute; width:'+totalWidth+'px;">';
227 // assemble the needed html
228 _D.originalTable.el.find('tr > th').each(function(i,v) {
229 sortableHtml += '<li>';
230 sortableHtml += '<table ' + attrsString + '>';
231 var row = _D.originalTable.el.find('tr > th:nth-child('+(i+1)+')');
232 if(opts.maxMovingRows > 1) {
233 row = row.add(_D.originalTable.el.find('tr > td:nth-child('+(i+1)+')').slice(0,opts.maxMovingRows-1));
234 }
235 row.each(function(j) {
236 /* the not so easy way (part 2)*/
237 if(jQuery.browser.msie && jQuery.browser.version.match('^7|^6')) {
238 sortableHtml += '<tr '+ rowAttrsArr[j] + '>';
239 // TODO: May cause duplicate style-Attribute
240 sortableHtml += $(this).clone().wrap('<div></div>').parent().html().replace('<TD','<TD style="height:'+heightArr[j]+'px;"');
241 }
242 /* the easy way, but does not work very good in IE < 8 (part 2) */
243 else {
244 // TODO: May cause duplicate style-Attribute
245 sortableHtml += '<tr ' + rowAttrsArr[j] + '" style="height:'+heightArr[j]+'px;">';
246 sortableHtml += $(this).clone().wrap('<div></div>').parent().html();
247 }
248 sortableHtml += '</tr>';
249 });
250 sortableHtml += '</table>';
251 sortableHtml += '</li>';
252 });
253 sortableHtml += '</ul>';
254 _D.sortableTable.el = _D.originalTable.el.before(sortableHtml).prev();
255 // set width if necessary
256 _D.sortableTable.el.find('th').each(function(i,v) {
257 var _this = $(this);
258 if(widthArr[i] > _this.width()) {
259 _this.css({'width':widthArr[i]});
260 }
261 });
262
263 // assign _D.sortableTable.selectedHandle
264 _D.sortableTable.selectedHandle = _D.sortableTable.el.find('th')
265 .find('.dragtable-handle-selected');
266
267 var items = !opts.dragaccept ? 'li' : 'li:has(' + opts.dragaccept + ')';
268 _D.sortableTable.el.sortable({stop:_D.rearrangeTable,
269 items:items,
270 revert:opts.revert,
271 distance: 0
272 })
273 .disableSelection();
274
275 // assign start index
276 _D.originalTable.startIndex = $(e.target).closest('th').prevAll().size() + 1;
277
278 opts.beforeMoving(_D.originalTable, _D.sortableTable);
279 // Start moving by delegating the original event to the new sortable table
280 _D.sortableTable.movingRow = _D.sortableTable.el.find('li:nth-child('+_D.originalTable.startIndex+')');
281 // TODO: learn more about events. Is this the right way?
282 // create down event and delegate it to sortable
283 var mousedownEvt = $.Event('mousedown');
284 mousedownEvt.pageX=e.pageX;
285 mousedownEvt.pageY=e.pageY;
286 mousedownEvt.which=1;
287 _D.sortableTable.movingRow.trigger(mousedownEvt);
288
289 if($.support.noCloneEvent) {
290 // create move event and delegate it to sortable
291 var mousemoveEvt = $.Event('mousemove');
292 mousemoveEvt.pageX=e.pageX+5;
293 mousemoveEvt.pageY=e.pageY+5;
294 _D.sortableTable.movingRow.trigger(mousemoveEvt);
295 }
296 },
297 /* Start asynchronously to be able to give the user a feedback on mousedown (rerender the dom)
298 * Currently disabled. Is it a bug in jQuery?
299 * TODO: Bugreport jQuery -> data.events not undefined-save line 4519, when using delayed events
300 * It issues only warnings in IE, but that offends me anyway.
301 */
302 delayedStart:function(evt) {
303 return function() {
304 _D.generateSortable(evt);
305 };
306 }
307 };
308
309 return this.each(function(){
310 _D.originalTable.el = $(this);
311 // bind draggable to 'th' by default
312 var bindTo = _D.originalTable.el.find('th');
313 // filter only the cols that are accepted
314 if(opts.dragaccept) { bindTo = bindTo.filter(opts.dragaccept); }
315 // bind draggable to handle if exists
316 if(bindTo.find(opts.dragHandle).size() > 0) { bindTo = bindTo.find(opts.dragHandle);}
317 // restore state if necessary
318 if(opts.restoreState !== null) {
319 $.isFunction(opts.restoreState) ? opts.restoreState(_D.originalTable) : _D.restoreState(opts.restoreState);
320 }
321 bindTo.bind('mousedown',function(evt) {
322 _D.originalTable.selectedHandle = $(this);
323 _D.originalTable.selectedHandle.addClass('dragtable-handle-selected');
324 opts.beforeStart(_D.originalTable);
325 // take a breath and rerender before creating sortable table
326 // setTimeout(_D.delayedStart(evt),10);
327 // for immediate start (no delay)
328 _D.generateSortable(evt);
329 });
330 });
331 };
332 })(jQuery);