itsa-react-table 16.8.0 → 16.8.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/lib/component.jsx CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';
1
+ "use strict";
2
2
 
3
3
  /**
4
4
  * Description here
@@ -12,1265 +12,1475 @@
12
12
  * @module component.jsx
13
13
  * @class Component
14
14
  * @since 2.0.0
15
- */
15
+ */
16
16
 
17
- require('itsa-jsext');
18
- require('itsa-dom');
17
+ require("itsa-jsext");
18
+ require("itsa-dom");
19
19
 
20
- const React = require('react'),
21
- PropTypes = require('prop-types'),
22
- utils = require('itsa-utils'),
23
- async = utils.async,
24
- later = utils.later,
25
- Button = require('itsa-react-button'),
26
- serializeStyles = require('./serialize-styles'),
27
- CLICK = 'click',
28
- RESIZE = 'resize',
29
- MAIN_CLASS = 'itsa-table',
30
- ROW_CLASS = 'itsa-table-row',
31
- CELL_CLASS = 'itsa-table-cell itsa-table-col-',
32
- EDITABLE_CELL_CLASS_SPACED = ' itsa-table-editable-cell',
33
- ROW_REMOVE_CLASS = '__row-remove',
34
- ROW_ADD_CLASS = '__row-add',
35
- REGEXP_TRANSPARENT = /^rgba\(\d+\,( )?\d+\,( )?\d+\,( )?0\)$/,
36
- COPY_STYLES = [
37
- 'width',
38
- 'height',
39
- 'padding-left',
40
- 'padding-right',
41
- 'padding-top',
42
- 'padding-bottom',
43
- 'border-top-color',
44
- 'border-top-left-radius',
45
- 'border-top-right-radius',
46
- 'border-top-style',
47
- 'border-top-width',
48
- 'border-bottom-color',
49
- 'border-bottom-left-radius',
50
- 'border-bottom-right-radius',
51
- 'border-bottom-style',
52
- 'border-bottom-width',
53
- 'border-left-color',
54
- 'border-left-style',
55
- 'border-left-width',
56
- 'border-right-color',
57
- 'border-right-style',
58
- 'border-right-width',
59
- 'background-color',
60
- 'background-image',
61
- 'background-attachment',
62
- 'background-blend-mode',
63
- 'background-clip',
64
- 'background-origin',
65
- 'background-position-x',
66
- 'background-position-y',
67
- 'background-repeat-x',
68
- 'background-repeat-y',
69
- 'background-size',
70
- 'color',
71
- 'font-family',
72
- 'font-feature-settings',
73
- 'font-kerning',
74
- 'font-size',
75
- 'font-stretch',
76
- 'font-style',
77
- 'font-variant-caps',
78
- 'font-variant-east-asian',
79
- 'font-variant-ligatures',
80
- 'font-variant-numeric',
81
- 'font-variant-settings',
82
- 'font-weight',
83
- 'font-smooting',
84
- 'font-size-delta',
85
- 'opacity',
86
- 'overflow',
87
- 'white-space',
88
- 'visibility',
89
- '-webkit-font-smooting',
90
- '-webkit-font-size-delta',
91
- '-ms-font-smooting',
92
- '-ms-font-size-delta',
93
- 'text-align',
94
- 'text-align-last',
95
- 'text-combine-upright',
96
- 'text-decoration-color',
97
- 'text-decoration-line',
98
- 'text-decoration-skip-ink',
99
- 'text-decoration-style',
100
- 'text-indent',
101
- 'text-orientation',
102
- 'text-overflow',
103
- 'text-rendering',
104
- 'text-shadow',
105
- 'text-size-adjust',
106
- 'text-transform',
107
- 'text-underline-position',
108
- '-webkit-text-align',
109
- '-webkit-text-combine',
110
- '-webkit-text-decorations-in-effect',
111
- '-webkit-text-emphasis-color',
112
- '-webkit-text-emphasis-position',
113
- '-webkit-text-emphasis-style',
114
- '-webkit-text-fill-color',
115
- '-webkit-text-orientation',
116
- '-webkit-text-security',
117
- '-webkit-text-stroke-color',
118
- '-webkit-text-stroke-width',
119
- '-ms-text-align',
120
- '-ms-text-combine',
121
- '-ms-text-decorations-in-effect',
122
- '-ms-text-emphasis-color',
123
- '-ms-text-emphasis-position',
124
- '-ms-text-emphasis-style',
125
- '-ms-text-fill-color',
126
- '-ms-text-orientation',
127
- '-ms-text-security',
128
- '-ms-text-stroke-color',
129
- '-ms-text-stroke-width'
130
- ];
20
+ const React = require("react"),
21
+ PropTypes = require("prop-types"),
22
+ utils = require("itsa-utils"),
23
+ async = utils.async,
24
+ later = utils.later,
25
+ Button = require("itsa-react-button"),
26
+ serializeStyles = require("./serialize-styles"),
27
+ CLICK = "click",
28
+ RESIZE = "resize",
29
+ MAIN_CLASS = "itsa-table",
30
+ ROW_CLASS = "itsa-table-row",
31
+ CELL_CLASS = "itsa-table-cell itsa-table-col-",
32
+ EDITABLE_CELL_CLASS_SPACED = " itsa-table-editable-cell",
33
+ ROW_REMOVE_CLASS = "__row-remove",
34
+ ROW_ADD_CLASS = "__row-add",
35
+ REGEXP_TRANSPARENT = /^rgba\(\d+\,( )?\d+\,( )?\d+\,( )?0\)$/,
36
+ COPY_STYLES = [
37
+ "width",
38
+ "height",
39
+ "padding-left",
40
+ "padding-right",
41
+ "padding-top",
42
+ "padding-bottom",
43
+ "border-top-color",
44
+ "border-top-left-radius",
45
+ "border-top-right-radius",
46
+ "border-top-style",
47
+ "border-top-width",
48
+ "border-bottom-color",
49
+ "border-bottom-left-radius",
50
+ "border-bottom-right-radius",
51
+ "border-bottom-style",
52
+ "border-bottom-width",
53
+ "border-left-color",
54
+ "border-left-style",
55
+ "border-left-width",
56
+ "border-right-color",
57
+ "border-right-style",
58
+ "border-right-width",
59
+ "background-color",
60
+ "background-image",
61
+ "background-attachment",
62
+ "background-blend-mode",
63
+ "background-clip",
64
+ "background-origin",
65
+ "background-position-x",
66
+ "background-position-y",
67
+ "background-repeat-x",
68
+ "background-repeat-y",
69
+ "background-size",
70
+ "color",
71
+ "font-family",
72
+ "font-feature-settings",
73
+ "font-kerning",
74
+ "font-size",
75
+ "font-stretch",
76
+ "font-style",
77
+ "font-variant-caps",
78
+ "font-variant-east-asian",
79
+ "font-variant-ligatures",
80
+ "font-variant-numeric",
81
+ "font-variant-settings",
82
+ "font-weight",
83
+ "font-smooting",
84
+ "font-size-delta",
85
+ "opacity",
86
+ "overflow",
87
+ "white-space",
88
+ "visibility",
89
+ "-webkit-font-smooting",
90
+ "-webkit-font-size-delta",
91
+ "-ms-font-smooting",
92
+ "-ms-font-size-delta",
93
+ "text-align",
94
+ "text-align-last",
95
+ "text-combine-upright",
96
+ "text-decoration-color",
97
+ "text-decoration-line",
98
+ "text-decoration-skip-ink",
99
+ "text-decoration-style",
100
+ "text-indent",
101
+ "text-orientation",
102
+ "text-overflow",
103
+ "text-rendering",
104
+ "text-shadow",
105
+ "text-size-adjust",
106
+ "text-transform",
107
+ "text-underline-position",
108
+ "-webkit-text-align",
109
+ "-webkit-text-combine",
110
+ "-webkit-text-decorations-in-effect",
111
+ "-webkit-text-emphasis-color",
112
+ "-webkit-text-emphasis-position",
113
+ "-webkit-text-emphasis-style",
114
+ "-webkit-text-fill-color",
115
+ "-webkit-text-orientation",
116
+ "-webkit-text-security",
117
+ "-webkit-text-stroke-color",
118
+ "-webkit-text-stroke-width",
119
+ "-ms-text-align",
120
+ "-ms-text-combine",
121
+ "-ms-text-decorations-in-effect",
122
+ "-ms-text-emphasis-color",
123
+ "-ms-text-emphasis-position",
124
+ "-ms-text-emphasis-style",
125
+ "-ms-text-fill-color",
126
+ "-ms-text-orientation",
127
+ "-ms-text-security",
128
+ "-ms-text-stroke-color",
129
+ "-ms-text-stroke-width",
130
+ ];
131
131
 
