2 Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
8 * The image loader is a framework to dynamically load images
9 * according to certain triggers, enabling faster load times
10 * and a more responsive UI.
13 * @namespace YAHOO.util
17 if (typeof(YAHOO.util.ImageLoader) == 'undefined') {
18 YAHOO.util.ImageLoader = {};
22 * A group for images. A group can have one time limit and a series of triggers. Thus the images belonging to this group must share these constraints.
23 * @class YAHOO.util.ImageLoader.group
24 * @requires YAHOO.util.Dom
25 * @requires YAHOO.util.Event
27 * @param {String|HTMLElement} trigEl The HTML element id or reference to assign the trigger event to. Can be null for no trigger
28 * @param {String} trigAct The type of event to assign to trigEl. Can be null for no trigger
29 * @param {Number} timeout Timeout (time limit) length, in seconds. Can be undefined, or <= 0, for no time limit
31 YAHOO.util.ImageLoader.group = function(trigEl, trigAct, timeout) {
33 * Name for the group. Only used to identify the group in logging statements
37 this.name = 'unnamed';
40 * Collection of images registered with this group
48 * Timeout (time limit) length, in seconds
49 * @property timeoutLen
52 this.timeoutLen = timeout;
55 * Timeout object to keep a handle on the time limit
63 * Collection of triggers for this group.
64 * Keeps track of each trigger's element, event, and event-listener-callback "fetch" function
72 * Flag to check if images are above the fold. If foldConditional is true, the group will check each of its image locations at page load. If any part of the image is within the client viewport, the image is displayed immediately
73 * @property foldConditional
76 this.foldConditional = false;
79 * Class name that will identify images belonging to the group. This class name will be removed from each element in order to fetch images.
80 * This class should have, in its CSS style definition, "background:none !important;"
84 this.className = null;
87 * HTML elements having the class name that is associated with this group
88 * Elements are stored during the _foldCheck function and reused later during the fetch function. Gives a slight performance improvement when className and foldConditional are both used
89 * @property _classImageEls
93 this._classImageEls = null;
95 // add a listener to set the time limit in the onload
96 YAHOO.util.Event.addListener(window, 'load', this._onloadTasks, this, true);
98 this.addTrigger(trigEl, trigAct);
103 * Adds a trigger to the group. Call this with the same style as YAHOO.util.Event.addListener
105 * @param {String|HTMLElement} trigEl The HTML element id or reference to assign the trigger event to
106 * @param {String} trigAct The type of event to assign to trigEl
108 YAHOO.util.ImageLoader.group.prototype.addTrigger = function(trigEl, trigAct) {
109 if (! trigEl || ! trigAct) {
112 /* Need to wrap the fetch function. Event Util can't distinguish prototyped functions of different instantiations
113 * Leads to this scenario: groupA and groupZ both have window-scroll triggers. groupZ also has a 2-sec timeout (groupA has no timeout).
114 * groupZ's timeout fires; we remove the triggers. The removeListener call finds the first window-scroll event with Y.u.IL.p.fetch, which is groupA's.
115 * groupA's trigger is removed and never fires, leaving images unfetched
117 var wrappedFetch = function() {
120 this._triggers.push([trigEl, trigAct, wrappedFetch]);
121 YAHOO.util.Event.addListener(trigEl, trigAct, wrappedFetch, this, true);
125 * Setup to do in the window's onload
126 * Initiates time limit for group; executes the fold check for the images
127 * @method _onloadTasks
130 YAHOO.util.ImageLoader.group.prototype._onloadTasks = function() {
131 if (this.timeoutLen && typeof(this.timeoutLen) == 'number' && this.timeoutLen > 0) {
132 this._timeout = setTimeout(this._getFetchTimeout(), this.timeoutLen * 1000);
135 if (this.foldConditional) {
141 * Returns the group's fetch method, with the proper closure, for use with setTimeout
142 * @method _getFetchTimeout
143 * @return {Function} group's fetch method
146 YAHOO.util.ImageLoader.group.prototype._getFetchTimeout = function() {
148 return function() { self.fetch(); };
152 * Registers a background image with the group
153 * @method registerBgImage
154 * @param {String} domId HTML DOM id of the image element
155 * @param {String} url URL for the image
156 * @return {Object} bgImgObj that was registered, for modifying any attributes in the object
158 YAHOO.util.ImageLoader.group.prototype.registerBgImage = function(domId, url) {
159 this._imgObjs[domId] = new YAHOO.util.ImageLoader.bgImgObj(domId, url);
160 return this._imgObjs[domId];
163 * Registers a src image with the group
164 * @method registerSrcImage
165 * @param {String} domId HTML DOM id of the image element
166 * @param {String} url URL for the image
167 * @param {Int} width pixel width of the image - defaults to image's natural size
168 * @param {Int} height pixel height of the image - defaults to image's natural size
169 * @return {Object} srcImgObj that was registered, for modifying any attributes in the object
171 YAHOO.util.ImageLoader.group.prototype.registerSrcImage = function(domId, url, width, height) {
172 this._imgObjs[domId] = new YAHOO.util.ImageLoader.srcImgObj(domId, url, width, height);
173 return this._imgObjs[domId];
176 * Registers an alpha-channel-type png background image with the group
177 * @method registerPngBgImage
178 * @param {String} domId HTML DOM id of the image element
179 * @param {String} url URL for the image
180 * @return {Object} pngBgImgObj that was registered, for modifying any attributes in the object
182 YAHOO.util.ImageLoader.group.prototype.registerPngBgImage = function(domId, url) {
183 this._imgObjs[domId] = new YAHOO.util.ImageLoader.pngBgImgObj(domId, url);
184 return this._imgObjs[domId];
188 * Displays the images in the group
191 YAHOO.util.ImageLoader.group.prototype.fetch = function() {
192 YAHOO.log('Fetching images in group: "' + this.name + '".', 'info', 'imageloader');
194 clearTimeout(this._timeout);
195 // remove all listeners
196 for (var i=0; i < this._triggers.length; i++) {
197 YAHOO.util.Event.removeListener(this._triggers[i][0], this._triggers[i][1], this._triggers[i][2]);
200 // fetch whatever we need to by className
201 this._fetchByClass();
203 // fetch registered images
204 for (var id in this._imgObjs) {
205 if (YAHOO.lang.hasOwnProperty(this._imgObjs, id)) {
206 this._imgObjs[id].fetch();
212 * Checks the position of each image in the group. If any part of the image is within the client viewport, shows the image immediately.
216 YAHOO.util.ImageLoader.group.prototype._foldCheck = function() {
217 YAHOO.log('Checking for images above the fold in group: "' + this.name + '"', 'info', 'imageloader');
218 var scrollTop = (document.compatMode != 'CSS1Compat') ? document.body.scrollTop : document.documentElement.scrollTop;
219 var viewHeight = YAHOO.util.Dom.getViewportHeight();
220 var hLimit = scrollTop + viewHeight;
221 var scrollLeft = (document.compatMode != 'CSS1Compat') ? document.body.scrollLeft : document.documentElement.scrollLeft;
222 var viewWidth = YAHOO.util.Dom.getViewportWidth();
223 var wLimit = scrollLeft + viewWidth;
224 for (var id in this._imgObjs) {
225 if (YAHOO.lang.hasOwnProperty(this._imgObjs, id)) {
226 var elPos = YAHOO.util.Dom.getXY(this._imgObjs[id].domId);
227 if (elPos[1] < hLimit && elPos[0] < wLimit) {
228 YAHOO.log('Image with id "' + this._imgObjs[id].domId + '" is above the fold. Fetching image.', 'info', 'imageloader');
229 this._imgObjs[id].fetch();
234 if (this.className) {
235 this._classImageEls = YAHOO.util.Dom.getElementsByClassName(this.className);
236 for (var i=0; i < this._classImageEls.length; i++) {
237 var elPos = YAHOO.util.Dom.getXY(this._classImageEls[i]);
238 if (elPos[1] < hLimit && elPos[0] < wLimit) {
239 YAHOO.log('Image with id "' + this._classImageEls[i].id + '" is above the fold. Fetching image. (Image registered by class name with the group - may not have an id.)', 'info', 'imageloader');
240 YAHOO.util.Dom.removeClass(this._classImageEls[i], this.className);
247 * Finds all elements in the Dom with the class name specified in the group. Removes the class from the element in order to let the style definitions trigger the image fetching
248 * @method _fetchByClass
251 YAHOO.util.ImageLoader.group.prototype._fetchByClass = function() {
252 if (! this.className) {
256 YAHOO.log('Fetching all images with class "' + this.className + '" in group "' + this.name + '".', 'info', 'imageloader');
257 // this._classImageEls may have been set during _foldCheck
258 if (this._classImageEls === null) {
259 this._classImageEls = YAHOO.util.Dom.getElementsByClassName(this.className);
261 YAHOO.util.Dom.removeClass(this._classImageEls, this.className);
266 * Base class for image objects to be registered with the groups
267 * @class YAHOO.util.ImageLoader.imgObj
269 * @param {String} domId HTML DOM id of the image element
270 * @param {String} url URL for the image
272 YAHOO.util.ImageLoader.imgObj = function(domId, url) {
274 * HTML DOM id of the image element
288 * Pixel width of the image. Will be set as a "width" attribute after the image is fetched.
289 * Detaults to the natural width of the image.
290 * Only appropriate with src images
297 * Pixel height of the image. Will be set as a "height" attribute after the image is fetched.
298 * Detaults to the natural height of the image.
299 * Only appropriate with src images
306 * Whether the style.visibility should be set to "visible" after the image is fetched.
307 * Used when setting src images as visibility:hidden prior to image fetching
308 * @property setVisible
311 this.setVisible = false;
314 * Whether the image has already been fetched. In the case of a foldCondional group, keeps track for when the trigger is fired so images aren't fetched twice
319 this._fetched = false;
323 * Displays the image; puts the URL into the DOM
326 YAHOO.util.ImageLoader.imgObj.prototype.fetch = function() {
330 var el = document.getElementById(this.domId);
334 YAHOO.log('Fetching image with id "' + this.domId + '".', 'info', 'imageloader');
337 if (this.setVisible) {
338 el.style.visibility = 'visible';
341 el.width = this.width;
344 el.height = this.height;
346 this._fetched = true;
350 * Inserts the image URL into the DOM so that the image is displayed.
351 * Must be overridden by child class
353 * @param {Object} el HTML DOM element
356 YAHOO.util.ImageLoader.imgObj.prototype._applyUrl = function(el) {
360 * Background image object. A background image is one whose URL is specified by "background-image" in the element's style
361 * @class YAHOO.util.ImageLoader.bgImgObj
363 * @extends YAHOO.util.ImageLoader.imgObj
364 * @param {String} domId HTML DOM id of the image element
365 * @param {String} url URL for the image
367 YAHOO.util.ImageLoader.bgImgObj = function(domId, url) {
368 YAHOO.util.ImageLoader.bgImgObj.superclass.constructor.call(this, domId, url);
371 YAHOO.lang.extend(YAHOO.util.ImageLoader.bgImgObj, YAHOO.util.ImageLoader.imgObj);
374 * Inserts the image URL into the DOM so that the image is displayed.
375 * Sets style.backgroundImage
377 * @param {Object} el HTML DOM element
380 YAHOO.util.ImageLoader.bgImgObj.prototype._applyUrl = function(el) {
381 el.style.backgroundImage = "url('" + this.url + "')";
385 * Source image object. A source image is one whose URL is specified by a src attribute in the DOM element
386 * @class YAHOO.util.ImageLoader.srcImgObj
388 * @extends YAHOO.util.ImageLoader.imgObj
389 * @param {String} domId HTML DOM id of the image element
390 * @param {String} url URL for the image
391 * @param {Int} width pixel width of the image - defaults to image's natural size
392 * @param {Int} height pixel height of the image - defaults to image's natural size
394 YAHOO.util.ImageLoader.srcImgObj = function(domId, url, width, height) {
395 YAHOO.util.ImageLoader.srcImgObj.superclass.constructor.call(this, domId, url);
397 this.height = height;
400 YAHOO.lang.extend(YAHOO.util.ImageLoader.srcImgObj, YAHOO.util.ImageLoader.imgObj);
403 * Inserts the image URL into the DOM so that the image is displayed.
406 * @param {Object} el HTML DOM element
409 YAHOO.util.ImageLoader.srcImgObj.prototype._applyUrl = function(el) {
414 * PNG background image object. A PNG background image is one whose URL is specified through AlphaImageLoader or by "background-image" in the element's style
415 * @class YAHOO.util.ImageLoader.pngBgImgObj
417 * @extends YAHOO.util.ImageLoader.imgObj
418 * @param {String} domId HTML DOM id of the image element
419 * @param {String} url URL for the image
421 YAHOO.util.ImageLoader.pngBgImgObj = function(domId, url) {
422 YAHOO.util.ImageLoader.pngBgImgObj.superclass.constructor.call(this, domId, url);
425 YAHOO.lang.extend(YAHOO.util.ImageLoader.pngBgImgObj, YAHOO.util.ImageLoader.imgObj);
428 * Inserts the image URL into the DOM so that the image is displayed.
429 * If the browser is determined to be IE6 (or older), sets the AlphaImageLoader src; otherwise sets style.backgroundImage
431 * @param {Object} el HTML DOM element
434 YAHOO.util.ImageLoader.pngBgImgObj.prototype._applyUrl = function(el) {
435 if (YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) {
436 el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + this.url + '", sizingMethod="scale")';
439 el.style.backgroundImage = "url('" + this.url + "')";
442 YAHOO.register("imageloader", YAHOO.util.ImageLoader, {version: "2.3.0", build: "442"});