]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/yui/build/imageloader/imageloader.js
Release 6.5.0
[Github/sugarcrm.git] / include / javascript / yui / build / imageloader / imageloader.js
1 /*
2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
5 version: 2.9.0
6 */
7 /**
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.
10  *
11  * @module imageloader
12  * @namespace YAHOO.util.ImageLoader
13  * @requires yahoo, dom, event
14  */
15
16 if (typeof(YAHOO.util.ImageLoader) == 'undefined') {
17         YAHOO.util.ImageLoader = {};
18 }
19
20 /**
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
25  * @constructor
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
29  */
30 YAHOO.util.ImageLoader.group = function(trigEl, trigAct, timeout) {
31         /**
32          * Name for the group. Only used to identify the group in logging statements
33          * @property name
34          * @type String
35          */
36         this.name = 'unnamed';
37         
38         /**
39          * Collection of images registered with this group
40          * @property _imgObjs
41          * @private
42          * @type Object
43          */
44         this._imgObjs = {};
45         
46         /**
47          * Timeout (time limit) length, in seconds
48          * @property timeoutLen
49          * @type Number
50          */
51         this.timeoutLen = timeout;
52         
53         /**
54          * Timeout object to keep a handle on the time limit
55          * @property _timeout
56          * @private
57          * @type Object
58          */
59         this._timeout = null;
60         
61         /**
62          * Collection of triggers for this group.
63          * Keeps track of each trigger's element, event, and event-listener-callback "fetch" function
64          * @property _triggers
65          * @private
66          * @type Array
67          */
68         this._triggers = [];
69
70         /**
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
74          * @private
75          * @type Array
76          */
77         this._customTriggers = [];
78
79         /**
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
82          * @type Boolean
83          */
84         this.foldConditional = false;
85
86         /**
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;"
89          * @property className
90          * @type String
91          */
92         this.className = null;
93
94         /**
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
98          * @private
99          * @type Array
100          */
101         this._classImageEls = null;
102
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) {
106                 this._onloadTasks();
107         }
108         else {
109                 YAHOO.util.Event.onDOMReady(this._onloadTasks, this, true);
110         }
111
112         // add the trigger
113         this.addTrigger(trigEl, trigAct);
114
115 };
116
117 /**
118  * Adds a trigger to the group. Call this with the same style as YAHOO.util.Event.addListener
119  * @method addTrigger
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
122  */
123 YAHOO.util.ImageLoader.group.prototype.addTrigger = function(trigEl, trigAct) {
124         if (! trigEl || ! trigAct) {
125                 return;
126         }
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
131          */
132         var wrappedFetch = function() {
133                 this.fetch();
134         };
135         this._triggers.push([trigEl, trigAct, wrappedFetch]);
136         YAHOO.util.Event.addListener(trigEl, trigAct, wrappedFetch, this, true);
137 };
138
139 /**
140  * Adds a custom event trigger to the group.
141  * @method addCustomTrigger
142  * @param {Object} event A YAHOO.util.CustomEvent object
143  */
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) {
147                 return;
148         }
149
150         // see comment in addTrigger()
151         var wrappedFetch = function() {
152                 this.fetch();
153         };
154         this._customTriggers.push([event, wrappedFetch]);
155         event.subscribe(wrappedFetch, this, true);
156 };
157
158 /**
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
162  * @private
163  */
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);
167         }
168
169         if (this.foldConditional) {
170                 this._foldCheck();
171         }
172 };
173
174 /**
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
178  * @private
179  */
180 YAHOO.util.ImageLoader.group.prototype._getFetchTimeout = function() {
181         var self = this;
182         return function() { self.fetch(); };
183 };
184
185 /**
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
191  */
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];
195 };
196 /**
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
204  */
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];
208 };
209 /**
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
217  */
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];
221 };
222
223 /**
224  * Displays the images in the group
225  * @method fetch
226  */
227 YAHOO.util.ImageLoader.group.prototype.fetch = function() {
228
229         var i, len, id;
230
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]);
235         }
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);
239         }
240
241         // fetch whatever we need to by className
242         this._fetchByClass();
243
244         // fetch registered images
245         for (id in this._imgObjs) {
246                 if (YAHOO.lang.hasOwnProperty(this._imgObjs, id)) {
247                         this._imgObjs[id].fetch();
248                 }
249         }
250 };
251
252 /**
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.
254  * @method _foldCheck
255  * @private
256  */
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,
264                         id, elPos, i, len;
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();
270                         }
271                 }
272         }
273         // and by class
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);
280                         }
281                 }
282         }
283 };
284
285 /**
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
288  * @private
289  */
290 YAHOO.util.ImageLoader.group.prototype._fetchByClass = function() {
291         if (! this.className) {
292                 return;
293         }
294
295         // this._classImageEls may have been set during _foldCheck
296         if (this._classImageEls === null) {
297                 this._classImageEls = YAHOO.util.Dom.getElementsByClassName(this.className);
298         }
299         YAHOO.util.Dom.removeClass(this._classImageEls, this.className);
300 };
301
302
303 /**
304  * Base class for image objects to be registered with the groups
305  * @class YAHOO.util.ImageLoader.imgObj
306  * @constructor
307  * @param {String}      domId   HTML DOM id of the image element
308  * @param {String}      url     URL for the image
309  */
310 YAHOO.util.ImageLoader.imgObj = function(domId, url) {
311         /**
312          * HTML DOM id of the image element
313          * @property domId
314          * @type String
315          */
316         this.domId = domId;
317
318         /**
319          * URL for the image
320          * @property url
321          * @type String
322          */
323         this.url = url;
324
325         /**
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
329          * @property width
330          * @type Int
331          */
332         this.width = null;
333
334         /**
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
338          * @property height
339          * @type Int
340          */
341         this.height = null;
342
343         /**
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
347          * @type Boolean
348          */
349         this.setVisible = false;
350
351         /**
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
353          * @property _fetched
354          * @type Boolean
355          * @private
356          */
357         this._fetched = false;
358 };
359
360 /**
361  * Displays the image; puts the URL into the DOM
362  * @method fetch
363  */
364 YAHOO.util.ImageLoader.imgObj.prototype.fetch = function() {
365         if (this._fetched) {
366                 return;
367         }
368         var el = document.getElementById(this.domId);
369         if (! el) {
370                 return;
371         }
372         this._applyUrl(el);
373
374         if (this.setVisible) {
375                 el.style.visibility = 'visible';
376         }
377         if (this.width) {
378                 el.width = this.width;
379         }
380         if (this.height) {
381                 el.height = this.height;
382         }
383         this._fetched = true;
384 };
385
386 /**
387  * Inserts the image URL into the DOM so that the image is displayed.
388  * Must be overridden by child class
389  * @method _applyUrl
390  * @param {Object}      el      HTML DOM element
391  * @private
392  */
393 YAHOO.util.ImageLoader.imgObj.prototype._applyUrl = function(el) {
394 };
395
396 /**
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
399  * @constructor
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
403  */
404 YAHOO.util.ImageLoader.bgImgObj = function(domId, url) {
405         YAHOO.util.ImageLoader.bgImgObj.superclass.constructor.call(this, domId, url);
406 };
407
408 YAHOO.lang.extend(YAHOO.util.ImageLoader.bgImgObj, YAHOO.util.ImageLoader.imgObj);
409
410 /**
411  * Inserts the image URL into the DOM so that the image is displayed.
412  * Sets style.backgroundImage
413  * @method _applyUrl
414  * @param {Object}      el      HTML DOM element
415  * @private
416  */
417 YAHOO.util.ImageLoader.bgImgObj.prototype._applyUrl = function(el) {
418         el.style.backgroundImage = "url('" + this.url + "')";
419 };
420
421 /**
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
424  * @constructor
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
430  */
431 YAHOO.util.ImageLoader.srcImgObj = function(domId, url, width, height) {
432         YAHOO.util.ImageLoader.srcImgObj.superclass.constructor.call(this, domId, url);
433         this.width = width;
434         this.height = height;
435 };
436
437 YAHOO.lang.extend(YAHOO.util.ImageLoader.srcImgObj, YAHOO.util.ImageLoader.imgObj);
438
439 /**
440  * Inserts the image URL into the DOM so that the image is displayed.
441  * Sets src
442  * @method _applyUrl
443  * @param {Object}      el      HTML DOM element
444  * @private
445  */
446 YAHOO.util.ImageLoader.srcImgObj.prototype._applyUrl = function(el) {
447         el.src = this.url;
448 };
449
450 /**
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
453  * @constructor
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'
459  */
460 YAHOO.util.ImageLoader.pngBgImgObj = function(domId, url, ailProps) {
461         YAHOO.util.ImageLoader.pngBgImgObj.superclass.constructor.call(this, domId, url);
462
463         /**
464          * AlphaImageLoader properties to be set for the image.
465          * Valid properties are "sizingMethod" and "enabled".
466          * @property props
467          * @type Object
468          */
469         this.props = ailProps || {};
470 };
471
472 YAHOO.lang.extend(YAHOO.util.ImageLoader.pngBgImgObj, YAHOO.util.ImageLoader.imgObj);
473
474 /**
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
477  * @method _applyUrl
478  * @param {Object}      el      HTML DOM element
479  * @private
480  */
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 + '")';
486         }
487         else {
488                 el.style.backgroundImage = "url('" + this.url + "')";
489         }
490 };
491 YAHOO.register("imageloader", YAHOO.util.ImageLoader, {version: "2.9.0", build: "2800"});