Skip to content

Commit 8c1332a

Browse files
committed
Made MouseEventDispatcher system more robust
1 parent b540951 commit 8c1332a

22 files changed

+906
-367
lines changed

build/App.js

Lines changed: 126 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ var _reactDom = require('react-dom');
1717

1818
var _reactDom2 = _interopRequireDefault(_reactDom);
1919

20+
var _Dom = require('./util/Dom');
21+
22+
var _DomRoute = require('./util/DomRoute');
23+
2024
var _DropdownMenu = require('./components/DropdownMenu.js');
2125

2226
var _Svg = require('./components/Svg.js');
@@ -59,17 +63,22 @@ require('./styles/menu.css');
5963
var TOOLBAR_HEIGHT = 82,
6064
PURPLE = '#5943aa',
6165
ORANGE = '#ff7c35',
62-
GREEN = '#2ead6d',
6366
RED = '#e31d65',
6467
YELLOW = '#ffcc00',
65-
COLORS = [PURPLE, ORANGE, GREEN, RED, YELLOW];
68+
COLORS = [PURPLE, ORANGE, RED, YELLOW];
69+
70+
var canvasElement;
71+
72+
//<editor-fold desc="Helper functions">
73+
function isCanvasElement(route) {
74+
return route.contains(canvasElement);
75+
}
6676

