PDA

View Full Version : How to make and navigation menu like Jack's Blog



met4lz
4 Dec 2006, 11:18 AM
Hi guys, I'm quite new to this wonderfull user interface, and I got a question.
How can I make a navigation menu with stacked collapsible panels like the ones found in Jack's Blog at: Downloads ----> Build your own yui-ext.js (Tab).
I'm using the borderlayout, and when I try to add another panel it is created on a new tab.

Thx

jbowman
4 Dec 2006, 2:40 PM
He's using nested layouts, in a layoutDialog... A layoutDialog is nothing more than a BasicDialog who's body element has had a BorderLayout inserted into it. So you can take this and modify it to fit your BorderLayout.

Jacks Download Dialog


showDialog : function(){
if(!dialog){
dialog = new YAHOO.ext.LayoutDialog("download-dlg", {
modal: true,
shim:true,
width:600,
height:450,
shadow:true,
minWidth:500,
minHeight:350,
autoTabs:true,
autoScroll:false,
center:{
tabPosition: 'top',
alwaysShowTabs: true
}
});
dialog.addKeyListener(27, dialog.hide, dialog);
dialog.setDefaultButton(dialog.addButton('Close', dialog.hide, dialog));
dlBtn = dialog.addButton('Build It!', this.getDownload, this);
var innerLayout = new YAHOO.ext.BorderLayout('dl-inner', {
east: {
initialSize: 200,
autoScroll:true,
split:true
},
center: {
autoScroll:true
}
});
innerLayout.beginUpdate();
innerLayout.add('east', new YAHOO.ext.ContentPanel('dl-details'));
innerLayout.add('center', new YAHOO.ext.ContentPanel('selection-panel'));
innerLayout.endUpdate(true);

var layout = dialog.getLayout();
dialog.beginUpdate();
var sp = layout.add('center', new YAHOO.ext.ContentPanel('standard-panel',
{title: 'Download the Source', fitToFrame:true}));
sp.on('activate', function(){
dlBtn.getEl().setStyle('display', 'none');
dlInfo.hide();
});
var p = layout.add('center', new YAHOO.ext.NestedLayoutPanel(innerLayout,
{title: 'Build your own yui-ext.js'}));
p.on('activate', function(){
dlBtn.getEl().setStyle('display', '');
dlInfo.show();
if(!detailTpl){
this.render();
}
}, this, true);
layout.getRegion('center').showPanel(sp);
dialog.endUpdate();
}
if(typeof Commentable != 'undefined' && Commentable.isOpen()){
Commentable.closeComment();
this.showDialog.defer(200, this);
return;
}
dialog.show(showBtn.dom);
},

