Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / docs / source / lightbox.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.1
11  * Copyright(c) 2006-2010 Sencha Inc.
12  * licensing@sencha.com
13  * http://www.sencha.com/license
14  */
15 Ext.ns('Ext.ux');
16
17 Ext.ux.Lightbox = (function(){
18     var els = {},
19         images = [],
20         activeImage,
21         initialized = false,
22         selectors = [];
23
24     return {
25         overlayOpacity: 0.85,
26         animate: true,
27         resizeSpeed: 8,
28         borderSize: 10,
29         labelImage: "Image",
30         labelOf: "of",
31
32         init: function() {
33             this.resizeDuration = this.animate ? ((11 - this.resizeSpeed) * 0.15) : 0;
34             this.overlayDuration = this.animate ? 0.2 : 0;
35
36             if(!initialized) {
37                 Ext.apply(this, Ext.util.Observable.prototype);
38                 Ext.util.Observable.constructor.call(this);
39                 this.addEvents('open', 'close');
40                 this.initMarkup();
41                 this.initEvents();
42                 initialized = true;
43             }
44         },
45
46         initMarkup: function() {
47             els.shim = Ext.DomHelper.append(document.body, {
48                 tag: 'iframe',
49                 id: 'ux-lightbox-shim'
50             }, true);
51             els.overlay = Ext.DomHelper.append(document.body, {
52                 id: 'ux-lightbox-overlay'
53             }, true);
54             
55             var lightboxTpl = new Ext.Template(this.getTemplate());
56             els.lightbox = lightboxTpl.append(document.body, {}, true);
57
58             var ids =
59                 ['outerImageContainer', 'imageContainer', 'image', 'hoverNav', 'navPrev', 'navNext', 'loading', 'loadingLink',
60                 'outerDataContainer', 'dataContainer', 'data', 'details', 'caption', 'imageNumber', 'bottomNav', 'navClose'];
61
62             Ext.each(ids, function(id){
63                 els[id] = Ext.get('ux-lightbox-' + id);
64             });
65
66             Ext.each([els.overlay, els.lightbox, els.shim], function(el){
67                 el.setVisibilityMode(Ext.Element.DISPLAY)
68                 el.hide();
69             });
70
71             var size = (this.animate ? 250 : 1) + 'px';
72             els.outerImageContainer.setStyle({
73                 width: size,
74                 height: size
75             });
76         },
77
78         getTemplate : function() {
79             return [
80                 '<div id="ux-lightbox">',
81                     '<div id="ux-lightbox-outerImageContainer">',
82                         '<div id="ux-lightbox-imageContainer">',
83                             '<img id="ux-lightbox-image">',
84                             '<div id="ux-lightbox-hoverNav">',
85                                 '<a href="#" id="ux-lightbox-navPrev"></a>',
86                                 '<a href="#" id="ux-lightbox-navNext"></a>',
87                             '</div>',
88                             '<div id="ux-lightbox-loading">',
89                                 '<a id="ux-lightbox-loadingLink"></a>',
90                             '</div>',
91                         '</div>',
92                     '</div>',
93                     '<div id="ux-lightbox-outerDataContainer">',
94                         '<div id="ux-lightbox-dataContainer">',
95                             '<div id="ux-lightbox-data">',
96                                 '<div id="ux-lightbox-details">',
97                                     '<span id="ux-lightbox-caption"></span>',
98                                     '<span id="ux-lightbox-imageNumber"></span>',
99                                 '</div>',
100                                 '<div id="ux-lightbox-bottomNav">',
101                                     '<a href="#" id="ux-lightbox-navClose"></a>',
102                                 '</div>',
103                             '</div>',
104                         '</div>',
105                     '</div>',
106                 '</div>'
107             ];
108         },
109
110         initEvents: function() {
111             var close = function(ev) {
112                 ev.preventDefault();
113                 this.close();
114             };
115
116             els.overlay.on('click', close, this);
117             els.loadingLink.on('click', close, this);
118             els.navClose.on('click', close, this);
119
120             els.lightbox.on('click', function(ev) {
121                 if(ev.getTarget().id == 'ux-lightbox') {
122                     this.close();
123                 }
124             }, this);
125
126             els.navPrev.on('click', function(ev) {
127                 ev.preventDefault();
128                 this.setImage(activeImage - 1);
129             }, this);
130
131             els.navNext.on('click', function(ev) {
132                 ev.preventDefault();
133                 this.setImage(activeImage + 1);
134             }, this);
135         },
136
137         register: function(sel, group) {
138             if(selectors.indexOf(sel) === -1) {
139                 selectors.push(sel);
140
141                 Ext.fly(document).on('click', function(ev){
142                     var target = ev.getTarget(sel);
143
144                     if (target) {
145                         ev.preventDefault();
146                         this.open(target, sel, group);
147                     }
148                 }, this);
149             }
150         },
151
152         open: function(image, sel, group) {
153             group = group || false;
154             this.setViewSize();
155             els.overlay.fadeIn({
156                 duration: this.overlayDuration,
157                 endOpacity: this.overlayOpacity,
158                 callback: function() {
159                     images = [];
160
161                     var index = 0;
162                     if(!group) {
163                         images.push([image.href, image.title]);
164                     }
165                     else {
166                         var setItems = Ext.query(sel);
167                         Ext.each(setItems, function(item) {
168                             if(item.href) {
169                                 images.push([item.href, item.title]);
170                             }
171                         });
172
173                         while (images[index][0] != image.href) {
174                             index++;
175                         }
176                     }
177
178                     // calculate top and left offset for the lightbox
179                     var pageScroll = Ext.fly(document).getScroll();
180
181                     var lightboxTop = pageScroll.top + (Ext.lib.Dom.getViewportHeight() / 10);
182                     var lightboxLeft = pageScroll.left;
183                     els.lightbox.setStyle({
184                         top: lightboxTop + 'px',
185                         left: lightboxLeft + 'px'
186                     }).show();
187
188                     this.setImage(index);
189                     
190                     this.fireEvent('open', images[index]);                                        
191                 },
192                 scope: this
193             });
194         },
195         
196         setViewSize: function(){
197             var viewSize = this.getViewSize();
198             els.overlay.setStyle({
199                 width: viewSize[0] + 'px',
200                 height: viewSize[1] + 'px'
201             });
202             els.shim.setStyle({
203                 width: viewSize[0] + 'px',
204                 height: viewSize[1] + 'px'
205             }).show();
206         },
207
208         setImage: function(index){
209             activeImage = index;
210                       
211             this.disableKeyNav();            
212             if (this.animate) {
213                 els.loading.show();
214             }
215
216             els.image.hide();
217             els.hoverNav.hide();
218             els.navPrev.hide();
219             els.navNext.hide();
220             els.dataContainer.setOpacity(0.0001);
221             els.imageNumber.hide();
222
223             var preload = new Image();
224             preload.onload = (function(){
225                 els.image.dom.src = images[activeImage][0];
226                 this.resizeImage(preload.width, preload.height);
227             }).createDelegate(this);
228             preload.src = images[activeImage][0];
229         },
230
231         resizeImage: function(w, h){
232             var wCur = els.outerImageContainer.getWidth();
233             var hCur = els.outerImageContainer.getHeight();
234
235             var wNew = (w + this.borderSize * 2);
236             var hNew = (h + this.borderSize * 2);
237
238             var wDiff = wCur - wNew;
239             var hDiff = hCur - hNew;
240
241             var afterResize = function(){
242                 els.hoverNav.setWidth(els.imageContainer.getWidth() + 'px');
243
244                 els.navPrev.setHeight(h + 'px');
245                 els.navNext.setHeight(h + 'px');
246
247                 els.outerDataContainer.setWidth(wNew + 'px');
248
249                 this.showImage();
250             };
251             
252             if (hDiff != 0 || wDiff != 0) {
253                 els.outerImageContainer.shift({
254                     height: hNew,
255                     width: wNew,
256                     duration: this.resizeDuration,
257                     scope: this,
258                     callback: afterResize,
259                     delay: 50
260                 });
261             }
262             else {
263                 afterResize.call(this);
264             }
265         },
266
267         showImage: function(){
268             els.loading.hide();
269             els.image.fadeIn({
270                 duration: this.resizeDuration,
271                 scope: this,
272                 callback: function(){
273                     this.updateDetails();
274                 }
275             });
276             this.preloadImages();
277         },
278
279         updateDetails: function(){
280             var detailsWidth = els.data.getWidth(true) - els.navClose.getWidth() - 10;
281             els.details.setWidth((detailsWidth > 0 ? detailsWidth : 0) + 'px');
282             
283             els.caption.update(images[activeImage][1]);
284
285             els.caption.show();
286             if (images.length > 1) {
287                 els.imageNumber.update(this.labelImage + ' ' + (activeImage + 1) + ' ' + this.labelOf + '  ' + images.length);
288                 els.imageNumber.show();
289             }
290
291             els.dataContainer.fadeIn({
292                 duration: this.resizeDuration/2,
293                 scope: this,
294                 callback: function() {
295                     var viewSize = this.getViewSize();
296                     els.overlay.setHeight(viewSize[1] + 'px');
297                     this.updateNav();
298                 }
299             });
300         },
301
302         updateNav: function(){
303             this.enableKeyNav();
304
305             els.hoverNav.show();
306
307             // if not first image in set, display prev image button
308             if (activeImage > 0)
309                 els.navPrev.show();
310
311             // if not last image in set, display next image button
312             if (activeImage < (images.length - 1))
313                 els.navNext.show();
314         },
315
316         enableKeyNav: function() {
317             Ext.fly(document).on('keydown', this.keyNavAction, this);
318         },
319
320         disableKeyNav: function() {
321             Ext.fly(document).un('keydown', this.keyNavAction, this);
322         },
323
324         keyNavAction: function(ev) {
325             var keyCode = ev.getKey();
326
327             if (
328                 keyCode == 88 || // x
329                 keyCode == 67 || // c
330                 keyCode == 27
331             ) {
332                 this.close();
333             }
334             else if (keyCode == 80 || keyCode == 37){ // display previous image
335                 if (activeImage != 0){
336                     this.setImage(activeImage - 1);
337                 }
338             }
339             else if (keyCode == 78 || keyCode == 39){ // display next image
340                 if (activeImage != (images.length - 1)){
341                     this.setImage(activeImage + 1);
342                 }
343             }
344         },
345
346         preloadImages: function(){
347             var next, prev;
348             if (images.length > activeImage + 1) {
349                 next = new Image();
350                 next.src = images[activeImage + 1][0];
351             }
352             if (activeImage > 0) {
353                 prev = new Image();
354                 prev.src = images[activeImage - 1][0];
355             }
356         },
357
358         close: function(){
359             this.disableKeyNav();
360             els.lightbox.hide();
361             els.overlay.fadeOut({
362                 duration: this.overlayDuration
363             });
364             els.shim.hide();
365             this.fireEvent('close', activeImage);
366         },
367
368         getViewSize: function() {
369             return [Ext.lib.Dom.getViewWidth(), Ext.lib.Dom.getViewHeight()];
370         }
371     }
372 })();
373
374 Ext.onReady(Ext.ux.Lightbox.init, Ext.ux.Lightbox);</pre>    
375 </body>
376 </html>