Skip to content

Commit

Permalink
Deprecate accessing jQuery.Event#originalEvent
Browse files Browse the repository at this point in the history
Implements the deprecation message for user-land code accessing `originalEvent` on `jQuery.Event` instances, as proposed by RFC#294 (https://github.com/emberjs/rfcs/blob/master/text/0294-optional-jquery.md#introducing-ember-jquery-legacy-and-deprecating-jqueryevent-usage)
  • Loading branch information
simonihmig committed May 25, 2018
1 parent 236dd24 commit d6a687b
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 1 deletion.
152 changes: 152 additions & 0 deletions packages/ember-glimmer/tests/integration/event-dispatcher-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
reset as instrumentationReset,
} from '@ember/instrumentation';
import { EMBER_IMPROVED_INSTRUMENTATION } from '@ember/canary-features';
import { jQueryDisabled, jQuery } from 'ember-views';
import { ENV } from 'ember-environment';

let canDataTransfer = !!document.createEvent('HTMLEvents').dataTransfer;

Expand Down Expand Up @@ -300,3 +302,153 @@ if (canDataTransfer) {
}
);
}

if (jQueryDisabled) {
moduleFor(
'EventDispatcher#native-events',
class extends RenderingTest {
['@test native events are passed when jQuery is not present'](assert) {
let receivedEvent;

this.registerComponent('x-foo', {
ComponentClass: Component.extend({
click(event) {
receivedEvent = event;
},
}),
template: `<button id="foo">bar</button>`,
});

this.render(`{{x-foo}}`);

this.runTask(() => this.$('#foo').click());
assert.ok(receivedEvent, 'click event was triggered');
assert.notOk(receivedEvent.originalEvent, 'event is not a jQuery.Event');
}
}
);
} else {
moduleFor(
'EventDispatcher#jquery-events',
class extends RenderingTest {

beforeEach() {
this.jqueryIntegration = ENV._JQUERY_INTEGRATION;
}

afterEach() {
ENV._JQUERY_INTEGRATION = this.jqueryIntegration;
}

['@test jQuery events are passed when jQuery is present'](assert) {
let receivedEvent;

this.registerComponent('x-foo', {
ComponentClass: Component.extend({
click(event) {
receivedEvent = event;
},
}),
template: `<button id="foo">bar</button>`,
});

this.render(`{{x-foo}}`);

this.runTask(() => this.$('#foo').click());
assert.ok(receivedEvent, 'click event was triggered');
assert.ok(receivedEvent instanceof jQuery.Event, 'event is a jQuery.Event');
}

['@test accessing jQuery.Event#originalEvent is deprecated'](assert) {
let receivedEvent;

this.registerComponent('x-foo', {
ComponentClass: Component.extend({
click(event) {
receivedEvent = event;
},
}),
template: `<button id="foo">bar</button>`,
});

this.render(`{{x-foo}}`);

this.runTask(() => this.$('#foo').click());
expectDeprecation(() => {
let { originalEvent } = receivedEvent;
assert.ok(originalEvent, 'jQuery event has originalEvent property');
assert.equal(originalEvent.type, 'click', 'properties of originalEvent are available');
}, 'Accessing jQuery.Event specific properties is deprecated. Either use the ember-jquery-legacy addon to normalize events to native events, or explicitly opt into jQuery integration using @ember/optional-features.');
}

['@test other jQuery.Event properties do not trigger deprecation'](assert) {
let receivedEvent;

this.registerComponent('x-foo', {
ComponentClass: Component.extend({
click(event) {
receivedEvent = event;
},
}),
template: `<button id="foo">bar</button>`,
});

this.render(`{{x-foo}}`);

this.runTask(() => this.$('#foo').click());
expectNoDeprecation(() => {
receivedEvent.stopPropagation();
receivedEvent.stopImmediatePropagation();
receivedEvent.preventDefault();
assert.ok(receivedEvent.bubbles, 'properties of jQuery event are available');
assert.equal(receivedEvent.type, 'click', 'properties of jQuery event are available');
});
}

['@test accessing jQuery.Event#originalEvent does not trigger deprecations when jquery integration is explicitly enabled'](assert) {
let receivedEvent;
ENV._JQUERY_INTEGRATION = true;

this.registerComponent('x-foo', {
ComponentClass: Component.extend({
click(event) {
receivedEvent = event;
},
}),
template: `<button id="foo">bar</button>`,
});

this.render(`{{x-foo}}`);

this.runTask(() => this.$('#foo').click());
expectNoDeprecation(() => {
let { originalEvent } = receivedEvent;
assert.ok(originalEvent, 'jQuery event has originalEvent property');
assert.equal(originalEvent.type, 'click', 'properties of originalEvent are available');
});
}

['@test accessing jQuery.Event#__originalEvent does not trigger deprecations to support ember-jquery-legacy'](assert) {
let receivedEvent;

this.registerComponent('x-foo', {
ComponentClass: Component.extend({
click(event) {
receivedEvent = event;
},
}),
template: `<button id="foo">bar</button>`,
});

this.render(`{{x-foo}}`);

this.runTask(() => this.$('#foo').click());
expectNoDeprecation(() => {
let { __originalEvent: originalEvent } = receivedEvent;
assert.ok(originalEvent, 'jQuery event has originalEvent property');
assert.equal(originalEvent.type, 'click', 'properties of originalEvent are available');
});
}
}
);
}
5 changes: 4 additions & 1 deletion packages/ember-views/lib/system/event_dispatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Object as EmberObject } from 'ember-runtime';
import jQuery from './jquery';
import ActionManager from './action_manager';
import fallbackViewRegistry from '../compat/fallback-view-registry';
import addJQueryEventDeprecation from './jquery_event_deprecation';

