From f5ae31a26d4914a4092c978dc19d0671eda31f1e Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 27 Jan 2019 22:28:59 -0500 Subject: [PATCH] Initial implementation of emberjs/rfcs#415 This is the initial implementation of [emberjs/rfcs#415](https://emberjs.github.io/rfcs/0415-render-element-modifiers.html). It currently depends on [ember-modifier-manager-polyfill](https://github.com/rwjblue/ember-modifier-manager-polyfill) in order to support Ember versions prior to 3.8 (should work back to at least 2.12). --- addon/.gitkeep | 0 addon/modifiers/did-insert.js | 17 ++++++ addon/modifiers/did-update.js | 22 ++++++++ addon/modifiers/will-destroy.js | 22 ++++++++ app/.gitkeep | 0 app/modifiers/did-insert.js | 1 + app/modifiers/did-update.js | 1 + app/modifiers/will-destroy.js | 1 + .../integration/modifiers/did-insert-test.js | 52 +++++++++++++++++++ .../integration/modifiers/did-update-test.js | 27 ++++++++++ .../modifiers/will-destroy-test.js | 46 ++++++++++++++++ 11 files changed, 189 insertions(+) delete mode 100644 addon/.gitkeep create mode 100644 addon/modifiers/did-insert.js create mode 100644 addon/modifiers/did-update.js create mode 100644 addon/modifiers/will-destroy.js delete mode 100644 app/.gitkeep create mode 100644 app/modifiers/did-insert.js create mode 100644 app/modifiers/did-update.js create mode 100644 app/modifiers/will-destroy.js create mode 100644 tests/integration/modifiers/did-insert-test.js create mode 100644 tests/integration/modifiers/did-update-test.js create mode 100644 tests/integration/modifiers/will-destroy-test.js 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..8da29a7 --- /dev/null +++ b/tests/integration/modifiers/did-insert-test.js @@ -0,0 +1,52 @@ +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-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.deepEqual(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.deepEqual(named, {}, 'named args match'); + assert.deepEqual(positional, ['initial'], 'positional args match'); + }; + + this.set('firstArg', 'initial'); + await render( + hbs`
` + ); + this.set('firstArg', 'updated'); + }); +}); diff --git a/tests/integration/modifiers/did-update-test.js b/tests/integration/modifiers/did-update-test.js new file mode 100644 index 0000000..10f5b29 --- /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.deepEqual(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..12218b9 --- /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.deepEqual(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); + }); +});