tableView.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. 'use strict';
  2. exports.__esModule = true;
  3. var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
  4. var _element = require('./helpers/dom/element');
  5. var _browser = require('./helpers/browser');
  6. var _eventManager = require('./eventManager');
  7. var _eventManager2 = _interopRequireDefault(_eventManager);
  8. var _event = require('./helpers/dom/event');
  9. var _src = require('./3rdparty/walkontable/src');
  10. var _src2 = _interopRequireDefault(_src);
  11. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  12. /**
  13. * Handsontable TableView constructor
  14. * @param {Object} instance
  15. */
  16. function TableView(instance) {
  17. var _this = this;
  18. var that = this;
  19. this.eventManager = new _eventManager2.default(instance);
  20. this.instance = instance;
  21. this.settings = instance.getSettings();
  22. this.selectionMouseDown = false;
  23. var originalStyle = instance.rootElement.getAttribute('style');
  24. if (originalStyle) {
  25. instance.rootElement.setAttribute('data-originalstyle', originalStyle); // needed to retrieve original style in jsFiddle link generator in HT examples. may be removed in future versions
  26. }
  27. (0, _element.addClass)(instance.rootElement, 'handsontable');
  28. var table = document.createElement('TABLE');
  29. (0, _element.addClass)(table, 'htCore');
  30. if (instance.getSettings().tableClassName) {
  31. (0, _element.addClass)(table, instance.getSettings().tableClassName);
  32. }
  33. this.THEAD = document.createElement('THEAD');
  34. table.appendChild(this.THEAD);
  35. this.TBODY = document.createElement('TBODY');
  36. table.appendChild(this.TBODY);
  37. instance.table = table;
  38. instance.container.insertBefore(table, instance.container.firstChild);
  39. this.eventManager.addEventListener(instance.rootElement, 'mousedown', function (event) {
  40. this.selectionMouseDown = true;
  41. if (!that.isTextSelectionAllowed(event.target)) {
  42. clearTextSelection();
  43. event.preventDefault();
  44. window.focus(); // make sure that window that contains HOT is active. Important when HOT is in iframe.
  45. }
  46. });
  47. this.eventManager.addEventListener(instance.rootElement, 'mouseup', function (event) {
  48. this.selectionMouseDown = false;
  49. });
  50. this.eventManager.addEventListener(instance.rootElement, 'mousemove', function (event) {
  51. if (this.selectionMouseDown && !that.isTextSelectionAllowed(event.target)) {
  52. clearTextSelection();
  53. event.preventDefault();
  54. }
  55. });
  56. this.eventManager.addEventListener(document.documentElement, 'keyup', function (event) {
  57. if (instance.selection.isInProgress() && !event.shiftKey) {
  58. instance.selection.finish();
  59. }
  60. });
  61. var isMouseDown;
  62. this.isMouseDown = function () {
  63. return isMouseDown;
  64. };
  65. this.eventManager.addEventListener(document.documentElement, 'mouseup', function (event) {
  66. if (instance.selection.isInProgress() && event.which === 1) {
  67. // is left mouse button
  68. instance.selection.finish();
  69. }
  70. isMouseDown = false;
  71. if ((0, _element.isOutsideInput)(document.activeElement)) {
  72. instance.unlisten();
  73. }
  74. });
  75. this.eventManager.addEventListener(document.documentElement, 'mousedown', function (event) {
  76. var originalTarget = event.target;
  77. var next = event.target;
  78. var eventX = event.x || event.clientX;
  79. var eventY = event.y || event.clientY;
  80. if (isMouseDown || !instance.rootElement) {
  81. return; // it must have been started in a cell
  82. }
  83. // immediate click on "holder" means click on the right side of vertical scrollbar
  84. if (next === instance.view.wt.wtTable.holder) {
  85. var scrollbarWidth = (0, _element.getScrollbarWidth)();
  86. if (document.elementFromPoint(eventX + scrollbarWidth, eventY) !== instance.view.wt.wtTable.holder || document.elementFromPoint(eventX, eventY + scrollbarWidth) !== instance.view.wt.wtTable.holder) {
  87. return;
  88. }
  89. } else {
  90. while (next !== document.documentElement) {
  91. if (next === null) {
  92. if (event.isTargetWebComponent) {
  93. break;
  94. }
  95. // click on something that was a row but now is detached (possibly because your click triggered a rerender)
  96. return;
  97. }
  98. if (next === instance.rootElement) {
  99. // click inside container
  100. return;
  101. }
  102. next = next.parentNode;
  103. }
  104. }
  105. // function did not return until here, we have an outside click!
  106. var outsideClickDeselects = typeof that.settings.outsideClickDeselects === 'function' ? that.settings.outsideClickDeselects(originalTarget) : that.settings.outsideClickDeselects;
  107. if (outsideClickDeselects) {
  108. instance.deselectCell();
  109. } else {
  110. instance.destroyEditor();
  111. }
  112. });
  113. this.eventManager.addEventListener(table, 'selectstart', function (event) {
  114. if (that.settings.fragmentSelection || (0, _element.isInput)(event.target)) {
  115. return;
  116. }
  117. // https://github.com/handsontable/handsontable/issues/160
  118. // Prevent text from being selected when performing drag down.
  119. event.preventDefault();
  120. });
  121. var clearTextSelection = function clearTextSelection() {
  122. // http://stackoverflow.com/questions/3169786/clear-text-selection-with-javascript
  123. if (window.getSelection) {
  124. if (window.getSelection().empty) {
  125. // Chrome
  126. window.getSelection().empty();
  127. } else if (window.getSelection().removeAllRanges) {
  128. // Firefox
  129. window.getSelection().removeAllRanges();
  130. }
  131. } else if (document.selection) {
  132. // IE?
  133. document.selection.empty();
  134. }
  135. };
  136. var selections = [new _src.Selection({
  137. className: 'current',
  138. border: {
  139. width: 2,
  140. color: '#5292F7',
  141. // style: 'solid', // not used
  142. cornerVisible: function cornerVisible() {
  143. return that.settings.fillHandle && !that.isCellEdited() && !instance.selection.isMultiple();
  144. },
  145. multipleSelectionHandlesVisible: function multipleSelectionHandlesVisible() {
  146. return !that.isCellEdited() && !instance.selection.isMultiple();
  147. }
  148. }
  149. }), new _src.Selection({
  150. className: 'area',
  151. border: {
  152. width: 1,
  153. color: '#89AFF9',
  154. // style: 'solid', // not used
  155. cornerVisible: function cornerVisible() {
  156. return that.settings.fillHandle && !that.isCellEdited() && instance.selection.isMultiple();
  157. },
  158. multipleSelectionHandlesVisible: function multipleSelectionHandlesVisible() {
  159. return !that.isCellEdited() && instance.selection.isMultiple();
  160. }
  161. }
  162. }), new _src.Selection({
  163. className: 'highlight',
  164. highlightHeaderClassName: that.settings.currentHeaderClassName,
  165. highlightRowClassName: that.settings.currentRowClassName,
  166. highlightColumnClassName: that.settings.currentColClassName
  167. }), new _src.Selection({
  168. className: 'fill',
  169. border: {
  170. width: 1,
  171. color: 'red'
  172. }
  173. })];
  174. selections.current = selections[0];
  175. selections.area = selections[1];
  176. selections.highlight = selections[2];
  177. selections.fill = selections[3];
  178. var walkontableConfig = {
  179. debug: function debug() {
  180. return that.settings.debug;
  181. },
  182. externalRowCalculator: this.instance.getPlugin('autoRowSize') && this.instance.getPlugin('autoRowSize').isEnabled(),
  183. table: table,
  184. preventOverflow: function preventOverflow() {
  185. return _this.settings.preventOverflow;
  186. },
  187. stretchH: function stretchH() {
  188. return that.settings.stretchH;
  189. },
  190. data: instance.getDataAtCell,
  191. totalRows: function totalRows() {
  192. return instance.countRows();
  193. },
  194. totalColumns: function totalColumns() {
  195. return instance.countCols();
  196. },
  197. fixedColumnsLeft: function fixedColumnsLeft() {
  198. return that.settings.fixedColumnsLeft;
  199. },
  200. fixedRowsTop: function fixedRowsTop() {
  201. return that.settings.fixedRowsTop;
  202. },
  203. fixedRowsBottom: function fixedRowsBottom() {
  204. return that.settings.fixedRowsBottom;
  205. },
  206. minSpareRows: function minSpareRows() {
  207. return that.settings.minSpareRows;
  208. },
  209. renderAllRows: that.settings.renderAllRows,
  210. rowHeaders: function rowHeaders() {
  211. var headerRenderers = [];
  212. if (instance.hasRowHeaders()) {
  213. headerRenderers.push(function (row, TH) {
  214. that.appendRowHeader(row, TH);
  215. });
  216. }
  217. instance.runHooks('afterGetRowHeaderRenderers', headerRenderers);
  218. return headerRenderers;
  219. },
  220. columnHeaders: function columnHeaders() {
  221. var headerRenderers = [];
  222. if (instance.hasColHeaders()) {
  223. headerRenderers.push(function (column, TH) {
  224. that.appendColHeader(column, TH);
  225. });
  226. }
  227. instance.runHooks('afterGetColumnHeaderRenderers', headerRenderers);
  228. return headerRenderers;
  229. },
  230. columnWidth: instance.getColWidth,
  231. rowHeight: instance.getRowHeight,
  232. cellRenderer: function cellRenderer(row, col, TD) {
  233. var cellProperties = that.instance.getCellMeta(row, col);
  234. var prop = that.instance.colToProp(col);
  235. var value = that.instance.getDataAtRowProp(row, prop);
  236. if (that.instance.hasHook('beforeValueRender')) {
  237. value = that.instance.runHooks('beforeValueRender', value);
  238. }
  239. that.instance.runHooks('beforeRenderer', TD, row, col, prop, value, cellProperties);
  240. that.instance.getCellRenderer(cellProperties)(that.instance, TD, row, col, prop, value, cellProperties);
  241. that.instance.runHooks('afterRenderer', TD, row, col, prop, value, cellProperties);
  242. },
  243. selections: selections,
  244. hideBorderOnMouseDownOver: function hideBorderOnMouseDownOver() {
  245. return that.settings.fragmentSelection;
  246. },
  247. onCellMouseDown: function onCellMouseDown(event, coords, TD, wt) {
  248. var blockCalculations = {
  249. row: false,
  250. column: false,
  251. cells: false
  252. };
  253. instance.listen();
  254. that.activeWt = wt;
  255. isMouseDown = true;
  256. instance.runHooks('beforeOnCellMouseDown', event, coords, TD, blockCalculations);
  257. if ((0, _event.isImmediatePropagationStopped)(event)) {
  258. return;
  259. }
  260. var actualSelection = instance.getSelectedRange();
  261. var selection = instance.selection;
  262. var selectedHeader = selection.selectedHeader;
  263. if (event.shiftKey && actualSelection) {
  264. if (coords.row >= 0 && coords.col >= 0 && !blockCalculations.cells) {
  265. selection.setSelectedHeaders(false, false);
  266. selection.setRangeEnd(coords);
  267. } else if ((selectedHeader.cols || selectedHeader.rows) && coords.row >= 0 && coords.col >= 0 && !blockCalculations.cells) {
  268. selection.setSelectedHeaders(false, false);
  269. selection.setRangeEnd(new _src.CellCoords(coords.row, coords.col));
  270. } else if (selectedHeader.cols && coords.row < 0 && !blockCalculations.column) {
  271. selection.setRangeEnd(new _src.CellCoords(actualSelection.to.row, coords.col));
  272. } else if (selectedHeader.rows && coords.col < 0 && !blockCalculations.row) {
  273. selection.setRangeEnd(new _src.CellCoords(coords.row, actualSelection.to.col));
  274. } else if ((!selectedHeader.cols && !selectedHeader.rows && coords.col < 0 || selectedHeader.cols && coords.col < 0) && !blockCalculations.row) {
  275. selection.setSelectedHeaders(true, false);
  276. selection.setRangeStartOnly(new _src.CellCoords(actualSelection.from.row, 0));
  277. selection.setRangeEnd(new _src.CellCoords(coords.row, instance.countCols() - 1));
  278. } else if ((!selectedHeader.cols && !selectedHeader.rows && coords.row < 0 || selectedHeader.rows && coords.row < 0) && !blockCalculations.column) {
  279. selection.setSelectedHeaders(false, true);
  280. selection.setRangeStartOnly(new _src.CellCoords(0, actualSelection.from.col));
  281. selection.setRangeEnd(new _src.CellCoords(instance.countRows() - 1, coords.col));
  282. }
  283. } else {
  284. var doNewSelection = true;
  285. if (actualSelection) {
  286. var from = actualSelection.from,
  287. to = actualSelection.to;
  288. var coordsNotInSelection = !selection.inInSelection(coords);
  289. if (coords.row < 0 && selectedHeader.cols) {
  290. var start = Math.min(from.col, to.col);
  291. var end = Math.max(from.col, to.col);
  292. doNewSelection = coords.col < start || coords.col > end;
  293. } else if (coords.col < 0 && selectedHeader.rows) {
  294. var _start = Math.min(from.row, to.row);
  295. var _end = Math.max(from.row, to.row);
  296. doNewSelection = coords.row < _start || coords.row > _end;
  297. } else {
  298. doNewSelection = coordsNotInSelection;
  299. }
  300. }
  301. var rightClick = (0, _event.isRightClick)(event);
  302. var leftClick = (0, _event.isLeftClick)(event) || event.type === 'touchstart';
  303. // clicked row header and when some column was selected
  304. if (coords.row < 0 && coords.col >= 0 && !blockCalculations.column) {
  305. selection.setSelectedHeaders(false, true);
  306. if (leftClick || rightClick && doNewSelection) {
  307. selection.setRangeStartOnly(new _src.CellCoords(0, coords.col));
  308. selection.setRangeEnd(new _src.CellCoords(Math.max(instance.countRows() - 1, 0), coords.col), false);
  309. }
  310. // clicked column header and when some row was selected
  311. } else if (coords.col < 0 && coords.row >= 0 && !blockCalculations.row) {
  312. selection.setSelectedHeaders(true, false);
  313. if (leftClick || rightClick && doNewSelection) {
  314. selection.setRangeStartOnly(new _src.CellCoords(coords.row, 0));
  315. selection.setRangeEnd(new _src.CellCoords(coords.row, Math.max(instance.countCols() - 1, 0)), false);
  316. }
  317. } else if (coords.col >= 0 && coords.row >= 0 && !blockCalculations.cells) {
  318. if (leftClick || rightClick && doNewSelection) {
  319. selection.setSelectedHeaders(false, false);
  320. selection.setRangeStart(coords);
  321. }
  322. } else if (coords.col < 0 && coords.row < 0) {
  323. coords.row = 0;
  324. coords.col = 0;
  325. selection.setSelectedHeaders(false, false, true);
  326. selection.setRangeStart(coords);
  327. }
  328. }
  329. instance.runHooks('afterOnCellMouseDown', event, coords, TD);
  330. that.activeWt = that.wt;
  331. },
  332. onCellMouseOut: function onCellMouseOut(event, coords, TD, wt) {
  333. that.activeWt = wt;
  334. instance.runHooks('beforeOnCellMouseOut', event, coords, TD);
  335. if ((0, _event.isImmediatePropagationStopped)(event)) {
  336. return;
  337. }
  338. instance.runHooks('afterOnCellMouseOut', event, coords, TD);
  339. that.activeWt = that.wt;
  340. },
  341. onCellMouseOver: function onCellMouseOver(event, coords, TD, wt) {
  342. var blockCalculations = {
  343. row: false,
  344. column: false,
  345. cell: false
  346. };
  347. that.activeWt = wt;
  348. instance.runHooks('beforeOnCellMouseOver', event, coords, TD, blockCalculations);
  349. if ((0, _event.isImmediatePropagationStopped)(event)) {
  350. return;
  351. }
  352. if (event.button === 0 && isMouseDown) {
  353. if (coords.row >= 0 && coords.col >= 0) {
  354. // is not a header
  355. if (instance.selection.selectedHeader.cols && !blockCalculations.column) {
  356. instance.selection.setRangeEnd(new _src.CellCoords(instance.countRows() - 1, coords.col), false);
  357. } else if (instance.selection.selectedHeader.rows && !blockCalculations.row) {
  358. instance.selection.setRangeEnd(new _src.CellCoords(coords.row, instance.countCols() - 1), false);
  359. } else if (!blockCalculations.cell) {
  360. instance.selection.setRangeEnd(coords);
  361. }
  362. } else {
  363. /* eslint-disable no-lonely-if */
  364. if (instance.selection.selectedHeader.cols && !blockCalculations.column) {
  365. instance.selection.setRangeEnd(new _src.CellCoords(instance.countRows() - 1, coords.col), false);
  366. } else if (instance.selection.selectedHeader.rows && !blockCalculations.row) {
  367. instance.selection.setRangeEnd(new _src.CellCoords(coords.row, instance.countCols() - 1), false);
  368. } else if (!blockCalculations.cell) {
  369. instance.selection.setRangeEnd(coords);
  370. }
  371. }
  372. }
  373. instance.runHooks('afterOnCellMouseOver', event, coords, TD);
  374. that.activeWt = that.wt;
  375. },
  376. onCellMouseUp: function onCellMouseUp(event, coords, TD, wt) {
  377. that.activeWt = wt;
  378. instance.runHooks('beforeOnCellMouseUp', event, coords, TD);
  379. instance.runHooks('afterOnCellMouseUp', event, coords, TD);
  380. that.activeWt = that.wt;
  381. },
  382. onCellCornerMouseDown: function onCellCornerMouseDown(event) {
  383. event.preventDefault();
  384. instance.runHooks('afterOnCellCornerMouseDown', event);
  385. },
  386. onCellCornerDblClick: function onCellCornerDblClick(event) {
  387. event.preventDefault();
  388. instance.runHooks('afterOnCellCornerDblClick', event);
  389. },
  390. beforeDraw: function beforeDraw(force, skipRender) {
  391. that.beforeRender(force, skipRender);
  392. },
  393. onDraw: function onDraw(force) {
  394. that.onDraw(force);
  395. },
  396. onScrollVertically: function onScrollVertically() {
  397. instance.runHooks('afterScrollVertically');
  398. },
  399. onScrollHorizontally: function onScrollHorizontally() {
  400. instance.runHooks('afterScrollHorizontally');
  401. },
  402. onBeforeDrawBorders: function onBeforeDrawBorders(corners, borderClassName) {
  403. instance.runHooks('beforeDrawBorders', corners, borderClassName);
  404. },
  405. onBeforeTouchScroll: function onBeforeTouchScroll() {
  406. instance.runHooks('beforeTouchScroll');
  407. },
  408. onAfterMomentumScroll: function onAfterMomentumScroll() {
  409. instance.runHooks('afterMomentumScroll');
  410. },
  411. onBeforeStretchingColumnWidth: function onBeforeStretchingColumnWidth(stretchedWidth, column) {
  412. return instance.runHooks('beforeStretchingColumnWidth', stretchedWidth, column);
  413. },
  414. onModifyRowHeaderWidth: function onModifyRowHeaderWidth(rowHeaderWidth) {
  415. return instance.runHooks('modifyRowHeaderWidth', rowHeaderWidth);
  416. },
  417. viewportRowCalculatorOverride: function viewportRowCalculatorOverride(calc) {
  418. var rows = instance.countRows();
  419. var viewportOffset = that.settings.viewportRowRenderingOffset;
  420. if (viewportOffset === 'auto' && that.settings.fixedRowsTop) {
  421. viewportOffset = 10;
  422. }
  423. if (typeof viewportOffset === 'number') {
  424. calc.startRow = Math.max(calc.startRow - viewportOffset, 0);
  425. calc.endRow = Math.min(calc.endRow + viewportOffset, rows - 1);
  426. }
  427. if (viewportOffset === 'auto') {
  428. var center = calc.startRow + calc.endRow - calc.startRow;
  429. var offset = Math.ceil(center / rows * 12);
  430. calc.startRow = Math.max(calc.startRow - offset, 0);
  431. calc.endRow = Math.min(calc.endRow + offset, rows - 1);
  432. }
  433. instance.runHooks('afterViewportRowCalculatorOverride', calc);
  434. },
  435. viewportColumnCalculatorOverride: function viewportColumnCalculatorOverride(calc) {
  436. var cols = instance.countCols();
  437. var viewportOffset = that.settings.viewportColumnRenderingOffset;
  438. if (viewportOffset === 'auto' && that.settings.fixedColumnsLeft) {
  439. viewportOffset = 10;
  440. }
  441. if (typeof viewportOffset === 'number') {
  442. calc.startColumn = Math.max(calc.startColumn - viewportOffset, 0);
  443. calc.endColumn = Math.min(calc.endColumn + viewportOffset, cols - 1);
  444. }
  445. if (viewportOffset === 'auto') {
  446. var center = calc.startColumn + calc.endColumn - calc.startColumn;
  447. var offset = Math.ceil(center / cols * 12);
  448. calc.startRow = Math.max(calc.startColumn - offset, 0);
  449. calc.endColumn = Math.min(calc.endColumn + offset, cols - 1);
  450. }
  451. instance.runHooks('afterViewportColumnCalculatorOverride', calc);
  452. },
  453. rowHeaderWidth: function rowHeaderWidth() {
  454. return that.settings.rowHeaderWidth;
  455. },
  456. columnHeaderHeight: function columnHeaderHeight() {
  457. var columnHeaderHeight = instance.runHooks('modifyColumnHeaderHeight');
  458. return that.settings.columnHeaderHeight || columnHeaderHeight;
  459. }
  460. };
  461. instance.runHooks('beforeInitWalkontable', walkontableConfig);
  462. this.wt = new _src2.default(walkontableConfig);
  463. this.activeWt = this.wt;
  464. if (!(0, _browser.isChrome)() && !(0, _browser.isSafari)()) {
  465. this.eventManager.addEventListener(instance.rootElement, 'wheel', function (event) {
  466. event.preventDefault();
  467. var lineHeight = parseInt((0, _element.getComputedStyle)(document.body)['font-size'], 10);
  468. var holder = that.wt.wtOverlays.scrollableElement;
  469. var deltaY = event.wheelDeltaY || event.deltaY;
  470. var deltaX = event.wheelDeltaX || event.deltaX;
  471. switch (event.deltaMode) {
  472. case 0:
  473. holder.scrollLeft += deltaX;
  474. holder.scrollTop += deltaY;
  475. break;
  476. case 1:
  477. holder.scrollLeft += deltaX * lineHeight;
  478. holder.scrollTop += deltaY * lineHeight;
  479. break;
  480. default:
  481. break;
  482. }
  483. });
  484. }
  485. this.eventManager.addEventListener(that.wt.wtTable.spreader, 'mousedown', function (event) {
  486. // right mouse button exactly on spreader means right click on the right hand side of vertical scrollbar
  487. if (event.target === that.wt.wtTable.spreader && event.which === 3) {
  488. (0, _event.stopPropagation)(event);
  489. }
  490. });
  491. this.eventManager.addEventListener(that.wt.wtTable.spreader, 'contextmenu', function (event) {
  492. // right mouse button exactly on spreader means right click on the right hand side of vertical scrollbar
  493. if (event.target === that.wt.wtTable.spreader && event.which === 3) {
  494. (0, _event.stopPropagation)(event);
  495. }
  496. });
  497. this.eventManager.addEventListener(document.documentElement, 'click', function () {
  498. if (that.settings.observeDOMVisibility) {
  499. if (that.wt.drawInterrupted) {
  500. that.instance.forceFullRender = true;
  501. that.render();
  502. }
  503. }
  504. });
  505. }
  506. TableView.prototype.isTextSelectionAllowed = function (el) {
  507. if ((0, _element.isInput)(el)) {
  508. return true;
  509. }
  510. var isChildOfTableBody = (0, _element.isChildOf)(el, this.instance.view.wt.wtTable.spreader);
  511. if (this.settings.fragmentSelection === true && isChildOfTableBody) {
  512. return true;
  513. }
  514. if (this.settings.fragmentSelection === 'cell' && this.isSelectedOnlyCell() && isChildOfTableBody) {
  515. return true;
  516. }
  517. if (!this.settings.fragmentSelection && this.isCellEdited() && this.isSelectedOnlyCell()) {
  518. return true;
  519. }
  520. return false;
  521. };
  522. /**
  523. * Check if selected only one cell.
  524. *
  525. * @returns {Boolean}
  526. */
  527. TableView.prototype.isSelectedOnlyCell = function () {
  528. var _ref = this.instance.getSelected() || [],
  529. _ref2 = _slicedToArray(_ref, 4),
  530. row = _ref2[0],
  531. col = _ref2[1],
  532. rowEnd = _ref2[2],
  533. colEnd = _ref2[3];
  534. return row !== void 0 && row === rowEnd && col === colEnd;
  535. };
  536. TableView.prototype.isCellEdited = function () {
  537. var activeEditor = this.instance.getActiveEditor();
  538. return activeEditor && activeEditor.isOpened();
  539. };
  540. TableView.prototype.beforeRender = function (force, skipRender) {
  541. if (force) {
  542. // this.instance.forceFullRender = did Handsontable request full render?
  543. this.instance.runHooks('beforeRender', this.instance.forceFullRender, skipRender);
  544. }
  545. };
  546. TableView.prototype.onDraw = function (force) {
  547. if (force) {
  548. // this.instance.forceFullRender = did Handsontable request full render?
  549. this.instance.runHooks('afterRender', this.instance.forceFullRender);
  550. }
  551. };
  552. TableView.prototype.render = function () {
  553. this.wt.draw(!this.instance.forceFullRender);
  554. this.instance.forceFullRender = false;
  555. this.instance.renderCall = false;
  556. };
  557. /**
  558. * Returns td object given coordinates
  559. *
  560. * @param {CellCoords} coords
  561. * @param {Boolean} topmost
  562. */
  563. TableView.prototype.getCellAtCoords = function (coords, topmost) {
  564. var td = this.wt.getCell(coords, topmost);
  565. if (td < 0) {
  566. // there was an exit code (cell is out of bounds)
  567. return null;
  568. }
  569. return td;
  570. };
  571. /**
  572. * Scroll viewport to selection.
  573. *
  574. * @param {CellCoords} coords
  575. */
  576. TableView.prototype.scrollViewport = function (coords) {
  577. this.wt.scrollViewport(coords);
  578. };
  579. /**
  580. * Append row header to a TH element
  581. * @param row
  582. * @param TH
  583. */
  584. TableView.prototype.appendRowHeader = function (row, TH) {
  585. if (TH.firstChild) {
  586. var container = TH.firstChild;
  587. if (!(0, _element.hasClass)(container, 'relative')) {
  588. (0, _element.empty)(TH);
  589. this.appendRowHeader(row, TH);
  590. return;
  591. }
  592. this.updateCellHeader(container.querySelector('.rowHeader'), row, this.instance.getRowHeader);
  593. } else {
  594. var div = document.createElement('div');
  595. var span = document.createElement('span');
  596. div.className = 'relative';
  597. span.className = 'rowHeader';
  598. this.updateCellHeader(span, row, this.instance.getRowHeader);
  599. div.appendChild(span);
  600. TH.appendChild(div);
  601. }
  602. this.instance.runHooks('afterGetRowHeader', row, TH);
  603. };
  604. /**
  605. * Append column header to a TH element
  606. * @param col
  607. * @param TH
  608. */
  609. TableView.prototype.appendColHeader = function (col, TH) {
  610. if (TH.firstChild) {
  611. var container = TH.firstChild;
  612. if ((0, _element.hasClass)(container, 'relative')) {
  613. this.updateCellHeader(container.querySelector('.colHeader'), col, this.instance.getColHeader);
  614. } else {
  615. (0, _element.empty)(TH);
  616. this.appendColHeader(col, TH);
  617. }
  618. } else {
  619. var div = document.createElement('div');
  620. var span = document.createElement('span');
  621. div.className = 'relative';
  622. span.className = 'colHeader';
  623. this.updateCellHeader(span, col, this.instance.getColHeader);
  624. div.appendChild(span);
  625. TH.appendChild(div);
  626. }
  627. this.instance.runHooks('afterGetColHeader', col, TH);
  628. };
  629. /**
  630. * Update header cell content
  631. *
  632. * @since 0.15.0-beta4
  633. * @param {HTMLElement} element Element to update
  634. * @param {Number} index Row index or column index
  635. * @param {Function} content Function which should be returns content for this cell
  636. */
  637. TableView.prototype.updateCellHeader = function (element, index, content) {
  638. var renderedIndex = index;
  639. var parentOverlay = this.wt.wtOverlays.getParentOverlay(element) || this.wt;
  640. // prevent wrong calculations from SampleGenerator
  641. if (element.parentNode) {
  642. if ((0, _element.hasClass)(element, 'colHeader')) {
  643. renderedIndex = parentOverlay.wtTable.columnFilter.sourceToRendered(index);
  644. } else if ((0, _element.hasClass)(element, 'rowHeader')) {
  645. renderedIndex = parentOverlay.wtTable.rowFilter.sourceToRendered(index);
  646. }
  647. }
  648. if (renderedIndex > -1) {
  649. (0, _element.fastInnerHTML)(element, content(index));
  650. } else {
  651. // workaround for https://github.com/handsontable/handsontable/issues/1946
  652. (0, _element.fastInnerText)(element, String.fromCharCode(160));
  653. (0, _element.addClass)(element, 'cornerHeader');
  654. }
  655. };
  656. /**
  657. * Given a element's left position relative to the viewport, returns maximum element width until the right
  658. * edge of the viewport (before scrollbar)
  659. *
  660. * @param {Number} leftOffset
  661. * @return {Number}
  662. */
  663. TableView.prototype.maximumVisibleElementWidth = function (leftOffset) {
  664. var workspaceWidth = this.wt.wtViewport.getWorkspaceWidth();
  665. var maxWidth = workspaceWidth - leftOffset;
  666. return maxWidth > 0 ? maxWidth : 0;
  667. };
  668. /**
  669. * Given a element's top position relative to the viewport, returns maximum element height until the bottom
  670. * edge of the viewport (before scrollbar)
  671. *
  672. * @param {Number} topOffset
  673. * @return {Number}
  674. */
  675. TableView.prototype.maximumVisibleElementHeight = function (topOffset) {
  676. var workspaceHeight = this.wt.wtViewport.getWorkspaceHeight();
  677. var maxHeight = workspaceHeight - topOffset;
  678. return maxHeight > 0 ? maxHeight : 0;
  679. };
  680. TableView.prototype.mainViewIsActive = function () {
  681. return this.wt === this.activeWt;
  682. };
  683. TableView.prototype.destroy = function () {
  684. this.wt.destroy();
  685. this.eventManager.destroy();
  686. };
  687. exports.default = TableView;