So here's the cocktail napkin view of the email client:
Like most Outlook-inspired email programs, it will have a three pane, split-screen layout with a toolbar on top and status bar on the bottom. The left hand side will use accordion panes that flip up and down like a window blinds. Fortunately, all the layout tools you need are already in Dijit.
Andy likes to build the layout from the inside-out best, so he'll tackle the steps in this order:
start with the message list and message area first. In between these two is the movable divider bar, called the sizer. In Dijit, you can use the dijit.layout.SplitContainer widget to model this like so:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}Usually the innermost children in a layout are dijit.layout.ContentPane's. You can place arbitrary HTML in the pane, as we've done here, or lazy load the content from other URL's, like a server-side include.
The dijit.layout.SplitContainer itself can be oriented horiztonally or vertically, as the "orientation" attribute shows. A vertically oriented SplitContainer means the components are stacked vertically. Note that the orientation is opposite of the sizer bar orientation - i.e. if the SplitContainer is vertical, as it is in this case, the sizer orientation is horizontal. The sizer bar here is 5 pixels and changing it does not change the content immediately, as the activeSizing attribute shows.
The left hand bar is an Accordion Container, which is easier to show than to describe. In Dijit, the dijit.layout.AccordionContainer holds dijit.layout.AccordionPane's, a special kind of ContentPane.
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}The title attributes give the label for the top of the AccordionPane. When the user clicks on this title or the arrow icon next to it, the pane will slide into view.
Now we can glue these two pieces together with another SplitContainer, this one oriented horizontally:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}The whole thing will be situated in a tab named Inbox. Though our cocktail napkin drawing doesn't show other tabs, the idea is to open them for new email composition. This way you can work on many emails at once, clicking on the tabs to switch between them. Dijit has a widget dijit.layout.TabContainer, and like the Split and Accordion containers, it's a container for subscontainers and panes.
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}The dijit.Layout.TabContainer can hold as many tabs as you want, each marked with a title attribute used to title the tab. This illustrates a familiar pattern in Dijit. Sometimes a widget contains attributes that don't really deal with the widget itself - title, for instance, or sizeMin and sizeShare in earlier examples. They only make sense when that widget is used within other widgets. So an AccordionContainer ignores a sizeMin attribute, but because it's a child of a SplitContainer, the SplitContainer uses it for sizing. Title is similar. In a normal HTML tag, title would display a tooltip, but because the SpilitContainer is inside a TabContainer, the title is used specially.
What is that jsId attribute? jsId sets a global JavaScript variable for the widget, which will make it easy to script widget actions later. For example:
// Note used for step 1 - this is a preview tabs.closeChild(tabs.selectedChildWidget);
closes the currently selected tab in the tab container. Without even knowing the Dijit API's, it's easy to understand what's going on here. That's object-oriented magic at work.
To top it all off, we smush these tabs into a dijit.layout.LayoutContainer. A LayoutContainer was pioneered by Borland Delphi and copied in Java AWT and other toolkits. The idea is to split a box into five areas: top, bottom, left, right, and client (the middle). If the box is resized, the client area takes most of the growth or shrinkage - it's the document part of the app.
In our email client, the toolbar will occupy the top, the status bar the bottom, and the TabContainer the client portion:
/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}The layoutAlign attributes tell LayoutContainer where they should be placed.
Now Andy just adds the standard Dojo headers and the skeleton is complete! /* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
There's no JavaScript at all beyond the dojo.require statements. And because he's using CDN, he didn't even have to install Dojo on the server. While Andy takes a moment to write more of his empassioned speech, you can download the code in step1.html below and try it out.
Ready? On to the next step...