
// Title: fader.js
// Date: 16:21 3 January 2008
// Version: 
// Copyright: Copyright (c) 1994-2010 Global Web Limited 
// Telephone: +44 1224 454000
// Web: http://www.globalweb.co.uk

/**

 * @fileoverview Fader.js <br />

 * Loads an array of images and fades them in and out. <br /><br />

 * Requires Prototype (http://www.prototypejs.org) 1.5 or later <br />

 * and Script.aculo.us 1.7 (http://script.aculo.us) or later. <br /></br />

 *

 * You may use this class in any way you like, but don't blame me if things go <br />

 * pear shaped. If you use this library I'd like a mention on your website, but <br />

 * it's not required. If you like it, send me an email. If you find bugs, send <br />

 * me an email. If you don't like it, don't tell me: you'll hurt my feelings. <br />

 * <br />

 * Change History:<br />

 * Version 1.0.1: 15 Aug 2007<br />

 * - Added attributes option<br />

 * - Now requires builder.js from Scriptaculous<br />

 * - Fixed a bug that started the blend with the 3rd image in the list<br />

 * Version 1.0.0: 11 Aug 2007<br />

 * - First version<br />

 * @class Fader

 * @version 1.0.0

 * @author Marc Heiligers marc@eternal.co.za http://www.eternal.co.za

 */

var Fader = Class.create();

Fader.prototype = {

	/**

	 * The Fader class constructor. <br />

	 * @constructor Fader

	 * @param {string|img element} img The id of or actual image element to be faded

	 * @param {array(string)} list  An array of paths (relative or absolute) of the images

	 * @param {object} [options] An object of options.

	 */

	initialize: function(img, list, options) {

		this.img = $(img);

		this.list = list;



		/**

		 * The default options object.

		 * @class

		 * @param {string} [id] The id used as queue scope. (default: img.id)

		 * @param {float} [fadeInDuration] The time in seconds of the fade in. (default: 2.5)

		 * @param {float} [fadeOutDuration] The time in seconds of the fade out. (default: 1.5)

		 * @param {float} [displayDuration] The time in seconds that the image is not faded out after being faded in. (default: 2.5)

		 * @param {bool} [autoSize] Set true if the image should be sized to it's container. Maintains aspect ratio. (default: false)

		 * @param {bool} [autoStart] If false the Blender will not start until Blender#start is called. (default: true)

		 * @param {array} [attributes] The attributes given to the image. (default: [])

		 */

		this.options = Object.extend({

			id: this.img.id,

			fadeInDuration: 2.5,

			fadeOutDuration: 1.5,

			displayDuration: 2.5,

			autoSize: false,

			autoStart: true,

			attributes: []

		}, options || {});

		this.options.attributes["id"] = this.options.id;



		this.index = 0;

		this.container = $(this.img.parentNode);

		this.loadedObserver = this.loaded.bind(this);

		this.fadeInObserver = this.fadeIn.bind(this);

		this.nextObserver = this.next.bind(this);



		if(this.options.autoStart) {

			setTimeout(this.start.bind(this), this.options.displayDuration * 1000);

		}

	},

	/**

	 * Starts the fading if the autoStart option was set to false or after a call to stop.

	 */

	start: function() {

		this.stopped = false;

		this.next();

	},

	/**

	 * Stops the fading and sets the opacity of the current image to 100%.

	 */

	stop: function() {

		this.stopped = true;

		try { clearTimeout(this.timeout); } catch(ex) { }

		try { Effect.Queues.get(this.options.id).each(function(effect) { effect.cancel() }) } catch(ex) { }

		if(this.oldImg) {

			this.img = this.oldImg;

			--this.index;

		}

		Element.setOpacity(this.img, 1);

	},

	/**

	 * Loads the next image in list

	 * @private

	 */

	next: function() {

		this.oldImg = this.img;

		if(this.stopped || this.list.length == 0) {

			return;

		}

		++this.index;

		if(this.index >= this.list.length) {

			this.index = 0;

		}

		this.img = Builder.node("img", this.options.attributes);

		Event.observe(this.img, "load", this.loadedObserver);

		this.img.src = this.list[this.index];

	},

	/**

	 * Event listener for image loaded

	 * @private

	 */

	loaded: function() {

		Event.stopObserving(this.img, "load", this.loadedObserver);

		new Effect.Opacity(this.oldImg, { duration: this.options.fadeOutDuration, from: 1.0, to: 0.0, queue: { scope: this.options.id } });

		this.timeout = setTimeout(this.fadeInObserver, this.options.fadeOutDuration * 1000);

	},

	/**

	 * Event listener for fadeIn

	 * @private

	 */

	fadeIn: function() {

		this.img.id = this.id;

		Element.setOpacity(this.img, 0);

		if(this.options.autoSize) {

			this.resize(this.img);

		}

		this.container.replaceChild(this.img, this.oldImg);

		this.oldImg = null;

		new Effect.Opacity(this.img, { duration: this.options.fadeInDuration, from: 0.0, to: 1.0, queue: { scope: this.options.id } });

		this.timeout = setTimeout(this.nextObserver, (this.options.fadeInDuration + this.options.displayDuration) * 1000);

	},

	/**

	 * Resize the image to the container while maintaining aspect ratio

	 * @private

	 */

	resize: function(img) {

		var dim = this.container.getDimensions();

		dim.width -= parseInt(this.container.getStyle("padding-left")) +

			parseInt(this.container.getStyle("padding-right")) +

			parseInt(this.container.getStyle("border-left-width")) +

			parseInt(this.container.getStyle("border-right-width"));

		dim.height -= parseInt(this.container.getStyle("padding-top")) +

			parseInt(this.container.getStyle("padding-bottom")) +

			parseInt(this.container.getStyle("border-top-width")) +

			parseInt(this.container.getStyle("border-bottom-width"));



		var dw = dim.width / img.width;

		var dh = dim.height / img.height;

		var w1 = img.width * dh;

		var h1 = img.height * dw;



		if(dw > dh) {

			img.width = w1;

			img.height = dim.height;

		} else {

			img.width = dim.width;

			img.height = h1;

		}

	}

};



 
