jquery.dgtable 0.6.19 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -70
- package/dist/lib.cjs.js +3935 -0
- package/dist/lib.cjs.js.map +1 -0
- package/dist/lib.cjs.min.js +3 -0
- package/dist/lib.cjs.min.js.map +1 -0
- package/dist/lib.es6.js +3933 -0
- package/dist/lib.es6.js.map +1 -0
- package/dist/lib.es6.min.js +3 -0
- package/dist/lib.es6.min.js.map +1 -0
- package/dist/lib.umd.js +1984 -0
- package/dist/lib.umd.js.map +1 -0
- package/dist/lib.umd.min.js +7 -0
- package/dist/lib.umd.min.js.map +1 -0
- package/index.js +27 -0
- package/package.json +47 -57
- package/scripts/build.js +162 -0
- package/LICENSE +0 -21
- package/dist/jquery.dgtable.cjs.js +0 -6389
- package/dist/jquery.dgtable.cjs.js.map +0 -1
- package/dist/jquery.dgtable.cjs.min.js +0 -7
- package/dist/jquery.dgtable.cjs.min.js.map +0 -1
- package/dist/jquery.dgtable.es6.js +0 -6387
- package/dist/jquery.dgtable.es6.js.map +0 -1
- package/dist/jquery.dgtable.es6.min.js +0 -7
- package/dist/jquery.dgtable.es6.min.js.map +0 -1
- package/dist/jquery.dgtable.umd.js +0 -4466
- package/dist/jquery.dgtable.umd.js.map +0 -1
- package/dist/jquery.dgtable.umd.min.js +0 -7
- package/dist/jquery.dgtable.umd.min.js.map +0 -1
- package/eslint.config.mjs +0 -133
- package/src/SelectionHelper.js +0 -65
- package/src/by_column_filter.js +0 -25
- package/src/column_collection.js +0 -153
- package/src/index.js +0 -4034
- package/src/row_collection.js +0 -183
- package/src/util.js +0 -23
|
@@ -1,4466 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* jquery.dgtable 0.6.19
|
|
3
|
-
* git://github.com/danielgindi/jquery.dgtable.git
|
|
4
|
-
*/
|
|
5
|
-
(function (global, factory) {
|
|
6
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('@danielgindi/dom-utils/lib/ScrollHelper.js'), require('@danielgindi/dom-utils/lib/Css.js'), require('@danielgindi/virtual-list-helper')) :
|
|
7
|
-
typeof define === 'function' && define.amd ? define(['jquery', '@danielgindi/dom-utils/lib/ScrollHelper.js', '@danielgindi/dom-utils/lib/Css.js', '@danielgindi/virtual-list-helper'], factory) :
|
|
8
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DGTable = factory(global.jQuery, global.domUtilsScrollHelper, global.domUtilsCss, global.VirtualListHelper));
|
|
9
|
-
})(this, (function (jQuery, ScrollHelper_js, Css_js, VirtualListHelper) { 'use strict';
|
|
10
|
-
|
|
11
|
-
const indexOf = Array.prototype.indexOf;
|
|
12
|
-
|
|
13
|
-
const includes = function includes(array, item) {
|
|
14
|
-
return indexOf.call(array, item) >= 0;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const find = function find(array, predicate) {
|
|
18
|
-
for (let i = 0, len = array.length; i >= 0 && i < len; i += 1) {
|
|
19
|
-
if (predicate(array[i], i, array))
|
|
20
|
-
return array[i];
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const htmlEncode = function htmlEncode(text) {
|
|
25
|
-
return text.replace(/&/g, "&").
|
|
26
|
-
replace(/</g, "<").
|
|
27
|
-
replace(/>/g, ">").
|
|
28
|
-
replace(/'/g, "'").
|
|
29
|
-
replace(/"/g, """).
|
|
30
|
-
replace(/\n/g, '<br />');
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// Define class RowCollection
|
|
34
|
-
function RowCollection() {
|
|
35
|
-
|
|
36
|
-
// Instantiate an Array. Seems like the `.length = ` of an inherited Array does not work well.
|
|
37
|
-
// I will not use the IFRAME solution either in fear of memory leaks, and we're supporting large datasets...
|
|
38
|
-
let collection = [];
|
|
39
|
-
|
|
40
|
-
// Synthetically set the 'prototype'
|
|
41
|
-
Object.assign(collection, RowCollection.prototype);
|
|
42
|
-
|
|
43
|
-
// Call initializer
|
|
44
|
-
collection.initialize.apply(collection, arguments);
|
|
45
|
-
|
|
46
|
-
return collection;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Inherit Array
|
|
50
|
-
RowCollection.prototype = [];
|
|
51
|
-
|
|
52
|
-
RowCollection.prototype.initialize = function (options) {
|
|
53
|
-
|
|
54
|
-
options = options || {};
|
|
55
|
-
|
|
56
|
-
/** @field {string} sortColumn */
|
|
57
|
-
this.sortColumn = options.sortColumn == null ? [] : options.sortColumn;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @param {Object|Object[]} rows - row or array of rows to add to this collection
|
|
62
|
-
* @param {number?} at - position to insert rows at
|
|
63
|
-
*/
|
|
64
|
-
RowCollection.prototype.add = function (rows, at) {
|
|
65
|
-
let isArray = 'splice' in rows && 'length' in rows,i,len;
|
|
66
|
-
if (isArray) {
|
|
67
|
-
if (typeof at === 'number') {
|
|
68
|
-
for (i = 0, len = rows.length; i < len; i++) {
|
|
69
|
-
this.splice(at++, 0, rows[i]);
|
|
70
|
-
}
|
|
71
|
-
} else {
|
|
72
|
-
for (i = 0, len = rows.length; i < len; i++) {
|
|
73
|
-
this.push(rows[i]);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
} else {
|
|
77
|
-
if (typeof at === 'number') {
|
|
78
|
-
this.splice(at, 0, rows);
|
|
79
|
-
} else {
|
|
80
|
-
this.push(rows);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* @param {Object|Object[]=} rows Row or array of rows to add to this collection
|
|
87
|
-
*/
|
|
88
|
-
RowCollection.prototype.reset = function (rows) {
|
|
89
|
-
this.length = 0;
|
|
90
|
-
if (rows) {
|
|
91
|
-
this.add(rows);
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* @param {Function} filterFunc - Filtering function
|
|
97
|
-
* @param {Object|null?} args - Options to pass to the function
|
|
98
|
-
* @returns {RowCollection} success result
|
|
99
|
-
*/
|
|
100
|
-
RowCollection.prototype.filteredCollection = function (filterFunc, args) {
|
|
101
|
-
if (filterFunc && args) {
|
|
102
|
-
let rows = new RowCollection({
|
|
103
|
-
sortColumn: this.sortColumn,
|
|
104
|
-
onComparatorRequired: this.onComparatorRequired,
|
|
105
|
-
customSortingProvider: this.customSortingProvider
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
for (let i = 0, len = this.length, row; i < len; i++) {
|
|
109
|
-
row = this[i];
|
|
110
|
-
if (filterFunc(row, args)) {
|
|
111
|
-
row['__i'] = i;
|
|
112
|
-
rows.push(row);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return rows;
|
|
116
|
-
} else {
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* @type {function(columnName: string, descending: boolean, defaultComparator: function(a,b):number)|null|undefined}
|
|
123
|
-
*/
|
|
124
|
-
RowCollection.prototype.onComparatorRequired = null;
|
|
125
|
-
/**
|
|
126
|
-
* @type {function(data: any[], sort: function(any[]):any[]):any[]|null|undefined}
|
|
127
|
-
*/
|
|
128
|
-
RowCollection.prototype.customSortingProvider = null;
|
|
129
|
-
|
|
130
|
-
let nativeSort = RowCollection.prototype.sort;
|
|
131
|
-
|
|
132
|
-
function getDefaultComparator(column, descending) {
|
|
133
|
-
let columnName = column.column;
|
|
134
|
-
let comparePath = column.comparePath || columnName;
|
|
135
|
-
if (typeof comparePath === 'string') {
|
|
136
|
-
comparePath = comparePath.split('.');
|
|
137
|
-
}
|
|
138
|
-
let pathLength = comparePath.length,
|
|
139
|
-
hasPath = pathLength > 1,
|
|
140
|
-
i;
|
|
141
|
-
|
|
142
|
-
let lessVal = descending ? 1 : -1,moreVal = descending ? -1 : 1;
|
|
143
|
-
return function (leftRow, rightRow) {
|
|
144
|
-
let leftVal = leftRow[comparePath[0]],
|
|
145
|
-
rightVal = rightRow[comparePath[0]];
|
|
146
|
-
if (hasPath) {
|
|
147
|
-
for (i = 1; i < pathLength; i++) {
|
|
148
|
-
leftVal = leftVal && leftVal[comparePath[i]];
|
|
149
|
-
rightVal = rightVal && rightVal[comparePath[i]];
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
if (leftVal === rightVal) return 0;
|
|
153
|
-
if (leftVal == null) return lessVal;
|
|
154
|
-
if (rightVal == null) return moreVal;
|
|
155
|
-
if (leftVal < rightVal) return lessVal;
|
|
156
|
-
return moreVal;
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* @returns {Function|undefined} the comparator that was used
|
|
162
|
-
*/
|
|
163
|
-
RowCollection.prototype.sort = function () {
|
|
164
|
-
let comparator;
|
|
165
|
-
|
|
166
|
-
if (this.sortColumn.length) {
|
|
167
|
-
let comparators = [];
|
|
168
|
-
|
|
169
|
-
for (let i = 0; i < this.sortColumn.length; i++) {
|
|
170
|
-
comparator = null;
|
|
171
|
-
const defaultComparator = getDefaultComparator(this.sortColumn[i], this.sortColumn[i].descending);
|
|
172
|
-
if (this.onComparatorRequired) {
|
|
173
|
-
comparator = this.onComparatorRequired(this.sortColumn[i].column, this.sortColumn[i].descending, defaultComparator);
|
|
174
|
-
}
|
|
175
|
-
if (!comparator) {
|
|
176
|
-
comparator = defaultComparator;
|
|
177
|
-
}
|
|
178
|
-
comparators.push(comparator.bind(this));
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (comparators.length === 1) {
|
|
182
|
-
comparator = comparators[0];
|
|
183
|
-
} else {
|
|
184
|
-
let len = comparators.length,
|
|
185
|
-
value;
|
|
186
|
-
|
|
187
|
-
comparator = function (leftRow, rightRow) {
|
|
188
|
-
for (let i = 0; i < len; i++) {
|
|
189
|
-
value = comparators[i](leftRow, rightRow);
|
|
190
|
-
if (value !== 0) {
|
|
191
|
-
return value;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return value;
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const sorter = (data) => nativeSort.call(data, comparator);
|
|
199
|
-
|
|
200
|
-
if (this.customSortingProvider) {
|
|
201
|
-
let results = this.customSortingProvider(this, sorter);
|
|
202
|
-
if (results !== this) {
|
|
203
|
-
this.splice(0, this.length, ...results);
|
|
204
|
-
}
|
|
205
|
-
} else {
|
|
206
|
-
sorter(this);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return comparator;
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
// Define class RowCollection
|
|
214
|
-
function ColumnCollection() {
|
|
215
|
-
|
|
216
|
-
// Instantiate an Array. Seems like the `.length = ` of an inherited Array does not work well.
|
|
217
|
-
// I will not use the IFRAME solution either in fear of memory leaks, and we're supporting large datasets...
|
|
218
|
-
let collection = [];
|
|
219
|
-
|
|
220
|
-
// Synthetically set the 'prototype'
|
|
221
|
-
Object.assign(collection, ColumnCollection.prototype);
|
|
222
|
-
|
|
223
|
-
// Call initializer
|
|
224
|
-
collection.initialize.apply(collection, arguments);
|
|
225
|
-
|
|
226
|
-
return collection;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Inherit Array
|
|
230
|
-
ColumnCollection.prototype = [];
|
|
231
|
-
|
|
232
|
-
ColumnCollection.prototype.initialize = function () {
|
|
233
|
-
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Get the column by this name
|
|
238
|
-
* @param {string} column column name
|
|
239
|
-
* @returns {Object} the column object
|
|
240
|
-
*/
|
|
241
|
-
ColumnCollection.prototype.get = function (column) {
|
|
242
|
-
for (let i = 0, len = this.length; i < len; i++) {
|
|
243
|
-
if (this[i].name === column) {
|
|
244
|
-
return this[i];
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return null;
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Get the index of the column by this name
|
|
252
|
-
* @param {string} column column name
|
|
253
|
-
* @returns {int} the index of this column
|
|
254
|
-
*/
|
|
255
|
-
ColumnCollection.prototype.indexOf = function (column) {
|
|
256
|
-
for (let i = 0, len = this.length; i < len; i++) {
|
|
257
|
-
if (this[i].name === column) {
|
|
258
|
-
return i;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
return -1;
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Get the column by the specified order
|
|
266
|
-
* @param {number} order the column's order
|
|
267
|
-
* @returns {Object} the column object
|
|
268
|
-
*/
|
|
269
|
-
ColumnCollection.prototype.getByOrder = function (order) {
|
|
270
|
-
for (let i = 0, len = this.length; i < len; i++) {
|
|
271
|
-
if (this[i].order === order) {
|
|
272
|
-
return this[i];
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return null;
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Normalize order
|
|
280
|
-
* @returns {ColumnCollection} self
|
|
281
|
-
*/
|
|
282
|
-
ColumnCollection.prototype.normalizeOrder = function () {
|
|
283
|
-
let ordered = [],i;
|
|
284
|
-
for (i = 0; i < this.length; i++) {
|
|
285
|
-
ordered.push(this[i]);
|
|
286
|
-
}
|
|
287
|
-
ordered.sort(function (col1, col2) {return col1.order < col2.order ? -1 : col1.order > col2.order ? 1 : 0;});
|
|
288
|
-
for (i = 0; i < ordered.length; i++) {
|
|
289
|
-
ordered[i].order = i;
|
|
290
|
-
}
|
|
291
|
-
return this;
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Get the array of columns, order by the order property
|
|
296
|
-
* @returns {Array<Object>} ordered array of columns
|
|
297
|
-
*/
|
|
298
|
-
ColumnCollection.prototype.getColumns = function () {
|
|
299
|
-
let cols = [];
|
|
300
|
-
for (let i = 0, column; i < this.length; i++) {
|
|
301
|
-
column = this[i];
|
|
302
|
-
cols.push(column);
|
|
303
|
-
}
|
|
304
|
-
cols.sort((col1, col2) => col1.order < col2.order ? -1 : col1.order > col2.order ? 1 : 0);
|
|
305
|
-
return cols;
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Get the array of visible columns, order by the order property
|
|
310
|
-
* @returns {Array<Object>} ordered array of visible columns
|
|
311
|
-
*/
|
|
312
|
-
ColumnCollection.prototype.getVisibleColumns = function () {
|
|
313
|
-
let cols = [];
|
|
314
|
-
for (let i = 0, column; i < this.length; i++) {
|
|
315
|
-
column = this[i];
|
|
316
|
-
if (column.visible) {
|
|
317
|
-
cols.push(column);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
cols.sort((col1, col2) => col1.order < col2.order ? -1 : col1.order > col2.order ? 1 : 0);
|
|
321
|
-
return cols;
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* @returns {int} maximum order currently in the array
|
|
326
|
-
*/
|
|
327
|
-
ColumnCollection.prototype.getMaxOrder = function () {
|
|
328
|
-
let order = 0;
|
|
329
|
-
for (let i = 0, column; i < this.length; i++) {
|
|
330
|
-
column = this[i];
|
|
331
|
-
if (column.order > order) {
|
|
332
|
-
order = column.order;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
return order;
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Move a column to a new spot in the collection
|
|
340
|
-
* @param {Object} src the column to move
|
|
341
|
-
* @param {Object} dest the destination column
|
|
342
|
-
* @returns {ColumnCollection} self
|
|
343
|
-
*/
|
|
344
|
-
ColumnCollection.prototype.moveColumn = function (src, dest) {
|
|
345
|
-
if (src && dest) {
|
|
346
|
-
let srcOrder = src.order,destOrder = dest.order,i,col;
|
|
347
|
-
if (srcOrder < destOrder) {
|
|
348
|
-
for (i = srcOrder + 1; i <= destOrder; i++) {
|
|
349
|
-
col = this.getByOrder(i);
|
|
350
|
-
col.order--;
|
|
351
|
-
}
|
|
352
|
-
} else {
|
|
353
|
-
for (i = srcOrder - 1; i >= destOrder; i--) {
|
|
354
|
-
col = this.getByOrder(i);
|
|
355
|
-
col.order++;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
src.order = destOrder;
|
|
359
|
-
}
|
|
360
|
-
return this;
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
/* eslint-env browser */
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
// saveSelection/restoreSelection courtesy of Tim Down, with my improvements
|
|
367
|
-
// https://stackoverflow.com/questions/13949059/persisting-the-changes-of-range-objects-after-selection-in-html/13950376#13950376
|
|
368
|
-
|
|
369
|
-
function isChildOf(child, parent) {
|
|
370
|
-
while ((child = child.parentNode) && child !== parent);
|
|
371
|
-
return !!child;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
class SelectionHelper {
|
|
375
|
-
|
|
376
|
-
static saveSelection(el) {
|
|
377
|
-
let range = window.getSelection().getRangeAt(0);
|
|
378
|
-
|
|
379
|
-
if (el !== range.commonAncestorContainer && !isChildOf(range.commonAncestorContainer, el))
|
|
380
|
-
return null;
|
|
381
|
-
|
|
382
|
-
let preSelectionRange = range.cloneRange();
|
|
383
|
-
preSelectionRange.selectNodeContents(el);
|
|
384
|
-
preSelectionRange.setEnd(range.startContainer, range.startOffset);
|
|
385
|
-
let start = preSelectionRange.toString().length;
|
|
386
|
-
|
|
387
|
-
return {
|
|
388
|
-
start: start,
|
|
389
|
-
end: start + range.toString().length
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
static restoreSelection(el, savedSel) {
|
|
394
|
-
let charIndex = 0;
|
|
395
|
-
let nodeStack = [el],node,foundStart = false,stop = false;
|
|
396
|
-
let range = document.createRange();
|
|
397
|
-
range.setStart(el, 0);
|
|
398
|
-
range.collapse(true);
|
|
399
|
-
|
|
400
|
-
while (!stop && (node = nodeStack.pop())) {
|
|
401
|
-
if (node.nodeType === 3) {
|
|
402
|
-
let nextCharIndex = charIndex + node.length;
|
|
403
|
-
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
|
|
404
|
-
range.setStart(node, savedSel.start - charIndex);
|
|
405
|
-
foundStart = true;
|
|
406
|
-
}
|
|
407
|
-
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
|
|
408
|
-
range.setEnd(node, savedSel.end - charIndex);
|
|
409
|
-
stop = true;
|
|
410
|
-
}
|
|
411
|
-
charIndex = nextCharIndex;
|
|
412
|
-
} else {
|
|
413
|
-
let i = node.childNodes.length;
|
|
414
|
-
while (i--) {
|
|
415
|
-
nodeStack.push(node.childNodes[i]);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
let sel = window.getSelection();
|
|
421
|
-
sel.removeAllRanges();
|
|
422
|
-
sel.addRange(range);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
function ByColumnFilter(row, args) {
|
|
427
|
-
|
|
428
|
-
let column = args.column;
|
|
429
|
-
let keyword = args.keyword == null ? '' : args.keyword.toString();
|
|
430
|
-
|
|
431
|
-
if (!keyword || !column) return true;
|
|
432
|
-
|
|
433
|
-
let actualVal = row[column];
|
|
434
|
-
if (actualVal == null) {
|
|
435
|
-
return false;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
actualVal = actualVal.toString();
|
|
439
|
-
|
|
440
|
-
if (!args.caseSensitive) {
|
|
441
|
-
actualVal = actualVal.toLowerCase();
|
|
442
|
-
keyword = keyword.toLowerCase();
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
return actualVal.indexOf(keyword) !== -1;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
/* eslint-env browser */
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
const nativeIndexOf = Array.prototype.indexOf;
|
|
452
|
-
const $ = jQuery;
|
|
453
|
-
|
|
454
|
-
let userAgent = navigator.userAgent;
|
|
455
|
-
let ieVersion = userAgent.indexOf('MSIE ') !== -1 ? parseFloat(userAgent.substr(userAgent.indexOf('MSIE ') + 5)) : null;
|
|
456
|
-
let hasIeDragAndDropBug = ieVersion && ieVersion < 10;
|
|
457
|
-
let createElement = document.createElement.bind(document);
|
|
458
|
-
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
459
|
-
|
|
460
|
-
const IsSafeSymbol = Symbol('safe');
|
|
461
|
-
const HoverInEventSymbol = Symbol('hover_in');
|
|
462
|
-
const HoverOutEventSymbol = Symbol('hover_out');
|
|
463
|
-
const RowClickEventSymbol = Symbol('row_click');
|
|
464
|
-
|
|
465
|
-
function webkitRenderBugfix(el) {
|
|
466
|
-
// BUGFIX: WebKit has a bug where it does not relayout, and this affects us because scrollbars
|
|
467
|
-
// are still calculated even though they are not there yet. This is the last resort.
|
|
468
|
-
let oldDisplay = el.style.display;
|
|
469
|
-
el.style.display = 'none';
|
|
470
|
-
//noinspection BadExpressionStatementJS
|
|
471
|
-
el.offsetHeight; // No need to store this anywhere, the reference is enough
|
|
472
|
-
el.style.display = oldDisplay;
|
|
473
|
-
return el;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
function relativizeElement($el) {
|
|
477
|
-
if (!includes(['relative', 'absolute', 'fixed'], $el.css('position'))) {
|
|
478
|
-
$el.css('position', 'relative');
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const isInputElementEvent = (event) => /^(?:INPUT|TEXTAREA|BUTTON|SELECT)$/.test(event.target.tagName);
|
|
483
|
-
|
|
484
|
-
/** @class DGTable */
|
|
485
|
-
let DGTable = function DGTable() {
|
|
486
|
-
if (!(this instanceof DGTable)) {
|
|
487
|
-
// Allow constructing without `new`
|
|
488
|
-
return new (Function.prototype.bind.apply(
|
|
489
|
-
DGTable,
|
|
490
|
-
[DGTable].concat(Array.prototype.slice.call(arguments, 0))))();
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
this.initialize.apply(this, arguments);
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
/**
|
|
497
|
-
* @public
|
|
498
|
-
* @expose
|
|
499
|
-
* @type {string}
|
|
500
|
-
*/
|
|
501
|
-
DGTable.VERSION = '@@VERSION';
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* @public
|
|
505
|
-
* @expose
|
|
506
|
-
* @type {string}
|
|
507
|
-
*/
|
|
508
|
-
DGTable.prototype.VERSION = DGTable.VERSION;
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* @constructs
|
|
512
|
-
* @param {DGTable.Options?} options - initialization options
|
|
513
|
-
* @returns {DGTable}
|
|
514
|
-
*/
|
|
515
|
-
DGTable.prototype.initialize = function (options) {
|
|
516
|
-
let that = this;
|
|
517
|
-
|
|
518
|
-
options = options || {};
|
|
519
|
-
|
|
520
|
-
/**
|
|
521
|
-
* @private
|
|
522
|
-
* @type {DGTable.Options}
|
|
523
|
-
* */
|
|
524
|
-
let o = that.o = {};
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* @private
|
|
528
|
-
* This is for encapsulating private data */
|
|
529
|
-
let p = that.p = {};
|
|
530
|
-
|
|
531
|
-
/** This is for encapsulating event callback */
|
|
532
|
-
p.events = {};
|
|
533
|
-
|
|
534
|
-
/**
|
|
535
|
-
* @public
|
|
536
|
-
* @expose
|
|
537
|
-
* */
|
|
538
|
-
that.el = options.el && options.el instanceof Element ? options.el : document.createElement('div');
|
|
539
|
-
|
|
540
|
-
/**
|
|
541
|
-
* @public
|
|
542
|
-
* @expose
|
|
543
|
-
* */
|
|
544
|
-
let $el = that.$el = $(that.el);
|
|
545
|
-
|
|
546
|
-
if (that.el !== options.el) {
|
|
547
|
-
$el.addClass(options.className || 'dgtable-wrapper');
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// Set control data
|
|
551
|
-
$el.
|
|
552
|
-
data('control', that).
|
|
553
|
-
data('dgtable', that);
|
|
554
|
-
|
|
555
|
-
// For jQuery.UI or jquery.removeevent
|
|
556
|
-
$el.on('remove', () => that.destroy());
|
|
557
|
-
|
|
558
|
-
p.onMouseMoveResizeAreaBound = this._onMouseMoveResizeArea.bind(this);
|
|
559
|
-
p.onEndDragColumnHeaderBound = this._onEndDragColumnHeader.bind(this);
|
|
560
|
-
p.onTableScrolledHorizontallyBound = this._onTableScrolledHorizontally.bind(this);
|
|
561
|
-
|
|
562
|
-
this.$el.on('dragend', p.onEndDragColumnHeaderBound);
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* @private
|
|
566
|
-
* @field {boolean} _tableSkeletonNeedsRendering */
|
|
567
|
-
p.tableSkeletonNeedsRendering = true;
|
|
568
|
-
|
|
569
|
-
/**
|
|
570
|
-
* @private
|
|
571
|
-
* @field {boolean} virtualTable */
|
|
572
|
-
o.virtualTable = options.virtualTable === undefined ? true : !!options.virtualTable;
|
|
573
|
-
|
|
574
|
-
/**
|
|
575
|
-
* @private
|
|
576
|
-
* @field {number} estimatedRowHeight */
|
|
577
|
-
o.estimatedRowHeight = options.estimatedRowHeight || undefined;
|
|
578
|
-
|
|
579
|
-
/**
|
|
580
|
-
* @private
|
|
581
|
-
* @field {number} rowsBufferSize */
|
|
582
|
-
o.rowsBufferSize = options.rowsBufferSize || 3;
|
|
583
|
-
|
|
584
|
-
/**
|
|
585
|
-
* @private
|
|
586
|
-
* @field {number} minColumnWidth */
|
|
587
|
-
o.minColumnWidth = Math.max(options.minColumnWidth || 35, 0);
|
|
588
|
-
|
|
589
|
-
/**
|
|
590
|
-
* @private
|
|
591
|
-
* @field {number} resizeAreaWidth */
|
|
592
|
-
o.resizeAreaWidth = options.resizeAreaWidth || 8;
|
|
593
|
-
|
|
594
|
-
/**
|
|
595
|
-
* @private
|
|
596
|
-
* @field {boolean} resizableColumns */
|
|
597
|
-
o.resizableColumns = options.resizableColumns === undefined ? true : !!options.resizableColumns;
|
|
598
|
-
|
|
599
|
-
/**
|
|
600
|
-
* @private
|
|
601
|
-
* @field {boolean} movableColumns */
|
|
602
|
-
o.movableColumns = options.movableColumns === undefined ? true : !!options.movableColumns;
|
|
603
|
-
|
|
604
|
-
/**
|
|
605
|
-
* @private
|
|
606
|
-
* @field {number} sortableColumns */
|
|
607
|
-
o.sortableColumns = options.sortableColumns === undefined ? 1 : parseInt(options.sortableColumns, 10) || 1;
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* @private
|
|
611
|
-
* @field {boolean} adjustColumnWidthForSortArrow */
|
|
612
|
-
o.adjustColumnWidthForSortArrow = options.adjustColumnWidthForSortArrow === undefined ? true : !!options.adjustColumnWidthForSortArrow;
|
|
613
|
-
|
|
614
|
-
/**
|
|
615
|
-
* @private
|
|
616
|
-
* @field {boolean} convertColumnWidthsToRelative */
|
|
617
|
-
o.convertColumnWidthsToRelative = options.convertColumnWidthsToRelative === undefined ? false : !!options.convertColumnWidthsToRelative;
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* @private
|
|
621
|
-
* @field {boolean} autoFillTableWidth */
|
|
622
|
-
o.autoFillTableWidth = options.autoFillTableWidth === undefined ? false : !!options.autoFillTableWidth;
|
|
623
|
-
|
|
624
|
-
/**
|
|
625
|
-
* @private
|
|
626
|
-
* @field {boolean} allowCancelSort */
|
|
627
|
-
o.allowCancelSort = options.allowCancelSort === undefined ? true : !!options.allowCancelSort;
|
|
628
|
-
|
|
629
|
-
/**
|
|
630
|
-
* @private
|
|
631
|
-
* @field {string} cellClasses */
|
|
632
|
-
o.cellClasses = options.cellClasses === undefined ? '' : options.cellClasses;
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* @private
|
|
636
|
-
* @field {string} resizerClassName */
|
|
637
|
-
o.resizerClassName = options.resizerClassName === undefined ? 'dgtable-resize' : options.resizerClassName;
|
|
638
|
-
|
|
639
|
-
/**
|
|
640
|
-
* @private
|
|
641
|
-
* @field {string} tableClassName */
|
|
642
|
-
o.tableClassName = options.tableClassName === undefined ? 'dgtable' : options.tableClassName;
|
|
643
|
-
|
|
644
|
-
/**
|
|
645
|
-
* @private
|
|
646
|
-
* @field {boolean} allowCellPreview */
|
|
647
|
-
o.allowCellPreview = options.allowCellPreview === undefined ? true : options.allowCellPreview;
|
|
648
|
-
|
|
649
|
-
/**
|
|
650
|
-
* @private
|
|
651
|
-
* @field {boolean} allowHeaderCellPreview */
|
|
652
|
-
o.allowHeaderCellPreview = options.allowHeaderCellPreview === undefined ? true : options.allowHeaderCellPreview;
|
|
653
|
-
|
|
654
|
-
/**
|
|
655
|
-
* @private
|
|
656
|
-
* @field {string} cellPreviewClassName */
|
|
657
|
-
o.cellPreviewClassName = options.cellPreviewClassName === undefined ? 'dgtable-cell-preview' : options.cellPreviewClassName;
|
|
658
|
-
|
|
659
|
-
/**
|
|
660
|
-
* @private
|
|
661
|
-
* @field {boolean} cellPreviewAutoBackground */
|
|
662
|
-
o.cellPreviewAutoBackground = options.cellPreviewAutoBackground === undefined ? true : options.cellPreviewAutoBackground;
|
|
663
|
-
|
|
664
|
-
/**
|
|
665
|
-
* @private
|
|
666
|
-
* @field {function(columnName: string, descending: boolean, defaultComparator: function(a,b):number):(function(a,b):number)} onComparatorRequired */
|
|
667
|
-
o.onComparatorRequired = options.onComparatorRequired === undefined ? null : options.onComparatorRequired;
|
|
668
|
-
if (!o.onComparatorRequired && typeof options['comparatorCallback'] === 'function') {
|
|
669
|
-
o.onComparatorRequired = options['comparatorCallback'];
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
o.customSortingProvider = options.customSortingProvider === undefined ? null : options.customSortingProvider;
|
|
673
|
-
|
|
674
|
-
/**
|
|
675
|
-
* @private
|
|
676
|
-
* @field {boolean} width */
|
|
677
|
-
o.width = options.width === undefined ? DGTable.Width.NONE : options.width;
|
|
678
|
-
|
|
679
|
-
/**
|
|
680
|
-
* @private
|
|
681
|
-
* @field {boolean} relativeWidthGrowsToFillWidth */
|
|
682
|
-
o.relativeWidthGrowsToFillWidth = options.relativeWidthGrowsToFillWidth === undefined ? true : !!options.relativeWidthGrowsToFillWidth;
|
|
683
|
-
|
|
684
|
-
/**
|
|
685
|
-
* @private
|
|
686
|
-
* @field {boolean} relativeWidthShrinksToFillWidth */
|
|
687
|
-
o.relativeWidthShrinksToFillWidth = options.relativeWidthShrinksToFillWidth === undefined ? false : !!options.relativeWidthShrinksToFillWidth;
|
|
688
|
-
|
|
689
|
-
this.setCellFormatter(options.cellFormatter);
|
|
690
|
-
this.setHeaderCellFormatter(options.headerCellFormatter);
|
|
691
|
-
this.setFilter(options.filter);
|
|
692
|
-
|
|
693
|
-
/** @private
|
|
694
|
-
* @field {number} height */
|
|
695
|
-
o.height = options.height;
|
|
696
|
-
|
|
697
|
-
// Prepare columns
|
|
698
|
-
that.setColumns(options.columns || [], false);
|
|
699
|
-
|
|
700
|
-
// Set sorting columns
|
|
701
|
-
let sortColumns = [];
|
|
702
|
-
|
|
703
|
-
if (options.sortColumn) {
|
|
704
|
-
|
|
705
|
-
let tmpSortColumns = options.sortColumn;
|
|
706
|
-
|
|
707
|
-
if (tmpSortColumns && !Array.isArray(tmpSortColumns)) {
|
|
708
|
-
tmpSortColumns = [tmpSortColumns];
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
if (tmpSortColumns) {
|
|
712
|
-
for (let i = 0, len = tmpSortColumns.length; i < len; i++) {
|
|
713
|
-
let sortColumn = tmpSortColumns[i];
|
|
714
|
-
if (typeof sortColumn === 'string') {
|
|
715
|
-
sortColumn = { column: sortColumn, descending: false };
|
|
716
|
-
}
|
|
717
|
-
let col = p.columns.get(sortColumn.column);
|
|
718
|
-
if (!col) continue;
|
|
719
|
-
|
|
720
|
-
sortColumns.push({
|
|
721
|
-
column: sortColumn.column,
|
|
722
|
-
comparePath: col.comparePath || col.dataPath,
|
|
723
|
-
descending: sortColumn.descending
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
/** @field {RowCollection} _rows */
|
|
730
|
-
p.rows = new RowCollection({ sortColumn: sortColumns });
|
|
731
|
-
p.rows.onComparatorRequired = (column, descending, defaultComparator) => {
|
|
732
|
-
if (o.onComparatorRequired) {
|
|
733
|
-
return o.onComparatorRequired(column, descending, defaultComparator);
|
|
734
|
-
}
|
|
735
|
-
};
|
|
736
|
-
p.rows.customSortingProvider = (data, sort) => {
|
|
737
|
-
if (o.customSortingProvider) {
|
|
738
|
-
return o.customSortingProvider(data, sort);
|
|
739
|
-
} else {
|
|
740
|
-
return sort(data);
|
|
741
|
-
}
|
|
742
|
-
};
|
|
743
|
-
|
|
744
|
-
/** @private
|
|
745
|
-
* @field {RowCollection} _filteredRows */
|
|
746
|
-
p.filteredRows = null;
|
|
747
|
-
|
|
748
|
-
p.scrollbarWidth = 0;
|
|
749
|
-
p.lastVirtualScrollHeight = 0;
|
|
750
|
-
|
|
751
|
-
this._setupHovers();
|
|
752
|
-
};
|
|
753
|
-
|
|
754
|
-
DGTable.prototype._setupHovers = function () {
|
|
755
|
-
const that = this,p = that.p;
|
|
756
|
-
|
|
757
|
-
/*
|
|
758
|
-
Setup hover mechanism.
|
|
759
|
-
We need this to be high performance, as there may be MANY cells to call this on, on creation and destruction.
|
|
760
|
-
Using native events to spare the overhead of jQuery's event binding, and even just the creation of the jQuery collection object.
|
|
761
|
-
*/
|
|
762
|
-
|
|
763
|
-
/**
|
|
764
|
-
* @param {MouseEvent} event
|
|
765
|
-
* @this {HTMLElement}
|
|
766
|
-
* */
|
|
767
|
-
let hoverMouseOverHandler = function (event) {
|
|
768
|
-
let relatedTarget = event.fromElement || event.relatedTarget;
|
|
769
|
-
if (relatedTarget === this || $.contains(this, relatedTarget)) return;
|
|
770
|
-
if (this['__previewCell'] && (relatedTarget === this['__previewCell'] || $.contains(this['__previewCell'], relatedTarget))) return;
|
|
771
|
-
that._cellMouseOverEvent.call(that, this);
|
|
772
|
-
};
|
|
773
|
-
|
|
774
|
-
/**
|
|
775
|
-
* @param {MouseEvent} evt
|
|
776
|
-
* @this {HTMLElement}
|
|
777
|
-
* */
|
|
778
|
-
let hoverMouseOutHandler = function (evt) {
|
|
779
|
-
evt = evt || event;
|
|
780
|
-
let relatedTarget = evt.toElement || evt.relatedTarget;
|
|
781
|
-
if (relatedTarget === this || $.contains(this, relatedTarget)) return;
|
|
782
|
-
if (this['__previewCell'] && (relatedTarget === this['__previewCell'] || $.contains(this['__previewCell'], relatedTarget))) return;
|
|
783
|
-
that._cellMouseOutEvent.call(that, this);
|
|
784
|
-
};
|
|
785
|
-
|
|
786
|
-
/**
|
|
787
|
-
* @param {HTMLElement} el cell or header-cell
|
|
788
|
-
* */
|
|
789
|
-
p._bindCellHoverIn = function (el) {
|
|
790
|
-
if (!el[HoverInEventSymbol]) {
|
|
791
|
-
el.addEventListener('mouseover', el[HoverInEventSymbol] = hoverMouseOverHandler.bind(el));
|
|
792
|
-
}
|
|
793
|
-
};
|
|
794
|
-
|
|
795
|
-
/**
|
|
796
|
-
* @param {HTMLElement} el cell or header-cell
|
|
797
|
-
* */
|
|
798
|
-
p._unbindCellHoverIn = function (el) {
|
|
799
|
-
if (el[HoverInEventSymbol]) {
|
|
800
|
-
el.removeEventListener('mouseover', el[HoverInEventSymbol]);
|
|
801
|
-
el[HoverInEventSymbol] = null;
|
|
802
|
-
}
|
|
803
|
-
};
|
|
804
|
-
|
|
805
|
-
/**
|
|
806
|
-
* @param {HTMLElement} el cell or header-cell
|
|
807
|
-
* @returns {DGTable} self
|
|
808
|
-
* */
|
|
809
|
-
p._bindCellHoverOut = function (el) {
|
|
810
|
-
if (!el[HoverOutEventSymbol]) {
|
|
811
|
-
el.addEventListener('mouseout', el[HoverOutEventSymbol] = hoverMouseOutHandler.bind(el['__cell'] || el));
|
|
812
|
-
}
|
|
813
|
-
return this;
|
|
814
|
-
};
|
|
815
|
-
|
|
816
|
-
/**
|
|
817
|
-
* @param {HTMLElement} el cell or header-cell
|
|
818
|
-
* @returns {DGTable} self
|
|
819
|
-
* */
|
|
820
|
-
p._unbindCellHoverOut = function (el) {
|
|
821
|
-
if (el[HoverOutEventSymbol]) {
|
|
822
|
-
el.removeEventListener('mouseout', el[HoverOutEventSymbol]);
|
|
823
|
-
el[HoverOutEventSymbol] = null;
|
|
824
|
-
}
|
|
825
|
-
return this;
|
|
826
|
-
};
|
|
827
|
-
};
|
|
828
|
-
|
|
829
|
-
DGTable.prototype._setupVirtualTable = function () {
|
|
830
|
-
const that = this,p = that.p,o = that.o;
|
|
831
|
-
|
|
832
|
-
const tableClassName = o.tableClassName,
|
|
833
|
-
rowClassName = tableClassName + '-row',
|
|
834
|
-
altRowClassName = tableClassName + '-row-alt',
|
|
835
|
-
cellClassName = tableClassName + '-cell';
|
|
836
|
-
|
|
837
|
-
let visibleColumns = p.visibleColumns,
|
|
838
|
-
colCount = visibleColumns.length;
|
|
839
|
-
|
|
840
|
-
p.notifyRendererOfColumnsConfig = () => {
|
|
841
|
-
visibleColumns = p.visibleColumns;
|
|
842
|
-
colCount = visibleColumns.length;
|
|
843
|
-
|
|
844
|
-
for (let colIndex = 0, column; colIndex < colCount; colIndex++) {
|
|
845
|
-
column = visibleColumns[colIndex];
|
|
846
|
-
column._finalWidth = column.actualWidthConsideringScrollbarWidth || column.actualWidth;
|
|
847
|
-
}
|
|
848
|
-
};
|
|
849
|
-
|
|
850
|
-
p.virtualListHelper = new VirtualListHelper({
|
|
851
|
-
list: p.table,
|
|
852
|
-
itemsParent: p.tbody,
|
|
853
|
-
autoVirtualWrapperWidth: false,
|
|
854
|
-
virtual: o.virtualTable,
|
|
855
|
-
buffer: o.rowsBufferSize,
|
|
856
|
-
estimatedItemHeight: o.estimatedRowHeight ? o.estimatedRowHeight : p.virtualRowHeight || 40,
|
|
857
|
-
itemElementCreatorFn: () => {
|
|
858
|
-
return createElement('div');
|
|
859
|
-
},
|
|
860
|
-
onItemRender: (row, index) => {
|
|
861
|
-
const rows = p.filteredRows || p.rows,
|
|
862
|
-
isDataFiltered = !!p.filteredRows,
|
|
863
|
-
allowCellPreview = o.allowCellPreview;
|
|
864
|
-
|
|
865
|
-
row.className = rowClassName;
|
|
866
|
-
if (index % 2 === 1)
|
|
867
|
-
row.className += ' ' + altRowClassName;
|
|
868
|
-
|
|
869
|
-
let rowData = rows[index];
|
|
870
|
-
let physicalRowIndex = isDataFiltered ? rowData['__i'] : index;
|
|
871
|
-
|
|
872
|
-
row['rowIndex'] = index;
|
|
873
|
-
row['physicalRowIndex'] = physicalRowIndex;
|
|
874
|
-
|
|
875
|
-
for (let colIndex = 0; colIndex < colCount; colIndex++) {
|
|
876
|
-
let column = visibleColumns[colIndex];
|
|
877
|
-
let cell = createElement('div');
|
|
878
|
-
cell['columnName'] = column.name;
|
|
879
|
-
cell.setAttribute('data-column', column.name);
|
|
880
|
-
cell.className = cellClassName;
|
|
881
|
-
cell.style.width = column._finalWidth + 'px';
|
|
882
|
-
if (column.cellClasses) cell.className += ' ' + column.cellClasses;
|
|
883
|
-
if (allowCellPreview) {
|
|
884
|
-
p._bindCellHoverIn(cell);
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
let cellInner = cell.appendChild(createElement('div'));
|
|
888
|
-
cellInner.innerHTML = this._getHtmlForCell(rowData, column);
|
|
889
|
-
|
|
890
|
-
row.appendChild(cell);
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
row.addEventListener('click', row[RowClickEventSymbol] = (event) => {
|
|
894
|
-
that.trigger('rowclick', event, index, physicalRowIndex, row, rowData);
|
|
895
|
-
});
|
|
896
|
-
|
|
897
|
-
that.trigger('rowcreate', index, physicalRowIndex, row, rowData);
|
|
898
|
-
},
|
|
899
|
-
|
|
900
|
-
onItemUnrender: (row) => {
|
|
901
|
-
if (row[RowClickEventSymbol]) {
|
|
902
|
-
row.removeEventListener('click', row[RowClickEventSymbol]);
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
that._unbindCellEventsForRow(row);
|
|
906
|
-
|
|
907
|
-
that.trigger('rowdestroy', row);
|
|
908
|
-
},
|
|
909
|
-
|
|
910
|
-
onScrollHeightChange: (height) => {
|
|
911
|
-
// only recalculate scrollbar width if height increased. we reset it in other situations.
|
|
912
|
-
if (height > p._lastVirtualScrollHeight && !p.scrollbarWidth) {
|
|
913
|
-
this._updateLastCellWidthFromScrollbar();
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
p._lastVirtualScrollHeight = height;
|
|
917
|
-
}
|
|
918
|
-
});
|
|
919
|
-
|
|
920
|
-
p.virtualListHelper.setCount((p.filteredRows ?? p.rows).length);
|
|
921
|
-
|
|
922
|
-
p.notifyRendererOfColumnsConfig();
|
|
923
|
-
};
|
|
924
|
-
|
|
925
|
-
/**
|
|
926
|
-
* Add an event listener
|
|
927
|
-
* @public
|
|
928
|
-
* @expose
|
|
929
|
-
* @param {string} eventName
|
|
930
|
-
* @param {Function} callback
|
|
931
|
-
* @returns {DGTable}
|
|
932
|
-
*/
|
|
933
|
-
DGTable.prototype.on = function (eventName, callback) {
|
|
934
|
-
let that = this,events = that.p.events;
|
|
935
|
-
|
|
936
|
-
if (typeof callback !== 'function')
|
|
937
|
-
return that;
|
|
938
|
-
|
|
939
|
-
if (!hasOwnProperty.call(events, eventName))
|
|
940
|
-
events[eventName] = [];
|
|
941
|
-
|
|
942
|
-
events[eventName].push({
|
|
943
|
-
cb: callback,
|
|
944
|
-
once: false
|
|
945
|
-
});
|
|
946
|
-
|
|
947
|
-
return that;
|
|
948
|
-
};
|
|
949
|
-
|
|
950
|
-
/**
|
|
951
|
-
* Add an event listener for a one shot
|
|
952
|
-
* @public
|
|
953
|
-
* @expose
|
|
954
|
-
* @param {string} eventName
|
|
955
|
-
* @param {Function} callback
|
|
956
|
-
* @returns {DGTable}
|
|
957
|
-
*/
|
|
958
|
-
DGTable.prototype.once = function (eventName, callback) {
|
|
959
|
-
let that = this,events = that.p.events;
|
|
960
|
-
|
|
961
|
-
if (typeof callback !== 'function')
|
|
962
|
-
return that;
|
|
963
|
-
|
|
964
|
-
if (!hasOwnProperty.call(events, eventName))
|
|
965
|
-
events[eventName] = [];
|
|
966
|
-
|
|
967
|
-
events[eventName].push({
|
|
968
|
-
cb: callback,
|
|
969
|
-
once: true
|
|
970
|
-
});
|
|
971
|
-
|
|
972
|
-
return that;
|
|
973
|
-
};
|
|
974
|
-
|
|
975
|
-
/**
|
|
976
|
-
* Remove an event listener
|
|
977
|
-
* @public
|
|
978
|
-
* @expose
|
|
979
|
-
* @param {string} eventName
|
|
980
|
-
* @param {Function} callback
|
|
981
|
-
* @returns {DGTable}
|
|
982
|
-
*/
|
|
983
|
-
DGTable.prototype.off = function (eventName, callback) {
|
|
984
|
-
let events = this.p.events;
|
|
985
|
-
|
|
986
|
-
if (!hasOwnProperty.call(events, eventName))
|
|
987
|
-
return this;
|
|
988
|
-
|
|
989
|
-
let callbacks = events[eventName];
|
|
990
|
-
for (let i = 0; i < callbacks.length; i++) {
|
|
991
|
-
let item = callbacks[i];
|
|
992
|
-
if (callback && item.cb !== callback) continue;
|
|
993
|
-
callbacks.splice(i--, 1);
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
return this;
|
|
997
|
-
};
|
|
998
|
-
|
|
999
|
-
DGTable.prototype.trigger = function (eventName) {
|
|
1000
|
-
const p = this.p;
|
|
1001
|
-
if (!p) return;
|
|
1002
|
-
|
|
1003
|
-
let events = p.events;
|
|
1004
|
-
|
|
1005
|
-
if (hasOwnProperty.call(events, eventName)) {
|
|
1006
|
-
let callbacks = events[eventName];
|
|
1007
|
-
for (let i = 0; i < callbacks.length; i++) {
|
|
1008
|
-
let item = callbacks[i];
|
|
1009
|
-
if (item.once) {
|
|
1010
|
-
callbacks.splice(i--, 1);
|
|
1011
|
-
}
|
|
1012
|
-
item.cb.apply(this, Array.prototype.slice.call(arguments, 1));
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
return this;
|
|
1017
|
-
};
|
|
1018
|
-
|
|
1019
|
-
/**
|
|
1020
|
-
* Detect column width mode
|
|
1021
|
-
* @private
|
|
1022
|
-
* @param {Number|string} width
|
|
1023
|
-
* @param {number} minWidth
|
|
1024
|
-
* @returns {Object} parsed width
|
|
1025
|
-
*/
|
|
1026
|
-
DGTable.prototype._parseColumnWidth = function (width, minWidth) {
|
|
1027
|
-
|
|
1028
|
-
let widthSize = Math.max(0, parseFloat(width)),
|
|
1029
|
-
widthMode = ColumnWidthMode.AUTO; // Default
|
|
1030
|
-
|
|
1031
|
-
if (widthSize > 0) {
|
|
1032
|
-
// Well, it's sure is not AUTO, as we have a value
|
|
1033
|
-
|
|
1034
|
-
if (width === widthSize + '%') {
|
|
1035
|
-
// It's a percentage!
|
|
1036
|
-
|
|
1037
|
-
widthMode = ColumnWidthMode.RELATIVE;
|
|
1038
|
-
widthSize /= 100;
|
|
1039
|
-
} else if (widthSize > 0 && widthSize < 1) {
|
|
1040
|
-
// It's a decimal value, as a relative value!
|
|
1041
|
-
|
|
1042
|
-
widthMode = ColumnWidthMode.RELATIVE;
|
|
1043
|
-
} else {
|
|
1044
|
-
// It's an absolute size!
|
|
1045
|
-
|
|
1046
|
-
if (widthSize < minWidth) {
|
|
1047
|
-
widthSize = minWidth;
|
|
1048
|
-
}
|
|
1049
|
-
widthMode = ColumnWidthMode.ABSOLUTE;
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
return { width: widthSize, mode: widthMode };
|
|
1054
|
-
};
|
|
1055
|
-
|
|
1056
|
-
/**
|
|
1057
|
-
* @private
|
|
1058
|
-
* @param {COLUMN_OPTIONS} columnData
|
|
1059
|
-
*/
|
|
1060
|
-
DGTable.prototype._initColumnFromData = function (columnData) {
|
|
1061
|
-
|
|
1062
|
-
let parsedWidth = this._parseColumnWidth(columnData.width, columnData.ignoreMin ? 0 : this.o.minColumnWidth);
|
|
1063
|
-
|
|
1064
|
-
let col = {
|
|
1065
|
-
name: columnData.name,
|
|
1066
|
-
label: columnData.label === undefined ? columnData.name : columnData.label,
|
|
1067
|
-
width: parsedWidth.width,
|
|
1068
|
-
widthMode: parsedWidth.mode,
|
|
1069
|
-
resizable: columnData.resizable === undefined ? true : columnData.resizable,
|
|
1070
|
-
sortable: columnData.sortable === undefined ? true : columnData.sortable,
|
|
1071
|
-
movable: columnData.movable === undefined ? true : columnData.movable,
|
|
1072
|
-
visible: columnData.visible === undefined ? true : columnData.visible,
|
|
1073
|
-
cellClasses: columnData.cellClasses === undefined ? this.o.cellClasses : columnData.cellClasses,
|
|
1074
|
-
ignoreMin: columnData.ignoreMin === undefined ? false : !!columnData.ignoreMin
|
|
1075
|
-
};
|
|
1076
|
-
|
|
1077
|
-
col.dataPath = columnData.dataPath === undefined ? col.name : columnData.dataPath;
|
|
1078
|
-
col.comparePath = columnData.comparePath === undefined ? col.dataPath : columnData.comparePath;
|
|
1079
|
-
|
|
1080
|
-
if (typeof col.dataPath === 'string') {
|
|
1081
|
-
col.dataPath = col.dataPath.split('.');
|
|
1082
|
-
}
|
|
1083
|
-
if (typeof col.comparePath === 'string') {
|
|
1084
|
-
col.comparePath = col.comparePath.split('.');
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
return col;
|
|
1088
|
-
};
|
|
1089
|
-
|
|
1090
|
-
/**
|
|
1091
|
-
* Destroy, releasing all memory, events and DOM elements
|
|
1092
|
-
* @public
|
|
1093
|
-
* @expose
|
|
1094
|
-
*/
|
|
1095
|
-
DGTable.prototype.close = DGTable.prototype.remove = DGTable.prototype.destroy = function () {
|
|
1096
|
-
|
|
1097
|
-
let that = this,
|
|
1098
|
-
p = that.p || {},
|
|
1099
|
-
$el = that.$el;
|
|
1100
|
-
|
|
1101
|
-
if (that.__removed) {
|
|
1102
|
-
return that;
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
if (p.$resizer) {
|
|
1106
|
-
p.$resizer.remove();
|
|
1107
|
-
p.$resizer = null;
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
p.virtualListHelper?.destroy();
|
|
1111
|
-
p.virtualListHelper = null;
|
|
1112
|
-
|
|
1113
|
-
// Using quotes for __super__ because Google Closure Compiler has a bug...
|
|
1114
|
-
|
|
1115
|
-
this._destroyHeaderCells();
|
|
1116
|
-
|
|
1117
|
-
if (p.$table) {
|
|
1118
|
-
p.$table.empty();
|
|
1119
|
-
}
|
|
1120
|
-
if (p.$tbody) {
|
|
1121
|
-
p.$tbody.empty();
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
if (p.workerListeners) {
|
|
1125
|
-
for (let j = 0; j < p.workerListeners.length; j++) {
|
|
1126
|
-
let worker = p.workerListeners[j];
|
|
1127
|
-
worker.worker.removeEventListener('message', worker.listener, false);
|
|
1128
|
-
}
|
|
1129
|
-
p.workerListeners.length = 0;
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
p.rows.length = p.columns.length = 0;
|
|
1133
|
-
|
|
1134
|
-
if (p._deferredRender) {
|
|
1135
|
-
clearTimeout(p._deferredRender);
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
// Cleanup
|
|
1139
|
-
for (let prop in that) {
|
|
1140
|
-
if (hasOwnProperty.call(that, prop)) {
|
|
1141
|
-
that[prop] = null;
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
that.__removed = true;
|
|
1146
|
-
|
|
1147
|
-
if ($el) {
|
|
1148
|
-
$el.remove();
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
return this;
|
|
1152
|
-
};
|
|
1153
|
-
|
|
1154
|
-
/**
|
|
1155
|
-
* @private
|
|
1156
|
-
* @returns {DGTable} self
|
|
1157
|
-
*/
|
|
1158
|
-
DGTable.prototype._unbindCellEventsForTable = function () {
|
|
1159
|
-
const p = this.p;
|
|
1160
|
-
|
|
1161
|
-
if (p.headerRow) {
|
|
1162
|
-
for (let i = 0, rows = p.headerRow.childNodes, rowCount = rows.length; i < rowCount; i++) {
|
|
1163
|
-
let rowToClean = rows[i];
|
|
1164
|
-
for (let j = 0, cells = rowToClean.childNodes, cellCount = cells.length; j < cellCount; j++) {
|
|
1165
|
-
p._unbindCellHoverIn(cells[j]);
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
return this;
|
|
1171
|
-
};
|
|
1172
|
-
|
|
1173
|
-
/**
|
|
1174
|
-
* @private
|
|
1175
|
-
* @param {HTMLElement} rowToClean
|
|
1176
|
-
* @returns {DGTable} self
|
|
1177
|
-
*/
|
|
1178
|
-
DGTable.prototype._unbindCellEventsForRow = function (rowToClean) {
|
|
1179
|
-
const p = this.p;
|
|
1180
|
-
for (let i = 0, cells = rowToClean.childNodes, cellCount = cells.length; i < cellCount; i++) {
|
|
1181
|
-
p._unbindCellHoverIn(cells[i]);
|
|
1182
|
-
}
|
|
1183
|
-
return this;
|
|
1184
|
-
};
|
|
1185
|
-
|
|
1186
|
-
/**
|
|
1187
|
-
* @public
|
|
1188
|
-
* @expose
|
|
1189
|
-
* @returns {DGTable} self
|
|
1190
|
-
*/
|
|
1191
|
-
DGTable.prototype.render = function () {
|
|
1192
|
-
const o = this.o,p = this.p;
|
|
1193
|
-
|
|
1194
|
-
if (!this.el.offsetParent) {
|
|
1195
|
-
if (!p._deferredRender) {
|
|
1196
|
-
p._deferredRender = setTimeout(() => {
|
|
1197
|
-
p._deferredRender = null;
|
|
1198
|
-
if (!this.__removed && this.el.offsetParent) {
|
|
1199
|
-
this.render();
|
|
1200
|
-
}
|
|
1201
|
-
});
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
return this;
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
if (p.tableSkeletonNeedsRendering === true) {
|
|
1208
|
-
p.tableSkeletonNeedsRendering = false;
|
|
1209
|
-
|
|
1210
|
-
if (o.width === DGTable.Width.AUTO) {
|
|
1211
|
-
// We need to do this to return to the specified widths instead. The arrows added to the column widths...
|
|
1212
|
-
this._clearSortArrows();
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
let lastScrollTop = p.table && p.table.parentNode ? p.table.scrollTop : NaN,
|
|
1216
|
-
lastScrollHorz = p.table && p.table.parentNode ? ScrollHelper_js.getScrollHorz(p.table) : NaN;
|
|
1217
|
-
|
|
1218
|
-
this._renderSkeletonBase().
|
|
1219
|
-
_renderSkeletonBody().
|
|
1220
|
-
tableWidthChanged(true, false) // Take this chance to calculate required column widths
|
|
1221
|
-
._renderSkeletonHeaderCells();
|
|
1222
|
-
|
|
1223
|
-
p.virtualListHelper.setCount((p.filteredRows ?? p.rows).length);
|
|
1224
|
-
|
|
1225
|
-
this._updateVirtualHeight();
|
|
1226
|
-
this._updateLastCellWidthFromScrollbar(true);
|
|
1227
|
-
this._updateTableWidth(true);
|
|
1228
|
-
|
|
1229
|
-
// Show sort arrows
|
|
1230
|
-
for (let i = 0; i < p.rows.sortColumn.length; i++) {
|
|
1231
|
-
this._showSortArrow(p.rows.sortColumn[i].column, p.rows.sortColumn[i].descending);
|
|
1232
|
-
}
|
|
1233
|
-
if (o.adjustColumnWidthForSortArrow && p.rows.sortColumn.length) {
|
|
1234
|
-
this.tableWidthChanged(true);
|
|
1235
|
-
} else if (!o.virtualTable) {
|
|
1236
|
-
this.tableWidthChanged();
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
if (!isNaN(lastScrollTop))
|
|
1240
|
-
p.table.scrollTop = lastScrollTop;
|
|
1241
|
-
|
|
1242
|
-
if (!isNaN(lastScrollHorz)) {
|
|
1243
|
-
ScrollHelper_js.setScrollHorz(p.table, lastScrollHorz);
|
|
1244
|
-
ScrollHelper_js.setScrollHorz(p.header, lastScrollHorz);
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
this.trigger('renderskeleton');
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
p.virtualListHelper.render();
|
|
1251
|
-
|
|
1252
|
-
this.trigger('render');
|
|
1253
|
-
return this;
|
|
1254
|
-
};
|
|
1255
|
-
|
|
1256
|
-
/**
|
|
1257
|
-
* Forces a full render of the table
|
|
1258
|
-
* @public
|
|
1259
|
-
* @expose
|
|
1260
|
-
* @param {boolean=true} render - Should render now?
|
|
1261
|
-
* @returns {DGTable} self
|
|
1262
|
-
*/
|
|
1263
|
-
DGTable.prototype.clearAndRender = function (render) {
|
|
1264
|
-
let p = this.p;
|
|
1265
|
-
|
|
1266
|
-
p.tableSkeletonNeedsRendering = true;
|
|
1267
|
-
p.notifyRendererOfColumnsConfig?.();
|
|
1268
|
-
|
|
1269
|
-
if (render === undefined || render) {
|
|
1270
|
-
this.render();
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
return this;
|
|
1274
|
-
};
|
|
1275
|
-
|
|
1276
|
-
/**
|
|
1277
|
-
* Calculate the size required for the table body width (which is the row's width)
|
|
1278
|
-
* @private
|
|
1279
|
-
* @returns {number} calculated width
|
|
1280
|
-
*/
|
|
1281
|
-
DGTable.prototype._calculateTbodyWidth = function () {
|
|
1282
|
-
const p = this.p;
|
|
1283
|
-
|
|
1284
|
-
let tableClassName = this.o.tableClassName,
|
|
1285
|
-
rowClassName = tableClassName + '-row',
|
|
1286
|
-
cellClassName = tableClassName + '-cell',
|
|
1287
|
-
visibleColumns = p.visibleColumns,
|
|
1288
|
-
colCount = visibleColumns.length,
|
|
1289
|
-
cell,
|
|
1290
|
-
colIndex,
|
|
1291
|
-
column;
|
|
1292
|
-
|
|
1293
|
-
let $row = $('<div>').addClass(rowClassName).css('float', 'left');
|
|
1294
|
-
let sumActualWidth = 0;
|
|
1295
|
-
|
|
1296
|
-
for (colIndex = 0; colIndex < colCount; colIndex++) {
|
|
1297
|
-
column = visibleColumns[colIndex];
|
|
1298
|
-
cell = createElement('div');
|
|
1299
|
-
cell.className = cellClassName;
|
|
1300
|
-
cell.style.width = column.actualWidth + 'px';
|
|
1301
|
-
if (column.cellClasses) cell.className += ' ' + column.cellClasses;
|
|
1302
|
-
cell.appendChild(createElement('div'));
|
|
1303
|
-
$row.append(cell);
|
|
1304
|
-
sumActualWidth += column.actualWidth;
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
let $thisWrapper = $('<div>').
|
|
1308
|
-
addClass(this.el.className).
|
|
1309
|
-
css({ 'z-index': -1, 'position': 'absolute', left: '0', top: '-9999px', 'float': 'left', width: '1px', overflow: 'hidden' }).
|
|
1310
|
-
append(
|
|
1311
|
-
$('<div>').addClass(tableClassName).append(
|
|
1312
|
-
$('<div>').addClass(tableClassName + '-body').css('width', sumActualWidth + 10000).append(
|
|
1313
|
-
$row
|
|
1314
|
-
)
|
|
1315
|
-
)
|
|
1316
|
-
);
|
|
1317
|
-
|
|
1318
|
-
$thisWrapper.appendTo(document.body);
|
|
1319
|
-
|
|
1320
|
-
let fractionTest = $('<div style="border:1.5px solid #000;width:0;height:0;position:absolute;left:0;top:-9999px">').appendTo(document.body);
|
|
1321
|
-
let fractionValue = parseFloat(fractionTest.css('border-width'));
|
|
1322
|
-
let hasFractions = Math.round(fractionValue) !== fractionValue;
|
|
1323
|
-
fractionTest.remove();
|
|
1324
|
-
|
|
1325
|
-
let width = Css_js.getElementWidth($row[0], true, true, true);
|
|
1326
|
-
width -= p.scrollbarWidth || 0;
|
|
1327
|
-
|
|
1328
|
-
if (hasFractions) {
|
|
1329
|
-
width++;
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
$thisWrapper.remove();
|
|
1333
|
-
return width;
|
|
1334
|
-
};
|
|
1335
|
-
|
|
1336
|
-
/**
|
|
1337
|
-
* Sets the columns of the table
|
|
1338
|
-
* @public
|
|
1339
|
-
* @expose
|
|
1340
|
-
* @param {COLUMN_OPTIONS[]} columns - Column definitions array
|
|
1341
|
-
* @param {boolean=true} render - Should render now?
|
|
1342
|
-
* @returns {DGTable} self
|
|
1343
|
-
*/
|
|
1344
|
-
DGTable.prototype.setColumns = function (columns, render) {
|
|
1345
|
-
const p = this.p;
|
|
1346
|
-
|
|
1347
|
-
columns = columns || [];
|
|
1348
|
-
|
|
1349
|
-
let normalizedCols = new ColumnCollection();
|
|
1350
|
-
for (let i = 0, order = 0; i < columns.length; i++) {
|
|
1351
|
-
|
|
1352
|
-
let columnData = columns[i];
|
|
1353
|
-
let normalizedColumn = this._initColumnFromData(columnData);
|
|
1354
|
-
|
|
1355
|
-
if (columnData.order !== undefined) {
|
|
1356
|
-
if (columnData.order > order) {
|
|
1357
|
-
order = columnData.order + 1;
|
|
1358
|
-
}
|
|
1359
|
-
normalizedColumn.order = columnData.order;
|
|
1360
|
-
} else {
|
|
1361
|
-
normalizedColumn.order = order++;
|
|
1362
|
-
}
|
|
1363
|
-
|
|
1364
|
-
normalizedCols.push(normalizedColumn);
|
|
1365
|
-
}
|
|
1366
|
-
normalizedCols.normalizeOrder();
|
|
1367
|
-
|
|
1368
|
-
p.columns = normalizedCols;
|
|
1369
|
-
p.visibleColumns = normalizedCols.getVisibleColumns();
|
|
1370
|
-
|
|
1371
|
-
this._ensureVisibleColumns().clearAndRender(render);
|
|
1372
|
-
|
|
1373
|
-
return this;
|
|
1374
|
-
};
|
|
1375
|
-
|
|
1376
|
-
/**
|
|
1377
|
-
* Add a column to the table
|
|
1378
|
-
* @public
|
|
1379
|
-
* @expose
|
|
1380
|
-
* @param {COLUMN_OPTIONS} columnData column properties
|
|
1381
|
-
* @param {string|number} [before=-1] column name or order to be inserted before
|
|
1382
|
-
* @param {boolean=true} render - Should render now?
|
|
1383
|
-
* @returns {DGTable} self
|
|
1384
|
-
*/
|
|
1385
|
-
DGTable.prototype.addColumn = function (columnData, before, render) {
|
|
1386
|
-
const p = this.p;
|
|
1387
|
-
let columns = p.columns;
|
|
1388
|
-
|
|
1389
|
-
if (columnData && !columns.get(columnData.name)) {
|
|
1390
|
-
let beforeColumn = null;
|
|
1391
|
-
if (before !== undefined) {
|
|
1392
|
-
beforeColumn = columns.get(before) || columns.getByOrder(before);
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
let column = this._initColumnFromData(columnData);
|
|
1396
|
-
column.order = beforeColumn ? beforeColumn.order : columns.getMaxOrder() + 1;
|
|
1397
|
-
|
|
1398
|
-
for (let i = columns.getMaxOrder(), to = column.order; i >= to; i--) {
|
|
1399
|
-
let col = columns.getByOrder(i);
|
|
1400
|
-
if (col) {
|
|
1401
|
-
col.order++;
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
columns.push(column);
|
|
1406
|
-
columns.normalizeOrder();
|
|
1407
|
-
|
|
1408
|
-
p.visibleColumns = columns.getVisibleColumns();
|
|
1409
|
-
this._ensureVisibleColumns().clearAndRender(render);
|
|
1410
|
-
|
|
1411
|
-
this.trigger('addcolumn', column.name);
|
|
1412
|
-
}
|
|
1413
|
-
return this;
|
|
1414
|
-
};
|
|
1415
|
-
|
|
1416
|
-
/**
|
|
1417
|
-
* Remove a column from the table
|
|
1418
|
-
* @public
|
|
1419
|
-
* @expose
|
|
1420
|
-
* @param {string} column column name
|
|
1421
|
-
* @param {boolean=true} render - Should render now?
|
|
1422
|
-
* @returns {DGTable} self
|
|
1423
|
-
*/
|
|
1424
|
-
DGTable.prototype.removeColumn = function (column, render) {
|
|
1425
|
-
const p = this.p;
|
|
1426
|
-
let columns = p.columns;
|
|
1427
|
-
|
|
1428
|
-
let colIdx = columns.indexOf(column);
|
|
1429
|
-
if (colIdx > -1) {
|
|
1430
|
-
columns.splice(colIdx, 1);
|
|
1431
|
-
columns.normalizeOrder();
|
|
1432
|
-
|
|
1433
|
-
p.visibleColumns = columns.getVisibleColumns();
|
|
1434
|
-
this._ensureVisibleColumns().clearAndRender(render);
|
|
1435
|
-
|
|
1436
|
-
this.trigger('removecolumn', column);
|
|
1437
|
-
}
|
|
1438
|
-
return this;
|
|
1439
|
-
};
|
|
1440
|
-
|
|
1441
|
-
/**
|
|
1442
|
-
* Sets a new cell formatter.
|
|
1443
|
-
* @public
|
|
1444
|
-
* @expose
|
|
1445
|
-
* @param {function(value: *, columnName: string, row: Object):string|null} [formatter=null] - The cell formatter. Should return an HTML.
|
|
1446
|
-
* @returns {DGTable} self
|
|
1447
|
-
*/
|
|
1448
|
-
DGTable.prototype.setCellFormatter = function (formatter) {
|
|
1449
|
-
if (!formatter) {
|
|
1450
|
-
formatter = (val) => typeof val === 'string' ? htmlEncode(val) : val;
|
|
1451
|
-
formatter[IsSafeSymbol] = true;
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
/**
|
|
1455
|
-
* @private
|
|
1456
|
-
* @field {Function} cellFormatter */
|
|
1457
|
-
this.o.cellFormatter = formatter;
|
|
1458
|
-
|
|
1459
|
-
return this;
|
|
1460
|
-
};
|
|
1461
|
-
|
|
1462
|
-
/**
|
|
1463
|
-
* Sets a new header cell formatter.
|
|
1464
|
-
* @public
|
|
1465
|
-
* @expose
|
|
1466
|
-
* @param {function(label: string, columnName: string):string|null} [formatter=null] - The cell formatter. Should return an HTML.
|
|
1467
|
-
* @returns {DGTable} self
|
|
1468
|
-
*/
|
|
1469
|
-
DGTable.prototype.setHeaderCellFormatter = function (formatter) {
|
|
1470
|
-
/**
|
|
1471
|
-
* @private
|
|
1472
|
-
* @field {Function} headerCellFormatter */
|
|
1473
|
-
this.o.headerCellFormatter = formatter || function (val) {
|
|
1474
|
-
return typeof val === 'string' ? htmlEncode(val) : val;
|
|
1475
|
-
};
|
|
1476
|
-
|
|
1477
|
-
return this;
|
|
1478
|
-
};
|
|
1479
|
-
|
|
1480
|
-
/**
|
|
1481
|
-
* @public
|
|
1482
|
-
* @expose
|
|
1483
|
-
* @param {function(row:Object,args:Object):boolean|null} [filterFunc=null] - The filter function to work with filters. Default is a by-colum filter.
|
|
1484
|
-
* @returns {DGTable} self
|
|
1485
|
-
*/
|
|
1486
|
-
DGTable.prototype.setFilter = function (filterFunc) {
|
|
1487
|
-
/** @private
|
|
1488
|
-
* @field {Function} filter */
|
|
1489
|
-
this.o.filter = filterFunc;
|
|
1490
|
-
return this;
|
|
1491
|
-
};
|
|
1492
|
-
|
|
1493
|
-
/**
|
|
1494
|
-
* @public
|
|
1495
|
-
* @expose
|
|
1496
|
-
* @param {Object|null} args - Options to pass to the filter function
|
|
1497
|
-
* @returns {DGTable} self
|
|
1498
|
-
*/
|
|
1499
|
-
DGTable.prototype.filter = function (args) {
|
|
1500
|
-
const p = this.p;
|
|
1501
|
-
|
|
1502
|
-
let filterFunc = this.o.filter || ByColumnFilter;
|
|
1503
|
-
|
|
1504
|
-
// Deprecated use of older by-column filter
|
|
1505
|
-
if (typeof arguments[0] === 'string' && typeof arguments[1] === 'string') {
|
|
1506
|
-
args = {
|
|
1507
|
-
column: arguments[0],
|
|
1508
|
-
keyword: arguments[1],
|
|
1509
|
-
caseSensitive: arguments[2]
|
|
1510
|
-
};
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
let hadFilter = !!p.filteredRows;
|
|
1514
|
-
if (p.filteredRows) {
|
|
1515
|
-
p.filteredRows = null; // Allow releasing array memory now
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
// Shallow-clone the args, as the filter function may want to modify it for keeping state
|
|
1519
|
-
p.filterArgs = args == null ? null : typeof args === 'object' && !Array.isArray(args) ? $.extend({}, args) : args;
|
|
1520
|
-
|
|
1521
|
-
if (p.filterArgs !== null) {
|
|
1522
|
-
p.filteredRows = p.rows.filteredCollection(filterFunc, p.filterArgs);
|
|
1523
|
-
|
|
1524
|
-
if (hadFilter || p.filteredRows) {
|
|
1525
|
-
this.clearAndRender();
|
|
1526
|
-
this.trigger('filter', args);
|
|
1527
|
-
}
|
|
1528
|
-
} else
|
|
1529
|
-
{
|
|
1530
|
-
p.filterArgs = null;
|
|
1531
|
-
p.filteredRows = null;
|
|
1532
|
-
this.clearAndRender();
|
|
1533
|
-
this.trigger('filterclear', {});
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
return this;
|
|
1537
|
-
};
|
|
1538
|
-
|
|
1539
|
-
/**
|
|
1540
|
-
* @public
|
|
1541
|
-
* @expose
|
|
1542
|
-
* @returns {DGTable} self
|
|
1543
|
-
*/
|
|
1544
|
-
DGTable.prototype.clearFilter = function () {
|
|
1545
|
-
const p = this.p;
|
|
1546
|
-
|
|
1547
|
-
if (p.filteredRows) {
|
|
1548
|
-
p.filterArgs = null;
|
|
1549
|
-
p.filteredRows = null;
|
|
1550
|
-
this.clearAndRender();
|
|
1551
|
-
this.trigger('filterclear', {});
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
return this;
|
|
1555
|
-
};
|
|
1556
|
-
|
|
1557
|
-
/**
|
|
1558
|
-
* @private
|
|
1559
|
-
* @returns {DGTable} self
|
|
1560
|
-
*/
|
|
1561
|
-
DGTable.prototype._refilter = function () {
|
|
1562
|
-
const p = this.p;
|
|
1563
|
-
|
|
1564
|
-
if (p.filteredRows && p.filterArgs) {
|
|
1565
|
-
let filterFunc = this.o.filter || ByColumnFilter;
|
|
1566
|
-
p.filteredRows = p.rows.filteredCollection(filterFunc, p.filterArgs);
|
|
1567
|
-
}
|
|
1568
|
-
return this;
|
|
1569
|
-
};
|
|
1570
|
-
|
|
1571
|
-
/**
|
|
1572
|
-
* Set a new label to a column
|
|
1573
|
-
* @public
|
|
1574
|
-
* @expose
|
|
1575
|
-
* @param {string} column Name of the column
|
|
1576
|
-
* @param {string} label New label for the column
|
|
1577
|
-
* @returns {DGTable} self
|
|
1578
|
-
*/
|
|
1579
|
-
DGTable.prototype.setColumnLabel = function (column, label) {
|
|
1580
|
-
const p = this.p;
|
|
1581
|
-
|
|
1582
|
-
let col = p.columns.get(column);
|
|
1583
|
-
if (col) {
|
|
1584
|
-
col.label = label === undefined ? col.name : label;
|
|
1585
|
-
|
|
1586
|
-
if (col.element) {
|
|
1587
|
-
for (let i = 0; i < col.element[0].firstChild.childNodes.length; i++) {
|
|
1588
|
-
let node = col.element[0].firstChild.childNodes[i];
|
|
1589
|
-
if (node.nodeType === 3) {
|
|
1590
|
-
node.textContent = col.label;
|
|
1591
|
-
break;
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
return this;
|
|
1597
|
-
};
|
|
1598
|
-
|
|
1599
|
-
/**
|
|
1600
|
-
* Move a column to a new position
|
|
1601
|
-
* @public
|
|
1602
|
-
* @expose
|
|
1603
|
-
* @param {string|number} src Name or position of the column to be moved
|
|
1604
|
-
* @param {string|number} dest Name of the column currently in the desired position, or the position itself
|
|
1605
|
-
* @param {boolean} [visibleOnly=true] Should consider only visible columns and visible-relative indexes
|
|
1606
|
-
* @returns {DGTable} self
|
|
1607
|
-
*/
|
|
1608
|
-
DGTable.prototype.moveColumn = function (src, dest) {let visibleOnly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
1609
|
-
const o = this.o,p = this.p;
|
|
1610
|
-
|
|
1611
|
-
let columns = p.columns,
|
|
1612
|
-
col,destCol;
|
|
1613
|
-
|
|
1614
|
-
let columnsArray = visibleOnly ? p.visibleColumns : columns.getColumns();
|
|
1615
|
-
|
|
1616
|
-
if (typeof src === 'string') {
|
|
1617
|
-
col = columns.get(src);
|
|
1618
|
-
} else if (typeof src === 'number') {
|
|
1619
|
-
col = columnsArray[src];
|
|
1620
|
-
}
|
|
1621
|
-
if (typeof dest === 'string') {
|
|
1622
|
-
destCol = columns.get(dest);
|
|
1623
|
-
} else if (typeof dest === 'number') {
|
|
1624
|
-
destCol = columnsArray[dest];
|
|
1625
|
-
}
|
|
1626
|
-
|
|
1627
|
-
if (col && destCol && src !== dest) {
|
|
1628
|
-
let srcOrder = col.order,destOrder = destCol.order;
|
|
1629
|
-
|
|
1630
|
-
let visibleColumns = columns.moveColumn(col, destCol).getVisibleColumns();
|
|
1631
|
-
|
|
1632
|
-
if (p.visibleColumns.length !== visibleColumns.length ||
|
|
1633
|
-
p.visibleColumns.some((x, i) => x !== visibleColumns[i])) {
|
|
1634
|
-
|
|
1635
|
-
p.visibleColumns = visibleColumns;
|
|
1636
|
-
this._ensureVisibleColumns();
|
|
1637
|
-
|
|
1638
|
-
if (o.virtualTable) {
|
|
1639
|
-
this.clearAndRender();
|
|
1640
|
-
} else {
|
|
1641
|
-
let headerCell = p.$headerRow.find('>div.' + o.tableClassName + '-header-cell');
|
|
1642
|
-
let beforePos = srcOrder < destOrder ? destOrder + 1 : destOrder,
|
|
1643
|
-
fromPos = srcOrder;
|
|
1644
|
-
headerCell[0].parentNode.insertBefore(headerCell[fromPos], headerCell[beforePos]);
|
|
1645
|
-
|
|
1646
|
-
let srcWidth = p.visibleColumns[srcOrder];
|
|
1647
|
-
srcWidth = (srcWidth.actualWidthConsideringScrollbarWidth || srcWidth.actualWidth) + 'px';
|
|
1648
|
-
let destWidth = p.visibleColumns[destOrder];
|
|
1649
|
-
destWidth = (destWidth.actualWidthConsideringScrollbarWidth || destWidth.actualWidth) + 'px';
|
|
1650
|
-
|
|
1651
|
-
let tbodyChildren = p.tbody.childNodes;
|
|
1652
|
-
for (let i = 0, count = tbodyChildren.length; i < count; i++) {
|
|
1653
|
-
let row = tbodyChildren[i];
|
|
1654
|
-
if (row.nodeType !== 1) continue;
|
|
1655
|
-
row.insertBefore(row.childNodes[fromPos], row.childNodes[beforePos]);
|
|
1656
|
-
row.childNodes[destOrder].firstChild.style.width = destWidth;
|
|
1657
|
-
row.childNodes[srcOrder].firstChild.style.width = srcWidth;
|
|
1658
|
-
}
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
this.trigger('movecolumn', col.name, srcOrder, destOrder);
|
|
1663
|
-
}
|
|
1664
|
-
return this;
|
|
1665
|
-
};
|
|
1666
|
-
|
|
1667
|
-
/**
|
|
1668
|
-
* Sort the table
|
|
1669
|
-
* @public
|
|
1670
|
-
* @expose
|
|
1671
|
-
* @param {string?} column Name of the column to sort on (or null to remove sort arrow)
|
|
1672
|
-
* @param {boolean=} descending Sort in descending order
|
|
1673
|
-
* @param {boolean} [add=false] Should this sort be on top of the existing sort? (For multiple column sort)
|
|
1674
|
-
* @returns {DGTable} self
|
|
1675
|
-
*/
|
|
1676
|
-
DGTable.prototype.sort = function (column, descending, add) {
|
|
1677
|
-
const o = this.o,p = this.p;
|
|
1678
|
-
|
|
1679
|
-
let columns = p.columns,
|
|
1680
|
-
col = columns.get(column);
|
|
1681
|
-
|
|
1682
|
-
let currentSort = p.rows.sortColumn;
|
|
1683
|
-
|
|
1684
|
-
if (col) {
|
|
1685
|
-
if (add) {// Add the sort to current sort stack
|
|
1686
|
-
|
|
1687
|
-
for (let i = 0; i < currentSort.length; i++) {
|
|
1688
|
-
if (currentSort[i].column === col.name) {
|
|
1689
|
-
if (i < currentSort.length - 1) {
|
|
1690
|
-
currentSort.length = 0;
|
|
1691
|
-
} else {
|
|
1692
|
-
descending = currentSort[currentSort.length - 1].descending;
|
|
1693
|
-
currentSort.splice(currentSort.length - 1, 1);
|
|
1694
|
-
}
|
|
1695
|
-
break;
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
if (o.sortableColumns > 0 /* allow manual sort when disabled */ && currentSort.length >= o.sortableColumns || currentSort.length >= p.visibleColumns.length) {
|
|
1699
|
-
currentSort.length = 0;
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
} else {// Sort only by this column
|
|
1703
|
-
currentSort.length = 0;
|
|
1704
|
-
}
|
|
1705
|
-
|
|
1706
|
-
// Default to ascending
|
|
1707
|
-
descending = descending === undefined ? false : descending;
|
|
1708
|
-
|
|
1709
|
-
// Set the required column in the front of the stack
|
|
1710
|
-
currentSort.push({
|
|
1711
|
-
column: col.name,
|
|
1712
|
-
comparePath: col.comparePath || col.dataPath,
|
|
1713
|
-
descending: !!descending
|
|
1714
|
-
});
|
|
1715
|
-
} else {
|
|
1716
|
-
currentSort.length = 0;
|
|
1717
|
-
}
|
|
1718
|
-
|
|
1719
|
-
this._clearSortArrows();
|
|
1720
|
-
|
|
1721
|
-
for (let i = 0; i < currentSort.length; i++) {
|
|
1722
|
-
this._showSortArrow(currentSort[i].column, currentSort[i].descending);
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
if (o.adjustColumnWidthForSortArrow && !p.tableSkeletonNeedsRendering) {
|
|
1726
|
-
this.tableWidthChanged(true);
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
p.rows.sortColumn = currentSort;
|
|
1730
|
-
|
|
1731
|
-
let comparator;
|
|
1732
|
-
if (currentSort.length) {
|
|
1733
|
-
comparator = p.rows.sort(!!p.filteredRows);
|
|
1734
|
-
if (p.filteredRows) {
|
|
1735
|
-
p.filteredRows.sort(!!p.filteredRows);
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
|
|
1739
|
-
if (p.virtualListHelper)
|
|
1740
|
-
p.virtualListHelper.invalidate().render();
|
|
1741
|
-
|
|
1742
|
-
// Build output for event, with option names that will survive compilers
|
|
1743
|
-
let sorts = [];
|
|
1744
|
-
for (let i = 0; i < currentSort.length; i++) {
|
|
1745
|
-
sorts.push({ 'column': currentSort[i].column, 'descending': currentSort[i].descending });
|
|
1746
|
-
}
|
|
1747
|
-
this.trigger('sort', sorts, true /* direct sort */, comparator);
|
|
1748
|
-
|
|
1749
|
-
return this;
|
|
1750
|
-
};
|
|
1751
|
-
|
|
1752
|
-
/**
|
|
1753
|
-
* Re-sort the table using current sort specifiers
|
|
1754
|
-
* @public
|
|
1755
|
-
* @expose
|
|
1756
|
-
* @returns {DGTable} self
|
|
1757
|
-
*/
|
|
1758
|
-
DGTable.prototype.resort = function () {
|
|
1759
|
-
const p = this.p;
|
|
1760
|
-
let columns = p.columns;
|
|
1761
|
-
|
|
1762
|
-
let currentSort = p.rows.sortColumn;
|
|
1763
|
-
if (currentSort.length) {
|
|
1764
|
-
|
|
1765
|
-
for (let i = 0; i < currentSort.length; i++) {
|
|
1766
|
-
if (!columns.get(currentSort[i].column)) {
|
|
1767
|
-
currentSort.splice(i--, 1);
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
|
|
1771
|
-
let comparator;
|
|
1772
|
-
p.rows.sortColumn = currentSort;
|
|
1773
|
-
if (currentSort.length) {
|
|
1774
|
-
comparator = p.rows.sort(!!p.filteredRows);
|
|
1775
|
-
if (p.filteredRows) {
|
|
1776
|
-
p.filteredRows.sort(!!p.filteredRows);
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
|
|
1780
|
-
// Build output for event, with option names that will survive compilers
|
|
1781
|
-
let sorts = [];
|
|
1782
|
-
for (let i = 0; i < currentSort.length; i++) {
|
|
1783
|
-
sorts.push({ 'column': currentSort[i].column, 'descending': currentSort[i].descending });
|
|
1784
|
-
}
|
|
1785
|
-
this.trigger('sort', sorts, false /* indirect sort */, comparator);
|
|
1786
|
-
}
|
|
1787
|
-
|
|
1788
|
-
return this;
|
|
1789
|
-
};
|
|
1790
|
-
|
|
1791
|
-
/**
|
|
1792
|
-
* Make sure there's at least one column visible
|
|
1793
|
-
* @private
|
|
1794
|
-
* @expose
|
|
1795
|
-
* @returns {DGTable} self
|
|
1796
|
-
*/
|
|
1797
|
-
DGTable.prototype._ensureVisibleColumns = function () {
|
|
1798
|
-
const p = this.p;
|
|
1799
|
-
|
|
1800
|
-
if (p.visibleColumns.length === 0 && p.columns.length) {
|
|
1801
|
-
p.columns[0].visible = true;
|
|
1802
|
-
p.visibleColumns.push(p.columns[0]);
|
|
1803
|
-
this.trigger('showcolumn', p.columns[0].name);
|
|
1804
|
-
}
|
|
1805
|
-
|
|
1806
|
-
return this;
|
|
1807
|
-
};
|
|
1808
|
-
|
|
1809
|
-
/**
|
|
1810
|
-
* Show or hide a column
|
|
1811
|
-
* @public
|
|
1812
|
-
* @expose
|
|
1813
|
-
* @param {string} column Unique column name
|
|
1814
|
-
* @param {boolean} visible New visibility mode for the column
|
|
1815
|
-
* @returns {DGTable} self
|
|
1816
|
-
*/
|
|
1817
|
-
DGTable.prototype.setColumnVisible = function (column, visible) {
|
|
1818
|
-
const p = this.p;
|
|
1819
|
-
|
|
1820
|
-
let col = p.columns.get(column);
|
|
1821
|
-
|
|
1822
|
-
//noinspection PointlessBooleanExpressionJS
|
|
1823
|
-
visible = !!visible;
|
|
1824
|
-
|
|
1825
|
-
if (col && !!col.visible !== visible) {
|
|
1826
|
-
col.visible = visible;
|
|
1827
|
-
p.visibleColumns = p.columns.getVisibleColumns();
|
|
1828
|
-
this.trigger(visible ? 'showcolumn' : 'hidecolumn', column);
|
|
1829
|
-
this._ensureVisibleColumns();
|
|
1830
|
-
this.clearAndRender();
|
|
1831
|
-
}
|
|
1832
|
-
return this;
|
|
1833
|
-
};
|
|
1834
|
-
|
|
1835
|
-
/**
|
|
1836
|
-
* Get the visibility mode of a column
|
|
1837
|
-
* @public
|
|
1838
|
-
* @expose
|
|
1839
|
-
* @returns {boolean} true if visible
|
|
1840
|
-
*/
|
|
1841
|
-
DGTable.prototype.isColumnVisible = function (column) {
|
|
1842
|
-
const p = this.p;
|
|
1843
|
-
let col = p.columns.get(column);
|
|
1844
|
-
if (col) {
|
|
1845
|
-
return col.visible;
|
|
1846
|
-
}
|
|
1847
|
-
return false;
|
|
1848
|
-
};
|
|
1849
|
-
|
|
1850
|
-
/**
|
|
1851
|
-
* Globally set the minimum column width
|
|
1852
|
-
* @public
|
|
1853
|
-
* @expose
|
|
1854
|
-
* @param {number} minColumnWidth Minimum column width
|
|
1855
|
-
* @returns {DGTable} self
|
|
1856
|
-
*/
|
|
1857
|
-
DGTable.prototype.setMinColumnWidth = function (minColumnWidth) {
|
|
1858
|
-
let o = this.o;
|
|
1859
|
-
minColumnWidth = Math.max(minColumnWidth, 0);
|
|
1860
|
-
if (o.minColumnWidth !== minColumnWidth) {
|
|
1861
|
-
o.minColumnWidth = minColumnWidth;
|
|
1862
|
-
this.tableWidthChanged(true);
|
|
1863
|
-
}
|
|
1864
|
-
return this;
|
|
1865
|
-
};
|
|
1866
|
-
|
|
1867
|
-
/**
|
|
1868
|
-
* Get the current minimum column width
|
|
1869
|
-
* @public
|
|
1870
|
-
* @expose
|
|
1871
|
-
* @returns {number} Minimum column width
|
|
1872
|
-
*/
|
|
1873
|
-
DGTable.prototype.getMinColumnWidth = function () {
|
|
1874
|
-
return this.o.minColumnWidth;
|
|
1875
|
-
};
|
|
1876
|
-
|
|
1877
|
-
/**
|
|
1878
|
-
* Set the limit on concurrent columns sorted
|
|
1879
|
-
* @public
|
|
1880
|
-
* @expose
|
|
1881
|
-
* @param {number} sortableColumns How many sortable columns to allow?
|
|
1882
|
-
* @returns {DGTable} self
|
|
1883
|
-
*/
|
|
1884
|
-
DGTable.prototype.setSortableColumns = function (sortableColumns) {
|
|
1885
|
-
const p = this.p,o = this.o;
|
|
1886
|
-
if (o.sortableColumns !== sortableColumns) {
|
|
1887
|
-
o.sortableColumns = sortableColumns;
|
|
1888
|
-
if (p.$table) {
|
|
1889
|
-
let headerCell = p.$headerRow.find('>div.' + o.tableClassName + '-header-cell');
|
|
1890
|
-
for (let i = 0; i < headerCell.length; i++) {
|
|
1891
|
-
$(headerCell[0])[o.sortableColumns > 0 && p.visibleColumns[i].sortable ? 'addClass' : 'removeClass']('sortable');
|
|
1892
|
-
}
|
|
1893
|
-
}
|
|
1894
|
-
}
|
|
1895
|
-
return this;
|
|
1896
|
-
};
|
|
1897
|
-
|
|
1898
|
-
/**
|
|
1899
|
-
* Get the limit on concurrent columns sorted
|
|
1900
|
-
* @public
|
|
1901
|
-
* @expose
|
|
1902
|
-
* @returns {number} How many sortable columns are allowed?
|
|
1903
|
-
*/
|
|
1904
|
-
DGTable.prototype.getSortableColumns = function () {
|
|
1905
|
-
return this.o.sortableColumns;
|
|
1906
|
-
};
|
|
1907
|
-
|
|
1908
|
-
/**
|
|
1909
|
-
* @public
|
|
1910
|
-
* @expose
|
|
1911
|
-
* @param {boolean?} movableColumns=true are the columns movable?
|
|
1912
|
-
* @returns {DGTable} self
|
|
1913
|
-
*/
|
|
1914
|
-
DGTable.prototype.setMovableColumns = function (movableColumns) {
|
|
1915
|
-
let o = this.o;
|
|
1916
|
-
//noinspection PointlessBooleanExpressionJS
|
|
1917
|
-
movableColumns = movableColumns === undefined ? true : !!movableColumns;
|
|
1918
|
-
if (o.movableColumns !== movableColumns) {
|
|
1919
|
-
o.movableColumns = movableColumns;
|
|
1920
|
-
}
|
|
1921
|
-
return this;
|
|
1922
|
-
};
|
|
1923
|
-
|
|
1924
|
-
/**
|
|
1925
|
-
* @public
|
|
1926
|
-
* @expose
|
|
1927
|
-
* @returns {boolean} are the columns movable?
|
|
1928
|
-
*/
|
|
1929
|
-
DGTable.prototype.getMovableColumns = function () {
|
|
1930
|
-
return this.o.movableColumns;
|
|
1931
|
-
};
|
|
1932
|
-
|
|
1933
|
-
/**
|
|
1934
|
-
* @public
|
|
1935
|
-
* @expose
|
|
1936
|
-
* @param {boolean} resizableColumns=true are the columns resizable?
|
|
1937
|
-
* @returns {DGTable} self
|
|
1938
|
-
*/
|
|
1939
|
-
DGTable.prototype.setResizableColumns = function (resizableColumns) {
|
|
1940
|
-
let o = this.o;
|
|
1941
|
-
//noinspection PointlessBooleanExpressionJS
|
|
1942
|
-
resizableColumns = resizableColumns === undefined ? true : !!resizableColumns;
|
|
1943
|
-
if (o.resizableColumns !== resizableColumns) {
|
|
1944
|
-
o.resizableColumns = resizableColumns;
|
|
1945
|
-
}
|
|
1946
|
-
return this;
|
|
1947
|
-
};
|
|
1948
|
-
|
|
1949
|
-
/**
|
|
1950
|
-
* @public
|
|
1951
|
-
* @expose
|
|
1952
|
-
* @returns {boolean} are the columns resizable?
|
|
1953
|
-
*/
|
|
1954
|
-
DGTable.prototype.getResizableColumns = function () {
|
|
1955
|
-
return this.o.resizableColumns;
|
|
1956
|
-
};
|
|
1957
|
-
|
|
1958
|
-
/**
|
|
1959
|
-
* Sets a functions that supplies comparators dynamically
|
|
1960
|
-
* @public
|
|
1961
|
-
* @expose
|
|
1962
|
-
* @param {{function(columnName: string, descending: boolean, defaultComparator: function(a,b):number):{function(a,b):number}}|null|undefined} comparatorCallback a function that returns the comparator for a specific column
|
|
1963
|
-
* @returns {DGTable} self
|
|
1964
|
-
*/
|
|
1965
|
-
DGTable.prototype.setOnComparatorRequired = function (comparatorCallback) {
|
|
1966
|
-
let o = this.o;
|
|
1967
|
-
if (o.onComparatorRequired !== comparatorCallback) {
|
|
1968
|
-
o.onComparatorRequired = comparatorCallback;
|
|
1969
|
-
}
|
|
1970
|
-
return this;
|
|
1971
|
-
};
|
|
1972
|
-
|
|
1973
|
-
DGTable.prototype.setComparatorCallback = DGTable.prototype.setOnComparatorRequired;
|
|
1974
|
-
|
|
1975
|
-
/**
|
|
1976
|
-
* sets custom sorting function for a data set
|
|
1977
|
-
* @public
|
|
1978
|
-
* @expose
|
|
1979
|
-
* @param {{function(data: any[], sort: function(any[]):any[]):any[]}|null|undefined} customSortingProvider provides a custom sorting function (not the comparator, but a sort() alternative) for a data set
|
|
1980
|
-
* @returns {DGTable} self
|
|
1981
|
-
*/
|
|
1982
|
-
DGTable.prototype.setCustomSortingProvider = function (customSortingProvider) {
|
|
1983
|
-
let o = this.o;
|
|
1984
|
-
if (o.customSortingProvider !== customSortingProvider) {
|
|
1985
|
-
o.customSortingProvider = customSortingProvider;
|
|
1986
|
-
}
|
|
1987
|
-
return this;
|
|
1988
|
-
};
|
|
1989
|
-
|
|
1990
|
-
/**
|
|
1991
|
-
* Set a new width to a column
|
|
1992
|
-
* @public
|
|
1993
|
-
* @expose
|
|
1994
|
-
* @param {string} column name of the column to resize
|
|
1995
|
-
* @param {number|string} width new column as pixels, or relative size (0.5, 50%)
|
|
1996
|
-
* @returns {DGTable} self
|
|
1997
|
-
*/
|
|
1998
|
-
DGTable.prototype.setColumnWidth = function (column, width) {
|
|
1999
|
-
|
|
2000
|
-
const p = this.p;
|
|
2001
|
-
|
|
2002
|
-
let col = p.columns.get(column);
|
|
2003
|
-
|
|
2004
|
-
let parsedWidth = this._parseColumnWidth(width, col.ignoreMin ? 0 : this.o.minColumnWidth);
|
|
2005
|
-
|
|
2006
|
-
if (col) {
|
|
2007
|
-
let oldWidth = this._serializeColumnWidth(col);
|
|
2008
|
-
|
|
2009
|
-
col.width = parsedWidth.width;
|
|
2010
|
-
col.widthMode = parsedWidth.mode;
|
|
2011
|
-
|
|
2012
|
-
let newWidth = this._serializeColumnWidth(col);
|
|
2013
|
-
|
|
2014
|
-
if (oldWidth !== newWidth) {
|
|
2015
|
-
this.tableWidthChanged(true); // Calculate actual sizes
|
|
2016
|
-
}
|
|
2017
|
-
|
|
2018
|
-
this.trigger('columnwidth', col.name, oldWidth, newWidth);
|
|
2019
|
-
}
|
|
2020
|
-
return this;
|
|
2021
|
-
};
|
|
2022
|
-
|
|
2023
|
-
/**
|
|
2024
|
-
* @public
|
|
2025
|
-
* @expose
|
|
2026
|
-
* @param {string} column name of the column
|
|
2027
|
-
* @returns {string|null} the serialized width of the specified column, or null if column not found
|
|
2028
|
-
*/
|
|
2029
|
-
DGTable.prototype.getColumnWidth = function (column) {
|
|
2030
|
-
const p = this.p;
|
|
2031
|
-
|
|
2032
|
-
let col = p.columns.get(column);
|
|
2033
|
-
if (col) {
|
|
2034
|
-
return this._serializeColumnWidth(col);
|
|
2035
|
-
}
|
|
2036
|
-
return null;
|
|
2037
|
-
};
|
|
2038
|
-
|
|
2039
|
-
/**
|
|
2040
|
-
* @public
|
|
2041
|
-
* @expose
|
|
2042
|
-
* @param {string} column name of the column
|
|
2043
|
-
* @returns {SERIALIZED_COLUMN|null} configuration for all columns
|
|
2044
|
-
*/
|
|
2045
|
-
DGTable.prototype.getColumnConfig = function (column) {
|
|
2046
|
-
const p = this.p;
|
|
2047
|
-
let col = p.columns.get(column);
|
|
2048
|
-
if (col) {
|
|
2049
|
-
return {
|
|
2050
|
-
'order': col.order,
|
|
2051
|
-
'width': this._serializeColumnWidth(col),
|
|
2052
|
-
'visible': col.visible,
|
|
2053
|
-
'label': col.label
|
|
2054
|
-
};
|
|
2055
|
-
}
|
|
2056
|
-
return null;
|
|
2057
|
-
};
|
|
2058
|
-
|
|
2059
|
-
/**
|
|
2060
|
-
* Returns a config object for the columns, to allow saving configurations for next time...
|
|
2061
|
-
* @public
|
|
2062
|
-
* @expose
|
|
2063
|
-
* @returns {Object} configuration for all columns
|
|
2064
|
-
*/
|
|
2065
|
-
DGTable.prototype.getColumnsConfig = function () {
|
|
2066
|
-
const p = this.p;
|
|
2067
|
-
|
|
2068
|
-
let config = {};
|
|
2069
|
-
for (let i = 0; i < p.columns.length; i++) {
|
|
2070
|
-
config[p.columns[i].name] = this.getColumnConfig(p.columns[i].name);
|
|
2071
|
-
}
|
|
2072
|
-
return config;
|
|
2073
|
-
};
|
|
2074
|
-
|
|
2075
|
-
/**
|
|
2076
|
-
* Returns an array of the currently sorted columns
|
|
2077
|
-
* @public
|
|
2078
|
-
* @expose
|
|
2079
|
-
* @returns {Array.<SERIALIZED_COLUMN_SORT>} configuration for all columns
|
|
2080
|
-
*/
|
|
2081
|
-
DGTable.prototype.getSortedColumns = function () {
|
|
2082
|
-
const p = this.p;
|
|
2083
|
-
|
|
2084
|
-
let sorted = [];
|
|
2085
|
-
for (let i = 0; i < p.rows.sortColumn.length; i++) {
|
|
2086
|
-
let sort = p.rows.sortColumn[i];
|
|
2087
|
-
sorted.push({ column: sort.column, descending: sort.descending });
|
|
2088
|
-
}
|
|
2089
|
-
return sorted;
|
|
2090
|
-
};
|
|
2091
|
-
|
|
2092
|
-
/**
|
|
2093
|
-
* Returns the HTML string for a specific cell. Can be used externally for special cases (i.e. when setting a fresh HTML in the cell preview through the callback).
|
|
2094
|
-
* @public
|
|
2095
|
-
* @expose
|
|
2096
|
-
* @param {number} rowIndex - index of the row
|
|
2097
|
-
* @param {string} columnName - name of the column
|
|
2098
|
-
* @returns {string} HTML string for the specified cell
|
|
2099
|
-
*/
|
|
2100
|
-
DGTable.prototype.getHtmlForRowCell = function (rowIndex, columnName) {
|
|
2101
|
-
const p = this.p;
|
|
2102
|
-
|
|
2103
|
-
if (rowIndex < 0 || rowIndex > p.rows.length - 1) return null;
|
|
2104
|
-
let column = p.columns.get(columnName);
|
|
2105
|
-
if (!column) return null;
|
|
2106
|
-
let rowData = p.rows[rowIndex];
|
|
2107
|
-
|
|
2108
|
-
return this._getHtmlForCell(rowData, column);
|
|
2109
|
-
};
|
|
2110
|
-
|
|
2111
|
-
/**
|
|
2112
|
-
* Returns the HTML string for a specific cell. Can be used externally for special cases (i.e. when setting a fresh HTML in the cell preview through the callback).
|
|
2113
|
-
* @public
|
|
2114
|
-
* @expose
|
|
2115
|
-
* @param {Object} rowData - row data
|
|
2116
|
-
* @param {Object} columnName - column data
|
|
2117
|
-
* @returns {string|null} HTML string for the specified cell
|
|
2118
|
-
*/
|
|
2119
|
-
DGTable.prototype.getHtmlForRowDataCell = function (rowData, columnName) {
|
|
2120
|
-
const p = this.p;
|
|
2121
|
-
|
|
2122
|
-
let column = p.columns.get(columnName);
|
|
2123
|
-
if (!column) return null;
|
|
2124
|
-
|
|
2125
|
-
return this._getHtmlForCell(rowData, column);
|
|
2126
|
-
};
|
|
2127
|
-
|
|
2128
|
-
/**
|
|
2129
|
-
* Returns the HTML string for a specific cell. Can be used externally for special cases (i.e. when setting a fresh HTML in the cell preview through the callback).
|
|
2130
|
-
* @private
|
|
2131
|
-
* @expose
|
|
2132
|
-
* @param {Object} rowData - row data
|
|
2133
|
-
* @param {Object} column - column data
|
|
2134
|
-
* @returns {string} HTML string for the specified cell
|
|
2135
|
-
*/
|
|
2136
|
-
DGTable.prototype._getHtmlForCell = function (rowData, column) {
|
|
2137
|
-
let dataPath = column.dataPath;
|
|
2138
|
-
let colValue = rowData[dataPath[0]];
|
|
2139
|
-
for (let dataPathIndex = 1; dataPathIndex < dataPath.length; dataPathIndex++) {
|
|
2140
|
-
if (colValue == null) break;
|
|
2141
|
-
colValue = colValue && colValue[dataPath[dataPathIndex]];
|
|
2142
|
-
}
|
|
2143
|
-
|
|
2144
|
-
const formatter = this.o.cellFormatter;
|
|
2145
|
-
let content;
|
|
2146
|
-
|
|
2147
|
-
if (formatter[IsSafeSymbol]) {
|
|
2148
|
-
content = formatter(colValue, column.name, rowData);
|
|
2149
|
-
} else {
|
|
2150
|
-
try {
|
|
2151
|
-
content = formatter(colValue, column.name, rowData);
|
|
2152
|
-
} catch (err) {
|
|
2153
|
-
content = '[ERROR]';
|
|
2154
|
-
// eslint-disable-next-line no-console
|
|
2155
|
-
console.error('Failed to generate content for cell ' + column.name, err);
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
|
|
2159
|
-
if (content === undefined || content === null) {
|
|
2160
|
-
content = '';
|
|
2161
|
-
}
|
|
2162
|
-
|
|
2163
|
-
return content;
|
|
2164
|
-
};
|
|
2165
|
-
|
|
2166
|
-
/**
|
|
2167
|
-
* Returns the y pos of a row by index
|
|
2168
|
-
* @public
|
|
2169
|
-
* @expose
|
|
2170
|
-
* @param {number} rowIndex - index of the row
|
|
2171
|
-
* @returns {number|null} Y pos
|
|
2172
|
-
*/
|
|
2173
|
-
DGTable.prototype.getRowYPos = function (rowIndex) {
|
|
2174
|
-
const p = this.p;
|
|
2175
|
-
|
|
2176
|
-
return p.virtualListHelper.getItemPosition(rowIndex) || null;
|
|
2177
|
-
};
|
|
2178
|
-
|
|
2179
|
-
/**
|
|
2180
|
-
* Returns the row data for a specific row
|
|
2181
|
-
* @public
|
|
2182
|
-
* @expose
|
|
2183
|
-
* @param {number} row index of the row
|
|
2184
|
-
* @returns {Object} Row data
|
|
2185
|
-
*/
|
|
2186
|
-
DGTable.prototype.getDataForRow = function (row) {
|
|
2187
|
-
const p = this.p;
|
|
2188
|
-
|
|
2189
|
-
if (row < 0 || row > p.rows.length - 1) return null;
|
|
2190
|
-
return p.rows[row];
|
|
2191
|
-
};
|
|
2192
|
-
|
|
2193
|
-
/**
|
|
2194
|
-
* Gets the number of rows
|
|
2195
|
-
* @public
|
|
2196
|
-
* @expose
|
|
2197
|
-
* @returns {number} Row count
|
|
2198
|
-
*/
|
|
2199
|
-
DGTable.prototype.getRowCount = function () {
|
|
2200
|
-
const p = this.p;
|
|
2201
|
-
return p.rows ? p.rows.length : 0;
|
|
2202
|
-
};
|
|
2203
|
-
|
|
2204
|
-
/**
|
|
2205
|
-
* Returns the physical row index for specific row
|
|
2206
|
-
* @public
|
|
2207
|
-
* @expose
|
|
2208
|
-
* @param {Object} rowData - Row data to find
|
|
2209
|
-
* @returns {number} Row index
|
|
2210
|
-
*/
|
|
2211
|
-
DGTable.prototype.getIndexForRow = function (rowData) {
|
|
2212
|
-
const p = this.p;
|
|
2213
|
-
return p.rows.indexOf(rowData);
|
|
2214
|
-
};
|
|
2215
|
-
|
|
2216
|
-
/**
|
|
2217
|
-
* Gets the number of filtered rows
|
|
2218
|
-
* @public
|
|
2219
|
-
* @expose
|
|
2220
|
-
* @returns {number} Filtered row count
|
|
2221
|
-
*/
|
|
2222
|
-
DGTable.prototype.getFilteredRowCount = function () {
|
|
2223
|
-
const p = this.p;
|
|
2224
|
-
return (p.filteredRows || p.rows).length;
|
|
2225
|
-
};
|
|
2226
|
-
|
|
2227
|
-
/**
|
|
2228
|
-
* Returns the filtered row index for specific row
|
|
2229
|
-
* @public
|
|
2230
|
-
* @expose
|
|
2231
|
-
* @param {Object} rowData - Row data to find
|
|
2232
|
-
* @returns {number} Row index
|
|
2233
|
-
*/
|
|
2234
|
-
DGTable.prototype.getIndexForFilteredRow = function (rowData) {
|
|
2235
|
-
const p = this.p;
|
|
2236
|
-
return (p.filteredRows || p.rows).indexOf(rowData);
|
|
2237
|
-
};
|
|
2238
|
-
|
|
2239
|
-
/**
|
|
2240
|
-
* Returns the row data for a specific row
|
|
2241
|
-
* @public
|
|
2242
|
-
* @expose
|
|
2243
|
-
* @param {number} row index of the filtered row
|
|
2244
|
-
* @returns {Object} Row data
|
|
2245
|
-
*/
|
|
2246
|
-
DGTable.prototype.getDataForFilteredRow = function (row) {
|
|
2247
|
-
const p = this.p;
|
|
2248
|
-
if (row < 0 || row > (p.filteredRows || p.rows).length - 1) return null;
|
|
2249
|
-
return (p.filteredRows || p.rows)[row];
|
|
2250
|
-
};
|
|
2251
|
-
|
|
2252
|
-
/**
|
|
2253
|
-
* Returns DOM element of the header row
|
|
2254
|
-
* @public
|
|
2255
|
-
* @expose
|
|
2256
|
-
* @returns {Element} Row element
|
|
2257
|
-
*/
|
|
2258
|
-
DGTable.prototype.getHeaderRowElement = function () {
|
|
2259
|
-
return this.p.headerRow;
|
|
2260
|
-
};
|
|
2261
|
-
|
|
2262
|
-
/**
|
|
2263
|
-
* @private
|
|
2264
|
-
* @param {Element} el
|
|
2265
|
-
* @returns {number} width
|
|
2266
|
-
*/
|
|
2267
|
-
DGTable.prototype._horizontalPadding = function (el) {
|
|
2268
|
-
return (parseFloat($.css(el, 'padding-left')) || 0) + (
|
|
2269
|
-
parseFloat($.css(el, 'padding-right')) || 0);
|
|
2270
|
-
};
|
|
2271
|
-
|
|
2272
|
-
/**
|
|
2273
|
-
* @private
|
|
2274
|
-
* @param {Element} el
|
|
2275
|
-
* @returns {number} width
|
|
2276
|
-
*/
|
|
2277
|
-
DGTable.prototype._horizontalBorderWidth = function (el) {
|
|
2278
|
-
return (parseFloat($.css(el, 'border-left')) || 0) + (
|
|
2279
|
-
parseFloat($.css(el, 'border-right')) || 0);
|
|
2280
|
-
};
|
|
2281
|
-
|
|
2282
|
-
/**
|
|
2283
|
-
* @private
|
|
2284
|
-
* @returns {number} width
|
|
2285
|
-
*/
|
|
2286
|
-
DGTable.prototype._calculateWidthAvailableForColumns = function () {
|
|
2287
|
-
const o = this.o,p = this.p;
|
|
2288
|
-
|
|
2289
|
-
// Changing display mode briefly, to prevent taking in account the parent's scrollbar width when we are the cause for it
|
|
2290
|
-
let oldDisplay, lastScrollTop, lastScrollLeft;
|
|
2291
|
-
if (p.table) {
|
|
2292
|
-
lastScrollTop = p.table ? p.table.scrollTop : 0;
|
|
2293
|
-
lastScrollLeft = p.table ? p.table.scrollLeft : 0;
|
|
2294
|
-
|
|
2295
|
-
if (o.virtualTable) {
|
|
2296
|
-
oldDisplay = p.table.style.display;
|
|
2297
|
-
p.table.style.display = 'none';
|
|
2298
|
-
}
|
|
2299
|
-
}
|
|
2300
|
-
|
|
2301
|
-
let detectedWidth = Css_js.getElementWidth(this.$el[0]);
|
|
2302
|
-
|
|
2303
|
-
if (p.table) {
|
|
2304
|
-
if (o.virtualTable) {
|
|
2305
|
-
p.table.style.display = oldDisplay;
|
|
2306
|
-
}
|
|
2307
|
-
|
|
2308
|
-
p.table.scrollTop = lastScrollTop;
|
|
2309
|
-
p.table.scrollLeft = lastScrollLeft;
|
|
2310
|
-
p.header.scrollLeft = lastScrollLeft;
|
|
2311
|
-
}
|
|
2312
|
-
|
|
2313
|
-
let tableClassName = o.tableClassName;
|
|
2314
|
-
|
|
2315
|
-
let $thisWrapper = $('<div>').addClass(this.el.className).css({ 'z-index': -1, 'position': 'absolute', left: '0', top: '-9999px' });
|
|
2316
|
-
let $header = $('<div>').addClass(tableClassName + '-header').appendTo($thisWrapper);
|
|
2317
|
-
let $headerRow = $('<div>').addClass(tableClassName + '-header-row').appendTo($header);
|
|
2318
|
-
for (let i = 0; i < p.visibleColumns.length; i++) {
|
|
2319
|
-
const column = p.visibleColumns[i];
|
|
2320
|
-
const $cell = $('<div><div></div></div>').
|
|
2321
|
-
addClass(tableClassName + '-header-cell').
|
|
2322
|
-
addClass(column.cellClasses || '');
|
|
2323
|
-
$cell[0]['columnName'] = column.name;
|
|
2324
|
-
$headerRow.append($cell);
|
|
2325
|
-
}
|
|
2326
|
-
$thisWrapper.appendTo(document.body);
|
|
2327
|
-
|
|
2328
|
-
detectedWidth -= this._horizontalBorderWidth($headerRow[0]);
|
|
2329
|
-
|
|
2330
|
-
let $cells = $headerRow.find('>div.' + tableClassName + '-header-cell');
|
|
2331
|
-
for (let i = 0; i < $cells.length; i++) {
|
|
2332
|
-
let $cell = $($cells[i]);
|
|
2333
|
-
|
|
2334
|
-
let isBoxing = $cell.css('boxSizing') === 'border-box';
|
|
2335
|
-
if (!isBoxing) {
|
|
2336
|
-
detectedWidth -=
|
|
2337
|
-
(parseFloat($cell.css('border-right-width')) || 0) + (
|
|
2338
|
-
parseFloat($cell.css('border-left-width')) || 0) +
|
|
2339
|
-
this._horizontalPadding($cell[0]); // CELL's padding
|
|
2340
|
-
|
|
2341
|
-
const colName = $cell[0]['columnName'];
|
|
2342
|
-
const column = p.columns.get(colName);
|
|
2343
|
-
if (column)
|
|
2344
|
-
detectedWidth -= column.arrowProposedWidth || 0;
|
|
2345
|
-
}
|
|
2346
|
-
}
|
|
2347
|
-
|
|
2348
|
-
if ($thisWrapper) {
|
|
2349
|
-
$thisWrapper.remove();
|
|
2350
|
-
}
|
|
2351
|
-
|
|
2352
|
-
return Math.max(0, detectedWidth);
|
|
2353
|
-
};
|
|
2354
|
-
|
|
2355
|
-
/**
|
|
2356
|
-
* Notify the table that its width has changed
|
|
2357
|
-
* @public
|
|
2358
|
-
* @expose
|
|
2359
|
-
* @returns {DGTable} self
|
|
2360
|
-
*/
|
|
2361
|
-
DGTable.prototype.tableWidthChanged = function () {
|
|
2362
|
-
|
|
2363
|
-
let getTextWidth = function (text) {
|
|
2364
|
-
let tableClassName = this.o.tableClassName;
|
|
2365
|
-
|
|
2366
|
-
let $cell,$tableWrapper = $('<div>').addClass(this.$el).append(
|
|
2367
|
-
$('<div>').addClass(tableClassName + '-header').append(
|
|
2368
|
-
$('<div>').addClass(tableClassName + '-header-row').append(
|
|
2369
|
-
$cell = $('<div>').addClass(tableClassName + '-header-cell').append(
|
|
2370
|
-
$('<div>').text(text)
|
|
2371
|
-
)
|
|
2372
|
-
)
|
|
2373
|
-
)
|
|
2374
|
-
).css({ 'position': 'absolute', top: '-9999px', 'visibility': 'hidden' });
|
|
2375
|
-
$tableWrapper.appendTo(document.body);
|
|
2376
|
-
|
|
2377
|
-
let width = Css_js.getElementWidth($cell[0]);
|
|
2378
|
-
|
|
2379
|
-
$tableWrapper.remove();
|
|
2380
|
-
|
|
2381
|
-
return width;
|
|
2382
|
-
};
|
|
2383
|
-
|
|
2384
|
-
let lastDetectedWidth = null;
|
|
2385
|
-
|
|
2386
|
-
/**
|
|
2387
|
-
* @public
|
|
2388
|
-
* @expose
|
|
2389
|
-
* @param {boolean} [forceUpdate=false]
|
|
2390
|
-
* @param {boolean} [renderColumns=true]
|
|
2391
|
-
* @returns {DGTable} self
|
|
2392
|
-
*/
|
|
2393
|
-
return function (forceUpdate, renderColumns) {
|
|
2394
|
-
|
|
2395
|
-
let that = this,
|
|
2396
|
-
o = that.o,
|
|
2397
|
-
p = that.p,
|
|
2398
|
-
detectedWidth = this._calculateWidthAvailableForColumns(),
|
|
2399
|
-
sizeLeft = detectedWidth,
|
|
2400
|
-
relatives = 0;
|
|
2401
|
-
|
|
2402
|
-
if (!p.$table) return this;
|
|
2403
|
-
|
|
2404
|
-
renderColumns = renderColumns === undefined || renderColumns;
|
|
2405
|
-
|
|
2406
|
-
let tableWidthBeforeCalculations = 0;
|
|
2407
|
-
|
|
2408
|
-
if (!p.tbody) {
|
|
2409
|
-
renderColumns = false;
|
|
2410
|
-
}
|
|
2411
|
-
|
|
2412
|
-
if (renderColumns) {
|
|
2413
|
-
tableWidthBeforeCalculations = parseFloat(p.tbody.style.minWidth) || 0;
|
|
2414
|
-
}
|
|
2415
|
-
|
|
2416
|
-
if (sizeLeft !== lastDetectedWidth || forceUpdate) {
|
|
2417
|
-
lastDetectedWidth = detectedWidth;
|
|
2418
|
-
|
|
2419
|
-
let absWidthTotal = 0,changedColumnIndexes = [],totalRelativePercentage = 0;
|
|
2420
|
-
|
|
2421
|
-
for (let i = 0; i < p.columns.length; i++) {
|
|
2422
|
-
p.columns[i].actualWidthConsideringScrollbarWidth = null;
|
|
2423
|
-
}
|
|
2424
|
-
|
|
2425
|
-
for (let i = 0; i < p.visibleColumns.length; i++) {
|
|
2426
|
-
let col = p.visibleColumns[i];
|
|
2427
|
-
if (col.widthMode === ColumnWidthMode.ABSOLUTE) {
|
|
2428
|
-
let width = col.width;
|
|
2429
|
-
width += col.arrowProposedWidth || 0; // Sort-arrow width
|
|
2430
|
-
if (!col.ignoreMin && width < o.minColumnWidth) {
|
|
2431
|
-
width = o.minColumnWidth;
|
|
2432
|
-
}
|
|
2433
|
-
sizeLeft -= width;
|
|
2434
|
-
absWidthTotal += width;
|
|
2435
|
-
|
|
2436
|
-
// Update actualWidth
|
|
2437
|
-
if (width !== col.actualWidth) {
|
|
2438
|
-
col.actualWidth = width;
|
|
2439
|
-
changedColumnIndexes.push(i);
|
|
2440
|
-
}
|
|
2441
|
-
} else if (col.widthMode === ColumnWidthMode.AUTO) {
|
|
2442
|
-
let width = getTextWidth.call(this, col.label) + 20;
|
|
2443
|
-
width += col.arrowProposedWidth || 0; // Sort-arrow width
|
|
2444
|
-
if (!col.ignoreMin && width < o.minColumnWidth) {
|
|
2445
|
-
width = o.minColumnWidth;
|
|
2446
|
-
}
|
|
2447
|
-
sizeLeft -= width;
|
|
2448
|
-
absWidthTotal += width;
|
|
2449
|
-
|
|
2450
|
-
// Update actualWidth
|
|
2451
|
-
if (width !== col.actualWidth) {
|
|
2452
|
-
col.actualWidth = width;
|
|
2453
|
-
if (!o.convertColumnWidthsToRelative) {
|
|
2454
|
-
changedColumnIndexes.push(i);
|
|
2455
|
-
}
|
|
2456
|
-
}
|
|
2457
|
-
} else if (col.widthMode === ColumnWidthMode.RELATIVE) {
|
|
2458
|
-
totalRelativePercentage += col.width;
|
|
2459
|
-
relatives++;
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2462
|
-
|
|
2463
|
-
// Normalize relative sizes if needed
|
|
2464
|
-
if (o.convertColumnWidthsToRelative) {
|
|
2465
|
-
for (let i = 0; i < p.visibleColumns.length; i++) {
|
|
2466
|
-
let col = p.visibleColumns[i];
|
|
2467
|
-
if (col.widthMode === ColumnWidthMode.AUTO) {
|
|
2468
|
-
col.widthMode = ColumnWidthMode.RELATIVE;
|
|
2469
|
-
sizeLeft += col.actualWidth;
|
|
2470
|
-
col.width = col.actualWidth / absWidthTotal;
|
|
2471
|
-
totalRelativePercentage += col.width;
|
|
2472
|
-
relatives++;
|
|
2473
|
-
}
|
|
2474
|
-
}
|
|
2475
|
-
}
|
|
2476
|
-
|
|
2477
|
-
// Normalize relative sizes if needed
|
|
2478
|
-
if (relatives && (totalRelativePercentage < 1 && o.relativeWidthGrowsToFillWidth ||
|
|
2479
|
-
totalRelativePercentage > 1 && o.relativeWidthShrinksToFillWidth)) {
|
|
2480
|
-
for (let i = 0; i < p.visibleColumns.length; i++) {
|
|
2481
|
-
let col = p.visibleColumns[i];
|
|
2482
|
-
if (col.widthMode === ColumnWidthMode.RELATIVE) {
|
|
2483
|
-
col.width /= totalRelativePercentage;
|
|
2484
|
-
}
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
|
-
|
|
2488
|
-
let sizeLeftForRelative = Math.max(0, sizeLeft); // Use this as the space to take the relative widths out of
|
|
2489
|
-
if (sizeLeftForRelative === 0) {
|
|
2490
|
-
sizeLeftForRelative = p.table.clientWidth;
|
|
2491
|
-
}
|
|
2492
|
-
|
|
2493
|
-
let minColumnWidthRelative = o.minColumnWidth / sizeLeftForRelative;
|
|
2494
|
-
if (isNaN(minColumnWidthRelative)) {
|
|
2495
|
-
minColumnWidthRelative = 0;
|
|
2496
|
-
}
|
|
2497
|
-
if (minColumnWidthRelative > 0) {
|
|
2498
|
-
let extraRelative = 0,delta;
|
|
2499
|
-
|
|
2500
|
-
// First pass - make sure they are all constrained to the minimum width
|
|
2501
|
-
for (let i = 0; i < p.visibleColumns.length; i++) {
|
|
2502
|
-
let col = p.visibleColumns[i];
|
|
2503
|
-
if (col.widthMode === ColumnWidthMode.RELATIVE) {
|
|
2504
|
-
if (!col.ignoreMin && col.width < minColumnWidthRelative) {
|
|
2505
|
-
extraRelative += minColumnWidthRelative - col.width;
|
|
2506
|
-
col.width = minColumnWidthRelative;
|
|
2507
|
-
}
|
|
2508
|
-
}
|
|
2509
|
-
}
|
|
2510
|
-
|
|
2511
|
-
// Second pass - try to take the extra width out of the other columns to compensate
|
|
2512
|
-
for (let i = 0; i < p.visibleColumns.length; i++) {
|
|
2513
|
-
let col = p.visibleColumns[i];
|
|
2514
|
-
if (col.widthMode === ColumnWidthMode.RELATIVE) {
|
|
2515
|
-
if (!col.ignoreMin && col.width > minColumnWidthRelative) {
|
|
2516
|
-
if (extraRelative > 0) {
|
|
2517
|
-
delta = Math.min(extraRelative, col.width - minColumnWidthRelative);
|
|
2518
|
-
col.width -= delta;
|
|
2519
|
-
extraRelative -= delta;
|
|
2520
|
-
}
|
|
2521
|
-
}
|
|
2522
|
-
}
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
2525
|
-
|
|
2526
|
-
// Try to fill width
|
|
2527
|
-
if (o.autoFillTableWidth && sizeLeft > 0) {
|
|
2528
|
-
let nonResizableTotal = 0;
|
|
2529
|
-
let sizeLeftToFill = sizeLeft;
|
|
2530
|
-
|
|
2531
|
-
for (let i = 0; i < p.visibleColumns.length; i++) {
|
|
2532
|
-
let col = p.visibleColumns[i];
|
|
2533
|
-
if (!col.resizable && col.widthMode === ColumnWidthMode.ABSOLUTE)
|
|
2534
|
-
nonResizableTotal += col.width;
|
|
2535
|
-
|
|
2536
|
-
if (col.widthMode === ColumnWidthMode.RELATIVE)
|
|
2537
|
-
sizeLeftToFill -= Math.round(sizeLeftForRelative * col.width);
|
|
2538
|
-
}
|
|
2539
|
-
|
|
2540
|
-
let conv = (detectedWidth - nonResizableTotal) / (detectedWidth - sizeLeftToFill - nonResizableTotal) || NaN;
|
|
2541
|
-
for (let i = 0; i < p.visibleColumns.length && sizeLeftToFill > 0; i++) {
|
|
2542
|
-
let col = p.visibleColumns[i];
|
|
2543
|
-
if (!col.resizable && col.widthMode === ColumnWidthMode.ABSOLUTE)
|
|
2544
|
-
continue;
|
|
2545
|
-
|
|
2546
|
-
if (col.widthMode === ColumnWidthMode.RELATIVE) {
|
|
2547
|
-
col.width *= conv;
|
|
2548
|
-
} else {
|
|
2549
|
-
let width = col.actualWidth * conv;
|
|
2550
|
-
if (col.actualWidth !== width) {
|
|
2551
|
-
col.actualWidth = width;
|
|
2552
|
-
if (changedColumnIndexes.indexOf(i) === -1)
|
|
2553
|
-
changedColumnIndexes.push(i);
|
|
2554
|
-
}
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
}
|
|
2558
|
-
|
|
2559
|
-
// Materialize relative sizes
|
|
2560
|
-
for (let i = 0; i < p.visibleColumns.length; i++) {
|
|
2561
|
-
let col = p.visibleColumns[i];
|
|
2562
|
-
if (col.widthMode === ColumnWidthMode.RELATIVE) {
|
|
2563
|
-
let width = Math.round(sizeLeftForRelative * col.width);
|
|
2564
|
-
sizeLeft -= width;
|
|
2565
|
-
relatives--;
|
|
2566
|
-
|
|
2567
|
-
// Take care of rounding errors
|
|
2568
|
-
if (relatives === 0 && sizeLeft === 1) {// Take care of rounding errors
|
|
2569
|
-
width++;
|
|
2570
|
-
sizeLeft--;
|
|
2571
|
-
}
|
|
2572
|
-
if (sizeLeft === -1) {
|
|
2573
|
-
width--;
|
|
2574
|
-
sizeLeft++;
|
|
2575
|
-
}
|
|
2576
|
-
|
|
2577
|
-
// Update actualWidth
|
|
2578
|
-
if (width !== col.actualWidth) {
|
|
2579
|
-
col.actualWidth = width;
|
|
2580
|
-
changedColumnIndexes.push(i);
|
|
2581
|
-
}
|
|
2582
|
-
}
|
|
2583
|
-
}
|
|
2584
|
-
|
|
2585
|
-
if (p.visibleColumns.length) {
|
|
2586
|
-
// (There should always be at least 1 column visible, but just in case)
|
|
2587
|
-
p.visibleColumns[p.visibleColumns.length - 1].actualWidthConsideringScrollbarWidth =
|
|
2588
|
-
p.visibleColumns[p.visibleColumns.length - 1].actualWidth - (p.scrollbarWidth || 0);
|
|
2589
|
-
}
|
|
2590
|
-
|
|
2591
|
-
p.notifyRendererOfColumnsConfig?.();
|
|
2592
|
-
|
|
2593
|
-
if (renderColumns) {
|
|
2594
|
-
let tableWidth = this._calculateTbodyWidth();
|
|
2595
|
-
|
|
2596
|
-
if (tableWidthBeforeCalculations < tableWidth) {
|
|
2597
|
-
this._updateTableWidth(false);
|
|
2598
|
-
}
|
|
2599
|
-
|
|
2600
|
-
for (let i = 0; i < changedColumnIndexes.length; i++) {
|
|
2601
|
-
this._resizeColumnElements(changedColumnIndexes[i]);
|
|
2602
|
-
}
|
|
2603
|
-
|
|
2604
|
-
if (tableWidthBeforeCalculations > tableWidth) {
|
|
2605
|
-
this._updateTableWidth(false);
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2608
|
-
}
|
|
2609
|
-
|
|
2610
|
-
return this;
|
|
2611
|
-
};
|
|
2612
|
-
}();
|
|
2613
|
-
|
|
2614
|
-
/**
|
|
2615
|
-
* Notify the table that its height has changed
|
|
2616
|
-
* @public
|
|
2617
|
-
* @expose
|
|
2618
|
-
* @returns {DGTable} self
|
|
2619
|
-
*/
|
|
2620
|
-
DGTable.prototype.tableHeightChanged = function () {
|
|
2621
|
-
let that = this,
|
|
2622
|
-
o = that.o,
|
|
2623
|
-
p = that.p;
|
|
2624
|
-
|
|
2625
|
-
if (!p.$table) {
|
|
2626
|
-
return that;
|
|
2627
|
-
}
|
|
2628
|
-
|
|
2629
|
-
let height = Css_js.getElementHeight(that.$el[0], true) - (
|
|
2630
|
-
parseFloat(p.$table.css('border-top-width')) || 0) // Subtract top border of inner element
|
|
2631
|
-
- (parseFloat(p.$table.css('border-bottom-width')) || 0); // Subtract bottom border of inner element
|
|
2632
|
-
|
|
2633
|
-
if (height !== o.height) {
|
|
2634
|
-
|
|
2635
|
-
o.height = height;
|
|
2636
|
-
|
|
2637
|
-
if (p.tbody) {
|
|
2638
|
-
// At least 1 pixel - to show scrollbars correctly.
|
|
2639
|
-
p.tbody.style.height = Math.max(o.height - Css_js.getElementHeight(p.$header[0], true, true, true), 1) + 'px';
|
|
2640
|
-
}
|
|
2641
|
-
|
|
2642
|
-
if (o.virtualTable) {
|
|
2643
|
-
that.clearAndRender();
|
|
2644
|
-
}
|
|
2645
|
-
}
|
|
2646
|
-
|
|
2647
|
-
return that;
|
|
2648
|
-
};
|
|
2649
|
-
|
|
2650
|
-
/**
|
|
2651
|
-
* Add rows to the table
|
|
2652
|
-
* @public
|
|
2653
|
-
* @expose
|
|
2654
|
-
* @param {Object[]} data - array of rows to add to the table
|
|
2655
|
-
* @param {number} [at=-1] - where to add the rows at
|
|
2656
|
-
* @param {boolean} [resort=false] - should resort all rows?
|
|
2657
|
-
* @param {boolean} [render=true]
|
|
2658
|
-
* @returns {DGTable} self
|
|
2659
|
-
*/
|
|
2660
|
-
DGTable.prototype.addRows = function (data, at, resort, render) {
|
|
2661
|
-
let that = this,
|
|
2662
|
-
p = that.p;
|
|
2663
|
-
|
|
2664
|
-
if (typeof at === 'boolean') {
|
|
2665
|
-
render = resort;
|
|
2666
|
-
resort = at;
|
|
2667
|
-
at = -1;
|
|
2668
|
-
}
|
|
2669
|
-
|
|
2670
|
-
if (typeof at !== 'number')
|
|
2671
|
-
at = -1;
|
|
2672
|
-
|
|
2673
|
-
if (at < 0 || at > p.rows.length)
|
|
2674
|
-
at = p.rows.length;
|
|
2675
|
-
|
|
2676
|
-
render = render === undefined ? true : !!render;
|
|
2677
|
-
|
|
2678
|
-
if (data) {
|
|
2679
|
-
p.rows.add(data, at);
|
|
2680
|
-
|
|
2681
|
-
if (p.filteredRows || resort && p.rows.sortColumn.length) {
|
|
2682
|
-
|
|
2683
|
-
if (resort && p.rows.sortColumn.length) {
|
|
2684
|
-
this.resort();
|
|
2685
|
-
} else {
|
|
2686
|
-
this._refilter();
|
|
2687
|
-
}
|
|
2688
|
-
|
|
2689
|
-
p.tableSkeletonNeedsRendering = true;
|
|
2690
|
-
|
|
2691
|
-
if (render) {
|
|
2692
|
-
// Render the skeleton with all rows from scratch
|
|
2693
|
-
this.render();
|
|
2694
|
-
}
|
|
2695
|
-
|
|
2696
|
-
} else if (render) {
|
|
2697
|
-
p.virtualListHelper.addItemsAt(data.length, at);
|
|
2698
|
-
|
|
2699
|
-
if (that.o.virtualTable) {
|
|
2700
|
-
this._updateVirtualHeight().
|
|
2701
|
-
_updateLastCellWidthFromScrollbar() // Detect vertical scrollbar height
|
|
2702
|
-
.render().
|
|
2703
|
-
_updateTableWidth(false); // Update table width to suit the required width considering vertical scrollbar
|
|
2704
|
-
|
|
2705
|
-
} else if (p.tbody) {
|
|
2706
|
-
this.render().
|
|
2707
|
-
_updateLastCellWidthFromScrollbar() // Detect vertical scrollbar height, and update existing last cells
|
|
2708
|
-
._updateTableWidth(true); // Update table width to suit the required width considering vertical scrollbar
|
|
2709
|
-
}
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
this.trigger('addrows', data.length, false);
|
|
2713
|
-
}
|
|
2714
|
-
return this;
|
|
2715
|
-
};
|
|
2716
|
-
|
|
2717
|
-
/**
|
|
2718
|
-
* Removes a row from the table
|
|
2719
|
-
* @public
|
|
2720
|
-
* @expose
|
|
2721
|
-
* @param {number} physicalRowIndex - index
|
|
2722
|
-
* @param {number} count - how many rows to remove
|
|
2723
|
-
* @param {boolean=true} render
|
|
2724
|
-
* @returns {DGTable} self
|
|
2725
|
-
*/
|
|
2726
|
-
DGTable.prototype.removeRows = function (physicalRowIndex, count, render) {
|
|
2727
|
-
let that = this,
|
|
2728
|
-
p = that.p;
|
|
2729
|
-
|
|
2730
|
-
if (typeof count !== 'number' || count <= 0) return this;
|
|
2731
|
-
|
|
2732
|
-
if (physicalRowIndex < 0 || physicalRowIndex > p.rows.length - 1) return this;
|
|
2733
|
-
|
|
2734
|
-
p.rows.splice(physicalRowIndex, count);
|
|
2735
|
-
render = render === undefined ? true : !!render;
|
|
2736
|
-
|
|
2737
|
-
if (p.filteredRows) {
|
|
2738
|
-
|
|
2739
|
-
this._refilter();
|
|
2740
|
-
|
|
2741
|
-
p.tableSkeletonNeedsRendering = true;
|
|
2742
|
-
|
|
2743
|
-
if (render) {
|
|
2744
|
-
// Render the skeleton with all rows from scratch
|
|
2745
|
-
this.render();
|
|
2746
|
-
}
|
|
2747
|
-
|
|
2748
|
-
} else if (render) {
|
|
2749
|
-
p.virtualListHelper.removeItemsAt(count, physicalRowIndex);
|
|
2750
|
-
|
|
2751
|
-
if (this.o.virtualTable) {
|
|
2752
|
-
this._updateVirtualHeight().
|
|
2753
|
-
_updateLastCellWidthFromScrollbar().
|
|
2754
|
-
render().
|
|
2755
|
-
_updateTableWidth(false); // Update table width to suit the required width considering vertical scrollbar
|
|
2756
|
-
} else {
|
|
2757
|
-
this.render().
|
|
2758
|
-
_updateLastCellWidthFromScrollbar().
|
|
2759
|
-
_updateTableWidth(true); // Update table width to suit the required width considering vertical scrollbar
|
|
2760
|
-
}
|
|
2761
|
-
}
|
|
2762
|
-
|
|
2763
|
-
return this;
|
|
2764
|
-
};
|
|
2765
|
-
|
|
2766
|
-
/**
|
|
2767
|
-
* Removes a row from the table
|
|
2768
|
-
* @public
|
|
2769
|
-
* @expose
|
|
2770
|
-
* @param {number} physicalRowIndex - index
|
|
2771
|
-
* @param {boolean=true} render
|
|
2772
|
-
* @returns {DGTable} self
|
|
2773
|
-
*/
|
|
2774
|
-
DGTable.prototype.removeRow = function (physicalRowIndex, render) {
|
|
2775
|
-
return this.removeRows(physicalRowIndex, 1, render);
|
|
2776
|
-
};
|
|
2777
|
-
|
|
2778
|
-
/**
|
|
2779
|
-
* Refreshes the row specified
|
|
2780
|
-
* @public
|
|
2781
|
-
* @expose
|
|
2782
|
-
* @param {number} physicalRowIndex index
|
|
2783
|
-
* @param {boolean} render should render the changes immediately?
|
|
2784
|
-
* @returns {DGTable} self
|
|
2785
|
-
*/
|
|
2786
|
-
DGTable.prototype.refreshRow = function (physicalRowIndex) {let render = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
2787
|
-
let that = this,
|
|
2788
|
-
p = that.p;
|
|
2789
|
-
|
|
2790
|
-
if (physicalRowIndex < 0 || physicalRowIndex > p.rows.length - 1) return this;
|
|
2791
|
-
|
|
2792
|
-
// Find out if the row is in the rendered dataset
|
|
2793
|
-
let rowIndex = -1;
|
|
2794
|
-
if (p.filteredRows && (rowIndex = p.filteredRows.indexOf(p.rows[physicalRowIndex])) === -1) return this;
|
|
2795
|
-
|
|
2796
|
-
if (rowIndex === -1) {
|
|
2797
|
-
rowIndex = physicalRowIndex;
|
|
2798
|
-
}
|
|
2799
|
-
|
|
2800
|
-
p.virtualListHelper.refreshItemAt(rowIndex);
|
|
2801
|
-
|
|
2802
|
-
if (render)
|
|
2803
|
-
p.virtualListHelper.render();
|
|
2804
|
-
|
|
2805
|
-
return this;
|
|
2806
|
-
};
|
|
2807
|
-
|
|
2808
|
-
/**
|
|
2809
|
-
* Get the DOM element for the specified row, if it exists
|
|
2810
|
-
* @public
|
|
2811
|
-
* @expose
|
|
2812
|
-
* @param {number} physicalRowIndex index
|
|
2813
|
-
* @returns {Element|null} row or null
|
|
2814
|
-
*/
|
|
2815
|
-
DGTable.prototype.getRowElement = function (physicalRowIndex) {
|
|
2816
|
-
let that = this,
|
|
2817
|
-
p = that.p;
|
|
2818
|
-
|
|
2819
|
-
if (physicalRowIndex < 0 || physicalRowIndex > p.rows.length - 1) return null;
|
|
2820
|
-
|
|
2821
|
-
// Find out if the row is in the rendered dataset
|
|
2822
|
-
let rowIndex = -1;
|
|
2823
|
-
if (p.filteredRows && (rowIndex = p.filteredRows.indexOf(p.rows[physicalRowIndex])) === -1) return this;
|
|
2824
|
-
|
|
2825
|
-
if (rowIndex === -1) {
|
|
2826
|
-
rowIndex = physicalRowIndex;
|
|
2827
|
-
}
|
|
2828
|
-
|
|
2829
|
-
return p.virtualListHelper.getItemElementAt(rowIndex) || null;
|
|
2830
|
-
};
|
|
2831
|
-
|
|
2832
|
-
/**
|
|
2833
|
-
* Refreshes all virtual rows
|
|
2834
|
-
* @public
|
|
2835
|
-
* @expose
|
|
2836
|
-
* @returns {DGTable} self
|
|
2837
|
-
*/
|
|
2838
|
-
DGTable.prototype.refreshAllVirtualRows = function () {
|
|
2839
|
-
const p = this.p;
|
|
2840
|
-
p.virtualListHelper.invalidate().render();
|
|
2841
|
-
return this;
|
|
2842
|
-
};
|
|
2843
|
-
|
|
2844
|
-
/**
|
|
2845
|
-
* Replace the whole dataset
|
|
2846
|
-
* @public
|
|
2847
|
-
* @expose
|
|
2848
|
-
* @param {Object[]} data array of rows to add to the table
|
|
2849
|
-
* @param {boolean} [resort=false] should resort all rows?
|
|
2850
|
-
* @returns {DGTable} self
|
|
2851
|
-
*/
|
|
2852
|
-
DGTable.prototype.setRows = function (data, resort) {
|
|
2853
|
-
let that = this,
|
|
2854
|
-
p = that.p;
|
|
2855
|
-
|
|
2856
|
-
// this.scrollTop = this.$el.find('.table').scrollTop();
|
|
2857
|
-
p.rows.reset(data);
|
|
2858
|
-
|
|
2859
|
-
if (resort && p.rows.sortColumn.length) {
|
|
2860
|
-
this.resort();
|
|
2861
|
-
} else {
|
|
2862
|
-
this._refilter();
|
|
2863
|
-
}
|
|
2864
|
-
|
|
2865
|
-
this.clearAndRender().trigger('addrows', data.length, true);
|
|
2866
|
-
|
|
2867
|
-
return this;
|
|
2868
|
-
};
|
|
2869
|
-
|
|
2870
|
-
/**
|
|
2871
|
-
* Creates a URL representing the data in the specified element.
|
|
2872
|
-
* This uses the Blob or BlobBuilder of the modern browsers.
|
|
2873
|
-
* The url can be used for a Web Worker.
|
|
2874
|
-
* @public
|
|
2875
|
-
* @expose
|
|
2876
|
-
* @param {string} id Id of the element containing your data
|
|
2877
|
-
* @returns {string|null} the url, or null if not supported
|
|
2878
|
-
*/
|
|
2879
|
-
DGTable.prototype.getUrlForElementContent = function (id) {
|
|
2880
|
-
let blob,
|
|
2881
|
-
el = document.getElementById(id);
|
|
2882
|
-
if (el) {
|
|
2883
|
-
let data = el.textContent;
|
|
2884
|
-
if (typeof Blob === 'function') {
|
|
2885
|
-
blob = new Blob([data]);
|
|
2886
|
-
} else {
|
|
2887
|
-
let BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
|
|
2888
|
-
if (!BlobBuilder) {
|
|
2889
|
-
return null;
|
|
2890
|
-
}
|
|
2891
|
-
let builder = new BlobBuilder();
|
|
2892
|
-
builder.append(data);
|
|
2893
|
-
blob = builder.getBlob();
|
|
2894
|
-
}
|
|
2895
|
-
return (window.URL || window.webkitURL).createObjectURL(blob);
|
|
2896
|
-
}
|
|
2897
|
-
return null;
|
|
2898
|
-
};
|
|
2899
|
-
|
|
2900
|
-
/**
|
|
2901
|
-
* @public
|
|
2902
|
-
* @expose
|
|
2903
|
-
* @returns {boolean} A value indicating whether Web Workers are supported
|
|
2904
|
-
*/
|
|
2905
|
-
DGTable.prototype.isWorkerSupported = function () {
|
|
2906
|
-
return window['Worker'] instanceof Function;
|
|
2907
|
-
};
|
|
2908
|
-
|
|
2909
|
-
/**
|
|
2910
|
-
* Creates a Web Worker for updating the table.
|
|
2911
|
-
* @public
|
|
2912
|
-
* @expose
|
|
2913
|
-
* @param {string} url Url to the script for the Web Worker
|
|
2914
|
-
* @param {boolean} [start=true] if true, starts the Worker immediately
|
|
2915
|
-
* @param {boolean} [resort=false]
|
|
2916
|
-
* @returns {Worker|null} the Web Worker, or null if not supported
|
|
2917
|
-
*/
|
|
2918
|
-
DGTable.prototype.createWebWorker = function (url, start, resort) {
|
|
2919
|
-
if (this.isWorkerSupported()) {
|
|
2920
|
-
let that = this,
|
|
2921
|
-
p = that.p;
|
|
2922
|
-
|
|
2923
|
-
let worker = new Worker(url);
|
|
2924
|
-
let listener = function (evt) {
|
|
2925
|
-
if (evt.data.append) {
|
|
2926
|
-
that.addRows(evt.data.rows, resort);
|
|
2927
|
-
} else {
|
|
2928
|
-
that.setRows(evt.data.rows, resort);
|
|
2929
|
-
}
|
|
2930
|
-
};
|
|
2931
|
-
worker.addEventListener('message', listener, false);
|
|
2932
|
-
if (!p.workerListeners) {
|
|
2933
|
-
p.workerListeners = [];
|
|
2934
|
-
}
|
|
2935
|
-
p.workerListeners.push({ worker: worker, listener: listener });
|
|
2936
|
-
if (start || start === undefined) {
|
|
2937
|
-
worker.postMessage(null);
|
|
2938
|
-
}
|
|
2939
|
-
return worker;
|
|
2940
|
-
}
|
|
2941
|
-
return null;
|
|
2942
|
-
};
|
|
2943
|
-
|
|
2944
|
-
/**
|
|
2945
|
-
* Unbinds a Web Worker from the table, stopping updates.
|
|
2946
|
-
* @public
|
|
2947
|
-
* @expose
|
|
2948
|
-
* @param {Worker} worker the Web Worker
|
|
2949
|
-
* @returns {DGTable} self
|
|
2950
|
-
*/
|
|
2951
|
-
DGTable.prototype.unbindWebWorker = function (worker) {
|
|
2952
|
-
let that = this,
|
|
2953
|
-
p = that.p;
|
|
2954
|
-
|
|
2955
|
-
if (p.workerListeners) {
|
|
2956
|
-
for (let j = 0; j < p.workerListeners.length; j++) {
|
|
2957
|
-
if (p.workerListeners[j].worker === worker) {
|
|
2958
|
-
worker.removeEventListener('message', p.workerListeners[j].listener, false);
|
|
2959
|
-
p.workerListeners.splice(j, 1);
|
|
2960
|
-
j--;
|
|
2961
|
-
}
|
|
2962
|
-
}
|
|
2963
|
-
}
|
|
2964
|
-
|
|
2965
|
-
return this;
|
|
2966
|
-
};
|
|
2967
|
-
|
|
2968
|
-
/**
|
|
2969
|
-
* A synonym for hideCellPreview()
|
|
2970
|
-
* @public
|
|
2971
|
-
* @expose
|
|
2972
|
-
* @returns {DGTable} self
|
|
2973
|
-
*/
|
|
2974
|
-
DGTable.prototype.abortCellPreview = function () {
|
|
2975
|
-
this.hideCellPreview();
|
|
2976
|
-
return this;
|
|
2977
|
-
};
|
|
2978
|
-
|
|
2979
|
-
/**
|
|
2980
|
-
* Cancel a resize in progress
|
|
2981
|
-
* @expose
|
|
2982
|
-
* @private
|
|
2983
|
-
* @returns {DGTable} self
|
|
2984
|
-
*/
|
|
2985
|
-
DGTable.prototype.cancelColumnResize = function () {
|
|
2986
|
-
const p = this.p;
|
|
2987
|
-
|
|
2988
|
-
if (p.$resizer) {
|
|
2989
|
-
p.$resizer.remove();
|
|
2990
|
-
p.$resizer = null;
|
|
2991
|
-
$(document).off('mousemove.dgtable', p.onMouseMoveResizeAreaBound).
|
|
2992
|
-
off('mouseup.dgtable', p.onEndDragColumnHeaderBound);
|
|
2993
|
-
}
|
|
2994
|
-
|
|
2995
|
-
return this;
|
|
2996
|
-
};
|
|
2997
|
-
|
|
2998
|
-
DGTable.prototype._onTableScrolledHorizontally = function () {
|
|
2999
|
-
const p = this.p;
|
|
3000
|
-
|
|
3001
|
-
p.header.scrollLeft = p.table.scrollLeft;
|
|
3002
|
-
};
|
|
3003
|
-
|
|
3004
|
-
/**previousElementSibling
|
|
3005
|
-
* Reverse-calculate the column to resize from mouse position
|
|
3006
|
-
* @private
|
|
3007
|
-
* @param {jQuery_Event} e jQuery mouse event
|
|
3008
|
-
* @returns {string} name of the column which the mouse is over, or null if the mouse is not in resize position
|
|
3009
|
-
*/
|
|
3010
|
-
DGTable.prototype._getColumnByResizePosition = function (e) {
|
|
3011
|
-
|
|
3012
|
-
let that = this,
|
|
3013
|
-
o = that.o,
|
|
3014
|
-
rtl = this._isTableRtl();
|
|
3015
|
-
|
|
3016
|
-
let $headerCell = $(e.target).closest('div.' + o.tableClassName + '-header-cell,div.' + o.cellPreviewClassName),
|
|
3017
|
-
headerCell = $headerCell[0];
|
|
3018
|
-
if (headerCell['__cell']) {
|
|
3019
|
-
headerCell = headerCell['__cell'];
|
|
3020
|
-
$headerCell = $(headerCell);
|
|
3021
|
-
}
|
|
3022
|
-
|
|
3023
|
-
let previousElementSibling = $headerCell[0].previousSibling;
|
|
3024
|
-
while (previousElementSibling && previousElementSibling.nodeType !== 1) {
|
|
3025
|
-
previousElementSibling = previousElementSibling.previousSibling;
|
|
3026
|
-
}
|
|
3027
|
-
|
|
3028
|
-
let firstCol = !previousElementSibling;
|
|
3029
|
-
|
|
3030
|
-
let mouseX = ((e.pageX != null ? e.pageX : e.originalEvent.pageX) || e.originalEvent.clientX) - $headerCell.offset().left;
|
|
3031
|
-
|
|
3032
|
-
if (rtl) {
|
|
3033
|
-
if (!firstCol && Css_js.getElementWidth($headerCell[0], true, true, true) - mouseX <= o.resizeAreaWidth / 2) {
|
|
3034
|
-
return previousElementSibling['columnName'];
|
|
3035
|
-
} else if (mouseX <= o.resizeAreaWidth / 2) {
|
|
3036
|
-
return headerCell['columnName'];
|
|
3037
|
-
}
|
|
3038
|
-
} else {
|
|
3039
|
-
if (!firstCol && mouseX <= o.resizeAreaWidth / 2) {
|
|
3040
|
-
return previousElementSibling['columnName'];
|
|
3041
|
-
} else if (Css_js.getElementWidth($headerCell[0], true, true, true) - mouseX <= o.resizeAreaWidth / 2) {
|
|
3042
|
-
return headerCell['columnName'];
|
|
3043
|
-
}
|
|
3044
|
-
}
|
|
3045
|
-
|
|
3046
|
-
return null;
|
|
3047
|
-
};
|
|
3048
|
-
|
|
3049
|
-
/**
|
|
3050
|
-
* @param {jQuery_Event} event
|
|
3051
|
-
*/
|
|
3052
|
-
DGTable.prototype._onTouchStartColumnHeader = function (event) {
|
|
3053
|
-
const p = this.p;
|
|
3054
|
-
|
|
3055
|
-
if (p.currentTouchId) return;
|
|
3056
|
-
|
|
3057
|
-
let startTouch = event.originalEvent.changedTouches[0];
|
|
3058
|
-
p.currentTouchId = startTouch.identifier;
|
|
3059
|
-
|
|
3060
|
-
let $eventTarget = $(event.currentTarget);
|
|
3061
|
-
|
|
3062
|
-
let startPos = { x: startTouch.pageX, y: startTouch.pageY },
|
|
3063
|
-
currentPos = startPos,
|
|
3064
|
-
distanceTreshold = 9;
|
|
3065
|
-
|
|
3066
|
-
let tapAndHoldTimeout;
|
|
3067
|
-
|
|
3068
|
-
let unbind = function () {
|
|
3069
|
-
p.currentTouchId = null;
|
|
3070
|
-
$eventTarget.off('touchend').off('touchcancel');
|
|
3071
|
-
clearTimeout(tapAndHoldTimeout);
|
|
3072
|
-
};
|
|
3073
|
-
|
|
3074
|
-
let fakeEvent = function (name) {
|
|
3075
|
-
let fakeEvent = $.Event(name);
|
|
3076
|
-
let extendObjects = Array.prototype.slice.call(arguments, 1);
|
|
3077
|
-
for (let key of ['target', 'clientX', 'clientY', 'offsetX', 'offsetY', 'screenX', 'screenY', 'pageX', 'pageY', 'which']) {
|
|
3078
|
-
fakeEvent[key] = event[key];
|
|
3079
|
-
for (let i = 0; i < extendObjects.length; i++) {
|
|
3080
|
-
if (extendObjects[i][key] != null) {
|
|
3081
|
-
fakeEvent[key] = extendObjects[i][key];
|
|
3082
|
-
}
|
|
3083
|
-
}
|
|
3084
|
-
}
|
|
3085
|
-
return fakeEvent;
|
|
3086
|
-
};
|
|
3087
|
-
|
|
3088
|
-
$eventTarget.trigger(fakeEvent('mousedown', event.originalEvent.changedTouches[0], { 'which': 1, target: event.target }));
|
|
3089
|
-
|
|
3090
|
-
tapAndHoldTimeout = setTimeout(() => {
|
|
3091
|
-
unbind();
|
|
3092
|
-
|
|
3093
|
-
$eventTarget.
|
|
3094
|
-
one('touchend', (event) => {
|
|
3095
|
-
// Prevent simulated mouse events after touchend
|
|
3096
|
-
if (!isInputElementEvent(event))
|
|
3097
|
-
event.preventDefault();
|
|
3098
|
-
|
|
3099
|
-
$eventTarget.off('touchend').off('touchcancel');
|
|
3100
|
-
}).
|
|
3101
|
-
one('touchcancel', (_event) => {
|
|
3102
|
-
$eventTarget.off('touchend').off('touchcancel');
|
|
3103
|
-
});
|
|
3104
|
-
|
|
3105
|
-
let distanceTravelled = Math.sqrt(Math.pow(Math.abs(currentPos.x - startPos.x), 2) + Math.pow(Math.abs(currentPos.y - startPos.y), 2));
|
|
3106
|
-
|
|
3107
|
-
if (distanceTravelled < distanceTreshold) {
|
|
3108
|
-
this.cancelColumnResize();
|
|
3109
|
-
$eventTarget.trigger(fakeEvent('mouseup', event.originalEvent.changedTouches[0], { 'which': 3, target: event.target }));
|
|
3110
|
-
}
|
|
3111
|
-
|
|
3112
|
-
}, 500);
|
|
3113
|
-
|
|
3114
|
-
$eventTarget.
|
|
3115
|
-
on('touchend', (event) => {
|
|
3116
|
-
let touch = find(event.originalEvent.changedTouches, (touch) => touch.identifier === p.currentTouchId);
|
|
3117
|
-
if (!touch) return;
|
|
3118
|
-
|
|
3119
|
-
unbind();
|
|
3120
|
-
|
|
3121
|
-
// Prevent simulated mouse events after touchend
|
|
3122
|
-
if (!isInputElementEvent(event))
|
|
3123
|
-
event.preventDefault();
|
|
3124
|
-
|
|
3125
|
-
currentPos = { x: touch.pageX, y: touch.pageY };
|
|
3126
|
-
let distanceTravelled = Math.sqrt(Math.pow(Math.abs(currentPos.x - startPos.x), 2) + Math.pow(Math.abs(currentPos.y - startPos.y), 2));
|
|
3127
|
-
|
|
3128
|
-
if (distanceTravelled < distanceTreshold || p.$resizer) {
|
|
3129
|
-
$eventTarget.trigger(fakeEvent('mouseup', touch, { 'which': 1, target: event.target }));
|
|
3130
|
-
$eventTarget.trigger(fakeEvent('click', touch, { 'which': 1, target: event.target }));
|
|
3131
|
-
}
|
|
3132
|
-
|
|
3133
|
-
}).
|
|
3134
|
-
on('touchcancel', () => {
|
|
3135
|
-
unbind();
|
|
3136
|
-
}).
|
|
3137
|
-
on('touchmove', (event) => {
|
|
3138
|
-
let touch = find(event.originalEvent.changedTouches, (touch) => touch.identifier === p.currentTouchId);
|
|
3139
|
-
if (!touch) return;
|
|
3140
|
-
|
|
3141
|
-
// Keep track of current position, so we know if we need to cancel the tap-and-hold
|
|
3142
|
-
currentPos = { x: touch.pageX, y: touch.pageY };
|
|
3143
|
-
|
|
3144
|
-
if (p.$resizer) {
|
|
3145
|
-
event.preventDefault();
|
|
3146
|
-
|
|
3147
|
-
$eventTarget.trigger(fakeEvent('mousemove', touch, { target: event.target }));
|
|
3148
|
-
}
|
|
3149
|
-
});
|
|
3150
|
-
};
|
|
3151
|
-
|
|
3152
|
-
/**
|
|
3153
|
-
* @param {jQuery_Event} event
|
|
3154
|
-
*/
|
|
3155
|
-
DGTable.prototype._onMouseDownColumnHeader = function (event) {
|
|
3156
|
-
if (event.which !== 1) return this; // Only treat left-clicks
|
|
3157
|
-
|
|
3158
|
-
let that = this,
|
|
3159
|
-
o = that.o,
|
|
3160
|
-
p = that.p,
|
|
3161
|
-
col = this._getColumnByResizePosition(event);
|
|
3162
|
-
|
|
3163
|
-
if (col) {
|
|
3164
|
-
let column = p.columns.get(col);
|
|
3165
|
-
if (!o.resizableColumns || !column || !column.resizable) {
|
|
3166
|
-
return false;
|
|
3167
|
-
}
|
|
3168
|
-
|
|
3169
|
-
let rtl = this._isTableRtl();
|
|
3170
|
-
|
|
3171
|
-
if (p.$resizer) {
|
|
3172
|
-
$(p.$resizer).remove();
|
|
3173
|
-
}
|
|
3174
|
-
p.$resizer = $('<div></div>').
|
|
3175
|
-
addClass(o.resizerClassName).
|
|
3176
|
-
css({
|
|
3177
|
-
'position': 'absolute',
|
|
3178
|
-
'display': 'block',
|
|
3179
|
-
'z-index': -1,
|
|
3180
|
-
'visibility': 'hidden',
|
|
3181
|
-
'width': '2px',
|
|
3182
|
-
'background': '#000',
|
|
3183
|
-
'opacity': 0.7
|
|
3184
|
-
}).
|
|
3185
|
-
appendTo(this.$el);
|
|
3186
|
-
|
|
3187
|
-
let selectedHeaderCell = column.element,
|
|
3188
|
-
commonAncestor = p.$resizer.parent();
|
|
3189
|
-
|
|
3190
|
-
let posCol = selectedHeaderCell.offset(),
|
|
3191
|
-
posRelative = commonAncestor.offset();
|
|
3192
|
-
if (ieVersion === 8) {
|
|
3193
|
-
posCol = selectedHeaderCell.offset(); // IE8 bug, first time it receives zeros...
|
|
3194
|
-
}
|
|
3195
|
-
posRelative.left += parseFloat(commonAncestor.css('border-left-width')) || 0;
|
|
3196
|
-
posRelative.top += parseFloat(commonAncestor.css('border-top-width')) || 0;
|
|
3197
|
-
posCol.left -= posRelative.left;
|
|
3198
|
-
posCol.top -= posRelative.top;
|
|
3199
|
-
posCol.top -= parseFloat(selectedHeaderCell.css('border-top-width')) || 0;
|
|
3200
|
-
let resizerWidth = Css_js.getElementWidth(p.$resizer[0], true, true, true);
|
|
3201
|
-
if (rtl) {
|
|
3202
|
-
posCol.left -= Math.ceil((parseFloat(selectedHeaderCell.css('border-left-width')) || 0) / 2);
|
|
3203
|
-
posCol.left -= Math.ceil(resizerWidth / 2);
|
|
3204
|
-
} else {
|
|
3205
|
-
posCol.left += Css_js.getElementWidth(selectedHeaderCell[0], true, true, true);
|
|
3206
|
-
posCol.left += Math.ceil((parseFloat(selectedHeaderCell.css('border-right-width')) || 0) / 2);
|
|
3207
|
-
posCol.left -= Math.ceil(resizerWidth / 2);
|
|
3208
|
-
}
|
|
3209
|
-
|
|
3210
|
-
p.$resizer.
|
|
3211
|
-
css({
|
|
3212
|
-
'z-index': '10',
|
|
3213
|
-
'visibility': 'visible',
|
|
3214
|
-
'left': posCol.left,
|
|
3215
|
-
'top': posCol.top,
|
|
3216
|
-
'height': Css_js.getElementHeight(this.$el[0])
|
|
3217
|
-
})[0]['columnName'] = selectedHeaderCell[0]['columnName'];
|
|
3218
|
-
|
|
3219
|
-
try {p.$resizer[0].style.zIndex = '';}
|
|
3220
|
-
catch (ignored) {/* we're ok with this */}
|
|
3221
|
-
|
|
3222
|
-
$(document).on('mousemove.dgtable', p.onMouseMoveResizeAreaBound);
|
|
3223
|
-
$(document).on('mouseup.dgtable', p.onEndDragColumnHeaderBound);
|
|
3224
|
-
|
|
3225
|
-
event.preventDefault();
|
|
3226
|
-
}
|
|
3227
|
-
};
|
|
3228
|
-
|
|
3229
|
-
/**
|
|
3230
|
-
* @param {jQuery_Event} event event
|
|
3231
|
-
*/
|
|
3232
|
-
DGTable.prototype._onMouseMoveColumnHeader = function (event) {
|
|
3233
|
-
|
|
3234
|
-
let that = this,
|
|
3235
|
-
o = that.o,
|
|
3236
|
-
p = that.p;
|
|
3237
|
-
|
|
3238
|
-
if (o.resizableColumns) {
|
|
3239
|
-
let col = this._getColumnByResizePosition(event);
|
|
3240
|
-
let headerCell = $(event.target).closest('div.' + o.tableClassName + '-header-cell,div.' + o.cellPreviewClassName)[0];
|
|
3241
|
-
if (!col || !p.columns.get(col).resizable) {
|
|
3242
|
-
headerCell.style.cursor = '';
|
|
3243
|
-
} else {
|
|
3244
|
-
headerCell.style.cursor = 'e-resize';
|
|
3245
|
-
}
|
|
3246
|
-
}
|
|
3247
|
-
};
|
|
3248
|
-
|
|
3249
|
-
/**
|
|
3250
|
-
* @param {jQuery_Event} event
|
|
3251
|
-
*/
|
|
3252
|
-
DGTable.prototype._onMouseUpColumnHeader = function (event) {
|
|
3253
|
-
if (event.which === 3) {
|
|
3254
|
-
let o = this.o;
|
|
3255
|
-
let $headerCell = $(event.target).closest('div.' + o.tableClassName + '-header-cell,div.' + o.cellPreviewClassName);
|
|
3256
|
-
let bounds = $headerCell.offset();
|
|
3257
|
-
bounds['width'] = Css_js.getElementWidth($headerCell[0], true, true, true);
|
|
3258
|
-
bounds['height'] = Css_js.getElementHeight($headerCell[0], true, true, true);
|
|
3259
|
-
this.trigger('headercontextmenu', $headerCell[0]['columnName'], event.pageX, event.pageY, bounds);
|
|
3260
|
-
}
|
|
3261
|
-
return this;
|
|
3262
|
-
};
|
|
3263
|
-
|
|
3264
|
-
/**
|
|
3265
|
-
* @private
|
|
3266
|
-
* @param {jQuery_Event} event event
|
|
3267
|
-
*/
|
|
3268
|
-
DGTable.prototype._onMouseLeaveColumnHeader = function (event) {
|
|
3269
|
-
let o = this.o;
|
|
3270
|
-
let headerCell = $(event.target).closest('div.' + o.tableClassName + '-header-cell,div.' + o.cellPreviewClassName)[0];
|
|
3271
|
-
headerCell.style.cursor = '';
|
|
3272
|
-
};
|
|
3273
|
-
|
|
3274
|
-
/**
|
|
3275
|
-
* @private
|
|
3276
|
-
* @param {jQuery_Event} event event
|
|
3277
|
-
*/
|
|
3278
|
-
DGTable.prototype._onClickColumnHeader = function (event) {
|
|
3279
|
-
if (isInputElementEvent(event))
|
|
3280
|
-
return;
|
|
3281
|
-
|
|
3282
|
-
if (!this._getColumnByResizePosition(event)) {
|
|
3283
|
-
|
|
3284
|
-
let that = this,
|
|
3285
|
-
o = that.o,
|
|
3286
|
-
p = that.p;
|
|
3287
|
-
|
|
3288
|
-
let headerCell = $(event.target).closest('div.' + o.tableClassName + '-header-cell,div.' + o.cellPreviewClassName)[0];
|
|
3289
|
-
if (o.sortableColumns) {
|
|
3290
|
-
let column = p.columns.get(headerCell['columnName']);
|
|
3291
|
-
let currentSort = p.rows.sortColumn;
|
|
3292
|
-
if (column && column.sortable) {
|
|
3293
|
-
let shouldAdd = true;
|
|
3294
|
-
|
|
3295
|
-
let lastSort = currentSort.length ? currentSort[currentSort.length - 1] : null;
|
|
3296
|
-
|
|
3297
|
-
if (lastSort && lastSort.column === column.name) {
|
|
3298
|
-
if (!lastSort.descending || !o.allowCancelSort) {
|
|
3299
|
-
lastSort.descending = !lastSort.descending;
|
|
3300
|
-
} else {
|
|
3301
|
-
shouldAdd = false;
|
|
3302
|
-
currentSort.splice(currentSort.length - 1, 1);
|
|
3303
|
-
}
|
|
3304
|
-
}
|
|
3305
|
-
|
|
3306
|
-
if (shouldAdd) {
|
|
3307
|
-
this.sort(column.name, undefined, true).render();
|
|
3308
|
-
} else {
|
|
3309
|
-
this.sort(); // just refresh current situation
|
|
3310
|
-
}
|
|
3311
|
-
}
|
|
3312
|
-
}
|
|
3313
|
-
}
|
|
3314
|
-
};
|
|
3315
|
-
|
|
3316
|
-
/**
|
|
3317
|
-
* @private
|
|
3318
|
-
* @param {jQuery_Event} event event
|
|
3319
|
-
*/
|
|
3320
|
-
DGTable.prototype._onStartDragColumnHeader = function (event) {
|
|
3321
|
-
|
|
3322
|
-
let that = this,
|
|
3323
|
-
o = that.o,
|
|
3324
|
-
p = that.p;
|
|
3325
|
-
|
|
3326
|
-
if (o.movableColumns) {
|
|
3327
|
-
|
|
3328
|
-
let $headerCell = $(event.target).closest('div.' + o.tableClassName + '-header-cell,div.' + o.cellPreviewClassName);
|
|
3329
|
-
let column = p.columns.get($headerCell[0]['columnName']);
|
|
3330
|
-
if (column && column.movable) {
|
|
3331
|
-
$headerCell[0].style.opacity = 0.35;
|
|
3332
|
-
p.dragId = Math.random() * 0x9999999; // Recognize this ID on drop
|
|
3333
|
-
event.originalEvent.dataTransfer.setData('text', JSON.stringify({ dragId: p.dragId, column: column.name }));
|
|
3334
|
-
} else {
|
|
3335
|
-
event.preventDefault();
|
|
3336
|
-
}
|
|
3337
|
-
|
|
3338
|
-
} else {
|
|
3339
|
-
|
|
3340
|
-
event.preventDefault();
|
|
3341
|
-
|
|
3342
|
-
}
|
|
3343
|
-
|
|
3344
|
-
return undefined;
|
|
3345
|
-
};
|
|
3346
|
-
|
|
3347
|
-
/**
|
|
3348
|
-
* @private
|
|
3349
|
-
* @param {MouseEvent} event event
|
|
3350
|
-
*/
|
|
3351
|
-
DGTable.prototype._onMouseMoveResizeArea = function (event) {
|
|
3352
|
-
|
|
3353
|
-
let that = this,
|
|
3354
|
-
p = that.p;
|
|
3355
|
-
|
|
3356
|
-
let column = p.columns.get(p.$resizer[0]['columnName']);
|
|
3357
|
-
let rtl = this._isTableRtl();
|
|
3358
|
-
|
|
3359
|
-
let selectedHeaderCell = column.element,
|
|
3360
|
-
commonAncestor = p.$resizer.parent();
|
|
3361
|
-
let posCol = selectedHeaderCell.offset(),posRelative = commonAncestor.offset();
|
|
3362
|
-
posRelative.left += parseFloat(commonAncestor.css('border-left-width')) || 0;
|
|
3363
|
-
posCol.left -= posRelative.left;
|
|
3364
|
-
let resizerWidth = Css_js.getElementWidth(p.$resizer[0], true, true, true);
|
|
3365
|
-
|
|
3366
|
-
let isBoxing = selectedHeaderCell.css('box-sizing') === 'border-box';
|
|
3367
|
-
|
|
3368
|
-
let actualX = event.pageX - posRelative.left;
|
|
3369
|
-
let minX = posCol.left;
|
|
3370
|
-
|
|
3371
|
-
minX -= Math.ceil(resizerWidth / 2);
|
|
3372
|
-
|
|
3373
|
-
if (rtl) {
|
|
3374
|
-
minX += Css_js.getElementWidth(selectedHeaderCell[0], true, true, true);
|
|
3375
|
-
minX -= column.ignoreMin ? 0 : this.o.minColumnWidth;
|
|
3376
|
-
|
|
3377
|
-
if (!isBoxing) {
|
|
3378
|
-
minX -= Math.ceil((parseFloat(selectedHeaderCell.css('border-left-width')) || 0) / 2);
|
|
3379
|
-
minX -= this._horizontalPadding(selectedHeaderCell[0]);
|
|
3380
|
-
}
|
|
3381
|
-
|
|
3382
|
-
if (actualX > minX) {
|
|
3383
|
-
actualX = minX;
|
|
3384
|
-
}
|
|
3385
|
-
} else {
|
|
3386
|
-
minX += column.ignoreMin ? 0 : this.o.minColumnWidth;
|
|
3387
|
-
|
|
3388
|
-
if (!isBoxing) {
|
|
3389
|
-
minX += Math.ceil((parseFloat(selectedHeaderCell.css('border-right-width')) || 0) / 2);
|
|
3390
|
-
minX += this._horizontalPadding(selectedHeaderCell[0]);
|
|
3391
|
-
}
|
|
3392
|
-
|
|
3393
|
-
if (actualX < minX) {
|
|
3394
|
-
actualX = minX;
|
|
3395
|
-
}
|
|
3396
|
-
}
|
|
3397
|
-
|
|
3398
|
-
p.$resizer.css('left', actualX + 'px');
|
|
3399
|
-
};
|
|
3400
|
-
|
|
3401
|
-
/**
|
|
3402
|
-
* @private
|
|
3403
|
-
* @param {Event} event event
|
|
3404
|
-
*/
|
|
3405
|
-
DGTable.prototype._onEndDragColumnHeader = function (event) {
|
|
3406
|
-
|
|
3407
|
-
let that = this,
|
|
3408
|
-
o = that.o,
|
|
3409
|
-
p = that.p;
|
|
3410
|
-
|
|
3411
|
-
if (!p.$resizer) {
|
|
3412
|
-
event.target.style.opacity = null;
|
|
3413
|
-
} else {
|
|
3414
|
-
$(document).off('mousemove.dgtable', p.onMouseMoveResizeAreaBound).
|
|
3415
|
-
off('mouseup.dgtable', p.onEndDragColumnHeaderBound);
|
|
3416
|
-
|
|
3417
|
-
let column = p.columns.get(p.$resizer[0]['columnName']);
|
|
3418
|
-
let rtl = this._isTableRtl();
|
|
3419
|
-
|
|
3420
|
-
let selectedHeaderCell = column.element,
|
|
3421
|
-
selectedHeaderCellInner = selectedHeaderCell[0].firstChild,
|
|
3422
|
-
commonAncestor = p.$resizer.parent();
|
|
3423
|
-
let posCol = selectedHeaderCell.offset(),posRelative = commonAncestor.offset();
|
|
3424
|
-
posRelative.left += parseFloat(commonAncestor.css('border-left-width')) || 0;
|
|
3425
|
-
posCol.left -= posRelative.left;
|
|
3426
|
-
let resizerWidth = Css_js.getElementWidth(p.$resizer[0], true, true, true);
|
|
3427
|
-
|
|
3428
|
-
let isBoxing = selectedHeaderCell.css('box-sizing') === 'border-box';
|
|
3429
|
-
|
|
3430
|
-
let actualX = event.pageX - posRelative.left;
|
|
3431
|
-
let baseX = posCol.left,minX = posCol.left;
|
|
3432
|
-
let width = 0;
|
|
3433
|
-
|
|
3434
|
-
baseX -= Math.ceil(resizerWidth / 2);
|
|
3435
|
-
|
|
3436
|
-
if (rtl) {
|
|
3437
|
-
if (!isBoxing) {
|
|
3438
|
-
actualX += this._horizontalPadding(selectedHeaderCell[0]);
|
|
3439
|
-
const innerComputedStyle = getComputedStyle(selectedHeaderCellInner || selectedHeaderCell[0]);
|
|
3440
|
-
actualX += parseFloat(innerComputedStyle.borderLeftWidth) || 0;
|
|
3441
|
-
actualX += parseFloat(innerComputedStyle.borderRightWidth) || 0;
|
|
3442
|
-
actualX += column.arrowProposedWidth || 0; // Sort-arrow width
|
|
3443
|
-
}
|
|
3444
|
-
|
|
3445
|
-
baseX += Css_js.getElementWidth(selectedHeaderCell[0], true, true, true);
|
|
3446
|
-
|
|
3447
|
-
minX = baseX - (column.ignoreMin ? 0 : this.o.minColumnWidth);
|
|
3448
|
-
if (actualX > minX) {
|
|
3449
|
-
actualX = minX;
|
|
3450
|
-
}
|
|
3451
|
-
|
|
3452
|
-
width = baseX - actualX;
|
|
3453
|
-
} else {
|
|
3454
|
-
if (!isBoxing) {
|
|
3455
|
-
actualX -= this._horizontalPadding(selectedHeaderCell[0]);
|
|
3456
|
-
const innerComputedStyle = getComputedStyle(selectedHeaderCellInner || selectedHeaderCell[0]);
|
|
3457
|
-
actualX -= parseFloat(innerComputedStyle.borderLeftWidth) || 0;
|
|
3458
|
-
actualX -= parseFloat(innerComputedStyle.borderRightWidth) || 0;
|
|
3459
|
-
actualX -= column.arrowProposedWidth || 0; // Sort-arrow width
|
|
3460
|
-
}
|
|
3461
|
-
|
|
3462
|
-
minX = baseX + (column.ignoreMin ? 0 : this.o.minColumnWidth);
|
|
3463
|
-
if (actualX < minX) {
|
|
3464
|
-
actualX = minX;
|
|
3465
|
-
}
|
|
3466
|
-
|
|
3467
|
-
width = actualX - baseX;
|
|
3468
|
-
}
|
|
3469
|
-
|
|
3470
|
-
p.$resizer.remove();
|
|
3471
|
-
p.$resizer = null;
|
|
3472
|
-
|
|
3473
|
-
let sizeToSet = width;
|
|
3474
|
-
|
|
3475
|
-
if (column.widthMode === ColumnWidthMode.RELATIVE) {
|
|
3476
|
-
let sizeLeft = this._calculateWidthAvailableForColumns();
|
|
3477
|
-
//sizeLeft -= p.table.offsetWidth - p.table.clientWidth;
|
|
3478
|
-
|
|
3479
|
-
let totalRelativePercentage = 0;
|
|
3480
|
-
let relatives = 0;
|
|
3481
|
-
|
|
3482
|
-
for (let i = 0; i < p.visibleColumns.length; i++) {
|
|
3483
|
-
let col = p.visibleColumns[i];
|
|
3484
|
-
if (col.name === column.name) continue;
|
|
3485
|
-
|
|
3486
|
-
if (col.widthMode === ColumnWidthMode.RELATIVE) {
|
|
3487
|
-
totalRelativePercentage += col.width;
|
|
3488
|
-
relatives++;
|
|
3489
|
-
} else {
|
|
3490
|
-
sizeLeft -= col.actualWidth;
|
|
3491
|
-
}
|
|
3492
|
-
}
|
|
3493
|
-
|
|
3494
|
-
sizeLeft = Math.max(1, sizeLeft);
|
|
3495
|
-
if (sizeLeft === 1)
|
|
3496
|
-
sizeLeft = p.table.clientWidth;
|
|
3497
|
-
sizeToSet = width / sizeLeft;
|
|
3498
|
-
|
|
3499
|
-
if (relatives > 0) {
|
|
3500
|
-
// When there's more than one relative overall,
|
|
3501
|
-
// we can do relative enlarging/shrinking.
|
|
3502
|
-
// Otherwise, we can end up having a 0 width.
|
|
3503
|
-
|
|
3504
|
-
let unNormalizedSizeToSet = sizeToSet / ((1 - sizeToSet) / totalRelativePercentage);
|
|
3505
|
-
|
|
3506
|
-
totalRelativePercentage += sizeToSet;
|
|
3507
|
-
|
|
3508
|
-
// Account for relative widths scaling later
|
|
3509
|
-
if (totalRelativePercentage < 1 && o.relativeWidthGrowsToFillWidth ||
|
|
3510
|
-
totalRelativePercentage > 1 && o.relativeWidthShrinksToFillWidth) {
|
|
3511
|
-
sizeToSet = unNormalizedSizeToSet;
|
|
3512
|
-
}
|
|
3513
|
-
}
|
|
3514
|
-
|
|
3515
|
-
sizeToSet *= 100;
|
|
3516
|
-
sizeToSet += '%';
|
|
3517
|
-
}
|
|
3518
|
-
|
|
3519
|
-
this.setColumnWidth(column.name, sizeToSet);
|
|
3520
|
-
}
|
|
3521
|
-
};
|
|
3522
|
-
|
|
3523
|
-
/**
|
|
3524
|
-
* @private
|
|
3525
|
-
* @param {jQuery_Event} event event
|
|
3526
|
-
*/
|
|
3527
|
-
DGTable.prototype._onDragEnterColumnHeader = function (event) {
|
|
3528
|
-
let that = this,
|
|
3529
|
-
o = that.o,
|
|
3530
|
-
p = that.p;
|
|
3531
|
-
|
|
3532
|
-
if (o.movableColumns) {
|
|
3533
|
-
let dataTransferred = event.originalEvent.dataTransfer.getData('text');
|
|
3534
|
-
if (dataTransferred) {
|
|
3535
|
-
dataTransferred = JSON.parse(dataTransferred);
|
|
3536
|
-
} else
|
|
3537
|
-
{
|
|
3538
|
-
dataTransferred = null; // WebKit does not provide the dataTransfer on dragenter?..
|
|
3539
|
-
}
|
|
3540
|
-
|
|
3541
|
-
let $headerCell = $(event.target).closest('div.' + o.tableClassName + '-header-cell,div.' + o.cellPreviewClassName);
|
|
3542
|
-
if (!dataTransferred ||
|
|
3543
|
-
p.dragId === dataTransferred.dragId && $headerCell['columnName'] !== dataTransferred.column) {
|
|
3544
|
-
|
|
3545
|
-
let column = p.columns.get($headerCell[0]['columnName']);
|
|
3546
|
-
if (column && (column.movable || column !== p.visibleColumns[0])) {
|
|
3547
|
-
$($headerCell).addClass('drag-over');
|
|
3548
|
-
}
|
|
3549
|
-
}
|
|
3550
|
-
}
|
|
3551
|
-
};
|
|
3552
|
-
|
|
3553
|
-
/**
|
|
3554
|
-
* @private
|
|
3555
|
-
* @param {jQuery_Event} event event
|
|
3556
|
-
*/
|
|
3557
|
-
DGTable.prototype._onDragOverColumnHeader = function (event) {
|
|
3558
|
-
event.preventDefault();
|
|
3559
|
-
};
|
|
3560
|
-
|
|
3561
|
-
/**
|
|
3562
|
-
* @private
|
|
3563
|
-
* @param {jQuery_Event} event event
|
|
3564
|
-
*/
|
|
3565
|
-
DGTable.prototype._onDragLeaveColumnHeader = function (event) {
|
|
3566
|
-
let o = this.o;
|
|
3567
|
-
let $headerCell = $(event.target).closest('div.' + o.tableClassName + '-header-cell,div.' + o.cellPreviewClassName);
|
|
3568
|
-
if (!$($headerCell[0].firstChild).
|
|
3569
|
-
has(event.originalEvent.relatedTarget).length) {
|
|
3570
|
-
$headerCell.removeClass('drag-over');
|
|
3571
|
-
}
|
|
3572
|
-
};
|
|
3573
|
-
|
|
3574
|
-
/**
|
|
3575
|
-
* @private
|
|
3576
|
-
* @param {jQuery_Event} event event
|
|
3577
|
-
*/
|
|
3578
|
-
DGTable.prototype._onDropColumnHeader = function (event) {
|
|
3579
|
-
event.preventDefault();
|
|
3580
|
-
|
|
3581
|
-
let that = this,
|
|
3582
|
-
o = that.o,
|
|
3583
|
-
p = that.p;
|
|
3584
|
-
|
|
3585
|
-
let dataTransferred = JSON.parse(event.originalEvent.dataTransfer.getData('text'));
|
|
3586
|
-
let $headerCell = $(event.target).closest('div.' + o.tableClassName + '-header-cell,div.' + o.cellPreviewClassName);
|
|
3587
|
-
if (o.movableColumns && dataTransferred.dragId === p.dragId) {
|
|
3588
|
-
let srcColName = dataTransferred.column,
|
|
3589
|
-
destColName = $headerCell[0]['columnName'],
|
|
3590
|
-
srcCol = p.columns.get(srcColName),
|
|
3591
|
-
destCol = p.columns.get(destColName);
|
|
3592
|
-
if (srcCol && destCol && srcCol.movable && (destCol.movable || destCol !== p.visibleColumns[0])) {
|
|
3593
|
-
this.moveColumn(srcColName, destColName);
|
|
3594
|
-
}
|
|
3595
|
-
}
|
|
3596
|
-
$($headerCell).removeClass('drag-over');
|
|
3597
|
-
};
|
|
3598
|
-
|
|
3599
|
-
/**
|
|
3600
|
-
* @private
|
|
3601
|
-
* @returns {DGTable} self
|
|
3602
|
-
*/
|
|
3603
|
-
DGTable.prototype._clearSortArrows = function () {
|
|
3604
|
-
|
|
3605
|
-
let that = this,
|
|
3606
|
-
p = that.p;
|
|
3607
|
-
|
|
3608
|
-
if (p.$table) {
|
|
3609
|
-
let tableClassName = this.o.tableClassName;
|
|
3610
|
-
let sortedColumns = p.$headerRow.find('>div.' + tableClassName + '-header-cell.sorted');
|
|
3611
|
-
let arrows = sortedColumns.find('>div>.sort-arrow');
|
|
3612
|
-
arrows.each((_, arrow) => {
|
|
3613
|
-
let col = p.columns.get(arrow.parentNode.parentNode['columnName']);
|
|
3614
|
-
if (col) {
|
|
3615
|
-
col.arrowProposedWidth = 0;
|
|
3616
|
-
}
|
|
3617
|
-
});
|
|
3618
|
-
arrows.remove();
|
|
3619
|
-
sortedColumns.removeClass('sorted').removeClass('desc');
|
|
3620
|
-
}
|
|
3621
|
-
return this;
|
|
3622
|
-
};
|
|
3623
|
-
|
|
3624
|
-
/**
|
|
3625
|
-
* @private
|
|
3626
|
-
* @param {string} column the name of the sort column
|
|
3627
|
-
* @param {boolean} descending table is sorted descending
|
|
3628
|
-
* @returns {DGTable} self
|
|
3629
|
-
*/
|
|
3630
|
-
DGTable.prototype._showSortArrow = function (column, descending) {
|
|
3631
|
-
|
|
3632
|
-
let that = this,
|
|
3633
|
-
p = that.p;
|
|
3634
|
-
|
|
3635
|
-
let col = p.columns.get(column);
|
|
3636
|
-
if (!col) return false;
|
|
3637
|
-
|
|
3638
|
-
let arrow = createElement('span');
|
|
3639
|
-
arrow.className = 'sort-arrow';
|
|
3640
|
-
|
|
3641
|
-
if (col.element) {
|
|
3642
|
-
col.element.addClass(descending ? 'sorted desc' : 'sorted');
|
|
3643
|
-
col.element[0].firstChild.insertBefore(arrow, col.element[0].firstChild.firstChild);
|
|
3644
|
-
}
|
|
3645
|
-
|
|
3646
|
-
if (col.widthMode !== ColumnWidthMode.RELATIVE && this.o.adjustColumnWidthForSortArrow) {
|
|
3647
|
-
col.arrowProposedWidth = arrow.scrollWidth + (parseFloat($(arrow).css('margin-right')) || 0) + (parseFloat($(arrow).css('margin-left')) || 0);
|
|
3648
|
-
}
|
|
3649
|
-
|
|
3650
|
-
return this;
|
|
3651
|
-
};
|
|
3652
|
-
|
|
3653
|
-
/**
|
|
3654
|
-
* @private
|
|
3655
|
-
* @param {number} cellIndex index of the column in the DOM
|
|
3656
|
-
* @returns {DGTable} self
|
|
3657
|
-
*/
|
|
3658
|
-
DGTable.prototype._resizeColumnElements = function (cellIndex) {
|
|
3659
|
-
|
|
3660
|
-
let that = this,
|
|
3661
|
-
p = that.p;
|
|
3662
|
-
|
|
3663
|
-
let headerCells = p.$headerRow.find('div.' + this.o.tableClassName + '-header-cell');
|
|
3664
|
-
let col = p.columns.get(headerCells[cellIndex]['columnName']);
|
|
3665
|
-
|
|
3666
|
-
if (col) {
|
|
3667
|
-
headerCells[cellIndex].style.width = (col.actualWidthConsideringScrollbarWidth || col.actualWidth) + 'px';
|
|
3668
|
-
|
|
3669
|
-
let width = (col.actualWidthConsideringScrollbarWidth || col.actualWidth) + 'px';
|
|
3670
|
-
let tbodyChildren = p.tbody.childNodes;
|
|
3671
|
-
for (let i = 0, count = tbodyChildren.length; i < count; i++) {
|
|
3672
|
-
let rowEl = tbodyChildren[i];
|
|
3673
|
-
if (rowEl.nodeType !== 1) continue;
|
|
3674
|
-
rowEl.childNodes[cellIndex].style.width = width;
|
|
3675
|
-
}
|
|
3676
|
-
}
|
|
3677
|
-
|
|
3678
|
-
return this;
|
|
3679
|
-
};
|
|
3680
|
-
|
|
3681
|
-
/**
|
|
3682
|
-
* @returns {DGTable} self
|
|
3683
|
-
* */
|
|
3684
|
-
DGTable.prototype._destroyHeaderCells = function () {
|
|
3685
|
-
|
|
3686
|
-
let that = this,
|
|
3687
|
-
o = that.o,
|
|
3688
|
-
p = that.p;
|
|
3689
|
-
|
|
3690
|
-
if (p.$headerRow) {
|
|
3691
|
-
this.trigger('headerrowdestroy', p.headerRow);
|
|
3692
|
-
p.$headerRow.find('div.' + o.tableClassName + '-header-cell').remove();
|
|
3693
|
-
p.$headerRow = null;
|
|
3694
|
-
p.headerRow = null;
|
|
3695
|
-
}
|
|
3696
|
-
return this;
|
|
3697
|
-
};
|
|
3698
|
-
|
|
3699
|
-
/**
|
|
3700
|
-
* @private
|
|
3701
|
-
* @returns {DGTable} self
|
|
3702
|
-
*/
|
|
3703
|
-
DGTable.prototype._renderSkeletonBase = function () {
|
|
3704
|
-
let that = this,
|
|
3705
|
-
p = that.p,
|
|
3706
|
-
o = that.o;
|
|
3707
|
-
|
|
3708
|
-
// Clean up old elements
|
|
3709
|
-
|
|
3710
|
-
p.virtualListHelper?.destroy();
|
|
3711
|
-
p.virtualListHelper = null;
|
|
3712
|
-
|
|
3713
|
-
if (p.$table && o.virtualTable) {
|
|
3714
|
-
p.$table.remove();
|
|
3715
|
-
p.$table = p.table = p.$tbody = p.tbody = null;
|
|
3716
|
-
}
|
|
3717
|
-
|
|
3718
|
-
that._destroyHeaderCells();
|
|
3719
|
-
p.currentTouchId = null;
|
|
3720
|
-
if (p.$header) {
|
|
3721
|
-
p.$header.remove();
|
|
3722
|
-
}
|
|
3723
|
-
|
|
3724
|
-
// Create new base elements
|
|
3725
|
-
let tableClassName = o.tableClassName,
|
|
3726
|
-
header = createElement('div'),
|
|
3727
|
-
$header = $(header),
|
|
3728
|
-
headerRow = createElement('div'),
|
|
3729
|
-
$headerRow = $(headerRow);
|
|
3730
|
-
|
|
3731
|
-
header.className = tableClassName + '-header';
|
|
3732
|
-
headerRow.className = tableClassName + '-header-row';
|
|
3733
|
-
|
|
3734
|
-
p.$header = $header;
|
|
3735
|
-
p.header = header;
|
|
3736
|
-
p.$headerRow = $headerRow;
|
|
3737
|
-
p.headerRow = headerRow;
|
|
3738
|
-
$headerRow.appendTo(p.$header);
|
|
3739
|
-
$header.prependTo(this.$el);
|
|
3740
|
-
|
|
3741
|
-
relativizeElement(that.$el);
|
|
3742
|
-
|
|
3743
|
-
if (o.width === DGTable.Width.SCROLL) {
|
|
3744
|
-
this.el.style.overflow = 'hidden';
|
|
3745
|
-
} else {
|
|
3746
|
-
this.el.style.overflow = '';
|
|
3747
|
-
}
|
|
3748
|
-
|
|
3749
|
-
if (!o.height && o.virtualTable) {
|
|
3750
|
-
o.height = Css_js.getElementHeight(this.$el[0], true);
|
|
3751
|
-
}
|
|
3752
|
-
|
|
3753
|
-
return this;
|
|
3754
|
-
};
|
|
3755
|
-
|
|
3756
|
-
/**
|
|
3757
|
-
* @private
|
|
3758
|
-
* @returns {DGTable} self
|
|
3759
|
-
*/
|
|
3760
|
-
DGTable.prototype._renderSkeletonHeaderCells = function () {
|
|
3761
|
-
let that = this,
|
|
3762
|
-
p = that.p,
|
|
3763
|
-
o = that.o;
|
|
3764
|
-
|
|
3765
|
-
let allowCellPreview = o.allowCellPreview,
|
|
3766
|
-
allowHeaderCellPreview = o.allowHeaderCellPreview;
|
|
3767
|
-
|
|
3768
|
-
let tableClassName = o.tableClassName,
|
|
3769
|
-
headerCellClassName = tableClassName + '-header-cell',
|
|
3770
|
-
headerRow = p.headerRow;
|
|
3771
|
-
|
|
3772
|
-
let ieDragDropHandler;
|
|
3773
|
-
if (hasIeDragAndDropBug) {
|
|
3774
|
-
ieDragDropHandler = function (evt) {
|
|
3775
|
-
evt.preventDefault();
|
|
3776
|
-
this.dragDrop();
|
|
3777
|
-
return false;
|
|
3778
|
-
};
|
|
3779
|
-
}
|
|
3780
|
-
|
|
3781
|
-
let preventDefault = function (event) {event.preventDefault();};
|
|
3782
|
-
|
|
3783
|
-
// Create header cells
|
|
3784
|
-
for (let i = 0; i < p.visibleColumns.length; i++) {
|
|
3785
|
-
let column = p.visibleColumns[i];
|
|
3786
|
-
if (column.visible) {
|
|
3787
|
-
let cell = createElement('div');
|
|
3788
|
-
let $cell = $(cell);
|
|
3789
|
-
cell.draggable = true;
|
|
3790
|
-
cell.className = headerCellClassName;
|
|
3791
|
-
cell.style.width = column.actualWidth + 'px';
|
|
3792
|
-
if (o.sortableColumns && column.sortable) {
|
|
3793
|
-
cell.className += ' sortable';
|
|
3794
|
-
}
|
|
3795
|
-
cell['columnName'] = column.name;
|
|
3796
|
-
cell.setAttribute('data-column', column.name);
|
|
3797
|
-
|
|
3798
|
-
let cellInside = createElement('div');
|
|
3799
|
-
cellInside.innerHTML = o.headerCellFormatter(column.label, column.name);
|
|
3800
|
-
cell.appendChild(cellInside);
|
|
3801
|
-
if (allowCellPreview && allowHeaderCellPreview) {
|
|
3802
|
-
p._bindCellHoverIn(cell);
|
|
3803
|
-
}
|
|
3804
|
-
headerRow.appendChild(cell);
|
|
3805
|
-
|
|
3806
|
-
p.visibleColumns[i].element = $cell;
|
|
3807
|
-
|
|
3808
|
-
$cell.on('mousedown.dgtable', that._onMouseDownColumnHeader.bind(that)).
|
|
3809
|
-
on('mousemove.dgtable', that._onMouseMoveColumnHeader.bind(that)).
|
|
3810
|
-
on('mouseup.dgtable', that._onMouseUpColumnHeader.bind(that)).
|
|
3811
|
-
on('mouseleave.dgtable', that._onMouseLeaveColumnHeader.bind(that)).
|
|
3812
|
-
on('touchstart.dgtable', that._onTouchStartColumnHeader.bind(that)).
|
|
3813
|
-
on('dragstart.dgtable', that._onStartDragColumnHeader.bind(that)).
|
|
3814
|
-
on('click.dgtable', that._onClickColumnHeader.bind(that)).
|
|
3815
|
-
on('contextmenu.dgtable', preventDefault);
|
|
3816
|
-
$(cellInside).
|
|
3817
|
-
on('dragenter.dgtable', that._onDragEnterColumnHeader.bind(that)).
|
|
3818
|
-
on('dragover.dgtable', that._onDragOverColumnHeader.bind(that)).
|
|
3819
|
-
on('dragleave.dgtable', that._onDragLeaveColumnHeader.bind(that)).
|
|
3820
|
-
on('drop.dgtable', that._onDropColumnHeader.bind(that));
|
|
3821
|
-
|
|
3822
|
-
if (hasIeDragAndDropBug) {
|
|
3823
|
-
$cell.on('selectstart.dgtable', ieDragDropHandler.bind(cell));
|
|
3824
|
-
}
|
|
3825
|
-
|
|
3826
|
-
// Disable these to allow our own context menu events without interruption
|
|
3827
|
-
$cell.css({ '-webkit-touch-callout': 'none', '-webkit-user-select': 'none', '-moz-user-select': 'none', '-ms-user-select': 'none', '-o-user-select': 'none', 'user-select': 'none' });
|
|
3828
|
-
}
|
|
3829
|
-
}
|
|
3830
|
-
|
|
3831
|
-
this.trigger('headerrowcreate', headerRow);
|
|
3832
|
-
|
|
3833
|
-
return this;
|
|
3834
|
-
};
|
|
3835
|
-
|
|
3836
|
-
/**
|
|
3837
|
-
* @private
|
|
3838
|
-
* @returns {DGTable} self
|
|
3839
|
-
*/
|
|
3840
|
-
DGTable.prototype._renderSkeletonBody = function () {
|
|
3841
|
-
let that = this,
|
|
3842
|
-
p = that.p,
|
|
3843
|
-
o = that.o;
|
|
3844
|
-
|
|
3845
|
-
let tableClassName = o.tableClassName;
|
|
3846
|
-
|
|
3847
|
-
// Calculate virtual row heights
|
|
3848
|
-
if (o.virtualTable && !p.virtualRowHeight) {
|
|
3849
|
-
let createDummyRow = function () {
|
|
3850
|
-
let row = createElement('div'),
|
|
3851
|
-
cell = row.appendChild(createElement('div')),
|
|
3852
|
-
cellInner = cell.appendChild(createElement('div'));
|
|
3853
|
-
row.className = tableClassName + '-row';
|
|
3854
|
-
cell.className = tableClassName + '-cell';
|
|
3855
|
-
cellInner.innerHTML = '0';
|
|
3856
|
-
row.style.visibility = 'hidden';
|
|
3857
|
-
row.style.position = 'absolute';
|
|
3858
|
-
return row;
|
|
3859
|
-
};
|
|
3860
|
-
|
|
3861
|
-
let $dummyTbody,$dummyWrapper = $('<div>').
|
|
3862
|
-
addClass(that.el.className).
|
|
3863
|
-
css({ 'z-index': -1, 'position': 'absolute', left: '0', top: '-9999px', width: '1px', overflow: 'hidden' }).
|
|
3864
|
-
append(
|
|
3865
|
-
$('<div>').addClass(tableClassName).append(
|
|
3866
|
-
$dummyTbody = $('<div>').addClass(tableClassName + '-body').css('width', 99999)
|
|
3867
|
-
)
|
|
3868
|
-
);
|
|
3869
|
-
|
|
3870
|
-
$dummyWrapper.appendTo(document.body);
|
|
3871
|
-
|
|
3872
|
-
let row1 = createDummyRow(),row2 = createDummyRow(),row3 = createDummyRow();
|
|
3873
|
-
$dummyTbody.append(row1, row2, row3);
|
|
3874
|
-
|
|
3875
|
-
p.virtualRowHeightFirst = Css_js.getElementHeight(row1, true, true, true);
|
|
3876
|
-
p.virtualRowHeight = Css_js.getElementHeight(row2, true, true, true);
|
|
3877
|
-
p.virtualRowHeightLast = Css_js.getElementHeight(row3, true, true, true);
|
|
3878
|
-
|
|
3879
|
-
$dummyWrapper.remove();
|
|
3880
|
-
}
|
|
3881
|
-
|
|
3882
|
-
// Create inner table and tbody
|
|
3883
|
-
if (!p.$table) {
|
|
3884
|
-
|
|
3885
|
-
let fragment = document.createDocumentFragment();
|
|
3886
|
-
|
|
3887
|
-
// Create the inner table element
|
|
3888
|
-
let table = createElement('div');
|
|
3889
|
-
let $table = $(table);
|
|
3890
|
-
table.className = tableClassName;
|
|
3891
|
-
|
|
3892
|
-
if (o.virtualTable) {
|
|
3893
|
-
table.className += ' virtual';
|
|
3894
|
-
}
|
|
3895
|
-
|
|
3896
|
-
let tableHeight = o.height - Css_js.getElementHeight(p.$header[0], true, true, true);
|
|
3897
|
-
if ($table.css('box-sizing') !== 'border-box') {
|
|
3898
|
-
tableHeight -= parseFloat($table.css('border-top-width')) || 0;
|
|
3899
|
-
tableHeight -= parseFloat($table.css('border-bottom-width')) || 0;
|
|
3900
|
-
tableHeight -= parseFloat($table.css('padding-top')) || 0;
|
|
3901
|
-
tableHeight -= parseFloat($table.css('padding-bottom')) || 0;
|
|
3902
|
-
}
|
|
3903
|
-
p.visibleHeight = tableHeight;
|
|
3904
|
-
table.style.height = o.height ? tableHeight + 'px' : 'auto';
|
|
3905
|
-
table.style.display = 'block';
|
|
3906
|
-
table.style.overflowY = 'auto';
|
|
3907
|
-
table.style.overflowX = o.width === DGTable.Width.SCROLL ? 'auto' : 'hidden';
|
|
3908
|
-
fragment.appendChild(table);
|
|
3909
|
-
|
|
3910
|
-
// Create the "tbody" element
|
|
3911
|
-
let tbody = createElement('div');
|
|
3912
|
-
let $tbody = $(tbody);
|
|
3913
|
-
tbody.className = o.tableClassName + '-body';
|
|
3914
|
-
tbody.style.minHeight = '1px';
|
|
3915
|
-
p.table = table;
|
|
3916
|
-
p.tbody = tbody;
|
|
3917
|
-
p.$table = $table;
|
|
3918
|
-
p.$tbody = $tbody;
|
|
3919
|
-
|
|
3920
|
-
relativizeElement($tbody);
|
|
3921
|
-
relativizeElement($table);
|
|
3922
|
-
|
|
3923
|
-
table.appendChild(tbody);
|
|
3924
|
-
that.el.appendChild(fragment);
|
|
3925
|
-
|
|
3926
|
-
this._setupVirtualTable();
|
|
3927
|
-
}
|
|
3928
|
-
|
|
3929
|
-
return this;
|
|
3930
|
-
};
|
|
3931
|
-
|
|
3932
|
-
/**
|
|
3933
|
-
* @private
|
|
3934
|
-
* @returns {DGTable} self
|
|
3935
|
-
* @deprecated
|
|
3936
|
-
*/
|
|
3937
|
-
DGTable.prototype._renderSkeleton = function () {
|
|
3938
|
-
return this;
|
|
3939
|
-
};
|
|
3940
|
-
|
|
3941
|
-
/**
|
|
3942
|
-
* @private
|
|
3943
|
-
* @returns {DGTable} self
|
|
3944
|
-
*/
|
|
3945
|
-
DGTable.prototype._updateVirtualHeight = function () {
|
|
3946
|
-
const o = this.o,p = this.p;
|
|
3947
|
-
|
|
3948
|
-
if (!p.tbody)
|
|
3949
|
-
return this;
|
|
3950
|
-
|
|
3951
|
-
if (o.virtualTable) {
|
|
3952
|
-
const virtualHeight = p.virtualListHelper.estimateFullHeight();
|
|
3953
|
-
p.lastVirtualScrollHeight = virtualHeight;
|
|
3954
|
-
p.tbody.style.height = virtualHeight + 'px';
|
|
3955
|
-
} else {
|
|
3956
|
-
p.tbody.style.height = '';
|
|
3957
|
-
}
|
|
3958
|
-
|
|
3959
|
-
return this;
|
|
3960
|
-
};
|
|
3961
|
-
|
|
3962
|
-
/**
|
|
3963
|
-
* @private
|
|
3964
|
-
* @returns {DGTable} self
|
|
3965
|
-
*/
|
|
3966
|
-
DGTable.prototype._updateLastCellWidthFromScrollbar = function (force) {
|
|
3967
|
-
|
|
3968
|
-
const p = this.p;
|
|
3969
|
-
|
|
3970
|
-
// Calculate scrollbar's width and reduce from lat column's width
|
|
3971
|
-
let scrollbarWidth = p.table.offsetWidth - p.table.clientWidth;
|
|
3972
|
-
if (scrollbarWidth !== p.scrollbarWidth || force) {
|
|
3973
|
-
p.scrollbarWidth = scrollbarWidth;
|
|
3974
|
-
for (let i = 0; i < p.columns.length; i++) {
|
|
3975
|
-
p.columns[i].actualWidthConsideringScrollbarWidth = null;
|
|
3976
|
-
}
|
|
3977
|
-
|
|
3978
|
-
if (p.scrollbarWidth > 0 && p.visibleColumns.length > 0) {
|
|
3979
|
-
// (There should always be at least 1 column visible, but just in case)
|
|
3980
|
-
let lastColIndex = p.visibleColumns.length - 1;
|
|
3981
|
-
|
|
3982
|
-
p.visibleColumns[lastColIndex].actualWidthConsideringScrollbarWidth = p.visibleColumns[lastColIndex].actualWidth - p.scrollbarWidth;
|
|
3983
|
-
let lastColWidth = p.visibleColumns[lastColIndex].actualWidthConsideringScrollbarWidth + 'px';
|
|
3984
|
-
let tbodyChildren = p.tbody.childNodes;
|
|
3985
|
-
for (let i = 0, count = tbodyChildren.length; i < count; i++) {
|
|
3986
|
-
let row = tbodyChildren[i];
|
|
3987
|
-
if (row.nodeType !== 1) continue;
|
|
3988
|
-
row.childNodes[lastColIndex].style.width = lastColWidth;
|
|
3989
|
-
}
|
|
3990
|
-
|
|
3991
|
-
p.headerRow.childNodes[lastColIndex].style.width = lastColWidth;
|
|
3992
|
-
}
|
|
3993
|
-
|
|
3994
|
-
p.notifyRendererOfColumnsConfig?.();
|
|
3995
|
-
}
|
|
3996
|
-
|
|
3997
|
-
return this;
|
|
3998
|
-
};
|
|
3999
|
-
|
|
4000
|
-
/**
|
|
4001
|
-
* Explicitly set the width of the table based on the sum of the column widths
|
|
4002
|
-
* @private
|
|
4003
|
-
* @param {boolean} parentSizeMayHaveChanged Parent size may have changed, treat rendering accordingly
|
|
4004
|
-
* @returns {DGTable} self
|
|
4005
|
-
*/
|
|
4006
|
-
DGTable.prototype._updateTableWidth = function (parentSizeMayHaveChanged) {
|
|
4007
|
-
const o = this.o,p = this.p;
|
|
4008
|
-
let width = this._calculateTbodyWidth();
|
|
4009
|
-
|
|
4010
|
-
p.tbody.style.minWidth = width + 'px';
|
|
4011
|
-
p.headerRow.style.minWidth = width + (p.scrollbarWidth || 0) + 'px';
|
|
4012
|
-
|
|
4013
|
-
p.$table.off('scroll', p.onTableScrolledHorizontallyBound);
|
|
4014
|
-
|
|
4015
|
-
if (o.width === DGTable.Width.AUTO) {
|
|
4016
|
-
// Update wrapper element's size to fully contain the table body
|
|
4017
|
-
|
|
4018
|
-
Css_js.setElementWidth(p.$table[0], Css_js.getElementWidth(p.tbody, true, true, true));
|
|
4019
|
-
Css_js.setElementWidth(this.$el[0], Css_js.getElementWidth(p.$table[0], true, true, true));
|
|
4020
|
-
|
|
4021
|
-
} else if (o.width === DGTable.Width.SCROLL) {
|
|
4022
|
-
|
|
4023
|
-
if (parentSizeMayHaveChanged) {
|
|
4024
|
-
let lastScrollTop = p.table ? p.table.scrollTop : 0,
|
|
4025
|
-
lastScrollLeft = p.table ? p.table.scrollLeft : 0;
|
|
4026
|
-
|
|
4027
|
-
// BUGFIX: Relayout before recording the widths
|
|
4028
|
-
webkitRenderBugfix(this.el);
|
|
4029
|
-
|
|
4030
|
-
p.table.scrollTop = lastScrollTop;
|
|
4031
|
-
p.table.scrollLeft = lastScrollLeft;
|
|
4032
|
-
p.header.scrollLeft = lastScrollLeft;
|
|
4033
|
-
}
|
|
4034
|
-
|
|
4035
|
-
p.$table.on('scroll', p.onTableScrolledHorizontallyBound);
|
|
4036
|
-
}
|
|
4037
|
-
|
|
4038
|
-
return this;
|
|
4039
|
-
};
|
|
4040
|
-
|
|
4041
|
-
/**
|
|
4042
|
-
* @private
|
|
4043
|
-
* @returns {boolean}
|
|
4044
|
-
*/
|
|
4045
|
-
DGTable.prototype._isTableRtl = function () {
|
|
4046
|
-
return this.p.$table.css('direction') === 'rtl';
|
|
4047
|
-
};
|
|
4048
|
-
|
|
4049
|
-
/**
|
|
4050
|
-
* @private
|
|
4051
|
-
* @param {Object} column column object
|
|
4052
|
-
* @returns {string}
|
|
4053
|
-
*/
|
|
4054
|
-
DGTable.prototype._serializeColumnWidth = function (column) {
|
|
4055
|
-
return column.widthMode === ColumnWidthMode.AUTO ? 'auto' :
|
|
4056
|
-
column.widthMode === ColumnWidthMode.RELATIVE ? column.width * 100 + '%' :
|
|
4057
|
-
column.width;
|
|
4058
|
-
};
|
|
4059
|
-
|
|
4060
|
-
/**
|
|
4061
|
-
* @private
|
|
4062
|
-
* @param {HTMLElement} el
|
|
4063
|
-
*/
|
|
4064
|
-
DGTable.prototype._cellMouseOverEvent = function (el) {
|
|
4065
|
-
const o = this.o,p = this.p;
|
|
4066
|
-
|
|
4067
|
-
let elInner = el.firstChild;
|
|
4068
|
-
|
|
4069
|
-
if (elInner.scrollWidth - elInner.clientWidth > 1 ||
|
|
4070
|
-
elInner.scrollHeight - elInner.clientHeight > 1) {
|
|
4071
|
-
|
|
4072
|
-
this.hideCellPreview();
|
|
4073
|
-
p.abortCellPreview = false;
|
|
4074
|
-
|
|
4075
|
-
let $el = $(el),$elInner = $(elInner);
|
|
4076
|
-
const rowNode = el.parentNode;
|
|
4077
|
-
let previewCell = createElement('div'),$previewCell = $(previewCell);
|
|
4078
|
-
previewCell.innerHTML = el.innerHTML;
|
|
4079
|
-
previewCell.className = o.cellPreviewClassName;
|
|
4080
|
-
|
|
4081
|
-
let isHeaderCell = $el.hasClass(o.tableClassName + '-header-cell');
|
|
4082
|
-
if (isHeaderCell) {
|
|
4083
|
-
previewCell.className += ' header';
|
|
4084
|
-
if ($el.hasClass('sortable')) {
|
|
4085
|
-
previewCell.className += ' sortable';
|
|
4086
|
-
}
|
|
4087
|
-
|
|
4088
|
-
previewCell.draggable = true;
|
|
4089
|
-
|
|
4090
|
-
$(previewCell).on('mousedown', this._onMouseDownColumnHeader.bind(this)).
|
|
4091
|
-
on('mousemove', this._onMouseMoveColumnHeader.bind(this)).
|
|
4092
|
-
on('mouseup', this._onMouseUpColumnHeader.bind(this)).
|
|
4093
|
-
on('mouseleave', this._onMouseLeaveColumnHeader.bind(this)).
|
|
4094
|
-
on('touchstart', this._onTouchStartColumnHeader.bind(this)).
|
|
4095
|
-
on('dragstart', this._onStartDragColumnHeader.bind(this)).
|
|
4096
|
-
on('click', this._onClickColumnHeader.bind(this)).
|
|
4097
|
-
on('contextmenu.dgtable', function (event) {event.preventDefault();});
|
|
4098
|
-
$(previewCell.firstChild).
|
|
4099
|
-
on('dragenter', this._onDragEnterColumnHeader.bind(this)).
|
|
4100
|
-
on('dragover', this._onDragOverColumnHeader.bind(this)).
|
|
4101
|
-
on('dragleave', this._onDragLeaveColumnHeader.bind(this)).
|
|
4102
|
-
on('drop', this._onDropColumnHeader.bind(this));
|
|
4103
|
-
|
|
4104
|
-
if (hasIeDragAndDropBug) {
|
|
4105
|
-
$(previewCell).on('selectstart', function (evt) {
|
|
4106
|
-
evt.preventDefault();
|
|
4107
|
-
this.dragDrop();
|
|
4108
|
-
return false;
|
|
4109
|
-
}.bind(previewCell));
|
|
4110
|
-
}
|
|
4111
|
-
}
|
|
4112
|
-
|
|
4113
|
-
let paddingL = parseFloat($el.css('padding-left')) || 0,
|
|
4114
|
-
paddingR = parseFloat($el.css('padding-right')) || 0,
|
|
4115
|
-
paddingT = parseFloat($el.css('padding-top')) || 0,
|
|
4116
|
-
paddingB = parseFloat($el.css('padding-bottom')) || 0;
|
|
4117
|
-
|
|
4118
|
-
let requiredWidth = elInner.scrollWidth + (el.clientWidth - elInner.offsetWidth);
|
|
4119
|
-
|
|
4120
|
-
let borderBox = $el.css('box-sizing') === 'border-box';
|
|
4121
|
-
if (borderBox) {
|
|
4122
|
-
$previewCell.css('box-sizing', 'border-box');
|
|
4123
|
-
} else {
|
|
4124
|
-
requiredWidth -= paddingL + paddingR;
|
|
4125
|
-
$previewCell.css('margin-top', parseFloat($(el).css('border-top-width')) || 0);
|
|
4126
|
-
}
|
|
4127
|
-
|
|
4128
|
-
if (!p.transparentBgColor1) {
|
|
4129
|
-
// Detect browser's transparent spec
|
|
4130
|
-
let tempDiv = document.createElement('div');
|
|
4131
|
-
tempDiv.style.backgroundColor = 'transparent';
|
|
4132
|
-
p.transparentBgColor1 = $(tempDiv).css('background-color');
|
|
4133
|
-
tempDiv.style.backgroundColor = 'rgba(0,0,0,0)';
|
|
4134
|
-
p.transparentBgColor2 = $(tempDiv).css('background-color');
|
|
4135
|
-
}
|
|
4136
|
-
|
|
4137
|
-
let css = {
|
|
4138
|
-
'box-sizing': borderBox ? 'border-box' : 'content-box',
|
|
4139
|
-
'width': requiredWidth,
|
|
4140
|
-
'min-height': Css_js.getElementHeight($el[0]),
|
|
4141
|
-
'padding-left': paddingL,
|
|
4142
|
-
'padding-right': paddingR,
|
|
4143
|
-
'padding-top': paddingT,
|
|
4144
|
-
'padding-bottom': paddingB,
|
|
4145
|
-
'overflow': 'hidden',
|
|
4146
|
-
'position': 'absolute',
|
|
4147
|
-
'z-index': '-1',
|
|
4148
|
-
'left': '0',
|
|
4149
|
-
'top': '0',
|
|
4150
|
-
'cursor': $el.css('cursor')
|
|
4151
|
-
};
|
|
4152
|
-
|
|
4153
|
-
if (css) {
|
|
4154
|
-
let bgColor = $(el).css('background-color');
|
|
4155
|
-
if (bgColor === p.transparentBgColor1 || bgColor === p.transparentBgColor2) {
|
|
4156
|
-
bgColor = $(rowNode).css('background-color');
|
|
4157
|
-
}
|
|
4158
|
-
if (bgColor === p.transparentBgColor1 || bgColor === p.transparentBgColor2) {
|
|
4159
|
-
bgColor = '#fff';
|
|
4160
|
-
}
|
|
4161
|
-
css['background-color'] = bgColor;
|
|
4162
|
-
}
|
|
4163
|
-
|
|
4164
|
-
$previewCell.css(css);
|
|
4165
|
-
|
|
4166
|
-
this.el.appendChild(previewCell);
|
|
4167
|
-
|
|
4168
|
-
$(previewCell.firstChild).css({
|
|
4169
|
-
'direction': $elInner.css('direction'),
|
|
4170
|
-
'white-space': $elInner.css('white-space')
|
|
4171
|
-
});
|
|
4172
|
-
|
|
4173
|
-
if (isHeaderCell) {
|
|
4174
|
-
// Disable these to allow our own context menu events without interruption
|
|
4175
|
-
$previewCell.css({
|
|
4176
|
-
'-webkit-touch-callout': 'none',
|
|
4177
|
-
'-webkit-user-select': 'none',
|
|
4178
|
-
'-moz-user-select': 'none',
|
|
4179
|
-
'-ms-user-select': 'none',
|
|
4180
|
-
'-o-user-select': 'none',
|
|
4181
|
-
'user-select': 'none'
|
|
4182
|
-
});
|
|
4183
|
-
}
|
|
4184
|
-
|
|
4185
|
-
previewCell['rowIndex'] = rowNode['rowIndex'];
|
|
4186
|
-
let physicalRowIndex = previewCell['physicalRowIndex'] = rowNode['physicalRowIndex'];
|
|
4187
|
-
previewCell['columnName'] = p.visibleColumns[nativeIndexOf.call(rowNode.childNodes, el)].name;
|
|
4188
|
-
|
|
4189
|
-
try {
|
|
4190
|
-
let selection = SelectionHelper.saveSelection(el);
|
|
4191
|
-
if (selection)
|
|
4192
|
-
SelectionHelper.restoreSelection(previewCell, selection);
|
|
4193
|
-
} catch (ignored) {/* we're ok with this */}
|
|
4194
|
-
|
|
4195
|
-
this.trigger(
|
|
4196
|
-
'cellpreview',
|
|
4197
|
-
previewCell.firstChild,
|
|
4198
|
-
physicalRowIndex == null ? null : physicalRowIndex,
|
|
4199
|
-
previewCell['columnName'],
|
|
4200
|
-
physicalRowIndex == null ? null : p.rows[physicalRowIndex],
|
|
4201
|
-
el
|
|
4202
|
-
);
|
|
4203
|
-
|
|
4204
|
-
if (p.abortCellPreview) {
|
|
4205
|
-
$previewCell.remove();
|
|
4206
|
-
return;
|
|
4207
|
-
}
|
|
4208
|
-
|
|
4209
|
-
if (physicalRowIndex != null) {
|
|
4210
|
-
previewCell.addEventListener('click', (event) => {
|
|
4211
|
-
this.trigger('rowclick', event,
|
|
4212
|
-
rowNode['rowIndex'], physicalRowIndex,
|
|
4213
|
-
rowNode, p.rows[physicalRowIndex]);
|
|
4214
|
-
});
|
|
4215
|
-
}
|
|
4216
|
-
|
|
4217
|
-
let $parent = this.$el;
|
|
4218
|
-
let $scrollParent = $parent[0] === window ? $(document) : $parent;
|
|
4219
|
-
|
|
4220
|
-
let offset = $el.offset();
|
|
4221
|
-
let parentOffset = $parent.offset();
|
|
4222
|
-
let rtl = $el.css('float') === 'right';
|
|
4223
|
-
let prop = rtl ? 'right' : 'left';
|
|
4224
|
-
|
|
4225
|
-
// Handle RTL, go from the other side
|
|
4226
|
-
if (rtl) {
|
|
4227
|
-
let windowWidth = $(window).width();
|
|
4228
|
-
offset.right = windowWidth - (offset.left + Css_js.getElementWidth($el[0], true, true, true));
|
|
4229
|
-
parentOffset.right = windowWidth - (parentOffset.left + Css_js.getElementWidth($parent[0], true, true, true));
|
|
4230
|
-
}
|
|
4231
|
-
|
|
4232
|
-
// If the parent has borders, then it would offset the offset...
|
|
4233
|
-
offset.left -= parseFloat($parent.css('border-left-width')) || 0;
|
|
4234
|
-
offset.right -= parseFloat($parent.css('border-right-width')) || 0;
|
|
4235
|
-
offset.top -= parseFloat($parent.css('border-top-width')) || 0;
|
|
4236
|
-
|
|
4237
|
-
// Handle border widths of the element being offset
|
|
4238
|
-
offset[prop] += parseFloat($(el).css('border-' + prop + '-width')) || 0;
|
|
4239
|
-
offset.top += parseFloat($(el).css('border-top-width')) || parseFloat($(el).css('border-bottom-width')) || 0;
|
|
4240
|
-
|
|
4241
|
-
// Subtract offsets to get offset relative to parent
|
|
4242
|
-
offset.left -= parentOffset.left;
|
|
4243
|
-
offset.right -= parentOffset.right;
|
|
4244
|
-
offset.top -= parentOffset.top;
|
|
4245
|
-
|
|
4246
|
-
// Constrain horizontally
|
|
4247
|
-
let minHorz = 0,
|
|
4248
|
-
maxHorz = $parent - Css_js.getElementWidth($previewCell[0], true, true, true);
|
|
4249
|
-
offset[prop] = offset[prop] < minHorz ?
|
|
4250
|
-
minHorz :
|
|
4251
|
-
offset[prop] > maxHorz ? maxHorz : offset[prop];
|
|
4252
|
-
|
|
4253
|
-
// Constrain vertically
|
|
4254
|
-
let totalHeight = Css_js.getElementHeight($el[0], true, true, true);
|
|
4255
|
-
let maxTop = $scrollParent.scrollTop() + Css_js.getElementHeight($parent[0], true) - totalHeight;
|
|
4256
|
-
if (offset.top > maxTop) {
|
|
4257
|
-
offset.top = Math.max(0, maxTop);
|
|
4258
|
-
}
|
|
4259
|
-
|
|
4260
|
-
// Apply css to preview cell
|
|
4261
|
-
let previewCss = {
|
|
4262
|
-
top: offset.top,
|
|
4263
|
-
'z-index': 9999
|
|
4264
|
-
};
|
|
4265
|
-
previewCss[prop] = offset[prop];
|
|
4266
|
-
|
|
4267
|
-
$previewCell.css(previewCss);
|
|
4268
|
-
|
|
4269
|
-
previewCell['__cell'] = el;
|
|
4270
|
-
p.$cellPreviewCell = $previewCell;
|
|
4271
|
-
el['__previewCell'] = previewCell;
|
|
4272
|
-
|
|
4273
|
-
p._bindCellHoverOut(el);
|
|
4274
|
-
p._bindCellHoverOut(previewCell);
|
|
4275
|
-
|
|
4276
|
-
// Avoid interfering with wheel scrolling the table
|
|
4277
|
-
$previewCell.on('wheel', () => {
|
|
4278
|
-
// Let the table naturally scroll with the wheel
|
|
4279
|
-
this.hideCellPreview();
|
|
4280
|
-
});
|
|
4281
|
-
}
|
|
4282
|
-
};
|
|
4283
|
-
|
|
4284
|
-
/**
|
|
4285
|
-
* @private
|
|
4286
|
-
* @param {HTMLElement} _el
|
|
4287
|
-
*/
|
|
4288
|
-
DGTable.prototype._cellMouseOutEvent = function (_el) {
|
|
4289
|
-
this.hideCellPreview();
|
|
4290
|
-
};
|
|
4291
|
-
|
|
4292
|
-
/**
|
|
4293
|
-
* Hides the current cell preview,
|
|
4294
|
-
* or prevents the one that is currently trying to show (in the 'cellpreview' event)
|
|
4295
|
-
* @public
|
|
4296
|
-
* @expose
|
|
4297
|
-
* @returns {DGTable} self
|
|
4298
|
-
*/
|
|
4299
|
-
DGTable.prototype.hideCellPreview = function () {
|
|
4300
|
-
const p = this.p;
|
|
4301
|
-
|
|
4302
|
-
if (p.$cellPreviewCell) {
|
|
4303
|
-
let previewCell = p.$cellPreviewCell[0];
|
|
4304
|
-
let origCell = previewCell['__cell'];
|
|
4305
|
-
let selection;
|
|
4306
|
-
|
|
4307
|
-
try {
|
|
4308
|
-
selection = SelectionHelper.saveSelection(previewCell);
|
|
4309
|
-
} catch (ignored) {/* we're ok with this */}
|
|
4310
|
-
|
|
4311
|
-
p.$cellPreviewCell.remove();
|
|
4312
|
-
p._unbindCellHoverOut(origCell);
|
|
4313
|
-
p._unbindCellHoverOut(previewCell);
|
|
4314
|
-
|
|
4315
|
-
try {
|
|
4316
|
-
if (selection)
|
|
4317
|
-
SelectionHelper.restoreSelection(origCell, selection);
|
|
4318
|
-
} catch (ignored) {/* we're ok with this */}
|
|
4319
|
-
|
|
4320
|
-
this.trigger('cellpreviewdestroy', previewCell.firstChild, previewCell['physicalRowIndex'], previewCell['columnName'], origCell);
|
|
4321
|
-
|
|
4322
|
-
origCell['__previewCell'] = null;
|
|
4323
|
-
previewCell['__cell'] = null;
|
|
4324
|
-
|
|
4325
|
-
p.$cellPreviewCell = null;
|
|
4326
|
-
p.abortCellPreview = false;
|
|
4327
|
-
} else {
|
|
4328
|
-
p.abortCellPreview = true;
|
|
4329
|
-
}
|
|
4330
|
-
|
|
4331
|
-
return this;
|
|
4332
|
-
};
|
|
4333
|
-
|
|
4334
|
-
// It's a shame the Google Closure Compiler does not support exposing a nested @param
|
|
4335
|
-
|
|
4336
|
-
/**
|
|
4337
|
-
* @typedef {Object} SERIALIZED_COLUMN
|
|
4338
|
-
* @property {number|null|undefined} [order=0]
|
|
4339
|
-
* @property {string|null|undefined} [width='auto']
|
|
4340
|
-
* @property {boolean|null|undefined} [visible=true]
|
|
4341
|
-
* */
|
|
4342
|
-
|
|
4343
|
-
/**
|
|
4344
|
-
* @typedef {Object} SERIALIZED_COLUMN_SORT
|
|
4345
|
-
* @property {string|null|undefined} [column='']
|
|
4346
|
-
* @property {boolean|null|undefined} [descending=false]
|
|
4347
|
-
* */
|
|
4348
|
-
|
|
4349
|
-
/**
|
|
4350
|
-
* @enum {ColumnWidthMode|number|undefined}
|
|
4351
|
-
* @const
|
|
4352
|
-
* @typedef {ColumnWidthMode}
|
|
4353
|
-
*/
|
|
4354
|
-
const ColumnWidthMode = {
|
|
4355
|
-
/** @const*/AUTO: 0,
|
|
4356
|
-
/** @const*/ABSOLUTE: 1,
|
|
4357
|
-
/** @const*/RELATIVE: 2
|
|
4358
|
-
};
|
|
4359
|
-
|
|
4360
|
-
/**
|
|
4361
|
-
* @enum {DGTable.Width|string|undefined}
|
|
4362
|
-
* @const
|
|
4363
|
-
* @typedef {DGTable.Width}
|
|
4364
|
-
*/
|
|
4365
|
-
DGTable.Width = {
|
|
4366
|
-
/** @const*/NONE: 'none',
|
|
4367
|
-
/** @const*/AUTO: 'auto',
|
|
4368
|
-
/** @const*/SCROLL: 'scroll'
|
|
4369
|
-
};
|
|
4370
|
-
|
|
4371
|
-
/**
|
|
4372
|
-
* @expose
|
|
4373
|
-
* @typedef {Object} COLUMN_SORT_OPTIONS
|
|
4374
|
-
* @property {string|null|undefined} column
|
|
4375
|
-
* @property {boolean|null|undefined} [descending=false]
|
|
4376
|
-
* */
|
|
4377
|
-
|
|
4378
|
-
/**
|
|
4379
|
-
* @expose
|
|
4380
|
-
* @typedef {Object} COLUMN_OPTIONS
|
|
4381
|
-
* @property {string|null|undefined} width
|
|
4382
|
-
* @property {string|null|undefined} name
|
|
4383
|
-
* @property {string|null|undefined} label
|
|
4384
|
-
* @property {string|null|undefined} dataPath - defaults to `name`
|
|
4385
|
-
* @property {string|null|undefined} comparePath - defaults to `dataPath`
|
|
4386
|
-
* @property {number|string|null|undefined} comparePath
|
|
4387
|
-
* @property {boolean|null|undefined} [resizable=true]
|
|
4388
|
-
* @property {boolean|null|undefined} [movable=true]
|
|
4389
|
-
* @property {boolean|null|undefined} [sortable=true]
|
|
4390
|
-
* @property {boolean|null|undefined} [visible=true]
|
|
4391
|
-
* @property {string|null|undefined} [cellClasses]
|
|
4392
|
-
* @property {boolean|null|undefined} [ignoreMin=false]
|
|
4393
|
-
* */
|
|
4394
|
-
|
|
4395
|
-
/**
|
|
4396
|
-
* @typedef {Object} DGTable.Options
|
|
4397
|
-
* @property {COLUMN_OPTIONS[]} [columns]
|
|
4398
|
-
* @property {number} [height]
|
|
4399
|
-
* @property {DGTable.Width} [width]
|
|
4400
|
-
* @property {boolean|null|undefined} [virtualTable=true]
|
|
4401
|
-
* @property {number|null|undefined} [estimatedRowHeight=40]
|
|
4402
|
-
* @property {boolean|null|undefined} [resizableColumns=true]
|
|
4403
|
-
* @property {boolean|null|undefined} [movableColumns=true]
|
|
4404
|
-
* @property {number|null|undefined} [sortableColumns=1]
|
|
4405
|
-
* @property {boolean|null|undefined} [adjustColumnWidthForSortArrow=true]
|
|
4406
|
-
* @property {boolean|null|undefined} [relativeWidthGrowsToFillWidth=true]
|
|
4407
|
-
* @property {boolean|null|undefined} [relativeWidthShrinksToFillWidth=false]
|
|
4408
|
-
* @property {boolean|null|undefined} [convertColumnWidthsToRelative=false]
|
|
4409
|
-
* @property {boolean|null|undefined} [autoFillTableWidth=false]
|
|
4410
|
-
* @property {boolean|null|undefined} [allowCancelSort=true]
|
|
4411
|
-
* @property {string|null|undefined} [cellClasses]
|
|
4412
|
-
* @property {string|string[]|COLUMN_SORT_OPTIONS|COLUMN_SORT_OPTIONS[]} [sortColumn]
|
|
4413
|
-
* @property {Function|null|undefined} [cellFormatter=null]
|
|
4414
|
-
* @property {Function|null|undefined} [headerCellFormatter=null]
|
|
4415
|
-
* @property {number|null|undefined} [rowsBufferSize=10]
|
|
4416
|
-
* @property {number|null|undefined} [minColumnWidth=35]
|
|
4417
|
-
* @property {number|null|undefined} [resizeAreaWidth=8]
|
|
4418
|
-
* @property {function(columnName: string, descending: boolean, defaultComparator: function(a,b):number):{function(a,b):number}} [onComparatorRequired]
|
|
4419
|
-
* @property {function(data: any[], sort: function(any[]):any[]):any[]} [customSortingProvider]
|
|
4420
|
-
* @property {string|null|undefined} [resizerClassName=undefined]
|
|
4421
|
-
* @property {string|null|undefined} [tableClassName=undefined]
|
|
4422
|
-
* @property {boolean|null|undefined} [allowCellPreview=true]
|
|
4423
|
-
* @property {boolean|null|undefined} [allowHeaderCellPreview=true]
|
|
4424
|
-
* @property {string|null|undefined} [cellPreviewClassName=undefined]
|
|
4425
|
-
* @property {boolean|null|undefined} [cellPreviewAutoBackground=true]
|
|
4426
|
-
* @property {Element|null|undefined} [el=undefined]
|
|
4427
|
-
* @property {string|null|undefined} [className=undefined]
|
|
4428
|
-
* @property {Function|null|undefined} [filter=undefined]
|
|
4429
|
-
* */
|
|
4430
|
-
|
|
4431
|
-
/**
|
|
4432
|
-
* @typedef {{
|
|
4433
|
-
* currentTarget: Element,
|
|
4434
|
-
* data: Object.<string, *>,
|
|
4435
|
-
* delegateTarget: Element,
|
|
4436
|
-
* isDefaultPrevented: boolean,
|
|
4437
|
-
* isImmediatePropagationStopped: boolean,
|
|
4438
|
-
* isPropagationStopped: boolean,
|
|
4439
|
-
* namespace: string,
|
|
4440
|
-
* originalEvent: MouseEvent|TouchEvent|Event,
|
|
4441
|
-
* pageX: number,
|
|
4442
|
-
* pageY: number,
|
|
4443
|
-
* preventDefault: Function,
|
|
4444
|
-
* props: Object.<string, *>,
|
|
4445
|
-
* relatedTarget: Element,
|
|
4446
|
-
* result: *,
|
|
4447
|
-
* stopImmediatePropagation: Function,
|
|
4448
|
-
* stopPropagation: Function,
|
|
4449
|
-
* target: Element,
|
|
4450
|
-
* timeStamp: number,
|
|
4451
|
-
* type: string,
|
|
4452
|
-
* which: number
|
|
4453
|
-
* }} jQuery_Event
|
|
4454
|
-
* */
|
|
4455
|
-
|
|
4456
|
-
if (!$.controls) {
|
|
4457
|
-
$.controls = {};
|
|
4458
|
-
}
|
|
4459
|
-
|
|
4460
|
-
$.controls.dgtable = DGTable;
|
|
4461
|
-
|
|
4462
|
-
return DGTable;
|
|
4463
|
-
|
|
4464
|
-
}));
|
|
4465
|
-
|
|
4466
|
-
//# sourceMappingURL=jquery.dgtable.umd.js.map
|