├── .gitmodules ├── .travis.yml ├── LICENSE.md ├── README.md ├── bgswitcher.jquery.json ├── demo ├── images │ ├── image_1.jpg │ ├── image_2.jpg │ ├── image_3.jpg │ ├── image_4.jpg │ └── image_5.jpg ├── index.html └── style.css ├── jquery.bgswitcher.js ├── lib └── jquery.js └── test ├── bg_switcher_spec.js ├── image_list_spec.js └── index.html /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/mocha"] 2 | path = lib/mocha 3 | url = https://github.com/visionmedia/mocha.git 4 | [submodule "lib/expect"] 5 | path = lib/expect 6 | url = https://github.com/LearnBoost/expect.js.git 7 | [submodule "lib/mocha-phantomjs"] 8 | path = lib/mocha-phantomjs 9 | url = https://github.com/metaskills/mocha-phantomjs.git 10 | [submodule "lib/sinon"] 11 | path = lib/sinon 12 | url = https://github.com/cjohansen/Sinon.JS.git 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | script: phantomjs lib/mocha-phantomjs/lib/mocha-phantomjs.coffee test/index.html -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2009 rewish 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jQuery.BgSwitcher [![Build Status](https://travis-ci.org/rewish/jquery-bgswitcher.png?branch=master)](https://travis-ci.org/rewish/jquery-bgswitcher) 2 | ========================= 3 | 4 | Switch the background image with using effect. 5 | 6 | Demo 7 | ------------------------- 8 | 9 | http://rewish.github.io/jquery-bgswitcher/ 10 | 11 | Usage 12 | ------------------------- 13 | 14 | ```html 15 |
16 |

Lorem ipsum dolor sit amet.

