fix(platform-browser): ensure that Hammer loader is called only once (#40911)
Currently, the function that is provided through `HAMMER_LOADER` is called the same number of times as the `HammerGesturesPlugin.addEventListener` method is called (until the Hammer is loaded). This commit adds a class property in which the loader call is saved, thereby preventing multiple calls to the loader function. PR Close #25995 PR Close #40911
This commit is contained in:
parent
aed2782c4a
commit
228b5f73b1
|
@ -162,6 +162,8 @@ export class HammerGestureConfig {
|
|||
*/
|
||||
@Injectable()
|
||||
export class HammerGesturesPlugin extends EventManagerPlugin {
|
||||
private _loaderPromise: Promise<void>|null = null;
|
||||
|
||||
constructor(
|
||||
@Inject(DOCUMENT) doc: any,
|
||||
@Inject(HAMMER_GESTURE_CONFIG) private _config: HammerGestureConfig, private console: Console,
|
||||
|
@ -175,9 +177,11 @@ export class HammerGesturesPlugin extends EventManagerPlugin {
|
|||
}
|
||||
|
||||
if (!(window as any).Hammer && !this.loader) {
|
||||
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
||||
this.console.warn(
|
||||
`The "${eventName}" event cannot be bound because Hammer.JS is not ` +
|
||||
`loaded and no custom loader has been specified.`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -191,6 +195,7 @@ export class HammerGesturesPlugin extends EventManagerPlugin {
|
|||
// If Hammer is not present but a loader is specified, we defer adding the event listener
|
||||
// until Hammer is loaded.
|
||||
if (!(window as any).Hammer && this.loader) {
|
||||
this._loaderPromise = this._loaderPromise || this.loader();
|
||||
// This `addEventListener` method returns a function to remove the added listener.
|
||||
// Until Hammer is loaded, the returned function needs to *cancel* the registration rather
|
||||
// than remove anything.
|
||||
|
@ -199,12 +204,14 @@ export class HammerGesturesPlugin extends EventManagerPlugin {
|
|||
cancelRegistration = true;
|
||||
};
|
||||
|
||||
this.loader()
|
||||
this._loaderPromise
|
||||
.then(() => {
|
||||
// If Hammer isn't actually loaded when the custom loader resolves, give up.
|
||||
if (!(window as any).Hammer) {
|
||||
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
||||
this.console.warn(
|
||||
`The custom HAMMER_LOADER completed, but Hammer.JS is not present.`);
|
||||
}
|
||||
deregister = () => {};
|
||||
return;
|
||||
}
|
||||
|
@ -216,9 +223,11 @@ export class HammerGesturesPlugin extends EventManagerPlugin {
|
|||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
||||
this.console.warn(
|
||||
`The "${eventName}" event cannot be bound because the custom ` +
|
||||
`Hammer.JS loader failed.`);
|
||||
}
|
||||
deregister = () => {};
|
||||
});
|
||||
|
||||
|
|
|
@ -67,6 +67,8 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
|
|||
ngZone = z;
|
||||
}));
|
||||
|
||||
let loaderCalled = 0;
|
||||
|
||||
beforeEach(() => {
|
||||
originalHammerGlobal = (window as any).Hammer;
|
||||
(window as any).Hammer = undefined;
|
||||
|
@ -76,10 +78,13 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
|
|||
off: jasmine.createSpy('mc.off'),
|
||||
};
|
||||
|
||||
loader = () => new Promise((resolve, reject) => {
|
||||
loader = () => {
|
||||
loaderCalled++;
|
||||
return new Promise((resolve, reject) => {
|
||||
resolveLoader = resolve;
|
||||
failLoader = reject;
|
||||
});
|
||||
};
|
||||
|
||||
// Make the hammer config return a fake hammer instance
|
||||
const hammerConfig = new HammerGestureConfig();
|
||||
|
@ -95,9 +100,19 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
|
|||
});
|
||||
|
||||
afterEach(() => {
|
||||
loaderCalled = 0;
|
||||
(window as any).Hammer = originalHammerGlobal;
|
||||
});
|
||||
|
||||
it('should call the loader provider only once', () => {
|
||||
plugin.addEventListener(someElement, 'swipe', () => {});
|
||||
plugin.addEventListener(someElement, 'panleft', () => {});
|
||||
plugin.addEventListener(someElement, 'panright', () => {});
|
||||
// Ensure that the loader is called only once, because previouly
|
||||
// it was called the same number of times as `addEventListener` was called.
|
||||
expect(loaderCalled).toEqual(1);
|
||||
});
|
||||
|
||||
it('should not log a warning when HammerJS is not loaded', () => {
|
||||
plugin.addEventListener(someElement, 'swipe', () => {});
|
||||
expect(fakeConsole.warn).not.toHaveBeenCalled();
|
||||
|
|
Loading…
Reference in New Issue