Repository URL to install this package:
|
Version:
1.2.9 ▾
|
"use strict";
// -------------------------- imagesLoaded -------------------------- //
/**
* @param {Array, Element, NodeList, String} elem
* @param {Object or Function} options - if function, use as callback
* @param {Function} onAlways - callback function
*/
function ImagesLoaded(elem, options, onAlways) {
// coerce ImagesLoaded() without new, to be new ImagesLoaded()
if (!(this instanceof ImagesLoaded)) {
return new ImagesLoaded(elem, options, onAlways);
} // use elem as selector string
if (typeof elem == 'string') {
elem = document.querySelectorAll(elem);
}
this.elements = makeArray(elem);
this.options = extend({}, this.options);
if (typeof options == 'function') {
onAlways = options;
} else {
extend(this.options, options);
}
if (onAlways) {
this.on('always', onAlways);
}
this.getImages();
if ($) {
// add jQuery Deferred object
this.jqDeferred = new $.Deferred();
} // HACK check async to allow time to bind listeners
setTimeout(function () {
this.check();
}.bind(this));
}
ImagesLoaded.prototype = Object.create(EvEmitter.prototype);
ImagesLoaded.prototype.options = {};
ImagesLoaded.prototype.getImages = function () {
this.images = []; // filter & find items if we have an item selector
this.elements.forEach(this.addElementImages, this);
};
/**
* @param {Node} element
*/
ImagesLoaded.prototype.addElementImages = function (elem) {
// filter siblings
if (elem.nodeName == 'IMG') {
this.addImage(elem);
} // get background image on element
if (this.options.background === true) {
this.addElementBackgroundImages(elem);
} // find children
// no non-element nodes, #143
var nodeType = elem.nodeType;
if (!nodeType || !elementNodeTypes[nodeType]) {
return;
}
var childImgs = elem.querySelectorAll('img'); // concat childElems to filterFound array
for (var i = 0; i < childImgs.length; i++) {
var img = childImgs[i];
this.addImage(img);
} // get child background images
if (typeof this.options.background == 'string') {
var children = elem.querySelectorAll(this.options.background);
for (i = 0; i < children.length; i++) {
var child = children[i];
this.addElementBackgroundImages(child);
}
}
};
var elementNodeTypes = {
1: true,
9: true,
11: true
};
ImagesLoaded.prototype.addElementBackgroundImages = function (elem) {
var style = getComputedStyle(elem);
if (!style) {
// Firefox returns null if in a hidden iframe https://bugzil.la/548397
return;
} // get url inside url("...")
var reURL = /url\((['"])?(.*?)\1\)/gi;
var matches = reURL.exec(style.backgroundImage);
while (matches !== null) {
var url = matches && matches[2];
if (url) {
this.addBackground(url, elem);
}
matches = reURL.exec(style.backgroundImage);
}
};
/**
* @param {Image} img
*/
ImagesLoaded.prototype.addImage = function (img) {
var loadingImage = new LoadingImage(img);
this.images.push(loadingImage);
};
ImagesLoaded.prototype.addBackground = function (url, elem) {
var background = new Background(url, elem);
this.images.push(background);
};
ImagesLoaded.prototype.check = function () {
var _this = this;
this.progressedCount = 0;
this.hasAnyBroken = false; // complete if no images
if (!this.images.length) {
this.complete();
return;
}
function onProgress(image, elem, message) {
// HACK - Chrome triggers event before object properties have changed. #83
setTimeout(function () {
_this.progress(image, elem, message);
});
}
this.images.forEach(function (loadingImage) {
loadingImage.once('progress', onProgress);
loadingImage.check();
});
};
ImagesLoaded.prototype.progress = function (image, elem, message) {
this.progressedCount++;
this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; // progress event
this.emitEvent('progress', [this, image, elem]);
if (this.jqDeferred && this.jqDeferred.notify) {
this.jqDeferred.notify(this, image);
} // check if completed
if (this.progressedCount == this.images.length) {
this.complete();
}
if (this.options.debug && console) {
console.log('progress: ' + message, image, elem);
}
};
ImagesLoaded.prototype.complete = function () {
var eventName = this.hasAnyBroken ? 'fail' : 'done';
this.isComplete = true;
this.emitEvent(eventName, [this]);
this.emitEvent('always', [this]);
if (this.jqDeferred) {
var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';
this.jqDeferred[jqMethod](this);
}
}; // -------------------------- -------------------------- //
function LoadingImage(img) {
this.img = img;
}
LoadingImage.prototype = Object.create(EvEmitter.prototype);
LoadingImage.prototype.check = function () {
// If complete is true and browser supports natural sizes,
// try to check for image status manually.
var isComplete = this.getIsImageComplete();
if (isComplete) {
// report based on naturalWidth
this.confirm(this.img.naturalWidth !== 0, 'naturalWidth');
return;
} // If none of the checks above matched, simulate loading on detached element.
this.proxyImage = new Image();
this.proxyImage.addEventListener('load', this);
this.proxyImage.addEventListener('error', this); // bind to image as well for Firefox. #191
this.img.addEventListener('load', this);
this.img.addEventListener('error', this);
this.proxyImage.src = this.img.src;
};
LoadingImage.prototype.getIsImageComplete = function () {
return this.img.complete && this.img.naturalWidth !== undefined;
};
LoadingImage.prototype.confirm = function (isLoaded, message) {
this.isLoaded = isLoaded;
this.emitEvent('progress', [this, this.img, message]);
}; // ----- events ----- //
// trigger specified handler for event type
LoadingImage.prototype.handleEvent = function (event) {
var method = 'on' + event.type;
if (this[method]) {
this[method](event);
}
};
LoadingImage.prototype.onload = function () {
this.confirm(true, 'onload');
this.unbindEvents();
};
LoadingImage.prototype.onerror = function () {
this.confirm(false, 'onerror');
this.unbindEvents();
};
LoadingImage.prototype.unbindEvents = function () {
this.proxyImage.removeEventListener('load', this);
this.proxyImage.removeEventListener('error', this);
this.img.removeEventListener('load', this);
this.img.removeEventListener('error', this);
}; // -------------------------- Background -------------------------- //
function Background(url, element) {
this.url = url;
this.element = element;
this.img = new Image();
} // inherit LoadingImage prototype
Background.prototype = Object.create(LoadingImage.prototype);
Background.prototype.check = function () {
this.img.addEventListener('load', this);
this.img.addEventListener('error', this);
this.img.src = this.url; // check if image is already complete
var isComplete = this.getIsImageComplete();
if (isComplete) {
this.confirm(this.img.naturalWidth !== 0, 'naturalWidth');
this.unbindEvents();
}
};
Background.prototype.unbindEvents = function () {
this.img.removeEventListener('load', this);
this.img.removeEventListener('error', this);
};
Background.prototype.confirm = function (isLoaded, message) {
this.isLoaded = isLoaded;
this.emitEvent('progress', [this, this.element, message]);
}; // -------------------------- -------------------------- //
// // browser global
// window.Flickity = factory(
// window,
// window.Flickity,
// window.imagesLoaded
// );
// }
Flickity.createMethods.push('_createImagesLoaded');
var proto = Flickity.prototype;
proto._createImagesLoaded = function () {
this.on('activate', this.imagesLoaded);
};
proto.imagesLoaded = function () {
if (!this.options.imagesLoaded) {
return;
}
var _this = this;
function onImagesLoadedProgress(instance, image) {
var cell = _this.getParentCell(image.img);
_this.cellSizeChange(cell && cell.element);
if (!_this.options.freeScroll) {
_this.positionSliderAtSelected();
}
}
imagesLoaded(this.slider).on('progress', onImagesLoadedProgress);
};