blob: f4efab139ca4e70ce5fbffe390c52a679cbe5406 [file] [log] [blame]
/* Copyright 2004-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT c;pWARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* The base application tag library for Grails many of which take inspiration from Rails helpers (thanks guys! :)
* This tag library tends to get extended by others as tags within here can be re-used in said libraries
*
* @author Graeme Rocher
* @since 17-Jan-2006
*/
import org.springframework.validation.Errors;
import org.springframework.context.NoSuchMessageException;
import org.springframework.web.servlet.support.RequestContextUtils as RCU;
import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU;
class ApplicationTagLib {
/**
* Creates a link to a resource, generally used as a method rather than a tag.
*
* eg. <link type="text/css" href="${createLinkTo(dir:'css',file:'main.css')}" />
*/
@Property createLinkTo = { attrs, body ->
out << grailsAttributes.getApplicationUri(request)
if(attrs['dir']) {
out << "/${attrs['dir']}"
}
if(attrs['file']) {
out << "/${attrs['file']}"
}
}
/**
* General linking to controllers, actions etc. Examples:
*
* <g:link action="myaction">link 1</gr:link>
* <g:link controller="myctrl" action="myaction">link 2</gr:link>
*/
@Property link = { attrs, body ->
out << "<a href=\""
// create the link
createLink(attrs)
out << '\" '
// process remaining attributes
attrs.each { k,v ->
out << k << "=\"" << v << "\" "
}
out << ">"
// output the body
body()
// close tag
out << "</a>"
}
/**
* Creates a grails application link from a set of attributes. This
* link can then be included in links, ajax calls etc. Generally used as a method call
* rather than a tag eg.
*
* <a href="${createLink(action:'list')}">List</a>
*/
@Property createLink = { attrs ->
out << grailsAttributes.getApplicationUri(request)
// prefer a URL attribute
if(attrs['url']) {
attrs = attrs.remove('url')
}
// if the current attribute null set the controller uri to the current controller
if(attrs["controller"]) {
out << '/' << attrs.remove("controller")
}
else {
out << grailsAttributes.getControllerUri(request)
}
if(attrs["action"]) {
out << '/' << attrs.remove("action")
}
if(attrs["id"]) {
out << '/' << attrs.remove("id")
}
if(attrs['params']) {
def pms = attrs.remove('params')
out << '?'
def i = 0
pms.each { k,v ->
out << "${k}=${v}"
if(++i < pms.size())
out << '&'
}
}
}
/**
* allows rendering of templates inside views for collections, models and beans. Examples:
*
* <g:render template="atemplate" collection="${users}" />
* <g:render template="atemplate" model="[user:user,company:company]" />
* <g:render template="atemplate" bean="${user}" />
*/
@Property render = { attrs, body ->
if(!attrs['template'])
throwTagError("Tag [render] is missing required attribute [template]")
def engine = grailsAttributes.getPagesTemplateEngine()
def uri = '/WEB-INF/grails-app/views' << grailsAttributes.getControllerUri(request)
uri << "/_${attrs['template']}.gsp"
uri = uri.toString()
def url = servletContext.getResource(uri)
if(!url)
throwTagError("No template found for name [${attrs['template']}] in tag [render]")
def t = engine.createTemplate( uri,
servletContext,
request,
response)
if(attrs['model'] instanceof Map) {
t.make( attrs['model'] ).writeTo(out)
}
else if(attrs['collection']) {
attrs['collection'].each {
t.make( ['it': it] ).writeTo(out)
}
}
else if(attrs['bean']) {
t.make( [ 'it' : attrs['bean'] ] ).writeTo(out)
}
}
/**
* Attempts to render input for a property value based by attempting to choose a rendering component
* to use based on the property type
*/
@Property renderInput = { attrs, body ->
def bean = attrs['bean']
if(!bean) {
throwTagError("Tag [renderInput] is missing required attribute [bean]")
}
if(!attrs['property']) {
throwTagError("Tag [renderInput] is missing required attribute [property]")
}
def app = grailsAttributes.getGrailsApplication()
def dc = app.getGrailsDomainClass(bean.class.name)
def pv = bean.metaPropertyValues.find {
it.name == attrs['property']
}
if(!pv) {
throwTagError("Property [${attrs['property']}] does not exist in tag [renderInput] for bean [${bean}]")
}
def engine = grailsAttributes.getPagesTemplateEngine()
def uri = findUriForType(pv.type)
if(!uri)
throwTagError("Type [${pv.type}] is unsupported by tag [renderInput]. No template found.")
def t = engine.createTemplate( uri,
servletContext,
request,
response)
if(!t) {
throwTagError("Type [${pv.type}] is unsupported by tag [renderInput]. No template found.")
}
def binding = [ name:pv.name,value:pv.value]
binding['constraints'] = (dc ? dc.constrainedProperties : null)
t.make(binding).writeTo(out)
}
private String findUriForType(type) {
if(type == Object.class)
return null;
def uri = "/WEB-INF/internal/render/${type.name}.gsp";
def url = servletContext.getResource(uri)
if(url != null) {
return uri
}
else {
return findUriForType(type.superClass)
}
}
}