Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | espaco | 1 | /*! Backstretch - v2.0.4 - 2013-06-19 |
| 2 | * http://srobbin.com/jquery-plugins/backstretch/ |
||
| 3 | * Copyright (c) 2013 Scott Robbin; Licensed MIT */ |
||
| 4 | |||
| 5 | ;(function ($, window, undefined) { |
||
| 6 | 'use strict'; |
||
| 7 | |||
| 8 | /* PLUGIN DEFINITION |
||
| 9 | * ========================= */ |
||
| 10 | |||
| 11 | $.fn.backstretch = function (images, options) { |
||
| 12 | // We need at least one image or method name |
||
| 13 | if (images === undefined || images.length === 0) { |
||
| 14 | $.error("No images were supplied for Backstretch"); |
||
| 15 | } |
||
| 16 | |||
| 17 | /* |
||
| 18 | * Scroll the page one pixel to get the right window height on iOS |
||
| 19 | * Pretty harmless for everyone else |
||
| 20 | */ |
||
| 21 | if ($(window).scrollTop() === 0 ) { |
||
| 22 | window.scrollTo(0, 0); |
||
| 23 | } |
||
| 24 | |||
| 25 | return this.each(function () { |
||
| 26 | var $this = $(this) |
||
| 27 | , obj = $this.data('backstretch'); |
||
| 28 | |||
| 29 | // Do we already have an instance attached to this element? |
||
| 30 | if (obj) { |
||
| 31 | |||
| 32 | // Is this a method they're trying to execute? |
||
| 33 | if (typeof images == 'string' && typeof obj[images] == 'function') { |
||
| 34 | // Call the method |
||
| 35 | obj[images](options); |
||
| 36 | |||
| 37 | // No need to do anything further |
||
| 38 | return; |
||
| 39 | } |
||
| 40 | |||
| 41 | // Merge the old options with the new |
||
| 42 | options = $.extend(obj.options, options); |
||
| 43 | |||
| 44 | // Remove the old instance |
||
| 45 | obj.destroy(true); |
||
| 46 | } |
||
| 47 | |||
| 48 | obj = new Backstretch(this, images, options); |
||
| 49 | $this.data('backstretch', obj); |
||
| 50 | }); |
||
| 51 | }; |
||
| 52 | |||
| 53 | // If no element is supplied, we'll attach to body |
||
| 54 | $.backstretch = function (images, options) { |
||
| 55 | // Return the instance |
||
| 56 | return $('body') |
||
| 57 | .backstretch(images, options) |
||
| 58 | .data('backstretch'); |
||
| 59 | }; |
||
| 60 | |||
| 61 | // Custom selector |
||
| 62 | $.expr[':'].backstretch = function(elem) { |
||
| 63 | return $(elem).data('backstretch') !== undefined; |
||
| 64 | }; |
||
| 65 | |||
| 66 | /* DEFAULTS |
||
| 67 | * ========================= */ |
||
| 68 | |||
| 69 | $.fn.backstretch.defaults = { |
||
| 70 | centeredX: true // Should we center the image on the X axis? |
||
| 71 | , centeredY: true // Should we center the image on the Y axis? |
||
| 72 | , duration: 5000 // Amount of time in between slides (if slideshow) |
||
| 73 | , fade: 0 // Speed of fade transition between slides |
||
| 74 | }; |
||
| 75 | |||
| 76 | /* STYLES |
||
| 77 | * |
||
| 78 | * Baked-in styles that we'll apply to our elements. |
||
| 79 | * In an effort to keep the plugin simple, these are not exposed as options. |
||
| 80 | * That said, anyone can override these in their own stylesheet. |
||
| 81 | * ========================= */ |
||
| 82 | var styles = { |
||
| 83 | wrap: { |
||
| 84 | left: 0 |
||
| 85 | , top: 0 |
||
| 86 | , overflow: 'hidden' |
||
| 87 | , margin: 0 |
||
| 88 | , padding: 0 |
||
| 89 | , height: '100%' |
||
| 90 | , width: '100%' |
||
| 91 | , zIndex: -999999 |
||
| 92 | } |
||
| 93 | , img: { |
||
| 94 | position: 'absolute' |
||
| 95 | , display: 'none' |
||
| 96 | , margin: 0 |
||
| 97 | , padding: 0 |
||
| 98 | , border: 'none' |
||
| 99 | , width: 'auto' |
||
| 100 | , height: 'auto' |
||
| 101 | , maxHeight: 'none' |
||
| 102 | , maxWidth: 'none' |
||
| 103 | , zIndex: -999999 |
||
| 104 | } |
||
| 105 | }; |
||
| 106 | |||
| 107 | /* CLASS DEFINITION |
||
| 108 | * ========================= */ |
||
| 109 | var Backstretch = function (container, images, options) { |
||
| 110 | this.options = $.extend({}, $.fn.backstretch.defaults, options || {}); |
||
| 111 | |||
| 112 | /* In its simplest form, we allow Backstretch to be called on an image path. |
||
| 113 | * e.g. $.backstretch('/path/to/image.jpg') |
||
| 114 | * So, we need to turn this back into an array. |
||
| 115 | */ |
||
| 116 | this.images = $.isArray(images) ? images : [images]; |
||
| 117 | |||
| 118 | // Preload images |
||
| 119 | $.each(this.images, function () { |
||
| 120 | $('<img />')[0].src = this; |
||
| 121 | }); |
||
| 122 | |||
| 123 | // Convenience reference to know if the container is body. |
||
| 124 | this.isBody = container === document.body; |
||
| 125 | |||
| 126 | /* We're keeping track of a few different elements |
||
| 127 | * |
||
| 128 | * Container: the element that Backstretch was called on. |
||
| 129 | * Wrap: a DIV that we place the image into, so we can hide the overflow. |
||
| 130 | * Root: Convenience reference to help calculate the correct height. |
||
| 131 | */ |
||
| 132 | this.$container = $(container); |
||
| 133 | this.$root = this.isBody ? supportsFixedPosition ? $(window) : $(document) : this.$container; |
||
| 134 | |||
| 135 | // Don't create a new wrap if one already exists (from a previous instance of Backstretch) |
||
| 136 | var $existing = this.$container.children(".backstretch").first(); |
||
| 137 | this.$wrap = $existing.length ? $existing : $('<div class="backstretch"></div>').css(styles.wrap).appendTo(this.$container); |
||
| 138 | |||
| 139 | // Non-body elements need some style adjustments |
||
| 140 | if (!this.isBody) { |
||
| 141 | // If the container is statically positioned, we need to make it relative, |
||
| 142 | // and if no zIndex is defined, we should set it to zero. |
||
| 143 | var position = this.$container.css('position') |
||
| 144 | , zIndex = this.$container.css('zIndex'); |
||
| 145 | |||
| 146 | this.$container.css({ |
||
| 147 | position: position === 'static' ? 'relative' : position |
||
| 148 | , zIndex: zIndex === 'auto' ? 0 : zIndex |
||
| 149 | , background: 'none' |
||
| 150 | }); |
||
| 151 | |||
| 152 | // Needs a higher z-index |
||
| 153 | this.$wrap.css({zIndex: -999998}); |
||
| 154 | } |
||
| 155 | |||
| 156 | // Fixed or absolute positioning? |
||
| 157 | this.$wrap.css({ |
||
| 158 | position: this.isBody && supportsFixedPosition ? 'fixed' : 'absolute' |
||
| 159 | }); |
||
| 160 | |||
| 161 | // Set the first image |
||
| 162 | this.index = 0; |
||
| 163 | this.show(this.index); |
||
| 164 | |||
| 165 | // Listen for resize |
||
| 166 | $(window).on('resize.backstretch', $.proxy(this.resize, this)) |
||
| 167 | .on('orientationchange.backstretch', $.proxy(function () { |
||
| 168 | // Need to do this in order to get the right window height |
||
| 169 | if (this.isBody && window.pageYOffset === 0) { |
||
| 170 | window.scrollTo(0, 1); |
||
| 171 | this.resize(); |
||
| 172 | } |
||
| 173 | }, this)); |
||
| 174 | }; |
||
| 175 | |||
| 176 | /* PUBLIC METHODS |
||
| 177 | * ========================= */ |
||
| 178 | Backstretch.prototype = { |
||
| 179 | resize: function () { |
||
| 180 | try { |
||
| 181 | var bgCSS = {left: 0, top: 0} |
||
| 182 | , rootWidth = this.isBody ? this.$root.width() : this.$root.innerWidth() |
||
| 183 | , bgWidth = rootWidth |
||
| 184 | , rootHeight = this.isBody ? ( window.innerHeight ? window.innerHeight : this.$root.height() ) : this.$root.innerHeight() |
||
| 185 | , bgHeight = bgWidth / this.$img.data('ratio') |
||
| 186 | , bgOffset; |
||
| 187 | |||
| 188 | // Make adjustments based on image ratio |
||
| 189 | if (bgHeight >= rootHeight) { |
||
| 190 | bgOffset = (bgHeight - rootHeight) / 2; |
||
| 191 | if(this.options.centeredY) { |
||
| 192 | bgCSS.top = '-' + bgOffset + 'px'; |
||
| 193 | } |
||
| 194 | } else { |
||
| 195 | bgHeight = rootHeight; |
||
| 196 | bgWidth = bgHeight * this.$img.data('ratio'); |
||
| 197 | bgOffset = (bgWidth - rootWidth) / 2; |
||
| 198 | if(this.options.centeredX) { |
||
| 199 | bgCSS.left = '-' + bgOffset + 'px'; |
||
| 200 | } |
||
| 201 | } |
||
| 202 | |||
| 203 | this.$wrap.css({width: rootWidth, height: rootHeight}) |
||
| 204 | .find('img:not(.deleteable)').css({width: bgWidth, height: bgHeight}).css(bgCSS); |
||
| 205 | } catch(err) { |
||
| 206 | // IE7 seems to trigger resize before the image is loaded. |
||
| 207 | // This try/catch block is a hack to let it fail gracefully. |
||
| 208 | } |
||
| 209 | |||
| 210 | return this; |
||
| 211 | } |
||
| 212 | |||
| 213 | // Show the slide at a certain position |
||
| 214 | , show: function (newIndex) { |
||
| 215 | |||
| 216 | // Validate index |
||
| 217 | if (Math.abs(newIndex) > this.images.length - 1) { |
||
| 218 | return; |
||
| 219 | } |
||
| 220 | |||
| 221 | // Vars |
||
| 222 | var self = this |
||
| 223 | , oldImage = self.$wrap.find('img').addClass('deleteable') |
||
| 224 | , evtOptions = { relatedTarget: self.$container[0] }; |
||
| 225 | |||
| 226 | // Trigger the "before" event |
||
| 227 | self.$container.trigger($.Event('backstretch.before', evtOptions), [self, newIndex]); |
||
| 228 | |||
| 229 | // Set the new index |
||
| 230 | this.index = newIndex; |
||
| 231 | |||
| 232 | // Pause the slideshow |
||
| 233 | clearInterval(self.interval); |
||
| 234 | |||
| 235 | // New image |
||
| 236 | self.$img = $('<img />') |
||
| 237 | .css(styles.img) |
||
| 238 | .bind('load', function (e) { |
||
| 239 | var imgWidth = this.width || $(e.target).width() |
||
| 240 | , imgHeight = this.height || $(e.target).height(); |
||
| 241 | |||
| 242 | // Save the ratio |
||
| 243 | $(this).data('ratio', imgWidth / imgHeight); |
||
| 244 | |||
| 245 | // Show the image, then delete the old one |
||
| 246 | // "speed" option has been deprecated, but we want backwards compatibilty |
||
| 247 | $(this).fadeIn(self.options.speed || self.options.fade, function () { |
||
| 248 | oldImage.remove(); |
||
| 249 | |||
| 250 | // Resume the slideshow |
||
| 251 | if (!self.paused) { |
||
| 252 | self.cycle(); |
||
| 253 | } |
||
| 254 | |||
| 255 | // Trigger the "after" and "show" events |
||
| 256 | // "show" is being deprecated |
||
| 257 | $(['after', 'show']).each(function () { |
||
| 258 | self.$container.trigger($.Event('backstretch.' + this, evtOptions), [self, newIndex]); |
||
| 259 | }); |
||
| 260 | }); |
||
| 261 | |||
| 262 | // Resize |
||
| 263 | self.resize(); |
||
| 264 | }) |
||
| 265 | .appendTo(self.$wrap); |
||
| 266 | |||
| 267 | // Hack for IE img onload event |
||
| 268 | self.$img.attr('src', self.images[newIndex]); |
||
| 269 | return self; |
||
| 270 | } |
||
| 271 | |||
| 272 | , next: function () { |
||
| 273 | // Next slide |
||
| 274 | return this.show(this.index < this.images.length - 1 ? this.index + 1 : 0); |
||
| 275 | } |
||
| 276 | |||
| 277 | , prev: function () { |
||
| 278 | // Previous slide |
||
| 279 | return this.show(this.index === 0 ? this.images.length - 1 : this.index - 1); |
||
| 280 | } |
||
| 281 | |||
| 282 | , pause: function () { |
||
| 283 | // Pause the slideshow |
||
| 284 | this.paused = true; |
||
| 285 | return this; |
||
| 286 | } |
||
| 287 | |||
| 288 | , resume: function () { |
||
| 289 | // Resume the slideshow |
||
| 290 | this.paused = false; |
||
| 291 | this.next(); |
||
| 292 | return this; |
||
| 293 | } |
||
| 294 | |||
| 295 | , cycle: function () { |
||
| 296 | // Start/resume the slideshow |
||
| 297 | if(this.images.length > 1) { |
||
| 298 | // Clear the interval, just in case |
||
| 299 | clearInterval(this.interval); |
||
| 300 | |||
| 301 | this.interval = setInterval($.proxy(function () { |
||
| 302 | // Check for paused slideshow |
||
| 303 | if (!this.paused) { |
||
| 304 | this.next(); |
||
| 305 | } |
||
| 306 | }, this), this.options.duration); |
||
| 307 | } |
||
| 308 | return this; |
||
| 309 | } |
||
| 310 | |||
| 311 | , destroy: function (preserveBackground) { |
||
| 312 | // Stop the resize events |
||
| 313 | $(window).off('resize.backstretch orientationchange.backstretch'); |
||
| 314 | |||
| 315 | // Clear the interval |
||
| 316 | clearInterval(this.interval); |
||
| 317 | |||
| 318 | // Remove Backstretch |
||
| 319 | if(!preserveBackground) { |
||
| 320 | this.$wrap.remove(); |
||
| 321 | } |
||
| 322 | this.$container.removeData('backstretch'); |
||
| 323 | } |
||
| 324 | }; |
||
| 325 | |||
| 326 | /* SUPPORTS FIXED POSITION? |
||
| 327 | * |
||
| 328 | * Based on code from jQuery Mobile 1.1.0 |
||
| 329 | * http://jquerymobile.com/ |
||
| 330 | * |
||
| 331 | * In a nutshell, we need to figure out if fixed positioning is supported. |
||
| 332 | * Unfortunately, this is very difficult to do on iOS, and usually involves |
||
| 333 | * injecting content, scrolling the page, etc.. It's ugly. |
||
| 334 | * jQuery Mobile uses this workaround. It's not ideal, but works. |
||
| 335 | * |
||
| 336 | * Modified to detect IE6 |
||
| 337 | * ========================= */ |
||
| 338 | |||
| 339 | var supportsFixedPosition = (function () { |
||
| 340 | var ua = navigator.userAgent |
||
| 341 | , platform = navigator.platform |
||
| 342 | // Rendering engine is Webkit, and capture major version |
||
| 343 | , wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ ) |
||
| 344 | , wkversion = !!wkmatch && wkmatch[ 1 ] |
||
| 345 | , ffmatch = ua.match( /Fennec\/([0-9]+)/ ) |
||
| 346 | , ffversion = !!ffmatch && ffmatch[ 1 ] |
||
| 347 | , operammobilematch = ua.match( /Opera Mobi\/([0-9]+)/ ) |
||
| 348 | , omversion = !!operammobilematch && operammobilematch[ 1 ] |
||
| 349 | , iematch = ua.match( /MSIE ([0-9]+)/ ) |
||
| 350 | , ieversion = !!iematch && iematch[ 1 ]; |
||
| 351 | |||
| 352 | return !( |
||
| 353 | // iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5) |
||
| 354 | ((platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1 || platform.indexOf( "iPod" ) > -1 ) && wkversion && wkversion < 534) || |
||
| 355 | |||
| 356 | // Opera Mini |
||
| 357 | (window.operamini && ({}).toString.call( window.operamini ) === "[object OperaMini]") || |
||
| 358 | (operammobilematch && omversion < 7458) || |
||
| 359 | |||
| 360 | //Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2) |
||
| 361 | (ua.indexOf( "Android" ) > -1 && wkversion && wkversion < 533) || |
||
| 362 | |||
| 363 | // Firefox Mobile before 6.0 - |
||
| 364 | (ffversion && ffversion < 6) || |
||
| 365 | |||
| 366 | // WebOS less than 3 |
||
| 367 | ("palmGetResource" in window && wkversion && wkversion < 534) || |
||
| 368 | |||
| 369 | // MeeGo |
||
| 370 | (ua.indexOf( "MeeGo" ) > -1 && ua.indexOf( "NokiaBrowser/8.5.0" ) > -1) || |
||
| 371 | |||
| 372 | // IE6 |
||
| 373 | (ieversion && ieversion <= 6) |
||
| 374 | ); |
||
| 375 | }()); |
||
| 376 | |||
| 377 | }(jQuery, window)); |