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.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +292 -0
  3. package/dist/index.d.ts +2382 -0
  4. package/dist/index.js +11286 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/jspreadsheet.css +723 -0
  7. package/dist/jspreadsheet.themes.css +104 -0
  8. package/package.json +57 -0
  9. package/src/index.js +95 -0
  10. package/src/test.js +50 -0
  11. package/src/utils/cells.js +36 -0
  12. package/src/utils/columns.js +742 -0
  13. package/src/utils/comments.js +87 -0
  14. package/src/utils/config.js +46 -0
  15. package/src/utils/copyPaste.js +438 -0
  16. package/src/utils/data.js +419 -0
  17. package/src/utils/dispatch.js +115 -0
  18. package/src/utils/download.js +38 -0
  19. package/src/utils/editor.js +430 -0
  20. package/src/utils/events.js +1639 -0
  21. package/src/utils/factory.js +216 -0
  22. package/src/utils/filter.js +128 -0
  23. package/src/utils/footer.js +51 -0
  24. package/src/utils/freeze.js +19 -0
  25. package/src/utils/headers.js +74 -0
  26. package/src/utils/helpers.js +409 -0
  27. package/src/utils/history.js +336 -0
  28. package/src/utils/internal.js +1299 -0
  29. package/src/utils/internalHelpers.js +96 -0
  30. package/src/utils/keys.js +406 -0
  31. package/src/utils/lazyLoading.js +143 -0
  32. package/src/utils/libraryBase.js +5 -0
  33. package/src/utils/merges.js +275 -0
  34. package/src/utils/meta.js +81 -0
  35. package/src/utils/orderBy.js +185 -0
  36. package/src/utils/pagination.js +181 -0
  37. package/src/utils/rows.js +624 -0
  38. package/src/utils/search.js +83 -0
  39. package/src/utils/selection.js +744 -0
  40. package/src/utils/style.js +147 -0
  41. package/src/utils/toolbar.js +566 -0
  42. package/src/utils/version.js +9 -0
  43. package/src/utils/worksheets.js +731 -0
  44. package/src/webcomponent.js +59 -0
