PDA

View Full Version : Enhancement submission: BasicDialog restacking onmousedown



Animal
20 Nov 2006, 2:03 AM
Jack, I've been hatching a little enhancement...

z-index stacking of BasicDialogs.

With them looking so "window-like", end users will be surprised that clicking on them doesn't bring them forwards. I think I saw that you assign BasicDialogs z-index 10001?
What I've done is to have a static MixedCollection in the BasicDialog prototype, and have the constructor register them all.

A mon("mousedown"...) on each "el" re-indexes, rotating the clicked one to the top. The One at the back would always be 10001, and they'd go upwards from there.

Here is the code. It starts from the last 3 lines of the constructor where the dialog is registered, then goes on to the first bit of the prototype where the 2 new properties are defined...



this.dialogList.add(this.id, this);
this.el.setStyle({zIndex:10000 + this.dialogList.getCount()});
this.el.mon("mousedown", this.onClick.createDelegate(this));
};

YAHOO.extendX(YAHOO.ext.BasicDialog, YAHOO.ext.util.Observable, {

dialogList: new YAHOO.ext.util.MixedCollection(),

/**
* @ignore
* Rotate this Dialog to the top in the dialog z order stack.
*/
onClick: function()
{
this.dialogList.each(function(dialog)
{
var z = dialog.el.getStyle("zIndex");
if (dialog == this) z = 10000 + this.dialogList.getCount(); else z--;
dialog.el.setStyle({zIndex: z});
}, this);
},

Animal
21 Nov 2006, 1:29 AM
Actualy, that had a bug.

Whenever you clicked on a dialog that was already on top, the others would get their zIndex decremented.

It should be this:



this.el.mon("mousedown", this.toFront.createDelegate(this));

};

YAHOO.extendX(YAHOO.ext.Window, YAHOO.ext.BasicDialog, {

dialogList: new YAHOO.ext.util.MixedCollection(),

/**
* Rotate this Dialog to the top in the dialog z order stack.
*/
toFront: function()
{
// Only do anything if we're not already on top
var topIndex = this.dialogList.getCount() + 10000;
if (this.el.getStyle("zIndex") != topIndex)
{
this.dialogList.each(function(dialog)
{
dialog.el.setStyle({zIndex: (dialog == this) ? topIndex : (dialog.el.getStyle("zIndex") - 1)});
}, this);
}
},

jack.slocum
21 Nov 2006, 3:23 AM
I like it. Any chance you can give me the dialog list creation as well? Thanks.

Animal
21 Nov 2006, 4:12 AM
It's created at the top of the prototype spec in the extendX call - you must be tired!

jack.slocum
21 Nov 2006, 4:13 AM
lol - whoops.

Animal
21 Nov 2006, 5:41 AM
I forgot, this will also be needed:


/**
* Destroys this dialog
* @param {Boolean} removeEl (optional) true to remove the element from the DOM, and the
* dialog from the static dialog list.
*/
destroy : function(removeEl){
YAHOO.ext.EventManager.removeResizeListener(this.adjustViewport, this);
if(this.tabs){
this.tabs.destroy(removeEl);
}
if(removeEl === true){
this.el.update('');
this.el.remove();
this.dialogList.remove(this);
}
}

jack.slocum
21 Nov 2006, 6:14 AM
Ok, I went ahead and took this logic and started the DialogManager class. The latest is in svn. Do you think you could check it out and see how it works? My logic is a little different for the idea is the same. Instead of MixedCollection, I used a basic array and object hash separate. This way I could sort based on the last time the dialog was accessed. That we can always have the dialog z-index seeding from the same seed.

I also added in z-indexing of the shadow and proxy elements so those work right.

Unfortunately I don't have any complex screens to test it in a production environment.

Here's the DialogManager class. I requires some other stuff added to BasicDialog so you are better off grabbing it from svn.



YAHOO.ext.DialogManager = function(){
var list = {};
var accessList = [];
var front = null;

var sortDialogs = function(d1, d2){
return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
};

var orderDialogs = function(){
accessList.sort(sortDialogs);
var seed = YAHOO.ext.DialogManager.zseed;
for(var i = 0, len = accessList.length; i < len; i++){
if(accessList[i]){
accessList[i].setZIndex(seed + (i*10));
}
}
};

return {
/**
* The starting z-index for BasicDialogs - defaults to 10000
* @type Number
*/
zseed : 10000,


register : function(dlg){
list[dlg.id] = dlg;
accessList.push(dlg);
},

unregister : function(dlg){
delete list[dlg.id];
if(!accessList.indexOf){
for(var i = 0, len = accessList.length; i < len; i++){
accessList.splice(i, 1);
return;
}
}else{
var i = accessList.indexOf(dlg);
if(i != -1){
accessList.splice(i, 1);
}
}
},

/**
* Gets a registered dialog by id
* @param {String/Object} id The id of the dialog or a dialog
* @return {YAHOO.ext.BasicDialog}
*/
get : function(id){
return typeof id == 'object' ? id : list[id];
},

/**
* Brings the specified dialog to the front
* @param {String/Object} dlg The id of the dialog or a dialog
* @return {YAHOO.ext.BasicDialog}
*/
bringToFront : function(dlg){
dlg = this.get(dlg);
if(dlg != front){
front = dlg;
dlg._lastAccess = new Date().getTime();
orderDialogs();
}
return dlg;
},

/**
* Sends the specified dialog to the back
* @param {String/Object} dlg The id of the dialog or a dialog
* @return {YAHOO.ext.BasicDialog}
*/
sendToBack : function(dlg){
dlg = this.get(dlg);
dlg._lastAccess = -(new Date().getTime());
orderDialogs();
return dlg;
}
};
}();

Animal
21 Nov 2006, 6:18 AM
I'll extract it and give it a go.

WIth this change, the panel's modality mask will have to use the correct zIndex to be just under the panel rather than be coded in static CSS to be 10000.

jack.slocum
21 Nov 2006, 6:22 AM
Funny, I just added that in.

Animal
21 Nov 2006, 7:29 AM
Can you post up your JSBuilder project file?

I'm having problems building yui-ext.js with everthing in the correct order for dependencies.

Animal
21 Nov 2006, 7:53 AM
OK, I swapped and moved them until it built.

Your Dialog stacking is working fine, I can switch between all these:

http://i131.photobucket.com/albums/p286/TimeTrialAnimal/Dialogs.jpg

I notice using DOM Inspector that you use zIndex gaps of 10 between them now.

Animal
21 Nov 2006, 8:03 AM
A very minor thing with constraining during dragging. It accounts for shadow even if there is no shadow:



startMove : function(){
if(this.proxyDrag){
this.proxy.show();
}
if(this.constraintoviewport !== false){
this.dd.resetConstraints();
this.viewSize = [YAHOO.util.Dom.getViewportWidth(),YAHOO.util.Dom.getViewportHeight()];
this.dd.setXConstraint(this.xy[0], this.viewSize[0]-this.xy[0]-this.el.getWidth()-this.shadowOffset);
this.dd.setYConstraint(this.xy[1], this.viewSize[1]-this.xy[1]-this.el.getHeight()-this.shadowOffset);
}
},


should be



startMove : function(){
if(this.proxyDrag){
this.proxy.show();
}
if(this.constraintoviewport !== false){
this.dd.resetConstraints();
this.viewSize = [YAHOO.util.Dom.getViewportWidth(),YAHOO.util.Dom.getViewportHeight()];
this.dd.setXConstraint(this.xy[0], this.viewSize[0]-this.xy[0]-this.el.getWidth()-(this.shadow ? this.shadowOffset : 0));
this.dd.setYConstraint(this.xy[1], this.viewSize[1]-this.xy[1]-this.el.getHeight()-(this.shadow ? this.shadowOffset : 0));
}
},

jack.slocum
21 Nov 2006, 8:13 AM
I'll add that in. Thanks.

By the way, thanks for the mousedown stacking code. I was having trouble trying to figure out how to do it. My initial thought was to use focus but that could have cross-browser issues.

I use 10 z-index blocks because each dialog can have 4 diff z-indexes (mask, shadow, dlg, proxy). I figured I was use a 10 increment to leave space for future elements or whatever that might want to be in between.

jack.slocum
21 Nov 2006, 8:15 AM
I did it like this in the constructor:


if(this.shadow){
... // creates shadow
} else {
this.shadowOffset = 0;
}

Animal
21 Nov 2006, 8:22 AM
So.....

Any chance of a "parent" config option making it into this release????

Probably not - it's quite a bit of work making masking and constraining work with a parent.

jack.slocum
21 Nov 2006, 8:26 AM
Yeah, not for this release. Soon though because it makes sense.

I will also be stealing your window code probably to make a desktop type demo. ;)