1/*! 2 * jQuery.BgSwitcher 3 * 4 * @version 0.4.3 5 * @author rewish <[email protected]> 6 * @license MIT License (https://github.com/rewish/jquery-bgswitcher/blob/master/LICENSE.md) 7 * @link https://github.com/rewish/jquery-bgswitcher 8 */ 9(function($) { 10 'use strict'; 11 12 var loadedImages = {}, 13 14 slice = Array.prototype.slice, 15 toString = Object.prototype.toString, 16 17 corners = ['Top', 'Right', 'Bottom', 'Left'], 18 backgroundProperties = [ 19 'Attachment', 'Color', 'Image', 'Repeat', 20 'Position', 'Size', 'Clip', 'Origin' 21 ]; 22 23 $.fn.bgswitcher = function() { 24 var args = arguments, 25 instanceKey = BgSwitcher.keys.instance; 26 27 return this.each(function() { 28 var instance = $.data(this, instanceKey); 29 30 if (!instance) { 31 instance = new BgSwitcher(this); 32 $.data(this, instanceKey, instance); 33 } 34 35 instance.dispatch.apply(instance, args); 36 }); 37 }; 38 39 // Backward Compatibility 40 $.fn.bgSwitcher = $.fn.bgswitcher; 41 42 /** 43 * BgSwitcher 44 * 45 * @param {HTMLElement} el 46 * @constructor 47 */ 48 function BgSwitcher(el) { 49 this.$el = $(el); 50 this.index = 0; 51 this.config = $.extend({}, BgSwitcher.defaultConfig); 52 53 this._setupBackgroundElement(); 54 this._listenToResize(); 55 } 56 57 $.extend(BgSwitcher.prototype, { 58 /** 59 * Dispatch 60 * 61 * @param {string|Array} one 62 */ 63 dispatch: function(one) { 64 switch (toString.call(one)) { 65 case '[object Object]': 66 this.setConfig(one); 67 break; 68 case '[object String]': 69 this[one].apply(this, slice.call(arguments, 1)); 70 break; 71 default: 72 throw new Error('Please specify a Object or String'); 73 } 74 }, 75 76 /** 77 * Set config 78 * 79 * @param {Object} config 80 */ 81 setConfig: function(config) { 82 this.config = $.extend(this.config, config); 83 84 if (typeof this.config.random !== 'undefined') { 85 this.config.shuffle = this.config.random; 86 } 87 88 this.refresh(); 89 }, 90 91 /** 92 * Set images 93 * 94 * @param {Array} images 95 */ 96 setImages: function(images) { 97 this.imageList = new this.constructor.ImageList(images); 98 99 if (this.config.shuffle) { 100 this.imageList.shuffle(); 101 } 102 }, 103 104 /** 105 * Set switch handler 106 * 107 * @param {Function} fn 108 */ 109 setSwitchHandler: function(fn) { 110 this.switchHandler = $.proxy(fn, this); 111 }, 112 113 /** 114 * Default switch handler 115 * 116 * @param {string} type 117 * @returns {Function} 118 */ 119 getBuiltInSwitchHandler: function(type) { 120 return this.constructor.switchHandlers[type || this.config.effect]; 121 }, 122 123 /** 124 * Refresh 125 */ 126 refresh: function() { 127 this.setImages(this.config.images); 128 this.setSwitchHandler(this.getBuiltInSwitchHandler()); 129 this._prepareSwitching(); 130 131 if (this.config.start) { 132 this.start(); 133 } 134 }, 135 136 /** 137 * Start switching 138 */ 139 start: function() { 140 if (!this._timerID) { 141 this._timerID = setTimeout($.proxy(this, 'next'), this.config.interval); 142 } 143 }, 144 145 /** 146 * Stop switching 147 */ 148 stop: function() { 149 if (this._timerID) { 150 clearTimeout(this._timerID); 151 this._timerID = null; 152 } 153 }, 154 155 /** 156 * Toggle between start/stop 157 */ 158 toggle: function() { 159 if (this._timerID) { 160 this.stop(); 161 } else { 162 this.start(); 163 } 164 }, 165 166 /** 167 * Reset switching 168 */ 169 reset: function() { 170 this.index = 0; 171 this._prepareSwitching(); 172 }, 173 174 /** 175 * Go to next switching 176 */ 177 next: function() { 178 var max = this.imageList.count(); 179 180 if (!this.config.loop && this.index + 1 === max) { 181 return; 182 } 183 184 if (++this.index === max) { 185 this.index = 0; 186 } 187 188 this.switching(); 189 }, 190 191 /** 192 * Go to previous switching 193 */ 194 prev: function() { 195 if (!this.config.loop && this.index === 0) { 196 return; 197 } 198 199 if (--this.index === -1) { 200 this.index = this.imageList.count() - 1; 201 } 202 203 this.switching(); 204 }, 205 206 /** 207 * Select the switching at index 208 * 209 * @param {number} index 210 */ 211 select: function(index) { 212 if (index === -1) { 213 index = this.imageList.count() - 1; 214 } 215 216 this.index = index; 217 this.switching(); 218 }, 219 220 /** 221 * Switching the background image 222 */ 223 switching: function() { 224 var started = !!this._timerID; 225 226 if (started) { 227 this.stop(); 228 } 229 230 this._createSwitchableElement(); 231 this._prepareSwitching(); 232 this.switchHandler(this.$switchable); 233 234 if (started) { 235 this.start(); 236 } 237 }, 238 239 /** 240 * Destroy... 241 */ 242 destroy: function() { 243 this.stop(); 244 this._stopListeningToResize(); 245 246 if (this.$switchable) { 247 this.$switchable.stop(); 248 this.$switchable.remove(); 249 this.$switchable = null; 250 } 251 252 if (this.$bg) { 253 this.$bg.remove(); 254 this.$bg = null; 255 } 256 257 this.$el.removeAttr('style'); 258 this.$el.removeData(this.constructor.keys.instance); 259 this.$el = null; 260 }, 261 262 /** 263 * Adjust rectangle 264 */ 265 _adjustRectangle: function() { 266 var corner, 267 i = 0, 268 length = corners.length, 269 offset = this.$el.position(), 270 copiedStyles = { 271 top: offset.top, 272 left: offset.left, 273 width: this.$el.innerWidth(),
274 height: this.$el.innerHeight() 275 }; 276 277 for (; i < length; i++) { 278 corner = corners[i]; 279 copiedStyles['margin' + corner] = this.$el.css('margin' + corner); 280 copiedStyles['border' + corner] = this.$el.css('border' + corner); 281 } 282 283 this.$bg.css(copiedStyles); 284 }, 285 286 /** 287 * Setup background element 288 */ 289 _setupBackgroundElement: function() { 290 this.$bg = $(document.createElement('div')); 291 this.$bg.css({ 292 position: 'absolute', 293 zIndex: (parseInt(this.$el.css('zIndex'), 10) || 0) - 1, 294 overflow: 'hidden' 295 }); 296 297 this._copyBackgroundStyles(); 298 this._adjustRectangle(); 299 300 if (this.$el[0].tagName === 'BODY') { 301 this.$el.prepend(this.$bg); 302 } else { 303 this.$el.before(this.$bg); 304 this.$el.css('background', 'none'); 305 } 306 }, 307 308 /** 309 * Create switchable element 310 */ 311 _createSwitchableElement: function() { 312 if (this.$switchable) { 313 this.$switchable.remove(); 314 } 315 316 this.$switchable = this.$bg.clone(); 317 this.$switchable.css({top: 0, left: 0, margin: 0, border: 'none'}); 318 this.$switchable.appendTo(this.$bg); 319 }, 320 321 /** 322 * Copy background styles 323 */ 324 _copyBackgroundStyles: function () { 325 var prop, 326 copiedStyle = {}, 327 i = 0, 328 length = backgroundProperties.length, 329 backgroundPosition = 'backgroundPosition'; 330 331 for (; i < length; i++) { 332 prop = 'background' + backgroundProperties[i]; 333 copiedStyle[prop] = this.$el.css(prop); 334 } 335 336 // For IE<=9 337 if (copiedStyle[backgroundPosition] === undefined) { 338 copiedStyle[backgroundPosition] = [ 339 this.$el.css(backgroundPosition + 'X'), 340 this.$el.css(backgroundPosition + 'Y') 341 ].join(' '); 342 } 343 344 this.$bg.css(copiedStyle); 345 }, 346 347 /** 348 * Listen to the resize event 349 */ 350 _listenToResize: function() { 351 var that = this; 352 this._resizeHandler = function() { 353 that._adjustRectangle(); 354 }; 355 $(window).on('resize', this._resizeHandler); 356 }, 357 358 /** 359 * Stop listening to the resize event 360 */ 361 _stopListeningToResize: function() { 362 $(window).off('resize', this._resizeHandler); 363 this._resizeHandler = null; 364 }, 365 366 /** 367 * Prepare the Switching 368 */ 369 _prepareSwitching: function() { 370 this.$bg.css('backgroundImage', this.imageList.url(this.index)); 371 } 372 }); 373 374 /** 375 * Data Keys 376 * @type {Object} 377 */ 378 BgSwitcher.keys = { 379 instance: 'bgSwitcher' 380 }; 381 382 /** 383 * Default Config 384 * @type {Object} 385 */ 386 BgSwitcher.defaultConfig = { 387 images: [], 388 interval: 5000, 389 start: true, 390 loop: true, 391 shuffle: false, 392 effect: 'fade', 393 duration: 1000, 394 easing: 'swing' 395 }; 396 397 /** 398 * Built-In switch handlers (effects) 399 * @type {Object} 400 */ 401 BgSwitcher.switchHandlers = { 402 fade: function($el) { 403 $el.animate({opacity: 0}, this.config.duration, this.config.easing); 404 }, 405 406 blind: function($el) { 407 $el.animate({height: 0}, this.config.duration, this.config.easing); 408 }, 409 410 clip: function($el) { 411 $el.animate({ 412 top: parseInt($el.css('top'), 10) + $el.height() / 2, 413 height: 0 414 }, this.config.duration, this.config.easing); 415 }, 416 417 slide: function($el) { 418 $el.animate({top: -$el.height()}, this.config.duration, this.config.easing); 419 }, 420 421 drop: function($el) { 422 $el.animate({ 423 left: -$el.width(), 424 opacity: 0 425 }, this.config.duration, this.config.easing); 426 }, 427 428 hide: function($el) { 429 $el.hide(); 430 } 431 }; 432 433 /** 434 * Define effect 435 * 436 * @param {String} name 437 * @param {Function} fn 438 */ 439 BgSwitcher.defineEffect = function(name, fn) { 440 this.switchHandlers[name] = fn; 441 }; 442 443 /** 444 * BgSwitcher.ImageList 445 * 446 * @param {Array} images 447 * @constructor 448 */ 449 BgSwitcher.ImageList = function(images) { 450 this.images = images; 451 this.createImagesBySequence(); 452 this.preload(); 453 }; 454 455 $.extend(BgSwitcher.ImageList.prototype, { 456 /** 457 * Images is sequenceable 458 * 459 * @returns {boolean} 460 */ 461 isSequenceable: function() { 462 return typeof this.images[0] === 'string' && 463 typeof this.images[1] === 'number' && 464 typeof this.images[2] === 'number'; 465 }, 466 467 /** 468 * Create an images by sequence 469 */ 470 createImagesBySequence: function() { 471 if (!this.isSequenceable()) { 472 return; 473 } 474 475 var images = [], 476 base = this.images[0], 477 min = this.images[1], 478 max = this.images[2]; 479 480 do { 481 images.push(base.replace(/\.\w+$/, min + '$&')); 482 } while (++min <= max); 483 484 this.images = images; 485 }, 486 487 /** 488 * Preload an images 489 */ 490 preload: function() { 491 var path, 492 length = this.images.length, 493 i = 0; 494 495 for (; i < length; i++) { 496 path = this.images[i]; 497 if (!loadedImages[path]) { 498 loadedImages[path] = new Image(); 499 loadedImages[path].src = path; 500 } 501 } 502 }, 503 504 /** 505 * Shuffle an images 506 */ 507 shuffle: function() { 508 var j, t, 509 i = this.images.length, 510 original = this.images.join(); 511 512 if (!i) { 513 return; 514 } 515 516 while (i) { 517 j = Math.floor(Math.random() * i); 518 t = this.images[--i]; 519 this.images[i] = this.images[j]; 520 this.images[j] = t; 521 } 522 523 if (this.images.join() === original) { 524 this.shuffle(); 525 } 526 }, 527 528 /** 529 * Get the image from index 530 * 531 * @param {number} index 532 * @returns {string} 533 */ 534 get: function(index) { 535 return this.images[index]; 536 }, 537 538 /** 539 * Get the URL with function of CSS 540 * 541 * @param {number} index 542 * @returns {string} 543 */ 544 url: function(index) { 545 return 'url(' + this.get(index) + ')'; 546 }, 547 548 /** 549 * Count of images 550 * 551 * @returns {number} 552 */ 553 count: function() { 554 return this.images.length; 555 } 556 }); 557 558 $.BgSwitcher = BgSwitcher; 559}(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.