Create...
Person
Home

Persons.tml


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- We need a doctype to allow us to use special characters like &nbsp; 
     We use a "strict" DTD to make IE follow the alignment rules. -->
     
<html t:type="together/Layout1" t:title="literal:With Layout: Filter CRUD" t:chosenOption="literal:Filter CRUD"
    xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter">
    
    <t:remove>
        <!-- At runtime the stylesheet will be provided by the Layout. The link here is only to enable preview. -->
        <link rel="stylesheet" type="text/css" href="../../../../css/together/layout1.css"/>
    </t:remove>

    <a t:type="eventLink" t:event="toCreate" href="#">Create...</a><br/>
    
    <table id="listAndEditor">
        <tbody>
            <tr>

                <!-- This is the left side of the table: a list of Persons -->

                <td id="listCell">

                    <div id="personFilter">
                        <form t:type="form" t:id="filterForm">
                            <div>
                                Person
                            </div>
                            <div>
                                <input t:id="partialName" t:type="TextField" size="15" t:validate="maxLength=15"/>
                                <input type="submit" value="Filter" title="Filter"/>
                            </div>
                        </form>
                    </div>
                    
                    <div id="personList">
                        <table t:type="grid" t:id="list" t:source="listPersons" t:row="listPerson"
                            t:exclude="id,version,firstName,lastName,region,startDate" t:add="name"
                            t:rowsPerPage="4" t:pagerPosition="bottom"
                            t:class="personGrid" t:empty="block:emptyPersons">[Grid here]
                            <p:nameCell>
                                <a t:type="eventLink" t:event="selected" t:context="listPerson.id" 
                                    class="prop:linkCSSClass" href="#">
                                    ${listPerson.firstName} ${listPerson.lastName}
                                </a>
                            </p:nameCell>
                        </table>
                    </div>
                    
                    <t:block t:id="emptyPersons">
                        <div id="noPersons">
                            (No persons found)
                        </div>
                    </t:block>

                </td>
                
                <!-- This is the right side of the table: where a Person will be created, reviewed, or updated. -->
        
                <td id="editorCell">

                    <t:if test="modeCreate">
                        <h1>Create</h1>
                        
                        <form t:type="CustomForm" t:id="createForm" >
                            <t:errors/>
                    
                            <table>
                                <tr>
                                    <th><t:label for="firstName"/>:</th>
                                    <td><input t:type="TextField" t:id="firstName" value="editorPerson.firstName" 
                                        t:validate="required, maxlength=10" size="10"/></td>
                                    <td>(required)</td>
                                </tr>
                                <tr class="err">
                                    <th></th>
                                    <td colspan="2"><t:CustomError for="firstName"/></td>
                                </tr>
                                <tr>
                                    <th><t:label for="lastName"/>:</th>
                                    <td><input t:type="TextField" t:id="lastName" t:clientid="clastname" 
                                        value="editorPerson.lastName" t:validate="required, maxlength=10" 
                                        size="10"/></td>
                                    <td>(required)</td>
                                </tr>
                                <tr class="err">
                                    <th></th>
                                    <td colspan="2"><t:CustomError for="lastName"/></td>
                                </tr>
                                <tr>
                                    <th><t:label for="region"/>:</th>
                                    <td><input t:type="Select" t:id="region" value="editorPerson.region" 
                                        t:validate="required" t:blankOption="ALWAYS"/></td>
                                    <td>(required)</td>
                                </tr>
                                <tr class="err">
                                    <th></th>
                                    <td colspan="2"><t:CustomError for="region"/></td>
                                </tr>
                                <tr>
                                    <th><t:label for="startDate"/>:</th>
                                    <td><input t:type="DateField" t:id="startDate" t:clientid="cstartdate" 
                                        value="editorPerson.startDate" t:format="prop:dateFormat" 
                                        t:validate="required" size="10"/></td>
                                    <td>(required, ${datePattern})</td>
                                </tr>
                                <tr class="err">
                                    <th></th>
                                    <td colspan="2"><t:CustomError for="startDate"/></td>
                                </tr>
                            </table>

                            <div class="buttons">
                                <a t:type="eventLink" t:event="cancelCreate" href="#">Cancel</a>
                                <input type="submit" value="Save"/>
                            </div>
                        </form>

                    </t:if>

                    <t:if test="modeReview">
                        <h1>Review</h1>
                        
                        <t:if test="editorPerson">
                            <div t:type="if" t:test="deleteMessage" class="error">
                                ${deleteMessage}
                            </div>

                            <table>
                                <tr>
                                    <th>Id:</th>
                                    <td>${editorPerson.id}</td>
                                </tr>
                                <tr>
                                    <th>Version:</th>
                                    <td>${editorPerson.version}</td>
                                </tr>
                                <tr>
                                    <th>Name:</th>
                                    <td>${editorPerson.firstName} ${editorPerson.lastName}</td>
                                </tr>
                                <tr>
                                    <th>Region:</th>
                                    <td>${editorPersonRegion}</td>
                                </tr>
                                <tr>
                                    <th>Start Date:</th>
                                    <td><t:output value="editorPerson.startDate" format="prop:dateFormat"/></td>
                                </tr>
                            </table>

                            <div class="buttons">
                                <a t:type="eventLink" t:event="toUpdate" t:context="editorPerson.id" href="#">Update...</a>
                                <a t:type="eventLink" t:event="delete" t:context="[editorPerson.id,editorPerson.version]" href="#" 
                                    t:mixins="Confirm" t:message="Delete ${editorPerson.firstName} ${editorPerson.lastName}?">Delete...</a>
                            </div>

                        </t:if>
                        <t:if negate="true" test="editorPerson">
                            Person ${editorPersonId} does not exist.<br/><br/>
                        </t:if>
                        
                    </t:if>

                    <t:if test="modeUpdate">
                        <h1>Update</h1>
                        
                        <form t:type="CustomForm" t:id="updateForm">
                            <t:errors/>
                    
                            <t:if test="editorPerson">
                                <!-- If optimistic locking is not needed then comment out this next line. It works because Hidden fields are part of the submit. -->
                                <t:hidden value="editorPerson.version"/>
                        
                                <table>
                                    <tr>
                                        <th><t:label for="updFirstName"/>:</th>
                                        <td><input t:type="TextField" t:id="updFirstName" value="editorPerson.firstName" 
                                            t:validate="required, maxlength=10" size="10"/></td>
                                        <td>(required)</td>
                                    </tr>
                                    <tr class="err">
                                        <th></th>
                                        <td colspan="2"><t:CustomError for="updFirstName"/></td>
                                    </tr>
                                    <tr>
                                        <th><t:label for="updLastName"/>:</th>
                                        <td><input t:type="TextField" t:id="updLastName" value="editorPerson.lastName" 
                                            t:validate="required, maxlength=10" size="10"/></td>
                                        <td>(required)</td>
                                    </tr>
                                    <tr class="err">
                                        <th></th>
                                        <td colspan="2"><t:CustomError for="updLastName"/></td>
                                    </tr>
                                    <tr>
                                        <th><t:label for="updRegion"/>:</th>
                                        <td><input t:type="Select" t:id="updRegion" value="editorPerson.region" t:validate="required"/></td>
                                        <td>(required)</td>
                                    </tr>
                                    <tr class="err">
                                        <th></th>
                                        <td colspan="2"><t:CustomError for="updRegion"/></td>
                                    </tr>
                                    <tr>
                                        <th><t:label for="updStartDate"/>:</th>
                                        <td><input t:type="DateField" t:id="updStartDate" value="editorPerson.startDate" 
                                            t:format="prop:dateFormat" t:validate="required" size="10"/></td>
                                        <td>(required, ${datePattern})</td>
                                    </tr>
                                    <tr class="err">
                                        <th></th>
                                        <td colspan="2"><t:CustomError for="updStartDate"/></td>
                                    </tr>
                                </table>

                                <div class="buttons">
                                    <a t:type="eventLink" t:event="cancelUpdate" t:context="editorPerson.id" href="#">Cancel</a>
                                    <input t:type="submit" value="Save"/>
                                </div>
                            </t:if>
                            <t:if negate="true" test="editorPerson">
                                Person ${editorPersonId} does not exist.<br/><br/>
                            </t:if>
                                
                        </form>
                        
                    </t:if>
 
                </td>
                
            </tr>
        </tbody>
    </table>

    <a t:type="pageLink" t:page="Index" href="#">Home</a><br/><br/>

    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/pages/together/withlayout/filtercrud/Persons.tml"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/components/together/Layout1.tml"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/components/together/Layout1.java"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/css/together/layout1.css"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/model/Menu.java"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/model/MenuOption.java"/>
