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 || " "); 1495 }); 1496 } else { 1497 1498 titleElement.val(def.title || " "); 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 || " "); 1507 }); 1508 } else { 1509 1510 titleHolderElement.html(def.title || " "); 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 '&': '&', 8851 8852 '<': '<', 8853 8854 '>': '>', 8855 8856 '"': '"', 8857 8858 "'": ''', 8859 8860 '/': '/', 8861 8862 '`': '`', 8863 8864 '=': '=' 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 ? " " : 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.