brian.moeskau
4 Dec 2006, 3:39 PM
If you are specifically asking about how to make the panels that expand and collapse, at the moment there is not a nice, packaged widget for this. However, the code to create it is pretty straight-forward. Here's a version I pulled out of Jack's source and have been playing with (note: it's not necessarily complete or working correctly at the moment, but it should point you in the right direction -- YMMV):


var Collapser = function(clickEl, collapseEl){
this.clickEl = getEl(clickEl);
this.collapseEl = getEl(collapseEl);
this.clickEl.addClass('accordion-expanded');
this.enabled = true;

this.clickEl.mon('click', function(){
if (this.enabled) this.collapsed === true ?
this.expand() : this.collapse();
}, this, true);
};

Collapser.prototype = {
collapse : function(){
this.collapseEl.clip();
this.collapseEl.setHeight(1, true, .35, this.afterCollapse.createDelegate(this), YAHOO.util.Easing.easeOut);
},

afterCollapse : function(){
this.collapsed = true;
this.collapseEl.setDisplayed(false);
this.clickEl.replaceClass('accordion-expanded','accordion-collapsed');
},

expand : function(){
this.collapseEl.setDisplayed(true);
this.collapseEl.autoHeight(true, .35, this.afterExpand.createDelegate(this), YAHOO.util.Easing.easeOut);
},

afterExpand : function(){
this.collapsed = false;
this.collapseEl.unclip();
this.collapseEl.setStyle('height', '');
this.clickEl.replaceClass('accordion-collapsed','accordion-expanded');
},

enable : function(){
this.enabled = true;
this.clickEl.removeClass('disabled');
},

disable : function(){
this.enabled = false;
this.collapse();
this.clickEl.addClass('disabled');
}
};

And then to use it you just do something like:


<div id="head">My Box</div>
<div id="body">Content goes here.</div>

<script>
var collapser = new Collapser('head', 'body');
collapser.expand();
</script>

Ultimately, it needs some more functionality and polish, and maybe I (or someone else) will eventually turn it into more of a component like the rest of Jack's stuff :)

Brian

met4lz
6 Dec 2006, 4:06 AM
Thanks guys, your tips were very useful to the project I'm working at.
And thanks for the quick answer too :D

luismalheiro
8 Dec 2006, 12:06 PM
Hi! I'm really a new newbie to this, but I've done some improvements to the Collapser posted above by Brian (bmoeskau). In particular, I added a state manager to it. I'm sure I could have done it in a better way, but my knowledged of YUI and YUI-ext is still limited. So, please, feel free to point out parts that could be improved.

Thanks!
Luis



// Collapser


var Collapser = function(collapsableContainer){

this.id = collapsableContainer.id;

this.clickEl = getEl(YAHOO.util.Dom.getElementsByClassName('ycollapsable-menuhead', null, collapsableContainer)[0]);
this.collapseEl = getEl(YAHOO.util.Dom.getElementsByClassName('ycollapsable-menucontent', null, collapsableContainer)[0]);

this.clickEl.addClass('ycollapsable-expanded');
this.enabled = true;

this.clickEl.mon('click', function(){
if (this.enabled) this.collapsed === true ?
this.expand() : this.collapse();
}, this, true);

this.events = {
'expanded' : new YAHOO.util.CustomEvent('expanded'),
'collapsed' : new YAHOO.util.CustomEvent('collapsed'),
'enabled' : new YAHOO.util.CustomEvent('enabled'),
'disabled' : new YAHOO.util.CustomEvent('disabled')
};

};

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

collapse : function(animate){
if (!this.collapsed) {
this.collapseEl.clip();
if (animate == null || animate == true) {
this.collapseEl.setHeight(1, true, .35, this.afterCollapse.createDelegate(this), YAHOO.util.Easing.easeOut);
} else {
this.collapseEl.setHeight(1);
this.afterCollapse();
}
}
},

afterCollapse : function(){
this.collapsed = true;
this.collapseEl.setDisplayed(false);
this.clickEl.replaceClass('ycollapsable-expanded','ycollapsable-collapsed');
this.fireEvent('collapsed', this);
},

expand : function(animate){
if (this.collapsed) {
this.collapseEl.setDisplayed(true);
if (animate == null || animate == true) {
this.collapseEl.autoHeight(animate, .35, this.afterExpand.createDelegate(this), YAHOO.util.Easing.easeOut);
} else {
this.collapseEl.autoHeight();
this.afterExapand();
}
}
},

afterExpand : function(){
this.collapsed = false;
this.collapseEl.unclip();
this.collapseEl.setStyle('height', '');
this.clickEl.replaceClass('ycollapsable-collapsed','ycollapsable-expanded');
this.fireEvent('expanded', this);
},

enable : function(){
this.enabled = true;
this.clickEl.removeClass('ycollapsable-disabled');
this.fireEvent('enabled', this);
},

disable : function(){
this.enabled = false;
this.collapse();
this.clickEl.addClass('ycollapsable-disabled');
this.fireEvent('disabled', this);
},

restoreState : function(provider){
if(!provider){
provider = YAHOO.ext.state.Manager;
}
var sm = new CollapserStateManager();
sm.init(this, provider);
}
});


var CollapserStateManager = function(collapserObject, provider){

this.state = {
collapsed: true,
enabled: true
};

};

CollapserStateManager.prototype = {
init : function(collapser, provider){
this.provider = provider;
var state = provider.get(collapser.id+'-collapser-state');
if(state){

if(state.collapsed){
collapser.collapse(false);
} else {
collapser.expand(false);
}

if(state.enabled == true){
collapser.enable();
}else{
collapser.disable();
}

this.state = state;
}
this.collapser = collapser;
collapser.on('collapsed', this.onCollapsed, this, true);
collapser.on('expanded', this.onExpanded, this, true);
collapser.on('enabled', this.onEnabled, this, true);
collapser.on('disabled', this.onDisabled, this, true);
},

storeState : function(){
this.provider.set(this.collapser.id+'-collapser-state', this.state);
},

onCollapsed : function(){
this.state.collapsed = true;
this.storeState();
},

onExpanded : function(){
this.state.collapsed = false;
this.storeState();
},

onEnabled : function(){
this.state.enabled = true;
this.storeState();
},

onDisabled : function(){
this.state.enabled = false;
this.storeState();
}
};

