% -*- mode: latex; -*- mustache tags:  
\ifx\wholebook\relax\else

	\documentclass[10pt,twoside,english]{root/support/latex/sbabook/sbabook}
  \usepackage{import}
  \subimport{root/support/latex/}{common.tex}

  \hypersetup{pdfinfo = {
    Title = {Contact Book},
    Author = {},
    Keywords = {pharo, smalltalk}}}
  \begin{document}
\fi

\chapter{Building A Simple Contact Book Application}
In this tutorial, you will develop a simple contact book application with a web interface. It consists of a couple of classes for the model and the UI of the application. Figure \ref{fig:final} shows the resulting application. As you see it is simple but covers many aspects of defining and deploying a web applications. 

You will develop the web interface using Seaside (\href{http://www.seaside.st}{http://ww.seaside.st}\footnote{\url{http://www.seaside.st}}). Seaside is a powerful web framework
for developing highly dynamic and complex web application. For more information you can read the book: 'Dynamic Web Development with Seaside' which 
is freely available at \url{http://book.seaside.st}. In this little tutorial we will only use some simple server side Seaside behavior. We will use the Twitter Bootstrap library that is fully integrated to Seaside.

Note that the presented solution is often simple and we will list ideas of further improvements that you could add. In addition, it is worth to know that Pharo developers often use object descriptions (as done via the Magritte framework) to generate new web components instead of manually developing them. 
\subsubsection{About development style}
While we love coding test first and coding in the debugger (since it let us go much faster), in this tutorial we will not follow such style
because it requires a lot of text to mention what to do with the user interface of the Pharo tools. We decided to take a neutral stand point and to let you decide if you code first the tests, if you prefer to go slowly or not. This tutorial presents the mandatory information so that you can get it done. Program it the way you want. 


\begin{figure}

\begin{center}
\includegraphics[width=0.8\textwidth]{figures/contact-book-final.png}\caption{Screenshot of the finished contact book application.\label{fig:final}}\end{center}
\end{figure}

\subsubsection{Getting Seaside}
In this tutorial, we use the Seaside web framework to define the views of our application. Seaside must be loaded in the image to start using it.
You have several ways to obtain Seaside

\begin{itemize}
\item either you start coding in the default pharo image and when needed you  open the \textit{Catalog browser} tool and search for Seaside. Install the stable version. Since Seaside is large it can take a moment. 
\item You can also download a pre-installed version of Seaside available at \url{https://ci.inria.fr/pharo-contribution/job/Seaside/} but you will need to migrate your code to this new image. This is easy with the code versioning control system: save from the current image to a code repository and load from the Seaside ready image from this repository. We prefer the second version. 
\end{itemize}
\section{The Model}
The contact book is composed of two model classes: \textcode{Contact} and \textcode{ContactBook}. Let us start with the \textcode{Contact} class.
\subsection{The Contact Class}
A contact has two instance variables \textcode{fullname} and \textcode{email}, both strings. Create the \textcode{Contact} class with its instance variables:

\begin{displaycode}{smalltalk}
Object subclass: #Contact
   instanceVariableNames: 'fullname email'
   classVariableNames: ''
   package: 'ContactBook'
\end{displaycode}

It should be possible to create a new contact by executing the following code:

\begin{displaycode}{smalltalk}
contact := Contact newNamed: 'Marcus Denker' email: 'marcus.denker@inria.fr'.
\end{displaycode}

It means that we send a message (\textcode{newNamed:email:}) to the class \textcode{Contact} itself and that it should return a \textcode{Contact} instance.

Add the \textcode{newNamed:email:} class method in the \textcode{instance creation} protocol of the \textcode{Contact} class. To define a class method, pay attention that you should browse the \textit{class side} of the \textcode{Contact} class.

\begin{displaycode}{smalltalk}
Contact class >> newNamed: aNameString email: anEmailString
   ^ self new
        fullname: aNameString;
        email: anEmailString;
        yourself
\end{displaycode}
\subsection{Adding a Test}
You can now define a test (in the \textcode{tests} protocol) to make sure that you can create an instance and that it contains the right information.

\begin{displaycode}{smalltalk}
TestCase subclass: #ContactTest
   instanceVariableNames: ''
   classVariableNames: ''
   package: 'ContactBook'
\end{displaycode}

\begin{displaycode}{smalltalk}
ContactTest >> testCreation
   | contact |
   contact := Contact newNamed: 'Marcus Denker' email: 'marcus.denker@inria.fr'.
   self assert: contact fullname = 'Marcus Denker'.
   self assert: contact email = 'marcus.denker@inria.fr'.
\end{displaycode}

For this test to work you need to define the following methods (in the \textcode{accessing} protocol).

\begin{displaycode}{smalltalk}
Contact >> fullname
   ^ fullname

Contact >> fullname: aString
   fullname := aString

Contact >> email
   ^ email

Contact >> email: aString
   email := aString
\end{displaycode}

Run the test to make sure it passes. It is a good idea to version your code and save the image. 
\paragraph{Further extensions. }
You can add some extra logic to make sure that the name is not surrounded by space. In addition handling whether you take care of note about lowercase and uppercase should be addressed. You can use messages such as \textcode{asLowercase} to, for example, store only lowercased strings. 
\subsection{Enhancing Object Textual Interface}
If you inspect or print the \textcode{contact} variable created above, you will see that the string representation of this \textcode{Contact} instance is \textcode{\symbol{34}a Contact\symbol{34}} which says nothing about the contact itself. This is problematic when debugging and developers typically appreciate nicer string representations. You can change that by overriding the method \textcode{Object\textgreater{}\textgreater{}printOn:} (in the \textcode{printing} protocol) in the \textcode{Contact} class and sending several \textcode{nextPutAll:} messages to the stream argument as follows:

\begin{displaycode}{smalltalk}
Contact >> printOn: aStream
   aStream
      nextPutAll: self fullname;
      nextPutAll: ' <';
      nextPutAll: self email;
      nextPutAll: '>'
\end{displaycode}

The string representation of the above \textcode{contact} variable will then be:

\begin{displaycode}{smalltalk}
'Marcus Denker <marcus.denker@inria.fr>'
\end{displaycode}
\subsubsection{Class Comment and Saving}
We hope you didn't forget to add a comment to the \textcode{Contact} class. If you did, here is a possible one:

\begin{displaycode}{smalltalk}
I represent a person with a name and an email address. I'm usually part of a contact book.
\end{displaycode}

Note that in a real application, it might be better to use an \textcode{Email} class to represent a contact's email address.

Save your image and save the code using the version control browser (Monticello Browser).
\subsection{The Contact Book Class}
A contact book contains a collection of \textcode{Contact} instances:

\begin{displaycode}{smalltalk}
Object subclass: #ContactBook
   instanceVariableNames: 'contacts'
   classVariableNames: ''
   package: 'ContactBook'
\end{displaycode}
\subsection{Initializing Contact Books}
To initialize the \textcode{contacts} variable to an empty collection, you can either define an \textcode{initialize} method (that is automatically invoked at instance-creation time) or use lazy initialization. The following code uses lazy initialization. Add this method in the \textcode{accessing} protocol.
Pay attention that with lazy initialization, you should systematically use accessors else you could access to a variable not well-initialized.

\begin{displaycode}{smalltalk}
ContactBook >> contacts
   ^ contacts ifNil: [ contacts := OrderedCollection new ]
\end{displaycode}

It should be possible to add and remove contacts from the collection. Add the necessary methods in the \textcode{action} protocol:

\begin{displaycode}{smalltalk}
ContactBook >> addContact: aContact
   self contacts add: aContact

ContactBook >> removeContact: aContact
    self contacts remove: aContact
\end{displaycode}
\paragraph{Add tests.}
Define some tests to cover the addition and removal of contacts. 
You will see in particular that the definition for \textcode{removeContact:} is not that robust when we want to remove a contact that is not in the collection: Removing an unexisting contact raises an error. Change the definition of the \textcode{removeContact:} method (check other remove: methods in collection) and define a test that covers this particular aspect. 
\subsection{Providing a Default Contact Book}
To simplify further development, we define a default contact book with predefined contacts inside. We do this by adding the method \textcode{createDefault} as a class method to the 'default instance' protocol of \textcode{ContactBook class}:

\begin{displaycode}{smalltalk}
ContactBook class >> createDefault
   ^ self new
			addContact: (Contact 
	  							newNamed: 'Damien Cassou' 
								email: 'damien@cassou.me');
    		addContact: (Contact 
	  							newNamed: 'Marcus Denker' 
								email: 'marcus.denker@inria.fr');
      		addContact: (Contact 
	  							newNamed: 'Tudor Girba' 
								email: 'tudor@tudorgirba.com');
			addContact: (Contact 
	  							newNamed: 'Clara Allende' 
								email: 'clari.allende@gmail.com');
      yourself
\end{displaycode}

Don't forget to comment the class and to save your image and version your code. 
\section{A First Web View}
Now that we have the model, we need a web view. We will use Seaside for that. Seaside is a component framework: Seaside web applications are built by aggregating components. Typically, an application consists of a top-level component delegating parts of its rendering to sub-components. 
Let us define a first simple component. 
\subsection{Defining the WAContactBook Component}
Our simple application consists of a top-level component represented by the \textcode{WAContactBook} class, subclass of \textcode{WAComponent}. Create the \textcode{WAContactBook} class with a \textcode{contactBook} instance variable:

\begin{displaycode}{smalltalk}
WAComponent subclass: #WAContactBook
   instanceVariableNames: 'contactBook'
   classVariableNames: ''
   package: 'ContactBook'
\end{displaycode}
\subsection{Rendering a Title}
Every Seaside component class must override the \textcode{renderContentOn:} method to specify how a component is rendered. Define this method in the \textcode{rendering} protocol:

\begin{displaycode}{smalltalk}
WAContactBook>>renderContentOn: html
   "Main entry point of the view. Render a title."

   html heading
      level: 1;
      with: 'My Contact Book'.
\end{displaycode}

The method argument \textcode{html} acts as a canvas that can emit adequate HTML code. Above code asks the heading brush to the canvas and uses it to emit this HTML code: \textcode{\textless{}h1\textgreater{}My Contact Book\textless{}/h1\textgreater{}}. Seaside abstracts you from the details of the syntax of the HTML expressions. 
\paragraph{Remark.}
It is not a good style to generate component UI using directly HTML commands representing styles (table, section...). Usually developers emit tags that map with css class tags provided by an application designer. We will show you that later. 
\subsection{Registering our 'App'}
The next step is to register the \textcode{WAContactBook} class to the \textcode{/contacts} URL path. This way you will be able to reach the application at \url{http://localhost:8080/contacts}. Do this by implementing an \textcode{initialize} class method in \textcode{WAContactBook class} (\textcode{class initialization} protocol):

\begin{displaycode}{smalltalk}
WAContactBook class >> initialize
     WAAdmin register: self asApplicationAt: 'contacts'.
\end{displaycode}

An \textcode{initialize} class method is executed when the class is loaded in memory. Because our class is already loaded, we should execute it once manually. Write and execute this code, as method comment or in the Playground for example:

\begin{displaycode}{smalltalk}
WAContactBook initialize
\end{displaycode}
\subsection{Starting the Server}
The last step before getting something on the web browser is to start the web server. Open the \textcode{Seaside control panel} tool (open the Pharo menu and go to the Tools sub-menu). Now, add a \textcode{ZnZincServerAdaptor} by right-clicking on the top pane and choosing \textcode{Add adaptor...}. When prompted, choose a port, for example 8080 and press \textcode{Start}.


\begin{figure}

\begin{center}
\includegraphics[width=0.8\textwidth]{figures/contact-book-title.png}\caption{Screenshot of the contact book application title\label{fig:title}}\end{center}
\end{figure}


Open your favorite web browser on \url{http://localhost:8080/contacts} and you should see something similar to Figure \ref{fig:title}. Currently, the title of the web page is \symbol{34}Seaside\symbol{34}, as we can see it in the web browser window title and the tab title. This can be changed by overriding the \textcode{updateRoot:} method (in the \textcode{updating} protocol):

\begin{displaycode}{smalltalk}
WAContactBook >> updateRoot: anHtmlRoot
    super updateRoot: anHtmlRoot.
    anHtmlRoot title: 'Contact Book'
\end{displaycode}

You can refresh the page in the web browser to see the result.
\subsection{Accessing the Model}
Now we define some methods to access to the model from the view. We define them in the \textcode{accessing} protocol:

\begin{displaycode}{smalltalk}
WAContactBook >> contacts
    ^ self contactBook contacts
\end{displaycode}

\begin{displaycode}{smalltalk}
WAContactBook >> contactBook
     ^ contactBook ifNil: [ contactBook := ContactBook createDefault ]
\end{displaycode}

In the 'iterating' protocol add the method \textcode{contactsDo:}

\begin{displaycode}{smalltalk}
WAContactBook >> contactsDo: aBlock
    self contacts do: aBlock
\end{displaycode}

This \textcode{contactsDo:} method is not as useless as it might seem. This method hides the existence of a \textcode{contactBook} collection and could be useful later to replace the collection by a database.
\subsection{Rendering a Table of Contacts}
Below the title, we want a table containing the contacts of the contact book. For this, we need to change the \textcode{renderContentOn:} method and add a few new messages. We will decompose the behavior in several methods to facilitate understanding.

\begin{displaycode}{smalltalk}
WAContactBook >> renderContentOn: html
   "Main entry point of the view. Render both a title and the list of contacts."

   html heading
      level: 1;
      with: 'My Contact Book'.
   self renderContactsOn: html
\end{displaycode}

We just used a new method named \textcode{renderContactsOn:} (all rendering methods should be put in the \textcode{rendering} protocol).
The method \textcode{renderContactsOn:} defines a table with a header and delegates the rest of the rendering to the method \textcode{renderContact:on:}.

\begin{displaycode}{smalltalk}
WAContactBook >> renderContactsOn: html
   html table: [
      html tableHead: [
         html
            tableHeading: 'Name';
            tableHeading: 'Email' ].
      self contactsDo: [ :contact | self renderContact: contact on: html ] ]
\end{displaycode}

  
The method \textcode{renderContact:on:} defines the rendering of a single contact in a table row.

\begin{displaycode}{smalltalk}
WAContactBook >> renderContact: aContact on: html
   html tableRow: [
      html
        tableData: aContact fullname;
        tableData: aContact email ]
\end{displaycode}

As we saw, the \textcode{renderContentOn:} method delegates the table rendering to the \textcode{renderContactsOn:} method. The latter creates a table with a heading row and delegates the contact rendering to the \textcode{renderContact:on:} method. This method renders a table row with the contact's details.


\begin{figure}

\begin{center}
\includegraphics[width=1.0\textwidth]{figures/contact-book-first-contacts.png}\caption{Screenshot of a contact book contacts.\label{fig:first-contacts}}\end{center}
\end{figure}


Refreshing the web browser should now show a list of contacts as can be seen in Figure \ref{fig:first-contacts}.
\section{Improving the View with Twitter Bootstrap}
The rendering can be visually improved by adding some Cascading Style Sheets (CSS). In the following, we use the \href{http://getbootstrap.com/}{Twitter Bootstrap framework}\footnote{\url{http://getbootstrap.com/}} that must be loaded in the image. It is loaded by default in the Seaside distribution. 
If not, open the \textit{Catalog browser} tool and search for Bootstrap. Install the stable version.
\subsection{Declaring Twitter Bootstrap Use}
The contact book application must declare its dependency on Bootstrap. This is done by modifying the  \textcode{initialize} class method:

\begin{displaycode}{smalltalk}
WAContactBook class >> initialize
    (WAAdmin register: self asApplicationAt: 'contacts')
        addLibrary: JQDeploymentLibrary;
        addLibrary: TBSDeploymentLibrary
\end{displaycode}

Execute this method manually again:

\begin{displaycode}{smalltalk}
WAContactBook initialize
\end{displaycode}
\subsection{Using Twitter Brushes}
The Seaside version of Bootstrap defines some special brushes as messages (such as \textcode{tbsContainer:} and \textcode{tbsTable}) to improve the application rendering. We now adapt our existing code to use these methods:

\begin{displaycode}{smalltalk}
WAContactBook >> renderContentOn: html
   "Main entry point of the view. Render both a title and the list of contacts."

   html
      tbsContainer: [
         html heading
            level: 1;
            with: 'My Contact Book'.
         self renderContactsOn: html ]
\end{displaycode}

\begin{displaycode}{smalltalk}
WAContactBook >> renderContactsOn: html
   html tbsTable: [
      html tableHead: [
         html
            tableHeading: 'Name';
            tableHeading: 'Email' ].
      self contactsDo: [ :contact | self renderContact: contact on: html ] ]
\end{displaycode}

As you can see, the adaptation consisted in adding a container with \textcode{tbsContainer:} and replacing a \textcode{table:} by a \textcode{tbsTable:} message.


\begin{figure}

\begin{center}
\includegraphics[width=1.0\textwidth]{figures/contact-book-with-bootstrap.png}\caption{Screenshot of the  contact book application with bootstrap.\label{fig:with-bootstrap}}\end{center}
\end{figure}


The result in Figure \ref{fig:with-bootstrap} already looks much nicer. However, in a real application, it is recommended to avoid Bootstrap specific methods such as \textcode{tbsContainer:} and \textcode{tbsTable:} but to use Bootstrap mixins instead. We explained the idea in Section \ref{secbootstrapmixin}.
\section{Adding Photos}
We now improve the contact book application by displaying photos next to each contact. We fetch these photos automatically from the web using \href{http://gravatar.com/}{Gravatar}\footnote{\url{http://gravatar.com/}}. Gravatar provides a \href{http://en.gravatar.com/site/implement/}{web API}\footnote{\url{http://en.gravatar.com/site/implement/}} to retrieve a photo from an email address:

\begin{displaycode}{smalltalk}
Contact >> gravatarUrl
   ^ 'http://www.gravatar.com/avatar/', (MD5 hashMessage: email trimBoth asLowercase) hex, '.jpg'
\end{displaycode}

For example, for \href{mailto:marcus.denker@inria.fr}{marcus.denker@inria.fr}, the Gravatar URL is:

\begin{displaycode}{smalltalk}
'http://www.gravatar.com/avatar/c147c32f94baa71afa9d7be0a289766d.jpg'
\end{displaycode}

The web application must be adapted with a new column for the photos:

\begin{displaycode}{smalltalk}
WAContactBook >> renderContactsOn: html
   html tbsTable: [
      html tableHead: [
         html
            tableHeading: 'Name';
            tableHeading: 'Email';
            tableHeading: 'Photo' ].
      self contactsDo: [ :contact | self renderContact: contact on: html ] ]
\end{displaycode}

  

\begin{displaycode}{smalltalk}
WAContactBook >> renderContact: aContact on: html
   html tableRow: [
      html
         tableData: aContact name;
         tableData: aContact email;
	 tableData: [ self renderPhotoOf: aContact on: html ] ]
\end{displaycode}

\begin{displaycode}{smalltalk}
WAContactBook >> renderPhotoOf: aContact on: html
   html image url: aContact gravatarUrl
\end{displaycode}


\begin{figure}

\begin{center}
\includegraphics[width=1.0\textwidth]{figures/contact-book-with-photos.png}\caption{Screenshot of the contact book application with photos\label{fig:with-photos}}\end{center}
\end{figure}

The result in Figure \ref{fig:with-photos} contains a new column for the contact photos, automatically fetched from a web service.
\section{Adding Actions}
We now add buttons to add a new contact and to remove and edit an existing contact.
\subsection{Adding a Remove Button}
We first add a remove button on each contact line in the table.

\begin{displaycode}{smalltalk}
WAContactBook >> renderContact: aContact on: html
   html tableRow: [
      html
         tableData: aContact name;
         tableData: aContact email;
         tableData: [ self renderPhotoOf: aContact on: html ];
	 tableData: [ self renderRemoveButtonForContact: aContact on: html ] 
\end{displaycode}

\begin{displaycode}{smalltalk}
WAContactBook >> renderRemoveButtonForContact: aContact on: html
   html tbsButton
      beDanger;
      callback: [ self contactBook removeContact: aContact ];
      with: 'Remove'
\end{displaycode}

You can refresh the page in the web browser and you will see the remove buttons. However, none of them will work because an HTML form must wrap the buttons. This can be done by modifying the \textcode{renderContentOn:} method again and add \textcode{tbsForm:}:

\begin{displaycode}{smalltalk}
WAContactBook >> renderContentOn: html
  "Main entry point of the view. Render both a title and the list of contacts."

  html
    tbsContainer: [
      html heading
        level: 1;
        with: 'My Contact Book'.
      html tbsForm: [ self renderContactsOn: html ] ]
\end{displaycode}

The remove buttons should now work fine.
\subsection{Add/Edit new Contact}
Implementing buttons to add a new contact or edit an existing one is a bit more involving because it requires creating a new component to edit the contact fields as in Figure \ref{fig:contact-book-edit}.


\begin{figure}

\begin{center}
\includegraphics[width=1.0\textwidth]{figures/contact-book-edit.png}\caption{Screenshot of the contact editor.\label{fig:contact-book-edit}}\end{center}
\end{figure}

\subsubsection{Creating a new Component}
We know create a component to be able to edit a contact. This is typically such task that the use of a system like Magritte can avoid. 
Create a new subclass of \textcode{WAComponent} which contains a \textcode{contact} instance variable.

\begin{displaycode}{smalltalk}
WAComponent subclass: #WAContact
   instanceVariableNames: 'contact
   classVariableNames: ''
   package: 'ContactBook'
\end{displaycode}

We define a class method \textcode{editContact:} to set the corresponding contact. 

\begin{displaycode}{smalltalk}
WAContact class >> editContact: aContact
   ^ self new
        setContact: aContact;
        yourself
\end{displaycode}

This time we do not use lazy initialization but we initialize the object by specialising the method \textcode{initialize}.

\begin{displaycode}{smalltalk}
WAContact >> initialize
	 super initialize. 
	 contact := Contact new. 
\end{displaycode}

\begin{displaycode}{smalltalk}
WAContact >> setContact: aContact
    contact := aContact

WAContact >> contact
    ^ contact
\end{displaycode}
\subsubsection{Rendering a Contact}
We define a new method \textcode{renderContentOn:} for the class \textcode{WAContact}

\begin{displaycode}{smalltalk}
WAContact >> renderContentOn: html
   html tbsContainer: [
      html heading with: Contact Editing'.
      html tbsForm with: [
         self renderFieldsOn: html ] ]
\end{displaycode}

\begin{displaycode}{smalltalk}
WAContact >> renderFieldsOn: html
    self renderFullnameFieldOn: html.
    self renderEmailFieldOn: html
\end{displaycode}

The method \textcode{renderFullnameFieldOn:} and \textcode{renderEmailFieldOn:} both render a label and an input field. 
\subsubsection{Fields}
Here is the \textcode{renderFullnameFieldOn:} method:

\begin{displaycode}{smalltalk}
WAContact >> renderFullnameFieldOn: html
   html tbsFormGroup: [
      html label: 'Fullname'.
      html textInput
         tbsFormControl;
         placeholder: 'fullname';
         callback: [ :value | self contact fullname: value ];
         value: (self contact fullname ifNil: '') ]
\end{displaycode}

The \textcode{tbsFormGroup:} method is a Bootstrap method to visually group a label and an input field together. Sending the \textcode{textInput} message to \textcode{html} creates a new text input. The other messages configure it:

\begin{itemize}
\item \textcode{tbsFormControl} adds Bootstrap-specific HTML markup;
\item \textcode{placeholder:} adds a ghost text indicating the purpose of the field and expected value that the user is expected to enter;
\item \textcode{callback:} attaches some code to be executed when the form is validated: the first parameter of the block is the value typed in the input field;
\item \textcode{value:} writes a default value in the field.
\end{itemize}

The \textcode{renderEmailFieldOn:} is very similar:

\begin{displaycode}{smalltalk}
WAContact >> renderEmailFieldOn: html
   html tbsFormGroup: [
      html label: 'Email'.
      html emailInput
         tbsFormControl;
         placeholder: 'your@email.eu';
         callback: [ :email | self contact email: email address ];
         value: (self contact email ifNil: '') ]
\end{displaycode}

The only difference with \textcode{renderFullnameFieldOn:} lies in the fact that the input field is dedicated to entering email addresses (the \textcode{textInput} message has been replaced by the \textcode{emailInput} message). In the \textcode{callback:} block, the parameter \textcode{email} is an instance of \textcode{WAEmailAddress}: it is necessary to send the message \textcode{address} to this object to get a string.
\subsubsection{Save/Cancel Buttons}
We now need to add 2 buttons: one to save the changes and one to cancel the changes. We introduce the message \textcode{renderButtonsOn:} in the \textcode{WAContact} as follows:

\begin{displaycode}{smalltalk}
WAContact >> renderContentOn: html
   html tbsContainer: [
      html heading with: 'Contact Editing'.
      html tbsForm with: [
         self renderFieldsOn: html.
         self renderButtonsOn: html ] ].
\end{displaycode}

Then we define the corresponding methods as follows: 

\begin{displaycode}{smalltalk}
WAContact >> renderButtonsOn: html
   html tbsFormGroup: [
      html tbsButtonGroup: [
         self
            renderSubmitButtonOn: html;
            renderCancelButtonOn: html ] ]
\end{displaycode}

\begin{displaycode}{smalltalk}
WAContact >> renderSubmitButtonOn: html
   html tbsSubmitButton
      beSuccess;
      bePrimary;
      callback: [ self answer: self contact ];
      with: 'Save'
\end{displaycode}

It is important to see that the callback of the submit button is using the message \textcode{answer:}.
This message is part of the \textcode{call:} and \textcode{answer:} protocol of Seaside. \textcode{call:} schedules a component 
and \textcode{answer:} unschedule it and return a value to the caller.

\begin{displaycode}{smalltalk}
WAContact >> renderCancelButtonOn: html
   html tbsButton
      beDanger;
      cancelCallback: [ self answer: nil ];
      with: 'Cancel'
\end{displaycode}

In the cancel button, we use \textcode{answer: nil}, since there is no value returned. Still the component (here the editor) should be closed. 
\subsection{Adding the Add/Edit Buttons to the ContactBook }
The last piece of the puzzle is the addition of the add and edit buttons on the contact book component. 
\subsubsection{Edit Button}
We start with the edit button, at the end of each contact row in the table:

\begin{displaycode}{smalltalk}
WAContactBook >> renderContact: aContact on: html
   html tableRow: [
      html
         tableData: aContact fullname;
         tableData: aContact email;
         tableData: [ self renderPhotoOf: aContact on: html ];
         tableData: [ self renderButtonsForContact: aContact on: html ] ]
\end{displaycode}

 

\begin{displaycode}{smalltalk}
WAContactBook >> renderButtonsForContact: aContact on: html
   html tbsButtonGroup: [
         self
            renderEditButtonForContact: aContact on: html;
            renderRemoveButtonForContact: aContact on: html ]
\end{displaycode}

\begin{displaycode}{smalltalk}
WAContactBook >> renderEditButtonForContact: aContact on: html
   html tbsButton
      beSuccess;
      callback: [ self call: (WAContact editContact: aContact) ];
      with: 'Edit'
\end{displaycode}

In the edit button callback, the message \textcode{call:} is sent to self to temporarily replace the contact book component by the contact editor. When the contact editor sends \textcode{answer:} to itself (in \textcode{WAContact\textgreater{}\textgreater{}renderSubmitButtonOn:} and \textcode{WAContact\textgreater{}\textgreater{}renderCancelButtonOn:}), the control flow comes back to this button's callback.
\subsection{Adding the Add new Button}
The add new contact button is as simple: We add a message \textcode{renderGlobalButtonsOn:}.

\begin{displaycode}{smalltalk}
WAContactBook >> renderContentOn: html
   "Main entry point of the view. Render both a title and the list of contacts."

   html tbsContainer: [
      html heading
         level: 1;
         with: 'My Contact Book'.
      html tbsForm: [
         self renderContactsOn: html.
	 self renderGlobalButtonsOn: html ] ]
\end{displaycode}

The method \textcode{renderGlobalButtonsOn:} defines a simple button.

\begin{displaycode}{smalltalk}
WAContactBook >> renderGlobalButtonsOn: html
   html tbsButtonGroup: [
      html tbsButton
         beSuccess;
         callback: [ self addContact ];
         with: 'New contact' ]
\end{displaycode}

\begin{displaycode}{smalltalk}
WAContactBook >> addContact
   (self call: WAContact new)
      ifNotNil: [ :contact | contactBook addContact: contact ]
\end{displaycode}

The message \textcode{call:} returns the same object that was returned by the corresponding message \textcode{answer:}  (in \textcode{WAContact\textgreater{}\textgreater{}renderSubmitButtonOn:} and \textcode{WAContact\textgreater{}\textgreater{}renderCancelButtonOn:}). Because pressing the cancel button in the contact editor passes \textcode{nil} to \textcode{answer:}, the message \textcode{call:} may return \textcode{nil}. If \textcode{call:} returns something different, it will be a new contact which should be added to the contact book.

You should now get the same result as in Figure \ref{fig:final}.
\section{About using Bootstrap tags}\label{secbootstrapmixin}
Now as we mentioned before when using the Seaside tags \textcode{tbs} we are promoting a bad practice. We did so because we did not want to spend time explain CSS and HTML. But you should really change your code. 

We are adding styling to the places where it should not be and we are breaking the idea that the code and its display should be separated. 
You can read the following blog to get a deeper view on it:
\url{http://ruby.bvision.com/blog/please-stop-embedding-bootstrap-classes-in-your-html}

Here is a summary

The argument is that having html code like this:

\begin{displaycode}{smalltalk}
    <div class="row">
      <div class="span6">...</div>
      <div class="span6">...</div>
    </div>
\end{displaycode}

goes against the separation of rendering and content that CSS is
supposed to bring. Adding all those bootstrap classes everywhere in the
HTML is not better than adding \textcode{\textless{}table\textgreater{}} tags to layout web pages.

The solution is to use SCSS/SASS/Less mixins to add sanity to your html. Something like:

\begin{displaycode}{smalltalk}
    <div class="book-previews">
      <div class="book-preview">...</div>
      <div class="book-preview">...</div>
    </div>
\end{displaycode}

and the SCSS/SASS/Less stylesheet:

\begin{displaycode}{smalltalk}
    .book-previews {
      .makeRow();        // Mixin provided by Bootstrap
      ...
    }
\end{displaycode}
\section{Summary}
During this tutorial we defined a simple model and two simple web views. We could have written tests and implement methods in the debugger while the application is running. Pharo developers often prefer to write code in the debugger because they go faster and the execution provides objects to play with.
\subsection{Further Development}
As you see the current functionality is rather limited, here is a list of possible extensions.

\begin{itemize}
\item Add more information to describe a contact. For this we suggest that you use Magritte (Magritte is a framework to describe data and its Seaside extension defines automatically Seaside component). You can read the Magritte chapter in the book as well as the Magritte tutorial available at \url{https://github.com/SquareBracketAssociates/PharoInProgress}. With Magritte, the components such as our ==WAContact= are automatically generated.
\item Use Twitter mixin class tags instead of hardcoded brushes. 
\item Save and load contacts in an external format such as JSON or STON (STON is a Pharo object notation format. It is by default in Pharo 50).
\item Save the contacts in a MongoDB using the Voyage framework (Check the chapters available on \url{http://books.pharo.org})
\item Deploy your application on \url{http://www.pharocloud.com} - It usually takes 3 min.
\end{itemize}


\ifx\wholebook\relax\else
\end{document}
\fi