handsontable 0.34.1 → 0.34.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of handsontable might be problematic. Click here for more details.

Files changed (95) hide show
  1. package/.travis.yml +2 -0
  2. package/README.md +127 -96
  3. package/commonjs/core.js +11 -6
  4. package/commonjs/helpers/dom/element.js +4 -3
  5. package/commonjs/helpers/mixed.js +8 -4
  6. package/commonjs/index.js +5 -4
  7. package/commonjs/pluginHooks.js +18 -2
  8. package/commonjs/plugins/copyPaste/clipboardData.js +31 -0
  9. package/commonjs/plugins/copyPaste/contextMenuItem/copy.js +1 -2
  10. package/commonjs/plugins/copyPaste/contextMenuItem/cut.js +1 -2
  11. package/commonjs/plugins/copyPaste/copyPaste.js +127 -134
  12. package/commonjs/plugins/copyPaste/pasteEvent.js +19 -0
  13. package/commonjs/plugins/copyPaste/test/copyPaste.e2e.js +90 -189
  14. package/commonjs/plugins/copyPaste/test/textarea.unit.js +2 -2
  15. package/commonjs/plugins/copyPaste/textarea.js +2 -1
  16. package/commonjs/plugins/manualColumnMove/manualColumnMove.js +8 -11
  17. package/commonjs/plugins/manualColumnMove/test/manualColumnMoveUI.e2e.js +35 -0
  18. package/commonjs/plugins/manualRowMove/manualRowMove.js +9 -12
  19. package/commonjs/plugins/manualRowMove/test/manualRowMove.e2e.js +256 -60
  20. package/commonjs/plugins/manualRowMove/test/manualRowMoveUI.e2e.js +40 -182
  21. package/commonjs/plugins/manualRowMove/ui/_base.js +2 -2
  22. package/commonjs/tableView.js +1 -0
  23. package/dist/handsontable.css +6 -5
  24. package/dist/handsontable.css.map +1 -1
  25. package/dist/handsontable.full.css +6 -5
  26. package/dist/handsontable.full.js +37721 -42290
  27. package/dist/handsontable.full.min.css +4 -4
  28. package/dist/handsontable.full.min.js +5 -5
  29. package/dist/handsontable.js +28732 -28433
  30. package/dist/handsontable.js.map +1 -1
  31. package/dist/handsontable.min.css +4 -4
  32. package/dist/handsontable.min.js +3 -3
  33. package/es/core.js +11 -6
  34. package/es/helpers/dom/element.js +4 -3
  35. package/es/helpers/mixed.js +4 -4
  36. package/es/index.js +3 -4
  37. package/es/pluginHooks.js +18 -2
  38. package/es/plugins/copyPaste/clipboardData.js +27 -0
  39. package/es/plugins/copyPaste/contextMenuItem/copy.js +1 -2
  40. package/es/plugins/copyPaste/contextMenuItem/cut.js +1 -2
  41. package/es/plugins/copyPaste/copyPaste.js +124 -132
  42. package/es/plugins/copyPaste/pasteEvent.js +11 -0
  43. package/es/plugins/copyPaste/test/copyPaste.e2e.js +90 -189
  44. package/es/plugins/copyPaste/test/textarea.unit.js +2 -2
  45. package/es/plugins/copyPaste/textarea.js +2 -1
  46. package/es/plugins/manualColumnMove/manualColumnMove.js +8 -11
  47. package/es/plugins/manualColumnMove/test/manualColumnMoveUI.e2e.js +35 -0
  48. package/es/plugins/manualRowMove/manualRowMove.js +9 -12
  49. package/es/plugins/manualRowMove/test/manualRowMove.e2e.js +256 -60
  50. package/es/plugins/manualRowMove/test/manualRowMoveUI.e2e.js +40 -182
  51. package/es/plugins/manualRowMove/ui/_base.js +2 -2
  52. package/es/tableView.js +1 -0
  53. package/handsontable.jquery.json +1 -1
  54. package/hot.config.js +1 -1
  55. package/package.json +5 -5
  56. package/src/3rdparty/walkontable/dist/walkontable.js +27234 -11175
  57. package/src/3rdparty/walkontable/dist/walkontable.js.map +1 -1
  58. package/src/3rdparty/walkontable/test/dist/helpers.entry.js +32 -36
  59. package/src/3rdparty/walkontable/test/dist/helpers.entry.js.map +1 -1
  60. package/src/3rdparty/walkontable/test/dist/specs.entry.js +36 -39
  61. package/src/3rdparty/walkontable/test/dist/specs.entry.js.map +1 -1
  62. package/src/core.js +11 -6
  63. package/src/css/handsontable.css +1 -2
  64. package/src/helpers/dom/element.js +4 -3
  65. package/src/helpers/mixed.js +3 -3
  66. package/src/index.js +1 -2
  67. package/src/pluginHooks.js +18 -2
  68. package/src/plugins/copyPaste/clipboardData.js +11 -0
  69. package/src/plugins/copyPaste/contextMenuItem/copy.js +1 -2
  70. package/src/plugins/copyPaste/contextMenuItem/cut.js +1 -2
  71. package/src/plugins/copyPaste/copyPaste.css +3 -1
  72. package/src/plugins/copyPaste/copyPaste.js +120 -127
  73. package/src/plugins/copyPaste/pasteEvent.js +7 -0
  74. package/src/plugins/copyPaste/test/copyPaste.e2e.js +75 -193
  75. package/src/plugins/copyPaste/test/textarea.unit.js +2 -2
  76. package/src/plugins/copyPaste/textarea.js +2 -1
  77. package/src/plugins/manualColumnMove/manualColumnMove.js +6 -9
  78. package/src/plugins/manualColumnMove/test/manualColumnMoveUI.e2e.js +35 -0
  79. package/src/plugins/manualRowMove/manualRowMove.js +7 -10
  80. package/src/plugins/manualRowMove/test/manualRowMove.e2e.js +282 -86
  81. package/src/plugins/manualRowMove/test/manualRowMoveUI.e2e.js +51 -190
  82. package/src/plugins/manualRowMove/ui/_base.js +2 -2
  83. package/test/dist/e2e.entry.js +31381 -31131
  84. package/test/dist/e2e.entry.js.map +1 -1
  85. package/test/dist/helpers.entry.js +16 -19
  86. package/test/dist/helpers.entry.js.map +1 -1
  87. package/test/e2e/Core_listen.spec.js +32 -0
  88. package/test/e2e/Core_selection.spec.js +1 -1
  89. package/test/e2e/Core_validate.spec.js +29 -0
  90. package/test/e2e/renderers/checkboxRenderer.spec.js +20 -7
  91. package/test/e2e/settings/fragmentSelection.spec.js +12 -9
  92. package/test/scripts/trigger-pro-tests.sh +41 -0
  93. package/yarn.lock +260 -208
  94. package/.npmignore +0 -19
  95. package/demo/bower_components/numbro/package.json +0 -63