</html>

Layout1.tml


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- We need a doctype to allow us to use special characters like &nbsp; 
     We use a "strict" DTD to make IE follow the alignment rules. -->
     
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">

<head>
    <title>${title}</title>
    <link rel="stylesheet" type="text/css" href="${context:css/together/layout1.css}"/>
</head>

<body>

    <table id="page">
        <tr>
            <td id="top">
                <div id="banner">
                    <h1>With Layout</h1>
            
                    <div class="bannerText">
                        In this example we show 3 pages that have the same layout: a gray margin, a title, this text, 
                        a menu, and the page's content. The Tapestry way to output all that stuff is to write a 
                        component to do it and use that component as your page's outermost tag. In this example the 
                        component is called <em>together/Layout1</em> and you can see it being used in the outermost 
                        tag of all 3 pages.<br/>
                    </div><br/>
                </div>

                <!-- Menu style is based on an example at http://www.dynamicdrive.com/dynamicindex1/ddtabmenu.htm -->
                <div id="menubar">
                    <ul>
                        <li t:type="Loop" t:source="menu.menuoptions" t:value="menuoption">
                            <a t:type="pagelink" t:page="prop:menuoption.page" class="prop:menuOptionCSSClass">
                                <span>${menuoption.label}</span>
                            </a>
                        </li>
                    </ul>
                </div>
                <div id="menubarline"/>
            </td>
        </tr>

        <tr>
            <td id="content">
                <!-- t:body is a directive that says "output the content that I surround". -->
                <t:body/>
            </td>
        </tr>
        
    </table>

