diff --git a/index.js b/index.js index 74bc85f..ef7ae02 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ 'use strict'; +const VersionChecker = require('ember-cli-version-checker'); const Funnel = require('broccoli-funnel'); module.exports = { @@ -8,9 +9,26 @@ module.exports = { included(...args) { this._super.included.apply(this, args); + const checker = new VersionChecker(this.project); + const ember = checker.forEmber(); + + this.hasNativeOnModifier = ember.gte('3.11.0-beta.1'); + this.hasEventHelpers = Boolean( this.project.findAddonByName('ember-event-helpers') ); + + if (this.hasNativeOnModifier && this.parent === this.project) { + let message = + 'The `{{on}}` modifier is available natively since Ember 3.11.0-beta.1. You can remove `ember-on-modifier` from your `package.json`.'; + + if (!this.hasEventHelpers) { + message += + ' If you use the `(prevent-default)` helper, please install `ember-event-helpers`.'; + } + + this.ui.writeDeprecateLine(message); + } }, treeForApp(...args) { @@ -22,10 +40,15 @@ module.exports = { }, filterTree(tree) { + const exclude = []; + + if (this.hasNativeOnModifier) { + exclude.push(/modifiers/); + } if (this.hasEventHelpers) { - return new Funnel(tree, { exclude: [/helpers/] }); + exclude.push(/helpers/); } - return tree; + return new Funnel(tree, { exclude }); } }; diff --git a/package.json b/package.json index e56ccd0..17b5d90 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "dependencies": { "broccoli-funnel": "^2.0.2", "ember-cli-babel": "^7.7.3", + "ember-cli-version-checker": "^3.1.3", "ember-modifier-manager-polyfill": "^1.0.3" }, "devDependencies": { diff --git a/tests/helpers/ember-on-modifier-polyfill.js b/tests/helpers/ember-on-modifier-polyfill.js new file mode 100644 index 0000000..287642e --- /dev/null +++ b/tests/helpers/ember-on-modifier-polyfill.js @@ -0,0 +1,6 @@ +import { test, skip } from 'qunit'; +import { gte } from 'ember-compatibility-helpers'; + +export const onModifierPolyfilled = !gte('3.11.0-beta.1'); + +export const testIfOnModifierPolyfilled = onModifierPolyfilled ? test : skip; diff --git a/tests/integration/modifiers/on-test.js b/tests/integration/modifiers/on-test.js index 260dc5a..621dbd7 100644 --- a/tests/integration/modifiers/on-test.js +++ b/tests/integration/modifiers/on-test.js @@ -11,12 +11,16 @@ import hbs from 'htmlbars-inline-precompile'; import { set } from '@ember/object'; import { run } from '@ember/runloop'; import { gte } from 'ember-compatibility-helpers'; +import { + testIfOnModifierPolyfilled, + onModifierPolyfilled +} from '../../helpers/ember-on-modifier-polyfill'; module('Integration | Modifier | on', function(hooks) { setupRenderingTest(hooks); hooks.afterEach(() => resetOnerror()); - test('it basically works', async function(assert) { + testIfOnModifierPolyfilled('it basically works', async function(assert) { assert.expect(6); this.someMethod = function(event) { @@ -47,7 +51,9 @@ module('Integration | Modifier | on', function(hooks) { assert.counts({ adds: 1, removes: 0 }); }); - test('it can accept the `once` option', async function(assert) { + testIfOnModifierPolyfilled('it can accept the `once` option', async function( + assert + ) { assert.expect(3); let n = 0; @@ -67,121 +73,136 @@ module('Integration | Modifier | on', function(hooks) { assert.strictEqual(n, 1, 'callback has only been called once'); }); - test('unrelated property changes do not break the `once` option', async function(assert) { - assert.expect(5); + testIfOnModifierPolyfilled( + 'unrelated property changes do not break the `once` option', + async function(assert) { + assert.expect(5); - let n = 0; - this.someMethod = () => n++; - this.someProp = 0; + let n = 0; + this.someMethod = () => n++; + this.someProp = 0; - await render( - hbs`` - ); + await render( + hbs`` + ); - assert.counts({ adds: 1, removes: 0 }); + assert.counts({ adds: 1, removes: 0 }); - await click('button'); - await click('button'); + await click('button'); + await click('button'); - assert.counts({ adds: 1, removes: 0 }); + assert.counts({ adds: 1, removes: 0 }); - assert.strictEqual(n, 1, 'callback has only been called once'); + assert.strictEqual(n, 1, 'callback has only been called once'); - run(() => set(this, 'someProp', 1)); - await settled(); - assert.counts({ adds: 1, removes: 0 }); + run(() => set(this, 'someProp', 1)); + await settled(); + assert.counts({ adds: 1, removes: 0 }); - await click('button'); - assert.strictEqual(n, 1, 'callback has only been called once'); - }); + await click('button'); + assert.strictEqual(n, 1, 'callback has only been called once'); + } + ); - test('unrelated property changes do not cause the listener to re-register', async function(assert) { - assert.expect(2); + testIfOnModifierPolyfilled( + 'unrelated property changes do not cause the listener to re-register', + async function(assert) { + assert.expect(2); - this.someMethod = () => {}; - this.someProp = 0; + this.someMethod = () => {}; + this.someProp = 0; - await render( - hbs`` - ); - assert.counts({ adds: 1, removes: 0 }); + await render( + hbs`` + ); + assert.counts({ adds: 1, removes: 0 }); - run(() => set(this, 'someProp', 1)); - await settled(); - assert.counts({ adds: 1, removes: 0 }); - }); + run(() => set(this, 'someProp', 1)); + await settled(); + assert.counts({ adds: 1, removes: 0 }); + } + ); - test('it can accept the `capture` option', async function(assert) { - assert.expect(5); + testIfOnModifierPolyfilled( + 'it can accept the `capture` option', + async function(assert) { + assert.expect(5); - this.outerListener = () => assert.step('outer'); - this.innerListener = () => assert.step('inner'); + this.outerListener = () => assert.step('outer'); + this.innerListener = () => assert.step('inner'); - await render(hbs` + await render(hbs`
`); - assert.counts({ adds: 2, removes: 0 }); + assert.counts({ adds: 2, removes: 0 }); - await click('button'); + await click('button'); - assert.counts({ adds: 2, removes: 0 }); + assert.counts({ adds: 2, removes: 0 }); - assert.verifySteps( - ['outer', 'inner'], - 'outer capture listener was called first' - ); - }); + assert.verifySteps( + ['outer', 'inner'], + 'outer capture listener was called first' + ); + } + ); - test('it can accept the `once` & `capture` option combined', async function(assert) { - assert.expect(6); + testIfOnModifierPolyfilled( + 'it can accept the `once` & `capture` option combined', + async function(assert) { + assert.expect(6); - this.outerListener = () => assert.step('outer'); - this.innerListener = () => assert.step('inner'); + this.outerListener = () => assert.step('outer'); + this.innerListener = () => assert.step('inner'); - await render(hbs` + await render(hbs`
`); - assert.counts({ adds: 2, removes: 0 }); + assert.counts({ adds: 2, removes: 0 }); - await click('button'); - await click('button'); + await click('button'); + await click('button'); - assert.counts({ adds: 2, removes: 0 }); + assert.counts({ adds: 2, removes: 0 }); - assert.verifySteps( - ['outer', 'inner', 'inner'], - 'outer capture listener was called first and was then unregistered' - ); - }); - - test('it raises an assertion when calling `event.preventDefault()` on a `passive` event', async function(assert) { - assert.expect(3); - - this.handler = event => { - assert.expectAssertion( - () => event.preventDefault(), - `ember-on-modifier: You marked this listener as 'passive', meaning that you must not call 'event.preventDefault()'.` + assert.verifySteps( + ['outer', 'inner', 'inner'], + 'outer capture listener was called first and was then unregistered' + ); + } + ); + + testIfOnModifierPolyfilled( + 'it raises an assertion when calling `event.preventDefault()` on a `passive` event', + async function(assert) { + assert.expect(3); + + this.handler = event => { + assert.expectAssertion( + () => event.preventDefault(), + `ember-on-modifier: You marked this listener as 'passive', meaning that you must not call 'event.preventDefault()'.` + ); + }; + + await render( + hbs`` ); - }; - - await render( - hbs`` - ); - assert.counts({ adds: 1, removes: 0 }); + assert.counts({ adds: 1, removes: 0 }); - await click('button'); + await click('button'); - assert.counts({ adds: 1, removes: 0 }); - }); + assert.counts({ adds: 1, removes: 0 }); + } + ); - (gte('3.0.0') // I have no clue how to catch the error in Ember 2.13 + (gte('3.0.0') && onModifierPolyfilled // I have no clue how to catch the error in Ember 2.13 ? test : skip)('it raises an assertion if an invalid event option is passed in', async function(assert) { assert.expect(2); @@ -201,7 +222,7 @@ module('Integration | Modifier | on', function(hooks) { assert.counts({ adds: 0, removes: 0 }); }); - (gte('3.0.0') // I have no clue how to catch the error in Ember 2.13 + (gte('3.0.0') && onModifierPolyfilled // I have no clue how to catch the error in Ember 2.13 ? test : skip)('it raises an assertion if an invalid event name or callback is passed in', async function(assert) { setupOnerror(error => assert.step(error.message)); @@ -223,7 +244,7 @@ module('Integration | Modifier | on', function(hooks) { ]); }); - (gte('3.0.0') // I have no clue how to catch the error in Ember 2.13 + (gte('3.0.0') && onModifierPolyfilled // I have no clue how to catch the error in Ember 2.13 ? test : skip)('it recovers after updating to incorrect parameters', async function(assert) { assert.expect(9); @@ -260,99 +281,108 @@ module('Integration | Modifier | on', function(hooks) { assert.counts({ adds: 2, removes: 2 }); }); - test('it passes additional parameters through to the listener', async function(assert) { - assert.expect(11); - - this.a = 1; - this.b = 3; - this.c = 5; - this.someMethod = (a, b, c, event) => { - assert.step([a, b, c].join('-')); - assert.ok(event instanceof MouseEvent, 'last parameter is an event'); - }; - - await render( - hbs`` - ); - assert.counts({ adds: 1, removes: 0 }); - - await click('button'); - await click('button'); - assert.counts({ adds: 1, removes: 0 }); - - run(() => set(this, 'c', 7)); - await settled(); - assert.counts({ adds: 2, removes: 1 }); - - await click('button'); - assert.counts({ adds: 2, removes: 1 }); - - assert.verifySteps( - [[1, 3, 5], [1, 3, 5], [1, 3, 7]].map(s => s.join('-')), - 'parameters were passed through and updated on change' - ); - }); - - test('it is re-registered, when the callback changes', async function(assert) { - assert.expect(6); - - let a = 0; - this.someMethod = () => a++; + testIfOnModifierPolyfilled( + 'it passes additional parameters through to the listener', + async function(assert) { + assert.expect(11); + + this.a = 1; + this.b = 3; + this.c = 5; + this.someMethod = (a, b, c, event) => { + assert.step([a, b, c].join('-')); + assert.ok(event instanceof MouseEvent, 'last parameter is an event'); + }; + + await render( + hbs`` + ); + assert.counts({ adds: 1, removes: 0 }); - await render(hbs``); - assert.counts({ adds: 1, removes: 0 }); + await click('button'); + await click('button'); + assert.counts({ adds: 1, removes: 0 }); - await click('button'); - assert.counts({ adds: 1, removes: 0 }); + run(() => set(this, 'c', 7)); + await settled(); + assert.counts({ adds: 2, removes: 1 }); - let b = 0; - run(() => set(this, 'someMethod', () => b++)); - await settled(); - assert.counts({ adds: 2, removes: 1 }); + await click('button'); + assert.counts({ adds: 2, removes: 1 }); - await click('button'); - assert.counts({ adds: 2, removes: 1 }); + assert.verifySteps( + [[1, 3, 5], [1, 3, 5], [1, 3, 7]].map(s => s.join('-')), + 'parameters were passed through and updated on change' + ); + } + ); - assert.strictEqual(a, 1); - assert.strictEqual(b, 1); - }); + testIfOnModifierPolyfilled( + 'it is re-registered, when the callback changes', + async function(assert) { + assert.expect(6); - test('it is re-registered, when the callback changes and `capture` is used', async function(assert) { - assert.expect(9); + let a = 0; + this.someMethod = () => a++; - let a = 0; - this.someMethod = () => a++; - this.capture = true; + await render(hbs``); + assert.counts({ adds: 1, removes: 0 }); - await render( - hbs`` - ); - assert.counts({ adds: 1, removes: 0 }); + await click('button'); + assert.counts({ adds: 1, removes: 0 }); - await click('button'); - assert.counts({ adds: 1, removes: 0 }); + let b = 0; + run(() => set(this, 'someMethod', () => b++)); + await settled(); + assert.counts({ adds: 2, removes: 1 }); - let b = 0; - run(() => set(this, 'someMethod', () => b++)); - await settled(); - assert.counts({ adds: 2, removes: 1 }); + await click('button'); + assert.counts({ adds: 2, removes: 1 }); - await click('button'); - assert.counts({ adds: 2, removes: 1 }); + assert.strictEqual(a, 1); + assert.strictEqual(b, 1); + } + ); - let c = 0; - run(() => { - set(this, 'someMethod', () => c++); - set(this, 'capture', false); - }); - await settled(); - assert.counts({ adds: 3, removes: 2 }); + testIfOnModifierPolyfilled( + 'it is re-registered, when the callback changes and `capture` is used', + async function(assert) { + assert.expect(9); - await click('button'); - assert.counts({ adds: 3, removes: 2 }); + let a = 0; + this.someMethod = () => a++; + this.capture = true; - assert.strictEqual(a, 1); - assert.strictEqual(b, 1); - assert.strictEqual(c, 1); - }); + await render( + hbs`` + ); + assert.counts({ adds: 1, removes: 0 }); + + await click('button'); + assert.counts({ adds: 1, removes: 0 }); + + let b = 0; + run(() => set(this, 'someMethod', () => b++)); + await settled(); + assert.counts({ adds: 2, removes: 1 }); + + await click('button'); + assert.counts({ adds: 2, removes: 1 }); + + let c = 0; + run(() => { + set(this, 'someMethod', () => c++); + set(this, 'capture', false); + }); + await settled(); + assert.counts({ adds: 3, removes: 2 }); + + await click('button'); + assert.counts({ adds: 3, removes: 2 }); + + assert.strictEqual(a, 1); + assert.strictEqual(b, 1); + assert.strictEqual(c, 1); + } + ); }); diff --git a/yarn.lock b/yarn.lock index 18dc3ab..df68b46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3152,7 +3152,7 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve resolve "^1.3.3" semver "^5.3.0" -ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.0.1: +ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.0.1, ember-cli-version-checker@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-3.1.3.tgz#7c9b4f5ff30fdebcd480b1c06c4de43bb51c522c" integrity sha512-PZNSvpzwWgv68hcXxyjREpj3WWb81A7rtYNQq1lLEgrWIchF8ApKJjWP3NBpHjaatwILkZAV8klair5WFlXAKg==