Skip to content

Commit

Permalink
feat(components): start using Element.closest() (#204)
Browse files Browse the repository at this point in the history
feat(components): start using Element.closest()
  • Loading branch information
asudoh authored and chrisdhanaraj committed Jul 14, 2017
1 parent e86fdc5 commit 0af095d
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 14 deletions.
11 changes: 11 additions & 0 deletions demo/polyfills/element-closest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
if (typeof Element.prototype.closest !== 'function') {
Element.prototype.closest = function closestElement(selector) {
const doc = this.ownerDocument;
for (let traverse = this; traverse && traverse !== doc; traverse = traverse.parentNode) {
if (traverse.matches(selector)) {
return traverse;
}
}
return null;
};
}
1 change: 1 addition & 0 deletions demo/polyfills/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ import 'core-js/modules/es6.object.assign';
/* eslint-enable import/no-extraneous-dependencies */

import './custom-event';
import './element-closest';
import './element-matches';
import './toggle-class';
9 changes: 1 addition & 8 deletions src/components/floating-menu/floating-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,7 @@ class FloatingMenu extends mixin(createComponent, eventedShowHideState) {
* @returns {Element} The element that this menu should be placed to.
*/
_getContainer() {
const element = this.element;
const body = element.ownerDocument.body;
for (let traverse = element; traverse && traverse !== body; traverse = traverse.parentNode) {
if (traverse.matches(this.options.selectorContainer)) {
return traverse;
}
}
return body;
return this.element.closest(this.options.selectorContainer) || this.element.ownerDocument.body;
}

/**
Expand Down
15 changes: 9 additions & 6 deletions src/globals/js/misc/event-matches.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* @param {Event} event The event.
* @param {string} selector The selector.
* @returns {Element}
* The closest ancestor of the event target (or the event target itself) which matches the selectors given in parameter.
*/
export default function eventMatches(event, selector) {
// <svg> in IE does not have `Element#msMatchesSelector()` (that should be copied to `Element#matches()` by a polyfill).
// Also a weird behavior is seen in IE where DOM tree seems broken when `event.target` is on <svg>.
Expand All @@ -7,12 +13,9 @@ export default function eventMatches(event, selector) {
// If event target itself matches the given selector, return it
return event.target;
} else if (event.target.matches(`${selector} *`)) {
// If event target is a child node of a DOM element that matches the given selector,
// find the DOM element by going up the DOM tree
for (let traverse = event.target; traverse && traverse !== event.currentTarget; traverse = traverse.parentNode) {
if (traverse.matches(selector)) {
return traverse;
}
const closest = event.target.closest(selector);
if (event.currentTarget.contains(closest)) {
return closest;
}
}
}
Expand Down

0 comments on commit 0af095d

Please sign in to comment.