-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
339 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}); | ||
}); | ||
}); |