1/* jQuery NailThumb Plugin - any image to any thumbnail 2 * Examples and documentation at: http://www.garralab.com/nailthumb.php 3 * Copyright (C) 2012 [email protected] 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18(function($) { 19 var DEBUG = false; 20 var version = '1.1'; 21 $.fn.nailthumb = function(options) { 22 var opts = $.extend({}, $.fn.nailthumb.defaults, options); 23 return this.each(function() { 24 var $this = $(this); 25 var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts; 26 thumbize($this,o) 27 }); 28 }; 29 function thumbize(element,options) { 30 var image = setImage(element,options); 31 var container = setContainer(element,options); 32 if (options.serverSideParams) { 33 $.fn.nailthumb.setServerSideParams(image,container,options); 34 } 35 debugObject('image',image); 36 debugObject('container',container); 37 if (options.onStart) options.onStart(container,options); 38 if (options.loadingClass) container.addClass(options.loadingClass); 39 40 if (options.preload || image.data('nailthumb.replaceto')) { 41 debug('wait on load'); 42 image.one('load',function() { 43 debugObject('before check',image); 44 if(!image.data('nailthumb.working') && !image.data('nailthumb.replacing')) { 45 image.data('nailthumb.working',true); 46 debugObject('inside check',image); 47 doThumb(image,container,options); 48 } 49 }); 50 var src = image.attr('src'); 51 image.attr('src',null).attr('src',src); 52 } else { 53 debug('nail thumb directly'); 54 image.data('nailthumb.working',true); 55 doThumb(image,container,options); 56 } 57 }; 58 function doThumb(image,container,options) { 59 resetImage(image,options); 60 resetContainer(container,options); 61 var imageDims = getImageDims(image,options); 62 debugObject('image',image); 63 debugObject('imageDims',imageDims); 64 if (imageDims.width==0 || imageDims.height==0) { 65 imageDims = getHiddenCloneDims(image); 66 debugObject('imageCloneDims',imageDims); 67 } 68 var containerDims = getContainerDims(container,options); 69 debugObject('container',container); 70 debugObject('containerDims',containerDims); 71 var prop = getProportion(containerDims,imageDims,options); 72 debug('proportions',prop); 73 resize(image, imageDims, container, containerDims, prop, options); 74 75 }; 76 function setImage(element,options) { 77 var image = element.find('img').first(); 78 var finder = options.imageCustomFinder; 79 if (!finder && options.imageUrl) { 80 finder = imageUrlFinder; 81 } else if(!finder && options.imageFromWrappingLink) { 82 finder = imageFromWrappingLinkFinder; 83 } 84 if (finder) { 85 var img = finder(element,options); 86 debugObject('finder',img); 87 if (!img) img = []; 88 if (img.length>0) { 89 image = img; 90 image.css('display','none'); 91 if(!image.data('nailthumb.replaceto')) image.data('nailthumb.replaceto',element); 92 image.data('nailthumb.originalImageDims',null); 93 } 94 } 95 if (image.length==0) { 96 if (element.is('img')) image = element; 97 } 98 99 return image; 100 }; 101 function imageUrlFinder(element,options) { 102 var image = $('<img />').attr('src',options.imageUrl).css('display','none').data('nailthumb.replaceto',element); 103 element.append(image); 104 return image; 105 }; 106 function imageFromWrappingLinkFinder(element,options) { 107 var image; 108 var link = element.find('a').first(); 109 if (link.length==0 && element.is('a')) { 110 link = element; 111 } 112 if (link.attr('href')) { 113 image = $('<img />').attr('src',link.attr('href')).css('display','none').data('nailthumb.replaceto',link); 114 if (link.attr('title')) image.attr('title',link.attr('title')); 115 link.append(image); 116 } 117 return image; 118 }; 119 function resetImage(image,options) { 120 if (!options.nostyle) { 121 image.css({ 122 'position':'relative' 123 }); 124 } 125 if (!image.data('nailthumb.originalImageDims')) { 126 image.css({ 127 'width':'auto', 128 'height':'auto', 129 'top':0, 130 'left':0 131 }).removeAttr('width') 132 .removeAttr('height'); 133 } 134 }; 135 function setContainer(element,options) { 136 var container = element; 137 if (element.is('img')) { 138 if (options.ifImageAddContainer) { 139 var c = $('<div></div>'); 140 element.wrap(c); 141 } 142 container = element.parent(); 143 } 144 return container; 145 }; 146 function resetContainer(container,options) { 147 if (options.containerClass) container.addClass(options.containerClass); 148 if (!options.nostyle) { 149 container.css({ 150 'overflow':'hidden', 151 'padding':'0px' 152 }); 153 } 154 155 if (options.replaceAnimation == 'animate') { 156 if (options.width || options.height) { 157 container.animate({ 158 'width':options.width, 159 'height':options.height 160 },options.animationTime,options.animation); 161 } 162 } else { 163 if (options.width) container.width(options.width); 164 if (options.height) container.height(options.height); 165 } 166 167 container.find('span.'+options.titleClass).remove(); 168 }; 169 function resize(image, imageDims, container, containerDims, prop, options) { 170 var iw = imageDims.width * prop; 171 var ih = imageDims.height * prop; 172 var top = 0, left = 0, diff; 173 var direction = getDirections(options.fitDirection); 174 if (ih<containerDims.innerHeight) { 175 switch (direction.v) { 176 case 'center': 177 top=-(ih-containerDims.innerHeight)/2; 178 break; 179 case 'bottom': 180 top=-(ih-containerDims.innerHeight); 181 diff='bottom'; 182 break; 183 case 'top': 184 top=0; 185 diff='top'; 186 break; 187 default: 188 break; 189 } 190 } else if (ih>containerDims.innerHeight) { 191 switch (direction.v) { 192 case 'center': 193 top=-(ih-containerDims.innerHeight)/2; 194 break; 195 case 'bottom': 196 top=-(ih-containerDims.innerHeight); 197 break; 198 default: 199 break; 200 } 201 } 202 if (iw<containerDims.innerWidth) { 203 switch (direction.h) { 204 case 'center': 205 left=-(iw-containerDims.innerWidth)/2; 206 break; 207 case 'right': 208 left=-(iw-containerDims.innerWidth); 209 break; 210 default: 211 break; 212 } 213 } else if (iw>containerDims.innerWidth) { 214 switch (direction.h) { 215 case 'center': 216 left=-(iw-containerDims.innerWidth)/2; 217 break; 218 case 'right': 219 left=-(iw-containerDims.innerWidth); 220 break; 221 default: 222 break; 223 } 224 } 225 image.addClass(options.imageClass); 226 if (image.data('nailthumb.replaceto')) { 227 replaceImage(image, imageDims, container, containerDims, ih, iw, left, top, diff, options); 228 } else { 229 showImage(image, imageDims, container, containerDims, ih, iw, left, top, diff, options); 230 } 231 }; 232 function replaceImage(image, imageDims, container, containerDims, ih, iw, left, top, diff, options) { 233 var element = image.data('nailthumb.replaceto'); 234 var replaceto = findReplaceTo(element,options); 235 image.data('nailthumb.replacing',true); 236 image.load(function() { 237 image.data('nailthumb.replacing',null); 238 }); 239 if (replaceto) { 240 replaceto.replaceWith(image); 241 } else { 242 element.append(image); 243 } 244 if (options.afterReplace) options.afterReplace(container, image, options); 245 showImage(image, imageDims, container, containerDims, ih, iw, left, top, diff, options); 246 }; 247 function showImage(image, imageDims, container, containerDims, ih, iw, left, top, diff, options) { 248 249 if (options.replaceAnimation == 'animate') { 250 image.css('display','inline'); 251 container.animate({ 252 'width':containerDims.innerWidth, 253 'height':containerDims.innerHeight 254 },options.animationTime,options.animation); 255 image.animate({ 256 'width':iw, 257 'height':ih, 258 'top':top, 259 'left':left 260 },options.animationTime,options.animation,function(){ 261 afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options); 262 }); 263 } else { 264 container.css({ 265 'width':containerDims.innerWidth, 266 'height':containerDims.innerHeight 267 }); 268 if (options.replaceAnimation) image.css('display','none'); 269 image.css({ 270 'width':iw, 271 'height':ih, 272 'top':top, 273 'left':left 274 }); 275 if (options.replaceAnimation == 'fade') { 276 image.fadeIn(options.animationTime,options.animation,function(){ 277 afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options); 278 }); 279 } else if (options.replaceAnimation == 'slide') { 280 image.slideDown(options.animationTime,options.animation,function(){ 281 afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options); 282 }); 283 } else if (options.replaceAnimation && options.replaceAnimation instanceof Function) { 284 options.replaceAnimation(image,function(){ 285 afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options); 286 },options); 287 if (!options.selfStartAfterAppear) { 288 afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options); 289 } 290 } else { 291 image.css('display','inline'); 292 afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options); 293 } 294 } 295 }; 296 function afterAppear(image, imageDims, container, containerDims, ih, iw, left, top, diff, options) { 297 if (options.afterAppear) options.afterAppear(container, image, options); 298 image.data('nailthumb.replaceto',null); 299 decorate(image, imageDims, container, containerDims, ih, iw, left, top, diff, options); 300 }; 301 function findReplaceTo(element,options) { 302 var rep = null; 303 element.find('img').each(function() { 304 if (!rep && !$(this).data('nailthumb.replaceto')) { 305 rep = $(this); 306 } 307 }); 308 return rep; 309 }; 310 function decorate(image, imageDims, container, containerDims, ih, iw, left, top, diff, options) { 311 if (options.title || (options.titleAttr && image.attr(options.titleAttr)) ) { 312 var title = options.title?options.title:image.attr(options.titleAttr); 313 if (title) { 314 var span = $('<span class="'+options.titleClass+'">'+title+'</span>'); 315 if (containerDims.innerHeight>ih) span.css('top',containerDims.innerHeight-ih); 316 else span.css('top','0px'); 317 container.append(span); 318 var tit = getHiddenDims(span); 319 var im = getHiddenDims(image); 320 debugObject('decorate containerDims',containerDims); 321 debugObject('decorate imageDims',imageDims); 322 debugObject('decorate imageDims',im); 323 debugObject('decorate tit',tit); 324 var outbound = containerDims.offsetTop+containerDims.innerHeight-tit.offsetTop; 325 if (containerDims.height>containerDims.innerHeight) { 326 outbound+=(containerDims.height-containerDims.innerHeight)/2 327 } 328 span.css('top','+='+outbound); 329 330 if (iw < tit.width) span.css('width',iw); 331 if (left > 0) span.css('left',left); 332 333 var delta = tit.height; 334 if (containerDims.innerHeight>ih && diff!='bottom') { 335 delta += (containerDims.innerHeight-ih)/((diff=='top')?1:2); 336 } 337 338 var clone = span.clone(); 339 clone.css('width','auto').css('display','none').css('position','absolute'); 340 container.append(clone); 341 var cloneDims = getHiddenDims(clone); 342 clone.remove(); 343 debugObject('decorate cloneDims',cloneDims); 344 345 if (options.titleWhen=='hover') { 346 container.unbind('mouseenter mouseleave').hover(function(){ 347 span.find('span.'+options.titleScrollerClass).css('left',0); 348 containerDims = getHiddenDims(container); 349 tit = getHiddenDims(span); 350 outbound = containerDims.offsetTop+containerDims.innerHeight-tit.offsetTop; 351 if (containerDims.height>containerDims.innerHeight) { 352 outbound+=(containerDims.height-containerDims.innerHeight)/2 353 } 354 debugObject('decorate hover tit',tit); 355 debug('decorate hover outbound',tit); 356 var doubleDelta = 0; 357 if (outbound<0) { 358 span.css('top','+='+outbound); 359 doubleDelta = delta; 360 } else {
361 doubleDelta = delta-outbound; 362 } 363 if(options.animateTitle) { 364 resetScrollTitle(span,options); 365 span.stop(true).animate({ 366 top:'-='+doubleDelta 367 },options.titleAnimationTime,options.titleAnimation,function(){ 368 scrollTitle(span, cloneDims.width, containerDims.innerWidth, options); 369 }); 370 } else { 371 span.css({ 372 top:'-='+doubleDelta 373 }); 374 scrollTitle(span, cloneDims.width, containerDims.innerWidth, options); 375 } 376 },function(){ 377 if(options.animateTitle) { 378 resetScrollTitle(span,options); 379 span.animate({ 380 top:'+='+delta 381 },options.titleAnimationTime,options.titleAnimation,function(){ 382 resetScrollTitle(span,options); 383 }); 384 } else { 385 resetScrollTitle(span,options); 386 span.css({ 387 top:'+='+delta 388 }); 389 } 390 }); 391 } else { 392 if(options.animateTitle) { 393 span.animate({ 394 top:'-='+delta 395 },options.titleAnimationTime,options.titleAnimation,function(){ 396 scrollTitle(span, cloneDims.width, containerDims.innerWidth, options); 397 }); 398 } else { 399 span.css({ 400 top:'-='+delta 401 }); 402 scrollTitle(span, cloneDims.width, containerDims.innerWidth, options); 403 } 404 } 405 } 406 } 407 if (options.onFinish) options.onFinish(container,options); 408 if (options.loadingClass) container.removeClass(options.loadingClass); 409 image.data('nailthumb.working',null); 410 }; 411 function resetScrollTitle(span,options) { 412 span.find('span.'+options.titleScrollerClass).stop(); 413 }; 414 function scrollTitle(span, width, visibleWidth, options) { 415 if (width > visibleWidth && options.titleScrolling) { 416 if (span.find('span.'+options.titleScrollerClass).length==0) { 417 span.wrapInner('<span class="'+options.titleScrollerClass+'" />'); 418 span.find('span.'+options.titleScrollerClass).width(width).css('position','relative').css('white-space','nowrap'); 419 } 420 span.find('span.'+options.titleScrollerClass).css('left',0); 421 setTimeout(scrollFunction(span, width, visibleWidth, options),1000); 422 } 423 }; 424 function scrollFunction(span, width, visibleWidth, options) { 425 return function() { 426 var indent = Number(span.find('span.'+options.titleScrollerClass).css('left').replace(/[^-\d]/g,'')); 427 debug('indent',indent); 428 debug('width',width); 429 debug('visibleWidth',visibleWidth); 430 debug('width <= -indent',(width <= -indent)); 431 var delta = width + indent; 432 if (delta <= 0) { 433 span.find('span.'+options.titleScrollerClass).css('left',visibleWidth); 434 delta = width + visibleWidth; 435 } 436 delta += 10; 437 span.find('span.'+options.titleScrollerClass).animate({ 438 'left':'-='+delta 439 },width*1000/30,'linear',scrollFunction(span, width, visibleWidth, options)); 440 }; 441 }; 442 function getProportion(containerDims, imageDims, options) { 443 if (options.proportions != null && options.proportions > 0) { 444 return options.proportions; 445 } else { 446 var prop = containerDims.innerWidth/imageDims.width; 447 if (options.method && options.method=='resize') { 448 if (containerDims.innerHeight/imageDims.height < prop) { 449 prop = containerDims.innerHeight/imageDims.height; 450 } 451 } else { 452 if (containerDims.innerHeight/imageDims.height > prop) { 453 prop = containerDims.innerHeight/imageDims.height; 454 } 455 } 456 if (options.maxEnlargement && options.maxEnlargement < prop) prop = options.maxEnlargement; 457 if (options.maxShrink && options.maxShrink > prop) prop = options.maxShrink; 458 return prop; 459 } 460 }; 461 function getDirections(option) { 462 var dir = { 463 h:'center', 464 v:'center' 465 }; 466 if (option) { 467 var opts = option.split(' '); 468 if (opts.length > 0) { 469 dir = getDirection(opts[0],dir); 470 } 471 if (opts.length > 1) { 472 dir = getDirection(opts[1],dir); 473 } 474 } 475 return dir; 476 }; 477 function getDirection(str,d) { 478 switch (str) { 479 case 'top': 480 d.v = 'top'; 481 break; 482 case 'bottom': 483 d.v = 'bottom'; 484 break; 485 case 'left': 486 d.h = 'left'; 487 break; 488 case 'right': 489 d.h = 'right'; 490 break; 491 default: 492 break; 493 } 494 return d; 495 }; 496 function getImageDims(image,options) { 497 var imageDims; 498 if (!image.data('nailthumb.originalImageDims') ) { 499 imageDims = getHiddenDims(image); 500 image.data('nailthumb.originalImageDims',imageDims); 501 if (!options.keepImageDimensions) { 502 image.one('load',function(){ 503 image.data('nailthumb.originalImageDims',null); 504 }); 505 } 506 } else { 507 imageDims = image.data('nailthumb.originalImageDims'); 508 } 509 return imageDims; 510 }; 511 function getContainerDims(container,options) { 512 var containerDims = getHiddenDims(container) 513 if (options.width) containerDims.innerWidth = options.width; 514 if (options.height) containerDims.innerHeight = options.height; 515 return containerDims; 516 }; 517 function getDims(elem) { 518 var offset = $(elem).offset(); 519 return { 520 offsetTop: offset.top, 521 offsetLeft: offset.left, 522 width: $(elem).outerWidth(), 523 height: $(elem).outerHeight(), 524 innerWidth: $(elem).innerWidth(), 525 innerHeight: $(elem).innerHeight() 526 }; 527 }; 528 function getHiddenDims(elems) { 529 var dims = null, i = 0, offset, elem; 530 531 while ((elem = elems[i++])) { 532 var hiddenElems = $(elem).parents().andSelf().filter(':hidden'); 533 if ( ! hiddenElems.length ) { 534 dims = getDims(elem); 535 } else { 536 var backupStyle = []; 537 hiddenElems.each( function() { 538 var style = $(this).attr('style'); 539 style = typeof style == 'undefined'? '': style; 540 backupStyle.push( style ); 541 $(this).attr( 'style', style + ' display: block !important;' ); 542 }); 543 544 hiddenElems.eq(0).css( 'left', -10000 ); 545 546 dims = getDims(elem); 547 548 hiddenElems.each( function() { 549 $(this).attr( 'style', backupStyle.shift() ); 550 }); 551 } 552 553 } 554 555 return dims; 556 }; 557 function getHiddenCloneDims(elems) { 558 var dims = null, i = 0, offset, elem; 559 560 while ((elem = elems[i++])) { 561 var hiddenElems = $(elem).parents().andSelf().filter(':hidden'); 562 if ( ! hiddenElems.length ) { 563 dims = getDims(elem); 564 } else { 565 var backupStyle = []; 566 hiddenElems.each( function() { 567 var style = $(this).attr('style'); 568 style = typeof style == 'undefined'? '': style; 569 backupStyle.push( style ); 570 $(this).attr( 'style', style + ' display: block !important;' ); 571 }); 572 573 hiddenElems.eq(0).css( 'left', -10000 ); 574 575 var clone = hiddenElems.eq(0).clone(); 576 $('body').append(clone); 577 578 dims = getDims(clone); 579 580 hiddenElems.each( function() { 581 $(this).attr( 'style', backupStyle.shift() ); 582 }); 583 clone.remove(); 584 } 585 586 } 587 588 return dims; 589 }; 590 $.fn.nailthumb.evalServerSideParams = function(image,container,options) { 591 if (options.serverSideParams) { 592 var params = {}; 593 if (!options.serverSideParams.noServerResize) { 594 var w = null, h = null; 595 if (options.serverSideParams.width) w = options.serverSideParams.width; 596 else if (options.width) w = options.width; 597 if (options.serverSideParams.height) h = options.serverSideParams.height; 598 else if (options.height) h = options.height; 599 if (!(w && h)) { 600 resetContainer(container,options); 601 var containerDims = getContainerDims(container,options); 602 w = containerDims.innerWidth; 603 h = containerDims.innerHeight; 604 } 605 if (w && h) { 606 params.w = w; 607 params.h = h; 608 if (options.serverSideParams.mode!='resize') { 609 if (options.method=='crop') params.mode = 'crop'; 610 if (options.serverSideParams.mode) params.mode = options.serverSideParams.mode; 611 } 612 } 613 } 614 615 $.each(options.serverSideParams, function(key,val) { 616 if (key!='width' && key!='height' && key!='mode' && key!='noServerResize' && val) { 617 params[key]=val; 618 } 619 }); 620 var pars = ""; 621 $.each(params, function(key,val) { 622 pars+=";"+key+"="+val; 623 }); 624 debug(pars,params); 625 return pars; 626 } else { 627 return ""; 628 } 629 }; 630 $.fn.nailthumb.setServerSideParams = function(image,container,options) { 631 if (options.serverSideParams) { 632 var url = image.attr("src"); 633 if (image.data('nailthumb.originalImageUrl')) { 634 url = image.data('nailthumb.originalImageUrl'); 635 } 636 image.data('nailthumb.originalImageUrl',url); 637 var pars = $.fn.nailthumb.evalServerSideParams(image,container,options); 638 url += pars; 639 image.attr("src",url); 640 } 641 }; 642 $.fn.nailthumb.toggleDebug = function() { 643 DEBUG = !DEBUG; 644 }; 645 $.fn.nailthumb.doThumb = function(image,container,options) { 646 doThumb(image,container,options); 647 }; 648 $.fn.nailthumb.defaults = { 649 onStart: null, 650 onFinish: null, 651 loadingClass: 'nailthumb-loading', 652 imageUrl: null, 653 imageFromWrappingLink: false, 654 imageCustomFinder: null/*function(element,options){ 655 return null; 656 }*/, 657 imageClass:'nailthumb-image', 658 afterReplace: null, 659 afterAppear: null, 660 replaceAnimation: 'fade', 661 selfStartAfterAppear: false, 662 animationTime: 1000, 663 animation: 'swing', 664 keepImageDimensions: false, 665 method: 'crop', 666 fitDirection: null, 667 proportions: null, 668 ifImageAddContainer: true, 669 containerClass: 'nailthumb-container', 670 maxEnlargement: null, 671 maxShrink: null, 672 preload: true, 673 nostyle: false, 674 width: null, 675 height: null, 676 title: null, 677 titleClass: 'nailthumb-title', 678 titleAttr: 'title', 679 titleWhen: 'hover', 680 titleScrolling: true, 681 titleScrollerClass: 'nailthumb-title-scroller', 682 animateTitle: true, 683 titleAnimationTime: 500, 684 titleAnimation: 'swing', 685 serverSideParams: null 686 }; 687 function log(log, jQueryobj) { 688 try { 689 debug(log, jQueryobj, true); 690 } catch(ex) {} 691 }; 692 function debug(log, jQueryobj, force) { 693 try { 694 if ((DEBUG && window.console && window.console.log) || force) 695 window.console.log(log + ': ' + jQueryobj); 696 } catch(ex) {} 697 }; 698 function debugObject(log, jQueryobj, force) { 699 try { 700 if (!jQueryobj) jQueryobj=log; 701 debug(log, jQueryobj); 702 if ((DEBUG && window.console && window.console.log) || force) 703 window.console.debug(jQueryobj); 704 } catch(ex) {} 705 }; 706})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.