px-jspreadsheet-ce 0.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/LICENSE +21 -0
- package/README.md +292 -0
- package/dist/index.d.ts +2382 -0
- package/dist/index.js +11286 -0
- package/dist/index.js.map +1 -0
- package/dist/jspreadsheet.css +723 -0
- package/dist/jspreadsheet.themes.css +104 -0
- package/package.json +57 -0
- package/src/index.js +95 -0
- package/src/test.js +50 -0
- package/src/utils/cells.js +36 -0
- package/src/utils/columns.js +742 -0
- package/src/utils/comments.js +87 -0
- package/src/utils/config.js +46 -0
- package/src/utils/copyPaste.js +438 -0
- package/src/utils/data.js +419 -0
- package/src/utils/dispatch.js +115 -0
- package/src/utils/download.js +38 -0
- package/src/utils/editor.js +430 -0
- package/src/utils/events.js +1639 -0
- package/src/utils/factory.js +216 -0
- package/src/utils/filter.js +128 -0
- package/src/utils/footer.js +51 -0
- package/src/utils/freeze.js +19 -0
- package/src/utils/headers.js +74 -0
- package/src/utils/helpers.js +409 -0
- package/src/utils/history.js +336 -0
- package/src/utils/internal.js +1299 -0
- package/src/utils/internalHelpers.js +96 -0
- package/src/utils/keys.js +406 -0
- package/src/utils/lazyLoading.js +143 -0
- package/src/utils/libraryBase.js +5 -0
- package/src/utils/merges.js +275 -0
- package/src/utils/meta.js +81 -0
- package/src/utils/orderBy.js +185 -0
- package/src/utils/pagination.js +181 -0
- package/src/utils/rows.js +624 -0
- package/src/utils/search.js +83 -0
- package/src/utils/selection.js +744 -0
- package/src/utils/style.js +147 -0
- package/src/utils/toolbar.js +566 -0
- package/src/utils/version.js +9 -0
- package/src/utils/worksheets.js +731 -0
- package/src/webcomponent.js +59 -0
|
@@ -0,0 +1,1299 @@
|
|
|
1
|
+
import jSuites from 'jsuites';
|
|
2
|
+
import formula from '@jspreadsheet/formula';
|
|
3
|
+
|
|
4
|
+
import dispatch from './dispatch.js';
|
|
5
|
+
import { refreshSelection, updateCornerPosition } from './selection.js';
|
|
6
|
+
import { getCellNameFromCoords, getColumnName } from './helpers.js';
|
|
7
|
+
import { updateMeta } from './meta.js';
|
|
8
|
+
import { getFreezeWidth } from './freeze.js';
|
|
9
|
+
import { updatePagination } from './pagination.js';
|
|
10
|
+
import { setFooter } from './footer.js';
|
|
11
|
+
import { getColumnNameFromId, getIdFromColumnName, getFreezeColumnLeft, getFreezeRowTop } from './internalHelpers.js';
|
|
12
|
+
|
|
13
|
+
export const updateTable = function () {
|
|
14
|
+
const obj = this;
|
|
15
|
+
|
|
16
|
+
// Check for spare
|
|
17
|
+
if (obj.options.minSpareRows > 0) {
|
|
18
|
+
let numBlankRows = 0;
|
|
19
|
+
for (let j = obj.rows.length - 1; j >= 0; j--) {
|
|
20
|
+
let test = false;
|
|
21
|
+
for (let i = 0; i < obj.headers.length; i++) {
|
|
22
|
+
if (obj.options.data[j][i]) {
|
|
23
|
+
test = true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (test) {
|
|
27
|
+
break;
|
|
28
|
+
} else {
|
|
29
|
+
numBlankRows++;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (obj.options.minSpareRows - numBlankRows > 0) {
|
|
34
|
+
obj.insertRow(obj.options.minSpareRows - numBlankRows);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (obj.options.minSpareCols > 0) {
|
|
39
|
+
let numBlankCols = 0;
|
|
40
|
+
for (let i = obj.headers.length - 1; i >= 0; i--) {
|
|
41
|
+
let test = false;
|
|
42
|
+
for (let j = 0; j < obj.rows.length; j++) {
|
|
43
|
+
if (obj.options.data[j][i]) {
|
|
44
|
+
test = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (test) {
|
|
48
|
+
break;
|
|
49
|
+
} else {
|
|
50
|
+
numBlankCols++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (obj.options.minSpareCols - numBlankCols > 0) {
|
|
55
|
+
obj.insertColumn(obj.options.minSpareCols - numBlankCols);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Update footers
|
|
60
|
+
if (obj.options.footers) {
|
|
61
|
+
setFooter.call(obj);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (obj.options.columns.length < obj.options.minDimensions[0]) {
|
|
65
|
+
obj.options.minDimensions[0] = obj.options.columns.length;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Update corner position
|
|
69
|
+
setTimeout(function () {
|
|
70
|
+
updateCornerPosition.call(obj);
|
|
71
|
+
}, 0);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Trying to extract a number from a string
|
|
76
|
+
*/
|
|
77
|
+
const parseNumber = function (value, i, j) {
|
|
78
|
+
const obj = this;
|
|
79
|
+
|
|
80
|
+
let config = obj.options.columns && obj.options.columns[i];
|
|
81
|
+
|
|
82
|
+
const cellName = getCellNameFromCoords(i, j);
|
|
83
|
+
const cells = obj.options.cells;
|
|
84
|
+
if (typeof cells === 'object' && cells[cellName]) {
|
|
85
|
+
config = cells[cellName];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Decimal point
|
|
89
|
+
const decimal = config && config.decimal ? config : '.';
|
|
90
|
+
|
|
91
|
+
// Parse both parts of the number
|
|
92
|
+
let number = '' + value;
|
|
93
|
+
number = number.split(decimal);
|
|
94
|
+
number[0] = number[0].match(/[+-]?[0-9]/g);
|
|
95
|
+
if (number[0]) {
|
|
96
|
+
number[0] = number[0].join('');
|
|
97
|
+
}
|
|
98
|
+
if (number[1]) {
|
|
99
|
+
number[1] = number[1].match(/[0-9]*/g).join('');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Is a valid number
|
|
103
|
+
if (number[0] && Number.isInteger(Number(number[0]))) {
|
|
104
|
+
if (!number[1]) {
|
|
105
|
+
value = Number(number[0] + '.00');
|
|
106
|
+
} else {
|
|
107
|
+
value = Number(number[0] + '.' + number[1]);
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
value = null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return value;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Parse formulas
|
|
118
|
+
*/
|
|
119
|
+
export const executeFormula = function (expression, x, y) {
|
|
120
|
+
const obj = this;
|
|
121
|
+
|
|
122
|
+
const formulaResults = [];
|
|
123
|
+
const formulaLoopProtection = [];
|
|
124
|
+
|
|
125
|
+
// Execute formula with loop protection
|
|
126
|
+
const execute = function (expression, x, y) {
|
|
127
|
+
// Parent column identification
|
|
128
|
+
const parentId = getColumnNameFromId([x, y]);
|
|
129
|
+
|
|
130
|
+
// Code protection
|
|
131
|
+
if (formulaLoopProtection[parentId]) {
|
|
132
|
+
console.error('Reference loop detected');
|
|
133
|
+
return '#ERROR';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
formulaLoopProtection[parentId] = true;
|
|
137
|
+
|
|
138
|
+
// Convert range tokens
|
|
139
|
+
const tokensUpdate = function (tokens) {
|
|
140
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
141
|
+
const f = [];
|
|
142
|
+
const token = tokens[index].split(':');
|
|
143
|
+
const e1 = getIdFromColumnName(token[0], true);
|
|
144
|
+
const e2 = getIdFromColumnName(token[1], true);
|
|
145
|
+
|
|
146
|
+
let x1, x2;
|
|
147
|
+
|
|
148
|
+
if (e1[0] <= e2[0]) {
|
|
149
|
+
x1 = e1[0];
|
|
150
|
+
x2 = e2[0];
|
|
151
|
+
} else {
|
|
152
|
+
x1 = e2[0];
|
|
153
|
+
x2 = e1[0];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let y1, y2;
|
|
157
|
+
|
|
158
|
+
if (e1[1] <= e2[1]) {
|
|
159
|
+
y1 = e1[1];
|
|
160
|
+
y2 = e2[1];
|
|
161
|
+
} else {
|
|
162
|
+
y1 = e2[1];
|
|
163
|
+
y2 = e1[1];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (let j = y1; j <= y2; j++) {
|
|
167
|
+
for (let i = x1; i <= x2; i++) {
|
|
168
|
+
f.push(getColumnNameFromId([i, j]));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
expression = expression.replace(tokens[index], f.join(','));
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// Range with $ remove $
|
|
177
|
+
expression = expression.replace(/\$?([A-Z]+)\$?([0-9]+)/g, '$1$2');
|
|
178
|
+
|
|
179
|
+
let tokens = expression.match(/([A-Z]+[0-9]+):([A-Z]+[0-9]+)/g);
|
|
180
|
+
if (tokens && tokens.length) {
|
|
181
|
+
tokensUpdate(tokens);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Get tokens
|
|
185
|
+
tokens = expression.match(/([A-Z]+[0-9]+)/g);
|
|
186
|
+
|
|
187
|
+
// Direct self-reference protection
|
|
188
|
+
if (tokens && tokens.indexOf(parentId) > -1) {
|
|
189
|
+
console.error('Self Reference detected');
|
|
190
|
+
return '#ERROR';
|
|
191
|
+
} else {
|
|
192
|
+
// Expressions to be used in the parsing
|
|
193
|
+
const formulaExpressions = {};
|
|
194
|
+
|
|
195
|
+
if (tokens) {
|
|
196
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
197
|
+
// Keep chain
|
|
198
|
+
if (!obj.formula[tokens[i]]) {
|
|
199
|
+
obj.formula[tokens[i]] = [];
|
|
200
|
+
}
|
|
201
|
+
// Is already in the register
|
|
202
|
+
if (obj.formula[tokens[i]].indexOf(parentId) < 0) {
|
|
203
|
+
obj.formula[tokens[i]].push(parentId);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Do not calculate again
|
|
207
|
+
if (eval('typeof(' + tokens[i] + ') == "undefined"')) {
|
|
208
|
+
// Coords
|
|
209
|
+
const position = getIdFromColumnName(tokens[i], 1);
|
|
210
|
+
// Get value
|
|
211
|
+
let value;
|
|
212
|
+
|
|
213
|
+
if (typeof obj.options.data[position[1]] != 'undefined' && typeof obj.options.data[position[1]][position[0]] != 'undefined') {
|
|
214
|
+
value = obj.options.data[position[1]][position[0]];
|
|
215
|
+
} else {
|
|
216
|
+
value = '';
|
|
217
|
+
}
|
|
218
|
+
// Get column data
|
|
219
|
+
if (('' + value).substr(0, 1) == '=') {
|
|
220
|
+
if (typeof formulaResults[tokens[i]] !== 'undefined') {
|
|
221
|
+
value = formulaResults[tokens[i]];
|
|
222
|
+
} else {
|
|
223
|
+
value = execute(value, position[0], position[1]);
|
|
224
|
+
formulaResults[tokens[i]] = value;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Type!
|
|
228
|
+
if (('' + value).trim() == '') {
|
|
229
|
+
// Null
|
|
230
|
+
formulaExpressions[tokens[i]] = null;
|
|
231
|
+
} else {
|
|
232
|
+
if (value == Number(value) && obj.parent.config.autoCasting != false) {
|
|
233
|
+
// Number
|
|
234
|
+
formulaExpressions[tokens[i]] = Number(value);
|
|
235
|
+
} else {
|
|
236
|
+
// Trying any formatted number
|
|
237
|
+
const number = parseNumber.call(obj, value, position[0], position[1]);
|
|
238
|
+
if (obj.parent.config.autoCasting != false && number) {
|
|
239
|
+
formulaExpressions[tokens[i]] = number;
|
|
240
|
+
} else {
|
|
241
|
+
formulaExpressions[tokens[i]] = '"' + value + '"';
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const ret = dispatch.call(obj, 'onbeforeformula', obj, expression, x, y);
|
|
250
|
+
if (ret === false) {
|
|
251
|
+
return expression;
|
|
252
|
+
} else if (ret) {
|
|
253
|
+
expression = ret;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Convert formula to javascript
|
|
257
|
+
let res;
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
res = formula(expression.substr(1), formulaExpressions, x, y, obj);
|
|
261
|
+
|
|
262
|
+
if (typeof res === 'function') {
|
|
263
|
+
res = '#ERROR';
|
|
264
|
+
}
|
|
265
|
+
} catch (e) {
|
|
266
|
+
res = '#ERROR';
|
|
267
|
+
|
|
268
|
+
if (obj.parent.config.debugFormulas === true) {
|
|
269
|
+
console.log(expression.substr(1), formulaExpressions, e);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return res;
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
return execute(expression, x, y);
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
export const parseValue = function (i, j, value, cell) {
|
|
281
|
+
const obj = this;
|
|
282
|
+
|
|
283
|
+
if (('' + value).substr(0, 1) == '=' && obj.parent.config.parseFormulas != false) {
|
|
284
|
+
value = executeFormula.call(obj, value, i, j);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
let config = obj.options.columns && obj.options.columns[i];
|
|
288
|
+
|
|
289
|
+
const cellName = getCellNameFromCoords(i, j);
|
|
290
|
+
const cells = obj.options.cells;
|
|
291
|
+
if (typeof cells === 'object' && cells[cellName]) {
|
|
292
|
+
config = cells[cellName];
|
|
293
|
+
}
|
|
294
|
+
if (config && !isFormula(value)) {
|
|
295
|
+
// Mask options
|
|
296
|
+
let opt = null;
|
|
297
|
+
if ((opt = getMask(config))) {
|
|
298
|
+
if (value && value == Number(value)) {
|
|
299
|
+
value = Number(value);
|
|
300
|
+
}
|
|
301
|
+
// Process the decimals to match the mask
|
|
302
|
+
let masked = jSuites.mask.render(value, opt, true);
|
|
303
|
+
// Negative indication
|
|
304
|
+
if (cell) {
|
|
305
|
+
if (opt.mask) {
|
|
306
|
+
const t = opt.mask.split(';');
|
|
307
|
+
if (t[1]) {
|
|
308
|
+
const t1 = t[1].match(new RegExp('\\[Red\\]', 'gi'));
|
|
309
|
+
if (t1) {
|
|
310
|
+
if (value < 0) {
|
|
311
|
+
cell.classList.add('red');
|
|
312
|
+
} else {
|
|
313
|
+
cell.classList.remove('red');
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const t2 = t[1].match(new RegExp('\\(', 'gi'));
|
|
317
|
+
if (t2) {
|
|
318
|
+
if (value < 0) {
|
|
319
|
+
masked = '(' + masked + ')';
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (masked) {
|
|
327
|
+
value = masked;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return value;
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Get dropdown value from key
|
|
337
|
+
*/
|
|
338
|
+
const getDropDownValue = function (source, key) {
|
|
339
|
+
const obj = this;
|
|
340
|
+
|
|
341
|
+
const value = [];
|
|
342
|
+
|
|
343
|
+
if (source) {
|
|
344
|
+
// Create array from source
|
|
345
|
+
const combo = [];
|
|
346
|
+
|
|
347
|
+
for (let i = 0; i < source.length; i++) {
|
|
348
|
+
if (typeof source[i] == 'object') {
|
|
349
|
+
combo[source[i].id] = source[i].name;
|
|
350
|
+
} else {
|
|
351
|
+
combo[source[i]] = source[i];
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Guarantee single multiple compatibility
|
|
356
|
+
const keys = Array.isArray(key) ? key : ('' + key).split(';');
|
|
357
|
+
|
|
358
|
+
for (let i = 0; i < keys.length; i++) {
|
|
359
|
+
if (typeof keys[i] === 'object') {
|
|
360
|
+
value.push(combo[keys[i].id]);
|
|
361
|
+
} else {
|
|
362
|
+
if (combo[keys[i]]) {
|
|
363
|
+
value.push(combo[keys[i]]);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
console.error('Invalid column');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return value.length > 0 ? value.join('; ') : '';
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
const validDate = function (date) {
|
|
375
|
+
date = '' + date;
|
|
376
|
+
if (date.substr(4, 1) == '-' && date.substr(7, 1) == '-') {
|
|
377
|
+
return true;
|
|
378
|
+
} else {
|
|
379
|
+
date = date.split('-');
|
|
380
|
+
if (date[0].length == 4 && date[0] == Number(date[0]) && date[1].length == 2 && date[1] == Number(date[1])) {
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return false;
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Strip tags
|
|
389
|
+
*/
|
|
390
|
+
const stripScript = function (a) {
|
|
391
|
+
const b = new Option();
|
|
392
|
+
b.innerHTML = a;
|
|
393
|
+
let c = null;
|
|
394
|
+
for (a = b.getElementsByTagName('script'); (c = a[0]); ) c.parentNode.removeChild(c);
|
|
395
|
+
return b.innerHTML;
|
|
396
|
+
};
|
|
397
|
+
// i:col j: row
|
|
398
|
+
export const createCell = function (i, j, value) {
|
|
399
|
+
const obj = this;
|
|
400
|
+
|
|
401
|
+
// Create cell and properties
|
|
402
|
+
let td = document.createElement('td');
|
|
403
|
+
td.setAttribute('data-x', i);
|
|
404
|
+
td.setAttribute('data-y', j);
|
|
405
|
+
|
|
406
|
+
if (obj.headers[i].style.display === 'none') {
|
|
407
|
+
td.style.display = 'none';
|
|
408
|
+
}
|
|
409
|
+
// Security
|
|
410
|
+
if (('' + value).substr(0, 1) == '=' && obj.options.secureFormulas == true) {
|
|
411
|
+
const val = secureFormula(value);
|
|
412
|
+
if (val != value) {
|
|
413
|
+
// Update the data container
|
|
414
|
+
value = val;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
let config = obj.options.columns && obj.options.columns[i];
|
|
419
|
+
|
|
420
|
+
const cellName = getCellNameFromCoords(i, j);
|
|
421
|
+
const cells = obj.options.cells;
|
|
422
|
+
if (typeof cells === 'object' && cells[cellName]) {
|
|
423
|
+
config = cells[cellName];
|
|
424
|
+
}
|
|
425
|
+
// 先默认处理,然后渲染定制editor
|
|
426
|
+
// Hidden column
|
|
427
|
+
if (config && config.type == 'hidden') {
|
|
428
|
+
td.style.display = 'none';
|
|
429
|
+
td.textContent = value;
|
|
430
|
+
} else if (config && (config.type == 'checkbox' || config.type == 'radio')) {
|
|
431
|
+
// Create input
|
|
432
|
+
const element = document.createElement('input');
|
|
433
|
+
element.type = config.type;
|
|
434
|
+
element.name = 'c' + i;
|
|
435
|
+
element.checked = value == 1 || value == true || value == 'true' ? true : false;
|
|
436
|
+
element.onclick = function () {
|
|
437
|
+
obj.setValue(td, this.checked);
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
if (config.readOnly == true || obj.options.editable == false) {
|
|
441
|
+
element.setAttribute('disabled', 'disabled');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Append to the table
|
|
445
|
+
td.appendChild(element);
|
|
446
|
+
// Make sure the values are correct
|
|
447
|
+
obj.options.data[j][i] = element.checked;
|
|
448
|
+
} else if (config && config.type == 'calendar') {
|
|
449
|
+
// Try formatted date
|
|
450
|
+
let formatted = null;
|
|
451
|
+
if (!validDate(value)) {
|
|
452
|
+
const tmp = jSuites.calendar.extractDateFromString(value, (config.options && config.options.format) || 'YYYY-MM-DD');
|
|
453
|
+
if (tmp) {
|
|
454
|
+
formatted = tmp;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
// Create calendar cell
|
|
458
|
+
td.textContent = jSuites.calendar.getDateString(formatted ? formatted : value, config.options && config.options.format);
|
|
459
|
+
} else if (config && config.type == 'dropdown') {
|
|
460
|
+
// Create dropdown cell
|
|
461
|
+
td.classList.add('jss_dropdown');
|
|
462
|
+
td.textContent = getDropDownValue.call(obj, config.source, value);
|
|
463
|
+
} else if (config && config.type == 'color') {
|
|
464
|
+
if (config.render == 'square') {
|
|
465
|
+
const color = document.createElement('div');
|
|
466
|
+
color.className = 'color';
|
|
467
|
+
color.style.backgroundColor = value;
|
|
468
|
+
td.appendChild(color);
|
|
469
|
+
} else {
|
|
470
|
+
td.style.color = value;
|
|
471
|
+
td.textContent = value;
|
|
472
|
+
}
|
|
473
|
+
} else if (config && config.type == 'image') {
|
|
474
|
+
if (value && value.substr(0, 10) == 'data:image') {
|
|
475
|
+
const img = document.createElement('img');
|
|
476
|
+
img.src = value;
|
|
477
|
+
td.appendChild(img);
|
|
478
|
+
}
|
|
479
|
+
} else {
|
|
480
|
+
if (config && config.type == 'html') {
|
|
481
|
+
td.innerHTML = stripScript(parseValue.call(this, i, j, value, td));
|
|
482
|
+
} else {
|
|
483
|
+
if (obj.parent.config.parseHTML === true) {
|
|
484
|
+
td.innerHTML = stripScript(parseValue.call(this, i, j, value, td));
|
|
485
|
+
} else {
|
|
486
|
+
td.textContent = parseValue.call(this, i, j, value, td);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Custom column
|
|
492
|
+
if (config && typeof config.type === 'object') {
|
|
493
|
+
if (obj.parent.config.parseHTML === true) {
|
|
494
|
+
td.innerHTML = value;
|
|
495
|
+
}
|
|
496
|
+
if (typeof config.type.createCell == 'function') {
|
|
497
|
+
config.type.createCell(td, value, parseInt(i), parseInt(j), obj, config);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Readonly
|
|
502
|
+
if (config && config.readOnly == true) {
|
|
503
|
+
td.classList.add('readonly');
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (obj.options.freezeRows > j) {
|
|
507
|
+
td.classList.add('jss_frozen_row');
|
|
508
|
+
td.style.top = getFreezeRowTop(j, obj.options.rows);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (obj.options.freezeColumns > i) {
|
|
512
|
+
td.classList.add('jss_frozen');
|
|
513
|
+
td.style.left = getFreezeColumnLeft(i, obj.options.columns);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Text align
|
|
517
|
+
const colAlign = (config && config.align) || obj.options.defaultColAlign || 'center';
|
|
518
|
+
td.style.textAlign = colAlign;
|
|
519
|
+
|
|
520
|
+
// Wrap option
|
|
521
|
+
if ((!config || config.wordWrap != false) && (obj.options.wordWrap == true || (config && config.wordWrap == true) || td.innerHTML.length > 200)) {
|
|
522
|
+
td.style.whiteSpace = 'pre-wrap';
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Overflow
|
|
526
|
+
if (i > 0) {
|
|
527
|
+
if (obj.options.textOverflow == true) {
|
|
528
|
+
if (value || td.innerHTML) {
|
|
529
|
+
obj.records[j][i - 1].element.style.overflow = 'hidden';
|
|
530
|
+
} else {
|
|
531
|
+
if (i == obj.options.columns.length - 1) {
|
|
532
|
+
td.style.overflow = 'hidden';
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
dispatch.call(obj, 'oncreatecell', obj, td, i, j, value);
|
|
539
|
+
|
|
540
|
+
return td;
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Update cell content
|
|
545
|
+
*
|
|
546
|
+
* @param object cell
|
|
547
|
+
* @return void
|
|
548
|
+
*/
|
|
549
|
+
export const updateCell = function (x, y, value, force) {
|
|
550
|
+
const obj = this;
|
|
551
|
+
|
|
552
|
+
let record;
|
|
553
|
+
|
|
554
|
+
// Changing value depending on the column type
|
|
555
|
+
if (obj.records[y][x].element.classList.contains('readonly') == true && !force) {
|
|
556
|
+
// Do nothing
|
|
557
|
+
record = {
|
|
558
|
+
x: x,
|
|
559
|
+
y: y,
|
|
560
|
+
col: x,
|
|
561
|
+
row: y,
|
|
562
|
+
};
|
|
563
|
+
} else {
|
|
564
|
+
// Security
|
|
565
|
+
if (('' + value).substr(0, 1) == '=' && obj.options.secureFormulas == true) {
|
|
566
|
+
const val = secureFormula(value);
|
|
567
|
+
if (val != value) {
|
|
568
|
+
// Update the data container
|
|
569
|
+
value = val;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// On change
|
|
574
|
+
const val = dispatch.call(obj, 'onbeforechange', obj, obj.records[y][x].element, x, y, value);
|
|
575
|
+
|
|
576
|
+
// If you return something this will overwrite the value
|
|
577
|
+
if (val != undefined) {
|
|
578
|
+
value = val;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
let config = obj.options.columns && obj.options.columns[x];
|
|
582
|
+
const cellName = getCellNameFromCoords(x, y);
|
|
583
|
+
const cells = obj.options.cells;
|
|
584
|
+
if (typeof cells === 'object' && cells[cellName]) {
|
|
585
|
+
config = cells[cellName];
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// custom editor
|
|
589
|
+
if (config && typeof config.type === 'object' && typeof config.type.updateCell === 'function') {
|
|
590
|
+
const result = config.type.updateCell(obj.records[y][x].element, value, parseInt(x), parseInt(y), obj, config);
|
|
591
|
+
|
|
592
|
+
if (result !== undefined) {
|
|
593
|
+
value = result;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// History format
|
|
598
|
+
record = {
|
|
599
|
+
x: x,
|
|
600
|
+
y: y,
|
|
601
|
+
col: x,
|
|
602
|
+
row: y,
|
|
603
|
+
value: value,
|
|
604
|
+
oldValue: obj.options.data[y][x],
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
let editor = config && typeof config.type === 'object' ? config.type : null;
|
|
608
|
+
if (editor) {
|
|
609
|
+
// Update data and cell
|
|
610
|
+
obj.options.data[y][x] = value;
|
|
611
|
+
if (typeof editor.setValue === 'function') {
|
|
612
|
+
editor.setValue(obj.records[y][x].element, value);
|
|
613
|
+
}
|
|
614
|
+
} else {
|
|
615
|
+
// Native functions
|
|
616
|
+
if (config && (config.type == 'checkbox' || config.type == 'radio')) {
|
|
617
|
+
// Unchecked all options
|
|
618
|
+
if (config.type == 'radio') {
|
|
619
|
+
for (let j = 0; j < obj.options.data.length; j++) {
|
|
620
|
+
obj.options.data[j][x] = false;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// Update data and cell
|
|
625
|
+
obj.records[y][x].element.children[0].checked = value == 1 || value == true || value == 'true' || value == 'TRUE' ? true : false;
|
|
626
|
+
obj.options.data[y][x] = obj.records[y][x].element.children[0].checked;
|
|
627
|
+
} else if (config && config.type == 'dropdown') {
|
|
628
|
+
// Update data and cell
|
|
629
|
+
obj.options.data[y][x] = value;
|
|
630
|
+
obj.records[y][x].element.textContent = getDropDownValue.call(obj, config.source, value);
|
|
631
|
+
} else if (config && config.type == 'calendar') {
|
|
632
|
+
// Try formatted date
|
|
633
|
+
let formatted = null;
|
|
634
|
+
if (!validDate(value)) {
|
|
635
|
+
const tmp = jSuites.calendar.extractDateFromString(value, (config.options && config.options.format) || 'YYYY-MM-DD');
|
|
636
|
+
if (tmp) {
|
|
637
|
+
formatted = tmp;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
// Update data and cell
|
|
641
|
+
obj.options.data[y][x] = value;
|
|
642
|
+
obj.records[y][x].element.textContent = jSuites.calendar.getDateString(formatted ? formatted : value, config.options && config.options.format);
|
|
643
|
+
} else if (config && config.type == 'color') {
|
|
644
|
+
// Update color
|
|
645
|
+
obj.options.data[y][x] = value;
|
|
646
|
+
// Render
|
|
647
|
+
if (config.render == 'square') {
|
|
648
|
+
const color = document.createElement('div');
|
|
649
|
+
color.className = 'color';
|
|
650
|
+
color.style.backgroundColor = value;
|
|
651
|
+
obj.records[y][x].element.textContent = '';
|
|
652
|
+
obj.records[y][x].element.appendChild(color);
|
|
653
|
+
} else {
|
|
654
|
+
obj.records[y][x].element.style.color = value;
|
|
655
|
+
obj.records[y][x].element.textContent = value;
|
|
656
|
+
}
|
|
657
|
+
} else if (config && config.type == 'image') {
|
|
658
|
+
value = '' + value;
|
|
659
|
+
obj.options.data[y][x] = value;
|
|
660
|
+
obj.records[y][x].element.innerHTML = '';
|
|
661
|
+
if (value && value.substr(0, 10) == 'data:image') {
|
|
662
|
+
const img = document.createElement('img');
|
|
663
|
+
img.src = value;
|
|
664
|
+
obj.records[y][x].element.appendChild(img);
|
|
665
|
+
}
|
|
666
|
+
} else {
|
|
667
|
+
// Update data and cell
|
|
668
|
+
obj.options.data[y][x] = value;
|
|
669
|
+
// Label
|
|
670
|
+
if (config && config.type == 'html') {
|
|
671
|
+
obj.records[y][x].element.innerHTML = stripScript(parseValue.call(obj, x, y, value));
|
|
672
|
+
} else {
|
|
673
|
+
if (obj.parent.config.parseHTML === true) {
|
|
674
|
+
obj.records[y][x].element.innerHTML = stripScript(parseValue.call(obj, x, y, value, obj.records[y][x].element));
|
|
675
|
+
} else {
|
|
676
|
+
obj.records[y][x].element.textContent = parseValue.call(obj, x, y, value, obj.records[y][x].element);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
// Handle big text inside a cell
|
|
680
|
+
if (
|
|
681
|
+
(!config || config.wordWrap != false) &&
|
|
682
|
+
(obj.options.wordWrap == true || (config && config.wordWrap == true) || obj.records[y][x].element.innerHTML.length > 200)
|
|
683
|
+
) {
|
|
684
|
+
obj.records[y][x].element.style.whiteSpace = 'pre-wrap';
|
|
685
|
+
} else {
|
|
686
|
+
obj.records[y][x].element.style.whiteSpace = '';
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Overflow
|
|
692
|
+
if (x > 0) {
|
|
693
|
+
if (value) {
|
|
694
|
+
obj.records[y][x - 1].element.style.overflow = 'hidden';
|
|
695
|
+
} else {
|
|
696
|
+
obj.records[y][x - 1].element.style.overflow = '';
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (config && typeof config.render === 'function') {
|
|
701
|
+
config.render(obj.records[y] && obj.records[y][x] ? obj.records[y][x].element : null, value, parseInt(x), parseInt(y), obj, config);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// On change
|
|
705
|
+
dispatch.call(obj, 'onchange', obj, obj.records[y] && obj.records[y][x] ? obj.records[y][x].element : null, x, y, value, record.oldValue);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
return record;
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* The value is a formula
|
|
713
|
+
*/
|
|
714
|
+
export const isFormula = function (value) {
|
|
715
|
+
const v = ('' + value)[0];
|
|
716
|
+
return v == '=' || v == '#' ? true : false;
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Get the mask in the jSuites.mask format
|
|
721
|
+
*/
|
|
722
|
+
export const getMask = function (o) {
|
|
723
|
+
if (o.format || o.mask || o.locale) {
|
|
724
|
+
const opt = {};
|
|
725
|
+
if (o.mask) {
|
|
726
|
+
opt.mask = o.mask;
|
|
727
|
+
} else if (o.format) {
|
|
728
|
+
opt.mask = o.format;
|
|
729
|
+
} else {
|
|
730
|
+
opt.locale = o.locale;
|
|
731
|
+
opt.options = o.options;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (o.decimal) {
|
|
735
|
+
if (!opt.options) {
|
|
736
|
+
opt.options = {};
|
|
737
|
+
}
|
|
738
|
+
opt.options = { decimal: o.decimal };
|
|
739
|
+
}
|
|
740
|
+
return opt;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return null;
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Secure formula
|
|
748
|
+
*/
|
|
749
|
+
const secureFormula = function (oldValue) {
|
|
750
|
+
let newValue = '';
|
|
751
|
+
let inside = 0;
|
|
752
|
+
|
|
753
|
+
for (let i = 0; i < oldValue.length; i++) {
|
|
754
|
+
if (oldValue[i] == '"') {
|
|
755
|
+
if (inside == 0) {
|
|
756
|
+
inside = 1;
|
|
757
|
+
} else {
|
|
758
|
+
inside = 0;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (inside == 1) {
|
|
763
|
+
newValue += oldValue[i];
|
|
764
|
+
} else {
|
|
765
|
+
newValue += oldValue[i].toUpperCase();
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
return newValue;
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Update all related cells in the chain
|
|
774
|
+
*/
|
|
775
|
+
let chainLoopProtection = [];
|
|
776
|
+
|
|
777
|
+
export const updateFormulaChain = function (x, y, records) {
|
|
778
|
+
const obj = this;
|
|
779
|
+
|
|
780
|
+
const cellId = getColumnNameFromId([x, y]);
|
|
781
|
+
if (obj.formula[cellId] && obj.formula[cellId].length > 0) {
|
|
782
|
+
if (chainLoopProtection[cellId]) {
|
|
783
|
+
obj.records[y][x].element.innerHTML = '#ERROR';
|
|
784
|
+
obj.formula[cellId] = '';
|
|
785
|
+
} else {
|
|
786
|
+
// Protection
|
|
787
|
+
chainLoopProtection[cellId] = true;
|
|
788
|
+
|
|
789
|
+
for (let i = 0; i < obj.formula[cellId].length; i++) {
|
|
790
|
+
const cell = getIdFromColumnName(obj.formula[cellId][i], true);
|
|
791
|
+
// Update cell
|
|
792
|
+
const value = '' + obj.options.data[cell[1]][cell[0]];
|
|
793
|
+
if (value.substr(0, 1) == '=') {
|
|
794
|
+
records.push(updateCell.call(obj, cell[0], cell[1], value, true));
|
|
795
|
+
} else {
|
|
796
|
+
// No longer a formula, remove from the chain
|
|
797
|
+
Object.keys(obj.formula)[i] = null;
|
|
798
|
+
}
|
|
799
|
+
updateFormulaChain.call(obj, cell[0], cell[1], records);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
chainLoopProtection = [];
|
|
805
|
+
};
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Update formula
|
|
809
|
+
*/
|
|
810
|
+
export const updateFormula = function (formula, referencesToUpdate) {
|
|
811
|
+
const testLetter = /[A-Z]/;
|
|
812
|
+
const testNumber = /[0-9]/;
|
|
813
|
+
|
|
814
|
+
let newFormula = '';
|
|
815
|
+
let letter = null;
|
|
816
|
+
let number = null;
|
|
817
|
+
let token = '';
|
|
818
|
+
|
|
819
|
+
for (let index = 0; index < formula.length; index++) {
|
|
820
|
+
if (testLetter.exec(formula[index])) {
|
|
821
|
+
letter = 1;
|
|
822
|
+
number = 0;
|
|
823
|
+
token += formula[index];
|
|
824
|
+
} else if (testNumber.exec(formula[index])) {
|
|
825
|
+
number = letter ? 1 : 0;
|
|
826
|
+
token += formula[index];
|
|
827
|
+
} else {
|
|
828
|
+
if (letter && number) {
|
|
829
|
+
token = referencesToUpdate[token] ? referencesToUpdate[token] : token;
|
|
830
|
+
}
|
|
831
|
+
newFormula += token;
|
|
832
|
+
newFormula += formula[index];
|
|
833
|
+
letter = 0;
|
|
834
|
+
number = 0;
|
|
835
|
+
token = '';
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
if (token) {
|
|
840
|
+
if (letter && number) {
|
|
841
|
+
token = referencesToUpdate[token] ? referencesToUpdate[token] : token;
|
|
842
|
+
}
|
|
843
|
+
newFormula += token;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
return newFormula;
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Update formulas
|
|
851
|
+
*/
|
|
852
|
+
const updateFormulas = function (referencesToUpdate) {
|
|
853
|
+
const obj = this;
|
|
854
|
+
|
|
855
|
+
// Update formulas
|
|
856
|
+
for (let j = 0; j < obj.options.data.length; j++) {
|
|
857
|
+
for (let i = 0; i < obj.options.data[0].length; i++) {
|
|
858
|
+
const value = '' + obj.options.data[j][i];
|
|
859
|
+
// Is formula
|
|
860
|
+
if (value.substr(0, 1) == '=') {
|
|
861
|
+
// Replace tokens
|
|
862
|
+
const newFormula = updateFormula(value, referencesToUpdate);
|
|
863
|
+
if (newFormula != value) {
|
|
864
|
+
obj.options.data[j][i] = newFormula;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// Update formula chain
|
|
871
|
+
const formula = [];
|
|
872
|
+
const keys = Object.keys(obj.formula);
|
|
873
|
+
for (let j = 0; j < keys.length; j++) {
|
|
874
|
+
// Current key and values
|
|
875
|
+
let key = keys[j];
|
|
876
|
+
const value = obj.formula[key];
|
|
877
|
+
// Update key
|
|
878
|
+
if (referencesToUpdate[key]) {
|
|
879
|
+
key = referencesToUpdate[key];
|
|
880
|
+
}
|
|
881
|
+
// Update values
|
|
882
|
+
formula[key] = [];
|
|
883
|
+
for (let i = 0; i < value.length; i++) {
|
|
884
|
+
let letter = value[i];
|
|
885
|
+
if (referencesToUpdate[letter]) {
|
|
886
|
+
letter = referencesToUpdate[letter];
|
|
887
|
+
}
|
|
888
|
+
formula[key].push(letter);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
obj.formula = formula;
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Update cell references
|
|
896
|
+
*
|
|
897
|
+
* @return void
|
|
898
|
+
*/
|
|
899
|
+
export const updateTableReferences = function () {
|
|
900
|
+
const obj = this;
|
|
901
|
+
if (obj.skipUpdateTableReferences) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Update headers
|
|
906
|
+
for (let i = 0; i < obj.headers.length; i++) {
|
|
907
|
+
const x = obj.headers[i].getAttribute('data-x');
|
|
908
|
+
|
|
909
|
+
if (x != i) {
|
|
910
|
+
// Update coords
|
|
911
|
+
obj.headers[i].setAttribute('data-x', i);
|
|
912
|
+
// Title
|
|
913
|
+
if (!obj.headers[i].getAttribute('title')) {
|
|
914
|
+
obj.headers[i].innerHTML = getColumnName(i);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// Update all rows
|
|
920
|
+
for (let j = 0; j < obj.rows.length; j++) {
|
|
921
|
+
if (obj.rows[j]) {
|
|
922
|
+
const y = obj.rows[j].element.getAttribute('data-y');
|
|
923
|
+
|
|
924
|
+
if (y != j) {
|
|
925
|
+
// Update coords
|
|
926
|
+
obj.rows[j].element.setAttribute('data-y', j);
|
|
927
|
+
obj.rows[j].element.children[0].setAttribute('data-y', j);
|
|
928
|
+
// Row number
|
|
929
|
+
obj.rows[j].element.children[0].innerHTML = j + 1;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// Regular cells affected by this change
|
|
935
|
+
const affectedTokens = [];
|
|
936
|
+
const mergeCellUpdates = [];
|
|
937
|
+
|
|
938
|
+
// Update cell
|
|
939
|
+
const updatePosition = function (x, y, i, j) {
|
|
940
|
+
if (x != i) {
|
|
941
|
+
obj.records[j][i].element.setAttribute('data-x', i);
|
|
942
|
+
}
|
|
943
|
+
if (y != j) {
|
|
944
|
+
obj.records[j][i].element.setAttribute('data-y', j);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// Other updates
|
|
948
|
+
if (x != i || y != j) {
|
|
949
|
+
const columnIdFrom = getColumnNameFromId([x, y]);
|
|
950
|
+
const columnIdTo = getColumnNameFromId([i, j]);
|
|
951
|
+
affectedTokens[columnIdFrom] = columnIdTo;
|
|
952
|
+
}
|
|
953
|
+
};
|
|
954
|
+
|
|
955
|
+
for (let j = 0; j < obj.records.length; j++) {
|
|
956
|
+
for (let i = 0; i < obj.records[0].length; i++) {
|
|
957
|
+
if (obj.records[j][i]) {
|
|
958
|
+
// Current values
|
|
959
|
+
const x = obj.records[j][i].element.getAttribute('data-x');
|
|
960
|
+
const y = obj.records[j][i].element.getAttribute('data-y');
|
|
961
|
+
|
|
962
|
+
// Update column
|
|
963
|
+
if (obj.records[j][i].element.getAttribute('data-merged')) {
|
|
964
|
+
const columnIdFrom = getColumnNameFromId([x, y]);
|
|
965
|
+
const columnIdTo = getColumnNameFromId([i, j]);
|
|
966
|
+
if (mergeCellUpdates[columnIdFrom] == null) {
|
|
967
|
+
if (columnIdFrom == columnIdTo) {
|
|
968
|
+
mergeCellUpdates[columnIdFrom] = false;
|
|
969
|
+
} else {
|
|
970
|
+
const totalX = parseInt(i - x);
|
|
971
|
+
const totalY = parseInt(j - y);
|
|
972
|
+
mergeCellUpdates[columnIdFrom] = [columnIdTo, totalX, totalY];
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
} else {
|
|
976
|
+
updatePosition(x, y, i, j);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Update merged if applicable
|
|
983
|
+
const keys = Object.keys(mergeCellUpdates);
|
|
984
|
+
if (keys.length) {
|
|
985
|
+
for (let i = 0; i < keys.length; i++) {
|
|
986
|
+
if (mergeCellUpdates[keys[i]]) {
|
|
987
|
+
const info = getIdFromColumnName(keys[i], true);
|
|
988
|
+
let x = info[0];
|
|
989
|
+
let y = info[1];
|
|
990
|
+
updatePosition(x, y, x + mergeCellUpdates[keys[i]][1], y + mergeCellUpdates[keys[i]][2]);
|
|
991
|
+
|
|
992
|
+
const columnIdFrom = keys[i];
|
|
993
|
+
const columnIdTo = mergeCellUpdates[keys[i]][0];
|
|
994
|
+
for (let j = 0; j < obj.options.mergeCells[columnIdFrom][2].length; j++) {
|
|
995
|
+
x = parseInt(obj.options.mergeCells[columnIdFrom][2][j].getAttribute('data-x'));
|
|
996
|
+
y = parseInt(obj.options.mergeCells[columnIdFrom][2][j].getAttribute('data-y'));
|
|
997
|
+
obj.options.mergeCells[columnIdFrom][2][j].setAttribute('data-x', x + mergeCellUpdates[keys[i]][1]);
|
|
998
|
+
obj.options.mergeCells[columnIdFrom][2][j].setAttribute('data-y', y + mergeCellUpdates[keys[i]][2]);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
obj.options.mergeCells[columnIdTo] = obj.options.mergeCells[columnIdFrom];
|
|
1002
|
+
delete obj.options.mergeCells[columnIdFrom];
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// Update formulas
|
|
1008
|
+
updateFormulas.call(obj, affectedTokens);
|
|
1009
|
+
|
|
1010
|
+
// Update meta data
|
|
1011
|
+
updateMeta.call(obj, affectedTokens);
|
|
1012
|
+
|
|
1013
|
+
// Refresh selection
|
|
1014
|
+
refreshSelection.call(obj);
|
|
1015
|
+
|
|
1016
|
+
// Update table with custom configuration if applicable
|
|
1017
|
+
updateTable.call(obj);
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Update scroll position based on the selection
|
|
1022
|
+
*/
|
|
1023
|
+
export const updateScroll = function (direction) {
|
|
1024
|
+
const obj = this;
|
|
1025
|
+
|
|
1026
|
+
// Jspreadsheet Container information
|
|
1027
|
+
const contentRect = obj.content.getBoundingClientRect();
|
|
1028
|
+
const x1 = contentRect.left;
|
|
1029
|
+
const y1 = contentRect.top;
|
|
1030
|
+
const w1 = contentRect.width;
|
|
1031
|
+
const h1 = contentRect.height;
|
|
1032
|
+
|
|
1033
|
+
// Direction Left or Up
|
|
1034
|
+
const reference = obj.records[obj.selectedCell[3]][obj.selectedCell[2]].element;
|
|
1035
|
+
|
|
1036
|
+
// Reference
|
|
1037
|
+
const referenceRect = reference.getBoundingClientRect();
|
|
1038
|
+
const x2 = referenceRect.left;
|
|
1039
|
+
const y2 = referenceRect.top;
|
|
1040
|
+
const w2 = referenceRect.width;
|
|
1041
|
+
const h2 = referenceRect.height;
|
|
1042
|
+
|
|
1043
|
+
let x, y;
|
|
1044
|
+
|
|
1045
|
+
// Direction
|
|
1046
|
+
if (direction == 0 || direction == 1) {
|
|
1047
|
+
x = x2 - x1 + obj.content.scrollLeft;
|
|
1048
|
+
y = y2 - y1 + obj.content.scrollTop - 2;
|
|
1049
|
+
} else {
|
|
1050
|
+
x = x2 - x1 + obj.content.scrollLeft + w2;
|
|
1051
|
+
y = y2 - y1 + obj.content.scrollTop + h2;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// Top position check
|
|
1055
|
+
if (y > obj.content.scrollTop + 30 && y < obj.content.scrollTop + h1) {
|
|
1056
|
+
// In the viewport
|
|
1057
|
+
} else {
|
|
1058
|
+
// Out of viewport
|
|
1059
|
+
if (y < obj.content.scrollTop + 30) {
|
|
1060
|
+
obj.content.scrollTop = y - h2;
|
|
1061
|
+
} else {
|
|
1062
|
+
obj.content.scrollTop = y - (h1 - 2);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// Freeze columns?
|
|
1067
|
+
const freezed = getFreezeWidth.call(obj);
|
|
1068
|
+
|
|
1069
|
+
// Left position check - TODO: change that to the bottom border of the element
|
|
1070
|
+
if (x > obj.content.scrollLeft + freezed && x < obj.content.scrollLeft + w1) {
|
|
1071
|
+
// In the viewport
|
|
1072
|
+
} else {
|
|
1073
|
+
// Out of viewport
|
|
1074
|
+
if (x < obj.content.scrollLeft + 30) {
|
|
1075
|
+
obj.content.scrollLeft = x;
|
|
1076
|
+
if (obj.content.scrollLeft < 50) {
|
|
1077
|
+
obj.content.scrollLeft = 0;
|
|
1078
|
+
}
|
|
1079
|
+
} else if (x < obj.content.scrollLeft + freezed) {
|
|
1080
|
+
obj.content.scrollLeft = x - freezed - 1;
|
|
1081
|
+
} else {
|
|
1082
|
+
obj.content.scrollLeft = x - (w1 - 20);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
|
|
1087
|
+
export const updateResult = function () {
|
|
1088
|
+
const obj = this;
|
|
1089
|
+
|
|
1090
|
+
let total = 0;
|
|
1091
|
+
let index = 0;
|
|
1092
|
+
|
|
1093
|
+
// Page 1
|
|
1094
|
+
if (obj.options.lazyLoading == true) {
|
|
1095
|
+
total = 100;
|
|
1096
|
+
} else if (obj.options.pagination > 0) {
|
|
1097
|
+
total = obj.options.pagination;
|
|
1098
|
+
} else {
|
|
1099
|
+
if (obj.results) {
|
|
1100
|
+
total = obj.results.length;
|
|
1101
|
+
} else {
|
|
1102
|
+
total = obj.rows.length;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// Reset current nodes
|
|
1107
|
+
while (obj.tbody.firstChild) {
|
|
1108
|
+
obj.tbody.removeChild(obj.tbody.firstChild);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// Hide all records from the table
|
|
1112
|
+
for (let j = 0; j < obj.rows.length; j++) {
|
|
1113
|
+
if (!obj.results || obj.results.indexOf(j) > -1) {
|
|
1114
|
+
if (index < total) {
|
|
1115
|
+
obj.tbody.appendChild(obj.rows[j].element);
|
|
1116
|
+
index++;
|
|
1117
|
+
}
|
|
1118
|
+
obj.rows[j].element.style.display = '';
|
|
1119
|
+
} else {
|
|
1120
|
+
obj.rows[j].element.style.display = 'none';
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// Update pagination
|
|
1125
|
+
if (obj.options.pagination > 0) {
|
|
1126
|
+
updatePagination.call(obj);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
updateCornerPosition.call(obj);
|
|
1130
|
+
|
|
1131
|
+
dispatch.call(obj, 'onupdateresult', obj, obj.results);
|
|
1132
|
+
|
|
1133
|
+
return total;
|
|
1134
|
+
};
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Get the cell object
|
|
1138
|
+
*
|
|
1139
|
+
* @param object cell
|
|
1140
|
+
* @return string value
|
|
1141
|
+
*/
|
|
1142
|
+
export const getCell = function (x, y) {
|
|
1143
|
+
const obj = this;
|
|
1144
|
+
|
|
1145
|
+
if (typeof x === 'string') {
|
|
1146
|
+
// Convert in case name is excel liked ex. A10, BB92
|
|
1147
|
+
const cell = getIdFromColumnName(x, true);
|
|
1148
|
+
|
|
1149
|
+
x = cell[0];
|
|
1150
|
+
y = cell[1];
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
return obj.records[y][x].element;
|
|
1154
|
+
};
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* Get the cell object from coords
|
|
1158
|
+
*
|
|
1159
|
+
* @param object cell
|
|
1160
|
+
* @return string value
|
|
1161
|
+
*/
|
|
1162
|
+
export const getCellFromCoords = function (x, y) {
|
|
1163
|
+
const obj = this;
|
|
1164
|
+
|
|
1165
|
+
return obj.records[y][x].element;
|
|
1166
|
+
};
|
|
1167
|
+
|
|
1168
|
+
/**
|
|
1169
|
+
* Get label
|
|
1170
|
+
*
|
|
1171
|
+
* @param object cell
|
|
1172
|
+
* @return string value
|
|
1173
|
+
*/
|
|
1174
|
+
export const getLabel = function (x, y) {
|
|
1175
|
+
const obj = this;
|
|
1176
|
+
|
|
1177
|
+
if (typeof x === 'string') {
|
|
1178
|
+
// Convert in case name is excel liked ex. A10, BB92
|
|
1179
|
+
const cell = getIdFromColumnName(x, true);
|
|
1180
|
+
|
|
1181
|
+
x = cell[0];
|
|
1182
|
+
y = cell[1];
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
return obj.records[y][x].element.innerHTML;
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* Activate/Disable fullscreen
|
|
1190
|
+
* use programmatically : table.fullscreen(); or table.fullscreen(true); or table.fullscreen(false);
|
|
1191
|
+
* @Param {boolean} activate
|
|
1192
|
+
*/
|
|
1193
|
+
export const fullscreen = function (activate) {
|
|
1194
|
+
const spreadsheet = this;
|
|
1195
|
+
|
|
1196
|
+
// If activate not defined, get reverse options.fullscreen
|
|
1197
|
+
if (activate == null) {
|
|
1198
|
+
activate = !spreadsheet.config.fullscreen;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// If change
|
|
1202
|
+
if (spreadsheet.config.fullscreen != activate) {
|
|
1203
|
+
spreadsheet.config.fullscreen = activate;
|
|
1204
|
+
|
|
1205
|
+
// Test LazyLoading conflict
|
|
1206
|
+
if (activate == true) {
|
|
1207
|
+
spreadsheet.element.classList.add('fullscreen');
|
|
1208
|
+
} else {
|
|
1209
|
+
spreadsheet.element.classList.remove('fullscreen');
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* Show index column
|
|
1216
|
+
*/
|
|
1217
|
+
export const showIndex = function () {
|
|
1218
|
+
const obj = this;
|
|
1219
|
+
|
|
1220
|
+
obj.table.classList.remove('jss_hidden_index');
|
|
1221
|
+
};
|
|
1222
|
+
|
|
1223
|
+
/**
|
|
1224
|
+
* Hide index column
|
|
1225
|
+
*/
|
|
1226
|
+
export const hideIndex = function () {
|
|
1227
|
+
const obj = this;
|
|
1228
|
+
|
|
1229
|
+
obj.table.classList.add('jss_hidden_index');
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* Create a nested header object
|
|
1234
|
+
*/
|
|
1235
|
+
export const createNestedHeader = function (nestedInformation) {
|
|
1236
|
+
const obj = this;
|
|
1237
|
+
|
|
1238
|
+
const tr = document.createElement('tr');
|
|
1239
|
+
tr.classList.add('jss_nested');
|
|
1240
|
+
const td = document.createElement('td');
|
|
1241
|
+
td.classList.add('jss_selectall');
|
|
1242
|
+
|
|
1243
|
+
tr.appendChild(td);
|
|
1244
|
+
// Element
|
|
1245
|
+
nestedInformation.element = tr;
|
|
1246
|
+
|
|
1247
|
+
let headerIndex = 0;
|
|
1248
|
+
for (let i = 0; i < nestedInformation.length; i++) {
|
|
1249
|
+
// Default values
|
|
1250
|
+
if (!nestedInformation[i].colspan) {
|
|
1251
|
+
nestedInformation[i].colspan = 1;
|
|
1252
|
+
}
|
|
1253
|
+
if (!nestedInformation[i].title) {
|
|
1254
|
+
nestedInformation[i].title = '';
|
|
1255
|
+
}
|
|
1256
|
+
if (!nestedInformation[i].id) {
|
|
1257
|
+
nestedInformation[i].id = '';
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// Number of columns
|
|
1261
|
+
let numberOfColumns = nestedInformation[i].colspan;
|
|
1262
|
+
|
|
1263
|
+
// Classes container
|
|
1264
|
+
const column = [];
|
|
1265
|
+
// Header classes for this cell
|
|
1266
|
+
for (let x = 0; x < numberOfColumns; x++) {
|
|
1267
|
+
if (obj.options.columns[headerIndex] && obj.options.columns[headerIndex].type == 'hidden') {
|
|
1268
|
+
numberOfColumns++;
|
|
1269
|
+
}
|
|
1270
|
+
column.push(headerIndex);
|
|
1271
|
+
headerIndex++;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
// Created the nested cell
|
|
1275
|
+
const td = document.createElement('td');
|
|
1276
|
+
td.setAttribute('data-column', column.join(','));
|
|
1277
|
+
td.setAttribute('colspan', nestedInformation[i].colspan);
|
|
1278
|
+
td.setAttribute('align', nestedInformation[i].align || 'center');
|
|
1279
|
+
td.setAttribute('id', nestedInformation[i].id);
|
|
1280
|
+
td.textContent = nestedInformation[i].title;
|
|
1281
|
+
tr.appendChild(td);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
return tr;
|
|
1285
|
+
};
|
|
1286
|
+
|
|
1287
|
+
export const getWorksheetActive = function () {
|
|
1288
|
+
const spreadsheet = this.parent ? this.parent : this;
|
|
1289
|
+
|
|
1290
|
+
return spreadsheet.element.tabs ? spreadsheet.element.tabs.getActive() : 0;
|
|
1291
|
+
};
|
|
1292
|
+
|
|
1293
|
+
export const getWorksheetInstance = function (index) {
|
|
1294
|
+
const spreadsheet = this;
|
|
1295
|
+
|
|
1296
|
+
const worksheetIndex = typeof index !== 'undefined' ? index : getWorksheetActive.call(spreadsheet);
|
|
1297
|
+
|
|
1298
|
+
return spreadsheet.worksheets[worksheetIndex];
|
|
1299
|
+
};
|