A view to a thrill

Let's break down the major views that will make up the main screen of the application:

A view to a thrill

1: header view, 2: thread view, 3: message view, and 4: composer view; main view encompasses views 1 - 4

The login view is the simplest; a self-contained view, view controller, and a view model to bind with the values of the login form. It's not shown in the preceding mockup because it's the only one on the screen at the time, almost standalone.

There's a caveat to this. For the first time, we'll be using an over-arching controller to deal with the interactions between views. In the previous chapter, this was left to the "main" view controller, since the "main" view was the container for every part of our application. Here, the login view and the rest of the application are effectively independent from each other and so it makes sense to have a "third party" helping them to work together.

We'll call this top-level controller our "root" controller. It's not a view controller, but a completely self-contained class that is responsible for showing the login view and reacting to a successful login. To formalize this:

Postcard.controller.RootController: extends Ext.app.Controller
- onLaunch -> check for valid login
- onLoginSuccess -> show main view

The login view controller is responsible for processing a login attempt and after doing so, it will fire off the appropriate actions. Along with its view and view model, it looks like this:

Postcard.view.login.Login: extends Ext.window.Window
- items[]
    - e-mail: extends Ext.form.Text
    - password: extends Ext.form.Text
    - rememberMe: extends Ext.form.Checkbox
    - submit: extends Ext.Button

Postcard.view.login.LoginModel: extends Ext.app.ViewModel
- e-mail
- password
- rememberMe

Postcard.view.login.LoginController: extends Ext.app.ViewController
- onLoginClick

Assuming the onLoginClick method is successful, we'll move on to the main screen of the application.

Mainly harmless

As in previous chapters, the main view is the viewport that contains the other views in the application, such as the application header and the list of threads. According to our design, the view should look like this:

Postcard.view.main.Main: extends Ext.Panel
- items[]
    - app-header: extends Ext.Container
    - threads: extends Ext.DataView
    - container: extends Ext.Container
        - items[]
            - messages: Ext.Container
            - composer: Ext.form.Panel

A couple of things to note here, the primary views that make up our application are mentioned here: header, threads, messages and, composer. We're also doing a bit of forward thinking regarding our design, in that the composer and messages views are enclosed in a separate container.

This will allow us to more easily work with the Ext JS layout system, having the threads view and this anonymous container in an hbox arrangement. The view model looks like this:

Postcard.view.main.MainModel: extends Ext.app.ViewModel
- currentTag
- searchTerm

It's just convenient for a few pieces of state that need to be shared between the views contained in the main view. The view controller looks like this:

Postcard.view.main.MainController: extends Ext.app.ViewController
- onLogout
- onHome
- onShowThread
- onNewThread
- onNewMessage

The first method (onLogout) will handle clicks on a logout button. The next four methods on the main view controller will be triggered by routing, and will be responsible for setting changes in the state of the application.

Remember that the main view and its associated classes don't really have any functionality of their own; they're responsible for orchestrating all of the other application parts contained within.

Full steam ahead

The first child view of the main viewport is the header view, containing a number of components that are available anywhere in the application as follows:

Postcard.view.header.Header: Ext.Toolbar
- items[]
    - homebutton: extends Ext.Button
    - searchfield: extends Ext.form.TextField
    - tagfilter: extends Ext.form.ComboBox
    - newmessagebutton: extends Ext.Button
    - menubutton: extends Ext.Button

There's actually a surprising amount happening here. We also have to bear in mind that this is the target for one of our portrait orientation pieces of functionality, so there will be some usage of the responsive plugin in our implementation, as shown in the following code:

Postcard.view.header.HeaderController: extends Ext.app.ViewController
- onHomeClick
- onNewMessageClick

These methods are event listeners that will in turn trigger further functionality. You might wonder why we don't have handlers to toggle the menu open and closed or to choose an item from the combo box. Think about data binding. If we bind the state of the menu button and the combo box to a view model, other components can bind to the values in the view model and will receive updates without us having to write any glue code. To this end, the header view model will look like:

Postcard.view.header.HeaderModel: extends Ext.app.ViewModel
- tags

Nothing more than a store to populate the tag filter combo box. We'll talk about this use of data binding further when we come to implement the header.

Threading our way

A thread is just a fancy way of saying "a collection of e-mail messages". We're going to use Ext.DataView for this:

Postcard.view.threads.Threads: extends Ext.DataView
- stripHtml

We're going to support HTML e-mails in this application, but to prevent the thread view from looking messy, we'll strip out this HTML before presenting it to the user. Other than this, it's a normal implementation of DataView.

Postbox.view.threads.ThreadsModel: extends Ext.app.ViewModel
- threads

The view model contains the thread store that powers the view as follows:

Postcard.view.threads.ThreadsController: extends
Ext.app.ViewController
- onThreadClick

There's only a single method here, one that is triggered by the itemclick event on the thread DataView. It'll be responsible for redirecting the user to a list of messages in this thread.

Send me a message

The message view is responsible for showing the messages that make up a thread. As such, it's mainly based on DataView. It's a little more complicated than this though because DataView doesn't inherit from Ext.Panel; it can't have its own child items or docked toolbar.

In this case, we need to have some tools at the bottom of the message list in order to change the thread tag and send a reply. Therefore, we wrap the DataView in a panel:

Postcard.view.messages.Messages: extends Ext.Panel
- items[]
    - panel: extends Ext.Panel
        - items[]
            - messagelist: extends Ext.DataView
        - bbar[]
            - tagpicker: extends Ext.form.ComboBox
            - reply: extends Ext.Button

In the view model, we need two stores: one for the messages in the thread, and one for the tags that are available to choose from.

Postcode.view.messages.MessagesModel: extends Ext.app.ViewModel
- messages
- threads

The view controller has a couple of event handlers to manage the user's interactions with the message view:

Postcard.view.messages.MessagesController: extends Ext.app.ViewController
- onReplyClick
- onNewThread
- onShwThread
- onTagChange

There's now only one missing piece to this application—how do we write new messages?

Stay composed

The composer view is responsible for writing new messages and writing replies. It needs several UI components to accomplish this:

Postcard.view.composer.Composer: extends Ext.form.Panel
- items[]
    - recipients: extends Ext.form.ComboBox
    - subject: extends Ext.form.TextField
    - message: extends Ext.form.HtmlEditor

Recipients and subject won't be used if the composer is replying to an existing thread. It will only be used when creating a new thread:

Postcard.view.Composer.ComposerModel: extends Ext.app.ViewModel
- items[]
    - contacts
    - newMessage

We have a store of contacts to power the recipients' field, and an object to store the form values as the user enters them:

Postcard.view.composer.ComposerController: extends
Ext.app.ViewController
- onSendClick

The view controller will be responsible for saving the message to the server, which in turn would send it to the designated recipients.

We don't exactly have an address book in this application; instead, any previously used e-mail addresses are just saved and are available to pick in future messages.

Design overview

We skipped over a lot of the data layer design this time around because it was very "boilerplate" in nature and we'd discussed such things in previous chapters. Why go through the class design process for the views and their associated view controllers and view models then? We've done this in previous chapters as well.

Clearly, every application is different. Breaking it down in this way helps us flesh out the code we're going to write without actually writing any code. This is important, because we'll avoid thinking too hard about the details of the implementation and have a better understanding of the shape of the larger pieces in the puzzle.

The next step is to revisit routes, events, and data flow and see how these large pieces will work together.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset