refactor(event_manager): use multi bindings to configure EventManager

Closes #3978
This commit is contained in:
vsavkin 2015-09-04 14:23:13 -07:00 committed by Victor Savkin
parent 5ebeaf7c9b
commit 855cb16cc7
8 changed files with 64 additions and 48 deletions

View File

@ -39,7 +39,11 @@ import {NgZone} from 'angular2/src/core/zone/ng_zone';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {XHR} from 'angular2/src/core/render/xhr'; import {XHR} from 'angular2/src/core/render/xhr';
import {XHRImpl} from 'angular2/src/core/render/xhr_impl'; import {XHRImpl} from 'angular2/src/core/render/xhr_impl';
import {EventManager, DomEventsPlugin} from 'angular2/src/core/render/dom/events/event_manager'; import {
EventManager,
DomEventsPlugin,
EVENT_MANAGER_PLUGINS
} from 'angular2/src/core/render/dom/events/event_manager';
import {KeyEventsPlugin} from 'angular2/src/core/render/dom/events/key_events'; import {KeyEventsPlugin} from 'angular2/src/core/render/dom/events/key_events';
import {HammerGesturesPlugin} from 'angular2/src/core/render/dom/events/hammer_gestures'; import {HammerGesturesPlugin} from 'angular2/src/core/render/dom/events/hammer_gestures';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper'; import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
@ -111,14 +115,10 @@ function _injectorBindings(appComponentType): Array<Type | Binding | any[]> {
.toFactory((p: Promise<any>) => p.then(ref => ref.instance), [APP_COMPONENT_REF_PROMISE]), .toFactory((p: Promise<any>) => p.then(ref => ref.instance), [APP_COMPONENT_REF_PROMISE]),
bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(null, assertionsEnabled()), bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(null, assertionsEnabled()),
[ExceptionHandler]), [ExceptionHandler]),
bind(EventManager) EventManager,
.toFactory( new Binding(EVENT_MANAGER_PLUGINS, {toClass: DomEventsPlugin, multi: true}),
(ngZone) => { new Binding(EVENT_MANAGER_PLUGINS, {toClass: KeyEventsPlugin, multi: true}),
var plugins = new Binding(EVENT_MANAGER_PLUGINS, {toClass: HammerGesturesPlugin, multi: true}),
[new HammerGesturesPlugin(), new KeyEventsPlugin(), new DomEventsPlugin()];
return new EventManager(plugins, ngZone);
},
[NgZone]),
DomRenderer, DomRenderer,
bind(Renderer).toAlias(DomRenderer), bind(Renderer).toAlias(DomRenderer),
APP_ID_RANDOM_BINDING, APP_ID_RANDOM_BINDING,

View File

