├── .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 [](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 |
17 |
18 |
90 |
91 |
92 |
Demo
93 |
94 | Start switching
95 | Stop switching
96 | Toggle start/stop
97 | Reset
98 | Next image
99 | Previous image
100 | Destroy
101 |
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 |
--------------------------------------------------------------------------------