PageSourceSearch

https://cceh.github.io/projects/tabulator/dist/js/tabulator.js

js cceh.github.io collected 2026-10-03 08:45:48 UTC 283,637 bytes, 13,291 lines download raw bytes

1'use strict';
2
3var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
4
5function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
7/*
8 * This file is part of the Tabulator package.
9 *
10 * (c) Oliver Folkerd <[email protected]>
11 *
12 * For the full copyright and license information, please view the LICENSE
13 * file that was distributed with this source code.
14 *
15 * Full Documentation & Demos can be found at: http://olifolkerd.github.io/tabulator/
16 *
17 */
18
19(function (factory) {
20  "use strict";
21
22  if (typeof define === 'function' && define.amd) {
23    define(['jquery'], factory);
24  } else if (typeof module !== 'undefined' && module.exports) {
25    module.exports = factory(require('jquery'));
26  } else {
27    factory(jQuery);
28  }
29})(function ($, undefined) {
30
31  (function () {
32
33    'use strict';
34
35    // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
36
37
38    var _options;
39
40    if (!Array.prototype.findIndex) {
41
42      Object.defineProperty(Array.prototype, 'findIndex', {
43
44        value: function value(predicate) {
45
46          // 1. Let O be ? ToObject(this value).
47
48
49          if (this == null) {
50
51            throw new TypeError('"this" is null or not defined');
52          }
53
54          var o = Object(this);
55
56          // 2. Let len be ? ToLength(? Get(O, "length")).
57
58
59          var len = o.length >>> 0;
60
61          // 3. If IsCallable(predicate) is false, throw a TypeError exception.
62
63
64          if (typeof predicate !== 'function') {
65
66            throw new TypeError('predicate must be a function');
67          }
68
69          // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
70
71
72          var thisArg = arguments[1];
73
74          // 5. Let k be 0.
75
76
77          var k = 0;
78
79          // 6. Repeat, while k < len
80
81
82          while (k < len) {
83
84            // a. Let Pk be ! ToString(k).
85
86
87            // b. Let kValue be ? Get(O, Pk).
88
89
90            // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
91
92
93            // d. If testResult is true, return k.
94
95
96            var kValue = o[k];
97
98            if (predicate.call(thisArg, kValue, k, o)) {
99
100              return k;
101            }
102
103            // e. Increase k by 1.
104
105
106            k++;
107          }
108
109          // 7. Return -1.
110
111
112          return -1;
113        }
114
115      });
116    }
117
118    // https://tc39.github.io/ecma262/#sec-array.prototype.find
119
120
121    if (!Array.prototype.find) {
122
123      Object.defineProperty(Array.prototype, 'find', {
124
125        value: function value(predicate) {
126
127          // 1. Let O be ? ToObject(this value).
128
129
130          if (this == null) {
131
132            throw new TypeError('"this" is null or not defined');
133          }
134
135          var o = Object(this);
136
137          // 2. Let len be ? ToLength(? Get(O, "length")).
138
139
140          var len = o.length >>> 0;
141
142          // 3. If IsCallable(predicate) is false, throw a TypeError exception.
143
144
145          if (typeof predicate !== 'function') {
146
147            throw new TypeError('predicate must be a function');
148          }
149
150          // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
151
152
153          var thisArg = arguments[1];
154
155          // 5. Let k be 0.
156
157
158          var k = 0;
159
160          // 6. Repeat, while k < len
161
162
163          while (k < len) {
164
165            // a. Let Pk be ! ToString(k).
166
167
168            // b. Let kValue be ? Get(O, Pk).
169
170
171            // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
172
173
174            // d. If testResult is true, return kValue.
175
176
177            var kValue = o[k];
178
179            if (predicate.call(thisArg, kValue, k, o)) {
180
181              return kValue;
182            }
183
184            // e. Increase k by 1.
185
186
187            k++;
188          }
189
190          // 7. Return undefined.
191
192
193          return undefined;
194        }
195
196      });
197    }
198
199    var ColumnManager = function ColumnManager(table) {
200
201      this.table = table; //hold parent table
202
203
204      this.headersElement = $("<div class='tabulator-headers'></div>");
205
206      this.element = $("<div class='tabulator-header'></div>"); //containing element
207
208
209      this.rowManager = null; //hold row manager object
210
211
212      this.columns = []; // column definition object
213
214
215      this.columnsByIndex = []; //columns by index
216
217
218      this.columnsByField = []; //columns by field
219
220
221      this.scrollLeft = 0;
222
223      this.element.prepend(this.headersElement);
224    };
225
226    ////////////// Setup Functions /////////////////
227
228
229    //link to row manager
230
231
232    ColumnManager.prototype.setRowManager = function (manager) {
233
234      this.rowManager = manager;
235    };
236
237    //return containing element
238
239
240    ColumnManager.prototype.getElement = function () {
241
242      return this.element;
243    };
244
245    //return header containing element
246
247
248    ColumnManager.prototype.getHeadersElement = function () {
249
250      return this.headersElement;
251    };
252
253    //scroll horizontally to match table body
254
255
256    ColumnManager.prototype.scrollHorizontal = function (left) {
257
258      var hozAdjust = 0,
259          scrollWidth = this.element[0].scrollWidth - this.table.element.innerWidth();
260
261      this.element.scrollLeft(left);
262
263      //adjust for vertical scrollbar moving table when present
264
265
266      if (left > scrollWidth) {
267
268        hozAdjust = left - scrollWidth;
269
270        this.element.css("margin-left", -hozAdjust);
271      } else {
272
273        this.element.css("margin-left", 0);
274      }
275
276      //keep frozen columns fixed in position
277
278
279      //this._calcFrozenColumnsPos(hozAdjust + 3);
280
281
282      this.scrollLeft = left;
283
284      if (this.table.extExists("frozenColumns")) {
285
286        this.table.extensions.frozenColumns.layout();
287      }
288    };
289
290    ///////////// Column Setup Functions /////////////
291
292
293    ColumnManager.prototype.setColumns = function (cols, row) {
294
295      var self = this;
296
297      self.headersElement.empty();
298
299      self.columns = [];
300
301      self.columnsByIndex = [];
302
303      self.columnsByField = [];
304
305      //reset frozen columns
306
307
308      if (self.table.extExists("frozenColumns")) {
309
310        self.table.extensions.frozenColumns.reset();
311      }
312
313      cols.forEach(function (def, i) {
314
315        self._addColumn(def);
316      });
317
318      self._reIndexColumns();
319
320      if (self.table.options.responsiveLayout && self.table.extExists("responsiveLayout", true)) {
321
322        self.table.extensions.responsiveLayout.initialize();
323      }
324
325      self.redraw(true);
326    };
327
328    ColumnManager.prototype._addColumn = function (definition, before, nextToColumn) {
329
330      var column = new Column(definition, this);
331
332      var index = nextToColumn ? this.findColumnIndex(nextToColumn) : nextToColumn;
333
334      if (nextToColumn && index > -1) {
335
336        var parentIndex = this.columns.indexOf(nextToColumn.getTopColumn());
337
338        if (before) {
339
340          this.columns.splice(parentIndex, 0, column);
341
342          nextToColumn.getElement().before(column.getElement());
343        } else {
344
345          this.columns.splice(parentIndex + 1, 0, column);
346
347          nextToColumn.getElement().after(column.getElement());
348        }
349      } else {
350
351        if (before) {
352
353          this.columns.unshift(column);
354
355          this.headersElement.prepend(column.getElement());
356        } else {
357
358          this.columns.push(column);
359
360          this.headersElement.append(column.getElement());
361        }
362      }
363    };
364
365    ColumnManager.prototype.registerColumnField = function (col) {
366
367      if (col.definition.field) {
368
369        this.columnsByField[col.definition.field] = col;
370      }
371    };
372
373    ColumnManager.prototype.registerColumnPosition = function (col) {
374
375      this.columnsByIndex.push(col);
376    };
377
378    ColumnManager.prototype._reIndexColumns = function () {
379
380      this.columnsByIndex = [];
381
382      this.columns.forEach(function (column) {
383
384        column.reRegisterPosition();
385      });
386    };
387
388    //ensure column headers take up the correct amount of space in column groups
389
390
391    ColumnManager.prototype._verticalAlignHeaders = function () {
392
393      var self = this;
394
395      self.columns.forEach(function (column) {
396
397        column.clearVerticalAlign();
398      });
399
400      self.columns.forEach(function (column) {
401
402        column.verticalAlign(self.table.options.columnVertAlign);
403      });
404
405      self.rowManager.adjustTableSize();
406    };
407
408    //////////////// Column Details /////////////////
409
410
411    ColumnManager.prototype.findColumn = function (subject) {
412
413      var self = this;
414
415      if ((typeof subject === 'undefined' ? 'undefined' : _typeof(subject)) == "object") {
416
417        if (subject instanceof Column) {
418
419          //subject is column element
420
421
422          return subject;
423        } else if (subject instanceof jQuery) {
424
425          //subject is a jquery element of the column header
426
427
428          var match = self.columns.find(function (column) {
429
430            return column.element === subject;
431          });
432
433          return match || false;
434        } else {
435
436          //subject is public column object
437
438
439          return subject._getSelf() || false;
440        }
441      } else {
442
443        //subject should be treated as the field name of the column
444
445
446        return this.columnsByField[subject] || false;
447      }
448
449      //catch all for any other type of input
450
451
452      return false;
453    };
454
455    ColumnManager.prototype.getColumnByField = function (field) {
456
457      return this.columnsByField[field];
458    };
459
460    ColumnManager.prototype.getColumnByIndex = function (index) {
461
462      return this.columnsByIndex[index];
463    };
464
465    ColumnManager.prototype.getColumns = function () {
466
467      return this.columns;
468    };
469
470    ColumnManager.prototype.findColumnIndex = function (column) {
471
472      return this.columnsByIndex.findIndex(function (col) {
473
474        return column === col;
475      });
476    };
477
478    //return all columns that are not groups
479
480
481    ColumnManager.prototype.getRealColumns = function () {
482
483      return this.columnsByIndex;
484    };
485
486    //travers across columns and call action
487
488
489    ColumnManager.prototype.traverse = function (callback) {
490
491      var self = this;
492
493      self.columnsByIndex.forEach(function (column, i) {
494
495        callback(column, i);
496      });
497    };
498
499    //get defintions of actual columns
500
501
502    ColumnManager.prototype.getDefinitions = function (active) {
503
504      var self = this,
505          output = [];
506
507      self.columnsByIndex.forEach(function (column) {
508
509        if (!active || active && column.visible) {
510
511          output.push(column.getDefinition());
512        }
513      });
514
515      return output;
516    };
517
518    //get full nested definition tree
519
520
521    ColumnManager.prototype.getDefinitionTree = function () {
522
523      var self = this,
524          output = [];
525
526      self.columns.forEach(function (column) {
527
528        output.push(column.getDefinition(true));
529      });
530
531      return output;
532    };
533
534    ColumnManager.prototype.getComponents = function () {
535
536      var self = this,
537          output = [];
538
539      self.columnsByIndex.forEach(function (column) {
540
541        output.push(column.getComponent());
542      });
543
544      return output;
545    };
546
547    ColumnManager.prototype.getWidth = function () {
548
549      var width = 0;
550
551      this.columnsByIndex.forEach(function (column) {
552
553        if (column.visible) {
554
555          width += column.getWidth();
556        }
557      });
558
559      return width;
560    };
561
562    ColumnManager.prototype.moveColumn = function (from, to, after) {
563
564      this._moveColumnInArray(this.columns, from, to, after);
565
566      this._moveColumnInArray(this.columnsByIndex, from, to, after, true);
567
568      this.table.options.columnMoved(from.getComponent());
569
570      if (this.table.options.persistentLayout && this.table.extExists("persistentLayout", true)) {
571
572        this.table.extensions.persistentLayout.save();
573      }
574    };
575
576    ColumnManager.prototype._moveColumnInArray = function (columns, from, to, after, updateRows) {
577
578      var fromIndex = columns.indexOf(from),
579          toIndex;
580
581      if (fromIndex > -1) {
582
583        columns.splice(fromIndex, 1);
584
585        toIndex = columns.indexOf(to);
586
587        if (toIndex > -1) {
588
589          if (after) {
590
591            toIndex = toIndex + 1;
592          }
593        } else {
594
595          toIndex = fromIndex;
596        }
597
598        columns.splice(toIndex, 0, from);
599
600        if (updateRows) {
601
602          this.table.rowManager.rows.forEach(function (row) {
603
604            if (row.cells.length) {
605
606              var cell = row.cells.splice(fromIndex, 1)[0];
607
608              row.cells.splice(toIndex, 0, cell);
609            }
610          });
611        }
612      }
613    };
614
615    //////////////// Cell Management /////////////////
616
617
618    ColumnManager.prototype.generateCells = function (row) {
619
620      var self = this;
621
622      var cells = [];
623
624      self.columnsByIndex.forEach(function (column) {
625
626        cells.push(column.generateCell(row));
627      });
628
629      return cells;
630    };
631
632    //////////////// Column Management /////////////////
633
634
635    //resize columns to fit data in cells
636
637
638    ColumnManager.prototype.fitToData = function () {
639
640      var self = this;
641
642      self.columnsByIndex.forEach(function (column) {
643
644        column.reinitializeWidth();
645      });
646
647      if (this.table.options.responsiveLayout && this.table.extExists("responsiveLayout", true)) {
648
649        this.table.extensions.responsiveLayout.update();
650      }
651    };
652
653    //resize columns to fill the table element
654
655
656    ColumnManager.prototype.fitToTable = function () {
657
658      var self = this;
659
660      var totalWidth = self.table.element.innerWidth(); //table element width
661
662
663      var fixedWidth = 0; //total width of columns with a defined width
664
665
666      var flexWidth = 0; //total width available to flexible columns
667
668
669      var flexColWidth = 0; //desired width of flexible columns
670
671
672      var flexColumns = []; //array of flexible width columns
673
674
675      var gapFill = 0; //number of pixels to be added to final column to close and half pixel gaps
676
677
678      if (this.table.options.responsiveLayout && this.table.extExists("responsiveLayout", true)) {
679
680        this.table.extensions.responsiveLayout.update();
681      }
682
683      //adjust for vertical scrollbar if present
684
685
686      if (self.rowManager.element[0].scrollHeight > self.rowManager.element.innerHeight()) {
687
688        totalWidth -= self.rowManager.element[0].offsetWidth - self.rowManager.element[0].clientWidth;
689      }
690
691      self.columnsByIndex.forEach(function (column) {
692
693        var width, minWidth, colWidth;
694
695        if (column.visible) {
696
697          width = column.definition.width;
698
699          if (width) {
700
701            minWidth = parseInt(column.minWidth);
702
703            if (typeof width == "string") {
704
705              if (width.indexOf("%") > -1) {
706
707                colWidth = totalWidth / 100 * parseInt(width);
708              } else {
709
710                colWidth = parseInt(width);
711              }
712            } else {
713
714              colWidth = width;
715            }
716
717            fixedWidth += colWidth > minWidth ? colWidth : minWidth;
718          } else {
719
720            flexColumns.push(column);
721          }
722        }
723      });
724
725      //calculate available space
726
727
728      flexWidth = totalWidth - fixedWidth;
729
730      //calculate correct column size
731
732
733      flexColWidth = Math.floor(flexWidth / flexColumns.length);
734
735      //calculate any sub pixel space that needs to be filed by the last column
736
737
738      gapFill = totalWidth - fixedWidth - flexColWidth * flexColumns.length;
739
740      gapFill = gapFill > 0 ? gapFill : 0;
741
742      flexColumns.forEach(function (column, i) {
743
744        var width = flexColWidth >= column.minWidth ? flexColWidth : column.minWidth;
745
746        if (i == flexColumns.length - 1 && gapFill) {
747
748          width += gapFill;
749        }
750
751        column.setWidth(width);
752      });
753    };
754
755    ColumnManager.prototype.getFlexBaseWidth = function () {
756
757      var self = this,
758          totalWidth = self.table.element.innerWidth(),
759          //table element width
760
761
762      fixedWidth = 0;
763
764      //adjust for vertical scrollbar if present
765
766
767      if (self.rowManager.element[0].scrollHeight > self.rowManager.element.innerHeight()) {
768
769        totalWidth -= self.rowManager.element[0].offsetWidth - self.rowManager.element[0].clientWidth;
770      }
771
772      this.columnsByIndex.forEach(function (column) {
773
774        var width, minWidth, colWidth;
775
776        if (column.visible) {
777
778          width = column.definition.width || 0;
779
780          minWidth = typeof column.minWidth == "undefined" ? self.table.options.columnMinWidth : parseInt(column.minWidth);
781
782          if (typeof width == "string") {
783
784            if (width.indexOf("%") > -1) {
785
786              colWidth = totalWidth / 100 * parseInt(width);
787            } else {
788
789              colWidth = parseInt(width);
790            }
791          } else {
792
793            colWidth = width;
794          }
795
796          fixedWidth += colWidth > minWidth ? colWidth : minWidth;
797        }
798      });
799
800      return fixedWidth;
801    };
802
803    ColumnManager.prototype.addColumn = function (definition, before, nextToColumn) {
804
805      this._addColumn(definition, before, nextToColumn);
806
807      this._reIndexColumns();
808
809      if (this.table.options.responsiveLayout && this.table.extExists("responsiveLayout", true)) {
810
811        this.table.extensions.responsiveLayout.initialize();
812      }
813
814      this.redraw();
815
816      this._verticalAlignHeaders();
817
818      this.table.rowManager.reinitialize();
819    };
820
821    //remove column from system
822
823
824    ColumnManager.prototype.deregisterColumn = function (column) {
825
826      var field = column.getField(),
827          index;
828
829      //remove from field list
830
831
832      if (field) {
833
834        delete this.columnsByField[field];
835      }
836
837      //remove from index list
838
839
840      index = this.columnsByIndex.indexOf(column);
841
842      if (index > -1) {
843
844        this.columnsByIndex.splice(index, 1);
845      }
846
847      //remove from column list
848
849
850      index = this.columns.indexOf(column);
851
852      if (index > -1) {
853
854        this.columns.splice(index, 1);
855      }
856
857      if (this.table.options.responsiveLayout && this.table.extExists("responsiveLayout", true)) {
858
859        this.table.extensions.responsiveLayout.initialize();
860      }
861
862      this.redraw();
863    };
864
865    //redraw columns
866
867
868    ColumnManager.prototype.redraw = function (force) {
869
870      if (force) {
871
872        if (this.element.is(":visible")) {
873
874          this._verticalAlignHeaders();
875        }
876
877        this.table.rowManager.resetScroll();
878
879        this.table.rowManager.reinitialize();
880      }
881
882      if (this.table.options.fitColumns) {
883
884        this.fitToTable();
885      } else {
886
887        if (force) {
888
889          this.fitToData();
890        } else {
891
892          if (this.table.options.responsiveLayout && this.table.extExists("responsiveLayout", true)) {
893
894            this.table.extensions.responsiveLayout.update();
895          }
896        }
897      }
898
899      if (this.table.extExists("frozenColumns")) {
900
901        this.table.extensions.frozenColumns.layout();
902      }
903
904      if (force) {
905
906        if (this.table.options.persistentLayout && this.table.extExists("persistentLayout", true)) {
907
908          this.table.extensions.persistentLayout.save();
909        }
910
911        if (this.table.extExists("columnCalcs")) {
912
913          this.table.extensions.columnCalcs.redraw();
914        }
915      }
916
917      this.table.footerManager.redraw();
918    };
919
920    //public column object
921
922    var ColumnComponent = function ColumnComponent(column) {
923
924      var obj = {
925
926        type: "ColumnComponent", //type of element
927
928        getElement: function getElement() {
929
930          return column.getElement();
931        },
932
933        getDefinition: function getDefinition() {
934
935          return column.getDefinition();
936        },
937
938        getField: function getField() {
939
940          return column.getField();
941        },
942
943        getCells: function getCells() {
944
945          var cells = [];
946
947          column.cells.forEach(function (cell) {
948
949            cells.push(cell.getComponent());
950          });
951
952          return cells;
953        },
954
955        getVisibility: function getVisibility() {
956
957          return column.visible;
958        },
959
960        show: function show() {
961
962          column.show();
963        },
964
965        hide: function hide() {
966
967          column.hide();
968        },
969
970        toggle: function toggle() {
971
972          if (column.visible) {
973
974            column.hide();
975          } else {
976
977            column.show();
978          }
979        },
980
981        delete: function _delete() {
982
983          column.delete();
984        },
985
986        _getSelf: function _getSelf() {
987
988          return column;
989        }
990
991      };
992
993      return obj;
994    };
995
996    var Column = function Column(def, parent) {
997
998      var self = this;
999
1000      this.table = parent.table;
1001
1002      this.definition = def; //column definition
1003
1004      this.parent = parent; //hold parent object
1005
1006      this.type = "column"; //type of element
1007
1008      this.columns = []; //child columns
1009
1010      this.cells = []; //cells bound to this column
1011
1012      this.element = $("<div class='tabulator-col' role='columnheader' aria-sort='none'></div>"); //column header element
1013
1014      this.contentElement = false;
1015
1016      this.groupElement = $("<div class='tabulator-col-group-cols'></div>"); //column group holder element
1017
1018      this.isGroup = false;
1019
1020      this.tooltip = false; //hold column tooltip
1021
1022      this.hozAlign = ""; //horizontal text alignment
1023
1024
1025      //multi dimentional filed handling
1026
1027      this.field = "";
1028
1029      this.fieldStructure = "";
1030
1031      this.getFieldValue = "";
1032
1033      this.setFieldValue = "";
1034
1035      this.setField(this.definition.field);
1036
1037      this.extensions = {}; //hold extension variables;
1038
1039
1040      this.cellEvents = {
1041
1042        cellClick: false,
1043
1044        cellDblClick: false,
1045
1046        cellContext: false,
1047
1048        cellTap: false,
1049
1050        cellDblTap: false,
1051
1052        cellTapHold: false
1053
1054      };
1055
1056      this.width = null; //column width
1057
1058      this.minWidth = null; //column minimum width
1059
1060      this.widthFixed = false; //user has specified a width for this column
1061
1062
1063      this.visible = true; //default visible state
1064
1065
1066      //initialize column
1067
1068      if (def.columns) {
1069
1070        this.isGroup = true;
1071
1072        def.columns.forEach(function (def, i) {
1073
1074          var newCol = new Column(def, self);
1075
1076          self.attachColumn(newCol);
1077        });
1078
1079        self.checkColumnVisibility();
1080      } else {
1081
1082        parent.registerColumnField(this);
1083      }
1084
1085      if (def.rowHandle && this.table.options.movableRows !== false && this.table.extExists("moveRow")) {
1086
1087        this.table.extensions.moveRow.setHandle(true);
1088      }
1089
1090      this._buildHeader();
1091    };
1092
1093    //////////////// Setup Functions /////////////////
1094
1095    Column.prototype.setField = function (field) {
1096
1097      this.field = field;
1098
1099      this.fieldStructure = field ? field.split(".") : [];
1100
1101      this.getFieldValue = this.fieldStructure.length > 1 ? this._getNestedData : this._getFlatData;
1102
1103      this.setFieldValue = this.fieldStructure.length > 1 ? this._setNesteData : this._setFlatData;
1104    };
1105
1106    //register column position with column manager
1107
1108    Column.prototype.registerColumnPosition = function (column) {
1109
1110      this.parent.registerColumnPosition(column);
1111    };
1112
1113    //register column position with column manager
1114
1115    Column.prototype.registerColumnField = function (column) {
1116
1117      this.parent.registerColumnField(column);
1118    };
1119
1120    //trigger position registration
1121
1122    Column.prototype.reRegisterPosition = function () {
1123
1124      if (this.isGroup) {
1125
1126        this.columns.forEach(function (column) {
1127
1128          column.reRegisterPosition();
1129        });
1130      } else {
1131
1132        this.registerColumnPosition(this);
1133      }
1134    };
1135
1136    //build header element
1137
1138    Column.prototype._buildHeader = function () {
1139
1140      var self = this,
1141          def = self.definition,
1142          dblTap,
1143          tapHold,
1144          tap;
1145
1146      self.element.empty();
1147
1148      self.contentElement = self._buildColumnHeaderContent();
1149
1150      self.element.append(self.contentElement);
1151
1152      if (self.isGroup) {
1153
1154        self._buildGroupHeader();
1155      } else {
1156
1157        self._buildColumnHeader();
1158      }
1159
1160      //set header tooltips
1161
1162      var tooltip = def.tooltipHeader || def.tooltip === false ? def.tooltipHeader : self.table.options.tooltipsHeader;
1163
1164      if (tooltip) {
1165
1166        if (tooltip === true) {
1167
1168          if (def.field) {
1169
1170            self.table.extensions.localize.bind("columns." + def.field, function (value) {
1171
1172              self.element.attr("title", value || def.title);
1173            });
1174          } else {
1175
1176            self.element.attr("title", def.title);
1177          }
1178        } else {
1179
1180          if (typeof tooltip == "function") {
1181
1182            tooltip = tooltip(column.getComponent());
1183          }
1184
1185          self.element.attr("title", tooltip);
1186        }
1187      } else {
1188
1189        self.element.attr("title", "");
1190      }
1191
1192      //set resizable handles
1193
1194      if (self.table.options.resizableColumns && self.table.extExists("resizeColumns")) {
1195
1196        self.table.extensions.resizeColumns.initializeColumn("header", self, self.element);
1197      }
1198
1199      //set resizable handles
1200
1201      if (def.headerFilter && self.table.extExists("filter") && self.table.extExists("edit")) {
1202
1203        if (typeof def.headerFilterPlaceholder !== "undefined" && def.field) {
1204
1205          self.table.extensions.localize.setHeaderFilterColumnPlaceholder(def.field, def.headerFilterPlaceholder);
1206        }
1207
1208        self.table.extensions.filter.initializeColumn(self);
1209      }
1210
1211      //set resizable handles
1212
1213      if (self.table.extExists("frozenColumns")) {
1214
1215        self.table.extensions.frozenColumns.initializeColumn(self);
1216      }
1217
1218      //set movable column
1219
1220      if (self.table.options.movableColumns && !self.isGroup && self.table.extExists("moveColumn")) {
1221
1222        self.table.extensions.moveColumn.initializeColumn(self);
1223      }
1224
1225      //set calcs column
1226
1227      if ((def.topCalc || def.bottomCalc) && self.table.extExists("columnCalcs")) {
1228
1229        self.table.extensions.columnCalcs.initializeColumn(self);
1230      }
1231
1232      //setup header click event bindings
1233
1234      if (typeof def.headerClick == "function") {
1235
1236        self.element.on("click", function (e) {
1237          def.headerClick(e, self.getComponent());
1238        });
1239      }
1240
1241      if (typeof def.headerDblClick == "function") {
1242
1243        self.element.on("dblclick", function (e) {
1244          def.headerDblClick(e, self.getComponent());
1245        });
1246      }
1247
1248      if (typeof def.headerContext == "function") {
1249
1250        self.element.on("contextmenu", function (e) {
1251          def.headerContext(e, self.getComponent());
1252        });
1253      }
1254
1255      //setup header tap event bindings
1256
1257      if (typeof def.headerTap == "function") {
1258
1259        tap = false;
1260
1261        self.element.on("touchstart", function (e) {
1262
1263          tap = true;
1264        });
1265
1266        self.element.on("touchend", function (e) {
1267
1268          if (tap) {
1269
1270            def.headerTap(e, self.getComponent());
1271          }
1272
1273          tap = false;
1274        });
1275      }
1276
1277      if (typeof def.headerDblTap == "function") {
1278
1279        dblTap = null;
1280
1281        self.element.on("touchend", function (e) {
1282
1283          if (dblTap) {
1284
1285            clearTimeout(dblTap);
1286
1287            dblTap = null;
1288
1289            def.headerDblTap(e, self.getComponent());
1290          } else {
1291
1292            dblTap = setTimeout(function () {
1293
1294              clearTimeout(dblTap);
1295
1296              dblTap = null;
1297            }, 300);
1298          }
1299        });
1300      }
1301
1302      if (typeof def.headerTapHold == "function") {
1303
1304        tapHold = null;
1305
1306        self.element.on("touchstart", function (e) {
1307
1308          clearTimeout(tapHold);
1309
1310          tapHold = setTimeout(function () {
1311
1312            clearTimeout(tapHold);
1313
1314            tapHold = null;
1315
1316            tap = false;
1317
1318            def.headerTapHold(e, self.getComponent());
1319          }, 1000);
1320        });
1321
1322        self.element.on("touchend", function (e) {
1323
1324          clearTimeout(tapHold);
1325
1326          tapHold = null;
1327        });
1328      }
1329
1330      //store column cell click event bindings
1331
1332      if (typeof def.cellClick == "function") {
1333
1334        self.cellEvents.cellClick = def.cellClick;
1335      }
1336
1337      if (typeof def.cellDblClick == "function") {
1338
1339        self.cellEvents.cellDblClick = def.cellDblClick;
1340      }
1341
1342      if (typeof def.cellContext == "function") {
1343
1344        self.cellEvents.cellContext = def.cellContext;
1345      }
1346
1347      //setup column cell tap event bindings
1348
1349      if (typeof def.cellTap == "function") {
1350
1351        self.cellEvents.cellTap = def.cellTap;
1352      }
1353
1354      if (typeof def.cellDblTap == "function") {
1355
1356        self.cellEvents.cellDblTap = def.cellDblTap;
1357      }
1358
1359      if (typeof def.cellTapHold == "function") {
1360
1361        self.cellEvents.cellTapHold = def.cellTapHold;
1362      }
1363    };
1364
1365    //build header element for header
1366
1367    Column.prototype._buildColumnHeader = function () {
1368
1369      var self = this,
1370          def = self.definition,
1371          table = self.table,
1372          sortable;
1373
1374      //set column sorter
1375
1376      if (table.extExists("sort")) {
1377
1378        table.extensions.sort.initializeColumn(self, self.contentElement);
1379      }
1380
1381      //set column formatter
1382
1383      if (table.extExists("format")) {
1384
1385        table.extensions.format.initializeColumn(self);
1386      }
1387
1388      //set column editor
1389
1390      if (typeof def.editor != "undefined" && table.extExists("edit")) {
1391
1392        table.extensions.edit.initializeColumn(self);
1393      }
1394
1395      //set column mutator
1396
1397      if (typeof def.mutator != "undefined" && table.extExists("mutator")) {
1398
1399        table.extensions.mutator.initializeColumn(self);
1400      }
1401
1402      //set column accessor
1403
1404      if (typeof def.accessor != "undefined" && table.extExists("accessor")) {
1405
1406        table.extensions.accessor.initializeColumn(self);
1407      }
1408
1409      //set column visibility
1410
1411      if (typeof def.visible != "undefined") {
1412
1413        if (def.visible) {
1414
1415          self.show();
1416        } else {
1417
1418          self.hide();
1419        }
1420      }
1421
1422      //asign additional css classes to column header
1423
1424      if (def.cssClass) {
1425
1426        self.element.addClass(def.cssClass);
1427      }
1428
1429      //set min width if present
1430
1431      self.setMinWidth(typeof def.minWidth == "undefined" ? self.table.options.columnMinWidth : def.minWidth);
1432
1433      self.reinitializeWidth();
1434
1435      //set tooltip if present
1436
1437      self.tooltip = self.definition.tooltip || self.definition.tooltip === false ? self.definition.tooltip : self.table.options.tooltips;
1438
1439      //set orizontal text alignment
1440
1441      self.hozAlign = typeof self.definition.align == "undefined" ? "" : self.definition.align;
1442    };
1443
1444    Column.prototype._buildColumnHeaderContent = function () {
1445
1446      var self = this,
1447          def = self.definition,
1448          table = self.table;
1449
1450      var contentElement = $("<div class='tabulator-col-content'></div>");
1451
1452      contentElement.append(self._buildColumnHeaderTitle());
1453
1454      return contentElement;
1455    };
1456
1457    //build title element of column
1458
1459    Column.prototype._buildColumnHeaderTitle = function () {
1460
1461      var self = this,
1462          def = self.definition,
1463          table = self.table,
1464          title;
1465
1466      var titleHolderElement = $("<div class='tabulator-col-title'></div>");
1467
1468      if (def.editableTitle) {
1469
1470        var titleElement = $("<input class='tabulator-title-editor'>");
1471
1472        titleElement.on("click", function (e) {
1473
1474          e.stopPropagation();
1475
1476          $(this).focus();
1477        });
1478
1479        titleElement.on("change", function () {
1480
1481          var newTitle = $(this).val();
1482
1483          def.title = newTitle;
1484
1485          table.options.columnTitleChanged(self.getComponent());
1486        });
1487
1488        titleHolderElement.append(titleElement);
1489
1490        if (def.field) {
1491
1492          table.extensions.localize.bind("columns." + def.field, function (text) {
1493
1494            titleElement.val(text || def.title || "&nbsp");
1495          });
1496        } else {
1497
1498          titleElement.val(def.title || "&nbsp");
1499        }
1500      } else {
1501
1502        if (def.field) {
1503
1504          table.extensions.localize.bind("columns." + def.field, function (text) {
1505
1506            titleHolderElement.html(text || def.title || "&nbsp");
1507          });
1508        } else {
1509
1510          titleHolderElement.html(def.title || "&nbsp");
1511        }
1512      }
1513
1514      return titleHolderElement;
1515    };
1516
1517    //build header element for column group
1518
1519    Column.prototype._buildGroupHeader = function () {
1520
1521      var self = this,
1522          def = self.definition,
1523          table = self.table;
1524
1525      self.element.addClass("tabulator-col-group").attr("role", "columngroup").attr("aria-title", def.title);
1526
1527      self.element.append(self.groupElement);
1528    };
1529
1530    //flat field lookup
1531
1532    Column.prototype._getFlatData = function (data) {
1533
1534      return data[this.field];
1535    };
1536
1537    //nested field lookup
1538
1539    Column.prototype._getNestedData = function (data) {
1540
1541      var dataObj = data,
1542          structure = this.fieldStructure,
1543          length = structure.length,
1544          output;
1545
1546      for (var i = 0; i < length; i++) {
1547
1548        dataObj = dataObj[structure[i]];
1549
1550        output = dataObj;
1551
1552        if (!dataObj) {
1553
1554          break;
1555        }
1556      }
1557
1558      return output;
1559    };
1560
1561    //flat field set
1562
1563    Column.prototype._setFlatData = function (data, value) {
1564
1565      data[this.field] = value;
1566    };
1567
1568    //nested field set
1569
1570    Column.prototype._setNesteData = function (data, value) {
1571
1572      var dataObj = data,
1573          structure = this.fieldStructure,
1574          length = structure.length;
1575
1576      for (var i = 0; i < length; i++) {
1577
1578        if (i == length - 1) {
1579
1580          dataObj[structure[i]] = value;
1581        } else {
1582
1583          if (!dataObj[structure[i]]) {
1584
1585            dataObj[structure[i]] = {};
1586          }
1587
1588          dataObj = dataObj[structure[i]];
1589        }
1590      }
1591    };
1592
1593    //attach column to this group
1594
1595    Column.prototype.attachColumn = function (column) {
1596
1597      var self = this;
1598
1599      if (self.groupElement) {
1600
1601        self.columns.push(column);
1602
1603        self.groupElement.append(column.getElement());
1604      } else {
1605
1606        console.warn("Column Warning - Column being attached to another column instead of column group");
1607      }
1608    };
1609
1610    //vertically align header in column
1611
1612    Column.prototype.verticalAlign = function (alignment) {
1613
1614      if (this.parent.isGroup) {
1615
1616        this.element.css("height", this.parent.getGroupElement().innerHeight());
1617      } else {
1618
1619        this.element.css("height", this.parent.getHeadersElement().innerHeight());
1620      }
1621
1622      //vertically align cell contents
1623
1624      if (!this.isGroup && alignment !== "top") {
1625
1626        if (alignment === "bottom") {
1627
1628          this.element.css({ "padding-top": this.element.innerHeight() - this.contentElement.outerHeight() });
1629        } else {
1630
1631          this.element.css({ "padding-top": (this.element.innerHeight() - this.contentElement.outerHeight()) / 2 });
1632        }
1633      }
1634
1635      this.columns.forEach(function (column) {
1636
1637        column.verticalAlign(alignment);
1638      });
1639    };
1640
1641    //clear vertical alignmenet
1642
1643    Column.prototype.clearVerticalAlign = function () {
1644
1645      this.element.css("padding-top", "");
1646
1647      this.element.css("height", "");
1648
1649      this.columns.forEach(function (column) {
1650
1651        column.clearVerticalAlign();
1652      });
1653    };
1654
1655    //// Retreive Column Information ////
1656
1657
1658    //return column header element
1659
1660    Column.prototype.getElement = function () {
1661
1662      return this.element;
1663    };
1664
1665    //return colunm group element
1666
1667    Column.prototype.getGroupElement = function () {
1668
1669      return this.groupElement;
1670    };
1671
1672    //return field name
1673
1674    Column.prototype.getField = function () {
1675
1676      return this.field;
1677    };
1678
1679    //return the first column in a group
1680
1681    Column.prototype.getFirstColumn = function () {
1682
1683      if (!this.isGroup) {
1684
1685        return this;
1686      } else {
1687
1688        if (this.columns.length) {
1689
1690          return this.columns[0].getFirstColumn();
1691        } else {
1692
1693          return false;
1694        }
1695      }
1696    };
1697
1698    //return the last column in a group
1699
1700    Column.prototype.getLastColumn = function () {
1701
1702      if (!this.isGroup) {
1703
1704        return this;
1705      } else {
1706
1707        if (this.columns.length) {
1708
1709          return this.columns[this.columns.length - 1].getLastColumn();
1710        } else {
1711
1712          return false;
1713        }
1714      }
1715    };
1716
1717    //return all columns in a group
1718
1719    Column.prototype.getColumns = function () {
1720
1721      return this.columns;
1722    };
1723
1724    //return all columns in a group
1725
1726    Column.prototype.getCells = function () {
1727
1728      return this.cells;
1729    };
1730
1731    //retreive the top column in a group of columns
1732
1733    Column.prototype.getTopColumn = function () {
1734
1735      if (this.parent.isGroup) {
1736
1737        return this.parent.getTopColumn();
1738      } else {
1739
1740        return this;
1741      }
1742    };
1743
1744    //return column definition object
1745
1746    Column.prototype.getDefinition = function (updateBranches) {
1747
1748      var colDefs = [];
1749
1750      if (this.isGroup && updateBranches) {
1751
1752        this.columns.forEach(function (column) {
1753
1754          colDefs.push(column.getDefinition(true));
1755        });
1756
1757        this.definition.columns = colDefs;
1758      }
1759
1760      return this.definition;
1761    };
1762
1763    //////////////////// Actions ////////////////////
1764
1765
1766    Column.prototype.checkColumnVisibility = function () {
1767
1768      var visible = false;
1769
1770      this.columns.forEach(function (column) {
1771
1772        if (column.visible) {
1773
1774          visible = true;
1775        }
1776      });
1777
1778      if (visible) {
1779
1780        this.show();
1781
1782        this.parent.table.options.columnVisibilityChanged(this.getComponent(), false);
1783      } else {
1784
1785        this.hide();
1786      }
1787    };
1788
1789    //show column
1790
1791    Column.prototype.show = function () {
1792
1793      if (!this.visible) {
1794
1795        this.visible = true;
1796
1797        this.element.show();
1798
1799        this.table.columnManager._verticalAlignHeaders();
1800
1801        if (this.parent.isGroup) {
1802
1803          this.parent.checkColumnVisibility();
1804        }
1805
1806        this.cells.forEach(function (cell) {
1807
1808          cell.show();
1809        });
1810
1811        if (this.table.options.persistentLayout && self.table.extExists("persistentLayout", true)) {
1812
1813          self.table.extensions.persistentLayout.save();
1814        }
1815
1816        this.table.options.groupVisibilityChanged(this.getComponent(), true);
1817      }
1818    };
1819
1820    //hide column
1821
1822    Column.prototype.hide = function () {
1823
1824      if (this.visible) {
1825
1826        this.visible = false;
1827
1828        this.element.hide();
1829
1830        this.table.columnManager._verticalAlignHeaders();
1831
1832        if (this.parent.isGroup) {
1833
1834          this.parent.checkColumnVisibility();
1835        }
1836
1837        this.cells.forEach(function (cell) {
1838
1839          cell.hide();
1840        });
1841
1842        if (this.table.options.persistentLayout && self.table.extExists("persistentLayout", true)) {
1843
1844          self.table.extensions.persistentLayout.save();
1845        }
1846
1847        this.table.options.groupVisibilityChanged(this.getComponent(), false);
1848      }
1849    };
1850
1851    Column.prototype.setWidth = function (width) {
1852
1853      this.widthFixed = true;
1854
1855      this.setWidthActual(width);
1856    };
1857
1858    Column.prototype.setWidthActual = function (width) {
1859
1860      if (isNaN(width)) {
1861
1862        width = Math.floor(this.table.element.innerWidth() / 100 * parseInt(width));
1863      }
1864
1865      width = Math.max(this.minWidth, width);
1866
1867      this.width = width;
1868
1869      if (!this.isGroup) {
1870
1871        this.element.css("width", width || "");
1872
1873        this.cells.forEach(function (cell) {
1874
1875          cell.setWidth(width);
1876        });
1877      }
1878
1879      //set resizable handles
1880
1881      if (this.table.extExists("frozenColumns")) {
1882
1883        this.table.extensions.frozenColumns.layout();
1884      }
1885    };
1886
1887    Column.prototype.checkCellHeights = function () {
1888
1889      var rows = [];
1890
1891      this.cells.forEach(function (cell) {
1892
1893        if (cell.row.heightInitialized) {
1894
1895          if (cell.row.element[0].offsetParent !== null) {
1896
1897            rows.push(cell.row);
1898
1899            cell.row.clearCellHeight();
1900          } else {
1901
1902            cell.row.heightInitialized = false;
1903          }
1904        }
1905      });
1906
1907      rows.forEach(function (row) {
1908
1909        row.calcHeight();
1910      });
1911
1912      rows.forEach(function (row) {
1913
1914        row.setCellHeight();
1915      });
1916    };
1917
1918    Column.prototype.getWidth = function () {
1919
1920      return this.element.outerWidth();
1921    };
1922
1923    Column.prototype.getHeight = function () {
1924
1925      return this.element.outerHeight();
1926    };
1927
1928    Column.prototype.setMinWidth = function (minWidth) {
1929
1930      this.minWidth = minWidth;
1931
1932      this.element.css("min-width", minWidth || "");
1933
1934      this.cells.forEach(function (cell) {
1935
1936        cell.setMinWidth(minWidth);
1937      });
1938    };
1939
1940    Column.prototype.delete = function () {
1941
1942      if (this.isGroup) {
1943
1944        this.columns.forEach(function (column) {
1945
1946          column.delete();
1947        });
1948      }
1949
1950      var cellCount = this.cells.length;
1951
1952      for (var i = 0; i < cellCount; i++) {
1953
1954        this.cells[0].delete();
1955      }
1956
1957      this.element.detach();
1958
1959      this.table.columnManager.deregisterColumn(this);
1960    };
1961
1962    //////////////// Cell Management /////////////////
1963
1964
1965    //generate cell for this column
1966
1967    Column.prototype.generateCell = function (row) {
1968
1969      var self = this;
1970
1971      var cell = new Cell(self, row);
1972
1973      this.cells.push(cell);
1974
1975      return cell;
1976    };
1977
1978    Column.prototype.reinitializeWidth = function () {
1979
1980      this.widthFixed = false;
1981
1982      //set width if present
1983
1984      if (typeof this.definition.width !== "undefined") {
1985
1986        this.setWidth(this.definition.width);
1987      }
1988
1989      this.fitToData();
1990    };
1991
1992    //set column width to maximum cell width
1993
1994    Column.prototype.fitToData = function () {
1995
1996      var self = this;
1997
1998      if (!this.widthFixed) {
1999
2000        this.element.css("width", "");
2001
2002        self.cells.forEach(function (cell) {
2003
2004          cell.setWidth("");
2005        });
2006      }
2007
2008      var maxWidth = this.element.outerWidth();
2009
2010      if (!self.width || !this.widthFixed) {
2011
2012        self.cells.forEach(function (cell) {
2013
2014          var width = cell.getWidth();
2015
2016          if (width > maxWidth) {
2017
2018            maxWidth = width;
2019          }
2020        });
2021
2022        if (maxWidth) {
2023
2024          self.setWidthActual(maxWidth + 1);
2025        }
2026      }
2027    };
2028
2029    Column.prototype.deleteCell = function (cell) {
2030
2031      var index = this.cells.indexOf(cell);
2032
2033      if (index > -1) {
2034
2035        this.cells.splice(index, 1);
2036      }
2037    };
2038
2039    //////////////// Event Bindings /////////////////
2040
2041
2042    //////////////// Object Generation /////////////////
2043
2044    Column.prototype.getComponent = function () {
2045
2046      return new ColumnComponent(this);
2047    };
2048
2049    var RowManager = function RowManager(table) {
2050
2051      this.table = table;
2052
2053      this.element = $("<div class='tabulator-tableHolder' tabindex='0'></div>"); //containing element
2054
2055      this.tableElement = $("<div class='tabulator-table'></div>"); //table element
2056
2057      this.columnManager = null; //hold column manager object
2058
2059      this.height = 0; //hold height of table element
2060
2061
2062      this.firstRender = false; //handle first render
2063
2064      this.renderMode = "classic"; //current rendering mode
2065
2066
2067      this.rows = []; //hold row data objects
2068
2069      this.activeRows = []; //rows currently available to on display in the table
2070
2071      this.activeRowsCount = 0; //count of active rows
2072
2073
2074      this.displayRows = []; //rows currently on display in the table
2075
2076      this.displayRowsCount = 0; //count of display rows
2077
2078
2079      this.scrollTop = 0;
2080
2081      this.scrollLeft = 0;
2082
2083      this.vDomRowHeight = 20; //approximation of row heights for padding
2084
2085
2086      this.vDomTop = 0; //hold position for first rendered row in the virtual DOM
2087
2088      this.vDomBottom = 0; //hold possition for last rendered row in the virtual DOM
2089
2090
2091      this.vDomScrollPosTop = 0; //last scroll position of the vDom top;
2092
2093      this.vDomScrollPosBottom = 0; //last scroll position of the vDom bottom;
2094
2095
2096      this.vDomTopPad = 0; //hold value of padding for top of virtual DOM
2097
2098      this.vDomBottomPad = 0; //hold value of padding for bottom of virtual DOM
2099
2100
2101      this.vDomMaxRenderChain = 90; //the maximum number of dom elements that can be rendered in 1 go
2102
2103
2104      this.vDomWindowBuffer = 0; //window row buffer before removing elements, to smooth scrolling
2105
2106
2107      this.vDomWindowMinTotalRows = 20; //minimum number of rows to be generated in virtual dom (prevent buffering issues on tables with tall rows)
2108
2109      this.vDomWindowMinMarginRows = 5; //minimum number of rows to be generated in virtual dom margin
2110
2111
2112      this.vDomTopNewRows = []; //rows to normalize after appending to optimize render speed
2113
2114      this.vDomBottomNewRows = []; //rows to normalize after appending to optimize render speed
2115
2116
2117      this._initialize();
2118    };
2119
2120    //////////////// Setup Functions /////////////////
2121
2122
2123    //return containing element
2124
2125    RowManager.prototype.getElement = function () {
2126
2127      return this.element;
2128    };
2129
2130    //return table element
2131
2132    RowManager.prototype.getTableElement = function () {
2133
2134      return this.tableElement;
2135    };
2136
2137    //link to column manager
2138
2139    RowManager.prototype.setColumnManager = function (manager) {
2140
2141      this.columnManager = manager;
2142    };
2143
2144    RowManager.prototype._initialize = function () {
2145
2146      var self = this;
2147
2148      //initialize manager
2149
2150      self.element.append(self.tableElement);
2151
2152      self.firstRender = true;
2153
2154      //scroll header along with table body
2155
2156      self.element.scroll(function () {
2157
2158        var left = self.element[0].scrollLeft;
2159
2160        //handle horizontal scrolling
2161
2162        if (self.scrollLeft != left) {
2163
2164          self.columnManager.scrollHorizontal(left);
2165
2166          if (self.table.options.groupBy) {
2167
2168            self.table.extensions.groupRows.scrollHeaders(left);
2169          }
2170
2171          if (self.table.extExists("columnCalcs")) {
2172
2173            self.table.extensions.columnCalcs.scrollHorizontal(left);
2174          }
2175        }
2176
2177        self.scrollLeft = left;
2178      });
2179
2180      //handle virtual dom scrolling
2181
2182      if (self.table.options.height && self.table.options.virtualDom) {
2183
2184        self.element.scroll(function () {
2185
2186          var top = self.element[0].scrollTop;
2187
2188          var dir = self.scrollTop > top;
2189
2190          //handle verical scrolling
2191
2192          if (self.scrollTop != top) {
2193
2194            self.scrollTop = top;
2195
2196            self.scrollVertical(dir);
2197          } else {
2198
2199            self.scrollTop = top;
2200          }
2201        });
2202      }
2203    };
2204
2205    ////////////////// Row Manipulation //////////////////
2206
2207
2208    RowManager.prototype.findRow = function (subject) {
2209
2210      var self = this;
2211
2212      if ((typeof subject === 'undefined' ? 'undefined' : _typeof(subject)) == "object") {
2213
2214        if (subject instanceof Row) {
2215
2216          //subject is row element
2217
2218          return subject;
2219        } else if (subject instanceof jQuery) {
2220
2221          //subject is a jquery element of the row
2222
2223          var match = self.rows.find(function (row) {
2224
2225            return row.element === subject;
2226          });
2227
2228          return match || false;
2229        } else {
2230
2231          //subject is public row object
2232
2233          return subject._getSelf() || false;
2234        }
2235      } else {
2236
2237        //subject should be treated as the index of the row
2238
2239        var _match = self.rows.find(function (row) {
2240
2241          return row.data[self.table.options.index] == subject;
2242        });
2243
2244        return _match || false;
2245      }
2246
2247      //catch all for any other type of input
2248
2249
2250      return false;
2251    };
2252
2253    RowManager.prototype.scrollToRow = function (row) {
2254
2255      var rowIndex;
2256
2257      rowIndex = this.displayRows.indexOf(row);
2258
2259      if (rowIndex > -1) {
2260
2261        switch (this.renderMode) {
2262
2263          case "classic":
2264
2265            this.element.scrollTop(row.element.offset().top - this.element.offset().top + this.element.scrollTop());
2266
2267            break;
2268
2269          case "virtual":
2270
2271            this._virtualRenderFill(rowIndex, true);
2272
2273            break;
2274
2275        }
2276      } else {
2277
2278        console.warn("Scroll Error - Row not visible");
2279      }
2280    };
2281
2282    ////////////////// Data Handling //////////////////
2283
2284
2285    RowManager.prototype.setData = function (data) {
2286
2287      var self = this;
2288
2289      self.table.options.dataLoading(data);
2290
2291      self.rows = [];
2292
2293      if (this.table.options.history && this.table.extExists("history")) {
2294
2295        this.table.extensions.history.clear();
2296      }
2297
2298      if (Array.isArray(data)) {
2299
2300        if (this.table.extExists("selectRow")) {
2301
2302          this.table.extensions.selectRow.clearSelectionData();
2303        }
2304
2305        data.forEach(function (def, i) {
2306
2307          var row = new Row(def, self);
2308
2309          self.rows.push(row);
2310        });
2311
2312        self.table.options.dataLoaded(data);
2313
2314        self.refreshActiveData(true);
2315      } else {
2316
2317        console.error("Data Loading Error - Unable to process data due to invalid data type \nExpecting: array \nReceived: ", typeof data === 'undefined' ? 'undefined' : _typeof(data), "\nData:     ", data);
2318      }
2319    };
2320
2321    RowManager.prototype.deleteRow = function (row) {
2322
2323      var allIndex = this.rows.indexOf(row),
2324          activeIndex = this.activeRows.indexOf(row),
2325          displayIndex = this.displayRows.indexOf(row);
2326
2327      if (displayIndex > -1) {
2328
2329        this.displayRows.splice(displayIndex, 1);
2330      }
2331
2332      if (activeIndex > -1) {
2333
2334        this.activeRows.splice(activeIndex, 1);
2335      }
2336
2337      if (allIndex > -1) {
2338
2339        this.rows.splice(allIndex, 1);
2340      }
2341
2342      this.setActiveRows(this.activeRows);
2343
2344      this.setDisplayRows(this.displayRows);
2345
2346      this.table.options.rowDeleted(row.getComponent());
2347
2348      this.table.options.dataEdited(this.getData());
2349
2350      if (this.table.options.pagination && this.table.extExists("page")) {
2351
2352        this.refreshActiveData();
2353      } else {
2354
2355        this.renderTable();
2356      }
2357    };
2358
2359    RowManager.prototype.addRow = function (data, pos, index) {
2360
2361      var row = this.addRowActual(data, pos, index);
2362
2363      if (this.table.options.history && this.table.extExists("history")) {
2364
2365        this.table.extensions.history.action("rowAdd", row, { data: data, pos: pos, index: index });
2366      };
2367
2368      return row;
2369    };
2370
2371    RowManager.prototype.addRowActual = function (data, pos, index) {
2372
2373      var safeData = data || {},
2374          row = new Row(safeData, this),
2375          top = typeof pos == "undefined" ? this.table.options.addRowPos : pos;
2376
2377      if (index) {
2378
2379        index = this.findRow(index);
2380      }
2381
2382      if (top === "top") {
2383
2384        top = true;
2385      }
2386
2387      if (top === "bottom") {
2388
2389        top = false;
2390      }
2391
2392      if (index) {
2393
2394        var allIndex = this.rows.indexOf(index),
2395            activeIndex = this.activeRows.indexOf(index),
2396            displayIndex = this.displayRows.indexOf(index);
2397
2398        if (displayIndex > -1) {
2399
2400          this.displayRows.splice(top ? displayIndex : displayIndex + 1, 0, row);
2401        }
2402
2403        if (activeIndex > -1) {
2404
2405          this.activeRows.splice(top ? activeIndex : activeIndex + 1, 0, row);
2406        }
2407
2408        if (allIndex > -1) {
2409
2410          this.rows.splice(top ? allIndex : allIndex + 1, 0, row);
2411        }
2412      } else {
2413
2414        if (top) {
2415
2416          this.displayRows.unshift(row);
2417
2418          this.activeRows.unshift(row);
2419
2420          this.rows.unshift(row);
2421        } else {
2422
2423          this.displayRows.push(row);
2424
2425          this.activeRows.push(row);
2426
2427          this.rows.push(row);
2428        }
2429      }
2430
2431      this.setDisplayRows(this.displayRows);
2432
2433      this.setActiveRows(this.activeRows);
2434
2435      this.table.options.rowAdded(row.getComponent());
2436
2437      this.table.options.dataEdited(this.getData());
2438
2439      this.renderTable();
2440
2441      return row;
2442    };
2443
2444    RowManager.prototype.moveRow = function (from, to, after) {
2445
2446      this._moveRowInArray(this.rows, from, to, after);
2447
2448      this._moveRowInArray(this.activeRows, from, to, after);
2449
2450      this._moveRowInArray(this.displayRows, from, to, after);
2451
2452      this.table.options.rowMoved(from.getComponent());
2453    };
2454
2455    RowManager.prototype._moveRowInArray = function (rows, from, to, after) {
2456
2457      var fromIndex = rows.indexOf(from),
2458          toIndex,
2459          start,
2460          end;
2461
2462      if (fromIndex > -1) {
2463
2464        rows.splice(fromIndex, 1);
2465
2466        toIndex = rows.indexOf(to);
2467
2468        if (toIndex > -1) {
2469
2470          if (after) {
2471
2472            rows.splice(toIndex + 1, 0, from);
2473          } else {
2474
2475            rows.splice(toIndex, 0, from);
2476          }
2477        } else {
2478
2479          rows.splice(fromIndex, 0, from);
2480        }
2481      }
2482
2483      //restyle rows
2484
2485      if (rows === this.displayRows) {
2486
2487        start = fromIndex < toIndex ? fromIndex : toIndex;
2488
2489        end = toIndex > fromIndex ? toIndex : fromIndex + 1;
2490
2491        for (var i = start; i <= end; i++) {
2492
2493          if (rows[i]) {
2494
2495            this.styleRow(rows[i], i);
2496          }
2497        }
2498      }
2499    };
2500
2501    RowManager.prototype.clearData = function () {
2502
2503      this.setData([]);
2504    };
2505
2506    RowManager.prototype.getRowIndex = function (row) {
2507
2508      return this.findRowIndex(row, this.rows);
2509    };
2510
2511    RowManager.prototype.getDisplayRowIndex = function (row) {
2512
2513      return this.findRowIndex(row, this.displayRows);
2514    };
2515
2516    RowManager.prototype.nextDisplayRow = function (row) {
2517
2518      var index = this.getDisplayRowIndex(row),
2519          nextRow = false;
2520
2521      if (index !== false && index < this.displayRowsCount - 1) {
2522
2523        nextRow = this.displayRows[index + 1];
2524      }
2525
2526      return nextRow;
2527    };
2528
2529    RowManager.prototype.prevDisplayRow = function (row) {
2530
2531      var index = this.getDisplayRowIndex(row),
2532          prevRow = false;
2533
2534      if (index) {
2535
2536        prevRow = this.displayRows[index - 1];
2537      }
2538
2539      return prevRow;
2540    };
2541
2542    RowManager.prototype.findRowIndex = function (row, list) {
2543
2544      var rowIndex;
2545
2546      row = this.findRow(row);
2547
2548      if (row) {
2549
2550        rowIndex = list.indexOf(row);
2551
2552        if (rowIndex > -1) {
2553
2554          return rowIndex;
2555        }
2556      }
2557
2558      return false;
2559    };
2560
2561    RowManager.prototype.getData = function (active) {
2562
2563      var self = this,
2564          output = [];
2565
2566      var rows = active ? self.activeRows : self.rows;
2567
2568      rows.forEach(function (row) {
2569
2570        output.push(row.getData(true));
2571      });
2572
2573      return output;
2574    };
2575
2576    RowManager.prototype.getComponents = function (active) {
2577
2578      var self = this,
2579          output = [];
2580
2581      var rows = active ? self.activeRows : self.rows;
2582
2583      rows.forEach(function (row) {
2584
2585        output.push(row.getComponent());
2586      });
2587
2588      return output;
2589    };
2590
2591    RowManager.prototype.getDataCount = function (active) {
2592
2593      return active ? this.rows.length : this.activeRows.length;
2594    };
2595
2596    RowManager.prototype._genRemoteRequest = function () {
2597
2598      var self = this,
2599          table = self.table,
2600          options = table.options,
2601          params = {};
2602
2603      if (table.extExists("page")) {
2604
2605        //set sort data if defined
2606
2607        if (options.ajaxSorting) {
2608
2609          var sorters = self.table.extensions.sort.getSort();
2610
2611          if (sorters[0] && typeof sorters[0].column != "function") {
2612
2613            params[self.table.extensions.page.paginationDataSentNames.sort] = sorters[0].column.getField();
2614
2615            params[self.table.extensions.page.paginationDataSentNames.sort_dir] = sorters[0].dir;
2616          }
2617        }
2618
2619        //set filter data if defined
2620
2621        if (options.ajaxFiltering) {
2622
2623          var filters = self.table.extensions.filter.getFilter();
2624
2625          if (filters[0] && typeof filters[0].field == "string") {
2626
2627            params[self.table.extensions.page.paginationDataSentNames.filter] = filters[0].field;
2628
2629            params[self.table.extensions.page.paginationDataSentNames.filter_type] = filters[0].type;
2630
2631            params[self.table.extensions.page.paginationDataSentNames.filter_value] = filters[0].value;
2632          }
2633        }
2634
2635        self.table.extensions.ajax.setParams(params, true);
2636      }
2637
2638      table.extensions.ajax.sendRequest(function (data) {
2639
2640        self.setData(data);
2641      });
2642    };
2643
2644    //choose the path to refresh data after a filter update
2645
2646    RowManager.prototype.filterRefresh = function () {
2647
2648      var table = this.table,
2649          options = table.options;
2650
2651      if (options.ajaxFiltering) {
2652
2653        if (options.pagination == "remote" && table.extExists("page")) {
2654
2655          table.extensions.page.reset(true);
2656
2657          table.extensions.page.setPage(1);
2658        } else {
2659
2660          //assume data is url, make ajax call to url to get data
2661
2662          this._genRemoteRequest();
2663        }
2664      } else {
2665
2666        this.refreshActiveData();
2667      }
2668    };
2669
2670    //choose the path to refresh data after a sorter update
2671
2672    RowManager.prototype.sorterRefresh = function () {
2673
2674      var table = this.table,
2675          options = this.table.options,
2676          left = this.scrollLeft;
2677
2678      if (options.ajaxSorting) {
2679
2680        if (options.pagination == "remote" && table.extExists("page")) {
2681
2682          table.extensions.page.reset(true);
2683
2684          table.extensions.page.setPage(1);
2685        } else {
2686
2687          //assume data is url, make ajax call to url to get data
2688
2689          this._genRemoteRequest();
2690        }
2691      } else {
2692
2693        this.refreshActiveData();
2694      }
2695
2696      this.element.scrollLeft(left);
2697    };
2698
2699    //set active data set
2700
2701    RowManager.prototype.refreshActiveData = function (dataChanged) {
2702
2703      var self = this,
2704          table = this.table;
2705
2706      if (table.options.selectable && !table.options.selectablePersistence && table.extExists("selectRow")) {
2707
2708        table.extensions.selectRow.deselectRows();
2709      }
2710
2711      //filter data
2712
2713      if (table.extExists("filter")) {
2714
2715        if (table.extensions.filter.hasChanged() || dataChanged) {
2716
2717          self.setActiveRows(table.extensions.filter.filter(self.rows));
2718
2719          dataChanged = true;
2720        }
2721      } else {
2722
2723        self.setActiveRows(self.rows.slice(0));
2724      }
2725
2726      //sort data
2727
2728      if (table.extExists("sort")) {
2729
2730        if (table.extensions.sort.hasChanged() || dataChanged) {
2731
2732          table.extensions.sort.sort();
2733
2734          dataChanged = true;
2735        }
2736      }
2737
2738      //group data
2739
2740      if (table.options.groupBy && table.extExists("groupRows")) {
2741
2742        self.setDisplayRows(table.extensions.groupRows.getRows(this.activeRows, dataChanged));
2743
2744        if (table.options.pagination) {
2745
2746          console.warn("Invalid Setup Combination - Pagination and Row Grouping cannot be enabled at the same time");
2747        }
2748      } else {
2749
2750        //paginate data
2751
2752        if (table.options.pagination && table.extExists("page")) {
2753
2754          if (table.extensions.page.getMode() == "local") {
2755
2756            if (dataChanged) {
2757
2758              table.extensions.page.reset();
2759            }
2760
2761            table.extensions.page.setMaxRows(this.activeRows.length);
2762          }
2763
2764          self.setDisplayRows(table.extensions.page.getRows(this.activeRows));
2765        } else {
2766
2767          self.setDisplayRows(self.activeRows.slice(0));
2768        }
2769      }
2770
2771      if (self.element.is(":visible")) {
2772
2773        self.renderTable();
2774      }
2775
2776      if (table.extExists("columnCalcs")) {
2777
2778        table.extensions.columnCalcs.recalc(this.displayRows);
2779      }
2780    };
2781
2782    RowManager.prototype.setActiveRows = function (activeRows) {
2783
2784      this.activeRows = activeRows;
2785
2786      this.activeRowsCount = this.activeRows.length;
2787    };
2788
2789    RowManager.prototype.setDisplayRows = function (displayRows) {
2790
2791      this.displayRows = displayRows;
2792
2793      this.displayRowsCount = this.displayRows.length;
2794    };
2795
2796    //return only actual rows (not group headers etc)
2797
2798    RowManager.prototype.getRows = function () {
2799
2800      return this.rows;
2801    };
2802
2803    ///////////////// Table Rendering /////////////////
2804
2805
2806    RowManager.prototype.renderTable = function () {
2807
2808      var self = this;
2809
2810      self.table.options.renderStarted();
2811
2812      self.element.scrollTop(0);
2813
2814      if (!self.height || !self.table.options.virtualDom || self.table.options.pagination) {
2815
2816        self.renderMode = "classic";
2817
2818        self._simpleRender();
2819      } else {
2820
2821        self.renderMode = "virtual";
2822
2823        self._virtualRenderFill();
2824      }
2825
2826      if (self.firstRender) {
2827
2828        if (self.displayRowsCount) {
2829
2830          self.firstRender = false;
2831
2832          if (self.table.options.fitColumns) {
2833
2834            self.columnManager.fitToTable();
2835          } else {
2836
2837            self.columnManager.fitToData();
2838          }
2839        } else {
2840
2841          self.renderEmptyScroll();
2842        }
2843      }
2844
2845      if (self.table.extExists("frozenColumns")) {
2846
2847        self.table.extensions.frozenColumns.layout();
2848      }
2849
2850      if (!self.displayRowsCount) {
2851
2852        if (self.table.options.placeholder) {
2853
2854          self.getElement().append(self.table.options.placeholder);
2855        }
2856      }
2857
2858      self.table.options.renderComplete();
2859    };
2860
2861    RowManager.prototype.getRenderMode = function () {
2862
2863      return this.renderMode;
2864    };
2865
2866    //simple render on heightless table
2867
2868    RowManager.prototype._simpleRender = function () {
2869
2870      var self = this,
2871          element = this.tableElement;
2872
2873      self._clearVirtualDom();
2874
2875      if (self.displayRowsCount) {
2876
2877        self.displayRows.forEach(function (row, index) {
2878
2879          self.styleRow(row, index);
2880
2881          element.append(row.getElement());
2882
2883          row.initialize(true);
2884        });
2885      } else {
2886
2887        self.renderEmptyScroll();
2888      }
2889    };
2890
2891    //show scrollbars on empty table div
2892
2893    RowManager.prototype.renderEmptyScroll = function () {
2894
2895      var self = this;
2896
2897      self.tableElement.css({
2898
2899        "min-width": self.table.columnManager.getWidth(),
2900
2901        "min-height": "1px",
2902
2903        "visibility": "hidden"
2904
2905      });
2906    };
2907
2908    RowManager.prototype._clearVirtualDom = function () {
2909
2910      var element = this.tableElement;
2911
2912      if (this.table.options.placeholder) {
2913
2914        this.table.options.placeholder.detach();
2915      }
2916
2917      element.children().detach();
2918
2919      element.css({
2920
2921        "padding-top": "",
2922
2923        "padding-bottom": "",
2924
2925        "min-width": "",
2926
2927        "min-height": "",
2928
2929        "visibility": ""
2930
2931      });
2932
2933      this.scrollTop = 0;
2934
2935      this.scrollLeft = 0;
2936
2937      this.vDomTop = 0;
2938
2939      this.vDomBottom = 0;
2940
2941      this.vDomTopPad = 0;
2942
2943      this.vDomBottomPad = 0;
2944    };
2945
2946    RowManager.prototype.styleRow = function (row, index) {
2947
2948      if (index % 2) {
2949
2950        row.element.addClass("tabulator-row-even").removeClass("tabulator-row-odd");
2951      } else {
2952
2953        row.element.addClass("tabulator-row-odd").removeClass("tabulator-row-even");
2954      }
2955    };
2956
2957    //full virtual render
2958
2959    RowManager.prototype._virtualRenderFill = function (position, forceMove) {
2960
2961      var self = this,
2962          element = self.tableElement,
2963          holder = self.element,
2964          topPad = 0,
2965          rowsHeight = 0,
2966          topPadHeight = 0,
2967          i = 0;
2968
2969      position = position || 0;
2970
2971      if (!position) {
2972
2973        self._clearVirtualDom();
2974      } else {
2975
2976        element.children().detach();
2977
2978        //check if position is too close to bottom of table
2979
2980        var heightOccpied = (self.displayRowsCount - position) * self.vDomRowHeight;
2981
2982        if (heightOccpied < self.height) {
2983
2984          position -= Math.ceil((self.height - heightOccpied) / self.displayRowsCount);
2985
2986          if (position < 0) {
2987
2988            position = 0;
2989          }
2990        }
2991
2992        //calculate initial pad
2993
2994        topPad = Math.min(Math.max(Math.floor(self.vDomWindowBuffer / self.vDomRowHeight), self.vDomWindowMinMarginRows), position);
2995
2996        position -= topPad;
2997      }
2998
2999      if (self.displayRowsCount && self.element.is(":visible")) {
3000
3001        self.vDomTop = position;
3002
3003        self.vDomBottom = position - 1;
3004
3005        while ((rowsHeight <= self.height + self.vDomWindowBuffer || i < self.vDomWindowMinTotalRows) && self.vDomBottom < self.dis
3005playRowsCount - 1) {
3006
3007          var index = self.vDomBottom + 1,
3008              row = self.displayRows[index];
3009
3010          self.styleRow(row, index);
3011
3012          element.append(row.getElement());
3013
3014          if (!row.initialized) {
3015
3016            row.initialize(true);
3017          } else {
3018
3019            if (!row.heightInitialized) {
3020
3021              row.normalizeHeight(true);
3022            }
3023          }
3024
3025          if (i < topPad) {
3026
3027            topPadHeight += row.getHeight();
3028          } else {
3029
3030            rowsHeight += row.getHeight();
3031          }
3032
3033          self.vDomBottom++;
3034
3035          i++;
3036        }
3037
3038        if (!position) {
3039
3040          this.vDomTopPad = 0;
3041
3042          //adjust rowheight to match average of rendered elements
3043
3044          self.vDomRowHeight = Math.floor((rowsHeight + topPadHeight) / i);
3045
3046          self.vDomBottomPad = self.vDomRowHeight * (self.displayRowsCount - self.vDomBottom - 1);
3047
3048          self.vDomScrollHeight = topPadHeight + rowsHeight + self.vDomBottomPad - self.height;
3049        } else {
3050
3051          self.vDomTopPad = !forceMove ? self.scrollTop - topPadHeight : self.vDomRowHeight * this.vDomTop + topPadHeight;
3052
3053          self.vDomBottomPad = self.vDomBottom == self.displayRowsCount - 1 ? 0 : Math.max(self.vDomScrollHeight - self.vDomTopPad - rowsHeight - topPadHeight, 0);
3054        }
3055
3056        element[0].style.paddingTop = self.vDomTopPad + "px";
3057
3058        element[0].style.paddingBottom = self.vDomBottomPad + "px";
3059
3060        if (forceMove) {
3061
3062          this.scrollTop = self.vDomTopPad + topPadHeight;
3063        }
3064
3065        this.scrollTop = Math.min(this.scrollTop, this.element[0].scrollHeight - this.height);
3066
3067        //adjust for horizontal scrollbar if present
3068
3069        if (this.element[0].scrollWidth > this.element[0].offsetWidt) {
3070
3071          this.scrollTop += this.element[0].offsetHeight - this.element[0].clientHeight;
3072        }
3073
3074        this.vDomScrollPosTop = this.scrollTop;
3075
3076        this.vDomScrollPosBottom = this.scrollTop;
3077
3078        holder.scrollTop(this.scrollTop);
3079      } else {
3080
3081        this.renderEmptyScroll();
3082      }
3083    };
3084
3085    //handle vertical scrolling
3086
3087    RowManager.prototype.scrollVertical = function (dir) {
3088
3089      var topDiff = this.scrollTop - this.vDomScrollPosTop;
3090
3091      var bottomDiff = this.scrollTop - this.vDomScrollPosBottom;
3092
3093      var margin = this.vDomWindowBuffer * 2;
3094
3095      if (-topDiff > margin || bottomDiff > margin) {
3096
3097        //if big scroll redraw table;
3098
3099        this._virtualRenderFill(Math.floor(this.element[0].scrollTop / this.element[0].scrollHeight * this.displayRowsCount));
3100      } else {
3101
3102        if (dir) {
3103
3104          //scrolling up
3105
3106          if (topDiff < 0) {
3107
3108            this._addTopRow(-topDiff);
3109          }
3110
3111          if (topDiff < 0) {
3112
3113            //hide bottom row if needed
3114
3115            if (this.vDomScrollHeight - this.scrollTop > this.vDomWindowBuffer) {
3116
3117              this._removeBottomRow(-bottomDiff);
3118            }
3119          }
3120        } else {
3121
3122          //scrolling down
3123
3124          if (topDiff >= 0) {
3125
3126            //hide top row if needed
3127
3128            if (this.scrollTop > this.vDomWindowBuffer) {
3129
3130              this._removeTopRow(topDiff);
3131            }
3132          }
3133
3134          if (bottomDiff >= 0) {
3135
3136            this._addBottomRow(bottomDiff);
3137          }
3138        }
3139      }
3140    };
3141
3142    RowManager.prototype._addTopRow = function (topDiff) {
3143      var i = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
3144
3145
3146      var table = this.tableElement;
3147
3148      if (this.vDomTop) {
3149
3150        var index = this.vDomTop - 1,
3151            topRow = this.displayRows[index],
3152            topRowHeight = topRow.getHeight() || this.vDomRowHeight;
3153
3154        //hide top row if needed
3155
3156        if (topDiff >= topRowHeight) {
3157
3158          this.styleRow(topRow, index);
3159
3160          table.prepend(topRow.getElement());
3161
3162          if (!topRow.initialized || !topRow.heightInitialized) {
3163
3164            this.vDomTopNewRows.push(topRow);
3165
3166            if (!topRow.heightInitialized) {
3167
3168              topRow.clearCellHeight();
3169            }
3170          }
3171
3172          topRow.initialize();
3173
3174          this.vDomTopPad -= topRowHeight;
3175
3176          if (this.vDomTopPad < 0) {
3177
3178            this.vDomTopPad = (this.vDomTop - 1) * this.vDomRowHeight;
3179          }
3180
3181          table[0].style.paddingTop = this.vDomTopPad + "px";
3182
3183          this.vDomScrollPosTop -= topRowHeight;
3184
3185          this.vDomTop--;
3186        }
3187
3188        topDiff = -(this.scrollTop - this.vDomScrollPosTop);
3189
3190        if (i < this.vDomMaxRenderChain && this.vDomTop && topDiff >= (this.displayRows[this.vDomTop - 1].getHeight() || this.vDomRowHeight)) {
3191
3192          this._addTopRow(topDiff, i + 1);
3193        } else {
3194
3195          this._quickNormalizeRowHeight(this.vDomTopNewRows);
3196        }
3197      }
3198    };
3199
3200    RowManager.prototype._removeTopRow = function (topDiff) {
3201
3202      var table = this.tableElement,
3203          topRow = this.displayRows[this.vDomTop],
3204          topRowHeight = topRow.getHeight() || this.vDomRowHeight;
3205
3206      if (topDiff >= topRowHeight) {
3207
3208        topRow.element.detach();
3209
3210        this.vDomTopPad += topRowHeight;
3211
3212        table[0].style.paddingTop = this.vDomTopPad + "px";
3213
3214        this.vDomScrollPosTop += this.vDomTop ? topRowHeight : topRowHeight + this.vDomWindowBuffer;
3215
3216        this.vDomTop++;
3217
3218        topDiff = this.scrollTop - this.vDomScrollPosTop;
3219
3220        this._removeTopRow(topDiff);
3221      }
3222    };
3223
3224    RowManager.prototype._addBottomRow = function (bottomDiff) {
3225      var i = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
3226
3227
3228      var table = this.tableElement;
3229
3230      if (this.vDomBottom < this.displayRowsCount - 1) {
3231
3232        var index = this.vDomBottom + 1,
3233            bottomRow = this.displayRows[index],
3234            bottomRowHeight = bottomRow.getHeight() || this.vDomRowHeight;
3235
3236        //hide bottom row if needed
3237
3238        if (bottomDiff >= bottomRowHeight) {
3239
3240          this.styleRow(bottomRow, index);
3241
3242          table.append(bottomRow.getElement());
3243
3244          if (!bottomRow.initialized || !bottomRow.heightInitialized) {
3245
3246            this.vDomBottomNewRows.push(bottomRow);
3247
3248            if (!bottomRow.heightInitialized) {
3249
3250              bottomRow.clearCellHeight();
3251            }
3252          }
3253
3254          bottomRow.initialize();
3255
3256          this.vDomBottomPad -= bottomRowHeight;
3257
3258          if (this.vDomBottomPad < 0 || index == this.displayRowsCount - 1) {
3259
3260            this.vDomBottomPad = 0;
3261          }
3262
3263          table[0].style.paddingBottom = this.vDomBottomPad + "px";
3264
3265          this.vDomScrollPosBottom += bottomRowHeight;
3266
3267          this.vDomBottom++;
3268        }
3269
3270        bottomDiff = this.scrollTop - this.vDomScrollPosBottom;
3271
3272        if (i < this.vDomMaxRenderChain && this.vDomBottom < this.displayRowsCount - 1 && bottomDiff >= (this.displayRows[this.vDomBottom + 1].getHeight() || this.vDomRowHeight)) {
3273
3274          this._addBottomRow(bottomDiff, i + 1);
3275        } else {
3276
3277          this._quickNormalizeRowHeight(this.vDomBottomNewRows);
3278        }
3279      }
3280    };
3281
3282    RowManager.prototype._removeBottomRow = function (bottomDiff) {
3283
3284      var table = this.tableElement,
3285          bottomRow = this.displayRows[this.vDomBottom],
3286          bottomRowHeight = bottomRow.getHeight() || this.vDomRowHeight;
3287
3288      if (bottomDiff >= bottomRowHeight) {
3289
3290        bottomRow.element.detach();
3291
3292        this.vDomBottomPad += bottomRowHeight;
3293
3294        if (this.vDomBottomPad < 0) {
3295
3296          this.vDomBottomPad == 0;
3297        }
3298
3299        table[0].style.paddingBottom = this.vDomBottomPad + "px";
3300
3301        this.vDomScrollPosBottom -= bottomRowHeight;
3302
3303        this.vDomBottom--;
3304
3305        bottomDiff = -(this.scrollTop - this.vDomScrollPosBottom);
3306
3307        this._removeBottomRow(bottomDiff);
3308      }
3309    };
3310
3311    RowManager.prototype._quickNormalizeRowHeight = function (rows) {
3312
3313      rows.forEach(function (row) {
3314
3315        row.calcHeight();
3316      });
3317
3318      rows.forEach(function (row) {
3319
3320        row.setCellHeight();
3321      });
3322
3323      rows.length = 0;
3324    };
3325
3326    //normalize height of active rows
3327
3328    RowManager.prototype.normalizeHeight = function () {
3329
3330      var self = this;
3331
3332      self.displayRows.forEach(function (row) {
3333
3334        row.normalizeHeight();
3335      });
3336    };
3337
3338    //adjust the height of the table holder to fit in the Tabulator element
3339
3340    RowManager.prototype.adjustTableSize = function () {
3341
3342      var self = this;
3343
3344      if (self.table.options.height) {
3345
3346        var otherHeigt = self.columnManager.getElement().outerHeight() + (self.table.footerManager ? self.table.footerManager.getElement().outerHeight() : 0);
3347
3348        self.element.css({
3349
3350          "min-height": "calc(100% - " + otherHeigt + "px)",
3351
3352          "height": "calc(100% - " + otherHeigt + "px)",
3353
3354          "max-height": "calc(100% - " + otherHeigt + "px)"
3355
3356        });
3357
3358        self.height = self.element.innerHeight();
3359
3360        self.vDomWindowBuffer = self.table.options.virtualDomBuffer || self.height;
3361      }
3362    };
3363
3364    //renitialize all rows
3365
3366    RowManager.prototype.reinitialize = function () {
3367
3368      this.rows.forEach(function (row) {
3369
3370        row.reinitialize();
3371      });
3372    };
3373
3374    //redraw table
3375
3376    RowManager.prototype.redraw = function (force) {
3377
3378      var pos = 0;
3379
3380      if (this.renderMode == "virtual") {
3381
3382        this.adjustTableSize();
3383      }
3384
3385      if (!force) {
3386
3387        if (self.renderMode == "simple") {
3388
3389          this._simpleRender();
3390        } else {
3391
3392          var pos = Math.floor(this.element.scrollTop() / this.element[0].scrollHeight * this.displayRowsCount);
3393
3394          this._virtualRenderFill(pos);
3395        }
3396
3397        if (!this.displayRowsCount) {
3398
3399          if (this.table.options.placeholder) {
3400
3401            this.getElement().append(this.table.options.placeholder);
3402          }
3403        }
3404      } else {
3405
3406        this.renderTable();
3407      }
3408    };
3409
3410    RowManager.prototype.resetScroll = function () {
3411
3412      this.element.scrollLeft(0);
3413
3414      this.element.scrollTop(0);
3415
3416      this.element.scroll();
3417    };
3418
3419    //public row object
3420
3421    var RowComponent = function RowComponent(row) {
3422
3423      var obj = {
3424
3425        getData: function getData() {
3426
3427          return row.getData(true);
3428        },
3429
3430        getElement: function getElement() {
3431
3432          return row.getElement();
3433        },
3434
3435        getCells: function getCells() {
3436
3437          var cells = [];
3438
3439          row.getCells().forEach(function (cell) {
3440
3441            cells.push(cell.getComponent());
3442          });
3443
3444          return cells;
3445        },
3446
3447        getCell: function getCell(column) {
3448
3449          return row.getCell(column).getComponent();
3450        },
3451
3452        getIndex: function getIndex() {
3453
3454          return row.getData(true)[row.table.options.index];
3455        },
3456
3457        delete: function _delete() {
3458
3459          row.delete();
3460        },
3461
3462        scrollTo: function scrollTo() {
3463
3464          row.table.rowManager.scrollToRow(row);
3465        },
3466
3467        update: function update(data) {
3468
3469          row.updateData(data);
3470        },
3471
3472        normalizeHeight: function normalizeHeight() {
3473
3474          row.normalizeHeight(true);
3475        },
3476
3477        select: function select() {
3478
3479          row.table.extensions.selectRow.selectRows(row);
3480        },
3481
3482        deselect: function deselect() {
3483
3484          row.table.extensions.selectRow.deselectRows(row);
3485        },
3486
3487        toggleSelect: function toggleSelect() {
3488
3489          row.table.extensions.selectRow.toggleRow(row);
3490        },
3491
3492        _getSelf: function _getSelf() {
3493
3494          return row;
3495        }
3496
3497      };
3498
3499      return obj;
3500    };
3501
3502    var Row = function Row(data, parent) {
3503
3504      this.table = parent.table;
3505
3506      this.parent = parent;
3507
3508      this.data = {};
3509
3510      this.type = "row"; //type of element
3511
3512      this.element = $("<div class='tabulator-row' role='row'></div>");
3513
3514      this.extensions = {}; //hold extension variables;
3515
3516      this.cells = [];
3517
3518      this.height = 0; //hold element height
3519
3520      this.outerHeight = 0; //holde lements outer height
3521
3522      this.initialized = false; //element has been rendered
3523
3524      this.heightInitialized = false; //element has resized cells to fit
3525
3526
3527      this.setData(data);
3528
3529      this.generateElement();
3530    };
3531
3532    Row.prototype.getElement = function () {
3533
3534      return this.element;
3535    };
3536
3537    Row.prototype.generateElement = function () {
3538
3539      var self = this,
3540          dblTap,
3541          tapHold,
3542          tap;
3543
3544      //set row selection characteristics
3545
3546      if (self.table.options.selectable !== false && self.table.extExists("selectRow")) {
3547
3548        self.table.extensions.selectRow.initializeRow(this);
3549      }
3550
3551      //setup movable rows
3552
3553      if (self.table.options.movableRows !== false && self.table.extExists("moveRow")) {
3554
3555        self.table.extensions.moveRow.initializeRow(this);
3556      }
3557
3558      //handle row click events
3559
3560      if (self.table.options.rowClick) {
3561
3562        self.element.on("click", function (e) {
3563
3564          self.table.options.rowClick(e, self.getComponent());
3565        });
3566      }
3567
3568      if (self.table.options.rowDblClick) {
3569
3570        self.element.on("dblclick", function (e) {
3571
3572          self.table.options.rowDblClick(e, self.getComponent());
3573        });
3574      }
3575
3576      if (self.table.options.rowContext) {
3577
3578        self.element.on("contextmenu", function (e) {
3579
3580          self.table.options.rowContext(e, self.getComponent());
3581        });
3582      }
3583
3584      if (self.table.options.rowTap) {
3585
3586        tap = false;
3587
3588        self.element.on("touchstart", function (e) {
3589
3590          tap = true;
3591        });
3592
3593        self.element.on("touchend", function (e) {
3594
3595          if (tap) {
3596
3597            self.table.options.rowTap(e, self.getComponent());
3598          }
3599
3600          tap = false;
3601        });
3602      }
3603
3604      if (self.table.options.rowDblTap) {
3605
3606        dblTap = null;
3607
3608        self.element.on("touchend", function (e) {
3609
3610          if (dblTap) {
3611
3612            clearTimeout(dblTap);
3613
3614            dblTap = null;
3615
3616            self.table.options.rowDblTap(e, self.getComponent());
3617          } else {
3618
3619            dblTap = setTimeout(function () {
3620
3621              clearTimeout(dblTap);
3622
3623              dblTap = null;
3624            }, 300);
3625          }
3626        });
3627      }
3628
3629      if (self.table.options.rowTapHold) {
3630
3631        tapHold = null;
3632
3633        self.element.on("touchstart", function (e) {
3634
3635          clearTimeout(tapHold);
3636
3637          tapHold = setTimeout(function () {
3638
3639            clearTimeout(tapHold);
3640
3641            tapHold = null;
3642
3643            tap = false;
3644
3645            self.table.options.rowTapHold(e, self.getComponent());
3646          }, 1000);
3647        });
3648
3649        self.element.on("touchend", function (e) {
3650
3651          clearTimeout(tapHold);
3652
3653          tapHold = null;
3654        });
3655      }
3656    };
3657
3658    Row.prototype.generateCells = function () {
3659
3660      this.cells = this.table.columnManager.generateCells(this);
3661    };
3662
3663    //functions to setup on first render
3664
3665    Row.prototype.initialize = function (force) {
3666
3667      var self = this;
3668
3669      if (!self.initialized || force) {
3670
3671        self.element.empty();
3672
3673        //handle frozen cells
3674
3675        if (this.table.extExists("frozenColumns")) {
3676
3677          this.table.extensions.frozenColumns.layoutRow(this);
3678        }
3679
3680        this.generateCells();
3681
3682        self.cells.forEach(function (cell) {
3683
3684          self.element.append(cell.getElement());
3685        });
3686
3687        if (force) {
3688
3689          self.normalizeHeight();
3690        }
3691
3692        if (self.table.options.rowFormatter) {
3693
3694          self.table.options.rowFormatter(self.getComponent());
3695        }
3696
3697        self.initialized = true;
3698      }
3699    };
3700
3701    Row.prototype.reinitializeHeight = function () {
3702
3703      this.heightInitialized = false;
3704
3705      if (this.element[0].offsetParent !== null) {
3706
3707        this.normalizeHeight(true);
3708      }
3709    };
3710
3711    Row.prototype.reinitialize = function () {
3712
3713      this.initialized = false;
3714
3715      this.heightInitialized = false;
3716
3717      this.height = 0;
3718
3719      if (this.element[0].offsetParent !== null) {
3720
3721        this.initialize(true);
3722      }
3723    };
3724
3725    //get heights when doing bulk row style calcs in virtual DOM
3726
3727    Row.prototype.calcHeight = function () {
3728
3729      this.height = this.element[0].clientHeight;
3730
3731      this.outerHeight = this.element[0].offsetHeight;
3732    };
3733
3734    //set of cells
3735
3736    Row.prototype.setCellHeight = function () {
3737
3738      var height = this.height;
3739
3740      this.cells.forEach(function (cell) {
3741
3742        cell.setHeight(height);
3743      });
3744
3745      this.heightInitialized = true;
3746    };
3747
3748    Row.prototype.clearCellHeight = function () {
3749
3750      this.cells.forEach(function (cell) {
3751
3752        cell.clearHeight();
3753      });
3754    };
3755
3756    //normalize the height of elements in the row
3757
3758    Row.prototype.normalizeHeight = function (force) {
3759
3760      if (force) {
3761
3762        this.clearCellHeight();
3763      }
3764
3765      this.calcHeight();
3766
3767      this.setCellHeight();
3768    };
3769
3770    //set height of rows
3771
3772    Row.prototype.setHeight = function (height, force) {
3773
3774      if (this.height != height || force) {
3775
3776        this.height = height;
3777
3778        this.setCellHeight();
3779
3780        // this.outerHeight = this.element.outerHeight();
3781
3782        this.outerHeight = this.element[0].offsetHeight;
3783      }
3784    };
3785
3786    //return rows outer height
3787
3788    Row.prototype.getHeight = function () {
3789
3790      return this.outerHeight;
3791    };
3792
3793    //return rows outer Width
3794
3795    Row.prototype.getWidth = function () {
3796
3797      return this.element.outerWidth();
3798    };
3799
3800    //////////////// Cell Management /////////////////
3801
3802
3803    Row.prototype.deleteCell = function (cell) {
3804
3805      var index = this.cells.indexOf(cell);
3806
3807      if (index > -1) {
3808
3809        this.cells.splice(index, 1);
3810      }
3811    };
3812
3813    //////////////// Data Management /////////////////
3814
3815
3816    Row.prototype.setData = function (data) {
3817
3818      var self = this;
3819
3820      if (self.table.extExists("mutator")) {
3821
3822        self.data = self.table.extensions.mutator.transformRow(data);
3823      } else {
3824
3825        self.data = data;
3826      }
3827    };
3828
3829    //update the rows data
3830
3831    Row.prototype.updateData = function (data) {
3832
3833      var self = this;
3834
3835      //mutate incomming data if needed
3836
3837      if (self.table.extExists("mutator")) {
3838
3839        data = self.table.extensions.mutator.transformRow(data);
3840      }
3841
3842      //set data
3843
3844      for (var attrname in data) {
3845
3846        self.data[attrname] = data[attrname];
3847      }
3848
3849      //update affected cells only
3850
3851      for (var attrname in data) {
3852
3853        var cell = this.getCell(attrname);
3854
3855        if (cell) {
3856
3857          if (cell.getValue() != data[attrname]) {
3858
3859            cell.setValueProcessData(data[attrname]);
3860          }
3861        }
3862      }
3863
3864      //Partial reinitialization if visible
3865
3866      if (this.element.is(":visible")) {
3867
3868        self.normalizeHeight();
3869
3870        if (self.table.options.rowFormatter) {
3871
3872          self.table.options.rowFormatter(self.getComponent());
3873        }
3874      } else {
3875
3876        this.initialized = false;
3877
3878        this.height = 0;
3879      }
3880
3881      //self.reinitialize();
3882
3883
3884      self.table.options.rowUpdated(self.getComponent());
3885    };
3886
3887    Row.prototype.getData = function (transform) {
3888
3889      var self = this;
3890
3891      if (transform) {
3892
3893        if (self.table.extExists("accessor")) {
3894
3895          return self.table.extensions.accessor.transformRow(self.data);
3896        }
3897      } else {
3898
3899        return this.data;
3900      }
3901    };
3902
3903    Row.prototype.getCell = function (column) {
3904
3905      var match = false,
3906          column = this.table.columnManager.findColumn(column);
3907
3908      match = this.cells.find(function (cell) {
3909
3910        return cell.column === column;
3911      });
3912
3913      return match;
3914    }, Row.prototype.getCellIndex = function (findCell) {
3915
3916      return this.cells.findIndex(function (cell) {
3917
3918        return cell === findCell;
3919      });
3920    }, Row.prototype.findNextEditableCell = function (index) {
3921
3922      var nextCell = false;
3923
3924      if (index < this.cells.length - 1) {
3925
3926        for (var i = index + 1; i < this.cells.length; i++) {
3927
3928          var cell = this.cells[i];
3929
3930          if (cell.column.extensions.edit && cell.getElement().is(":visible")) {
3931
3932            var allowEdit = true;
3933
3934            if (typeof cell.column.extensions.edit.check == "function") {
3935
3936              allowEdit = cell.column.extensions.edit.check(cell.getComponent());
3937            }
3938
3939            if (allowEdit) {
3940
3941              nextCell = cell;
3942
3943              break;
3944            }
3945          }
3946        }
3947      }
3948
3949      return nextCell;
3950    }, Row.prototype.findPrevEditableCell = function (index) {
3951
3952      var prevCell = false;
3953
3954      if (index > 0) {
3955
3956        for (var i = index - 1; i >= 0; i--) {
3957
3958          var cell = this.cells[i],
3959              allowEdit = true;
3960
3961          if (cell.column.extensions.edit && cell.getElement().is(":visible")) {
3962
3963            if (typeof cell.column.extensions.edit.check == "function") {
3964
3965              allowEdit = cell.column.extensions.edit.check(cell.getComponent());
3966            }
3967
3968            if (allowEdit) {
3969
3970              prevCell = cell;
3971
3972              break;
3973            }
3974          }
3975        }
3976      }
3977
3978      return prevCell;
3979    }, Row.prototype.getCells = function () {
3980
3981      return this.cells;
3982    },
3983
3984    ///////////////////// Actions  /////////////////////
3985
3986
3987    Row.prototype.delete = function () {
3988
3989      var index = this.table.rowManager.getRowIndex(this);
3990
3991      this.deleteActual();
3992
3993      if (this.table.options.history && this.table.extExists("history")) {
3994
3995        if (index) {
3996
3997          index = this.table.rowManager.rows[index - 1];
3998        }
3999
4000        this.table.extensions.history.action("rowDelete", this, { data: this.getData(), pos: !index, index: index });
4001      };
4002    };
4003
4004    Row.prototype.deleteActual = function () {
4005
4006      this.table.rowManager.deleteRow(this);
4007
4008      var cellCount = this.cells.length;
4009
4010      for (var i = 0; i < cellCount; i++) {
4011
4012        this.cells[0].delete();
4013      }
4014    };
4015
4016    //////////////// Object Generation /////////////////
4017
4018    Row.prototype.getComponent = function () {
4019
4020      return new RowComponent(this);
4021    };
4022
4023    //public row object
4024
4025    var CellComponent = function CellComponent(cell) {
4026
4027      var obj = {
4028
4029        getValue: function getValue() {
4030
4031          return cell.getValue();
4032        },
4033
4034        getOldValue: function getOldValue() {
4035
4036          return cell.getOldValue();
4037        },
4038
4039        getElement: function getElement() {
4040
4041          return cell.getElement();
4042        },
4043
4044        getRow: function getRow() {
4045
4046          return cell.row.getComponent();
4047        },
4048
4049        getData: function getData() {
4050
4051          return cell.row.getData();
4052        },
4053
4054        getField: function getField() {
4055
4056          return cell.column.getField();
4057        },
4058
4059        getColumn: function getColumn() {
4060
4061          return cell.column.getComponent();
4062        },
4063
4064        setValue: function setValue(value, mutate) {
4065
4066          if (typeof mutate == "undefined") {
4067
4068            mutate = true;
4069          }
4070
4071          cell.setValue(value, mutate);
4072        },
4073
4074        edit: function edit() {
4075
4076          cell.edit();
4077        },
4078
4079        nav: function nav() {
4080
4081          return cell.nav();
4082        },
4083
4084        checkHeight: function checkHeight() {
4085
4086          cell.checkHeight();
4087        },
4088
4089        _getSelf: function _getSelf() {
4090
4091          return cell;
4092        }
4093
4094      };
4095
4096      return obj;
4097    };
4098
4099    var Cell = function Cell(column, row) {
4100
4101      this.table = column.table;
4102
4103      this.column = column;
4104
4105      this.row = row;
4106
4107      // this.element = $("<div class='tabulator-cell' role='gridcell'></div>");
4108
4109      this.element = null;
4110
4111      this.value = null;
4112
4113      this.oldValue = null;
4114
4115      this.height = null;
4116
4117      this.width = null;
4118
4119      this.minWidth = null;
4120
4121      this.build();
4122    };
4123
4124    //////////////// Setup Functions /////////////////
4125
4126
4127    //generate element
4128
4129    Cell.prototype.build = function () {
4130
4131      this.generateElement();
4132
4133      this.setWidth(this.column.width);
4134
4135      this._configureCell();
4136
4137      this.setValueActual(this.column.getFieldValue(this.row.data));
4138    };
4139
4140    Cell.prototype.generateElement = function () {
4141
4142      this.element = document.createElement('div');
4143
4144      this.element.className = "tabulator-cell";
4145
4146      this.element.setAttribute("role", "gridcell");
4147
4148      this.element = $(this.element);
4149    };
4150
4151    Cell.prototype._configureCell = function () {
4152
4153      var self = this,
4154          cellEvents = self.column.cellEvents,
4155          element = self.element,
4156          field = this.column.getField(),
4157          dblTap,
4158          tapHold,
4159          tap;
4160
4161      //set text alignment
4162
4163      element[0].style.textAlign = self.column.hozAlign;
4164
4165      if (field) {
4166
4167        element.attr("tabulator-field", field);
4168      }
4169
4170      if (self.column.definition.cssClass) {
4171
4172        element.addClass(self.column.definition.cssClass);
4173      }
4174
4175      //set event bindings
4176
4177      if (cellEvents.cellClick) {
4178
4179        self.element.on("click", function (e) {
4180
4181          cellEvents.cellClick(e, self.getComponent());
4182        });
4183      }
4184
4185      if (cellEvents.cellDblClick) {
4186
4187        self.element.on("dblclick", function (e) {
4188
4189          cellEvents.cellDblClick(e, self.getComponent());
4190        });
4191      }
4192
4193      if (cellEvents.cellContext) {
4194
4195        self.element.on("contextmenu", function (e) {
4196
4197          cellEvents.cellContext(e, self.getComponent());
4198        });
4199      }
4200
4201      if (cellEvents.cellTap) {
4202
4203        tap = false;
4204
4205        self.element.on("touchstart", function (e) {
4206
4207          tap = true;
4208        });
4209
4210        self.element.on("touchend", function (e) {
4211
4212          if (tap) {
4213
4214            cellEvents.cellTap(e, self.getComponent());
4215          }
4216
4217          tap = false;
4218        });
4219      }
4220
4221      if (cellEvents.cellDblTap) {
4222
4223        dblTap = null;
4224
4225        self.element.on("touchend", function (e) {
4226
4227          if (dblTap) {
4228
4229            clearTimeout(dblTap);
4230
4231            dblTap = null;
4232
4233            cellEvents.cellDblTap(e, self.getComponent());
4234          } else {
4235
4236            dblTap = setTimeout(function () {
4237
4238              clearTimeout(dblTap);
4239
4240              dblTap = null;
4241            }, 300);
4242          }
4243        });
4244      }
4245
4246      if (cellEvents.cellTapHold) {
4247
4248        tapHold = null;
4249
4250        self.element.on("touchstart", function (e) {
4251
4252          clearTimeout(tapHold);
4253
4254          tapHold = setTimeout(function () {
4255
4256            clearTimeout(tapHold);
4257
4258            tapHold = null;
4259
4260            tap = false;
4261
4262            cellEvents.cellTapHold(e, self.getComponent());
4263          }, 1000);
4264        });
4265
4266        self.element.on("touchend", function (e) {
4267
4268          clearTimeout(tapHold);
4269
4270          tapHold = null;
4271        });
4272      }
4273
4274      if (self.column.extensions.edit) {
4275
4276        self.table.extensions.edit.bindEditor(self);
4277      }
4278
4279      if (self.column.definition.rowHandle && self.table.options.movableRows !== false && self.table.extExists("moveRow")) {
4280
4281        self.table.extensions.moveRow.initializeCell(self);
4282      }
4283
4284      //hide cell if not visible
4285
4286      if (!self.column.visible) {
4287
4288        self.hide();
4289      }
4290    };
4291
4292    //generate cell contents
4293
4294    Cell.prototype._generateContents = function () {
4295
4296      var self = this;
4297
4298      if (self.table.extExists("format")) {
4299
4300        self.element.html(self.table.extensions.format.formatValue(self));
4301      } else {
4302
4303        self.element.html(self.value);
4304      }
4305    };
4306
4307    //generate tooltip text
4308
4309    Cell.prototype._generateTooltip = function () {
4310
4311      var self = this;
4312
4313      var tooltip = self.column.tooltip;
4314
4315      if (tooltip) {
4316
4317        if (tooltip === true) {
4318
4319          tooltip = self.value;
4320        } else if (typeof tooltip == "function") {
4321
4322          tooltip = tooltip(self.getComponent());
4323        }
4324
4325        self.element[0].setAttribute("title", tooltip);
4326      } else {
4327
4328        self.element[0].setAttribute("title", "");
4329      }
4330    };
4331
4332    //////////////////// Getters ////////////////////
4333
4334    Cell.prototype.getElement = function () {
4335
4336      return this.element;
4337    };
4338
4339    Cell.prototype.getValue = function () {
4340
4341      return this.value;
4342    };
4343
4344    Cell.prototype.getOldValue = function () {
4345
4346      return this.oldValue;
4347    };
4348
4349    //////////////////// Actions ////////////////////
4350
4351
4352    Cell.prototype.setValue = function (value, mutate) {
4353
4354      var changed = this.setValueProcessData(value, mutate);
4355
4356      if (changed) {
4357
4358        if (this.table.options.history && this.table.extExists("history")) {
4359
4360          this.table.extensions.history.action("cellEdit", this, { oldValue: this.oldValue, newValue: this.value });
4361        };
4362
4363        this.table.options.cellEdited(this.getComponent());
4364
4365        this.table.options.dataEdited(this.table.rowManager.getData());
4366      }
4367
4368      if (this.table.extExists("columnCalcs")) {
4369
4370        this.table.extensions.columnCalcs.recalc(this.table.rowManager.displayRows);
4371      }
4372    };
4373
4374    Cell.prototype.setValueProcessData = function (value, mutate) {
4375
4376      var changed = false;
4377
4378      if (this.value != value) {
4379
4380        changed = true;
4381
4382        if (mutate) {
4383
4384          if (this.column.extensions.mutate && this.column.extensions.mutate.type !== "data") {
4385
4386            value = this.table.extensions.mutator.transformCell(this, value);
4387          }
4388        }
4389      }
4390
4391      this.setValueActual(value);
4392
4393      return changed;
4394    };
4395
4396    Cell.prototype.setValueActual = function (value) {
4397
4398      this.oldValue = this.value;
4399
4400      this.value = value;
4401
4402      this.column.setFieldValue(this.row.data, value);
4403
4404      this._generateContents();
4405
4406      this._generateTooltip();
4407
4408      //set resizable handles
4409
4410      if (this.table.options.resizableColumns && this.table.extExists("resizeColumns")) {
4411
4412        this.table.extensions.resizeColumns.initializeColumn("cell", this.column, this.element);
4413      }
4414
4415      //handle frozen cells
4416
4417      if (this.table.extExists("frozenColumns")) {
4418
4419        this.table.extensions.frozenColumns.layoutElement(this.element, this.column);
4420      }
4421    };
4422
4423    Cell.prototype.setWidth = function (width) {
4424
4425      this.width = width;
4426
4427      // this.element.css("width", width || "");
4428
4429      this.element[0].style.width = width ? width + "px" : "";
4430    };
4431
4432    Cell.prototype.getWidth = function () {
4433
4434      return this.width || this.element.outerWidth();
4435    };
4436
4437    Cell.prototype.setMinWidth = function (minWidth) {
4438
4439      this.minWidth = minWidth;
4440
4441      this.element[0].style.minWidth = minWidth ? minWidth + "px" : "";
4442    };
4443
4444    Cell.prototype.checkHeight = function () {
4445
4446      var height = this.element.css("height");
4447
4448      this.row.reinitializeHeight();
4449    };
4450
4451    Cell.prototype.clearHeight = function () {
4452
4453      this.element[0].style.height = "";
4454    };
4455
4456    Cell.prototype.setHeight = function (height) {
4457
4458      this.height = height;
4459
4460      this.element[0].style.height = height ? height + "px" : "";
4461    };
4462
4463    Cell.prototype.getHeight = function () {
4464
4465      return this.height || this.element.outerHeight();
4466    };
4467
4468    Cell.prototype.show = function () {
4469
4470      this.element[0].style.display = "";
4471    };
4472
4473    Cell.prototype.hide = function () {
4474
4475      this.element[0].style.display = "none";
4476    };
4477
4478    Cell.prototype.edit = function () {
4479
4480      this.element.focus();
4481    };
4482
4483    Cell.prototype.delete = function () {
4484
4485      this.element.detach();
4486
4487      this.column.deleteCell(this);
4488
4489      this.row.deleteCell(this);
4490    };
4491
4492    //////////////// Navigation /////////////////
4493
4494
4495    Cell.prototype.nav = function () {
4496
4497      var self = this,
4498          nextCell = false,
4499          index = this.row.getCellIndex(this);
4500
4501      return {
4502
4503        next: function next() {
4504
4505          var nextCell = this.right(),
4506              nextRow;
4507
4508          if (!nextCell) {
4509
4510            nextRow = self.table.rowManager.nextDisplayRow(self.row);
4511
4512            if (nextRow) {
4513
4514              nextCell = nextRow.findNextEditableCell(-1);
4515
4516              if (nextCell) {
4517
4518                nextCell.edit();
4519
4520                return true;
4521              }
4522            }
4523          } else {
4524
4525            return true;
4526          }
4527
4528          return false;
4529        },
4530
4531        prev: function prev() {
4532
4533          var nextCell = this.left(),
4534              prevRow;
4535
4536          if (!nextCell) {
4537
4538            prevRow = self.table.rowManager.prevDisplayRow(self.row);
4539
4540            if (prevRow) {
4541
4542              nextCell = prevRow.findPrevEditableCell(prevRow.cells.length);
4543
4544              if (nextCell) {
4545
4546                nextCell.edit();
4547
4548                return true;
4549              }
4550            }
4551          } else {
4552
4553            return true;
4554          }
4555
4556          return false;
4557        },
4558
4559        left: function left() {
4560
4561          nextCell = self.row.findPrevEditableCell(index);
4562
4563          if (nextCell) {
4564
4565            nextCell.edit();
4566
4567            return true;
4568          } else {
4569
4570            return false;
4571          }
4572        },
4573
4574        right: function right() {
4575
4576          nextCell = self.row.findNextEditableCell(index);
4577
4578          if (nextCell) {
4579
4580            nextCell.edit();
4581
4582            return true;
4583          } else {
4584
4585            return false;
4586          }
4587        },
4588
4589        up: function up() {
4590
4591          var nextRow = self.table.rowManager.prevDisplayRow(self.row);
4592
4593          if (nextRow) {
4594
4595            nextRow.cells[index].edit();
4596          }
4597        },
4598
4599        down: function down() {
4600
4601          var nextRow = self.table.rowManager.nextDisplayRow(self.row);
4602
4603          if (nextRow) {
4604
4605            nextRow.cells[index].edit();
4606          }
4607        }
4608
4609      };
4610    };
4611
4612    Cell.prototype.getIndex = function () {
4613
4614      this.row.getCellIndex(this);
4615    };
4616
4617    //////////////// Object Generation /////////////////
4618
4619    Cell.prototype.getComponent = function () {
4620
4621      return new CellComponent(this);
4622    };
4623
4624    var FooterManager = function FooterManager(table) {
4625
4626      this.table = table;
4627
4628      this.active = false;
4629
4630      this.element = $("<div class='tabulator-footer'></div>"); //containing element
4631
4632      this.links = [];
4633
4634      this._initialize();
4635    };
4636
4637    FooterManager.prototype._initialize = function (element) {
4638
4639      if (this.table.options.footerElement) {
4640
4641        this.element = this.table.options.footerElement;
4642      }
4643    };
4644
4645    FooterManager.prototype.getElement = function () {
4646
4647      return this.element;
4648    };
4649
4650    FooterManager.prototype.append = function (element, parent) {
4651
4652      this.activate(parent);
4653
4654      this.element.append(element);
4655
4656      this.table.rowManager.adjustTableSize();
4657    };
4658
4659    FooterManager.prototype.prepend = function (element, parent) {
4660
4661      this.activate(parent);
4662
4663      this.element.prepend(element);
4664
4665      this.table.rowManager.adjustTableSize();
4666    };
4667
4668    FooterManager.prototype.activate = function (parent) {
4669
4670      if (!this.active) {
4671
4672        this.active = true;
4673
4674        this.table.element.append(this.getElement());
4675      }
4676
4677      if (parent) {
4678
4679        this.links.push(parent);
4680      }
4681    };
4682
4683    FooterManager.prototype.redraw = function () {
4684
4685      this.links.forEach(function (link) {
4686
4687        link.footerRedraw();
4688      });
4689    };
4690
4691    window.Tabulator = {
4692
4693      columnManager: null, // hold Column Manager
4694
4695      rowManager: null, //hold Row Manager
4696
4697      footerManager: null, //holder Footer Manager
4698
4699      browser: "", //hold current browser type
4700
4701      browserSlow: false, //handle reduced functionality for slower browsers
4702
4703
4704      //setup options
4705
4706      options: (_options = {
4707
4708        height: false, //height of tabulator
4709
4710
4711        fitColumns: false, //fit colums to width of screen;
4712
4713        columnMinWidth: 40, //minimum global width for a column
4714
4715        columnVertAlign: "top", //vertical alignment of column headers
4716
4717
4718        resizableColumns: true, //resizable columns
4719
4720
4721        columns: [], //store for colum header info
4722
4723
4724        data: [], //default starting data
4725
4726
4727        tooltips: false, //Tool tip value
4728
4729        tooltipsHeader: false, //Tool tip for headers
4730
4731
4732        initialSort: false, //initial sorting criteria
4733
4734
4735        footerElement: false, //hold footer element
4736
4737
4738        index: "id", //filed for row index
4739
4740
4741        keybindings: [], //array for keybindings
4742
4743
4744        downloadDataMutator: false, //function to manipulate table data before it is downloaded
4745
4746
4747        addRowPos: "bottom", //position to insert blank rows, top|bottom
4748
4749
4750        selectable: "highlight", //highlight rows on hover
4751
4752        selectableRollingSelection: true, //roll selection once maximum number of selectable rows is reached
4753
4754        selectablePersistence: true, // maintain selection when table view is updated
4755
4756        selectableCheck: function selectableCheck(data, row) {
4757          return true;
4758        }, //check wheather row is selectable
4759
4760
4761        headerFilterPlaceholder: false, //placeholder text to display in header filters
4762
4763
4764        history: false, //enable edit history
4765
4766
4767        locale: false, //current system language
4768
4769        langs: {},
4770
4771        virtualDom: true, //enable DOM virtualization
4772
4773
4774        persistentLayout: false, //store cookie with column _styles
4775
4776        persistentLayoutID: "", //id for stored cookie
4777
4778
4779        responsiveLayout: false, //responsive layout flags
4780
4781
4782        pagination: false, //set pagination type
4783
4784        paginationSize: false, //set number of rows to a page
4785
4786        paginationElement: false, //element to hold pagination numbers
4787
4788        paginationDataSent: {}, //pagination data sent to the server
4789
4790        paginationDataReceived: {}, //pagination data received from the server
4791
4792        paginator: false, //pagination url string builder
4793
4794
4795        ajaxURL: false, //url for ajax loading
4796
4797        ajaxParams: {}, //params for ajax loading
4798
4799        ajaxConfig: "get", //ajax request type
4800
4801        ajaxLoader: true, //show loader
4802
4803        ajaxLoaderLoading: false, //loader element
4804
4805        ajaxLoaderError: false, //loader element
4806
4807        ajaxFiltering: false,
4808
4809        ajaxSorting: false,
4810
4811        groupBy: false, //enable table grouping and set field to group by
4812
4813        groupStartOpen: true, //starting state of group
4814
4815
4816        groupHeader: false, //header generation function
4817
4818
4819        movableColumns: false, //enable movable columns
4820
4821        movableRows: false, //enable movable rows
4822
4823
4824        rowFormatter: false,
4825
4826        placeholder: false,
4827
4828        //table building callbacks
4829
4830        tableBuilding: function tableBuilding() {},
4831
4832        tableBuilt: function tableBuilt() {},
4833
4834        //render callbacks
4835
4836        renderStarted: function renderStarted() {},
4837
4838        renderComplete: function renderComplete() {},
4839
4840        //row callbacks
4841
4842        rowClick: false,
4843
4844        rowDblClick: false,
4845
4846        rowContext: false
4847
4848      }, _defineProperty(_options, 'rowContext', false), _defineProperty(_options, 'rowTap', false), _defineProperty(_options, 'rowDblTap', false), _defineProperty(_options, 'rowTapHold', false), _defineProperty(_options, 'rowAdded', function rowAdded() {}), _defineProperty(_options, 'rowDeleted', function rowDeleted() {}), _defineProperty(_options, 'rowMoved', function rowMoved() {}), _defineProperty(_options, 'rowUpdated', function rowUpdated() {}), _defineProperty(_options, 'rowSelectionChanged', function rowSelectionChanged() {}), _defineProperty(_options, 'rowSelected', function rowSelected() {}), _defineProperty(_options, 'rowDeselected', function rowDeselected() {}), _defineProperty(_options, 'cellEditing', function cellEditing() {}), _defineProperty(_options, 'cellEdited', function cellEdited() {}), _defineProperty(_options, 'cellEditCancelled', function cellEditCancelled() {}), _defineProperty(_options, 'columnMoved', function columnMoved() {}), _defineProperty(_options, 'columnResized', function columnResized() {}), _defineProperty(_options, 'columnTitleChanged', function columnTitleChanged() {}), _defineProperty(_options, 'columnVisibilityChanged', function columnVisibilityChanged() {}), _defineProperty(_options, 'htmlImporting', function htmlImporting() {}), _defineProperty(_options, 'htmlImported', function htmlImported() {}), _defineProperty(_options, 'dataLoading', function dataLoading() {}), _defineProperty(_options, 'dataLoaded', function dataLoaded() {}), _defineProperty(_options, 'dataEdited', function dataEdited() {}), _defineProperty(_options, 'ajaxRequesting', function ajaxRequesting() {}), _defineProperty(_options, 'ajaxResponse', false), _defineProperty(_options, 'ajaxError', function ajaxError() {}), _defineProperty(_options, 'dataFiltering', false), _defineProperty(_options, 'dataFiltered', false), _defineProperty(_options, 'dataSorting', function dataSorting() {}), _defineProperty(_options, 'dataSorted', function dataSorted() {}), _defineProperty(_options, 'dataGrouping', function dataGrouping() {}), _defineProperty(_options, 'dataGrouped', false), _defineProperty(_options, 'groupVisibilityChanged', function groupVisibilityChanged() {}), _defineProperty(_options, 'pageLoaded', function pageLoaded() {}), _defineProperty(_options, 'localized', function localized() {}), _options),
4849
4850      //constructor
4851
4852      _create: function _create() {
4853
4854        var self = this,
4855            element = this.element;
4856
4857        self.bindExtensions();
4858
4859        if (element.is("table")) {
4860
4861          if (this.extExists("htmlTableImport", true)) {
4862
4863            self.extensions.htmlTableImport.parseTable();
4864          }
4865        } else {
4866
4867          self.columnManager = new ColumnManager(self);
4868
4869          self.rowManager = new RowManager(self);
4870
4871          self.footerManager = new FooterManager(self);
4872
4873          self.columnManager.setRowManager(self.rowManager);
4874
4875          self.rowManager.setColumnManager(self.columnManager);
4876
4877          self._buildElement();
4878
4879          //give the browser a chance to fully render the table then load first data set if present
4880
4881          // setTimeout(function(){
4882
4883
4884          //load initial data set
4885
4886          this._loadInitialData();
4887
4888          // },20)
4889        }
4890      },
4891
4892      //build tabulator element
4893
4894      _buildElement: function _buildElement() {
4895
4896        var element = this.element,
4897            ext = this.extensions,
4898            options = this.options;
4899
4900        options.tableBuilding();
4901
4902        element.addClass("tabulator").attr("role", "grid").empty();
4903
4904        this._detectBrowser();
4905
4906        //set localization
4907
4908        if (options.headerFilterPlaceholder !== false) {
4909
4910          ext.localize.setHeaderFilterPlaceholder(options.headerFilterPlaceholder);
4911        }
4912
4913        for (var locale in options.langs) {
4914
4915          ext.localize.installLang(locale, options.langs[locale]);
4916        }
4917
4918        ext.localize.setLocale(options.locale);
4919
4920        //configure placeholder element
4921
4922        if (typeof options.placeholder == "string") {
4923
4924          options.placeholder = $("<div class='tabulator-placeholder'><span>" + options.placeholder + "</span></div>");
4925        }
4926
4927        //set table height
4928
4929        if (options.height) {
4930
4931          options.height = isNaN(options.height) ? options.height : options.height + "px";
4932
4933          this.element.css({ "height": options.height });
4934        }
4935
4936        //build table elements
4937
4938        element.append(this.columnManager.getElement());
4939
4940        element.append(this.rowManager.getElement());
4941
4942        if (options.footerElement) {
4943
4944          this.footerManager.activate();
4945        }
4946
4947        if (options.persistentLayout && this.extExists("persistentLayout", true)) {
4948
4949          ext.persistentLayout.initialize(options.persistentLayout, options.persistentLayoutID);
4950
4951          options.columns = ext.persistentLayout.load(options.columns);
4952        }
4953
4954        this.columnManager.setColumns(options.columns);
4955
4956        if (options.initialSort && this.extExists("sort", true)) {
4957
4958          ext.sort.setSort(options.initialSort);
4959        }
4960
4961        if (options.pagination && this.extExists("page", true)) {
4962
4963          ext.page.initialize();
4964        }
4965
4966        if (options.groupBy && this.extExists("groupRows", true)) {
4967
4968          ext.groupRows.initialize();
4969        }
4970
4971        if (this.extExists("ajax")) {
4972
4973          ext.ajax.initialize();
4974        }
4975
4976        if (this.extExists("columnCalcs")) {
4977
4978          ext.columnCalcs.initialize();
4979        }
4980
4981        if (this.extExists("keybindings")) {
4982
4983          ext.keybindings.initialize();
4984        }
4985
4986        if (this.extExists("selectRow")) {
4987
4988          ext.selectRow.clearSelectionData();
4989        }
4990
4991        options.tableBuilt();
4992      },
4993
4994      _loadInitialData: function _loadInitialData() {
4995
4996        var self = this;
4997
4998        if (self.options.pagination && self.extExists("page")) {
4999
5000          self.extensions.page.reset(true);
5001
5002          self.extensions.page.setPage(1);
5003
5004          if (self.options.pagination == "local") {
5005
5006            self.rowManager.setData(self.options.data);
5007          }
5008        } else {
5009
5010          if (self.options.data.length) {
5011
5012            self.rowManager.setData(self.options.data);
5013          } else {
5014
5015            if (self.options.ajaxURL && self.extExists("ajax")) {
5016
5017              self.extensions.ajax.sendRequest(function (data) {
5018
5019                self.rowManager.setData(data);
5020              });
5021            } else {
5022
5023              self.rowManager.setData(self.options.data);
5024            }
5025          }
5026        }
5027      },
5028
5029      //set options
5030
5031      _setOption: function _setOption(option, value) {
5032
5033        console.error("Options Error - Tabulator does not allow options to be set after initialization unless there is a function defined for that purpose");
5034      },
5035
5036      //deconstructor
5037
5038      _destroy: function _destroy() {
5039
5040        var element = this.element;
5041
5042        element.empty();
5043
5044        element.removeClass("tabulator");
5045      },
5046
5047      _detectBrowser: function _detectBrowser() {
5048
5049        var ua = navigator.userAgent;
5050
5051        if (ua.indexOf("Trident") > -1) {
5052
5053          this.brower = "ie";
5054
5055          this.browserSlow = true;
5056        } else if (ua.indexOf("Edge") > -1) {
5057
5058          this.brower = "edge";
5059
5060          this.browserSlow = true;
5061        } else {
5062
5063          this.brower = "other";
5064
5065          this.browserSlow = false;
5066        }
5067      },
5068
5069
5070      ////////////////// Data Handling //////////////////
5071
5072
5073      //load data
5074
5075      setData: function setData(data, params, config) {
5076
5077        var self = this;
5078
5079        var self = this;
5080
5081        if (typeof data === "string") {
5082
5083          if (data.indexOf("{") == 0 || data.indexOf("[") == 0) {
5084
5085            //data is a json encoded string
5086
5087            self.rowManager.setData(JSON.parse(data));
5088          } else {
5089
5090            if (self.extExists("ajax", true)) {
5091
5092              if (params) {
5093
5094                self.extensions.ajax.setParams(params);
5095              }
5096
5097              if (config) {
5098
5099                self.extensions.ajax.setConfig(config);
5100              }
5101
5102              self.extensions.ajax.setUrl(data);
5103
5104              if (self.options.pagination == "remote" && self.extExists("page", true)) {
5105
5106                self.extensions.page.reset(true);
5107
5108                self.extensions.page.setPage(1);
5109              } else {
5110
5111                //assume data is url, make ajax call to url to get data
5112
5113                self.extensions.ajax.sendRequest(function (data) {
5114
5115                  self.rowManager.setData(data);
5116                });
5117              }
5118            }
5119          }
5120        } else {
5121
5122          if (data) {
5123
5124            //asume data is already an object
5125
5126            self.rowManager.setData(data);
5127          } else {
5128
5129            //no data provided, check if ajaxURL is present;
5130
5131            if (self.extExists("ajax") && self.extensions.ajax.getUrl) {
5132
5133              if (self.options.pagination == "remote" && self.extExists("page", true)) {
5134
5135                self.extensions.page.reset(true);
5136
5137                self.extensions.page.setPage(1);
5138              } else {
5139
5140                self.extensions.ajax.sendRequest(function (data) {
5141
5142                  self.rowManager.setData(data);
5143                });
5144              }
5145            } else {
5146
5147              //empty data
5148
5149              self.rowManager.setData([]);
5150            }
5151          }
5152        }
5153      },
5154
5155      //clear data
5156
5157      clearData: function clearData() {
5158
5159        this.rowManager.clearData();
5160      },
5161
5162      //get table data array
5163
5164      getData: function getData(active) {
5165
5166        return this.rowManager.getData(active);
5167      },
5168
5169      //get table data array count
5170
5171      getDataCount: function getDataCount(active) {
5172
5173        return this.rowManager.getDataCount(active);
5174      },
5175
5176      //update table data
5177
5178      updateData: function updateData(data) {
5179
5180        var self = this;
5181
5182        if (data) {
5183
5184          data.forEach(function (item) {
5185
5186            var row = self.rowManager.findRow(item[self.options.index]);
5187
5188            if (row) {
5189
5190              row.updateData(item);
5191            }
5192          });
5193        } else {
5194
5195          console.warn("Update Error - No data provided");
5196        }
5197      },
5198
5199      //update table data
5200
5201      updateOrAddData: function updateOrAddData(data) {
5202
5203        var self = this;
5204
5205        if (data) {
5206
5207          data.forEach(function (item) {
5208
5209            var row = self.rowManager.findRow(item[self.options.index]);
5210
5211            if (row) {
5212
5213              row.updateData(item);
5214            } else {
5215
5216              self.rowManager.addRow(item);
5217            }
5218          });
5219        } else {
5220
5221          console.warn("Update Error - No data provided");
5222        }
5223      },
5224
5225      //get row object
5226
5227      getRow: function getRow(index) {
5228
5229        var row = this.rowManager.findRow(index);
5230
5231        if (row) {
5232
5233          return row.getComponent();
5234        } else {
5235
5236          console.warn("Find Error - No matching row found:", index);
5237
5238          return false;
5239        }
5240      },
5241
5242      //delete row from table
5243
5244      deleteRow: function deleteRow(index) {
5245
5246        var row = this.rowManager.findRow(index);
5247
5248        if (row) {
5249
5250          row.delete();
5251
5252          return true;
5253        } else {
5254
5255          console.warn("Delete Error - No matching row found:", index);
5256
5257          return false;
5258        }
5259      },
5260
5261      //add row to table
5262
5263      addRow: function addRow(data, pos, index) {
5264
5265        return this.rowManager.addRow(data, pos, index).getComponent();
5266      },
5267
5268      //update a row if it exitsts otherwise create it
5269
5270      updateOrAddRow: function updateOrAddRow(index, data) {
5271
5272        var row = this.rowManager.findRow(index);
5273
5274        if (row) {
5275
5276          row.updateData(data);
5277        } else {
5278
5279          row = this.rowManager.addRow(data);
5280        }
5281
5282        return row.getComponent();
5283      },
5284
5285      //update row data
5286
5287      updateRow: function updateRow(index, data) {
5288
5289        var row = this.rowManager.findRow(index);
5290
5291        if (row) {
5292
5293          row.updateData(data);
5294
5295          return row.getComponent();
5296        } else {
5297
5298          console.warn("Update Error - No matching row found:", index);
5299
5300          return false;
5301        }
5302      },
5303
5304      //scroll to row in DOM
5305
5306      scrollToRow: function scrollToRow(index) {
5307
5308        var row = this.rowManager.findRow(index);
5309
5310        if (row) {
5311
5312          return this.rowManager.scrollToRow(row);
5313        } else {
5314
5315          console.warn("Scroll Error - No matching row found:", index);
5316
5317          return false;
5318        }
5319      },
5320
5321      getRows: function getRows(active) {
5322
5323        return this.rowManager.getComponents(active);
5324      },
5325
5326      /////////////// Column Functions  ///////////////
5327
5328
5329      setColumns: function setColumns(definition) {
5330
5331        this.columnManager.setColumns(definition);
5332      },
5333
5334      getColumns: function getColumns() {
5335
5336        return this.columnManager.getComponents();
5337      },
5338
5339      getColumnDefinitions: function getColumnDefinitions() {
5340
5341        return this.columnManager.getDefinitionTree();
5342      },
5343
5344      getColumnLayout: function getColumnLayout() {
5345
5346        if (this.extExists("persistentLayout", true)) {
5347
5348          return this.extensions.persistentLayout.parseColumns(this.columnManager.getColumns());
5349        }
5350      },
5351
5352      setColumnLayout: function setColumnLayout(layout) {
5353
5354        if (this.extExists("persistentLayout", true)) {
5355
5356          this.columnManager.setColumns(this.extensions.persistentLayout.mergeDefinition(this.options.columns, layout));
5357
5358          return true;
5359        }
5360
5361        return false;
5362      },
5363
5364      showColumn: function showColumn(field) {
5365
5366        var column = this.columnManager.findColumn(field);
5367
5368        if (column) {
5369
5370          column.show();
5371        } else {
5372
5373          console.warn("Column Show Error - No matching column found:", field);
5374
5375          return false;
5376        }
5377      },
5378
5379      hideColumn: function hideColumn(field) {
5380
5381        var column = this.columnManager.findColumn(field);
5382
5383        if (column) {
5384
5385          column.hide();
5386        } else {
5387
5388          console.warn("Column Hide Error - No matching column found:", field);
5389
5390          return false;
5391        }
5392      },
5393
5394      toggleColumn: function toggleColumn(field) {
5395
5396        var column = this.columnManager.findColumn(field);
5397
5398        if (column) {
5399
5400          if (column.visible) {
5401
5402            column.hide();
5403          } else {
5404
5405            column.show();
5406          }
5407        } else {
5408
5409          console.warn("Column Visibility Toggle Error - No matching column found:", field);
5410
5411          return false;
5412        }
5413      },
5414
5415      addColumn: function addColumn(definition, before, field) {
5416
5417        var column = this.columnManager.findColumn(field);
5418
5419        this.columnManager.addColumn(definition, before, column);
5420      },
5421
5422      deleteColumn: function deleteColumn(field) {
5423
5424        var column = this.columnManager.findColumn(field);
5425
5426        if (column) {
5427
5428          column.delete();
5429        } else {
5430
5431          console.warn("Column Delete Error - No matching column found:", field);
5432
5433          return false;
5434        }
5435      },
5436
5437      //////////// Localization Functions  ////////////
5438
5439      setLocale: function setLocale(locale) {
5440
5441        this.extensions.localize.setLocale(locale);
5442      },
5443
5444      getLocale: function getLocale() {
5445
5446        return this.extensions.localize.getLocale();
5447      },
5448
5449      getLang: function getLang(locale) {
5450
5451        return this.extensions.localize.getLang(locale);
5452      },
5453
5454      //////////// General Public Functions ////////////
5455
5456
5457      //redraw list without updating data
5458
5459      redraw: function redraw(force) {
5460
5461        this.columnManager.redraw(force);
5462
5463        this.rowManager.redraw(force);
5464      },
5465
5466      setHeight: function setHeight(height) {
5467
5468        this.options.height = isNaN(height) ? height : height + "px";
5469
5470        this.element.css({ "height": this.options.height });
5471
5472        this.rowManager.redraw();
5473      },
5474
5475      ///////////////////// Sorting ////////////////////
5476
5477
5478      //trigger sort
5479
5480      setSort: function setSort(sortList, dir) {
5481
5482        if (this.extExists("sort", true)) {
5483
5484          this.extensions.sort.setSort(sortList, dir);
5485
5486          this.rowManager.sorterRefresh();
5487        }
5488      },
5489
5490      getSort: function getSort() {
5491
5492        if (this.extExists("sort", true)) {
5493
5494          return this.extensions.sort.getSort();
5495        }
5496      },
5497
5498      clearSort: function clearSort() {
5499
5500        if (this.extExists("sort", true)) {
5501
5502          this.extensions.sort.clear();
5503
5504          this.rowManager.sorterRefresh();
5505        }
5506      },
5507
5508      ///////////////////// Filtering ////////////////////
5509
5510
5511      //set standard filters
5512
5513      setFilter: function setFilter(field, type, value) {
5514
5515        if (this.extExists("filter", true)) {
5516
5517          this.extensions.filter.setFilter(field, type, value);
5518
5519          this.rowManager.filterRefresh();
5520        }
5521      },
5522
5523      //add filter to array
5524
5525      addFilter: function addFilter(field, type, value) {
5526
5527        if (this.extExists("filter", true)) {
5528
5529          this.extensions.filter.addFilter(field, type, value);
5530
5531          this.rowManager.filterRefresh();
5532        }
5533      },
5534
5535      //get all filters
5536
5537      getFilter: function getFilter() {
5538
5539        if (this.extExists("filter", true)) {
5540
5541          return this.extensions.filter.getFilter();
5542        }
5543      },
5544
5545      //remove filter from array
5546
5547      removeFilter: function removeFilter(field, type, value) {
5548
5549        if (this.extExists("filter", true)) {
5550
5551          this.extensions.filter.removeFilter(field, type, value);
5552
5553          this.rowManager.filterRefresh();
5554        }
5555      },
5556
5557      //clear filters
5558
5559      clearFilter: function clearFilter(all) {
5560
5561        if (this.extExists("filter", true)) {
5562
5563          this.extensions.filter.clearFilter(all);
5564
5565          this.rowManager.filterRefresh();
5566        }
5567      },
5568
5569      //clear header filters
5570
5571      clearHeaderFilter: function clearHeaderFilter() {
5572
5573        if (this.extExists("filter", true)) {
5574
5575          this.extensions.filter.clearHeaderFilter();
5576
5577          this.rowManager.filterRefresh();
5578        }
5579      },
5580
5581      ///////////////////// Filtering ////////////////////
5582
5583      selectRow: function selectRow(rows) {
5584
5585        if (this.extExists("selectRow", true)) {
5586
5587          this.extensions.selectRow.selectRows(rows);
5588        }
5589      },
5590
5591      deselectRow: function deselectRow(rows) {
5592
5593        if (this.extExists("selectRow", true)) {
5594
5595          this.extensions.selectRow.deselectRows(rows);
5596        }
5597      },
5598
5599      toggleSelectRow: function toggleSelectRow(row) {
5600
5601        if (this.extExists("selectRow", true)) {
5602
5603          this.extensions.selectRow.toggleRow(row);
5604        }
5605      },
5606
5607      getSelectedRows: function getSelectedRows() {
5608
5609        if (this.extExists("selectRow", true)) {
5610
5611          return this.extensions.selectRow.getSelectedRows();
5612        }
5613      },
5614
5615      getSelectedData: function getSelectedData() {
5616
5617        if (this.extExists("selectRow", true)) {
5618
5619          return this.extensions.selectRow.getSelectedData();
5620        }
5621      },
5622
5623      //////////// Pagination Functions  ////////////
5624
5625
5626      setMaxPage: function setMaxPage(max) {
5627
5628        if (this.options.pagination && this.extExists("page")) {
5629
5630          this.extensions.page.setMaxPage(max);
5631        } else {
5632
5633          return false;
5634        }
5635      },
5636
5637      setPage: function setPage(page) {
5638
5639        if (this.options.pagination && this.extExists("page")) {
5640
5641          this.extensions.page.setPage(page);
5642        } else {
5643
5644          return false;
5645        }
5646      },
5647
5648      setPageSize: function setPageSize(size) {
5649
5650        if (this.options.pagination && this.extExists("page")) {
5651
5652          this.extensions.page.setPageSize(size);
5653
5654          this.extensions.page.setPage(1);
5655        } else {
5656
5657          return false;
5658        }
5659      },
5660
5661      previousPage: function previousPage() {
5662
5663        if (this.options.pagination && this.extExists("page")) {
5664
5665          this.extensions.page.previousPage();
5666        } else {
5667
5668          return false;
5669        }
5670      },
5671
5672      nextPage: function nextPage() {
5673
5674        if (this.options.pagination && this.extExists("page")) {
5675
5676          this.extensions.page.nextPage();
5677        } else {
5678
5679          return false;
5680        }
5681      },
5682
5683      getPage: function getPage() {
5684
5685        if (this.options.pagination && this.extExists("page")) {
5686
5687          this.extensions.page.getPage();
5688        } else {
5689
5690          return false;
5691        }
5692      },
5693
5694      getPageMax: function getPageMax() {
5695
5696        if (this.options.pagination && this.extExists("page")) {
5697
5698          this.extensions.page.getPageMax();
5699        } else {
5700
5701          return false;
5702        }
5703      },
5704
5705      ///////////////// Grouping Functions ///////////////
5706
5707
5708      setGroupBy: function setGroupBy(groups) {
5709
5710        if (this.extExists("groupRows", true)) {
5711
5712          this.options.groupBy = groups;
5713
5714          this.extensions.groupRows.initialize();
5715
5716          this.rowManager.refreshActiveData();
5717        } else {
5718
5719          return false;
5720        }
5721      },
5722
5723      setGroupStartOpen: function setGroupStartOpen(values) {
5724
5725        if (this.extExists("groupRows", true)) {
5726
5727          this.options.groupStartOpen = values;
5728
5729          this.extensions.groupRows.initialize();
5730
5731          if (this.options.groupBy) {
5732
5733            this.rowManager.refreshActiveData();
5734          } else {
5735
5736            console.warn("Grouping Update - cant refresh view, no groups have been set");
5737          }
5738        } else {
5739
5740          return false;
5741        }
5742      },
5743
5744      setGroupHeader: function setGroupHeader(values) {
5745
5746        if (this.extExists("groupRows", true)) {
5747
5748          this.options.groupHeader = values;
5749
5750          this.extensions.groupRows.initialize();
5751
5752          if (this.options.groupBy) {
5753
5754            this.rowManager.refreshActiveData();
5755          } else {
5756
5757            console.warn("Grouping Update - cant refresh view, no groups have been set");
5758          }
5759        } else {
5760
5761          return false;
5762        }
5763      },
5764
5765      /////////////// Navigation Management //////////////
5766
5767
5768      navigatePrev: function navigatePrev() {
5769
5770        var cell = false;
5771
5772        if (this.table.extExists("edit", true)) {
5773
5774          cell = this.table.extensions.edit.currentCell;
5775
5776          if (cell) {
5777
5778            e.preventDefault();
5779
5780            return cell.nav().prev();
5781          }
5782        }
5783
5784        return false;
5785      },
5786
5787      navigateNext: function navigateNext() {
5788
5789        var cell = false;
5790
5791        if (this.table.extExists("edit", true)) {
5792
5793          cell = this.table.extensions.edit.currentCell;
5794
5795          if (cell) {
5796
5797            e.preventDefault();
5798
5799            return cell.nav().next();
5800          }
5801        }
5802
5803        return false;
5804      },
5805
5806      navigateLeft: function navigateLeft() {
5807
5808        var cell = false;
5809
5810        if (this.table.extExists("edit", true)) {
5811
5812          cell = this.table.extensions.edit.currentCell;
5813
5814          if (cell) {
5815
5816            e.preventDefault();
5817
5818            return cell.nav().left();
5819          }
5820        }
5821
5822        return false;
5823      },
5824
5825      navigateRight: function navigateRight() {
5826
5827        var cell = false;
5828
5829        if (this.table.extExists("edit", true)) {
5830
5831          cell = this.table.extensions.edit.currentCell;
5832
5833          if (cell) {
5834
5835            e.preventDefault();
5836
5837            return cell.nav().right();
5838          }
5839        }
5840
5841        return false;
5842      },
5843
5844      navigateUp: function navigateUp() {
5845
5846        var cell = false;
5847
5848        if (this.table.extExists("edit", true)) {
5849
5850          cell = this.table.extensions.edit.currentCell;
5851
5852          if (cell) {
5853
5854            e.preventDefault();
5855
5856            return cell.nav().up();
5857          }
5858        }
5859
5860        return false;
5861      },
5862
5863      navigateDown: function navigateDown() {
5864
5865        var cell = false;
5866
5867        if (this.table.extExists("edit", true)) {
5868
5869          cell = this.table.extensions.edit.currentCell;
5870
5871          if (cell) {
5872
5873            e.preventDefault();
5874
5875            return cell.nav().dpwn();
5876          }
5877        }
5878
5879        return false;
5880      },
5881
5882      /////////////// History Management //////////////
5883
5884      undo: function undo() {
5885
5886        if (this.options.history && this.extExists("history", true)) {
5887
5888          return this.extensions.history.undo();
5889        } else {
5890
5891          return false;
5892        }
5893      },
5894
5895      redo: function redo() {
5896
5897        if (this.options.history && this.extExists("history", true)) {
5898
5899          return this.extensions.history.redo();
5900        } else {
5901
5902          return false;
5903        }
5904      },
5905
5906      /////////////// Download Management //////////////
5907
5908
5909      download: function download(type, filename, options) {
5910
5911        if (this.extExists("download", true)) {
5912
5913          this.extensions.download.download(type, filename, options);
5914        }
5915      },
5916
5917      ////////////// Extension Management //////////////
5918
5919
5920      //object to hold extensions
5921
5922      extensions: {},
5923
5924      extensionBindings: {},
5925
5926      //extend extension
5927
5928      extendExtension: function extendExtension(name, property, values) {
5929
5930        if (this.extensionBindings[name]) {
5931
5932          var source = this.extensionBindings[name].prototype[property];
5933
5934          if (source) {
5935
5936            if ((typeof values === 'undefined' ? 'undefined' : _typeof(values)) == "object") {
5937
5938              for (var key in values) {
5939
5940                source[key] = values[key];
5941              }
5942            } else {
5943
5944              console.warn("Extension Error - Invalid value type, it must be an object");
5945            }
5946          } else {
5947
5948            console.warn("Extension Error - property does not exist:", property);
5949          }
5950        } else {
5951
5952          console.warn("Extension Error - extension does not exist:", name);
5953        }
5954      },
5955
5956      //add extension to tabulator
5957
5958      registerExtension: function registerExtension(name, extension) {
5959
5960        var self = this;
5961
5962        this.extensionBindings[name] = extension;
5963      },
5964
5965      //ensure that extensions are bound to instantiated function
5966
5967      bindExtensions: function bindExtensions() {
5968
5969        var self = this;
5970
5971        this.extensions = {};
5972
5973        for (var name in self.extensionBindings) {
5974
5975          self.extensions[name] = new self.extensionBindings[name](self);
5976        }
5977      },
5978
5979      //Check for plugin
5980
5981      extExists: function extExists(plugin, required) {
5982
5983        if (this.extensions[plugin]) {
5984
5985          return true;
5986        } else {
5987
5988          if (required) {
5989
5990            console.error("Tabulator Plugin Not Installed: " + plugin);
5991          }
5992
5993          return false;
5994        }
5995      }
5996
5997    };
5998
5999    var Localize = function Localize(table) {
6000
6001      this.table = table; //hold Tabulator object
6002
6003
6004      this.locale = "default"; //current locale
6005
6006
6007      this.lang = false; //current language
6008
6009
6010      this.bindings = {}; //update events to call when locale is changed
6011
6012    };
6013
6014    //set header placehoder
6015
6016
6017    Localize.prototype.setHeaderFilterPlaceholder = function (placeholder) {
6018
6019      this.langs.default.headerFilters.default = placeholder;
6020    };
6021
6022    //set header filter placeholder by column
6023
6024
6025    Localize.prototype.setHeaderFilterColumnPlaceholder = function (column, placeholder) {
6026
6027      this.langs.default.headerFilters.columns[column] = placeholder;
6028
6029      if (this.lang && !this.lang.headerFilters.columns[column]) {
6030
6031        this.lang.headerFilters.columns[column] = placeholder;
6032      }
6033    };
6034
6035    //setup a lang description object
6036
6037
6038    Localize.prototype.installLang = function (locale, lang) {
6039
6040      if (this.langs[locale]) {
6041
6042        this._setLangProp(this.langs[locale], lang);
6043      } else {
6044
6045        this.langs[locale] = lang;
6046      }
6047    };
6048
6049    Localize.prototype._setLangProp = function (lang, values) {
6050
6051      for (var key in values) {
6052
6053        if (lang[key] && _typeof(lang[key]) == "object") {
6054
6055          this._setLangProp(lang[key], values[key]);
6056        } else {
6057
6058          lang[key] = values[key];
6059        }
6060      }
6061    };
6062
6063    //set current locale
6064
6065
6066    Localize.prototype.setLocale = function (desiredLocale) {
6067
6068      var self = this;
6069
6070      desiredLocale = desiredLocale || "default";
6071
6072      //fill in any matching languge values
6073
6074
6075      function traverseLang(trans, path) {
6076
6077        for (var prop in trans) {
6078
6079          if (_typeof(trans[prop]) == "object") {
6080
6081            if (!path[prop]) {
6082
6083              path[prop] = {};
6084            }
6085
6086            traverseLang(trans[prop], path[prop]);
6087          } else {
6088
6089            path[prop] = trans[prop];
6090          }
6091        }
6092      }
6093
6094      //determing correct locale to load
6095
6096
6097      if (desiredLocale === true && navigator.language) {
6098
6099        //get local from system
6100
6101
6102        desiredLocale = navigator.language.toLowerCase();
6103      }
6104
6105      if (desiredLocale) {
6106
6107        //if locale is not set, check for matching top level locale else use default
6108
6109
6110        if (!self.langs[desiredLocale]) {
6111
6112          var prefix = desiredLocale.split("-")[0];
6113
6114          if (self.langs[prefix]) {
6115
6116            console.warn("Localization Error - Exact matching locale not found, using closest match: ", desiredLocale, prefix);
6117
6118            desiredLocale = prefix;
6119          } else {
6120
6121            console.warn("Localization Error - Matching locale not found, using default: ", desiredLocale);
6122
6123            desiredLocale = "default";
6124          }
6125        }
6126      }
6127
6128      self.locale = desiredLocale;
6129
6130      //load default lang template
6131
6132
6133      self.lang = $.extend(true, {}, self.langs.default);
6134
6135      if (desiredLocale != "default") {
6136
6137        traverseLang(self.langs[desiredLocale], self.lang);
6138      }
6139
6140      self.table.options.localized(self.locale, self.lang);
6141
6142      self._executeBindings();
6143    };
6144
6145    //get current locale
6146
6147
6148    Localize.prototype.getLocale = function (locale) {
6149
6150      return self.locale;
6151    };
6152
6153    //get lang object for given local or current if none provided
6154
6155
6156    Localize.prototype.getLang = function (locale) {
6157
6158      return locale ? this.langs[locale] : this.lang;
6159    };
6160
6161    //get text for current locale
6162
6163
6164    Localize.prototype.getText = function (path, value) {
6165
6166      var path = value ? path + "." + value : path,
6167          pathArray = path.split("."),
6168          text = this._getLangElement(pathArray, this.locale);
6169
6170      // if(text === false){
6171
6172
6173      // 	console.warn("Localization Error - Matching localized text not found for given path: ", path);
6174
6175
6176      // }
6177
6178
6179      return text || "";
6180    };
6181
6182    //traverse langs object and find localized copy
6183
6184
6185    Localize.prototype._getLangElement = function (path, locale) {
6186
6187      var self = this;
6188
6189      var root = self.lang;
6190
6191      path.forEach(function (level) {
6192
6193        var rootPath;
6194
6195        if (root) {
6196
6197          rootPath = root[level];
6198
6199          if (typeof rootPath != "undefined") {
6200
6201            root = rootPath;
6202          } else {
6203
6204            root = false;
6205          }
6206        }
6207      });
6208
6209      return root;
6210    };
6211
6212    //set update binding
6213
6214
6215    Localize.prototype.bind = function (path, callback) {
6216
6217      if (!this.bindings[path]) {
6218
6219        this.bindings[path] = [];
6220      }
6221
6222      this.bindings[path].push(callback);
6223
6224      callback(this.getText(path), this.lang);
6225    };
6226
6227    //itterate through bindings and trigger updates
6228
6229
6230    Localize.prototype._executeBindings = function () {
6231
6232      var self = this;
6233
6234      var _loop = function _loop(path) {
6235
6236        self.bindings[path].forEach(function (binding) {
6237
6238          binding(self.getText(path), self.lang);
6239        });
6240      };
6241
6242      for (var path in self.bindings) {
6243        _loop(path);
6244      }
6245    };
6246
6247    //Localized text listings
6248
6249
6250    Localize.prototype.langs = {
6251
6252      "default": { //hold default locale text
6253
6254
6255        "groups": {
6256
6257          "item": "item",
6258
6259          "items": "items"
6260
6261        },
6262
6263        "columns": {},
6264
6265        "ajax": {
6266
6267          "loading": "Loading",
6268
6269          "error": "Error"
6270
6271        },
6272
6273        "pagination": {
6274
6275          "first": "First",
6276
6277          "first_title": "First Page",
6278
6279          "last": "Last",
6280
6281          "last_title": "Last Page",
6282
6283          "prev": "Prev",
6284
6285          "prev_title": "Prev Page",
6286
6287          "next": "Next",
6288
6289          "next_title": "Next Page"
6290
6291        },
6292
6293        "headerFilters": {
6294
6295          "default": "filter column...",
6296
6297          "columns": {}
6298
6299        }
6300
6301      }
6302
6303    };
6304
6305    Tabulator.registerExtension("localize", Localize);
6306
6307    var Accessor = function Accessor(table) {
6308
6309      this.table = table; //hold Tabulator object
6310
6311    };
6312
6313    //initialize column accessor
6314
6315
6316    Accessor.prototype.initializeColumn = function (column) {
6317
6318      var config = { accessor: false, params: column.definition.accessorParams || {} };
6319
6320      //set column accessor
6321
6322
6323      switch (_typeof(column.definition.accessor)) {
6324
6325        case "string":
6326
6327          if (this.accessors[column.definition.accessor]) {
6328
6329            config.accessor = this.accessors[column.definition.accessor];
6330          } else {
6331
6332            console.warn("Accessor Error - No such accessor found, ignoring: ", column.definition.accessor);
6333          }
6334
6335          break;
6336
6337        case "function":
6338
6339          config.accessor = column.definition.accessor;
6340
6341          break;
6342
6343      }
6344
6345      if (config.accessor) {
6346
6347        column.extensions.accessor = config;
6348      }
6349    },
6350
6351    //apply accessor to row
6352
6353
6354    Accessor.prototype.transformRow = function (dataIn) {
6355
6356      var self = this;
6357
6358      //clone data object with deep copy to isolate internal data from returned result
6359
6360
6361      var data = $.extend(true, {}, dataIn || {});
6362
6363      self.table.columnManager.traverse(function (column) {
6364
6365        var field;
6366
6367        if (column.extensions.accessor) {
6368
6369          field = column.getField();
6370
6371          if (typeof data[field] != "undefined") {
6372
6373            column.setFieldValue(data, column.extensions.accessor.accessor(column.getFieldValue(data), data, column.extensions.accessor.params));
6374          }
6375        }
6376      });
6377
6378      return data;
6379    },
6380
6381    //default accessors
6382
6383
6384    Accessor.prototype.accessors = {};
6385
6386    Tabulator.registerExtension("accessor", Accessor);
6387
6388    var Ajax = function Ajax(table) {
6389
6390      this.table = table; //hold Tabulator object
6391
6392
6393      this.config = false; //hold config object for ajax request
6394
6395
6396      this.url = ""; //request URL
6397
6398
6399      this.params = false; //request parameters
6400
6401
6402      this.loaderElement = $("<div class='tablulator-loader'></div>"); //loader message div
6403
6404
6405      this.msgElement = $("<div class='tabulator-loader-msg' role='alert'></div>"); //message element
6406
6407
6408      this.loadingElement = false;
6409
6410      this.errorElement = false;
6411    };
6412
6413    //initialize setup options
6414
6415
6416    Ajax.prototype.initialize = function () {
6417
6418      this.loaderElement.append(this.msgElement);
6419
6420      if (this.table.options.ajaxLoaderLoading) {
6421
6422        this.loadingElement = this.table.options.ajaxLoaderLoading;
6423      }
6424
6425      if (this.table.options.ajaxLoaderError) {
6426
6427        this.errorElement = this.table.options.ajaxLoaderError;
6428      }
6429
6430      if (this.table.options.ajaxParams) {
6431
6432        this.setParams(this.table.options.ajaxParams);
6433      }
6434
6435      if (this.table.options.ajaxConfig) {
6436
6437        this.setConfig(this.table.options.ajaxConfig);
6438      }
6439
6440      if (this.table.options.ajaxURL) {
6441
6442        this.setUrl(this.table.options.ajaxURL);
6443      }
6444    };
6445
6446    //set ajax params
6447
6448
6449    Ajax.prototype.setParams = function (params, update) {
6450
6451      if (update) {
6452
6453        this.params = this.params || {};
6454
6455        for (var key in params) {
6456
6457          this.params[key] = params[key];
6458        }
6459      } else {
6460
6461        this.params = params;
6462      }
6463    };
6464
6465    Ajax.prototype.getParams = function () {
6466
6467      return this.params || {};
6468    };
6469
6470    //load config object
6471
6472
6473    Ajax.prototype.setConfig = function (config) {
6474
6475      this._loadDefaultConfig();
6476
6477      if (typeof config == "string") {
6478
6479        this.config.type = config;
6480      } else {
6481
6482        for (var key in config) {
6483
6484          this.config[key] = config[key];
6485        }
6486      }
6487    };
6488
6489    //create config object from default
6490
6491
6492    Ajax.prototype._loadDefaultConfig = function (force) {
6493
6494      var self = this;
6495
6496      if (!self.config || force) {
6497
6498        self.config = {};
6499
6500        //load base config from defaults
6501
6502
6503        for (var key in self.defaultConfig) {
6504
6505          self.config[key] = self.defaultConfig[key];
6506        }
6507      }
6508    };
6509
6510    //set request url
6511
6512
6513    Ajax.prototype.setUrl = function (url) {
6514
6515      this.url = url;
6516    };
6517
6518    //get request url
6519
6520
6521    Ajax.prototype.getUrl = function () {
6522
6523      return this.url;
6524    };
6525
6526    //send ajax request
6527
6528
6529    Ajax.prototype.sendRequest = function (callback) {
6530
6531      var self = this;
6532
6533      if (self.url) {
6534
6535        self._loadDefaultConfig();
6536
6537        self.config.url = self.url;
6538
6539        if (self.params) {
6540
6541          self.config.data = self.params;
6542        }
6543
6544        self.table.options.ajaxRequesting(self.url, self.params);
6545
6546        self.showLoader();
6547
6548        $.ajax(self.config).done(function (data) {
6549
6550          if (self.table.options.ajaxResponse) {
6551
6552            data = self.table.options.ajaxResponse(self.url, self.params, data);
6553          }
6554
6555          self.table.options.dataLoaded(data);
6556
6557          callback(data);
6558
6559          self.hideLoader();
6560        }).fail(function (xhr, textStatus, errorThrown) {
6561
6562          console.error("Ajax Load Error - Connection Error: " + xhr.status, errorThrown);
6563
6564          self.table.options.ajaxError(xhr, textStatus, errorThrown);
6565
6566          self.showError();
6567
6568          setTimeout(function () {
6569
6570            self.hideLoader();
6571          }, 3000);
6572        });
6573      } else {
6574
6575        console.warn("Ajax Load Error - No URL Set");
6576
6577        return false;
6578      }
6579    };
6580
6581    Ajax.prototype.showLoader = function () {
6582
6583      this.loaderElement.detach();
6584
6585      this.msgElement.empty().removeClass("tabulator-error").addClass("tabulator-loading");
6586
6587      if (this.loadingElement) {
6588
6589        this.msgElement.append(this.loadingElement);
6590      } else {
6591
6592        this.msgElement.append(this.table.extensions.localize.getText("ajax.loading"));
6593      }
6594
6595      this.table.element.append(this.loaderElement);
6596    };
6597
6598    Ajax.prototype.showError = function () {
6599
6600      this.loaderElement.detach();
6601
6602      this.msgElement.empty().removeClass("tabulator-loading").addClass("tabulator-error");
6603
6604      if (this.errorElement) {
6605
6606        this.msgElement.append(this.errorElement);
6607      } else {
6608
6609        this.msgElement.append(this.table.extensions.localize.getText("ajax.error"));
6610      }
6611
6612      this.table.element.append(this.loaderElement);
6613    };
6614
6615    Ajax.prototype.hideLoader = function () {
6616
6617      this.loaderElement.detach();
6618    };
6619
6620    //default ajax config object
6621
6622
6623    Ajax.prototype.defaultConfig = {
6624
6625      url: "",
6626
6627      type: "GET",
6628
6629      async: true,
6630
6631      dataType: "json",
6632
6633      success: function success(data) {}
6634
6635    };
6636
6637    Tabulator.registerExtension("ajax", Ajax);
6638
6639    var ColumnCalcs = function ColumnCalcs(table) {
6640
6641      this.table = table; //hold Tabulator object
6642
6643
6644      this.topCalcs = [];
6645
6646      this.botCalcs = [];
6647
6648      this.genColumn = false;
6649
6650      this.topElement = $("<div class='tabulator-calcs-holder'></div>");
6651
6652      this.botElement = $("<div class='tabulator-calcs-holder'></div>");
6653
6654      this.topRow = false;
6655
6656      this.botRow = false;
6657
6658      this.topInitialized = false;
6659
6660      this.botInitialized = false;
6661
6662      this.initialize();
6663    };
6664
6665    ColumnCalcs.prototype.initialize = function () {
6666
6667      this.genColumn = new Column({ field: "value" }, this);
6668    };
6669
6670    //dummy functions to handle being mock column manager
6671
6672
6673    ColumnCalcs.prototype.registerColumnField = function () {};
6674
6675    //initialize column calcs
6676
6677
6678    ColumnCalcs.prototype.initializeColumn = function (column) {
6679
6680      var def = column.definition;
6681
6682      var config = {
6683
6684        topCalcParams: def.topCalcParams || {},
6685
6686        botCalcParams: def.bottomCalcParams || {}
6687
6688      };
6689
6690      if (def.topCalc) {
6691
6692        switch (_typeof(def.topCalc)) {
6693
6694          case "string":
6695
6696            if (this.calculations[def.topCalc]) {
6697
6698              config.topCalc = this.calculations[def.topCalc];
6699            } else {
6700
6701              console.warn("Column Calc Error - No such calculation found, ignoring: ", def.topCalc);
6702            }
6703
6704            break;
6705
6706          case "function":
6707
6708            config.topCalc = def.topCalc;
6709
6710            break;
6711
6712        }
6713
6714        if (config.topCalc) {
6715
6716          column.extensions.columnCalcs = config;
6717
6718          this.topCalcs.push(column);
6719
6720          if (!this.table.options.groupBy) {
6721
6722            this.initializeTopRow();
6723          }
6724        }
6725      }
6726
6727      if (def.bottomCalc) {
6728
6729        switch (_typeof(def.bottomCalc)) {
6730
6731          case "string":
6732
6733            if (this.calculations[def.bottomCalc]) {
6734
6735              config.botCalc = this.calculations[def.bottomCalc];
6736            } else {
6737
6738              console.warn("Column Calc Error - No such calculation found, ignoring: ", def.bottomCalc);
6739            }
6740
6741            break;
6742
6743          case "function":
6744
6745            config.botCalc = def.bottomCalc;
6746
6747            break;
6748
6749        }
6750
6751        if (config.botCalc) {
6752
6753          column.extensions.columnCalcs = config;
6754
6755          this.botCalcs.push(column);
6756
6757          if (!this.table.options.groupBy) {
6758
6759            this.initializeBottomRow();
6760          }
6761        }
6762      }
6763    };
6764
6765    ColumnCalcs.prototype.initializeTopRow = function () {
6766
6767      if (!this.topInitialized) {
6768
6769        this.table.columnManager.element.append(this.topElement);
6770
6771        this.topInitialized = true;
6772      }
6773    };
6774
6775    ColumnCalcs.prototype.initializeBottomRow = function () {
6776
6777      if (!this.botInitialized) {
6778
6779        this.table.footerManager.prepend(this.botElement);
6780
6781        this.botInitialized = true;
6782      }
6783    };
6784
6785    ColumnCalcs.prototype.scrollHorizontal = function (left) {
6786
6787      var hozAdjust = 0,
6788          scrollWidth = this.table.columnManager.element[0].scrollWidth - this.table.element.innerWidth();
6789
6790      if (this.botInitialized) {
6791
6792        this.botRow.getElement().css("margin-left", -left);
6793      }
6794    };
6795
6796    ColumnCalcs.prototype.recalc = function (rows) {
6797
6798      var data, row;
6799
6800      if (this.topInitialized || this.botInitialized) {
6801
6802        data = this.rowsToData(rows);
6803
6804        if (this.topInitialized) {
6805
6806          row = this.generateRow("top", this.rowsToData(rows));
6807
6808          this.topRow = row;
6809
6810          this.topElement.empty();
6811
6812          this.topElement.append(row.getElement());
6813
6814          row.initialize(true);
6815        }
6816
6817        if (this.botInitialized) {
6818
6819          row = this.generateRow("bottom", this.rowsToData(rows));
6820
6821          this.botRow = row;
6822
6823          this.botElement.empty();
6824
6825          this.botElement.append(row.getElement());
6826
6827          row.initialize(true);
6828        }
6829
6830        this.table.rowManager.adjustTableSize();
6831
6832        //set resizable handles
6833
6834
6835        if (this.table.extExists("frozenColumns")) {
6836
6837          this.table.extensions.frozenColumns.layout();
6838        }
6839      }
6840    };
6841
6842    //generate top stats row
6843
6844
6845    ColumnCalcs.prototype.generateTopRow = function (rows) {
6846
6847      return this.generateRow("top", this.rowsToData(rows));
6848    };
6849
6850    //generate bottom stats row
6851
6852
6853    ColumnCalcs.prototype.generateBottomRow = function (rows) {
6854
6855      return this.generateRow("bottom", this.rowsToData(rows));
6856    };
6857
6858    ColumnCalcs.prototype.rowsToData = function (rows) {
6859
6860      var data = [];
6861
6862      rows.forEach(function (row) {
6863
6864        data.push(row.getData());
6865      });
6866
6867      return data;
6868    };
6869
6870    //generate stats row
6871
6872
6873    ColumnCalcs.prototype.generateRow = function (pos, data) {
6874
6875      var self = this,
6876          rowData = this.generateRowData(pos, data),
6877          row = new Row(rowData, this);
6878
6879      row.getElement().addClass("tabulator-calcs").addClass("tabulator-calcs-" + pos);
6880
6881      row.type = "calc";
6882
6883      row.generateCells = function () {
6884
6885        var cells = [];
6886
6887        self.table.columnManager.columnsByIndex.forEach(function (column) {
6888
6889          //set field name of mock column
6890
6891
6892          self.genColumn.setField(column.getField());
6893
6894          self.genColumn.hozAlign = column.hozAlign;
6895
6896          //generate cell and assign to correct column
6897
6898
6899          var cell = new Cell(self.genColumn, row);
6900
6901          cell.column = column;
6902
6903          cell.setWidth(column.getWidth());
6904
6905          column.cells.push(cell);
6906
6907          cells.push(cell);
6908        });
6909
6910        this.cells = cells;
6911      };
6912
6913      return row;
6914    };
6915
6916    //generate stats row
6917
6918
6919    ColumnCalcs.prototype.generateRowData = function (pos, data) {
6920
6921      var rowData = {},
6922          calcs = pos == "top" ? this.topCalcs : this.botCalcs,
6923          type = pos == "top" ? "topCalc" : "botCalc";
6924
6925      calcs.forEach(function (column) {
6926
6927        var values = [];
6928
6929        if (column.extensions.columnCalcs && column.extensions.columnCalcs[type]) {
6930
6931          data.forEach(function (item) {
6932
6933            values.push(column.getFieldValue(item));
6934          });
6935
6936          column.setFieldValue(rowData, column.extensions.columnCalcs[type](values, data, column.extensions.columnCalcs[type + "Params"]));
6937        }
6938      });
6939
6940      return rowData;
6941    };
6942
6943    ColumnCalcs.prototype.hasTopCalcs = function () {
6944
6945      return !!this.topCalcs.length;
6946    }, ColumnCalcs.prototype.hasBottomCalcs = function () {
6947
6948      return !!this.botCalcs.length;
6949    },
6950
6951    //handle table redraw
6952
6953
6954    ColumnCalcs.prototype.redraw = function () {
6955
6956      if (this.topRow) {
6957
6958        this.topRow.normalizeHeight(true);
6959      }
6960
6961      if (this.botRow) {
6962
6963        this.botRow.normalizeHeight(true);
6964      }
6965    };
6966
6967    //default calculations
6968
6969
6970    ColumnCalcs.prototype.calculations = {
6971
6972      "avg": function avg(values, data, calcParams) {
6973
6974        var output = 0,
6975            precision = typeof calcParams.precision !== "undefined" ? calcParams.precision : 2;
6976
6977        if (values.length) {
6978
6979          output = values.reduce(function (sum, value) {
6980
6981            return sum + value;
6982          });
6983
6984          output = output / values.length;
6985
6986          output = precision !== false ? output.toFixed(precision) : output;
6987        }
6988
6989        return parseFloat(output).toString();
6990      },
6991
6992      "max": function max(values, data, calcParams) {
6993
6994        var output = null;
6995
6996        values.forEach(function (value) {
6997
6998          if (value > output || output === null) {
6999
7000            output = value;
7001          }
7002        });
7003
7004        return output !== null ? output : "";
7005      },
7006
7007      "min": function min(values, data, calcParams) {
7008
7009        var output = null;
7010
7011        values.forEach(function (value) {
7012
7013          if (value < output || output === null) {
7014
7015            output = value;
7016          }
7017        });
7018
7019        return output !== null ? output : "";
7020      },
7021
7022      "sum": function sum(values, data, calcParams) {
7023
7024        var output = 0;
7025
7026        if (values.length) {
7027
7028          values.forEach(function (value) {
7029
7030            output += !isNaN(value) ? Number(value) : 0;
7031          });
7032        }
7033
7034        return output;
7035      },
7036
7037      "concat": function concat(values, data, calcParams) {
7038
7039        var output = 0;
7040
7041        if (values.length) {
7042
7043          output = values.reduce(function (sum, value) {
7044
7045            return String(sum) + String(value);
7046          });
7047        }
7048
7049        return output;
7050      },
7051
7052      "count": function count(values, data, calcParams) {
7053
7054        var output = 0;
7055
7056        if (values.length) {
7057
7058          values.forEach(function (value) {
7059
7060            if (value) {
7061
7062              output++;
7063            }
7064          });
7065        }
7066
7067        return output;
7068      }
7069
7070    };
7071
7072    Tabulator.registerExtension("columnCalcs", ColumnCalcs);
7073
7074    var Download = function Download(table) {
7075
7076      this.table = table; //hold Tabulator object
7077
7078
7079      this.fields = {}; //hold filed multi dimension arrays
7080
7081    };
7082
7083    //trigger file download
7084
7085
7086    Download.prototype.download = function (type, filename, options) {
7087
7088      var self = this,
7089          downloadFunc = false;
7090
7091      function buildLink(data, mime) {
7092
7093        self.triggerDownload(data, mime, type, filename);
7094      }
7095
7096      if (typeof type == "function") {
7097
7098        downloadFunc = type;
7099      } else {
7100
7101        if (self.downloaders[type]) {
7102
7103          downloadFunc = self.downloaders[type];
7104        } else {
7105
7106          console.warn("Download Error - No such download type found: ", type);
7107        }
7108      }
7109
7110      if (downloadFunc) {
7111
7112        downloadFunc.call(this, self.processDefinitions(), self.processData(), options, buildLink);
7113      }
7114    };
7115
7116    Download.prototype.processDefinitions = function () {
7117
7118      var self = this,
7119          definitions = self.table.columnManager.getDefinitions(),
7120          processedDefinitions = [];
7121
7122      self.fields = {};
7123
7124      definitions.forEach(function (column) {
7125
7126        if (column.field) {
7127
7128          self.fields[column.field] = column.field.split(".");
7129
7130          if (column.download !== false) {
7131
7132            processedDefinitions.push(column);
7133          }
7134        }
7135      });
7136
7137      return processedDefinitions;
7138    };
7139
7140    Download.prototype.processData = function () {
7141
7142      var self = this,
7143          data = self.table.rowManager.getData(true);
7144
7145      //add user data processing step;
7146
7147
7148      if (typeof self.table.options.downloadDataMutator == "function") {
7149
7150        data = self.table.options.downloadDataMutator(data);
7151      }
7152
7153      return data;
7154    };
7155
7156    Download.prototype.triggerDownload = function (data, mime, type, filename) {
7157
7158      var element = document.createElement('a'),
7159          blob = new Blob([data], { type: mime }),
7160          filename = filename || "Tabulator." + (typeof type === "function" ? "txt" : type);
7161
7162      if (navigator.msSaveOrOpenBlob) {
7163
7164        navigator.msSaveOrOpenBlob(blob, filename);
7165      } else {
7166
7167        element.setAttribute('href', window.URL.createObjectURL(blob));
7168
7169        //set file title
7170
7171
7172        element.setAttribute('download', filename);
7173
7174        //trigger download
7175
7176
7177        element.style.display = 'none';
7178
7179        document.body.appendChild(element);
7180
7181        element.click();
7182
7183        //remove temporary link element
7184
7185
7186        document.body.removeChild(element);
7187      }
7188    };
7189
7190    //nested field lookup
7191
7192
7193    Download.prototype.getFieldValue = function (field, data) {
7194
7195      var dataObj = data,
7196          structure = this.fields[field],
7197          length = structure.length,
7198          output;
7199
7200      for (var i = 0; i < length; i++) {
7201
7202        dataObj = dataObj[structure[i]];
7203
7204        output = dataObj;
7205
7206        if (!dataObj) {
7207
7208          break;
7209        }
7210      }
7211
7212      return output;
7213    };
7214
7215    //downloaders
7216
7217
7218    Download.prototype.downloaders = {
7219
7220      csv: function csv(columns, data, options, setFileContents) {
7221
7222        var self = this,
7223            titles = [],
7224            fields = [],
7225            delimiter = options && options.delimiter ? options.delimiter : ",",
7226            fileContents;
7227
7228        //get field lists
7229
7230
7231        columns.forEach(function (column) {
7232
7233          if (column.field) {
7234
7235            titles.push('"' + String(column.title).split('"').join('""') + '"');
7236
7237            fields.push(column.field);
7238          }
7239        });
7240
7241        //generate header row
7242
7243
7244        fileContents = [titles.join(delimiter)];
7245
7246        //generate each row of the table
7247
7248
7249        data.forEach(function (row) {
7250
7251          var rowData = [];
7252
7253          fields.forEach(function (field) {
7254
7255            var value = self.getFieldValue(field, row);
7256
7257            switch (typeof value === 'undefined' ? 'undefined' : _typeof(value)) {
7258
7259              case "object":
7260
7261                value = JSON.stringify(value);
7262
7263                break;
7264
7265              case "undefined":
7266
7267              case "null":
7268
7269                value = "";
7270
7271                break;
7272
7273              default:
7274
7275                value = value;
7276
7277            }
7278
7279            //escape uotation marks
7280
7281
7282            rowData.push('"' + String(value).split('"').join('""') + '"');
7283          });
7284
7285          fileContents.push(rowData.join(delimiter));
7286        });
7287
7288        setFileContents(fileContents.join("\n"), "text/csv");
7289      },
7290
7291      json: function json(columns, data, options, setFileContents) {
7292
7293        var fileContents = JSON.stringify(data, null, '\t');
7294
7295        setFileContents(fileContents, "application/json");
7296      },
7297
7298      xlsx: function xlsx(columns, data, options, setFileContents) {
7299
7300        var self = this,
7301            titles = [],
7302            fields = [],
7303            rows = [],
7304            workbook = { SheetNames: ["Sheet1"], Sheets: {} },
7305            worksheet,
7306            output;
7307
7308        //convert rows to worksheet
7309
7310
7311        function rowsToSheet() {
7312
7313          var sheet = {};
7314
7315          var range = { s: { c: 0, r: 0 }, e: { c: fields.length, r: rows.length } };
7316
7317          rows.forEach(function (row, i) {
7318
7319            row.forEach(function (value, j) {
7320
7321              var cell = { v: typeof value == "undefined" || value === null ? "" : value };
7322
7323              if (cell != null) {
7324
7325                switch (_typeof(cell.v)) {
7326
7327                  case "number":
7328
7329                    cell.t = 'n';
7330
7331                    break;
7332
7333                  case "boolean":
7334
7335                    cell.t = 'b';
7336
7337                    break;
7338
7339                  default:
7340
7341                    cell.t = 's';
7342
7343                    break;
7344
7345                }
7346
7347                sheet[XLSX.utils.encode_cell({ c: j, r: i })] = cell;
7348              }
7349            });
7350          });
7351
7352          sheet['!ref'] = XLSX.utils.encode_range(range);
7353
7354          return sheet;
7355        }
7356
7357        //convert workbook to binary array
7358
7359
7360        function s2ab(s) {
7361
7362          var buf = new ArrayBuffer(s.length);
7363
7364          var view = new Uint8Array(buf);
7365
7366          for (var i = 0; i != s.length; ++i) {
7367            view[i] = s.charCodeAt(i) & 0xFF;
7368          }return buf;
7369        }
7370
7371        //get field lists
7372
7373
7374        columns.forEach(function (column) {
7375
7376          if (column.field) {
7377
7378            titles.push(column.title);
7379
7380            fields.push(column.field);
7381          }
7382        });
7383
7384        rows.push(titles);
7385
7386        //generate each row of the table
7387
7388
7389        data.forEach(function (row) {
7390
7391          var rowData = [];
7392
7393          fields.forEach(function (field) {
7394
7395            rowData.push(self.getFieldValue(field, row));
7396          });
7397
7398          rows.push(rowData);
7399        });
7400
7401        worksheet = rowsToSheet();
7402
7403        workbook.Sheets["Sheet1"] = worksheet;
7404
7405        output = XLSX.write(workbook, { bookType: 'xlsx', bookSST: true, type: 'binary' });
7406
7407        setFileContents(s2ab(output), "application/octet-stream");
7408      }
7409
7410    };
7411
7412    Tabulator.registerExtension("download", Download);
7413
7414    var Edit = function Edit(table) {
7415
7416      this.table = table; //hold Tabulator object
7417
7418
7419      this.currentCell = false; //hold currently editing cell
7420
7421    };
7422
7423    //initialize column editor
7424
7425
7426    Edit.prototype.initializeColumn = function (column) {
7427
7428      var self = this,
7429          config = {
7430
7431        editor: false,
7432
7433        blocked: false,
7434
7435        check: column.definition.editable,
7436
7437        params: column.definition.editorParams || {}
7438
7439      };
7440
7441      //set column editor
7442
7443
7444      switch (_typeof(column.definition.editor)) {
7445
7446        case "string":
7447
7448          if (self.editors[column.definition.editor]) {
7449
7450            config.editor = self.editors[column.definition.editor];
7451          } else {
7452
7453            console.warn("Editor Error - No such editor found: ", column.definition.editor);
7454          }
7455
7456          break;
7457
7458        case "function":
7459
7460          config.editor = column.definition.editor;
7461
7462          break;
7463
7464        case "boolean":
7465
7466          if (column.definition.editor === true) {
7467
7468            if (typeof column.definition.formatter !== "function") {
7469
7470              if (self.editors[column.definition.formatter]) {
7471
7472                config.editor = self.editors[column.definition.formatter];
7473              } else {
7474
7475                config.editor = self.editors["input"];
7476              }
7477            } else {
7478
7479              console.warn("Editor Error - Cannot auto lookup editor for a custom formatter: ", column.definition.formatter);
7480            }
7481          }
7482
7483          break;
7484
7485      }
7486
7487      if (config.editor) {
7488
7489        column.extensions.edit = config;
7490      }
7491    };
7492
7493    Edit.prototype.getCurrentCell = function () {
7494
7495      return this.currentCell ? this.currentCell.getComponent() : false;
7496    };
7497
7498    Edit.prototype.clearEditor = function (cell) {
7499
7500      this.currentCell = false;
7501
7502      cell.getElement().removeClass("tabulator-editing").empty();
7503
7504      cell.row.getElement().removeClass("tabulator-row-editing");
7505    };
7506
7507    //return a formatted value for a cell
7508
7509
7510    Edit.prototype.bindEditor = function (cell) {
7511
7512      var self = this,
7513          element = cell.getElement(),
7514          mouseClick = false;
7515
7516      //handle successfull value change
7517
7518
7519      function success(value) {
7520
7521        self.clearEditor(cell);
7522
7523        cell.setValue(value, true);
7524      };
7525
7526      //handle aborted edit
7527
7528
7529      function cancel() {
7530
7531        self.clearEditor(cell);
7532
7533        cell.setValueActual(cell.getValue());
7534
7535        self.table.options.cellEditCancelled(cell.getComponent());
7536      };
7537
7538      element.attr("tabindex", 0);
7539
7540      element.on("click", function (e) {
7541
7542        if (!$(this).hasClass("tabulator-editing")) {
7543
7544          $(this).focus();
7545        }
7546      });
7547
7548      element.on("mousedown", function (e) {
7549
7550        mouseClick = true;
7551      });
7552
7553      element.on("focus", function (e) {
7554
7555        var rendered = function rendered() {},
7556            allowEdit = true,
7557            cellEditor;
7558
7559        self.currentCell = cell;
7560
7561        if (mouseClick) {
7562
7563          mouseClick = false;
7564
7565          if (cell.column.cellEvents.cellClick) {
7566
7567            cell.column.cellEvents.cellClick(e, cell.getComponent());
7568          }
7569        }
7570
7571        function onRendered(callback) {
7572
7573          rendered = callback;
7574        }
7575
7576        if (!cell.column.extensions.edit.blocked) {
7577
7578          e.stopPropagation();
7579
7580          if (typeof cell.column.extensions.edit.check == "function") {
7581
7582            allowEdit = cell.column.extensions.edit.check(cell.getComponent());
7583          }
7584
7585          if (allowEdit) {
7586
7587            self.table.options.cellEditing(cell.getComponent());
7588
7589            cellEditor = cell.column.extensions.edit.editor.call(self, cell.getComponent(), onRendered, success, cancel, cell.column.extensions.edit.params);
7590
7591            //if editor returned, add to DOM, if false, abort edit
7592
7593
7594            if (cellEditor !== false) {
7595
7596              element.addClass("tabulator-editing");
7597
7598              cell.row.getElement().addClass("tabulator-row-editing");
7599
7600              element.empty();
7601
7602              element.append(cellEditor);
7603
7604              //trigger onRendered Callback
7605
7606
7607              rendered();
7608
7609              //prevent editing from triggering rowClick event
7610
7611
7612              element.children().click(function (e) {
7613
7614                e.stopPropagation();
7615              });
7616            } else {
7617
7618              element.blur();
7619            }
7620          } else {
7621
7622            element.blur();
7623          }
7624        } else {
7625
7626          element.blur();
7627        }
7628      });
7629    };
7630
7631    //default data editors
7632
7633
7634    Edit.prototype.editors = {
7635
7636      //input element
7637
7638
7639      input: function input(cell, onRendered, success, cancel, editorParams) {
7640
7641        //create and style input
7642
7643
7644        var input = $("<input type='text'/>");
7645
7646        input.css({
7647
7648          "padding": "4px",
7649
7650          "width": "100%",
7651
7652          "box-sizing": "border-box"
7653
7654        }).val(cell.getValue());
7655
7656        onRendered(function () {
7657
7658          input.focus();
7659
7660          input.css("height", "100%");
7661        });
7662
7663        //submit new value on blur
7664
7665
7666        input.on("change blur", function (e) {
7667
7668          if (input.val() != cell.getValue()) {
7669
7670            success(input.val());
7671          } else {
7672
7673            cancel();
7674          }
7675        });
7676
7677        //submit new value on enter
7678
7679
7680        input.on("keydown", function (e) {
7681
7682          if (e.keyCode == 13) {
7683
7684            success(input.val());
7685          }
7686        });
7687
7688        return input;
7689      },
7690
7691      //resizable text area element
7692
7693
7694      textarea: function textarea(cell, onRendered, success, cancel, editorParams) {
7695
7696        var self = this,
7697            cellValue = cell.getValue(),
7698            value = String(typeof cellValue == "null" || typeof cellValue == "undefined" ? "" : cellValue),
7699            count = (value.match(/(?:\r\n|\r|\n)/g) || []).length + 1,
7700            input = $("<textarea></textarea>"),
7701            scrollHeight = 0;
7702
7703        //create and style input
7704
7705
7706        input.css({
7707
7708          "display": "block",
7709
7710          "height": "100%",
7711
7712          "width": "100%",
7713
7714          "padding": "2px",
7715
7716          "box-sizing": "border-box",
7717
7718          "white-space": "pre-wrap",
7719
7720          "resize": "none"
7721
7722        }).val(value);
7723
7724        onRendered(function () {
7725
7726          input.focus();
7727
7728          input.css("height", "100%");
7729        });
7730
7731        //submit new value on blur
7732
7733
7734        input.on("change blur", function (e) {
7735
7736          if (input.val() != cell.getValue()) {
7737
7738            success(input.val());
7739
7740            setTimeout(function () {
7741
7742              cell.getRow().normalizeHeight();
7743            }, 300);
7744          } else {
7745
7746            cancel();
7747          }
7748        });
7749
7750        input.on("keyup", function () {
7751
7752          input.css({ "height": "" });
7753
7754          var heightNow = input[0].scrollHeight;
7755
7756          input.css({ "height": heightNow });
7757
7758          if (heightNow != scrollHeight) {
7759
7760            scrollHeight = heightNow;
7761
7762            cell.getRow().normalizeHeight();
7763          }
7764        });
7765
7766        return input;
7767      },
7768
7769      //input element with type of number
7770
7771
7772      number: function number(cell, onRendered, success, cancel, editorParams) {
7773
7774        var input = $("<input type='number'/>");
7775
7776        //create and style input
7777
7778
7779        input.css({
7780
7781          "padding": "4px",
7782
7783          "width": "100%",
7784
7785          "box-sizing": "border-box"
7786
7787        }).val(cell.getValue());
7788
7789        onRendered(function () {
7790
7791          input.focus();
7792
7793          input.css("height", "100%");
7794        });
7795
7796        //submit new value on blur
7797
7798
7799        input.on("blur", function (e) {
7800
7801          var value = input.val();
7802
7803          if (!isNaN(value)) {
7804
7805            value = Number(value);
7806          }
7807
7808          if (value != cell.getValue()) {
7809
7810            success(value);
7811          } else {
7812
7813            cancel();
7814          }
7815        });
7816
7817        //submit new value on enter
7818
7819
7820        input.on("keydown", function (e) {
7821
7822          var value;
7823
7824          if (e.keyCode == 13) {
7825
7826            value = input.val();
7827
7828            if (!isNaN(value)) {
7829
7830              value = Number(value);
7831            }
7832
7833            success(value);
7834          }
7835        });
7836
7837        return input;
7838      },
7839
7840      //start rating
7841
7842
7843      star: function star(cell, onRendered, success, cancel, editorParams) {
7844
7845        var element = cell.getElement(),
7846            value = cell.getValue(),
7847            maxStars = $("svg", element).length || 5,
7848            size = $("svg:first", element).attr("width") || 14,
7849            stars = $("<div style='vertical-align:middle; padding:4px; display:inline-block; vertical-align:middle;'></div>"),
7850            starActive = $('<svg width="' + size + '" height="' + size + '" class="tabulator-star-active" viewBox="0 0 512 512" xml:space="preserve" style="padding:0 1px;"><polygon fill="#488CE9" stroke="#014AAE" stroke-width="37.6152" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 "/></svg>'),
7851            starInactive = $('<svg width="' + size + '" height="' + size + '" class="tabulator-star-inactive" viewBox="0 0 512 512" xml:space="preserve" style="padding:0 1px;"><polygon fill="#010155" stroke="#686868" stroke-width="37.6152" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 "/></svg>');
7852
7853        //change number of active stars
7854
7855
7856        var starChange = function starChange(element) {
7857
7858          if ($(".tabulator-star-active", element.closest("div")).length != element.prevAll("svg").length + 1) {
7859
7860            element.prevAll("svg").replaceWith(starActive.clone());
7861
7862            element.nextAll("svg").replaceWith(starInactive.clone());
7863
7864            element.replaceWith(starActive.clone());
7865          }
7866        };
7867
7868        value = parseInt(value) < maxStars ? parseInt(value) : maxStars;
7869
7870        for (var i = 1; i <= maxStars; i++) {
7871
7872          var nextStar = i <= value ? starActive : starInactive;
7873
7874          stars.append(nextStar.clone());
7875        }
7876
7877        stars.on("mouseover", "svg", function (e) {
7878
7879          e.stopPropagation();
7880
7881          starChange($(this));
7882        });
7883
7884        stars.on("mouseover", function (e) {
7885
7886          $("svg", $(this)).replaceWith(starInactive.clone());
7887        });
7888
7889        stars.on("click", function (e) {
7890
7891          success(0);
7892        });
7893
7894        stars.on("click", "svg", function (e) {
7895
7896          e.stopPropagation();
7897
7898          success($(this).prevAll("svg").length + 1);
7899        });
7900
7901        element.css({
7902
7903          "white-space": "nowrap",
7904
7905          "overflow": "hidden",
7906
7907          "text-overflow": "ellipsis"
7908
7909        });
7910
7911        element.on("blur", function () {
7912
7913          cancel();
7914        });
7915
7916        //allow key based navigation
7917
7918
7919        element.on("keydown", function (e) {
7920
7921          switch (e.keyCode) {
7922
7923            case 39:
7924              //right arrow
7925
7926
7927              starChange($(".tabulator-star-inactive:first", stars));
7928
7929              break;
7930
7931            case 37:
7932              //left arrow
7933
7934
7935              var prevstar = $(".tabulator-star-active:last", stars).prev("svg");
7936
7937              if (prevstar.length) {
7938
7939                starChange(prevstar);
7940              } else {
7941
7942                $("svg", stars).replaceWith(starInactive.clone());
7943              }
7944
7945              break;
7946
7947            case 13:
7948              //enter
7949
7950
7951              success($(".tabulator-star-active", stars).length);
7952
7953              break;
7954
7955          }
7956        });
7957
7958        return stars;
7959      },
7960
7961      //draggable progress bar
7962
7963
7964      progress: function progress(cell, onRendered, success, cancel, editorParams) {
7965
7966        var element = cell.getElement(),
7967            max = $("div", element).data("max"),
7968            min = $("div", element).data("min"),
7969            percent = (max - min) / 100,
7970            value = cell.getValue() || 0,
7971            handle = $("<div class='tabulator-progress-handle' style='position:absolute; right:0; top:0; bottom:0; width:5px;'></div>"),
7972            bar;
7973
7974        var newVal = function newVal() {
7975
7976          var calcVal = percent * Math.round(bar.outerWidth() / (element.width() / 100)) + min;
7977
7978          success(calcVal);
7979
7980          element.attr("aria-valuenow", calcVal).attr("aria-label", value);
7981        };
7982
7983        //make sure value is in range
7984
7985
7986        value = parseFloat(value) <= max ? parseFloat(value) : max;
7987
7988        value = parseFloat(value) >= min ? parseFloat(value) : min;
7989
7990        //workout percentage
7991
7992
7993        value = 100 - Math.round((value - min) / percent);
7994
7995        bar = $("<div style='position:absolute; top:8px; bottom:8px; left:4px; right:" + value + "%; margin-right:4px; background-color:#488CE9; display:inline-block; max-width:100%; min-width:0%;' data-max='" + max + "' data-min='" + min + "'></div>"), element.css({
7996
7997          padding: "0 4px"
7998
7999        });
8000
8001        element.attr("aria-valuemin", min).attr("aria-valuemax", max);
8002
8003        bar.append(handle);
8004
8005        handle.on("mousedown", function (e) {
8006
8007          bar.data("mouseDrag", e.screenX);
8008
8009          bar.data("mouseDragWidth", bar.outerWidth());
8010        });
8011
8012        handle.on("mouseover", function () {
8013          $(this).css({ cursor: "ew-resize" });
8014        });
8015
8016        element.on("mousemove", function (e) {
8017
8018          if (bar.data("mouseDrag")) {
8019
8020            bar.css({ width: bar.data("mouseDragWidth") + (e.screenX - bar.data("mouseDrag")) });
8021          }
8022        });
8023
8024        element.on("mouseup", function (e) {
8025
8026          if (bar.data("mouseDrag")) {
8027
8028            e.stopPropagation();
8029
8030            e.stopImmediatePropagation();
8031
8032            bar.data("mouseDragOut", true);
8033
8034            bar.data("mouseDrag", false);
8035
8036            bar.data("mouseDragWidth", false);
8037
8038            newVal();
8039          }
8040        });
8041
8042        //allow key based navigation
8043
8044
8045        element.on("keydown", function (e) {
8046
8047          switch (e.keyCode) {
8048
8049            case 39:
8050              //right arrow
8051
8052
8053              bar.css({ "width": bar.width() + element.width() / 100 });
8054
8055              break;
8056
8057            case 37:
8058              //left arrow
8059
8060
8061              bar.css({ "width": bar.width() - element.width() / 100 });
8062
8063              break;
8064
8065            case 13:
8066              //enter
8067
8068
8069              newVal();
8070
8071              break;
8072
8073          }
8074        });
8075
8076        element.on("blur", function () {
8077
8078          cancel();
8079        });
8080
8081        return bar;
8082      },
8083
8084      //checkbox
8085
8086
8087      tickCross: function tickCross(cell, onRendered, success, cancel, editorParams) {
8088
8089        var value = cell.getValue(),
8090            input = $("<input type='checkbox'/>");
8091
8092        //create and style input
8093
8094
8095        input.css({
8096
8097          "margin-top": "5px",
8098
8099          "box-sizing": "border-box"
8100
8101        }).val(value);
8102
8103        onRendered(function () {
8104
8105          input.focus();
8106        });
8107
8108        if (value === true || value === "true" || value === "True" || value === 1) {
8109
8110          input.prop("checked", true);
8111        } else {
8112
8113          input.prop("checked", false);
8114        }
8115
8116        //submit new value on blur
8117
8118
8119        input.on("change blur", function (e) {
8120
8121          success(input.is(":checked"));
8122        });
8123
8124        //submit new value on enter
8125
8126
8127        input.on("keydown", function (e) {
8128
8129          if (e.keyCode == 13) {
8130
8131            success(input.is(":checked"));
8132          }
8133        });
8134
8135        return input;
8136      },
8137
8138      //checkbox
8139
8140
8141      tick: function tick(cell, onRendered, success, cancel, editorParams) {
8142
8143        var value = cell.getValue(),
8144            input = $("<input type='checkbox'/>");
8145
8146        //create and style input
8147
8148
8149        input.css({
8150
8151          "margin-top": "5px",
8152
8153          "box-sizing": "border-box"
8154
8155        }).val(value);
8156
8157        onRendered(function () {
8158
8159          input.focus();
8160        });
8161
8162        if (value === true || value === "true" || value === "True" || value === 1) {
8163
8164          input.prop("checked", true);
8165        } else {
8166
8167          input.prop("checked", false);
8168        }
8169
8170        //submit new value on blur
8171
8172
8173        input.on("change blur", function (e) {
8174
8175          success(input.is(":checked"));
8176        });
8177
8178        //submit new value on enter
8179
8180
8181        input.on("keydown", function (e) {
8182
8183          if (e.keyCode == 13) {
8184
8185            success(input.is(":checked"));
8186          }
8187        });
8188
8189        return input;
8190      }
8191
8192    };
8193
8194    Tabulator.registerExtension("edit", Edit);
8195
8196    var Filter = function Filter(table) {
8197
8198      this.table = table; //hold Tabulator object
8199
8200
8201      this.filterList = []; //hold filter list
8202
8203
8204      this.headerFilters = {}; //hold column filters
8205
8206
8207      this.headerFilterElements = []; //hold header filter elements for manipulation
8208
8209
8210      this.changed = false; //has filtering changed since last render
8211
8212    };
8213
8214    //initialize column header filter
8215
8216
8217    Filter.prototype.initializeColumn = function (column) {
8218
8219      var self = this,
8220          field = column.getField(),
8221          filterElement,
8222          editor,
8223          editorElement,
8224          cellWrapper,
8225          typingTimer,
8226          tagType,
8227          attrType;
8228
8229      //handle successfull value change
8230
8231
8232      function success(value) {
8233
8234        var filterType = tagType == "input" && attrType == "text" ? "partial" : "match",
8235            filterFunc;
8236
8237        if (value) {
8238
8239          switch (_typeof(column.definition.headerFilterFunc)) {
8240
8241            case "string":
8242
8243              if (self.filters[column.definition.headerFilterFunc]) {
8244
8245                filterFunc = function filterFunc(data) {
8246
8247                  return self.filters[column.definition.headerFilterFunc](value, column.getFieldValue(data));
8248                };
8249              } else {
8250
8251                console.warn("Header Filter Error - Matching filter function not found: ", column.definition.headerFilterFunc);
8252              }
8253
8254              break;
8255
8256            case "function":
8257
8258              filterFunc = function filterFunc(data) {
8259
8260                return column.definition.headerFilterFunc(value, column.getFieldValue(data), data, column.definition.headerFilterFuncParams || {});
8261              };
8262
8263              break;
8264
8265          }
8266
8267          if (!filterFunc) {
8268
8269            switch (filterType) {
8270
8271              case "partial":
8272
8273                filterFunc = function filterFunc(data) {
8274
8275                  return String(column.getFieldValue(data)).toLowerCase().indexOf(String(value).toLowerCase()) > -1;
8276                };
8277
8278                break;
8279
8280              default:
8281
8282                filterFunc = function filterFunc(data) {
8283
8284                  return column.getFieldValue(data) == value;
8285                };
8286
8287            }
8288          }
8289
8290          self.headerFilters[field] = { value: value, func: filterFunc };
8291        } else {
8292
8293          delete self.headerFilters[field];
8294        }
8295
8296        self.changed = true;
8297
8298        self.table.rowManager.filterRefresh();
8299      };
8300
8301      //handle aborted edit
8302
8303
8304      function cancel() {};
8305
8306      if (field) {
8307
8308        filterElement = $("<div class='tabulator-header-filter'></div>");
8309
8310        //set column editor
8311
8312
8313        switch (_typeof(column.definition.headerFilter)) {
8314
8315          case "string":
8316
8317            if (self.table.extensions.edit.editors[column.definition.headerFilter]) {
8318
8319              editor = self.table.extensions.edit.editors[column.definition.headerFilter];
8320            } else {
8321
8322              console.warn("Filter Error - Cannot build header filter, No such editor found: ", column.definition.editor);
8323            }
8324
8325            break;
8326
8327          case "function":
8328
8329            editor = column.definition.headerFilter;
8330
8331            break;
8332
8333          case "boolean":
8334
8335            if (column.extensions.edit && column.extensions.edit.editor) {
8336
8337              editor = column.extensions.edit.editor;
8338            } else {
8339
8340              if (column.definition.formatter && self.table.extensions.edit.editors[column.definition.formatter]) {
8341
8342                editor = self.table.extensions.edit.editors[column.definition.formatter];
8343              } else {
8344
8345                editor = self.table.extensions.edit.editors["input"];
8346              }
8347            }
8348
8349            break;
8350
8351        }
8352
8353        if (editor) {
8354
8355          cellWrapper = {
8356
8357            getValue: function getValue() {
8358
8359              return "";
8360            },
8361
8362            getElement: function getElement() {
8363
8364              return filterElement;
8365            }
8366
8367          };
8368
8369          editorElement = editor.call(self, cellWrapper, function () {}, success, cancel, column.definition.headerFilterParams || {});
8370
8371          //set Placeholder Text
8372
8373
8374          if (field) {
8375
8376            self.table.extensions.localize.bind("headerFilters.columns." + column.definition.field, function (value) {
8377
8378              editorElement.attr("placeholder", typeof value !== "undefined" && value ? value : self.table.extensions.localize.getText("headerFilters.default"));
8379            });
8380          } else {
8381
8382            self.table.extensions.localize.bind("headerFilters.default", function (value) {
8383
8384              editorElement.attr("placeholdder", typeof self.column.definition.headerFilterPlaceholder !== "undefined" && self.column.definition.headerFilterPlaceholder ? self.column.definition.headerFilterPlaceholder : value);
8385            });
8386          }
8387
8388          //focus on element on click
8389
8390
8391          editorElement.on("click", function (e) {
8392
8393            e.stopPropagation();
8394
8395            $(this).focus();
8396          });
8397
8398          //live update filters as user types
8399
8400
8401          typingTimer = false;
8402
8403          editorElement.on("keyup search", function (e) {
8404
8405            var element = $(this);
8406
8407            if (typingTimer) {
8408
8409              clearTimeout(typingTimer);
8410            }
8411
8412            typingTimer = setTimeout(function () {
8413
8414              success(element.val());
8415            }, 300);
8416          });
8417
8418          //update number filtered columns on change
8419
8420
8421          attrType = editorElement.attr("type") ? editorElement.attr("type").toLowerCase() : "";
8422
8423          if (attrType == "number") {
8424
8425            editorElement.on("change", function (e) {
8426
8427              success($(this).val());
8428            });
8429          }
8430
8431          //change text inputs to search inputs to allow for clearing of field
8432
8433
8434          if (attrType == "text") {
8435
8436            editorElement.attr("type", "search");
8437
8438            editorElement.off("change blur"); //prevent blur from triggering filter and preventing selection click
8439
8440          }
8441
8442          //prevent input and select elements from propegating click to column sorters etc
8443
8444
8445          tagType = editorElement.prop("tagName").toLowerCase();
8446
8447          if (tagType == "input" || tagType == "select") {
8448
8449            editorElement.on("mousedown", function (e) {
8450
8451              e.stopPropagation();
8452            });
8453          }
8454
8455          filterElement.append(editorElement);
8456
8457          column.contentElement.append(filterElement);
8458
8459          self.headerFilterElements.push(editorElement);
8460        }
8461      } else {
8462
8463        console.warn("Filter Error - Cannot add header filter, column has no field set:", column.definition.title);
8464      }
8465    };
8466
8467    //check if the filters has changed since last use
8468
8469
8470    Filter.prototype.hasChanged = function () {
8471
8472      var changed = this.changed;
8473
8474      this.changed = false;
8475
8476      return changed;
8477    };
8478
8479    //set standard filters
8480
8481
8482    Filter.prototype.setFilter = function (field, type, value) {
8483
8484      var self = this;
8485
8486      self.filterList = [];
8487
8488      if (!Array.isArray(field)) {
8489
8490        field = [{ field: field, type: type, value: value }];
8491      }
8492
8493      self.addFilter(field);
8494    };
8495
8496    //add filter to array
8497
8498
8499    Filter.prototype.addFilter = function (field, type, value) {
8500
8501      var self = this,
8502          column;
8503
8504      if (!Array.isArray(field)) {
8505
8506        field = [{ field: field, type: type, value: value }];
8507      }
8508
8509      field.forEach(function (filter) {
8510
8511        var filterFunc = false;
8512
8513        if (typeof filter.field == "function") {
8514
8515          filterFunc = function filterFunc(data) {
8516
8517            return filter.field(data, filter.type || {}); // pass params to custom filter function
8518
8519          };
8520        } else {
8521
8522          if (self.filters[filter.type]) {
8523
8524            column = self.table.columnManager.getColumnByField(filter.field);
8525
8526            if (column) {
8527
8528              filterFunc = function filterFunc(data) {
8529
8530                return self.filters[filter.type](filter.value, column.getFieldValue(data));
8531              };
8532            } else {
8533
8534              filterFunc = function filterFunc(data) {
8535
8536                return self.filters[filter.type](filter.value, data[filter.field]);
8537              };
8538            }
8539          } else {
8540
8541            console.warn("Filter Error - No such filter type found, ignoring: ", filter.type);
8542          }
8543        }
8544
8545        if (filterFunc) {
8546
8547          filter.func = filterFunc;
8548
8549          self.filterList.push(filter);
8550
8551          self.changed = true;
8552        }
8553      });
8554    };
8555
8556    //get all filters
8557
8558
8559    Filter.prototype.getFilter = function () {
8560
8561      var self = this,
8562          output = [];
8563
8564      self.filterList.forEach(function (filter) {
8565
8566        output.push({ field: filter.field, type: filter.type, value: filter.value });
8567      });
8568
8569      return output;
8570    };
8571
8572    //remove filter from array
8573
8574
8575    Filter.prototype.removeFilter = function (field, type, value) {
8576
8577      var self = this;
8578
8579      if (!Array.isArray(field)) {
8580
8581        field = [{ field: field, type: type, value: value }];
8582      }
8583
8584      field.forEach(function (filter) {
8585
8586        var index = -1;
8587
8588        if (_typeof(filter.field) == "object") {
8589
8590          index = self.filterList.findIndex(function (element) {
8591
8592            return filter === element;
8593          });
8594        } else {
8595
8596          index = self.filterList.findIndex(function (element) {
8597
8598            return filter.field === element.field && filter.type === element.type && filter.value === element.value;
8599          });
8600        }
8601
8602        if (index > -1) {
8603
8604          self.filterList.splice(index, 1);
8605
8606          self.changed = true;
8607        } else {
8608
8609          console.warn("Filter Error - No matching filter type found, ignoring: ", filter.type);
8610        }
8611      });
8612    };
8613
8614    //clear filters
8615
8616
8617    Filter.prototype.clearFilter = function (all) {
8618
8619      this.filterList = [];
8620
8621      if (all) {
8622
8623        this.clearHeaderFilter();
8624      }
8625
8626      this.changed = true;
8627    };
8628
8629    //clear header filters
8630
8631
8632    Filter.prototype.clearHeaderFilter = function () {
8633
8634      this.headerFilters = {};
8635
8636      this.headerFilterElements.forEach(function (element) {
8637
8638        element.val("");
8639      });
8640
8641      self.changed = true;
8642    };
8643
8644    //filter row array
8645
8646
8647    Filter.prototype.filter = function (rowList) {
8648
8649      var self = this,
8650          activeRows = [],
8651          activeRowComponents = [];
8652
8653      if (self.table.options.dataFiltering) {
8654
8655        self.table.options.dataFiltering(self.getFilter());
8656      }
8657
8658      if (!self.table.options.ajaxFiltering && (self.filterList.length || Object.keys(self.headerFilters).length)) {
8659
8660        rowList.forEach(function (row) {
8661
8662          if (self.filterRow(row)) {
8663
8664            activeRows.push(row);
8665          }
8666        });
8667
8668        activeRows;
8669      } else {
8670
8671        activeRows = rowList.slice(0);
8672      }
8673
8674      if (self.table.options.dataFiltered) {
8675
8676        activeRows.forEach(function (row) {
8677
8678          activeRowComponents.push(row.getComponent());
8679        });
8680
8681        self.table.options.dataFiltered(self.getFilter(), activeRowComponents);
8682      }
8683
8684      return activeRows;
8685    };
8686
8687    //filter individual row
8688
8689
8690    Filter.prototype.filterRow = function (row) {
8691
8692      var self = this,
8693          match = true,
8694          data = row.getData();
8695
8696      self.filterList.forEach(function (filter) {
8697
8698        if (!filter.func(data)) {
8699
8700          match = false;
8701        }
8702      });
8703
8704      for (var field in self.headerFilters) {
8705
8706        if (!self.headerFilters[field].func(data)) {
8707
8708          match = false;
8709        }
8710      }
8711
8712      return match;
8713    };
8714
8715    //list of available filters
8716
8717
8718    Filter.prototype.filters = {
8719
8720      //equal to
8721
8722
8723      "=": function _(filterVal, rowVal) {
8724
8725        return rowVal == filterVal ? true : false;
8726      },
8727
8728      //less than
8729
8730
8731      "<": function _(filterVal, rowVal) {
8732
8733        return rowVal < filterVal ? true : false;
8734      },
8735
8736      //less than or equal to
8737
8738
8739      "<=": function _(filterVal, rowVal) {
8740
8741        return rowVal <= filterVal ? true : false;
8742      },
8743
8744      //greater than
8745
8746
8747      ">": function _(filterVal, rowVal) {
8748
8749        return rowVal > filterVal ? true : false;
8750      },
8751
8752      //greater than or equal to
8753
8754
8755      ">=": function _(filterVal, rowVal) {
8756
8757        return rowVal >= filterVal ? true : false;
8758      },
8759
8760      //not equal to
8761
8762
8763      "!=": function _(filterVal, rowVal) {
8764
8765        return rowVal != filterVal ? true : false;
8766      },
8767
8768      //contains the string
8769
8770
8771      "like": function like(filterVal, rowVal) {
8772
8773        if (filterVal === null) {
8774
8775          return rowVal === filterVal ? true : false;
8776        } else {
8777
8778          return rowVal.toLowerCase().indexOf(filterVal.toLowerCase()) > -1 ? true : false;
8779        }
8780      }
8781
8782    };
8783
8784    Tabulator.registerExtension("filter", Filter);
8785
8786    var Format = function Format(table) {
8787
8788      this.table = table; //hold Tabulator object
8789
8790    };
8791
8792    //initialize column formatter
8793
8794
8795    Format.prototype.initializeColumn = function (column) {
8796
8797      var self = this,
8798          config = { params: column.definition.formatterParams || {} };
8799
8800      //set column formatter
8801
8802
8803      switch (_typeof(column.definition.formatter)) {
8804
8805        case "string":
8806
8807          if (self.formatters[column.definition.formatter]) {
8808
8809            config.formatter = self.formatters[column.definition.formatter];
8810          } else {
8811
8812            console.warn("Formatter Error - No such formatter found: ", column.definition.formatter);
8813
8814            config.formatter = self.formatters.plaintext;
8815          }
8816
8817          break;
8818
8819        case "function":
8820
8821          config.formatter = column.definition.formatter;
8822
8823          break;
8824
8825        default:
8826
8827          config.formatter = self.formatters.plaintext;
8828
8829          break;
8830
8831      }
8832
8833      column.extensions.format = config;
8834    };
8835
8836    //return a formatted value for a cell
8837
8838
8839    Format.prototype.formatValue = function (cell) {
8840
8841      return cell.column.extensions.format.formatter.call(this, cell.getComponent(), cell.column.extensions.format.params);
8842    };
8843
8844    Format.prototype.sanitizeHTML = function (value) {
8845
8846      if (value) {
8847
8848        var entityMap = {
8849
8850          '&': '&amp;',
8851
8852          '<': '&lt;',
8853
8854          '>': '&gt;',
8855
8856          '"': '&quot;',
8857
8858          "'": '&#39;',
8859
8860          '/': '&#x2F;',
8861
8862          '`': '&#x60;',
8863
8864          '=': '&#x3D;'
8865
8866        };
8867
8868        return String(value).replace(/[&<>"'`=\/]/g, function (s) {
8869
8870          return entityMap[s];
8871        });
8872      } else {
8873
8874        return value;
8875      }
8876    };
8877
8878    Format.prototype.emptyToSpace = function (value) {
8879
8880      return value === null ? "&nbsp" : value;
8881    };
8882
8883    //default data formatters
8884
8885
8886    Format.prototype.formatters = {
8887
8888      //plain text value
8889
8890
8891      plaintext: function plaintext(cell, formatterParams) {
8892
8893        return this.emptyToSpace(this.sanitizeHTML(cell.getValue()));
8894      },
8895
8896      //html text value
8897
8898
8899      html: function html(cell, formatterParams) {
8900
8901        return cell.getValue();
8902      },
8903
8904      //multiline text area
8905
8906
8907      textarea: function textarea(cell, formatterParams) {
8908
8909        cell.getElement().css({ "white-space": "pre-wrap" });
8910
8911        return this.emptyToSpace(this.sanitizeHTML(cell.getValue()));
8912      },
8913
8914      //currency formatting
8915
8916
8917      money: function money(cell, formatterParams) {
8918
8919        var floatVal = parseFloat(cell.getValue()),
8920            number,
8921            integer,
8922            decimal,
8923            rgx;
8924
8925        var decimalSym = formatterParams.decimal || ".";
8926
8927        var thousandSym = formatterParams.thousand || ",";
8928
8929        var symbol = formatterParams.symbol || "";
8930
8931        var after = !!formatterParams.symbolAfter;
8932
8933        var precision = typeof formatterParams.precision !== "undefined" ? formatterParams.precision : 2;
8934
8935        if (isNaN(floatVal)) {
8936
8937          return this.emptyToSpace(this.sanitizeHTML(cell.getValue()));
8938        }
8939
8940        number = precision !== false ? floatVal.toFixed(precision) : floatVal;
8941
8942        number = number.split(".");
8943
8944        integer = number[0];
8945
8946        decimal = number.length > 1 ? decimalSym + number[1] : "";
8947
8948        rgx = /(\d+)(\d{3})/;
8949
8950        while (rgx.test(integer)) {
8951
8952          integer = integer.replace(rgx, "$1" + thousandSym + "$2");
8953        }
8954
8955        return after ? integer + decimal + symbol : symbol + integer + decimal;
8956      },
8957
8958      //clickable mailto link
8959
8960
8961      email: function email(cell, formatterParams) {
8962
8963        var value = this.sanitizeHTML(cell.getValue());
8964
8965        return "<a href='mailto:" + value + "'>" + this.emptyToSpace(value) + "</a>";
8966      },
8967
8968      //clickable anchor tag
8969
8970
8971      link: function link(cell, formatterParams) {
8972
8973        var value = this.sanitizeHTML(cell.getValue());
8974
8975        return "<a href='" + value + "'>" + this.emptyToSpace(value) + "</a>";
8976      },
8977
8978      //image element
8979
8980
8981      image: function image(cell, formatterParams) {
8982
8983        var value = this.sanitizeHTML(cell.getValue());
8984
8985        return "<img src='" + value + "'/>";
8986      },
8987
8988      //tick or empty cell
8989
8990
8991      tick: function tick(cell, formatterParams) {
8992
8993        var value = cell.getValue(),
8994            element = cell.getElement();
8995
8996        var tick = '<svg enable-background="new 0 0 24 24" height="14" width="14" viewBox="0 0 24 24" xml:space="preserve" ><path fill="#2DC214" clip-rule="evenodd" d="M21.652,3.211c-0.293-0.295-0.77-0.295-1.061,0L9.41,14.34  c-0.293,0.297-0.771,0.297-1.062,0L3.449,9.351C3.304,9.203,3.114,9.13,2.923,9.129C2.73,9.128,2.534,9.201,2.387,9.351  l-2.165,1.946C0.078,11.445,0,11.63,0,11.823c0,0.194,0.078,0.397,0.223,0.544l4.94,5.184c0.292,0.296,0.771,0.776,1.062,1.07  l2.124,2.141c0.292,0.293,0.769,0.293,1.062,0l14.366-14.34c0.293-0.294,0.293-0.777,0-1.071L21.652,3.211z" fill-rule="evenodd"/></svg>';
8997
8998        if (value === true || value === "true" || value === "True" || value === 1 || value === "1") {
8999
9000          element.attr("aria-checked", true);
9001
9002          return tick;
9003        } else {
9004
9005          element.attr("aria-checked", false);
9006
9007          return "";
9008        }
9009      },
9010
9011      //tick or cross
9012
9013
9014      tickCross: function tickCross(cell, formatterParams) {
9015
9016        var value = cell.getValue(),
9017            element = cell.getElement(),
9018            tick = '<svg enable-background="new 0 0 24 24" height="14" width="14" viewBox="0 0 24 24" xml:space="preserve" ><path fill="#2DC214" clip-rule="evenodd" d="M21.652,3.211c-0.293-0.295-0.77-0.295-1.061,0L9.41,14.34  c-0.293,0.297-0.771,0.297-1.062,0L3.449,9.351C3.304,9.203,3.114,9.13,2.923,9.129C2.73,9.128,2.534,9.201,2.387,9.351  l-2.165,1.946C0.078,11.445,0,11.63,0,11.823c0,0.194,0.078,0.397,0.223,0.544l4.94,5.184c0.292,0.296,0.771,0.776,1.062,1.07  l2.124,2.141c0.292,0.293,0.769,0.293,1.062,0l14.366-14.34c0.293-0.294,0.293-0.777,0-1.071L21.652,3.211z" fill-rule="evenodd"/></svg>',
9019            cross = '<svg enable-background="new 0 0 24 24" height="14" width="14"  viewBox="0 0 24 24" xml:space="preserve" ><path fill="#CE1515" d="M22.245,4.015c0.313,0.313,0.313,0.826,0,1.139l-6.276,6.27c-0.313,0.312-0.313,0.826,0,1.14l6.273,6.272  c0.313,0.313,0.313,0.826,0,1.14l-2.285,2.277c-0.314,0.312-0.828,0.312-1.142,0l-6.271-6.271c-0.313-0.313-0.828-0.313-1.141,0  l-6.276,6.267c-0.313,0.313-0.828,0.313
9019-1.141,0l-2.282-2.28c-0.313-0.313-0.313-0.826,0-1.14l6.278-6.269  c0.313-0.312,0.313-0.826,0-1.14L1.709,5.147c-0.314-0.313-0.314-0.827,0-1.14l2.284-2.278C4.308,1.417,4.821,1.417,5.135,1.73  L11.405,8c0.314,0.314,0.828,0.314,1.141,0.001l6.276-6.267c0.312-0.312,0.826-0.312,1.141,0L22.245,4.015z"/></svg>';
9020
9021        if (value === true || value === "true" || value === "True" || value === 1 || value === "1") {
9022
9023          element.attr("aria-checked", true);
9024
9025          return tick;
9026        } else {
9027
9028          element.attr("aria-checked", false);
9029
9030          return cross;
9031        }
9032      },
9033
9034      //star rating
9035
9036
9037      star: function star(cell, formatterParams) {
9038
9039        var value = cell.getValue(),
9040            element = cell.getElement(),
9041            maxStars = formatterParams && formatterParams.stars ? formatterParams.stars : 5,
9042            stars = $("<span style='vertical-align:middle;'></span>"),
9043            starActive = $('<svg width="14" height="14" viewBox="0 0 512 512" xml:space="preserve" style="margin:0 1px;"><polygon fill="#FFEA00" stroke="#C1AB60" stroke-width="37.6152" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 "/></svg>'),
9044            starInactive = $('<svg width="14" height="14" viewBox="0 0 512 512" xml:space="preserve" style="margin:0 1px;"><polygon fill="#D2D2D2" stroke="#686868" stroke-width="37.6152" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="259.216,29.942 330.27,173.919 489.16,197.007 374.185,309.08 401.33,467.31 259.216,392.612 117.104,467.31 144.25,309.08 29.274,197.007 188.165,173.919 "/></svg>');
9045
9046        value = parseInt(value) < maxStars ? parseInt(value) : maxStars;
9047
9048        for (var i = 1; i <= maxStars; i++) {
9049
9050          var nextStar = i <= value ? starActive : starInactive;
9051
9052          stars.append(nextStar.clone());
9053        }
9054
9055        element.css({
9056
9057          "white-space": "nowrap",
9058
9059          "overflow": "hidden",
9060
9061          "text-overflow": "ellipsis"
9062
9063        });
9064
9065        element.attr("aria-label", value);
9066
9067        return stars.html();
9068      },
9069
9070      //progress bar
9071
9072
9073      progress: function progress(cell, formatterParams) {
9074        //progress bar
9075
9076
9077        var value = this.sanitizeHTML(cell.getValue()) || 0,
9078            element = cell.getElement(),
9079            max = formatterParams && formatterParams.max ? formatterParams.max : 100,
9080            min = formatterParams && formatterParams.min ? formatterParams.min : 0,
9081            color = formatterParams && formatterParams.color ? formatterParams.color : "#2DC214",
9082            percent;
9083
9084        //make sure value is in range
9085
9086
9087        value = parseFloat(value) <= max ? parseFloat(value) : max;
9088
9089        value = parseFloat(value) >= min ? parseFloat(value) : min;
9090
9091        //workout percentage
9092
9093
9094        percent = (max - min) / 100;
9095
9096        value = 100 - Math.round((value - min) / percent);
9097
9098        element.css({
9099
9100          "min-width": "30px",
9101
9102          "position": "relative"
9103
9104        });
9105
9106        element.attr("aria-label", value);
9107
9108        return "<div style='position:absolute; top:8px; bottom:8px; left:4px; right:" + value + "%; margin-right:4px; background-color:" + color + "; display:inline-block;' data-max='" + max + "' data-min='" + min + "'></div>";
9109      },
9110
9111      //background color
9112
9113
9114      color: function color(cell, formatterParams) {
9115
9116        cell.getElement().css({ "background-color": this.sanitizeHTML(cell.getValue()) });
9117
9118        return "";
9119      },
9120
9121      //tick icon
9122
9123
9124      buttonTick: function buttonTick(cell, formatterParams) {
9125
9126        return '<svg enable-background="new 0 0 24 24" height="14" width="14" viewBox="0 0 24 24" xml:space="preserve" ><path fill="#2DC214" clip-rule="evenodd" d="M21.652,3.211c-0.293-0.295-0.77-0.295-1.061,0L9.41,14.34  c-0.293,0.297-0.771,0.297-1.062,0L3.449,9.351C3.304,9.203,3.114,9.13,2.923,9.129C2.73,9.128,2.534,9.201,2.387,9.351  l-2.165,1.946C0.078,11.445,0,11.63,0,11.823c0,0.194,0.078,0.397,0.223,0.544l4.94,5.184c0.292,0.296,0.771,0.776,1.062,1.07  l2.124,2.141c0.292,0.293,0.769,0.293,1.062,0l14.366-14.34c0.293-0.294,0.293-0.777,0-1.071L21.652,3.211z" fill-rule="evenodd"/></svg>';
9127      },
9128
9129      //cross icon
9130
9131
9132      buttonCross: function buttonCross(cell, formatterParams) {
9133
9134        return '<svg enable-background="new 0 0 24 24" height="14" width="14" viewBox="0 0 24 24" xml:space="preserve" ><path fill="#CE1515" d="M22.245,4.015c0.313,0.313,0.313,0.826,0,1.139l-6.276,6.27c-0.313,0.312-0.313,0.826,0,1.14l6.273,6.272  c0.313,0.313,0.313,0.826,0,1.14l-2.285,2.277c-0.314,0.312-0.828,0.312-1.142,0l-6.271-6.271c-0.313-0.313-0.828-0.313-1.141,0  l-6.276,6.267c-0.313,0.313-0.828,0.313
9134-1.141,0l-2.282-2.28c-0.313-0.313-0.313-0.826,0-1.14l6.278-6.269  c0.313-0.312,0.313-0.826,0-1.14L1.709,5.147c-0.314-0.313-0.314-0.827,0-1.14l2.284-2.278C4.308,1.417,4.821,1.417,5.135,1.73  L11.405,8c0.314,0.314,0.828,0.314,1.141,0.001l6.276-6.267c0.312-0.312,0.826-0.312,1.141,0L22.245,4.015z"/></svg>';
9135      },
9136
9137      //current row number
9138
9139
9140      rownum: function rownum(cell, formatterParams) {
9141
9142        return this.table.rowManager.activeRows.indexOf(cell.getRow()._getSelf()) + 1;
9143      },
9144
9145      //row handle
9146
9147
9148      handle: function handle(cell, formatterParams) {
9149
9150        cell.getElement().addClass("tabulator-row-handle");
9151
9152        return "<div class='tabulator-row-handle-bar'></div><div class='tabulator-row-handle-bar'></div><div class='tabulator-row-handle-bar'></div>";
9153      }
9154
9155    };
9156
9157    Tabulator.registerExtension("format", Format);
9158
9159    var FrozenColumns = function FrozenColumns(table) {
9160
9161      this.table = table; //hold Tabulator object
9162
9163
9164      this.leftColumns = [];
9165
9166      this.rightColumns = [];
9167
9168      this.leftMargin = 0;
9169
9170      this.rightMargin = 0;
9171
9172      this.initializationMode = "left";
9173
9174      this.active = false;
9175    };
9176
9177    //reset initial state
9178
9179
9180    FrozenColumns.prototype.reset = function () {
9181
9182      this.initializationMode = "left";
9183
9184      this.leftColumns = [];
9185
9186      this.rightColumns = [];
9187
9188      this.active = false;
9189    };
9190
9191    //initialize specific column
9192
9193
9194    FrozenColumns.prototype.initializeColumn = function (column) {
9195
9196      var config = { margin: 0, edge: false };
9197
9198      if (column.definition.frozen) {
9199
9200        if (!column.parent.isGroup) {
9201
9202          if (!column.isGroup) {
9203
9204            config.position = this.initializationMode;
9205
9206            if (this.initializationMode == "left") {
9207
9208              this.leftColumns.push(column);
9209            } else {
9210
9211              this.rightColumns.unshift(column);
9212            }
9213
9214            this.active = true;
9215
9216            column.extensions.frozen = config;
9217          } else {
9218
9219            console.warn("Frozen Column Error - Column Groups cannot be frozen");
9220          }
9221        } else {
9222
9223          console.warn("Frozen Column Error - Grouped columns cannot be frozen");
9224        }
9225      } else {
9226
9227        this.initializationMode = "right";
9228      }
9229    };
9230
9231    //layout columns appropropriatly
9232
9233
9234    FrozenColumns.prototype.layout = function () {
9235
9236      var self = this,
9237          tableHolder = this.table.rowManager.element,
9238          rightMargin = 0;
9239
9240      if (self.active) {
9241
9242        //calculate row padding
9243
9244
9245        self.leftMargin = self._calcSpace(self.leftColumns, self.leftColumns.length);
9246
9247        self.table.columnManager.headersElement.css("margin-left", self.leftMargin);
9248
9249        self.rightMargin = self._calcSpace(self.rightColumns, self.rightColumns.length);
9250
9251        self.table.columnManager.element.css("padding-right", self.rightMargin);
9252
9253        self.table.rowManager.activeRows.forEach(function (row) {
9254
9255          self.layoutRow(row);
9256        });
9257
9258        if (self.table.extExists("columnCalcs")) {
9259
9260          if (self.table.extensions.columnCalcs.topInitialized && self.table.extensions.columnCalcs.topRow) {
9261
9262            self.layoutRow(self.table.extensions.columnCalcs.topRow);
9263          }
9264
9265          if (self.table.extensions.columnCalcs.botInitialized && self.table.extensions.columnCalcs.botRow) {
9266
9267            self.layoutRow(self.table.extensions.columnCalcs.botRow);
9268          }
9269        }
9270
9271        //calculate left columns
9272
9273
9274        self.leftColumns.forEach(function (column, i) {
9275
9276          column.extensions.frozen.margin = self._calcSpace(self.leftColumns, i) + self.table.columnManager.scrollLeft;
9277
9278          if (i == self.leftColumns.length - 1) {
9279
9280            column.extensions.frozen.edge = true;
9281          } else {
9282
9283            column.extensions.frozen.edge = false;
9284          }
9285
9286          self.layoutColumn(column);
9287        });
9288
9289        //calculate right frozen columns
9290
9291
9292        rightMargin = self.table.rowManager.element.innerWidth() + self.table.columnManager.scrollLeft;
9293
9294        if (tableHolder[0].scrollHeight > tableHolder.innerHeight()) {
9295
9296          rightMargin -= tableHolder[0].offsetWidth - tableHolder[0].clientWidth;
9297        }
9298
9299        self.rightColumns.forEach(function (column, i) {
9300
9301          column.extensions.frozen.margin = rightMargin - self._calcSpace(self.rightColumns, i + 1);
9302
9303          if (i == self.rightColumns.length - 1) {
9304
9305            column.extensions.frozen.edge = true;
9306          } else {
9307
9308            column.extensions.frozen.edge = false;
9309          }
9310
9311          self.layoutColumn(column);
9312        });
9313      }
9314    };
9315
9316    FrozenColumns.prototype.layoutColumn = function (column) {
9317
9318      var self = this;
9319
9320      self.layoutElement(column.element, column);
9321
9322      column.cells.forEach(function (cell) {
9323
9324        self.layoutElement(cell.element, column);
9325      });
9326    };
9327
9328    FrozenColumns.prototype.layoutRow = function (row) {
9329
9330      row.getElement().css({
9331
9332        "padding-left": this.leftMargin,
9333
9334        "padding-right": this.rightMargin
9335
9336      });
9337    };
9338
9339    FrozenColumns.prototype.layoutElement = function (element, column) {
9340
9341      if (column.extensions.frozen) {
9342
9343        var css = {
9344
9345          position: "absolute",
9346
9347          left: column.extensions.frozen.margin
9348
9349        };
9350
9351        element.css(css);
9352
9353        element.addClass("tabulator-frozen");
9354
9355        if (column.extensions.frozen.edge) {
9356
9357          element.addClass("tabulator-frozen-" + column.extensions.frozen.position);
9358        }
9359      }
9360    };
9361
9362    FrozenColumns.prototype._calcSpace = function (columns, index) {
9363
9364      var width = 0;
9365
9366      for (var i = 0; i < index; i++) {
9367
9368        if (columns[i].visible) {
9369
9370          width += columns[i].getWidth();
9371        }
9372      }
9373
9374      return width;
9375    };
9376
9377    Tabulator.registerExtension("frozenColumns", FrozenColumns);
9378
9379    //public group object
9380
9381
9382    var GroupComponent = function GroupComponent(group) {
9383
9384      var obj = {
9385
9386        type: "GroupComponent", //type of element
9387
9388
9389        getKey: function getKey() {
9390
9391          return group.key;
9392        },
9393
9394        getElement: function getElement() {
9395
9396          return group.element;
9397        },
9398
9399        getRows: function getRows() {
9400
9401          var output = [];
9402
9403          group.rows.forEach(function (row) {
9404
9405            output.push(row.getComponent());
9406          });
9407
9408          return output;
9409        },
9410
9411        getSubGroups: function getSubGroups() {
9412
9413          var output = [];
9414
9415          group.groupList.forEach(function (child) {
9416
9417            output.push(child.getComponent());
9418          });
9419
9420          return output;
9421        },
9422
9423        getParentGroup: function getParentGroup() {
9424
9425          return group.parent ? group.parent.getComponent() : false;
9426        },
9427
9428        getVisibility: function getVisibility() {
9429
9430          return group.visible;
9431        },
9432
9433        show: function show() {
9434
9435          group.show();
9436        },
9437
9438        hide: function hide() {
9439
9440          group.hide();
9441        },
9442
9443        toggle: function toggle() {
9444
9445          group.toggleVisibility();
9446        },
9447
9448        _getSelf: function _getSelf() {
9449
9450          return group;
9451        }
9452
9453      };
9454
9455      return obj;
9456    };
9457
9458    //////////////////////////////////////////////////
9459
9460
9461    //////////////// Group Functions /////////////////
9462
9463
9464    //////////////////////////////////////////////////
9465
9466
9467    var Group = function Group(groupManager, parent, level, key, generator, oldGroup) {
9468
9469      this.groupManager = groupManager;
9470
9471      this.parent = parent;
9472
9473      this.key = key;
9474
9475      this.level = level;
9476
9477      this.hasSubGroups = level < groupManager.groupIDLookups.length - 1;
9478
9479      this.addRow = this.hasSubGroups ? this._addRowToGroup : this._addRow;
9480
9481      this.type = "group"; //type of element
9482
9483
9484      this.old = oldGroup;
9485
9486      this.rows = [];
9487
9488      this.groups = [];
9489
9490      this.groupList = [];
9491
9492      this.generator = generator;
9493
9494      this.element = $("<div class='tabulator-row tabulator-group tabulator-group-level-" + level + "' role='rowgroup'></div>");
9495
9496      this.arrowElement = $("<div class='tabulator-arrow'></div>");
9497
9498      this.height = 0;
9499
9500      this.outerHeight = 0;
9501
9502      this.initialized = false;
9503
9504      this.visible = oldGroup ? oldGroup.visible : typeof groupManager.startOpen[level] !== "undefined" ? groupManager.startOpen[level] : groupManager.startOpen[0];
9505
9506      this.addBindings();
9507    };
9508
9509    Group.prototype.addBindings = function () {
9510
9511      var self = this;
9512
9513      self.arrowElement.on("click", function (e) {
9514
9515        e.stopPropagation();
9516
9517        e.stopImmediatePropagation();
9518
9519        self.toggleVisibility();
9520      });
9521    };
9522
9523    Group.prototype._addRowToGroup = function (row) {
9524
9525      var level = this.level + 1;
9526
9527      if (this.hasSubGroups) {
9528
9529        var groupID = this.groupManager.groupIDLookups[level](row.getData());
9530
9531        if (!this.groups[groupID]) {
9532
9533          var group = new Group(this.groupManager, this, level, groupID, this.groupManager.headerGenerator[level] || this.groupManager.headerGenerator[0], this.old ? this.old.groups[groupID] : false);
9534
9535          this.groups[groupID] = group;
9536
9537          this.groupList.push(group);
9538        }
9539
9540        this.groups[groupID].addRow(row);
9541      }
9542    };
9543
9544    Group.prototype._addRow = function (row) {
9545
9546      this.rows.push(row);
9547    };
9548
9549    Group.prototype.getHeadersAndRows = function () {
9550
9551      var output = [];
9552
9553      output.push(this);
9554
9555      this._visSet();
9556
9557      if (this.visible) {
9558
9559        if (this.groupList.length) {
9560
9561          this.groupList.forEach(function (group) {
9562
9563            output = output.concat(group.getHeadersAndRows());
9564          });
9565        } else {
9566
9567          if (this.groupManager.table.extExists("columnCalcs") && this.groupManager.table.extensions.columnCalcs.hasTopCalcs()) {
9568
9569            output.push(this.groupManager.table.extensions.columnCalcs.generateTopRow(this.rows));
9570          }
9571
9572          output = output.concat(this.rows);
9573
9574          if (this.groupManager.table.extExists("columnCalcs") && this.groupManager.table.extensions.columnCalcs.hasBottomCalcs()) {
9575
9576            output.push(this.groupManager.table.extensions.columnCalcs.generateBottomRow(this.rows));
9577          }
9578        }
9579      }
9580
9581      return output;
9582    };
9583
9584    Group.prototype.getRows = function () {
9585
9586      this._visSet();
9587
9588      return this.visible ? this.rows : [];
9589    };
9590
9591    Group.prototype.getRowCount = function () {
9592
9593      var count = 0;
9594
9595      if (this.groupList.length) {
9596
9597        this.groupList.forEach(function (group) {
9598
9599          count += group.getRowCount();
9600        });
9601      } else {
9602
9603        count = this.rows.length;
9604      }
9605
9606      return count;
9607    };
9608
9609    Group.prototype.toggleVisibility = function () {
9610
9611      if (this.visible) {
9612
9613        this.hide();
9614      } else {
9615
9616        this.show();
9617      }
9618    };
9619
9620    Group.prototype.hide = function () {
9621
9622      this.visible = false;
9623
9624      if (this.groupManager.table.rowManager.getRenderMode() == "classic") {
9625
9626        this.rows.forEach(function (row) {
9627
9628          row.getElement().detach();
9629        });
9630      } else {
9631
9632        this.groupManager.updateGroupRows(true);
9633      }
9634
9635      this.groupManager.table.options.groupVisibilityChanged(this.getComponent(), false);
9636    };
9637
9638    Group.prototype.show = function () {
9639
9640      var self = this;
9641
9642      self.visible = true;
9643
9644      if (this.groupManager.table.rowManager.getRenderMode() == "classic") {
9645
9646        self.rows.forEach(function (row) {
9647
9648          self.getElement().after(row.getElement());
9649
9650          row.initialize();
9651        });
9652      } else {
9653
9654        this.groupManager.updateGroupRows(true);
9655      }
9656
9657      this.groupManager.table.options.groupVisibilityChanged(this.getComponent(), true);
9658    };
9659
9660    Group.prototype._visSet = function () {
9661
9662      var data = [];
9663
9664      if (typeof this.visible == "function") {
9665
9666        this.rows.forEach(function (row) {
9667
9668          data.push(row.getData());
9669        });
9670
9671        this.visible = this.visible(this.key, this.getRowCount(), data);
9672      }
9673    };
9674
9675    ////////////// Standard Row Functions //////////////
9676
9677
9678    Group.prototype.getElement = function () {
9679
9680      this.addBindingsd = false;
9681
9682      this._visSet();
9683
9684      var data = [];
9685
9686      this.rows.forEach(function (row) {
9687
9688        data.push(row.getData());
9689      });
9690
9691      if (this.visible) {
9692
9693        this.element.addClass("tabulator-group-visible");
9694      } else {
9695
9696        this.element.removeClass("tabulator-group-visible");
9697      }
9698
9699      this.element.children().detach();
9700
9701      this.element.html(this.generator(this.key, this.getRowCount(), data)).prepend(this.arrowElement);
9702
9703      this.addBindings();
9704
9705      return this.element;
9706    };
9707
9708    //normalize the height of elements in the row
9709
9710
9711    Group.prototype.normalizeHeight = function () {
9712
9713      this.setHeight(this.element.innerHeight());
9714    };
9715
9716    Group.prototype.initialize = function (force) {
9717
9718      if (!this.initialized || force) {
9719
9720        this.normalizeHeight();
9721
9722        this.initialized = true;
9723      }
9724    };
9725
9726    Group.prototype.reinitialize = function () {
9727
9728      this.initialized = false;
9729
9730      this.height = 0;
9731
9732      if (this.element.is(":visible")) {
9733
9734        this.initialize(true);
9735      }
9736    };
9737
9738    Group.prototype.setHeight = function (height) {
9739
9740      if (this.height != height) {
9741
9742        this.height = height;
9743
9744        this.outerHeight = this.element.outerHeight();
9745      }
9746    };
9747
9748    //return rows outer height
9749
9750
9751    Group.prototype.getHeight = function () {
9752
9753      return this.outerHeight;
9754    };
9755
9756    Group.prototype.reinitializeHeight = function () {};
9757
9758    Group.prototype.calcHeight = function () {};
9759
9760    Group.prototype.setCellHeight = function () {};
9761
9762    Group.prototype.clearCellHeight = function () {};
9763
9764    //////////////// Object Generation /////////////////
9765
9766
9767    Group.prototype.getComponent = function () {
9768
9769      return new GroupComponent(this);
9770    };
9771
9772    //////////////////////////////////////////////////
9773
9774
9775    ////////////// Group Row Extension ///////////////
9776
9777
9778    //////////////////////////////////////////////////
9779
9780
9781    var GroupRows = function GroupRows(table) {
9782
9783      this.table = table; //hold Tabulator object
9784
9785
9786      this.groupIDLookups = false; //enable table grouping and set field to group by
9787
9788
9789      this.startOpen = [function () {
9790        return false;
9791      }]; //starting state of group
9792
9793
9794      this.headerGenerator = [function () {
9795        return "";
9796      }];
9797
9798      this.groupList = []; //ordered list of groups
9799
9800
9801      this.groups = {}; //hold row groups
9802
9803    };
9804
9805    //initialize group configuration
9806
9807
9808    GroupRows.prototype.initialize = function () {
9809
9810      var self = this,
9811          groupBy = self.table.options.groupBy,
9812          startOpen = self.table.options.groupStartOpen,
9813          groupHeader = self.table.options.groupHeader;
9814
9815      self.headerGenerator = [function () {
9816        return "";
9817      }];
9818
9819      this.startOpen = [function () {
9820        return false;
9821      }]; //starting state of group
9822
9823
9824      self.table.extensions.localize.bind("groups.item", function (langValue, lang) {
9825
9826        self.headerGenerator[0] = function (value, count, data) {
9827          //header layout function
9828
9829
9830          return value + "<span>(" + count + " " + (count === 1 ? langValue : lang.groups.items) + ")</span>";
9831        };
9832      });
9833
9834      this.groupIDLookups = [];
9835
9836      if (!Array.isArray(groupBy)) {
9837
9838        groupBy = [groupBy];
9839      }
9840
9841      groupBy.forEach(function (group) {
9842
9843        var lookupFunc, column;
9844
9845        if (typeof group == "function") {
9846
9847          lookupFunc = group;
9848        } else {
9849
9850          column = self.table.columnManager.getColumnByField(group);
9851
9852          if (column) {
9853
9854            lookupFunc = function lookupFunc(data) {
9855
9856              return column.getFieldValue(data);
9857            };
9858          } else {
9859
9860            lookupFunc = function lookupFunc(data) {
9861
9862              return data[group];
9863            };
9864          }
9865        }
9866
9867        self.groupIDLookups.push(lookupFunc);
9868      });
9869
9870      if (startOpen) {
9871
9872        if (!Array.isArray(startOpen)) {
9873
9874          startOpen = [startOpen];
9875        }
9876
9877        startOpen.forEach(function (level) {
9878
9879          level = typeof level == "function" ? level : function () {
9880            return true;
9881          };
9882        });
9883
9884        self.startOpen = startOpen;
9885      }
9886
9887      if (groupHeader) {
9888
9889        self.headerGenerator = Array.isArray(groupHeader) ? groupHeader : [groupHeader];
9890      }
9891    };
9892
9893    //return appropriate rows with group headers
9894
9895
9896    GroupRows.prototype.getRows = function (rows) {
9897
9898      var self = this,
9899          groupComponents = [];
9900
9901      if (self.groupIDLookups.length) {
9902
9903        self.table.options.dataGrouping();
9904
9905        this.generateGroups(rows);
9906
9907        if (self.table.options.dataGrouped) {
9908
9909          self.groupList.forEach(function (group) {
9910
9911            groupComponents.push(group.getComponent());
9912          });
9913
9914          self.table.options.dataGrouped(groupComponents);
9915        };
9916
9917        return this.updateGroupRows();
9918      } else {
9919
9920        return rows.slice(0);
9921      }
9922    };
9923
9924    GroupRows.prototype.generateGroups = function (rows) {
9925
9926      var self = this,
9927          oldGroups = self.groups;
9928
9929      self.groups = {};
9930
9931      self.groupList = [];
9932
9933      rows.forEach(function (row) {
9934
9935        var groupID = self.groupIDLookups[0](row.getData());
9936
9937        if (!self.groups[groupID]) {
9938
9939          var group = new Group(self, false, 0, groupID, self.headerGenerator[0], oldGroups[groupID]);
9940
9941          self.groups[groupID] = group;
9942
9943          self.groupList.push(group);
9944        }
9945
9946        self.groups[groupID].addRow(row);
9947      });
9948    };
9949
9950    GroupRows.prototype.updateGroupRows = function (force) {
9951
9952      var self = this,
9953          output = [],
9954          oldRowCount;
9955
9956      self.groupList.forEach(function (group) {
9957
9958        output = output.concat(group.getHeadersAndRows());
9959      });
9960
9961      //force update of table display
9962
9963
9964      if (force) {
9965
9966        oldRowCount = self.table.rowManager.displayRowsCount;
9967
9968        self.table.rowManager.setDisplayRows(output);
9969
9970        self.table.rowManager._virtualRenderFill(Math.floor(self.table.rowManager.element.scrollTop() / self.table.rowManager.element[0].scrollHeight * oldRowCount));
9971      }
9972
9973      return output;
9974    };
9975
9976    GroupRows.prototype.scrollHeaders = function (left) {
9977
9978      this.groupList.forEach(function (group) {
9979
9980        group.arrowElement.css("margin-left", left);
9981      });
9982    };
9983
9984    Tabulator.registerExtension("groupRows", GroupRows);
9985
9986    var History = function History(table) {
9987
9988      this.table = table; //hold Tabulator object
9989
9990
9991      this.history = [];
9992
9993      this.index = -1;
9994    };
9995
9996    History.prototype.clear = function () {
9997
9998      this.history = [];
9999
10000      this.index = -1;
10001    };
10002
10003    History.prototype.action = function (type, component, data) {
10004
10005      if (this.index > -1) {
10006
10007        this.history = this.history.slice(0, this.index + 1);
10008      }
10009
10010      this.history.push({
10011
10012        type: type,
10013
10014        component: component,
10015
10016        data: data
10017
10018      });
10019
10020      this.index++;
10021    };
10022
10023    History.prototype.undo = function () {
10024
10025      if (this.index > -1) {
10026
10027        var action = this.history[this.index];
10028
10029        this.undoers[action.type].call(this, action);
10030
10031        this.index--;
10032
10033        return true;
10034      } else {
10035
10036        console.warn("History Undo Error - No more history to undo");
10037
10038        return false;
10039      }
10040    };
10041
10042    History.prototype.redo = function () {
10043
10044      if (this.history.length - 1 > this.index) {
10045
10046        this.index++;
10047
10048        var action = this.history[this.index];
10049
10050        this.redoers[action.type].call(this, action);
10051
10052        return true;
10053      } else {
10054
10055        console.warn("History Redo Error - No more history to redo");
10056
10057        return false;
10058      }
10059    };
10060
10061    History.prototype.undoers = {
10062
10063      cellEdit: function cellEdit(action) {
10064
10065        action.component.setValueProcessData(action.data.oldValue);
10066      },
10067
10068      rowAdd: function rowAdd(action) {
10069
10070        action.component.delete();
10071      },
10072
10073      rowDelete: function rowDelete(action) {
10074
10075        var newRow = this.table.rowManager.addRowActual(action.data.data, action.data.pos, action.data.index);
10076
10077        this._rebindRow(action.component, newRow);
10078      }
10079
10080    };
10081
10082    History.prototype.redoers = {
10083
10084      cellEdit: function cellEdit(action) {
10085
10086        action.component.setValueProcessData(action.data.newValue);
10087      },
10088
10089      rowAdd: function rowAdd(action) {
10090
10091        var newRow = this.table.rowManager.addRowActual(action.data.data, action.data.pos, action.data.index);
10092
10093        this._rebindRow(action.component, newRow);
10094      },
10095
10096      rowDelete: function rowDelete(action) {
10097
10098        action.component.delete();
10099      }
10100
10101    };
10102
10103    //rebind rows to new element after deletion
10104
10105
10106    History.prototype._rebindRow = function (oldRow, newRow) {
10107
10108      this.history.forEach(function (action) {
10109
10110        if (action.component instanceof Row) {
10111
10112          if (action.component === oldRow) {
10113
10114            action.component = newRow;
10115          }
10116        } else if (action.component instanceof Cell) {
10117
10118          if (action.component.row === oldRow) {
10119
10120            var field = action.component.column.getField();
10121
10122            if (field) {
10123
10124              action.component = newRow.getCell(field);
10125            }
10126          }
10127        }
10128      });
10129    };
10130
10131    Tabulator.registerExtension("history", History);
10132
10133    var HtmlTableImport = function HtmlTableImport(table) {
10134
10135      this.table = table; //hold Tabulator object
10136
10137    };
10138
10139    HtmlTableImport.prototype.parseTable = function () {
10140
10141      var self = this,
10142          element = self.table.element,
10143          options = self.table.options,
10144          columns = options.columns,
10145          headers = $("th", element),
10146          hasIndex = false,
10147          rows = $("tbody tr", element),
10148          data = [];
10149
10150      self.table.options.htmlImporting();
10151
10152      //check for tablator inline options
10153
10154
10155      self._extractOptions(element, options);
10156
10157      if (headers.length) {
10158
10159        self._extractHeaders(element);
10160      } else {
10161
10162        self._generateBlankHeaders(element);
10163      }
10164
10165      //iterate through table rows and build data set
10166
10167
10168      rows.each(function (rowIndex) {
10169
10170        var item = {};
10171
10172        //create index if the dont exist in table
10173
10174
10175        if (!hasIndex) {
10176
10177          item[options.index] = rowIndex;
10178        }
10179
10180        //add row data to item
10181
10182
10183        $("td", $(this)).each(function (colIndex) {
10184
10185          item[$(this).data("field")] = $(this).html();
10186        });
10187
10188        data.push(item);
10189      });
10190
10191      //create new element
10192
10193
10194      var newElement = $("<div></div>");
10195
10196      //transfer attributes to new element
10197
10198
10199      var attributes = element.prop("attributes");
10200
10201      // loop through attributes and apply them on div
10202
10203
10204      $.each(attributes, function () {
10205
10206        newElement.attr(this.name, this.value);
10207      });
10208
10209      // replace table with div element
10210
10211
10212      element.replaceWith(newElement);
10213
10214      options.data = data;
10215
10216      self.table.options.htmlImported();
10217
10218      newElement.tabulator(options);
10219    };
10220
10221    //extract tabluator attribute options
10222
10223
10224    HtmlTableImport.prototype._extractOptions = function (element, options) {
10225
10226      var self = this,
10227          attributes = element[0].attributes;
10228
10229      for (var index in attributes) {
10230
10231        var attrib = attributes[index];
10232
10233        var name;
10234
10235        if (attrib && attrib.name && attrib.name.indexOf("tabulator-") === 0) {
10236
10237          name = attrib.name.replace("tabulator-", "");
10238
10239          for (var key in options) {
10240
10241            if (key.toLowerCase() == name) {
10242
10243              options[key] = self._attribValue(attrib.value);
10244            }
10245          }
10246        }
10247      }
10248    };
10249
10250    //get value of attribute
10251
10252
10253    HtmlTableImport.prototype._attribValue = function (value) {
10254
10255      if (value === "true") {
10256
10257        return true;
10258      }
10259
10260      if (value === "false") {
10261
10262        return false;
10263      }
10264
10265      return value;
10266    };
10267
10268    //find column if it has already been defined
10269
10270
10271    HtmlTableImport.prototype._findCol = function (title) {
10272
10273      var self = this;
10274
10275      var match = self.table.options.columns.find(function (column) {
10276
10277        return column.title === title;
10278      });
10279
10280      return match || false;
10281    };
10282
10283    //extract column from headers
10284
10285
10286    HtmlTableImport.prototype._extractHeaders = function (element) {
10287
10288      var self = this,
10289          headers = $("th", element),
10290          rows = $("tbody tr", element);
10291
10292      headers.each(function (index) {
10293
10294        var header = $(this),
10295            exists = false,
10296            col = self._findCol(header.text()),
10297            width,
10298            attributes;
10299
10300        //list of possible attributes
10301
10302
10303        var attribList = ["title", "field", "align", "width", "minWidth", "frozen", "sortable", "sorter", "formatter", "cellClick", "cellDblClick", "cellContext", "editable", "editor", "visible", "cssClass", "tooltip", "tooltipHeader", "editableTitle", "headerFilter", "mutator", "mutateType", "accessor"];
10304
10305        if (col) {
10306
10307          exists = true;
10308        } else {
10309
10310          col = { title: header.text().trim() };
10311        }
10312
10313        if (!col.field) {
10314
10315          col.field = header.text().trim().toLowerCase().replace(" ", "_");
10316        }
10317
10318        width = header.attr("width");
10319
10320        if (width && !col.width) {
10321
10322          col.width = width;
10323        }
10324
10325        //check for tablator inline options
10326
10327
10328        attributes = header[0].attributes;
10329
10330        //check for tablator inline options
10331
10332
10333        for (var i in attributes) {
10334
10335          var attrib = attributes[i],
10336              name;
10337
10338          if (attrib && attrib.name && attrib.name.indexOf("tabulator-") === 0) {
10339
10340            name = attrib.name.replace("tabulator-", "");
10341
10342            attribList.forEach(function (key) {
10343
10344              if (key.toLowerCase() == name) {
10345
10346                col[key] = self._attribValue(attrib.value);
10347              }
10348            });
10349          }
10350        }
10351
10352        $("td:eq(" + index + ")", rows).data("field", col.field);
10353
10354        if (col.field == self.table.options.index) {
10355
10356          hasIndex = true;
10357        }
10358
10359        if (!exists) {
10360
10361          self.table.options.columns.push(col);
10362        }
10363      });
10364    };
10365
10366    //generate blank headers
10367
10368
10369    HtmlTableImport.prototype._generateBlankHeaders = function (element) {
10370
10371      var self = this;
10372
10373      var headers = $("tr:first td", element);
10374
10375      headers.each(function (index) {
10376
10377        var col = { title: "", field: "col" + index };
10378
10379        $("td:eq(" + index + ")", rows).data("field", col.field);
10380
10381        var width = $(this).attr("width");
10382
10383        if (width) {
10384
10385          col.width = width;
10386        }
10387
10388        self.table.options.columns.push(col);
10389      });
10390    };
10391
10392    Tabulator.registerExtension("htmlTableImport", HtmlTableImport);
10393
10394    var Keybindings = function Keybindings(table) {
10395
10396      this.table = table; //hold Tabulator object
10397
10398
10399      this.watchKeys = null;
10400
10401      this.pressedKeys = null;
10402    };
10403
10404    Keybindings.prototype.initialize = function () {
10405
10406      var bindings = this.table.options.keybindings,
10407          mergedBindings = {};
10408
10409      this.watchKeys = {};
10410
10411      this.pressedKeys = [];
10412
10413      if (bindings !== false) {
10414
10415        for (var key in this.bindings) {
10416
10417          mergedBindings[key] = this.bindings[key];
10418        }
10419
10420        if (Object.keys(bindings).length) {
10421
10422          for (var _key in bindings) {
10423
10424            mergedBindings[_key] = bindings[_key];
10425          }
10426        }
10427
10428        this.mapBindings(mergedBindings);
10429
10430        this.bindEvents();
10431      }
10432    };
10433
10434    Keybindings.prototype.mapBindings = function (bindings) {
10435      var _this = this;
10436
10437      var self = this;
10438
10439      var _loop2 = function _loop2(key) {
10440
10441        if (_this.actions[key]) {
10442
10443          if (bindings[key]) {
10444
10445            if (_typeof(bindings[key]) !== "object") {
10446
10447              bindings[key] = [bindings[key]];
10448            }
10449
10450            bindings[key].forEach(function (binding) {
10451
10452              self.mapBinding(key, binding);
10453            });
10454          }
10455        } else {
10456
10457          console.warn("Key Binding Error - no such action:", key);
10458        }
10459      };
10460
10461      for (var key in bindings) {
10462        _loop2(key);
10463      }
10464    };
10465
10466    Keybindings.prototype.mapBinding = function (action, symbolsList) {
10467
10468      var self = this;
10469
10470      var binding = {
10471
10472        action: this.actions[action],
10473
10474        keys: [],
10475
10476        ctrl: false,
10477
10478        shift: false
10479
10480      };
10481
10482      var symbols = symbolsList.toString().toLowerCase().split(" ").join("").split("+");
10483
10484      symbols.forEach(function (symbol) {
10485
10486        switch (symbol) {
10487
10488          case "ctrl":
10489
10490            binding.ctrl = true;
10491
10492            break;
10493
10494          case "shift":
10495
10496            binding.shift = true;
10497
10498            break;
10499
10500          default:
10501
10502            symbol = parseInt(symbol);
10503
10504            binding.keys.push(symbol);
10505
10506            if (!self.watchKeys[symbol]) {
10507
10508              self.watchKeys[symbol] = [];
10509            }
10510
10511            self.watchKeys[symbol].push(binding);
10512
10513        }
10514      });
10515    };
10516
10517    Keybindings.prototype.bindEvents = function () {
10518
10519      var self = this;
10520
10521      this.table.element.on("keydown", function (e) {
10522
10523        var code = e.keyCode;
10524
10525        var bindings = self.watchKeys[code];
10526
10527        if (bindings) {
10528
10529          self.pressedKeys.push(code);
10530
10531          bindings.forEach(function (binding) {
10532
10533            self.checkBinding(e, binding);
10534          });
10535        }
10536      });
10537
10538      this.table.element.on("keyup", function (e) {
10539
10540        var code = e.keyCode;
10541
10542        var bindings = self.watchKeys[code];
10543
10544        if (bindings) {
10545
10546          var index = self.pressedKeys.indexOf(code);
10547
10548          if (index > -1) {
10549
10550            self.pressedKeys.splice(index, 1);
10551          }
10552        }
10553      });
10554    };
10555
10556    Keybindings.prototype.checkBinding = function (e, binding) {
10557
10558      var self = this,
10559          match = true;
10560
10561      if (e.ctrlKey == binding.ctrl && e.shiftKey == binding.shift) {
10562
10563        binding.keys.forEach(function (key) {
10564
10565          var index = self.pressedKeys.indexOf(key);
10566
10567          if (index == -1) {
10568
10569            match = false;
10570          }
10571        });
10572
10573        if (match) {
10574
10575          binding.action.call(self, e);
10576        }
10577
10578        return true;
10579      }
10580
10581      return false;
10582    };
10583
10584    //default bindings
10585
10586
10587    Keybindings.prototype.bindings = {
10588
10589      navPrev: "shift + 9",
10590
10591      navNext: 9,
10592
10593      navUp: 38,
10594
10595      navDown: 40,
10596
10597      scrollPageUp: 33,
10598
10599      scrollPageDown: 34,
10600
10601      scrollToStart: 36,
10602
10603      scrollToEnd: 35,
10604
10605      undo: "ctrl + 90",
10606
10607      redo: "ctrl + 89"
10608
10609    };
10610
10611    //default actions
10612
10613
10614    Keybindings.prototype.actions = {
10615
10616      keyBlock: function keyBlock(e) {
10617
10618        e.stopPropagation();
10619
10620        e.preventDefault();
10621      },
10622
10623      scrollPageUp: function scrollPageUp(e) {
10624
10625        var rowManager = this.table.rowManager,
10626            newPos = rowManager.scrollTop - rowManager.height,
10627            scrollMax = rowManager.element[0].scrollHeight;
10628
10629        e.preventDefault();
10630
10631        if (rowManager.displayRowsCount) {
10632
10633          if (newPos >= 0) {
10634
10635            rowManager.element.scrollTop(newPos);
10636          } else {
10637
10638            rowManager.scrollToRow(rowManager.displayRows[0]);
10639          }
10640        }
10641
10642        this.table.element.focus();
10643      },
10644
10645      scrollPageDown: function scrollPageDown(e) {
10646
10647        var rowManager = this.table.rowManager,
10648            newPos = rowManager.scrollTop + rowManager.height,
10649            scrollMax = rowManager.element[0].scrollHeight;
10650
10651        e.preventDefault();
10652
10653        if (rowManager.displayRowsCount) {
10654
10655          if (newPos <= scrollMax) {
10656
10657            rowManager.element.scrollTop(newPos);
10658          } else {
10659
10660            rowManager.scrollToRow(rowManager.displayRows[rowManager.displayRows.length - 1]);
10661          }
10662        }
10663
10664        this.table.element.focus();
10665      },
10666
10667      scrollToStart: function scrollToStart(e) {
10668
10669        var rowManager = this.table.rowManager;
10670
10671        e.preventDefault();
10672
10673        if (rowManager.displayRowsCount) {
10674
10675          rowManager.scrollToRow(rowManager.displayRows[0]);
10676        }
10677
10678        this.table.element.focus();
10679      },
10680
10681      scrollToEnd: function scrollToEnd(e) {
10682
10683        var rowManager = this.table.rowManager;
10684
10685        e.preventDefault();
10686
10687        if (rowManager.displayRowsCount) {
10688
10689          rowManager.scrollToRow(rowManager.displayRows[rowManager.displayRows.length - 1]);
10690        }
10691
10692        this.table.element.focus();
10693      },
10694
10695      navPrev: function navPrev(e) {
10696
10697        var cell = false;
10698
10699        if (this.table.extExists("edit")) {
10700
10701          cell = this.table.extensions.edit.currentCell;
10702
10703          if (cell) {
10704
10705            e.preventDefault();
10706
10707            cell.nav().prev();
10708          }
10709        }
10710      },
10711
10712      navNext: function navNext(e) {
10713
10714        var cell = false;
10715
10716        if (this.table.extExists("edit")) {
10717
10718          cell = this.table.extensions.edit.currentCell;
10719
10720          if (cell) {
10721
10722            e.preventDefault();
10723
10724            cell.nav().next();
10725          }
10726        }
10727      },
10728
10729      navLeft: function navLeft(e) {
10730
10731        var cell = false;
10732
10733        if (this.table.extExists("edit")) {
10734
10735          cell = this.table.extensions.edit.currentCell;
10736
10737          if (cell) {
10738
10739            e.preventDefault();
10740
10741            cell.nav().left();
10742          }
10743        }
10744      },
10745
10746      navRight: function navRight(e) {
10747
10748        var cell = false;
10749
10750        if (this.table.extExists("edit")) {
10751
10752          cell = this.table.extensions.edit.currentCell;
10753
10754          if (cell) {
10755
10756            e.preventDefault();
10757
10758            cell.nav().right();
10759          }
10760        }
10761      },
10762
10763      navUp: function navUp(e) {
10764
10765        var cell = false;
10766
10767        if (this.table.extExists("edit")) {
10768
10769          cell = this.table.extensions.edit.currentCell;
10770
10771          if (cell) {
10772
10773            e.preventDefault();
10774
10775            cell.nav().up();
10776          }
10777        }
10778      },
10779
10780      navDown: function navDown(e) {
10781
10782        var cell = false;
10783
10784        if (this.table.extExists("edit")) {
10785
10786          cell = this.table.extensions.edit.currentCell;
10787
10788          if (cell) {
10789
10790            e.preventDefault();
10791
10792            cell.nav().down();
10793          }
10794        }
10795      },
10796
10797      undo: function undo(e) {
10798
10799        var cell = false;
10800
10801        if (this.table.options.history && this.table.extExists("history") && this.table.extExists("edit")) {
10802
10803          cell = this.table.extensions.edit.currentCell;
10804
10805          if (!cell) {
10806
10807            e.preventDefault();
10808
10809            this.table.extensions.history.undo();
10810          }
10811        }
10812      },
10813
10814      redo: function redo(e) {
10815
10816        var cell = false;
10817
10818        if (this.table.options.history && this.table.extExists("history") && this.table.extExists("edit")) {
10819
10820          cell = this.table.extensions.edit.currentCell;
10821
10822          if (!cell) {
10823
10824            e.preventDefault();
10825
10826            this.table.extensions.history.redo();
10827          }
10828        }
10829      }
10830
10831    };
10832
10833    Tabulator.registerExtension("keybindings", Keybindings);
10834
10835    var MoveColumns = function MoveColumns(table) {
10836
10837      this.table = table; //hold Tabulator object
10838
10839
10840      this.placeholderElement = $("<div class='tabulator-col tabulator-col-placeholder'></div>");
10841
10842      this.hoverElement = $(); //floating column header element
10843
10844
10845      this.checkTimeout = false; //click check timeout holder
10846
10847
10848      this.checkPeriod = 250; //period to wait on mousedown to consider this a move and not a click
10849
10850
10851      this.moving = false; //currently moving column
10852
10853
10854      this.toCol = false; //destination column
10855
10856
10857      this.toColAfter = false; //position of moving column relative to the desitnation column
10858
10859
10860      this.startX = 0; //starting position within header element
10861
10862
10863      this.autoScrollMargin = 40; //auto scroll on edge when within margin
10864
10865
10866      this.autoScrollStep = 5; //auto scroll distance in pixels
10867
10868
10869      this.autoScrollTimeout = false; //auto scroll timeout
10870
10871
10872      this.moveHover = this.moveHover.bind(this);
10873
10874      this.endMove = this.endMove.bind(this);
10875    };
10876
10877    MoveColumns.prototype.initializeColumn = function (column) {
10878
10879      var self = this,
10880          config = {};
10881
10882      if (!column.extensions.frozen) {
10883
10884        config.mousemove = function (e) {
10885
10886          if (column.parent === self.moving.parent) {
10887
10888            if (e.pageX - column.element.offset().left + self.table.columnManager.element.scrollLeft() > column.getWidth() / 2) {
10889
10890              if (self.toCol !== column || !self.toColAfter) {
10891
10892                column.element.after(self.placeholderElement);
10893
10894                self.moveColumn(column, true);
10895              }
10896            } else {
10897
10898              if (self.toCol !== column || self.toColAfter) {
10899
10900                column.element.before(self.placeholderElement);
10901
10902                self.moveColumn(column, false);
10903              }
10904            }
10905          }
10906        }.bind(self);
10907
10908        column.getElement().on("mousedown", function (e) {
10909
10910          self.checkTimeout = setTimeout(function () {
10911
10912            self.startMove(e, column);
10913          }, self.checkPeriod);
10914        });
10915
10916        column.getElement().on("mouseup", function (e) {
10917
10918          if (self.checkTimeout) {
10919
10920            clearTimeout(self.checkTimeout);
10921          }
10922        });
10923      }
10924
10925      column.extensions.moveColumn = config;
10926    };
10927
10928    MoveColumns.prototype.startMove = function (e, column) {
10929
10930      var self = this,
10931          element = column.getElement();
10932
10933      self.moving = column;
10934
10935      self.startX = e.pageX - element.offset().left;
10936
10937      self.table.element.addClass("tabulator-block-select");
10938
10939      //create placeholder
10940
10941
10942      self.placeholderElement.css({
10943
10944        width: column.getWidth(),
10945
10946        height: column.getHeight()
10947
10948      });
10949
10950      element.before(self.placeholderElement);
10951
10952      element.detach();
10953
10954      //create hover element
10955
10956
10957      self.hoverElement = element.clone();
10958
10959      self.hoverElement.addClass("tabulator-moving");
10960
10961      self.table.columnManager.getElement().append(self.hoverElement);
10962
10963      self.hoverElement.css({
10964
10965        "left": 0,
10966
10967        "bottom": 0
10968
10969      });
10970
10971      self._bindMouseMove();
10972
10973      $("body").on("mousemove", self.moveHover);
10974
10975      $("body").on("mouseup", self.endMove);
10976
10977      self.moveHover(e);
10978    };
10979
10980    MoveColumns.prototype._bindMouseMove = function () {
10981
10982      var self = this;
10983
10984      self.table.columnManager.columnsByIndex.forEach(function (column) {
10985
10986        if (column.extensions.moveColumn.mousemove) {
10987
10988          column.element.on("mousemove", column.extensions.moveColumn.mousemove);
10989        }
10990      });
10991    };
10992
10993    MoveColumns.prototype._unbindMouseMove = function () {
10994
10995      var self = this;
10996
10997      self.table.columnManager.columnsByIndex.forEach(function (column) {
10998
10999        if (column.extensions.moveColumn.mousemove) {
11000
11001          column.element.off("mousemove", column.extensions.moveColumn.mousemove);
11002        }
11003      });
11004    };
11005
11006    MoveColumns.prototype.moveColumn = function (column, after) {
11007
11008      var self = this,
11009          movingCells = this.moving.getCells();
11010
11011      self.toCol = column;
11012
11013      self.toColAfter = after;
11014
11015      if (after) {
11016
11017        column.getCells().forEach(function (cell, i) {
11018
11019          cell.getElement().after(movingCells[i].getElement());
11020        });
11021      } else {
11022
11023        column.getCells().forEach(function (cell, i) {
11024
11025          cell.getElement().before(movingCells[i].getElement());
11026        });
11027      }
11028    };
11029
11030    MoveColumns.prototype.endMove = function (column) {
11031
11032      var self = this;
11033
11034      self._unbindMouseMove();
11035
11036      self.placeholderElement.after(self.moving.getElement());
11037
11038      self.placeholderElement.detach();
11039
11040      self.hoverElement.detach();
11041
11042      self.table.element.removeClass("tabulator-block-select");
11043
11044      if (self.toCol) {
11045
11046        self.table.columnManager.moveColumn(self.moving, self.toCol, self.toColAfter);
11047      }
11048
11049      self.moving = false;
11050
11051      self.toCol = false;
11052
11053      self.toColAfter = false;
11054
11055      $("body").off("mousemove", self.moveHover);
11056
11057      $("body").off("mouseup", self.endMove);
11058    };
11059
11060    MoveColumns.prototype.moveHover = function (e) {
11061
11062      var self = this,
11063          columnHolder = self.table.columnManager.getElement(),
11064          scrollLeft = columnHolder.scrollLeft(),
11065          xPos = e.pageX - columnHolder.offset().left + scrollLeft,
11066          scrollPos;
11067
11068      self.hoverElement.css({
11069
11070        "left": xPos - self.startX
11071
11072      });
11073
11074      if (xPos - scrollLeft < self.autoScrollMargin) {
11075
11076        if (!self.autoScrollTimeout) {
11077
11078          self.autoScrollTimeout = setTimeout(function () {
11079
11080            scrollPos = Math.max(0, scrollLeft - 5);
11081
11082            self.table.rowManager.getElement().scrollLeft(scrollPos);
11083
11084            self.autoScrollTimeout = false;
11085          }, 1);
11086        }
11087      }
11088
11089      if (scrollLeft + columnHolder.innerWidth() - xPos < self.autoScrollMargin) {
11090
11091        if (!self.autoScrollTimeout) {
11092
11093          self.autoScrollTimeout = setTimeout(function () {
11094
11095            scrollPos = Math.min(columnHolder.innerWidth(), scrollLeft + 5);
11096
11097            self.table.rowManager.getElement().scrollLeft(scrollPos);
11098
11099            self.autoScrollTimeout = false;
11100          }, 1);
11101        }
11102      }
11103    };
11104
11105    Tabulator.registerExtension("moveColumn", MoveColumns);
11106
11107    var MoveRows = function MoveRows(table) {
11108
11109      this.table = table; //hold Tabulator object
11110
11111
11112      this.placeholderElement = $("<div class='tabulator-row tabulator-row-placeholder'></div>");
11113
11114      this.hoverElement = $(); //floating row header element
11115
11116
11117      this.checkTimeout = false; //click check timeout holder
11118
11119
11120      this.checkPeriod = 150; //period to wait on mousedown to consider this a move and not a click
11121
11122
11123      this.moving = false; //currently moving row
11124
11125
11126      this.toRow = false; //destination row
11127
11128
11129      this.toRowAfter = false; //position of moving row relative to the desitnation row
11130
11131
11132      this.hasHandle = false; //row has handle instead of fully movable row
11133
11134
11135      this.startY = 0; //starting position within header element
11136
11137
11138      this.moveHover = this.moveHover.bind(this);
11139
11140      this.endMove = this.endMove.bind(this);
11141    };
11142
11143    MoveRows.prototype.setHandle = function (handle) {
11144
11145      this.hasHandle = handle;
11146    };
11147
11148    MoveRows.prototype.initializeRow = function (row) {
11149
11150      var self = this,
11151          config = {};
11152
11153      config.mousemove = function (e) {
11154
11155        if (e.pageY - row.element.offset().top + self.table.rowManager.element.scrollTop() > row.getHeight() / 2) {
11156
11157          if (self.toRow !== row || !self.toRowAfter) {
11158
11159            row.element.after(self.placeholderElement);
11160
11161            self.moveRow(row, true);
11162          }
11163        } else {
11164
11165          if (self.toRow !== row || self.toRowAfter) {
11166
11167            row.element.before(self.placeholderElement);
11168
11169            self.moveRow(row, false);
11170          }
11171        }
11172      }.bind(self);
11173
11174      if (!this.hasHandle) {
11175
11176        row.getElement().on("mousedown", function (e) {
11177
11178          self.checkTimeout = setTimeout(function () {
11179
11180            self.startMove(e, row);
11181          }, self.checkPeriod);
11182        });
11183
11184        row.getElement().on("mouseup", function (e) {
11185
11186          if (self.checkTimeout) {
11187
11188            clearTimeout(self.checkTimeout);
11189          }
11190        });
11191      }
11192
11193      row.extensions.moveRow = config;
11194    };
11195
11196    MoveRows.prototype.initializeCell = function (cell) {
11197
11198      var self = this;
11199
11200      cell.getElement().on("mousedown", function (e) {
11201
11202        self.checkTimeout = setTimeout(function () {
11203
11204          self.startMove(e, cell.row);
11205        }, self.checkPeriod);
11206      });
11207
11208      cell.getElement().on("mouseup", function (e) {
11209
11210        if (self.checkTimeout) {
11211
11212          clearTimeout(self.checkTimeout);
11213        }
11214      });
11215    };
11216
11217    MoveRows.prototype._bindMouseMove = function () {
11218
11219      var self = this;
11220
11221      self.table.rowManager.displayRows.forEach(function (row) {
11222
11223        if (row.type === "row" && row.extensions.moveRow.mousemove) {
11224
11225          row.element.on("mousemove", row.extensions.moveRow.mousemove);
11226        }
11227      });
11228    };
11229
11230    MoveRows.prototype._unbindMouseMove = function () {
11231
11232      var self = this;
11233
11234      self.table.rowManager.displayRows.forEach(function (row) {
11235
11236        if (row.type === "row" && row.extensions.moveRow.mousemove) {
11237
11238          row.element.off("mousemove", row.extensions.moveRow.mousemove);
11239        }
11240      });
11241    };
11242
11243    MoveRows.prototype.startMove = function (e, row) {
11244
11245      var self = this,
11246          element = row.getElement();
11247
11248      self.moving = row;
11249
11250      self.startY = e.pageY - element.offset().top;
11251
11252      self.table.element.addClass("tabulator-block-select");
11253
11254      //create placeholder
11255
11256
11257      self.placeholderElement.css({
11258
11259        width: row.getWidth(),
11260
11261        height: row.getHeight()
11262
11263      });
11264
11265      element.before(self.placeholderElement);
11266
11267      element.detach();
11268
11269      //create hover element
11270
11271
11272      self.hoverElement = element.clone();
11273
11274      self.hoverElement.addClass("tabulator-moving");
11275
11276      self.table.rowManager.getTableElement().append(self.hoverElement);
11277
11278      self.hoverElement.css({
11279
11280        "left": 0,
11281
11282        "top": 0
11283
11284      });
11285
11286      self._bindMouseMove();
11287
11288      $("body").on("mousemove", self.moveHover);
11289
11290      $("body").on("mouseup", self.endMove);
11291
11292      self.moveHover(e);
11293    };
11294
11295    MoveRows.prototype.endMove = function (column) {
11296
11297      var self = this;
11298
11299      self._unbindMouseMove();
11300
11301      self.placeholderElement.after(self.moving.getElement());
11302
11303      self.placeholderElement.detach();
11304
11305      self.hoverElement.detach();
11306
11307      self.table.element.removeClass("tabulator-block-select");
11308
11309      if (self.toRow) {
11310
11311        self.table.rowManager.moveRow(self.moving, self.toRow, self.toRowAfter);
11312      }
11313
11314      self.moving = false;
11315
11316      self.toRow = false;
11317
11318      self.toRowAfter = false;
11319
11320      $("body").off("mousemove", self.moveHover);
11321
11322      $("body").off("mouseup", self.endMove);
11323    };
11324
11325    MoveRows.prototype.moveRow = function (row, after) {
11326
11327      var self = this;
11328
11329      self.toRow = row;
11330
11331      self.toRowAfter = after;
11332    };
11333
11334    MoveRows.prototype.moveHover = function (e) {
11335
11336      var self = this,
11337          rowHolder = self.table.rowManager.getElement(),
11338          scrollTop = rowHolder.scrollTop(),
11339          yPos = e.pageY - rowHolder.offset().top + scrollTop,
11340          scrollPos;
11341
11342      self.hoverElement.css({
11343
11344        "top": yPos - self.startY
11345
11346      });
11347    };
11348
11349    Tabulator.registerExtension("moveRow", MoveRows);
11350
11351    var Mutator = function Mutator(table) {
11352
11353      this.table = table; //hold Tabulator object
11354
11355    };
11356
11357    //initialize column mutator
11358
11359
11360    Mutator.prototype.initializeColumn = function (column) {
11361
11362      var config = { mutator: false, type: column.definition.mutateType, params: column.definition.mutatorParams || {} };
11363
11364      //set column mutator
11365
11366
11367      switch (_typeof(column.definition.mutator)) {
11368
11369        case "string":
11370
11371          if (this.mutators[column.definition.mutator]) {
11372
11373            config.mutator = this.mutators[column.definition.mutator];
11374          } else {
11375
11376            console.warn("Mutator Error - No such mutator found, ignoring: ", column.definition.mutator);
11377          }
11378
11379          break;
11380
11381        case "function":
11382
11383          config.mutator = column.definition.mutator;
11384
11385          break;
11386
11387      }
11388
11389      if (config.mutator) {
11390
11391        column.extensions.mutate = config;
11392      }
11393    };
11394
11395    //apply mutator to row
11396
11397
11398    Mutator.prototype.transformRow = function (data) {
11399
11400      var self = this;
11401
11402      self.table.columnManager.traverse(function (column) {
11403
11404        var field;
11405
11406        if (column.extensions.mutate) {
11407
11408          field = column.getField();
11409
11410          if (column.extensions.mutate.type != "edit") {
11411
11412            column.setFieldValue(data, column.extensions.mutate.mutator(column.getFieldValue(data), data, "data", column.extensions.mutate.params));
11413          }
11414        }
11415      });
11416
11417      return data;
11418    };
11419
11420    //apply mutator to new cell value
11421
11422
11423    Mutator.prototype.transformCell = function (cell, value) {
11424
11425      return cell.column.extensions.mutate.mutator(value, cell.row.getData(), "edit", cell.column.extensions.mutate.params, cell.getComponent());
11426    };
11427
11428    //default mutators
11429
11430
11431    Mutator.prototype.mutators = {};
11432
11433    Tabulator.registerExtension("mutator", Mutator);
11434
11435    var Page = function Page(table) {
11436
11437      this.table = table; //hold Tabulator object
11438
11439
11440      this.element = $("<span class='tabulator-paginator'></span>");
11441
11442      this.pagesElement = $("<span class='tabulator-pages'></span>");
11443
11444      this.firstBut = $("<button class='tabulator-page' data-page='first' role='button' aria-label='' title=''></button>");
11445
11446      this.prevBut = $("<button class='tabulator-page' data-page='prev' role='button' aria-label='' title=''></button>");
11447
11448      this.nextBut = $("<button class='tabulator-page' data-page='next' role='button' aria-label='' title=''></button>");
11449
11450      this.lastBut = $("<button class='tabulator-page' data-page='last' role='button' aria-label='' title=''></button>");
11451
11452      this.mode = "local";
11453
11454      this.size = 0;
11455
11456      this.page = 1;
11457
11458      this.max = 1;
11459
11460      this.paginator = false;
11461    };
11462
11463    //setup pageination
11464
11465
11466    Page.prototype.initialize = function () {
11467
11468      var self = this;
11469
11470      //update param names
11471
11472
11473      for (var key in self.table.options.paginationDataSent) {
11474
11475        self.paginationDataSentNames[key] = self.table.options.paginationDataSent[key];
11476      }
11477
11478      for (var _key2 in self.table.options.paginationDataReceived) {
11479
11480        self.paginationDataReceivedNames[_key2] = self.table.options.paginationDataReceived[_key2];
11481      }
11482
11483      if (self.table.options.paginator) {
11484
11485        self.paginator = self.table.options.paginator;
11486      }
11487
11488      //build pagination element
11489
11490
11491      //bind localizations
11492
11493
11494      self.table.extensions.localize.bind("pagination.first", function (value) {
11495
11496        self.firstBut.html(value);
11497      });
11498
11499      self.table.extensions.localize.bind("pagination.first_title", function (value) {
11500
11501        self.firstBut.attr("aria-label", value).attr("title", value);
11502      });
11503
11504      self.table.extensions.localize.bind("pagination.prev", function (value) {
11505
11506        self.prevBut.html(value);
11507      });
11508
11509      self.table.extensions.localize.bind("pagination.prev_title", function (value) {
11510
11511        self.prevBut.attr("aria-label", value).attr("title", value);
11512      });
11513
11514      self.table.extensions.localize.bind("pagination.next", function (value) {
11515
11516        self.nextBut.html(value);
11517      });
11518
11519      self.table.extensions.localize.bind("pagination.next_title", function (value) {
11520
11521        self.nextBut.attr("aria-label", value).attr("title", value);
11522      });
11523
11524      self.table.extensions.localize.bind("pagination.last", function (value) {
11525
11526        self.lastBut.html(value);
11527      });
11528
11529      self.table.extensions.localize.bind("pagination.last_title", function (value) {
11530
11531        self.lastBut.attr("aria-label", value).attr("title", value);
11532      });
11533
11534      //click bindings
11535
11536
11537      self.firstBut.on("click", function () {
11538
11539        self.setPage(1);
11540      });
11541
11542      self.prevBut.on("click", function () {
11543
11544        self.previousPage();
11545      });
11546
11547      self.nextBut.on("click", function () {
11548
11549        self.nextPage();
11550      });
11551
11552      self.lastBut.on("click", function () {
11553
11554        self.setPage(self.max);
11555      });
11556
11557      if (self.table.options.paginationElement) {
11558
11559        self.element = self.table.options.paginationElement;
11560      }
11561
11562      //append to DOM
11563
11564
11565      self.element.append(self.firstBut);
11566
11567      self.element.append(self.prevBut);
11568
11569      self.element.append(self.pagesElement);
11570
11571      self.element.append(self.nextBut);
11572
11573      self.element.append(self.lastBut);
11574
11575      if (!self.table.options.paginationElement) {
11576
11577        self.table.footerManager.append(self.element, self);
11578      }
11579
11580      //set default values
11581
11582
11583      self.mode = self.table.options.pagination;
11584
11585      self.size = self.table.options.paginationSize || Math.floor(self.table.rowManager.getElement().innerHeight() / 26);
11586    };
11587
11588    //calculate maximum page from number of rows
11589
11590
11591    Page.prototype.setMaxRows = function (rowCount) {
11592
11593      if (!rowCount) {
11594
11595        this.max = 1;
11596      } else {
11597
11598        this.max = Math.ceil(rowCount / this.size);
11599      }
11600
11601      if (this.page > this.max) {
11602
11603        this.page = this.max;
11604      }
11605    };
11606
11607    //reset to first page without triggering action
11608
11609
11610    Page.prototype.reset = function (force) {
11611
11612      if (this.mode == "local" || force) {
11613
11614        this.page = 1;
11615      }
11616
11617      return true;
11618    };
11619
11620    //set the maxmum page
11621
11622
11623    Page.prototype.setMaxPage = function (max) {
11624
11625      this.max = max || 1;
11626
11627      if (this.page > this.max) {
11628
11629        this.page = this.max;
11630
11631        this.trigger();
11632      }
11633    };
11634
11635    //set current page number
11636
11637
11638    Page.prototype.setPage = function (page) {
11639
11640      if (page > 0 && page <= this.max) {
11641
11642        this.page = page;
11643
11644        this.trigger();
11645
11646        return true;
11647      } else {
11648
11649        console.warn("Pagination Error - Requested page is out of range of 1 - " + this.max + ":", page);
11650
11651        return false;
11652      }
11653    };
11654
11655    Page.prototype.setPageSize = function (size) {
11656
11657      if (size > 0) {
11658
11659        this.size = size;
11660      }
11661    };
11662
11663    //setup the pagination buttons
11664
11665
11666    Page.prototype._setPageButtons = function () {
11667
11668      var self = this;
11669
11670      var min = this.page < this.max - 2 ? this.page - 2 : this.page - (4 - (this.max - this.page));
11671
11672      var max = this.page > 3 ? this.page + 2 : this.page + (5 - this.page);
11673
11674      self.pagesElement.empty();
11675
11676      if (self.page == 1) {
11677
11678        self.firstBut.prop("disabled", true);
11679
11680        self.prevBut.prop("disabled", true);
11681      } else {
11682
11683        self.firstBut.prop("disabled", false);
11684
11685        self.prevBut.prop("disabled", false);
11686      }
11687
11688      if (self.page == self.max) {
11689
11690        self.lastBut.prop("disabled", true);
11691
11692        self.nextBut.prop("disabled", true);
11693      } else {
11694
11695        self.lastBut.prop("disabled", false);
11696
11697        self.nextBut.prop("disabled", false);
11698      }
11699
11700      for (var i = min; i <= max; i++) {
11701
11702        if (i > 0 && i <= self.max) {
11703
11704          self.pagesElement.append(self._generatePageButton(i));
11705        }
11706      }
11707
11708      this.footerRedraw();
11709    };
11710
11711    Page.prototype._generatePageButton = function (page) {
11712
11713      var self = this;
11714
11715      var button = $("<button class='tabulator-page " + (page == self.page ? "active" : "") + "' data-page='" + page + "' role='button' arpagea-label='Show Page " + page + "'>" + page + "</button>");
11716
11717      button.on("click", function (e) {
11718
11719        self.setPage(page);
11720      });
11721
11722      return button;
11723    };
11724
11725    //previous page
11726
11727
11728    Page.prototype.previousPage = function () {
11729
11730      if (this.page > 1) {
11731
11732        this.page--;
11733
11734        this.trigger();
11735
11736        return true;
11737      } else {
11738
11739        console.warn("Pagination Error - Previous page would be less than page 1:", 0);
11740
11741        return false;
11742      }
11743    };
11744
11745    //next page
11746
11747
11748    Page.prototype.nextPage = function () {
11749
11750      if (this.page < this.max) {
11751
11752        this.page++;
11753
11754        this.trigger();
11755
11756        return true;
11757      } else {
11758
11759        console.warn("Pagination Error - Next page would be greater than maximum page of " + this.max + ":", this.max + 1);
11760
11761        return false;
11762      }
11763    };
11764
11765    //return current page number
11766
11767
11768    Page.prototype.getPage = function () {
11769
11770      return this.page;
11771    };
11772
11773    //return max page number
11774
11775
11776    Page.prototype.getPageMax = function () {
11777
11778      return this.max;
11779    };
11780
11781    Page.prototype.getMode = function () {
11782
11783      return this.mode;
11784    };
11785
11786    //return appropriate rows for current page
11787
11788
11789    Page.prototype.getRows = function (data) {
11790
11791      var output, start, end;
11792
11793      if (this.mode == "local") {
11794
11795        output = [];
11796
11797        start = this.size * (this.page - 1);
11798
11799        end = start + this.size;
11800
11801        this._setPageButtons();
11802
11803        for (var i = start; i < end; i++) {
11804
11805          if (data[i]) {
11806
11807            output.push(data[i]);
11808          }
11809        }
11810
11811        return output;
11812      } else {
11813
11814        this._setPageButtons();
11815
11816        return data.slice(0);
11817      }
11818    };
11819
11820    Page.prototype.trigger = function () {
11821
11822      switch (this.mode) {
11823
11824        case "local":
11825
11826          this.table.rowManager.refreshActiveData();
11827
11828          this.table.options.pageLoaded(this.getPage());
11829
11830          break;
11831
11832        case "remote":
11833
11834          this._getRemotePage();
11835
11836          break;
11837
11838        default:
11839
11840          console.warn("Pagination Error - no such pagination mode:", this.mode);
11841
11842      }
11843    };
11844
11845    Page.prototype._getRemotePage = function () {
11846
11847      if (this.table.extExists("ajax", true)) {
11848
11849        if (this.paginator) {
11850
11851          this._getRemotePagePaginator();
11852        } else {
11853
11854          this._getRemotePageAuto();
11855        }
11856      }
11857    };
11858
11859    Page.prototype._getRemotePagePaginator = function () {
11860
11861      var self = this,
11862          ajax = self.table.extensions.ajax,
11863          oldUrl = ajax.getUrl();
11864
11865      ajax.setUrl(self.paginator(ajax.getUrl(), self.page, self.size, ajax.getParams()));
11866
11867      ajax.sendRequest(function (data) {
11868
11869        self._parseRemoteData(data);
11870      });
11871
11872      ajax.setUrl(oldUrl);
11873    };
11874
11875    Page.prototype._getRemotePageAuto = function () {
11876
11877      var self = this,
11878          oldParams,
11879          pageParams;
11880
11881      //record old params and restore after request has been made
11882
11883
11884      oldParams = $.extend(true, {}, self.table.extensions.ajax.getParams());
11885
11886      pageParams = self.table.extensions.ajax.getParams();
11887
11888      //configure request params
11889
11890
11891      pageParams[this.paginationDataSentNames.page] = self.page;
11892
11893      //set page size if defined
11894
11895
11896      if (this.size) {
11897
11898        pageParams[this.paginationDataSentNames.size] = this.size;
11899      }
11900
11901      //set sort data if defined
11902
11903
11904      if (this.table.extExists("sort")) {
11905
11906        var sorters = self.table.extensions.sort.getSort();
11907
11908        if (sorters[0] && typeof sorters[0].column != "function") {
11909
11910          pageParams[this.paginationDataSentNames.sort] = sorters[0].column.getField();
11911
11912          pageParams[this.paginationDataSentNames.sort_dir] = sorters[0].dir;
11913        }
11914      }
11915
11916      //set filter data if defined
11917
11918
11919      if (this.table.extExists("filter")) {
11920
11921        var filters = self.table.extensions.filter.getFilter();
11922
11923        if (filters[0] && typeof filters[0].field == "string") {
11924
11925          pageParams[this.paginationDataSentNames.filter] = filters[0].field;
11926
11927          pageParams[this.paginationDataSentNames.filter_type] = filters[0].type;
11928
11929          pageParams[this.paginationDataSentNames.filter_value] = filters[0].value;
11930        }
11931      }
11932
11933      self.table.extensions.ajax.setParams(pageParams);
11934
11935      self.table.extensions.ajax.sendRequest(function (data) {
11936
11937        self._parseRemoteData(data);
11938      });
11939
11940      self.table.extensions.ajax.setParams(oldParams);
11941    };
11942
11943    Page.prototype._parseRemoteData = function (data) {
11944
11945      if (data[this.paginationDataReceivedNames.last_page]) {
11946
11947        if (data[this.paginationDataReceivedNames.data]) {
11948
11949          this.max = parseInt(data[this.paginationDataReceivedNames.last_page]);
11950
11951          this.table.rowManager.setData(data[this.paginationDataReceivedNames.data]);
11952
11953          this.table.options.pageLoaded(this.getPage());
11954        } else {
11955
11956          console.warn("Remote Pagination Error - Server response missing '" + this.paginationDataReceivedNames.data + "' property");
11957        }
11958      } else {
11959
11960        console.warn("Remote Pagination Error - Server response missing '" + this.paginationDataReceivedNames.last_page + "' property");
11961      }
11962    };
11963
11964    //handle the footer element being redrawn
11965
11966
11967    Page.prototype.footerRedraw = function () {
11968
11969      var footer = this.table.footerManager.element;
11970
11971      if (footer.innerWidth() - footer[0].scrollWidth < 0) {
11972
11973        this.pagesElement.hide();
11974      } else {
11975
11976        this.pagesElement.show();
11977
11978        if (footer.innerWidth() - footer[0].scrollWidth < 0) {
11979
11980          this.pagesElement.hide();
11981        }
11982      }
11983    };
11984
11985    //set the paramter names for pagination requests
11986
11987
11988    Page.prototype.paginationDataSentNames = {
11989
11990      "page": "page",
11991
11992      "size": "size",
11993
11994      "sort": "sort",
11995
11996      "sort_dir": "sort_dir",
11997
11998      "filter": "filter",
11999
12000      "filter_value": "filter_value",
12001
12002      "filter_type": "filter_type"
12003
12004    };
12005
12006    //set the property names for pagination responses
12007
12008
12009    Page.prototype.paginationDataReceivedNames = {
12010
12011      "current_page": "current_page",
12012
12013      "last_page": "last_page",
12014
12015      "data": "data"
12016
12017    };
12018
12019    Tabulator.registerExtension("page", Page);
12020
12021    var PersistentLayout = function PersistentLayout(table) {
12022
12023      this.table = table; //hold Tabulator object
12024
12025
12026      this.mode = "";
12027
12028      this.id = "";
12029
12030      this.persistProps = ["field", "width", "visible"];
12031    };
12032
12033    //setup parameters
12034
12035
12036    PersistentLayout.prototype.initialize = function (mode, id) {
12037
12038      //determine persistent layout storage type
12039
12040
12041      this.mode = mode !== true ? mode : typeof window.localStorage !== 'undefined' ? "local" : "cookie";
12042
12043      //set storage tag
12044
12045
12046      this.id = "tabulator-" + (id || this.table.element.attr("id") || "");
12047    };
12048
12049    //load saved definitions
12050
12051
12052    PersistentLayout.prototype.load = function (definition) {
12053
12054      var newDefinition = "";
12055
12056      switch (this.mode) {
12057
12058        case "local":
12059
12060          newDefinition = localStorage.getItem(this.id);
12061
12062          break;
12063
12064        case "cookie":
12065
12066          //find cookie
12067
12068
12069          var cookie = document.cookie,
12070              cookiePos = cookie.indexOf(this.id + "="),
12071              end = void 0;
12072
12073          //if cookie exists, decode and load column data into tabulator
12074
12075
12076          if (cookiePos > -1) {
12077
12078            cookie = cookie.substr(cookiePos);
12079
12080            end = cookie.indexOf(";");
12081
12082            if (end > -1) {
12083
12084              cookie = cookie.substr(0, end);
12085            }
12086
12087            newDefinition = cookie.replace(this.id + "=", "");
12088          }
12089
12090          break;
12091
12092        default:
12093
12094          console.warn("Persistance Load Error - invalid mode selected", this.mode);
12095
12096      }
12097
12098      if (newDefinition) {
12099
12100        newDefinition = JSON.parse(newDefinition);
12101
12102        definition = this.mergeDefinition(definition, newDefinition);
12103      }
12104
12105      return definition;
12106    };
12107
12108    //merge old and new column defintions
12109
12110
12111    PersistentLayout.prototype.mergeDefinition = function (oldCols, newCols) {
12112
12113      var self = this,
12114          output = [];
12115
12116      newCols.forEach(function (column, to) {
12117
12118        var from = self._findColumn(oldCols, column);
12119
12120        if (from) {
12121
12122          from.width = column.width;
12123
12124          from.visible = column.visible;
12125
12126          if (from.columns) {
12127
12128            from.columns = self.mergeDefinition(from.columns, column.columns);
12129          }
12130
12131          output.push(from);
12132        }
12133      });
12134
12135      return output;
12136    };
12137
12138    //find matching columns
12139
12140
12141    PersistentLayout.prototype._findColumn = function (columns, subject) {
12142
12143      var type = subject.columns ? "group" : subject.field ? "field" : "object";
12144
12145      return columns.find(function (col) {
12146
12147        switch (type) {
12148
12149          case "group":
12150
12151            return col.title === subject.title && col.columns.length === subject.columns.length;
12152
12153            break;
12154
12155          case "field":
12156
12157            return col.field === subject.field;
12158
12159            break;
12160
12161          case "object":
12162
12163            return col === subject;
12164
12165            break;
12166
12167        }
12168      });
12169    };
12170
12171    //save current definitions
12172
12173
12174    PersistentLayout.prototype.save = function () {
12175
12176      var definition = this.parseColumns(this.table.columnManager.getColumns()),
12177          data = JSON.stringify(definition);
12178
12179      switch (this.mode) {
12180
12181        case "local":
12182
12183          localStorage.setItem(this.id, data);
12184
12185          break;
12186
12187        case "cookie":
12188
12189          var expireDate = new Date();
12190
12191          expireDate.setDate(expireDate.getDate() + 10000);
12192
12193          //save cookie
12194
12195
12196          document.cookie = this.id + "=" + data + "; expires=" + expireDate.toUTCString();
12197
12198          break;
12199
12200        default:
12201
12202          console.warn("Persistance Save Error - invalid mode selected", this.mode);
12203
12204      }
12205    };
12206
12207    //build premission list
12208
12209
12210    PersistentLayout.prototype.parseColumns = function (columns) {
12211
12212      var self = this,
12213          definitions = [];
12214
12215      columns.forEach(function (column) {
12216
12217        var def = {};
12218
12219        if (column.isGroup) {
12220
12221          def.title = column.getDefinition().title;
12222
12223          def.columns = self.parseColumns(column.getColumns());
12224        } else {
12225
12226          def.title = column.getDefinition().title;
12227
12228          def.field = column.getField();
12229
12230          def.width = column.getWidth();
12231
12232          def.visible = column.visible;
12233        }
12234
12235        definitions.push(def);
12236      });
12237
12238      return definitions;
12239    };
12240
12241    Tabulator.registerExtension("persistentLayout", PersistentLayout);
12242
12243    var ResizeColumns = function ResizeColumns(table) {
12244
12245      this.table = table; //hold Tabulator object
12246
12247
12248      this.startColumn = false;
12249
12250      this.startX = false;
12251
12252      this.startWidth = false;
12253
12254      this.handle = null;
12255
12256      this.prevHandle = null;
12257    };
12258
12259    ResizeColumns.prototype.initializeColumn = function (type, column, element) {
12260
12261      var self = this,
12262          variableHeight = false,
12263          mode = this.table.options.resizableColumns;
12264
12265      //set column resize mode
12266
12267
12268      if (type === "header") {
12269
12270        variableHeight = column.definition.formatter == "textarea" || column.definition.variableHeight;
12271
12272        column.extensions.resize = { variableHeight: variableHeight };
12273      }
12274
12275      if (mode === true || mode == type) {
12276
12277        var handle = document.createElement('div');
12278
12279        handle.className = "tabulator-col-resize-handle";
12280
12281        var prevHandle = document.createElement('div');
12282
12283        prevHandle.className = "tabulator-col-resize-handle prev";
12284
12285        handle.addEventListener("click", function (e) {
12286
12287          e.stopPropagation();
12288        });
12289
12290        handle.addEventListener("mousedown", function (e) {
12291
12292          var nearestColumn = column.getLastColumn();
12293
12294          if (nearestColumn) {
12295
12296            self.startColumn = column;
12297
12298            self._mouseDown(e, nearestColumn);
12299          }
12300        });
12301
12302        prevHandle.addEventListener("click", function (e) {
12303
12304          e.stopPropagation();
12305        });
12306
12307        prevHandle.addEventListener("mousedown", function (e) {
12308
12309          var nearestColumn, colIndex, prevColumn;
12310
12311          nearestColumn = column.getFirstColumn();
12312
12313          if (nearestColumn) {
12314
12315            colIndex = self.table.columnManager.findColumnIndex(nearestColumn);
12316
12317            prevColumn = colIndex > 0 ? self.table.columnManager.getColumnByIndex(colIndex - 1) : false;
12318
12319            if (prevColumn) {
12320
12321              self.startColumn = column;
12322
12323              self._mouseDown(e, prevColumn);
12324            }
12325          }
12326        });
12327
12328        element.append(handle).append(prevHandle);
12329      }
12330    };
12331
12332    ResizeColumns.prototype._mouseDown = function (e, column) {
12333
12334      var self = this;
12335
12336      self.table.element.addClass("tabulator-block-select");
12337
12338      function mouseMove(e) {
12339
12340        column.setWidth(self.startWidth + (e.screenX - self.startX));
12341
12342        if (!self.table.browserSlow && column.extensions.resize && column.extensions.resize.variableHeight) {
12343
12344          column.checkCellHeights();
12345        }
12346      }
12347
12348      function mouseUp(e) {
12349
12350        //block editor from taking action while resizing is taking place
12351
12352
12353        if (self.startColumn.extensions.edit) {
12354
12355          self.startColumn.extensions.edit.blocked = false;
12356        }
12357
12358        if (self.table.browserSlow && column.extensions.resize && column.extensions.resize.variableHeight) {
12359
12360          column.checkCellHeights();
12361        }
12362
12363        $("body").off("mouseup", mouseMove);
12364
12365        $("body").off("mousemove", mouseMove);
12366
12367        self.table.element.removeClass("tabulator-block-select");
12368
12369        if (self.table.options.persistentLayout && self.table.extExists("persistentLayout", true)) {
12370
12371          self.table.extensions.persistentLayout.save();
12372        }
12373
12374        self.table.options.columnResized(self.startColumn.getComponent());
12375      }
12376
12377      e.stopPropagation(); //prevent resize from interfereing with movable columns
12378
12379
12380      //block editor from taking action while resizing is taking place
12381
12382
12383      if (self.startColumn.extensions.edit) {
12384
12385        self.startColumn.extensions.edit.blocked = true;
12386      }
12387
12388      self.startX = e.screenX;
12389
12390      self.startWidth = column.getWidth();
12391
12392      $("body").on("mousemove", mouseMove);
12393
12394      $("body").on("mouseup", mouseUp);
12395    };
12396
12397    Tabulator.registerExtension("resizeColumns", ResizeColumns);
12398
12399    var ResponsiveLayout = function ResponsiveLayout(table) {
12400
12401      this.table = table; //hold Tabulator object
12402
12403
12404      this.columns = [];
12405
12406      this.index = 0;
12407    };
12408
12409    //generate resposivle columns list
12410
12411
12412    ResponsiveLayout.prototype.initialize = function () {
12413
12414      var columns = [];
12415
12416      //detemine level of responsivity for each column
12417
12418
12419      this.table.columnManager.columnsByIndex.forEach(function (column) {
12420
12421        var def = column.getDefinition();
12422
12423        column.extensions.responsive = { order: typeof def.responsive === "undefined" ? 1 : def.responsive };
12424
12425        if (column.extensions.responsive.order) {
12426
12427          columns.push(column);
12428        }
12429      });
12430
12431      //sort list by responsivity
12432
12433
12434      columns = columns.reverse();
12435
12436      columns = columns.sort(function (a, b) {
12437
12438        return b.extensions.responsive.order - a.extensions.responsive.order;
12439      });
12440
12441      this.columns = columns;
12442    };
12443
12444    ResponsiveLayout.prototype.update = function () {
12445
12446      var self = this,
12447          working = true;
12448
12449      while (working) {
12450
12451        var width = self.table.options.fitColumns ? self.table.columnManager.getFlexBaseWidth() : self.table.columnManager.getWidth();
12452
12453        var diff = self.table.columnManager.element.innerWidth() - width;
12454
12455        if (diff < 0) {
12456
12457          //table is too wide
12458
12459
12460          var _column = self.columns[self.index];
12461
12462          if (_column) {
12463
12464            _column.hide();
12465
12466            self.index++;
12467          } else {
12468
12469            working = false;
12470          }
12471        } else {
12472
12473          //table has spare space
12474
12475
12476          var _column2 = self.columns[self.index - 1];
12477
12478          if (_column2) {
12479
12480            if (diff > 0) {
12481
12482              if (diff >= _column2.getWidth()) {
12483
12484                _column2.show();
12485
12486                self.index--;
12487              } else {
12488
12489                working = false;
12490              }
12491            } else {
12492
12493              working = false;
12494            }
12495          } else {
12496
12497            working = false;
12498          }
12499        }
12500
12501        if (!self.table.rowManager.activeRowsCount) {
12502
12503          self.table.rowManager.renderEmptyScroll();
12504        }
12505      }
12506    };
12507
12508    Tabulator.registerExtension("responsiveLayout", ResponsiveLayout);
12509
12510    var SelectRow = function SelectRow(table) {
12511
12512      this.table = table; //hold Tabulator object
12513
12514
12515      this.selecting = false; //flag selecting in progress
12516
12517
12518      this.selectPrev = []; //hold previously selected element for drag drop selection
12519
12520
12521      this.selectedRows = []; //hold selected rows
12522
12523    };
12524
12525    SelectRow.prototype.clearSelectionData = function () {
12526
12527      this.selecting = false;
12528
12529      this.selectPrev = [];
12530
12531      this.selectedRows = [];
12532    };
12533
12534    SelectRow.prototype.initializeRow = function (row) {
12535
12536      var self = this,
12537          element = row.getElement();
12538
12539      // trigger end of row selection
12540
12541
12542      var endSelect = function endSelect() {
12543
12544        setTimeout(function () {
12545
12546          self.selecting = false;
12547        }, 50);
12548
12549        $("body").off("mouseup", endSelect);
12550      };
12551
12552      row.extensions.select = { selected: false };
12553
12554      //set row selection class
12555
12556
12557      if (self.table.options.selectableCheck(row.getComponent())) {
12558
12559        element.addClass("tabulator-selectable").removeClass("tabulator-unselectable");
12560
12561        if (self.table.options.selectable && self.table.options.selectable != "highlight") {
12562
12563          element.on("click", function (e) {
12564
12565            if (!self.selecting) {
12566
12567              self.toggleRow(row);
12568            }
12569          });
12570
12571          element.on("mousedown", function (e) {
12572
12573            if (e.shiftKey) {
12574
12575              self.selecting = true;
12576
12577              self.selectPrev = [];
12578
12579              $("body").on("mouseup", endSelect);
12580
12581              $("body").on("keyup", endSelect);
12582
12583              self.toggleRow(row);
12584
12585              return false;
12586            }
12587          });
12588
12589          element.on("mouseenter", function (e) {
12590
12591            if (self.selecting) {
12592
12593              self.toggleRow(row);
12594
12595              if (self.selectPrev[1] == row) {
12596
12597                self.toggleRow(self.selectPrev[0]);
12598              }
12599            }
12600          });
12601
12602          element.on("mouseout", function (e) {
12603
12604            if (self.selecting) {
12605
12606              self.selectPrev.unshift(row);
12607            }
12608          });
12609        }
12610      } else {
12611
12612        row.getElement().addClass("tabulator-unselectable").removeClass("tabulator-selectable");
12613      }
12614    };
12615
12616    //toggle row selection
12617
12618
12619    SelectRow.prototype.toggleRow = function (row) {
12620
12621      if (this.table.options.selectableCheck(row.getComponent())) {
12622
12623        if (row.extensions.select.selected) {
12624
12625          this._deselectRow(row);
12626        } else {
12627
12628          this._selectRow(row);
12629        }
12630      }
12631    };
12632
12633    //select a number of rows
12634
12635
12636    SelectRow.prototype.selectRows = function (rows) {
12637
12638      var self = this;
12639
12640      if (typeof rows == "undefined") {
12641
12642        self.table.rowManager.rows.forEach(function (row) {
12643
12644          self._selectRow(row, true, true);
12645        });
12646
12647        self._rowSelectionChanged();
12648      } else {
12649
12650        if (Array.isArray(rows)) {
12651
12652          rows.forEach(function (row) {
12653
12654            self._selectRow(row, true);
12655          });
12656
12657          self._rowSelectionChanged();
12658        } else {
12659
12660          self._selectRow(rows);
12661        }
12662      }
12663    };
12664
12665    //select an individual row
12666
12667
12668    SelectRow.prototype._selectRow = function (rowInfo, silent, force) {
12669
12670      var self = this,
12671          index;
12672
12673      //handle max row count
12674
12675
12676      if (!isNaN(self.table.options.selectable) && self.table.options.selectable !== true && !force) {
12677
12678        if (self.selectedRows.length >= self.table.options.selectable) {
12679
12680          if (self.table.options.selectableRollingSelection) {
12681
12682            self._deselectRow(self.selectedRows[0], true);
12683          } else {
12684
12685            return false;
12686          }
12687        }
12688      }
12689
12690      var row = self.table.rowManager.findRow(rowInfo);
12691
12692      if (row) {
12693
12694        var self = this;
12695
12696        row.extensions.select.selected = true;
12697
12698        row.getElement().addClass("tabulator-selected");
12699
12700        self.selectedRows.push(row);
12701
12702        if (!silent) {
12703
12704          self.table.options.rowSelected(row.getComponent());
12705
12706          self._rowSelectionChanged();
12707        }
12708      } else {
12709
12710        console.warn("Selection Error - No such row found, ignoring selection:" + rowInfo);
12711      }
12712    };
12713
12714    //deselect a number of rows
12715
12716
12717    SelectRow.prototype.deselectRows = function (rows) {
12718
12719      var self = this;
12720
12721      if (typeof rows == "undefined") {
12722
12723        var rowCount = self.selectedRows.length;
12724
12725        for (var i = 0; i < rowCount; i++) {
12726
12727          self._deselectRow(self.selectedRows[0], true);
12728        }
12729
12730        self._rowSelectionChanged();
12731      } else {
12732
12733        if (Array.isArray(rows)) {
12734
12735          rows.forEach(function (row) {
12736
12737            self._deselectRow(row, true);
12738          });
12739
12740          self._rowSelectionChanged();
12741        } else {
12742
12743          self._deselectRow(rows);
12744        }
12745      }
12746    };
12747
12748    //deselect an individual row
12749
12750
12751    SelectRow.prototype._deselectRow = function (rowInfo, silent) {
12752
12753      var self = this,
12754          row = self.table.rowManager.findRow(rowInfo),
12755          index;
12756
12757      if (row) {
12758
12759        index = self.selectedRows.findIndex(function (selectedRow) {
12760
12761          return selectedRow == row;
12762        });
12763
12764        if (index > -1) {
12765
12766          row.extensions.select.selected = false;
12767
12768          row.getElement().removeClass("tabulator-selected");
12769
12770          self.selectedRows.splice(index, 1);
12771
12772          if (!silent) {
12773
12774            self.table.options.rowDeselected(row.getComponent());
12775
12776            self._rowSelectionChanged();
12777          }
12778        }
12779      } else {
12780
12781        console.warn("Selection Error - No such row found, ignoring selection:" + rowInfo);
12782      }
12783    };
12784
12785    SelectRow.prototype.getSelectedData = function () {
12786
12787      var data = [];
12788
12789      this.selectedRows.forEach(function (row) {
12790
12791        data.push(row.getData());
12792      });
12793
12794      return data;
12795    };
12796
12797    SelectRow.prototype.getSelectedRows = function () {
12798
12799      var rows = [];
12800
12801      this.selectedRows.forEach(function (row) {
12802
12803        rows.push(row.getComponent());
12804      });
12805
12806      return rows;
12807    };
12808
12809    SelectRow.prototype._rowSelectionChanged = function () {
12810
12811      this.table.options.rowSelectionChanged(this.getSelectedData(), this.getSelectedRows());
12812    };
12813
12814    Tabulator.registerExtension("selectRow", SelectRow);
12815
12816    var Sort = function Sort(table) {
12817
12818      this.table = table; //hold Tabulator object
12819
12820
12821      this.sortList = []; //holder current sort
12822
12823
12824      this.changed = false; //has the sort changed since last render
12825
12826    };
12827
12828    //initialize column header for sorting
12829
12830
12831    Sort.prototype.initializeColumn = function (column, content) {
12832
12833      var self = this,
12834          sorter = false;
12835
12836      switch (_typeof(column.definition.sorter)) {
12837
12838        case "string":
12839
12840          if (self.sorters[column.definition.sorter]) {
12841
12842            sorter = self.sorters[column.definition.sorter];
12843          } else {
12844
12845            console.warn("Sort Error - No such sorter found: ", column.definition.sorter);
12846          }
12847
12848          break;
12849
12850        case "function":
12851
12852          sorter = column.definition.sorter;
12853
12854          break;
12855
12856      }
12857
12858      column.extensions.sort = { sorter: sorter, dir: "none", params: column.definition.sorterParams || {} };
12859
12860      if (column.definition.headerSort !== false) {
12861
12862        column.element.addClass("tabulator-sortable");
12863
12864        //create sorter arrow
12865
12866
12867        content.append($("<div class='tabulator-arrow'></div>"));
12868
12869        //sort on click
12870
12871
12872        column.element.on("click", function () {
12873
12874          if (column.extensions.sort) {
12875
12876            if (column.extensions.sort.dir == "asc") {
12877
12878              self.setSort(column, "desc");
12879            } else {
12880
12881              self.setSort(column, "asc");
12882            }
12883
12884            self.table.rowManager.sorterRefresh();
12885          }
12886        });
12887      }
12888    };
12889
12890    //check if the sorters have changed since last use
12891
12892
12893    Sort.prototype.hasChanged = function () {
12894
12895      var changed = this.changed;
12896
12897      this.changed = false;
12898
12899      return changed;
12900    };
12901
12902    //return current sorters
12903
12904
12905    Sort.prototype.getSort = function () {
12906
12907      var self = this,
12908          sorters = [];
12909
12910      self.sortList.forEach(function (item) {
12911
12912        if (item.column) {
12913
12914          sorters.push({ column: item.column.getComponent(), field: item.column.getField(), dir: item.dir });
12915        }
12916      });
12917
12918      return sorters;
12919    };
12920
12921    //change sort list and trigger sort
12922
12923
12924    Sort.prototype.setSort = function (sortList, dir) {
12925
12926      var self = this,
12927          newSortList = [];
12928
12929      if (!Array.isArray(sortList)) {
12930
12931        sortList = [{ column: sortList, dir: dir }];
12932      }
12933
12934      sortList.forEach(function (item) {
12935
12936        var column;
12937
12938        column = self.table.columnManager.findColumn(item.column);
12939
12940        if (column) {
12941
12942          item.column = column;
12943
12944          newSortList.push(item);
12945
12946          self.changed = true;
12947        } else {
12948
12949          console.warn("Sort Warning - Sort field does not exist and is being ignored: ", item.column);
12950        }
12951      });
12952
12953      self.sortList = newSortList;
12954    };
12955
12956    //clear sorters
12957
12958
12959    Sort.prototype.clear = function () {
12960
12961      this.setSort([]);
12962    },
12963
12964    //find appropriate sorter for column
12965
12966
12967    Sort.prototype.findSorter = function (column) {
12968
12969      var row = this.table.rowManager.activeRows[0],
12970          sorter = "string",
12971          field,
12972          value;
12973
12974      if (row) {
12975
12976        row = row.getData();
12977
12978        field = column.getField();
12979
12980        if (field) {
12981
12982          value = column.getFieldValue(row);
12983
12984          switch (typeof value === 'undefined' ? 'undefined' : _typeof(value)) {
12985
12986            case "undefined":
12987
12988              sorter = "string";
12989
12990              break;
12991
12992            case "boolean":
12993
12994              sorter = "boolean";
12995
12996              break;
12997
12998            default:
12999
13000              if (!isNaN(value) && value !== "") {
13001
13002                sorter = "number";
13003              } else {
13004
13005                if (value.match(/((^[0-9]+[a-z]+)|(^[a-z]+[0-9]+))+$/i)) {
13006
13007                  sorter = "alphanum";
13008                }
13009              }
13010
13011              break;
13012
13013          }
13014        }
13015      }
13016
13017      return this.sorters[sorter];
13018    };
13019
13020    //work through sort list sorting data
13021
13022
13023    Sort.prototype.sort = function () {
13024
13025      var self = this,
13026          lastSort;
13027
13028      if (self.table.options.dataSorting) {
13029
13030        self.table.options.dataSorting(self.getSort());
13031      }
13032
13033      self.clearColumnHeaders();
13034
13035      if (!self.table.options.ajaxSorting) {
13036
13037        self.sortList.forEach(function (item, i) {
13038
13039          if (item.column && item.column.extensions.sort) {
13040
13041            //if no sorter has been defined, take a guess
13042
13043
13044            if (!item.column.extensions.sort.sorter) {
13045
13046              item.column.extensions.sort.sorter = self.findSorter(item.column);
13047            }
13048
13049            self._sortItem(item.column, item.dir, self.sortList, i);
13050          }
13051        });
13052      }
13053
13054      if (self.sortList.length) {
13055
13056        lastSort = self.sortList[self.sortList.length - 1];
13057
13058        if (lastSort.column) {
13059
13060          self.setColumnHeader(lastSort.column, lastSort.dir);
13061        }
13062      }
13063
13064      if (self.table.options.dataSorted) {
13065
13066        self.table.options.dataSorted(self.getSort());
13067      }
13068    };
13069
13070    //clear sort arrows on columns
13071
13072
13073    Sort.prototype.clearColumnHeaders = function () {
13074
13075      this.table.columnManager.getRealColumns().forEach(function (column) {
13076
13077        if (column.extensions.sort) {
13078
13079          column.extensions.sort.dir = "none";
13080
13081          column.element.attr("aria-sort", "none");
13082        }
13083      });
13084    };
13085
13086    //set the column header sort direction
13087
13088
13089    Sort.prototype.setColumnHeader = function (column, dir) {
13090
13091      this.clearColumnHeaders();
13092
13093      column.extensions.sort.dir = dir;
13094
13095      column.element.attr("aria-sort", dir);
13096    };
13097
13098    //sort each item in sort list
13099
13100
13101    Sort.prototype._sortItem = function (column, dir, sortList, i) {
13102
13103      var self = this;
13104
13105      var activeRows = self.table.rowManager.activeRows;
13106
13107      activeRows.sort(function (a, b) {
13108
13109        var result = self._sortRow(a, b, column, dir);
13110
13111        //if results match recurse through previous searchs to be sure
13112
13113
13114        if (result == 0 && i) {
13115
13116          for (var j = i - 1; j >= 0; j--) {
13117
13118            result = self._sortRow(a, b, sortList[j].column, sortList[j].dir);
13119
13120            if (result != 0) {
13121
13122              break;
13123            }
13124          }
13125        }
13126
13127        return result;
13128      });
13129    };
13130
13131    //process individual rows for a sort function on active data
13132
13133
13134    Sort.prototype._sortRow = function (a, b, column, dir) {
13135
13136      var self = this;
13137
13138      //switch elements depending on search direction
13139
13140
13141      var el1 = dir == "asc" ? a : b;
13142
13143      var el2 = dir == "asc" ? b : a;
13144
13145      a = column.getFieldValue(el1.getData());
13146
13147      b = column.getFieldValue(el2.getData());
13148
13149      a = typeof a !== "undefined" ? a : "";
13150
13151      b = typeof b !== "undefined" ? b : "";
13152
13153      return column.extensions.sort.sorter.call(self, a, b, el1, el2, column.getComponent(), dir, column.extensions.sort.params);
13154    };
13155
13156    //default data sorters
13157
13158
13159    Sort.prototype.sorters = {
13160
13161      //sort numbers
13162
13163
13164      number: function number(a, b, aData, bData, column, dir, params) {
13165
13166        return parseFloat(String(a).replace(",", "")) - parseFloat(String(b).replace(",", ""));
13167      },
13168
13169      //sort strings
13170
13171
13172      string: function string(a, b, aData, bData, column, dir, params) {
13173
13174        return String(a).toLowerCase().localeCompare(String(b).toLowerCase());
13175      },
13176
13177      //sort date
13178
13179
13180      date: function date(a, b, aData, bData, column, dir, params) {
13181
13182        var self = this;
13183
13184        var format = params.format || "DD/MM/YYYY";
13185
13186        if (typeof moment != "undefined") {
13187
13188          a = moment(a, format);
13189
13190          b = moment(b, format);
13191        } else {
13192
13193          console.error("Sort Error - 'date' sorter is dependant on moment.js");
13194        }
13195
13196        return a - b;
13197      },
13198
13199      //sort booleans
13200
13201
13202      boolean: function boolean(a, b, aData, bData, column, dir, params) {
13203
13204        var el1 = a === true || a === "true" || a === "True" || a === 1 ? 1 : 0;
13205
13206        var el2 = b === true || b === "true" || b === "True" || b === 1 ? 1 : 0;
13207
13208        return el1 - el2;
13209      },
13210
13211      //sort alpha numeric strings
13212
13213
13214      alphanum: function alphanum(as, bs, aData, bData, column, dir, params) {
13215
13216        var a,
13217            b,
13218            a1,
13219            b1,
13220            i = 0,
13221            L,
13222            rx = /(\d+)|(\D+)/g,
13223            rd = /\d/;
13224
13225        if (isFinite(as) && isFinite(bs)) return as - bs;
13226
13227        a = String(as).toLowerCase();
13228
13229        b = String(bs).toLowerCase();
13230
13231        if (a === b) return 0;
13232
13233        if (!(rd.test(a) && rd.test(b))) return a > b ? 1 : -1;
13234
13235        a = a.match(rx);
13236
13237        b = b.match(rx);
13238
13239        L = a.length > b.length ? b.length : a.length;
13240
13241        while (i < L) {
13242
13243          a1 = a[i];
13244
13245          b1 = b[i++];
13246
13247          if (a1 !== b1) {
13248
13249            if (isFinite(a1) && isFinite(b1)) {
13250
13251              if (a1.charAt(0) === "0") a1 = "." + a1;
13252
13253              if (b1.charAt(0) === "0") b1 = "." + b1;
13254
13255              return a1 - b1;
13256            } else return a1 > b1 ? 1 : -1;
13257          }
13258        }
13259
13260        return a.length > b.length;
13261      },
13262
13263      //sort hh:mm formatted times
13264
13265
13266      time: function time(a, b, aData, bData, column, dir, params) {
13267
13268        var self = this;
13269
13270        var format = params.format || "hh:mm";
13271
13272        if (typeof moment != "undefined") {
13273
13274          a = moment(a, format);
13275
13276          b = moment(b, format);
13277        } else {
13278
13279          console.error("Sort Error - 'date' sorter is dependant on moment.js");
13280        }
13281
13282        return a - b;
13283      }
13284
13285    };
13286
13287    Tabulator.registerExtension("sort", Sort);
13288  })();
13289
13290  $.widget("ui.tabulator", Tabulator);
13291});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.