Today I start a series of posts dedicated to Ext JS layouts. I will initiate this series creating a messenger-like interface that will have an area for displaying contacts and their statuses, and an area for displaying a conversation. The goal is not to implement a messenger system, but rather to walk through the steps required for building a user interface, and end up with some code that you can use as a learning tool.
In this post I will focus on the contacts area of my messenger-like interface. I will use a window as the container. Inside this window I will place a number of controls that will satisfy these requirements:
- Display the name, avatar and status of the current user
- Provide the user with a means to change her current status, selecting from available, busy, away or appear offline
- Provide the user with a means to share a quick message and show the music she’s listening to
- Provide the user with a means to navigate to her profile, contact card, or space
- Display a the user’s contacts, organized by favorites, available and offline
In future posts I will enhance and refine this interface. By the end of this post, I will have a window that looks like this:
Looks familiar? :-)
All right. Let’s get started.
The messenger window
I already decided that my container will be a window. All I need for the moment is a title and the dimensions:
var wnd = new Ext.Window({
width: 300,
height: 450,
layout:'fit',
title: 'Instant Messenger'
});
And this is how it looks like:
Display the name, avatar and status of the current user
I will use the window’s toolbar to display the name and avatar of the user. First, I will create the toolbar and use the new button group component to layout the toolbar items in two columns, one for the avatar and one for the user’s name:
var wnd = new Ext.Window({
width: 300,
height: 450,
layout:'fit',
title: 'Instant Messenger',
tbar: [{
xtype: 'buttongroup',
columns: 2
}]
});
The avatar and user name go in as toolbar buttons. I’m making them buttons because I want to allow the user to click on them and perform some tasks. This is the window now:
var wnd = new Ext.Window({
width: 300,
height: 450,
layout:'fit',
title: 'Instant Messenger',
tbar: [{
xtype: 'buttongroup',
columns: 2,
items: [{ xtype: 'button', scale: 'large', iconCls: 'icon-user', rowspan: 2 },
{ xtype: 'splitbutton', text: 'Jorge (available)' }]
}]
});
It’s starting to look good:

Provide the user with a means to change her current status
To allow for status changes, I will add a menu to the username button. Here’s the code:
var wnd = new Ext.Window({
width: 300,
height: 450,
layout:'fit',
title: 'Instant Messenger',
tbar: [{
xtype: 'buttongroup',
columns: 2,
items: [{ xtype: 'button', scale: 'large', iconCls: 'icon-user', rowspan: 2 },
{ xtype: 'splitbutton', text: 'Jorge (available)',
menu: [{ text: 'Available', iconCls: 'ico-sts-available' },
{ text: 'Busy', iconCls: 'ico-sts-busy' },
{ text: 'Away', iconCls: 'ico-sts-away' },
{ text: 'Appear Offline', iconCls: 'ico-sts-offline'}]
}]
}]
});
And this is how it looks:

Provide the user with a means to share a quick message and show the music she’s listening to
For this, I will use a split button, placed immediately below the username button:
var wnd = new Ext.Window({
width: 300,
height: 450,
layout:'fit',
title: 'Instant Messenger',
tbar: [{
xtype: 'buttongroup',
columns: 2,
items: [{ xtype: 'button', scale: 'large', iconCls: 'icon-user', rowspan: 2 },
{ xtype: 'splitbutton', text: 'Jorge (available)',
menu: [{ text: 'Available', iconCls: 'ico-sts-available' },
{ text: 'Busy', iconCls: 'ico-sts-busy' },
{ text: 'Away', iconCls: 'ico-sts-away' },
{ text: 'Appear Offline', iconCls: 'ico-sts-offline'}]
},{ xtype: 'splitbutton', text: 'Share a quick message',
menu: [{ text: 'Show what I am listening to'}]
}]
}]
});

Provide the user with a means to navigate to her profile, contact card, or space
I will add this feature in the form of a menu attached to the avatar button:
var wnd = new Ext.Window({
width: 300,
height: 450,
layout:'fit',
title: 'Instant Messenger',
tbar: [{
xtype: 'buttongroup',
columns: 2,
items: [{ xtype: 'button', scale: 'large', iconCls: 'icon-user', rowspan: 2,
menu: [{ text: 'Show profile' }, { text: 'View contact card' },
{ text: 'Go to your space'}]
},{ xtype: 'splitbutton', text: 'Jorge (available)',
menu: [{ text: 'Available', iconCls: 'ico-sts-available' },
{ text: 'Busy', iconCls: 'ico-sts-busy' },
{ text: 'Away', iconCls: 'ico-sts-away' },
{ text: 'Appear Offline', iconCls: 'ico-sts-offline'}]
},{ xtype: 'splitbutton', text: 'Share a quick message',
menu: [{ text: 'Show what I am listening to'}]
}]
}]
});
This is how the menu looks:
Display a the user’s contacts, organized by favorites, available and offline
The contacts will be shown with a treview. I will create an invisible root node and three branch nodes named Favorites, Available and Offline. The user’s contacts will be leaf nodes under these branches.
First, I add the tree to the window:
items: [{ xtype: 'treepanel',
id: 'contacts-tree',
border: false,
useArrows: true,
autoScroll: true,
animate: true,
containerScroll: true,
bodyCssClass: 'tree-body',
dataUrl: 'messenger.aspx',
requestMethod: 'get',
rootVisible: false,
root: {
nodeType: 'async',
text: 'My Reporting Project',
draggable: false,
id: 'root-node'
}}]
Then, below the window definition, I add the favorites, available and offline branch nodes, as well as a few dummy contacts. I use the afterrender event to acquire a reference to the root node and then add child nodes to it:
var tree = Ext.getCmp('contacts-tree');
tree.on('afterrender', function(loader, node) {
var root = tree.getRootNode();
var node = root.appendChild({ id: 'favorites', text: 'Favorites', expanded: true, iconCls: 'ico-fav' });
node.appendChild({ text: 'Susie', leaf: true, iconCls: 'ico-sts-available' });
node.appendChild({ text: 'Lara', leaf: true, iconCls: 'ico-sts-away' });
node = root.appendChild({ text: 'Available', expanded: true, iconCls: 'ico-grp-available' });
node.appendChild({ text: 'Jonh', leaf: true, iconCls: 'ico-sts-busy' });
node.appendChild({ text: 'Lara', leaf: true, iconCls: 'ico-sts-away' });
node.appendChild({ text: 'Susie', leaf: true, iconCls: 'ico-sts-available' });
node = root.appendChild({ text: 'Offline', expanded: true, iconCls: 'ico-grp-offline' });
})
And the window looks just the way I had planned:
This does it for now. In the next post of this series I will continue adding features to this contacts window.
Downloads
Download the full sample from my downloads page.