1/** 2 * Copyright (c) 2010 Anders Ekdahl (http://coffeescripter.com/) 3 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 4 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 5 * 6 * Version: 1.2.4 7 * 8 * Demo and documentation: http://coffeescripter.com/code/ad-gallery/ 9 */ 10(function($) { 11 $.fn.adGallery = function(options) { 12 var defaults = { loader_image: '/loader.gif', 13 start_at_index: 0, 14 description_wrapper: false, 15 thumb_opacity: 1, 16 animate_first_image: false, 17 animation_speed: 1200, 18 width: false, 19 height: false, 20 display_next_and_prev: true, 21 display_back_and_forward: true, 22 scroll_jump: 0, // If 0, it jumps the width of the container 23 slideshow: { 24 enable: true, 25 autostart: false, 26 speed: 8000, 27 start_label: 'Start', 28 stop_label: 'Stop', 29 stop_on_scroll: true, 30 countdown_prefix: '(', 31 countdown_sufix: ')', 32 onStart: false, 33 onStop: false 34 }, 35 effect: 'slide-hori', // or 'slide-vert', 'fade', or 'resize', 'none' 36 enable_keyboard_move: true, 37 cycle: true, 38 callbacks: { 39 init: false, 40 afterImageVisible: false, 41 beforeImageVisible: false 42 } 43 }; 44 var settings = $.extend(false, defaults, options); 45 if(options && options.slideshow) { 46 settings.slideshow = $.extend(false, defaults.slideshow, options.slideshow); 47 }; 48 if(!settings.slideshow.enable) { 49 settings.slideshow.autostart = false;
50 }; 51 var galleries = []; 52 $(this).each(function() { 53 var gallery = new AdGallery(this, settings); 54 galleries[galleries.length] = gallery; 55 }); 56 // Sorry, breaking the jQuery chain because the gallery instances 57 // are returned so you can fiddle with them 58 return galleries; 59 }; 60 61 function VerticalSlideAnimation(img_container, direction, desc) { 62 var current_top = parseInt(img_container.css('top'), 10); 63 if(direction == 'left') { 64 var old_image_top = '-'+ this.image_wrapper_height +'px'; 65 img_container.css('top', this.image_wrapper_height +'px'); 66 } else { 67 var old_image_top = this.image_wrapper_height +'px'; 68 img_container.css('top', '-'+ this.image_wrapper_height +'px'); 69 }; 70 /* 71 if(desc) { 72 desc.css('bottom', '-'+ desc[0].offsetHeight +'px'); 73 desc.animate({bottom: 0}, this.settings.animation_speed * 2); 74 }; 75 */ 76 if(this.current_description) { 77 //this.current_description.animate({bottom: '-'+ this.current_description[0].offsetHeight +'px'}, this.settings.animation_speed * 2); 78 }; 79 return {old_image: {top: old_image_top}, 80 new_image: {top: current_top}}; 81 }; 82 83 function HorizontalSlideAnimation(img_container, direction, desc) { 84 var current_left = parseInt(img_container.css('left'), 10); 85 if(direction == 'left') { 86 var old_image_left = '-'+ this.image_wrapper_width +'px'; 87 //img_container.css('left',this.image_wrapper_width +'px'); 88 } else { 89 var old_image_left = this.image_wrapper_width +'px'; 90 //img_container.css('left','-'+ this.image_wrapper_width +'px'); 91 }; 92 /* 93 if(desc) { 94 desc.css('bottom', '-'+ desc[0].offsetHeight +'px'); 95 desc.animate({bottom: 0}, this.settings.animation_speed * 2); 96 }; 97 */ 98 if(this.current_description) { 99 //this.current_description.animate({bottom: '-'+ this.current_description[0].offsetHeight +'px'}, this.settings.animation_speed * 2); 100 }; 101 return {old_image: {left: old_image_left}, 102 new_image: {left: current_left}}; 103 }; 104 105 function ResizeAnimation(img_container, direction, desc) { 106 /* 107 var image_width = img_container.width(); 108 var image_height = img_container.height(); 109 var current_left = parseInt(img_container.css('left'), 10); 110 var current_top = parseInt(img_container.css('top'), 10); 111 img_container.css({width: 0, height: 0, top: this.image_wrapper_height / 2, left: this.image_wrapper_width / 2}); 112 return {old_image: {width: 0, 113 height: 0, 114 top: this.image_wrapper_height / 2, 115 left: this.image_wrapper_width / 2}, 116 new_image: {width: image_width, 117 height: image_height, 118 top: current_top, 119 left: current_left}}; 120 */ 121 }; 122 123 function FadeAnimation(img_container, direction, desc) { 124 img_container.css('opacity', 0); 125 return {old_image: {opacity: 0}, 126 new_image: {opacity: 1}}; 127 }; 128 129 // Sort of a hack, will clean this up... eventually 130 function NoneAnimation(img_container, direction, desc) { 131 img_container.css('opacity', 0); 132 return {old_image: {opacity: 0}, 133 new_image: {opacity: 1}, 134 speed: 0}; 135 }; 136 137 function AdGallery(wrapper, settings) { 138 this.init(wrapper, settings); 139 }; 140 AdGallery.prototype = { 141 // Elements 142 wrapper: false, 143 image_wrapper: false, 144 gallery_info: false, 145 nav: false, 146 loader: false, 147 preloads: false, 148 thumbs_wrapper: false, 149 scroll_back: false, 150 scroll_forward: false, 151 next_link: false, 152 prev_link: false, 153 154 slideshow: false, 155 image_wrapper_width: 0, 156 image_wrapper_height: 0, 157 current_index: 0, 158 current_image: false, 159 current_description: false, 160 nav_display_width: 0, 161 settings: false, 162 images: false, 163 in_transition: false, 164 animations: false, 165 init: function(wrapper, settings) { 166 var context = this; 167 this.wrapper = $(wrapper); 168 this.settings = settings; 169 this.setupElements(); 170 this.setupAnimations(); 171 if(this.settings.width) { 172 this.image_wrapper_width = this.settings.width; 173 this.image_wrapper.width(this.settings.width); 174 this.wrapper.width(this.settings.width); 175 } else { 176 this.image_wrapper_width = this.image_wrapper.width(); 177 }; 178 if(this.settings.height) { 179 this.image_wrapper_height = this.settings.height; 180 this.image_wrapper.height(this.settings.height); 181 } else { 182 this.image_wrapper_height = this.image_wrapper.height(); 183 }; 184 this.nav_display_width = this.nav.width(); 185 this.current_index = 0; 186 this.current_image = false;
187 this.current_description = false; 188 this.in_transition = false; 189 this.findImages(); 190 if(this.settings.display_next_and_prev) { 191 this.initNextAndPrev(); 192 }; 193 // The slideshow needs a callback to trigger the next image to be shown 194 // but we don't want to give it access to the whole gallery instance 195 var nextimage_callback = function(callback) { 196 return context.nextImage(callback); 197 }; 198 this.slideshow = new AdGallerySlideshow(nextimage_callback, this.settings.slideshow); 199 this.controls.append(this.slideshow.create()); 200 if(this.settings.slideshow.enable) { 201 this.slideshow.enable(); 202 } else { 203 this.slideshow.disable(); 204 }; 205 if(this.settings.display_back_and_forward) { 206 this.initBackAndForward(); 207 }; 208 if(this.settings.enable_keyboard_move) { 209 this.initKeyEvents(); 210 }; 211 var start_at = parseInt(this.settings.start_at_index, 10); 212 if(window.location.hash && window.location.hash.indexOf('#ad-image') === 0) { 213 start_at = window.location.hash.replace(/[^0-9]+/g, ''); 214 // Check if it's a number 215 if((start_at * 1) != start_at) { 216 start_at = this.settings.start_at_index; 217 }; 218 }; 219 220 this.loading(true); 221 this.showImage(start_at, 222 function() { 223 // We don't want to start the slideshow before the image has been 224 // displayed 225 if(context.settings.slideshow.autostart) { 226 context.preloadImage(start_at + 1); 227 context.slideshow.start(); 228 }; 229 } 230 ); 231 this.fireCallback(this.settings.callbacks.init); 232 }, 233 setupAnimations: function() { 234 this.animations = { 235 'slide-vert': VerticalSlideAnimation, 236 'slide-hori': HorizontalSlideAnimation, 237 'resize': ResizeAnimation, 238 'fade': FadeAnimation, 239 'none': NoneAnimation 240 }; 241 }, 242 setupElements: function() { 243 this.controls = this.wrapper.find('.ad-controls'); 244 this.gallery_info = $('<p class="ad-info"></p>'); 245 this.controls.append(this.gallery_info); 246 this.image_wrapper = this.wrapper.find('.ad-image-wrapper'); 247 this.image_wrapper.empty(); 248 this.nav = this.wrapper.find('.ad-nav'); 249 this.thumbs_wrapper = this.nav.find('.ad-thumbs'); 250 this.preloads = $('<div class="ad-preloads"></div>'); 251 this.loader = $('<img class="ad-loader" src="'+ this.settings.loader_image +'">'); 252 this.image_wrapper.append(this.loader); 253 this.loader.hide(); 254 $(document.body).append(this.preloads); 255 }, 256 loading: function(bool) { 257 if(bool) { 258 this.loader.show(); 259 } else { 260 this.loader.hide(); 261 }; 262 }, 263 addAnimation: function(name, fn) { 264 if($.isFunction(fn)) { 265 this.animations[name] = fn; 266 }; 267 }, 268 findImages: function() { 269 var context = this; 270 this.images = []; 271 var thumb_wrapper_width = 0; 272 var thumbs_loaded = 0; 273 var thumbs = this.thumbs_wrapper.find('a'); 274 var thumb_count = thumbs.length; 275 if(this.settings.thumb_opacity < 1) { 276 thumbs.find('img').css('opacity', this.settings.thumb_opacity); 277 }; 278 thumbs.each( 279 function(i) { 280 var link = $(this); 281 var image_src = link.attr('href'); 282 var thumb = link.find('img'); 283 // Check if the thumb has already loaded 284 if(!context.isImageLoaded(thumb[0])) { 285 thumb.load( 286 function() { 287 thumb_wrapper_width += this.parentNode.parentNode.offsetWidth; 288 thumbs_loaded++; 289 } 290 ); 291 } else{ 292 thumb_wrapper_width += thumb[0].parentNode.parentNode.offsetWidth; 293 thumbs_loaded++; 294 }; 295 link.addClass('ad-thumb'+ i); 296 link.click( 297 function() { 298 context.showImage(i); 299 context.slideshow.stop(); 300 return false; 301 } 302 ).hover( 303 function() { 304 if(!$(this).is('.ad-active') && context.settings.thumb_opacity < 1) { 305 $(this).find('img').fadeTo(300, 1); 306 }; 307 context.preloadImage(i); 308 }, 309 function() { 310 if(!$(this).is('.ad-active') && context.settings.thumb_opacity < 1) { 311 $(this).find('img').fadeTo(300, context.settings.thumb_opacity); 312 }; 313 } 314 ); 315 var link = false;
316 if(thumb.data('ad-link')) { 317 link = thumb.data('ad-link'); 318 } else if(thumb.attr('longdesc') && thumb.attr('longdesc').length) { 319 link = thumb.attr('longdesc'); 320 }; 321 var desc = false; 322 if(thumb.data('ad-desc')) { 323 desc = thumb.data('ad-desc'); 324 } else if(thumb.attr('alt') && thumb.attr('alt').length) { 325 desc = thumb.attr('alt'); 326 }; 327 var title = false; 328 if(thumb.data('ad-title')) { 329 title = thumb.data('ad-title'); 330 } else if(thumb.attr('title') && thumb.attr('title').length) { 331 title = thumb.attr('title'); 332 }; 333 context.images[i] = { thumb: thumb.attr('src'), image: image_src, error: false, 334 preloaded: false, desc: desc, title: title, size: false, 335 link: link }; 336 } 337 ); 338 // Wait until all thumbs are loaded, and then set the width of the ul 339 var inter = setInterval( 340 function() { 341 if(thumb_count == thumbs_loaded) { 342 thumb_wrapper_width -= 100; 343 var list = context.nav.find('.ad-thumb-list'); 344 list.css('width', thumb_wrapper_width +'px'); 345 var i = 1; 346 var last_height = list.height(); 347 while(i < 201) { 348 list.css('width', (thumb_wrapper_width + i) +'px'); 349 if(last_height != list.height()) { 350 break; 351 } 352 last_height = list.height(); 353 i++; 354 } 355 clearInterval(inter); 356 }; 357 }, 358 100 359 ); 360 }, 361 initKeyEvents: function() { 362 var context = this; 363 $(document).keydown( 364 function(e) { 365 if(e.keyCode == 39) { 366 // right arrow 367 context.nextImage(); 368 context.slideshow.stop(); 369 } else if(e.keyCode == 37) { 370 // left arrow 371 context.prevImage(); 372 context.slideshow.stop(); 373 }; 374 } 375 ); 376 }, 377 initNextAndPrev: function() { 378 this.next_link = $('<div class="ad-next"><div class="ad-next-image"></div></div>'); 379 this.prev_link = $('<div class="ad-prev"><div class="ad-prev-image"></div></div>'); 380 this.image_wrapper.append(this.next_link); 381 this.image_wrapper.append(this.prev_link); 382 var context = this; 383 this.prev_link.add(this.next_link).mouseover( 384 function(e) { 385 // IE 6 hides the wrapper div, so we have to set it's width 386 $(this).css('height', context.image_wrapper_height); 387 $(this).find('div').show(); 388 } 389 ).mouseout( 390 function(e) { 391 $(this).find('div').hide(); 392 } 393 ).click( 394 function() { 395 if($(this).is('.ad-next')) { 396 context.nextImage(); 397 context.slideshow.stop(); 398 } else { 399 context.prevImage(); 400 context.slideshow.stop(); 401 }; 402 } 403 ).find('div').css('opacity', 0.7); 404 }, 405 initBackAndForward: function() { 406 var context = this; 407 this.scroll_forward = $('<div class="ad-forward"></div>'); 408 this.scroll_back = $('<div class="ad-back"></div>'); 409 this.nav.append(this.scroll_forward); 410 this.nav.prepend(this.scroll_back); 411 var has_scrolled = 0; 412 var thumbs_scroll_interval = false; 413 $(this.scroll_back).add(this.scroll_forward).click( 414 function() { 415 // We don't want to jump the whole width, since an image 416 // might be cut at the edge 417 var width = context.nav_display_width - 50; 418 if(context.settings.scroll_jump > 0) { 419 var width = context.settings.scroll_jump; 420 }; 421 if($(this).is('.ad-forward')) { 422 var left = context.thumbs_wrapper.scrollLeft() + width; 423 } else { 424 var left = context.thumbs_wrapper.scrollLeft() - width; 425 }; 426 if(context.settings.slideshow.stop_on_scroll) { 427 context.slideshow.stop(); 428 }; 429 context.thumbs_wrapper.animate({scrollLeft: left +'px'}); 430 return false;
431 } 432 ).css('opacity', 0.6).hover( 433 function() { 434 var direction = 'left'; 435 if($(this).is('.ad-forward')) { 436 direction = 'right'; 437 }; 438 thumbs_scroll_interval = setInterval( 439 function() { 440 has_scrolled++; 441 // Don't want to stop the slideshow just because we scrolled a pixel or two 442 if(has_scrolled > 30 && context.settings.slideshow.stop_on_scroll) { 443 context.slideshow.stop(); 444 }; 445 var left = context.thumbs_wrapper.scrollLeft() + 1; 446 if(direction == 'left') { 447 left = context.thumbs_wrapper.scrollLeft() - 1; 448 }; 449 context.thumbs_wrapper.scrollLeft(left); 450 }, 451 10 452 ); 453 $(this).css('opacity', 1); 454 }, 455 function() { 456 has_scrolled = 0; 457 clearInterval(thumbs_scroll_interval); 458 $(this).css('opacity', 0.6); 459 } 460 ); 461 }, 462 _afterShow: function() { 463 this.gallery_info.html((this.current_index + 1) +' / '+ this.images.length); 464 if(!this.settings.cycle) { 465 // Needed for IE 466 this.prev_link.show().css('height', this.image_wrapper_height); 467 this.next_link.show().css('height', this.image_wrapper_height); 468 if(this.current_index == (this.images.length - 1)) { 469 this.next_link.hide(); 470 }; 471 if(this.current_index == 0) { 472 this.prev_link.hide(); 473 }; 474 }; 475 this.fireCallback(this.settings.callbacks.afterImageVisible); 476 }, 477 /** 478 * Checks if the image is small enough to fit inside the container 479 * If it's not, shrink it proportionally 480 */ 481 _getContainedImageSize: function(image_width, image_height) { 482 if(image_height > this.image_wrapper_height) { 483 var ratio = image_width / image_height; 484 image_height = this.image_wrapper_height; 485 image_width = this.image_wrapper_height * ratio; 486 }; 487 if(image_width > this.image_wrapper_width) { 488 var ratio = image_height / image_width; 489 image_width = this.image_wrapper_width; 490 image_height = this.image_wrapper_width * ratio; 491 }; 492 return {width: image_width, height: image_height}; 493 }, 494 /** 495 * If the image dimensions are smaller than the wrapper, we position 496 * it in the middle anyway 497 */ 498 _centerImage: function(img_container, image_width, image_height) { 499 /* 500 img_container.css('top', '0px'); 501 if(image_height < this.image_wrapper_height) { 502 var dif = this.image_wrapper_height - image_height; 503 img_container.css('top', (dif / 2) +'px'); 504 }; 505 img_container.css('left', '0px'); 506 if(image_width < this.image_wrapper_width) { 507 var dif = this.image_wrapper_width - image_width; 508 img_container.css('left', (dif / 2) +'px'); 509 };*/ 510 }, 511 _getDescription: function(image) { 512 var desc = false; 513 if(image.desc.length || image.title.length) { 514 var title = ''; 515 if(image.title.length) { 516 title = '<strong class="ad-description-title">'+ image.title +'</strong>'; 517 }; 518 var desc = ''; 519 if(image.desc.length) { 520 desc = '<span>'+ image.desc +'</span>'; 521 }; 522 $(".ad-image-description").fadeOut(500); 523 desc = $('<p class="ad-image-description">'+ title + desc +'</p>'); 524 }; 525 return desc; 526 }, 527 /** 528 * @param function callback Gets fired when the image has loaded, is displaying 529 * and it's animation has finished 530 */ 531 showImage: function(index, callback) { 532 if(this.images[index] && !this.in_transition) { 533 var context = this; 534 var image = this.images[index]; 535 this.in_transition = true; 536 if(!image.preloaded) { 537 this.loading(true); 538 this.preloadImage(index, function() { 539 context.loading(false); 540 context._showWhenLoaded(index, callback); 541 }); 542 } else { 543 this._showWhenLoaded(index, callback); 544 }; 545 }; 546 }, 547 /** 548 * @param function callback Gets fired when the image has loaded, is displaying 549 * and it's animation has finished 550 */ 551 _showWhenLoaded: function(index, callback) { 552 if(this.images[index]) { 553 var context = this; 554 var image = this.images[index]; 555 var img_container = $(document.createElement('div')).addClass('ad-image'); 556 var img = $(new Image()).attr('src', image.image); 557 if(image.link) { 558 var link = $('<a href="'+ image.link +'"></a>'); 559 link.append(img); 560 img_container.append(link); 561 } else { 562 img_container.append(img); 563 }; 564 this.image_wrapper.prepend(img_container); 565 var size = this._getContainedImageSize(image.size.width, image.size.height); 566 //img.attr('width', size.width); 567 //img.attr('height', size.height); 568 //img_container.css({width: size.width +'px', height: size.height +'px'}); 569 this._centerImage(img_container, size.width, size.height); 570 var desc = this._getDescription(image, img_container); 571 if(desc) { 572 if(!this.settings.description_wrapper) { 573 /* 574 var width = size.width - parseInt(desc.css('padding-left'), 10) - parseInt(desc.css('padding-right'), 10); 575 desc.css('width', width +'px'); 576 */ 577 } else { 578 this.settings.description_wrapper.append(desc); 579 } 580 } 581 this.highLightThumb(this.nav.find('.ad-thumb'+ index)); 582 583 var direction = 'right'; 584 if(this.current_index < index) { 585 direction = 'left'; 586 }; 587 this.fireCallback(this.settings.callbacks.beforeImageVisible); 588 if(this.current_image || this.settings.animate_first_image) { 589 var animation_speed = this.settings.animation_speed; 590 var easing = 'swing'; 591 var animation = this.animations[this.settings.effect].call(this, img_container, direction, desc); 592 if(typeof animation.speed != 'undefined') { 593 animation_speed = animation.speed; 594 }; 595 if(typeof animation.easing != 'undefined') { 596 easing = animation.easing; 597 }; 598 if(this.current_image) { 599 var old_image = this.current_image; 600 var old_description = this.current_description; 601 old_image.animate(animation.old_image, animation_speed, easing, 602 function() { 603 old_image.remove(); 604 if(old_description) old_description.remove(); 605 } 606 ); 607 }; 608 img_container.animate(animation.new_image, animation_speed, easing, 609 function() { 610 context.current_index = index; 611 context.current_image = img_container; 612 context.current_description = desc;
613 context.in_transition = false; 614 context._afterShow(); 615 context.fireCallback(callback); 616 } 617 ); 618 } else { 619 this.current_index = index; 620 this.current_image = img_container; 621 context.current_description = desc; 622 this.in_transition = false; 623 context._afterShow(); 624 this.fireCallback(callback); 625 }; 626 }; 627 628 }, 629 nextIndex: function() { 630 if(this.current_index == (this.images.length - 1)) { 631 if(!this.settings.cycle) { 632 return false; 633 }; 634 var next = 0; 635 } else { 636 var next = this.current_index + 1; 637 }; 638 return next; 639 }, 640 nextImage: function(callback) { 641 var next = this.nextIndex(); 642 if(next === false) return false; 643 this.preloadImage(next + 1); 644 this.showImage(next, callback); 645 return true; 646 }, 647 prevIndex: function() { 648 if(this.current_index == 0) { 649 if(!this.settings.cycle) { 650 return false; 651 }; 652 var prev = this.images.length - 1; 653 } else { 654 var prev = this.current_index - 1; 655 }; 656 return prev; 657 }, 658 prevImage: function(callback) { 659 var prev = this.prevIndex(); 660 if(prev === false) return false; 661 this.preloadImage(prev - 1); 662 this.showImage(prev, callback); 663 return true; 664 }, 665 preloadAll: function() { 666 var context = this; 667 var i = 0; 668 function preloadNext() {
669 if(i < context.images.length) { 670 i++; 671 context.preloadImage(i, preloadNext); 672 }; 673 }; 674 context.preloadImage(i, preloadNext); 675 }, 676 preloadImage: function(index, callback) { 677 if(this.images[index]) { 678 var image = this.images[index]; 679 if(!this.images[index].preloaded) { 680 var img = $(new Image()); 681 img.attr('src', image.image); 682 if(!this.isImageLoaded(img[0])) { 683 this.preloads.append(img); 684 var context = this; 685 img.load( 686 function() { 687 image.preloaded = true; 688 image.size = { width: this.width, height: this.height }; 689 context.fireCallback(callback); 690 } 691 ).error( 692 function() { 693 image.error = true; 694 image.preloaded = false; 695 image.size = false; 696 } 697 ); 698 } else { 699 image.preloaded = true; 700 image.size = { width: img[0].width, height: img[0].height }; 701 this.fireCallback(callback); 702 }; 703 } else { 704 this.fireCallback(callback); 705 }; 706 }; 707 }, 708 isImageLoaded: function(img) { 709 if(typeof img.complete != 'undefined' && !img.complete) { 710 return false; 711 }; 712 if(typeof img.naturalWidth != 'undefined' && img.naturalWidth == 0) { 713 return false; 714 }; 715 return true; 716 }, 717 highLightThumb: function(thumb) { 718 this.thumbs_wrapper.find('.ad-active').removeClass('ad-active'); 719 thumb.addClass('ad-active'); 720 if(this.settings.thumb_opacity < 1) { 721 this.thumbs_wrapper.find('a:not(.ad-active) img').fadeTo(300, this.settings.thumb_opacity); 722 thumb.find('img').fadeTo(300, 1); 723 }; 724 var left = thumb[0].parentNode.offsetLeft; 725 left -= (this.nav_display_width / 2) - (thumb[0].offsetWidth / 2); 726 this.thumbs_wrapper.animate({scrollLeft: left +'px'}); 727 }, 728 fireCallback: function(fn) { 729 if($.isFunction(fn)) { 730 fn.call(this); 731 }; 732 } 733 }; 734 735 function AdGallerySlideshow(nextimage_callback, settings) { 736 this.init(nextimage_callback, settings); 737 }; 738 AdGallerySlideshow.prototype = { 739 start_link: false, 740 stop_link: false, 741 countdown: false, 742 controls: false, 743 744 settings: false, 745 nextimage_callback: false, 746 enabled: false, 747 running: false, 748 countdown_interval: false, 749 init: function(nextimage_callback, settings) { 750 var context = this; 751 this.nextimage_callback = nextimage_callback; 752 this.settings = settings; 753 }, 754 create: function() { 755 this.start_link = $('<span class="ad-slideshow-start">'+ this.settings.start_label +'</span>'); 756 this.stop_link = $('<span class="ad-slideshow-stop">'+ this.settings.stop_label +'</span>'); 757 this.countdown = $('<span class="ad-slideshow-countdown"></span>'); 758 this.controls = $('<div class="ad-slideshow-controls"></div>'); 759 this.controls.append(this.start_link).append(this.stop_link).append(this.countdown); 760 this.countdown.hide(); 761 762 var context = this; 763 this.start_link.click( 764 function() { 765 context.start(); 766 } 767 ); 768 this.stop_link.click( 769 function() { 770 context.stop(); 771 } 772 ); 773 $(document).keydown( 774 function(e) { 775 if(e.keyCode == 83) { 776 // 's' 777 if(context.running) { 778 context.stop(); 779 } else { 780 context.start(); 781 }; 782 }; 783 } 784 ); 785 return this.controls; 786 }, 787 disable: function() { 788 this.enabled = false; 789 this.stop(); 790 this.controls.hide(); 791 }, 792 enable: function() { 793 this.enabled = true; 794 this.controls.show(); 795 }, 796 toggle: function() { 797 if(this.enabled) { 798 this.disable(); 799 } else { 800 this.enable(); 801 }; 802 }, 803 start: function() { 804 if(this.running || !this.enabled) return false; 805 var context = this; 806 this.running = true; 807 this.controls.addClass('ad-slideshow-running'); 808 this._next(); 809 this.fireCallback(this.settings.onStart); 810 return true; 811 }, 812 stop: function() { 813 if(!this.running) return false;
814 this.running = false; 815 this.countdown.hide(); 816 this.controls.removeClass('ad-slideshow-running'); 817 clearInterval(this.countdown_interval); 818 this.fireCallback(this.settings.onStop); 819 return true; 820 }, 821 _next: function() { 822 var context = this; 823 var pre = this.settings.countdown_prefix; 824 var su = this.settings.countdown_sufix; 825 clearInterval(context.countdown_interval); 826 this.countdown.show().html(pre + (this.settings.speed / 1000) + su); 827 var slide_timer = 0; 828 this.countdown_interval = setInterval( 829 function() { 830 slide_timer += 1000; 831 if(slide_timer >= context.settings.speed) { 832 var whenNextIsShown = function() { 833 // A check so the user hasn't stoped the slideshow during the 834 // animation 835 if(context.running) { 836 context._next(); 837 }; 838 slide_timer = 0; 839 }; 840 if(!context.nextimage_callback(whenNextIsShown)) { 841 context.stop(); 842 }; 843 slide_timer = 0; 844 }; 845 var sec = parseInt(context.countdown.text().replace(/[^0-9]/g, ''), 10); 846 sec--; 847 if(sec > 0) { 848 context.countdown.html(pre + sec + su); 849 }; 850 }, 851 1000 852 ); 853 }, 854 fireCallback: function(fn) { 855 if($.isFunction(fn)) { 856 fn.call(this); 857 }; 858 } 859 }; 860 861})(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.