Opened 14 years ago

Closed 14 years ago

Last modified 14 years ago

#5512 closed defect (fixed)

dojox.image.Lightbox infinite loading when image not found

Reported by: guest Owned by: Adam Peller
Priority: high Milestone:
Component: Dojox Version: 1.0
Keywords: Lightbox onerror Cc: [email protected]
Blocked By: Blocking:


This patch should fix it:

check and click on one of the images to see the patched version.. Or mail me [email protected]… :)


.dojoxLightboxError {

height:50px; position:relative; bottom:0; left:0; margin-top:8px; color:#990000; z-index:1000; font-size:10pt; background-color: #fff; text-align: center;


JS Lightbox.js:

if(!dojo._hasResourcedojox.image.Lightbox?){ _hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResourcedojox.image.Lightbox? = true; dojo.provide("dojox.image.Lightbox"); dojo.experimental("dojox.image.Lightbox");

dojo.require("dijit.Dialog"); dojo.require("dojox.fx");


dijit._Widget,{ summary: a dojo-based Lightbox implementation. description: an Elegant, keyboard accessible, markup and store capable Lightbox widget to show images in a modal dialog-esque format. Can show individual images as Modal dialog, or can group images with multiple entry points, all using a single "master" Dialog for visualization examples: <a href="image1.jpg" dojoType="dojox.image.Lightbox">show lightbox</a> <a href="image2.jpg" dojoType="dojox.image.Lightbox" group="one">show group lightbox</a> <a href="image3.jpg" dojoType="dojox.image.Lightbox" group="one">show group lightbox</a> FIXME: not implemented fully yet, though works with basic datastore access. need to manually call widget._attachedDialog.addImage(item,"fromStore") for each item in a store result set. <div dojoType="dojox.image.Lightbox" group="fromStore" store="storeName"></div>

group: String grouping images in a page with similar tags will provide a 'slideshow' like grouping of images group: "",

title: String A string of text to be shown in the Lightbox beneath the image (empty if using a store) title: "",

href; String link to image to use for this Lightbox node (empty if using a store). href: "",

duration: Integer generic time in MS to adjust the feel of widget. could possibly add various durations for the various actions (dialog fadein, sizeing, img fadein ...) duration: 500,

_allowPassthru: Boolean privately set this to disable/enable natural link of anchor tags _allowPassthru: false, _attachedDialog: null, try to share a single underlay per page?

startup: function(){

this.inherited("startup", arguments); setup an attachment to the masterDialog (or create the masterDialog) var tmp = dijit.byId('dojoxLightboxDialog'); if(tmp){

this._attachedDialog = tmp;


this is the first instance to start, so we make the masterDialog this._attachedDialog = new dojox.image._LightboxDialog({ id: "dojoxLightboxDialog" }); this._attachedDialog.startup();

} if(!{

FIXME: full store support lacking, have to manually call this._attachedDialog.addImage(imgage,group) as it stands this._addSelf(); this.connect(this.domNode, "onclick", "_handleClick");



_addSelf: function(){


href: this.href, title: this.title



_handleClick: function(/* Event */e){

summary: handle the click on the link if(!this._allowPassthru){ e.preventDefault(); } else{ return; };


show: function(){;


disable: function(){

summary, disables event clobbering and dialog, and follows natural link this._allowPassthru = true;


enable: function(){

summary: enables the dialog (prevents default link) this._allowPassthru = false;




dijit.Dialog,{ Description: a widget that intercepts anchor links (typically around images) and displays a modal Dialog. this is the actual Popup, and should not be created directly. there will only be one of these on a page, so all dojox.image.Lightbox's will us it (the first instance of a Lightbox to be show()'n will create me If i do not exist) note: the could be the ImagePane? i was talking about?

title: String the current title title: "",

FIXME: implement titleTemplate

inGroup: Array Array of objects. this is populated by from the JSON object _groups, and should not be populate manually. it is a placeholder for the currently showing group of images in this master dialog inGroup: null,

imgUrl: String the src="" attrib of our imageNode (can be null at statup) imgUrl: "",

an array of objects, each object being a unique 'group' _groups: { XnoGroupX: [] }, _imageReady: false,

templateString:"<div class="dojoxLightbox" dojoAttachPoint="containerNode"> <div style="position:relative">

<div dojoAttachPoint="imageContainer" class="dojoxLightboxContainer">

<div class="dojoxLightboxError" style="display: none;" dojoAttachPoint="errNode"></div> <img dojoAttachPoint="imgNode" src="${imgUrl}" class="dojoxLightboxImage" alt="${title}"> <div class="dojoxLightboxFooter" dojoAttachPoint="titleNode">

<div class="dijitInline LightboxClose?" dojoAttachPoint="closeNode"></div> <div class="dijitInline LightboxNext?" dojoAttachPoint="nextNode"></div> <div class="dijitInline LightboxPrev?" dojoAttachPoint="prevNode"></div>

<div class="dojoxLightboxText"><span dojoAttachPoint="textNode">${title}</span><span dojoAttachPoint="groupCount" class="dojoxLightboxGroupText"></span></div>




</div> ",

startup: function(){

summary: add some extra event handlers, and startup our superclass. this.inherited("startup", arguments);

FIXME: these are supposed to be available in dijit.Dialog already, but aren't making it over. dojo.connect(document.documentElement,"onkeypress",this,"_handleKey"); this.connect(window,"onresize","_position");

this.connect(this.nextNode, "onclick", "_nextImage"); this.connect(this.prevNode, "onclick", "_prevImage"); this.connect(this.closeNode, "onclick", "hide");


show: function(/* Object */groupData){

summary: starts the chain of events to show an image in the dialog, including showing the dialog if it is not already visible,"opacity","0");,"opacity","0");

we only need to call if we're not already open. if(!{ this.inherited("show", arguments); }

this._imageReady = false;

this.imgNode.src = groupData.href;

if(( && !(groupData == "XnoGroupX"))


this.inGroup = this._groups[(]; var i = 0; determine where we were or are in the show dojo.forEach(this.inGroup,function(g){

if (g.href == groupData.href){

this._positionIndex = i;

} i++;


} if(!this._positionIndex){ this._positionIndex=0; this.imgNode.src = this.inGroup[this._positionIndex].href; } this.groupCount.innerHTML = " (" +(this._positionIndex+1) +" of "+this.inGroup.length+")"; = "visible"; = "visible";


this.groupCount.innerHTML = ""; = "hidden"; = "hidden";

} this.textNode.innerHTML = groupData.title;

this.imgNode.complete === true){

this._imgConnect = dojo.connect(this.imgNode,"onload", this, function(){

this._imageReady = true; this.resizeTo({ w: this.imgNode.width, h:this.imgNode.height, duration:this.duration }); dojo.disconnect(this._imgConnect);

}); this._imgErrorConnect = dojo.connect(this.imgNode,"onerror", this, function(){

this._imageReady = true; this._showError("Image not found"); dojo.disconnect(this._imgErrorConnect);

}); onload doesn't fire in IE if you connect before you set the src. hack to re-set the src after onload connection made: if(dojo.isIE){ this.imgNode.src = this.imgNode.src; }


do it quickly. kind of a hack, but image is ready now this.resizeTo({ w: this.imgNode.width, h:this.imgNode.height, duration:1 });



_showError: function(/*String*/err) {

this.errNode.innerHTML = err; = ; this.groupCount.innerHTML = ; this.textNode.innerHTML = ; do this to prevend too large text descriptions var _sizeAnim = dojox.fx.sizeTo({

node: this.containerNode, duration:this.duration, width: 200, height:80


summary: fade in the image, and fire showNav this.connect(_sizeAnim,"onEnd",dojo.hitch(this, function() { = ; dojo.fadeIn({ node: this.errNode, duration:this.duration,

onEnd: dojo.hitch(this,"_showNav")




_nextImage: function(){

summary: load next image in group if(this._positionIndex+1<this.inGroup.length){



this._positionIndex = 0;

} this._loadImage();


_prevImage: function(){

summary: load previous image in group if(this._positionIndex==0){

this._positionIndex = this.inGroup.length-1;



} this._loadImage();


_loadImage: function(){

summary: do the prep work before we can show another image var _loading = dojo.fx.combine([

dojo.fadeOut({ node:this.imgNode, duration:(this.duration/2) }), dojo.fadeOut({ node:this.titleNode, duration:(this.duration/2) }), dojo.fadeOut({ node: this.errNode, duration:(this.duration/2) })

]); this.connect(_loading,"onEnd",dojo.hitch(this, function() { = 'none'; this.errNode.innerHTML = ; this._prepNodes();



_prepNodes: function(){

summary: a localized hook to accompany _loadImage this._imageReady = false;{

href: this.inGroup[this._positionIndex].href, title: this.inGroup[this._positionIndex].title



resizeTo: function(/* Object */size){

summary: resize our dialog container, and fire _showImage var _sizeAnim = dojox.fx.sizeTo({

node: this.containerNode,


width: size.w, height:size.h+30

}); this.connect(_sizeAnim,"onEnd","_showImage");;


_showImage: function(){

summary: fade in the image, and fire showNav dojo.fadeIn({ node: this.imgNode, duration:this.duration,

onEnd: dojo.hitch(this,"_showNav")



_showNav: function(){

summary: fade in the footer, and setup our connections. dojo.fadeIn({ node: this.titleNode, duration:200 }).play(25);


hide: function(){

summary: close the Lightbox dojo.fadeOut({node:this.titleNode, duration:200 }).play(25); this.inherited("hide", arguments); this.inGroup = null; this._positionIndex = null;


addImage: function(/* object */child,/* String? */group){

summary: add an image to this master dialog child.href: String - link to image (required) child.title: String - title to display group: String - attach to group of similar tag or null for individual image instance

var g = group; if(!child.href){ return; } if(g){




this._groups[(g)] = [(child)];


}else{ this._groupsXnoGroupX?.push(child); }


_handleKey: function(/* Event */e){

summary: handle keyboard navigation if(!{ return; } var key = (e.charCode == dojo.keys.SPACE ? dojo.keys.SPACE : e.keyCode); switch(key){

case dojo.keys.ESCAPE: this.hide(); break;

case dojo.keys.DOWN_ARROW: case dojo.keys.RIGHT_ARROW: case 78: key "n"

this._nextImage(); break;

case dojo.keys.UP_ARROW: case dojo.keys.LEFT_ARROW: case 80: key "p"

this._prevImage(); break;





Change History (2)

comment:1 Changed 14 years ago by Adam Peller

Resolution: fixed
Status: newclosed

(In [12201]) One more bogus checkin to make corrupt ticket disappear. Fixes #5512

comment:2 Changed 14 years ago by (none)

Milestone: 1.0.3

Milestone 1.0.3 deleted

Note: See TracTickets for help on using tickets.