Skip to content

Instantly share code, notes, and snippets.

@FuriouZz
Last active October 21, 2015 12:38
Show Gist options
  • Save FuriouZz/fb7ee4e431e27bb7e7c1 to your computer and use it in GitHub Desktop.
Save FuriouZz/fb7ee4e431e27bb7e7c1 to your computer and use it in GitHub Desktop.
"use strict"
/**
*
* Loader.js
*
* ------------------------------------------------------------
*
* Available property:
*
* Loader.isLoading
*
* Available methods:
*
* Loader.load( String|Object|Array )
* Loader.loadItem( Object )
* Loader.loadUrl( String )
* Loader.create()
* Loader.createAndLoad( String|Object|Array )
*
* ------------------------------------------------------------
*
* Events:
*
* oncomplete # Call when every item of the loop is loaded
* ondidload # Call when an item is loaded
* ondiderror # Call when an item loading failed
*
* ------------------------------------------------------------
*
* Notes:
*
* Use load, loadItem or loadUrl if you want to load something in the main loop
* Use create, createAndLoad if you want to load something in a separate loop (for example a manifest)
*
* ------------------------------------------------------------
*
* Examples:
*
* var url = 'my_image.jpg'
* Loader.load(url)
* Loader.on('onfileloaded', function(){
* console.log('File loaded')
* });
*
* var item = { type: 'audio', url: 'my_audio.mp3' }
* Loader.load(item, function(item){
* if(item.loaded) {
* document.body.appendChild(item.element);
* }
* });
*
* var items = ['image01.jpg', { type: 'video', 'my_video.mp4' }]
* Loader.load(items);
*
* var manifest = ['image02.jpg', { type: 'video', 'my_video01.mp4' }]
* var loader = Loader.createAndload(manifest);
* loader.on('oncomplete', function(){
* console.log('oncomplete')
* });
*
* // OR
* loader.oncomplete = function(){
* console.log('oncomplete')
* }
*
* ------------------------------------------------------------
*
*/
import { EventEmitter } from 'events'
const typesRegExp = /(image|audio|video)/gi
const imageRegExp = /.(jpg|jpeg|png|gif)/gi
const videoRegExp = /.(mp4|webm)/gi
const audioRegExp = /.(mp3|ogg)/gi
class Loader extends EventEmitter {
constructor() {
super()
this.isLoading = false
this._queue = []
this._current = null
this._bindEvents()
}
/**
* Add an url, an item or an array to the queue
* Params:
* => {String|Object|Array} urlOrItemOrArray
* Return
* => {Boolean} If it is loadable or not
*/
load(urlOrItemOrArray) {
// Is an url
if (typeof urlOrItemOrArray === 'string') {
this.loadUrl(urlOrItemOrArray)
}
// Is an item
else if (urlOrItemOrArray.hasOwnProperty('type')
&& urlOrItemOrArray.hasOwnProperty('url')) {
this.loadItem(urlOrItemOrArray)
}
// Is an array
else if (typeof urlOrItemOrArray.length === 'number') {
urlOrItemOrArray.forEach((item) => {
this.load(item)
})
}
else {
console.log("This content cannot be loaded")
return false
}
this._next()
return true
}
/**
* Add an item to the queue
* Params:
* => {Object} item
* type => {String} (image|audio|video)
* url => {String}
* Return
* => {Boolean} If it is loadable or not
*/
loadItem(item) {
if (item.type && item.url && item.type.match(typesRegExp)) {
this._queue.push(item)
return true
}
console.log('This item cannot be loaded')
return false
}
/**
* Create an item from the url and add it to the queue
* Params:
* => {String} url
* => {Function} callback (default: null)
* Return
* => {Boolean} If it is loadable or not
*/
loadUrl(url, callback = null) {
const item = { url: url, callback: callback }
if (url.match(imageRegExp)) { item.type = 'image' }
else if (url.match(videoRegExp)) { item.type = 'video' }
else if (url.match(audioRegExp)) { item.type = 'audio' }
else { console.log("This url cannot be loaded"); return false }
return this.loadItem(item)
}
/**
* Create a new loader
* Returns:
* {Object} Loader
*/
create() {
return new Loader()
}
/**
* Create a new loader and load url, item, or array on this loader's scope
* Params:
* => {String|Object|Array} urlOrItemOrArray
* Returns:
* => {Object} Loader
*/
createAndLoad(urlOrItemOrArray) {
const l = this.create()
l.load(urlOrItemOrArray)
return l
}
_bindEvents() {
this._onFileLoaded = this._onFileLoaded.bind(this)
this._onFileError = this._onFileError.bind(this)
}
_onLoad(item) {
switch (item.type) {
case 'image': {
let image
image = new Image()
image.onload = this._onFileLoaded
image.onerror = this._onFileError
image.src = item.url
item.element = image
break;
}
case 'audio':
case 'video': {
console.log('video or audio')
let media;
if (item.type === 'video') { media = document.createElement('video') }
else { media = document.createElement('audio') }
media.preload = 'auto'
media.addEventListener('loadedmetadata', this._onFileLoaded, false)
media.addEventListener('error', this._onFileError, false)
media.src = item.url
media.load()
item.element = media
break;
}
default: {
console.log('This item cannot be loaded', item)
return false;
}
}
this.isLoading = true
item.loaded = false
item.event = null
this._current = item
}
_onFileLoaded(e) {
this._current.event = e
this._current.loaded = true
this.emit('onfileloaded', this._current)
if (typeof this.onfileloaded === 'function') {
this.onfileloaded(this._current)
}
if (typeof this._current.callback === 'function') {
this._current.callback(this._current)
}
this._reset()
}
_onFileError(e) {
this._current.event = e
this._current.loaded = false
this.emit('onfileerror', this._current)
if (typeof this.onfileerror === 'function') {
this.onfileerror(this._current)
}
if (typeof this._current.callback === 'function') {
this._current.callback(this._current)
}
this._reset()
}
_onContentLoaded(){
this.emit('oncomplete')
if (typeof this.oncomplete === 'function') {
this.oncomplete()
}
}
_reset() {
var item = this._current
this._current = null
if (item.type === 'video' || item.type === 'audio') {
item.element.removeEventListener('loadedmetadata', this._onFileLoaded, false)
item.element.removeEventListener('error', this._onFileError, false)
}
if (item.type === 'image') {
item.element.onload = null
item.element.onerror = null
}
this.isLoading = false
this._next()
}
_next() {
if (!this.isLoading && this._queue.length > 0) {
this._onLoad(this._queue.shift())
}
if (!this.isLoading && this._queue.length === 0) {
this._onContentLoaded()
}
}
}
const _loader = new Loader()
export default _loader
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment