Skip to content
Browse files

a helper for getting bindable properties of domain types

  • Loading branch information...
1 parent c82c8b5 commit 1ca62c87457c1fe9a9999090c89fbd19d19dd3f9 Rob Fletcher committed Jun 11, 2012
View
1 .gitignore
@@ -10,6 +10,7 @@
.DS_Store
# IntelliJ project files
+/.idea
/*.iws
/*.iml
/*.ipr
View
3 TODO.md
@@ -0,0 +1,3 @@
+- i18n
+- flash messages
+- use proper REST URL scheme
View
6 grails-app/conf/BuildConfig.groovy
@@ -21,10 +21,14 @@ grails.project.dependency.resolution = {
}
runtime(":hibernate:$grailsVersion",
- ':resources:1.0-RC2',
+ ':resources:1.1.6',
':jquery:1.7.2',
':ember:0.9.8.1') {
export = false
}
+
+ test(':spock:0.6') {
+ export = false
+ }
}
}
View
23 src/groovy/grails/plugin/emberscaffolding/ScaffoldingHelper.groovy
@@ -0,0 +1,23 @@
+package grails.plugin.emberscaffolding
+
+import org.codehaus.groovy.grails.web.binding.DefaultASTDatabindingHelper
+
+class ScaffoldingHelper {
+
+ static List<String> getBindableProperties(Class domainClass) {
+ domainClass."$DefaultASTDatabindingHelper.DEFAULT_DATABINDING_WHITELIST".findAll {
+ !it.endsWith('_*')
+ }
+ }
+
+ static Map<String, Object> getBindablePropertyValues(domainInstance) {
+ domainInstance.properties.getAt(getBindableProperties(domainInstance.getClass()))
+ }
+
+ static Collection<Map<String, Object>> getBindablePropertyValues(Collection domainInstances) {
+ domainInstances.collect {
+ getBindablePropertyValues(it)
+ }
+ }
+
+}
View
182 src/templates/scaffolding/Controller.groovy
@@ -1,101 +1,103 @@
<%=packageName ? "package ${packageName}\n\n" : ''%>import org.springframework.dao.DataIntegrityViolationException
+import grails.converters.JSON
+import grails.plugin.emberscaffolding.ScaffoldingHelper
class ${className}Controller {
- static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
+ static scaffold = true
- def index() {
- redirect(action: "list", params: params)
- }
+ static allowedMethods = [save: 'POST', update: 'POST', delete: 'POST']
+
+ def index() {}
def list() {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
- [${propertyName}List: ${className}.list(params), ${propertyName}Total: ${className}.count()]
- }
-
- def create() {
- [${propertyName}: new ${className}(params)]
+ render ScaffoldingHelper.getBindablePropertyValues(${className}.list(params)) as JSON
}
- def save() {
- def ${propertyName} = new ${className}(params)
- if (!${propertyName}.save(flush: true)) {
- render(view: "create", model: [${propertyName}: ${propertyName}])
- return
- }
-
- flash.message = message(code: 'default.created.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
- redirect(action: "show", id: ${propertyName}.id)
- }
-
- def show() {
- def ${propertyName} = ${className}.get(params.id)
- if (!${propertyName}) {
- flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
- redirect(action: "list")
- return
- }
-
- [${propertyName}: ${propertyName}]
- }
-
- def edit() {
- def ${propertyName} = ${className}.get(params.id)
- if (!${propertyName}) {
- flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
- redirect(action: "list")
- return
- }
-
- [${propertyName}: ${propertyName}]
- }
-
- def update() {
- def ${propertyName} = ${className}.get(params.id)
- if (!${propertyName}) {
- flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
- redirect(action: "list")
- return
- }
-
- if (params.version) {
- def version = params.version.toLong()
- if (${propertyName}.version > version) {<% def lowerCaseName = grails.util.GrailsNameUtils.getPropertyName(className) %>
- ${propertyName}.errors.rejectValue("version", "default.optimistic.locking.failure",
- [message(code: '${domainClass.propertyName}.label', default: '${className}')] as Object[],
- "Another user has updated this ${className} while you were editing")
- render(view: "edit", model: [${propertyName}: ${propertyName}])
- return
- }
- }
-
- ${propertyName}.properties = params
-
- if (!${propertyName}.save(flush: true)) {
- render(view: "edit", model: [${propertyName}: ${propertyName}])
- return
- }
-
- flash.message = message(code: 'default.updated.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
- redirect(action: "show", id: ${propertyName}.id)
- }
-
- def delete() {
- def ${propertyName} = ${className}.get(params.id)
- if (!${propertyName}) {
- flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
- redirect(action: "list")
- return
- }
-
- try {
- ${propertyName}.delete(flush: true)
- flash.message = message(code: 'default.deleted.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
- redirect(action: "list")
- }
- catch (DataIntegrityViolationException e) {
- flash.message = message(code: 'default.not.deleted.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
- redirect(action: "show", id: params.id)
- }
- }
+// def create() {
+// [${propertyName}: new ${className}(params)]
+// }
+//
+// def save() {
+// def ${propertyName} = new ${className}(params)
+// if (!${propertyName}.save(flush: true)) {
+// render(view: "create", model: [${propertyName}: ${propertyName}])
+// return
+// }
+//
+// flash.message = message(code: 'default.created.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
+// redirect(action: "show", id: ${propertyName}.id)
+// }
+//
+// def show() {
+// def ${propertyName} = ${className}.get(params.id)
+// if (!${propertyName}) {
+// flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
+// redirect(action: "list")
+// return
+// }
+//
+// [${propertyName}: ${propertyName}]
+// }
+//
+// def edit() {
+// def ${propertyName} = ${className}.get(params.id)
+// if (!${propertyName}) {
+// flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
+// redirect(action: "list")
+// return
+// }
+//
+// [${propertyName}: ${propertyName}]
+// }
+//
+// def update() {
+// def ${propertyName} = ${className}.get(params.id)
+// if (!${propertyName}) {
+// flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
+// redirect(action: "list")
+// return
+// }
+//
+// if (params.version) {
+// def version = params.version.toLong()
+// if (${propertyName}.version > version) {<% def lowerCaseName = grails.util.GrailsNameUtils.getPropertyName(className) %>
+// ${propertyName}.errors.rejectValue("version", "default.optimistic.locking.failure",
+// [message(code: '${domainClass.propertyName}.label', default: '${className}')] as Object[],
+// "Another user has updated this ${className} while you were editing")
+// render(view: "edit", model: [${propertyName}: ${propertyName}])
+// return
+// }
+// }
+//
+// ${propertyName}.properties = params
+//
+// if (!${propertyName}.save(flush: true)) {
+// render(view: "edit", model: [${propertyName}: ${propertyName}])
+// return
+// }
+//
+// flash.message = message(code: 'default.updated.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
+// redirect(action: "show", id: ${propertyName}.id)
+// }
+//
+// def delete() {
+// def ${propertyName} = ${className}.get(params.id)
+// if (!${propertyName}) {
+// flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
+// redirect(action: "list")
+// return
+// }
+//
+// try {
+// ${propertyName}.delete(flush: true)
+// flash.message = message(code: 'default.deleted.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
+// redirect(action: "list")
+// }
+// catch (DataIntegrityViolationException e) {
+// flash.message = message(code: 'default.not.deleted.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
+// redirect(action: "show", id: params.id)
+// }
+// }
}
View
157 src/templates/scaffolding/Test.groovy
@@ -1,157 +0,0 @@
-<%=packageName ? "package ${packageName}\n\n" : ''%>
-
-import org.junit.*
-import grails.test.mixin.*
-
-@TestFor(${className}Controller)
-@Mock(${className})
-class ${className}ControllerTests {
-
-
- def populateValidParams(params) {
- assert params != null
- // TODO: Populate valid properties like...
- //params["name"] = 'someValidName'
- }
-
- void testIndex() {
- controller.index()
- assert "/$propertyName/list" == response.redirectedUrl
- }
-
- void testList() {
-
- def model = controller.list()
-
- assert model.${propertyName}InstanceList.size() == 0
- assert model.${propertyName}InstanceTotal == 0
- }
-
- void testCreate() {
- def model = controller.create()
-
- assert model.${propertyName}Instance != null
- }
-
- void testSave() {
- controller.save()
-
- assert model.${propertyName}Instance != null
- assert view == '/${propertyName}/create'
-
- response.reset()
-
- populateValidParams(params)
- controller.save()
-
- assert response.redirectedUrl == '/${propertyName}/show/1'
- assert controller.flash.message != null
- assert ${className}.count() == 1
- }
-
- void testShow() {
- controller.show()
-
- assert flash.message != null
- assert response.redirectedUrl == '/${propertyName}/list'
-
-
- populateValidParams(params)
- def ${propertyName} = new ${className}(params)
-
- assert ${propertyName}.save() != null
-
- params.id = ${propertyName}.id
-
- def model = controller.show()
-
- assert model.${propertyName}Instance == ${propertyName}
- }
-
- void testEdit() {
- controller.edit()
-
- assert flash.message != null
- assert response.redirectedUrl == '/${propertyName}/list'
-
-
- populateValidParams(params)
- def ${propertyName} = new ${className}(params)
-
- assert ${propertyName}.save() != null
-
- params.id = ${propertyName}.id
-
- def model = controller.edit()
-
- assert model.${propertyName}Instance == ${propertyName}
- }
-
- void testUpdate() {
- controller.update()
-
- assert flash.message != null
- assert response.redirectedUrl == '/${propertyName}/list'
-
- response.reset()
-
-
- populateValidParams(params)
- def ${propertyName} = new ${className}(params)
-
- assert ${propertyName}.save() != null
-
- // test invalid parameters in update
- params.id = ${propertyName}.id
- //TODO: add invalid values to params object
-
- controller.update()
-
- assert view == "/${propertyName}/edit"
- assert model.${propertyName}Instance != null
-
- ${propertyName}.clearErrors()
-
- populateValidParams(params)
- controller.update()
-
- assert response.redirectedUrl == "/${propertyName}/show/\$${propertyName}.id"
- assert flash.message != null
-
- //test outdated version number
- response.reset()
- ${propertyName}.clearErrors()
-
- populateValidParams(params)
- params.id = ${propertyName}.id
- params.version = -1
- controller.update()
-
- assert view == "/${propertyName}/edit"
- assert model.${propertyName}Instance != null
- assert model.${propertyName}Instance.errors.getFieldError('version')
- assert flash.message != null
- }
-
- void testDelete() {
- controller.delete()
- assert flash.message != null
- assert response.redirectedUrl == '/${propertyName}/list'
-
- response.reset()
-
- populateValidParams(params)
- def ${propertyName} = new ${className}(params)
-
- assert ${propertyName}.save() != null
- assert ${className}.count() == 1
-
- params.id = ${propertyName}.id
-
- controller.delete()
-
- assert ${className}.count() == 0
- assert ${className}.get(${propertyName}.id) == null
- assert response.redirectedUrl == '/${propertyName}/list'
- }
-}
View
44 src/templates/scaffolding/_form.gsp
@@ -1,44 +0,0 @@
-<%=packageName%>
-<% import grails.persistence.Event %>
-
-<% excludedProps = Event.allEvents.toList() << 'version' << 'dateCreated' << 'lastUpdated'
- persistentPropNames = domainClass.persistentProperties*.name
- boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate')
- if (hasHibernate && org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder.getMapping(domainClass)?.identity?.generator == 'assigned') {
- persistentPropNames << domainClass.identifier.name
- }
- props = domainClass.properties.findAll { persistentPropNames.contains(it.name) && !excludedProps.contains(it.name) }
- Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
- for (p in props) {
- if (p.embedded) {
- def embeddedPropNames = p.component.persistentProperties*.name
- def embeddedProps = p.component.properties.findAll { embeddedPropNames.contains(it.name) && !excludedProps.contains(it.name) }
- Collections.sort(embeddedProps, comparator.constructors[0].newInstance([p.component] as Object[]))
- %><fieldset class="embedded"><legend><g:message code="${domainClass.propertyName}.${p.name}.label" default="${p.naturalName}" /></legend><%
- for (ep in p.component.properties) {
- renderFieldForProperty(ep, p.component, "${p.name}.")
- }
- %></fieldset><%
- } else {
- renderFieldForProperty(p, domainClass)
- }
- }
-
-private renderFieldForProperty(p, owningClass, prefix = "") {
- boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate')
- boolean display = true
- boolean required = false
- if (hasHibernate) {
- cp = owningClass.constrainedProperties[p.name]
- display = (cp ? cp.display : true)
- required = (cp ? !(cp.propertyType in [boolean, Boolean]) && !cp.nullable && (cp.propertyType != String || !cp.blank) : false)
- }
- if (display) { %>
-<div class="fieldcontain \${hasErrors(bean: ${propertyName}, field: '${prefix}${p.name}', 'error')} ${required ? 'required' : ''}">
- <label for="${prefix}${p.name}">
- <g:message code="${domainClass.propertyName}.${prefix}${p.name}.label" default="${p.naturalName}" />
- <% if (required) { %><span class="required-indicator">*</span><% } %>
- </label>
- ${renderEditor(p)}
-</div>
-<% } } %>
View
39 src/templates/scaffolding/create.gsp
@@ -1,39 +0,0 @@
-<%=packageName%>
-<!doctype html>
-<html>
- <head>
- <meta name="layout" content="main">
- <g:set var="entityName" value="\${message(code: '${domainClass.propertyName}.label', default: '${className}')}" />
- <title><g:message code="default.create.label" args="[entityName]" /></title>
- </head>
- <body>
- <a href="#create-${domainClass.propertyName}" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content&hellip;"/></a>
- <div class="nav" role="navigation">
- <ul>
- <li><a class="home" href="\${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
- <li><g:link class="list" action="list"><g:message code="default.list.label" args="[entityName]" /></g:link></li>
- </ul>
- </div>
- <div id="create-${domainClass.propertyName}" class="content scaffold-create" role="main">
- <h1><g:message code="default.create.label" args="[entityName]" /></h1>
- <g:if test="\${flash.message}">
- <div class="message" role="status">\${flash.message}</div>
- </g:if>
- <g:hasErrors bean="\${${propertyName}}">
- <ul class="errors" role="alert">
- <g:eachError bean="\${${propertyName}}" var="error">
- <li <g:if test="\${error in org.springframework.validation.FieldError}">data-field-id="\${error.field}"</g:if>><g:message error="\${error}"/></li>
- </g:eachError>
- </ul>
- </g:hasErrors>
- <g:form action="save" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
- <fieldset class="form">
- <g:render template="form"/>
- </fieldset>
- <fieldset class="buttons">
- <g:submitButton name="create" class="save" value="\${message(code: 'default.button.create.label', default: 'Create')}" />
- </fieldset>
- </g:form>
- </div>
- </body>
-</html>
View
43 src/templates/scaffolding/edit.gsp
@@ -1,43 +0,0 @@
-<%=packageName%>
-<!doctype html>
-<html>
- <head>
- <meta name="layout" content="main">
- <g:set var="entityName" value="\${message(code: '${domainClass.propertyName}.label', default: '${className}')}" />
- <title><g:message code="default.edit.label" args="[entityName]" /></title>
- </head>
- <body>
- <a href="#edit-${domainClass.propertyName}" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content&hellip;"/></a>
- <div class="nav" role="navigation">
- <ul>
- <li><a class="home" href="\${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
- <li><g:link class="list" action="list"><g:message code="default.list.label" args="[entityName]" /></g:link></li>
- <li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
- </ul>
- </div>
- <div id="edit-${domainClass.propertyName}" class="content scaffold-edit" role="main">
- <h1><g:message code="default.edit.label" args="[entityName]" /></h1>
- <g:if test="\${flash.message}">
- <div class="message" role="status">\${flash.message}</div>
- </g:if>
- <g:hasErrors bean="\${${propertyName}}">
- <ul class="errors" role="alert">
- <g:eachError bean="\${${propertyName}}" var="error">
- <li <g:if test="\${error in org.springframework.validation.FieldError}">data-field-id="\${error.field}"</g:if>><g:message error="\${error}"/></li>
- </g:eachError>
- </ul>
- </g:hasErrors>
- <g:form method="post" <%= multiPart ? ' enctype="multipart/form-data"' : '' %>>
- <g:hiddenField name="id" value="\${${propertyName}?.id}" />
- <g:hiddenField name="version" value="\${${propertyName}?.version}" />
- <fieldset class="form">
- <g:render template="form"/>
- </fieldset>
- <fieldset class="buttons">
- <g:actionSubmit class="save" action="update" value="\${message(code: 'default.button.update.label', default: 'Update')}" />
- <g:actionSubmit class="delete" action="delete" value="\${message(code: 'default.button.delete.label', default: 'Delete')}" formnovalidate="" onclick="return confirm('\${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" />
- </fieldset>
- </g:form>
- </div>
- </body>
-</html>
View
25 src/templates/scaffolding/index.gsp
@@ -0,0 +1,25 @@
+<% import grails.persistence.Event %>
+<%=packageName%>
+<!doctype html>
+<html>
+ <head>
+ <meta name="layout" content="main">
+ <g:set var="entityName" value="\${message(code: '${domainClass.propertyName}.label', default: '${className}')}" />
+ <title>\${entityName}</title>
+ <r:require module="ember"/>
+ </head>
+ <body>
+ <div class="nav" role="navigation">
+ <ul>
+ <li><a class="home" href="\${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
+ <li><g:link class="list" action="list"><g:message code="default.list.label" args="[entityName]" /></g:link></li>
+ <li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
+ </ul>
+ </div>
+ <div class="content" role="main">
+ </div>
+ <script type="text/x-handlebars" data-template-name="\${entityName}-list">
+ <g:include view="list.handlebars"/>
+ </script>
+ </body>
+</html>
View
62 src/templates/scaffolding/list.gsp
@@ -1,62 +0,0 @@
-<% import grails.persistence.Event %>
-<%=packageName%>
-<!doctype html>
-<html>
- <head>
- <meta name="layout" content="main">
- <g:set var="entityName" value="\${message(code: '${domainClass.propertyName}.label', default: '${className}')}" />
- <title><g:message code="default.list.label" args="[entityName]" /></title>
- </head>
- <body>
- <a href="#list-${domainClass.propertyName}" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content&hellip;"/></a>
- <div class="nav" role="navigation">
- <ul>
- <li><a class="home" href="\${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
- <li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
- </ul>
- </div>
- <div id="list-${domainClass.propertyName}" class="content scaffold-list" role="main">
- <h1><g:message code="default.list.label" args="[entityName]" /></h1>
- <g:if test="\${flash.message}">
- <div class="message" role="status">\${flash.message}</div>
- </g:if>
- <table>
- <thead>
- <tr>
- <% excludedProps = Event.allEvents.toList() << 'id' << 'version'
- allowedNames = domainClass.persistentProperties*.name << 'dateCreated' << 'lastUpdated'
- props = domainClass.properties.findAll { allowedNames.contains(it.name) && !excludedProps.contains(it.name) && it.type != null && !Collection.isAssignableFrom(it.type) }
- Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
- props.eachWithIndex { p, i ->
- if (i < 6) {
- if (p.isAssociation()) { %>
- <th><g:message code="${domainClass.propertyName}.${p.name}.label" default="${p.naturalName}" /></th>
- <% } else { %>
- <g:sortableColumn property="${p.name}" title="\${message(code: '${domainClass.propertyName}.${p.name}.label', default: '${p.naturalName}')}" />
- <% } } } %>
- </tr>
- </thead>
- <tbody>
- <g:each in="\${${propertyName}List}" status="i" var="${propertyName}">
- <tr class="\${(i % 2) == 0 ? 'even' : 'odd'}">
- <% 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) {
- if (p.type == Boolean || p.type == boolean) { %>
- <td><g:formatBoolean boolean="\${${propertyName}.${p.name}}" /></td>
- <% } else if (p.type == Date || p.type == java.sql.Date || p.type == java.sql.Time || p.type == Calendar) { %>
- <td><g:formatDate date="\${${propertyName}.${p.name}}" /></td>
- <% } else { %>
- <td>\${fieldValue(bean: ${propertyName}, field: "${p.name}")}</td>
- <% } } } %>
- </tr>
- </g:each>
- </tbody>
- </table>
- <div class="pagination">
- <g:paginate total="\${${propertyName}Total}" />
- </div>
- </div>
- </body>
-</html>
View
18 src/templates/scaffolding/list.handlebars
@@ -0,0 +1,18 @@
+<% import grails.persistence.Event %>
+<h1>List</h1>
+<table>
+ <thead>
+ <tr>
+ <% excludedProps = Event.allEvents.toList() << 'id' << 'version'
+ allowedNames = domainClass.persistentProperties*.name << 'dateCreated' << 'lastUpdated'
+ props = domainClass.properties.findAll { allowedNames.contains(it.name) && !excludedProps.contains(it.name) && it.type != null && !Collection.isAssignableFrom(it.type) }
+ Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
+ props.eachWithIndex { p, i ->
+ <th><g:message code="${domainClass.propertyName}.${p.name}.label" default="${p.naturalName}" /></th>
+ } %>
+ </tr>
+ </thead>
+ <tbody>
+ </g:each>
+ </tbody>
+</table>
View
266 src/templates/scaffolding/renderEditor.template
@@ -1,266 +0,0 @@
-<% if (property.type == Boolean || property.type == boolean)
- out << renderBooleanEditor(domainClass, property)
- else if (property.type && Number.isAssignableFrom(property.type) || (property.type?.isPrimitive() && property.type != boolean))
- out << renderNumberEditor(domainClass, property)
- else if (property.type == String)
- out << renderStringEditor(domainClass, property)
- else if (property.type == Date || property.type == java.sql.Date || property.type == java.sql.Time || property.type == Calendar)
- out << renderDateEditor(domainClass, property)
- else if (property.type == URL)
- out << renderStringEditor(domainClass, property)
- else if (property.type && property.isEnum())
- out << renderEnumEditor(domainClass, property)
- else if (property.type == TimeZone)
- out << renderSelectTypeEditor("timeZone", domainClass, property)
- else if (property.type == Locale)
- out << renderSelectTypeEditor("locale", domainClass, property)
- else if (property.type == Currency)
- 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())) {
- def str = renderManyToMany(domainClass, property)
- if(str != null) {
- out << str
- }
- }
- else if (property.oneToMany)
- out << renderOneToMany(domainClass, property)
-
- private renderEnumEditor(domainClass, property) {
- def sb = new StringBuilder("")
- sb << '<g:select name="' << property.name << '"'
- sb << ' from="${' << "${property.type.name}?.values()" << '}"'
- sb << ' keys="${' << property.type.name << '.values()*.name()}"'
- if (isRequired()) sb << ' required=""'
- sb << ' value="${' << "${domainInstance}?.${property.name}?.name()" << '}"'
- sb << renderNoSelection(property)
- sb << '/>'
- sb as String
- }
-
- private renderStringEditor(domainClass, property) {
- if (!cp) {
- return "<g:textField name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" />"
- } else {
- def sb = new StringBuilder("")
- if ("textarea" == cp.widget || (cp.maxSize > 250 && !cp.password && !cp.inList)) {
- sb << '<g:textArea name="' << property.name << '"'
- sb << ' cols="40" rows="5"'
- if (cp.maxSize) sb << ' maxlength="' << cp.maxSize << '"'
- if (isRequired()) sb << ' required=""'
- sb << ' value="${' << "${domainInstance}?.${property.name}" << '}"'
- sb << '/>'
- } else if (cp.inList) {
- sb << '<g:select name="' << property.name << '"'
- sb << ' from="${' << "${domainInstance}.constraints.${property.name}.inList" << '}"'
- if (isRequired()) sb << ' required=""'
- sb << ' value="${' << "${domainInstance}?.${property.name}" << '}"'
- sb << ' valueMessagePrefix="' << "${domainClass.propertyName}.${property.name}" << '"'
- sb << renderNoSelection(property)
- sb << '/>'
- } else {
- if (cp.password) {
- sb << '<g:field type="password"'
- } else if (cp.url) {
- sb << '<g:field type="url"'
- } else if (cp.email) {
- sb << '<g:field type="email"'
- } else {
- sb << '<g:textField'
- }
- sb << ' name="' << property.name << '"'
- if (cp.maxSize) sb << ' maxlength="' << cp.maxSize << '"'
- if (!cp.editable) sb << ' readonly="readonly"'
- if (cp.matches) sb << ' pattern="${' << "${domainInstance}.constraints.${property.name}.matches" << '}"'
- if (isRequired()) sb << ' required=""'
- sb << ' value="${' << "${domainInstance}?.${property.name}" << '}"'
- sb << '/>'
- }
- sb as String
- }
- }
-
- private renderByteArrayEditor(domainClass, property) {
- return "<input type=\"file\" id=\"${property.name}\" name=\"${property.name}\" />"
- }
-
- private renderManyToOne(domainClass,property) {
- if (property.association) {
- def sb = new StringBuilder()
- sb << '<g:select'
- // id is "x" and name is "x.id" as the label will have for="x" and "." in an id will confuse CSS
- sb << ' id="' << property.name << '"'
- sb << ' name="' << property.name << '.id"'
- sb << ' from="${' << property.type.name << '.list()}"'
- sb << ' optionKey="id"'
- if (isRequired()) sb << ' required=""'
- sb << ' value="${' << "${domainInstance}?.${property.name}" << '?.id}"'
- sb << ' class="many-to-one"'
- sb << renderNoSelection(property)
- sb << '/>'
- sb as String
- }
- }
-
- private renderManyToMany(domainClass, property) {
- def cls = property.referencedDomainClass?.clazz
- if(cls == null) {
- if(property.type instanceof Collection) {
- cls = org.springframework.core.GenericCollectionTypeResolver.getCollectionType(property.type)
- }
- }
-
- if(cls != null) {
- def sb = new StringBuilder()
- sb << '<g:select name="' << property.name << '"'
- sb << ' from="${' << cls.name << '.list()}"'
- sb << ' multiple="multiple"'
- sb << ' optionKey="id"'
- sb << ' size="5"'
- if (isRequired()) sb << ' required=""'
- sb << ' value="${' << "${domainInstance}?.${property.name}" << '*.id}"'
- sb << ' class="many-to-many"'
- sb << '/>'
- sb as String
-
- }
-
- }
-
- private renderOneToMany(domainClass, property) {
- def sw = new StringWriter()
- def pw = new PrintWriter(sw)
- pw.println()
- pw.println '<ul class="one-to-many">'
- pw.println "<g:each in=\"\${${domainInstance}?.${property.name}?}\" var=\"${property.name[0]}\">"
- 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 '<li class="add">'
- pw.println "<g:link controller=\"${property.referencedDomainClass.propertyName}\" action=\"create\" params=\"['${domainClass.propertyName}.id': ${domainInstance}?.id]\">\${message(code: 'default.add.label', args: [message(code: '${property.referencedDomainClass.propertyName}.label', default: '${property.referencedDomainClass.shortName}')])}</g:link>"
- pw.println '</li>'
- pw.println '</ul>'
- return sw.toString()
- }
-
- private renderNumberEditor(domainClass, property) {
- if (!cp) {
- if (property.type == Byte) {
- return "<g:select name=\"${property.name}\" from=\"\${-128..127}\" class=\"range\" value=\"\${fieldValue(bean: ${domainInstance}, field: '${property.name}')}\" />"
- } else {
- return "<g:field type=\"number\" name=\"${property.name}\" value=\"\${${domainInstance}.${property.name}}\" />"
- }
- } else {
- def sb = new StringBuilder()
- if (cp.range) {
- sb << '<g:select name="' << property.name << '"'
- sb << ' from="${' << "${cp.range.from}..${cp.range.to}" << '}"'
- sb << ' class="range"'
- if (isRequired()) sb << ' required=""'
- sb << ' value="${' << "fieldValue(bean: ${domainInstance}, field: '${property.name}')" << '}"'
- sb << renderNoSelection(property)
- sb << '/>'
- } else if (cp.inList) {
- sb << '<g:select name="' << property.name << '"'
- sb << ' from="${' << "${domainInstance}.constraints.${property.name}.inList" << '}"'
- if (isRequired()) sb << ' required=""'
- sb << ' value="${' << "fieldValue(bean: ${domainInstance}, field: '${property.name}')" << '}"'
- sb << ' valueMessagePrefix="' << "${domainClass.propertyName}.${property.name}" << '"'
- sb << renderNoSelection(property)
- sb << '/>'
- } else {
- sb << '<g:field type="number" name="' << property.name << '"'
- if (cp.scale != null && cp.scale < 7) sb << ' step="' << BigDecimal.valueOf(1).movePointLeft(cp.scale).toString() << '"'
- else if (property.type in [float, double, Float, Double, BigDecimal]) sb << ' step="any"'
- if (cp.min != null) sb << ' min="' << cp.min << '"'
- if (cp.max != null) sb << ' max="' << cp.max << '"'
- if (isRequired()) sb << ' required=""'
- sb << ' value="${' << domainInstance << '.' << property.name << '}"'
- sb << '/>'
- }
- sb as String
- }
- }
-
- private renderBooleanEditor(domainClass, property) {
- if (!cp) {
- return "<g:checkBox name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" />"
- } else {
- def sb = new StringBuilder("<g:checkBox name=\"${property.name}\" ")
- if (cp.widget) sb << "widget=\"${cp.widget}\" ";
- cp.attributes.each { k, v ->
- sb << "${k}=\"${v}\" "
- }
- sb << "value=\"\${${domainInstance}?.${property.name}}\" />"
- return sb.toString()
- }
- }
-
- private renderDateEditor(domainClass, property) {
- def precision = (property.type == Date || property.type == java.sql.Date || property.type == Calendar) ? "day" : "minute";
- if (!cp) {
- return "<g:datePicker name=\"${property.name}\" precision=\"${precision}\" value=\"\${${domainInstance}?.${property.name}}\" />"
- } else {
- if (!cp.editable) {
- return "\${${domainInstance}?.${property.name}?.toString()}"
- } else {
- def sb = new StringBuilder("<g:datePicker name=\"${property.name}\" ")
- if (cp.format) sb << "format=\"${cp.format}\" "
- if (cp.widget) sb << "widget=\"${cp.widget}\" "
- cp.attributes.each { k, v ->
- sb << "${k}=\"${v}\" "
- }
- if (!cp.attributes.precision){
- sb << "precision=\"${precision}\" "
- }
- sb << " value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)} />"
-
- return sb.toString()
- }
- }
- }
-
- private renderSelectTypeEditor(type, domainClass,property) {
- if (!cp) {
- return "<g:${type}Select name=\"${property.name}\" value=\"\${${domainInstance}?.${property.name}}\" />"
- } else {
- def sb = new StringBuilder("<g:${type}Select name=\"${property.name}\" ")
- if (cp.widget) sb << "widget=\"${cp.widget}\" ";
- cp.attributes.each { k, v ->
- sb << "${k}=\"${v}\" "
- }
- sb << "value=\"\${${domainInstance}?.${property.name}}\" ${renderNoSelection(property)} />"
- return sb.toString()
- }
- }
-
- private renderNoSelection(property) {
- if (isOptional()) {
- if (property.manyToOne || property.oneToOne) {
- return " noSelection=\"['null': '']\""
- } else if (property.type == Date || property.type == java.sql.Date || property.type == java.sql.Time || property.type == Calendar) {
- return "default=\"none\" noSelection=\"['': '']\""
- } else {
- return " noSelection=\"['': '']\""
- }
- }
- return ""
- }
-
- private boolean isRequired() {
- !isOptional()
- }
-
- private boolean isOptional() {
- if(!cp) {
- return false
- }
- else {
- cp.nullable || (cp.propertyType == String && cp.blank) || cp.propertyType in [boolean, Boolean]
- }
- }
-%>
View
61 src/templates/scaffolding/show.gsp
@@ -1,61 +0,0 @@
-<% import grails.persistence.Event %>
-<%=packageName%>
-<!doctype html>
-<html>
- <head>
- <meta name="layout" content="main">
- <g:set var="entityName" value="\${message(code: '${domainClass.propertyName}.label', default: '${className}')}" />
- <title><g:message code="default.show.label" args="[entityName]" /></title>
- </head>
- <body>
- <a href="#show-${domainClass.propertyName}" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content&hellip;"/></a>
- <div class="nav" role="navigation">
- <ul>
- <li><a class="home" href="\${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
- <li><g:link class="list" action="list"><g:message code="default.list.label" args="[entityName]" /></g:link></li>
- <li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
- </ul>
- </div>
- <div id="show-${domainClass.propertyName}" class="content scaffold-show" role="main">
- <h1><g:message code="default.show.label" args="[entityName]" /></h1>
- <g:if test="\${flash.message}">
- <div class="message" role="status">\${flash.message}</div>
- </g:if>
- <ol class="property-list ${domainClass.propertyName}">
- <% excludedProps = Event.allEvents.toList() << 'id' << 'version'
- allowedNames = domainClass.persistentProperties*.name << 'dateCreated' << 'lastUpdated'
- props = domainClass.properties.findAll { allowedNames.contains(it.name) && !excludedProps.contains(it.name) }
- Collections.sort(props, comparator.constructors[0].newInstance([domainClass] as Object[]))
- props.each { p -> %>
- <g:if test="\${${propertyName}?.${p.name}}">
- <li class="fieldcontain">
- <span id="${p.name}-label" class="property-label"><g:message code="${domainClass.propertyName}.${p.name}.label" default="${p.naturalName}" /></span>
- <% if (p.isEnum()) { %>
- <span class="property-value" aria-labelledby="${p.name}-label"><g:fieldValue bean="\${${propertyName}}" field="${p.name}"/></span>
- <% } else if (p.oneToMany || p.manyToMany) { %>
- <g:each in="\${${propertyName}.${p.name}}" var="${p.name[0]}">
- <span class="property-value" aria-labelledby="${p.name}-label"><g:link controller="${p.referencedDomainClass?.propertyName}" action="show" id="\${${p.name[0]}.id}">\${${p.name[0]}?.encodeAsHTML()}</g:link></span>
- </g:each>
- <% } else if (p.manyToOne || p.oneToOne) { %>
- <span class="property-value" aria-labelledby="${p.name}-label"><g:link controller="${p.referencedDomainClass?.propertyName}" action="show" id="\${${propertyName}?.${p.name}?.id}">\${${propertyName}?.${p.name}?.encodeAsHTML()}</g:link></span>
- <% } else if (p.type == Boolean || p.type == boolean) { %>
- <span class="property-value" aria-labelledby="${p.name}-label"><g:formatBoolean boolean="\${${propertyName}?.${p.name}}" /></span>
- <% } else if (p.type == Date || p.type == java.sql.Date || p.type == java.sql.Time || p.type == Calendar) { %>
- <span class="property-value" aria-labelledby="${p.name}-label"><g:formatDate date="\${${propertyName}?.${p.name}}" /></span>
- <% } else if(!p.type.isArray()) { %>
- <span class="property-value" aria-labelledby="${p.name}-label"><g:fieldValue bean="\${${propertyName}}" field="${p.name}"/></span>
- <% } %>
- </li>
- </g:if>
- <% } %>
- </ol>
- <g:form>
- <fieldset class="buttons">
- <g:hiddenField name="id" value="\${${propertyName}?.id}" />
- <g:link class="edit" action="edit" id="\${${propertyName}?.id}"><g:message code="default.button.edit.label" default="Edit" /></g:link>
- <g:actionSubmit class="delete" action="delete" value="\${message(code: 'default.button.delete.label', default: 'Delete')}" onclick="return confirm('\${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" />
- </fieldset>
- </g:form>
- </div>
- </body>
-</html>
View
37 test/unit/grails/plugin/emberscaffolding/ScaffoldingHelperSpec.groovy
@@ -0,0 +1,37 @@
+package grails.plugin.emberscaffolding
+
+import grails.plugin.emberscaffolding.test.Pirate
+import grails.test.mixin.Mock
+import spock.lang.Specification
+
+@Mock(Pirate)
+class ScaffoldingHelperSpec extends Specification {
+
+ void 'can get list of bindable properties for a domain class'() {
+ expect:
+ ScaffoldingHelper.getBindableProperties(Pirate) == ['name', 'nickname', 'dateOfBirth']
+ }
+
+ void 'can get property values for a domain instance'() {
+ given:
+ def pirate = new Pirate(name: 'Edward Teach', nickname: 'Blackbeard')
+
+ expect:
+ ScaffoldingHelper.getBindablePropertyValues(pirate) == [name: pirate.name, nickname: pirate.nickname, dateOfBirth: pirate.dateOfBirth]
+ }
+
+ void 'can get property values for a collection of domain instances'() {
+ given:
+ def pirates = [
+ new Pirate(name: 'Edward Teach', nickname: 'Blackbeard'),
+ new Pirate(name: 'Jack Rackham', nickname: 'Calico Jack', dateOfBirth: new Date(1682, 12, 21))
+ ]
+
+ expect:
+ ScaffoldingHelper.getBindablePropertyValues(pirates) == [
+ [name: pirates[0].name, nickname: pirates[0].nickname, dateOfBirth: pirates[0].dateOfBirth],
+ [name: pirates[1].name, nickname: pirates[1].nickname, dateOfBirth: pirates[1].dateOfBirth]
+ ]
+ }
+
+}
View
572 web-app/WEB-INF/tld/c.tld
@@ -0,0 +1,572 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
+ version="2.1">
+
+ <description>JSTL 1.2 core library</description>
+ <display-name>JSTL core</display-name>
+ <tlib-version>1.2</tlib-version>
+ <short-name>c</short-name>
+ <uri>http://java.sun.com/jsp/jstl/core</uri>
+
+ <validator>
+ <description>
+ Provides core validation features for JSTL tags.
+ </description>
+ <validator-class>
+ org.apache.taglibs.standard.tlv.JstlCoreTLV
+ </validator-class>
+ </validator>
+
+ <tag>
+ <description>
+ Catches any Throwable that occurs in its body and optionally
+ exposes it.
+ </description>
+ <name>catch</name>
+ <tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Name of the exported scoped variable for the
+exception thrown from a nested action. The type of the
+scoped variable is the type of the exception thrown.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Simple conditional tag that establishes a context for
+ mutually exclusive conditional operations, marked by
+ &lt;when&gt; and &lt;otherwise&gt;
+ </description>
+ <name>choose</name>
+ <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
+ <body-content>JSP</body-content>
+ </tag>
+
+ <tag>
+ <description>
+ Simple conditional tag, which evalutes its body if the
+ supplied condition is true and optionally exposes a Boolean
+ scripting variable representing the evaluation of this condition
+ </description>
+ <name>if</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+The test condition that determines whether or
+not the body content should be processed.
+ </description>
+ <name>test</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>boolean</type>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable for the
+resulting value of the test condition. The type
+of the scoped variable is Boolean.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope for var.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Retrieves an absolute or relative URL and exposes its contents
+ to either the page, a String in 'var', or a Reader in 'varReader'.
+ </description>
+ <name>import</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.core.ImportTag</tag-class>
+ <tei-class>org.apache.taglibs.standard.tei.ImportTEI</tei-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+The URL of the resource to import.
+ </description>
+ <name>url</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable for the
+resource's content. The type of the scoped
+variable is String.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope for var.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable for the
+resource's content. The type of the scoped
+variable is Reader.
+ </description>
+ <name>varReader</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the context when accessing a relative
+URL resource that belongs to a foreign
+context.
+ </description>
+ <name>context</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Character encoding of the content at the input
+resource.
+ </description>
+ <name>charEncoding</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ The basic iteration tag, accepting many different
+ collection types and supporting subsetting and other
+ functionality
+ </description>
+ <name>forEach</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.core.ForEachTag</tag-class>
+ <tei-class>org.apache.taglibs.standard.tei.ForEachTEI</tei-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Collection of items to iterate over.
+ </description>
+ <name>items</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>java.lang.Object</type>
+ <deferred-value>
+ <type>java.lang.Object</type>
+ </deferred-value>
+ </attribute>
+ <attribute>
+ <description>
+If items specified:
+Iteration begins at the item located at the
+specified index. First item of the collection has
+index 0.
+If items not specified:
+Iteration begins with index set at the value
+specified.
+ </description>
+ <name>begin</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>int</type>
+ </attribute>
+ <attribute>
+ <description>
+If items specified:
+Iteration ends at the item located at the
+specified index (inclusive).
+If items not specified:
+Iteration ends when index reaches the value
+specified.
+ </description>
+ <name>end</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>int</type>
+ </attribute>
+ <attribute>
+ <description>
+Iteration will only process every step items of
+the collection, starting with the first one.
+ </description>
+ <name>step</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>int</type>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable for the
+current item of the iteration. This scoped
+variable has nested visibility. Its type depends
+on the object of the underlying collection.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable for the
+status of the iteration. Object exported is of type
+javax.servlet.jsp.jstl.core.LoopTagStatus. This scoped variable has nested
+visibility.
+ </description>
+ <name>varStatus</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Iterates over tokens, separated by the supplied delimeters
+ </description>
+ <name>forTokens</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.core.ForTokensTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+String of tokens to iterate over.
+ </description>
+ <name>items</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>java.lang.String</type>
+ <deferred-value>
+ <type>java.lang.String</type>
+ </deferred-value>
+ </attribute>
+ <attribute>
+ <description>
+The set of delimiters (the characters that
+separate the tokens in the string).
+ </description>
+ <name>delims</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>java.lang.String</type>
+ </attribute>
+ <attribute>
+ <description>
+Iteration begins at the token located at the
+specified index. First token has index 0.
+ </description>
+ <name>begin</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>int</type>
+ </attribute>
+ <attribute>
+ <description>
+Iteration ends at the token located at the
+specified index (inclusive).
+ </description>
+ <name>end</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>int</type>
+ </attribute>
+ <attribute>
+ <description>
+Iteration will only process every step tokens
+of the string, starting with the first one.
+ </description>
+ <name>step</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>int</type>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable for the
+current item of the iteration. This scoped
+variable has nested visibility.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable for the
+status of the iteration. Object exported is of
+type
+javax.servlet.jsp.jstl.core.LoopTag
+Status. This scoped variable has nested
+visibility.
+ </description>
+ <name>varStatus</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Like &lt;%= ... &gt;, but for expressions.
+ </description>
+ <name>out</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Expression to be evaluated.
+ </description>
+ <name>value</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Default value if the resulting value is null.
+ </description>
+ <name>default</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Determines whether characters &lt;,&gt;,&amp;,'," in the
+resulting string should be converted to their
+corresponding character entity codes. Default value is
+true.
+ </description>
+ <name>escapeXml</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ </tag>
+
+
+ <tag>
+ <description>
+ Subtag of &lt;choose&gt; that follows &lt;when&gt; tags
+ and runs only if all of the prior conditions evaluated to
+ 'false'
+ </description>
+ <name>otherwise</name>
+ <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
+ <body-content>JSP</body-content>
+ </tag>
+
+ <tag>
+ <description>
+ Adds a parameter to a containing 'import' tag's URL.
+ </description>
+ <name>param</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.core.ParamTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Name of the query string parameter.
+ </description>
+ <name>name</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Value of the parameter.
+ </description>
+ <name>value</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Redirects to a new URL.
+ </description>
+ <name>redirect</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.core.RedirectTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+The URL of the resource to redirect to.
+ </description>
+ <name>url</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the context when redirecting to a relative URL
+resource that belongs to a foreign context.
+ </description>
+ <name>context</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Removes a scoped variable (from a particular scope, if specified).
+ </description>
+ <name>remove</name>
+ <tag-class>org.apache.taglibs.standard.tag.common.core.RemoveTag</tag-class>
+ <body-content>empty</body-content>
+ <attribute>
+ <description>
+Name of the scoped variable to be removed.
+ </description>
+ <name>var</name>
+ <required>true</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope for var.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Sets the result of an expression evaluation in a 'scope'
+ </description>
+ <name>set</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.core.SetTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Name of the exported scoped variable to hold the value
+specified in the action. The type of the scoped variable is
+whatever type the value expression evaluates to.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Expression to be evaluated.
+ </description>
+ <name>value</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ <deferred-value>
+ <type>java.lang.Object</type>
+ </deferred-value>
+ </attribute>
+ <attribute>
+ <description>
+Target object whose property will be set. Must evaluate to
+a JavaBeans object with setter property property, or to a
+java.util.Map object.
+ </description>
+ <name>target</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the property to be set in the target object.
+ </description>
+ <name>property</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope for var.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Creates a URL with optional query parameters.
+ </description>
+ <name>url</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.core.UrlTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Name of the exported scoped variable for the
+processed url. The type of the scoped variable is
+String.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope for var.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+URL to be processed.
+ </description>
+ <name>value</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the context when specifying a relative URL
+resource that belongs to a foreign context.
+ </description>
+ <name>context</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Subtag of &lt;choose&gt; that includes its body if its
+ condition evalutes to 'true'
+ </description>
+ <name>when</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.core.WhenTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+The test condition that determines whether or not the
+body content should be processed.
+ </description>
+ <name>test</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ <type>boolean</type>
+ </attribute>
+ </tag>
+
+</taglib>
View
671 web-app/WEB-INF/tld/fmt.tld
@@ -0,0 +1,671 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<taglib xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
+ version="2.1">
+
+ <description>JSTL 1.2 i18n-capable formatting library</description>
+ <display-name>JSTL fmt</display-name>
+ <tlib-version>1.2</tlib-version>
+ <short-name>fmt</short-name>
+ <uri>http://java.sun.com/jsp/jstl/fmt</uri>
+
+ <validator>
+ <description>
+ Provides core validation features for JSTL tags.
+ </description>
+ <validator-class>
+ org.apache.taglibs.standard.tlv.JstlFmtTLV
+ </validator-class>
+ </validator>
+
+ <tag>
+ <description>
+ Sets the request character encoding
+ </description>
+ <name>requestEncoding</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.RequestEncodingTag</tag-class>
+ <body-content>empty</body-content>
+ <attribute>
+ <description>
+Name of character encoding to be applied when
+decoding request parameters.
+ </description>
+ <name>value</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Stores the given locale in the locale configuration variable
+ </description>
+ <name>setLocale</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetLocaleTag</tag-class>
+ <body-content>empty</body-content>
+ <attribute>
+ <description>
+A String value is interpreted as the
+printable representation of a locale, which
+must contain a two-letter (lower-case)
+language code (as defined by ISO-639),
+and may contain a two-letter (upper-case)
+country code (as defined by ISO-3166).
+Language and country codes must be
+separated by hyphen (-) or underscore
+(_).
+ </description>
+ <name>value</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Vendor- or browser-specific variant.
+See the java.util.Locale javadocs for
+more information on variants.
+ </description>
+ <name>variant</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope of the locale configuration variable.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Specifies the time zone for any time formatting or parsing actions
+ nested in its body
+ </description>
+ <name>timeZone</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.TimeZoneTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+The time zone. A String value is interpreted as
+a time zone ID. This may be one of the time zone
+IDs supported by the Java platform (such as
+"America/Los_Angeles") or a custom time zone
+ID (such as "GMT-8"). See
+java.util.TimeZone for more information on
+supported time zone formats.
+ </description>
+ <name>value</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Stores the given time zone in the time zone configuration variable
+ </description>
+ <name>setTimeZone</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetTimeZoneTag</tag-class>
+ <body-content>empty</body-content>
+ <attribute>
+ <description>
+The time zone. A String value is interpreted as
+a time zone ID. This may be one of the time zone
+IDs supported by the Java platform (such as
+"America/Los_Angeles") or a custom time zone
+ID (such as "GMT-8"). See java.util.TimeZone for
+more information on supported time zone
+formats.
+ </description>
+ <name>value</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable which
+stores the time zone of type
+java.util.TimeZone.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope of var or the time zone configuration
+variable.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Loads a resource bundle to be used by its tag body
+ </description>
+ <name>bundle</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.BundleTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Resource bundle base name. This is the bundle's
+fully-qualified resource name, which has the same
+form as a fully-qualified class name, that is, it uses
+"." as the package component separator and does not
+have any file type (such as ".class" or ".properties")
+suffix.
+ </description>
+ <name>basename</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Prefix to be prepended to the value of the message
+key of any nested &lt;fmt:message&gt; action.
+ </description>
+ <name>prefix</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Loads a resource bundle and stores it in the named scoped variable or
+ the bundle configuration variable
+ </description>
+ <name>setBundle</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.SetBundleTag</tag-class>
+ <body-content>empty</body-content>
+ <attribute>
+ <description>
+Resource bundle base name. This is the bundle's
+fully-qualified resource name, which has the same
+form as a fully-qualified class name, that is, it uses
+"." as the package component separator and does not
+have any file type (such as ".class" or ".properties")
+suffix.
+ </description>
+ <name>basename</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable which stores
+the i18n localization context of type
+javax.servlet.jsp.jstl.fmt.LocalizationC
+ontext.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope of var or the localization context
+configuration variable.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Maps key to localized message and performs parametric replacement
+ </description>
+ <name>message</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.MessageTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Message key to be looked up.
+ </description>
+ <name>key</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Localization context in whose resource
+bundle the message key is looked up.
+ </description>
+ <name>bundle</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable
+which stores the localized message.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope of var.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Supplies an argument for parametric replacement to a containing
+ &lt;message&gt; tag
+ </description>
+ <name>param</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParamTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Argument used for parametric replacement.
+ </description>
+ <name>value</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Formats a numeric value as a number, currency, or percentage
+ </description>
+ <name>formatNumber</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.FormatNumberTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Numeric value to be formatted.
+ </description>
+ <name>value</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Specifies whether the value is to be
+formatted as number, currency, or
+percentage.
+ </description>
+ <name>type</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Custom formatting pattern.
+ </description>
+ <name>pattern</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+ISO 4217 currency code. Applied only
+when formatting currencies (i.e. if type is
+equal to "currency"); ignored otherwise.
+ </description>
+ <name>currencyCode</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Currency symbol. Applied only when
+formatting currencies (i.e. if type is equal
+to "currency"); ignored otherwise.
+ </description>
+ <name>currencySymbol</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Specifies whether the formatted output
+will contain any grouping separators.
+ </description>
+ <name>groupingUsed</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Maximum number of digits in the integer
+portion of the formatted output.
+ </description>
+ <name>maxIntegerDigits</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Minimum number of digits in the integer
+portion of the formatted output.
+ </description>
+ <name>minIntegerDigits</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Maximum number of digits in the
+fractional portion of the formatted output.
+ </description>
+ <name>maxFractionDigits</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Minimum number of digits in the
+fractional portion of the formatted output.
+ </description>
+ <name>minFractionDigits</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable
+which stores the formatted result as a
+String.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope of var.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Parses the string representation of a number, currency, or percentage
+ </description>
+ <name>parseNumber</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParseNumberTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+String to be parsed.
+ </description>
+ <name>value</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Specifies whether the string in the value
+attribute should be parsed as a number,
+currency, or percentage.
+ </description>
+ <name>type</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Custom formatting pattern that determines
+how the string in the value attribute is to be
+parsed.
+ </description>
+ <name>pattern</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Locale whose default formatting pattern (for
+numbers, currencies, or percentages,
+respectively) is to be used during the parse
+operation, or to which the pattern specified
+via the pattern attribute (if present) is
+applied.
+ </description>
+ <name>parseLocale</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Specifies whether just the integer portion of
+the given value should be parsed.
+ </description>
+ <name>integerOnly</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable which
+stores the parsed result (of type
+java.lang.Number).
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope of var.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Formats a date and/or time using the supplied styles and pattern
+ </description>
+ <name>formatDate</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.FormatDateTag</tag-class>
+ <body-content>empty</body-content>
+ <attribute>
+ <description>
+Date and/or time to be formatted.
+ </description>
+ <name>value</name>
+ <required>true</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Specifies whether the time, the date, or both
+the time and date components of the given
+date are to be formatted.
+ </description>
+ <name>type</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Predefined formatting style for dates. Follows
+the semantics defined in class
+java.text.DateFormat. Applied only
+when formatting a date or both a date and
+time (i.e. if type is missing or is equal to
+"date" or "both"); ignored otherwise.
+ </description>
+ <name>dateStyle</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Predefined formatting style for times. Follows
+the semantics defined in class
+java.text.DateFormat. Applied only
+when formatting a time or both a date and
+time (i.e. if type is equal to "time" or "both");
+ignored otherwise.
+ </description>
+ <name>timeStyle</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Custom formatting style for dates and times.
+ </description>
+ <name>pattern</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Time zone in which to represent the formatted
+time.
+ </description>
+ <name>timeZone</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable which
+stores the formatted result as a String.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope of var.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+ <tag>
+ <description>
+ Parses the string representation of a date and/or time
+ </description>
+ <name>parseDate</name>
+ <tag-class>org.apache.taglibs.standard.tag.rt.fmt.ParseDateTag</tag-class>
+ <body-content>JSP</body-content>
+ <attribute>
+ <description>
+Date string to be parsed.
+ </description>
+ <name>value</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Specifies whether the date string in the
+value attribute is supposed to contain a
+time, a date, or both.
+ </description>
+ <name>type</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Predefined formatting style for days
+which determines how the date
+component of the date string is to be
+parsed. Applied only when formatting a
+date or both a date and time (i.e. if type
+is missing or is equal to "date" or "both");
+ignored otherwise.
+ </description>
+ <name>dateStyle</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Predefined formatting styles for times
+which determines how the time
+component in the date string is to be
+parsed. Applied only when formatting a
+time or both a date and time (i.e. if type
+is equal to "time" or "both"); ignored
+otherwise.
+ </description>
+ <name>timeStyle</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Custom formatting pattern which
+determines how the date string is to be
+parsed.
+ </description>
+ <name>pattern</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Time zone in which to interpret any time
+information in the date string.
+ </description>
+ <name>timeZone</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Locale whose predefined formatting styles
+for dates and times are to be used during
+the parse operation, or to which the
+pattern specified via the pattern
+attribute (if present) is applied.
+ </description>
+ <name>parseLocale</name>
+ <required>false</required>
+ <rtexprvalue>true</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Name of the exported scoped variable in
+which the parsing result (of type
+java.util.Date) is stored.
+ </description>
+ <name>var</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ <attribute>
+ <description>
+Scope of var.
+ </description>
+ <name>scope</name>
+ <required>false</required>
+ <rtexprvalue>false</rtexprvalue>
+ </attribute>
+ </tag>
+
+</taglib>

0 comments on commit 1ca62c8

Please sign in to comment.
Something went wrong with that request. Please try again.