2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
8 * The ImageLoader Utility is a framework to dynamically load images according to certain triggers,
9 * enabling faster load times and a more responsive UI.
12 * @namespace YAHOO.util
13 * @requires yahoo, dom, event
16 if (typeof(YAHOO.util.ImageLoader) == 'undefined') {
17 YAHOO.util.ImageLoader = {};
21 * 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.
22 * @class YAHOO.util.ImageLoader.group
23 * @requires YAHOO.util.Dom
24 * @requires YAHOO.util.Event
26 * @param {String|HTMLElement} trigEl The HTML element id or reference to assign the trigger event to. Can be null for no trigger
27 * @param {String} trigAct The type of event to assign to trigEl. Can be null for no trigger
28 * @param {Number} timeout Timeout (time limit) length, in seconds. Can be undefined, or <= 0, for no time limit
30 YAHOO.util.ImageLoader.group = function(trigEl, trigAct, timeout) {
32 * Name for the group. Only used to identify the group in logging statements
36 this.name = 'unnamed';
39 * Collection of images registered with this group
47 * Timeout (time limit) length, in seconds
48 * @property timeoutLen
51 this.timeoutLen = timeout;
54 * Timeout object to keep a handle on the time limit
62 * Collection of triggers for this group.
63 * Keeps track of each trigger's element, event, and event-listener-callback "fetch" function
71 * Collection of custom-event triggers for this group.
72 * Keeps track of each trigger's event object and event-listener-callback "fetch" function
73 * @property _customTriggers
77 this._customTriggers = [];
80 * 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
81 * @property foldConditional
84 this.foldConditional = false;
87 * Class name that will identify images belonging to the group. This class name will be removed from each element in order to fetch images.
88 * This class should have, in its CSS style definition, "background:none !important;"
92 this.className = null;
95 * HTML elements having the class name that is associated with this group
96 * 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
97 * @property _classImageEls
101 this._classImageEls = null;
103 // add a listener to set the time limit in the onload
104 YAHOO.util.Event.addListener(window, 'load', this._onloadTasks, this, true);
106 this.addTrigger(trigEl, trigAct);
111 * Adds a trigger to the group. Call this with the same style as YAHOO.util.Event.addListener
113 * @param {String|HTMLElement} trigEl The HTML element id or reference to assign the trigger event to
114 * @param {String} trigAct The type of event to assign to trigEl
116 YAHOO.util.ImageLoader.group.prototype.addTrigger = function(trigEl, trigAct) {
117 if (! trigEl || ! trigAct) {
120 /* Need to wrap the fetch function. Event Util can't distinguish prototyped functions of different instantiations
121 * Leads to this scenario: groupA and groupZ both have window-scroll triggers. groupZ also has a 2-sec timeout (groupA has no timeout).
122 * 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.
123 * groupA's trigger is removed and never fires, leaving images unfetched
125 var wrappedFetch = function() {
128 this._triggers.push([trigEl, trigAct, wrappedFetch]);
129 YAHOO.util.Event.addListener(trigEl, trigAct, wrappedFetch, this, true);
133 * Adds a custom event trigger to the group.
134 * @method addCustomTrigger
135 * @param {Object} event A YAHOO.util.CustomEvent object
137 YAHOO.util.ImageLoader.group.prototype.addCustomTrigger = function(event) {
138 // make sure we're dealing with a CustomEvent object
139 if (! event || ! event instanceof YAHOO.util.CustomEvent) {
143 // see comment in addTrigger()
144 var wrappedFetch = function() {
147 this._customTriggers.push([event, wrappedFetch]);
148 event.subscribe(wrappedFetch, this, true);
152 * Setup to do in the window's onload
153 * Initiates time limit for group; executes the fold check for the images
154 * @method _onloadTasks
157 YAHOO.util.ImageLoader.group.prototype._onloadTasks = function() {
158 if (this.timeoutLen && typeof(this.timeoutLen) == 'number' && this.timeoutLen > 0) {
159 this._timeout = setTimeout(this._getFetchTimeout(), this.timeoutLen * 1000);
162 if (this.foldConditional) {
168 * Returns the group's fetch method, with the proper closure, for use with setTimeout
169 * @method _getFetchTimeout
170 * @return {Function} group's fetch method
173 YAHOO.util.ImageLoader.group.prototype._getFetchTimeout = function() {
175 return function() { self.fetch(); };
179 * Registers a background image with the group
180 * @method registerBgImage
181 * @param {String} domId HTML DOM id of the image element
182 * @param {String} url URL for the image
183 * @return {Object} bgImgObj that was registered, for modifying any attributes in the object
185 YAHOO.util.ImageLoader.group.prototype.registerBgImage = function(domId, url) {
186 this._imgObjs[domId] = new YAHOO.util.ImageLoader.bgImgObj(domId, url);
187 return this._imgObjs[domId];
190 * Registers a src image with the group
191 * @method registerSrcImage
192 * @param {String} domId HTML DOM id of the image element
193 * @param {String} url URL for the image
194 * @param {Int} width pixel width of the image - defaults to image's natural size
195 * @param {Int} height pixel height of the image - defaults to image's natural size
196 * @return {Object} srcImgObj that was registered, for modifying any attributes in the object
198 YAHOO.util.ImageLoader.group.prototype.registerSrcImage = function(domId, url, width, height) {
199 this._imgObjs[domId] = new YAHOO.util.ImageLoader.srcImgObj(domId, url, width, height);
200 return this._imgObjs[domId];
203 * Registers an alpha-channel-type png background image with the group
204 * @method registerPngBgImage
205 * @param {String} domId HTML DOM id of the image element
206 * @param {String} url URL for the image
207 * @param {Object} ailProps The AlphaImageLoader properties to be set for the image
208 * Valid properties are 'sizingMethod' and 'enabled'
209 * @return {Object} pngBgImgObj that was registered, for modifying any attributes in the object
211 YAHOO.util.ImageLoader.group.prototype.registerPngBgImage = function(domId, url, ailProps) {
212 this._imgObjs[domId] = new YAHOO.util.ImageLoader.pngBgImgObj(domId, url, ailProps);
213 return this._imgObjs[domId];
217 * Displays the images in the group
220 YAHOO.util.ImageLoader.group.prototype.fetch = function() {
222 clearTimeout(this._timeout);
223 // remove all listeners
224 for (var i=0, len = this._triggers.length; i < len; i++) {
225 YAHOO.util.Event.removeListener(this._triggers[i][0], this._triggers[i][1], this._triggers[i][2]);
227 // remove custom event subscriptions
228 for (var i=0, len = this._customTriggers.length; i < len; i++) {
229 this._customTriggers[i][0].unsubscribe(this._customTriggers[i][1], this);
232 // fetch whatever we need to by className
233 this._fetchByClass();
235 // fetch registered images
236 for (var id in this._imgObjs) {
237 if (YAHOO.lang.hasOwnProperty(this._imgObjs, id)) {
238 this._imgObjs[id].fetch();
244 * Checks the position of each image in the group. If any part of the image is within the client viewport, shows the image immediately.
248 YAHOO.util.ImageLoader.group.prototype._foldCheck = function() {
249 var scrollTop = (document.compatMode != 'CSS1Compat') ? document.body.scrollTop : document.documentElement.scrollTop;
250 var viewHeight = YAHOO.util.Dom.getViewportHeight();
251 var hLimit = scrollTop + viewHeight;
252 var scrollLeft = (document.compatMode != 'CSS1Compat') ? document.body.scrollLeft : document.documentElement.scrollLeft;
253 var viewWidth = YAHOO.util.Dom.getViewportWidth();
254 var wLimit = scrollLeft + viewWidth;
255 for (var id in this._imgObjs) {
256 if (YAHOO.lang.hasOwnProperty(this._imgObjs, id)) {
257 var elPos = YAHOO.util.Dom.getXY(this._imgObjs[id].domId);
258 if (elPos[1] < hLimit && elPos[0] < wLimit) {
259 this._imgObjs[id].fetch();
264 if (this.className) {
265 this._classImageEls = YAHOO.util.Dom.getElementsByClassName(this.className);
266 for (var i=0, len = this._classImageEls.length; i < len; i++) {
267 var elPos = YAHOO.util.Dom.getXY(this._classImageEls[i]);
268 if (elPos[1] < hLimit && elPos[0] < wLimit) {
269 YAHOO.util.Dom.removeClass(this._classImageEls[i], this.className);
276 * 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
277 * @method _fetchByClass
280 YAHOO.util.ImageLoader.group.prototype._fetchByClass = function() {
281 if (! this.className) {
285 // this._classImageEls may have been set during _foldCheck
286 if (this._classImageEls === null) {
287 this._classImageEls = YAHOO.util.Dom.getElementsByClassName(this.className);
289 YAHOO.util.Dom.removeClass(this._classImageEls, this.className);
294 * Base class for image objects to be registered with the groups
295 * @class YAHOO.util.ImageLoader.imgObj
297 * @param {String} domId HTML DOM id of the image element
298 * @param {String} url URL for the image
300 YAHOO.util.ImageLoader.imgObj = function(domId, url) {
302 * HTML DOM id of the image element
316 * Pixel width of the image. Will be set as a "width" attribute after the image is fetched.
317 * Detaults to the natural width of the image.
318 * Only appropriate with src images
325 * Pixel height of the image. Will be set as a "height" attribute after the image is fetched.
326 * Detaults to the natural height of the image.
327 * Only appropriate with src images
334 * Whether the style.visibility should be set to "visible" after the image is fetched.
335 * Used when setting src images as visibility:hidden prior to image fetching
336 * @property setVisible
339 this.setVisible = false;
342 * 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
347 this._fetched = false;
351 * Displays the image; puts the URL into the DOM
354 YAHOO.util.ImageLoader.imgObj.prototype.fetch = function() {
358 var el = document.getElementById(this.domId);
364 if (this.setVisible) {
365 el.style.visibility = 'visible';
368 el.width = this.width;
371 el.height = this.height;
373 this._fetched = true;
377 * Inserts the image URL into the DOM so that the image is displayed.
378 * Must be overridden by child class
380 * @param {Object} el HTML DOM element
383 YAHOO.util.ImageLoader.imgObj.prototype._applyUrl = function(el) {
387 * Background image object. A background image is one whose URL is specified by "background-image" in the element's style
388 * @class YAHOO.util.ImageLoader.bgImgObj
390 * @extends YAHOO.util.ImageLoader.imgObj
391 * @param {String} domId HTML DOM id of the image element
392 * @param {String} url URL for the image
394 YAHOO.util.ImageLoader.bgImgObj = function(domId, url) {
395 YAHOO.util.ImageLoader.bgImgObj.superclass.constructor.call(this, domId, url);
398 YAHOO.lang.extend(YAHOO.util.ImageLoader.bgImgObj, YAHOO.util.ImageLoader.imgObj);
401 * Inserts the image URL into the DOM so that the image is displayed.
402 * Sets style.backgroundImage
404 * @param {Object} el HTML DOM element
407 YAHOO.util.ImageLoader.bgImgObj.prototype._applyUrl = function(el) {
408 el.style.backgroundImage = "url('" + this.url + "')";
412 * Source image object. A source image is one whose URL is specified by a src attribute in the DOM element
413 * @class YAHOO.util.ImageLoader.srcImgObj
415 * @extends YAHOO.util.ImageLoader.imgObj
416 * @param {String} domId HTML DOM id of the image element
417 * @param {String} url URL for the image
418 * @param {Int} width pixel width of the image - defaults to image's natural size
419 * @param {Int} height pixel height of the image - defaults to image's natural size
421 YAHOO.util.ImageLoader.srcImgObj = function(domId, url, width, height) {
422 YAHOO.util.ImageLoader.srcImgObj.superclass.constructor.call(this, domId, url);
424 this.height = height;
427 YAHOO.lang.extend(YAHOO.util.ImageLoader.srcImgObj, YAHOO.util.ImageLoader.imgObj);
430 * Inserts the image URL into the DOM so that the image is displayed.
433 * @param {Object} el HTML DOM element
436 YAHOO.util.ImageLoader.srcImgObj.prototype._applyUrl = function(el) {
441 * 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
442 * @class YAHOO.util.ImageLoader.pngBgImgObj
444 * @extends YAHOO.util.ImageLoader.imgObj
445 * @param {String} domId HTML DOM id of the image element
446 * @param {String} url URL for the image
447 * @param {Object} ailProps The AlphaImageLoader properties to be set for the image
448 * Valid properties are 'sizingMethod' and 'enabled'
450 YAHOO.util.ImageLoader.pngBgImgObj = function(domId, url, ailProps) {
451 YAHOO.util.ImageLoader.pngBgImgObj.superclass.constructor.call(this, domId, url);
454 * AlphaImageLoader properties to be set for the image.
455 * Valid properties are "sizingMethod" and "enabled".
459 this.props = ailProps || {};
462 YAHOO.lang.extend(YAHOO.util.ImageLoader.pngBgImgObj, YAHOO.util.ImageLoader.imgObj);
465 * Inserts the image URL into the DOM so that the image is displayed.
466 * If the browser is determined to be IE6 (or older), sets the AlphaImageLoader src; otherwise sets style.backgroundImage
468 * @param {Object} el HTML DOM element
471 YAHOO.util.ImageLoader.pngBgImgObj.prototype._applyUrl = function(el) {
472 if (YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) {
473 var sizingMethod = (YAHOO.lang.isUndefined(this.props.sizingMethod)) ? 'scale' : this.props.sizingMethod;
474 var enabled = (YAHOO.lang.isUndefined(this.props.enabled)) ? 'true' : this.props.enabled;
475 el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + this.url + '", sizingMethod="' + sizingMethod + '", enabled="' + enabled + '")';
478 el.style.backgroundImage = "url('" + this.url + "')";
481 YAHOO.register("imageloader", YAHOO.util.ImageLoader, {version: "2.8.0r4", build: "2449"});