//
//Usage example:
//
//
// <div id="config-collapser" class="ycollapsable">
// <div class="ycollapsable-menuhead">
// <asp:Label ID="MenuHeader0" runat="server" Text="Configuração"></asp:Label>
// </div>
// <div class="ycollapsable-menucontent">
// <div>
// <asp:LinkButton ID="UserAdmLinkPage" runat="server" Text="Gerenciamento de Usuário"></asp:LinkButton>
// </div>
// <div>
// <asp:LinkButton ID="LinkButton1" runat="server" Text="Parâmetros"></asp:LinkButton>
// </div>
// </div>
// </div>
//
// <div id="monitoring-collapser" class="ycollapsable">
// <div class="ycollapsable-menuhead">
// <asp:Label ID="Label1" runat="server" Text="Monitoring"></asp:Label>
// </div>
// <div class="ycollapsable-menucontent">
// <div>
// <asp:LinkButton ID="LinkButton6" runat="server" Text="Diagnosticos"></asp:LinkButton>
// </div>
// <div>
// <asp:LinkButton ID="LinkButton7" runat="server" Text="Modelos"></asp:LinkButton>
// </div>
// </div>
// </div>
//
// <script>
//
// var collapsables = YAHOO.util.Dom.getElementsByClassName('ycollapsable')
//
// for (i in collapsables) {
// var collapser = new Collapser(collapsables[i]);
// collapser.restoreState();
// collapser.enable();
// }
//
// </script>

brian.moeskau
8 Dec 2006, 3:38 PM
Hey Luis,

Nice job! I took your improvements one step further:

- Added a default cookie provider if none is specified since the StateManager doesn't do anything without a valid provider.
- Changed restoreState() to accept an optional defaultState parameter that gets used the first time through when there is no valid saved state.
- Added: containerEl = getEl(collapsableContainer); as the first line of the constructor so that you can simply pass in an id from the page (although passing an element will still work).
- Added functionality in the sample to demonstrate disabling/enabling a panel. Also made the sample html a little more generic, included the style defs, etc.

Let me know if you improve it even further :)

- Brian

New script (collapser.js):

// Collapser

var Collapser = function(collapsableContainer){

containerEl = getEl(collapsableContainer);
this.clickEl = getEl(YAHOO.util.Dom.getElementsByClassName('ycollapsable-menuhead', null, collapsableContainer)[0]);
this.collapseEl = getEl(YAHOO.util.Dom.getElementsByClassName('ycollapsable-menucontent', null, collapsableContainer)[0]);
this.clickEl.addClass('ycollapsable-expanded');

this.id = containerEl.id;
this.enabled = true;
this.collapsed = false;

this.clickEl.mon('click', function(){
if (this.enabled) this.collapsed == true ?
this.expand() : this.collapse();
}, this, true);

this.events = {
'expanded' : new YAHOO.util.CustomEvent('expanded'),
'collapsed' : new YAHOO.util.CustomEvent('collapsed'),
'enabled' : new YAHOO.util.CustomEvent('enabled'),
'disabled' : new YAHOO.util.CustomEvent('disabled')
};

};

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

collapse : function(animate){
if (!this.collapsed) {
this.collapseEl.clip();
if (animate == null || animate == true) {
this.collapseEl.setHeight(1, true, .15, this.afterCollapse.createDelegate(this), YAHOO.util.Easing.easeIn);
} else {
this.collapseEl.setHeight(1);
this.afterCollapse();
}
}
},

afterCollapse : function(){
this.collapsed = true;
this.collapseEl.setDisplayed(false);
this.clickEl.replaceClass('ycollapsable-expanded','ycollapsable-collapsed');
this.fireEvent('collapsed', this);
},

