Reference Manual for Gracelets - 2.0.0.RC2SourceForge.net Logo
3.2 - Examples : My Blog
First we setup our entity
Blog Entry Entity in Java (BlogEntry.java)
Toggle Line Numbers
1 package org.ponder.gracelets.demo.blog; 
2  
3 import java.util.Date; 
4  
5 import javax.persistence.Entity; 
6 import javax.persistence.FetchType; 
7 import javax.persistence.GeneratedValue; 
8 import javax.persistence.Id; 
9 import javax.persistence.ManyToOne; 
10 import javax.persistence.Temporal; 
11 import javax.persistence.TemporalType; 
12  
13 /** 
14  * @author ponder 
15  * $Revision$ 
16  */ 
17 @Entity public class BlogEntry { 
18  
19     private int id; 
20     private Date date; 
21     private String title; 
22     private String text; 
23      
24     private BlogEntry parent; 
25      
26     @Id @GeneratedValue public int getId() { return id; } 
27     public void setId(int id) { this.id = id; } 
28      
29     @Temporal(TemporalType.TIMESTAMP) public Date getDate() { return date; } 
30     public void setDate(Date date) { this.date = date; } 
31      
32     public String getText() { return text; } 
33     public void setText(String text) { this.text = text; } 
34      
35     public String getTitle() { return title; } 
36     public void setTitle(String title) { this.title = title; } 
37      
38     @ManyToOne(fetch=FetchType.EAGER) 
39     public BlogEntry getParent() { return parent; } 
40     public void setParent(BlogEntry parent) { this.parent = parent; } 
41      
42 } 
We then write our view, which in this case is the only thing outside of the entity definition and the directory view (below) that makes this example run.