const HAS_JQUERY = jQuery !== undefined;
const ROOT_ELEMENT_CLASS = 'ember-application';
Expand Down Expand Up @@ -244,7 +245,7 @@ export default EmberObject.extend({
let result = true;

if (view) {
result = view.handleEvent(eventName, evt);
result = view.handleEvent(eventName, addJQueryEventDeprecation(evt));
}

return result;
Expand All @@ -254,6 +255,8 @@ export default EmberObject.extend({
let attributes = evt.currentTarget.attributes;
let handledActions = [];

evt = addJQueryEventDeprecation(evt);

for (let i = 0; i < attributes.length; i++) {
let attr = attributes.item(i);
let attrName = attr.name;
Expand Down
47 changes: 47 additions & 0 deletions packages/ember-views/lib/system/jquery_event_deprecation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { deprecate } from '@ember/debug';
import { get, set } from 'ember-metal';
import { ENV } from 'ember-environment';
import { HAS_NATIVE_PROXY } from 'ember-utils';

function deprecateJQueryEvent() {
deprecate(
'Accessing jQuery.Event specific properties is deprecated. Either use the ember-jquery-legacy addon to normalize events to native events, or explicitly opt into jQuery integration using @ember/optional-features.',
ENV._JQUERY_INTEGRATION === true,
{
id: 'ember-views.event-dispatcher.jquery-event',
until: '4.0.0',
}
);
}

export default function addJQueryEventDeprecation(jqEvent) {
if (!HAS_NATIVE_PROXY) {
return jqEvent;
}

// wrap the jQuery event in a Proxy to add the deprecation message for originalEvent, according to RFC#294
// we need a native Proxy here, so we can make sure that the internal use of originalEvent in jQuery itself does
// not trigger a deprecation
return new Proxy(jqEvent, {
get (target, name) {
switch (name) {
case 'originalEvent':
deprecateJQueryEvent();
return target[name];

// provide an escape hatch for ember-jquery-legacy to access originalEvent without a deprecation
case '__originalEvent':
return target.originalEvent;

default:
if (typeof target[name] === 'function') {
// for methods jQuery.Event call them with `target` as the `this` context, so they will use access
// `originalEvent` from the original jQuery event, not our proxy, thus not trigger the deprecation
return target[name].bind(target);
}
// same for jQuery's getter functions for simple properties
return target[name];
}
}
});
}

0 comments on commit d6a687b

Please sign in to comment.