Skip to content

Commit c346719

Browse files
authored
Merge pull request #1106 from neomjs/dev
v1.3.56
2 parents 364d5f2 + 8471f96 commit c346719

File tree

6 files changed

+272
-9
lines changed

6 files changed

+272
-9
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "neo.mjs",
3-
"version": "1.3.55",
3+
"version": "1.3.56",
44
"description": "The webworkers driven UI framework",
55
"repository": {
66
"type": "git",

src/main/DomEvents.mjs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,16 @@ class DomEvents extends Base {
323323
};
324324
}
325325

326+
/**
327+
* Returns the first touch event found in touches or changedTouches of a TouchEvent
328+
* @param {TouchEvent} event
329+
* @returns {Touch}
330+
*/
331+
getTouchCoords(event) {
332+
const {touches, changedTouches} = event;
333+
return (touches && touches[0]) || (changedTouches && changedTouches[0]);
334+
}
335+
326336
/**
327337
* Only in use if Neo.config.useSharedWorkers = true
328338
* @param {Object} event

src/main/addon/DragDrop.mjs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import Base from '../../core/Base.mjs';
2-
import DomEvents from '../DomEvents.mjs';
3-
import {default as MouseSensor} from '../draggable/sensor/Mouse.mjs';
1+
import Base from '../../core/Base.mjs';
2+
import DomEvents from '../DomEvents.mjs';
43

54
/**
65
* @class Neo.main.addon.DragDrop
@@ -95,11 +94,22 @@ class DragDrop extends Base {
9594
*/
9695
constructor(config) {
9796
super(config);
97+
98+
let imports = []
99+
98100
this.addGlobalEventListeners();
99101

100-
// testing
101-
const mouseSensor = Neo.create({
102-
module: MouseSensor
102+
if (Neo.config.hasTouchEvents) {
103+
imports.push(import(/* webpackChunkName: 'src/main/draggable/sensor/Touch.js' */ '../draggable/sensor/Touch.mjs'));
104+
} else {
105+
imports.push(import(/* webpackChunkName: 'src/main/draggable/sensor/Mouse.js' */ '../draggable/sensor/Mouse.mjs'));
106+
}
107+
108+
Promise.all(imports).then(modules => {
109+
// create the Touch or MouseSensor
110+
Neo.create({
111+
module: modules[0].default
112+
});
103113
});
104114
}
105115

src/main/draggable/sensor/Mouse.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class Mouse extends Base {
6565

6666
/**
6767
* Detect change in distance, starting drag when both delay and distance requirements are met
68-
* @param {MouseEvent} event
68+
* @param {MouseEvent|Object} event - Object in case it does get trigger via the mouseDownTimeout
6969
*/
7070
onDistanceChange(event) {
7171
let me = this;
@@ -107,7 +107,7 @@ class Mouse extends Base {
107107
document.addEventListener('mousemove', me.onDistanceChange);
108108
document.addEventListener('mouseup', me.onMouseUp);
109109

110-
me.mouseDownTimeout = window.setTimeout(() => {
110+
me.mouseDownTimeout = setTimeout(() => {
111111
me.onDistanceChange({pageX: me.pageX, pageY: me.pageY});
112112
}, me.delay);
113113
}
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
import Base from './Base.mjs';
2+
import DomEvents from '../../DomEvents.mjs';
3+
4+
let preventScrolling = false;
5+
6+
// WebKit requires cancelable touchmove events to be added as early as possible
7+
window.addEventListener('touchmove', event => {
8+
if (!preventScrolling) {
9+
return;
10+
}
11+
12+
// Prevent scrolling
13+
if (event.cancelable) {
14+
event.preventDefault();
15+
}
16+
}, {cancelable: true, passive: false});
17+
18+
/**
19+
* @class Neo.main.draggable.sensor.Touch
20+
* @extends Neo.main.draggable.sensor.Base
21+
*/
22+
class Touch extends Base {
23+
static getConfig() {return {
24+
/**
25+
* @member {String} className='Neo.main.draggable.sensor.Touch'
26+
* @protected
27+
*/
28+
className: 'Neo.main.draggable.sensor.Touch',
29+
/**
30+
* @member {Number} delay=200
31+
*/
32+
delay: 200,
33+
/**
34+
* @member {Number} minDistance=0
35+
*/
36+
minDistance: 0,
37+
/**
38+
* @member {Number|null} pageX=null
39+
* @protected
40+
*/
41+
pageX: null,
42+
/**
43+
* @member {Number|null} pageY=null
44+
* @protected
45+
*/
46+
pageY: null,
47+
/**
48+
* @member {Number|null} tapTimeout=null
49+
*/
50+
tapTimeout: null,
51+
/**
52+
* @member {Number} touchStartTime=0
53+
*/
54+
touchStartTime: 0
55+
}}
56+
57+
/**
58+
*
59+
* @param config
60+
*/
61+
constructor(config) {
62+
super(config);
63+
Neo.bindMethods(this, ['onDistanceChange', 'onTouchEnd', 'onTouchMove', 'onTouchStart', 'startDrag']);
64+
}
65+
66+
/**
67+
* Attaches sensors event listeners to the DOM
68+
*/
69+
attach() {
70+
document.addEventListener('touchstart', this.onTouchStart);
71+
}
72+
73+
/**
74+
* Detaches sensors event listeners from the DOM
75+
*/
76+
detach() {
77+
document.removeEventListener('touchstart', this.onTouchStart);
78+
}
79+
80+
/**
81+
* Detect change in distance, starting drag when both delay and distance requirements are met
82+
* @param {TouchEvent|Object} event - Object in case it does get trigger via the tapTimeout
83+
*/
84+
onDistanceChange(event) {
85+
let me = this;
86+
87+
if (me.currentElement) {
88+
const {pageX, pageY} = DomEvents.getTouchCoords(event),
89+
start = DomEvents.getTouchCoords(me.startEvent),
90+
timeElapsed = Date.now() - me.touchStartTime,
91+
distanceTravelled = DomEvents.getDistance(start.pageX, start.pageY, pageX, pageY) || 0;
92+
93+
Object.assign(me, {pageX, pageY});
94+
95+
if (timeElapsed >= me.delay && distanceTravelled >= me.minDistance) {
96+
clearTimeout(me.tapTimeout);
97+
document.removeEventListener('touchmove', me.onDistanceChange);
98+
me.startDrag();
99+
}
100+
}
101+
}
102+
103+
/**
104+
*
105+
* @param {TouchEvent} event
106+
*/
107+
onTouchEnd(event) {
108+
preventScrolling = false;
109+
110+
let me = this;
111+
112+
clearTimeout(me.tapTimeout);
113+
114+
document.removeEventListener('dragstart', stopEvent);
115+
document.removeEventListener('touchcancel', me.onTouchEnd);
116+
document.removeEventListener('touchend', me.onTouchEnd);
117+
document.removeEventListener('touchmove', me.onDistanceChange);
118+
119+
if (me.dragging) {
120+
const {pageX, pageY} = DomEvents.getTouchCoords(event);
121+
122+
let element = me.currentElement,
123+
target = document.elementFromPoint(pageX - window.scrollX, pageY - window.scrollY);
124+
125+
event.preventDefault();
126+
127+
me.trigger(element, {
128+
clientX : pageX,
129+
clientY : pageY,
130+
element,
131+
originalEvent: event,
132+
path : me.startEvent.path || me.startEvent.composedPath(),
133+
target,
134+
type : 'drag:end'
135+
});
136+
137+
document.removeEventListener('contextmenu', stopEvent, true);
138+
document.removeEventListener('touchmove', me.onTouchMove);
139+
140+
Object.assign(me, {
141+
currentElement: null,
142+
dragging : false,
143+
startEvent : null
144+
});
145+
}
146+
147+
me.dragging = false;
148+
}
149+
150+
/**
151+
*
152+
* @param {TouchEvent} event
153+
*/
154+
onTouchMove(event) {
155+
let me = this;
156+
157+
if (me.dragging) {
158+
const {pageX, pageY} = DomEvents.getTouchCoords(event);
159+
160+
let element = me.currentElement,
161+
target = document.elementFromPoint(pageX - window.scrollX, pageY - window.scrollY);
162+
163+
me.trigger(element, {
164+
clientX : pageX,
165+
clientY : pageY,
166+
element,
167+
originalEvent: event,
168+
path : me.startEvent.path || me.startEvent.composedPath(),
169+
target,
170+
type : 'drag:move'
171+
});
172+
}
173+
}
174+
175+
/**
176+
*
177+
* @param {TouchEvent} event
178+
*/
179+
onTouchStart(event) {
180+
let me = this,
181+
target = DomEvents.testPathInclusion(event, me.dragTargetClasses);
182+
183+
if (target) {
184+
const {pageX, pageY} = DomEvents.getTouchCoords(event);
185+
186+
Object.assign(me, {
187+
currentElement: target.node,
188+
pageX : pageX,
189+
pageY : pageY,
190+
startEvent : event,
191+
touchStartTime: Date.now()
192+
});
193+
194+
document.addEventListener('dragstart', stopEvent);
195+
document.addEventListener('touchcancel', me.onTouchEnd);
196+
document.addEventListener('touchend', me.onTouchEnd);
197+
document.addEventListener('touchmove', me.onDistanceChange, {cancelable: true});
198+
199+
me.tapTimeout = setTimeout(() => {
200+
me.onDistanceChange({touches: [{pageX: me.pageX, pageY: me.pageY}]});
201+
}, me.delay);
202+
}
203+
}
204+
205+
/**
206+
*
207+
*/
208+
startDrag() {
209+
let me = this,
210+
element = me.currentElement,
211+
startEvent = me.startEvent,
212+
touch = DomEvents.getTouchCoords(me.startEvent);
213+
214+
me.trigger(element, {
215+
clientX : touch.pageX,
216+
clientY : touch.pageY,
217+
element,
218+
originalEvent: startEvent,
219+
path : startEvent.path || startEvent.composedPath(),
220+
target : startEvent.target,
221+
type : 'drag:start'
222+
});
223+
224+
me.dragging = true; // todo
225+
226+
if (me.dragging) {
227+
document.addEventListener('contextmenu', stopEvent, true);
228+
document.addEventListener('touchmove', me.onTouchMove);
229+
}
230+
231+
preventScrolling = me.dragging;
232+
}
233+
}
234+
235+
function stopEvent(event) {
236+
event.stopEvent();
237+
}
238+
239+
Neo.applyClassConfig(Touch);
240+
241+
export {Touch as default};

src/worker/Manager.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ class Manager extends Base {
181181
detectFeatures() {
182182
const me = this;
183183

184+
Neo.config.hasTouchEvents = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
185+
184186
if (window.Worker) {
185187
me.webWorkersEnabled = true;
186188
} else {

0 commit comments

Comments
 (0)