Skip to content

Commit

Permalink
Add more ways to specify the base element (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
fregante authored and zenorocha committed Dec 5, 2017
1 parent d1c8fd1 commit 23f15b0
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 1 deletion.
42 changes: 42 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,42 @@ var delegate = require('delegate');

### Add event delegation

#### With the default base (`document`)

```js
delegate('.btn', 'click', function(e) {
console.log(e.delegateTarget);
}, false);
```

#### With an element as base

```js
delegate(document.body, '.btn', 'click', function(e) {
console.log(e.delegateTarget);
}, false);
```

#### With a selector (of existing elements) as base

```js
delegate('.container', '.btn', 'click', function(e) {
console.log(e.delegateTarget);
}, false);
```

#### With an array/array-like of elements as base

```js
delegate(document.querySelectorAll('.container'), '.btn', 'click', function(e) {
console.log(e.delegateTarget);
}, false);
```

### Remove event delegation

#### With a single base element (default or specified)

```js
var delegation = delegate(document.body, '.btn', 'click', function(e) {
console.log(e.delegateTarget);
Expand All @@ -46,6 +74,20 @@ var delegation = delegate(document.body, '.btn', 'click', function(e) {
delegation.destroy();
```

#### With multiple elements (via selector or array)

Note: selectors are always treated as multiple elements, even if one or none are matched. `delegate()` will return an array.

```js
var delegations = delegate('.container', '.btn', 'click', function(e) {
console.log(e.delegateTarget);
}, false);

delegations.forEach(function (delegation) {
delegation.destroy();
});
```

## Browser Support

| <img src="https://clipboardjs.com/assets/images/chrome.png" width="48px" height="48px" alt="Chrome logo"> | <img src="https://clipboardjs.com/assets/images/edge.png" width="48px" height="48px" alt="Edge logo"> | <img src="https://clipboardjs.com/assets/images/firefox.png" width="48px" height="48px" alt="Firefox logo"> | <img src="https://clipboardjs.com/assets/images/ie.png" width="48px" height="48px" alt="Internet Explorer logo"> | <img src="https://clipboardjs.com/assets/images/opera.png" width="48px" height="48px" alt="Opera logo"> | <img src="https://clipboardjs.com/assets/images/safari.png" width="48px" height="48px" alt="Safari logo"> |
Expand Down
36 changes: 35 additions & 1 deletion src/delegate.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var closest = require('./closest');
* @param {Boolean} useCapture
* @return {Object}
*/
function delegate(element, selector, type, callback, useCapture) {
function _delegate(element, selector, type, callback, useCapture) {
var listenerFn = listener.apply(this, arguments);

element.addEventListener(type, listenerFn, useCapture);
Expand All @@ -22,6 +22,40 @@ function delegate(element, selector, type, callback, useCapture) {
}
}

/**
* Delegates event to a selector.
*
* @param {Element|String|Array} [elements]
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @param {Boolean} useCapture
* @return {Object}
*/
function delegate(elements, selector, type, callback, useCapture) {
// Handle the regular Element usage
if (typeof elements.addEventListener === 'function') {
return _delegate.apply(null, arguments);
}

// Handle Element-less usage, it defaults to global delegation
if (typeof type === 'function') {
// Use `document` as the first parameter, then apply arguments
// This is a short way to .unshift `arguments` without running into deoptimizations
return _delegate.bind(null, document).apply(null, arguments);
}

// Handle Selector-based usage
if (typeof elements === 'string') {
elements = document.querySelectorAll(elements);
}

// Handle Array-like based usage
return Array.prototype.map.call(elements, function (element) {
return _delegate(element, selector, type, callback, useCapture);
});
}

/**
* Finds closest match and invokes callback.
*
Expand Down
75 changes: 75 additions & 0 deletions test/delegate.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,79 @@ describe('delegate', function() {
delegation.destroy();
assert.ok(global.spy.calledOnce);
});

it('should use `document` if the element is unspecified', function(done) {
delegate('a', 'click', function() {
done();
});

simulant.fire(global.anchor, simulant('click'));
});

it('should remove an event listener the unspecified base (`document`)', function() {
var delegation = delegate('a', 'click', function() {});
var spy = sinon.spy(document, 'removeEventListener');

delegation.destroy();
assert.ok(spy.calledOnce);

spy.restore();
});

it('should add event listeners to all the elements in a base selector', function() {
var spy = sinon.spy();
delegate('li', 'a', 'click', spy);

var anchors = document.querySelectorAll('a');
simulant.fire(anchors[0], simulant('click'));
simulant.fire(anchors[1], simulant('click'));
assert.ok(spy.calledTwice);
});

it('should remove the event listeners from all the elements in a base selector', function() {
var items = document.querySelectorAll('li')
var spies = Array.prototype.map.call(items, function (li) {
return sinon.spy(li, 'removeEventListener');
});

var delegations = delegate('li', 'a', 'click', function() {});
delegations.forEach(function (delegation) {
delegation.destroy();
});

spies.every(function (spy) {
var success = spy.calledOnce;
spy.restore();
return success;
});
});

it('should add event listeners to all the elements in a base array', function() {
var spy = sinon.spy();
var items = document.querySelectorAll('li')
delegate(items, 'a', 'click', spy);

var anchors = document.querySelectorAll('a')
simulant.fire(anchors[0], simulant('click'));
simulant.fire(anchors[1], simulant('click'));
assert.ok(spy.calledTwice);
});

it('should remove the event listeners from all the elements in a base array', function() {
var items = document.querySelectorAll('li')
var spies = Array.prototype.map.call(items, function (li) {
return sinon.spy(li, 'removeEventListener');
});

var delegations = delegate(items, 'a', 'click', function() {});
delegations.forEach(function (delegation) {
delegation.destroy();
});

spies.every(function (spy) {
var success = spy.calledOnce;
spy.restore();
return success;
});
});
});

0 comments on commit 23f15b0

Please sign in to comment.