expand : function(animate){
if (this.collapsed) {
this.collapseEl.setDisplayed(true);
if (animate == null || animate == true) {
this.collapseEl.autoHeight(animate, .25, this.afterExpand.createDelegate(this), YAHOO.util.Easing.easeOut);
} else {
this.collapseEl.autoHeight();
this.afterExapand();
}
}
},

afterExpand : function(){
this.collapsed = false;
this.collapseEl.unclip();
this.collapseEl.setStyle('height', '');
this.clickEl.replaceClass('ycollapsable-collapsed','ycollapsable-expanded');
this.fireEvent('expanded', this);
},

enable : function(){
this.enabled = true;
this.clickEl.removeClass('ycollapsable-disabled');
this.fireEvent('enabled', this);
},

disable : function(animate){
this.enabled = false;
this.collapse(animate);
this.clickEl.addClass('ycollapsable-disabled');
this.fireEvent('disabled', this);
},

restoreState : function(defaultState, provider){
if(!provider){
YAHOO.ext.state.Manager.setProvider(new YAHOO.ext.state.CookieProvider());
provider = YAHOO.ext.state.Manager;
}
var sm = new CollapserStateManager();
sm.init(this, provider, defaultState);
}
});

var CollapserStateManager = function(collapserObject, provider){

this.state = {
collapsed: true,
enabled: true
};

};

CollapserStateManager.prototype = {
init : function(collapser, provider, defaultState){

this.provider = provider;

if (!defaultState) {
defaultState = { enabled: true, collapsed: false };
}
var savedState = provider.get(collapser.id+'-collapser-state');
this.state = savedState || defaultState;

if(this.state.collapsed){
collapser.collapse(false);
} else {
collapser.expand(false);
}

if(this.state.enabled == true){
collapser.enable();
}else{
collapser.disable();
}

this.collapser = collapser;
collapser.on('collapsed', this.onCollapsed, this, true);
collapser.on('expanded', this.onExpanded, this, true);
collapser.on('enabled', this.onEnabled, this, true);
collapser.on('disabled', this.onDisabled, this, true);
},

storeState : function(){
this.provider.set(this.collapser.id+'-collapser-state', this.state);
},

onCollapsed : function(){
this.state.collapsed = true;
this.storeState();
},

onExpanded : function(){
this.state.collapsed = false;
this.storeState();
},

onEnabled : function(){
this.state.enabled = true;
this.storeState();
},

onDisabled : function(){
this.state.enabled = false;
this.storeState();
}
};


New html:

<html>
<head>
<script type="text/javascript" src="scripts/yahoo-debug.js"></script>
<script type="text/javascript" src="scripts/dom-debug.js"></script>
<script type="text/javascript" src="scripts/event-debug.js"></script>
<script type="text/javascript" src="scripts/animation-debug.js"></script>
<script type="text/javascript" src="scripts/yui-ext-debug.js"></script>
<script type="text/javascript" src="scripts/collapser.js"></script>
<style>
.ycollapsable-menuhead {border:1px solid #555;background:#369;color:#fff;cursor:pointer;padding-left:10px;}
.ycollapsable-menucontent {border:1px solid #555;padding:20px;}
.ycollapsable-disabled {background:#999;color:#ddd;cursor:default;}
</style>
</head>
<body>
<div id="collapser1" class="ycollapsable">
<div class="ycollapsable-menuhead">
Header
</div>
<div class="ycollapsable-menucontent">
<div>
Content
Content
Content
Content
</div>
</div>
</div>

<div id="collapser2" class="ycollapsable">
<div class="ycollapsable-menuhead">
Header 2
</div>
<div class="ycollapsable-menucontent">
<div>
Content 2
Content 2
</div>
</div>
</div>



<input id="toggleButton" type="button" value="Enable" /></p>

<script>
var coll1 = new Collapser('collapser1');
var coll2 = new Collapser('collapser2');

coll1.restoreState({enabled: true, collapsed: true});
coll2.restoreState({enabled: false});
setButtonState();

YAHOO.util.Event.on('toggleButton', 'click', toggleCollapser, coll2, true);

function toggleCollapser(){
if (coll2.enabled) {
coll2.disable(false);
}
else {
coll2.enable(false);
}
setButtonState();
}

function setButtonState() {
YAHOO.util.Dom.get('toggleButton').value = (coll2.enabled ? "Disable" : "Enable");
}
</script>
</body>
</html>