diff --git a/src/lib/core/gestures/gesture-annotations.ts b/src/lib/core/gestures/gesture-annotations.ts index c7193f31b9e..81d56172a56 100644 --- a/src/lib/core/gestures/gesture-annotations.ts +++ b/src/lib/core/gestures/gesture-annotations.ts @@ -9,7 +9,7 @@ /** * Stripped-down HammerJS annotations to be used within Material, which are necessary, * because HammerJS is an optional dependency. For the full annotations see: - * https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/hammerjs + * https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/hammerjs/index.d.ts */ /** @docs-private */ @@ -54,3 +54,16 @@ export interface HammerManager { off(events: string, handler?: Function): void; on(events: string, handler: Function): void; } + +/** @docs-private */ +export interface HammerOptions { + cssProps?: {[key: string]: string}; + domEvents?: boolean; + enable?: boolean | ((manager: HammerManager) => boolean); + preset?: any[]; + touchAction?: string; + recognizers?: any[]; + + inputClass?: HammerInput; + inputTarget?: EventTarget; +} diff --git a/src/lib/core/gestures/gesture-config.spec.ts b/src/lib/core/gestures/gesture-config.spec.ts new file mode 100644 index 00000000000..40abf09d903 --- /dev/null +++ b/src/lib/core/gestures/gesture-config.spec.ts @@ -0,0 +1,55 @@ +import {TestBed, async} from '@angular/core/testing'; +import {Component} from '@angular/core'; +import {HAMMER_GESTURE_CONFIG} from '@angular/platform-browser'; +import {GestureConfig, MAT_HAMMER_OPTIONS} from './gesture-config'; + +describe('GestureConfig', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [TestApp], + providers: [{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig}] + }).compileComponents(); + })); + + it('should instantiate HammerJS', () => { + spyOn(window, 'Hammer' as any).and.callThrough(); + + const fixture = TestBed.createComponent(TestApp); + fixture.detectChanges(); + + expect(window['Hammer']).toHaveBeenCalled(); + }); + + it('should be able to pass options to HammerJS', () => { + TestBed + .resetTestingModule() + .configureTestingModule({ + declarations: [TestApp], + providers: [ + {provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig}, + {provide: MAT_HAMMER_OPTIONS, useValue: {cssProps: {touchAction: 'auto'}}} + ] + }) + .compileComponents(); + + spyOn(window, 'Hammer' as any).and.callThrough(); + + const fixture = TestBed.createComponent(TestApp); + fixture.detectChanges(); + + const button = fixture.debugElement.nativeElement.querySelector('button'); + const firstCallArgs = window['Hammer'].calls.first().args; + + expect(firstCallArgs[0]).toBe(button); + expect(firstCallArgs[1].cssProps.touchAction).toBe('auto'); + }); + +}); + + +@Component({ + template: `` +}) +class TestApp { + noop() {} +} diff --git a/src/lib/core/gestures/gesture-config.ts b/src/lib/core/gestures/gesture-config.ts index 2299daede94..02a692430eb 100644 --- a/src/lib/core/gestures/gesture-config.ts +++ b/src/lib/core/gestures/gesture-config.ts @@ -6,10 +6,22 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injectable, Optional} from '@angular/core'; +import {Injectable, InjectionToken, Inject, Optional} from '@angular/core'; import {HammerGestureConfig} from '@angular/platform-browser'; import {MatCommonModule} from '../common-behaviors/common-module'; -import {HammerInstance, HammerStatic, Recognizer, RecognizerStatic} from './gesture-annotations'; +import { + HammerStatic, + HammerInstance, + Recognizer, + RecognizerStatic, + HammerOptions, +} from './gesture-annotations'; + +/** + * Injection token that can be used to provide options to the Hammerjs instance. + * More info at http://hammerjs.github.io/api/. + */ +export const MAT_HAMMER_OPTIONS = new InjectionToken('MAT_HAMMER_OPTIONS'); /* Adjusts configuration of our gesture library, Hammer. */ @Injectable() @@ -26,7 +38,9 @@ export class GestureConfig extends HammerGestureConfig { 'slideleft' ] : []; - constructor(@Optional() commonModule?: MatCommonModule) { + constructor( + @Optional() @Inject(MAT_HAMMER_OPTIONS) private _hammerOptions?: HammerOptions, + @Optional() commonModule?: MatCommonModule) { super(); if (commonModule) { commonModule._checkHammerIsAvailable(); @@ -47,18 +61,18 @@ export class GestureConfig extends HammerGestureConfig { * @returns Newly-created HammerJS instance. */ buildHammer(element: HTMLElement): HammerInstance { - const mc = new this._hammer(element); + const mc = new this._hammer(element, this._hammerOptions || undefined); // Default Hammer Recognizers. - let pan = new this._hammer.Pan(); - let swipe = new this._hammer.Swipe(); - let press = new this._hammer.Press(); + const pan = new this._hammer.Pan(); + const swipe = new this._hammer.Swipe(); + const press = new this._hammer.Press(); // Notice that a HammerJS recognizer can only depend on one other recognizer once. // Otherwise the previous `recognizeWith` will be dropped. // TODO: Confirm threshold numbers with Material Design UX Team - let slide = this._createRecognizer(pan, {event: 'slide', threshold: 0}, swipe); - let longpress = this._createRecognizer(press, {event: 'longpress', time: 500}); + const slide = this._createRecognizer(pan, {event: 'slide', threshold: 0}, swipe); + const longpress = this._createRecognizer(press, {event: 'longpress', time: 500}); // Overwrite the default `pan` event to use the swipe event. pan.recognizeWith(swipe);