Blog Application View (index.groovy)
Toggle Line Numbers
1 import org.ponder.gracelets.demo.blog.BlogEntry 
2  
3 Factory("blogEntryPage") { "list" } 
4  
5 Factory("blogComments", "event") { 
6     if (!blogToView) return 
7     demodb.getResults("SELECT e FROM BlogEntry e WHERE e.parent = :parent", parent: blogToView) 
8 } 
9  
10 u.composition(template: "template.groovy") { 
11     g.subpages (value: Value { blogEntryPage }) { 
12          
13         u.component(page: "list") { 
14             g.form { 
15              
16                 g.grid(value: DataModel("myBlogs") {  
17                     demodb.managedQuery("e", "BlogEntry e", "e.parent IS NULL", "e.date DESC").model  
18                 }, caption: "Blog Entries", width: "50%", var: "entry") { 
19                      
20                     h.column(facets: [header: { print "Posted" }], valign: "top") {  
21                         print { entry.date << "MM/dd/yy hh:mma" }  
22                     } 
23                      
24                     h.column(facets: [header: { print "Title" }], valign: "top") { 
25                         xh.a(href: { "/gracelets/demo/blog/entries/$entry.title" }) { print { entry.title } } 
26                     } 
27                      
28                 } 
29                  
30                 xh.table (width: "50%", cellspacing: 0, cellpadding: 0, border: 0) { 
31                     handler(cond: { myBlogs.rowCount == 0 }) { 
32                         tr { td("No blog entries") } 
33                     } 
34                     tr { td (align: "right", style: "background-color: rgb(180,180,180); padding: 2px") { 
35                         h.commandButton("New Entry...", action: {  
36                             System.out.println("New entry called") 
37                             selectedBlogEntry = new BlogEntry(); 
38                             selectedBlogEntry.date = new Date(); 
39                             blogEntryPage = "blogEdit" 
40                         }) 
41                     } } 
42                 } 
43                  
44             } 
45         } 
46          
47         u.component(page: "blogEdit") { 
48              
49             xh.table (width: "50%") { tr { td { 
50                 g.form { 
51                      
52                     fieldset {  
53                         legend { 
54                             h.inputText(size: 40, maxlength: 50,  
55                                 value: Value { selectedBlogEntry.title },  
56                                 required: true, requiredMessage: "Please enter a title") 
57                         } 
58                          
59                         h.inputTextarea(requiredMessage: "Please enter something first",  
60                             required: true, cols: 70, rows: 20, value: Value { selectedBlogEntry.text }, 
61                             validatorMessage: "Please enter more than 20 characters") { 
62                             j.validateLength(minimum: 20) 
63                         } 
64                          
65                     } 
66                      
67                     xh.div(style: "background-color: rgb(180,180,180); padding: 2px; text-align: right;") { 
68                         h.commandButton("Cancel", action: { System.out.println("Canceled"); blogEntryPage = "list" }, immediate: true) 
69                         h.commandButton("Save Blog", action: { 
70                             demodb.save(selectedBlogEntry) 
71                             jsfMessages.add("Blog has been added") 
72                             myBlogs.clear() 
73                             blogEntryPage = "list" 
74                         }) 
75                     } 
76                      
77                 } 
78             } } } 
79              
80         } 
81     } 
82              
83 } 
We then write a directory view to handle the blog entries as shown below:
Blog Entry Directory View
Toggle Line Numbers
1 import org.ponder.gracelets.demo.blog.BlogEntry 
2  
3 Factory("blogToView", "event") { 
4     if (DIRECTORY_PATH) { 
5         return demodb.getSingleResult("SELECT e FROM BlogEntry e WHERE UPPER(e.title) = :title",  
6             title: DIRECTORY_PATH.substring(1).replaceAll("_", " ").toUpperCase()) 
7     } 
8     if (!param['blogId']) return 
9     demodb.getSingleResult("SELECT e FROM BlogEntry e WHERE e.id = :id", id:  
10         Integer.parseInt(param['blogId'])) 
11 } 
12  
13 u.composition(template: "template.groovy") { 
14     xh.table(width: "50%") { tr { td(colspan: 2) { 
15         print { "$blogToView.title - " } 
16         print { blogToView.date << "MM/dd/yyyy hh:mm:ssa" } 
17     } } 
18     tr { td(colspan: 2) {  
19         g.form { 
20             xh.sub { 
21                 h.commandLink("[View Entries]", action: { 
22                     System.out.println("The action link was called.") 
23                     return "index.groovy"  
24                 }) 
25             } 
26         } 
27     } } 
28     tr { td(colspan: 2) { 
29         hr(style: "color: blue") 
30         print { blogToView.text } 
31     } } 
32      
33         render { cmp -> 
34             def x = cmp.builder 
35             if (blogComments.size() > 0) { 
36                 blogComments.each { comment -> 
37                     x.tr { td (width: 200) {  
38                         br(); br(); br(); 
39                         print "Comment - " + (comment.date << "MM/dd/yyyy hh:mm:ssa") 
40                     } } 
41                     x.tr { td(colspan: 2) { 
42                         hr(style: "color: blue") 
43                         print comment.text 
44                     } } 
45                 } 
46             } 
47         } 
48          
49         tr { td { 
50             xh.br(); xh.br(); 
51              
52             g.form { 
53                 xh.input(type: "hidden", name: "blogId", value: { blogToView.id }) 
54                 h.commandButton("Add Comment...", action: { 
55                     def comment = new BlogEntry(); 
56                     comment.date = new Date() 
57                     comment.parent = blogToView 
58                     comment.text = newBlogComment 
59                     demodb.save(comment) 
60                     jsfMessages.add("Comment has been added") 
61                     newBlogComment = null 
62                 }) 
63                 xh.br() 
64                 h.inputTextarea(required: true, cols: 50, rows: 15, value: Value { newBlogComment }, 
65                     validatorMessage: "Please enter at least a 20 character comment", 
66                     requiredMessage: "Please enter a comment first") { 
67                     j.validateLength(minimum: 20) 
68                 } 
69             } 
70         } } 
71     } 
72 }