From 647420f3ab6240c9cac2579dcca3179f30cc2473 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Wed, 29 Jul 2020 18:11:44 -0400 Subject: [PATCH 1/2] chore: add on-click-inside modifier --- .../rose/addon/modifiers/on-click-inside.js | 20 ++++++++++ addons/rose/app/modifiers/on-click-inside.js | 1 + .../modifiers/on-click-inside-test.js | 37 +++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 addons/rose/addon/modifiers/on-click-inside.js create mode 100644 addons/rose/app/modifiers/on-click-inside.js create mode 100644 addons/rose/tests/integration/modifiers/on-click-inside-test.js diff --git a/addons/rose/addon/modifiers/on-click-inside.js b/addons/rose/addon/modifiers/on-click-inside.js new file mode 100644 index 000000000..ec64ff5f7 --- /dev/null +++ b/addons/rose/addon/modifiers/on-click-inside.js @@ -0,0 +1,20 @@ +import { modifier } from 'ember-modifier'; + +/** + * Used to detect clicks occuring _inside_ the modified element. + * This is useful especially for dropdowns to toggle content visibility + * when the user clicks an item. + */ +export default modifier((element, [callback]) => { + function handleClick(event) { + if (element.contains(event.target)) { + callback(element, event); + } + } + + element.addEventListener('click', handleClick, false); + + return () => { + element.removeEventListener('click', handleClick, false); + }; +}); diff --git a/addons/rose/app/modifiers/on-click-inside.js b/addons/rose/app/modifiers/on-click-inside.js new file mode 100644 index 000000000..c137452fe --- /dev/null +++ b/addons/rose/app/modifiers/on-click-inside.js @@ -0,0 +1 @@ +export { default } from 'rose/modifiers/on-click-inside'; diff --git a/addons/rose/tests/integration/modifiers/on-click-inside-test.js b/addons/rose/tests/integration/modifiers/on-click-inside-test.js new file mode 100644 index 000000000..8197a2258 --- /dev/null +++ b/addons/rose/tests/integration/modifiers/on-click-inside-test.js @@ -0,0 +1,37 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, click } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Modifier | on-click-inside', function (hooks) { + setupRenderingTest(hooks); + + test('it fires event when inside is clicked', async function (assert) { + assert.expect(2); + this.set('clickedInside', (element) => { + assert.ok(element); + assert.equal(element.id, 'inside'); + }); + await render(hbs` +
+
+
+
+ `); + await click('#item'); + }); + + test('it does not fire event when outside is clicked', async function (assert) { + assert.expect(0); + this.set('clickedInside', () => { + assert.ok(true); + }); + await render(hbs` +
+
+
+
+ `); + await click('#outside'); + }); +}); From 372cf202f82357325901ae1906184bec5d4dc13f Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Wed, 29 Jul 2020 18:19:43 -0400 Subject: [PATCH 2/2] apply on-click-inside modifier to dropdown component --- addons/rose/addon/components/rose/dropdown.js | 8 +++++--- .../addon/templates/components/rose/dropdown.hbs | 2 +- .../integration/components/rose/dropdown-test.js | 13 +++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/addons/rose/addon/components/rose/dropdown.js b/addons/rose/addon/components/rose/dropdown.js index 07e9ba14b..4e6ffea81 100644 --- a/addons/rose/addon/components/rose/dropdown.js +++ b/addons/rose/addon/components/rose/dropdown.js @@ -12,13 +12,15 @@ export default Component.extend({ /** * Closes the details element by setting its `open` attribute to `false`. - * While the details element handles open/close functionality without - * JavaScript, we include this helper action to ensure that when the user - * clicks _outside_ of the element, it still closes. + * While the details element handles open/close functionality when clicking + * directly on the summar elemenet without JavaScript, we include this helper + * action to ensure that when the user clicks _outside_ of the element, + * or _inside_ the content, it still closes. * @param {HTMLElement} element */ @action close(element) { if (element.open) element.open = false; + if (element.parentElement.open) element.parentElement.open = false; }, }); diff --git a/addons/rose/addon/templates/components/rose/dropdown.hbs b/addons/rose/addon/templates/components/rose/dropdown.hbs index 51b429435..c65c640ba 100644 --- a/addons/rose/addon/templates/components/rose/dropdown.hbs +++ b/addons/rose/addon/templates/components/rose/dropdown.hbs @@ -22,7 +22,7 @@ -
+
{{yield (hash link=(component "link-to" class="rose-dropdown-link") button=(component "rose/button" style="dropdown") diff --git a/addons/rose/tests/integration/components/rose/dropdown-test.js b/addons/rose/tests/integration/components/rose/dropdown-test.js index 4d9ce49d0..3d4597c95 100644 --- a/addons/rose/tests/integration/components/rose/dropdown-test.js +++ b/addons/rose/tests/integration/components/rose/dropdown-test.js @@ -67,4 +67,17 @@ module('Integration | Component | rose/dropdown', function (hooks) { await click('#wrapper'); assert.notOk(find('#dropdown').open); }); + + test('it is closed when inside content is clicked', async function (assert) { + await render(hbs` + + Button + + `); + + await click('summary'); + assert.ok(find('.rose-dropdown').open); + await click('button'); + assert.notOk(find('.rose-dropdown').open); + }); });