menu.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. import Core from './../../core';
  4. import { addClass, empty, fastInnerHTML, getScrollbarWidth, isChildOf, removeClass } from './../../helpers/dom/element';
  5. import { arrayEach, arrayFilter, arrayReduce } from './../../helpers/array';
  6. import Cursor from './cursor';
  7. import EventManager from './../../eventManager';
  8. import { mixin, hasOwnProperty } from './../../helpers/object';
  9. import { debounce } from './../../helpers/function';
  10. import { filterSeparators, hasSubMenu, isDisabled, isItemHidden, isSeparator, isSelectionDisabled, normalizeSelection } from './utils';
  11. import { KEY_CODES } from './../../helpers/unicode';
  12. import localHooks from './../../mixins/localHooks';
  13. import { SEPARATOR } from './predefinedItems';
  14. import { stopImmediatePropagation } from './../../helpers/dom/event';
  15. /**
  16. * @class Menu
  17. * @plugin ContextMenu
  18. */
  19. var Menu = function () {
  20. function Menu(hotInstance, options) {
  21. _classCallCheck(this, Menu);
  22. this.hot = hotInstance;
  23. this.options = options || {
  24. parent: null,
  25. name: null,
  26. className: '',
  27. keepInViewport: true,
  28. standalone: false
  29. };
  30. this.eventManager = new EventManager(this);
  31. this.container = this.createContainer(this.options.name);
  32. this.hotMenu = null;
  33. this.hotSubMenus = {};
  34. this.parentMenu = this.options.parent || null;
  35. this.menuItems = null;
  36. this.origOutsideClickDeselects = null;
  37. this.keyEvent = false;
  38. this.offset = {
  39. above: 0,
  40. below: 0,
  41. left: 0,
  42. right: 0
  43. };
  44. this._afterScrollCallback = null;
  45. this.registerEvents();
  46. }
  47. /**
  48. * Register event listeners.
  49. *
  50. * @private
  51. */
  52. _createClass(Menu, [{
  53. key: 'registerEvents',
  54. value: function registerEvents() {
  55. var _this = this;
  56. this.eventManager.addEventListener(document.documentElement, 'mousedown', function (event) {
  57. return _this.onDocumentMouseDown(event);
  58. });
  59. }
  60. /**
  61. * Set array of objects which defines menu items.
  62. *
  63. * @param {Array} menuItems Menu items to display.
  64. */
  65. }, {
  66. key: 'setMenuItems',
  67. value: function setMenuItems(menuItems) {
  68. this.menuItems = menuItems;
  69. }
  70. /**
  71. * Set offset menu position for specified area (`above`, `below`, `left` or `right`).
  72. *
  73. * @param {String} area Specified area name (`above`, `below`, `left` or `right`).
  74. * @param {Number} offset Offset value.
  75. */
  76. }, {
  77. key: 'setOffset',
  78. value: function setOffset(area) {
  79. var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
  80. this.offset[area] = offset;
  81. }
  82. /**
  83. * Check if menu is using as sub-menu.
  84. *
  85. * @returns {Boolean}
  86. */
  87. }, {
  88. key: 'isSubMenu',
  89. value: function isSubMenu() {
  90. return this.parentMenu !== null;
  91. }
  92. /**
  93. * Open menu.
  94. */
  95. }, {
  96. key: 'open',
  97. value: function open() {
  98. var _this2 = this;
  99. this.container.removeAttribute('style');
  100. this.container.style.display = 'block';
  101. var delayedOpenSubMenu = debounce(function (row) {
  102. return _this2.openSubMenu(row);
  103. }, 300);
  104. var filteredItems = arrayFilter(this.menuItems, function (item) {
  105. return isItemHidden(item, _this2.hot);
  106. });
  107. filteredItems = filterSeparators(filteredItems, SEPARATOR);
  108. var settings = {
  109. data: filteredItems,
  110. colHeaders: false,
  111. colWidths: [200],
  112. autoRowSize: false,
  113. readOnly: true,
  114. copyPaste: false,
  115. columns: [{
  116. data: 'name',
  117. renderer: function renderer(hot, TD, row, col, prop, value) {
  118. return _this2.menuItemRenderer(hot, TD, row, col, prop, value);
  119. }
  120. }],
  121. renderAllRows: true,
  122. fragmentSelection: 'cell',
  123. disableVisualSelection: 'area',
  124. beforeKeyDown: function beforeKeyDown(event) {
  125. return _this2.onBeforeKeyDown(event);
  126. },
  127. afterOnCellMouseOver: function afterOnCellMouseOver(event, coords, TD) {
  128. if (_this2.isAllSubMenusClosed()) {
  129. delayedOpenSubMenu(coords.row);
  130. } else {
  131. _this2.openSubMenu(coords.row);
  132. }
  133. },
  134. rowHeights: function rowHeights(row) {
  135. return filteredItems[row].name === SEPARATOR ? 1 : 23;
  136. }
  137. };
  138. this.origOutsideClickDeselects = this.hot.getSettings().outsideClickDeselects;
  139. this.hot.getSettings().outsideClickDeselects = false;
  140. this.hotMenu = new Core(this.container, settings);
  141. this.hotMenu.addHook('afterInit', function () {
  142. return _this2.onAfterInit();
  143. });
  144. this.hotMenu.addHook('afterSelection', function (r, c, r2, c2, preventScrolling) {
  145. return _this2.onAfterSelection(r, c, r2, c2, preventScrolling);
  146. });
  147. this.hotMenu.init();
  148. this.hotMenu.listen();
  149. this.blockMainTableCallbacks();
  150. this.runLocalHooks('afterOpen');
  151. }
  152. /**
  153. * Close menu.
  154. *
  155. * @param {Boolean} [closeParent=false] if `true` try to close parent menu if exists.
  156. */
  157. }, {
  158. key: 'close',
  159. value: function close() {
  160. var closeParent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  161. if (!this.isOpened()) {
  162. return;
  163. }
  164. if (closeParent && this.parentMenu) {
  165. this.parentMenu.close();
  166. } else {
  167. this.closeAllSubMenus();
  168. this.container.style.display = 'none';
  169. this.releaseMainTableCallbacks();
  170. this.hotMenu.destroy();
  171. this.hotMenu = null;
  172. this.hot.getSettings().outsideClickDeselects = this.origOutsideClickDeselects;
  173. this.runLocalHooks('afterClose');
  174. if (this.parentMenu) {
  175. this.parentMenu.hotMenu.listen();
  176. }
  177. }
  178. }
  179. /**
  180. * Open sub menu at the provided row index.
  181. *
  182. * @param {Number} row Row index.
  183. * @returns {Menu|Boolean} Returns created menu or `false` if no one menu was created.
  184. */
  185. }, {
  186. key: 'openSubMenu',
  187. value: function openSubMenu(row) {
  188. if (!this.hotMenu) {
  189. return false;
  190. }
  191. var cell = this.hotMenu.getCell(row, 0);
  192. this.closeAllSubMenus();
  193. if (!cell || !hasSubMenu(cell)) {
  194. return false;
  195. }
  196. var dataItem = this.hotMenu.getSourceDataAtRow(row);
  197. var subMenu = new Menu(this.hot, {
  198. parent: this,
  199. name: dataItem.name,
  200. className: this.options.className,
  201. keepInViewport: true
  202. });
  203. subMenu.setMenuItems(dataItem.submenu.items);
  204. subMenu.open();
  205. subMenu.setPosition(cell.getBoundingClientRect());
  206. this.hotSubMenus[dataItem.key] = subMenu;
  207. return subMenu;
  208. }
  209. /**
  210. * Close sub menu at row index.
  211. *
  212. * @param {Number} row Row index.
  213. */
  214. }, {
  215. key: 'closeSubMenu',
  216. value: function closeSubMenu(row) {
  217. var dataItem = this.hotMenu.getSourceDataAtRow(row);
  218. var menus = this.hotSubMenus[dataItem.key];
  219. if (menus) {
  220. menus.destroy();
  221. delete this.hotSubMenus[dataItem.key];
  222. }
  223. }
  224. /**
  225. * Close all opened sub menus.
  226. */
  227. }, {
  228. key: 'closeAllSubMenus',
  229. value: function closeAllSubMenus() {
  230. var _this3 = this;
  231. arrayEach(this.hotMenu.getData(), function (value, row) {
  232. return _this3.closeSubMenu(row);
  233. });
  234. }
  235. /**
  236. * Checks if all created and opened sub menus are closed.
  237. *
  238. * @returns {Boolean}
  239. */
  240. }, {
  241. key: 'isAllSubMenusClosed',
  242. value: function isAllSubMenusClosed() {
  243. return Object.keys(this.hotSubMenus).length === 0;
  244. }
  245. /**
  246. * Destroy instance.
  247. */
  248. }, {
  249. key: 'destroy',
  250. value: function destroy() {
  251. this.clearLocalHooks();
  252. this.close();
  253. this.parentMenu = null;
  254. this.eventManager.destroy();
  255. }
  256. /**
  257. * Checks if menu was opened.
  258. *
  259. * @returns {Boolean} Returns `true` if menu was opened.
  260. */
  261. }, {
  262. key: 'isOpened',
  263. value: function isOpened() {
  264. return this.hotMenu !== null;
  265. }
  266. /**
  267. * Execute menu command.
  268. *
  269. * @param {Event} [event]
  270. */
  271. }, {
  272. key: 'executeCommand',
  273. value: function executeCommand(event) {
  274. if (!this.isOpened() || !this.hotMenu.getSelected()) {
  275. return;
  276. }
  277. var selectedItem = this.hotMenu.getSourceDataAtRow(this.hotMenu.getSelected()[0]);
  278. this.runLocalHooks('select', selectedItem, event);
  279. if (selectedItem.isCommand === false || selectedItem.name === SEPARATOR) {
  280. return;
  281. }
  282. var selRange = this.hot.getSelectedRange();
  283. var normalizedSelection = selRange ? normalizeSelection(selRange) : {};
  284. var autoClose = true;
  285. // Don't close context menu if item is disabled or it has submenu
  286. if (selectedItem.disabled === true || typeof selectedItem.disabled === 'function' && selectedItem.disabled.call(this.hot) === true || selectedItem.submenu) {
  287. autoClose = false;
  288. }
  289. this.runLocalHooks('executeCommand', selectedItem.key, normalizedSelection, event);
  290. if (this.isSubMenu()) {
  291. this.parentMenu.runLocalHooks('executeCommand', selectedItem.key, normalizedSelection, event);
  292. }
  293. if (autoClose) {
  294. this.close(true);
  295. }
  296. }
  297. /**
  298. * Set menu position based on dom event or based on literal object.
  299. *
  300. * @param {Event|Object} coords Event or literal Object with coordinates.
  301. */
  302. }, {
  303. key: 'setPosition',
  304. value: function setPosition(coords) {
  305. var cursor = new Cursor(coords);
  306. if (this.options.keepInViewport) {
  307. if (cursor.fitsBelow(this.container)) {
  308. this.setPositionBelowCursor(cursor);
  309. } else if (cursor.fitsAbove(this.container)) {
  310. this.setPositionAboveCursor(cursor);
  311. } else {
  312. this.setPositionBelowCursor(cursor);
  313. }
  314. if (cursor.fitsOnRight(this.container)) {
  315. this.setPositionOnRightOfCursor(cursor);
  316. } else {
  317. this.setPositionOnLeftOfCursor(cursor);
  318. }
  319. } else {
  320. this.setPositionBelowCursor(cursor);
  321. this.setPositionOnRightOfCursor(cursor);
  322. }
  323. }
  324. /**
  325. * Set menu position above cursor object.
  326. *
  327. * @param {Cursor} cursor `Cursor` object.
  328. */
  329. }, {
  330. key: 'setPositionAboveCursor',
  331. value: function setPositionAboveCursor(cursor) {
  332. var top = this.offset.above + cursor.top - this.container.offsetHeight;
  333. if (this.isSubMenu()) {
  334. top = cursor.top + cursor.cellHeight - this.container.offsetHeight + 3;
  335. }
  336. this.container.style.top = top + 'px';
  337. }
  338. /**
  339. * Set menu position below cursor object.
  340. *
  341. * @param {Cursor} cursor `Cursor` object.
  342. */
  343. }, {
  344. key: 'setPositionBelowCursor',
  345. value: function setPositionBelowCursor(cursor) {
  346. var top = this.offset.below + cursor.top;
  347. if (this.isSubMenu()) {
  348. top = cursor.top - 1;
  349. }
  350. this.container.style.top = top + 'px';
  351. }
  352. /**
  353. * Set menu position on the right of cursor object.
  354. *
  355. * @param {Cursor} cursor `Cursor` object.
  356. */
  357. }, {
  358. key: 'setPositionOnRightOfCursor',
  359. value: function setPositionOnRightOfCursor(cursor) {
  360. var left = void 0;
  361. if (this.isSubMenu()) {
  362. left = 1 + cursor.left + cursor.cellWidth;
  363. } else {
  364. left = this.offset.right + 1 + cursor.left;
  365. }
  366. this.container.style.left = left + 'px';
  367. }
  368. /**
  369. * Set menu position on the left of cursor object.
  370. *
  371. * @param {Cursor} cursor `Cursor` object.
  372. */
  373. }, {
  374. key: 'setPositionOnLeftOfCursor',
  375. value: function setPositionOnLeftOfCursor(cursor) {
  376. var left = this.offset.left + cursor.left - this.container.offsetWidth + getScrollbarWidth() + 4;
  377. this.container.style.left = left + 'px';
  378. }
  379. /**
  380. * Select first cell in opened menu.
  381. */
  382. }, {
  383. key: 'selectFirstCell',
  384. value: function selectFirstCell() {
  385. var cell = this.hotMenu.getCell(0, 0);
  386. if (isSeparator(cell) || isDisabled(cell) || isSelectionDisabled(cell)) {
  387. this.selectNextCell(0, 0);
  388. } else {
  389. this.hotMenu.selectCell(0, 0);
  390. }
  391. }
  392. /**
  393. * Select last cell in opened menu.
  394. */
  395. }, {
  396. key: 'selectLastCell',
  397. value: function selectLastCell() {
  398. var lastRow = this.hotMenu.countRows() - 1;
  399. var cell = this.hotMenu.getCell(lastRow, 0);
  400. if (isSeparator(cell) || isDisabled(cell) || isSelectionDisabled(cell)) {
  401. this.selectPrevCell(lastRow, 0);
  402. } else {
  403. this.hotMenu.selectCell(lastRow, 0);
  404. }
  405. }
  406. /**
  407. * Select next cell in opened menu.
  408. *
  409. * @param {Number} row Row index.
  410. * @param {Number} col Column index.
  411. */
  412. }, {
  413. key: 'selectNextCell',
  414. value: function selectNextCell(row, col) {
  415. var nextRow = row + 1;
  416. var cell = nextRow < this.hotMenu.countRows() ? this.hotMenu.getCell(nextRow, col) : null;
  417. if (!cell) {
  418. return;
  419. }
  420. if (isSeparator(cell) || isDisabled(cell) || isSelectionDisabled(cell)) {
  421. this.selectNextCell(nextRow, col);
  422. } else {
  423. this.hotMenu.selectCell(nextRow, col);
  424. }
  425. }
  426. /**
  427. * Select previous cell in opened menu.
  428. *
  429. * @param {Number} row Row index.
  430. * @param {Number} col Column index.
  431. */
  432. }, {
  433. key: 'selectPrevCell',
  434. value: function selectPrevCell(row, col) {
  435. var prevRow = row - 1;
  436. var cell = prevRow >= 0 ? this.hotMenu.getCell(prevRow, col) : null;
  437. if (!cell) {
  438. return;
  439. }
  440. if (isSeparator(cell) || isDisabled(cell) || isSelectionDisabled(cell)) {
  441. this.selectPrevCell(prevRow, col);
  442. } else {
  443. this.hotMenu.selectCell(prevRow, col);
  444. }
  445. }
  446. /**
  447. * Menu item renderer.
  448. *
  449. * @private
  450. */
  451. }, {
  452. key: 'menuItemRenderer',
  453. value: function menuItemRenderer(hot, TD, row, col, prop, value) {
  454. var _this4 = this;
  455. var item = hot.getSourceDataAtRow(row);
  456. var wrapper = document.createElement('div');
  457. var isSubMenu = function isSubMenu(item) {
  458. return hasOwnProperty(item, 'submenu');
  459. };
  460. var itemIsSeparator = function itemIsSeparator(item) {
  461. return new RegExp(SEPARATOR, 'i').test(item.name);
  462. };
  463. var itemIsDisabled = function itemIsDisabled(item) {
  464. return item.disabled === true || typeof item.disabled == 'function' && item.disabled.call(_this4.hot) === true;
  465. };
  466. var itemIsSelectionDisabled = function itemIsSelectionDisabled(item) {
  467. return item.disableSelection;
  468. };
  469. if (typeof value === 'function') {
  470. value = value.call(this.hot);
  471. }
  472. empty(TD);
  473. addClass(wrapper, 'htItemWrapper');
  474. TD.appendChild(wrapper);
  475. if (itemIsSeparator(item)) {
  476. addClass(TD, 'htSeparator');
  477. } else if (typeof item.renderer === 'function') {
  478. addClass(TD, 'htCustomMenuRenderer');
  479. TD.appendChild(item.renderer(hot, wrapper, row, col, prop, value));
  480. } else {
  481. fastInnerHTML(wrapper, value);
  482. }
  483. if (itemIsDisabled(item)) {
  484. addClass(TD, 'htDisabled');
  485. this.eventManager.addEventListener(TD, 'mouseenter', function () {
  486. return hot.deselectCell();
  487. });
  488. } else if (itemIsSelectionDisabled(item)) {
  489. addClass(TD, 'htSelectionDisabled');
  490. this.eventManager.addEventListener(TD, 'mouseenter', function () {
  491. return hot.deselectCell();
  492. });
  493. } else if (isSubMenu(item)) {
  494. addClass(TD, 'htSubmenu');
  495. if (itemIsSelectionDisabled(item)) {
  496. this.eventManager.addEventListener(TD, 'mouseenter', function () {
  497. return hot.deselectCell();
  498. });
  499. } else {
  500. this.eventManager.addEventListener(TD, 'mouseenter', function () {
  501. return hot.selectCell(row, col, void 0, void 0, false, false);
  502. });
  503. }
  504. } else {
  505. removeClass(TD, 'htSubmenu');
  506. removeClass(TD, 'htDisabled');
  507. if (itemIsSelectionDisabled(item)) {
  508. this.eventManager.addEventListener(TD, 'mouseenter', function () {
  509. return hot.deselectCell();
  510. });
  511. } else {
  512. this.eventManager.addEventListener(TD, 'mouseenter', function () {
  513. return hot.selectCell(row, col, void 0, void 0, false, false);
  514. });
  515. }
  516. }
  517. }
  518. /**
  519. * Create container/wrapper for handsontable.
  520. *
  521. * @private
  522. * @param {String} [name] Class name.
  523. * @returns {HTMLElement}
  524. */
  525. }, {
  526. key: 'createContainer',
  527. value: function createContainer() {
  528. var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
  529. if (name) {
  530. name = name.replace(/[^A-z0-9]/g, '_');
  531. name = this.options.className + 'Sub_' + name;
  532. }
  533. var container = void 0;
  534. if (name) {
  535. container = document.querySelector('.' + this.options.className + '.' + name);
  536. } else {
  537. container = document.querySelector('.' + this.options.className);
  538. }
  539. if (!container) {
  540. container = document.createElement('div');
  541. addClass(container, 'htMenu ' + this.options.className);
  542. if (name) {
  543. addClass(container, name);
  544. }
  545. document.getElementsByTagName('body')[0].appendChild(container);
  546. }
  547. return container;
  548. }
  549. /**
  550. * @private
  551. */
  552. }, {
  553. key: 'blockMainTableCallbacks',
  554. value: function blockMainTableCallbacks() {
  555. this._afterScrollCallback = function () {};
  556. this.hot.addHook('afterScrollVertically', this._afterScrollCallback);
  557. this.hot.addHook('afterScrollHorizontally', this._afterScrollCallback);
  558. }
  559. /**
  560. * @private
  561. */
  562. }, {
  563. key: 'releaseMainTableCallbacks',
  564. value: function releaseMainTableCallbacks() {
  565. if (this._afterScrollCallback) {
  566. this.hot.removeHook('afterScrollVertically', this._afterScrollCallback);
  567. this.hot.removeHook('afterScrollHorizontally', this._afterScrollCallback);
  568. this._afterScrollCallback = null;
  569. }
  570. }
  571. /**
  572. * On before key down listener.
  573. *
  574. * @private
  575. * @param {Event} event
  576. */
  577. }, {
  578. key: 'onBeforeKeyDown',
  579. value: function onBeforeKeyDown(event) {
  580. var selection = this.hotMenu.getSelected();
  581. var stopEvent = false;
  582. this.keyEvent = true;
  583. switch (event.keyCode) {
  584. case KEY_CODES.ESCAPE:
  585. this.close();
  586. stopEvent = true;
  587. break;
  588. case KEY_CODES.ENTER:
  589. if (selection) {
  590. if (this.hotMenu.getSourceDataAtRow(selection[0]).submenu) {
  591. stopEvent = true;
  592. } else {
  593. this.executeCommand(event);
  594. this.close(true);
  595. }
  596. }
  597. break;
  598. case KEY_CODES.ARROW_DOWN:
  599. if (selection) {
  600. this.selectNextCell(selection[0], selection[1]);
  601. } else {
  602. this.selectFirstCell();
  603. }
  604. stopEvent = true;
  605. break;
  606. case KEY_CODES.ARROW_UP:
  607. if (selection) {
  608. this.selectPrevCell(selection[0], selection[1]);
  609. } else {
  610. this.selectLastCell();
  611. }
  612. stopEvent = true;
  613. break;
  614. case KEY_CODES.ARROW_RIGHT:
  615. if (selection) {
  616. var menu = this.openSubMenu(selection[0]);
  617. if (menu) {
  618. menu.selectFirstCell();
  619. }
  620. }
  621. stopEvent = true;
  622. break;
  623. case KEY_CODES.ARROW_LEFT:
  624. if (selection && this.isSubMenu()) {
  625. this.close();
  626. if (this.parentMenu) {
  627. this.parentMenu.hotMenu.listen();
  628. }
  629. stopEvent = true;
  630. }
  631. break;
  632. default:
  633. break;
  634. }
  635. if (stopEvent) {
  636. event.preventDefault();
  637. stopImmediatePropagation(event);
  638. }
  639. this.keyEvent = false;
  640. }
  641. /**
  642. * On after init listener.
  643. *
  644. * @private
  645. */
  646. }, {
  647. key: 'onAfterInit',
  648. value: function onAfterInit() {
  649. var data = this.hotMenu.getSettings().data;
  650. var hiderStyle = this.hotMenu.view.wt.wtTable.hider.style;
  651. var holderStyle = this.hotMenu.view.wt.wtTable.holder.style;
  652. var currentHiderWidth = parseInt(hiderStyle.width, 10);
  653. var realHeight = arrayReduce(data, function (accumulator, value) {
  654. return accumulator + (value.name === SEPARATOR ? 1 : 26);
  655. }, 0);
  656. holderStyle.width = currentHiderWidth + 22 + 'px';
  657. holderStyle.height = realHeight + 4 + 'px';
  658. hiderStyle.height = holderStyle.height;
  659. }
  660. /**
  661. * On after selection listener.
  662. *
  663. * @param {Number} r Selection start row index.
  664. * @param {Number} c Selection start column index.
  665. * @param {Number} r2 Selection end row index.
  666. * @param {Number} c2 Selection end column index.
  667. * @param {Object} preventScrolling Object with `value` property where its value change will be observed.
  668. */
  669. }, {
  670. key: 'onAfterSelection',
  671. value: function onAfterSelection(r, c, r2, c2, preventScrolling) {
  672. if (this.keyEvent === false) {
  673. preventScrolling.value = true;
  674. }
  675. }
  676. /**
  677. * Document mouse down listener.
  678. *
  679. * @private
  680. * @param {Event} event
  681. */
  682. }, {
  683. key: 'onDocumentMouseDown',
  684. value: function onDocumentMouseDown(event) {
  685. if (!this.isOpened()) {
  686. return;
  687. }
  688. if (this.container && isChildOf(event.target, this.container)) {
  689. this.executeCommand(event);
  690. }
  691. // Close menu when clicked element is not belongs to menu itself
  692. if (this.options.standalone && this.hotMenu && !isChildOf(event.target, this.hotMenu.rootElement)) {
  693. this.close(true);
  694. // Automatically close menu when clicked element is not belongs to menu or submenu (not necessarily to itself)
  695. } else if ((this.isAllSubMenusClosed() || this.isSubMenu()) && !isChildOf(event.target, '.htMenu') && isChildOf(event.target, document)) {
  696. this.close(true);
  697. }
  698. }
  699. }]);
  700. return Menu;
  701. }();
  702. mixin(Menu, localHooks);
  703. export default Menu;