/*****************************************************************
*
* 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(
'' +
((this.options.showText == true)?'0%':''));
// 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);
}