@ -1,12 +1,25 @@
import {isBlank, BaseException, isPresent, StringWrapper} from 'angular2/src/core/facade/lang'; import {
isBlank,
BaseException,
isPresent,
StringWrapper,
CONST_EXPR
} from 'angular2/src/core/facade/lang';
import {ListWrapper} from 'angular2/src/core/facade/collection';
import {DOM} from 'angular2/src/core/dom/dom_adapter'; import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {NgZone} from 'angular2/src/core/zone/ng_zone'; import {NgZone} from 'angular2/src/core/zone/ng_zone';
import {Injectable, Inject, OpaqueToken} from 'angular2/di';
export const EVENT_MANAGER_PLUGINS: OpaqueToken =
CONST_EXPR(new OpaqueToken("EventManagerPlugins"));
@Injectable()
export class EventManager { export class EventManager {
constructor(public _plugins: EventManagerPlugin[], public _zone: NgZone) { private _plugins: EventManagerPlugin[];
for (var i = 0; i < _plugins.length; i++) {
_plugins[i].manager = this; constructor(@Inject(EVENT_MANAGER_PLUGINS) plugins: EventManagerPlugin[], private _zone: NgZone) {
} plugins.forEach(p => p.manager = this);
this._plugins = ListWrapper.reversed(plugins);
} }
addEventListener(element: HTMLElement, eventName: string, handler: Function) { addEventListener(element: HTMLElement, eventName: string, handler: Function) {
@ -48,6 +61,7 @@ export class EventManagerPlugin {
} }
} }
@Injectable()
export class DomEventsPlugin extends EventManagerPlugin { export class DomEventsPlugin extends EventManagerPlugin {
manager: EventManager; manager: EventManager;
@ -56,16 +70,16 @@ export class DomEventsPlugin extends EventManagerPlugin {
supports(eventName: string): boolean { return true; } supports(eventName: string): boolean { return true; }
addEventListener(element: HTMLElement, eventName: string, handler: Function) { addEventListener(element: HTMLElement, eventName: string, handler: Function) {
var zone = this.manager._zone; var zone = this.manager.getZone();
var outsideHandler = (event) => zone.run(() => handler(event)); var outsideHandler = (event) => zone.run(() => handler(event));
this.manager._zone.runOutsideAngular(() => { DOM.on(element, eventName, outsideHandler); }); this.manager.getZone().runOutsideAngular(() => { DOM.on(element, eventName, outsideHandler); });
} }
addGlobalEventListener(target: string, eventName: string, handler: Function): Function { addGlobalEventListener(target: string, eventName: string, handler: Function): Function {
var element = DOM.getGlobalEventTarget(target); var element = DOM.getGlobalEventTarget(target);
var zone = this.manager._zone; var zone = this.manager.getZone();
var outsideHandler = (event) => zone.run(() => handler(event)); var outsideHandler = (event) => zone.run(() => handler(event));
return this.manager._zone.runOutsideAngular( return this.manager.getZone().runOutsideAngular(
() => { return DOM.onAndCancel(element, eventName, outsideHandler); }); () => { return DOM.onAndCancel(element, eventName, outsideHandler); });
} }
} }

View File

@ -3,9 +3,11 @@ library angular.events;
import 'dart:html'; import 'dart:html';
import './hammer_common.dart'; import './hammer_common.dart';
import 'package:angular2/src/core/facade/lang.dart' show BaseException; import 'package:angular2/src/core/facade/lang.dart' show BaseException;
import "package:angular2/di.dart" show Injectable;
import 'dart:js' as js; import 'dart:js' as js;
@Injectable()
class HammerGesturesPlugin extends HammerGesturesPluginCommon { class HammerGesturesPlugin extends HammerGesturesPluginCommon {
bool supports(String eventName) { bool supports(String eventName) {
if (!super.supports(eventName)) return false; if (!super.supports(eventName)) return false;

View File

@ -2,10 +2,10 @@
import {HammerGesturesPluginCommon} from './hammer_common'; import {HammerGesturesPluginCommon} from './hammer_common';
import {isPresent, BaseException} from 'angular2/src/core/facade/lang'; import {isPresent, BaseException} from 'angular2/src/core/facade/lang';
import {Injectable} from 'angular2/di';
@Injectable()
export class HammerGesturesPlugin extends HammerGesturesPluginCommon { export class HammerGesturesPlugin extends HammerGesturesPluginCommon {
constructor() { super(); }
supports(eventName: string): boolean { supports(eventName: string): boolean {
if (!super.supports(eventName)) return false; if (!super.supports(eventName)) return false;

View File

@ -10,6 +10,7 @@ import {
import {StringMapWrapper, ListWrapper} from 'angular2/src/core/facade/collection'; import {StringMapWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
import {EventManagerPlugin} from './event_manager'; import {EventManagerPlugin} from './event_manager';
import {NgZone} from 'angular2/src/core/zone/ng_zone'; import {NgZone} from 'angular2/src/core/zone/ng_zone';
import {Injectable} from 'angular2/di';
var modifierKeys = ['alt', 'control', 'meta', 'shift']; var modifierKeys = ['alt', 'control', 'meta', 'shift'];
var modifierKeyGetters: StringMap<string, Function> = { var modifierKeyGetters: StringMap<string, Function> = {
@ -19,6 +20,7 @@ var modifierKeyGetters: StringMap<string, Function> = {
'shift': (event) => event.shiftKey 'shift': (event) => event.shiftKey
}; };
@Injectable()
export class KeyEventsPlugin extends EventManagerPlugin { export class KeyEventsPlugin extends EventManagerPlugin {
constructor() { super(); } constructor() { super(); }

View File

@ -30,7 +30,11 @@ import {NgZone} from 'angular2/src/core/zone/ng_zone';
import {DOM} from 'angular2/src/core/dom/dom_adapter'; import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {EventManager, DomEventsPlugin} from 'angular2/src/core/render/dom/events/event_manager'; import {
EventManager,
DomEventsPlugin,
EVENT_MANAGER_PLUGINS
} from 'angular2/src/core/render/dom/events/event_manager';
import {MockViewResolver} from 'angular2/src/mock/view_resolver_mock'; import {MockViewResolver} from 'angular2/src/mock/view_resolver_mock';
import {MockXHR} from 'angular2/src/core/render/xhr_mock'; import {MockXHR} from 'angular2/src/core/render/xhr_mock';
@ -144,15 +148,8 @@ function _getAppBindings() {
StyleInliner, StyleInliner,
TestComponentBuilder, TestComponentBuilder,
bind(NgZone).toClass(MockNgZone), bind(NgZone).toClass(MockNgZone),
bind(EventManager) EventManager,
.toFactory( new Binding(EVENT_MANAGER_PLUGINS, {toClass: DomEventsPlugin, multi: true})
(zone) => {
var plugins = [
new DomEventsPlugin(),
];
return new EventManager(plugins, zone);
},
[NgZone]),
]; ];
} }

View File

@ -11,7 +11,11 @@ import {
PreGeneratedChangeDetection PreGeneratedChangeDetection
} from 'angular2/src/core/change_detection/change_detection'; } from 'angular2/src/core/change_detection/change_detection';
import {DEFAULT_PIPES} from 'angular2/pipes'; import {DEFAULT_PIPES} from 'angular2/pipes';
import {EventManager, DomEventsPlugin} from 'angular2/src/core/render/dom/events/event_manager'; import {
EventManager,
DomEventsPlugin,
EVENT_MANAGER_PLUGINS
} from 'angular2/src/core/render/dom/events/event_manager';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter'; import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter';
import {KeyEventsPlugin} from 'angular2/src/core/render/dom/events/key_events'; import {KeyEventsPlugin} from 'angular2/src/core/render/dom/events/key_events';
@ -87,14 +91,10 @@ function _injectorBindings(): any[] {
return [ return [
bind(DOCUMENT) bind(DOCUMENT)
.toValue(DOM.defaultDoc()), .toValue(DOM.defaultDoc()),
bind(EventManager) EventManager,
.toFactory( new Binding(EVENT_MANAGER_PLUGINS, {toClass: DomEventsPlugin, multi: true}),
(ngZone) => { new Binding(EVENT_MANAGER_PLUGINS, {toClass: KeyEventsPlugin, multi: true}),
var plugins = new Binding(EVENT_MANAGER_PLUGINS, {toClass: HammerGesturesPlugin, multi: true}),
[new HammerGesturesPlugin(), new KeyEventsPlugin(), new DomEventsPlugin()];
return new EventManager(plugins, ngZone);
},
[NgZone]),
DomRenderer, DomRenderer,
bind(Renderer).toAlias(DomRenderer), bind(Renderer).toAlias(DomRenderer),
APP_ID_RANDOM_BINDING, APP_ID_RANDOM_BINDING,

View File

@ -25,14 +25,15 @@ export function main() {
describe('EventManager', () => { describe('EventManager', () => {
it('should delegate event bindings to plugins', () => { it('should delegate event bindings to plugins that are passed in from the most generic one to the most specific one',
var element = el('<div></div>'); () => {
var handler = (e) => e; var element = el('<div></div>');
var plugin = new FakeEventManagerPlugin(['click']); var handler = (e) => e;
var manager = new EventManager([plugin, domEventPlugin], new FakeNgZone()); var plugin = new FakeEventManagerPlugin(['click']);
manager.addEventListener(element, 'click', handler); var manager = new EventManager([domEventPlugin, plugin], new FakeNgZone());
expect(plugin._eventHandler.get('click')).toBe(handler); manager.addEventListener(element, 'click', handler);
}); expect(plugin._eventHandler.get('click')).toBe(handler);
});
it('should delegate event bindings to the first plugin supporting the event', () => { it('should delegate event bindings to the first plugin supporting the event', () => {
var element = el('<div></div>'); var element = el('<div></div>');
@ -40,7 +41,7 @@ export function main() {
var dblClickHandler = (e) => e; var dblClickHandler = (e) => e;
var plugin1 = new FakeEventManagerPlugin(['dblclick']); var plugin1 = new FakeEventManagerPlugin(['dblclick']);
var plugin2 = new FakeEventManagerPlugin(['click', 'dblclick']); var plugin2 = new FakeEventManagerPlugin(['click', 'dblclick']);
var manager = new EventManager([plugin1, plugin2], new FakeNgZone()); var manager = new EventManager([plugin2, plugin1], new FakeNgZone());
manager.addEventListener(element, 'click', clickHandler); manager.addEventListener(element, 'click', clickHandler);
manager.addEventListener(element, 'dblclick', dblClickHandler); manager.addEventListener(element, 'dblclick', dblClickHandler);
expect(plugin1._eventHandler.has('click')).toBe(false); expect(plugin1._eventHandler.has('click')).toBe(false);