PDA

View Full Version : Lightbox document scroll and window resize



danh2000
28 Dec 2009, 11:16 AM
Something like this might be a good addition to the lightbox example:


var fixSize = function(){
var ps = Ext.fly(document).getScroll();
Ext.fly('ux-lightbox-shim').setStyle({
top: ps.top + 'px',
});
Ext.fly('ux-lightbox-overlay').setStyle({
top: ps.top + 'px',
});
Ext.ux.Lightbox.setViewSize();
};
Ext.fly(window).on({
resize : fixSize,
scroll : fixSize
});

danh2000
4 Jan 2010, 5:18 AM
The above code was the result of quickly tinkering in the Firebug console when I realized that the lightbox didn't work well when the page had scrollbars or when the window was resized.

I've now had a look at the source and propose the following version which fixes these issues:



Ext.ns('Ext.ux');

Ext.ux.Lightbox = (function(){
var els = {},
images = [],
activeImage,
initialized = false,
selectors = [];

return {
overlayOpacity: 0.85,
animate: true,
resizeSpeed: 8,
borderSize: 10,
labelImage: "Image",
labelOf: "of",

init: function() {
this.resizeDuration = this.animate ? ((11 - this.resizeSpeed) * 0.15) : 0;
this.overlayDuration = this.animate ? 0.2 : 0;

if(!initialized) {
Ext.apply(this, Ext.util.Observable.prototype);
Ext.util.Observable.constructor.call(this);
this.addEvents('open', 'close');
this.initMarkup();
this.initEvents();
initialized = true;

Ext.fly(window).on({
resize : this.fixViewSize,
scope : this
});
}
},
initMarkup: function() {
els.shim = Ext.DomHelper.append(document.body, {
tag: 'iframe',
id: 'ux-lightbox-shim'
}, true);
els.overlay = Ext.DomHelper.append(document.body, {
id: 'ux-lightbox-overlay'
}, true);

var lightboxTpl = new Ext.Template(this.getTemplate());
els.lightbox = lightboxTpl.append(document.body, {}, true);

var ids =
['outerImageContainer', 'imageContainer', 'image', 'hoverNav', 'navPrev', 'navNext', 'loading', 'loadingLink',
'outerDataContainer', 'dataContainer', 'data', 'details', 'caption', 'imageNumber', 'bottomNav', 'navClose'];

Ext.each(ids, function(id){
els[id] = Ext.get('ux-lightbox-' + id);
});

Ext.each([els.overlay, els.lightbox, els.shim], function(el){
el.setVisibilityMode(Ext.Element.DISPLAY)
el.hide();
});

var size = (this.animate ? 250 : 1) + 'px';
els.outerImageContainer.setStyle({
width: size,
height: size
});
},

getTemplate : function() {
return [
'<div id="ux-lightbox">',
'<div id="ux-lightbox-outerImageContainer">',
'<div id="ux-lightbox-imageContainer">',
'<img id="ux-lightbox-image">',
'<div id="ux-lightbox-hoverNav">',
'<a href="#" id="ux-lightbox-navPrev"></a>',
'<a href="#" id="ux-lightbox-navNext"></a>',
'</div>',
'<div id="ux-lightbox-loading">',
'<a id="ux-lightbox-loadingLink"></a>',
'</div>',
'</div>',
'</div>',
'<div id="ux-lightbox-outerDataContainer">',
'<div id="ux-lightbox-dataContainer">',
'<div id="ux-lightbox-data">',
'<div id="ux-lightbox-details">',
'<span id="ux-lightbox-caption"></span>',
'<span id="ux-lightbox-imageNumber"></span>',
'</div>',
'<div id="ux-lightbox-bottomNav">',
'<a href="#" id="ux-lightbox-navClose"></a>',
'</div>',
'</div>',
'</div>',
'</div>',
'</div>'
];
},

initEvents: function() {
var close = function(ev) {
ev.preventDefault();
this.close();
};

els.overlay.on('click', close, this);
els.loadingLink.on('click', close, this);
els.navClose.on('click', close, this);

els.lightbox.on('click', function(ev) {
if(ev.getTarget().id == 'ux-lightbox') {
this.close();
}
}, this);

els.navPrev.on('click', function(ev) {
ev.preventDefault();
this.setImage(activeImage - 1);
}, this);

els.navNext.on('click', function(ev) {
ev.preventDefault();
this.setImage(activeImage + 1);
}, this);
},

register: function(sel, group) {
if(selectors.indexOf(sel) === -1) {
selectors.push(sel);

Ext.fly(document).on('click', function(ev){
var target = ev.getTarget(sel);

if (target) {
ev.preventDefault();
this.open(target, sel, group);
}
}, this);
}
},

open: function(image, sel, group) {
group = group || false;
this.setViewSize();
els.overlay.fadeIn({
duration: this.overlayDuration,
endOpacity: this.overlayOpacity,
callback: function() {
images = [];

var index = 0;
if(!group) {
images.push([image.href, image.title]);
}
else {
var setItems = Ext.query(sel);
Ext.each(setItems, function(item) {
if(item.href) {
images.push([item.href, item.title]);
}
});

while (images[index][0] != image.href) {
index++;
}
}

// calculate top and left offset for the lightbox
var pageScroll = Ext.fly(document).getScroll();

var lightboxTop = pageScroll.top + (Ext.lib.Dom.getViewportHeight() / 10);
var lightboxLeft = pageScroll.left;
els.lightbox.setStyle({
top: lightboxTop + 'px',
left: lightboxLeft + 'px'
}).show();

this.setImage(index);

this.fireEvent('open', images[index]);
},
scope: this
});
},
fixViewSize : function(){
var o = els.overlay, oh = o.isVisible(), s = els.shim, sh = s.isVisible();
o.hide();
s.hide();
this.setViewSize(true);
o.setVisible(oh);
s.setVisible(sh);
},
setViewSize: function(preventShow){
var viewSize = this.getViewSize();
els.overlay.setStyle({
width: viewSize[0] + 'px',
height: viewSize[1] + 'px'
});
els.shim.setStyle({
width: viewSize[0] + 'px',
height: viewSize[1] + 'px'
});
if(!preventShow){
els.shim.show();
}
},

setImage: function(index){
activeImage = index;

this.disableKeyNav();
if (this.animate) {
els.loading.show();
}

els.image.hide();
els.hoverNav.hide();
els.navPrev.hide();
els.navNext.hide();
els.dataContainer.setOpacity(0.0001);
els.imageNumber.hide();

var preload = new Image();
preload.onload = (function(){
els.image.dom.src = images[activeImage][0];
this.resizeImage(preload.width, preload.height);
}).createDelegate(this);
preload.src = images[activeImage][0];
},

resizeImage: function(w, h){
var wCur = els.outerImageContainer.getWidth();
var hCur = els.outerImageContainer.getHeight();

var wNew = (w + this.borderSize * 2);
var hNew = (h + this.borderSize * 2);

var wDiff = wCur - wNew;
var hDiff = hCur - hNew;

var afterResize = function(){
els.hoverNav.setWidth(els.imageContainer.getWidth() + 'px');

els.navPrev.setHeight(h + 'px');
els.navNext.setHeight(h + 'px');

els.outerDataContainer.setWidth(wNew + 'px');

this.showImage();
};

if (hDiff != 0 || wDiff != 0) {
els.outerImageContainer.shift({
height: hNew,
width: wNew,
duration: this.resizeDuration,
scope: this,
callback: afterResize,
delay: 50
});
}
else {
afterResize.call(this);
}
},

showImage: function(){
els.loading.hide();
els.image.fadeIn({
duration: this.resizeDuration,
scope: this,
callback: function(){
this.updateDetails();
}
});
this.preloadImages();
},

updateDetails: function(){
var detailsWidth = els.data.getWidth(true) - els.navClose.getWidth() - 10;
els.details.setWidth((detailsWidth > 0 ? detailsWidth : 0) + 'px');

els.caption.update(images[activeImage][1]);

els.caption.show();
if (images.length > 1) {
els.imageNumber.update(this.labelImage + ' ' + (activeImage + 1) + ' ' + this.labelOf + ' ' + images.length);
els.imageNumber.show();
}

els.dataContainer.fadeIn({
duration: this.resizeDuration/2,
scope: this,
callback: function() {
var viewSize = this.getViewSize();
els.overlay.setHeight(viewSize[1] + 'px');
this.updateNav();
}
});
},

updateNav: function(){
this.enableKeyNav();

els.hoverNav.show();

// if not first image in set, display prev image button
if (activeImage > 0)
els.navPrev.show();

// if not last image in set, display next image button
if (activeImage < (images.length - 1))
els.navNext.show();
},

enableKeyNav: function() {
Ext.fly(document).on('keydown', this.keyNavAction, this);
},

disableKeyNav: function() {
Ext.fly(document).un('keydown', this.keyNavAction, this);
},

keyNavAction: function(ev) {
var keyCode = ev.getKey();

if (
keyCode == 88 || // x
keyCode == 67 || // c
keyCode == 27
) {
this.close();
}
else if (keyCode == 80 || keyCode == 37){ // display previous image
if (activeImage != 0){
this.setImage(activeImage - 1);
}
}
else if (keyCode == 78 || keyCode == 39){ // display next image
if (activeImage != (images.length - 1)){
this.setImage(activeImage + 1);
}
}
},

preloadImages: function(){
var next, prev;
if (images.length > activeImage + 1) {
next = new Image();
next.src = images[activeImage + 1][0];
}
if (activeImage > 0) {
prev = new Image();
prev.src = images[activeImage - 1][0];
}
},

close: function(){
this.disableKeyNav();
els.lightbox.hide();
els.overlay.fadeOut({
duration: this.overlayDuration
});
els.shim.hide();
this.fireEvent('close', activeImage);
},

getViewSize: function() {
return [Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true)];
}
}
})();

Ext.onReady(Ext.ux.Lightbox.init, Ext.ux.Lightbox);

danh2000
4 Jan 2010, 6:22 AM
I've update the fixViewSize method in the code above because when the lightbox was open, the getViewSize method took the width of the shim and overlay into account and therefore these elements weren't resized properly.

g2mac
7 Mar 2010, 1:36 PM
Very very big thanks! You have saved my time ))
So obvious error. It seems that developer of the lightbox use it not very often )

g2mac
7 Mar 2010, 2:45 PM
Unfortunately if i have vertical scrollbar on my page (long page) when lightbox calls .open() method it makes horizontal scrollbar to appear (wrong definition of viewable areas Width in setViewSize() method)
So i have wrote:

getViewSize: function() {
return [document.body.clientWidth, Ext.lib.Dom.getViewHeight(true)];
}

and all looks good