diff --git a/addon/.gitkeep b/addon/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/addon/modifiers/did-insert.js b/addon/modifiers/did-insert.js new file mode 100644 index 0000000..a25337d --- /dev/null +++ b/addon/modifiers/did-insert.js @@ -0,0 +1,17 @@ +import Ember from 'ember'; + +export default Ember._setModifierManager( + () => ({ + createModifier() {}, + + installModifier(_state, element, args) { + let [fn, ...positional] = args.positional; + + fn(element, positional, args.named); + }, + + updateModifier() {}, + destroyModifier() {}, + }), + class DidInsertModifier {} +); diff --git a/addon/modifiers/did-update.js b/addon/modifiers/did-update.js new file mode 100644 index 0000000..ef1ae11 --- /dev/null +++ b/addon/modifiers/did-update.js @@ -0,0 +1,22 @@ +import Ember from 'ember'; + +export default Ember._setModifierManager( + () => ({ + createModifier() { + return { element: null }; + }, + installModifier(state, element) { + // save element into state bucket + state.element = element; + }, + + updateModifier({ element }, args) { + let [fn, ...positional] = args.positional; + + fn(element, positional, args.named); + }, + + destroyModifier() {}, + }), + class DidUpdateModifier {} +); diff --git a/addon/modifiers/will-destroy.js b/addon/modifiers/will-destroy.js new file mode 100644 index 0000000..a30556a --- /dev/null +++ b/addon/modifiers/will-destroy.js @@ -0,0 +1,22 @@ +import Ember from 'ember'; + +export default Ember._setModifierManager( + () => ({ + createModifier() { + return { element: null }; + }, + + installModifier(state, element) { + state.element = element; + }, + + updateModifier() {}, + + destroyModifier({ element }, args) { + let [fn, ...positional] = args.positional; + + fn(element, positional, args.named); + }, + }), + class WillDestroyModifier {} +); diff --git a/app/.gitkeep b/app/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/app/modifiers/did-insert.js b/app/modifiers/did-insert.js new file mode 100644 index 0000000..024e068 --- /dev/null +++ b/app/modifiers/did-insert.js @@ -0,0 +1 @@ +export { default } from '@ember/render-modifiers/modifiers/did-insert'; diff --git a/app/modifiers/did-update.js b/app/modifiers/did-update.js new file mode 100644 index 0000000..a682cca --- /dev/null +++ b/app/modifiers/did-update.js @@ -0,0 +1 @@ +export { default } from '@ember/render-modifiers/modifiers/did-update'; diff --git a/app/modifiers/will-destroy.js b/app/modifiers/will-destroy.js new file mode 100644 index 0000000..a738673 --- /dev/null +++ b/app/modifiers/will-destroy.js @@ -0,0 +1 @@ +export { default } from '@ember/render-modifiers/modifiers/will-destroy'; diff --git a/tests/integration/modifiers/did-insert-test.js b/tests/integration/modifiers/did-insert-test.js new file mode 100644 index 0000000..1a164d9 --- /dev/null +++ b/tests/integration/modifiers/did-insert-test.js @@ -0,0 +1,79 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; +import Component from '@ember/component'; + +module('Integration | Modifier | did-insert', function(hooks) { + setupRenderingTest(hooks); + + test('it basically works', async function(assert) { + assert.expect(2); + + this.someMethod = element => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + }; + await render(hbs`
`); + }); + + test('it can accept arguments', async function(assert) { + assert.expect(4); + + this.someMethod = (element, positional, named) => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + + assert.namedArgsEqual(named, { some: 'hash-value' }, 'named args match'); + assert.deepEqual(positional, ['some-positional-value'], 'positional args match'); + }; + + await render( + hbs`
` + ); + }); + + test('it is not invoked again when arguments change', async function(assert) { + assert.expect(4); + + this.someMethod = (element, positional, named) => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + + assert.namedArgsEqual(named, {}, 'named args match'); + assert.deepEqual(positional, ['initial'], 'positional args match'); + }; + + this.set('firstArg', 'initial'); + await render( + hbs`
` + ); + this.set('firstArg', 'updated'); + }); + + test('adding class on insert (RFC example)', async function(assert) { + this.owner.register( + 'component:sometimes-fades-in', + Component.extend({ + fadeIn(element) { + element.classList.add('fade-in'); + }, + }) + ); + + this.owner.register( + 'template:components/sometimes-fades-in', + hbs` + {{#if shouldShow}} +
+ {{yield}} +
+ {{/if}} + ` + ); + + await render(hbs`{{sometimes-fades-in shouldShow=true}}`); + + assert.dom('.alert').hasClass('fade-in'); + }); +}); diff --git a/tests/integration/modifiers/did-update-test.js b/tests/integration/modifiers/did-update-test.js new file mode 100644 index 0000000..a11e9bf --- /dev/null +++ b/tests/integration/modifiers/did-update-test.js @@ -0,0 +1,27 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Modifier | did-update', function(hooks) { + setupRenderingTest(hooks); + + test('it basically works', async function(assert) { + assert.expect(4); + + this.someMethod = (element, positional, named) => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + + assert.namedArgsEqual(named, {}, 'named args match'); + assert.deepEqual(positional, ['update'], 'positional args match'); + }; + + this.set('boundValue', 'initial'); + await render( + hbs`
` + ); + + this.set('boundValue', 'update'); + }); +}); diff --git a/tests/integration/modifiers/will-destroy-test.js b/tests/integration/modifiers/will-destroy-test.js new file mode 100644 index 0000000..3ea2726 --- /dev/null +++ b/tests/integration/modifiers/will-destroy-test.js @@ -0,0 +1,46 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Modifier | will-destroy', function(hooks) { + setupRenderingTest(hooks); + + test('it basically works', async function(assert) { + assert.expect(2); + + this.someMethod = element => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + }; + this.set('show', true); + + await render( + hbs`{{#if show}}
{{/if}}` + ); + + // trigger destroy + this.set('show', false); + }); + + test('it can accept arguments', async function(assert) { + assert.expect(4); + + this.someMethod = (element, positional, named) => { + assert.equal(element.tagName, 'DIV', 'correct element tagName'); + assert.dom(element).hasAttribute('data-foo', 'some-thing'); + + assert.namedArgsEqual(named, { some: 'hash-value' }, 'named args match'); + assert.deepEqual(positional, ['some-positional-value'], 'positional args match'); + }; + + this.set('show', true); + + await render( + hbs`{{#if show}}
{{/if}}` + ); + + // trigger destroy + this.set('show', false); + }); +}); diff --git a/tests/test-helper.js b/tests/test-helper.js index 0382a84..74890db 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -2,7 +2,17 @@ import Application from '../app'; import config from '../config/environment'; import { setApplication } from '@ember/test-helpers'; import { start } from 'ember-qunit'; +import { assign } from '@ember/polyfills'; +import QUnit from 'qunit'; setApplication(Application.create(config.APP)); start(); + +QUnit.assert.namedArgsEqual = function(actual, expected, message) { + // this is needed because older versions of Ember pass an `EmptyObject` + // based object and QUnit fails due to the prototypes not matching + let sanitizedActual = assign({}, actual); + + this.deepEqual(sanitizedActual, expected, message); +};