1 /*****************************************************************
\r
3 * jsProgressBarHandler 0.3.3 - by Bramus! - http://www.bram.us/
\r
5 * v 0.3.3 - 2008.11.10 - UPD: fixed IE compatibility issue (thanks Kevin - Sep 19 2008 / 6pm)
\r
6 * - UPD: setPercentage now parses the targetPercentage to an Integer to avoid infinite loop (thanks Jack - Sep 07 2008 / 9pm)
\r
7 * - 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.
\r
8 * - UPD: setPercentage now takes an overrideQueue param. If set the current queue is cleared.
\r
9 * - ADD: Added onTick callback event which gets called when the percentage is updated.
\r
10 * - ADD: Added stable (as in "non-crashing") versions of the additions which first surfaced in the (unreleased) 0.3.2 release
\r
11 * 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)
\r
12 * v 0.3.2 - 2008.04.09 (*UNRELEASED*)
\r
13 * - ADD: implemented preloading of images to avoid slight flicker when switching images (BUGGY!)
\r
14 * - ADD: percentage image now has class percentImage and percentage Text now has class percentText; This allows you to style the output easily.
\r
15 * v 0.3.1 - 2008.02.20 - UPD: fixed queue bug when animate was set to false (thanks Jamie Chong)
\r
16 * - UPD: update Prototype to version 1.6.0.2
\r
17 * v 0.3.0 - 2008.02.01 - ADD: animation queue, prevents from the progressbar getting stuck when multiple calls are made during an animation
\r
18 * - UPD: multiple barImages now work properly in Safari
\r
19 * v 0.2.1 - 2007.12.20 - ADD: option : set boxImage
\r
20 * ADD: option : set barImage (one or more)
\r
21 * ADD: option : showText
\r
22 * v 0.2 - 2007.12.13 - SYS: rewrite in 2 classs including optimisations
\r
23 * ADD: Config options
\r
24 * v 0.1 - 2007.08.02 - initial release
\r
26 * @see http://www.barenakedapp.com/the-design/displaying-percentages on how to create a progressBar Background Image!
\r
28 * Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
\r
30 *****************************************************************/
\r
35 * -------------------------------------------------------------
\r
38 // Should jsProgressBarHandler hook itself to all span.progressBar elements? - default : true
\r
39 var autoHook = true;
\r
42 var defaultOptions = {
\r
43 animate : true, // Animate the progress? - default: true
\r
44 showText : true, // show text with percentage in next to the progressbar? - default : true
\r
45 width : 120, // Width of the progressbar - don't forget to adjust your image too!!!
\r
46 boxImage : 'images/bramus/percentImage.png', // boxImage : image around the progress bar
\r
47 barImage : 'images/bramus/percentImage_back1.png', // Image to use in the progressbar. Can be an array of images too.
\r
48 height : 12, // Height of the progressbar - don't forget to adjust your image too!!!
\r
49 onTick : function(pbObj) { return true }
\r
53 * NO NEED TO CHANGE ANYTHING BENEATH THIS LINE
\r
54 * -------------------------------------------------------------
\r
59 * -------------------------------------------------------------
\r
62 if (!JS_BRAMUS) { var JS_BRAMUS = new Object(); }
\r
67 * -------------------------------------------------------------
\r
70 JS_BRAMUS.jsProgressBar = Class.create();
\r
72 JS_BRAMUS.jsProgressBar.prototype = {
\r
77 * -------------------------------------------------------------
\r
80 el : null, // Element where to render the progressBar in
\r
81 id : null, // Unique ID of the progressbar
\r
82 percentage : null, // Percentage of the progressbar
\r
84 options : null, // The options
\r
86 initialPos : null, // Initial postion of the background in the progressbar
\r
87 initialPerc : null, // Initial percentage the progressbar should hold
\r
88 pxPerPercent : null, // Number of pixels per 1 percent
\r
90 backIndex : null, // index in the array of background images currently used
\r
91 numPreloaded : null, // number of images preloaded
\r
93 running : null, // is this one running (being animated) or not?
\r
95 queue : false, // queue of percentages to set to
\r
101 * @param HTMLElement el
\r
103 * @param int percentage
\r
105 * -------------------------------------------------------------
\r
108 initialize : function(el, percentage, options) {
\r
111 this.options = Object.clone(defaultOptions);
\r
112 Object.extend(this.options, options || {});
\r
114 // datamembers from arguments
\r
116 this.id = $(el).id;
\r
117 this.percentage = 0; // Set to 0 intially, we'll change this later.
\r
118 this.backIndex = 0; // Set to 0 initially
\r
119 this.numPreloaded = 0; // Set to 0 initially
\r
120 this.running = false; // Set to false initially
\r
121 this.queue = Array(); // Set to empty Array initially
\r
123 // datamembers which are calculatef
\r
124 this.imgWidth = this.options.width * 2; // define the width of the image (twice the width of the progressbar)
\r
125 this.initialPos = this.options.width * (-1); // Initial postion of the background in the progressbar (0% is the middle of our image!)
\r
126 this.pxPerPercent = this.options.width / 100; // Define how much pixels go into 1%
\r
127 this.initialPerc = percentage; // Store this, we'll need it later.
\r
129 // enfore backimage array
\r
130 if (this.options.barImage.constructor != Array) { // used to be (but doesn't work in Safari): if (this.options.barImage.constructor.toString().indexOf("Array") == -1) {
\r
131 this.options.barImage = Array(this.options.barImage);
\r
135 this.preloadImages();
\r
141 * Preloads the images needed for the progressbar
\r
144 * -------------------------------------------------------------
\r
147 preloadImages : function() {
\r
149 // loop all barimages
\r
150 for (i = 0; i < this.options.barImage.length; i++) {
\r
152 // create new image ref
\r
153 var newImage = null;
\r
154 newImage = new Image();
\r
156 // set onload, onerror and onabort functions
\r
157 newImage.onload = function() { this.numPreloaded++; }.bind(this);
\r
158 newImage.onerror = function() { this.numPreloaded++; }.bind(this);
\r
159 newImage.onabort = function() { this.numPreloaded++; }.bind(this);
\r
161 // set image source (preload it!)
\r
162 newImage.src = this.options.barImage[i];
\r
164 // image is in cache
\r
165 if (newImage.complete) {
\r
166 this.numPreloaded++;
\r
171 // if not IE, check if they're loaded
\r
172 if (!Prototype.Browser.IE) {
\r
173 this.checkPreloadedImages();
\r
175 // if IE, just init the visuals as it's quite hard to tame all IE's
\r
177 this.initVisuals();
\r
184 * Check whether all images are preloaded and loads the percentage if so
\r
187 * -------------------------------------------------------------
\r
190 checkPreloadedImages : function() {
\r
192 // all images are loaded, go init the visuals
\r
193 if (parseInt(this.numPreloaded,10) >= parseInt(this.options.barImage.length,10) ) {
\r
196 this.initVisuals();
\r
198 // not all images are loaded ... wait a little and then retry
\r
201 if ( parseInt(this.numPreloaded,10) <= parseInt(this.options.barImage.length,10) ) {
\r
202 // $(this.el).update(this.id + ' : ' + this.numPreloaded + '/' + this.options.barImage.length);
\r
203 setTimeout(function() { this.checkPreloadedImages(); }.bind(this), 100);
\r
212 * Intializes the visual output and sets the percentage
\r
215 * -------------------------------------------------------------
\r
218 initVisuals : function () {
\r
220 // create the visual aspect of the progressBar
\r
222 '<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" />' +
\r
223 ((this.options.showText == true)?'<span id="' + this.id + '_percentText" class="percentText">0%</span>':''));
\r
225 // set the percentage
\r
226 this.setPercentage(this.initialPerc);
\r
231 * Sets the percentage of the progressbar
\r
233 * @param string targetPercentage
\r
234 * @param boolen clearQueue
\r
236 * -------------------------------------------------------------
\r
238 setPercentage : function(targetPercentage, clearQueue) {
\r
240 // if clearQueue is set, empty the queue and then set the percentage
\r
243 this.percentage = (this.queue.length != 0) ? this.queue[0] : targetPercentage;
\r
247 setTimeout(function() { this.setPercentage(targetPercentage); }.bind(this), 10);
\r
249 // no clearQueue defined, set the percentage
\r
252 // add the percentage on the queue
\r
253 this.queue.push(targetPercentage);
\r
255 // process the queue (if not running already)
\r
256 if (this.running == false) {
\r
257 this.processQueue();
\r
265 * Processes the queue
\r
268 * -------------------------------------------------------------
\r
271 processQueue : function() {
\r
274 if (this.queue.length > 0) {
\r
276 // tell the world that we're busy
\r
277 this.running = true;
\r
279 // process the entry
\r
280 this.processQueueEntry(this.queue[0]);
\r
282 // no stuff on queue
\r
294 * Processes an entry from the queue (viz. animates it)
\r
296 * @param string targetPercentage
\r
298 * -------------------------------------------------------------
\r
301 processQueueEntry : function(targetPercentage) {
\r
303 // get the current percentage
\r
304 var curPercentage = parseInt(this.percentage,10);
\r
306 // define the new percentage
\r
307 if ((targetPercentage.toString().substring(0,1) == "+") || (targetPercentage.toString().substring(0,1) == "-")) {
\r
308 targetPercentage = curPercentage + parseInt(targetPercentage);
\r
311 // min and max percentages
\r
312 if (targetPercentage < 0) targetPercentage = 0;
\r
313 if (targetPercentage > 100) targetPercentage = 100;
\r
315 // if we don't need to animate, just change the background position right now and return
\r
316 if (this.options.animate == false) {
\r
318 // remove the entry from the queue
\r
319 this.queue.splice(0,1); // @see: http://www.bram.us/projects/js_bramus/jsprogressbarhandler/#comment-174878
\r
321 // Change the background position (and update this.percentage)
\r
322 this._setBgPosition(targetPercentage);
\r
325 if (!this.options.onTick(this)) {
\r
329 // we're not running anymore
\r
330 this.running = false;
\r
332 // continue processing the queue
\r
333 this.processQueue();
\r
339 // define if we need to add/subtract something to the current percentage in order to reach the target percentage
\r
340 if (targetPercentage != curPercentage) {
\r
341 if (curPercentage < targetPercentage) {
\r
342 newPercentage = curPercentage + 1;
\r
344 newPercentage = curPercentage - 1;
\r
348 newPercentage = curPercentage;
\r
352 // Change the background position (and update this.percentage)
\r
353 this._setBgPosition(newPercentage);
\r
356 if (callTick && !this.options.onTick(this)) {
\r
360 // Percentage not reached yet : continue processing entry
\r
361 if (curPercentage != newPercentage) {
\r
363 this.timer = setTimeout(function() { this.processQueueEntry(targetPercentage); }.bind(this), 10);
\r
365 // Percentage reached!
\r
368 // remove the entry from the queue
\r
369 this.queue.splice(0,1);
\r
371 // we're not running anymore
\r
372 this.running = false;
\r
377 // process the rest of the queue
\r
378 this.processQueue();
\r
388 * Gets the percentage of the progressbar
\r
392 getPercentage : function(id) {
\r
393 return this.percentage;
\r
398 * Set the background position
\r
400 * @param int percentage
\r
402 _setBgPosition : function(percentage) {
\r
403 // adjust the background position
\r
404 $(this.id + "_percentImage").style.backgroundPosition = (this.initialPos + (percentage * this.pxPerPercent)) + "px 50%";
\r
406 // adjust the background image and backIndex
\r
407 var newBackIndex = Math.floor((percentage-1) / (100/this.options.barImage.length));
\r
409 if ((newBackIndex != this.backIndex) && (this.options.barImage[newBackIndex] != undefined)) {
\r
410 $(this.id + "_percentImage").style.backgroundImage = "url(" + this.options.barImage[newBackIndex] + ")";
\r
413 this.backIndex = newBackIndex;
\r
415 // Adjust the alt & title of the image
\r
416 $(this.id + "_percentImage").alt = percentage + "%";
\r
417 $(this.id + "_percentImage").title = percentage + "%";
\r
420 if (this.options.showText == true) {
\r
421 $(this.id + "_percentText").update("" + percentage + "%");
\r
424 // adjust datamember to stock the percentage
\r
425 this.percentage = percentage;
\r
431 * ProgressHandlerBar Class - automatically create ProgressBar instances
\r
432 * -------------------------------------------------------------
\r
435 JS_BRAMUS.jsProgressBarHandler = Class.create();
\r
438 JS_BRAMUS.jsProgressBarHandler.prototype = {
\r
443 * -------------------------------------------------------------
\r
446 pbArray : new Array(), // Array of progressBars
\r
453 * -------------------------------------------------------------
\r
456 initialize : function() {
\r
458 // get all span.progressBar elements
\r
459 $$('span.progressBar').each(function(el) {
\r
461 // create a progressBar for each element
\r
462 this.pbArray[el.id] = new JS_BRAMUS.jsProgressBar(el, parseInt(el.innerHTML.replace("%","")));
\r
469 * Set the percentage of a progressbar
\r
472 * @param string percentage
\r
474 * -------------------------------------------------------------
\r
476 setPercentage : function(el, percentage, clearQueue) {
\r
477 this.pbArray[el].setPercentage(percentage, clearQueue);
\r
482 * Get the percentage of a progressbar
\r
485 * @return int percentage
\r
486 * -------------------------------------------------------------
\r
488 getPercentage : function(el) {
\r
489 return this.pbArray[el].getPercentage();
\r
496 * ProgressHandlerBar Class - hook me or not?
\r
497 * -------------------------------------------------------------
\r
500 if (autoHook == true) {
\r
501 function initProgressBarHandler() { myJsProgressBarHandler = new JS_BRAMUS.jsProgressBarHandler(); }
\r
502 document.observe('dom:loaded', initProgressBarHandler, false);
\r