Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
60 lines
1.7 KiB
JavaScript
Executable file
60 lines
1.7 KiB
JavaScript
Executable file
'use strict';
|
|
/* exported eventSafety */
|
|
|
|
/**
|
|
* Listens for an event to fire _once_ or a timeout to expire.
|
|
* This is generally used for things which are waiting on transitions
|
|
* as it's sometimes possible to miss the transitionend event.
|
|
* This should not be necessary once we have web animations as they
|
|
* will guarantee that a callback is fired.
|
|
*
|
|
* Usage:
|
|
*
|
|
* eventSafety(window, 'transitionend', callback, 400);
|
|
*
|
|
* eventSafety(window, 'transitionend', 400).then(() => { ... });
|
|
*
|
|
* @param {Object} obj
|
|
* Object to listen to the event on.
|
|
* @param {String} event
|
|
* The name of the event.
|
|
* @param {Function} callback
|
|
Optional; called after the event is fired.
|
|
* @param {Integer} timeout The duration of the safety timeout.
|
|
*
|
|
* @return {Promise}
|
|
* A promise that will never reject.
|
|
*/
|
|
function eventSafety(obj, event, callback, timeout) {
|
|
if (typeof callback === 'number') {
|
|
timeout = callback;
|
|
callback = null;
|
|
}
|
|
|
|
if (!timeout) {
|
|
throw new Error('You must pass a valid timeout value to `eventSafety`.');
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
var finishTimeout;
|
|
function done(e) {
|
|
// Both "transitionend" and "animationend" events bubble by default;
|
|
// ignore them here if they're not targeted on the element we care about.
|
|
if (e && e.target !== obj &&
|
|
(e.type === 'transitionend' || e.type === 'animationend')) {
|
|
return;
|
|
}
|
|
|
|
clearTimeout(finishTimeout);
|
|
obj.removeEventListener(event, done);
|
|
if (callback) {
|
|
/*jshint validthis:true */
|
|
resolve(callback.apply(this, arguments));
|
|
} else {
|
|
resolve(e);
|
|
}
|
|
}
|
|
finishTimeout = setTimeout(done, timeout);
|
|
obj.addEventListener(event, done);
|
|
});
|
|
}
|