aboutsummaryrefslogtreecommitdiffstats
path: root/site/js/bramus/jsProgressBarHandler.js
blob: 0051235c5c4cee66b598b220e6460998ba60c1af (plain)
1
2
3
4
5
6
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
/*****************************************************************
 *
 * jsProgressBarHandler 0.3.3 - by Bramus! - http://www.bram.us/
 *
 * v 0.3.3 - 2008.11.10 - UPD: fixed IE compatibility issue (thanks Kevin - Sep 19 2008 / 6pm)
 *                      - UPD: setPercentage now parses the targetPercentage to an Integer to avoid infinite loop (thanks Jack - Sep 07 2008 / 9pm)
 *                      - UPD: Moved from Event.Observe(window, 'load', fn) to document.observe('dom:loaded', fn) in order to force people to use an up to date Prototype release.
 *                      - UPD: setPercentage now takes an overrideQueue param. If set the current queue is cleared.
 *                      - ADD: Added onTick callback event which gets called when the percentage is updated.
 *                      - ADD: Added stable (as in "non-crashing") versions of the additions which first surfaced in the (unreleased) 0.3.2 release
 *                             Preloading support partially implemented in IE as all versions (IE6,7&8) are quite hard to tame (one time they work, the next reload they don't anymore)
 * v 0.3.2 - 2008.04.09 (*UNRELEASED*)
 *                      - ADD: implemented preloading of images to avoid slight flicker when switching images (BUGGY!)
 *                      - ADD: percentage image now has class percentImage and percentage Text now has class percentText; This allows you to style the output easily.
 * v 0.3.1 - 2008.02.20 - UPD: fixed queue bug when animate was set to false (thanks Jamie Chong)
 *                      - UPD: update Prototype to version 1.6.0.2
 * v 0.3.0 - 2008.02.01 - ADD: animation queue, prevents from the progressbar getting stuck when multiple calls are made during an animation
 *                      - UPD: multiple barImages now work properly in Safari
 * v 0.2.1 - 2007.12.20 - ADD: option : set boxImage
 *                        ADD: option : set barImage (one or more)
 *                        ADD: option : showText
 * v 0.2   - 2007.12.13 - SYS: rewrite in 2 classs including optimisations
 *                        ADD: Config options
 * v 0.1   - 2007.08.02 - initial release
 *
 * @see http://www.barenakedapp.com/the-design/displaying-percentages on how to create a progressBar Background Image!
 *
 * Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
 *
 *****************************************************************/


 /**
  * CONFIG
  * -------------------------------------------------------------
  */

 	// Should jsProgressBarHandler hook itself to all span.progressBar elements? - default : true
		var autoHook	= true;	
 
 	// Default Options
		var defaultOptions = {
			animate		: true,										// Animate the progress? - default: true
			showText	: true,										// show text with percentage in next to the progressbar? - default : true
			width		: 120,										// Width of the progressbar - don't forget to adjust your image too!!!
			boxImage	: 'images/bramus/percentImage.png',			// boxImage : image around the progress bar
			barImage	: 'images/bramus/percentImage_back1.png',	// Image to use in the progressbar. Can be an array of images too.
			height		: 12,										// Height of the progressbar - don't forget to adjust your image too!!!
			onTick		: function(pbObj) { return true }
		}

 /**
  * NO NEED TO CHANGE ANYTHING BENEATH THIS LINE
  * -------------------------------------------------------------
  */

	/**
	 * JS_BRAMUS Object
	 * -------------------------------------------------------------
	 */

		if (!JS_BRAMUS) { var JS_BRAMUS = new Object(); }


	/**
	 * ProgressBar Class
	 * -------------------------------------------------------------
	 */

		JS_BRAMUS.jsProgressBar = Class.create();

		JS_BRAMUS.jsProgressBar.prototype = {


			/**
			 * Datamembers
			 * -------------------------------------------------------------
			 */
			 
				el				: null,								// Element where to render the progressBar in
				id				: null,								// Unique ID of the progressbar
				percentage		: null,								// Percentage of the progressbar

				options			: null,								// The options

				initialPos		: null,								// Initial postion of the background in the progressbar
				initialPerc		: null,								// Initial percentage the progressbar should hold
				pxPerPercent	: null,								// Number of pixels per 1 percent

				backIndex		: null,								// index in the array of background images currently used
				numPreloaded	: null,								// number of images preloaded

				running			: null,								// is this one running (being animated) or not?

				queue			: false,							// queue of percentages to set to


			/**
			 * Constructor
			 *
			 * @param HTMLElement el
			 * @param string id
			 * @param int percentage
			 * @return void
			 * -------------------------------------------------------------
			 */
			 
				initialize		: function(el, percentage, options) {

					// get the options
					this.options			= Object.clone(defaultOptions);
					Object.extend(this.options, options || {});

					// datamembers from arguments
					this.el				= $(el);
					this.id				= $(el).id;
					this.percentage		= 0;							// Set to 0 intially, we'll change this later.
					this.backIndex		= 0;							// Set to 0 initially
					this.numPreloaded	= 0;							// Set to 0 initially
					this.running		= false;						// Set to false initially
					this.queue			= Array();						// Set to empty Array initially

					// datamembers which are calculatef
					this.imgWidth		= this.options.width * 2;		// define the width of the image (twice the width of the progressbar)
					this.initialPos		= this.options.width * (-1);	// Initial postion of the background in the progressbar (0% is the middle of our image!)
					this.pxPerPercent	= this.options.width / 100;		// Define how much pixels go into 1%
					this.initialPerc	= percentage;					// Store this, we'll need it later.

					// enfore backimage array
					if (this.options.barImage.constructor != Array) { 	// used to be (but doesn't work in Safari): if (this.options.barImage.constructor.toString().indexOf("Array") == -1) {
						this.options.barImage = Array(this.options.barImage);
					}

					// preload Images
					this.preloadImages();

				},


			/**
			 * Preloads the images needed for the progressbar
			 *
			 * @return void
			 * -------------------------------------------------------------
			 */

				preloadImages	: function() {

					// loop all barimages
					for (i = 0; i < this.options.barImage.length; i++) {

						// create new image ref
						var newImage = null;
						newImage = new Image();

						// set onload, onerror and onabort functions
						newImage.onload		= function() { this.numPreloaded++; }.bind(this);
						newImage.onerror	= function() { this.numPreloaded++; }.bind(this);
						newImage.onabort	= function() { this.numPreloaded++; }.bind(this);

						// set image source (preload it!)
						newImage.src = this.options.barImage[i];

						// image is in cache
						if (newImage.complete) {
							this.numPreloaded++;
						}
						
					}

					// if not IE, check if they're loaded
					if (!Prototype.Browser.IE) {
						this.checkPreloadedImages();

					// if IE, just init the visuals as it's quite hard to tame all IE's
					} else {
						this.initVisuals();
					}

				},


			/**
			 * Check whether all images are preloaded and loads the percentage if so
			 *
			 * @return void
			 * -------------------------------------------------------------
			 */

			 	checkPreloadedImages	: function() {

					// all images are loaded, go init the visuals
					if (parseInt(this.numPreloaded,10) >= parseInt(this.options.barImage.length,10) ) {

						// initVisuals
						this.initVisuals();

					// not all images are loaded ... wait a little and then retry
					} else {

						if ( parseInt(this.numPreloaded,10) <= parseInt(this.options.barImage.length,10) ) {
							// $(this.el).update(this.id + ' : ' + this.numPreloaded + '/' + this.options.barImage.length);
							setTimeout(function() { this.checkPreloadedImages(); }.bind(this), 100);
						}

					}

				},


			/**
			 * Intializes the visual output and sets the percentage
			 *
			 * @return void
			 * -------------------------------------------------------------
			 */				
				
				initVisuals		: function () {

					// create the visual aspect of the progressBar
					$(this.el).update(
						'<img id="' + this.id + '_percentImage" src="' + this.options.boxImage + '" alt="0%" style="width: ' + this.options.width + 'px; height: ' + this.options.height + 'px; background-position: ' + this.initialPos + 'px 50%; background-image: url(' + this.options.barImage[this.backIndex] + '); padding: 0; margin: 0;" class="percentImage" />' + 
						((this.options.showText == true)?'<span id="' + this.id + '_percentText" class="percentText">0%</span>':''));
				
					// set the percentage
					this.setPercentage(this.initialPerc);
				},
			
			
			/**
			 * Sets the percentage of the progressbar
			 *
			 * @param string targetPercentage
			 * @param boolen clearQueue
			 * @return void
			 * -------------------------------------------------------------
			 */
				setPercentage	: function(targetPercentage, clearQueue) {
					
					// if clearQueue is set, empty the queue and then set the percentage
					if (clearQueue) {
						
						this.percentage = (this.queue.length != 0) ? this.queue[0] : targetPercentage;
						this.timer		= null;
						this.queue 		= [];
						
						setTimeout(function() { this.setPercentage(targetPercentage); }.bind(this), 10);
						
					// no clearQueue defined, set the percentage
					} else {
					
						// add the percentage on the queue
						this.queue.push(targetPercentage);
						
						// process the queue (if not running already)
						if (this.running == false) {
							this.processQueue();
						}
					}
					
				},
			
			
			/**
			 * Processes the queue
			 *
			 * @return void
			 * -------------------------------------------------------------
			 */
				
				processQueue	: function() {
					
					// stuff on queue?
					if (this.queue.length > 0) {
						
						// tell the world that we're busy
						this.running = true;
						
						// process the entry
						this.processQueueEntry(this.queue[0]);
						
					// no stuff on queue
					} else {
							
						// return;
						return;
							
					}
					
				},
			
			
			/**
			 * Processes an entry from the queue (viz. animates it)
			 *
			 * @param string targetPercentage
			 * @return void
			 * -------------------------------------------------------------
			 */
				
				processQueueEntry	: function(targetPercentage) {
										
					// get the current percentage
					var curPercentage	= parseInt(this.percentage,10);
					
					// define the new percentage
					if ((targetPercentage.toString().substring(0,1) == "+") || (targetPercentage.toString().substring(0,1) == "-")) {
						targetPercentage	= curPercentage + parseInt(targetPercentage);
					}
				
					// min and max percentages
					if (targetPercentage < 0)		targetPercentage = 0;
					if (targetPercentage > 100)		targetPercentage = 100;
					
					// if we don't need to animate, just change the background position right now and return
					if (this.options.animate == false) {
						
						// remove the entry from the queue 
						this.queue.splice(0,1);	// @see: http://www.bram.us/projects/js_bramus/jsprogressbarhandler/#comment-174878
						
						// Change the background position (and update this.percentage)
						this._setBgPosition(targetPercentage);
					
						// call onTick
						if (!this.options.onTick(this)) {
							return;	
						}
						
						// we're not running anymore
						this.running = false;
						
						// continue processing the queue
						this.processQueue();
						
						// we're done!
						return;
					}
					
					// define if we need to add/subtract something to the current percentage in order to reach the target percentage
					if (targetPercentage != curPercentage) {					
						if (curPercentage < targetPercentage) {
							newPercentage = curPercentage + 1;
						} else {
							newPercentage = curPercentage - 1;	
						}						
						callTick = true;						
					} else {
						newPercentage = curPercentage;
						callTick = false;
					}											
											
					// Change the background position (and update this.percentage)
					this._setBgPosition(newPercentage);
					
					// call onTick
					if (callTick && !this.options.onTick(this)) {
						return;	
					}
					
					// Percentage not reached yet : continue processing entry
					if (curPercentage != newPercentage) {
						
						this.timer = setTimeout(function() { this.processQueueEntry(targetPercentage); }.bind(this), 10);
						
					// Percentage reached!
					} else {
														  
						// remove the entry from the queue
						this.queue.splice(0,1);
						
						// we're not running anymore
						this.running = false;	
						
						// unset timer
						this.timer = null;
						
						// process the rest of the queue
						this.processQueue();
						
						// we're done!
						return;
					}
					
				},
			
			
			/**
			 * Gets the percentage of the progressbar
			 *
			 * @return int
			 */
				getPercentage		: function(id) {
					return this.percentage;
				},
			
			
			/**
			 * Set the background position
			 *
			 * @param int percentage
			 */
				_setBgPosition		: function(percentage) {
					// adjust the background position
						$(this.id + "_percentImage").style.backgroundPosition 	= (this.initialPos + (percentage * this.pxPerPercent)) + "px 50%";
												
					// adjust the background image and backIndex
						var newBackIndex										= Math.floor((percentage-1) / (100/this.options.barImage.length));
						
						if ((newBackIndex != this.backIndex) && (this.options.barImage[newBackIndex] != undefined)) {
							$(this.id + "_percentImage").style.backgroundImage 	= "url(" + this.options.barImage[newBackIndex] + ")";
						}
						
						this.backIndex											= newBackIndex;
					
					// Adjust the alt & title of the image
						$(this.id + "_percentImage").alt 						= percentage + "%";
						$(this.id + "_percentImage").title 						= percentage + "%";
						
					// Update the text
						if (this.options.showText == true) {
							$(this.id + "_percentText").update("" + percentage + "%");
						}
						
					// adjust datamember to stock the percentage
						this.percentage	= percentage;
				}
		}


	/**
	 * ProgressHandlerBar Class - automatically create ProgressBar instances
	 * -------------------------------------------------------------
	 */
	 
		JS_BRAMUS.jsProgressBarHandler = Class.create();

	
		JS_BRAMUS.jsProgressBarHandler.prototype = {
			
			
			/**
			 * Datamembers
			 * -------------------------------------------------------------
			 */
			 
				pbArray				: new Array(),		// Array of progressBars
		
		
			/**
			 * Constructor
			 *
			 * @return void
			 * -------------------------------------------------------------
			 */
			 
				initialize			: function() {		
				
					// get all span.progressBar elements
					$$('span.progressBar').each(function(el) {
														 
						// create a progressBar for each element
						this.pbArray[el.id]	= new JS_BRAMUS.jsProgressBar(el, parseInt(el.innerHTML.replace("%",""))); 
					
					}.bind(this));
				},
		
		
			/**
			 * Set the percentage of a progressbar
			 *
			 * @param string el
			 * @param string percentage
			 * @return void
			 * -------------------------------------------------------------
			 */
				setPercentage		: function(el, percentage, clearQueue) {
					this.pbArray[el].setPercentage(percentage, clearQueue);
				},
		
		
			/**
			 * Get the percentage of a progressbar
			 *
			 * @param string el
			 * @return int percentage
			 * -------------------------------------------------------------
			 */
				getPercentage		: function(el) {
					return this.pbArray[el].getPercentage();
				}
			
		}


	/**
	 * ProgressHandlerBar Class - hook me or not?
	 * -------------------------------------------------------------
	 */
	
		if (autoHook == true) {
			function initProgressBarHandler() { myJsProgressBarHandler = new JS_BRAMUS.jsProgressBarHandler(); }
			document.observe('dom:loaded', initProgressBarHandler, false);
		}