Skip to content

Commit 629e81a

Browse files
authored
Merge pull request #128 from lupestro/feature/recognize-gesture-modifier
feature(modifier): Add recognize-gesture modifier
2 parents d242897 + 0ae5d85 commit 629e81a

File tree

13 files changed

+2289
-2204
lines changed

13 files changed

+2289
-2204
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Changelog
22
---------
33

4+
## v2.0.0
5+
6+
- [#129](https://github.com/html-next/ember-gestures/pull/129) [BREAKING] Set minimum node version to 8.x and bump to most recent qunit and ember-cli-babel 7 *by [Lupestro](https://github.com/lupestro)*
7+
- [#128](https://github.com/html-next/ember-gestures/pull/128) Added {recognize-gesture} modifier as alternative to mixin. Modifier requires Ember 2.18 or later to use. *by [Lupestro](https://github.com/lupestro)*
8+
49
## v1.1.3
510

611
- update yarn.lock *by [html-next](https://github.com/html-next)*

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,21 @@ warned `pinch` `rotate` `pan` and `swipe` can break scrolling behavior if not pl
8383
`pan` and `swipe` are horizontal only (configured this way to avoid breaking vertical scroll).
8484
`vertical-pan` and `vertical-swipe` are vertical only (configured this way to avoid breaking horizontal scroll).
8585

86+
##### Modifier
87+
As an alternative to using the `RecognizerMixin`, you may use the `{{recognize-gesture}}` modifier. This is particularly useful when you are applying the recognizer to an element within the handlebars of your component, rather than to the root element of a component, and vital when your component _has_ no root element, as when you use Glimmer components or components with `tagName=""`.
88+
89+
Example
90+
```hbs
91+
<div {{recognize-gesture "pan" "tap" "press" }}>
92+
```
93+
Gestures to recognize are supplied using positional parameters on the modifier. Hammer manager options can be supplied using named parameters on the modifier.
94+
95+
When using `{{ember-on-modifier}}` with these events, you must use the real DOM event names, which are lowercase without hyphens. So your event for "double-tap" would be "doubletap".
96+
97+
Also, if you are using objects derived from `EmberObject`, like Ember components, avoid using action names that are the camel-case form of the gesture names, like `doubleTap`, as these are also the names for the component's generated event listeners, and may get unexpectedly triggered when an event bubbles up to the component as well as when your `{{on}}` action fires on the element. (This is one more reason to migrate to Glimmer components, which don't automatically add event handlers to your namespace.)
98+
99+
The modifier can only be used with Ember 2.18 or later.
100+
86101
#### Using Gestures
87102

88103
Using gestures emitted by Hammer recognizers with Ember is almost like using any other event with Ember.

addon/modifiers/recognize-gesture.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2+
import Modifier from 'ember-class-based-modifier';
3+
import { getOwner } from '@ember/application';
4+
5+
export default class RecognizeGestureModifier extends Modifier {
6+
7+
constructor() {
8+
super(...arguments);
9+
this.recognizers = null;
10+
this.manager = null;
11+
this.gestures = getOwner(this).lookup('service:-gestures');
12+
13+
if (this.args.positional) {
14+
this.recognizers = this.gestures.retrieve(this.args.positional);
15+
}
16+
this.managerOptions = (this.args.named && (Object.keys(this.args.named).length > 0)) ? Object.assign({}, this.args.named) : { domEvents: true };
17+
this.managerOptions.useCapture = this.gestures.useCapture;
18+
19+
}
20+
21+
didInstall() {
22+
if (!this.recognizers) return;
23+
this.element.style['touch-action'] = 'manipulation';
24+
this.element.style['-ms-touch-action'] = 'manipulation';
25+
this.recognizers.then ( (recognizers) => {
26+
if (this.isDestroyed) return;
27+
this.sortRecognizers(recognizers);
28+
this.manager = new Hammer.Manager(this.element, this.managerOptions);
29+
recognizers.forEach((recognizer) => { this.manager.add(recognizer); });
30+
});
31+
}
32+
33+
willRemove() {
34+
this.manager.destroy();
35+
this.manager = null;
36+
}
37+
38+
// Move each recognizer after all recognizers it excludes in the list - why?
39+
sortRecognizers(recognizers) {
40+
for (let i = 0; i < recognizers.length; i++) {
41+
const r = recognizers[i];
42+
let currentIndex = i;
43+
if (r.exclude.length) {
44+
for (let j = 0; j < r.exclude.length; j++) {
45+
const newIndex = recognizers.indexOf(r.exclude[j]);
46+
if (newIndex > 0 && currentIndex < newIndex) {
47+
recognizers.splice(currentIndex, 1);
48+
recognizers.splice(newIndex, 0, r);
49+
currentIndex = newIndex;
50+
}
51+
}
52+
}
53+
}
54+
}
55+
}

app/modifiers/recognize-gesture.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from 'ember-gestures/modifiers/recognize-gesture';

config/dependency-lint.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
'use strict';
2+
3+
module.exports = {
4+
//generateTests: false
5+
};

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"broccoli-funnel": "^2.0.2",
4545
"broccoli-merge-trees": "^3.0.2",
4646
"ember-cli-babel": "^7.7.0",
47+
"ember-class-based-modifier": "^0.10.0",
4748
"ember-cli-htmlbars": "^2.0.1",
4849
"ember-cli-version-checker": "^2.1.0",
4950
"ember-copy": "^1.0.0",
@@ -55,6 +56,7 @@
5556
"broccoli-asset-rev": "^2.4.5",
5657
"ember-cli": "~3.1.2",
5758
"ember-cli-dependency-checker": "^2.0.0",
59+
"ember-cli-dependency-lint": "^1.1.3",
5860
"ember-cli-eslint": "^4.2.1",
5961
"ember-cli-htmlbars-inline-precompile": "^1.0.0",
6062
"ember-cli-inject-live-reload": "^1.4.1",
@@ -69,6 +71,7 @@
6971
"ember-hammertime": "^1.2.3",
7072
"ember-load-initializers": "^1.0.0",
7173
"ember-maybe-import-regenerator": "^0.1.6",
74+
"ember-on-modifier": "1.0.0",
7275
"ember-resolver": "^4.0.0",
7376
"ember-source": "~3.1.0",
7477
"ember-source-channel-url": "^1.0.1",
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Component from '@ember/component';
2+
import { run } from '@ember/runloop';
3+
import layout from '../templates/components/recognizes-single-and-double-tap';
4+
5+
export default Component.extend({
6+
layout,
7+
tagName: '',
8+
sawSingle: false,
9+
sawDouble: false,
10+
11+
reset: function () {
12+
if (!this.get('isDestroyed')) {
13+
this.set('sawSingle', false);
14+
this.set('sawDouble', false);
15+
}
16+
},
17+
18+
actions: {
19+
doTap: function() {
20+
this.set('sawSingle', true);
21+
run.debounce(this, this.reset, 1000);
22+
},
23+
24+
doDoubleTap: function() {
25+
this.set('sawDouble', true);
26+
run.debounce(this, this.reset, 1000);
27+
}
28+
29+
}
30+
31+
});

tests/dummy/app/router.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const Router = EmberRouter.extend({
88

99
Router.map(function() {
1010
this.route('taps');
11+
this.route('modtaps');
1112
});
1213

1314
export default Router;

tests/dummy/app/routes/modtaps.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Route from '@ember/routing/route';
2+
3+
export default Route.extend({
4+
init: function() {
5+
this._super(...arguments);
6+
}
7+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<div
2+
{{recognize-gesture "tap" "double-tap"}}
3+
{{on "tap" (action "doTap") }}
4+
{{on "doubletap" (action "doDoubleTap") }}
5+
>
6+
<span>Tap on me once or twice (implemented with modifier).</span>
7+
8+
{{#if sawSingle}}
9+
I saw a single-tap.
10+
{{/if}}
11+
12+
{{#if sawDouble}}
13+
I saw a double-tap.
14+
{{/if}}
15+
</div>

tests/dummy/app/templates/index.hbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<h2>Demos index</h2>
22
<ol>
33
<li>{{#link-to "taps"}}taps{{/link-to}}</li>
4+
<li>{{#link-to "modtaps"}}taps (w/Modifiers){{/link-to}}</li>
45
</ol>

tests/dummy/app/templates/modtaps.hbs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<div>{{#link-to "index"}}back to index{{/link-to}}</div>
2+
3+
<h2>Taps tests (with modifiers)</h2>
4+
<ol>
5+
<li>{{single-and-double-tap-modifier}}</li>
6+
<li>{{traditional-click}}</li>
7+
</ol>
8+
9+

0 commit comments

Comments
 (0)