</body>

</html>

Layout1.java


package jumpstart.web.components.together;

import jumpstart.web.annotation.ProtectedPage;
import jumpstart.web.model.Menu;
import jumpstart.web.model.MenuOption;

import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.Property;

@ProtectedPage
public class Layout1 {
    private static final String CHOSEN_OPTION_CSS_CLASS = "chosenOption";

    // Parameters

    @Parameter
    @Property
    private String title;

    @Parameter
    @Property
    private String chosenOption;

    // Screen fields

    private Menu menu;

    @Property
    private MenuOption menuOption;

    // The code

    public Menu getMenu() {

        if (menu == null) {
            menu = new Menu();
            menu.add(new MenuOption("Hello World", "together/withlayout/HelloWorld"));
            menu.add(new MenuOption("Filter CRUD", "together/withlayout/filtercrud/Persons"));
            menu.add(new MenuOption("Components CRUD", "together/withlayout/componentscrud/Persons"));
        }

        return menu;
    }

    public String getMenuOptionCSSClass() {
        return menuOption.getLabel().equals(chosenOption) ? CHOSEN_OPTION_CSS_CLASS : "";
    }

}

layout1.css


body, td        { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13px; font-weight: normal; color: #333;
                    line-height: 17px; max-width: 1000px; }

.eg             { margin: 20px 0; padding: 20px; 
                    border: 1px solid #ddd; border-radius: 4px; -webkit-border-radius: 4px; -mox-border-radius: 4px; }

a               { text-decoration: none; color: #3D69B6; }
a:hover         { text-decoration: underline; }

table       { border-collapse: collapse; border-spacing: 0; }
:root table { border-collapse: separate; } /* Firefox 3 */
th, td      { padding: 0; }
form        { margin-bottom: 0; } /* IE 7 */

/***************
 * Layout elements
 ***************/
 
#page               { margin: 10px; background-color: white; }

#top                { width: 100%; background-color: #eee; padding-top: 0px; }
#banner             { background-color: #eee; padding: 0px 10px 10px 10px; }
.bannerText         { max-width: 800px; }

/* Based on example 4 at http://www.dynamicdrive.com/dynamicindex1/ddtabmenu.htm minus the images that give rounded corners */
#menubar            { padding: 0; width: 100%; background-color: transparent; voice-family: "\"}\""; voice-family: inherit; }
#menubar ul         { font: normal 11px Arial, Verdana, sans-serif; margin:0; padding:0; list-style:none; }
#menubar li         { display:inline; margin:0 2px 0 0; padding:0; }
#menubar a          { float:left; color: white; background: #3d69b6; margin:0 2px 0 0;
                            padding:0 0 1px 3px; text-decoration:none; letter-spacing: 1px; }
#menubar a span     { float:none; display:block; background: transparent; padding: 6px 8px 3px 7px; }
#menubar a:hover    { background-color: #8cb85c; }
#menubar a:hover span   { background-color: #8cb85c; }
#menubar a.chosenOption, #menubar a.chosenOption span   { /*currently selected tab*/ background-color: #809FFF; }
#menubarline        { clear: both; padding: 0; width: 100%; height: 8px; line-height: 8px; background: #809FFF;
                            border-top: 1px solid #fff; /*Remove this to remove border between bar and tabs*/ }

#content            { width: 100%; background-color: white; margin: 0; padding: 10px; }

/***************
 * Page body elements
 ***************/

#listAndEditor          { width: 800px; border: none; margin: 10px 0; }

#listCell               { width: 25%; border: 1px solid white; background-color: #eee; vertical-align: top; }

#personFilter           { width: 100%; padding: 5px 0 10px 0; text-align: center; vertical-align: middle; 
                            background-color: #3d69b6; color: white; font-weight: bold; border: 1px solid white; }

/* Add some padding around the list so that we can see the yellow flash when "Highlight zone updates" is on. */ 
#listZone               { padding: 4px; background-color: inherit; /* For IE7: */ background-color: #eee; }

#personList             { height: 240px; position: relative; }
#personListInZone       { height: 238px; position: relative; }
.personGrid             { width: 100%; font-family: Arial, Helvetica, sans-serif; }
.personGrid th          { display: none; }
.personGrid td          { border: thin solid white; background-color: #eee; }
.personGrid a           { width: 100%; line-height: 50px; display: block; text-align: center;
                            text-decoration: none; color: black; }
.personGrid a:visited   { color: inherit; }
.personGrid a:hover     { background: #ccc; color: #fff; }
.personGrid a.active    { background: #999; color: #fff; }
.personGrid span.current    { background-color: #3d69b6; }

#personList .t-data-grid-pager  /* Need line-height to work around IE7 hasLayout and missing margins bug */
                        { line-height: 24px; position: absolute; left: 4px; bottom: 3px; margin: 0;
                            font-family: Arial, Helvetica, sans-serif; }
#personListInZone .t-data-grid-pager    /* Need line-height to work around IE7 hasLayout and missing margins bug */
                        { line-height: 24px; position: absolute; left: 2px; bottom: 0px; margin: 0;
                            font-family: Arial, Helvetica, sans-serif; }

#noPersons              { text-align: center; padding-top: 10px; }

#editorCell             { width: 75%; height: 100%; vertical-align: top; 
                             border: 1px solid white; background-color: #eee; padding: 20px; }
#editorZone             { background-color: inherit; /* For IE7: */ background-color: #eee; }
#editorCell table       { margin: auto; } 
#editorCell h1          { font-size: large; text-align: center; } 
#editorCell th          { padding: 2px 5px; text-align: right; }
#editorCell td          { padding: 2px 5px; text-align: left; }
#editorCell tr.err th   { padding: 0; }
#editorCell tr.err td   { padding: 0; }
#editorCell tr.err td.error-msg-c   { padding: 0 0 4px 7px; font-size: 11px; color: red; } 
#editorCell .buttons    { text-align: center; padding-top: 15px; } 

.error                  { color: red; text-align: center; padding-bottom: 13px; }

.Zsourcecodedisplay     { width: 980px; overflow-x: scroll; }

Menu.java


package jumpstart.web.model;

import java.util.ArrayList;
import java.util.List;

/**
 * Menu holds a list of MenuOption.
 */
public class Menu {
    private List<MenuOption> menuOptions = new ArrayList<MenuOption>();

    public Menu() {
    }

    public void add(MenuOption menuOption) {
        menuOptions.add(menuOption);
    };

    public List<MenuOption> getMenuOptions() {
        return menuOptions;
    };
}

MenuOption.java


package jumpstart.web.model;

/**
 * MenuOption holds a label to display and a logical page name, eg. "Hello World" and "previews/withlayout/HelloWorld".
 */
public class MenuOption {
    private String label;
    private String page;

    public MenuOption(String label, String page) {
        this.label = label;
        this.page = page;
    }

    public String getLabel() {
        return label;
    };

    public String getPage() {
        return page;
    };
}