package/src/core.js CHANGED
@@ -1049,7 +1049,7 @@ export default function Core(rootElement, userSettings, rootInstanceSymbol = fal
1049
1049
  if (result === false && cellProperties.allowInvalid === false) {
1050
1050
  changes.splice(i, 1); // cancel the change
1051
1051
  cellProperties.valid = true; // we cancelled the change, so cell value is still valid
1052
- const cell = instance.getCell(cellProperties.row, cellProperties.col);
1052
+ const cell = instance.getCell(cellProperties.visualRow, cellProperties.visualCol);
1053
1053
  removeClass(cell, instance.getSettings().invalidCellClassName);
1054
1054
  --i;
1055
1055
  }
@@ -1305,7 +1305,10 @@ export default function Core(rootElement, userSettings, rootInstanceSymbol = fal
1305
1305
  document.body.focus();
1306
1306
  }
1307
1307
 
1308
- activeGuid = instance.guid;
1308
+ if (instance && !instance.isListening()) {
1309
+ activeGuid = instance.guid;
1310
+ instance.runHooks('afterListen');
1311
+ }
1309
1312
  };
1310
1313
 
1311
1314
  /**
@@ -1318,6 +1321,7 @@ export default function Core(rootElement, userSettings, rootInstanceSymbol = fal
1318
1321
  this.unlisten = function() {
1319
1322
  if (this.isListening()) {
1320
1323
  activeGuid = null;
1324
+ instance.runHooks('afterUnlisten');
1321
1325
  }
1322
1326
  };
1323
1327
 
@@ -3058,7 +3062,6 @@ export default function Core(rootElement, userSettings, rootInstanceSymbol = fal
3058
3062
  selection.setRangeEnd(new CellCoords(endRow, endCol), scrollToCell);
3059
3063
  }
3060
3064
  instance.selection.finish();
3061
-
3062
3065
  return true;
3063
3066
  };
3064
3067
 
@@ -3155,10 +3158,12 @@ export default function Core(rootElement, userSettings, rootInstanceSymbol = fal
3155
3158
  }
3156
3159
  dataSource = null;
3157
3160
 
3158
- const nextSibling = instance.rootElement.nextSibling;
3161
+ if (process.env.HOT_PACKAGE_TYPE !== '\x63\x65' && isRootInstance(instance)) {
3162
+ const licenseInfo = document.querySelector('#hot-display-license-info');
3159
3163
 
3160
- if (isRootInstance(instance) && nextSibling) {
3161
- instance.rootElement.parentNode.removeChild(nextSibling);
3164
+ if (licenseInfo) {
3165
+ licenseInfo.parentNode.removeChild(licenseInfo);
3166
+ }
3162
3167
  }
3163
3168
  empty(instance.rootElement);
3164
3169
  eventManager.destroy();
@@ -174,8 +174,7 @@
174
174
  color: #000;
175
175
  }
176
176
 
177
- .handsontable + .display-license-info {
178
- background-color: rgba(255, 255, 255, 0.8);
177
+ #hot-display-license-info {
179
178
  font-size: 9px;
180
179
  color: #323232 ;
181
180
  padding: 5px 0 3px 0;
@@ -287,7 +287,7 @@ if (classListSupport) {
287
287
 
288
288
  _hasClass = function _hasClass(element, className) {
289
289
  // http://snipplr.com/view/3561/addclass-removeclass-hasclass/
290
- return element.className !== void 0 && element.className.test(createClassNameRegExp(className));
290
+ return element.className !== void 0 && createClassNameRegExp(className).test(element.className);
291
291
  };
292
292
 
293
293
  _addClass = function _addClass(element, className) {
@@ -613,11 +613,12 @@ export function getScrollableElement(element) {
613
613
  }
614
614
  }
615
615
 
616
- if (el.clientHeight <= el.scrollHeight && (props.indexOf(overflowY) !== -1 || props.indexOf(overflow) !== -1 ||
616
+ // The '+ 1' after the scrollHeight/scrollWidth is to prevent problems with zoomed out Chrome.
617
+ if (el.clientHeight <= el.scrollHeight + 1 && (props.indexOf(overflowY) !== -1 || props.indexOf(overflow) !== -1 ||
617
618
  props.indexOf(computedOverflow) !== -1 || props.indexOf(computedOverflowY) !== -1)) {
618
619
  return el;
619
620
  }
620
- if (el.clientWidth <= el.scrollWidth && (props.indexOf(overflowX) !== -1 || props.indexOf(overflow) !== -1 ||
621
+ if (el.clientWidth <= el.scrollWidth + 1 && (props.indexOf(overflowX) !== -1 || props.indexOf(overflow) !== -1 ||
621
622
  props.indexOf(computedOverflow) !== -1 || props.indexOf(computedOverflowX) !== -1)) {
622
623
  return el;
623
624
  }
@@ -1,4 +1,4 @@
1
- import {addClass} from './dom/element';
1
+ import moment from 'moment';
2
2
  import {toSingleLine} from './templateLiteralTag';
3
3
 
4
4
  /**
@@ -76,7 +76,7 @@ const _hd = (v) => parseInt(v, 16);
76
76
  const _pi = (v) => parseInt(v, 10);
77
77
  const _ss = (v, s, l) => v['\x73\x75\x62\x73\x74\x72'](s, l);
78
78
  const _cp = (v) => v['\x63\x6F\x64\x65\x50\x6F\x69\x6E\x74\x41\x74'](0) - 65;
79
- const _norm = (v) => v.replace(/\-/g, '');
79
+ const _norm = (v) => `${v}`.replace(/\-/g, '');
80
80
  const _extractTime = (v) => _hd(_ss(_norm(v), _hd('12'), _cp('\x46'))) / (_hd(_ss(_norm(v), _cp('\x42'), ~~![][_m])) || 9);
81
81
  const _ignored = () => typeof location !== 'undefined' && /^([a-z0-9\-]+\.)?\x68\x61\x6E\x64\x73\x6F\x6E\x74\x61\x62\x6C\x65\x2E\x63\x6F\x6D$/i.test(location.host);
82
82
  let _notified = false;
@@ -128,7 +128,7 @@ export function _injectProductInfo(key, element) {
128
128
  if (showDomMessage && element.parentNode) {
129
129
  const message = document.createElement('div');
130
130
 
131
- addClass(message, 'display-license-info');
131
+ message.id = 'hot-display-license-info';
132
132
  message.appendChild(document.createTextNode('Evaluation version of Handsontable Pro.'));
133
133
  message.appendChild(document.createElement('br'));
134
134
  message.appendChild(document.createTextNode('Not licensed for production use.'));
package/src/index.js CHANGED
@@ -166,5 +166,4 @@ arrayHelpers.arrayEach(Object.getOwnPropertyNames(plugins), (pluginName) => {
166
166
 
167
167
  Handsontable.plugins.registerPlugin = registerPlugin;
168
168
 
169
- // Export Handsontable
170
- module.exports = Handsontable;
169
+ export default Handsontable;
@@ -1107,7 +1107,7 @@ const REGISTERED_HOOKS = [
1107
1107
  /**
1108
1108
  * Fired after values are pasted into table.
1109
1109
  *
1110
- * @event Hooks#afterePaste
1110
+ * @event Hooks#afterPaste
1111
1111
  * @since 0.31.1
1112
1112
  * @param {Array} data An array of arrays which contains the pasted data.
1113
1113
  * @param {Array} coords An array of objects with ranges of the visual indexes (`startRow`, `startCol`, `endRow`, `endCol`)
@@ -1484,7 +1484,23 @@ const REGISTERED_HOOKS = [
1484
1484
  * @param {Number} row Row index of the edited cell.
1485
1485
  * @param {Number} column Column index of the edited cell.
1486
1486
  */
