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.
This commit is contained in:
Kristiyan Kostadinov
2017-11-20 19:14:05 +01:00
committed by Jeremy Elbourn
parent f69c8e6d71
commit f2a0206691
3 changed files with 92 additions and 10 deletions
+14 -1
View File
@@ -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;
}
@@ -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: `<button (longpress)="noop()">Long press me</button>`
})
class TestApp {
noop() {}
}
+23 -9
View File
@@ -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<HammerOptions>('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);