25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

ContextMenu.js 11 KiB

3 yıl önce
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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 _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  3. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  4. function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
  5. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
  6. import React from 'react';
  7. import PropTypes from 'prop-types';
  8. import cx from 'classnames';
  9. import assign from 'object-assign';
  10. import listener from './globalEventListener';
  11. import AbstractMenu from './AbstractMenu';
  12. import SubMenu from './SubMenu';
  13. import { hideMenu } from './actions';
  14. import { cssClasses, callIfExists, store } from './helpers';
  15. var ContextMenu = function (_AbstractMenu) {
  16. _inherits(ContextMenu, _AbstractMenu);
  17. function ContextMenu(props) {
  18. _classCallCheck(this, ContextMenu);
  19. var _this = _possibleConstructorReturn(this, (ContextMenu.__proto__ || Object.getPrototypeOf(ContextMenu)).call(this, props));
  20. _this.registerHandlers = function () {
  21. document.addEventListener('mousedown', _this.handleOutsideClick);
  22. document.addEventListener('touchstart', _this.handleOutsideClick);
  23. if (!_this.props.preventHideOnScroll) document.addEventListener('scroll', _this.handleHide);
  24. if (!_this.props.preventHideOnContextMenu) document.addEventListener('contextmenu', _this.handleHide);
  25. document.addEventListener('keydown', _this.handleKeyNavigation);
  26. if (!_this.props.preventHideOnResize) window.addEventListener('resize', _this.handleHide);
  27. };
  28. _this.unregisterHandlers = function () {
  29. document.removeEventListener('mousedown', _this.handleOutsideClick);
  30. document.removeEventListener('touchstart', _this.handleOutsideClick);
  31. document.removeEventListener('scroll', _this.handleHide);
  32. document.removeEventListener('contextmenu', _this.handleHide);
  33. document.removeEventListener('keydown', _this.handleKeyNavigation);
  34. window.removeEventListener('resize', _this.handleHide);
  35. };
  36. _this.handleShow = function (e) {
  37. if (e.detail.id !== _this.props.id || _this.state.isVisible) return;
  38. var _e$detail$position = e.detail.position,
  39. x = _e$detail$position.x,
  40. y = _e$detail$position.y;
  41. _this.setState({ isVisible: true, x: x, y: y });
  42. _this.registerHandlers();
  43. callIfExists(_this.props.onShow, e);
  44. };
  45. _this.handleHide = function (e) {
  46. if (_this.state.isVisible && (!e.detail || !e.detail.id || e.detail.id === _this.props.id)) {
  47. _this.unregisterHandlers();
  48. _this.setState({ isVisible: false, selectedItem: null, forceSubMenuOpen: false });
  49. callIfExists(_this.props.onHide, e);
  50. }
  51. };
  52. _this.handleOutsideClick = function (e) {
  53. if (!_this.menu.contains(e.target)) hideMenu();
  54. };
  55. _this.handleMouseLeave = function (event) {
  56. event.preventDefault();
  57. callIfExists(_this.props.onMouseLeave, event, assign({}, _this.props.data, store.data), store.target);
  58. if (_this.props.hideOnLeave) hideMenu();
  59. };
  60. _this.handleContextMenu = function (e) {
  61. if (process.env.NODE_ENV === 'production') {
  62. e.preventDefault();
  63. }
  64. _this.handleHide(e);
  65. };
  66. _this.hideMenu = function (e) {
  67. if (e.keyCode === 27 || e.keyCode === 13) {
  68. // ECS or enter
  69. hideMenu();
  70. }
  71. };
  72. _this.getMenuPosition = function () {
  73. var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
  74. var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
  75. var menuStyles = {
  76. top: y,
  77. left: x
  78. };
  79. if (!_this.menu) return menuStyles;
  80. var _window = window,
  81. innerWidth = _window.innerWidth,
  82. innerHeight = _window.innerHeight;
  83. var rect = _this.menu.getBoundingClientRect();
  84. if (y + rect.height > innerHeight) {
  85. menuStyles.top -= rect.height;
  86. }
  87. if (x + rect.width > innerWidth) {
  88. menuStyles.left -= rect.width;
  89. }
  90. if (menuStyles.top < 0) {
  91. menuStyles.top = rect.height < innerHeight ? (innerHeight - rect.height) / 2 : 0;
  92. }
  93. if (menuStyles.left < 0) {
  94. menuStyles.left = rect.width < innerWidth ? (innerWidth - rect.width) / 2 : 0;
  95. }
  96. return menuStyles;
  97. };
  98. _this.getRTLMenuPosition = function () {
  99. var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
  100. var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
  101. var menuStyles = {
  102. top: y,
  103. left: x
  104. };
  105. if (!_this.menu) return menuStyles;
  106. var _window2 = window,
  107. innerWidth = _window2.innerWidth,
  108. innerHeight = _window2.innerHeight;
  109. var rect = _this.menu.getBoundingClientRect();
  110. // Try to position the menu on the left side of the cursor
  111. menuStyles.left = x - rect.width;
  112. if (y + rect.height > innerHeight) {
  113. menuStyles.top -= rect.height;
  114. }
  115. if (menuStyles.left < 0) {
  116. menuStyles.left += rect.width;
  117. }
  118. if (menuStyles.top < 0) {
  119. menuStyles.top = rect.height < innerHeight ? (innerHeight - rect.height) / 2 : 0;
  120. }
  121. if (menuStyles.left + rect.width > innerWidth) {
  122. menuStyles.left = rect.width < innerWidth ? (innerWidth - rect.width) / 2 : 0;
  123. }
  124. return menuStyles;
  125. };
  126. _this.menuRef = function (c) {
  127. _this.menu = c;
  128. };
  129. _this.state = assign({}, _this.state, {
  130. x: 0,
  131. y: 0,
  132. isVisible: false
  133. });
  134. return _this;
  135. }
  136. _createClass(ContextMenu, [{
  137. key: 'getSubMenuType',
  138. value: function getSubMenuType() {
  139. // eslint-disable-line class-methods-use-this
  140. return SubMenu;
  141. }
  142. }, {
  143. key: 'componentDidMount',
  144. value: function componentDidMount() {
  145. this.listenId = listener.register(this.handleShow, this.handleHide);
  146. }
  147. }, {
  148. key: 'componentDidUpdate',
  149. value: function componentDidUpdate() {
  150. var _this2 = this;
  151. var wrapper = window.requestAnimationFrame || setTimeout;
  152. if (this.state.isVisible) {
  153. wrapper(function () {
  154. var _state = _this2.state,
  155. x = _state.x,
  156. y = _state.y;
  157. var _ref = _this2.props.rtl ? _this2.getRTLMenuPosition(x, y) : _this2.getMenuPosition(x, y),
  158. top = _ref.top,
  159. left = _ref.left;
  160. wrapper(function () {
  161. if (!_this2.menu) return;
  162. _this2.menu.style.top = top + 'px';
  163. _this2.menu.style.left = left + 'px';
  164. _this2.menu.style.opacity = 1;
  165. _this2.menu.style.pointerEvents = 'auto';
  166. });
  167. });
  168. } else {
  169. wrapper(function () {
  170. if (!_this2.menu) return;
  171. _this2.menu.style.opacity = 0;
  172. _this2.menu.style.pointerEvents = 'none';
  173. });
  174. }
  175. }
  176. }, {
  177. key: 'componentWillUnmount',
  178. value: function componentWillUnmount() {
  179. if (this.listenId) {
  180. listener.unregister(this.listenId);
  181. }
  182. this.unregisterHandlers();
  183. }
  184. }, {
  185. key: 'render',
  186. value: function render() {
  187. var _props = this.props,
  188. children = _props.children,
  189. className = _props.className,
  190. style = _props.style;
  191. var isVisible = this.state.isVisible;
  192. var inlineStyle = assign({}, style, { position: 'fixed', opacity: 0, pointerEvents: 'none' });
  193. var menuClassnames = cx(cssClasses.menu, className, _defineProperty({}, cssClasses.menuVisible, isVisible));
  194. return React.createElement(
  195. 'nav',
  196. {
  197. role: 'menu', tabIndex: '-1', ref: this.menuRef, style: inlineStyle, className: menuClassnames,
  198. onContextMenu: this.handleContextMenu, onMouseLeave: this.handleMouseLeave },
  199. this.renderChildren(children)
  200. );
  201. }
  202. }]);
  203. return ContextMenu;
  204. }(AbstractMenu);
  205. ContextMenu.propTypes = {
  206. id: PropTypes.string.isRequired,
  207. children: PropTypes.node.isRequired,
  208. data: PropTypes.object,
  209. className: PropTypes.string,
  210. hideOnLeave: PropTypes.bool,
  211. rtl: PropTypes.bool,
  212. onHide: PropTypes.func,
  213. onMouseLeave: PropTypes.func,
  214. onShow: PropTypes.func,
  215. preventHideOnContextMenu: PropTypes.bool,
  216. preventHideOnResize: PropTypes.bool,
  217. preventHideOnScroll: PropTypes.bool,
  218. style: PropTypes.object
  219. };
  220. ContextMenu.defaultProps = {
  221. className: '',
  222. data: {},
  223. hideOnLeave: false,
  224. rtl: false,
  225. onHide: function onHide() {
  226. return null;
  227. },
  228. onMouseLeave: function onMouseLeave() {
  229. return null;
  230. },
  231. onShow: function onShow() {
  232. return null;
  233. },
  234. preventHideOnContextMenu: false,
  235. preventHideOnResize: false,
  236. preventHideOnScroll: false,
  237. style: {}
  238. };
  239. export default ContextMenu;