From acbb0b2d2551e2032490ce56becccc08e8bf5e4d Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 11 Aug 2015 20:07:50 -0400 Subject: [PATCH] [BUGFIX canary] Honor `customEvents` opting out of event listeners. Setting `customEvents` to a hash in an application is a way to add new listeners that the `EventDispatcher` knows about. Often, users see this and decide that they want to disable a given event (for example `mouseenter` and `mouseleave` events) and think they can do something like: ```javascript var App = Ember.Application.create({ customEvents: { mouseenter: null, mouseleave: null } }); ``` Unfortunately, that just makes the `EventDispatcher` call a method named `null` on the view/component instances (LOL). This fixes that bug by allowing a `null` value to disable the event listener. --- .../lib/system/application.js | 31 +++++++++++++++- .../lib/system/event_dispatcher.js | 35 ++++++++++++++----- .../tests/system/event_dispatcher_test.js | 31 ++++++++++++++++ 3 files changed, 88 insertions(+), 9 deletions(-) diff --git a/packages/ember-application/lib/system/application.js b/packages/ember-application/lib/system/application.js index 58ba2d94c96..3ef6b80cb79 100644 --- a/packages/ember-application/lib/system/application.js +++ b/packages/ember-application/lib/system/application.js @@ -123,6 +123,20 @@ var librariesRegistered = false; }); ``` + To prevent Ember from setting up a listener for a default event, + specify the event name with a `null` value in the `customEvents` + property: + + ```javascript + var App = Ember.Application.create({ + customEvents: { + // prevent listeners for mouseenter/mouseleave events + mouseenter: null, + mouseleave: null + } + }); + ``` + By default, the application sets up these event listeners on the document body. However, in cases where you are embedding an Ember application inside an existing page, you may want it to set up the listeners on an element @@ -243,7 +257,11 @@ var Application = Namespace.extend(RegistryProxy, { If you would like additional bubbling events to be delegated to your views, set your `Ember.Application`'s `customEvents` property to a hash containing the DOM event name as the key and the - corresponding view method name as the value. For example: + corresponding view method name as the value. Setting an event to + a value of `null` will prevent a default event listener from being + added for that event. + + To add new events to be listened to: ```javascript var App = Ember.Application.create({ @@ -254,6 +272,17 @@ var Application = Namespace.extend(RegistryProxy, { }); ``` + To prevent default events from being listened to: + + ```javascript + var App = Ember.Application.create({ + customEvents: { + // remove support for mouseenter / mouseleave events + mouseenter: null, + mouseleave: null + } + }); + ``` @property customEvents @type Object @default null diff --git a/packages/ember-views/lib/system/event_dispatcher.js b/packages/ember-views/lib/system/event_dispatcher.js index c5ea715f842..e7ded84191b 100644 --- a/packages/ember-views/lib/system/event_dispatcher.js +++ b/packages/ember-views/lib/system/event_dispatcher.js @@ -12,7 +12,7 @@ import EmberObject from 'ember-runtime/system/object'; import jQuery from 'ember-views/system/jquery'; import ActionManager from 'ember-views/system/action_manager'; import View from 'ember-views/views/view'; -import merge from 'ember-metal/merge'; +import assign from 'ember-metal/assign'; /** `Ember.EventDispatcher` handles delegating browser events to their @@ -29,12 +29,29 @@ export default EmberObject.extend({ /** The set of events names (and associated handler function names) to be setup - and dispatched by the `EventDispatcher`. Custom events can added to this list at setup - time, generally via the `Ember.Application.customEvents` hash. Only override this - default set to prevent the EventDispatcher from listening on some events all together. + and dispatched by the `EventDispatcher`. Modifications to this list can be done + at setup time, generally via the `Ember.Application.customEvents` hash. - This set will be modified by `setup` to also include any events added at that time. + To add new events to be listened to: + ```javascript + var App = Ember.Application.create({ + customEvents: { + paste: 'paste' + } + }); + ``` + + To prevent default events from being listened to: + + ```javascript + var App = Ember.Application.create({ + customEvents: { + mouseenter: null, + mouseleave: null + } + }); + ``` @property events @type Object @private @@ -129,9 +146,7 @@ export default EmberObject.extend({ */ setup(addedEvents, rootElement) { var event; - var events = get(this, 'events'); - - merge(events, addedEvents || {}); + var events = assign({}, get(this, 'events'), addedEvents); if (!isNone(rootElement)) { set(this, 'rootElement', rootElement); @@ -172,6 +187,10 @@ export default EmberObject.extend({ var self = this; var viewRegistry = this.container && this.container.lookup('-view-registry:main') || View.views; + if (eventName === null) { + return; + } + rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) { var view = viewRegistry[this.id]; var result = true; diff --git a/packages/ember-views/tests/system/event_dispatcher_test.js b/packages/ember-views/tests/system/event_dispatcher_test.js index bea3525dbd7..33eb51b732e 100644 --- a/packages/ember-views/tests/system/event_dispatcher_test.js +++ b/packages/ember-views/tests/system/event_dispatcher_test.js @@ -312,3 +312,34 @@ QUnit.test('additional events and rootElement can be specified', function () { jQuery('#leView').trigger('myevent'); }); + +QUnit.test('default events can be disabled via `customEvents`', function () { + expect(1); + + run(function () { + dispatcher.setup({ + click: null + }); + + view = View.create({ + elementId: 'leView', + + null() { + // yes, at one point `click: null` made an event handler + // for `click` that called `null` on the view + ok(false, 'null event has been triggered'); + }, + + click() { + ok(false, 'click event has been triggered'); + }, + + doubleClick() { + ok(true, 'good event was still triggered'); + } + }).appendTo(dispatcher.get('rootElement')); + }); + + jQuery('#leView').trigger('click'); + jQuery('#leView').trigger('dblclick'); +});