Login Register

Basic Layout

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:

  1. Divide the screen into list and messages areas
  2. Add the navigation bars - address book, message list, etc. - to the left hand area
  3. Add the message preview pane
  4. Add the tabbed panes for Compose Mail
  5. Glue on the toolbar and progress bar

Dividing the Screen with SplitContainer

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:

<div dojoType="dijit.layout.SplitContainer" id="rightPane"
        orientation="vertical"  sizerWidth="5"  activeSizing="0">

        <div id="listPane" dojoType="dijit.layout.ContentPane" sizeMin="20" sizeShare="20">
              Message List will go here
        </div>
                                       
        <div id="message" dojoType="dijit.layout.ContentPane" sizeMin="20" sizeShare="80">
            Message will go here
        </div>
</div> <!--  End right hand side split container -->

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 Navigation Bars: AccordionContainer

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.

<div dojoType="dijit.layout.AccordionContainer" sizeMin="20" sizeShare="20">
        <div dojoType="dijit.layout.AccordionPane" title="Folders">
            Folders will go here
        </div>
        <div dojoType="dijit.layout.AccordionPane" title="Address Book">
            Address Book will go here
        </div>
</div>

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.

The Message Preview Pane - SplitContainer

Now we can glue these two pieces together with another SplitContainer, this one oriented horizontally:

<!-- main section with tree, table, and preview -->
<div dojoType="dijit.layout.SplitContainer"
        orientation="horizontal" sizerWidth="5" activeSizing="0" title="Inbox">

    <div dojoType="dijit.layout.AccordionContainer" sizeMin="20" sizeShare="20">
     ...
    </div>
    <div dojoType="dijit.layout.SplitContainer" id="rightPane"
        orientation="vertical"  sizerWidth="5"  activeSizing="0">

    ...
    </div>
</div>

Tabbed Panes - TabContainer

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.

<div dojoType="dijit.layout.TabContainer"  id="tabs" jsId="tabs" layoutAlign="client">
    <div dojoType="dijit.layout.SplitContainer"
            orientation="horizontal" sizerWidth="5" activeSizing="0" title="Inbox">

    ...
    </div>
</div>

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.

Gluing On Toolbar and Status Areas - LayoutContainer

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:

<div dojoType="dijit.layout.LayoutContainer" id="main">
        <div dojoType="dijit.Toolbar" layoutAlign="top" style="height:25px;">
           Toolbar will go here
        </div>
               
        <div dojoType="dijit.layout.ContentPane" layoutAlign="bottom"
             id="footer" align="left">

                <span style="float:right;">DojoMail v1.0 (demo only)</span>
                Progress bar will go here
        </div>
        <div dojoType="dijit.layout.TabContainer"
            id="tabs" jsId="tabs" layoutAlign="client">

         ...
        </div>
</div>

The layoutAlign attributes tell LayoutContainer where they should be placed.

Now Andy just adds the standard Dojo headers and the skeleton is complete!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Demo Mail Application</title>
    <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js"
                djConfig="parseOnLoad: true">
</script>
    <script type="text/javascript">
        dojo.require("dojo.parser");
                dojo.require("dijit.Toolbar");
                dojo.require("dijit.layout.LayoutContainer");
                dojo.require("dijit.layout.SplitContainer");
                dojo.require("dijit.layout.AccordionContainer");
                dojo.require("dijit.layout.TabContainer");
                dojo.require("dijit.layout.ContentPane");
    </script>
        <style type="text/css">
                @import "http://o.aolcdn.com/dojo/1.0.0/resources/dojo.css";
                @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/soria/soria.css";
                @import "http://o.aolcdn.com/dojo/1.0.0/dijit/demos/mail/mail.css";
        </style>
</head>
<body class="soria">

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...

AttachmentSize
step1.html2.65 KB

dojo 1.0 required more dependencies

I tried the example, and it wouldn't display the Inbox tab.
I added:

dojo.require("dijit.dijit");
dojo.require("dijit.dijit-all");

and now it works as advertised.

Shouldn't have to load those

... unless you're doing a custom build and smooshing all the Dijit classes into a big file. If the example isn't working using the dojo.require's listed, I would suspect there's an error being thrown somewhere which describes the problem.

i noticed this yesterday,

i noticed this yesterday, for some reason its saying invalid syntax with ItemFileReadStore (but only write store is required() in?) ... I tried updating the AOL CDN to 1.0.0 and set isDebug:true on the djConfig, and couldn't figure out why (mail.json ...) so i tried to copy it locally and get the invalid syntax thing. good catch on the mail.css ...

you _should_ be able to point that directly at the completed mail demo css direcly in the test case.

hopefully my doc tool idea will make this easier:

demos/mail/book/step1.css, step2.css, step3.css etc ... so each iteration of a file will be available in the same svn spot as the demo itself. ? (and the code blocks in the book are directly sourced from the stepN.css/js/html files, and each step has a "parsed" version of the three componenets in a single step1-example.html file (automatically).

so if you change the css or html template, it gets updated in the book (and all the links still work) ...

I dunno - i like the idea. :)

Me too

Keep me posted on your progress in this area. This will be an excellent method now that we have so many code examples in the book.

Mail.css

I know it isn't directly related to Dojo, but it would would be nice to have mail.css explained. The layout code above relies heavily on the styling in mail.css, and the explanation doesn't seem complete without it. Clearly keeping the styling in a separate file is the correct way to do it, however, I feel that inline styles would lead to better understanding (even if it isn't a 'good example').

* EDIT * - Looked a bit closer at the CSS
The only bit of CSS that really needs explaining is that the following is required to make the layout fill the browser window:

html, body, #main{
        width: 100%;    /* make the body expand to fill the visible window */
        height: 100%;
}

Personally I think the rest of the CSS should have been left out, for the purposes of the tutorial example - to keep it as simple and straightforward as possible. IMHO there shouldn't be any code in the tutorial example which isn't explained (even if only briefly), neither should anything achieved by the tutorial example without explaining how it was acheived. Otherwise, you may as well just give the example code without the tutorial.