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,409 @@
|
|
|
1
|
+
import { getColumnNameFromId } from './internalHelpers.js';
|
|
2
|
+
|
|
3
|
+
export { getColumnNameFromId };
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get carret position for one element
|
|
7
|
+
*/
|
|
8
|
+
export const getCaretIndex = function (e) {
|
|
9
|
+
let d;
|
|
10
|
+
|
|
11
|
+
if (this.config.root) {
|
|
12
|
+
d = this.config.root;
|
|
13
|
+
} else {
|
|
14
|
+
d = window;
|
|
15
|
+
}
|
|
16
|
+
let pos = 0;
|
|
17
|
+
const s = d.getSelection();
|
|
18
|
+
if (s) {
|
|
19
|
+
if (s.rangeCount !== 0) {
|
|
20
|
+
const r = s.getRangeAt(0);
|
|
21
|
+
const p = r.cloneRange();
|
|
22
|
+
p.selectNodeContents(e);
|
|
23
|
+
p.setEnd(r.endContainer, r.endOffset);
|
|
24
|
+
pos = p.toString().length;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return pos;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Invert keys and values
|
|
32
|
+
*/
|
|
33
|
+
export const invert = function (o) {
|
|
34
|
+
const d = [];
|
|
35
|
+
const k = Object.keys(o);
|
|
36
|
+
for (let i = 0; i < k.length; i++) {
|
|
37
|
+
d[o[k[i]]] = k[i];
|
|
38
|
+
}
|
|
39
|
+
return d;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get letter based on a number
|
|
44
|
+
*
|
|
45
|
+
* @param {number} columnNumber
|
|
46
|
+
* @return string letter
|
|
47
|
+
*/
|
|
48
|
+
export const getColumnName = function (columnNumber) {
|
|
49
|
+
let dividend = columnNumber + 1;
|
|
50
|
+
let columnName = '';
|
|
51
|
+
let modulo;
|
|
52
|
+
|
|
53
|
+
while (dividend > 0) {
|
|
54
|
+
modulo = (dividend - 1) % 26;
|
|
55
|
+
columnName = String.fromCharCode(65 + modulo).toString() + columnName;
|
|
56
|
+
dividend = parseInt((dividend - modulo) / 26);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return columnName;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get column name from coords
|
|
64
|
+
*/
|
|
65
|
+
export const getCellNameFromCoords = function (x, y) {
|
|
66
|
+
return getColumnName(parseInt(x)) + (parseInt(y) + 1);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const getCoordsFromCellName = function (columnName) {
|
|
70
|
+
// Get the letters
|
|
71
|
+
const t = /^[a-zA-Z]+/.exec(columnName);
|
|
72
|
+
|
|
73
|
+
if (t) {
|
|
74
|
+
// Base 26 calculation
|
|
75
|
+
let code = 0;
|
|
76
|
+
for (let i = 0; i < t[0].length; i++) {
|
|
77
|
+
code += parseInt(t[0].charCodeAt(i) - 64) * Math.pow(26, t[0].length - 1 - i);
|
|
78
|
+
}
|
|
79
|
+
code--;
|
|
80
|
+
// Make sure jspreadsheet starts on zero
|
|
81
|
+
if (code < 0) {
|
|
82
|
+
code = 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Number
|
|
86
|
+
let number = parseInt(/[0-9]+$/.exec(columnName)) || null;
|
|
87
|
+
if (number > 0) {
|
|
88
|
+
number--;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return [code, number];
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const getCoordsFromRange = function (range) {
|
|
96
|
+
const [start, end] = range.split(':');
|
|
97
|
+
|
|
98
|
+
return [...getCoordsFromCellName(start), ...getCoordsFromCellName(end)];
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* From stack overflow contributions
|
|
103
|
+
*/
|
|
104
|
+
export const parseCSV = function (str, delimiter) {
|
|
105
|
+
// user-supplied delimeter or default comma
|
|
106
|
+
delimiter = delimiter || ',';
|
|
107
|
+
// Remove last line break
|
|
108
|
+
str = str.replace(/\r?\n$|\r$|\n$/g, '');
|
|
109
|
+
|
|
110
|
+
const arr = [];
|
|
111
|
+
let quote = false; // true means we're inside a quoted field
|
|
112
|
+
// iterate over each character, keep track of current row and column (of the returned array)
|
|
113
|
+
let maxCol = 0;
|
|
114
|
+
let row = 0,
|
|
115
|
+
col = 0;
|
|
116
|
+
for (let c = 0; c < str.length; c++) {
|
|
117
|
+
const cc = str[c],
|
|
118
|
+
nc = str[c + 1];
|
|
119
|
+
arr[row] = arr[row] || [];
|
|
120
|
+
arr[row][col] = arr[row][col] || '';
|
|
121
|
+
|
|
122
|
+
// If the current character is a quotation mark, and we're inside a quoted field, and the next character is also a quotation mark, add a quotation mark to the current column and skip the next character
|
|
123
|
+
if (cc == '"' && quote && nc == '"') {
|
|
124
|
+
arr[row][col] += cc;
|
|
125
|
+
++c;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// If it's just one quotation mark, begin/end quoted field
|
|
130
|
+
if (cc == '"') {
|
|
131
|
+
quote = !quote;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// If it's a comma and we're not in a quoted field, move on to the next column
|
|
136
|
+
if (cc == delimiter && !quote) {
|
|
137
|
+
++col;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// If it's a newline (CRLF) and we're not in a quoted field, skip the next character and move on to the next row and move to column 0 of that new row
|
|
142
|
+
if (cc == '\r' && nc == '\n' && !quote) {
|
|
143
|
+
++row;
|
|
144
|
+
maxCol = Math.max(maxCol, col);
|
|
145
|
+
col = 0;
|
|
146
|
+
++c;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// If it's a newline (LF or CR) and we're not in a quoted field, move on to the next row and move to column 0 of that new row
|
|
151
|
+
if (cc == '\n' && !quote) {
|
|
152
|
+
++row;
|
|
153
|
+
maxCol = Math.max(maxCol, col);
|
|
154
|
+
col = 0;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (cc == '\r' && !quote) {
|
|
158
|
+
++row;
|
|
159
|
+
maxCol = Math.max(maxCol, col);
|
|
160
|
+
col = 0;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Otherwise, append the current character to the current column
|
|
165
|
+
arr[row][col] += cc;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// fix array length
|
|
169
|
+
arr.forEach((row, i) => {
|
|
170
|
+
for (let i = row.length; i <= maxCol; i++) {
|
|
171
|
+
row.push('');
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
return arr;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
export const createFromTable = function (el, options) {
|
|
178
|
+
if (el.tagName != 'TABLE') {
|
|
179
|
+
console.log('Element is not a table');
|
|
180
|
+
} else {
|
|
181
|
+
// Configuration
|
|
182
|
+
if (!options) {
|
|
183
|
+
options = {};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
options.columns = [];
|
|
187
|
+
options.data = [];
|
|
188
|
+
|
|
189
|
+
// Colgroup
|
|
190
|
+
const colgroup = el.querySelectorAll('colgroup > col');
|
|
191
|
+
if (colgroup.length) {
|
|
192
|
+
// Get column width
|
|
193
|
+
for (let i = 0; i < colgroup.length; i++) {
|
|
194
|
+
let width = colgroup[i].style.width;
|
|
195
|
+
if (!width) {
|
|
196
|
+
width = colgroup[i].getAttribute('width');
|
|
197
|
+
}
|
|
198
|
+
// Set column width
|
|
199
|
+
if (width) {
|
|
200
|
+
if (!options.columns[i]) {
|
|
201
|
+
options.columns[i] = {};
|
|
202
|
+
}
|
|
203
|
+
options.columns[i].width = width;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Parse header
|
|
209
|
+
const parseHeader = function (header, i) {
|
|
210
|
+
// Get width information
|
|
211
|
+
let info = header.getBoundingClientRect();
|
|
212
|
+
const width = info.width > 50 ? info.width : 50;
|
|
213
|
+
|
|
214
|
+
// Create column option
|
|
215
|
+
if (!options.columns[i]) {
|
|
216
|
+
options.columns[i] = {};
|
|
217
|
+
}
|
|
218
|
+
if (header.getAttribute('data-celltype')) {
|
|
219
|
+
options.columns[i].type = header.getAttribute('data-celltype');
|
|
220
|
+
} else {
|
|
221
|
+
options.columns[i].type = 'text';
|
|
222
|
+
}
|
|
223
|
+
options.columns[i].width = width + 'px';
|
|
224
|
+
options.columns[i].title = header.innerHTML;
|
|
225
|
+
if (header.style.textAlign) {
|
|
226
|
+
options.columns[i].align = header.style.textAlign;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if ((info = header.getAttribute('name'))) {
|
|
230
|
+
options.columns[i].name = info;
|
|
231
|
+
}
|
|
232
|
+
if ((info = header.getAttribute('id'))) {
|
|
233
|
+
options.columns[i].id = info;
|
|
234
|
+
}
|
|
235
|
+
if ((info = header.getAttribute('data-mask'))) {
|
|
236
|
+
options.columns[i].mask = info;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// Headers
|
|
241
|
+
const nested = [];
|
|
242
|
+
let headers = el.querySelectorAll(':scope > thead > tr');
|
|
243
|
+
if (headers.length) {
|
|
244
|
+
for (let j = 0; j < headers.length - 1; j++) {
|
|
245
|
+
const cells = [];
|
|
246
|
+
for (let i = 0; i < headers[j].children.length; i++) {
|
|
247
|
+
const row = {
|
|
248
|
+
title: headers[j].children[i].textContent,
|
|
249
|
+
colspan: headers[j].children[i].getAttribute('colspan') || 1,
|
|
250
|
+
};
|
|
251
|
+
cells.push(row);
|
|
252
|
+
}
|
|
253
|
+
nested.push(cells);
|
|
254
|
+
}
|
|
255
|
+
// Get the last row in the thead
|
|
256
|
+
headers = headers[headers.length - 1].children;
|
|
257
|
+
// Go though the headers
|
|
258
|
+
for (let i = 0; i < headers.length; i++) {
|
|
259
|
+
parseHeader(headers[i], i);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Content
|
|
264
|
+
let rowNumber = 0;
|
|
265
|
+
const mergeCells = {};
|
|
266
|
+
const rows = {};
|
|
267
|
+
const style = {};
|
|
268
|
+
const classes = {};
|
|
269
|
+
|
|
270
|
+
let content = el.querySelectorAll(':scope > tr, :scope > tbody > tr');
|
|
271
|
+
for (let j = 0; j < content.length; j++) {
|
|
272
|
+
options.data[rowNumber] = [];
|
|
273
|
+
if (options.parseTableFirstRowAsHeader == true && !headers.length && j == 0) {
|
|
274
|
+
for (let i = 0; i < content[j].children.length; i++) {
|
|
275
|
+
parseHeader(content[j].children[i], i);
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
for (let i = 0; i < content[j].children.length; i++) {
|
|
279
|
+
// WickedGrid formula compatibility
|
|
280
|
+
let value = content[j].children[i].getAttribute('data-formula');
|
|
281
|
+
if (value) {
|
|
282
|
+
if (value.substr(0, 1) != '=') {
|
|
283
|
+
value = '=' + value;
|
|
284
|
+
}
|
|
285
|
+
} else {
|
|
286
|
+
value = content[j].children[i].innerHTML;
|
|
287
|
+
}
|
|
288
|
+
options.data[rowNumber].push(value);
|
|
289
|
+
|
|
290
|
+
// Key
|
|
291
|
+
const cellName = getColumnNameFromId([i, j]);
|
|
292
|
+
|
|
293
|
+
// Classes
|
|
294
|
+
const tmp = content[j].children[i].getAttribute('class');
|
|
295
|
+
if (tmp) {
|
|
296
|
+
classes[cellName] = tmp;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Merged cells
|
|
300
|
+
const mergedColspan = parseInt(content[j].children[i].getAttribute('colspan')) || 0;
|
|
301
|
+
const mergedRowspan = parseInt(content[j].children[i].getAttribute('rowspan')) || 0;
|
|
302
|
+
if (mergedColspan || mergedRowspan) {
|
|
303
|
+
mergeCells[cellName] = [mergedColspan || 1, mergedRowspan || 1];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Avoid problems with hidden cells
|
|
307
|
+
if (content[j].children[i].style && content[j].children[i].style.display == 'none') {
|
|
308
|
+
content[j].children[i].style.display = '';
|
|
309
|
+
}
|
|
310
|
+
// Get style
|
|
311
|
+
const s = content[j].children[i].getAttribute('style');
|
|
312
|
+
if (s) {
|
|
313
|
+
style[cellName] = s;
|
|
314
|
+
}
|
|
315
|
+
// Bold
|
|
316
|
+
if (content[j].children[i].classList.contains('styleBold')) {
|
|
317
|
+
if (style[cellName]) {
|
|
318
|
+
style[cellName] += '; font-weight:bold;';
|
|
319
|
+
} else {
|
|
320
|
+
style[cellName] = 'font-weight:bold;';
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Row Height
|
|
326
|
+
if (content[j].style && content[j].style.height) {
|
|
327
|
+
rows[j] = { height: content[j].style.height };
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Index
|
|
331
|
+
rowNumber++;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Nested
|
|
336
|
+
if (Object.keys(nested).length > 0) {
|
|
337
|
+
options.nestedHeaders = nested;
|
|
338
|
+
}
|
|
339
|
+
// Style
|
|
340
|
+
if (Object.keys(style).length > 0) {
|
|
341
|
+
options.style = style;
|
|
342
|
+
}
|
|
343
|
+
// Merged
|
|
344
|
+
if (Object.keys(mergeCells).length > 0) {
|
|
345
|
+
options.mergeCells = mergeCells;
|
|
346
|
+
}
|
|
347
|
+
// Row height
|
|
348
|
+
if (Object.keys(rows).length > 0) {
|
|
349
|
+
options.rows = rows;
|
|
350
|
+
}
|
|
351
|
+
// Classes
|
|
352
|
+
if (Object.keys(classes).length > 0) {
|
|
353
|
+
options.classes = classes;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
content = el.querySelectorAll('tfoot tr');
|
|
357
|
+
if (content.length) {
|
|
358
|
+
const footers = [];
|
|
359
|
+
for (let j = 0; j < content.length; j++) {
|
|
360
|
+
let footer = [];
|
|
361
|
+
for (let i = 0; i < content[j].children.length; i++) {
|
|
362
|
+
footer.push(content[j].children[i].textContent);
|
|
363
|
+
}
|
|
364
|
+
footers.push(footer);
|
|
365
|
+
}
|
|
366
|
+
if (Object.keys(footers).length > 0) {
|
|
367
|
+
options.footers = footers;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// TODO: data-hiddencolumns="3,4"
|
|
371
|
+
|
|
372
|
+
// I guess in terms the better column type
|
|
373
|
+
if (options.parseTableAutoCellType == true) {
|
|
374
|
+
const pattern = [];
|
|
375
|
+
for (let i = 0; i < options.columns.length; i++) {
|
|
376
|
+
let test = true;
|
|
377
|
+
let testCalendar = true;
|
|
378
|
+
pattern[i] = [];
|
|
379
|
+
for (let j = 0; j < options.data.length; j++) {
|
|
380
|
+
const value = options.data[j][i];
|
|
381
|
+
if (!pattern[i][value]) {
|
|
382
|
+
pattern[i][value] = 0;
|
|
383
|
+
}
|
|
384
|
+
pattern[i][value]++;
|
|
385
|
+
if (value.length > 25) {
|
|
386
|
+
test = false;
|
|
387
|
+
}
|
|
388
|
+
if (value.length == 10) {
|
|
389
|
+
if (!(value.substr(4, 1) == '-' && value.substr(7, 1) == '-')) {
|
|
390
|
+
testCalendar = false;
|
|
391
|
+
}
|
|
392
|
+
} else {
|
|
393
|
+
testCalendar = false;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const keys = Object.keys(pattern[i]).length;
|
|
398
|
+
if (testCalendar) {
|
|
399
|
+
options.columns[i].type = 'calendar';
|
|
400
|
+
} else if (test == true && keys > 1 && keys <= parseInt(options.data.length * 0.1)) {
|
|
401
|
+
options.columns[i].type = 'dropdown';
|
|
402
|
+
options.columns[i].source = Object.keys(pattern[i]);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return options;
|
|
408
|
+
}
|
|
409
|
+
};
|