/* jQuery NailThumb Plugin - any image to any thumbnail
* Examples and documentation at: http://www.garralab.com/nailthumb.php
* Copyright (C) 2012 garralab@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
(function($) {
var DEBUG = false;
var version = '1.1';
$.fn.nailthumb = function(options) {
var opts = $.extend({}, $.fn.nailthumb.defaults, options);
return this.each(function() {
var $this = $(this);
var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
thumbize($this,o)
});
};
function thumbize(element,options) {
var image = setImage(element,options);
var container = setContainer(element,options);
if (options.serverSideParams) {
$.fn.nailthumb.setServerSideParams(image,container,options);
}
debugObject('image',image);
debugObject('container',container);
if (options.onStart) options.onStart(container,options);
if (options.loadingClass) container.addClass(options.loadingClass);
if (options.preload || image.data('nailthumb.replaceto')) {
debug('wait on load');
image.one('load',function() {
debugObject('before check',image);
if(!image.data('nailthumb.working') && !image.data('nailthumb.replacing')) {
image.data('nailthumb.working',true);
debugObject('inside check',image);
doThumb(image,container,options);
}
});
var src = image.attr('src');
image.attr('src',null).attr('src',src);
} else {
debug('nail thumb directly');
image.data('nailthumb.working',true);
doThumb(image,container,options);
}
};
function doThumb(image,container,options) {
resetImage(image,options);
resetContainer(container,options);
var imageDims = getImageDims(image,options);
debugObject('image',image);
debugObject('imageDims',imageDims);
if (imageDims.width==0 || imageDims.height==0) {
imageDims = getHiddenCloneDims(image);
debugObject('imageCloneDims',imageDims);
}
var containerDims = getContainerDims(container,options);
debugObject('container',container);
debugObject('containerDims',containerDims);
var prop = getProportion(containerDims,imageDims,options);
debug('proportions',prop);
resize(image, imageDims, container, containerDims, prop, options);
};
function setImage(element,options) {
var image = element.find('img').first();
var finder = options.imageCustomFinder;
if (!finder && options.imageUrl) {
finder = imageUrlFinder;
} else if(!finder && options.imageFromWrappingLink) {
finder = imageFromWrappingLinkFinder;
}
if (finder) {
var img = finder(element,options);
debugObject('finder',img);
if (!img) img = [];
if (img.length>0) {
image = img;
image.css('display','none');
if(!image.data('nailthumb.replaceto')) image.data('nailthumb.replaceto',element);
image.data('nailthumb.originalImageDims',null);
}
}
if (image.length==0) {
if (element.is('img')) image = element;
}
return image;
};
function imageUrlFinder(element,options) {
var image = $('
').attr('src',options.imageUrl).css('display','none').data('nailthumb.replaceto',element);
element.append(image);
return image;
};
function imageFromWrappingLinkFinder(element,options) {
var image;
var link = element.find('a').first();
if (link.length==0 && element.is('a')) {
link = element;
}
if (link.attr('href')) {
image = $('
').attr('src',link.attr('href')).css('display','none').data('nailthumb.replaceto',link);
if (link.attr('title')) image.attr('title',link.attr('title'));
link.append(image);
}
return image;
};
function resetImage(image,options) {
if (!options.nostyle) {
image.css({
'position':'relative'
});
}
if (!image.data('nailthumb.originalImageDims')) {
image.css({
'width':'auto',
'height':'auto',
'top':0,
'left':0
}).removeAttr('width')
.removeAttr('height');
}
};
function setContainer(element,options) {
var container = element;
if (element.is('img')) {
if (options.ifImageAddContainer) {
var c = $('
');
element.wrap(c);
}
container = element.parent();
}
return container;
};
function resetContainer(container,options) {
if (options.containerClass) container.addClass(options.containerClass);
if (!options.nostyle) {
container.css({
'overflow':'hidden',
'padding':'0px'
});
}
if (options.replaceAnimation == 'animate') {
if (options.width || options.height) {
container.animate({
'width':options.width,
'height':options.height
},options.animationTime,options.animation);
}
} else {
if (options.width) container.width(options.width);
if (options.height) container.height(options.height);
}
container.find('span.'+options.titleClass).remove();
};
function resize(image, imageDims, container, containerDims, prop, options) {
var iw = imageDims.width * prop;
var ih = imageDims.height * prop;
var top = 0, left = 0, diff;
var direction = getDirections(options.fitDirection);
if (ihcontainerDims.innerHeight) {
switch (direction.v) {
case 'center':
top=-(ih-containerDims.innerHeight)/2;
break;
case 'bottom':
top=-(ih-containerDims.innerHeight);
break;
default:
break;
}
}
if (iwcontainerDims.innerWidth) {
switch (direction.h) {
case 'center':
left=-(iw-containerDims.innerWidth)/2;
break;
case 'right':
left=-(iw-containerDims.innerWidth);
break;
default:
break;
}
}
image.addClass(options.imageClass);
if (image.data('nailthumb.replaceto')) {
replaceImage(image, imageDims, container, containerDims, ih, iw, left, top, diff, options);
} else {
showImage(image, imageDims, container, containerDims, ih, iw, left, top, diff, options);
}
};
function replaceImage(image, imageDims, container, containerDims, ih, iw, left, top, diff, options) {
var element = image.data('nailthumb.replaceto');
var replaceto = findReplaceTo(element,options);
image.data('nailthumb.replacing',true);
image.load(function() {
image.data('nailthumb.replacing',null);
});
if (replaceto) {
replaceto.replaceWith(image);
} else {
element.append(image);
}
if (options.afterReplace) options.afterReplace(container, image, options);
showImage(image, imageDims, container, containerDims, ih, iw, left, top, diff, options);
};
function showImage(image, imageDims, container, containerDims, ih, iw, left, top, diff, options) {
if (options.replaceAnimation == 'animate') {
image.css('display','inline');
container.animate({
'width':containerDims.innerWidth,
'height':containerDims.innerHeight
},options.animationTime,options.animation);
image.animate({
'width':iw,
'height':ih,
'top':top,
'left':left
},options.animationTime,options.animation,function(){
afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options);
});
} else {
container.css({
'width':containerDims.innerWidth,
'height':containerDims.innerHeight
});
if (options.replaceAnimation) image.css('display','none');
image.css({
'width':iw,
'height':ih,
'top':top,
'left':left
});
if (options.replaceAnimation == 'fade') {
image.fadeIn(options.animationTime,options.animation,function(){
afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options);
});
} else if (options.replaceAnimation == 'slide') {
image.slideDown(options.animationTime,options.animation,function(){
afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options);
});
} else if (options.replaceAnimation && options.replaceAnimation instanceof Function) {
options.replaceAnimation(image,function(){
afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options);
},options);
if (!options.selfStartAfterAppear) {
afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options);
}
} else {
image.css('display','inline');
afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options);
}
}
};
function afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options) {
if (options.afterAppear) options.afterAppear(container, image, options);
image.data('nailthumb.replaceto',null);
decorate(image, imageDims, container, containerDims, ih, iw, left, top, diff, options);
};
function findReplaceTo(element,options) {
var rep = null;
element.find('img').each(function() {
if (!rep && !$(this).data('nailthumb.replaceto')) {
rep = $(this);
}
});
return rep;
};
function decorate(image, imageDims, container, containerDims, ih, iw, left, top, diff, options) {
if (options.title || (options.titleAttr && image.attr(options.titleAttr)) ) {
var title = options.title?options.title:image.attr(options.titleAttr);
if (title) {
var span = $(''+title+'');
if (containerDims.innerHeight>ih) span.css('top',containerDims.innerHeight-ih);
else span.css('top','0px');
container.append(span);
var tit = getHiddenDims(span);
var im = getHiddenDims(image);
debugObject('decorate containerDims',containerDims);
debugObject('decorate imageDims',imageDims);
debugObject('decorate imageDims',im);
debugObject('decorate tit',tit);
var outbound = containerDims.offsetTop+containerDims.innerHeight-tit.offsetTop;
if (containerDims.height>containerDims.innerHeight) {
outbound+=(containerDims.height-containerDims.innerHeight)/2
}
span.css('top','+='+outbound);
if (iw < tit.width) span.css('width',iw);
if (left > 0) span.css('left',left);
var delta = tit.height;
if (containerDims.innerHeight>ih && diff!='bottom') {
delta += (containerDims.innerHeight-ih)/((diff=='top')?1:2);
}
var clone = span.clone();
clone.css('width','auto').css('display','none').css('position','absolute');
container.append(clone);
var cloneDims = getHiddenDims(clone);
clone.remove();
debugObject('decorate cloneDims',cloneDims);
if (options.titleWhen=='hover') {
container.unbind('mouseenter mouseleave').hover(function(){
span.find('span.'+options.titleScrollerClass).css('left',0);
containerDims = getHiddenDims(container);
tit = getHiddenDims(span);
outbound = containerDims.offsetTop+containerDims.innerHeight-tit.offsetTop;
if (containerDims.height>containerDims.innerHeight) {
outbound+=(containerDims.height-containerDims.innerHeight)/2
}
debugObject('decorate hover tit',tit);
debug('decorate hover outbound',tit);
var doubleDelta = 0;
if (outbound<0) {
span.css('top','+='+outbound);
doubleDelta = delta;
} else {
doubleDelta = delta-outbound;
}
if(options.animateTitle) {
resetScrollTitle(span,options);
span.stop(true).animate({
top:'-='+doubleDelta
},options.titleAnimationTime,options.titleAnimation,function(){
scrollTitle(span, cloneDims.width, containerDims.innerWidth, options);
});
} else {
span.css({
top:'-='+doubleDelta
});
scrollTitle(span, cloneDims.width, containerDims.innerWidth, options);
}
},function(){
if(options.animateTitle) {
resetScrollTitle(span,options);
span.animate({
top:'+='+delta
},options.titleAnimationTime,options.titleAnimation,function(){
resetScrollTitle(span,options);
});
} else {
resetScrollTitle(span,options);
span.css({
top:'+='+delta
});
}
});
} else {
if(options.animateTitle) {
span.animate({
top:'-='+delta
},options.titleAnimationTime,options.titleAnimation,function(){
scrollTitle(span, cloneDims.width, containerDims.innerWidth, options);
});
} else {
span.css({
top:'-='+delta
});
scrollTitle(span, cloneDims.width, containerDims.innerWidth, options);
}
}
}
}
if (options.onFinish) options.onFinish(container,options);
if (options.loadingClass) container.removeClass(options.loadingClass);
image.data('nailthumb.working',null);
};
function resetScrollTitle(span,options) {
span.find('span.'+options.titleScrollerClass).stop();
};
function scrollTitle(span, width, visibleWidth, options) {
if (width > visibleWidth && options.titleScrolling) {
if (span.find('span.'+options.titleScrollerClass).length==0) {
span.wrapInner('');
span.find('span.'+options.titleScrollerClass).width(width).css('position','relative').css('white-space','nowrap');
}
span.find('span.'+options.titleScrollerClass).css('left',0);
setTimeout(scrollFunction(span, width, visibleWidth, options),1000);
}
};
function scrollFunction(span, width, visibleWidth, options) {
return function() {
var indent = Number(span.find('span.'+options.titleScrollerClass).css('left').replace(/[^-\d]/g,''));
debug('indent',indent);
debug('width',width);
debug('visibleWidth',visibleWidth);
debug('width <= -indent',(width <= -indent));
var delta = width + indent;
if (delta <= 0) {
span.find('span.'+options.titleScrollerClass).css('left',visibleWidth);
delta = width + visibleWidth;
}
delta += 10;
span.find('span.'+options.titleScrollerClass).animate({
'left':'-='+delta
},width*1000/30,'linear',scrollFunction(span, width, visibleWidth, options));
};
};
function getProportion(containerDims, imageDims, options) {
if (options.proportions != null && options.proportions > 0) {
return options.proportions;
} else {
var prop = containerDims.innerWidth/imageDims.width;
if (options.method && options.method=='resize') {
if (containerDims.innerHeight/imageDims.height < prop) {
prop = containerDims.innerHeight/imageDims.height;
}
} else {
if (containerDims.innerHeight/imageDims.height > prop) {
prop = containerDims.innerHeight/imageDims.height;
}
}
if (options.maxEnlargement && options.maxEnlargement < prop) prop = options.maxEnlargement;
if (options.maxShrink && options.maxShrink > prop) prop = options.maxShrink;
return prop;
}
};
function getDirections(option) {
var dir = {
h:'center',
v:'center'
};
if (option) {
var opts = option.split(' ');
if (opts.length > 0) {
dir = getDirection(opts[0],dir);
}
if (opts.length > 1) {
dir = getDirection(opts[1],dir);
}
}
return dir;
};
function getDirection(str,d) {
switch (str) {
case 'top':
d.v = 'top';
break;
case 'bottom':
d.v = 'bottom';
break;
case 'left':
d.h = 'left';
break;
case 'right':
d.h = 'right';
break;
default:
break;
}
return d;
};
function getImageDims(image,options) {
var imageDims;
if (!image.data('nailthumb.originalImageDims') ) {
imageDims = getHiddenDims(image);
image.data('nailthumb.originalImageDims',imageDims);
if (!options.keepImageDimensions) {
image.one('load',function(){
image.data('nailthumb.originalImageDims',null);
});
}
} else {
imageDims = image.data('nailthumb.originalImageDims');
}
return imageDims;
};
function getContainerDims(container,options) {
var containerDims = getHiddenDims(container)
if (options.width) containerDims.innerWidth = options.width;
if (options.height) containerDims.innerHeight = options.height;
return containerDims;
};
function getDims(elem) {
var offset = $(elem).offset();
return {
offsetTop: offset.top,
offsetLeft: offset.left,
width: $(elem).outerWidth(),
height: $(elem).outerHeight(),
innerWidth: $(elem).innerWidth(),
innerHeight: $(elem).innerHeight()
};
};
function getHiddenDims(elems) {
var dims = null, i = 0, offset, elem;
while ((elem = elems[i++])) {
var hiddenElems = $(elem).parents().andSelf().filter(':hidden');
if ( ! hiddenElems.length ) {
dims = getDims(elem);
} else {
var backupStyle = [];
hiddenElems.each( function() {
var style = $(this).attr('style');
style = typeof style == 'undefined'? '': style;
backupStyle.push( style );
$(this).attr( 'style', style + ' display: block !important;' );
});
hiddenElems.eq(0).css( 'left', -10000 );
dims = getDims(elem);
hiddenElems.each( function() {
$(this).attr( 'style', backupStyle.shift() );
});
}
}
return dims;
};
function getHiddenCloneDims(elems) {
var dims = null, i = 0, offset, elem;
while ((elem = elems[i++])) {
var hiddenElems = $(elem).parents().andSelf().filter(':hidden');
if ( ! hiddenElems.length ) {
dims = getDims(elem);
} else {
var backupStyle = [];
hiddenElems.each( function() {
var style = $(this).attr('style');
style = typeof style == 'undefined'? '': style;
backupStyle.push( style );
$(this).attr( 'style', style + ' display: block !important;' );
});
hiddenElems.eq(0).css( 'left', -10000 );
var clone = hiddenElems.eq(0).clone();
$('body').append(clone);
dims = getDims(clone);
hiddenElems.each( function() {
$(this).attr( 'style', backupStyle.shift() );
});
clone.remove();
}
}
return dims;
};
$.fn.nailthumb.evalServerSideParams = function(image,container,options) {
if (options.serverSideParams) {
var params = {};
if (!options.serverSideParams.noServerResize) {
var w = null, h = null;
if (options.serverSideParams.width) w = options.serverSideParams.width;
else if (options.width) w = options.width;
if (options.serverSideParams.height) h = options.serverSideParams.height;
else if (options.height) h = options.height;
if (!(w && h)) {
resetContainer(container,options);
var containerDims = getContainerDims(container,options);
w = containerDims.innerWidth;
h = containerDims.innerHeight;
}
if (w && h) {
params.w = w;
params.h = h;
if (options.serverSideParams.mode!='resize') {
if (options.method=='crop') params.mode = 'crop';
if (options.serverSideParams.mode) params.mode = options.serverSideParams.mode;
}
}
}
$.each(options.serverSideParams, function(key,val) {
if (key!='width' && key!='height' && key!='mode' && key!='noServerResize' && val) {
params[key]=val;
}
});
var pars = "";
$.each(params, function(key,val) {
pars+=";"+key+"="+val;
});
debug(pars,params);
return pars;
} else {
return "";
}
};
$.fn.nailthumb.setServerSideParams = function(image,container,options) {
if (options.serverSideParams) {
var url = image.attr("src");
if (image.data('nailthumb.originalImageUrl')) {
url = image.data('nailthumb.originalImageUrl');
}
image.data('nailthumb.originalImageUrl',url);
var pars = $.fn.nailthumb.evalServerSideParams(image,container,options);
url += pars;
image.attr("src",url);
}
};
$.fn.nailthumb.toggleDebug = function() {
DEBUG = !DEBUG;
};
$.fn.nailthumb.doThumb = function(image,container,options) {
doThumb(image,container,options);
};
$.fn.nailthumb.defaults = {
onStart: null,
onFinish: null,
loadingClass: 'nailthumb-loading',
imageUrl: null,
imageFromWrappingLink: false,
imageCustomFinder: null/*function(element,options){
return null;
}*/,
imageClass:'nailthumb-image',
afterReplace: null,
afterAppear: null,
replaceAnimation: 'fade',
selfStartAfterAppear: false,
animationTime: 1000,
animation: 'swing',
keepImageDimensions: false,
method: 'crop',
fitDirection: null,
proportions: null,
ifImageAddContainer: true,
containerClass: 'nailthumb-container',
maxEnlargement: null,
maxShrink: null,
preload: true,
nostyle: false,
width: null,
height: null,
title: null,
titleClass: 'nailthumb-title',
titleAttr: 'title',
titleWhen: 'hover',
titleScrolling: true,
titleScrollerClass: 'nailthumb-title-scroller',
animateTitle: true,
titleAnimationTime: 500,
titleAnimation: 'swing',
serverSideParams: null
};
function log(log, jQueryobj) {
try {
debug(log, jQueryobj, true);
} catch(ex) {}
};
function debug(log, jQueryobj, force) {
try {
if ((DEBUG && window.console && window.console.log) || force)
window.console.log(log + ': ' + jQueryobj);
} catch(ex) {}
};
function debugObject(log, jQueryobj, force) {
try {
if (!jQueryobj) jQueryobj=log;
debug(log, jQueryobj);
if ((DEBUG && window.console && window.console.log) || force)
window.console.debug(jQueryobj);
} catch(ex) {}
};
})(jQuery);