132
- const retrieveFieldName = field => {
133
- return (typeof field==='object') ? field.key : field;
132
+ const retrieveFieldName = (field) => {
133
+ return typeof field === "object" ? field.key : field;
134
134
  };
135
135
 
136
- const cloneData = arr => {
137
- return arr.map(record => {
138
- let newRecord = {};
139
- record.itsa_each((value, key) => {
140
- newRecord[key] = value;
141
- });
142
- return newRecord;
136
+ const cloneData = (arr) => {
137
+ return arr.map((record) => {
138
+ let newRecord = {};
139
+ record.itsa_each((value, key) => {
140
+ newRecord[key] = value;
143
141
  });
142
+ return newRecord;
143
+ });
144
144
  };
145
145
 
146
146
  class Table extends React.Component {
147
- constructor(props) {
148
- super(props);
149
- const instance = this;
150
- instance.state = {
151
- editableRow: null,
152
- editableCol: null,
153
- editValue: ''
154
- };
155
- instance.changeCell = instance.changeCell.bind(instance);
156
- instance.handleCellKeyDown = instance.handleCellKeyDown.bind(instance);
157
- instance.focus = instance.focus.bind(instance);
158
- instance._focusActiveCell = instance._focusActiveCell.bind(instance);
159
- instance.generateHead = instance.generateHead.bind(instance);
160
- instance.generateRows = instance.generateRows.bind(instance);
161
- instance.refocus = instance.refocus.bind(instance);
162
- instance.addRow = instance.addRow.bind(instance);
163
- instance.addCol = instance.addCol.bind(instance);
164
- instance.deleteRow = instance.deleteRow.bind(instance);
165
- instance._handleDocumentClick = instance._handleDocumentClick.bind(instance);
166
- instance._handleResize = instance._handleResize.bind(instance);
167
- instance.focusTextArea = instance.focusTextArea.bind(instance);
168
- instance.setFixedHeaderDimensions = instance.setFixedHeaderDimensions.bind(instance);
169
- }
147
+ constructor(props) {
148
+ super(props);
149
+ const instance = this;
150
+ instance.state = {
151
+ editableRow: null,
152
+ editableCol: null,
153
+ editValue: "",
154
+ };
155
+ instance.changeCell = instance.changeCell.bind(instance);
156
+ instance.handleCellKeyDown = instance.handleCellKeyDown.bind(instance);
157
+ instance.focus = instance.focus.bind(instance);
158
+ instance._focusActiveCell = instance._focusActiveCell.bind(instance);
159
+ instance.generateHead = instance.generateHead.bind(instance);
160
+ instance.generateRows = instance.generateRows.bind(instance);
161
+ instance.refocus = instance.refocus.bind(instance);
162
+ instance.addRow = instance.addRow.bind(instance);
163
+ instance.addCol = instance.addCol.bind(instance);
164
+ instance.deleteRow = instance.deleteRow.bind(instance);
165
+ instance._handleDocumentClick =
166
+ instance._handleDocumentClick.bind(instance);
167
+ instance._handleResize = instance._handleResize.bind(instance);
168
+ instance.focusTextArea = instance.focusTextArea.bind(instance);
169
+ instance.setFixedHeaderDimensions =
170
+ instance.setFixedHeaderDimensions.bind(instance);
171
+ }
170
172
 
171
- componentDidMount() {
172
- const instance = this,
173
- props = instance.props;
174
- instance._tableWidth = instance._tableNode.offsetWidth;
175
- // set outside clickHandler which watches for outside clicks that will collapse the component:
176
- instance.IE8_EVENTS = !instance._componentNode.addEventListener;
177
- if (instance.IE8_EVENTS) {
178
- document.attachEvent('on'+CLICK, instance._handleDocumentClick);
179
- window.attachEvent('on'+RESIZE, instance._handleResize);
180
- }
181
- else {
182
- document.addEventListener(CLICK, instance._handleDocumentClick, true);
183
- window.addEventListener(RESIZE, instance._handleResize, true);
184
- }
185
- props.autoFocus && instance.focus();
186
- if (props.fixedHeaders) {
187
- async(instance.setFixedHeaderDimensions);
188
- instance._timer = later(instance.setFixedHeaderDimensions, 300, true);
189
- }
173
+ componentDidMount() {
174
+ const instance = this,
175
+ props = instance.props;
176
+ instance._tableWidth = instance._tableNode.offsetWidth;
177
+ // set outside clickHandler which watches for outside clicks that will collapse the component:
178
+ instance.IE8_EVENTS = !instance._componentNode.addEventListener;
179
+ if (instance.IE8_EVENTS) {
180
+ document.attachEvent("on" + CLICK, instance._handleDocumentClick);
181
+ window.attachEvent("on" + RESIZE, instance._handleResize);
182
+ } else {
183
+ document.addEventListener(CLICK, instance._handleDocumentClick, true);
184
+ window.addEventListener(RESIZE, instance._handleResize, true);
190
185
  }
191
-
192
- /**
193
- * componentWilUnmount does some cleanup.
194
- *
195
- * @method componentWillUnmount
196
- * @since 0.0.1
197
- */
198
- componentWillUnmount() {
199
- const instance = this;
200
- instance._timer && instance._timer.cancel();
201
- instance.unmounted = true;
202
- if (instance.IE8_EVENTS) {
203
- document.detachEvent('on'+CLICK, instance._handleDocumentClick);
204
- window.detachEvent('on'+RESIZE, instance._handleResize);
205
- }
206
- else {
207
- document.removeEventListener(CLICK, instance._handleDocumentClick, true);
208
- window.removeEventListener(RESIZE, instance._handleResize, true);
209
- }
186
+ props.autoFocus && instance.focus();
187
+ if (props.fixedHeaders) {
188
+ async(instance.setFixedHeaderDimensions);
189
+ instance._timer = later(instance.setFixedHeaderDimensions, 300, true);
210
190
  }
191
+ }
211
192
 
212
- componentDidUpdate() {
213
- this.setFixedHeaderDimensions();
193
+ /**
194
+ * componentWilUnmount does some cleanup.
195
+ *
196
+ * @method componentWillUnmount
197
+ * @since 0.0.1
198
+ */
199
+ componentWillUnmount() {
200
+ const instance = this;
201
+ instance._timer && instance._timer.cancel();
202
+ instance.unmounted = true;
203
+ if (instance.IE8_EVENTS) {
204
+ document.detachEvent("on" + CLICK, instance._handleDocumentClick);
205
+ window.detachEvent("on" + RESIZE, instance._handleResize);
206
+ } else {
207
+ document.removeEventListener(CLICK, instance._handleDocumentClick, true);
208
+ window.removeEventListener(RESIZE, instance._handleResize, true);
214
209
  }
210
+ }
215
211
 
216
- _handleResize() {
217
- const instance = this,
218
- newWidth = instance._tableNode.offsetWidth;
219
- if (instance._tableWidth!==newWidth) {
220
- instance._tableWidth = newWidth;
221
- instance.setFixedHeaderDimensions();
222
- }
223
- }
212
+ componentDidUpdate() {
213
+ this.setFixedHeaderDimensions();
214
+ }
224
215
 
225
- setFixedHeaderDimensions() {
226
- let headNode, ths;
227
- const instance = this,
228
- props = instance.props;
229
- if (props.fixedHeaders && props.columns && !instance.unmounted) {
230
- headNode = instance._headNode;
231
- if (headNode) {
232
- ths = headNode.itsa_getAll('th');
233
- Array.prototype.forEach.call(ths, thNode => {
234
- let inlineStyle = {},
235
- fixedNode, fixedContainerNode, contStyle, currentLeft, currentTop, prevAttr, newAttr;
236
- COPY_STYLES.forEach(style => {
237
- let nodeStyle = thNode.itsa_getStyle(style);
238
- if ((style==='background-color') && nodeStyle && REGEXP_TRANSPARENT.test(nodeStyle)) {
239
- nodeStyle = undefined; // fixed headers cannot be transparent -> revert to the class background-color
240
- }
241
- (nodeStyle===undefined) || (inlineStyle[style]=nodeStyle+' !important');
242
- });
243
- fixedContainerNode = thNode.itsa_getElement('div.itsa-table-header-cont');
244
- if (fixedContainerNode) {
245
- currentLeft = fixedContainerNode.itsa_getInlineStyle('left');
246
- if (currentLeft) {
247
- currentLeft = parseInt(currentLeft, 10);
248
- }
249
- else {
250
- currentLeft = 0;
251
- }
252
- currentTop = fixedContainerNode.itsa_getInlineStyle('top');
253
- if (currentTop) {
254
- currentTop = parseInt(currentTop, 10);
255
- }
256
- else {
257
- currentTop = 0;
258
- }
259
- contStyle = {
260
- left: (thNode.itsa_left-fixedContainerNode.itsa_left+currentLeft)+'px',
261
- top: (thNode.itsa_top-fixedContainerNode.itsa_top+currentTop)+'px'
262
- };
263
- prevAttr = fixedContainerNode.getAttribute('style');
264
- newAttr = serializeStyles.serialize(contStyle);
265
- (prevAttr===newAttr) || fixedContainerNode.setAttribute('style', newAttr);
266
- }
267
- fixedNode = thNode.itsa_getElement('div.itsa-table-header');
268
- if (fixedNode) {
269
- prevAttr = fixedNode.getAttribute('style');
270
- newAttr = serializeStyles.serialize(inlineStyle);
271
- (prevAttr===newAttr) || fixedNode.setAttribute('style', newAttr);
272
- }
273
- });
274
- }
275
- }
216
+ _handleResize() {
217
+ const instance = this,
218
+ newWidth = instance._tableNode.offsetWidth;
219
+ if (instance._tableWidth !== newWidth) {
220
+ instance._tableWidth = newWidth;
221
+ instance.setFixedHeaderDimensions();
276
222
  }
223
+ }
277
224
 
278
- changeCell(e) {
279
- const value = e.target.value;
280
- this._editValueBeforeBlur = value;
281
- this.setState({
282
- editValue: value
225
+ setFixedHeaderDimensions() {
226
+ let headNode, ths;
227
+ const instance = this,
228
+ props = instance.props;
229
+ if (props.fixedHeaders && props.columns && !instance.unmounted) {
230
+ headNode = instance._headNode;
231
+ if (headNode) {
232
+ ths = headNode.itsa_getAll("th");
233
+ Array.prototype.forEach.call(ths, (thNode) => {
234
+ let inlineStyle = {},
235
+ fixedNode,
236
+ fixedContainerNode,
237
+ contStyle,
238
+ currentLeft,
239
+ currentTop,
240
+ prevAttr,
241
+ newAttr;
242
+ COPY_STYLES.forEach((style) => {
243
+ let nodeStyle = thNode.itsa_getStyle(style);
244
+ if (
245
+ style === "background-color" &&
246
+ nodeStyle &&
247
+ REGEXP_TRANSPARENT.test(nodeStyle)
248
+ ) {
249
+ nodeStyle = undefined; // fixed headers cannot be transparent -> revert to the class background-color
250
+ }
251
+ nodeStyle === undefined ||
252
+ (inlineStyle[style] = nodeStyle + " !important");
253
+ });
254
+ fixedContainerNode = thNode.itsa_getElement(
255
+ "div.itsa-table-header-cont"
256
+ );
257
+ if (fixedContainerNode) {
258
+ currentLeft = fixedContainerNode.itsa_getInlineStyle("left");
259
+ if (currentLeft) {
260
+ currentLeft = parseInt(currentLeft, 10);
261
+ } else {
262
+ currentLeft = 0;
263
+ }
264
+ currentTop = fixedContainerNode.itsa_getInlineStyle("top");
265
+ if (currentTop) {
266
+ currentTop = parseInt(currentTop, 10);
267
+ } else {
268
+ currentTop = 0;
269
+ }
270
+ contStyle = {
271
+ left:
272
+ thNode.itsa_left -
273
+ fixedContainerNode.itsa_left +
274
+ currentLeft +
275
+ "px",
276
+ top:
277
+ thNode.itsa_top -
278
+ fixedContainerNode.itsa_top +
279
+ currentTop +
280
+ "px",
281
+ };
282
+ prevAttr = fixedContainerNode.getAttribute("style");
283
+ newAttr = serializeStyles.serialize(contStyle);
284
+ prevAttr === newAttr ||
285
+ fixedContainerNode.setAttribute("style", newAttr);
286
+ }
287
+ fixedNode = thNode.itsa_getElement("div.itsa-table-header");
288
+ if (fixedNode) {
289
+ prevAttr = fixedNode.getAttribute("style");
290
+ newAttr = serializeStyles.serialize(inlineStyle);
291
+ prevAttr === newAttr || fixedNode.setAttribute("style", newAttr);
292
+ }
283
293
  });
294
+ }
284
295
  }
296
+ }
285
297
 
286
- handleCellKeyDown(e) {
287
- const instance = this;
288
- if (e.keyCode===27) {
289
- instance.setState(prevState => {
290
- return {
291
- editValue: instance._editValueBeforeEdit,
292
- editableRow: null,
293
- editableCol: null
294
- };
295
- }, () => {
296
- instance._blurActiveCell();
297
- });
298
+ changeCell(e) {
299
+ const value = e.target.value;
300
+ this._editValueBeforeBlur = value;
301
+ this.setState({
302
+ editValue: value,
303
+ });
304
+ }
305
+
306
+ handleCellKeyDown(e) {
307
+ const instance = this;
308
+ if (e.keyCode === 27) {
309
+ instance.setState(
310
+ (prevState) => {
311
+ return {
312
+ editValue: instance._editValueBeforeEdit,
313
+ editableRow: null,
314
+ editableCol: null,
315
+ };
316
+ },
317
+ () => {
318
+ instance._blurActiveCell();
298
319
  }
320
+ );
299
321
  }
322
+ }
300
323
 
301
- implementCellChanges(rowIndex, field, force) {
302
- let changed, newData, col, secondField, x, y, columns, cells, editableCols;
303
- const instance = this,
304
- props = instance.props,
305
- propsData = props.data,
306
- state = instance.state,
307
- onChange = props.onChange,
308
- onChangeCell = props.onChangeCell,
309
- selectedRange = state.selectedRange,
310
- editValueBeforeBlur = instance._editValueBeforeBlur,
311
- editValueBeforeEdit = instance._editValueBeforeEdit;
324
+ implementCellChanges(rowIndex, field, force) {
325
+ let changed, newData, col, secondField, x, y, columns, cells, editableCols;
326
+ const instance = this,
327
+ props = instance.props,
328
+ propsData = props.data,
329
+ state = instance.state,
330
+ onChange = props.onChange,
331
+ onChangeCell = props.onChangeCell,
332
+ selectedRange = state.selectedRange,
333
+ editValueBeforeBlur = instance._editValueBeforeBlur,
334
+ editValueBeforeEdit = instance._editValueBeforeEdit;
312
335
 
313
- delete instance._editValueBeforeBlur;
314
- if (typeof field==='object') {
315
- field = field.key;
316
- }
336
+ delete instance._editValueBeforeBlur;
337
+ if (typeof field === "object") {
338
+ field = field.key;
339
+ }
317
340
 
318
- if (((editValueBeforeEdit===editValueBeforeBlur) && !selectedRange) || (editValueBeforeBlur===undefined)) {
319
- // nothing changed
320
- return;
321
- }
341
+ if (
342
+ (editValueBeforeEdit === editValueBeforeBlur && !selectedRange) ||
343
+ editValueBeforeBlur === undefined
344
+ ) {
345
+ // nothing changed
346
+ return;
347
+ }
322
348
 
323
- // if ((props.data[rowIndex][field]==editValueBeforeBlur) ||
324
- // ((props.data[rowIndex][field]===undefined) && (editValueBeforeBlur==='')) ||
325
- // ((props.data[rowIndex][field]===null) && (editValueBeforeBlur===''))) { // DO NOT tripple check -> the original value may not be a string, whereas the editvalue is!!
326
- // // nothing changed
327
- // return;
328
- // }
349
+ // if ((props.data[rowIndex][field]==editValueBeforeBlur) ||
350
+ // ((props.data[rowIndex][field]===undefined) && (editValueBeforeBlur==='')) ||
351
+ // ((props.data[rowIndex][field]===null) && (editValueBeforeBlur===''))) { // DO NOT tripple check -> the original value may not be a string, whereas the editvalue is!!
352
+ // // nothing changed
353
+ // return;
354
+ // }
329
355
 
330
- if (selectedRange) {
331
- // editableCols: PropTypes.oneOfType([PropTypes.array, PropTypes.number]),
332
- if (force!==true) {
333
- return;
334
- }
335
- columns = props.columns;
336
- if (!columns || (columns.length===0)) {
337
- columns = instance._columns;
338
- }
339
- editableCols = props.editableCols;
340
- if (typeof editableCols==='number') {
341
- editableCols = [editableCols];
342
- }
343
- }
344
- if (onChange) {
345
- changed = false;
346
- newData = cloneData(propsData);
347
- if (newData[rowIndex][field]!=editValueBeforeBlur) {
356
+ if (selectedRange) {
357
+ // editableCols: PropTypes.oneOfType([PropTypes.array, PropTypes.number]),
358
+ if (force !== true) {
359
+ return;
360
+ }
361
+ columns = props.columns;
362
+ if (!columns || columns.length === 0) {
363
+ columns = instance._columns;
364
+ }
365
+ editableCols = props.editableCols;
366
+ if (typeof editableCols === "number") {
367
+ editableCols = [editableCols];
368
+ }
369
+ }
370
+ if (onChange) {
371
+ changed = false;
372
+ newData = cloneData(propsData);
373
+ if (newData[rowIndex][field] != editValueBeforeBlur) {
374
+ changed = true;
375
+ newData[rowIndex][field] = editValueBeforeBlur;
376
+ }
377
+ // we might need to change multiple cells, in case `multiEdit` is set, which leads into a value for state.selectedRange:
378
+ if (selectedRange) {
379
+ // editableCols: PropTypes.oneOfType([PropTypes.array, PropTypes.number]),
380
+ for (x = selectedRange.x1; x <= selectedRange.x2; x++) {
381
+ if (!editableCols || editableCols.itsa_contains(x)) {
382
+ for (y = selectedRange.y1; y <= selectedRange.y2; y++) {
383
+ col = columns[x];
384
+ secondField = typeof col === "string" ? col : col.key;
385
+ if (newData[y][secondField] != editValueBeforeBlur) {
348
386
  changed = true;
349
- newData[rowIndex][field] = editValueBeforeBlur;
387
+ newData[y][secondField] = editValueBeforeBlur;
388
+ }
350
389
  }
351
- // we might need to change multiple cells, in case `multiEdit` is set, which leads into a value for state.selectedRange:
352
- if (selectedRange) {
353
- // editableCols: PropTypes.oneOfType([PropTypes.array, PropTypes.number]),
354
- for (x=selectedRange.x1; x<=selectedRange.x2; x++) {
355
- if (!editableCols || editableCols.itsa_contains(x)) {
356
- for (y=selectedRange.y1; y<=selectedRange.y2; y++) {
357
- col = columns[x];
358
- secondField = (typeof col==='string') ? col : col.key;
359
- if (newData[y][secondField]!=editValueBeforeBlur) {
360
- changed = true;
361
- newData[y][secondField] = editValueBeforeBlur;
362
- }
363
- }
364
- }
365
- }
366
- }
367
- changed && onChange(newData);
390
+ }
368
391
  }
369
- if (onChangeCell) {
370
- if (!props.multiEdit) {
371
- if (propsData[rowIndex][field]!=editValueBeforeBlur) {
372
- onChangeCell(rowIndex, field, editValueBeforeBlur);
373
- }
374
- }
375
- else {
376
- changed = false;
377
- cells = [{row: rowIndex, field}];
378
- if (propsData[rowIndex][field]!=editValueBeforeBlur) {
379
- changed = true;
380
- }
381
- // we might need to change multiple cells, in case `multiEdit` is set, which leads into a value for state.selectedRange:
382
- if (selectedRange) {
383
- // editableCols: PropTypes.oneOfType([PropTypes.array, PropTypes.number]),
384
- for (x=selectedRange.x1; x<=selectedRange.x2; x++) {
385
- if (!editableCols || editableCols.itsa_contains(x)) {
386
- for (y=selectedRange.y1; y<=selectedRange.y2; y++) {
387
- col = columns[x];
388
- secondField = (typeof col==='string') ? col : col.key;
389
- cells.push({row: y, field: secondField});
390
- if (propsData[y][secondField]!=editValueBeforeBlur) {
391
- changed = true;
392
- }
393
- }
394
- }
395
- }
396
- }
397
- changed && onChangeCell(cells, editValueBeforeBlur);
398
- }
392
+ }
393
+ changed && onChange(newData);
394
+ }
395
+ if (onChangeCell) {
396
+ if (!props.multiEdit) {
397
+ if (propsData[rowIndex][field] != editValueBeforeBlur) {
398
+ onChangeCell(rowIndex, field, editValueBeforeBlur);
399
399
  }
400
- if (selectedRange) {
401
- instance.setState({selectedRange: null});
400
+ } else {
401
+ changed = false;
402
+ cells = [{ row: rowIndex, field }];
403
+ if (propsData[rowIndex][field] != editValueBeforeBlur) {
404
+ changed = true;
402
405
  }
403
- }
404
-
405
- focus() {
406
- let editableCol, columns, hasColumns, item, editValue, editableCols;
407
- const instance = this,
408
- props = instance.props,
409
- state = instance.state;
410
- editableCols = props.editableCols;
411
- if ((state.editableRow===null) || (state.editableCol===null)) {
412
- editableCol = props.rowHeader ? 1 : 0;
413
- if (typeof editableCols==='number') {
414
- editableCols = [editableCols];
415
- }
416
- if (editableCols) {
417
- editableCol += editableCols[0];
418
- if (props.rowHeader) {
419
- editableCol--;
406
+ // we might need to change multiple cells, in case `multiEdit` is set, which leads into a value for state.selectedRange:
407
+ if (selectedRange) {
408
+ // editableCols: PropTypes.oneOfType([PropTypes.array, PropTypes.number]),
409
+ for (x = selectedRange.x1; x <= selectedRange.x2; x++) {
410
+ if (!editableCols || editableCols.itsa_contains(x)) {
411
+ for (y = selectedRange.y1; y <= selectedRange.y2; y++) {
412
+ col = columns[x];
413
+ secondField = typeof col === "string" ? col : col.key;
414
+ cells.push({ row: y, field: secondField });
415
+ if (propsData[y][secondField] != editValueBeforeBlur) {
416
+ changed = true;
420
417
  }
418
+ }
421
419
  }
422
- columns = props.columns;
423
- hasColumns = (columns && (columns.length>0));
424
- item = props.data[0];
425
- editValue = hasColumns ? item[retrieveFieldName(columns[editableCol])] : item[retrieveFieldName(instance._columns[editableCol])];
426
- instance.setState({
427
- editableRow: 0,
428
- editableCol,
429
- editValue,
430
- selectedRangeStart: {
431
- x: editableCol,
432
- y: 0
433
- }
434
- });
420
+ }
435
421
  }
436
- instance._focusActiveCell();
422
+ changed && onChangeCell(cells, editValueBeforeBlur);
423
+ }
437
424
  }
438
-
439
- focusTextArea(e) {
440
- let length;
441
- const instance = this,
442
- node = e.target;
443
- instance._editValueBeforeBlur = node.value;
444
- if (instance.props.fullSelectOnEdit) {
445
- length = node.value.length;
446
- node.setSelectionRange(length, length);
447
- }
425
+ if (selectedRange) {
426
+ instance.setState({ selectedRange: null });
448
427
  }
428
+ }
449
429
 
450
- _blurActiveCell() {
451
- const instance = this,
452
- state = instance.state,
453
- textareaNode = instance['_textarea_'+state.editableRow+'_'+state.editableCol],
454
- componentContainerNode = instance['_component_'+state.editableRow+'_'+state.editableCol],
455
- componentNode = componentContainerNode && componentContainerNode.itsa_getElement('button'),
456
- focussableNode = textareaNode || componentNode;
457
- if (focussableNode && ((document.activeElement===focussableNode) || document.activeElement.contains(focussableNode))) {
458
- focussableNode.blur();
430
+ focus() {
431
+ let editableCol, columns, hasColumns, item, editValue, editableCols;
432
+ const instance = this,
433
+ props = instance.props,
434
+ state = instance.state;
435
+ editableCols = props.editableCols;
436
+ if (state.editableRow === null || state.editableCol === null) {
437
+ editableCol = props.rowHeader ? 1 : 0;
438
+ if (typeof editableCols === "number") {
439
+ editableCols = [editableCols];
440
+ }
441
+ if (editableCols) {
442
+ editableCol += editableCols[0];
443
+ if (props.rowHeader) {
444
+ editableCol--;
459
445
  }
446
+ }
447
+ columns = props.columns;
448
+ hasColumns = columns && columns.length > 0;
449
+ item = props.data[0];
450
+ editValue = hasColumns
451
+ ? item[retrieveFieldName(columns[editableCol])]
452
+ : item[retrieveFieldName(instance._columns[editableCol])];
453
+ instance.setState({
454
+ editableRow: 0,
455
+ editableCol,
456
+ editValue,
457
+ selectedRangeStart: {
458
+ x: editableCol,
459
+ y: 0,
460
+ },
461
+ });
460
462
  }
463
+ instance._focusActiveCell();
464
+ }
461
465
 
462
- _focusActiveCell() {
463
- const instance = this;
464
- async(() => {
465
- let length;
466
- const state = instance.state,
467
- textareaNode = instance['_textarea_'+state.editableRow+'_'+state.editableCol],
468
- componentContainerNode = instance['_component_'+state.editableRow+'_'+state.editableCol],
469
- componentNode = componentContainerNode && componentContainerNode.itsa_getElement('button');
470
- if (textareaNode && (document.activeElement!==textareaNode)) {
471
- instance._editValueBeforeEdit = textareaNode.value || '';
472
- textareaNode.focus();
473
- if (textareaNode.setSelectionRange) {
474
- length = textareaNode.value.length;
475
- textareaNode.setSelectionRange(0, length);
476
- }
477
- }
478
- else if (componentNode) {
479
- componentNode.focus();
480
- }
481
- });
466
+ focusTextArea(e) {
467
+ let length;
468
+ const instance = this,
469
+ node = e.target;
470
+ instance._editValueBeforeBlur = node.value;
471
+ if (instance.props.fullSelectOnEdit) {
472
+ length = node.value.length;
473
+ node.setSelectionRange(length, length);
482
474
  }
475
+ }
483
476
 
484
- scrollTo(amount) {
485
- this._componentNode.scrollTop = amount;
477
+ _blurActiveCell() {
478
+ const instance = this,
479
+ state = instance.state,
480
+ textareaNode =
481
+ instance["_textarea_" + state.editableRow + "_" + state.editableCol],
482
+ componentContainerNode =
483
+ instance["_component_" + state.editableRow + "_" + state.editableCol],
484
+ componentNode =
485
+ componentContainerNode &&
486
+ componentContainerNode.itsa_getElement("button"),
487
+ focussableNode = textareaNode || componentNode;
488
+ if (
489
+ focussableNode &&
490
+ (document.activeElement === focussableNode ||
491
+ document.activeElement.contains(focussableNode))
492
+ ) {
493
+ focussableNode.blur();
486
494
  }
495
+ }
487
496
 
488
- generateHead() {
489
- let cols, alreadyDefined,
490
- j = -1;
491
- const instance = this,
492
- props = instance.props,
493
- removeableY = props.removeableY,
494
- extendableY = props.extendableY,
495
- columns = props.columns,
496
- fixedHeaders = props.fixedHeaders,
497
- rowHeader = props.rowHeader,
498
- onHeaderClick = props.onHeaderClick;
497
+ _focusActiveCell() {
498
+ const instance = this;
499
+ async(() => {
500
+ let length;
501
+ const state = instance.state,
502
+ textareaNode =
503
+ instance["_textarea_" + state.editableRow + "_" + state.editableCol],
504
+ componentContainerNode =
505
+ instance["_component_" + state.editableRow + "_" + state.editableCol],
506
+ componentNode =
507
+ componentContainerNode &&
508
+ componentContainerNode.itsa_getElement("button");
509
+ if (textareaNode && document.activeElement !== textareaNode) {
510
+ instance._editValueBeforeEdit = textareaNode.value || "";
511
+ textareaNode.focus();
512
+ if (textareaNode.setSelectionRange) {
513
+ length = textareaNode.value.length;
514
+ textareaNode.setSelectionRange(0, length);
515
+ }
516
+ } else if (componentNode) {
517
+ componentNode.focus();
518
+ }
519
+ });
520
+ }
499
521
 
500
- if (columns && (columns.length>0)) {
501
- // first dedupe duplicated col-keys
502
- alreadyDefined = {};
503
- cols = columns.filter(col => {
504
- let dupe;
505
- const field = (typeof col==='string') ? col : col.key;
506
- dupe = alreadyDefined[field];
507
- alreadyDefined[field] = true;
508
- return !dupe;
509
- }).map((col, i) => {
510
- let colName, classname, key, cellContent, headerClick;
511
- const field = (typeof col==='string') ? col : col.key;
512
- classname = 'itsa-table-header itsa-table-col-'+field;
513
- headerClick = e => {
514
- let selectedRange;
515
- const state = instance.state,
516
- rowIndex = state.editableRow,
517
- colIndex = state.editableCol,
518
- editCol = (typeof colIndex==='number') && columns[colIndex],
519
- editField = editCol && ((typeof editCol==='string') ? editCol : editCol.key);
520
- if (state.selectedRange) {
521
- selectedRange = state.selectedRange.itsa_deepClone();
522
- }
523
- instance.setState({
524
- editableRow: null,
525
- editableCol: null,
526
- editValue: ''
527
- }, () => {
528
- if (selectedRange) {
529
- instance.setState({selectedRange: null});
530
- }
531
- });
532
- if (typeof rowIndex==='number') {
533
- instance.implementCellChanges(rowIndex, editField);
534
- }
535
- if (onHeaderClick) {
536
- async(onHeaderClick.call(null, field, editField, state.editValue, rowIndex, colIndex, selectedRange, e));
537
- }
538
- };
539
- if ((i>0) || !rowHeader) {
540
- colName = (typeof col==='string') ? col : (col.label || col.key);
541
- key = (typeof col==='string') ? col : col.key;
542
- }
543
- else {
544
- classname += ' itsa-table-header-rowheader';
545
- key=j--;
546
- }
547
- if (fixedHeaders) {
548
- colName || (colName='&nbsp;');
549
- cellContent = '<div class="itsa-table-header-cont"><div class="itsa-table-header">'+colName+'</div></div>'+colName;
550
- return (<th className={classname} dangerouslySetInnerHTML={{__html: cellContent}} key={key} onClick={headerClick} />);
551
- }
552
- return (<th className={classname} dangerouslySetInnerHTML={{__html: colName}} key={key} onClick={headerClick} />);
553
- });
554
- if (extendableY==="full") {
555
- if (fixedHeaders) {
556
- cols.unshift((<th className={'itsa-table-header '+ROW_ADD_CLASS} key={j--}><div className="itsa-table-header-cont"><div className="itsa-table-header">&nbsp;</div></div>&nbsp;</th>));
557
- }
558
- else {
559
- cols.unshift((<th className={'itsa-table-header '+ROW_ADD_CLASS} key={j--} />));
560
- }
522
+ scrollTo(amount) {
523
+ this._componentNode.scrollTop = amount;
524
+ }
525
+
526
+ generateHead() {
527
+ let cols,
528
+ alreadyDefined,
529
+ j = -1;
530
+ const instance = this,
531
+ props = instance.props,
532
+ removeableY = props.removeableY,
533
+ extendableY = props.extendableY,
534
+ columns = props.columns,
535
+ fixedHeaders = props.fixedHeaders,
536
+ rowHeader = props.rowHeader,
537
+ onHeaderClick = props.onHeaderClick;
538
+
539
+ if (columns && columns.length > 0) {
540
+ // first dedupe duplicated col-keys
541
+ alreadyDefined = {};
542
+ cols = columns
543
+ .filter((col) => {
544
+ let dupe;
545
+ const field = typeof col === "string" ? col : col.key;
546
+ dupe = alreadyDefined[field];
547
+ alreadyDefined[field] = true;
548
+ return !dupe;
549
+ })
550
+ .map((col, i) => {
551
+ let colName, classname, key, cellContent, headerClick;
552
+ const field = typeof col === "string" ? col : col.key;
553
+ classname = "itsa-table-header itsa-table-col-" + field;
554
+ headerClick = (e) => {
555
+ let selectedRange;
556
+ const state = instance.state,
557
+ rowIndex = state.editableRow,
558
+ colIndex = state.editableCol,
559
+ editCol = typeof colIndex === "number" && columns[colIndex],
560
+ editField =
561
+ editCol &&
562
+ (typeof editCol === "string" ? editCol : editCol.key);
563
+ if (state.selectedRange) {
564
+ selectedRange = state.selectedRange.itsa_deepClone();
561
565
  }
562
- if (removeableY) {
563
- if (fixedHeaders) {
564
- cols.unshift((<th className={'itsa-table-header '+ROW_REMOVE_CLASS} key={j--}><div className="itsa-table-header-cont"><div className="itsa-table-header">&nbsp;</div></div>&nbsp;</th>));
565
- }
566
- else {
567
- cols.unshift((<th className={'itsa-table-header '+ROW_REMOVE_CLASS} key={j--} />));
566
+ instance.setState(
567
+ {
568
+ editableRow: null,
569
+ editableCol: null,
570
+ editValue: "",
571
+ },
572
+ () => {
573
+ if (selectedRange) {
574
+ instance.setState({ selectedRange: null });
568
575
  }
576
+ }
577
+ );
578
+ if (typeof rowIndex === "number") {
579
+ instance.implementCellChanges(rowIndex, editField);
569
580
  }
570
-
581
+ if (onHeaderClick) {
582
+ async(
583
+ onHeaderClick.call(
584
+ null,
585
+ field,
586
+ editField,
587
+ state.editValue,
588
+ rowIndex,
589
+ colIndex,
590
+ selectedRange,
591
+ e
592
+ )
593
+ );
594
+ }
595
+ };
596
+ if (i > 0 || !rowHeader) {
597
+ colName = typeof col === "string" ? col : col.label || col.key;
598
+ key = typeof col === "string" ? col : col.key;
599
+ } else {
600
+ classname += " itsa-table-header-rowheader";
601
+ key = j--;
602
+ }
603
+ if (fixedHeaders) {
604
+ colName || (colName = "&nbsp;");
605
+ cellContent = (
606
+ <div>
607
+ <div class="itsa-table-header-cont">
608
+ <div class="itsa-table-header">{colName}</div>
609
+ </div>
610
+ {colName}
611
+ </div>
612
+ );
571
613
  return (
572
- <thead ref={node => instance._headNode=node}>
573
- <tr>
574
- {cols}
575
- </tr>
576
- </thead>
614
+ <th className={classname} key={key} onClick={headerClick}>
615
+ {cellContent}
616
+ </th>
577
617
  );
618
+ }
619
+ cellContent = <div>{colName}</div>;
620
+ return (
621
+ <th className={classname} key={key} onClick={headerClick}>
622
+ {colName}
623
+ </th>
624
+ );
625
+ });
626
+ if (extendableY === "full") {
627
+ if (fixedHeaders) {
628
+ cols.unshift(
629
+ <th className={"itsa-table-header " + ROW_ADD_CLASS} key={j--}>
630
+ <div className="itsa-table-header-cont">
631
+ <div className="itsa-table-header">&nbsp;</div>
632
+ </div>
633
+ &nbsp;
634
+ </th>
635
+ );
636
+ } else {
637
+ cols.unshift(
638
+ <th className={"itsa-table-header " + ROW_ADD_CLASS} key={j--} />
639
+ );
578
640
  }
641
+ }
642
+ if (removeableY) {
643
+ if (fixedHeaders) {
644
+ cols.unshift(
645
+ <th className={"itsa-table-header " + ROW_REMOVE_CLASS} key={j--}>
646
+ <div className="itsa-table-header-cont">
647
+ <div className="itsa-table-header">&nbsp;</div>
648
+ </div>
649
+ &nbsp;
650
+ </th>
651
+ );
652
+ } else {
653
+ cols.unshift(
654
+ <th className={"itsa-table-header " + ROW_REMOVE_CLASS} key={j--} />
655
+ );
656
+ }
657
+ }
658
+
659
+ return (
660
+ <thead ref={(node) => (instance._headNode = node)}>
661
+ <tr>{cols}</tr>
662
+ </thead>
663
+ );
579
664
  }
665
+ }
580
666
 
581
- generateRows() {
582
- let rowclass, editableColsArray;
583
- const instance = this,
584
- props = instance.props,
585
- state = instance.state,
586
- data = props.data,
587
- disabled = props.disabled,
588
- columns = props.columns,
589
- selectedRange = state.selectedRange,
590
- editableCols = props.editableCols,
591
- rowClassRenderer = props.rowClassRenderer,
592
- rowHeader = props.rowHeader,
593
- editable = props.editable,
594
- removeableY = props.removeableY,
595
- extendableY = props.extendableY,
596
- fullEditable = (editable==='full'),
597
- hasColumns = (columns && (columns.length>0));
667
+ generateRows() {
668
+ let rowclass, editableColsArray;
669
+ const instance = this,
670
+ props = instance.props,
671
+ state = instance.state,
672
+ data = props.data,
673
+ disabled = props.disabled,
674
+ columns = props.columns,
675
+ selectedRange = state.selectedRange,
676
+ editableCols = props.editableCols,
677
+ rowClassRenderer = props.rowClassRenderer,
678
+ rowHeader = props.rowHeader,
679
+ editable = props.editable,
680
+ removeableY = props.removeableY,
681
+ extendableY = props.extendableY,
682
+ fullEditable = editable === "full",
683
+ hasColumns = columns && columns.length > 0;
598
684
 
599
- const colIsEditable = colIndex => {
600
- if (disabled) {
601
- return false;
685
+ const colIsEditable = (colIndex) => {
686
+ if (disabled) {
687
+ return false;
688
+ }
689
+ if (!editableCols) {
690
+ return true;
691
+ }
692
+ if (typeof editableCols === "number") {
693
+ return editableCols === colIndex;
694
+ }
695
+ return editableCols.itsa_contains(colIndex);
696
+ };
697
+
698
+ if (editableCols) {
699
+ editableColsArray =
700
+ typeof editableCols === "number" ? [editableCols] : editableCols;
701
+ }
702
+
703
+ return data.map((rowdata, i) => {
704
+ let cells, extraClass;
705
+ if (hasColumns) {
706
+ // create based upon the columns
707
+ cells = columns.map((col, j) => {
708
+ const field = typeof col === "string" ? col : col.key;
709
+ let classname = CELL_CLASS + field,
710
+ value = rowdata[field],
711
+ cellContent,
712
+ onBlur,
713
+ textAreaValue;
714
+ if (rowHeader && j === 0) {
715
+ classname += " itsa-table-rowheader";
716
+ if (value === null) {
717
+ value = "";
602
718
  }
603
- if (!editableCols) {
604
- return true;
719
+ cellContent = String(value);
720
+ return (
721
+ <td
722
+ className={classname}
723
+ dangerouslySetInnerHTML={{ __html: cellContent }}
724
+ data-colid={j}
725
+ key={field}
726
+ />
727
+ );
728
+ } else if (Object.itsa_isObject(value)) {
729
+ return (
730
+ <td
731
+ className={classname}
732
+ data-colid={j}
733
+ key={field}
734
+ ref={(node) => (instance["_component_" + i + "_" + j] = node)}
735
+ >
736
+ {value}
737
+ </td>
738
+ );
739
+ } else if (
740
+ fullEditable ||
741
+ (editable === true &&
742
+ state.editableRow === i &&
743
+ state.editableCol === j &&
744
+ colIsEditable(j))
745
+ ) {
746
+ classname += EDITABLE_CELL_CLASS_SPACED;
747
+ typeof value === "number" || value || (value = "");
748
+ value = String(value);
749
+ if (
750
+ state.editableRow === i &&
751
+ state.editableCol === j &&
752
+ typeof instance._editValueBeforeBlur === "string"
753
+ ) {
754
+ textAreaValue = state.editValue;
755
+ } else {
756
+ textAreaValue = value;
605
757
  }
606
- if (typeof editableCols==='number') {
607
- return editableCols===colIndex;
758
+ if (textAreaValue === null || textAreaValue === undefined) {
759
+ textAreaValue = "";
608
760
  }
609
- return editableCols.itsa_contains(colIndex);
610
- };
611
-
612
- if (editableCols) {
613
- editableColsArray = (typeof editableCols==='number') ? [editableCols] : editableCols;
614
- }
615
-
616
- return data.map((rowdata, i) => {
617
- let cells, extraClass;
618
- if (hasColumns) {
619
- // create based upon the columns
620
- cells = columns.map((col, j) => {
621
- const field = (typeof col==='string') ? col : col.key;
622
- let classname = CELL_CLASS+field,
623
- value = rowdata[field],
624
- cellContent, onBlur, textAreaValue;
625
- if (rowHeader && (j===0)) {
626
- classname += ' itsa-table-rowheader';
627
- if (value===null) {
628
- value = '';
629
- }
630
- cellContent = String(value);
631
- return (
632
- <td
633
- className={classname}
634
- dangerouslySetInnerHTML={{__html: cellContent}}
635
- data-colid={j}
636
- key={field} />
637
- );
638
- }
639
- else if (Object.itsa_isObject(value)) {
640
- return (
641
- <td
642
- className={classname}
643
- data-colid={j}
644
- key={field}
645
- ref={node => instance['_component_'+i+'_'+j] = node}>
646
- {value}
647
- </td>
648
- );
649
- }
650
- else if (fullEditable || ((editable===true) && (state.editableRow===i) && (state.editableCol===j)) && colIsEditable(j)) {
651
- classname += EDITABLE_CELL_CLASS_SPACED;
652
- (typeof value==='number') || value || (value='');
653
- value = String(value);
654
- if ((state.editableRow===i) && (state.editableCol===j) && (typeof instance._editValueBeforeBlur==='string')) {
655
- textAreaValue = state.editValue;
656
- }
657
- else {
658
- textAreaValue = value;
659
- }
660
- if ((textAreaValue===null) || (textAreaValue===undefined)) {
661
- textAreaValue = '';
662
- }
663
- fullEditable && (onBlur=instance.implementCellChanges.bind(instance, i, field));
664
- cellContent = (
665
- <textarea
666
- disabled={disabled}
667
- onBlur={onBlur}
668
- onChange={instance.changeCell}
669
- onFocus={instance.focusTextArea}
670
- onKeyDown={instance.handleCellKeyDown}
671
- ref={node => instance['_textarea_'+i+'_'+j] = node}
672
- rows={1}
673
- value={textAreaValue} />
674
- );
675
- return (
676
- <td
677
- className={classname}
678
- data-colid={j}
679
- key={field}>
680
- <span>{textAreaValue}</span>
681
- {cellContent}
682
- </td>
683
- );
684
- }
685
- (typeof value==='number') || value || (value='');
686
- // we may need to add an 'selected' class:
687
- if (selectedRange &&
688
- (j>=selectedRange.x1) &&
689
- (j<=selectedRange.x2) &&
690
- (i>=selectedRange.y1) &&
691
- (i<=selectedRange.y2) &&
692
- (!editableCols || editableColsArray.itsa_contains(j))) {
693
- classname += ' selected-range';
694
- }
695
- if (typeof value!=='object') {
696
- value = String(value);
697
- (value.itsa_trim()==='') && (value='&nbsp;');
698
- cellContent = value.itsa_replaceAll('\n', '<br />');
699
- return (
700
- <td
701
- className={classname}
702
- dangerouslySetInnerHTML={{__html: cellContent}}
703
- data-colid={j}
704
- key={field} />
705
- );
706
- }
707
- // else
708
- return (
709
- <td
710
- className={classname}
711
- data-colid={j}
712
- key={field}
713
- ref={node => instance['_component_'+i+'_'+j] = node}>
714
- {value}
715
- </td>
716
- );
717
- });
761
+ fullEditable &&
762
+ (onBlur = instance.implementCellChanges.bind(instance, i, field));
763
+ cellContent = (
764
+ <textarea
765
+ disabled={disabled}
766
+ onBlur={onBlur}
767
+ onChange={instance.changeCell}
768
+ onFocus={instance.focusTextArea}
769
+ onKeyDown={instance.handleCellKeyDown}
770
+ ref={(node) => (instance["_textarea_" + i + "_" + j] = node)}
771
+ rows={1}
772
+ value={textAreaValue}
773
+ />
774
+ );
775
+ return (
776
+ <td className={classname} data-colid={j} key={field}>
777
+ <span>{textAreaValue}</span>
778
+ {cellContent}
779
+ </td>
780
+ );
781
+ }
782
+ typeof value === "number" || value || (value = "");
783
+ // we may need to add an 'selected' class:
784
+ if (
785
+ selectedRange &&
786
+ j >= selectedRange.x1 &&
787
+ j <= selectedRange.x2 &&
788
+ i >= selectedRange.y1 &&
789
+ i <= selectedRange.y2 &&
790
+ (!editableCols || editableColsArray.itsa_contains(j))
791
+ ) {
792
+ classname += " selected-range";
793
+ }
794
+ if (typeof value !== "object") {
795
+ value = String(value);
796
+ value.itsa_trim() === "" && (value = "&nbsp;");
797
+ cellContent = value.itsa_replaceAll("\n", "<br />");
798
+ return (
799
+ <td
800
+ className={classname}
801
+ dangerouslySetInnerHTML={{ __html: cellContent }}
802
+ data-colid={j}
803
+ key={field}
804
+ />
805
+ );
806
+ }
807
+ // else
808
+ return (
809
+ <td
810
+ className={classname}
811
+ data-colid={j}
812
+ key={field}
813
+ ref={(node) => (instance["_component_" + i + "_" + j] = node)}
814
+ >
815
+ {value}
816
+ </td>
817
+ );
818
+ });
819
+ } else {
820
+ // all fields
821
+ cells = [];
822
+ let j = -1;
823
+ instance._columns = [];
824
+ rowdata.itsa_each((value, key) => {
825
+ const field = typeof key === "string" ? key : key.key;
826
+ let classname = CELL_CLASS + key,
827
+ cellContent,
828
+ onBlur,
829
+ textAreaValue,
830
+ colCount = cells.length;
831
+ j++;
832
+ instance._columns[j] = key;
833
+ if (rowHeader && colCount === 0) {
834
+ classname += " itsa-table-rowheader";
835
+ if (value === null) {
836
+ value = "";
718
837
  }
719
- else {
720
- // all fields
721
- cells = [];
722
- let j = -1;
723
- instance._columns = [];
724
- rowdata.itsa_each((value, key) => {
725
- const field = (typeof key==='string') ? key : key.key;
726
- let classname = CELL_CLASS+key,
727
- cellContent, onBlur, textAreaValue,
728
- colCount = cells.length;
729
- j++;
730
- instance._columns[j] = key;
731
- if (rowHeader && (colCount===0)) {
732
- classname += ' itsa-table-rowheader';
733
- if (value===null) {
734
- value = '';
735
- }
736
- cellContent = value;
737
- cells.push((<td className={classname} dangerouslySetInnerHTML={{__html: cellContent}} data-colid={colCount} key={key} />));
738
- }
739
- else if (Object.itsa_isObject(value)) {
740
- return (
741
- <td
742
- className={classname}
743
- data-colid={j}
744
- key={field}
745
- ref={node => instance['_component_'+i+'_'+j] = node}>
746
- {value}
747
- </td>
748
- );
749
- }
750
- else if (fullEditable || ((editable===true) && (state.editableRow===i) && (state.editableCol===colCount))) {
751
- classname += EDITABLE_CELL_CLASS_SPACED;
752
- (typeof value==='number') || value || (value='');
753
- value = String(value);
754
- if ((state.editableRow===i) && (state.editableCol===j)) {
755
- textAreaValue = state.editValue;
756
- }
757
- else {
758
- textAreaValue = value;
759
- }
760
- if ((textAreaValue===null) || (textAreaValue===undefined)) {
761
- textAreaValue = '';
762
- }
763
- fullEditable && (onBlur=instance.implementCellChanges.bind(instance, i, field));
764
- cellContent = (
765
- <textarea
766
- disabled={disabled}
767
- onBlur={onBlur}
768
- onChange={instance.changeCell}
769
- onFocus={instance.focusTextArea}
770
- onKeyDown={instance.handleCellKeyDown}
771
- ref={node => instance['_textarea_'+i+'_'+colCount] = node}
772
- rows={1}
773
- value={textAreaValue} />
774
- );
775
- cells.push((
776
- <td className={classname} data-colid={colCount} key={key}>
777
- {cellContent}
778
- <span>{textAreaValue}</span>
779
- </td>
780
- ));
781
- }
782
- else {
783
- (typeof value==='number') || value || (value='');
784
- // we may need to add an 'selected' class:
785
- if (selectedRange &&
786
- (j>=selectedRange.x1) &&
787
- (j<=selectedRange.x2) &&
788
- (i>=selectedRange.y1) &&
789
- (i<=selectedRange.y2) &&
790
- (!editableCols || editableColsArray.itsa_contains(j))) {
791
- classname += ' selected-range';
792
- }
793
- if (typeof value!=='object') {
794
- value = String(value);
795
- (value.itsa_trim()==='') && (value='&nbsp;');
796
- cellContent = value.itsa_replaceAll('\n', '<br />');
797
- cells.push((<td className={classname} dangerouslySetInnerHTML={{__html: cellContent}} data-colid={colCount} key={key} />));
798
- }
799
- else {
800
- cells.push((<td className={classname} data-colid={colCount} key={key} ref={node => instance['_component_'+i+'_'+j] = node}>{value}</td>));
801
- }
802
- }
803
- });
838
+ cellContent = value;
839
+ cells.push(
840
+ <td
841
+ className={classname}
842
+ dangerouslySetInnerHTML={{ __html: cellContent }}
843
+ data-colid={colCount}
844
+ key={key}
845
+ />
846
+ );
847
+ } else if (Object.itsa_isObject(value)) {
848
+ return (
849
+ <td
850
+ className={classname}
851
+ data-colid={j}
852
+ key={field}
853
+ ref={(node) => (instance["_component_" + i + "_" + j] = node)}
854
+ >
855
+ {value}
856
+ </td>
857
+ );
858
+ } else if (
859
+ fullEditable ||
860
+ (editable === true &&
861
+ state.editableRow === i &&
862
+ state.editableCol === colCount)
863
+ ) {
864
+ classname += EDITABLE_CELL_CLASS_SPACED;
865
+ typeof value === "number" || value || (value = "");
866
+ value = String(value);
867
+ if (state.editableRow === i && state.editableCol === j) {
868
+ textAreaValue = state.editValue;
869
+ } else {
870
+ textAreaValue = value;
804
871
  }
805
- if (extendableY==='full') {
806
- cells.unshift((
807
- <td className={CELL_CLASS+ROW_ADD_CLASS} key={ROW_ADD_CLASS}>
808
- <Button buttonText="+" className="controll-btn" disabled={disabled} onClick={instance.addRow.bind(instance, i)} />
809
- </td>
810
- ));
872
+ if (textAreaValue === null || textAreaValue === undefined) {
873
+ textAreaValue = "";
811
874
  }
812
- if (removeableY) {
813
- cells.unshift((
814
- <td className={CELL_CLASS+ROW_REMOVE_CLASS} key={ROW_REMOVE_CLASS}>
815
- <Button buttonText="-" className="controll-btn" disabled={disabled} onClick={instance.deleteRow.bind(instance, i)} />
816
- </td>
817
- ));
875
+ fullEditable &&
876
+ (onBlur = instance.implementCellChanges.bind(instance, i, field));
877
+ cellContent = (
878
+ <textarea
879
+ disabled={disabled}
880
+ onBlur={onBlur}
881
+ onChange={instance.changeCell}
882
+ onFocus={instance.focusTextArea}
883
+ onKeyDown={instance.handleCellKeyDown}
884
+ ref={(node) =>
885
+ (instance["_textarea_" + i + "_" + colCount] = node)
886
+ }
887
+ rows={1}
888
+ value={textAreaValue}
889
+ />
890
+ );
891
+ cells.push(
892
+ <td className={classname} data-colid={colCount} key={key}>
893
+ {cellContent}
894
+ <span>{textAreaValue}</span>
895
+ </td>
896
+ );
897
+ } else {
898
+ typeof value === "number" || value || (value = "");
899
+ // we may need to add an 'selected' class:
900
+ if (
901
+ selectedRange &&
902
+ j >= selectedRange.x1 &&
903
+ j <= selectedRange.x2 &&
904
+ i >= selectedRange.y1 &&
905
+ i <= selectedRange.y2 &&
906
+ (!editableCols || editableColsArray.itsa_contains(j))
907
+ ) {
908
+ classname += " selected-range";
818
909
  }
819
- rowclass = ROW_CLASS;
820
- if (rowClassRenderer) {
821
- extraClass = rowClassRenderer(i, rowdata);
822
- extraClass && (rowclass+=' '+extraClass);
910
+ if (typeof value !== "object") {
911
+ value = String(value);
912
+ value.itsa_trim() === "" && (value = "&nbsp;");
913
+ cellContent = value.itsa_replaceAll("\n", "<br />");
914
+ cells.push(
915
+ <td
916
+ className={classname}
917
+ dangerouslySetInnerHTML={{ __html: cellContent }}
918
+ data-colid={colCount}
919
+ key={key}
920
+ />
921
+ );
922
+ } else {
923
+ cells.push(
924
+ <td
925
+ className={classname}
926
+ data-colid={colCount}
927
+ key={key}
928
+ ref={(node) => (instance["_component_" + i + "_" + j] = node)}
929
+ >
930
+ {value}
931
+ </td>
932
+ );
823
933
  }
824
- return (<tr className={rowclass} data-recordid={i} data-rowid={i} key={i}>{cells}</tr>);
934
+ }
825
935
  });
826
- }
936
+ }
937
+ if (extendableY === "full") {
938
+ cells.unshift(
939
+ <td className={CELL_CLASS + ROW_ADD_CLASS} key={ROW_ADD_CLASS}>
940
+ <Button
941
+ buttonText="+"
942
+ className="controll-btn"
943
+ disabled={disabled}
944
+ onClick={instance.addRow.bind(instance, i)}
945
+ />
946
+ </td>
947
+ );
948
+ }
949
+ if (removeableY) {
950
+ cells.unshift(
951
+ <td className={CELL_CLASS + ROW_REMOVE_CLASS} key={ROW_REMOVE_CLASS}>
952
+ <Button
953
+ buttonText="-"
954
+ className="controll-btn"
955
+ disabled={disabled}
956
+ onClick={instance.deleteRow.bind(instance, i)}
957
+ />
958
+ </td>
959
+ );
960
+ }
961
+ rowclass = ROW_CLASS;
962
+ if (rowClassRenderer) {
963
+ extraClass = rowClassRenderer(i, rowdata);
964
+ extraClass && (rowclass += " " + extraClass);
965
+ }
966
+ return (
967
+ <tr className={rowclass} data-recordid={i} data-rowid={i} key={i}>
968
+ {cells}
969
+ </tr>
970
+ );
971
+ });
972
+ }
827
973
 
828
- refocus(e) {
829
- let focusRow, focusCol, match, maxRow, maxCol, firstItem, item, editValue, colChangedByRow, isSelectComponent, less,
830
- prevRowIndex, prevColIndex, field, editDirectionDown, arrowDown, arrowUp, node, trNode, trParentNode, tds, trs;
831
- const instance = this,
832
- props = instance.props,
833
- state = instance.state,
834
- keyCode = e.keyCode,
835
- shiftKey = e.shiftKey,
836
- ctrlKey = e.metaKey || e.ctrlKey,
837
- data = props.data,
838
- loop = props.loop,
839
- editableCols = props.editableCols,
840
- cursorNav = props.cursorNav,
841
- lowestColIndex = props.rowHeader ? 1 : 0,
842
- highestColIndex = data.itsa_keys().length-(props.rowHeader ? 0 : 1),
843
- columns = props.columns,
844
- hasColumns = (columns && (columns.length>0));
974
+ refocus(e) {
975
+ let focusRow,
976
+ focusCol,
977
+ match,
978
+ maxRow,
979
+ maxCol,
980
+ firstItem,
981
+ item,
982
+ editValue,
983
+ colChangedByRow,
984
+ isSelectComponent,
985
+ less,
986
+ prevRowIndex,
987
+ prevColIndex,
988
+ field,
989
+ editDirectionDown,
990
+ arrowDown,
991
+ arrowUp,
992
+ node,
993
+ trNode,
994
+ trParentNode,
995
+ tds,
996
+ trs;
997
+ const instance = this,
998
+ props = instance.props,
999
+ state = instance.state,
1000
+ keyCode = e.keyCode,
1001
+ shiftKey = e.shiftKey,
1002
+ ctrlKey = e.metaKey || e.ctrlKey,
1003
+ data = props.data,
1004
+ loop = props.loop,
1005
+ editableCols = props.editableCols,
1006
+ cursorNav = props.cursorNav,
1007
+ lowestColIndex = props.rowHeader ? 1 : 0,
1008
+ highestColIndex = data.itsa_keys().length - (props.rowHeader ? 0 : 1),
1009
+ columns = props.columns,
1010
+ hasColumns = columns && columns.length > 0;
845
1011
 
846
- const implementChanges = keepFocus => {
847
- if ((props.editable===true) || (state.selectedRange)) { // NOT 'full' for that would take care of itself
848
- field = hasColumns ? columns[prevColIndex] : instance._columns[prevColIndex];
849
- instance.implementCellChanges(prevRowIndex, field, true);
850
- keepFocus && (instance._editValueBeforeEdit=instance._editValueBeforeBlur);
851
- }
852
- };
853
- editDirectionDown = ((keyCode===9) || (keyCode===37) || (keyCode===39)) ? false : props.editDirectionDown;
854
- if (keyCode===13) {
855
- if (shiftKey) {
856
- return;
857
- }
858
- }
1012
+ const implementChanges = (keepFocus) => {
1013
+ if (props.editable === true || state.selectedRange) {
1014
+ // NOT 'full' for that would take care of itself
1015
+ field = hasColumns
1016
+ ? columns[prevColIndex]
1017
+ : instance._columns[prevColIndex];
1018
+ instance.implementCellChanges(prevRowIndex, field, true);
1019
+ keepFocus &&
1020
+ (instance._editValueBeforeEdit = instance._editValueBeforeBlur);
1021
+ }
1022
+ };
1023
+ editDirectionDown =
1024
+ keyCode === 9 || keyCode === 37 || keyCode === 39
1025
+ ? false
1026
+ : props.editDirectionDown;
1027
+ if (keyCode === 13) {
1028
+ if (shiftKey) {
1029
+ return;
1030
+ }
1031
+ }
859
1032
 
860
- match = (
861
- (keyCode===9) ||
862
- (keyCode===13) ||
863
- (cursorNav && ((keyCode===40) || (keyCode===38))) ||
864
- (cursorNav && ctrlKey && ((keyCode===37) || (keyCode===39)))
865
- ); // 40=arrowDown, 38=arrowUp
1033
+ match =
1034
+ keyCode === 9 ||
1035
+ keyCode === 13 ||
1036
+ (cursorNav && (keyCode === 40 || keyCode === 38)) ||
1037
+ (cursorNav && ctrlKey && (keyCode === 37 || keyCode === 39)); // 40=arrowDown, 38=arrowUp
866
1038
 
867
- // we need to ignore MOVING DOWN in case the focus lies on a button component
868
- if ((document.activeElement.tagName==='BUTTON') && (keyCode===13)) {
869
- match = false;
870
- }
1039
+ // we need to ignore MOVING DOWN in case the focus lies on a button component
1040
+ if (document.activeElement.tagName === "BUTTON" && keyCode === 13) {
1041
+ match = false;
1042
+ }
871
1043
 
872
- isSelectComponent = (document.activeElement.itsa_hasClass('itsa-select') || document.activeElement.itsa_inside('.itsa-select'));
873
- if (isSelectComponent && ((keyCode===13) || (cursorNav && ((keyCode===38) || (keyCode===40))))) {
874
- match = false;
875
- }
1044
+ isSelectComponent =
1045
+ document.activeElement.itsa_hasClass("itsa-select") ||
1046
+ document.activeElement.itsa_inside(".itsa-select");
1047
+ if (
1048
+ isSelectComponent &&
1049
+ (keyCode === 13 || (cursorNav && (keyCode === 38 || keyCode === 40)))
1050
+ ) {
1051
+ match = false;
1052
+ }
876
1053
 
877
- if (match) {
878
- e.preventDefault();
879
- arrowDown = (keyCode===40);
880
- arrowUp = (keyCode===38);
881
- maxRow = data.length - 1;
882
- if (columns) {
883
- maxCol = columns.length - 1;
884
- }
885
- else {
886
- firstItem = data[0];
887
- maxCol = firstItem ? firstItem.itsa_size()-1 : 0;
888
- }
1054
+ if (match) {
1055
+ e.preventDefault();
1056
+ arrowDown = keyCode === 40;
1057
+ arrowUp = keyCode === 38;
1058
+ maxRow = data.length - 1;
1059
+ if (columns) {
1060
+ maxCol = columns.length - 1;
1061
+ } else {
1062
+ firstItem = data[0];
1063
+ maxCol = firstItem ? firstItem.itsa_size() - 1 : 0;
1064
+ }
889
1065
 
890
- if (isSelectComponent) {
891
- // we need to catch editableRow and editableCol because thay are not set
892
- less = 0;
893
- if (props.removeableY) {
894
- less++;
895
- }
896
- if (props.extendableY==='full') {
897
- less++;
898
- }
1066
+ if (isSelectComponent) {
1067
+ // we need to catch editableRow and editableCol because thay are not set
1068
+ less = 0;
1069
+ if (props.removeableY) {
1070
+ less++;
1071
+ }
1072
+ if (props.extendableY === "full") {
1073
+ less++;
1074
+ }
899
1075
 
900
- node = document.activeElement;
901
- while (node && (node.tagName!=='TD')) {
902
- node = node.parentNode;
903
- }
904
- trNode = node.parentNode;
905
- tds = trNode.childNodes;
906
- prevColIndex = Array.prototype.indexOf.call(tds, node) - less;
907
- trParentNode = trNode.parentNode;
908
- trs = trParentNode.childNodes;
909
- prevRowIndex = Array.prototype.indexOf.call(trs, trNode);
910
- }
911
- else {
912
- prevRowIndex = state.editableRow;
913
- prevColIndex = state.editableCol;
914
- }
915
- focusRow = prevRowIndex;
916
- focusCol = prevColIndex;
1076
+ node = document.activeElement;
1077
+ while (node && node.tagName !== "TD") {
1078
+ node = node.parentNode;
1079
+ }
1080
+ trNode = node.parentNode;
1081
+ tds = trNode.childNodes;
1082
+ prevColIndex = Array.prototype.indexOf.call(tds, node) - less;
1083
+ trParentNode = trNode.parentNode;
1084
+ trs = trParentNode.childNodes;
1085
+ prevRowIndex = Array.prototype.indexOf.call(trs, trNode);
1086
+ } else {
1087
+ prevRowIndex = state.editableRow;
1088
+ prevColIndex = state.editableCol;
1089
+ }
1090
+ focusRow = prevRowIndex;
1091
+ focusCol = prevColIndex;
917
1092
 
918
- if (((keyCode===9) && shiftKey) || ((keyCode===37) && ctrlKey) || arrowUp) {
919
- // backwards
920
- if (editDirectionDown || arrowUp) {
921
- focusRow--;
922
- }
923
- else {
924
- do {
925
- focusCol--;
926
- if (focusCol<lowestColIndex) {
927
- break;
928
- }
929
- }
930
- while (!editableCols || !editableCols.itsa_contains(focusCol));
931
- }
932
- }
933
- else {
934
- // forewards
935
- if (editDirectionDown || arrowDown) {
936
- focusRow++;
937
- }
938
- else {
939
- do {
940
- focusCol++;
941
- if (focusCol>highestColIndex) {
942
- break;
943
- }
944
- }
945
- while (!editableCols || !editableCols.itsa_contains(focusCol));
946
- }
947
- }
948
- // now we might need to adjust the values when out of range
949
- if (focusRow<0) {
950
- if (!loop) {
951
- implementChanges(true);
952
- return;
953
- }
954
- focusRow = maxRow;
955
- do {
956
- focusCol--;
957
- if (focusCol<lowestColIndex) {
958
- focusCol = highestColIndex;
959
- }
960
- }
961
- while (!editableCols || !editableCols.itsa_contains(focusCol));
962
- colChangedByRow = true;
963
- }
964
- else if (focusRow>maxRow) {
965
- if (!loop) {
966
- implementChanges(true);
967
- return;
968
- }
969
- focusRow = 0;
970
- do {
971
- focusCol++;
972
- if (focusCol>highestColIndex) {
973
- focusCol = lowestColIndex;
974
- }
975
- }
976
- while (!editableCols || !editableCols.itsa_contains(focusCol));
977
- colChangedByRow = true;
1093
+ if (
1094
+ (keyCode === 9 && shiftKey) ||
1095
+ (keyCode === 37 && ctrlKey) ||
1096
+ arrowUp
1097
+ ) {
1098
+ // backwards
1099
+ if (editDirectionDown || arrowUp) {
1100
+ focusRow--;
1101
+ } else {
1102
+ do {
1103
+ focusCol--;
1104
+ if (focusCol < lowestColIndex) {
1105
+ break;
978
1106
  }
979
- if (focusCol<lowestColIndex) {
980
- if (!loop) {
981
- implementChanges(true);
982
- return;
983
- }
984
- colChangedByRow || focusRow--;
985
- (focusRow<0) && (focusRow=maxRow);
986
- focusCol = maxCol;
987
- }
988
- else if (focusCol>maxCol) {
989
- if (!loop) {
990
- implementChanges(true);
991
- return;
992
- }
993
- colChangedByRow || focusRow++;
994
- focusCol = lowestColIndex;
995
- (focusRow>maxRow) && (focusRow=0);
996
- }
997
- item = props.data[focusRow];
998
- if (item) {
999
- editValue = hasColumns ? item[retrieveFieldName(columns[focusCol])] : item[retrieveFieldName(instance._columns[focusCol])];
1000
- this.setState({
1001
- editableRow: focusRow,
1002
- editableCol: focusCol,
1003
- editValue,
1004
- selectedRangeStart: {
1005
- x: focusCol,
1006
- y: focusRow
1007
- },
1008
- selectedRange: null
1009
- });
1010
- instance._focusActiveCell();
1011
- implementChanges();
1107
+ } while (!editableCols || !editableCols.itsa_contains(focusCol));
1108
+ }
1109
+ } else {
1110
+ // forewards
1111
+ if (editDirectionDown || arrowDown) {
1112
+ focusRow++;
1113
+ } else {
1114
+ do {
1115
+ focusCol++;
1116
+ if (focusCol > highestColIndex) {
1117
+ break;
1012
1118
  }
1119
+ } while (!editableCols || !editableCols.itsa_contains(focusCol));
1013
1120
  }
1014
- }
1015
-
1016
- handleClick(editable, e) {
1017
- const instance = this,
1018
- props = instance.props,
1019
- onClick = instance.props.onClick,
1020
- state = instance.state,
1021
- shiftClick = e.shiftKey;
1022
- let node = e.target,
1023
- editableCols = props.editableCols,
1024
- colId, rowId, columns, hasColumns, item, editValue, newState, prevRowId, prevColId, selectedRangeStart;
1025
- (node.tagName==='TD') || (node=node.parentNode);
1026
- colId = parseInt(node.getAttribute('data-colid'), 10);
1027
- node = node.parentNode;
1028
- rowId = parseInt(node.getAttribute('data-rowid'), 10);
1029
- if (typeof editableCols==='number') {
1030
- editableCols = [editableCols];
1121
+ }
1122
+ // now we might need to adjust the values when out of range
1123
+ if (focusRow < 0) {
1124
+ if (!loop) {
1125
+ implementChanges(true);
1126
+ return;
1031
1127
  }
1032
- if (editable && (!editableCols || editableCols.itsa_contains(colId))) {
1033
- columns = props.columns;
1034
- hasColumns = (columns && (columns.length>0));
1035
- item = props.data[rowId];
1036
- editValue = hasColumns ? item[retrieveFieldName(columns[colId])] : item[retrieveFieldName(instance._columns[colId])];
1037
- newState = {
1038
- editableRow: rowId,
1039
- editableCol: colId,
1040
- editValue
1041
- };
1042
- if (props.editable && props.multiEdit) {
1043
- if (shiftClick) {
1044
- selectedRangeStart = state.selectedRangeStart;
1045
- if (selectedRangeStart) {
1046
- prevRowId = selectedRangeStart.y;
1047
- prevColId = selectedRangeStart.x;
1048
- if ((typeof prevRowId==='number') && (typeof prevColId==='number') && ((prevColId!==colId) || (prevRowId!==rowId))) {
1049
- newState.selectedRange = {
1050
- x1: Math.min(prevColId, colId),
1051
- y1: Math.min(prevRowId, rowId),
1052
- x2: Math.max(prevColId, colId),
1053
- y2: Math.max(prevRowId, rowId)
1054
- };
1055
- }
1056
- }
1057
- else {
1058
- newState.selectedRange = null;
1059
- }
1060
- }
1061
- else {
1062
- newState.selectedRange = null;
1063
- newState.selectedRangeStart = {
1064
- x: colId,
1065
- y: rowId
1066
- };
1067
- }
1068
- }
1069
- instance.setState(newState);
1070
- instance._focusActiveCell();
1128
+ focusRow = maxRow;
1129
+ do {
1130
+ focusCol--;
1131
+ if (focusCol < lowestColIndex) {
1132
+ focusCol = highestColIndex;
1133
+ }
1134
+ } while (!editableCols || !editableCols.itsa_contains(focusCol));
1135
+ colChangedByRow = true;
1136
+ } else if (focusRow > maxRow) {
1137
+ if (!loop) {
1138
+ implementChanges(true);
1139
+ return;
1140
+ }
1141
+ focusRow = 0;
1142
+ do {
1143
+ focusCol++;
1144
+ if (focusCol > highestColIndex) {
1145
+ focusCol = lowestColIndex;
1146
+ }
1147
+ } while (!editableCols || !editableCols.itsa_contains(focusCol));
1148
+ colChangedByRow = true;
1149
+ }
1150
+ if (focusCol < lowestColIndex) {
1151
+ if (!loop) {
1152
+ implementChanges(true);
1153
+ return;
1071
1154
  }
1072
- onClick && onClick(rowId, colId);
1155
+ colChangedByRow || focusRow--;
1156
+ focusRow < 0 && (focusRow = maxRow);
1157
+ focusCol = maxCol;
1158
+ } else if (focusCol > maxCol) {
1159
+ if (!loop) {
1160
+ implementChanges(true);
1161
+ return;
1162
+ }
1163
+ colChangedByRow || focusRow++;
1164
+ focusCol = lowestColIndex;
1165
+ focusRow > maxRow && (focusRow = 0);
1166
+ }
1167
+ item = props.data[focusRow];
1168
+ if (item) {
1169
+ editValue = hasColumns
1170
+ ? item[retrieveFieldName(columns[focusCol])]
1171
+ : item[retrieveFieldName(instance._columns[focusCol])];
1172
+ this.setState({
1173
+ editableRow: focusRow,
1174
+ editableCol: focusCol,
1175
+ editValue,
1176
+ selectedRangeStart: {
1177
+ x: focusCol,
1178
+ y: focusRow,
1179
+ },
1180
+ selectedRange: null,
1181
+ });
1182
+ instance._focusActiveCell();
1183
+ implementChanges();
1184
+ }
1073
1185
  }
1186
+ }
1074
1187
 
1075
- addRow(index) {
1076
- let newData, len, newRecord;
1077
- const props = this.props,
1078
- onChange = props.onChange;
1079
- if (onChange) {
1080
- newData = cloneData(props.data);
1081
- len = newData.length;
1082
- if (len==0) {
1083
- newData = [{'__row0': null}];
1084
- }
1085
- else {
1086
- newRecord = newData[0].itsa_map(() => null);
1087
- if (typeof index==='number') {
1088
- newData.itsa_insertAt(newRecord, index);
1089
- }
1090
- else {
1091
- newData[props.extendableY==="begin" ? "unshift" : "push"](newRecord);
1092
- }
1188
+ handleClick(editable, e) {
1189
+ const instance = this,
1190
+ props = instance.props,
1191
+ onClick = instance.props.onClick,
1192
+ state = instance.state,
1193
+ shiftClick = e.shiftKey;
1194
+ let node = e.target,
1195
+ editableCols = props.editableCols,
1196
+ colId,
1197
+ rowId,
1198
+ columns,
1199
+ hasColumns,
1200
+ item,
1201
+ editValue,
1202
+ newState,
1203
+ prevRowId,
1204
+ prevColId,
1205
+ selectedRangeStart;
1206
+ node.tagName === "TD" || (node = node.parentNode);
1207
+ colId = parseInt(node.getAttribute("data-colid"), 10);
1208
+ node = node.parentNode;
1209
+ rowId = parseInt(node.getAttribute("data-rowid"), 10);
1210
+ if (typeof editableCols === "number") {
1211
+ editableCols = [editableCols];
1212
+ }
1213
+ if (editable && (!editableCols || editableCols.itsa_contains(colId))) {
1214
+ columns = props.columns;
1215
+ hasColumns = columns && columns.length > 0;
1216
+ item = props.data[rowId];
1217
+ editValue = hasColumns
1218
+ ? item[retrieveFieldName(columns[colId])]
1219
+ : item[retrieveFieldName(instance._columns[colId])];
1220
+ newState = {
1221
+ editableRow: rowId,
1222
+ editableCol: colId,
1223
+ editValue,
1224
+ };
1225
+ if (props.editable && props.multiEdit) {
1226
+ if (shiftClick) {
1227
+ selectedRangeStart = state.selectedRangeStart;
1228
+ if (selectedRangeStart) {
1229
+ prevRowId = selectedRangeStart.y;
1230
+ prevColId = selectedRangeStart.x;
1231
+ if (
1232
+ typeof prevRowId === "number" &&
1233
+ typeof prevColId === "number" &&
1234
+ (prevColId !== colId || prevRowId !== rowId)
1235
+ ) {
1236
+ newState.selectedRange = {
1237
+ x1: Math.min(prevColId, colId),
1238
+ y1: Math.min(prevRowId, rowId),
1239
+ x2: Math.max(prevColId, colId),
1240
+ y2: Math.max(prevRowId, rowId),
1241
+ };
1093
1242
  }
1094
- onChange(newData);
1243
+ } else {
1244
+ newState.selectedRange = null;
1245
+ }
1246
+ } else {
1247
+ newState.selectedRange = null;
1248
+ newState.selectedRangeStart = {
1249
+ x: colId,
1250
+ y: rowId,
1251
+ };
1095
1252
  }
1253
+ }
1254
+ instance.setState(newState);
1255
+ instance._focusActiveCell();
1096
1256
  }
1257
+ onClick && onClick(rowId, colId);
1258
+ }
1097
1259
 
1098
- addCol() {
1099
- let newData, len, size;
1100
- const props = this.props,
1101
- onChange = props.onChange;
1102
- if (onChange) {
1103
- newData = cloneData(props.data);
1104
- len = newData.length;
1105
- if (len==0) {
1106
- size = 0;
1107
- }
1108
- else {
1109
- size = newData[0].itsa_size();
1110
- }
1111
- newData.forEach(record => {
1112
- record['__col'+size] = null;
1113
- });
1114
- onChange(newData);
1260
+ addRow(index) {
1261
+ let newData, len, newRecord;
1262
+ const props = this.props,
1263
+ onChange = props.onChange;
1264
+ if (onChange) {
1265
+ newData = cloneData(props.data);
1266
+ len = newData.length;
1267
+ if (len == 0) {
1268
+ newData = [{ __row0: null }];
1269
+ } else {
1270
+ newRecord = newData[0].itsa_map(() => null);
1271
+ if (typeof index === "number") {
1272
+ newData.itsa_insertAt(newRecord, index);
1273
+ } else {
1274
+ newData[props.extendableY === "begin" ? "unshift" : "push"](
1275
+ newRecord
1276
+ );
1115
1277
  }
1278
+ }
1279
+ onChange(newData);
1116
1280
  }
1281
+ }
1117
1282
 
1118
- deleteRow(index) {
1119
- let newData;
1120
- const props = this.props,
1121
- onChange = props.onChange;
1122
- if (onChange) {
1123
- newData = cloneData(props.data);
1124
- newData.splice(index, 1);
1125
- onChange(newData);
1126
- }
1283
+ addCol() {
1284
+ let newData, len, size;
1285
+ const props = this.props,
1286
+ onChange = props.onChange;
1287
+ if (onChange) {
1288
+ newData = cloneData(props.data);
1289
+ len = newData.length;
1290
+ if (len == 0) {
1291
+ size = 0;
1292
+ } else {
1293
+ size = newData[0].itsa_size();
1294
+ }
1295
+ newData.forEach((record) => {
1296
+ record["__col" + size] = null;
1297
+ });
1298
+ onChange(newData);
1127
1299
  }
1300
+ }
1128
1301
 
1129
- /**
1130
- * React render-method --> renderes the Component.
1131
- *
1132
- * @method render
1133
- * @return ReactComponent
1134
- * @since 2.0.0
1135
- */
1136
- render() {
1137
- let classname = MAIN_CLASS,
1138
- handleClick, refocus, addRowBtn, addColBtn, tableClassName, addRowClass;
1139
- const instance = this,
1140
- props = instance.props,
1141
- editable = props.editable,
1142
- disabled = props.disabled,
1143
- propsClassName = props.className;
1302
+ deleteRow(index) {
1303
+ let newData;
1304
+ const props = this.props,
1305
+ onChange = props.onChange;
1306
+ if (onChange) {
1307
+ newData = cloneData(props.data);
1308
+ newData.splice(index, 1);
1309
+ onChange(newData);
1310
+ }
1311
+ }
1144
1312
 
1145
- tableClassName = props.tableClass;
1146
- propsClassName && (classname+=' '+propsClassName);
1147
- if (props.extendableY) {
1148
- addRowClass = 'add-row controll-btn';
1149
- if ((props.removeableY) && (props.extendableY==='full')) {
1150
- addRowClass += ' add-row-indent';
1151
- }
1152
- addRowBtn = (<Button buttonText="+" className={addRowClass} disabled={disabled} onClick={instance.addRow} />);
1153
- }
1154
- if (props.extendableX && !props.columns) {
1155
- addColBtn = (<Button buttonText="+" className="controll-btn" disabled={disabled} onClick={instance.addCol} />);
1156
- }
1157
- if ((editable===true) || (editable==='full')) {
1158
- handleClick = instance.handleClick.bind(instance, true);
1159
- refocus = instance.refocus;
1160
- }
1161
- else {
1162
- handleClick = instance.handleClick.bind(instance, false);
1163
- }
1164
- if (props.fixedHeaders) {
1165
- tableClassName += ' fixed-headers';
1166
- classname += ' scrollable-y';
1167
- // fixedHeadertable = (
1168
- // <table className={props.tableClass+' fixed-headers'}>
1169
- // {instance.generateHead()}
1170
- // <tbody>
1171
- // {instance.generateRows()}
1172
- // </tbody>
1173
- // </table>
1174
- // );
1175
- }
1176
- // classname+='flex-container-vertical';
1177
- return (
1178
- <div
1179
- className={classname}
1180
- onScroll={props.onScroll}
1181
- ref={node => instance._componentNode = node}>
1182
- <table
1183
- className={tableClassName}
1184
- ref={node => instance._tableNode=node}>
1185
- {instance.generateHead()}
1186
- <tbody
1187
- onClick={handleClick}
1188
- onKeyDown={refocus}>
1189
- {instance.generateRows()}
1190
- </tbody>
1191
- </table>
1192
- {addColBtn}
1193
- {addRowBtn}
1194
- </div>
1195
- );
1313
+ /**
1314
+ * React render-method --> renderes the Component.
1315
+ *
1316
+ * @method render
1317
+ * @return ReactComponent
1318
+ * @since 2.0.0
1319
+ */
1320
+ render() {
1321
+ let classname = MAIN_CLASS,
1322
+ handleClick,
1323
+ refocus,
1324
+ addRowBtn,
1325
+ addColBtn,
1326
+ tableClassName,
1327
+ addRowClass;
1328
+ const instance = this,
1329
+ props = instance.props,
1330
+ editable = props.editable,
1331
+ disabled = props.disabled,
1332
+ propsClassName = props.className;
1333
+
1334
+ tableClassName = props.tableClass;
1335
+ propsClassName && (classname += " " + propsClassName);
1336
+ if (props.extendableY) {
1337
+ addRowClass = "add-row controll-btn";
1338
+ if (props.removeableY && props.extendableY === "full") {
1339
+ addRowClass += " add-row-indent";
1340
+ }
1341
+ addRowBtn = (
1342
+ <Button
1343
+ buttonText="+"
1344
+ className={addRowClass}
1345
+ disabled={disabled}
1346
+ onClick={instance.addRow}
1347
+ />
1348
+ );
1349
+ }
1350
+ if (props.extendableX && !props.columns) {
1351
+ addColBtn = (
1352
+ <Button
1353
+ buttonText="+"
1354
+ className="controll-btn"
1355
+ disabled={disabled}
1356
+ onClick={instance.addCol}
1357
+ />
1358
+ );
1196
1359
  }
1360
+ if (editable === true || editable === "full") {
1361
+ handleClick = instance.handleClick.bind(instance, true);
1362
+ refocus = instance.refocus;
1363
+ } else {
1364
+ handleClick = instance.handleClick.bind(instance, false);
1365
+ }
1366
+ if (props.fixedHeaders) {
1367
+ tableClassName += " fixed-headers";
1368
+ classname += " scrollable-y";
1369
+ // fixedHeadertable = (
1370
+ // <table className={props.tableClass+' fixed-headers'}>
1371
+ // {instance.generateHead()}
1372
+ // <tbody>
1373
+ // {instance.generateRows()}
1374
+ // </tbody>
1375
+ // </table>
1376
+ // );
1377
+ }
1378
+ // classname+='flex-container-vertical';
1379
+ return (
1380
+ <div
1381
+ className={classname}
1382
+ onScroll={props.onScroll}
1383
+ ref={(node) => (instance._componentNode = node)}
1384
+ >
1385
+ <table
1386
+ className={tableClassName}
1387
+ ref={(node) => (instance._tableNode = node)}
1388
+ >
1389
+ {instance.generateHead()}
1390
+ <tbody onClick={handleClick} onKeyDown={refocus}>
1391
+ {instance.generateRows()}
1392
+ </tbody>
1393
+ </table>
1394
+ {addColBtn}
1395
+ {addRowBtn}
1396
+ </div>
1397
+ );
1398
+ }
1197
1399
 
1198
- /**
1199
- * Callback for a click on the document. Is needed to close the Component when clicked outside.
1200
- *
1201
- * @method _handleDocumentClick
1202
- * @private
1203
- * @param Object e
1204
- * @since 0.0.1
1205
- */
1206
- _handleDocumentClick(e) {
1207
- let rowIndex, field, colIndex, columns, hasColumns;
1208
- const instance = this,
1209
- targetNode = e.target;
1210
- if ((instance.props.editable===true) && (!instance._componentNode.contains(targetNode) || ((targetNode.tagName!=='TEXTAREA') && !instance._headNode.contains(targetNode)))) {
1211
- rowIndex = instance.state.editableRow;
1212
- colIndex = instance.state.editableCol;
1213
- columns = instance.props.columns;
1214
- hasColumns = (columns && (columns.length>0));
1215
- field = hasColumns ? columns[colIndex] : instance._columns[colIndex];
1216
- instance.setState({
1217
- editableRow: null,
1218
- editableCol: null,
1219
- editValue: ''
1220
- }, () => {
1221
- (typeof rowIndex==='number') && instance.implementCellChanges(rowIndex, field);
1222
- });
1400
+ /**
1401
+ * Callback for a click on the document. Is needed to close the Component when clicked outside.
1402
+ *
1403
+ * @method _handleDocumentClick
1404
+ * @private
1405
+ * @param Object e
1406
+ * @since 0.0.1
1407
+ */
1408
+ _handleDocumentClick(e) {
1409
+ let rowIndex, field, colIndex, columns, hasColumns;
1410
+ const instance = this,
1411
+ targetNode = e.target;
1412
+ if (
1413
+ instance.props.editable === true &&
1414
+ (!instance._componentNode.contains(targetNode) ||
1415
+ (targetNode.tagName !== "TEXTAREA" &&
1416
+ !instance._headNode.contains(targetNode)))
1417
+ ) {
1418
+ rowIndex = instance.state.editableRow;
1419
+ colIndex = instance.state.editableCol;
1420
+ columns = instance.props.columns;
1421
+ hasColumns = columns && columns.length > 0;
1422
+ field = hasColumns ? columns[colIndex] : instance._columns[colIndex];
1423
+ instance.setState(
1424
+ {
1425
+ editableRow: null,
1426
+ editableCol: null,
1427
+ editValue: "",
1428
+ },
1429
+ () => {
1430
+ typeof rowIndex === "number" &&
1431
+ instance.implementCellChanges(rowIndex, field);
1223
1432
  }
1433
+ );
1224
1434
  }
1225
-
1435
+ }
1226
1436
  }
1227
1437
 
1228
1438
  Table.propTypes = {
1229
- autoFocus: PropTypes.bool,
1230
- columns: PropTypes.array,
1231
- /**
1232
- * The Component its children
1233
- *
1234
- * @property children
1235
- * @type Object
1236
- * @since 2.0.0
1237
- */
1238
- cursorNav: PropTypes.bool,
1239
- data: PropTypes.array,
1240
- disabled: PropTypes.bool,
1241
- editable: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
1242
- editableCols: PropTypes.oneOfType([PropTypes.array, PropTypes.number]),
1243
- editDirectionDown: PropTypes.bool,
1244
- extendableX: PropTypes.bool,
1245
- extendableY: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]), // true, "begin" or "all"
1246
- fixedHeaders: PropTypes.bool,
1247
- fullSelectOnEdit: PropTypes.bool,
1248
- loop: PropTypes.bool,
1249
- multiEdit: PropTypes.bool,
1250
- onChange: PropTypes.func,
1251
- onChangeCell: PropTypes.func,
1252
- onClick: PropTypes.func,
1253
- onHeaderClick: PropTypes.func,
1254
- onScroll: PropTypes.func,
1255
- removeableY: PropTypes.bool,
1256
- rowClassRenderer: PropTypes.func,
1257
- rowHeader: PropTypes.bool,
1258
- tableClass: PropTypes.string
1439
+ autoFocus: PropTypes.bool,
1440
+ columns: PropTypes.array,
1441
+ /**
1442
+ * The Component its children
1443
+ *
1444
+ * @property children
1445
+ * @type Object
1446
+ * @since 2.0.0
1447
+ */
1448
+ cursorNav: PropTypes.bool,
1449
+ data: PropTypes.array,
1450
+ disabled: PropTypes.bool,
1451
+ editable: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
1452
+ editableCols: PropTypes.oneOfType([PropTypes.array, PropTypes.number]),
1453
+ editDirectionDown: PropTypes.bool,
1454
+ extendableX: PropTypes.bool,
1455
+ extendableY: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]), // true, "begin" or "all"
1456
+ fixedHeaders: PropTypes.bool,
1457
+ fullSelectOnEdit: PropTypes.bool,
1458
+ loop: PropTypes.bool,
1459
+ multiEdit: PropTypes.bool,
1460
+ onChange: PropTypes.func,
1461
+ onChangeCell: PropTypes.func,
1462
+ onClick: PropTypes.func,
1463
+ onHeaderClick: PropTypes.func,
1464
+ onScroll: PropTypes.func,
1465
+ removeableY: PropTypes.bool,
1466
+ rowClassRenderer: PropTypes.func,
1467
+ rowHeader: PropTypes.bool,
1468
+ tableClass: PropTypes.string,
1259
1469
  };
1260
1470
 
1261
1471
  Table.defaultProps = {
1262
- autoFocus: false,
1263
- cursorNav: false,
1264
- data: [],
1265
- editable: false,
1266
- editDirectionDown: true,
1267
- extendableX: false,
1268
- extendableY: false,
1269
- fullSelectOnEdit: true,
1270
- loop: true,
1271
- multiEdit: false,
1272
- removeableY: false,
1273
- rowHeader: false
1472
+ autoFocus: false,
1473
+ cursorNav: false,
1474
+ data: [],
1475
+ editable: false,
1476
+ editDirectionDown: true,
1477
+ extendableX: false,
1478
+ extendableY: false,
1479
+ fullSelectOnEdit: true,
1480
+ loop: true,
1481
+ multiEdit: false,
1482
+ removeableY: false,
1483
+ rowHeader: false,
1274
1484
  };
1275
1485
 
1276
1486
  module.exports = Table;