1// wpvSlider.js 2/** 3 * A tipical HTML structure after the script has ran ( NOT FINAL!): 4 * <div class="wpv-wrapper"> 5 * <div class="wpv-view"> 6 * <div class="wpv-slide-wrapper"><img class="wpv-slide" /></div> 7 * <div class="wpv-slide-wrapper"><img class="wpv-slide" /></div> 8 * <div class="wpv-slide-wrapper"><img class="wpv-slide" /></div> 9 * <div class="wpv-slide-wrapper"><img class="wpv-slide" /></div> 10 * </div> 11 * <div class="wpv-prev" /></div> 12 * <div class="wpv-next" /></div> 13 * <div class="wpv-pager" /> 14 * <a href="#slide1" /> 15 * <a href="#slide2" /> 16 * <a href="#slide3" /> 17 * </div> 18 * <div class="wpv-caption" /> 19 * <div class="wpv-caption" /> 20 * </div> 21 */ 22(function ($) { 23 24 // Force the hardware acceleration on Safari (this is cousing problems on Chrome) 25 // Please consider this EXPERIMENTAL and remove it if needed 26 //if ($.browser.webkit && !window.chrome) { 27 // $("body").css({ 28 // "WebkitTransform": "translateZ(0)" 29 // }); 30 //} 31 var _defaults = { 32 33 // inner width of the slider (content width) 34 width: "auto", 35 36 // height of the slider (content height) 37 height: 300, 38 39 // No height (let it resize to fit to the slide's height). 40 // NOTE: If this is true the "height" option is ignored 41 autoHeight: false, 42 43 // boolean that indicates whether the slider expands horizontally to the 44 // viewport or sticks to the content width (option allowing a) boxed layout 45 // where the slider?s width equals to the content width, or b) slider that 46 // is laid to the whole width of the screen resolution) 47 expand: false, 48 49 // ms in which each slide is shown 50 pause_time: 4000, 51 52 // in ms 53 animation_time: 800, 54 55 // effect slug. If this is a function, it is expected to 56 // return the fx name 57 effect: "fade", 58 59 // A placeholder for custom fx settings 60 effect_settings: { 61 easing: "easeInOutExpo" 62 }, 63 64 // initial slide index 65 start_slide: 0, 66 67 // ?left?, ?right? or ?none? 68 auto_direction: "right", 69 70 // boolean; whether to show left/right arrows 71 show_arrows: true, 72 73 // boolean; whether to show slide bullets as navigation 74 show_bullets: true, 75 76 // boolean; whether to show captions 77 show_caption: true, 78 79 // boolean; whether to clear the pending timeout for next animation 80 pause_on_hover: true, 81 82 // string: 83 // "crop" - Display the content as is, centered and cropped if needed 84 // "cropTop" - Display the content as is, cropped from the top if needed 85 // "fit" - Resize proportionally untill both sides are less or equal 86 // to the available space 87 // "stretch" - Resize both sides to match the available space. For HTML 88 // The proportion is lost... 89 resizing: "crop", 90 91 // string; text for ?Previous? button 92 prev_text: "Previous", 93 94 // string; for ?Next? button 95 next_text: "Next", 96 97 // boolean; whether to show slide number in each bullet, used when 98 // show_bullets is true 99 //show_bullet_numbers : false, 100 // boolean, looks for the data-thumb attribute in the current slide and 101 // uses this link as a thumbnail for the current bullet. We will provide 102 // a single slider with consistent sized thumbnails, but each slider 103 // should accommodate for different sized thumbnail. If it is a problem 104 // to auto detect their sizes, we may add options for that. 105 //thumbnail_bullets : false, 106 // number from 0 to 1, you should convert it to a MS filter rule for IE. 107 caption_opacity: 0.6, 108 109 // Others maybe? ------------------------------------------------------- 110 loop: 0, 111 112 // The following are selectors that should match existing elements to be 113 // used as custom containers for captions and navigation elements. If these 114 // are not found, the generig elements will be appended to the gallery's 115 // outer-most wrapper. These can also be dom elements. 116 captionContainer: null, 117 navContainer : null,// for prev/next buttons 118 pagerContainer : null, 119 loadingMask : null 120 }; 121 122 /** ========================================================================== 123 * The Slide class. Each slider has a "slides" property that is an array 124 * collection of Slide instancies 125 */ 126 127 function Slide(element, type, slider) { 128 129 var slideInstance = this; 130
131 this.element = element; 132 133 this.wrapper = element.parentNode; 134 135 this.type = type; 136 137 this.slider = slider; 138 139 /** 140 * This should be private and is only used to cache the object! 141 * Use the "getCaption" getter instead. 142 */ 143 this._caption = null; 144 145 var $element = $(element); 146 147 $.data(this.element, "Slide", this); 148 $.data(this.wrapper, "Slide", this); 149 150 // Store it's natural Width and Height 151 if ("naturalWidth" in element) { 152 this.width = element.naturalWidth; 153 this.height = element.naturalHeight; 154 } else { 155 this.width = $element.width(); 156 this.height = $element.height(); 157 } 158 159 // Apply the custom style (if any) 160 $element.parent().attr("style", this.getStyle()); 161 162 // Center the content and crop it if needed 163 $element.css({ 164 top : "50%", 165 left: "50%", 166 marginLeft: -this.width/2, 167 marginTop: -this.height/2 168 }); 169 170 // The slides are initially hidden (BUT AFTER the above measurenments and if 171 // NOT already marked as active) 172 if (!$element.parent().is(".active")) { 173 $element.parent().hide(); 174 } 175 176 // Attach the onclick behavior if needed 177 var _href = this.getHref(); 178 if (_href) { 179 $(this.wrapper).css({ 180 cursor: "hand", // Old IE 181 cursor: "pointer" 182 }).click(function(e) { 183 184 // Attaching link behavior to the slides makes sence for image 185 // slides only. However, it is not disabled for the HTML slides 186 // here are some cases that should be filtered: 187 // 1. Click on link - let it go 188 // 2. Click anything within form - leave it as is. Too many 189 // things could be broken otherwise... 190 if ($(e.target).is("a, form")) { 191 return true; 192 } 193 194 // Respect those 195 if (e.isDefaultPrevented()) { 196 return false; 197 } 198 199 if (!$(this).is(".active")) { 200 return false; 201 } 202 203 var target = slideInstance.getHrefTarget().replace(/^_/, ""); 204 if (target == "blank" || target == "new") { 205 window.open(_href); 206 } 207 else { 208 try { 209 // top, parent, self, frame name... 210 window[target].location = _href; 211 } 212 catch (ex) { 213 // perhaps cross-domain restriction 214 } 215 } 216 }); 217 } 218 219 var wrapper; 220 this.getCaptionWrapper = function () { 221 if ( !wrapper ) { 222 if ( !! this.slider.options.captionContainer) { 223 wrapper = $(this.slider.options.captionContainer); 224 if (!wrapper.length) { 225 wrapper = $(this.element).closest(".wpv-wrapper"); 226 } else { 227 // Attach the pause_on_hover listeners 228 if ( !!this.slider.options.pause_on_hover ) { 229 var _inst = this.slider; 230 wrapper.hover( 231 function () { _inst.pause(); }, 232 function () { _inst.resume();} 233 ); 234 } 235 wrapper = wrapper.eq(0); 236 } 237 } else { 238 wrapper = $(this.element).closest(".wpv-wrapper"); 239 } 240 } 241 return wrapper; 242 }; 243 } 244 245 Slide.prototype = { 246 247 /** 248 * Returns the caption element (jQuery) for this slide or null 249 */ 250 getCaption: function () { 251 if (!this._caption) { // check for cached object 252 var src = unescape($(this.element).attr("data-caption") || $(this.element).attr("alt") || ""); 253 254 if (!src) { 255 return null; 256 } 257 258 var wrapper = this.getCaptionWrapper(); 259 260 // If a slide?s caption starts with a hash sign, then this is an id 261 // pointing to the html element containing a html caption 262 var isId = src.indexOf("#") === 0, 263 elem = null; 264 265 if (isId) { 266 elem = $(src); 267 if (!elem.length) { 268 elem = null; 269 } else { 270 271 // clone the element and append it to container (but only if its not 272 // allready a child of the container) 273 if (!elem.closest(wrapper).length) { 274 elem = elem.clone().removeAttr("id").addClass("wpv-caption").appendTo(wrapper); 275 } 276 } 277 } 278 279 // create one if needed 280 if (!elem && !isId) { 281 elem = $('<div class="wpv-caption" />').html(src).appendTo(wrapper); 282 } 283 284 if (elem) { 285 elem.addClass("wpv-caption"); 286 var style = this.getCaptionStyle(); 287 if (style) { 288 elem.attr("style", style); 289 } 290 this._caption = elem; 291 } 292 } 293 return this._caption; 294 }, 295 296 /** 297 * Returns the custom style for this slide as string (can be empty string) 298 */ 299 getStyle: function () { 300 return unescape($(this.element).attr("data-style") || ""); 301 }, 302 303 /** 304 * Returns the custom style for this slide's caption as string 305 * (can be empty string) 306 */ 307 getCaptionStyle: function () { 308 return unescape($(this.element).attr("data-caption-style") || ""); 309 }, 310 311 /** 312 * Returns the "link URL" for that slide as string 313 * (can be empty string) 314 */ 315 getHref: function () { 316 return unescape($(this.element).attr("data-href") || ""); 317 }, 318 319 /** 320 * Returns the "link URL - target" for that slide as string 321 */ 322 getHrefTarget: function () { 323 return unescape($(this.element).attr("data-target") || "_self"); 324 } 325 326 }; 327 328 /** ========================================================================== 329 * The WPVSlider class 330 */ 331 332 function WPVSlider(elem, options) { 333 334 var _inst = this; 335 336 this.view = elem; 337 338 var _cfg = $.extend(true, {}, _defaults, options); 339 340 this.options = _cfg;
341 342 /** 343 * The id (unique name) of the FX that is currently in use 344 */ 345 var _fxId = "fade"; 346 347 this.slides = []; 348 349 this.showLoadingMask = function () { 350 var mask = _cfg.loadingMask ? $(_cfg.loadingMask) : $(".wpv-loading-mask", this.view); 351 if (!mask.length) { 352 mask = $('<div class="wpv-loading-mask"/>').appendTo(this.view); 353 } 354 mask.css({ 355 top: 0, 356 left: 0, 357 right: 0, 358 bottom: 0, 359 opacity: 1, 360 display: "block" 361 }); 362 }; 363 364 this.hideLoadingMask = function (callback) { 365 var mask = _cfg.loadingMask ? $(_cfg.loadingMask) : $(".wpv-loading-mask", this.view); 366 if (mask.length) { 367 mask.animate({ 368 opacity: 0 369 }, 1000, "linear", function () { 370 $(this).hide(); 371 (callback || $.noop)(); 372 }); 373 } 374 }; 375 376 this.showLoadingMask(); 377 378 // Slideshow and Navigation Controll Methods ------------------------------- 379 var _slideShowTimer, _paused = 0, 380 _isAnimating, _isAnimatingCaptions; 381 382 // Be CAREFUL with timers! 383 $(window).bind("unload beforeunload", function () { 384 _inst.stop(); 385 }); 386 387 /** 388 * Starts the slideshow if it's not already running 389 */ 390 this.start = function (delay) { 391 392 if (_isAnimating || _isAnimatingCaptions || _paused) { 393 _slideShowTimer = window.setTimeout(function () { 394 _inst.start(_cfg.pause_time); 395 }, 200); 396 return; 397 } 398 399 _slideShowTimer = window.setTimeout(function () { 400 if (_paused) { 401 _inst.start(_cfg.pause_time); 402 } else { 403 _inst[_inst.getDirection() == "right" ? "next" : "prev"](function () { 404 if ( !! _slideShowTimer) { // false if stopped while animating 405 _inst.start(_cfg.pause_time); 406 } 407 }); 408 } 409 }, delay || 0); 410 }; 411 412 /** 413 * Stops the slideshow (if it is currently running) 414 */ 415 this.stop = function () { 416 if (_slideShowTimer) { 417 window.clearTimeout(_slideShowTimer); 418 _slideShowTimer = null; 419 } 420 _paused = 0; 421 }; 422 423 /** 424 * Pauses the running slideshow 425 */ 426 this.pause = function () { 427 _paused = +new Date(); 428 }; 429 430 /** 431 * Resumes the running slideshow 432 */ 433 this.resume = function () { 434 _paused = 0; 435 }; 436 437 /** 438 * Returns a boolean to indicate if the slideshow is currently running 439 */ 440 this.isRunning = function () { 441 return !!_slideShowTimer; 442 }; 443 444 /** 445 * Returns the zero-based index of the currently active slide. If there is 446 * no active slide (initially, and if none is specified in start_slide 447 * option) this method just returns -1. 448 * @return {int} 449 */ 450 this.getIindex = function () { 451 return $(".wpv-slide-wrapper", elem).filter(".active").index(); 452 }; 453 454 this.getSlideElements = function () { 455 return $(".wpv-slide-wrapper", elem); 456 }; 457 458 /** 459 * Returns the currently active Slide object. 460 * NOTE: This can be undefined if there is no active item! 461 * @return {Slide} 462 */ 463 this.getCurrentSlide = function () { 464 return $(".wpv-slide-wrapper.active", elem).eq(0); 465 }; 466 467 /** 468 * Returns next slide (the one after the currently active). If the last 469 * slide is active this will return the first one. 470 * NOTE: This can be undefined if there are no slides! 471 * NOTE: This can be the active slide if there is only one slide! 472 * @return {jQuery} 473 */ 474 this.getNextSlide = function () { 475 var cur = this.getCurrentSlide(); 476 var next = cur.next(".wpv-slide-wrapper", elem); 477 if (!next.length) { 478 next = $(".wpv-slide-wrapper:first", elem); 479 } 480 return next.eq(0); 481 }; 482 483 /** 484 * Returns previous slide (the one before the currently active). If the 485 * first slide is active this will return the last one. 486 * NOTE: This can be an empty jQuery object if there are no slides! 487 * NOTE: This can be the active slide if there is only one slide! 488 * @return {jQuery} 489 */ 490 this.getPreviousSlide = function () { 491 var cur = this.getCurrentSlide(); 492 var prev = cur.prev(".wpv-slide-wrapper", elem); 493 if (!prev.length) { 494 prev = $(".wpv-slide-wrapper:last", elem); 495 } 496 return prev.eq(0); 497 }; 498 499 /** 500 * Returns "left" or "right" depending on the CURRENT value of the 501 * "auto_direction" config. property. 502 * @return {string} 503 */ 504 this.getDirection = function () { 505 return _cfg.auto_direction == "left" ? "left" : "right"; 506 }; 507 508 /** 509 * Runs a transition to the next slide 510 */ 511 this.next = function (callback) { 512 this.goTo("next", callback); 513 }; 514 515 /** 516 * Runs a transition to the previous slide 517 */ 518 this.prev = function (callback) { 519 this.goTo("prev", callback); 520 }; 521 522 this.goTo = function (index, callback) { 523 524 if (_isAnimating || _isAnimatingCaptions) { 525 return false; // Do we need queue here? 526 } 527 528 if (index == this.getIindex()) { 529 return; 530 } 531 532 var toHide = this.getCurrentSlide(); 533 534 var toShow; 535 if (index == "prev") { 536 toShow = this.getPreviousSlide(); 537 } else { 538 if (index == "next") { 539 toShow = this.getNextSlide(); 540 } else { 541 toShow = $(".wpv-slide-wrapper", elem).eq(index); 542 } 543 } 544 545 var evt = new $.Event("beforeChange"); 546 $(elem).trigger(evt, [this, toShow, toHide]); 547 548 if (evt.isDefaultPrevented()) { 549 return; 550 } 551 552 toHide.removeClass("active").addClass("animated"); 553 toShow.addClass("active animated"); 554 555 function _mainAnimationCallback() { 556 557 toShow.removeClass("animated"); 558 toHide.removeClass("animated"); 559 $(_inst.view.parentNode).removeClass("animated");
560 _isAnimating = false; 561 562 if ($.isFunction(callback)) { 563 callback.apply(_inst, arguments); 564 } 565 566 var evt = new $.Event("afterChange"); 567 $(elem).trigger(evt, [_inst, toShow, toHide]); 568 if (evt.isDefaultPrevented()) { 569 _inst.stop(); 570 } 571 572 if (toShow[0] == $(".wpv-slide-wrapper", elem).filter(":last")[0]) { 573 evt = new $.Event("lastSlide"); 574 $(elem).trigger(evt, [_inst, toShow, toHide]); 575 if (evt.isDefaultPrevented()) { 576 _inst.stop(); 577 } 578 } else { 579 if (toShow[0] == $(".wpv-slide-wrapper", elem).filter(":first")[0]) { 580 evt = new $.Event("firstSlide"); 581 $(elem).trigger(evt, [_inst, toShow, toHide]); 582 if (evt.isDefaultPrevented()) { 583 _inst.stop(); 584 } 585 } 586 } 587 } 588 589 function _runMainAnimation() { 590 $(_inst.view.parentNode).addClass("animated"); 591 592 _inst.setFX(_inst.options.effect); 593 594 _isAnimating = true; 595 596 if (!WPVSlider.fx[_fxId]) { 597 _mainAnimationCallback(); 598 } else { 599 600 var dir = $.WPVSlider.Util.getDirection(toHide, toShow, $(".wpv-slide-wrapper", elem)); 601 602 if (!dir) { 603 $(_inst.view.parentNode).removeClass("animated"); 604 _isAnimating = false; 605 return; 606 } 607 608 toShow.stop(1, 1).trigger("fxStop"); 609 toHide.stop(1, 1).trigger("fxStop"); 610 611 WPVSlider.fx[_fxId].run({ 612 slider: _inst, 613 toShow: toShow, 614 toHide: toHide, 615 dir: dir, 616 callback: _mainAnimationCallback, 617 duration: _cfg.animation_time, 618 easing: _cfg.effect_settings.easing 619 }); 620 } 621 } 622 623 _runMainAnimation(); 624 }; 625 626 this.getFX = function () { 627 return _fxId; 628 }; 629 630 this.setFX = function (fxId) { 631 var _oldId = _fxId; 632 var id = $.isFunction(fxId) ? fxId() : fxId; 633 if (id in WPVSlider.fx) { 634 if (id != _fxId) { 635 636 var oldFx = WPVSlider.fx[id]; 637 if ($.isFunction(oldFx.uninit)) { 638 oldFx.uninit(this); 639 } 640 oldFx = null; 641 642 var newFx = WPVSlider.fx[id]; 643 if ($.isFunction(newFx.init)) { 644 newFx.init(this); 645 } 646 newFx = null; 647 648 _fxId = id; 649 } 650 } 651 }; 652 653 this.getOption = function (name) { 654 return _cfg[name]; 655 }; 656 657 this.setOption = function (name, value) { 658 _cfg[name] = value; 659 return this; 660 }; 661 662 // Layout Controll Methods --------------------------------------------- 663 this.setWidth = function (w) { 664 $elem.width(calcWidth(w)); 665 }; 666 667 this.setHeight = function (h) { 668 $elem.height(h); 669 }; 670 671 this.setResizing = function( resizing ) { 672 var view = $elem.closest(".wpv-view"), 673 viewWidth = view.width(), 674 viewHeight = view.height(); 675 676 function cropSlide($el) { 677 var slide = $el.data("Slide"); 678 if (slide) { 679 $el.css({ 680 width : "auto", 681 height : "auto", 682 top : "50%", 683 left : "50%", 684 marginLeft: -slide.width/2, 685 marginTop : -slide.height/2 686 }).find("iframe").each(function() { 687 $(this).css({ 688 width : $(this).attr("width" ) || 'auto', 689 height: $(this).attr("height") || 'auto' 690 }); 691 }); 692 } 693 } 694 695 // same as crop but takes the cropped rectangle from the top 696 function cropTopSlide($el) { 697 var slide = $el.data("Slide"); 698 if (slide) { 699 var eWidth = slide.width, 700 eHeight = slide.height, 701 sWidth = $(this).width(), 702 sHeight = $(this).height(), 703 _width = $(this).width(); 704 705 if(sWidth/eWidth*eHeight < sHeight) { 706 // should be stretched horizontally 707 _width = sHeight/eHeight*eWidth; 708 } 709 710 $el.css({ 711 width : _width, 712 height : "auto", 713 top : 0, 714 left : "50%", 715 marginLeft: -_width/2, 716 marginTop : 0 717 }).find("iframe").each(function() { 718 $(this).css({ 719 width : $(this).attr("width" ) || 'auto', 720 height: $(this).attr("height") || 'auto' 721 }); 722 }); 723 } 724 } 725 726 function fitSlide($el) { 727 var slide = $el.data("Slide"); 728 if (slide) { 729 var w = slide.width, 730 h = slide.height; 731 732 if ( viewWidth < slide.width ) { 733 w = viewWidth; 734 h = h * (viewWidth / slide.width); 735 } 736 if ( h > viewHeight ) { 737 w = w * (viewHeight / h); 738 h = viewHeight; 739 } 740 $el.css({ 741 width : w, 742 height : h, 743 top : "50%", 744 left : "50%", 745 marginLeft: -w/2, 746 marginTop : -h/2 747 }); 748 } 749 } 750 751 function stretchSlide($el) { 752 $el.css({ 753 width : viewWidth, 754 height: viewHeight, 755 top : "50%", 756 left : "50%", 757 marginLeft: -viewWidth/2, 758 marginTop : -viewHeight/2 759 }).find("iframe").css({ 760 width : viewWidth, 761 height: viewHeight 762 }); 763 } 764 765 $(".wpv-slide", view).each(function (i, o) { 766 var $el = $(o), 767 slide = $el.data("Slide"); 768 769 // The image is not yet loaded 770 if (!slide) { 771 return true; 772 } 773
774 resizing = String(resizing).toLowerCase(); 775 switch ( resizing ) { 776 case "fit": 777 if ($el.is("img")) { 778 fitSlide($el); 779 } 780 else { 781 cropSlide($el); 782 } 783 break; 784 case "stretch": 785 stretchSlide($el); 786 break; 787 case "croptop": 788 cropTopSlide($el); 789 break; 790 case "crop": 791 default: 792 cropSlide($el); 793 break; 794 } 795 }); 796 }; 797 798 this.setExpanded = function (bExpanded) { 799 var _outerWrapper = $elem.parent(); 800 _outerWrapper.height(_outerWrapper.height()); 801 _outerWrapper[ !! bExpanded ? "addClass" : "removeClass"]("wpv-full-width"); 802 803 function syncExpandedView() { 804 if (bExpanded) { 805 var w = $("body").width(); 806 807 _outerWrapper.width(w); 808 809 var bp = (window.width - window.innerWidth) / 2; 810 var l = _outerWrapper.offset().left; 811 812 if (l > bp) { 813 _outerWrapper.css("left", bp - l); 814 } 815 } else { 816 $(elem).add(_outerWrapper).width(calcWidth()); 817 } 818 _inst.setResizing(_cfg.resizing); 819 } 820 821 if ( !! bExpanded) { 822 $(window).unbind("resize.syncWPV", syncExpandedView).bind("resize.syncWPV", syncExpandedView); 823 syncExpandedView(); 824 } else { 825 syncExpandedView(); 826 $(window).unbind("resize.syncWPV"); 827 } 828 }; 829 830 this.isExpanded = function () { 831 return $(elem).parent().hasClass("wpv-full-width"); 832 }; 833 834 this.setShowArrows = function (bShow) { 835 var _outerWrapper = _cfg.navContainer ? $(_cfg.navContainer) : $(elem).parent(); 836 var leftArrow = $(".wpv-nav-prev", _outerWrapper); 837 var rightArrow = $(".wpv-nav-next", _outerWrapper); 838 839 // create them if needed 840 if ( !! bShow) { 841 842 if (!leftArrow.length) { 843 leftArrow = $('<div class="wpv-nav-prev" />').html(_cfg.prev_text).bind({ 844 click: function () { 845 _inst.prev(); 846 }, 847 mouseenter: function () { 848 _inst.pause(); 849 }, 850 mouseleave: function () { 851 _inst.resume(); 852 }, 853 "mousedown selectstart": false // unselectable 854 }).appendTo(_outerWrapper); 855 } 856 857 if (!rightArrow.length) { 858 rightArrow = $('<div class="wpv-nav-next" />').html(_cfg.next_text).bind({ 859 click: function () { 860 _inst.next(); 861 }, 862 mouseenter: function () { 863 _inst.pause(); 864 }, 865 mouseleave: function () { 866 _inst.resume(); 867 }, 868 "mousedown selectstart": false // unselectable 869 }).appendTo(_outerWrapper); 870 } 871 } 872 873 // hide them if needed 874 else { 875 leftArrow.hide(); 876 rightArrow.hide(); 877 } 878 }; 879 880 this.setShowBullets = function (bShow) { 881 var _outerWrapper = $(_cfg.pagerContainer || elem.parentNode); 882 var pager = $(".wpv-nav-pager", _outerWrapper).empty(); 883 884 // create it if needed 885 if ( !! bShow) { 886 if (!pager.length) { 887 pager = $('<ul class="wpv-nav-pager" />').appendTo(_outerWrapper); 888 } 889 //pager.show(); 890 var curIndex = _inst.getIindex(); 891 $(".wpv-slide-wrapper", elem).each(function (i, slide) { 892 var li = $('<li/>').click(function () { 893 _inst.goTo(i); 894 }) 895 .bind("mousedown selectstart", false) 896 .hover(function () { 897 _inst.pause(); 898 $(this).addClass("hover"); 899 }, function () { 900 _inst.resume(); 901 $(this).removeClass("hover"); 902 }).appendTo(pager); 903 904 if (curIndex === i) { 905 li.addClass("active"); 906 } 907 }); 908 909 $elem.bind({ 910 "beforeChange": function (e, slider, toShow, toHide) { 911 pager.find("li.active").removeClass("active"); 912 pager.find("li").eq(toShow.index()).addClass("active"); 913 } 914 }); 915 } 916 917 // hide it if needed 918 else { 919 pager.hide(); 920 } 921 }; 922 923 this.setShowCaption = function (bShow) { 924 if ( !! bShow) { 925 $elem.unbind("beforeChange.changeCaption").bind({ 926 "beforeChange.changeCaption": function (e, slider, newSlide, oldSlide) { 927 if (_isAnimatingCaptions || !newSlide || !slider.options.show_caption) { 928 return; 929 } 930 931 var newCaption = $(newSlide ? newSlide.data("Slide").getCaption() : "<div />"); 932 var oldCaption = $(oldSlide ? oldSlide.data("Slide").getCaption() : "<div />"); 933 934 var worker = WPVSlider.fx[_fxId] && WPVSlider.fx[_fxId].changeCaptions ? WPVSlider.fx[_fxId].changeCaptions : WPVSlider.captionFx.fadeToggle; 935 936 var speed = slider.options.effect_settings.caption_animation_time; 937 if (!speed && speed !== 0) { 938 speed = slider.options.animation_time; 939 } 940
941 var delay = slider.options.effect_settings.caption_delay || 0; 942 943 _isAnimatingCaptions = true; 944 945 $(slider.view.parentNode).addClass("animated"); 946 947 worker({ 948 oldCaption: oldCaption, 949 newCaption: newCaption, 950 slider: slider, 951 slideToShow: newSlide, 952 slideToHide: oldSlide, 953 speed: speed, 954 delay: delay 955 }, function () { 956 $(slider.view.parentNode).removeClass("animated"); 957 _isAnimatingCaptions = false; 958 }); 959 } 960 }); 961 } else { 962 $elem.unbind("beforeChange.changeCaption"); 963 } 964 }; 965 966 967 function calcWidth(width) { 968 var _width = String(width || _cfg.width); 969 if (_width != "auto") { 970 var m = _width.match(/([\+-]?(\d*\.)?\d+)([^\d]*)/); //console.dir(m); 971 _width = "auto"; 972 if (m && m[1]) { 973 var _width2 = parseFloat(m[1]); 974 if (!isNaN(_width2)) { // NaN remains auto 975 if (_width2 !== 0) { // 0 remains auto 976 977 // Get the parent's width 978 var prtWidth = $(elem).closest(".wpv-wrapper").parent().width(); 979 980 // Number without units 981 if (!m[3]) { 982 if (_width2 < 0) { 983 _width = Math.max(prtWidth + _width2, 100); 984 } 985 else if (_width2 < 1) { 986 _width = Math.max(prtWidth * _width2, 100); 987 } 988 else { 989 _width = _width2; 990 } 991 } 992 else { 993 if (m[3] == "%") { 994 _width = Math.max(prtWidth * (_width2/100), 100); 995 //console.log(prtWidth, _width); 996 } 997 else { 998 _width = m[0]; // as is 999 } 1000 } 1001 } 1002 } 1003 } 1004 else { 1005 _width = "auto"; 1006 } 1007 } 1008 1009 return _width; 1010 } 1011 1012 //////////////////////////////////////////////////////////////////////////// 1013 // // 1014 // INITIALIZE // 1015 // // 1016 //////////////////////////////////////////////////////////////////////////// 1017 var $elem = $(elem); 1018 1019 // Mark it as our's 1020 $elem.addClass("wpv-view"); 1021 1022 // Wrap it with a fixed-size wrapper 1023 $elem.wrap('<div class="wpv-wrapper">'); 1024 var _outerWrapper = $elem.parent(); 1025 1026 $elem.wrapInner('<div class="wpv-htmlslide-wrap"/>'); 1027 var _innerWrapper = $elem.find("> .wpv-htmlslide-wrap"); 1028 1029 // Resize it and make it invisible while initializing 1030 $elem.css({ 1031 visibility: "hidden", 1032 width : calcWidth(), 1033 height: _cfg.height 1034 }); 1035 1036 if (_cfg.height == "auto" || _cfg.height + "" == "0") { 1037 _outerWrapper.addClass("no-center"); 1038 } 1039 1040 // Attach the pause_on_hover listeners 1041 if ( !!_cfg.pause_on_hover) { 1042 $(_outerWrapper).add(_cfg.captionContainer).hover(function () { 1043 _inst.pause(); 1044 }, function () { 1045 _inst.resume(); 1046 }); 1047 } 1048 1049 1050 // Collect all slides now ================================================== 1051 var slides = $elem.find(".wpv-slide").wrap('<div class="wpv-slide-wrapper"/>'), 1052 len = slides.length, 1053 totalHeight = 0, 1054 initialSlide, loadCallback = function (el, type, initial) { 1055 var slide = new Slide(el, type, _inst); 1056 _inst.slides.push(slide); 1057 1058 if (initial) { 1059 initialSlide = slide; 1060 } 1061 1062 // When ALL the slides are ready fire the load event 1063 if (_inst.slides.length === len) { 1064 $elem.css("visibility", "visible"); 1065 _inst.setExpanded(_cfg.expand); 1066 _outerWrapper.addClass("wpv-loaded"); 1067 if (_cfg.height == "auto" || _cfg.height + "" == "0") { 1068 $.each(_inst.slides, function() { 1069 var cssBackup = { 1070 visibility: $(this.wrapper).css("visibility"), 1071 display : $(this.wrapper).css("display"), 1072 opacity : $(this.wrapper).css("opacity") 1073 }; 1074 $(this.wrapper).css({ 1075 "height": "auto", 1076 opacity : 0 1077 }).show(); 1078 totalHeight = Math.max(totalHeight, $(this.element).outerHeight()); 1079 $(this.wrapper).css(cssBackup); 1080 }); 1081 $(".wpv-slide, .wpv-slide-wrapper, .wpv-htmlslide-wrap", $elem) 1082 .add(_outerWrapper) 1083 .add(elem) 1084 .add(_innerWrapper) 1085 .add(_outerWrapper.closest(".slider-shortcode-wrapper")) 1086 .css({ 1087 height: totalHeight 1088 }); 1089 } 1090 1091 _inst.hideLoadingMask(function () { 1092 1093 1094 $elem.trigger("sliderload", [_inst]); 1095 initialSlide.getCaption(); 1096
1097 // Do I need these ? 1098 $elem.trigger("beforeChange", [_inst, $(initialSlide.wrapper)]); 1099 //elem.trigger("afterChange", [_inst, $(initialSlide.wrapper)]); 1100 if (len > 1 && (_cfg.auto_direction == "left" || _cfg.auto_direction == "right")) { 1101 _inst.start(_cfg.pause_time); 1102 } 1103 1104 initialSlide = null; 1105 }); 1106 1107 } 1108 1109 slide = null; 1110 }; 1111 1112 // Add some classNames to the outer wrapper to help the CSS styling 1113 if ( !! _cfg.show_arrows && len > 1) { 1114 _outerWrapper.addClass("wpv-show-arrows"); 1115 } 1116 if ( !! _cfg.show_bullets && len > 1) { 1117 _outerWrapper.addClass("wpv-show-bullets"); 1118 } 1119 if ( !! _cfg.show_caption) { 1120 _outerWrapper.addClass("wpv-show-caption"); 1121 } 1122 1123 slides.each(function (i, o) { 1124 1125 var $o = $(o), 1126 type = "html"; 1127 1128 switch (o.nodeName.toLowerCase()) { 1129 case "img": 1130 type = "image"; 1131 break; 1132 case "iframe": 1133 type = "frame"; 1134 break; 1135 case "object": 1136 type = "object"; 1137 break; 1138 case "embed": 1139 type = "embed"; 1140 $o.attr("wmode", "transparent").removeAttr("bgcolor"); 1141 o.wmode = "transparent"; 1142 break; 1143 } 1144 1145 if (type == "image" || type == "frame") { 1146 if ( !! o.complete || o.readyState == "complete" || o.readyState == "loaded") { 1147 loadCallback(o, type, i === (_cfg.start_slide || 0)); 1148 } else { 1149 $o.bind("load readystatechange", function (e) { 1150 if (e.type == "load") { 1151 $o.unbind("load").unbind("readystatechange"); 1152 loadCallback(o, type, i === (_cfg.start_slide || 0)); 1153 } else { 1154 if (o.readyState == "complete" || o.readyState == "loaded") { 1155 $o.unbind("load").unbind("readystatechange"); 1156 loadCallback(o, type, i === (_cfg.start_slide || 0)); 1157 } 1158 } 1159 }); 1160 } 1161 } else { 1162 loadCallback(o, type, i === (_cfg.start_slide || 0)); 1163 } 1164 }); 1165 1166 // Find and show the initial slide 1167 var startSlide = $(".wpv-slide-wrapper.active", elem); 1168 if (!startSlide.length) { 1169 startSlide = $(".wpv-slide-wrapper", elem).eq(_cfg.start_slide || 0); 1170 } 1171 startSlide.addClass("active").show(); //.closest(".wpv-view").css("visibility", "visible"); 1172 _inst.setExpanded(_cfg.expand); 1173 1174 _inst.setFX(_cfg.effect); 1175 1176 // Show the arrows if needed 1177 _inst.setShowArrows(_cfg.show_arrows && len > 1); 1178 1179 // Show the pager if needed 1180 _inst.setShowBullets(_cfg.show_bullets && len > 1); 1181 1182 // Show the captions? 1183 _inst.setShowCaption(_cfg.show_caption); 1184 1185 // Autorun the slideshow if needed 1186 //if (_cfg.auto_direction == "left" || _cfg.auto_direction == "right") { 1187 // _inst.start(_cfg.pause_time); 1188 //} 1189 // 1190 startSlide.closest(".wpv-view").css("visibility", "visible"); 1191 1192 _outerWrapper.addClass("wpv-ready"); 1193 1194 // Trigger the "sliderready" event 1195 $elem.trigger("sliderready", [_inst]); 1196 } 1197 1198 WPVSlider.getInstance = function (elem, options) { 1199 var inst = $.data(elem, "WPVSlider"); 1200 if (!inst) { 1201 inst = new WPVSlider(elem, options); 1202 $.data(elem, "WPVSlider", inst); 1203 } 1204 return inst; 1205 }; 1206 1207 // Expose the constructor 1208 $.WPVSlider = WPVSlider; 1209 1210 $.WPVSlider.Util = { 1211 getDirection: function (from, to, all) { 1212 var fromIndex = all.index(from); 1213 var toIndex = all.index(to); 1214 if (fromIndex === 0 && toIndex == all.length - 1) { 1215 return "prev"; 1216 } 1217 if (fromIndex == all.length - 1 && toIndex === 0) { 1218 return "next"; 1219 } 1220 if (fromIndex < toIndex) { 1221 return "next"; 1222 } 1223 if (fromIndex > toIndex) { 1224 return "prev"; 1225 } 1226 } 1227 }; 1228 1229 /** 1230 * Public container for transition effects (available as jQuery.WPVSlider.fx) 1231 */ 1232 WPVSlider.fx = {}; 1233 1234 // Built-in Effects ---------------------------------------------------------- 1235 WPVSlider.fx.fade = { 1236 init: function(slider) { 1237 slider.getSlideElements().fadeOut(0); 1238 }, 1239 run: function (cfg) { 1240 cfg = $.extend({ 1241 duration: 1000, 1242 easing: "linear" 1243 }, cfg); 1244 cfg.toShow.css({ 1245 opacity: 0, 1246 zIndex: 3 1247 }).show(); 1248 1249 //var w1 = cfg.toHide ? $("> .wpv-slide", cfg.toHide).width() : 0; 1250 //var h1 = cfg.toHide ? $("> .wpv-slide", cfg.toHide).height() : 0; 1251 //var w2 = $("> .wpv-slide", cfg.toShow).width(); 1252 //var h2 = $("> .wpv-slide", cfg.toShow).height(); 1253 //if (cfg.toHide && (w1 > w2 || h1 > h2)) { 1254 cfg.toHide.fadeTo(cfg.duration, 0, "linear", function () { 1255 cfg.toHide.css({ 1256 display: "none", 1257 opacity: 1 1258 }); 1259 }); 1260 //} 1261 cfg.toShow.animate({ 1262 opacity: 1 1263 }, cfg.duration, cfg.easing, function () { 1264 cfg.toHide.hide(); 1265 cfg.callback(); 1266 }); 1267 1268 cfg.toHide.css({ 1269 zIndex: 2 1270 }); 1271 } 1272 }; 1273 1274 WPVSlider.fx.slide = { 1275 run: function (cfg) { 1276 cfg = $.extend({
1277 duration: 800, 1278 easing: "easeOutExpo" 1279 }, cfg); 1280 //console.log(cfg.toShow.data("Slide").width) 1281 cfg.toShow.css({ 1282 //left: cfg.toShow.width() * (cfg.dir == "next" ? 1 : -1), 1283 left: cfg.toShow.data("Slide").width * (cfg.dir == "next" ? 1 : -1), 1284 zIndex: 3 1285 }).show(); 1286 1287 1288 1289 //var w1 = cfg.toHide ? $("> .wpv-slide", cfg.toHide).width() : 0; 1290 //var h1 = cfg.toHide ? $("> .wpv-slide", cfg.toHide).height() : 0; 1291 //var w2 = $("> .wpv-slide", cfg.toShow).width(); 1292 //var h2 = $("> .wpv-slide", cfg.toShow).height(); 1293 //if (cfg.toHide && (w1 > w2 || h1 > h2)) { 1294 cfg.toHide.fadeTo(cfg.duration, 0, "linear", function () { 1295 cfg.toHide.css({ 1296 display: "none", 1297 opacity: 1 1298 }); 1299 }); 1300 //} 1301 cfg.toShow.animate({ 1302 left: 0 1303 }, cfg.duration, cfg.easing, function () { 1304 cfg.toHide.stop(1, 0).hide(); 1305 cfg.callback(); 1306 }); 1307 1308 if (cfg.toHide) { 1309 cfg.toHide.css({ 1310 zIndex: 2 1311 }); 1312 } 1313 1314 } 1315 }; 1316 1317 WPVSlider.fx.random = { 1318 run: function () { 1319 var fx = []; 1320 for (var name in WPVSlider.fx) { 1321 if (name != "random") { 1322 fx.push(name); 1323 } 1324 } 1325 return WPVSlider.fx[fx[Math.floor(Math.random() * fx.length)]].run.apply(this, arguments); 1326 } 1327 }; 1328 // --------------------------------------------------------------------------- 1329 /** 1330 * And some public static caption effects that the effects may refer to 1331 */ 1332 WPVSlider.captionFx = {}; 1333 1334 /** 1335 * Caption effects factory 1336 */ 1337 WPVSlider.createCaptionFx = function (cfg, hideFn, showFn, onComplete) { 1338 1339 var queue = (function () { 1340 1341 var q = []; 1342 1343 function next() { 1344 if (q.length) { 1345 q.shift()(next); 1346 } else { 1347 onComplete(); 1348 } 1349 } 1350 1351 function add(fn) { 1352 q.push(fn); 1353 } 1354 1355 return { 1356 next: next, 1357 add: add 1358 }; 1359 1360 })(); 1361 1362 if (!$.isArray(hideFn)) { 1363 hideFn = hideFn ? [hideFn] : []; 1364 } 1365 1366 if (!$.isArray(showFn)) { 1367 showFn = showFn ? [showFn] : []; 1368 } 1369 1370 return function () { 1371 1372 $.each(hideFn, function (i, fn) { 1373 queue.add(function (next) { 1374 setTimeout(function () { 1375 fn(next); 1376 }, cfg.delay || 0); 1377 }); 1378 }); 1379 1380 $.each(showFn, function (i, fn) { 1381 queue.add(function (next) { 1382 setTimeout(function () { 1383 fn(next); 1384 }, cfg.delay || 0); 1385 }); 1386 }); 1387 1388 queue.next(); 1389 }; 1390 }; 1391 1392 /** 1393 * Just show/hide captions without animation (but thay still can have delays) 1394 */ 1395 WPVSlider.captionFx.toggle = function (cfg, callback) { 1396 if (cfg.newCaption.length) { 1397 $(cfg.newCaption).hide(); 1398 } 1399 WPVSlider.createCaptionFx( 1400 cfg, function (next) { // hideFn 1401 if (cfg.oldCaption.length) { 1402 $(cfg.oldCaption).hide(); 1403 } 1404 next(); 1405 }, function (next) { // showFn 1406 if (cfg.newCaption.length) { 1407 $(cfg.newCaption).show(); 1408 } 1409 next(); 1410 }, callback || $.noop)(); 1411 }; 1412 1413 /** 1414 * Fade-in/out both captions at the same time 1415 */ 1416 WPVSlider.captionFx.fadeToggle = function (cfg, callback) { //console.log(arguments) 1417 if (cfg.newCaption.length) { 1418 $(cfg.newCaption).fadeOut(0); 1419 } 1420 WPVSlider.createCaptionFx( 1421 cfg, function (next) { // hideFn 1422 if (cfg.oldCaption.length) { 1423 $(cfg.oldCaption).fadeIn(0).fadeOut(cfg.speed, "linear"); 1424 } 1425 next(); 1426 }, function (next) { // showFn 1427 if (cfg.newCaption.length) { 1428 $(cfg.newCaption || []).fadeTo(cfg.speed, cfg.slider.options.caption_opacity, "linear", next); 1429 } else { 1430 next(); 1431 } 1432 }, callback || $.noop)(); 1433 }; 1434 1435 1436 // The jQuery Plugin --------------------------------------------------------- 1437 $.fn.wpvSlider = function (opt) { 1438 1439 var _args = arguments, 1440 result; 1441 1442 var isMethodCall = typeof opt == "string"; 1443 1444 this.each(function (i, o) { 1445 1446 // Method call 1447 if (isMethodCall) { 1448 if (opt.charAt(0) != "_") { 1449 var _inst = WPVSlider.getInstance(o); 1450 if (_inst && $.isFunction(_inst[opt])) { 1451 result = _inst[opt].apply(_inst, Array.prototype.slice.call(_args, 1)); 1452 if (result !== undefined) { 1453 return false; // break each 1454 } 1455 } 1456 _inst = null; // free object refs 1457 } 1458 } 1459 1460 // Create instance 1461 else { 1462 WPVSlider.getInstance(o, opt); 1463 } 1464 }); 1465 1466 _args = null; // free object refs 1467 return isMethodCall ? result : this; 1468 }; 1469 1470 $(window).bind("keydown", function(e) { 1471 if (e.shiftKey) { 1472 //console.log(e.keyCode); 1473 switch (e.keyCode) { 1474 case 67: // Shift + C 1475 jQuery('.wpv-view').wpvSlider("setResizing", "crop"); 1476 break; 1477 case 70: // Shift + F 1478 jQuery('.wpv-view').wpvSlider("setResizing", "fit"); 1479 break; 1480 case 83: // Shift + S 1481 jQuery('.wpv-view').wpvSlider("setResizing", "stretch"); 1482 break; 1483 } 1484 } 1485 }) 1486 1487})(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.