2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
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.ImageLoader
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 on DOM ready
104 // if DOM is already ready, do so immediately
105 if (YAHOO.util.Event.DOMReady) {
109 YAHOO.util.Event.onDOMReady(this._onloadTasks, this, true);
113 this.addTrigger(trigEl, trigAct);
118 * Adds a trigger to the group. Call this with the same style as YAHOO.util.Event.addListener
120 * @param {String|HTMLElement} trigEl The HTML element id or reference to assign the trigger event to
121 * @param {String} trigAct The type of event to assign to trigEl
123 YAHOO.util.ImageLoader.group.prototype.addTrigger = function(trigEl, trigAct) {
124 if (! trigEl || ! trigAct) {
127 /* Need to wrap the fetch function. Event Util can't distinguish prototyped functions of different instantiations
128 * Leads to this scenario: groupA and groupZ both have window-scroll triggers. groupZ also has a 2-sec timeout (groupA has no timeout).
129 * 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.
130 * groupA's trigger is removed and never fires, leaving images unfetched
132 var wrappedFetch = function() {
135 this._triggers.push([trigEl, trigAct, wrappedFetch]);
136 YAHOO.util.Event.addListener(trigEl, trigAct, wrappedFetch, this, true);
140 * Adds a custom event trigger to the group.
141 * @method addCustomTrigger
142 * @param {Object} event A YAHOO.util.CustomEvent object
144 YAHOO.util.ImageLoader.group.prototype.addCustomTrigger = function(event) {
145 // make sure we're dealing with a CustomEvent object
146 if (! event || ! event instanceof YAHOO.util.CustomEvent) {
150 // see comment in addTrigger()
151 var wrappedFetch = function() {
154 this._customTriggers.push([event, wrappedFetch]);
155 event.subscribe(wrappedFetch, this, true);
159 * Setup to do in the window's onload
160 * Initiates time limit for group; executes the fold check for the images
161 * @method _onloadTasks
164 YAHOO.util.ImageLoader.group.prototype._onloadTasks = function() {
165 if (this.timeoutLen && typeof(this.timeoutLen) == 'number' && this.timeoutLen > 0) {
166 this._timeout = setTimeout(this._getFetchTimeout(), this.timeoutLen * 1000);
169 if (this.foldConditional) {
175 * Returns the group's fetch method, with the proper closure, for use with setTimeout
176 * @method _getFetchTimeout
177 * @return {Function} group's fetch method
180 YAHOO.util.ImageLoader.group.prototype._getFetchTimeout = function() {
182 return function() { self.fetch(); };
186 * Registers a background image with the group
187 * @method registerBgImage
188 * @param {String} domId HTML DOM id of the image element
189 * @param {String} url URL for the image
190 * @return {Object} bgImgObj that was registered, for modifying any attributes in the object
192 YAHOO.util.ImageLoader.group.prototype.registerBgImage = function(domId, url) {
193 this._imgObjs[domId] = new YAHOO.util.ImageLoader.bgImgObj(domId, url);
194 return this._imgObjs[domId];
197 * Registers a src image with the group
198 * @method registerSrcImage
199 * @param {String} domId HTML DOM id of the image element
200 * @param {String} url URL for the image
201 * @param {Int} width pixel width of the image - defaults to image's natural size
202 * @param {Int} height pixel height of the image - defaults to image's natural size
203 * @return {Object} srcImgObj that was registered, for modifying any attributes in the object
205 YAHOO.util.ImageLoader.group.prototype.registerSrcImage = function(domId, url, width, height) {
206 this._imgObjs[domId] = new YAHOO.util.ImageLoader.srcImgObj(domId, url, width, height);
207 return this._imgObjs[domId];
210 * Registers an alpha-channel-type png background image with the group
211 * @method registerPngBgImage
212 * @param {String} domId HTML DOM id of the image element
213 * @param {String} url URL for the image
214 * @param {Object} ailProps The AlphaImageLoader properties to be set for the image
215 * Valid properties are 'sizingMethod' and 'enabled'
216 * @return {Object} pngBgImgObj that was registered, for modifying any attributes in the object
218 YAHOO.util.ImageLoader.group.prototype.registerPngBgImage = function(domId, url, ailProps) {
219 this._imgObjs[domId] = new YAHOO.util.ImageLoader.pngBgImgObj(domId, url, ailProps);
220 return this._imgObjs[domId];
224 * Displays the images in the group
227 YAHOO.util.ImageLoader.group.prototype.fetch = function() {
231 clearTimeout(this._timeout);
232 // remove all listeners
233 for (i=0, len = this._triggers.length; i < len; i++) {
234 YAHOO.util.Event.removeListener(this._triggers[i][0], this._triggers[i][1], this._triggers[i][2]);
236 // remove custom event subscriptions
237 for (i=0, len = this._customTriggers.length; i < len; i++) {
238 this._customTriggers[i][0].unsubscribe(this._customTriggers[i][1], this);
241 // fetch whatever we need to by className
242 this._fetchByClass();
244 // fetch registered images
245 for (id in this._imgObjs) {
246 if (YAHOO.lang.hasOwnProperty(this._imgObjs, id)) {
247 this._imgObjs[id].fetch();
253 * Checks the position of each image in the group. If any part of the image is within the client viewport, shows the image immediately.
257 YAHOO.util.ImageLoader.group.prototype._foldCheck = function() {
258 var scrollTop = (document.compatMode != 'CSS1Compat') ? document.body.scrollTop : document.documentElement.scrollTop,
259 viewHeight = YAHOO.util.Dom.getViewportHeight(),
260 hLimit = scrollTop + viewHeight,
261 scrollLeft = (document.compatMode != 'CSS1Compat') ? document.body.scrollLeft : document.documentElement.scrollLeft,
262 viewWidth = YAHOO.util.Dom.getViewportWidth(),
263 wLimit = scrollLeft + viewWidth,
265 for (id in this._imgObjs) {
266 if (YAHOO.lang.hasOwnProperty(this._imgObjs, id)) {
267 elPos = YAHOO.util.Dom.getXY(this._imgObjs[id].domId);
268 if (elPos[1] < hLimit && elPos[0] < wLimit) {
269 this._imgObjs[id].fetch();
274 if (this.className) {
275 this._classImageEls = YAHOO.util.Dom.getElementsByClassName(this.className);
276 for (i=0, len = this._classImageEls.length; i < len; i++) {
277 elPos = YAHOO.util.Dom.getXY(this._classImageEls[i]);
278 if (elPos[1] < hLimit && elPos[0] < wLimit) {
279 YAHOO.util.Dom.removeClass(this._classImageEls[i], this.className);
286 * 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
287 * @method _fetchByClass
290 YAHOO.util.ImageLoader.group.prototype._fetchByClass = function() {
291 if (! this.className) {
295 // this._classImageEls may have been set during _foldCheck
296 if (this._classImageEls === null) {
297 this._classImageEls = YAHOO.util.Dom.getElementsByClassName(this.className);
299 YAHOO.util.Dom.removeClass(this._classImageEls, this.className);
304 * Base class for image objects to be registered with the groups
305 * @class YAHOO.util.ImageLoader.imgObj
307 * @param {String} domId HTML DOM id of the image element
308 * @param {String} url URL for the image
310 YAHOO.util.ImageLoader.imgObj = function(domId, url) {
312 * HTML DOM id of the image element
326 * Pixel width of the image. Will be set as a "width" attribute after the image is fetched.
327 * Detaults to the natural width of the image.
328 * Only appropriate with src images
335 * Pixel height of the image. Will be set as a "height" attribute after the image is fetched.
336 * Detaults to the natural height of the image.
337 * Only appropriate with src images
344 * Whether the style.visibility should be set to "visible" after the image is fetched.
345 * Used when setting src images as visibility:hidden prior to image fetching
346 * @property setVisible
349 this.setVisible = false;
352 * 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
357 this._fetched = false;
361 * Displays the image; puts the URL into the DOM
364 YAHOO.util.ImageLoader.imgObj.prototype.fetch = function() {
368 var el = document.getElementById(this.domId);
374 if (this.setVisible) {
375 el.style.visibility = 'visible';
378 el.width = this.width;
381 el.height = this.height;
383 this._fetched = true;
387 * Inserts the image URL into the DOM so that the image is displayed.
388 * Must be overridden by child class
390 * @param {Object} el HTML DOM element
393 YAHOO.util.ImageLoader.imgObj.prototype._applyUrl = function(el) {
397 * Background image object. A background image is one whose URL is specified by "background-image" in the element's style
398 * @class YAHOO.util.ImageLoader.bgImgObj
400 * @extends YAHOO.util.ImageLoader.imgObj
401 * @param {String} domId HTML DOM id of the image element
402 * @param {String} url URL for the image
404 YAHOO.util.ImageLoader.bgImgObj = function(domId, url) {
405 YAHOO.util.ImageLoader.bgImgObj.superclass.constructor.call(this, domId, url);
408 YAHOO.lang.extend(YAHOO.util.ImageLoader.bgImgObj, YAHOO.util.ImageLoader.imgObj);
411 * Inserts the image URL into the DOM so that the image is displayed.
412 * Sets style.backgroundImage
414 * @param {Object} el HTML DOM element
417 YAHOO.util.ImageLoader.bgImgObj.prototype._applyUrl = function(el) {
418 el.style.backgroundImage = "url('" + this.url + "')";
422 * Source image object. A source image is one whose URL is specified by a src attribute in the DOM element
423 * @class YAHOO.util.ImageLoader.srcImgObj
425 * @extends YAHOO.util.ImageLoader.imgObj
426 * @param {String} domId HTML DOM id of the image element
427 * @param {String} url URL for the image
428 * @param {Int} width pixel width of the image - defaults to image's natural size
429 * @param {Int} height pixel height of the image - defaults to image's natural size
431 YAHOO.util.ImageLoader.srcImgObj = function(domId, url, width, height) {
432 YAHOO.util.ImageLoader.srcImgObj.superclass.constructor.call(this, domId, url);
434 this.height = height;
437 YAHOO.lang.extend(YAHOO.util.ImageLoader.srcImgObj, YAHOO.util.ImageLoader.imgObj);
440 * Inserts the image URL into the DOM so that the image is displayed.
443 * @param {Object} el HTML DOM element
446 YAHOO.util.ImageLoader.srcImgObj.prototype._applyUrl = function(el) {
451 * 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
452 * @class YAHOO.util.ImageLoader.pngBgImgObj
454 * @extends YAHOO.util.ImageLoader.imgObj
455 * @param {String} domId HTML DOM id of the image element
456 * @param {String} url URL for the image
457 * @param {Object} ailProps The AlphaImageLoader properties to be set for the image
458 * Valid properties are 'sizingMethod' and 'enabled'
460 YAHOO.util.ImageLoader.pngBgImgObj = function(domId, url, ailProps) {
461 YAHOO.util.ImageLoader.pngBgImgObj.superclass.constructor.call(this, domId, url);
464 * AlphaImageLoader properties to be set for the image.
465 * Valid properties are "sizingMethod" and "enabled".
469 this.props = ailProps || {};
472 YAHOO.lang.extend(YAHOO.util.ImageLoader.pngBgImgObj, YAHOO.util.ImageLoader.imgObj);
475 * Inserts the image URL into the DOM so that the image is displayed.
476 * If the browser is determined to be IE6 (or older), sets the AlphaImageLoader src; otherwise sets style.backgroundImage
478 * @param {Object} el HTML DOM element
481 YAHOO.util.ImageLoader.pngBgImgObj.prototype._applyUrl = function(el) {
482 if (YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) {
483 var sizingMethod = (YAHOO.lang.isUndefined(this.props.sizingMethod)) ? 'scale' : this.props.sizingMethod,
484 enabled = (YAHOO.lang.isUndefined(this.props.enabled)) ? 'true' : this.props.enabled;
485 el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + this.url + '", sizingMethod="' + sizingMethod + '", enabled="' + enabled + '")';
488 el.style.backgroundImage = "url('" + this.url + "')";
491 YAHOO.register("imageloader", YAHOO.util.ImageLoader, {version: "2.9.0", build: "2800"});