diff --git a/README.md b/README.md index 522a17d..e213345 100644 --- a/README.md +++ b/README.md @@ -176,13 +176,13 @@ domassist.html('.my-div', 'hello world'); // add html domassist.html('.my-div', ''); // remove html ``` -### closest(element, selector) +### closest(origin, selector) Find the closest parent element that matches the given selector #### Parameters: -`element` - {Element} the element where you want to start looking from +`origin` - {string|Element} - the element where you want to start looking from. It can be either a valid CSS selector or an Element. `selector` - {string} A valid CSS of the element to be found. @@ -262,7 +262,7 @@ domassist.modify('.my-div', { ``` -### on(selector, event, callback, capture) +### on(selector, event, callback, [capture]) Attach an event to an element based on a valid CSS selector or an Element. @@ -287,7 +287,7 @@ domassist.on('a', 'click', (e) => { ``` -### off(selector, event) +### off(selector, event, [capture]) Remove an attached event. @@ -297,6 +297,8 @@ Remove an attached event. `event` - {string} The name of the event to remove such as `click`, `mouseenter`, or `touchend` +`[capture = false]` - {Boolean} Determines which phase to the attach the event to. Default is `false` when means the event is attached to the bubble phase. If `true` then it's attached to the capture phase. + ### Example: ```javascript @@ -304,13 +306,13 @@ domassist.off('a', 'click'); ``` -### once(element, event, callback, capture) +### once(selector, event, callback, capture) Attach an event to an element to be fired once. #### Parameters: -`selector` - {Element} +`selector` - {string|Element} `event` - {string} The name of the event to attach such as `click`, `mouseenter`, or `touchend` diff --git a/lib/closest.js b/lib/closest.js index a1b8bd4..8e20ec8 100644 --- a/lib/closest.js +++ b/lib/closest.js @@ -1,6 +1,9 @@ import matches from './matches'; +import findOne from './findOne'; + +function closest(origin, selector) { + const el = (selector instanceof HTMLElement) ? origin : findOne(origin); -function closest(el, selector) { let parent = el.parentElement; while (parent.parentElement && !matches(parent, selector)) { parent = parent.parentElement; diff --git a/lib/off.js b/lib/off.js index a859db8..17b178d 100644 --- a/lib/off.js +++ b/lib/off.js @@ -1,8 +1,8 @@ import find from './find'; -function off(selector, event) { +function off(selector, event, capture = false) { if (Array.isArray(selector)) { - selector.forEach((item) => off(item, event)); + selector.forEach((item) => off(item, event, capture)); } if (!window._domassistevents) { window._domassistevents = {}; diff --git a/lib/once.js b/lib/once.js index 6582f68..7d95484 100644 --- a/lib/once.js +++ b/lib/once.js @@ -1,9 +1,9 @@ import on from './on'; import off from './off'; -function once(el, event, run, capture = false) { - on(el, event, e => { - off(el, event); +function once(selector, event, run, capture = false) { + on(selector, event, e => { + off(selector, event, capture); run(e); }, capture); } diff --git a/test/closest.test.js b/test/closest.test.js new file mode 100644 index 0000000..67907af --- /dev/null +++ b/test/closest.test.js @@ -0,0 +1,46 @@ +import domassist from '../domassist'; +import test from 'tape-rollup'; + +function addNodes() { + return ` +
1 +
2 +
3 +
4
+
+
+
`; +} + +const teardown = (el) => { + while (el.firstChild) { + el.removeChild(el.firstChild); + } +}; + +test('closest - element', assert => { + const el = domassist.findOne('#domassist'); + const levels = 4; + domassist.html(el, addNodes()); + const startEl = domassist.findOne(`.level-${levels}`); + let count = levels - 1; + while (count) { + assert.ok(domassist.closest(startEl, `.level-${count}`), `Should find element with class of level-${count}`); + --count; + } + teardown(el); + assert.end(); +}); + +test('closest - selector', assert => { + const el = domassist.findOne('#domassist'); + const levels = 4; + domassist.html(el, addNodes()); + let count = levels - 1; + while (count) { + assert.ok(domassist.closest(`.level-${levels}`, `.level-${count}`), `Should find element with class of level-${count}`); + --count; + } + teardown(el); + assert.end(); +}); diff --git a/test/domassist.test.js b/test/domassist.test.js index a884413..9c49c4a 100644 --- a/test/domassist.test.js +++ b/test/domassist.test.js @@ -10,6 +10,8 @@ import './on.test'; import './off.test'; import './html.test'; import './modify.test'; +import './closest.test'; +import './once.test'; import './show-hide.test'; import './styles.test'; @@ -71,37 +73,6 @@ test('matches', assert => { assert.end(); }); -test('closest', assert => { - const el = domassist.findOne('#domassist'); - const levels = 4; - // clean up test dom - while (el.firstChild) { - el.removeChild(el.firstChild); - } - function addNode(num) { - const node = document.createElement('div'); - node.innerText = num; - node.classList.add(`level-${num}`); - const children = el.children; - if (children.length) { - const child = domassist.findOne(`.level-${num - 1}`); - child.appendChild(node); - } else { - el.appendChild(node); - } - } - for (let i = 0; i < levels; i += 1) { - addNode(i + 1); - } - const startEl = domassist.findOne(`.level-${levels}`); - let count = levels - 1; - while (count) { - assert.ok(domassist.closest(startEl, `.level-${count}`), `Should find element with class of level-${count}`); - --count; - } - assert.end(); -}); - test('Events - delegate', assert => { const el = domassist.findOne('#domassist'); @@ -120,32 +91,6 @@ test('Events - delegate', assert => { page.sendEvent('click', pos.left + pos.width / 2, pos.top + pos.height / 2); }); -test('Events - once', assert => { - const el = domassist.findOne('#domassist'); - - el.innerHTML = ` - Click - `; - - const link = domassist.findOne('a', el); - const pos = link.getBoundingClientRect(); - - let clicks = 0; - - domassist.once(link, 'click', e => { - clicks++; - }); - - page.sendEvent('click', pos.left + pos.width / 2, pos.top + pos.height / 2); - page.sendEvent('click', pos.left + pos.width / 2, pos.top + pos.height / 2); - page.sendEvent('click', pos.left + pos.width / 2, pos.top + pos.height / 2); - - setTimeout(() => { - assert.equal(clicks, 1, 'Only fired once'); - assert.end(); - }, 500); -}); - test('Events - hover', assert => { const el = domassist.findOne('#domassist'); diff --git a/test/once.test.js b/test/once.test.js new file mode 100644 index 0000000..c2aa9e3 --- /dev/null +++ b/test/once.test.js @@ -0,0 +1,63 @@ +import domassist from '../domassist'; +import test from 'tape-rollup'; + +const page = window.phantom.page; + +const teardown = (el) => { + while (el.firstChild) { + el.removeChild(el.firstChild); + } +}; + +test('Events - once with Element', assert => { + const el = domassist.findOne('#domassist'); + + el.innerHTML = ` + Click + `; + + const link = domassist.findOne('a', el); + const pos = link.getBoundingClientRect(); + + let clicks = 0; + + domassist.once(link, 'click', e => { + clicks++; + }); + + page.sendEvent('click', pos.left + pos.width / 2, pos.top + pos.height / 2); + page.sendEvent('click', pos.left + pos.width / 2, pos.top + pos.height / 2); + page.sendEvent('click', pos.left + pos.width / 2, pos.top + pos.height / 2); + + setTimeout(() => { + assert.equal(clicks, 1, 'Element only fired once'); + teardown(el); + assert.end(); + }, 500); +}); + +test('Events - once with selector', assert => { + const el = domassist.findOne('#domassist'); + + el.innerHTML = ` + Click + `; + const link = domassist.findOne('a', el); + const pos = link.getBoundingClientRect(); + + let clicks = 0; + + domassist.once('a', 'click', e => { + clicks++; + }); + + page.sendEvent('click', pos.left + pos.width / 2, pos.top + pos.height / 2); + page.sendEvent('click', pos.left + pos.width / 2, pos.top + pos.height / 2); + page.sendEvent('click', pos.left + pos.width / 2, pos.top + pos.height / 2); + + setTimeout(() => { + assert.equal(clicks, 1, 'Selector only fired once'); + teardown(el); + assert.end(); + }, 500); +});