1487
- 'afterBeginEditing'
1487
+ 'afterBeginEditing',
1488
+
1489
+ /**
1490
+ * Fired after the listening is turned on.
1491
+ *
1492
+ * @event Hooks#afterListen
1493
+ * @since 0.34.5
1494
+ */
1495
+ 'afterListen',
1496
+
1497
+ /**
1498
+ * Fired after the listening is turned off.
1499
+ *
1500
+ * @event Hooks#afterUnlisten
1501
+ * @since 0.34.5
1502
+ */
1503
+ 'afterUnlisten',
1488
1504
  ];
1489
1505
 
1490
1506
  class Hooks {
@@ -0,0 +1,11 @@
1
+ export default class ClipboardData {
2
+ constructor() {
3
+ this.data = {};
4
+ }
5
+ setData(type, value) {
6
+ this.data[type] = value;
7
+ }
8
+ getData(type) {
9
+ return this.data[type] || void 0;
10
+ }
11
+ }
@@ -3,8 +3,7 @@ export default function copyItem(copyPastePlugin) {
3
3
  key: 'copy',
4
4
  name: 'Copy',
5
5
  callback() {
6
- copyPastePlugin.setCopyableText();
7
- copyPastePlugin.copy(true);
6
+ copyPastePlugin.copy();
8
7
  },
9
8
  disabled() {
10
9
  return !copyPastePlugin.hot.getSelected();
@@ -3,8 +3,7 @@ export default function cutItem(copyPastePlugin) {
3
3
  key: 'cut',
4
4
  name: 'Cut',
5
5
  callback() {
6
- copyPastePlugin.setCopyableText();
7
- copyPastePlugin.cut(true);
6
+ copyPastePlugin.cut();
8
7
  },
9
8
  disabled() {
10
9
  return !copyPastePlugin.hot.getSelected();
@@ -1,6 +1,8 @@
1
1
  textarea#HandsontableCopyPaste {
2
2
  position: fixed !important;
3
- bottom: 100% !important;
3
+ top: 0 !important;
4
4
  right: 100% !important;
5
+ overflow: hidden;
6
+ opacity: 0;
5
7
  outline: 0 none !important;
6
8
  }
@@ -2,16 +2,15 @@ import BasePlugin from './../_base.js';
2
2
  import Hooks from './../../pluginHooks';
3
3
  import SheetClip from './../../../lib/SheetClip/SheetClip';
4
4
  import {CellCoords, CellRange} from './../../3rdparty/walkontable/src';
5
- import {KEY_CODES, isCtrlKey} from './../../helpers/unicode';
6
5
  import {getSelectionText} from './../../helpers/dom/element';
7
6
  import {arrayEach} from './../../helpers/array';
8
7
  import {rangeEach} from './../../helpers/number';
9
- import {stopImmediatePropagation, stopPropagation, isImmediatePropagationStopped} from './../../helpers/dom/event';
10
8
  import {registerPlugin} from './../../plugins';
11
9
  import Textarea from './textarea';
12
10
  import copyItem from './contextMenuItem/copy';
13
11
  import cutItem from './contextMenuItem/cut';
14
12
  import EventManager from './../../eventManager';
13
+ import PasteEvent from './pasteEvent';
15
14
 
16
15
  import './copyPaste.css';
17
16
 
@@ -94,7 +93,10 @@ class CopyPaste extends BasePlugin {
94
93
  this.textarea = void 0;
95
94
 
96
95
  privatePool.set(this, {
97
- isTriggeredByPaste: false,
96
+ isTriggeredByCopy: false,
97
+ isTriggeredByCut: false,
98
+ isBeginEditing: false,
99
+ isFragmentSelectionEnabled: false,
98
100
  });
99
101
  }
100
102
 
@@ -114,10 +116,11 @@ class CopyPaste extends BasePlugin {
114
116
  if (this.enabled) {
115
117
  return;
116
118
  }
117
-
118
119
  const settings = this.hot.getSettings();
120
+ const priv = privatePool.get(this);
119
121
 
120
122
  this.textarea = Textarea.getSingleton();
123
+ priv.isFragmentSelectionEnabled = settings.fragmentSelection;
121
124
 
122
125
  if (typeof settings.copyPaste === 'object') {
123
126
  this.pasteMode = settings.copyPaste.pasteMode || this.pasteMode;
@@ -126,12 +129,13 @@ class CopyPaste extends BasePlugin {
126
129
  }
127
130
 
128
131
  this.addHook('afterContextMenuDefaultOptions', (options) => this.onAfterContextMenuDefaultOptions(options));
129
- this.addHook('beforeKeyDown', (event) => this.onBeforeKeyDown(event));
132
+ this.addHook('afterSelectionEnd', () => this.onAfterSelectionEnd());
130
133
 
131
134
  this.registerEvents();
132
135
 
133
136
  super.enablePlugin();
134
137
  }
138
+
135
139
  /**
136
140
  * Updates the plugin to use the latest options you have specified.
137
141
  */
@@ -186,10 +190,6 @@ class CopyPaste extends BasePlugin {
186
190
 
187
191
  this.copyableRanges = this.hot.runHooks('modifyCopyableRange', this.copyableRanges);
188
192
 
189
- let copyableData = this.getRangedCopyableData(this.copyableRanges);
190
-
191
- this.textarea.setValue(copyableData);
192
-
193
193
  if (endRow !== finalEndRow || endCol !== finalEndCol) {
194
194
  this.hot.runHooks('afterCopyLimit', endRow - startRow + 1, endCol - startCol + 1, this.rowsLimit, this.columnsLimit);
195
195
  }
@@ -275,53 +275,26 @@ class CopyPaste extends BasePlugin {
275
275
 
276
276
  /**
277
277
  * Copy action.
278
- *
279
- * @param {Boolean} isTriggeredByClick Flag to determine that copy action was executed by the mouse click.
280
278
  */
281
- copy(isTriggeredByClick) {
282
- let rangedData = this.getRangedData(this.copyableRanges);
283
-
284
- let allowCopying = !!this.hot.runHooks('beforeCopy', rangedData, this.copyableRanges);
285
-
286
- if (allowCopying) {
287
- this.textarea.setValue(SheetClip.stringify(rangedData));
288
- this.textarea.select();
289
-
290
- if (isTriggeredByClick) {
291
- document.execCommand('copy');
292
- }
279
+ copy() {
280
+ const priv = privatePool.get(this);
293
281
 
294
- this.hot.runHooks('afterCopy', rangedData, this.copyableRanges);
282
+ priv.isTriggeredByCopy = true;
295
283
 
296
- } else {
297
- this.textarea.setValue('');
298
- }
284
+ this.textarea.select();
285
+ document.execCommand('copy');
299
286
  }
300
287
 
301
288
  /**
302
289
  * Cut action.
303
- *
304
- * @param {Boolean} isTriggeredByClick Flag to determine that cut action was executed by the mouse click.
305
290
  */
306
- cut(isTriggeredByClick) {
307
- let rangedData = this.getRangedData(this.copyableRanges);
308
-
309
- let allowCuttingOut = !!this.hot.runHooks('beforeCut', rangedData, this.copyableRanges);
310
-
311
- if (allowCuttingOut) {
312
- this.textarea.setValue(SheetClip.stringify(rangedData));
313
- this.hot.selection.empty();
314
- this.textarea.select();
315
-
316
- if (isTriggeredByClick) {
317
- document.execCommand('cut');
318
- }
291
+ cut() {
292
+ const priv = privatePool.get(this);
319
293
 
320
- this.hot.runHooks('afterCut', rangedData, this.copyableRanges);
294
+ priv.isTriggeredByCut = true;
321
295
 
322
- } else {
323
- this.textarea.setValue('');
324
- }
296
+ this.textarea.select();
297
+ document.execCommand('cut');
325
298
  }
326
299
 
327
300
  /**
@@ -330,10 +303,10 @@ class CopyPaste extends BasePlugin {
330
303
  * @param {String} [value=''] New value, which should be `pasted`.
331
304
  */
332
305
  paste(value = '') {
333
- this.textarea.setValue(value);
306
+ let pasteData = new PasteEvent();
307
+ pasteData.clipboardData.setData('text/plain', value);
334
308
 
335
- this.onPaste();
336
- this.onInput();
309
+ this.onPaste(pasteData);
337
310
  }
338
311
 
339
312
  /**
@@ -343,58 +316,112 @@ class CopyPaste extends BasePlugin {
343
316
  */
344
317
  registerEvents() {
345
318
  this.eventManager.addEventListener(this.textarea.element, 'paste', (event) => this.onPaste(event));
346
- this.eventManager.addEventListener(this.textarea.element, 'input', (event) => this.onInput(event));
319
+ this.eventManager.addEventListener(this.textarea.element, 'cut', (event) => this.onCut(event));
320
+ this.eventManager.addEventListener(this.textarea.element, 'copy', (event) => this.onCopy(event));
347
321
  }
348
322
 
349
323
  /**
350
- * Trigger to make possible observe `onInput` in textarea.
324
+ * `copy` event callback on textarea element.
351
325
  *
326
+ * @param {Event} event ClipboardEvent.
352
327
  * @private
353
328
  */
354
- triggerPaste() {
355
- this.textarea.select();
329
+ onCopy(event) {
330
+ const priv = privatePool.get(this);
331
+
332
+ if (!this.hot.isListening() && !priv.isTriggeredByCopy) {
333
+ return;
334
+ }
335
+
336
+ this.setCopyableText();
337
+ priv.isTriggeredByCopy = false;
338
+
339
+ let rangedData = this.getRangedData(this.copyableRanges);
340
+ let allowCopying = !!this.hot.runHooks('beforeCopy', rangedData, this.copyableRanges);
341
+ let value = '';
342
+
343
+ if (allowCopying) {
344
+ value = SheetClip.stringify(rangedData);
345
+
346
+ if (event && event.clipboardData) {
347
+ event.clipboardData.setData('text/plain', value);
348
+
349
+ } else if (typeof ClipboardEvent === 'undefined') {
350
+ window.clipboardData.setData('Text', value);
351
+ }
352
+
353
+ this.hot.runHooks('afterCopy', rangedData, this.copyableRanges);
354
+ }
356
355
 
357
- this.onPaste();
356
+ event.preventDefault();
358
357
  }
359
358
 
360
359
  /**
361
- * `paste` event callback on textarea element.
360
+ * `cut` event callback on textarea element.
362
361
  *
362
+ * @param {Event} event ClipboardEvent.
363
363
  * @private
364
364
  */
365
- onPaste() {
365
+ onCut(event) {
366
366
  const priv = privatePool.get(this);
367
367
 
368
- priv.isTriggeredByPaste = true;
368
+ if (!this.hot.isListening() && !priv.isTriggeredByCut) {
369
+ return;
370
+ }
371
+
372
+ this.setCopyableText();
373
+ priv.isTriggeredByCut = false;
374
+
375
+ let rangedData = this.getRangedData(this.copyableRanges);
376
+ let allowCuttingOut = !!this.hot.runHooks('beforeCut', rangedData, this.copyableRanges);
377
+ let value;
378
+
379
+ if (allowCuttingOut) {
380
+ value = SheetClip.stringify(rangedData);
381
+
382
+ if (event && event.clipboardData) {
383
+ event.clipboardData.setData('text/plain', value);
384
+
385
+ } else if (typeof ClipboardEvent === 'undefined') {
386
+ window.clipboardData.setData('Text', value);
387
+ }
388
+
389
+ this.hot.selection.empty();
390
+ this.hot.runHooks('afterCut', rangedData, this.copyableRanges);
391
+ }
392
+
393
+ event.preventDefault();
369
394
  }
370
395
 
371
396
  /**
372
- * `input` event callback is called after `paste` event callback.
397
+ * `paste` event callback on textarea element.
373
398
  *
399
+ * @param {Event} event ClipboardEvent or pseudo ClipboardEvent, if paste was called manually.
374
400
  * @private
375
401
  */
376
- onInput() {
377
- const priv = privatePool.get(this);
378
-
379
- if (!this.hot.isListening() || !priv.isTriggeredByPaste) {
402
+ onPaste(event) {
403
+ if (!this.hot.isListening()) {
380
404
  return;
381
405
  }
406
+ if (event && event.preventDefault) {
407
+ event.preventDefault();
408
+ }
409
+
410
+ let inputArray;
382
411
 
383
- priv.isTriggeredByPaste = false;
412
+ if (event && typeof event.clipboardData !== 'undefined') {
413
+ this.textarea.setValue(event.clipboardData.getData('text/plain'));
384
414
 
385
- let input,
386
- inputArray,
387
- selected,
388
- coordsFrom,
389
- coordsTo,
390
- cellRange,
391
- topLeftCorner,
392
- bottomRightCorner,
393
- areaStart,
394
- areaEnd;
415
+ } else if (typeof ClipboardEvent === 'undefined' && typeof window.clipboardData !== 'undefined') {
416
+ this.textarea.setValue(window.clipboardData.getData('Text'));
417
+ }
418
+
419
+ inputArray = SheetClip.parse(this.textarea.getValue());
420
+ this.textarea.setValue(' ');
395
421
 
396
- input = this.textarea.getValue();
397
- inputArray = SheetClip.parse(input);
422
+ if (inputArray.length === 0) {
423
+ return;
424
+ }
398
425
 
399
426
  let allowPasting = !!this.hot.runHooks('beforePaste', inputArray, this.copyableRanges);
400
427
 
@@ -402,21 +429,21 @@ class CopyPaste extends BasePlugin {
402
429
  return;
403
430
  }
404
431
 
405
- selected = this.hot.getSelected();
406
- coordsFrom = new CellCoords(selected[0], selected[1]);
407
- coordsTo = new CellCoords(selected[2], selected[3]);
408
- cellRange = new CellRange(coordsFrom, coordsFrom, coordsTo);
409
- topLeftCorner = cellRange.getTopLeftCorner();
410
- bottomRightCorner = cellRange.getBottomRightCorner();
411
- areaStart = topLeftCorner;
412
- areaEnd = new CellCoords(
432
+ let selected = this.hot.getSelected();
433
+ let coordsFrom = new CellCoords(selected[0], selected[1]);
434
+ let coordsTo = new CellCoords(selected[2], selected[3]);
435
+ let cellRange = new CellRange(coordsFrom, coordsFrom, coordsTo);
436
+ let topLeftCorner = cellRange.getTopLeftCorner();
437
+ let bottomRightCorner = cellRange.getBottomRightCorner();
438
+ let areaStart = topLeftCorner;
439
+ let areaEnd = new CellCoords(
413
440
  Math.max(bottomRightCorner.row, inputArray.length - 1 + topLeftCorner.row),
414
441
  Math.max(bottomRightCorner.col, inputArray[0].length - 1 + topLeftCorner.col));
415
442
 
416
443
  let isSelRowAreaCoverInputValue = coordsTo.row - coordsFrom.row >= inputArray.length - 1;
417
444
  let isSelColAreaCoverInputValue = coordsTo.col - coordsFrom.col >= inputArray[0].length - 1;
418
445
 
419
- this.hot.addHookOnce('afterChange', (changes, source) => {
446
+ this.hot.addHookOnce('afterChange', (changes) => {
420
447
  let changesLength = changes ? changes.length : 0;
421
448
 
422
449
  if (changesLength) {
@@ -461,57 +488,23 @@ class CopyPaste extends BasePlugin {
461
488
  }
462
489
 
463
490
  /**
464
- * beforeKeyDown callback.
491
+ * We have to keep focus on textarea element, to make possible use of the browser tools (copy, cut, paste).
465
492
  *
466
493
  * @private
467
- * @param {Event} event
468
494
  */
469
- onBeforeKeyDown(event) {
470
- if (!this.hot.getSelected()) {
471
- return;
472
- }
473
- if (this.hot.getActiveEditor() && this.hot.getActiveEditor().isOpened()) {
474
- return;
475
- }
476
- if (isImmediatePropagationStopped(event)) {
495
+ onAfterSelectionEnd() {
496
+ const priv = privatePool.get(this);
497
+ const editor = this.hot.getActiveEditor();
498
+
499
+ if (editor && typeof editor.isOpened !== 'undefined' && editor.isOpened()) {
477
500
  return;
478
501
  }
479
- if (!this.textarea.isActive() && getSelectionText()) {
502
+ if (priv.isFragmentSelectionEnabled && !this.textarea.isActive() && getSelectionText()) {
480
503
  return;
481
504
  }
482
505
 
483
- if (isCtrlKey(event.keyCode)) {
484
- // When fragmentSelection is enabled and some text is selected then don't blur selection calling 'setCopyableText'
485
- if (this.hot.getSettings().fragmentSelection && getSelectionText()) {
486
- return;
487
- }
488
-
489
- // when CTRL is pressed, prepare selectable text in textarea
490
- this.setCopyableText();
491
- stopImmediatePropagation(event);
492
-
493
- return;
494
- }
495
-
496
- // catch CTRL but not right ALT (which in some systems triggers ALT+CTRL)
497
- let ctrlDown = (event.ctrlKey || event.metaKey) && !event.altKey;
498
-
499
- if (ctrlDown) {
500
- if (event.keyCode == KEY_CODES.A) {
501
- setTimeout(() => {
502
- this.setCopyableText();
503
- }, 0);
504
- }
505
- if (event.keyCode == KEY_CODES.X) {
506
- this.cut();
507
- }
508
- if (event.keyCode == KEY_CODES.C) {
509
- this.copy();
510
- }
511
- if (event.keyCode == KEY_CODES.V) {
512
- this.triggerPaste();
513
- }
514
- }
506
+ this.setCopyableText();
507
+ this.textarea.select();
515
508
  }
516
509
 
517
510
  /**
@@ -0,0 +1,7 @@
1
+ import ClipboardData from './clipboardData';
2
+
3
+ export default class PasteEvent {
4
+ constructor() {
5
+ this.clipboardData = new ClipboardData();
6
+ }
7
+ }