(function() {
/**
* @namespace MediaWatcher
* @memberof Help4.jscore
*/
Help4.jscore.MediaWatcher = {
/**
* @param {HTMLElement} elem the to be observed element
* @returns {Promise<Array<HTMLImageElement|HTMLVideoElement>>} indicates whether media is loaded
*/
observe: async function(elem) {
const nn = elem.nodeName;
if (nn === 'IMG') {
// single mode: IMG
return [await _observeImage(elem)];
} else if (nn === 'VIDEO') {
// single mode: VIDEO
return [await _observeVideo(elem)];
}
// multi mode
const promises = /** @type {Array<Promise<HTMLImageElement|HTMLVideoElement>>} */ [];
const images = elem.getElementsByTagName('img');
for (const image of images) {
promises.push(_observeImage(image));
}
const videos = elem.getElementsByTagName('video');
for (const video of videos) {
promises.push(_observeVideo(video))
}
return Help4.Promise.all(promises);
}
};
/**
* observes an image
* @memberof Help4.jscore.MediaWatcher
* @private
* @param {HTMLImageElement} imgElem
* @returns {Promise<HTMLImageElement>}
*/
function _observeImage(imgElem) {
return new Help4.Promise(resolve => {
if (imgElem.complete) return resolve(imgElem);
const done = () => {
imgElem.removeEventListener('load', done);
imgElem.removeEventListener('error', done);
resolve(imgElem);
}
// media not yet loaded, observe it
imgElem.addEventListener('load', done);
imgElem.addEventListener('error', done);
});
}
/**
* observes a video
* @memberof Help4.jscore.MediaWatcher
* @private
* @param {HTMLVideoElement} videoElem
* @returns {Promise<HTMLVideoElement>}
*/
function _observeVideo(videoElem) {
return new Help4.Promise(resolve => {
// data for the current playback position is available
if (videoElem.readyState >= 2) return resolve(videoElem);
const onLoadedData = () => {
if (videoElem.readyState >= 2) {
videoElem.removeEventListener('loadeddata', onLoadedData);
resolve(videoElem);
}
}
// wait for data load
videoElem.addEventListener('loadeddata', onLoadedData);
});
}
})();