@@ -0,0 +1,87 @@
1
+ import dispatch from './dispatch.js';
2
+ import { getCoordsFromCellName } from './helpers.js';
3
+ import { setHistory } from './history.js';
4
+ import { getColumnNameFromId, getIdFromColumnName } from './internalHelpers.js';
5
+
6
+ /**
7
+ * Get cell comments, null cell for all
8
+ */
9
+ export const getComments = function (cell) {
10
+ const obj = this;
11
+
12
+ if (cell) {
13
+ if (typeof cell !== 'string') {
14
+ return getComments.call(obj);
15
+ }
16
+
17
+ cell = getIdFromColumnName(cell, true);
18
+
19
+ return obj.records[cell[1]][cell[0]].element.getAttribute('title') || '';
20
+ } else {
21
+ const data = {};
22
+ for (let j = 0; j < obj.options.data.length; j++) {
23
+ for (let i = 0; i < obj.options.columns.length; i++) {
24
+ const comments = obj.records[j][i].element.getAttribute('title');
25
+ if (comments) {
26
+ const cell = getColumnNameFromId([i, j]);
27
+ data[cell] = comments;
28
+ }
29
+ }
30
+ }
31
+ return data;
32
+ }
33
+ };
34
+
35
+ /**
36
+ * Set cell comments
37
+ */
38
+ export const setComments = function (cellId, comments) {
39
+ const obj = this;
40
+
41
+ let commentsObj;
42
+
43
+ if (typeof cellId == 'string') {
44
+ commentsObj = { [cellId]: comments };
45
+ } else {
46
+ commentsObj = cellId;
47
+ }
48
+
49
+ const oldValue = {};
50
+
51
+ Object.entries(commentsObj).forEach(function ([cellName, comment]) {
52
+ const cellCoords = getCoordsFromCellName(cellName);
53
+
54
+ // Keep old value
55
+ oldValue[cellName] = obj.records[cellCoords[1]][cellCoords[0]].element.getAttribute('title');
56
+
57
+ // Set new values
58
+ obj.records[cellCoords[1]][cellCoords[0]].element.setAttribute('title', comment ? comment : '');
59
+
60
+ // Remove class if there is no comment
61
+ if (comment) {
62
+ obj.records[cellCoords[1]][cellCoords[0]].element.classList.add('jss_comments');
63
+
64
+ if (!obj.options.comments) {
65
+ obj.options.comments = {};
66
+ }
67
+
68
+ obj.options.comments[cellName] = comment;
69
+ } else {
70
+ obj.records[cellCoords[1]][cellCoords[0]].element.classList.remove('jss_comments');
71
+
72
+ if (obj.options.comments && obj.options.comments[cellName]) {
73
+ delete obj.options.comments[cellName];
74
+ }
75
+ }
76
+ });
77
+
78
+ // Save history
79
+ setHistory.call(obj, {
80
+ action: 'setComments',
81
+ newValue: commentsObj,
82
+ oldValue: oldValue,
83
+ });
84
+
85
+ // Set comments
86
+ dispatch.call(obj, 'oncomments', obj, commentsObj, oldValue);
87
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Get table config information
3
+ */
4
+ export const getWorksheetConfig = function () {
5
+ const obj = this;
6
+
7
+ return obj.options;
8
+ };
9
+
10
+ export const getSpreadsheetConfig = function () {
11
+ const spreadsheet = this;
12
+
13
+ return spreadsheet.config;
14
+ };
15
+
16
+ export const setConfig = function (config, spreadsheetLevel) {
17
+ const obj = this;
18
+
19
+ const keys = Object.keys(config);
20
+
21
+ let spreadsheet;
22
+
23
+ if (!obj.parent) {
24
+ spreadsheetLevel = true;
25
+
26
+ spreadsheet = obj;
27
+ } else {
28
+ spreadsheet = obj.parent;
29
+ }
30
+
31
+ keys.forEach(function (key) {
32
+ if (spreadsheetLevel) {
33
+ spreadsheet.config[key] = config[key];
34
+
35
+ if (key === 'toolbar') {
36
+ if (config[key] === true) {
37
+ spreadsheet.showToolbar();
38
+ } else if (config[key] === false) {
39
+ spreadsheet.hideToolbar();
40
+ }
41
+ }
42
+ } else {
43
+ obj.options[key] = config[key];
44
+ }
45
+ });
46
+ };
@@ -0,0 +1,438 @@
1
+ import jSuites from 'jsuites';
2
+
3
+ import { parseCSV } from './helpers.js';
4
+ import dispatch from './dispatch.js';
5
+ import { setHistory } from './history.js';
6
+ import { updateCell, updateFormulaChain, updateTable, updateTableReferences } from './internal.js';
7
+ import { downGet, rightGet } from './keys.js';
8
+ import { hash, removeCopyingSelection, updateSelectionFromCoords } from './selection.js';
9
+ import { getColumnNameFromId } from './internalHelpers.js';
10
+
11
+ /**
12
+ * Copy method
13
+ *
14
+ * @param bool highlighted - Get only highlighted cells
15
+ * @param delimiter - \t default to keep compatibility with excel
16
+ * @return string value
17
+ */
18
+ export const copy = function (highlighted, delimiter, returnData, includeHeaders, download, isCut, processed) {
19
+ const obj = this;
20
+
21
+ if (!delimiter) {
22
+ delimiter = '\t';
23
+ }
24
+
25
+ const div = new RegExp(delimiter, 'ig');
26
+
27
+ // Controls
28
+ const header = [];
29
+ let col = [];
30
+ let colLabel = [];
31
+ const row = [];
32
+ const rowLabel = [];
33
+ const x = obj.options.data[0].length;
34
+ const y = obj.options.data.length;
35
+ let tmp = '';
36
+ let copyHeader = false;
37
+ let headers = '';
38
+ let nestedHeaders = '';
39
+ let numOfCols = 0;
40
+ let numOfRows = 0;
41
+
42
+ // Partial copy
43
+ let copyX = 0;
44
+ let copyY = 0;
45
+ let isPartialCopy = true;
46
+ // Go through the columns to get the data
47
+ for (let j = 0; j < y; j++) {
48
+ for (let i = 0; i < x; i++) {
49
+ // If cell is highlighted
50
+ if (!highlighted || obj.records[j][i].element.classList.contains('highlight')) {
51
+ if (copyX <= i) {
52
+ copyX = i;
53
+ }
54
+ if (copyY <= j) {
55
+ copyY = j;
56
+ }
57
+ }
58
+ }
59
+ }
60
+ if (x === copyX + 1 && y === copyY + 1) {
61
+ isPartialCopy = false;
62
+ }
63
+
64
+ if (download && (obj.parent.config.includeHeadersOnDownload == true || includeHeaders)) {
65
+ // Nested headers
66
+ if (obj.options.nestedHeaders && obj.options.nestedHeaders.length > 0) {
67
+ tmp = obj.options.nestedHeaders;
68
+
69
+ for (let j = 0; j < tmp.length; j++) {
70
+ const nested = [];
71
+ for (let i = 0; i < tmp[j].length; i++) {
72
+ const colspan = parseInt(tmp[j][i].colspan);
73
+ nested.push(tmp[j][i].title);
74
+ for (let c = 0; c < colspan - 1; c++) {
75
+ nested.push('');
76
+ }
77
+ }
78
+ nestedHeaders += nested.join(delimiter) + '\r\n';
79
+ }
80
+ }
81
+
82
+ copyHeader = true;
83
+ }
84
+
85
+ // Reset container
86
+ obj.style = [];
87
+
88
+ // Go through the columns to get the data
89
+ for (let j = 0; j < y; j++) {
90
+ col = [];
91
+ colLabel = [];
92
+
93
+ for (let i = 0; i < x; i++) {
94
+ // If cell is highlighted
95
+ if (!highlighted || obj.records[j][i].element.classList.contains('highlight')) {
96
+ if (copyHeader == true) {
97
+ header.push(obj.headers[i].textContent);
98
+ }
99
+ // Values
100
+ let value = obj.options.data[j][i];
101
+ if (value.match && (value.match(div) || value.match(/,/g) || value.match(/\n/) || value.match(/"/))) {
102
+ value = value.replace(new RegExp('"', 'g'), '""');
103
+ value = '"' + value + '"';
104
+ }
105
+ col.push(value);
106
+
107
+ // Labels
108
+ let label;
109
+
110
+ if (obj.options.columns && obj.options.columns[i] && (obj.options.columns[i].type == 'checkbox' || obj.options.columns[i].type == 'radio')) {
111
+ label = value;
112
+ } else {
113
+ label = obj.records[j][i].element.innerHTML;
114
+ if (label.match && (label.match(div) || label.match(/,/g) || label.match(/\n/) || label.match(/"/))) {
115
+ // Scape double quotes
116
+ label = label.replace(new RegExp('"', 'g'), '""');
117
+ label = '"' + label + '"';
118
+ }
119
+ }
120
+ colLabel.push(label);
121
+
122
+ // Get style
123
+ tmp = obj.records[j][i].element.getAttribute('style');
124
+ tmp = tmp.replace('display: none;', '');
125
+ obj.style.push(tmp ? tmp : '');
126
+ }
127
+ }
128
+
129
+ if (col.length) {
130
+ if (copyHeader) {
131
+ numOfCols = col.length;
132
+ row.push(header.join(delimiter));
133
+ }
134
+ row.push(col.join(delimiter));
135
+ }
136
+ if (colLabel.length) {
137
+ numOfRows++;
138
+ if (copyHeader) {
139
+ rowLabel.push(header.join(delimiter));
140
+ copyHeader = false;
141
+ }
142
+ rowLabel.push(colLabel.join(delimiter));
143
+ }
144
+ }
145
+
146
+ if (x == numOfCols && y == numOfRows) {
147
+ headers = nestedHeaders;
148
+ }
149
+
150
+ // Final string
151
+ const str = headers + row.join('\r\n');
152
+ let strLabel = headers + rowLabel.join('\r\n');
153
+
154
+ // Create a hidden textarea to copy the values
155
+ if (!returnData) {
156
+ // Paste event
157
+ const selectedRange = [
158
+ Math.min(obj.selectedCell[0], obj.selectedCell[2]),
159
+ Math.min(obj.selectedCell[1], obj.selectedCell[3]),
160
+ Math.max(obj.selectedCell[0], obj.selectedCell[2]),
161
+ Math.max(obj.selectedCell[1], obj.selectedCell[3]),
162
+ ];
163
+
164
+ const result = dispatch.call(obj, 'oncopy', obj, selectedRange, strLabel, isCut);
165
+
166
+ if (result) {
167
+ strLabel = result;
168
+ } else if (result === false) {
169
+ return false;
170
+ }
171
+
172
+ obj.textarea.value = strLabel;
173
+ obj.textarea.select();
174
+ document.execCommand('copy');
175
+ }
176
+
177
+ // Keep data
178
+ if (processed == true) {
179
+ obj.data = strLabel;
180
+ } else {
181
+ obj.data = str;
182
+ }
183
+ // Keep non visible information
184
+ obj.hashString = hash.call(obj, obj.data);
185
+
186
+ // Any exiting border should go
187
+ if (!returnData) {
188
+ removeCopyingSelection.call(obj);
189
+
190
+ // Border
191
+ if (obj.highlighted) {
192
+ for (let i = 0; i < obj.highlighted.length; i++) {
193
+ obj.highlighted[i].element.classList.add('copying');
194
+ if (obj.highlighted[i].element.classList.contains('highlight-left')) {
195
+ obj.highlighted[i].element.classList.add('copying-left');
196
+ }
197
+ if (obj.highlighted[i].element.classList.contains('highlight-right')) {
198
+ obj.highlighted[i].element.classList.add('copying-right');
199
+ }
200
+ if (obj.highlighted[i].element.classList.contains('highlight-top')) {
201
+ obj.highlighted[i].element.classList.add('copying-top');
202
+ }
203
+ if (obj.highlighted[i].element.classList.contains('highlight-bottom')) {
204
+ obj.highlighted[i].element.classList.add('copying-bottom');
205
+ }
206
+ }
207
+ }
208
+ }
209
+
210
+ return obj.data;
211
+ };
212
+
213
+ /**
214
+ * Jspreadsheet paste method
215
+ *
216
+ * @param x target column
217
+ * @param y target row
218
+ * @param data paste data. if data hash is the same as the copied data, apply style from copied cells
219
+ * @return string value
220
+ */
221
+ export const paste = function (x, y, data) {
222
+ const obj = this;
223
+
224
+ // Controls
225
+ const dataHash = hash(data);
226
+ let style = dataHash == obj.hashString ? obj.style : null;
227
+
228
+ // Depending on the behavior
229
+ if (dataHash == obj.hashString) {
230
+ data = obj.data;
231
+ }
232
+
233
+ // Split new line
234
+ data = parseCSV(data, '\t');
235
+
236
+ const ex = obj.selectedCell[2];
237
+ const ey = obj.selectedCell[3];
238
+
239
+ const w = ex - x + 1;
240
+ const h = ey - y + 1;
241
+
242
+ // Modify data to allow wor extending paste range in multiples of input range
243
+ const srcW = data[0].length;
244
+ if ((w > 1) & Number.isInteger(w / srcW)) {
245
+ const repeats = w / srcW;
246
+ if (style) {
247
+ const newStyle = [];
248
+ for (let i = 0; i < style.length; i += srcW) {
249
+ const chunk = style.slice(i, i + srcW);
250
+ for (let j = 0; j < repeats; j++) {
251
+ newStyle.push(...chunk);
252
+ }
253
+ }
254
+ style = newStyle;
255
+ }
256
+
257
+ const arrayB = data.map(function (row, i) {
258
+ const arrayC = Array.apply(null, { length: repeats * row.length }).map(function (e, i) {
259
+ return row[i % row.length];
260
+ });
261
+ return arrayC;
262
+ });
263
+ data = arrayB;
264
+ }
265
+ const srcH = data.length;
266
+ if ((h > 1) & Number.isInteger(h / srcH)) {
267
+ const repeats = h / srcH;
268
+ if (style) {
269
+ const newStyle = [];
270
+ for (let j = 0; j < repeats; j++) {
271
+ newStyle.push(...style);
272
+ }
273
+ style = newStyle;
274
+ }
275
+ const arrayB = Array.apply(null, { length: repeats * srcH }).map(function (e, i) {
276
+ return data[i % srcH];
277
+ });
278
+ data = arrayB;
279
+ }
280
+
281
+ // Paste filter
282
+ const ret = dispatch.call(
283
+ obj,
284
+ 'onbeforepaste',
285
+ obj,
286
+ data.map(function (row) {
287
+ return row.map(function (item) {
288
+ return { value: item };
289
+ });
290
+ }),
291
+ x,
292
+ y
293
+ );
294
+
295
+ if (ret === false) {
296
+ return false;
297
+ } else if (ret) {
298
+ data = ret;
299
+ }
300
+
301
+ if (x != null && y != null && data) {
302
+ // Records
303
+ let i = 0;
304
+ let j = 0;
305
+ const records = [];
306
+ const newStyle = {};
307
+ const oldStyle = {};
308
+ let styleIndex = 0;
309
+
310
+ // Index
311
+ let colIndex = parseInt(x);
312
+ let rowIndex = parseInt(y);
313
+ let row = null;
314
+
315
+ const hiddenColCount = obj.headers.slice(colIndex).filter((x) => x.style.display === 'none').length;
316
+ const expandedColCount = colIndex + hiddenColCount + data[0].length;
317
+ const currentColCount = obj.headers.length;
318
+ if (expandedColCount > currentColCount) {
319
+ obj.skipUpdateTableReferences = true;
320
+ obj.insertColumn(expandedColCount - currentColCount);
321
+ }
322
+ const hiddenRowCount = obj.rows.slice(rowIndex).filter((x) => x.element.style.display === 'none').length;
323
+ const expandedRowCount = rowIndex + hiddenRowCount + data.length;
324
+ const currentRowCount = obj.rows.length;
325
+ if (expandedRowCount > currentRowCount) {
326
+ obj.skipUpdateTableReferences = true;
327
+ obj.insertRow(expandedRowCount - currentRowCount);
328
+ }
329
+
330
+ if (obj.skipUpdateTableReferences) {
331
+ obj.skipUpdateTableReferences = false;
332
+ updateTableReferences.call(obj);
333
+ }
334
+
335
+ // Go through the columns to get the data
336
+ while ((row = data[j])) {
337
+ i = 0;
338
+ colIndex = parseInt(x);
339
+
340
+ while (row[i] != null) {
341
+ let value = row[i];
342
+
343
+ if (obj.options.columns && obj.options.columns[i] && obj.options.columns[i].type == 'calendar') {
344
+ value = jSuites.calendar.extractDateFromString(
345
+ value,
346
+ (obj.options.columns[i].options && obj.options.columns[i].options.format) || 'YYYY-MM-DD'
347
+ );
348
+ }
349
+
350
+ // Update and keep history
351
+ const record = updateCell.call(obj, colIndex, rowIndex, value);
352
+ // Keep history
353
+ records.push(record);
354
+ // Update all formulas in the chain
355
+ updateFormulaChain.call(obj, colIndex, rowIndex, records);
356
+ // Style
357
+ if (style && style[styleIndex]) {
358
+ const columnName = getColumnNameFromId([colIndex, rowIndex]);
359
+ newStyle[columnName] = style[styleIndex];
360
+ oldStyle[columnName] = obj.getStyle(columnName);
361
+ obj.records[rowIndex][colIndex].element.setAttribute('style', style[styleIndex]);
362
+ styleIndex++;
363
+ }
364
+ i++;
365
+ if (row[i] != null) {
366
+ if (colIndex >= obj.headers.length - 1) {
367
+ // If the pasted column is out of range, create it if possible
368
+ if (obj.options.allowInsertColumn != false) {
369
+ obj.insertColumn();
370
+ // Otherwise skip the pasted data that overflows
371
+ } else {
372
+ break;
373
+ }
374
+ }
375
+ colIndex = rightGet.call(obj, colIndex, rowIndex);
376
+ }
377
+ }
378
+
379
+ j++;
380
+ if (data[j]) {
381
+ if (rowIndex >= obj.rows.length - 1) {
382
+ // If the pasted row is out of range, create it if possible
383
+ if (obj.options.allowInsertRow != false) {
384
+ obj.insertRow();
385
+ // Otherwise skip the pasted data that overflows
386
+ } else {
387
+ break;
388
+ }
389
+ }
390
+ rowIndex = downGet.call(obj, x, rowIndex);
391
+ }
392
+ }
393
+
394
+ // Select the new cells
395
+ updateSelectionFromCoords.call(obj, x, y, colIndex, rowIndex);
396
+
397
+ // Update history
398
+ setHistory.call(obj, {
399
+ action: 'setValue',
400
+ records: records,
401
+ selection: obj.selectedCell,
402
+ newStyle: newStyle,
403
+ oldStyle: oldStyle,
404
+ });
405
+
406
+ // Update table
407
+ updateTable.call(obj);
408
+
409
+ // Paste event
410
+ const eventRecords = [];
411
+
412
+ for (let j = 0; j < data.length; j++) {
413
+ for (let i = 0; i < data[j].length; i++) {
414
+ eventRecords.push({
415
+ x: i + x,
416
+ y: j + y,
417
+ value: data[j][i],
418
+ });
419
+ }
420
+ }
421
+
422
+ dispatch.call(obj, 'onpaste', obj, eventRecords);
423
+
424
+ // On after changes
425
+ const onafterchangesRecords = records.map(function (record) {
426
+ return {
427
+ x: record.x,
428
+ y: record.y,
429
+ value: record.value,
430
+ oldValue: record.oldValue,
431
+ };
432
+ });
433
+
434
+ dispatch.call(obj, 'onafterchanges', obj, onafterchangesRecords);
435
+ }
436
+
437
+ removeCopyingSelection();
438
+ };