Subversion Repositories Integrator Subversion

Rev

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));