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