67-
function extractPosition(e) {
68-
return {
69-
x: e.clientX,
70-
y: e.clientY
71-
};
77+
function isCircle(target) {
78+
console.log('target', target);
79+
return isCanvasElement && target.id.startsWith('circle');
7280
}
81+
//</editor-fold>
7382

7483
var App = exports.App = function (_Component) {
7584
_inherits(App, _Component);
@@ -80,7 +89,7 @@ var App = exports.App = function (_Component) {
8089
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(App).call(this, props));
8190

8291
_this.state = {
83-
showMenu: false,
92+
contextMenuVisible: false,
8493
openOnMouseOver: false,
8594
circles: [{
8695
x: 200, y: 200, r: 100, color: PURPLE
@@ -90,75 +99,101 @@ var App = exports.App = function (_Component) {
9099
current: -1
91100
};
92101

93-
_this.onAppContextMenu = _this.onAppContextMenu.bind(_this);
94-
_this.onAppTouchStart = _this.onAppTouchStart.bind(_this);
95-
_this.onCircleContextMenu = _this.onCircleContextMenu.bind(_this);
96-
_this.onCircleTouchStart = _this.onCircleTouchStart.bind(_this);
97102
_this.onMenuClose = _this.onMenuClose.bind(_this);
103+
_this.onClickOutside = _this.onClickOutside.bind(_this);
104+
_this.onContextMenu = _this.onContextMenu.bind(_this);
98105
_this.executeCommand = _this.executeCommand.bind(_this);
99-
_this.onAnywhereClickOrContextMenu = _this.onAnywhereClickOrContextMenu.bind(_this);
100106

107+
// subscribing to menu event dispatcher
101108
_MenuEventDispatcher2.default.getInstance().connect({
102-
onAnywhereClick: _this.onAnywhereClickOrContextMenu,
103-
onAnywhereContextMenu: _this.onAnywhereClickOrContextMenu
109+
onClickOutside: _this.onClickOutside,
110+
onContextMenu: _this.onContextMenu
104111
});
105112
return _this;
106113
}
107114

115+
//<editor-fold desc="Handlers">
116+
/**
117+
* Fires when clicked outside of the current menu
118+
*/
119+
120+
108121
_createClass(App, [{
109-
key: 'onAnywhereClickOrContextMenu',
110-
value: function onAnywhereClickOrContextMenu(e) {
122+
key: 'onClickOutside',
123+
value: function onClickOutside() {
111124
this.setState({
112125
openOnMouseOver: false
113126
});
114127
}
115128

116-
//<editor-fold desc="Show/hide menu">
129+
/**
130+
* Fires on contextmenu or tap-and-hold
131+
* @param e
132+
* @param position
133+
* @param route DomRoute
134+
*/
117135

118136
}, {
119-
key: 'showMenu',
120-
value: function showMenu(e, position, items) {
121-
this.menuPosition = position;
122-
e.preventDefault();
123-
e.stopPropagation();
137+
key: 'onContextMenu',
138+
value: function onContextMenu(e, position, route) {
139+
console.log('route', route.getPath());
140+
//var target = route.getTarget();
141+
var target = e.target;
142+
124143
this.setState({
125-
showMenu: true,
126-
items: items
144+
openOnMouseOver: false
127145
});
146+
147+
if (!isCanvasElement(route)) {
148+
return; // we're interested only in canvas clicks
149+
}
150+
if (isCircle(target)) {
151+
// circle clicked
152+
this.selectCircle(target);
153+
this.showContextMenu(e, position, this.circleMenuItems);
154+
} else {
155+
// background clicked
156+
this.setState({
157+
current: -1
158+
});
159+
this.showContextMenu(e, position, this.appMenuItems);
160+
}
128161
}
129-
}, {
130-
key: 'onAppContextMenu',
131-
value: function onAppContextMenu(e) {
132-
this.showMenu(e, extractPosition(e), this.appMenuItems);
133-
}
134-
}, {
135-
key: 'onAppTouchStart',
136-
value: function onAppTouchStart(e) {
137-
this.showMenu(e, extractPosition(e.nativeEvent.targetTouches[0]), this.appMenuItems);
138-
}
139-
}, {
140-
key: 'onCircleContextMenu',
141-
value: function onCircleContextMenu(source, e) {
142-
this.state.current = source;
143-
this.showMenu(e, extractPosition(e), this.circleMenuItems);
144-
}
145-
}, {
146-
key: 'onCircleTouchStart',
147-
value: function onCircleTouchStart(source, e) {
148-
this.state.current = source;
149-
this.showMenu(e, extractPosition(e.nativeEvent.targetTouches[0]), this.circleMenuItems);
150-
}
162+
163+
/**
164+
* Fires on menu close
165+
* We would accomplish the same effect by subscribing to dispatched directly, instead of the Menu
166+
*/
167+
151168
}, {
152169
key: 'onMenuClose',
153170
value: function onMenuClose() {
154171
this.setState({
155-
showMenu: false,
172+
contextMenuVisible: false,
156173
current: -1
157174
});
158175
}
159176
//</editor-fold>
160177

161-
//<editor-fold desc="Commands">
178+
//<editor-fold desc="Show/hide menu">
179+
180+
}, {
181+
key: 'showContextMenu',
182+
value: function showContextMenu(e, position, items) {
183+
var self = this;
184+
185+
e.preventDefault();
186+
e.stopPropagation();
187+
188+
self.setState({
189+
contextMenuVisible: true,
190+
menuPosition: position,
191+
items: items
192+
});
193+
}
194+
//</editor-fold>
195+
196+
//<editor-fold desc="Circles & commands">
162197

163198
}, {
164199
key: 'executeCommand',
@@ -218,6 +253,13 @@ var App = exports.App = function (_Component) {
218253

219254
this.setState({ circles: circles });
220255
}
256+
}, {
257+
key: 'selectCircle',
258+
value: function selectCircle(circleElement) {
259+
var circleIndex = parseInt(circleElement.id.split('-')[1]);
260+
261+
this.state.current = circleIndex;
262+
}
221263
}, {
222264
key: 'bringToTop',
223265
value: function bringToTop(circles, circle, current) {
@@ -233,7 +275,7 @@ var App = exports.App = function (_Component) {
233275
}, {
234276
key: 'newCircle',
235277
value: function newCircle(circles) {
236-
var pos = this.menuPosition,
278+
var pos = this.state.menuPosition,
237279
r = Math.floor(Math.random() * 150) + 50,
238280
color = COLORS[Math.floor(Math.random() * COLORS.length)],
239281
circle = {
@@ -254,43 +296,20 @@ var App = exports.App = function (_Component) {
254296
}
255297
//</editor-fold>
256298

257-
}, {
258-
key: 'componentDidMount',
259-
value: function componentDidMount() {
260-
var self = this;
261-
262-
function binder() {
263-
var _self$executeCommand;
264-
265-
return (_self$executeCommand = self.executeCommand).bind.apply(_self$executeCommand, [self].concat(Array.prototype.slice.call(arguments)));
266-
}
267-
this.circleMenuItems = new _CircleMenuItems.CircleMenuItems(binder);
268-
this.appMenuItems = new _AppMenuItems.AppMenuItems(binder);
269-
}
270-
}, {
271-
key: 'cancelEvent',
272-
value: function cancelEvent(e) {
273-
var e = event || window.event;
274-
e.preventDefault && e.preventDefault();
275-
e.stopPropagation && e.stopPropagation();
276-
e.cancelBubble = true;
277-
e.returnValue = false;
278-
return false;
279-
}
280299
}, {
281300
key: 'render',
282301
value: function render() {
283302
var self = this,
284303
index = 0,
285-
menu = this.state.showMenu ? _react2.default.createElement(_Menu.Menu, { items: this.state.items, position: this.menuPosition, onClose: this.onMenuClose }) : null,
304+
menu = this.state.contextMenuVisible ? _react2.default.createElement(_Menu.Menu, { items: this.state.items,
305+
position: this.state.menuPosition,
306+
onClose: this.onMenuClose }) : null,
286307
circles = this.state.circles.map(function (circle) {
287-
var circleIndex = index++;
308+
var circle = _react2.default.createElement(_Circle.Circle, _extends({}, circle, { id: 'circle-' + index, key: 'circle-' + index, strokeColor: 'white',
309+
selected: self.state.current === index }));
288310

289-
return _react2.default.createElement(_Circle.Circle, _extends({}, circle, { key: 'circle-' + index, strokeColor: 'white',
290-
selected: self.state.current === index,
291-
onContextMenu: self.onCircleContextMenu.bind(this, circleIndex),
292-
onTouchStart: self.onCircleTouchStart.bind(this, circleIndex),
293-
onMenuClose: self.onMenuClose }));
311+
index++;
312+
return circle;
294313
}),
295314
renderers = {
296315
'link': _LinkRenderer.LinkRenderer
@@ -307,20 +326,18 @@ var App = exports.App = function (_Component) {
307326

308327
return _react2.default.createElement(
309328
'div',
310-
{ onContextMenu: this.onAppContextMenu,
311-
onTouchStart: this.onAppTouchStart,
312-
onTouchEnd: this.cancelEvent,
313-
onTouchCancel: this.cancelEvent,
314-
onTouchMove: this.cancelEvent },
329+
null,
315330
_react2.default.createElement(
316331
'div',
317332
{ className: 'toolbar' },
318333
_react2.default.createElement(_DropdownMenu.DropdownMenu, _extends({ buttonText: 'React Data Menu', items: _items.items1 }, common)),
319-
_react2.default.createElement(_DropdownMenu.DropdownMenu, _extends({ buttonText: 'Example', items: _items2.items2 }, common))
334+
_react2.default.createElement(_DropdownMenu.DropdownMenu, _extends({ buttonText: 'Menu 1', items: _items2.items2 }, common)),
335+
_react2.default.createElement(_DropdownMenu.DropdownMenu, _extends({ buttonText: 'Menu 2', items: _items2.items2 }, common)),
336+
_react2.default.createElement(_DropdownMenu.DropdownMenu, _extends({ buttonText: 'Menu 3', items: _items2.items2 }, common))
320337
),
321338
_react2.default.createElement(
322339
'div',
323-
{ className: 'container' },
340+
{ ref: 'canvas', className: 'container' },
324341
_react2.default.createElement(
325342
_Svg.Svg,
326343
{ width: '100%', height: '100%' },
@@ -334,19 +351,22 @@ var App = exports.App = function (_Component) {
334351
{ className: 'toolbar toolbar-bottom' },
335352
_react2.default.createElement(
336353
_DropdownMenu.DropdownMenu,
337-
_extends({ items: _items.items1 }, common),
354+
_extends({ items: _items.items1 }, common, { toggleMode: false }),
338355
_react2.default.createElement(
339356
'button',
340-
{ ref: 'button', className: 'menu-button' },
341-
'Nice menu?'
357+
{ className: 'menu-button' },
358+
'Menu 4'
342359
)
343360
),
361+
_react2.default.createElement(_DropdownMenu.DropdownMenu, _extends({ buttonText: 'Menu 5', items: _items2.items2 }, common, { toggleMode: false })),
362+
_react2.default.createElement(_DropdownMenu.DropdownMenu, _extends({ buttonText: 'Menu 6', items: _items2.items2 }, common, { toggleMode: false })),
344363
_react2.default.createElement(
345364
_DropdownMenu.DropdownMenu,
346365
{
347366
items: _helpItems.helpItems,
348367
className: 'about',
349368
classPrefix: 'help-',
369+
toggleMode: false,
350370
openOnMouseOver: true,
351371
closeOnMouseOut: false,
352372
mouseEnterDelay: 500,
@@ -359,13 +379,28 @@ var App = exports.App = function (_Component) {
359379
} },
360380
_react2.default.createElement(
361381
'button',
362-
{ ref: 'button', className: 'menu-button' },
382+
{ className: 'menu-button' },
363383
'?'
364384
)
365385
)
366386
)
367387
);
368388
}
389+
}, {
390+
key: 'componentDidMount',
391+
value: function componentDidMount() {
392+
var self = this;
393+
394+
function binder() {
395+
var _self$executeCommand;
396+
397+
return (_self$executeCommand = self.executeCommand).bind.apply(_self$executeCommand, [self].concat(Array.prototype.slice.call(arguments)));
398+
}
399+
this.circleMenuItems = new _CircleMenuItems.CircleMenuItems(binder);
400+
this.appMenuItems = new _AppMenuItems.AppMenuItems(binder);
401+
402+
canvasElement = _reactDom2.default.findDOMNode(this.refs.canvas);
403+
}
369404
}]);
370405

371406
return App;

0 commit comments

Comments
 (0)