Repository URL to install this package:
|
Version:
1.0.4 ▾
|
// -------------------------- 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)
}