Content-Length: 525635 | pFad | http://github.com/jsor/domestique/commit/7d7d8a909f78061e86102dedc220801699c58f9a

80 Add onTransitionEnd() helper · jsor/domestique@7d7d8a9 · GitHub
Skip to content

Commit

Permalink
Add onTransitionEnd() helper
Browse files Browse the repository at this point in the history
  • Loading branch information
jsor committed Aug 17, 2018
1 parent 1dfbb19 commit 7d7d8a9
Show file tree
Hide file tree
Showing 4 changed files with 339 additions and 0 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {
// Event
ready,
on,
onTransitionEnd,
off,
delegate,
dispatch,
Expand Down Expand Up @@ -88,6 +89,7 @@ API
* [Event](#event)
* [ready()](#ready)
* [on()](#on)
* [onTransitionEnd()](#ontransitionend)
* [off()](#off)
* [delegate()](#delegate)
* [dispatch()](#dispatch)
Expand Down Expand Up @@ -373,6 +375,34 @@ const remove = on(
remove(); // Remove event listener
```

#### onTransitionEnd()

```
onTransitionEnd(target: EventTarget, listener: EventListener): function
```

Registers a one-time `listener` for the `transitionend` event on `target`.

The function returns another function which can be used to unregister the event listener.

##### Example

```javascript
const target = document.querySelector('.my-element');
const listener = function (target) {
target.classList.add('transition-ended');

console.log('Transition ended');
};

const remove = onTransitionEnd(
target,
listener
);

remove(); // Remove event listener
```

#### off()

```
Expand Down
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import delegate from './src/event/delegate';
import dispatch from './src/event/dispatch';
import off from './src/event/off';
import on from './src/event/on';
import onTransitionEnd from './src/event/on-transition-end';
import ready from './src/event/ready';

import closest from './src/query/closest';
Expand Down Expand Up @@ -41,6 +42,7 @@ export {
delegate,
dispatch,
on,
onTransitionEnd,
off,
ready,

Expand Down
95 changes: 95 additions & 0 deletions src/event/on-transition-end.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import on from './on';

export function parseTransition(element) {
const fallback = ['', 0];

if (!element || !element.nodeType) {
return fallback;
}

function toArray(value) {
return value.replace(' ', '').split(',');
}

function toMsArray(value) {
return toArray(value).map(time => {
const multiplier = time.indexOf('ms') === -1 ? 1000 : 1;

return (parseFloat(time) || 0) * multiplier;
});
}

const styles = getComputedStyle(element);

const properties = toArray(styles.transitionProperty);
const durations = toMsArray(styles.transitionDuration);
const delays = toMsArray(styles.transitionDelay);

const maxLength = Math.max(
properties.length,
durations.length,
delays.length
);

const map = [];
const ignoreProps = [];

for (let i = 0; i < maxLength; i++) {
const prop = properties[i] || 'all';

if (prop !== 'all') {
ignoreProps.push(prop);
}

map.push([
prop,
(durations[i] || durations[0]) + (delays[i] || delays[0])
]);
}

const longest = map
.reduce((prev, curr) => {
return curr[1] >= prev[1] ? curr : prev;
}, fallback);

longest.push(ignoreProps);

return longest;
}

export default function onTransitionEnd(target, listener) {
const [prop, timeout, ignoreProps] = parseTransition(target);

const off = on(target, 'transitionend', e => {
if (e.target !== target) {
return;
}

if (prop !== 'all' && prop !== e.propertyName) {
return;
}

if (prop === 'all' && ignoreProps.indexOf(e.propertyName) !== -1) {
return;
}

done();
}, {passive: true});

const backupTimer = setTimeout(
done,
timeout + 100
);

function remove() {
clearTimeout(backupTimer);
off();
}

function done() {
remove();
listener.call(target, target);
}

return remove;
}
212 changes: 212 additions & 0 deletions test/event/on-transition-end.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import {onTransitionEnd, ready} from '../..';
import {parseTransition} from '../../src/event/on-transition-end';
import createFixture from '../fixture';

describe('onTransitionEnd()', function () {
this.timeout(5000);

let fixture;

beforeEach(() => {
fixture = createFixture();
});

afterEach(() => {
fixture.destroy();
fixture = null;
});

it('adds a listener', done => {
const el = fixture.append('<div></div>');

el.style.width = '10px';

el.style.transitionProperty = 'all';
el.style.transitionDuration = '.15s';

onTransitionEnd(el, () => done());

ready(() => {
el.style.width = '1000px';
});
});

it('adds a listener with duration in ms', done => {
const el = fixture.append('<div></div>');

el.style.width = '10px';

el.style.transitionProperty = 'all';
el.style.transitionDuration = '150ms';

onTransitionEnd(el, () => done());

ready(() => {
el.style.width = '1000px';
});
});

it('adds a listener with mixed transition', done => {
const el = fixture.append('<div></div>');

el.style.width = '10px';

el.style.transitionProperty = 'height';
el.style.transitionDuration = '.2ms, .4ms';
el.style.transitionDelay = '.2ms';

onTransitionEnd(el, () => done());

ready(() => {
el.style.width = '1000px';
});
});

it('works for non-event-targets', () => {
assert.isFunction(onTransitionEnd(undefined, () => {}));
assert.isFunction(onTransitionEnd('string', () => {}));
assert.isFunction(onTransitionEnd(true, () => {}));
assert.isFunction(onTransitionEnd(null, () => {}));
assert.isFunction(onTransitionEnd(1, () => {}));
assert.isFunction(onTransitionEnd(1.2, () => {}));
assert.isFunction(onTransitionEnd({foo: 'bar'}, () => {}));
assert.isFunction(onTransitionEnd(['bar'], () => {}));
});

describe('getLongestTransition()', () => {
it('parses transition with only duration set', () => {
const el = fixture.append('<div></div>');

el.style.transitionDuration = '2s';

assert.equal(parseTransition(el)[1], 2000);
});

it('parses transition in seconds as integer', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'all';
el.style.transitionDuration = '2s';
el.style.transitionDelay = '1s';

assert.equal(parseTransition(el)[1], 3000);
});

it('parses transition in seconds as float', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'all';
el.style.transitionDuration = '.2s';
el.style.transitionDelay = '.1s';

assert.equal(parseTransition(el)[1], 300);
});

it('parses transition in milliseconds as integer', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'all';
el.style.transitionDuration = '2000ms';
el.style.transitionDelay = '1000ms';

assert.equal(parseTransition(el)[1], 3000);
});

it('parses transition in milliseconds as float', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'all';
el.style.transitionDuration = '2000.5ms';
el.style.transitionDelay = '1000.5ms';

assert.closeTo(parseTransition(el)[1], 3001, 1);
});

it('parses multiple transition in seconds as integer', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'width, height';
el.style.transitionDuration = '4s, 2s';
el.style.transitionDelay = '2s, 1s';

assert.equal(parseTransition(el)[1], 6000);
});

it('parses multiple transition in seconds as float', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'width, height';
el.style.transitionDuration = '.2s, .4s';
el.style.transitionDelay = '.1s, .2s';

assert.equal(parseTransition(el)[1], 600);
});

it('parses multiple transition in milliseconds as integer', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'width, height';
el.style.transitionDuration = '2000ms, 4000ms';
el.style.transitionDelay = '1000ms, 2000ms';

assert.equal(parseTransition(el)[1], 6000);
});

it('parses multiple transition in milliseconds as float', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'width, height';
el.style.transitionDuration = '2000.5ms, 4000.5ms';
el.style.transitionDelay = '1000.5ms, 2000.5ms';

assert.closeTo(parseTransition(el)[1], 6001, 1); // IE 10 floor()'s
});

it('parses multiple transition with mixed duration', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'height';
el.style.transitionDuration = '2000.5ms, 4000.5ms';
el.style.transitionDelay = '2000.5ms';

assert.closeTo(parseTransition(el)[1], 6001, 1); // IE 10 floor()'s
});

it('parses multiple transition with mixed properties', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'height, width';
el.style.transitionDuration = '2000.5ms';
el.style.transitionDelay = '2000.5ms';

assert.closeTo(parseTransition(el)[1], 4001, 1); // IE 10 floor()'s
});

it('parses multiple transition with mixed delay', () => {
const el = fixture.append('<div></div>');

el.style.transitionProperty = 'height';
el.style.transitionDuration = '2000.5ms';
el.style.transitionDelay = '2000.5ms, 4000.5ms';

assert.closeTo(parseTransition(el)[1], 6001, 1); // IE 10 floor()'s
});

it('works for non-elements', () => {
const fallback = ['', 0];

assert.deepEqual(parseTransition(undefined), fallback);
assert.deepEqual(parseTransition('string'), fallback);
assert.deepEqual(parseTransition(true), fallback);
assert.deepEqual(parseTransition(null), fallback);
assert.deepEqual(parseTransition(1), fallback);
assert.deepEqual(parseTransition(1.2), fallback);
assert.deepEqual(parseTransition({foo: 'bar'}), fallback);
assert.deepEqual(parseTransition(['bar']), fallback);

assert.deepEqual(parseTransition({style: {}}), fallback);
assert.deepEqual(parseTransition({style: {transitionDuration: 'test'}}), fallback);
assert.deepEqual(parseTransition({style: {transitionDuration: {}}}), fallback);
});
});
});

0 comments on commit 7d7d8a9

Please sign in to comment.








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/jsor/domestique/commit/7d7d8a909f78061e86102dedc220801699c58f9a

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy