1 //java -jar app/js.jar app/run.js -t=templates/sweet -p -d=docs D:\Libraries\Prototype.Widgets\src\js\fader.js 2 //remove -p to remove private functions 3 /** 4 * @fileoverview Widget.Fader <br /> 5 * Loads an array of images and fades them in and out in sequence.<br /> 6 * <br /> 7 * Requires Prototype 1.6 (http://www.prototypejs.org) or later <br /> 8 * and Scriptaculous 1.8 (http://script.aculo.us) or later. <br /> 9 * <br /> 10 * Widget.Fader is licensed under the Creative Commons Attribution 2.5 South Africa License<br /> 11 * (more information at: http://creativecommons.org/licenses/by/2.5/za/)<br /> 12 * Under this license you are free to<br /> 13 * - to copy, distribute and transmit the work<br /> 14 * - to adapt the work<br /> 15 * However you must<br /> 16 * - You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).<br /> 17 * - That is by providing a link back to http://www.eternal.co.za or to the specific script page. This link need not be on the page using the script, or even nescessarily even on the same domain, as long as it's accessible from the site.<br /> 18 * I'd also like an email telling me where you are using the script, although this is not required. More often than not I will link back to the site using the script.<br /> 19 * Other than that, you may use this class in any way you like, but don't blame me if things go <br /> 20 * pear shaped. If you use this library I'd like a mention on your website, but <br /> 21 * it's not required. If you like it, send me an email. If you find bugs, send <br /> 22 * me an email. If you don't like it, don't tell me: you'll hurt my feelings. <br /> 23 * <br /> 24 * Change History:<br /> 25 * Version 1.2.0: 11 Feb 2007<br /> 26 * - Fixed a bug: minified version of Prototype broke Ajax (see http://www.eternal.co.za/blog/?p=50)<br /> 27 * - Added builder option and imageBuilder (so that default behaviour does not change)<br /> 28 * - Added textBuilder<br /> 29 * - Updated included Prototype to 1.6.0.2<br /> 30 * Version 1.1.1: 17 Nov 2007<br /> 31 * - Fixed a bug: options.attributes should have been an associative array object<br /> 32 * Version 1.1.0: 11 Nov 2007<br /> 33 * - Updated script for Prototype 1.6 and Scriptaculous 1.8<br /> 34 * - Fader is now in the Widget namespace (Widget.Fader).<br /> 35 * - Fader no longer requires Scriptactulous Builder and uses Prototypes new Element(...) instead.<br /> 36 * - Minified script and minified single script files added to download.<br /> 37 * - New license: Creative Commons Attribution 2.5 South Africa License.<br /> 38 * see more at: http://creativecommons.org/licenses/by/2.5/za/<br /> 39 * - new Fader(...) has been deprecated and will be removed in the next major version<br /> 40 * Version 1.0.2: 20 Sep 2007<br /> 41 * - Added dir option<br /> 42 * - Added beforeFade callback option<br /> 43 * - Added startIndex option<br /> 44 * Version 1.0.1: 15 Aug 2007<br /> 45 * - Added attributes option<br /> 46 * - Now requires builder.js from Scriptaculous<br /> 47 * - Fixed a bug that started the blend with the 3rd image in the list<br /> 48 * Version 1.0.0: 11 Aug 2007<br /> 49 * - First version<br /> 50 * @class Widget.Fader 51 * @version 1.2.0 52 * @author Marc Heiligers marc@eternal.co.za http://www.eternal.co.za 53 */ 54 if(typeof Widget == "undefined") Widget = {}; 55 /** 56 * The Widget.Fader class constructor. <br /> 57 * @constructor Widget.Fader 58 * @param {string|img element} img The id of or actual image element to be faded 59 * @param {array(string)} list An array of paths (relative or absolute) of the images 60 * @param {object} [options] An object of options. 61 */ 62 Widget.Fader = Class.create(/** @scope Widget.Fader **/{ 63 initialize: function(img, list, options) { 64 this.img = $(img); 65 this.list = list; 66 67 /** 68 * The default options object. 69 * @class 70 * @param {string} [id] The id used as queue scope. (default: img.id) 71 * @param {float} [fadeInDuration] The time in seconds of the fade in. (default: 2.5) 72 * @param {float} [fadeOutDuration] The time in seconds of the fade out. (default: 1.5) 73 * @param {float} [displayDuration] The time in seconds that the image is not faded out after being faded in. (default: 2.5) 74 * @param {bool} [autoSize] Set true if the image should be sized to it's container. Maintains aspect ratio. (default: false) 75 * @param {bool} [autoStart] If false the Blender will not start until Blender#start is called. (default: true) 76 * @param {object} [attributes] An associative array of attributes given to the image. (default: {}) 77 * @param {string} [dir] The directory that all images reside in. Used as a prefix for the image src. (default: null) 78 * @param {function} [beforeFade] A function that is called before the image is faded. 2 parameters are passed: 1. the image; 2. a boolean indicating if the image is being faded in (true) or out (false) (default: null) 79 * @param {int} [startIndex] The index of the first new image to be shown. (default: 0) 80 * @param {function} [builder] The function called to build the items. (default: Widget.Fader.imageBuilder) 81 */ 82 this.options = Object.extend({ 83 id: this.img.id, 84 fadeInDuration: 2.5, 85 fadeOutDuration: 1.5, 86 displayDuration: 2.5, 87 autoSize: false, 88 autoStart: true, 89 attributes: {}, 90 dir: "", 91 beforeFade: null, 92 startIndex: 0, 93 builder: Widget.Fader.imageBuilder 94 }, options || {}); 95 this.options.attributes["id"] = this.options.id; 96 97 this.index = this.options.startIndex; 98 this.container = $(this.img.parentNode); 99 this.loadedObserver = this.loaded.bind(this); 100 this.fadeInObserver = this.fadeIn.bind(this); 101 this.nextObserver = this.next.bind(this); 102 103 if(this.options.autoStart) { 104 setTimeout(this.start.bind(this), this.options.displayDuration * 1000); 105 } 106 }, 107 /** 108 * Starts the fading if the autoStart option was set to false or after a call to stop. 109 * @function 110 */ 111 start: function() { 112 this.stopped = false; 113 this.next(); 114 }, 115 /** 116 * Stops the fading and sets the opacity of the current image to 100%. 117 * @function 118 */ 119 stop: function() { 120 this.stopped = true; 121 try { clearTimeout(this.timeout); } catch(ex) { } 122 try { Effect.Queues.get(this.options.id).each(function(effect) { effect.cancel() }) } catch(ex) { } 123 if(this.oldImg) { 124 this.img = this.oldImg; 125 --this.index; 126 } 127 Element.setOpacity(this.img, 1); 128 }, 129 /** 130 * Loads the next image in list 131 * @private 132 * @function 133 */ 134 next: function() { 135 this.oldImg = this.img; 136 if(this.stopped || this.list.length == 0) { 137 return; 138 } 139 ++this.index; 140 if(this.index >= this.list.length) { 141 this.index = 0; 142 } 143 /*this.img = new Element("img", this.options.attributes); 144 Event.observe(this.img, "load", this.loadedObserver); 145 this.img.src = this.options.dir + this.list[this.index];*/ 146 this.img = this.options.builder(this, this.list[this.index], this.loadedObserver); 147 148 }, 149 /** 150 * Event listener for image loaded 151 * @private 152 * @function 153 */ 154 loaded: function() { 155 Event.stopObserving(this.img, "load", this.loadedObserver); 156 if(typeof this.options.beforeFade == "function") { 157 this.options.beforeFade(this.oldImg, false); 158 } 159 new Effect.Opacity(this.oldImg, { duration: this.options.fadeOutDuration, from: 1.0, to: 0.0, queue: { scope: this.options.id } }); 160 this.timeout = setTimeout(this.fadeInObserver, this.options.fadeOutDuration * 1000); 161 }, 162 /** 163 * Event listener for fadeIn 164 * @private 165 * @function 166 */ 167 fadeIn: function() { 168 if(typeof this.options.beforeFade == "function") { 169 this.options.beforeFade(this.img, true); 170 } 171 this.img.id = this.id; 172 Element.setOpacity(this.img, 0); 173 if(this.options.autoSize) { 174 this.resize(this.img); 175 } 176 this.container.replaceChild(this.img, this.oldImg); 177 this.oldImg = null; 178 new Effect.Opacity(this.img, { duration: this.options.fadeInDuration, from: 0.0, to: 1.0, queue: { scope: this.options.id } }); 179 this.timeout = setTimeout(this.nextObserver, (this.options.fadeInDuration + this.options.displayDuration) * 1000); 180 }, 181 /** 182 * Resize the image to the container while maintaining aspect ratio 183 * @private 184 * @function 185 */ 186 resize: function(img) { 187 var dim = this.container.getDimensions(); 188 dim.width -= parseInt(this.container.getStyle("padding-left")) + 189 parseInt(this.container.getStyle("padding-right")) + 190 parseInt(this.container.getStyle("border-left-width")) + 191 parseInt(this.container.getStyle("border-right-width")); 192 dim.height -= parseInt(this.container.getStyle("padding-top")) + 193 parseInt(this.container.getStyle("padding-bottom")) + 194 parseInt(this.container.getStyle("border-top-width")) + 195 parseInt(this.container.getStyle("border-bottom-width")); 196 197 var dw = dim.width / img.width; 198 var dh = dim.height / img.height; 199 var w1 = img.width * dh; 200 var h1 = img.height * dw; 201 202 if(dw > dh) { 203 img.width = w1; 204 img.height = dim.height; 205 } else { 206 img.width = dim.width; 207 img.height = h1; 208 } 209 } 210 }); 211 212 /** 213 * Builds an image item out the item passed by fader. 214 * This is the default builder. 215 * @function 216 * @param {object} fader The calling Widget.Fader 217 * @param {object} item The current item 218 * @param {object} loaded A callback bound to the fader for when the item has loaded. 219 **/ 220 Widget.Fader.imageBuilder = function(fader, item, loaded) { 221 var img = new Element("img", fader.options.attributes); 222 img.observe("load", loaded); 223 img.src = fader.options.dir + item; 224 return img; 225 }; 226 227 /** 228 * Builds div containing the text from the item passed by fader. 229 * The Widget.Fader.options.dir is ignored. 230 * @function 231 * @param {object} fader The calling Widget.Fader 232 * @param {object} item The current item 233 * @param {object} loaded A callback bound to the fader for when the item has loaded. 234 **/ 235 Widget.Fader.textBuilder = function(fader, item, loaded) { 236 var div = new Element("div", fader.options.attributes).update(item); 237 loaded.defer(); 238 return div; 239 }; 240 241 /** 242 * @class 243 * @deprecated 244 **/ 245 var Fader = Widget.Fader;