otsdaq_utilities  v2_05_02_indev
moveable_rows.js
1 var MoveRows = function(table){
2 
3  this.table = table; //hold Tabulator object
4  this.placeholderElement = this.createPlaceholderElement();
5  this.hoverElement = false; //floating row header element
6  this.checkTimeout = false; //click check timeout holder
7  this.checkPeriod = 150; //period to wait on mousedown to consider this a move and not a click
8  this.moving = false; //currently moving row
9  this.toRow = false; //destination row
10  this.toRowAfter = false; //position of moving row relative to the desitnation row
11  this.hasHandle = false; //row has handle instead of fully movable row
12  this.startY = 0; //starting Y position within header element
13  this.startX = 0; //starting X position within header element
14 
15  this.moveHover = this.moveHover.bind(this);
16  this.endMove = this.endMove.bind(this);
17  this.tableRowDropEvent = false;
18 
19  this.touchMove = false;
20 
21  this.connection = false;
22  this.connections = [];
23 
24  this.connectedTable = false;
25  this.connectedRow = false;
26 };
27 
28 MoveRows.prototype.createPlaceholderElement = function(){
29  var el = document.createElement("div");
30 
31  el.classList.add("tabulator-row");
32  el.classList.add("tabulator-row-placeholder");
33 
34  return el;
35 };
36 
37 
38 MoveRows.prototype.initialize = function(handle){
39  this.connection = this.table.options.movableRowsConnectedTables;
40 };
41 
42 MoveRows.prototype.setHandle = function(handle){
43  this.hasHandle = handle;
44 };
45 
46 MoveRows.prototype.initializeGroupHeader = function(group){
47  var self = this,
48  config = {},
49  rowEl;
50 
51  //inter table drag drop
52  config.mouseup = function(e){
53  self.tableRowDrop(e, row);
54  }.bind(self);
55 
56  //same table drag drop
57  config.mousemove = function(e){
58  if(((e.pageY - Tabulator.prototype.helpers.elOffset(group.element).top) + self.table.rowManager.element.scrollTop) > (group.getHeight() / 2)){
59  if(self.toRow !== group || !self.toRowAfter){
60  var rowEl = group.getElement();
61  rowEl.parentNode.insertBefore(self.placeholderElement, rowEl.nextSibling);
62  self.moveRow(group, true);
63  }
64  }else{
65  if(self.toRow !== group || self.toRowAfter){
66  var rowEl = group.getElement();
67  if(rowEl.previousSibling){
68  rowEl.parentNode.insertBefore(self.placeholderElement, rowEl);
69  self.moveRow(group, false);
70  }
71  }
72  }
73  }.bind(self);
74 
75  group.modules.moveRow = config;
76 };
77 
78 MoveRows.prototype.initializeRow = function(row){
79  var self = this,
80  config = {},
81  rowEl;
82 
83  //inter table drag drop
84  config.mouseup = function(e){
85  self.tableRowDrop(e, row);
86  }.bind(self);
87 
88  //same table drag drop
89  config.mousemove = function(e){
90  if(((e.pageY - Tabulator.prototype.helpers.elOffset(row.element).top) + self.table.rowManager.element.scrollTop) > (row.getHeight() / 2)){
91  if(self.toRow !== row || !self.toRowAfter){
92  var rowEl = row.getElement();
93  rowEl.parentNode.insertBefore(self.placeholderElement, rowEl.nextSibling);
94  self.moveRow(row, true);
95  }
96  }else{
97  if(self.toRow !== row || self.toRowAfter){
98  var rowEl = row.getElement();
99  rowEl.parentNode.insertBefore(self.placeholderElement, rowEl);
100  self.moveRow(row, false);
101  }
102  }
103  }.bind(self);
104 
105 
106  if(!this.hasHandle){
107 
108  rowEl = row.getElement();
109 
110  rowEl.addEventListener("mousedown", function(e){
111  if(e.which === 1){
112  self.checkTimeout = setTimeout(function(){
113  self.startMove(e, row);
114  }, self.checkPeriod);
115  }
116  });
117 
118  rowEl.addEventListener("mouseup", function(e){
119  if(e.which === 1){
120  if(self.checkTimeout){
121  clearTimeout(self.checkTimeout);
122  }
123  }
124  });
125 
126  this.bindTouchEvents(row, row.getElement());
127  }
128 
129  row.modules.moveRow = config;
130 };
131 
132 MoveRows.prototype.initializeCell = function(cell){
133  var self = this,
134  cellEl = cell.getElement();
135 
136  cellEl.addEventListener("mousedown", function(e){
137  if(e.which === 1){
138  self.checkTimeout = setTimeout(function(){
139  self.startMove(e, cell.row);
140  }, self.checkPeriod);
141  }
142  });
143 
144  cellEl.addEventListener("mouseup", function(e){
145  if(e.which === 1){
146  if(self.checkTimeout){
147  clearTimeout(self.checkTimeout);
148  }
149  }
150  });
151 
152  this.bindTouchEvents(cell.row, cell.getElement());
153 };
154 
155 MoveRows.prototype.bindTouchEvents = function(row, element){
156  var self = this,
157  startYMove = false, //shifting center position of the cell
158  dir = false,
159  currentRow, nextRow, prevRow, nextRowHeight, prevRowHeight, nextRowHeightLast, prevRowHeightLast;
160 
161  element.addEventListener("touchstart", function(e){
162  self.checkTimeout = setTimeout(function(){
163  self.touchMove = true;
164  currentRow = row;
165  nextRow = row.nextRow();
166  nextRowHeight = nextRow ? nextRow.getHeight()/2 : 0;
167  prevRow = row.prevRow();
168  prevRowHeight = prevRow ? prevRow.getHeight()/2 : 0;
169  nextRowHeightLast = 0;
170  prevRowHeightLast = 0;
171  startYMove = false;
172 
173  self.startMove(e, row);
174  }, self.checkPeriod);
175  }, {passive: true});
176  this.moving, this.toRow, this.toRowAfter
177  element.addEventListener("touchmove", function(e){
178 
179  var halfCol, diff, moveToRow;
180 
181  if(self.moving){
182  e.preventDefault();
183 
184  self.moveHover(e);
185 
186  if(!startYMove){
187  startYMove = e.touches[0].pageY;
188  }
189 
190  diff = e.touches[0].pageY - startYMove;
191 
192  if(diff > 0){
193  if(nextRow && diff - nextRowHeightLast > nextRowHeight){
194  moveToRow = nextRow;
195 
196  if(moveToRow !== row){
197  startYMove = e.touches[0].pageY
198  moveToRow.getElement().parentNode.insertBefore(self.placeholderElement, moveToRow.getElement().nextSibling);
199  self.moveRow(moveToRow, true);
200  }
201  }
202  }else{
203  if(prevRow && -diff - prevRowHeightLast > prevRowHeight){
204  moveToRow = prevRow;
205 
206  if(moveToRow !== row){
207  startYMove = e.touches[0].pageY;
208  moveToRow.getElement().parentNode.insertBefore(self.placeholderElement, moveToRow.getElement());
209  self.moveRow(moveToRow, false);
210  }
211  }
212  }
213 
214  if(moveToRow){
215  currentRow = moveToRow;
216  nextRow = moveToRow.nextRow();
217  nextRowHeightLast = nextRowHeight;
218  nextRowHeight = nextRow ? nextRow.getHeight() / 2 : 0;
219  prevRow = moveToRow.prevRow();
220  prevRowHeightLast = prevRowHeight;
221  prevRowHeight = prevRow ? prevRow.getHeight() / 2 : 0;
222  }
223  }
224  });
225 
226  element.addEventListener("touchend", function(e){
227  if(self.checkTimeout){
228  clearTimeout(self.checkTimeout);
229  }
230  if(self.moving){
231  self.endMove(e);
232  self.touchMove = false;
233  }
234  });
235 };
236 
237 MoveRows.prototype._bindMouseMove = function(){
238  var self = this;
239 
240  self.table.rowManager.getDisplayRows().forEach(function(row){
241  if((row.type === "row" || row.type === "group") && row.modules.moveRow.mousemove){
242  row.getElement().addEventListener("mousemove", row.modules.moveRow.mousemove);
243  }
244  });
245 };
246 
247 MoveRows.prototype._unbindMouseMove = function(){
248  var self = this;
249 
250  self.table.rowManager.getDisplayRows().forEach(function(row){
251  if((row.type === "row" || row.type === "group") && row.modules.moveRow.mousemove){
252  row.getElement().removeEventListener("mousemove", row.modules.moveRow.mousemove);
253  }
254  });
255 };
256 
257 MoveRows.prototype.startMove = function(e, row){
258  var element = row.getElement();
259 
260  this.setStartPosition(e, row);
261 
262  this.moving = row;
263 
264  this.table.element.classList.add("tabulator-block-select");
265 
266  //create placeholder
267  this.placeholderElement.style.width = row.getWidth() + "px";
268  this.placeholderElement.style.height = row.getHeight() + "px";
269 
270  if(!this.connection){
271  element.parentNode.insertBefore(this.placeholderElement, element);
272  element.parentNode.removeChild(element);
273  }else{
274  this.table.element.classList.add("tabulator-movingrow-sending");
275  this.connectToTables(row);
276  }
277 
278  //create hover element
279  this.hoverElement = element.cloneNode(true);
280  this.hoverElement.classList.add("tabulator-moving");
281 
282  if(this.connection){
283  document.body.appendChild(this.hoverElement);
284  this.hoverElement.style.left = "0";
285  this.hoverElement.style.top = "0";
286  this.hoverElement.style.width = this.table.element.clientWidth + "px";
287  this.hoverElement.style.whiteSpace = "nowrap";
288  this.hoverElement.style.overflow = "hidden";
289  this.hoverElement.style.pointerEvents = "none";
290  }else{
291  this.table.rowManager.getTableElement().appendChild(this.hoverElement);
292 
293  this.hoverElement.style.left = "0";
294  this.hoverElement.style.top = "0";
295 
296  this._bindMouseMove();
297  }
298 
299  document.body.addEventListener("mousemove", this.moveHover);
300  document.body.addEventListener("mouseup", this.endMove);
301 
302  this.moveHover(e);
303 };
304 
305 
306 MoveRows.prototype.setStartPosition = function(e, row){
307  var pageX = this.touchMove ? e.touches[0].pageX : e.pageX,
308  pageY = this.touchMove ? e.touches[0].pageY : e.pageY,
309  element, position;
310 
311  element = row.getElement();
312  if(this.connection){
313  position = element.getBoundingClientRect();
314 
315  this.startX = position.left - pageX + window.pageXOffset;
316  this.startY = position.top - pageY + window.pageYOffset;
317  }else{
318  this.startY = (pageY - element.getBoundingClientRect().top);
319  }
320 };
321 
322 MoveRows.prototype.endMove = function(e){
323  if(!e || e.which === 1 || this.touchMove){
324  this._unbindMouseMove();
325 
326  if(!this.connection){
327  this.placeholderElement.parentNode.insertBefore(this.moving.getElement(), this.placeholderElement.nextSibling);
328  this.placeholderElement.parentNode.removeChild(this.placeholderElement);
329  }
330 
331  this.hoverElement.parentNode.removeChild(this.hoverElement);
332 
333  this.table.element.classList.remove("tabulator-block-select");
334 
335  if(this.toRow){
336  this.table.rowManager.moveRow(this.moving, this.toRow, this.toRowAfter);
337  }
338 
339  this.moving = false;
340  this.toRow = false;
341  this.toRowAfter = false;
342 
343  document.body.removeEventListener("mousemove", this.moveHover);
344  document.body.removeEventListener("mouseup", this.endMove);
345 
346  if(this.connection){
347  this.table.element.classList.remove("tabulator-movingrow-sending");
348  this.disconnectFromTables();
349  }
350  }
351 };
352 
353 MoveRows.prototype.moveRow = function(row, after){
354  this.toRow = row;
355  this.toRowAfter = after;
356 };
357 
358 MoveRows.prototype.moveHover = function(e){
359  if(this.connection){
360  this.moveHoverConnections.call(this, e);
361  }else{
362  this.moveHoverTable.call(this, e);
363  }
364 };
365 
366 MoveRows.prototype.moveHoverTable = function(e){
367  var rowHolder = this.table.rowManager.getElement(),
368  scrollTop = rowHolder.scrollTop,
369  yPos = ((this.touchMove ? e.touches[0].pageY : e.pageY) - rowHolder.getBoundingClientRect().top) + scrollTop,
370  scrollPos;
371 
372  this.hoverElement.style.top = (yPos - this.startY) + "px";
373 };
374 
375 
376 MoveRows.prototype.moveHoverConnections = function(e){
377  this.hoverElement.style.left = (this.startX + (this.touchMove ? e.touches[0].pageX : e.pageX)) + "px";
378  this.hoverElement.style.top = (this.startY + (this.touchMove ? e.touches[0].pageY : e.pageY)) + "px";
379 };
380 
381 
382 //establish connection with other tables
383 MoveRows.prototype.connectToTables = function(row){
384  var self = this,
385  connections = this.table.modules.comms.getConnections(this.connection);
386 
387  this.table.options.movableRowsSendingStart.call(this.table, connections);
388 
389  this.table.modules.comms.send(this.connection, "moveRow", "connect", {
390  row:row,
391  });
392 };
393 
394 
395 //disconnect from other tables
396 MoveRows.prototype.disconnectFromTables = function(){
397  var self = this,
398  connections = this.table.modules.comms.getConnections(this.connection);
399 
400  this.table.options.movableRowsSendingStop.call(this.table, connections);
401 
402  this.table.modules.comms.send(this.connection, "moveRow", "disconnect");
403 };
404 
405 
406 //accept incomming connection
407 MoveRows.prototype.connect = function(table, row){
408  var self = this;
409  if(!this.connectedTable){
410  this.connectedTable = table;
411  this.connectedRow = row;
412 
413  this.table.element.classList.add("tabulator-movingrow-receiving");
414 
415  self.table.rowManager.getDisplayRows().forEach(function(row){
416  if(row.type === "row" && row.modules.moveRow && row.modules.moveRow.mouseup){
417  row.getElement().addEventListener("mouseup", row.modules.moveRow.mouseup);
418  }
419  });
420 
421  self.tableRowDropEvent = self.tableRowDrop.bind(self);
422 
423  self.table.element.addEventListener("mouseup", self.tableRowDropEvent);
424 
425  this.table.options.movableRowsReceivingStart.call(this.table, row, table);
426 
427  return true;
428  }else{
429  console.warn("Move Row Error - Table cannot accept connection, already connected to table:", this.connectedTable);
430  return false;
431  }
432 };
433 
434 //close incomming connection
435 MoveRows.prototype.disconnect = function(table){
436  var self = this;
437  if(table === this.connectedTable){
438  this.connectedTable = false;
439  this.connectedRow = false;
440 
441  this.table.element.classList.remove("tabulator-movingrow-receiving");
442 
443  self.table.rowManager.getDisplayRows().forEach(function(row){
444  if(row.type === "row" && row.modules.moveRow && row.modules.moveRow.mouseup){
445  row.getElement().removeEventListener("mouseup", row.modules.moveRow.mouseup);
446  }
447  });
448 
449  self.table.element.removeEventListener("mouseup", self.tableRowDropEvent);
450 
451  this.table.options.movableRowsReceivingStop.call(this.table, table);
452  }else{
453  console.warn("Move Row Error - trying to disconnect from non connected table")
454  }
455 };
456 
457 MoveRows.prototype.dropComplete = function(table, row, success){
458  var sender = false;
459 
460  if(success){
461 
462  switch(typeof this.table.options.movableRowsSender){
463  case "string":
464  sender = this.senders[this.table.options.movableRowsSender];
465  break;
466 
467  case "function":
468  sender = this.table.options.movableRowsSender;
469  break;
470  }
471 
472  if(sender){
473  sender.call(this, this.moving.getComponent(), row ? row.getComponent() : undefined, table)
474  }else{
475  if(this.table.options.movableRowsSender){
476  console.warn("Mover Row Error - no matching sender found:", this.table.options.movableRowsSender);
477  }
478  }
479 
480  this.table.options.movableRowsSent.call(this.table, this.moving.getComponent(), row ? row.getComponent() : undefined, table);
481 
482  }else{
483  this.table.options.movableRowsSentFailed.call(this.table, this.moving.getComponent(), row ? row.getComponent() : undefined, table);
484  }
485 
486  this.endMove();
487 
488 };
489 
490 
491 MoveRows.prototype.tableRowDrop = function(e, row){
492  var receiver = false,
493  success = false;
494 
495  e.stopImmediatePropagation();
496 
497  switch(typeof this.table.options.movableRowsReceiver){
498  case "string":
499  receiver = this.receivers[this.table.options.movableRowsReceiver];
500  break;
501 
502  case "function":
503  receiver = this.table.options.movableRowsReceiver;
504  break;
505  }
506 
507  if(receiver){
508  success = receiver.call(this, this.connectedRow.getComponent(), row ? row.getComponent() : undefined, this.connectedTable)
509  }else{
510  console.warn("Mover Row Error - no matching receiver found:", this.table.options.movableRowsReceiver)
511  }
512 
513  if(success){
514  this.table.options.movableRowsReceived.call(this.table, this.connectedRow.getComponent(), row ? row.getComponent() : undefined, this.connectedTable);
515  }else{
516  this.table.options.movableRowsReceivedFailed.call(this.table, this.connectedRow.getComponent(), row ? row.getComponent() : undefined, this.connectedTable);
517  }
518 
519  this.table.modules.comms.send(this.connectedTable, "moveRow", "dropcomplete", {
520  row:row,
521  success:success,
522  });
523 };
524 
525 
526 
527 MoveRows.prototype.receivers = {
528  insert:function(fromRow, toRow, fromTable){
529  this.table.addRow(fromRow.getData(), undefined, toRow);
530  return true;
531  },
532 
533  add:function(fromRow, toRow, fromTable){
534  this.table.addRow(fromRow.getData());
535  return true;
536  },
537 
538  update:function(fromRow, toRow, fromTable){
539  if(toRow){
540  toRow.update(fromRow.getData());
541  return true;
542  }
543 
544  return false;
545  },
546 
547  replace:function(fromRow, toRow, fromTable){
548  if(toRow){
549  this.table.addRow(fromRow.getData(), undefined, toRow);
550  toRow.delete();
551  return true;
552  }
553 
554  return false;
555  },
556 };
557 
558 MoveRows.prototype.senders = {
559  delete:function(fromRow, toRow, toTable){
560  fromRow.delete();
561  }
562 };
563 
564 
565 MoveRows.prototype.commsReceived = function(table, action, data){
566  switch(action){
567  case "connect":
568  return this.connect(table, data.row);
569  break;
570 
571  case "disconnect":
572  return this.disconnect(table);
573  break;
574 
575  case "dropcomplete":
576  return this.dropComplete(table, data.row, data.success);
577  break;
578  }
579 };
580 
581 
582 Tabulator.prototype.registerModule("moveRow", MoveRows);