17 |
18 | ``` 19 | 20 | ```js 21 | $(".box").bgswitcher({ 22 | images: ["pic1.jpg", "pic2.jpg", "pic3.jpg"], 23 | ... Something Config ... 24 | }); 25 | ``` 26 | 27 | For example, if you want to disable the loop of switching: 28 | 29 | ```js 30 | $(".box").bgswitcher({ 31 | images: ["pic1.jpg", "pic2.jpg", "pic3.jpg"], 32 | loop: false 33 | }); 34 | ``` 35 | 36 | Configs 37 | ------------------------- 38 | 39 | | Key | Type | Default | Description | 40 | | -------- | ------- | ------- | ------------| 41 | | images | array | [] | Background images | 42 | | interval | number | 5000 | Interval of switching | 43 | | start | boolean | true | Start the switch on after initialization ([Calling the Methods](#calling-the-methods)) | 44 | | loop | boolean | true | Loop the switch | 45 | | shuffle | boolean | false | Shuffle the image order | 46 | | effect | string | fade | Effect type ([Built-In effect types](#built-in-effect-types)) | 47 | | duration | number | 1000 | Effect duration | 48 | | easing | string | swing | Effect easing | 49 | 50 | Effect Types 51 | ------------------------- 52 | 53 | ### Built-In effect types 54 | 55 | * fade 56 | * blind 57 | * clip 58 | * slide 59 | * drop 60 | * hide (No effect) 61 | 62 | ### Adding the effect type 63 | 64 | First, define effect with using the `$.BgSwitcher.defineEffect()`. 65 | 66 | ```js 67 | $.BgSwitcher.defineEffect("extraSlide", function($el) { 68 | $el.animate({left: $el.width()}, this.config.duration, this.config.easing); 69 | }); 70 | ``` 71 | 72 | Then, specify the effect name that you added. 73 | 74 | ```js 75 | $(".box").bgswitcher({ 76 | images: ["pic1.jpg", "pic2.jpg", "pic3.jpg"], 77 | effect: "extraSlide" 78 | }); 79 | ``` 80 | 81 | Calling the Methods 82 | ------------------------- 83 | 84 | Support the method calls like jQuery UI Widget. 85 | 86 | ```js 87 | $(".box").bgswitcher("method name"); 88 | ``` 89 | 90 | You can call various methods, For example: 91 | 92 | Name | Description 93 | ------- | ----------------------------- 94 | start | Start the switching 95 | stop | Stop the switching 96 | toggle | Toggle between start/stop 97 | reset | Return to the first switching 98 | select | Select the switching at index 99 | next | Go to the next switching 100 | prev | Go to the previous switching 101 | destroy | !!Destroy BgSwitcher!! 102 | 103 | Example for `select` with button: 104 | 105 | ```js 106 | var $el = $(".box").bgswitcher({ 107 | images: ["foo.jpg", "bar.jpg", "baz.jpg"] 108 | }); 109 | 110 | $("button").on("click", function() { 111 | $el.bgswitcher("select", 1); // bar.jpg 112 | }); 113 | ``` 114 | 115 | Dependencies 116 | ------------------------- 117 | 118 | Requires jQuery 1.7.x or higher. 119 | 120 | Support browsers 121 | ------------------------- 122 | 123 | * IE7+ 124 | * and modern browsers 125 | * Mobile Safari 126 | 127 | Running the Tests 128 | ------------------------- 129 | 130 | Setup the modules required for testing. 131 | 132 | ```sh 133 | git submodule update --init --recursive 134 | ``` 135 | 136 | You can testing in two ways: 137 | 138 | * Open the `test/index.html` in the Web browser 139 | * Command Line Testing with the PhantomJS 140 | 141 | ```sh 142 | phantomjs lib/mocha-phantomjs/lib/mocha-phantomjs.coffee test/index.html 143 | ``` 144 | 145 | License 146 | ------------------------- 147 | 148 | The [MIT License](https://github.com/rewish/jquery-bgswitcher/blob/master/LICENSE.md), Copyright (c) 2009-2014 [@rewish](https://github.com/rewish). 149 | -------------------------------------------------------------------------------- /bgswitcher.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bgswitcher", 3 | "version": "0.4.3", 4 | "title": "jQuery.BgSwitcher", 5 | "author": { 6 | "name": "rewish", 7 | "email": "rewish.org@gmail.com", 8 | "url": "https://github.com/rewish" 9 | }, 10 | "licenses": [ 11 | { 12 | "type": "MIT", 13 | "url": "https://github.com/rewish/jquery-bgswitcher/blob/master/LICENSE.md" 14 | } 15 | ], 16 | "dependencies": { 17 | "jquery": ">=1.7" 18 | }, 19 | "description": "Switch the background image with using effect.", 20 | "keywords": ["image", "gallery"], 21 | "docs": "https://github.com/rewish/jquery-bgswitcher#readme", 22 | "demo": "http://rewish.github.io/jquery-bgswitcher/", 23 | "bugs": "https://github.com/rewish/jquery-bgswitcher/issues" 24 | } 25 | -------------------------------------------------------------------------------- /demo/images/image_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rewish/jquery-bgswitcher/ae9d4054f468174513f46e30ca8f569868062323/demo/images/image_1.jpg -------------------------------------------------------------------------------- /demo/images/image_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rewish/jquery-bgswitcher/ae9d4054f468174513f46e30ca8f569868062323/demo/images/image_2.jpg -------------------------------------------------------------------------------- /demo/images/image_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rewish/jquery-bgswitcher/ae9d4054f468174513f46e30ca8f569868062323/demo/images/image_3.jpg -------------------------------------------------------------------------------- /demo/images/image_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rewish/jquery-bgswitcher/ae9d4054f468174513f46e30ca8f569868062323/demo/images/image_4.jpg -------------------------------------------------------------------------------- /demo/images/image_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rewish/jquery-bgswitcher/ae9d4054f468174513f46e30ca8f569868062323/demo/images/image_5.jpg -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Demo - jQuery.BgSwitcher 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |

Demo - jQuery.BgSwitcher

15 |

Switch the background image with using effect.

16 |
17 | 18 |
19 |

Config

20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 35 | 36 | 37 | 38 | 44 | 45 | 46 | 47 | 53 | 54 | 55 |
Start 30 | 31 | 32 | 33 | 34 |
Loop 39 | 40 | 41 | 42 | 43 |
Shuffle 48 | 49 | 50 | 51 | 52 |
56 | 57 | 58 | 59 | 60 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 85 | 86 | 87 |
61 | 62 | 71 |
80 | 84 |
88 |
89 |
90 | 91 |
92 |

Demo

93 | 102 |
103 | 109 |
110 | 111 | 116 | 117 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /demo/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0 10px; 3 | padding: 0 0 50px; 4 | background: #F2F2F2; 5 | color: #222; 6 | line-height: 1; 7 | font-size: 20px; 8 | } 9 | 10 | .header, .footer, .section { 11 | display: block; 12 | width: 700px; 13 | margin: 0 auto; 14 | } 15 | 16 | .header, .footer { 17 | text-align: center; 18 | } 19 | 20 | .footer { 21 | margin-top: 1em; 22 | } 23 | 24 | h2 { 25 | margin: 1em auto 0.5em; 26 | } 27 | 28 | p { 29 | margin: 0.5em 0 0; 30 | line-height: 1.5; 31 | } 32 | 33 | p:first-child { 34 | margin-top: 0; 35 | } 36 | 37 | form { 38 | overflow: hidden; 39 | } 40 | 41 | input, label, select { 42 | vertical-align: middle; 43 | } 44 | 45 | input[type="radio"] + label { 46 | margin-right: 10px; 47 | } 48 | 49 | input[type="number"] { 50 | width: 5em; 51 | padding: 2px 5px; 52 | border: 1px solid #CCC; 53 | border-radius: 3px; 54 | font-size: 15px; 55 | } 56 | 57 | table { 58 | float: right; 59 | width: 320px; 60 | border-collapse: collapse; 61 | border-spacing: 0; 62 | } 63 | 64 | table:first-child { 65 | float: left; 66 | } 67 | 68 | th, td { 69 | height: 50px; 70 | border-bottom: 2px solid #CCC; 71 | text-align: left; 72 | vertical-align: middle; 73 | font-weight: normal; 74 | } 75 | 76 | .actions { 77 | padding: 0; 78 | overflow: hidden; 79 | vertical-align: middle; 80 | } 81 | 82 | .actions li { 83 | display: inline; 84 | list-style: none; 85 | } 86 | 87 | .box { 88 | min-height: 460px; 89 | margin: 0 auto; 90 | padding: 20px; 91 | } 92 | 93 | .box p { 94 | padding: 20px; 95 | background: rgba(255, 255, 255, .7); 96 | filter:progid:DXImageTransform.Microsoft.gradient(startcolorstr=#B2FFFFFF,endcolorstr=#B2FFFFFF,gradienttype=0); 97 | -ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#B2FFFFFF,endColorstr=#B2FFFFFF)"; 98 | zoom: 1; 99 | letter-spacing: 1px; 100 | } 101 | 102 | .box p + p { 103 | margin-top: 20px; 104 | } -------------------------------------------------------------------------------- /jquery.bgswitcher.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery.BgSwitcher 3 | * 4 | * @version 0.4.3 5 | * @author rewish 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)); 560 | -------------------------------------------------------------------------------- /test/bg_switcher_spec.js: -------------------------------------------------------------------------------- 1 | describe('jQuery.BgSwitcher', function() { 2 | var INTERVAL = 10000; 3 | 4 | var bs; 5 | var el = document.getElementById('sandbox'); 6 | 7 | beforeEach(function() { 8 | bs = new $.BgSwitcher(el); 9 | }); 10 | 11 | afterEach(function() { 12 | bs.destroy(); 13 | }); 14 | 15 | describe('#constructor', function() { 16 | it('set an element wrapped in jQuery', function() { 17 | expect(bs.$el[0]).to.be(el); 18 | }); 19 | 20 | it('set 0 to index', function() { 21 | expect(bs.index).to.be(0); 22 | }); 23 | 24 | it('set config based on the default config', function() { 25 | var key, defaultConfig = bs.constructor.defaultConfig; 26 | for (key in defaultConfig) { 27 | expect(bs.config).to.have.property(key, defaultConfig[key]); 28 | } 29 | }); 30 | 31 | it('setup background element', function() { 32 | expect(bs.$bg).to.not.be(undefined); 33 | }); 34 | 35 | it('listen to the resize event of window', function() { 36 | bs._adjustRectangle = sinon.spy(); 37 | $(window).trigger('resize'); 38 | expect(bs._adjustRectangle.calledOnce).to.be.ok(); 39 | }); 40 | }); 41 | 42 | describe('#dispatch', function() { 43 | context('when call with string', function() { 44 | it('should be call "method name" with args', function() { 45 | var first = {}, second = {}; 46 | bs.fooMethod = sinon.spy(); 47 | bs.dispatch('fooMethod', first, second); 48 | expect(bs.fooMethod.calledOnce).to.be.ok(); 49 | expect(bs.fooMethod.calledWith(first, second)).to.be.ok(); 50 | }); 51 | }); 52 | 53 | context('when call with object', function() { 54 | it('should be call #setConfig with object', function() { 55 | var object = {}; 56 | bs.setConfig = sinon.spy(); 57 | bs.dispatch(object); 58 | expect(bs.setConfig.calledOnce).to.be.ok(); 59 | expect(bs.setConfig.calledWith(object)).to.be.ok(); 60 | }); 61 | }); 62 | 63 | context('when call with unknown type', function() { 64 | it('should be throw error', function() { 65 | expect(bs.dispatch).to.throwException(); 66 | expect(bs.dispatch).withArgs(undefined).to.throwException(); 67 | expect(bs.dispatch).withArgs(function(){}).to.throwException(); 68 | }); 69 | }); 70 | }); 71 | 72 | describe('#setConfig', function() { 73 | it('merge into the config from first arg', function() { 74 | var config = {foo: {}, bar: {}}; 75 | bs.setConfig(config); 76 | expect(bs.config).to.have.property('foo', config.foo); 77 | expect(bs.config).to.have.property('bar', config.bar); 78 | }); 79 | 80 | context('when "random" is specified', function() { 81 | it('set "random" to "shuffle"', function() { 82 | bs.setConfig({random: {}}); 83 | expect(bs.config).to.have.property('shuffle', bs.config.random); 84 | }); 85 | }); 86 | 87 | it('should be call #refresh', function() { 88 | bs.refresh = sinon.spy(); 89 | bs.setConfig(); 90 | expect(bs.refresh.calledOnce).to.be.ok(); 91 | }); 92 | 93 | // Describe a more specs in #refresh 94 | }); 95 | 96 | describe('#setImages', function() { 97 | it('set an instance of ImageList to the imageList', function() { 98 | bs.setImages([]); 99 | expect(bs.imageList).to.be.an(bs.constructor.ImageList); 100 | }); 101 | }); 102 | 103 | describe('#setSwitchHandler', function() { 104 | it('set function to switchHandler', function() { 105 | bs.setSwitchHandler(function() { 106 | expect(this).to.be(bs); 107 | }); 108 | bs.switchHandler(); 109 | }); 110 | }); 111 | 112 | describe('#getBuiltInSwitchHandler', function() { 113 | it('return built-lt handler at config.effect', function() { 114 | bs.config = {effect: 'clip'}; 115 | expect(bs.getBuiltInSwitchHandler()).to.be(bs.constructor.switchHandlers.clip); 116 | }); 117 | 118 | context('when specified type', function() { 119 | it('return built-in handler at type', function() { 120 | expect(bs.getBuiltInSwitchHandler('drop')).to.be(bs.constructor.switchHandlers.drop); 121 | }); 122 | }); 123 | }); 124 | 125 | describe('#start', function() { 126 | beforeEach(function() { 127 | bs.setConfig({ 128 | interval: INTERVAL, 129 | start: false 130 | }); 131 | }); 132 | 133 | it('call #next after config.interval', function() { 134 | var clock = sinon.useFakeTimers(); 135 | 136 | bs.next = sinon.spy(); 137 | bs.start(); 138 | 139 | clock.tick(INTERVAL - 1); 140 | expect(bs.next.called).to.not.be.ok(); 141 | 142 | clock.tick(1); 143 | expect(bs.next.calledOnce).to.be.ok(); 144 | 145 | clock.restore(); 146 | }); 147 | }); 148 | 149 | describe('#stop', function() { 150 | beforeEach(function() { 151 | bs.setConfig({ 152 | interval: INTERVAL, 153 | start: false 154 | }); 155 | }); 156 | 157 | it('kill the switching timer', function() { 158 | var clock = sinon.useFakeTimers(); 159 | 160 | bs.next = sinon.spy(); 161 | bs.start(); 162 | bs.stop(); 163 | 164 | clock.tick(INTERVAL); 165 | expect(bs.next.called).to.not.be.ok(); 166 | 167 | clock.restore(); 168 | }); 169 | }); 170 | 171 | describe('#toggle', function() { 172 | beforeEach(function() { 173 | bs.setConfig({ 174 | interval: INTERVAL, 175 | start: false 176 | }); 177 | }); 178 | 179 | it('call alternately #start/#stop', function() { 180 | var start = bs.start, 181 | stop = bs.stop; 182 | 183 | bs.start = sinon.spy(); 184 | bs.stop = sinon.spy(); 185 | 186 | bs.toggle(); 187 | expect(bs.start.callCount).to.be(1); 188 | expect(bs.stop.callCount).to.be(0); 189 | 190 | start.call(bs); 191 | bs.toggle(); 192 | expect(bs.start.callCount).to.be(1); 193 | expect(bs.stop.callCount).to.be(1); 194 | 195 | stop.call(bs); 196 | bs.toggle(); 197 | expect(bs.start.callCount).to.be(2); 198 | expect(bs.stop.callCount).to.be(1); 199 | }); 200 | }); 201 | 202 | describe('#next', function() { 203 | beforeEach(function() { 204 | bs.setConfig({images: ['foo', 'bar', 'baz']}); 205 | }); 206 | 207 | it('go to next switching', function() { 208 | bs.next(); 209 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('bar'); 210 | bs.next(); 211 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('baz'); 212 | bs.next(); 213 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('foo'); 214 | }); 215 | 216 | context('when config.loop is false', function() { 217 | it('should stop if reaches the last index', function() { 218 | bs.config.loop = false; 219 | bs.next(); 220 | bs.next(); 221 | bs.next(); 222 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('baz'); 223 | }); 224 | }); 225 | }); 226 | 227 | describe('#prev', function() { 228 | beforeEach(function() { 229 | bs.setConfig({images: ['foo', 'bar', 'baz']}); 230 | }); 231 | 232 | it('go to previous switching', function() { 233 | bs.prev(); 234 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('baz'); 235 | bs.prev(); 236 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('bar'); 237 | bs.prev(); 238 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('foo'); 239 | }); 240 | 241 | context('when config.loop is false', function() { 242 | it('should stop if reaches the last index', function() { 243 | bs.config.loop = false; 244 | bs.prev(); 245 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('foo'); 246 | }); 247 | }); 248 | }); 249 | 250 | describe('#select', function() { 251 | beforeEach(function() { 252 | bs.setConfig({images: ['foo', 'bar', 'baz']}); 253 | }); 254 | 255 | it('select switching at index', function() { 256 | bs.select(0); 257 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('foo'); 258 | bs.select(1); 259 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('bar'); 260 | }); 261 | 262 | context('when the index is -1', function() { 263 | it('select the last switching', function() { 264 | bs.select(-1); 265 | expect(bs.$bg.css('backgroundImage').split('/').pop()).to.have.contain('baz'); 266 | }); 267 | }); 268 | }); 269 | 270 | describe('#switching', function() { 271 | beforeEach(function() { 272 | bs.setConfig({interval: INTERVAL}); 273 | }); 274 | 275 | it('call switchHandler with $switchable', function() { 276 | bs.switchHandler = sinon.spy(); 277 | bs.switching(); 278 | expect(bs.switchHandler.calledOnce).to.be.ok(); 279 | expect(bs.switchHandler.calledWith(bs.$switchable)).to.be.ok(); 280 | }); 281 | 282 | context('when starting the timer', function() { 283 | beforeEach(function() { 284 | bs.start(); 285 | }); 286 | 287 | it('should be call #stop', function() { 288 | bs.stop = sinon.spy(); 289 | bs.switching(); 290 | expect(bs.stop.calledOnce).to.be.ok(); 291 | }); 292 | 293 | it('should be call #start', function() { 294 | bs.start = sinon.spy(); 295 | bs.switching(); 296 | expect(bs.start.calledOnce).to.be.ok(); 297 | }); 298 | }); 299 | }); 300 | 301 | describe('#refresh', function() { 302 | beforeEach(function() { 303 | bs.config = { 304 | images: [], 305 | effect: 'clip' 306 | }; 307 | }); 308 | 309 | it('call #setImages with config.images', function() { 310 | bs.setImages([]); // Avoid an errors 311 | bs.setImages = sinon.spy(); 312 | bs.refresh(); 313 | expect(bs.setImages.calledOnce).to.be.ok(); 314 | expect(bs.setImages.calledWith(bs.config.images)).to.be.ok(); 315 | }); 316 | 317 | it('call #setSwitchHandler with built-in switch handler', function() { 318 | bs.setSwitchHandler = sinon.spy(); 319 | bs.refresh(); 320 | expect(bs.setSwitchHandler.calledOnce).to.be.ok(); 321 | expect(bs.setSwitchHandler.calledWith(bs.constructor.switchHandlers.clip)).to.be.ok(); 322 | }); 323 | 324 | context('when config.start is true', function() { 325 | it('should be call #start', function() { 326 | bs.config.start = true; 327 | bs.start = sinon.spy(); 328 | bs.refresh(); 329 | expect(bs.start.calledOnce).to.be.ok(); 330 | }); 331 | }); 332 | 333 | context('when config.start is false', function() { 334 | it('should be not call #start', function() { 335 | bs.config.start = false; 336 | bs.start = sinon.spy(); 337 | bs.refresh(); 338 | expect(bs.start.calledOnce).to.not.be.ok(); 339 | }); 340 | }); 341 | }); 342 | 343 | describe('#_adjustRectangle', function() { 344 | it('adjust the $bg rectangle from the $el rectangle'); 345 | }); 346 | 347 | describe('#_copyBackgroundStyles', function() { 348 | it('copy background-position or background-position-(x|y)', function() { 349 | bs.$el.css('backgroundPosition', '123px 456px'); 350 | bs._copyBackgroundStyles(); 351 | expect(bs.$bg.attr('style')).match(/123px 456px/); 352 | }); 353 | }); 354 | 355 | describe('.defineEffect', function() { 356 | it('should be set a function', function() { 357 | var fn = function() {}; 358 | $.BgSwitcher.defineEffect('foo', fn); 359 | expect($.BgSwitcher.switchHandlers.foo).to.be(fn); 360 | }); 361 | }); 362 | }); 363 | -------------------------------------------------------------------------------- /test/image_list_spec.js: -------------------------------------------------------------------------------- 1 | describe('jQuery.BgSwitcher.ImageList', function() { 2 | var IMAGES = [ 3 | '../demo/images/image_1.jpg', 4 | '../demo/images/image_2.jpg', 5 | '../demo/images/image_3.jpg', 6 | '../demo/images/image_4.jpg', 7 | '../demo/images/image_5.jpg' 8 | ]; 9 | 10 | var SEQUENCEABLE_IMAGES = ['../demo/images/image_.jpg', 1, 5]; 11 | 12 | var il; 13 | 14 | beforeEach(function() { 15 | il = new $.BgSwitcher.ImageList(IMAGES.concat()); 16 | }); 17 | 18 | describe('#constructor', function() { 19 | it('call #createImagesBySequence', function() { 20 | var spy = sinon.spy($.BgSwitcher.ImageList.prototype, 'createImagesBySequence'); 21 | il = new $.BgSwitcher.ImageList(IMAGES); 22 | expect(spy.calledOnce).to.be.ok(); 23 | spy.restore(); 24 | }); 25 | 26 | it('call #preload', function() { 27 | var spy = sinon.spy($.BgSwitcher.ImageList.prototype, 'preload'); 28 | il = new $.BgSwitcher.ImageList(IMAGES); 29 | expect(spy.calledOnce).to.be.ok(); 30 | spy.restore(); 31 | }); 32 | }); 33 | 34 | describe('#isSequenceable', function() { 35 | it('return true if sequenceable', function() { 36 | il.images = SEQUENCEABLE_IMAGES; 37 | expect(il.isSequenceable()).to.be.ok(); 38 | }); 39 | 40 | it('return false if not sequenceable', function() { 41 | il.images = IMAGES; 42 | expect(il.isSequenceable()).to.not.be.ok(); 43 | }); 44 | }); 45 | 46 | describe('#createImagesBySequence', function() { 47 | it('create images by sequence number', function() { 48 | il.images = ['foo.jpg', 2, 3]; 49 | il.createImagesBySequence(); 50 | expect(il.images).to.have.length(2); 51 | expect(il.images[0]).to.be('foo2.jpg'); 52 | expect(il.images[1]).to.be('foo3.jpg'); 53 | }); 54 | }); 55 | 56 | describe('#preload', function() { 57 | it('load an images'); 58 | }); 59 | 60 | describe('#shuffle', function() { 61 | it('shuffle an images', function() { 62 | il.shuffle(); 63 | expect(il.images.join()).to.not.be(IMAGES.join()); 64 | }); 65 | }); 66 | 67 | describe('#get', function() { 68 | it('return the image', function() { 69 | il.images = ['foo', 'bar', 'baz']; 70 | expect(il.get(0)).to.be('foo'); 71 | expect(il.get(1)).to.be('bar'); 72 | expect(il.get(2)).to.be('baz'); 73 | }); 74 | }); 75 | 76 | describe('#url', function() { 77 | it('return the image URL with function of CSS', function() { 78 | il.images = ['foo', 'bar', 'baz']; 79 | expect(il.url(0)).to.be('url(foo)'); 80 | expect(il.url(1)).to.be('url(bar)'); 81 | expect(il.url(2)).to.be('url(baz)'); 82 | }); 83 | }); 84 | 85 | describe('#count', function() { 86 | it('return an images length', function() { 87 | il.images = [1,2,3,4,5,6]; 88 | expect(il.count()).to.be(6); 89 | }); 90 | }); 91 | }); -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Test - jQuery.bgSwitcher 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 40 | 41 | --------------------------------------------------------------------------------