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()
|
@Injectable()
|
||||||
export class HammerGesturesPlugin extends EventManagerPlugin {
|
export class HammerGesturesPlugin extends EventManagerPlugin {
|
||||||
|
private _loaderPromise: Promise<void>|null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DOCUMENT) doc: any,
|
@Inject(DOCUMENT) doc: any,
|
||||||
@Inject(HAMMER_GESTURE_CONFIG) private _config: HammerGestureConfig, private console: Console,
|
@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 (!(window as any).Hammer && !this.loader) {
|
||||||
|
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
||||||
this.console.warn(
|
this.console.warn(
|
||||||
`The "${eventName}" event cannot be bound because Hammer.JS is not ` +
|
`The "${eventName}" event cannot be bound because Hammer.JS is not ` +
|
||||||
`loaded and no custom loader has been specified.`);
|
`loaded and no custom loader has been specified.`);
|
||||||
|
}
|
||||||
return false;
|
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
|
// If Hammer is not present but a loader is specified, we defer adding the event listener
|
||||||
// until Hammer is loaded.
|
// until Hammer is loaded.
|
||||||
if (!(window as any).Hammer && this.loader) {
|
if (!(window as any).Hammer && this.loader) {
|
||||||
|
this._loaderPromise = this._loaderPromise || this.loader();
|
||||||
// This `addEventListener` method returns a function to remove the added listener.
|
// This `addEventListener` method returns a function to remove the added listener.
|
||||||
// Until Hammer is loaded, the returned function needs to *cancel* the registration rather
|
// Until Hammer is loaded, the returned function needs to *cancel* the registration rather
|
||||||
// than remove anything.
|
// than remove anything.
|
||||||
|
@ -199,12 +204,14 @@ export class HammerGesturesPlugin extends EventManagerPlugin {
|
||||||
cancelRegistration = true;
|
cancelRegistration = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.loader()
|
this._loaderPromise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// If Hammer isn't actually loaded when the custom loader resolves, give up.
|
// If Hammer isn't actually loaded when the custom loader resolves, give up.
|
||||||
if (!(window as any).Hammer) {
|
if (!(window as any).Hammer) {
|
||||||
|
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
||||||
this.console.warn(
|
this.console.warn(
|
||||||
`The custom HAMMER_LOADER completed, but Hammer.JS is not present.`);
|
`The custom HAMMER_LOADER completed, but Hammer.JS is not present.`);
|
||||||
|
}
|
||||||
deregister = () => {};
|
deregister = () => {};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -216,9 +223,11 @@ export class HammerGesturesPlugin extends EventManagerPlugin {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
||||||
this.console.warn(
|
this.console.warn(
|
||||||
`The "${eventName}" event cannot be bound because the custom ` +
|
`The "${eventName}" event cannot be bound because the custom ` +
|
||||||
`Hammer.JS loader failed.`);
|
`Hammer.JS loader failed.`);
|
||||||
|
}
|
||||||
deregister = () => {};
|
deregister = () => {};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,8 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
|
||||||
ngZone = z;
|
ngZone = z;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
let loaderCalled = 0;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
originalHammerGlobal = (window as any).Hammer;
|
originalHammerGlobal = (window as any).Hammer;
|
||||||
(window as any).Hammer = undefined;
|
(window as any).Hammer = undefined;
|
||||||
|
@ -76,10 +78,13 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
|
||||||
off: jasmine.createSpy('mc.off'),
|
off: jasmine.createSpy('mc.off'),
|
||||||
};
|
};
|
||||||
|
|
||||||
loader = () => new Promise((resolve, reject) => {
|
loader = () => {
|
||||||
|
loaderCalled++;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
resolveLoader = resolve;
|
resolveLoader = resolve;
|
||||||
failLoader = reject;
|
failLoader = reject;
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Make the hammer config return a fake hammer instance
|
// Make the hammer config return a fake hammer instance
|
||||||
const hammerConfig = new HammerGestureConfig();
|
const hammerConfig = new HammerGestureConfig();
|
||||||
|
@ -95,9 +100,19 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
loaderCalled = 0;
|
||||||
(window as any).Hammer = originalHammerGlobal;
|
(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', () => {
|
it('should not log a warning when HammerJS is not loaded', () => {
|
||||||
plugin.addEventListener(someElement, 'swipe', () => {});
|
plugin.addEventListener(someElement, 'swipe', () => {});
|
||||||
expect(fakeConsole.warn).not.toHaveBeenCalled();
|
expect(fakeConsole.warn).not.toHaveBeenCalled();
|
||||||
|
|
Loading…
Reference in New Issue