Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added the scaffolding templates, was an error in production when I di…

…d not do this
  • Loading branch information...
commit 4a62589143ff73f2a3790a1e60dfd4d321ea7373 1 parent 58cb6c8
@jettro authored
View
4 src/templates/artifacts/Controller.groovy
@@ -0,0 +1,4 @@
+@artifact.package@class @artifact.name@ {
+
+ def index = { }
+}
View
5 src/templates/artifacts/DomainClass.groovy
@@ -0,0 +1,5 @@
+@artifact.package@class @artifact.name@ {
+
+ static constraints = {
+ }
+}
View
17 src/templates/artifacts/Filters.groovy
@@ -0,0 +1,17 @@
+@artifact.package@class @artifact.name@ {
+
+ def filters = {
+ all(controller:'*', action:'*') {
+ before = {
+
+ }
+ after = {
+
+ }
+ afterView = {
+
+ }
+ }
+ }
+
+}
View
7 src/templates/artifacts/Script.groovy
@@ -0,0 +1,7 @@
+includeTargets << grailsScript("Init")
+
+target(main: "The description of the script goes here!") {
+ // TODO: Implement script here
+}
+
+setDefaultTarget(main)
View
8 src/templates/artifacts/Service.groovy
@@ -0,0 +1,8 @@
+@artifact.package@class @artifact.name@ {
+
+ boolean transactional = true
+
+ def serviceMethod() {
+
+ }
+}
View
3  src/templates/artifacts/TagLib.groovy
@@ -0,0 +1,3 @@
+@artifact.package@class @artifact.name@ {
+
+}
View
15 src/templates/artifacts/Tests.groovy
@@ -0,0 +1,15 @@
+@artifact.package@import grails.test.*
+
+class @artifact.name@ extends @artifact.superclass@ {
+ protected void setUp() {
+ super.setUp()
+ }
+
+ protected void tearDown() {
+ super.tearDown()
+ }
+
+ void testSomething() {
+
+ }
+}
View
54 src/templates/artifacts/WebTest.groovy
@@ -0,0 +1,54 @@
+class @webtest.name.caps@Test extends grails.util.WebTest {
+
+ // Unlike unit tests, functional tests are often sequence dependent.
+ // Specify that sequence here.
+ void suite() {
+ test@webtest.name.caps@ListNewDelete()
+ // add tests for more operations here
+ }
+
+ def test@webtest.name.caps@ListNewDelete() {
+ webtest('@webtest.name.caps@ basic operations: view list, create new entry, view, edit, delete, view') {
+ invoke(url:'@webtest.name.lower@')
+ verifyText(text:'Home')
+
+ verifyListPage(0)
+
+ clickLink(label:'New @webtest.name.caps@')
+ verifyText(text:'Create @webtest.name.caps@')
+ clickButton(label:'Create')
+ verifyText(text:'Show @webtest.name.caps@', description:'Detail page')
+ clickLink(label:'List', description:'Back to list view')
+
+ verifyListPage(1)
+
+ group(description:'edit the one element') {
+ clickLink(label:'Show', description:'go to detail view')
+ clickButton(label:'Edit')
+ verifyText(text:'Edit @webtest.name.caps@')
+ clickButton(label:'Update')
+ verifyText(text:'Show @webtest.name.caps@')
+ clickLink(label:'List', description:'Back to list view')
+ }
+
+ verifyListPage(1)
+
+ group(description:'delete the only element') {
+ clickLink(label:'Show', description:'go to detail view')
+ clickButton(label:'Delete')
+ verifyXPath(xpath:"//div[@class='message']", text:/@webtest.name.caps@.*deleted./, regex:true)
+ }
+
+ verifyListPage(0)
+ }
+ }
+
+ String ROW_COUNT_XPATH = "count(//td[@class='actionButtons']/..)"
+
+ def verifyListPage(int count) {
+ ant.group(description:"verify @webtest.name.caps@ list view with $count row(s)") {
+ verifyText(text:'@webtest.name.caps@ List')
+ verifyXPath(xpath:ROW_COUNT_XPATH, text:count, description:"$count row(s) of data expected")
+ }
+ }
+}
View
99 src/templates/scaffolding/Controller.groovy
@@ -0,0 +1,99 @@
+
+
+<%=packageName ? "package ${packageName}\n\n" : ''%>class ${className}Controller {
+
+ def index = { redirect(action:list,params:params) }
+
+ // the delete, save and update actions only accept POST requests
+ static allowedMethods = [delete:'POST', save:'POST', update:'POST']
+
+ def list = {
+ params.max = Math.min( params.max ? params.max.toInteger() : 10, 100)
+ [ ${propertyName}List: ${className}.list( params ), ${propertyName}Total: ${className}.count() ]
+ }
+
+ def show = {
+ def ${propertyName} = ${className}.get( params.id )
+
+ if(!${propertyName}) {
+ flash.message = "${className} not found with id \${params.id}"
+ redirect(action:list)
+ }
+ else { return [ ${propertyName} : ${propertyName} ] }
+ }
+
+ def delete = {
+ def ${propertyName} = ${className}.get( params.id )
+ if(${propertyName}) {
+ try {
+ ${propertyName}.delete(flush:true)
+ flash.message = "${className} \${params.id} deleted"
+ redirect(action:list)
+ }
+ catch(org.springframework.dao.DataIntegrityViolationException e) {
+ flash.message = "${className} \${params.id} could not be deleted"
+ redirect(action:show,id:params.id)
+ }
+ }
+ else {
+ flash.message = "${className} not found with id \${params.id}"
+ redirect(action:list)
+ }
+ }
+
+ def edit = {
+ def ${propertyName} = ${className}.get( params.id )
+
+ if(!${propertyName}) {
+ flash.message = "${className} not found with id \${params.id}"
+ redirect(action:list)
+ }
+ else {
+ return [ ${propertyName} : ${propertyName} ]
+ }
+ }
+
+ def update = {
+ def ${propertyName} = ${className}.get( params.id )
+ if(${propertyName}) {
+ if(params.version) {
+ def version = params.version.toLong()
+ if(${propertyName}.version > version) {
+ <%def lowerCaseName = grails.util.GrailsNameUtils.getPropertyName(className)%>
+ ${propertyName}.errors.rejectValue("version", "${lowerCaseName}.optimistic.locking.failure", "Another user has updated this ${className} while you were editing.")
+ render(view:'edit',model:[${propertyName}:${propertyName}])
+ return
+ }
+ }
+ ${propertyName}.properties = params
+ if(!${propertyName}.hasErrors() && ${propertyName}.save()) {
+ flash.message = "${className} \${params.id} updated"
+ redirect(action:show,id:${propertyName}.id)
+ }
+ else {
+ render(view:'edit',model:[${propertyName}:${propertyName}])
+ }
+ }
+ else {
+ flash.message = "${className} not found with id \${params.id}"
+ redirect(action:list)
+ }
+ }
+
+ def create = {
+ def ${propertyName} = new ${className}()
+ ${propertyName}.properties = params
+ return ['${propertyName}':${propertyName}]
+ }
+
+ def save = {
+ def ${propertyName} = new ${className}(params)
+ if(!${propertyName}.hasErrors() && ${propertyName}.save()) {
+ flash.message = "${className} \${${propertyName}.id} created"
+ redirect(action:show,id:${propertyName}.id)
+ }
+ else {
+ render(view:'create',model:[${propertyName}:${propertyName}])
+ }
+ }
+}
View
62 src/templates/scaffolding/create.gsp
@@ -0,0 +1,62 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <meta name="layout" content="main" />
+ <title>Create ${className}</title>
+ </head>
+ <body>
+ <div class="nav">
+ <span class="menuButton"><a class="home" href="\${resource(dir:'')}">Home</a></span>
+ <span class="menuButton"><g:link class="list" action="list">${className} List</g:link></span>
+ </div>
+ <div class="body">
+ <h1>Create ${className}</h1>
+ <g:if test="\${flash.message}">
+ <div class="message">\${flash.message}</div>
+ </g:if>
+ <g:hasErrors bean="\${${propertyName}}">
+ <div class="errors">
+ <g:renderErrors bean="\${${propertyName}}" as="list" />
+ </div>
+ </g:hasErrors>
+ <g:form action="save" method="post" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
+ <div class="dialog">
+ <table>
+ <tbody>
+ <%
+
+ excludedProps = ['version',
+ 'id',
+ Events.ONLOAD_EVENT,
+ Events.BEFORE_DELETE_EVENT,
+ Events.BEFORE_INSERT_EVENT,
+ Events.BEFORE_UPDATE_EVENT]
+ props = domainClass.properties.findAll { !excludedProps.contains(it.name) }
+
+ Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+ props.each { p ->
+ if(!Collection.class.isAssignableFrom(p.type)) {
+ cp = domainClass.constrainedProperties[p.name]
+ display = (cp ? cp.display : true)
+ if(display) { %>
+ <tr class="prop">
+ <td valign="top" class="name">
+ <label for="${p.name}">${p.naturalName}:</label>
+ </td>
+ <td valign="top" class="value \${hasErrors(bean:${propertyName},field:'${p.name}','errors')}">
+ ${renderEditor(p)}
+ </td>
+ </tr>
+ <% } } } %>
+ </tbody>
+ </table>
+ </div>
+ <div class="buttons">
+ <span class="button"><input class="save" type="submit" value="Create" /></span>
+ </div>
+ </g:form>
+ </div>
+ </body>
+</html>
View
64 src/templates/scaffolding/edit.gsp
@@ -0,0 +1,64 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <meta name="layout" content="main" />
+ <title>Edit ${className}</title>
+ </head>
+ <body>
+ <div class="nav">
+ <span class="menuButton"><a class="home" href="\${resource(dir:'')}">Home</a></span>
+ <span class="menuButton"><g:link class="list" action="list">${className} List</g:link></span>
+ <span class="menuButton"><g:link class="create" action="create">New ${className}</g:link></span>
+ </div>
+ <div class="body">
+ <h1>Edit ${className}</h1>
+ <g:if test="\${flash.message}">
+ <div class="message">\${flash.message}</div>
+ </g:if>
+ <g:hasErrors bean="\${${propertyName}}">
+ <div class="errors">
+ <g:renderErrors bean="\${${propertyName}}" as="list" />
+ </div>
+ </g:hasErrors>
+ <g:form method="post" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
+ <input type="hidden" name="id" value="\${${propertyName}?.id}" />
+ <input type="hidden" name="version" value="\${${propertyName}?.version}" />
+ <div class="dialog">
+ <table>
+ <tbody>
+ <%
+ excludedProps = ['version',
+ 'id',
+ Events.ONLOAD_EVENT,
+ Events.BEFORE_DELETE_EVENT,
+ Events.BEFORE_INSERT_EVENT,
+ Events.BEFORE_UPDATE_EVENT]
+ props = domainClass.properties.findAll { !excludedProps.contains(it.name) }
+
+ Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+ props.each { p ->
+ cp = domainClass.constrainedProperties[p.name]
+ display = (cp ? cp.display : true)
+ if(display) { %>
+ <tr class="prop">
+ <td valign="top" class="name">
+ <label for="${p.name}">${p.naturalName}:</label>
+ </td>
+ <td valign="top" class="value \${hasErrors(bean:${propertyName},field:'${p.name}','errors')}">
+ ${renderEditor(p)}
+ </td>
+ </tr>
+ <% } } %>
+ </tbody>
+ </table>
+ </div>
+ <div class="buttons">
+ <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+ <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+ </div>
+ </g:form>
+ </div>
+ </body>
+</html>
View
60 src/templates/scaffolding/list.gsp
@@ -0,0 +1,60 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <meta name="layout" content="main" />
+ <title>${className} List</title>
+ </head>
+ <body>
+ <div class="nav">
+ <span class="menuButton"><a class="home" href="\${createLinkTo(dir:'')}">Home</a></span>
+ <span class="menuButton"><g:link class="create" action="create">New ${className}</g:link></span>
+ </div>
+ <div class="body">
+ <h1>${className} List</h1>
+ <g:if test="\${flash.message}">
+ <div class="message">\${flash.message}</div>
+ </g:if>
+ <div class="list">
+ <table>
+ <thead>
+ <tr>
+ <%
+ excludedProps = ['version',
+ Events.ONLOAD_EVENT,
+ Events.BEFORE_DELETE_EVENT,
+ Events.BEFORE_INSERT_EVENT,
+ Events.BEFORE_UPDATE_EVENT]
+
+ props = domainClass.properties.findAll { !excludedProps.contains(it.name) && it.type != Set.class }
+ Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+ props.eachWithIndex { p,i ->
+ if(i < 6) {
+ if(!p.type.name.startsWith('org.joda.time') && p.isAssociation()) { %>
+ <th>${p.naturalName}</th>
+ <% } else { %>
+ <g:sortableColumn property="${p.name}" title="${p.naturalName}" />
+ <% } } } %>
+ </tr>
+ </thead>
+ <tbody>
+ <g:each in="\${${propertyName}List}" status="i" var="${propertyName}">
+ <tr class="\${(i % 2) == 0 ? 'odd' : 'even'}">
+ <% props.eachWithIndex { p,i ->
+ if(i == 0) { %>
+ <td><g:link action="show" id="\${${propertyName}.id}">\${fieldValue(bean:${propertyName}, field:'${p.name}')}</g:link></td>
+ <% } else if(i < 6) { %>
+ <td>\${fieldValue(bean:${propertyName}, field:'${p.name}')}</td>
+ <% } } %>
+ </tr>
+ </g:each>
+ </tbody>
+ </table>
+ </div>
+ <div class="paginateButtons">
+ <g:paginate total="\${${propertyName}Total}" />
+ </div>
+ </div>
+ </body>
+</html>
View
281 src/templates/scaffolding/renderEditor.template
@@ -0,0 +1,281 @@
+<% if(property.type == Boolean.class || property.type == boolean.class)
+ out << renderBooleanEditor(domainClass,property)
+ else if(Number.class.isAssignableFrom(property.type) || (property.type.isPrimitive() && property.type != boolean.class))
+ out << renderNumberEditor(domainClass,property)
+ else if(property.type == String.class)
+ out << renderStringEditor(domainClass,property)
+ else if(property.type == Date.class || property.type == java.sql.Date.class || property.type == java.sql.Time.class)
+ out << renderDateEditor(domainClass,property)
+ else if(property.type == Calendar.class)
+ out << renderDateEditor(domainClass,property)
+ else if(org.joda.time.ReadableInstant.class.isAssignableFrom(property.type) || property.type == org.joda.time.LocalDateTime.class)
+ out << renderJodaDateTimeEditor(domainClass,property)
+ else if(property.type == org.joda.time.LocalDate.class)
+ out << renderJodaDateEditor(domainClass,property)
+ else if(property.type == org.joda.time.LocalTime.class)
+ out << renderJodaTimeEditor(domainClass,property)
+ else if(property.type == org.joda.time.Period.class || property.type == org.joda.time.Duration.class)
+ out << renderJodaPeriodEditor(domainClass,property)
+ else if(property.type == URL.class)
+ out << renderStringEditor(domainClass,property)
+ else if(property.isEnum())
+ out << renderEnumEditor(domainClass,property)
+ else if(property.type == TimeZone.class)
+ out << renderSelectTypeEditor("timeZone",domainClass,property)
+ else if(property.type == Locale.class)
+ out << renderSelectTypeEditor("locale",domainClass,property)
+ else if(property.type == Currency.class)
+ out << renderSelectTypeEditor("currency",domainClass,property)
+ else if(property.type==([] as Byte[]).class) //TODO: Bug in groovy means i have to do this :(
+ out << renderByteArrayEditor(domainClass,property)
+ else if(property.type==([] as byte[]).class) //TODO: Bug in groovy means i have to do this :(
+ out << renderByteArrayEditor(domainClass,property)
+ else if(property.manyToOne || property.oneToOne)
+ out << renderManyToOne(domainClass,property)
+ else if((property.oneToMany && !property.bidirectional) || (property.manyToMany && property.isOwningSide()))
+ out << renderManyToMany(domainClass, property)
+ else if(property.oneToMany)
+ out << renderOneToMany(domainClass,property)
+
+ private renderEnumEditor(domainClass,property) {
+ if(property.isEnum()) {
+ return "<g:select from=\"\${${property.type.name}?.values()}\" value=\"\${${domainInstance}?.${property.name}}\" name=\"${property.name}\" ${renderNoSelection(property)}></g:select>"
+ }
+ }
+
+ private renderStringEditor(domainClass, property) {
+ if(!cp) {
+ return "<input type=\"text\" name=\"${property.name}\" id=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\" />"
+ }
+ else {
+ if("textarea" == cp.widget || (cp.maxSize > 250 && !cp.password && !cp.inList)) {
+ return "<textarea rows=\"5\" cols=\"40\" name=\"${property.name}\">\${fieldValue(bean:${domainInstance}, field:'${property.name}')}</textarea>"
+ }
+ else {
+ if(cp.inList) {
+ def sb = new StringBuffer('<g:select ')
+ sb << "id=\"${property.name}\" name=\"${property.name}\" from=\"\${${domainInstance}.constraints.${property.name}.inList}\" value=\"\${${domainInstance}.${property?.name}}\" ${renderNoSelection(property)}>"
+ sb << '</g:select>'
+ return sb.toString()
+ }
+ else {
+ def sb = new StringBuffer('<input ')
+ cp.password ? sb << 'type="password" ' : sb << 'type="text" '
+ if(!cp.editable) sb << 'readonly="readonly" '
+ if(cp.maxSize) sb << "maxlength=\"${cp.maxSize}\" "
+ sb << "id=\"${property.name}\" name=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\"/>"
+ return sb.toString()
+ }
+ }
+ }
+ }
+
+ private renderByteArrayEditor(domainClass,property) {
+ return "<input type=\"file\" id=\"${property.name}\" name=\"${property.name}\" />"
+ }
+
+ private renderManyToOne(domainClass,property) {
+ if(property.association) {
+ return "<g:select optionKey=\"id\" from=\"\${${property.type.name}.list()}\" name=\"${property.name}.id\" value=\"\${${domainInstance}?.${property.name}?.id}\" ${renderNoSelection(property)}></g:select>"
+ }
+ }
+
+ private renderManyToMany(domainClass,property) {
+ def sw = new StringWriter()
+ def pw = new PrintWriter(sw)
+
+ pw.println "<g:select name=\"${property.name}\""
+ pw.println "from=\"\${${property.referencedDomainClass.fullName}.list()}\""
+ pw.println "size=\"5\" multiple=\"yes\" optionKey=\"id\""
+ pw.println "value=\"\${${domainInstance}?.${property.name}}\" />"
+
+ return sw.toString()
+ }
+
+ private renderOneToMany(domainClass,property) {
+ def sw = new StringWriter()
+ def pw = new PrintWriter(sw)
+ pw.println()
+ pw.println "<ul>"
+ pw.println "<g:each var=\"${property.name[0]}\" in=\"\${${domainInstance}?.${property.name}?}\">"
+ pw.println " <li><g:link controller=\"${property.referencedDomainClass.propertyName}\" action=\"show\" id=\"\${${property.name[0]}.id}\">\${${property.name[0]}?.encodeAsHTML()}</g:link></li>"
+ pw.println "</g:each>"
+ pw.println "</ul>"
+ pw.println "<g:link controller=\"${property.referencedDomainClass.propertyName}\" params=\"['${domainClass.propertyName}.id':${domainInstance}?.id]\" action=\"create\">Add ${property.referencedDomainClass.shortName}</g:link>"
+ return sw.toString()
+ }
+
+ private renderNumberEditor(domainClass,property) {
+ if(!cp) {
+ if(property.type == Byte.class) {
+ return "<g:select from=\"\${-128..127}\" name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:select>"
+ }
+ else {
+ return "<input type=\"text\" id=\"${property.name}\" name=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\" />"
+ }
+ }
+ else {
+ if(cp.range) {
+ return "<g:select from=\"\${${cp.range.from}..${cp.range.to}}\" id=\"${property.name}\" name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></g:select>"
+ }
+ else if(cp.inList) {
+ def sb = new StringBuffer('<g:select ')
+ sb << "id=\"${property.name}\" name=\"${property.name}\" from=\"\${${domainClass.propertyName}.constraints.${property.name}.inList}\" value=\"\${${domainClass.propertyName}.${property?.name}}\" ${renderNoSelection(property)}>"
+ sb << '</g:select>'
+ return sb.toString()
+ }
+ else {
+ return "<input type=\"text\" id=\"${property.name}\" name=\"${property.name}\" value=\"\${fieldValue(bean:${domainInstance},field:'${property.name}')}\" />"
+ }
+ }
+ }
+
+ private renderBooleanEditor(domainClass,property) {
+ if(!cp) {
+ return "<g:checkBox name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:checkBox>"
+ }
+ else {
+ def buf = new StringBuffer('<g:checkBox ')
+ if(cp.widget) buf << "widget=\"${cp.widget}\"";
+
+ buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" "
+ cp.attributes.each { k,v ->
+ buf << "${k}=\"${v}\" "
+ }
+ buf << '></g:checkBox>'
+ return buf.toString()
+ }
+ }
+
+ private renderDateEditor(domainClass,property) {
+ if(!cp) {
+ return "<g:datePicker name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:datePicker>"
+ }
+ else {
+ if(!cp.editable) {
+ return "\${${domainInstance}?.${property.name}?.toString()}"
+ }
+ else {
+ def buf = new StringBuffer('<g:datePicker ')
+ if(cp.widget) buf << "widget=\"${cp.widget}\" "
+ if(cp.format) buf << "format=\"${cp.format}\" "
+ cp.attributes.each { k,v ->
+ buf << "${k}=\"${v}\" "
+ }
+ buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></g:datePicker>"
+ return buf.toString()
+ }
+ }
+ }
+
+ private renderJodaDateTimeEditor(domainClass,property) {
+ if(!cp) {
+ return "<joda:dateTimePicker name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></joda:dateTimePicker>"
+ }
+ else {
+ if(!cp.editable) {
+ return "\${${domainInstance}?.${property.name}?.toString()}"
+ }
+ else {
+ def buf = new StringBuffer('<joda:dateTimePicker ')
+ if(cp.widget) buf << "widget=\"${cp.widget}\" "
+ if(cp.format) buf << "format=\"${cp.format}\" "
+ cp.attributes.each { k,v ->
+ buf << "${k}=\"${v}\" "
+ }
+ buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></joda:dateTimePicker>"
+ return buf.toString()
+ }
+ }
+ }
+
+ private renderJodaDateEditor(domainClass,property) {
+ if(!cp) {
+ return "<joda:datePicker name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></joda:datePicker>"
+ }
+ else {
+ if(!cp.editable) {
+ return "\${${domainInstance}?.${property.name}?.toString()}"
+ }
+ else {
+ def buf = new StringBuffer('<joda:datePicker ')
+ if(cp.widget) buf << "widget=\"${cp.widget}\" "
+ if(cp.format) buf << "format=\"${cp.format}\" "
+ cp.attributes.each { k,v ->
+ buf << "${k}=\"${v}\" "
+ }
+ buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></joda:datePicker>"
+ return buf.toString()
+ }
+ }
+ }
+
+ private renderJodaTimeEditor(domainClass,property) {
+ if(!cp) {
+ return "<joda:timePicker name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></joda:timePicker>"
+ }
+ else {
+ if(!cp.editable) {
+ return "\${${domainInstance}?.${property.name}?.toString()}"
+ }
+ else {
+ def buf = new StringBuffer('<joda:timePicker ')
+ if(cp.widget) buf << "widget=\"${cp.widget}\" "
+ if(cp.format) buf << "format=\"${cp.format}\" "
+ cp.attributes.each { k,v ->
+ buf << "${k}=\"${v}\" "
+ }
+ buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></joda:timePicker>"
+ return buf.toString()
+ }
+ }
+ }
+
+ private renderJodaPeriodEditor(domainClass,property) {
+ if(!cp) {
+ return "<joda:periodPicker name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></joda:periodPicker>"
+ }
+ else {
+ if(!cp.editable) {
+ return "\${${domainInstance}?.${property.name}?.toString()}"
+ }
+ else {
+ def buf = new StringBuffer('<joda:periodPicker ')
+ if(cp.widget) buf << "widget=\"${cp.widget}\" "
+ if(cp.format) buf << "format=\"${cp.format}\" "
+ cp.attributes.each { k,v ->
+ buf << "${k}=\"${v}\" "
+ }
+ buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></joda:periodPicker>"
+ return buf.toString()
+ }
+ }
+ }
+
+ private renderSelectTypeEditor(type,domainClass,property) {
+ if(!cp) {
+ return "<g:${type}Select name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\"></g:${type}Select>"
+ }
+ else {
+ def buf = new StringBuffer("<g:${type}Select ")
+ if(cp.widget) buf << "widget=\"${cp.widget}\" ";
+ cp.attributes.each { k,v ->
+ buf << "${k}=\"${v}\" "
+ }
+ buf << "name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)}></g:${type}Select>"
+ return buf.toString()
+ }
+ }
+
+ private renderNoSelection(property) {
+ if(property.optional) {
+ if(property.manyToOne || property.oneToOne) {
+ return "noSelection=\"['null':'']\""
+ }
+ else {
+ return "noSelection=\"['':'']\""
+ }
+ }
+ return ""
+ }
+%>
View
66 src/templates/scaffolding/show.gsp
@@ -0,0 +1,66 @@
+<% import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events %>
+<%=packageName%>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <meta name="layout" content="main" />
+ <title>Show ${className}</title>
+ </head>
+ <body>
+ <div class="nav">
+ <span class="menuButton"><a class="home" href="\${createLinkTo(dir:'')}">Home</a></span>
+ <span class="menuButton"><g:link class="list" action="list">${className} List</g:link></span>
+ <span class="menuButton"><g:link class="create" action="create">New ${className}</g:link></span>
+ </div>
+ <div class="body">
+ <h1>Show ${className}</h1>
+ <g:if test="\${flash.message}">
+ <div class="message">\${flash.message}</div>
+ </g:if>
+ <div class="dialog">
+ <table>
+ <tbody>
+
+ <%
+ excludedProps = ['version',
+ Events.ONLOAD_EVENT,
+ Events.BEFORE_DELETE_EVENT,
+ Events.BEFORE_INSERT_EVENT,
+ Events.BEFORE_UPDATE_EVENT]
+ props = domainClass.properties.findAll { !excludedProps.contains(it.name) }
+ Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+ props.each { p -> %>
+ <tr class="prop">
+ <td valign="top" class="name">${p.naturalName}:</td>
+ <% if(p.type in [org.joda.time.LocalTime, org.joda.time.LocalDate, org.joda.time.LocalDateTime, org.joda.time.DateTime ]) { %>
+ <td valign="top" class="value">\${fieldValue(bean:${propertyName}, field:'${p.name}')}</td>
+ <% } else if(p.isEnum()) { %>
+ <td valign="top" class="value">\${${propertyName}?.${p.name}?.encodeAsHTML()}</td>
+ <% } else if(p.oneToMany || p.manyToMany) { %>
+ <td valign="top" style="text-align:left;" class="value">
+ <ul>
+ <g:each var="${p.name[0]}" in="\${${propertyName}.${p.name}}">
+ <li><g:link controller="${p.referencedDomainClass?.propertyName}" action="show" id="\${${p.name[0]}.id}">\${${p.name[0]}?.encodeAsHTML()}</g:link></li>
+ </g:each>
+ </ul>
+ </td>
+ <% } else if(p.manyToOne || p.oneToOne) { %>
+ <td valign="top" class="value"><g:link controller="${p.referencedDomainClass?.propertyName}" action="show" id="\${${propertyName}?.${p.name}?.id}">\${${propertyName}?.${p.name}?.encodeAsHTML()}</g:link></td>
+ <% } else { %>
+ <td valign="top" class="value">\${fieldValue(bean:${propertyName}, field:'${p.name}')}</td>
+ <% } %>
+ </tr>
+ <% } %>
+ </tbody>
+ </table>
+ </div>
+ <div class="buttons">
+ <g:form>
+ <input type="hidden" name="id" value="\${${propertyName}?.id}" />
+ <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
+ <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
+ </g:form>
+ </div>
+ </div>
+ </body>
+</html>
View
102 src/templates/war/web.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.4"
+ xmlns="http://java.sun.com/xml/ns/j2ee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+ <display-name>/@grails.project.key@</display-name>
+
+
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>/WEB-INF/applicationContext.xml</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>webAppRootKey</param-name>
+ <param-value>@grails.project.key@</param-value>
+ </context-param>
+
+ <filter>
+ <filter-name>sitemesh</filter-name>
+ <filter-class>org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter</filter-class>
+ </filter>
+
+ <filter>
+ <filter-name>charEncodingFilter</filter-name>
+ <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
+ <init-param>
+ <param-name>targetBeanName</param-name>
+ <param-value>characterEncodingFilter</param-value>
+ </init-param>
+ <init-param>
+ <param-name>targetFilterLifecycle</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>charEncodingFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <filter-mapping>
+ <filter-name>sitemesh</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <listener>
+ <listener-class>org.codehaus.groovy.grails.web.util.Log4jConfigListener</listener-class>
+ </listener>
+
+ <listener>
+ <listener-class>org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener</listener-class>
+ </listener>
+
+ <!-- Grails dispatcher servlet -->
+ <servlet>
+ <servlet-name>grails</servlet-name>
+ <servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <!-- The Groovy Server Pages servlet -->
+ <servlet>
+ <servlet-name>gsp</servlet-name>
+ <servlet-class>org.codehaus.groovy.grails.web.pages.GroovyPagesServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>gsp</servlet-name>
+ <url-pattern>*.gsp</url-pattern>
+ </servlet-mapping>
+
+ <welcome-file-list>
+ <!--
+ The order of the welcome pages is important. JBoss deployment will
+ break if index.gsp is first in the list.
+ -->
+ <welcome-file>index.html</welcome-file>
+ <welcome-file>index.jsp</welcome-file>
+ <welcome-file>index.gsp</welcome-file>
+ </welcome-file-list>
+
+ <jsp-config>
+ <taglib>
+ <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
+ <taglib-location>/WEB-INF/tld/c.tld</taglib-location>
+ </taglib>
+ <taglib>
+ <taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
+ <taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
+ </taglib>
+ <taglib>
+ <taglib-uri>http://www.springframework.org/tags</taglib-uri>
+ <taglib-location>/WEB-INF/tld/spring.tld</taglib-location>
+ </taglib>
+ <taglib>
+ <taglib-uri>http://grails.codehaus.org/tags</taglib-uri>
+ <taglib-location>/WEB-INF/tld/grails.tld</taglib-location>
+ </taglib>
+ </jsp-config>
+
+</web-app>
Please sign in to comment.
Something went wrong with that request. Please try again.