Skip to content

Commit f2a0206

Browse files
crisbetojelbourn
authored andcommitted
feat(gestures): add injection token for specifying Hammer.js options (#8106)
Adds the `MAT_HAMMER_OPTIONS` injection token that allows users to pass in options to the Hammer.js constructor. Fixes #7097.
1 parent f69c8e6 commit f2a0206

File tree

3 files changed

+92
-10
lines changed

3 files changed

+92
-10
lines changed

src/lib/core/gestures/gesture-annotations.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
/**
1010
* Stripped-down HammerJS annotations to be used within Material, which are necessary,
1111
* because HammerJS is an optional dependency. For the full annotations see:
12-
* https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/hammerjs
12+
* https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/hammerjs/index.d.ts
1313
*/
1414

1515
/** @docs-private */
@@ -54,3 +54,16 @@ export interface HammerManager {
5454
off(events: string, handler?: Function): void;
5555
on(events: string, handler: Function): void;
5656
}
57+
58+
/** @docs-private */
59+
export interface HammerOptions {
60+
cssProps?: {[key: string]: string};
61+
domEvents?: boolean;
62+
enable?: boolean | ((manager: HammerManager) => boolean);
63+
preset?: any[];
64+
touchAction?: string;
65+
recognizers?: any[];
66+
67+
inputClass?: HammerInput;
68+
inputTarget?: EventTarget;
69+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import {TestBed, async} from '@angular/core/testing';
2+
import {Component} from '@angular/core';
3+
import {HAMMER_GESTURE_CONFIG} from '@angular/platform-browser';
4+
import {GestureConfig, MAT_HAMMER_OPTIONS} from './gesture-config';
5+
6+
describe('GestureConfig', () => {
7+
beforeEach(async(() => {
8+
TestBed.configureTestingModule({
9+
declarations: [TestApp],
10+
providers: [{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig}]
11+
}).compileComponents();
12+
}));
13+
14+
it('should instantiate HammerJS', () => {
15+
spyOn(window, 'Hammer' as any).and.callThrough();
16+
17+
const fixture = TestBed.createComponent(TestApp);
18+
fixture.detectChanges();
19+
20+
expect(window['Hammer']).toHaveBeenCalled();
21+
});
22+
23+
it('should be able to pass options to HammerJS', () => {
24+
TestBed
25+
.resetTestingModule()
26+
.configureTestingModule({
27+
declarations: [TestApp],
28+
providers: [
29+
{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig},
30+
{provide: MAT_HAMMER_OPTIONS, useValue: {cssProps: {touchAction: 'auto'}}}
31+
]
32+
})
33+
.compileComponents();
34+
35+
spyOn(window, 'Hammer' as any).and.callThrough();
36+
37+
const fixture = TestBed.createComponent(TestApp);
38+
fixture.detectChanges();
39+
40+
const button = fixture.debugElement.nativeElement.querySelector('button');
41+
const firstCallArgs = window['Hammer'].calls.first().args;
42+
43+
expect(firstCallArgs[0]).toBe(button);
44+
expect(firstCallArgs[1].cssProps.touchAction).toBe('auto');
45+
});
46+
47+
});
48+
49+
50+
@Component({
51+
template: `<button (longpress)="noop()">Long press me</button>`
52+
})
53+
class TestApp {
54+
noop() {}
55+
}

src/lib/core/gestures/gesture-config.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,22 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Injectable, Optional} from '@angular/core';
9+
import {Injectable, InjectionToken, Inject, Optional} from '@angular/core';
1010
import {HammerGestureConfig} from '@angular/platform-browser';
1111
import {MatCommonModule} from '../common-behaviors/common-module';
12-
import {HammerInstance, HammerStatic, Recognizer, RecognizerStatic} from './gesture-annotations';
12+
import {
13+
HammerStatic,
14+
HammerInstance,
15+
Recognizer,
16+
RecognizerStatic,
17+
HammerOptions,
18+
} from './gesture-annotations';
19+
20+
/**
21+
* Injection token that can be used to provide options to the Hammerjs instance.
22+
* More info at http://hammerjs.github.io/api/.
23+
*/
24+
export const MAT_HAMMER_OPTIONS = new InjectionToken<HammerOptions>('MAT_HAMMER_OPTIONS');
1325

1426
/* Adjusts configuration of our gesture library, Hammer. */
1527
@Injectable()
@@ -26,7 +38,9 @@ export class GestureConfig extends HammerGestureConfig {
2638
'slideleft'
2739
] : [];
2840

29-
constructor(@Optional() commonModule?: MatCommonModule) {
41+
constructor(
42+
@Optional() @Inject(MAT_HAMMER_OPTIONS) private _hammerOptions?: HammerOptions,
43+
@Optional() commonModule?: MatCommonModule) {
3044
super();
3145
if (commonModule) {
3246
commonModule._checkHammerIsAvailable();
@@ -47,18 +61,18 @@ export class GestureConfig extends HammerGestureConfig {
4761
* @returns Newly-created HammerJS instance.
4862
*/
4963
buildHammer(element: HTMLElement): HammerInstance {
50-
const mc = new this._hammer(element);
64+
const mc = new this._hammer(element, this._hammerOptions || undefined);
5165

5266
// Default Hammer Recognizers.
53-
let pan = new this._hammer.Pan();
54-
let swipe = new this._hammer.Swipe();
55-
let press = new this._hammer.Press();
67+
const pan = new this._hammer.Pan();
68+
const swipe = new this._hammer.Swipe();
69+
const press = new this._hammer.Press();
5670

5771
// Notice that a HammerJS recognizer can only depend on one other recognizer once.
5872
// Otherwise the previous `recognizeWith` will be dropped.
5973
// TODO: Confirm threshold numbers with Material Design UX Team
60-
let slide = this._createRecognizer(pan, {event: 'slide', threshold: 0}, swipe);
61-
let longpress = this._createRecognizer(press, {event: 'longpress', time: 500});
74+
const slide = this._createRecognizer(pan, {event: 'slide', threshold: 0}, swipe);
75+
const longpress = this._createRecognizer(press, {event: 'longpress', time: 500});
6276

6377
// Overwrite the default `pan` event to use the swipe event.
6478
pan.recognizeWith(swipe);

0 commit comments

Comments
 (0)