Skip to content

Commit 82f3cec

Browse files
authored
Fix removing event listener for shadow root element (#973)
* Fix removing event listener for shadow root element * Add test from PR #965
1 parent cb294b0 commit 82f3cec

2 files changed

Lines changed: 64 additions & 21 deletions

File tree

ember-basic-dropdown/src/components/basic-dropdown-content.ts

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
7070
private handleRootMouseDown?: RootMouseDownHandler;
7171
private scrollableAncestors: Element[] = [];
7272
private mutationObserver: MutationObserver | undefined;
73+
private rootElement: HTMLElement | undefined;
7374
@tracked private _contentWormhole?: Element;
7475
@tracked animationClass = this.transitioningInClass;
7576

@@ -186,16 +187,18 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
186187
);
187188

188189
// We need to register closing event on shadow dom element, otherwise all clicks inside a shadow dom are not closing the dropdown
189-
let rootElement;
190+
// In additional store the rootElement for outside clicks (ensure that we do removeEventListener on correct element)
190191
if (
191192
this._contentWormhole &&
192193
this._contentWormhole.getRootNode() instanceof ShadowRoot
193194
) {
194-
rootElement = this._contentWormhole.getRootNode() as HTMLElement;
195+
this.rootElement = this._contentWormhole.getRootNode() as HTMLElement;
196+
} else {
197+
this.rootElement = undefined;
195198
}
196199

197-
if (rootElement) {
198-
rootElement.addEventListener(
200+
if (this.rootElement) {
201+
this.rootElement.addEventListener(
199202
this.args.rootEventType || 'click',
200203
this.handleRootMouseDown,
201204
true,
@@ -216,13 +219,13 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
216219
);
217220
document.addEventListener('touchend', this.handleRootMouseDown, true);
218221

219-
if (rootElement) {
220-
rootElement.addEventListener(
222+
if (this.rootElement) {
223+
this.rootElement.addEventListener(
221224
'touchstart',
222225
this.touchStartHandlerBound,
223226
true,
224227
);
225-
rootElement.addEventListener(
228+
this.rootElement.addEventListener(
226229
'touchend',
227230
this.handleRootMouseDown,
228231
true,
@@ -247,16 +250,8 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
247250
true,
248251
);
249252

250-
let rootElement;
251-
if (
252-
this._contentWormhole &&
253-
this._contentWormhole.getRootNode() instanceof ShadowRoot
254-
) {
255-
rootElement = this._contentWormhole.getRootNode() as HTMLElement;
256-
}
257-
258-
if (rootElement) {
259-
rootElement.removeEventListener(
253+
if (this.rootElement) {
254+
this.rootElement.removeEventListener(
260255
this.args.rootEventType || 'click',
261256
this.handleRootMouseDown as RootMouseDownHandler,
262257
true,
@@ -275,13 +270,13 @@ export default class BasicDropdownContent extends Component<BasicDropdownContent
275270
true,
276271
);
277272

278-
if (rootElement) {
279-
rootElement.removeEventListener(
273+
if (this.rootElement) {
274+
this.rootElement.removeEventListener(
280275
'touchstart',
281276
this.touchStartHandlerBound,
282277
true,
283278
);
284-
rootElement.removeEventListener(
279+
this.rootElement.removeEventListener(
285280
'touchend',
286281
this.handleRootMouseDown as RootMouseDownHandler,
287282
true,

test-app/tests/integration/components/basic-dropdown-test.js

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,54 @@ module('Integration | Component | basic-dropdown', function (hooks) {
13971397
wormhole.remove();
13981398
});
13991399

1400+
test('Shadow dom: Its `toggle` action opens and closes the dropdown with renderInPlace', async function (assert) {
1401+
await render(hbs`
1402+
<Shadow>
1403+
<BasicDropdown @renderInPlace={{true}} as |dropdown|>
1404+
<dropdown.Trigger>Click me</dropdown.Trigger>
1405+
<dropdown.Content>
1406+
<div style="height: 100px; width: 100px; background: black" id="dropdown-is-opened"></div>
1407+
</dropdown.Content>
1408+
</BasicDropdown>
1409+
</Shadow>
1410+
`);
1411+
1412+
assert
1413+
.dom('#dropdown-is-opened', this.element.getRootNode())
1414+
.doesNotExist('The dropdown is closed');
1415+
1416+
const triggerElement = find('[data-shadow]')?.shadowRoot.querySelector(
1417+
'.ember-basic-dropdown-trigger',
1418+
);
1419+
1420+
await click(triggerElement);
1421+
1422+
assert
1423+
.dom('.ember-basic-dropdown-content', find('[data-shadow]').shadowRoot)
1424+
.exists('The dropdown is rendered');
1425+
1426+
1427+
assert.dom('#dropdown-is-opened', find('[data-shadow]').shadowRoot).exists('The dropdown is opened');
1428+
1429+
await click(find('[data-shadow]').shadowRoot.getElementById('dropdown-is-opened'));
1430+
1431+
assert.dom('#dropdown-is-opened', find('[data-shadow]').shadowRoot).exists('The dropdown stays opened when clicking content');
1432+
1433+
await click(triggerElement);
1434+
1435+
assert
1436+
.dom('#dropdown-is-opened', find('[data-shadow]').shadowRoot)
1437+
.doesNotExist('The dropdown is closed again');
1438+
1439+
await click(triggerElement);
1440+
1441+
assert.dom('#dropdown-is-opened', find('[data-shadow]').shadowRoot).exists('The dropdown is opened 2d time');
1442+
1443+
await click(find('[data-shadow]').shadowRoot.getElementById('dropdown-is-opened'));
1444+
1445+
assert.dom('#dropdown-is-opened', find('[data-shadow]').shadowRoot).exists('The dropdown stays opened when clicking content after 2d open');
1446+
});
1447+
14001448
test('Shadow dom: Its `toggle` action opens and closes the dropdown when wormhole is inside shadow dom', async function (assert) {
14011449
await render(hbs`
14021450
<Shadow>
@@ -1406,7 +1454,7 @@ module('Integration | Component | basic-dropdown', function (hooks) {
14061454
<div id="dropdown-is-opened"></div>
14071455
</dropdown.Content>
14081456
</BasicDropdown>
1409-
1457+
14101458
<div id="wormhole-in-shadow-dom"></div>
14111459
</Shadow>
14121460
`);

0 commit comments

Comments
 (0)