ui.menu.js 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067
  1. /**
  2. * DevExtreme (ui/menu/ui.menu.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. function _typeof(obj) {
  11. "@babel/helpers - typeof";
  12. return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) {
  13. return typeof obj
  14. } : function(obj) {
  15. return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj
  16. }, _typeof(obj)
  17. }
  18. var _renderer = require("../../core/renderer");
  19. var _renderer2 = _interopRequireDefault(_renderer);
  20. var _events_engine = require("../../events/core/events_engine");
  21. var _events_engine2 = _interopRequireDefault(_events_engine);
  22. var _component_registrator = require("../../core/component_registrator");
  23. var _component_registrator2 = _interopRequireDefault(_component_registrator);
  24. var _common = require("../../core/utils/common");
  25. var _dom = require("../../core/utils/dom");
  26. var _iterator = require("../../core/utils/iterator");
  27. var _type = require("../../core/utils/type");
  28. var _extend = require("../../core/utils/extend");
  29. var _utils = require("../overlay/utils");
  30. var _utils2 = require("../../events/utils");
  31. var _pointer = require("../../events/pointer");
  32. var _pointer2 = _interopRequireDefault(_pointer);
  33. var _hover = require("../../events/hover");
  34. var _hover2 = _interopRequireDefault(_hover);
  35. var _ui = require("../context_menu/ui.menu_base");
  36. var _ui2 = _interopRequireDefault(_ui);
  37. var _overlay = require("../overlay");
  38. var _overlay2 = _interopRequireDefault(_overlay);
  39. var _ui3 = require("./ui.submenu");
  40. var _ui4 = _interopRequireDefault(_ui3);
  41. var _button = require("../button");
  42. var _button2 = _interopRequireDefault(_button);
  43. var _tree_view = require("../tree_view");
  44. var _tree_view2 = _interopRequireDefault(_tree_view);
  45. function _interopRequireDefault(obj) {
  46. return obj && obj.__esModule ? obj : {
  47. "default": obj
  48. }
  49. }
  50. function _classCallCheck(instance, Constructor) {
  51. if (!(instance instanceof Constructor)) {
  52. throw new TypeError("Cannot call a class as a function")
  53. }
  54. }
  55. function _defineProperties(target, props) {
  56. for (var i = 0; i < props.length; i++) {
  57. var descriptor = props[i];
  58. descriptor.enumerable = descriptor.enumerable || false;
  59. descriptor.configurable = true;
  60. if ("value" in descriptor) {
  61. descriptor.writable = true
  62. }
  63. Object.defineProperty(target, descriptor.key, descriptor)
  64. }
  65. }
  66. function _createClass(Constructor, protoProps, staticProps) {
  67. if (protoProps) {
  68. _defineProperties(Constructor.prototype, protoProps)
  69. }
  70. if (staticProps) {
  71. _defineProperties(Constructor, staticProps)
  72. }
  73. Object.defineProperty(Constructor, "prototype", {
  74. writable: false
  75. });
  76. return Constructor
  77. }
  78. function _get() {
  79. if ("undefined" !== typeof Reflect && Reflect.get) {
  80. _get = Reflect.get.bind()
  81. } else {
  82. _get = function(target, property, receiver) {
  83. var base = _superPropBase(target, property);
  84. if (!base) {
  85. return
  86. }
  87. var desc = Object.getOwnPropertyDescriptor(base, property);
  88. if (desc.get) {
  89. return desc.get.call(arguments.length < 3 ? target : receiver)
  90. }
  91. return desc.value
  92. }
  93. }
  94. return _get.apply(this, arguments)
  95. }
  96. function _superPropBase(object, property) {
  97. while (!Object.prototype.hasOwnProperty.call(object, property)) {
  98. object = _getPrototypeOf(object);
  99. if (null === object) {
  100. break
  101. }
  102. }
  103. return object
  104. }
  105. function _inherits(subClass, superClass) {
  106. if ("function" !== typeof superClass && null !== superClass) {
  107. throw new TypeError("Super expression must either be null or a function")
  108. }
  109. subClass.prototype = Object.create(superClass && superClass.prototype, {
  110. constructor: {
  111. value: subClass,
  112. writable: true,
  113. configurable: true
  114. }
  115. });
  116. Object.defineProperty(subClass, "prototype", {
  117. writable: false
  118. });
  119. if (superClass) {
  120. _setPrototypeOf(subClass, superClass)
  121. }
  122. }
  123. function _setPrototypeOf(o, p) {
  124. _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function(o, p) {
  125. o.__proto__ = p;
  126. return o
  127. };
  128. return _setPrototypeOf(o, p)
  129. }
  130. function _createSuper(Derived) {
  131. var hasNativeReflectConstruct = _isNativeReflectConstruct();
  132. return function() {
  133. var result, Super = _getPrototypeOf(Derived);
  134. if (hasNativeReflectConstruct) {
  135. var NewTarget = _getPrototypeOf(this).constructor;
  136. result = Reflect.construct(Super, arguments, NewTarget)
  137. } else {
  138. result = Super.apply(this, arguments)
  139. }
  140. return _possibleConstructorReturn(this, result)
  141. }
  142. }
  143. function _possibleConstructorReturn(self, call) {
  144. if (call && ("object" === _typeof(call) || "function" === typeof call)) {
  145. return call
  146. } else {
  147. if (void 0 !== call) {
  148. throw new TypeError("Derived constructors may only return object or undefined")
  149. }
  150. }
  151. return _assertThisInitialized(self)
  152. }
  153. function _assertThisInitialized(self) {
  154. if (void 0 === self) {
  155. throw new ReferenceError("this hasn't been initialised - super() hasn't been called")
  156. }
  157. return self
  158. }
  159. function _isNativeReflectConstruct() {
  160. if ("undefined" === typeof Reflect || !Reflect.construct) {
  161. return false
  162. }
  163. if (Reflect.construct.sham) {
  164. return false
  165. }
  166. if ("function" === typeof Proxy) {
  167. return true
  168. }
  169. try {
  170. Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
  171. return true
  172. } catch (e) {
  173. return false
  174. }
  175. }
  176. function _getPrototypeOf(o) {
  177. _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function(o) {
  178. return o.__proto__ || Object.getPrototypeOf(o)
  179. };
  180. return _getPrototypeOf(o)
  181. }
  182. var DX_MENU_CLASS = "dx-menu";
  183. var DX_MENU_VERTICAL_CLASS = DX_MENU_CLASS + "-vertical";
  184. var DX_MENU_HORIZONTAL_CLASS = DX_MENU_CLASS + "-horizontal";
  185. var DX_MENU_ITEM_CLASS = DX_MENU_CLASS + "-item";
  186. var DX_MENU_ITEMS_CONTAINER_CLASS = DX_MENU_CLASS + "-items-container";
  187. var DX_MENU_ITEM_EXPANDED_CLASS = DX_MENU_ITEM_CLASS + "-expanded";
  188. var DX_CONTEXT_MENU_CLASS = "dx-context-menu";
  189. var DX_CONTEXT_MENU_CONTAINER_BORDER_CLASS = DX_CONTEXT_MENU_CLASS + "-container-border";
  190. var DX_CONTEXT_MENU_CONTENT_DELIMITER_CLASS = "dx-context-menu-content-delimiter";
  191. var DX_SUBMENU_CLASS = "dx-submenu";
  192. var DX_STATE_DISABLED_CLASS = "dx-state-disabled";
  193. var DX_STATE_HOVER_CLASS = "dx-state-hover";
  194. var DX_STATE_ACTIVE_CLASS = "dx-state-active";
  195. var DX_ADAPTIVE_MODE_CLASS = DX_MENU_CLASS + "-adaptive-mode";
  196. var DX_ADAPTIVE_HAMBURGER_BUTTON_CLASS = DX_MENU_CLASS + "-hamburger-button";
  197. var DX_ADAPTIVE_MODE_OVERLAY_WRAPPER_CLASS = DX_ADAPTIVE_MODE_CLASS + "-overlay-wrapper";
  198. var FOCUS_UP = "up";
  199. var FOCUS_DOWN = "down";
  200. var FOCUS_LEFT = "left";
  201. var FOCUS_RIGHT = "right";
  202. var SHOW_SUBMENU_OPERATION = "showSubmenu";
  203. var NEXTITEM_OPERATION = "nextItem";
  204. var PREVITEM_OPERATION = "prevItem";
  205. var DEFAULT_DELAY = {
  206. show: 50,
  207. hide: 300
  208. };
  209. var ACTIONS = ["onSubmenuShowing", "onSubmenuShown", "onSubmenuHiding", "onSubmenuHidden", "onItemContextMenu", "onItemClick", "onSelectionChanged"];
  210. var Menu = function(_MenuBase) {
  211. _inherits(Menu, _MenuBase);
  212. var _super = _createSuper(Menu);
  213. function Menu() {
  214. _classCallCheck(this, Menu);
  215. return _super.apply(this, arguments)
  216. }
  217. _createClass(Menu, [{
  218. key: "_getDefaultOptions",
  219. value: function() {
  220. return (0, _extend.extend)(_get(_getPrototypeOf(Menu.prototype), "_getDefaultOptions", this).call(this), {
  221. orientation: "horizontal",
  222. submenuDirection: "auto",
  223. showFirstSubmenuMode: {
  224. name: "onClick",
  225. delay: {
  226. show: 50,
  227. hide: 300
  228. }
  229. },
  230. hideSubmenuOnMouseLeave: false,
  231. onSubmenuShowing: null,
  232. onSubmenuShown: null,
  233. onSubmenuHiding: null,
  234. onSubmenuHidden: null,
  235. adaptivityEnabled: false
  236. })
  237. }
  238. }, {
  239. key: "_setOptionsByReference",
  240. value: function() {
  241. _get(_getPrototypeOf(Menu.prototype), "_setOptionsByReference", this).call(this);
  242. (0, _extend.extend)(this._optionsByReference, {
  243. animation: true,
  244. selectedItem: true
  245. })
  246. }
  247. }, {
  248. key: "_itemElements",
  249. value: function() {
  250. var rootMenuElements = _get(_getPrototypeOf(Menu.prototype), "_itemElements", this).call(this);
  251. var submenuElements = this._submenuItemElements();
  252. return rootMenuElements.add(submenuElements)
  253. }
  254. }, {
  255. key: "_submenuItemElements",
  256. value: function() {
  257. var elements = [];
  258. var itemSelector = ".".concat(DX_MENU_ITEM_CLASS);
  259. var currentSubmenu = this._submenus.length && this._submenus[0];
  260. if (currentSubmenu && currentSubmenu.itemsContainer()) {
  261. elements = currentSubmenu.itemsContainer().find(itemSelector)
  262. }
  263. return elements
  264. }
  265. }, {
  266. key: "_focusTarget",
  267. value: function() {
  268. return this.$element()
  269. }
  270. }, {
  271. key: "_isMenuHorizontal",
  272. value: function() {
  273. return "horizontal" === this.option("orientation")
  274. }
  275. }, {
  276. key: "_moveFocus",
  277. value: function(location) {
  278. var $items = this._getAvailableItems();
  279. var isMenuHorizontal = this._isMenuHorizontal();
  280. var $activeItem = this._getActiveItem(true);
  281. var argument;
  282. var operation;
  283. var navigationAction;
  284. var $newTarget;
  285. switch (location) {
  286. case FOCUS_UP:
  287. operation = isMenuHorizontal ? SHOW_SUBMENU_OPERATION : this._getItemsNavigationOperation(PREVITEM_OPERATION);
  288. argument = isMenuHorizontal ? $activeItem : $items;
  289. navigationAction = this._getKeyboardNavigationAction(operation, argument);
  290. $newTarget = navigationAction();
  291. break;
  292. case FOCUS_DOWN:
  293. operation = isMenuHorizontal ? SHOW_SUBMENU_OPERATION : this._getItemsNavigationOperation(NEXTITEM_OPERATION);
  294. argument = isMenuHorizontal ? $activeItem : $items;
  295. navigationAction = this._getKeyboardNavigationAction(operation, argument);
  296. $newTarget = navigationAction();
  297. break;
  298. case FOCUS_RIGHT:
  299. operation = isMenuHorizontal ? this._getItemsNavigationOperation(NEXTITEM_OPERATION) : SHOW_SUBMENU_OPERATION;
  300. argument = isMenuHorizontal ? $items : $activeItem;
  301. navigationAction = this._getKeyboardNavigationAction(operation, argument);
  302. $newTarget = navigationAction();
  303. break;
  304. case FOCUS_LEFT:
  305. operation = isMenuHorizontal ? this._getItemsNavigationOperation(PREVITEM_OPERATION) : SHOW_SUBMENU_OPERATION;
  306. argument = isMenuHorizontal ? $items : $activeItem;
  307. navigationAction = this._getKeyboardNavigationAction(operation, argument);
  308. $newTarget = navigationAction();
  309. break;
  310. default:
  311. return _get(_getPrototypeOf(Menu.prototype), "_moveFocus", this).call(this, location)
  312. }
  313. if ($newTarget && 0 !== $newTarget.length) {
  314. this.option("focusedElement", (0, _dom.getPublicElement)($newTarget))
  315. }
  316. }
  317. }, {
  318. key: "_getItemsNavigationOperation",
  319. value: function(operation) {
  320. var navOperation = operation;
  321. if (this.option("rtlEnabled")) {
  322. navOperation = operation === PREVITEM_OPERATION ? NEXTITEM_OPERATION : PREVITEM_OPERATION
  323. }
  324. return navOperation
  325. }
  326. }, {
  327. key: "_getKeyboardNavigationAction",
  328. value: function(operation, argument) {
  329. var action = _common.noop;
  330. switch (operation) {
  331. case SHOW_SUBMENU_OPERATION:
  332. if (!argument.hasClass(DX_STATE_DISABLED_CLASS)) {
  333. action = this._showSubmenu.bind(this, argument)
  334. }
  335. break;
  336. case NEXTITEM_OPERATION:
  337. action = this._nextItem.bind(this, argument);
  338. break;
  339. case PREVITEM_OPERATION:
  340. action = this._prevItem.bind(this, argument)
  341. }
  342. return action
  343. }
  344. }, {
  345. key: "_clean",
  346. value: function() {
  347. _get(_getPrototypeOf(Menu.prototype), "_clean", this).call(this);
  348. this.option("templatesRenderAsynchronously") && clearTimeout(this._resizeEventTimer)
  349. }
  350. }, {
  351. key: "_visibilityChanged",
  352. value: function(visible) {
  353. if (visible) {
  354. if (!this._menuItemsWidth) {
  355. this._updateItemsWidthCache()
  356. }
  357. this._dimensionChanged()
  358. }
  359. }
  360. }, {
  361. key: "_isAdaptivityEnabled",
  362. value: function() {
  363. return this.option("adaptivityEnabled") && "horizontal" === this.option("orientation")
  364. }
  365. }, {
  366. key: "_updateItemsWidthCache",
  367. value: function() {
  368. var $menuItems = this.$element().find("ul").first().children("li").children(".".concat(DX_MENU_ITEM_CLASS));
  369. this._menuItemsWidth = this._getSummaryItemsWidth($menuItems, true)
  370. }
  371. }, {
  372. key: "_dimensionChanged",
  373. value: function() {
  374. if (!this._isAdaptivityEnabled()) {
  375. return
  376. }
  377. var containerWidth = this.$element().outerWidth();
  378. this._toggleAdaptiveMode(this._menuItemsWidth > containerWidth)
  379. }
  380. }, {
  381. key: "_init",
  382. value: function() {
  383. _get(_getPrototypeOf(Menu.prototype), "_init", this).call(this);
  384. this._submenus = []
  385. }
  386. }, {
  387. key: "_initActions",
  388. value: function() {
  389. var _this = this;
  390. this._actions = {};
  391. (0, _iterator.each)(ACTIONS, function(index, action) {
  392. _this._actions[action] = _this._createActionByOption(action)
  393. })
  394. }
  395. }, {
  396. key: "_initMarkup",
  397. value: function() {
  398. this._visibleSubmenu = null;
  399. this.$element().addClass(DX_MENU_CLASS);
  400. _get(_getPrototypeOf(Menu.prototype), "_initMarkup", this).call(this);
  401. this.setAria("role", "menubar")
  402. }
  403. }, {
  404. key: "_render",
  405. value: function() {
  406. _get(_getPrototypeOf(Menu.prototype), "_render", this).call(this);
  407. this._initAdaptivity()
  408. }
  409. }, {
  410. key: "_renderHamburgerButton",
  411. value: function() {
  412. this._hamburger = new _button2.default((0, _renderer2.default)("<div>").addClass(DX_ADAPTIVE_HAMBURGER_BUTTON_CLASS), {
  413. icon: "menu",
  414. activeStateEnabled: false,
  415. onClick: this._toggleTreeView.bind(this)
  416. });
  417. return this._hamburger.$element()
  418. }
  419. }, {
  420. key: "_toggleTreeView",
  421. value: function(state) {
  422. if ((0, _type.isPlainObject)(state)) {
  423. state = !this._overlay.option("visible")
  424. }
  425. this._overlay.option("visible", state);
  426. this._toggleHamburgerActiveState(state)
  427. }
  428. }, {
  429. key: "_toggleHamburgerActiveState",
  430. value: function(state) {
  431. this._hamburger && this._hamburger.$element().toggleClass(DX_STATE_ACTIVE_CLASS, state)
  432. }
  433. }, {
  434. key: "_toggleAdaptiveMode",
  435. value: function(state) {
  436. var $menuItemsContainer = this.$element().find(".".concat(DX_MENU_HORIZONTAL_CLASS));
  437. var $adaptiveElements = this.$element().find(".".concat(DX_ADAPTIVE_MODE_CLASS));
  438. if (state) {
  439. this._hideVisibleSubmenu()
  440. } else {
  441. this._treeView && this._treeView.collapseAll();
  442. this._overlay && this._toggleTreeView(state)
  443. }
  444. $menuItemsContainer.toggle(!state);
  445. $adaptiveElements.toggle(state)
  446. }
  447. }, {
  448. key: "_removeAdaptivity",
  449. value: function() {
  450. if (!this._$adaptiveContainer) {
  451. return
  452. }
  453. this._toggleAdaptiveMode(false);
  454. this._$adaptiveContainer.remove();
  455. this._$adaptiveContainer = null;
  456. this._treeView = null;
  457. this._hamburger = null;
  458. this._overlay = null
  459. }
  460. }, {
  461. key: "_treeviewItemClickHandler",
  462. value: function(e) {
  463. this._actions.onItemClick(e);
  464. if (!e.node.children.length) {
  465. this._toggleTreeView(false)
  466. }
  467. }
  468. }, {
  469. key: "_getAdaptiveOverlayOptions",
  470. value: function() {
  471. var _this2 = this;
  472. var rtl = this.option("rtlEnabled");
  473. var position = rtl ? "right" : "left";
  474. return {
  475. maxHeight: function() {
  476. return (0, _utils.getElementMaxHeightByWindow)(_this2.$element())
  477. },
  478. deferRendering: false,
  479. shading: false,
  480. animation: false,
  481. closeOnTargetScroll: true,
  482. onHidden: function() {
  483. _this2._toggleHamburgerActiveState(false)
  484. },
  485. height: "auto",
  486. closeOnOutsideClick: function(e) {
  487. return !(0, _renderer2.default)(e.target).closest(".".concat(DX_ADAPTIVE_HAMBURGER_BUTTON_CLASS)).length
  488. },
  489. position: {
  490. collision: "flipfit",
  491. at: "bottom " + position,
  492. my: "top " + position,
  493. of: this._hamburger.$element()
  494. }
  495. }
  496. }
  497. }, {
  498. key: "_getTreeViewOptions",
  499. value: function() {
  500. var _this3 = this;
  501. var menuOptions = {};
  502. var optionsToTransfer = ["rtlEnabled", "width", "accessKey", "activeStateEnabled", "animation", "dataSource", "disabled", "displayExpr", "displayExpr", "focusStateEnabled", "hint", "hoverStateEnabled", "itemsExpr", "items", "itemTemplate", "selectedExpr", "selectionMode", "tabIndex", "visible"];
  503. var actionsToTransfer = ["onItemContextMenu", "onSelectionChanged"];
  504. (0, _iterator.each)(optionsToTransfer, function(_, option) {
  505. menuOptions[option] = _this3.option(option)
  506. });
  507. (0, _iterator.each)(actionsToTransfer, function(_, actionName) {
  508. menuOptions[actionName] = function(e) {
  509. _this3._actions[actionName](e)
  510. }
  511. });
  512. return (0, _extend.extend)(menuOptions, {
  513. dataSource: this.getDataSource(),
  514. animationEnabled: !!this.option("animation"),
  515. onItemClick: this._treeviewItemClickHandler.bind(this),
  516. onItemExpanded: function(e) {
  517. _this3._overlay.repaint();
  518. _this3._actions.onSubmenuShown(e)
  519. },
  520. onItemCollapsed: function(e) {
  521. _this3._overlay.repaint();
  522. _this3._actions.onSubmenuHidden(e)
  523. },
  524. selectNodesRecursive: false,
  525. selectByClick: this.option("selectByClick"),
  526. expandEvent: "click"
  527. })
  528. }
  529. }, {
  530. key: "_initAdaptivity",
  531. value: function() {
  532. if (!this._isAdaptivityEnabled()) {
  533. return
  534. }
  535. this._$adaptiveContainer = (0, _renderer2.default)("<div>").addClass(DX_ADAPTIVE_MODE_CLASS);
  536. var $hamburger = this._renderHamburgerButton();
  537. this._treeView = this._createComponent((0, _renderer2.default)("<div>"), _tree_view2.default, this._getTreeViewOptions());
  538. this._overlay = this._createComponent((0, _renderer2.default)("<div>"), _overlay2.default, this._getAdaptiveOverlayOptions());
  539. this._overlay.$content().append(this._treeView.$element()).addClass(DX_ADAPTIVE_MODE_CLASS).addClass(this.option("cssClass"));
  540. this._overlay._wrapper().addClass(DX_ADAPTIVE_MODE_OVERLAY_WRAPPER_CLASS);
  541. this._$adaptiveContainer.append($hamburger);
  542. this._$adaptiveContainer.append(this._overlay.$element());
  543. this.$element().append(this._$adaptiveContainer);
  544. this._updateItemsWidthCache();
  545. this._dimensionChanged()
  546. }
  547. }, {
  548. key: "_getDelay",
  549. value: function(delayType) {
  550. var delay = this.option("showFirstSubmenuMode").delay;
  551. if (!(0, _type.isDefined)(delay)) {
  552. return DEFAULT_DELAY[delayType]
  553. } else {
  554. return (0, _type.isObject)(delay) ? delay[delayType] : delay
  555. }
  556. }
  557. }, {
  558. key: "_keyboardHandler",
  559. value: function(e) {
  560. return this._visibleSubmenu ? true : _get(_getPrototypeOf(Menu.prototype), "_keyboardHandler", this).call(this, e)
  561. }
  562. }, {
  563. key: "_renderContainer",
  564. value: function() {
  565. var $wrapper = (0, _renderer2.default)("<div>");
  566. $wrapper.appendTo(this.$element()).addClass(this._isMenuHorizontal() ? DX_MENU_HORIZONTAL_CLASS : DX_MENU_VERTICAL_CLASS);
  567. return _get(_getPrototypeOf(Menu.prototype), "_renderContainer", this).call(this, $wrapper)
  568. }
  569. }, {
  570. key: "_renderSubmenuItems",
  571. value: function(node, $itemFrame) {
  572. var submenu = this._createSubmenu(node, $itemFrame);
  573. this._submenus.push(submenu);
  574. this._renderBorderElement($itemFrame);
  575. return submenu
  576. }
  577. }, {
  578. key: "_createSubmenu",
  579. value: function(node, $rootItem) {
  580. var $submenuContainer = (0, _renderer2.default)("<div>").addClass(DX_CONTEXT_MENU_CLASS).appendTo($rootItem);
  581. var childKeyboardProcessor = this._keyboardProcessor && this._keyboardProcessor.attachChildProcessor();
  582. var items = this._getChildNodes(node);
  583. var result = this._createComponent($submenuContainer, _ui4.default, (0, _extend.extend)(this._getSubmenuOptions(), {
  584. _keyboardProcessor: childKeyboardProcessor,
  585. _dataAdapter: this._dataAdapter,
  586. _parentKey: node.internalFields.key,
  587. items: items,
  588. onHoverStart: this._clearTimeouts.bind(this),
  589. position: this.getSubmenuPosition($rootItem)
  590. }));
  591. this._attachSubmenuHandlers($rootItem, result);
  592. return result
  593. }
  594. }, {
  595. key: "_getSubmenuOptions",
  596. value: function() {
  597. var _this4 = this;
  598. var $submenuTarget = (0, _renderer2.default)("<div>");
  599. var isMenuHorizontal = this._isMenuHorizontal();
  600. return {
  601. itemTemplate: this.option("itemTemplate"),
  602. target: $submenuTarget,
  603. orientation: this.option("orientation"),
  604. selectionMode: this.option("selectionMode"),
  605. cssClass: this.option("cssClass"),
  606. selectByClick: this.option("selectByClick"),
  607. hoverStateEnabled: this.option("hoverStateEnabled"),
  608. activeStateEnabled: this.option("activeStateEnabled"),
  609. focusStateEnabled: this.option("focusStateEnabled"),
  610. animation: this.option("animation"),
  611. showSubmenuMode: this.option("showSubmenuMode"),
  612. displayExpr: this.option("displayExpr"),
  613. disabledExpr: this.option("disabledExpr"),
  614. selectedExpr: this.option("selectedExpr"),
  615. itemsExpr: this.option("itemsExpr"),
  616. onFocusedItemChanged: function(e) {
  617. if (!e.component.option("visible")) {
  618. return
  619. }
  620. _this4.option("focusedElement", e.component.option("focusedElement"))
  621. },
  622. onSelectionChanged: this._nestedItemOnSelectionChangedHandler.bind(this),
  623. onItemClick: this._nestedItemOnItemClickHandler.bind(this),
  624. onItemRendered: this.option("onItemRendered"),
  625. onLeftFirstItem: isMenuHorizontal ? null : this._moveMainMenuFocus.bind(this, PREVITEM_OPERATION),
  626. onLeftLastItem: isMenuHorizontal ? null : this._moveMainMenuFocus.bind(this, NEXTITEM_OPERATION),
  627. onCloseRootSubmenu: this._moveMainMenuFocus.bind(this, isMenuHorizontal ? PREVITEM_OPERATION : null),
  628. onExpandLastSubmenu: isMenuHorizontal ? this._moveMainMenuFocus.bind(this, NEXTITEM_OPERATION) : null
  629. }
  630. }
  631. }, {
  632. key: "_getShowFirstSubmenuMode",
  633. value: function() {
  634. if (!this._isDesktopDevice()) {
  635. return "onClick"
  636. }
  637. var optionValue = this.option("showFirstSubmenuMode");
  638. return (0, _type.isObject)(optionValue) ? optionValue.name : optionValue
  639. }
  640. }, {
  641. key: "_moveMainMenuFocus",
  642. value: function(direction) {
  643. var $items = this._getAvailableItems();
  644. var itemCount = $items.length;
  645. var $currentItem = $items.filter(".".concat(DX_MENU_ITEM_EXPANDED_CLASS)).eq(0);
  646. var itemIndex = $items.index($currentItem);
  647. this._hideSubmenu(this._visibleSubmenu);
  648. itemIndex += direction === PREVITEM_OPERATION ? -1 : 1;
  649. if (itemIndex >= itemCount) {
  650. itemIndex = 0
  651. } else {
  652. if (itemIndex < 0) {
  653. itemIndex = itemCount - 1
  654. }
  655. }
  656. var $newItem = $items.eq(itemIndex);
  657. this.option("focusedElement", (0, _dom.getPublicElement)($newItem))
  658. }
  659. }, {
  660. key: "_nestedItemOnSelectionChangedHandler",
  661. value: function(args) {
  662. var selectedItem = args.addedItems.length && args.addedItems[0];
  663. var submenu = _ui4.default.getInstance(args.element);
  664. var onSelectionChanged = this._actions.onSelectionChanged;
  665. onSelectionChanged(args);
  666. selectedItem && this._clearSelectionInSubmenus(selectedItem[0], submenu);
  667. this._clearRootSelection();
  668. this._setOptionSilent("selectedItem", selectedItem)
  669. }
  670. }, {
  671. key: "_clearSelectionInSubmenus",
  672. value: function(item, targetSubmenu) {
  673. var _this5 = this;
  674. var cleanAllSubmenus = !arguments.length;
  675. (0, _iterator.each)(this._submenus, function(index, submenu) {
  676. var $submenu = submenu._itemContainer();
  677. var isOtherItem = !$submenu.is(targetSubmenu && targetSubmenu._itemContainer());
  678. var $selectedItem = $submenu.find(".".concat(_this5._selectedItemClass()));
  679. if (isOtherItem && $selectedItem.length || cleanAllSubmenus) {
  680. $selectedItem.removeClass(_this5._selectedItemClass());
  681. var selectedItemData = _this5._getItemData($selectedItem);
  682. if (selectedItemData) {
  683. selectedItemData.selected = false
  684. }
  685. submenu._clearSelectedItems()
  686. }
  687. })
  688. }
  689. }, {
  690. key: "_clearRootSelection",
  691. value: function() {
  692. var $prevSelectedItem = this.$element().find(".".concat(DX_MENU_ITEMS_CONTAINER_CLASS)).first().children().children().filter(".".concat(this._selectedItemClass()));
  693. if ($prevSelectedItem.length) {
  694. var prevSelectedItemData = this._getItemData($prevSelectedItem);
  695. prevSelectedItemData.selected = false;
  696. $prevSelectedItem.removeClass(this._selectedItemClass())
  697. }
  698. }
  699. }, {
  700. key: "_nestedItemOnItemClickHandler",
  701. value: function(e) {
  702. this._actions.onItemClick(e)
  703. }
  704. }, {
  705. key: "_attachSubmenuHandlers",
  706. value: function($rootItem, submenu) {
  707. var _this6 = this;
  708. var $submenuOverlayContent = submenu.getOverlayContent();
  709. var submenus = $submenuOverlayContent.find(".".concat(DX_SUBMENU_CLASS));
  710. var submenuMouseLeaveName = (0, _utils2.addNamespace)(_hover2.default.end, this.NAME + "_submenu");
  711. submenu.option({
  712. onShowing: this._submenuOnShowingHandler.bind(this, $rootItem, submenu),
  713. onShown: this._submenuOnShownHandler.bind(this, $rootItem, submenu),
  714. onHiding: this._submenuOnHidingHandler.bind(this, $rootItem, submenu),
  715. onHidden: this._submenuOnHiddenHandler.bind(this, $rootItem, submenu)
  716. });
  717. (0, _iterator.each)(submenus, function(index, submenu) {
  718. _events_engine2.default.off(submenu, submenuMouseLeaveName);
  719. _events_engine2.default.on(submenu, submenuMouseLeaveName, null, _this6._submenuMouseLeaveHandler.bind(_this6, $rootItem))
  720. })
  721. }
  722. }, {
  723. key: "_submenuOnShowingHandler",
  724. value: function($rootItem, submenu) {
  725. var $border = $rootItem.children(".".concat(DX_CONTEXT_MENU_CONTAINER_BORDER_CLASS));
  726. this._actions.onSubmenuShowing({
  727. rootItem: (0, _dom.getPublicElement)($rootItem),
  728. submenu: submenu
  729. });
  730. $border.show();
  731. $rootItem.addClass(DX_MENU_ITEM_EXPANDED_CLASS)
  732. }
  733. }, {
  734. key: "_submenuOnShownHandler",
  735. value: function($rootItem, submenu) {
  736. this._actions.onSubmenuShown({
  737. rootItem: (0, _dom.getPublicElement)($rootItem),
  738. submenu: submenu
  739. })
  740. }
  741. }, {
  742. key: "_submenuOnHidingHandler",
  743. value: function($rootItem, submenu, eventArgs) {
  744. var $border = $rootItem.children(".".concat(DX_CONTEXT_MENU_CONTAINER_BORDER_CLASS));
  745. var args = eventArgs;
  746. args.rootItem = (0, _dom.getPublicElement)($rootItem);
  747. args.submenu = submenu;
  748. this._actions.onSubmenuHiding(args);
  749. eventArgs = args;
  750. if (!eventArgs.cancel) {
  751. if (this._visibleSubmenu === submenu) {
  752. this._visibleSubmenu = null
  753. }
  754. $border.hide();
  755. $rootItem.removeClass(DX_MENU_ITEM_EXPANDED_CLASS)
  756. }
  757. }
  758. }, {
  759. key: "_submenuOnHiddenHandler",
  760. value: function($rootItem, submenu) {
  761. this._actions.onSubmenuHidden({
  762. rootItem: (0, _dom.getPublicElement)($rootItem),
  763. submenu: submenu
  764. })
  765. }
  766. }, {
  767. key: "_submenuMouseLeaveHandler",
  768. value: function($rootItem, eventArgs) {
  769. var target = (0, _renderer2.default)(eventArgs.relatedTarget).parents(".".concat(DX_CONTEXT_MENU_CLASS))[0];
  770. var contextMenu = this._getSubmenuByRootElement($rootItem).getOverlayContent()[0];
  771. if (this.option("hideSubmenuOnMouseLeave") && target !== contextMenu) {
  772. this._clearTimeouts();
  773. setTimeout(this._hideSubmenuAfterTimeout.bind(this), this._getDelay("hide"))
  774. }
  775. }
  776. }, {
  777. key: "_hideSubmenuAfterTimeout",
  778. value: function() {
  779. if (!this._visibleSubmenu) {
  780. return
  781. }
  782. var isRootItemHovered = (0, _renderer2.default)(this._visibleSubmenu.$element().context).hasClass(DX_STATE_HOVER_CLASS);
  783. var isSubmenuItemHovered = this._visibleSubmenu.getOverlayContent().find(".".concat(DX_STATE_HOVER_CLASS)).length;
  784. var hoveredElementFromSubMenu = this._visibleSubmenu.getOverlayContent().get(0).querySelector(":hover");
  785. if (!hoveredElementFromSubMenu && !isSubmenuItemHovered && !isRootItemHovered) {
  786. this._visibleSubmenu.hide()
  787. }
  788. }
  789. }, {
  790. key: "_getSubmenuByRootElement",
  791. value: function($rootItem) {
  792. if (!$rootItem) {
  793. return false
  794. }
  795. var $submenu = $rootItem.children(".".concat(DX_CONTEXT_MENU_CLASS));
  796. return $submenu.length && _ui4.default.getInstance($submenu)
  797. }
  798. }, {
  799. key: "getSubmenuPosition",
  800. value: function($rootItem) {
  801. var isHorizontalMenu = this._isMenuHorizontal();
  802. var submenuDirection = this.option("submenuDirection").toLowerCase();
  803. var rtlEnabled = this.option("rtlEnabled");
  804. var submenuPosition = {
  805. collision: "flip",
  806. of: $rootItem
  807. };
  808. switch (submenuDirection) {
  809. case "leftortop":
  810. submenuPosition.at = "left top";
  811. submenuPosition.my = isHorizontalMenu ? "left bottom" : "right top";
  812. break;
  813. case "rightorbottom":
  814. submenuPosition.at = isHorizontalMenu ? "left bottom" : "right top";
  815. submenuPosition.my = "left top";
  816. break;
  817. default:
  818. if (isHorizontalMenu) {
  819. submenuPosition.at = rtlEnabled ? "right bottom" : "left bottom";
  820. submenuPosition.my = rtlEnabled ? "right top" : "left top"
  821. } else {
  822. submenuPosition.at = rtlEnabled ? "left top" : "right top";
  823. submenuPosition.my = rtlEnabled ? "right top" : "left top"
  824. }
  825. }
  826. return submenuPosition
  827. }
  828. }, {
  829. key: "_renderBorderElement",
  830. value: function($item) {
  831. (0, _renderer2.default)("<div>").appendTo($item).addClass(DX_CONTEXT_MENU_CONTAINER_BORDER_CLASS).hide()
  832. }
  833. }, {
  834. key: "_itemPointerDownHandler",
  835. value: function(e) {
  836. var $target = (0, _renderer2.default)(e.target);
  837. var $closestItem = $target.closest(this._itemElements());
  838. if ($closestItem.hasClass("dx-menu-item-has-submenu")) {
  839. this.option("focusedElement", null);
  840. return
  841. }
  842. _get(_getPrototypeOf(Menu.prototype), "_itemPointerDownHandler", this).call(this, e)
  843. }
  844. }, {
  845. key: "_hoverStartHandler",
  846. value: function(e) {
  847. var mouseMoveEventName = (0, _utils2.addNamespace)(_pointer2.default.move, this.NAME);
  848. var $item = this._getItemElementByEventArgs(e);
  849. var node = this._dataAdapter.getNodeByItem(this._getItemData($item));
  850. var isSelectionActive = (0, _type.isDefined)(e.buttons) && 1 === e.buttons || !(0, _type.isDefined)(e.buttons) && 1 === e.which;
  851. if (this._isItemDisabled($item)) {
  852. return
  853. }
  854. _events_engine2.default.off($item, mouseMoveEventName);
  855. if (!this._hasChildren(node)) {
  856. this._showSubmenuTimer = setTimeout(this._hideSubmenuAfterTimeout.bind(this), this._getDelay("hide"));
  857. return
  858. }
  859. if ("onHover" === this._getShowFirstSubmenuMode() && !isSelectionActive) {
  860. var submenu = this._getSubmenuByElement($item);
  861. this._clearTimeouts();
  862. if (!submenu.isOverlayVisible()) {
  863. _events_engine2.default.on($item, mouseMoveEventName, this._itemMouseMoveHandler.bind(this));
  864. this._showSubmenuTimer = this._getDelay("hide")
  865. }
  866. }
  867. }
  868. }, {
  869. key: "_hoverEndHandler",
  870. value: function(eventArg) {
  871. var _this7 = this;
  872. var $item = this._getItemElementByEventArgs(eventArg);
  873. var relatedTarget = (0, _renderer2.default)(eventArg.relatedTarget);
  874. _get(_getPrototypeOf(Menu.prototype), "_hoverEndHandler", this).call(this, eventArg);
  875. this._clearTimeouts();
  876. if (this._isItemDisabled($item)) {
  877. return
  878. }
  879. if (relatedTarget.hasClass(DX_CONTEXT_MENU_CONTENT_DELIMITER_CLASS)) {
  880. return
  881. }
  882. if (this.option("hideSubmenuOnMouseLeave") && !relatedTarget.hasClass(DX_MENU_ITEMS_CONTAINER_CLASS)) {
  883. this._hideSubmenuTimer = setTimeout(function() {
  884. _this7._hideSubmenuAfterTimeout()
  885. }, this._getDelay("hide"))
  886. }
  887. }
  888. }, {
  889. key: "_hideVisibleSubmenu",
  890. value: function() {
  891. if (!this._visibleSubmenu) {
  892. return false
  893. }
  894. this._hideSubmenu(this._visibleSubmenu);
  895. return true
  896. }
  897. }, {
  898. key: "_showSubmenu",
  899. value: function($itemElement) {
  900. var submenu = this._getSubmenuByElement($itemElement);
  901. if (this._visibleSubmenu !== submenu) {
  902. this._hideVisibleSubmenu()
  903. }
  904. if (submenu) {
  905. submenu.show();
  906. this.option("focusedElement", submenu.option("focusedElement"))
  907. }
  908. this._visibleSubmenu = submenu;
  909. this._hoveredRootItem = $itemElement
  910. }
  911. }, {
  912. key: "_hideSubmenu",
  913. value: function(submenu) {
  914. submenu && submenu.hide();
  915. if (this._visibleSubmenu === submenu) {
  916. this._visibleSubmenu = null
  917. }
  918. this._hoveredRootItem = null
  919. }
  920. }, {
  921. key: "_itemMouseMoveHandler",
  922. value: function(e) {
  923. var _this8 = this;
  924. if (e.pointers && e.pointers.length) {
  925. return
  926. }
  927. var $item = (0, _renderer2.default)(e.currentTarget);
  928. if (!(0, _type.isDefined)(this._showSubmenuTimer)) {
  929. return
  930. }
  931. this._clearTimeouts();
  932. this._showSubmenuTimer = setTimeout(function() {
  933. var submenu = _this8._getSubmenuByElement($item);
  934. if (submenu && !submenu.isOverlayVisible()) {
  935. _this8._showSubmenu($item)
  936. }
  937. }, this._getDelay("show"))
  938. }
  939. }, {
  940. key: "_clearTimeouts",
  941. value: function() {
  942. clearTimeout(this._hideSubmenuTimer);
  943. clearTimeout(this._showSubmenuTimer)
  944. }
  945. }, {
  946. key: "_getSubmenuByElement",
  947. value: function($itemElement, itemData) {
  948. var submenu = this._getSubmenuByRootElement($itemElement);
  949. if (submenu) {
  950. return submenu
  951. } else {
  952. itemData = itemData || this._getItemData($itemElement);
  953. var node = this._dataAdapter.getNodeByItem(itemData);
  954. return this._hasChildren(node) && this._renderSubmenuItems(node, $itemElement)
  955. }
  956. }
  957. }, {
  958. key: "_updateSubmenuVisibilityOnClick",
  959. value: function(actionArgs) {
  960. var args = actionArgs.args.length && actionArgs.args[0];
  961. if (!args || this._disabledGetter(args.itemData)) {
  962. return
  963. }
  964. var $itemElement = (0, _renderer2.default)(args.itemElement);
  965. var currentSubmenu = this._getSubmenuByElement($itemElement, args.itemData);
  966. this._updateSelectedItemOnClick(actionArgs);
  967. if (this._visibleSubmenu) {
  968. if (this._visibleSubmenu === currentSubmenu) {
  969. if ("onClick" === this.option("showFirstSubmenuMode")) {
  970. this._hideSubmenu(this._visibleSubmenu)
  971. }
  972. return
  973. } else {
  974. this._hideSubmenu(this._visibleSubmenu)
  975. }
  976. }
  977. if (!currentSubmenu) {
  978. return
  979. }
  980. if (!currentSubmenu.isOverlayVisible()) {
  981. this._showSubmenu($itemElement);
  982. return
  983. }
  984. }
  985. }, {
  986. key: "_optionChanged",
  987. value: function(args) {
  988. switch (args.name) {
  989. case "orientation":
  990. case "submenuDirection":
  991. this._invalidate();
  992. break;
  993. case "showFirstSubmenuMode":
  994. case "hideSubmenuOnMouseLeave":
  995. break;
  996. case "showSubmenuMode":
  997. this._changeSubmenusOption(args.name, args.value);
  998. break;
  999. case "onSubmenuShowing":
  1000. case "onSubmenuShown":
  1001. case "onSubmenuHiding":
  1002. case "onSubmenuHidden":
  1003. this._initActions();
  1004. break;
  1005. case "adaptivityEnabled":
  1006. args.value ? this._initAdaptivity() : this._removeAdaptivity();
  1007. break;
  1008. case "width":
  1009. if (this._isAdaptivityEnabled()) {
  1010. this._treeView.option(args.name, args.value);
  1011. this._overlay.option(args.name, args.value)
  1012. }
  1013. _get(_getPrototypeOf(Menu.prototype), "_optionChanged", this).call(this, args);
  1014. this._dimensionChanged();
  1015. break;
  1016. case "animation":
  1017. if (this._isAdaptivityEnabled()) {
  1018. this._treeView.option("animationEnabled", !!args.value)
  1019. }
  1020. _get(_getPrototypeOf(Menu.prototype), "_optionChanged", this).call(this, args);
  1021. break;
  1022. default:
  1023. if (this._isAdaptivityEnabled()) {
  1024. this._treeView.option(args.name, args.value)
  1025. }
  1026. _get(_getPrototypeOf(Menu.prototype), "_optionChanged", this).call(this, args)
  1027. }
  1028. }
  1029. }, {
  1030. key: "_changeSubmenusOption",
  1031. value: function(name, value) {
  1032. (0, _iterator.each)(this._submenus, function(index, submenu) {
  1033. submenu.option(name, value)
  1034. })
  1035. }
  1036. }, {
  1037. key: "selectItem",
  1038. value: function(itemElement) {
  1039. this._hideSubmenu(this._visibleSubmenu);
  1040. _get(_getPrototypeOf(Menu.prototype), "selectItem", this).call(this, itemElement)
  1041. }
  1042. }, {
  1043. key: "unselectItem",
  1044. value: function(itemElement) {
  1045. this._hideSubmenu(this._visibleSubmenu);
  1046. _get(_getPrototypeOf(Menu.prototype), "selectItem", this).call(this, itemElement)
  1047. }
  1048. }]);
  1049. return Menu
  1050. }(_ui2.default);
  1051. (0, _component_registrator2.default)("dxMenu", Menu);
  1052. module.exports = Menu;