src/ImagePreloader/index.js
'use strict';
var QueryLoaderImage = require('./Image.js');
var ImagePreloader = {
getImageSrcs: function(element) {
this.sources = [];
if (typeof element !== 'undefined') {
this.findImageInElement(element);
if (this.deepSearch === true) {
var elements = element.querySelectorAll('*');
for (var i = 0; i < elements.length; i++) {
if (elements[i].tagName !== 'SCRIPT') {
this.findImageInElement(elements[i]);
}
}
}
}
// if there's no img or bg-img, use a 1px transparent data uri as a fallback,
// otherwise the user will be blocked for 10s
if (!this.sources.length) {
this.sources.push('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
}
return this.sources;
},
findAndPreload: function(element) {
if (typeof element === 'undefined') {
return;
}
this.sources = this.getImageSrcs(element);
for (var i = 0; i < this.sources.length; i++) {
var image = QueryLoaderImage(this.sources[i]);
image.preload(this.imageLoaded.bind(this));
this.images.push(image);
}
},
imageLoaded: function() {
this.loaded++;
this.updateProgress();
},
updateProgress: function() {
this.parent.updateProgress(this.loaded, this.sources.length);
},
findImageInElement: function(element) {
var urlType = this.determineUrlAndType(element);
//skip if gradient
if (!this.hasGradient(urlType.url)) {
//remove unwanted chars
urlType.url = this.stripUrl(urlType.url);
//split urls
var urls = urlType.url.split(', ');
for (var i = 0; i < urls.length; i++) {
if (this.validUrl(urls[i]) && this.urlIsNew(urls[i])) {
var extra = '';
if (this.isIE() || this.isOpera()) {
//filthy always no cache for IE, sorry peeps!
extra = '?rand=' + Math.random();
}
//add image to found list
this.sources.push(urls[i] + extra);
}
}
}
},
determineUrlAndType: function(element) {
var url = '';
var type = 'normal';
var style = element.currentStyle || window.getComputedStyle(element, null);
var blacklisted = ['', 'none', 'initial', 'inherit'];
if (typeof style.backgroundImage !== 'undefined' && blacklisted.indexOf(style.backgroundImage) === -1) {
//if object has background image (computed style)
url = style.backgroundImage;
type = 'background';
} else if (typeof element.style.backgroundImage !== 'undefined' && blacklisted.indexOf(element.style.backgroundImage) === -1) {
//if object has background image (inline style)
url = element.style.backgroundImage;
type = 'background';
} else if (element.nodeName.toLowerCase() === 'img') {
//if is img and has src
url = element.src;
}
return {
url: url,
type: type,
};
},
hasGradient: function(url) {
return (url && typeof url.indexOf !== 'undefined' ? url.indexOf('gradient(') !== -1 : false);
},
stripUrl: function(url) {
url = url.replace(/url\(\'/g, '');
url = url.replace(/url\(/g, '');
url = url.replace(/\'\)/g, '');
url = url.replace(/\)/g, '');
url = url.replace(/"/g, '');
return url;
},
validUrl: function(url) {
if (url.length > 0 && !url.match(/^(data:)/i)) {
return true;
} else {
return false;
}
},
urlIsNew: function(url) {
return this.sources.indexOf(url) === -1;
},
isIE: function() {
return navigator.userAgent.match(/msie/i);
},
isOpera: function() {
return navigator.userAgent.match(/Opera/i);
},
};
module.exports = function(parent) {
var imagePreloader = Object.create(ImagePreloader);
imagePreloader.parent = parent;
imagePreloader.sources = [];
imagePreloader.images = [];
imagePreloader.loaded = 0;
imagePreloader.deepSearch = true;
return imagePreloader;
};