diff --git a/addon/helpers/-clear-element.js b/addon/helpers/-clear-element.js new file mode 100644 index 0000000..2ffa31d --- /dev/null +++ b/addon/helpers/-clear-element.js @@ -0,0 +1,9 @@ +import { helper } from "@ember/component/helper"; + +export default helper(function clearElement([element] /*, hash*/) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + + return element; +}); diff --git a/app/helpers/-clear-element.js b/app/helpers/-clear-element.js new file mode 100644 index 0000000..1222702 --- /dev/null +++ b/app/helpers/-clear-element.js @@ -0,0 +1 @@ +export { default, clearElement } from 'ember-in-element-polyfill/helpers/-clear-element'; diff --git a/index.js b/index.js index 9ea7c9c..4710296 100644 --- a/index.js +++ b/index.js @@ -40,6 +40,18 @@ module.exports = { } }, + treeForAddon() { + if (!this.hasPublicInElement()) { + return this._super.treeForAddon.apply(this, arguments); + } + }, + + treeForApp() { + if (!this.hasPublicInElement()) { + return this._super.treeForApp.apply(this, arguments); + } + }, + hasPublicInElement() { // @todo once https://github.com/emberjs/rfcs/pull/287 is accepted and implemented, this function should return // true for any Ember version that already ships a public `in-element`! diff --git a/lib/in-element-transform.js b/lib/in-element-transform.js index 8256c21..d785e0d 100644 --- a/lib/in-element-transform.js +++ b/lib/in-element-transform.js @@ -2,11 +2,29 @@ module.exports = class InElementTransform { transform(ast) { + let b = this.syntax.builders; + this.syntax.traverse(ast, { BlockStatement(node) { if (node.path.original === 'in-element') { node.path.original = '-in-element'; node.path.parts = ['-in-element']; + + let insertBeforeHash = node.hash.pairs.find(pair => pair.key === "insertBefore"); + if (insertBeforeHash) { + if (insertBeforeHash.value.type !== "NullLiteral") { + throw new SyntaxError('insertBefore only takes `null` as an argument'); + } + + node.hash.pairs = node.hash.pairs.filter(hash => hash !== insertBeforeHash); + } else { + let [targetNode] = node.params; + + node.params[0] = b.sexpr( + '-clear-element', + [targetNode] + ); + } } } }); diff --git a/tests/integration/.gitkeep b/tests/integration/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/integration/helpers/clear-element-test.js b/tests/integration/helpers/clear-element-test.js new file mode 100644 index 0000000..5517066 --- /dev/null +++ b/tests/integration/helpers/clear-element-test.js @@ -0,0 +1,56 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; +import { helper } from '@ember/component/helper'; + +module('Integration | Helper | clear-element', function(hooks) { + setupRenderingTest(hooks); + + test('it clears the provided element', async function(assert) { + let element = document.createElement('div'); + element.innerHTML = `

Some Contents!

`; + + this.set('elementToClear', element); + + assert.strictEqual( + element.outerHTML, + '

Some Contents!

', + 'precond' + ); + + await render(hbs`{{-clear-element this.elementToClear}}`); + + assert.strictEqual(element.outerHTML, '
', 'element was emptied'); + }); + + test('it returns the element', async function(assert) { + let element = document.createElement('div'); + element.setAttribute('class', 'test-div'); + element.innerHTML = `

Some Contents!

`; + + this.set('elementToClear', element); + + await render(hbs`{{-clear-element this.elementToClear}}`); + + assert.dom('.test-div').exists(); + }); + + test('it can be used with -in-element', async function(assert) { + this.owner.register( + 'helper:query-selector', + helper(function([selector]) { + return document.querySelector(selector); + }) + ); + + await render(hbs` +
Original Content!
+ {{#-in-element (-clear-element (query-selector '#test-div'))}} + Replacement Content! + {{/-in-element}} + `); + + assert.dom('#test-div').hasText('Replacement Content!'); + }); +}); diff --git a/tests/integration/in-element-test.js b/tests/integration/in-element-test.js index 70527d1..631dbaa 100644 --- a/tests/integration/in-element-test.js +++ b/tests/integration/in-element-test.js @@ -6,15 +6,27 @@ import hbs from 'htmlbars-inline-precompile'; module('Integration | in-element', function(hooks) { setupRenderingTest(hooks); - test('renders into destination element', async function(assert) { + test('renders into destination element by replacing', async function(assert) { await render(hbs` -
+
Dummy
{{#if ready}} {{#in-element destinationElement}}Some text{{/in-element}} {{/if}} `); this.set('destinationElement', document.querySelector('#test-destination-element')); this.set('ready', true); - assert.dom('#test-destination-element').containsText('Some text', 'The content has been rendered in the destination element'); + assert.dom('#test-destination-element').hasText('Some text', 'The content has been rendered in the destination element'); + }); + + test('renders into destination element by appending', async function(assert) { + await render(hbs` +
Dummy
+ {{#if ready}} + {{#in-element destinationElement insertBefore=null}}Some text{{/in-element}} + {{/if}} + `); + this.set('destinationElement', document.querySelector('#test-destination-element')); + this.set('ready', true); + assert.dom('#test-destination-element').hasText('DummySome text', 'The content has been rendered in the destination element'); }); });