e6417b2a858e79c2c624c3bf679c06ff11b8bf4554e9650f93e8c1bd5ea0dfc2294b5ed8b8b134577171f79016e1b296cf0c09c8878d20b91ba2a2d42b831f 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. import {
  2. getScrollableElement,
  3. getScrollbarWidth,
  4. getScrollLeft,
  5. getScrollTop,
  6. } from './../../../helpers/dom/element';
  7. import {arrayEach} from './../../../helpers/array';
  8. import {isKey} from './../../../helpers/unicode';
  9. import {isMobileBrowser} from './../../../helpers/browser';
  10. import EventManager from './../../../eventManager';
  11. import Overlay from './overlay/_base.js';
  12. /**
  13. * @class Overlays
  14. */
  15. class Overlays {
  16. /**
  17. * @param {Walkontable} wotInstance
  18. */
  19. constructor(wotInstance) {
  20. this.wot = wotInstance;
  21. // legacy support
  22. this.instance = this.wot;
  23. this.eventManager = new EventManager(this.wot);
  24. this.wot.update('scrollbarWidth', getScrollbarWidth());
  25. this.wot.update('scrollbarHeight', getScrollbarWidth());
  26. this.scrollableElement = getScrollableElement(this.wot.wtTable.TABLE);
  27. this.prepareOverlays();
  28. this.destroyed = false;
  29. this.keyPressed = false;
  30. this.spreaderLastSize = {
  31. width: null,
  32. height: null,
  33. };
  34. this.overlayScrollPositions = {
  35. master: {
  36. top: 0,
  37. left: 0,
  38. },
  39. top: {
  40. top: null,
  41. left: 0,
  42. },
  43. bottom: {
  44. top: null,
  45. left: 0
  46. },
  47. left: {
  48. top: 0,
  49. left: null
  50. }
  51. };
  52. this.pendingScrollCallbacks = {
  53. master: {
  54. top: 0,
  55. left: 0,
  56. },
  57. top: {
  58. left: 0,
  59. },
  60. bottom: {
  61. left: 0,
  62. },
  63. left: {
  64. top: 0,
  65. }
  66. };
  67. this.verticalScrolling = false;
  68. this.horizontalScrolling = false;
  69. this.delegatedScrollCallback = false;
  70. this.registeredListeners = [];
  71. this.registerListeners();
  72. }
  73. /**
  74. * Prepare overlays based on user settings.
  75. *
  76. * @returns {Boolean} Returns `true` if changes applied to overlay needs scroll synchronization.
  77. */
  78. prepareOverlays() {
  79. let syncScroll = false;
  80. if (this.topOverlay) {
  81. syncScroll = this.topOverlay.updateStateOfRendering() || syncScroll;
  82. } else {
  83. this.topOverlay = Overlay.createOverlay(Overlay.CLONE_TOP, this.wot);
  84. }
  85. if (!Overlay.hasOverlay(Overlay.CLONE_BOTTOM)) {
  86. this.bottomOverlay = {
  87. needFullRender: false,
  88. updateStateOfRendering: () => false,
  89. };
  90. }
  91. if (!Overlay.hasOverlay(Overlay.CLONE_BOTTOM_LEFT_CORNER)) {
  92. this.bottomLeftCornerOverlay = {
  93. needFullRender: false,
  94. updateStateOfRendering: () => false,
  95. };
  96. }
  97. if (this.bottomOverlay) {
  98. syncScroll = this.bottomOverlay.updateStateOfRendering() || syncScroll;
  99. } else {
  100. this.bottomOverlay = Overlay.createOverlay(Overlay.CLONE_BOTTOM, this.wot);
  101. }
  102. if (this.leftOverlay) {
  103. syncScroll = this.leftOverlay.updateStateOfRendering() || syncScroll;
  104. } else {
  105. this.leftOverlay = Overlay.createOverlay(Overlay.CLONE_LEFT, this.wot);
  106. }
  107. if (this.topOverlay.needFullRender && this.leftOverlay.needFullRender) {
  108. if (this.topLeftCornerOverlay) {
  109. syncScroll = this.topLeftCornerOverlay.updateStateOfRendering() || syncScroll;
  110. } else {
  111. this.topLeftCornerOverlay = Overlay.createOverlay(Overlay.CLONE_TOP_LEFT_CORNER, this.wot);
  112. }
  113. }
  114. if (this.bottomOverlay.needFullRender && this.leftOverlay.needFullRender) {
  115. if (this.bottomLeftCornerOverlay) {
  116. syncScroll = this.bottomLeftCornerOverlay.updateStateOfRendering() || syncScroll;
  117. } else {
  118. this.bottomLeftCornerOverlay = Overlay.createOverlay(Overlay.CLONE_BOTTOM_LEFT_CORNER, this.wot);
  119. }
  120. }
  121. if (this.wot.getSetting('debug') && !this.debug) {
  122. this.debug = Overlay.createOverlay(Overlay.CLONE_DEBUG, this.wot);
  123. }
  124. return syncScroll;
  125. }
  126. /**
  127. * Refresh and redraw table
  128. */
  129. refreshAll() {
  130. if (!this.wot.drawn) {
  131. return;
  132. }
  133. if (!this.wot.wtTable.holder.parentNode) {
  134. // Walkontable was detached from DOM, but this handler was not removed
  135. this.destroy();
  136. return;
  137. }
  138. this.wot.draw(true);
  139. if (this.verticalScrolling) {
  140. this.leftOverlay.onScroll();
  141. }
  142. if (this.horizontalScrolling) {
  143. this.topOverlay.onScroll();
  144. }
  145. this.verticalScrolling = false;
  146. this.horizontalScrolling = false;
  147. }
  148. /**
  149. * Register all necessary event listeners.
  150. */
  151. registerListeners() {
  152. const topOverlayScrollable = this.topOverlay.mainTableScrollableElement;
  153. const leftOverlayScrollable = this.leftOverlay.mainTableScrollableElement;
  154. let listenersToRegister = [];
  155. listenersToRegister.push([document.documentElement, 'keydown', (event) => this.onKeyDown(event)]);
  156. listenersToRegister.push([document.documentElement, 'keyup', () => this.onKeyUp()]);
  157. listenersToRegister.push([document, 'visibilitychange', () => this.onKeyUp()]);
  158. listenersToRegister.push([topOverlayScrollable, 'scroll', (event) => this.onTableScroll(event)]);
  159. if (topOverlayScrollable !== leftOverlayScrollable) {
  160. listenersToRegister.push([leftOverlayScrollable, 'scroll', (event) => this.onTableScroll(event)]);
  161. }
  162. if (this.topOverlay.needFullRender) {
  163. listenersToRegister.push([this.topOverlay.clone.wtTable.holder, 'scroll', (event) => this.onTableScroll(event)]);
  164. listenersToRegister.push([this.topOverlay.clone.wtTable.holder, 'wheel', (event) => this.onTableScroll(event)]);
  165. }
  166. if (this.bottomOverlay.needFullRender) {
  167. listenersToRegister.push([this.bottomOverlay.clone.wtTable.holder, 'scroll', (event) => this.onTableScroll(event)]);
  168. listenersToRegister.push([this.bottomOverlay.clone.wtTable.holder, 'wheel', (event) => this.onTableScroll(event)]);
  169. }
  170. if (this.leftOverlay.needFullRender) {
  171. listenersToRegister.push([this.leftOverlay.clone.wtTable.holder, 'scroll', (event) => this.onTableScroll(event)]);
  172. listenersToRegister.push([this.leftOverlay.clone.wtTable.holder, 'wheel', (event) => this.onTableScroll(event)]);
  173. }
  174. if (this.topLeftCornerOverlay && this.topLeftCornerOverlay.needFullRender) {
  175. listenersToRegister.push([this.topLeftCornerOverlay.clone.wtTable.holder, 'wheel', (event) => this.onTableScroll(event)]);
  176. }
  177. if (this.bottomLeftCornerOverlay && this.bottomLeftCornerOverlay.needFullRender) {
  178. listenersToRegister.push([this.bottomLeftCornerOverlay.clone.wtTable.holder, 'wheel', (event) => this.onTableScroll(event)]);
  179. }
  180. if (this.topOverlay.trimmingContainer !== window && this.leftOverlay.trimmingContainer !== window) {
  181. // This is necessary?
  182. // eventManager.addEventListener(window, 'scroll', (event) => this.refreshAll(event));
  183. listenersToRegister.push([window, 'wheel', (event) => {
  184. let overlay;
  185. let deltaY = event.wheelDeltaY || event.deltaY;
  186. let deltaX = event.wheelDeltaX || event.deltaX;
  187. if (this.topOverlay.clone.wtTable.holder.contains(event.realTarget)) {
  188. overlay = 'top';
  189. } else if (this.bottomOverlay.clone && this.bottomOverlay.clone.wtTable.holder.contains(event.realTarget)) {
  190. overlay = 'bottom';
  191. } else if (this.leftOverlay.clone.wtTable.holder.contains(event.realTarget)) {
  192. overlay = 'left';
  193. } else if (this.topLeftCornerOverlay && this.topLeftCornerOverlay.clone && this.topLeftCornerOverlay.clone.wtTable.holder.contains(event.realTarget)) {
  194. overlay = 'topLeft';
  195. } else if (this.bottomLeftCornerOverlay && this.bottomLeftCornerOverlay.clone && this.bottomLeftCornerOverlay.clone.wtTable.holder.contains(event.realTarget)) {
  196. overlay = 'bottomLeft';
  197. }
  198. if ((overlay == 'top' && deltaY !== 0) ||
  199. (overlay == 'left' && deltaX !== 0) ||
  200. (overlay == 'bottom' && deltaY !== 0) ||
  201. ((overlay === 'topLeft' || overlay === 'bottomLeft') && (deltaY !== 0 || deltaX !== 0))) {
  202. event.preventDefault();
  203. }
  204. }]);
  205. }
  206. while (listenersToRegister.length) {
  207. let listener = listenersToRegister.pop();
  208. this.eventManager.addEventListener(listener[0], listener[1], listener[2]);
  209. this.registeredListeners.push(listener);
  210. }
  211. }
  212. /**
  213. * Deregister all previously registered listeners.
  214. */
  215. deregisterListeners() {
  216. while (this.registeredListeners.length) {
  217. let listener = this.registeredListeners.pop();
  218. this.eventManager.removeEventListener(listener[0], listener[1], listener[2]);
  219. }
  220. }
  221. /**
  222. * Scroll listener
  223. *
  224. * @param {Event} event
  225. */
  226. onTableScroll(event) {
  227. // if mobile browser, do not update scroll positions, as the overlays are hidden during the scroll
  228. if (isMobileBrowser()) {
  229. return;
  230. }
  231. const masterHorizontal = this.leftOverlay.mainTableScrollableElement;
  232. const masterVertical = this.topOverlay.mainTableScrollableElement;
  233. const target = event.target;
  234. // For key press, sync only master -> overlay position because while pressing Walkontable.render is triggered
  235. // by hot.refreshBorder
  236. if (this.keyPressed) {
  237. if ((masterVertical !== window && target !== window && !event.target.contains(masterVertical)) ||
  238. (masterHorizontal !== window && target !== window && !event.target.contains(masterHorizontal))) {
  239. return;
  240. }
  241. }
  242. if (event.type === 'scroll') {
  243. this.syncScrollPositions(event);
  244. } else {
  245. this.translateMouseWheelToScroll(event);
  246. }
  247. }
  248. /**
  249. * Key down listener
  250. */
  251. onKeyDown(event) {
  252. this.keyPressed = isKey(event.keyCode, 'ARROW_UP|ARROW_RIGHT|ARROW_DOWN|ARROW_LEFT');
  253. }
  254. /**
  255. * Key up listener
  256. */
  257. onKeyUp() {
  258. this.keyPressed = false;
  259. }
  260. /**
  261. * Translate wheel event into scroll event and sync scroll overlays position
  262. *
  263. * @private
  264. * @param {Event} event
  265. * @returns {Boolean}
  266. */
  267. translateMouseWheelToScroll(event) {
  268. const topOverlay = this.topOverlay.clone.wtTable.holder;
  269. const bottomOverlay = this.bottomOverlay.clone ? this.bottomOverlay.clone.wtTable.holder : null;
  270. const leftOverlay = this.leftOverlay.clone.wtTable.holder;
  271. const topLeftCornerOverlay = this.topLeftCornerOverlay && this.topLeftCornerOverlay.clone ? this.topLeftCornerOverlay.clone.wtTable.holder : null;
  272. const bottomLeftCornerOverlay = this.bottomLeftCornerOverlay && this.bottomLeftCornerOverlay.clone ? this.bottomLeftCornerOverlay.clone.wtTable.holder : null;
  273. const mouseWheelSpeedRatio = -0.2;
  274. let deltaY = event.wheelDeltaY || (-1) * event.deltaY;
  275. let deltaX = event.wheelDeltaX || (-1) * event.deltaX;
  276. let parentHolder = null;
  277. let eventMockup = {type: 'wheel'};
  278. let tempElem = event.target;
  279. let delta = null;
  280. // Fix for extremely slow header scrolling with a mousewheel on Firefox
  281. if (event.deltaMode === 1) {
  282. deltaY *= 120;
  283. deltaX *= 120;
  284. }
  285. while (tempElem != document && tempElem != null) {
  286. if (tempElem.className.indexOf('wtHolder') > -1) {
  287. parentHolder = tempElem;
  288. break;
  289. }
  290. tempElem = tempElem.parentNode;
  291. }
  292. eventMockup.target = parentHolder;
  293. if (parentHolder === topLeftCornerOverlay || parentHolder === bottomLeftCornerOverlay) {
  294. this.syncScrollPositions(eventMockup, mouseWheelSpeedRatio * deltaX, 'x');
  295. this.syncScrollPositions(eventMockup, mouseWheelSpeedRatio * deltaY, 'y');
  296. } else {
  297. if (parentHolder === topOverlay || parentHolder === bottomOverlay) {
  298. delta = deltaY;
  299. } else if (parentHolder === leftOverlay) {
  300. delta = deltaX;
  301. }
  302. this.syncScrollPositions(eventMockup, mouseWheelSpeedRatio * delta);
  303. }
  304. return false;
  305. }
  306. /**
  307. * Synchronize scroll position between master table and overlay table.
  308. *
  309. * @private
  310. * @param {Event|Object} event
  311. * @param {Number} [fakeScrollValue=null]
  312. * @param {String} [fakeScrollDirection=null] `x` or `y`.
  313. */
  314. syncScrollPositions(event, fakeScrollValue = null, fakeScrollDirection = null) {
  315. if (this.destroyed) {
  316. return;
  317. }
  318. if (arguments.length === 0) {
  319. this.syncScrollWithMaster();
  320. return;
  321. }
  322. let masterHorizontal = this.leftOverlay.mainTableScrollableElement;
  323. let masterVertical = this.topOverlay.mainTableScrollableElement;
  324. let target = event.target;
  325. let tempScrollValue = 0;
  326. let scrollValueChanged = false;
  327. let topOverlay;
  328. let leftOverlay;
  329. let topLeftCornerOverlay;
  330. let bottomLeftCornerOverlay;
  331. let bottomOverlay;
  332. let delegatedScroll = false;
  333. let preventOverflow = this.wot.getSetting('preventOverflow');
  334. if (this.topOverlay.needFullRender) {
  335. topOverlay = this.topOverlay.clone.wtTable.holder;
  336. }
  337. if (this.bottomOverlay.needFullRender) {
  338. bottomOverlay = this.bottomOverlay.clone.wtTable.holder;
  339. }
  340. if (this.leftOverlay.needFullRender) {
  341. leftOverlay = this.leftOverlay.clone.wtTable.holder;
  342. }
  343. if (this.leftOverlay.needFullRender && this.topOverlay.needFullRender) {
  344. topLeftCornerOverlay = this.topLeftCornerOverlay.clone.wtTable.holder;
  345. }
  346. if (this.leftOverlay.needFullRender && this.bottomOverlay.needFullRender) {
  347. bottomLeftCornerOverlay = this.bottomLeftCornerOverlay.clone.wtTable.holder;
  348. }
  349. if (target === document) {
  350. target = window;
  351. }
  352. if (target === masterHorizontal || target === masterVertical) {
  353. if (preventOverflow) {
  354. tempScrollValue = getScrollLeft(this.scrollableElement);
  355. } else {
  356. tempScrollValue = getScrollLeft(target);
  357. }
  358. // if scrolling the master table - populate the scroll values to both top and left overlays
  359. this.horizontalScrolling = true;
  360. this.overlayScrollPositions.master.left = tempScrollValue;
  361. scrollValueChanged = true;
  362. if (this.pendingScrollCallbacks.master.left > 0) {
  363. this.pendingScrollCallbacks.master.left--;
  364. } else {
  365. if (topOverlay && topOverlay.scrollLeft !== tempScrollValue) {
  366. if (fakeScrollValue == null) {
  367. this.pendingScrollCallbacks.top.left++;
  368. }
  369. topOverlay.scrollLeft = tempScrollValue;
  370. delegatedScroll = (masterHorizontal !== window);
  371. }
  372. if (bottomOverlay && bottomOverlay.scrollLeft !== tempScrollValue) {
  373. if (fakeScrollValue == null) {
  374. this.pendingScrollCallbacks.bottom.left++;
  375. }
  376. bottomOverlay.scrollLeft = tempScrollValue;
  377. delegatedScroll = (masterHorizontal !== window);
  378. }
  379. }
  380. tempScrollValue = getScrollTop(target);
  381. this.verticalScrolling = true;
  382. this.overlayScrollPositions.master.top = tempScrollValue;
  383. scrollValueChanged = true;
  384. if (this.pendingScrollCallbacks.master.top > 0) {
  385. this.pendingScrollCallbacks.master.top--;
  386. } else if (leftOverlay && leftOverlay.scrollTop !== tempScrollValue) {
  387. if (fakeScrollValue == null) {
  388. this.pendingScrollCallbacks.left.top++;
  389. }
  390. leftOverlay.scrollTop = tempScrollValue;
  391. delegatedScroll = (masterVertical !== window);
  392. }
  393. } else if (target === bottomOverlay) {
  394. tempScrollValue = getScrollLeft(target);
  395. // if scrolling the bottom overlay - populate the horizontal scroll to the master table
  396. this.horizontalScrolling = true;
  397. this.overlayScrollPositions.bottom.left = tempScrollValue;
  398. scrollValueChanged = true;
  399. if (this.pendingScrollCallbacks.bottom.left > 0) {
  400. this.pendingScrollCallbacks.bottom.left--;
  401. } else {
  402. if (fakeScrollValue == null) {
  403. this.pendingScrollCallbacks.master.left++;
  404. }
  405. masterHorizontal.scrollLeft = tempScrollValue;
  406. if (topOverlay && topOverlay.scrollLeft !== tempScrollValue) {
  407. if (fakeScrollValue == null) {
  408. this.pendingScrollCallbacks.top.left++;
  409. }
  410. topOverlay.scrollLeft = tempScrollValue;
  411. delegatedScroll = (masterVertical !== window);
  412. }
  413. }
  414. // "fake" scroll value calculated from the mousewheel event
  415. if (fakeScrollValue !== null) {
  416. scrollValueChanged = true;
  417. masterVertical.scrollTop += fakeScrollValue;
  418. }
  419. } else if (target === topOverlay) {
  420. tempScrollValue = getScrollLeft(target);
  421. // if scrolling the top overlay - populate the horizontal scroll to the master table
  422. this.horizontalScrolling = true;
  423. this.overlayScrollPositions.top.left = tempScrollValue;
  424. scrollValueChanged = true;
  425. if (this.pendingScrollCallbacks.top.left > 0) {
  426. this.pendingScrollCallbacks.top.left--;
  427. } else {
  428. if (fakeScrollValue == null) {
  429. this.pendingScrollCallbacks.master.left++;
  430. }
  431. masterHorizontal.scrollLeft = tempScrollValue;
  432. }
  433. // "fake" scroll value calculated from the mousewheel event
  434. if (fakeScrollValue !== null) {
  435. scrollValueChanged = true;
  436. masterVertical.scrollTop += fakeScrollValue;
  437. }
  438. if (bottomOverlay && bottomOverlay.scrollLeft !== tempScrollValue) {
  439. if (fakeScrollValue == null) {
  440. this.pendingScrollCallbacks.bottom.left++;
  441. }
  442. bottomOverlay.scrollLeft = tempScrollValue;
  443. delegatedScroll = (masterVertical !== window);
  444. }
  445. } else if (target === leftOverlay) {
  446. tempScrollValue = getScrollTop(target);
  447. // if scrolling the left overlay - populate the vertical scroll to the master table
  448. if (this.overlayScrollPositions.left.top !== tempScrollValue) {
  449. this.verticalScrolling = true;
  450. this.overlayScrollPositions.left.top = tempScrollValue;
  451. scrollValueChanged = true;
  452. if (this.pendingScrollCallbacks.left.top > 0) {
  453. this.pendingScrollCallbacks.left.top--;
  454. } else {
  455. if (fakeScrollValue == null) {
  456. this.pendingScrollCallbacks.master.top++;
  457. }
  458. masterVertical.scrollTop = tempScrollValue;
  459. }
  460. }
  461. // "fake" scroll value calculated from the mousewheel event
  462. if (fakeScrollValue !== null) {
  463. scrollValueChanged = true;
  464. masterVertical.scrollLeft += fakeScrollValue;
  465. }
  466. } else if (target === topLeftCornerOverlay || target === bottomLeftCornerOverlay) {
  467. if (fakeScrollValue !== null) {
  468. scrollValueChanged = true;
  469. if (fakeScrollDirection === 'x') {
  470. masterVertical.scrollLeft += fakeScrollValue;
  471. } else if (fakeScrollDirection === 'y') {
  472. masterVertical.scrollTop += fakeScrollValue;
  473. }
  474. }
  475. }
  476. if (!this.keyPressed && scrollValueChanged && event.type === 'scroll') {
  477. if (this.delegatedScrollCallback) {
  478. this.delegatedScrollCallback = false;
  479. } else {
  480. this.refreshAll();
  481. }
  482. if (delegatedScroll) {
  483. this.delegatedScrollCallback = true;
  484. }
  485. }
  486. }
  487. /**
  488. * Synchronize overlay scrollbars with the master scrollbar
  489. */
  490. syncScrollWithMaster() {
  491. const master = this.topOverlay.mainTableScrollableElement;
  492. const {scrollLeft, scrollTop} = master;
  493. if (this.topOverlay.needFullRender) {
  494. this.topOverlay.clone.wtTable.holder.scrollLeft = scrollLeft;
  495. }
  496. if (this.bottomOverlay.needFullRender) {
  497. this.bottomOverlay.clone.wtTable.holder.scrollLeft = scrollLeft;
  498. }
  499. if (this.leftOverlay.needFullRender) {
  500. this.leftOverlay.clone.wtTable.holder.scrollTop = scrollTop;
  501. }
  502. }
  503. /**
  504. * Update the main scrollable elements for all the overlays.
  505. */
  506. updateMainScrollableElements() {
  507. this.deregisterListeners();
  508. this.leftOverlay.updateMainScrollableElement();
  509. this.topOverlay.updateMainScrollableElement();
  510. if (this.bottomOverlay.needFullRender) {
  511. this.bottomOverlay.updateMainScrollableElement();
  512. }
  513. this.scrollableElement = getScrollableElement(this.wot.wtTable.TABLE);
  514. this.registerListeners();
  515. }
  516. /**
  517. *
  518. */
  519. destroy() {
  520. this.eventManager.destroy();
  521. this.topOverlay.destroy();
  522. if (this.bottomOverlay.clone) {
  523. this.bottomOverlay.destroy();
  524. }
  525. this.leftOverlay.destroy();
  526. if (this.topLeftCornerOverlay) {
  527. this.topLeftCornerOverlay.destroy();
  528. }
  529. if (this.bottomLeftCornerOverlay && this.bottomLeftCornerOverlay.clone) {
  530. this.bottomLeftCornerOverlay.destroy();
  531. }
  532. if (this.debug) {
  533. this.debug.destroy();
  534. }
  535. this.destroyed = true;
  536. }
  537. /**
  538. * @param {Boolean} [fastDraw=false]
  539. */
  540. refresh(fastDraw = false) {
  541. if (this.topOverlay.areElementSizesAdjusted && this.leftOverlay.areElementSizesAdjusted) {
  542. let container = this.wot.wtTable.wtRootElement.parentNode || this.wot.wtTable.wtRootElement;
  543. let width = container.clientWidth;
  544. let height = container.clientHeight;
  545. if (width !== this.spreaderLastSize.width || height !== this.spreaderLastSize.height) {
  546. this.spreaderLastSize.width = width;
  547. this.spreaderLastSize.height = height;
  548. this.adjustElementsSize();
  549. }
  550. }
  551. if (this.bottomOverlay.clone) {
  552. this.bottomOverlay.refresh(fastDraw);
  553. }
  554. this.leftOverlay.refresh(fastDraw);
  555. this.topOverlay.refresh(fastDraw);
  556. if (this.topLeftCornerOverlay) {
  557. this.topLeftCornerOverlay.refresh(fastDraw);
  558. }
  559. if (this.bottomLeftCornerOverlay && this.bottomLeftCornerOverlay.clone) {
  560. this.bottomLeftCornerOverlay.refresh(fastDraw);
  561. }
  562. if (this.debug) {
  563. this.debug.refresh(fastDraw);
  564. }
  565. }
  566. /**
  567. * Adjust overlays elements size and master table size
  568. *
  569. * @param {Boolean} [force=false]
  570. */
  571. adjustElementsSize(force = false) {
  572. let totalColumns = this.wot.getSetting('totalColumns');
  573. let totalRows = this.wot.getSetting('totalRows');
  574. let headerRowSize = this.wot.wtViewport.getRowHeaderWidth();
  575. let headerColumnSize = this.wot.wtViewport.getColumnHeaderHeight();
  576. let hiderStyle = this.wot.wtTable.hider.style;
  577. hiderStyle.width = `${headerRowSize + this.leftOverlay.sumCellSizes(0, totalColumns)}px`;
  578. hiderStyle.height = `${headerColumnSize + this.topOverlay.sumCellSizes(0, totalRows) + 1}px`;
  579. this.topOverlay.adjustElementsSize(force);
  580. this.leftOverlay.adjustElementsSize(force);
  581. if (this.bottomOverlay.clone) {
  582. this.bottomOverlay.adjustElementsSize(force);
  583. }
  584. }
  585. /**
  586. *
  587. */
  588. applyToDOM() {
  589. if (!this.topOverlay.areElementSizesAdjusted || !this.leftOverlay.areElementSizesAdjusted) {
  590. this.adjustElementsSize();
  591. }
  592. this.topOverlay.applyToDOM();
  593. if (this.bottomOverlay.clone) {
  594. this.bottomOverlay.applyToDOM();
  595. }
  596. this.leftOverlay.applyToDOM();
  597. }
  598. /**
  599. * Get the parent overlay of the provided element.
  600. *
  601. * @param {HTMLElement} element
  602. * @returns {Object|null}
  603. */
  604. getParentOverlay(element) {
  605. if (!element) {
  606. return null;
  607. }
  608. let overlays = [
  609. this.topOverlay,
  610. this.leftOverlay,
  611. this.bottomOverlay,
  612. this.topLeftCornerOverlay,
  613. this.bottomLeftCornerOverlay
  614. ];
  615. let result = null;
  616. arrayEach(overlays, (elem, i) => {
  617. if (!elem) {
  618. return;
  619. }
  620. if (elem.clone && elem.clone.wtTable.TABLE.contains(element)) {
  621. result = elem.clone;
  622. }
  623. });
  624. return result;
  625. }
  626. }
  627. export default Overlays;