Syntax coloring

quinta-feira, 27 de março de 2008

Main layout by convention in Grails

Grails supports selecting the page layout either using the <meta name="layout" content="NAME"> tag or by convention, where the layout is grails-app/views/layouts/CONTROLLER.gsp or grails-app/views/layouts/CONTROLLER/ACTION.gsp.

I've asked myself several times why doesn't it support the main layout by convention? Maybe because of the partial pages retrieved by Ajax (like the <g:remoteLink> tag). Even on those cases, an heuristic might be applied to determine those cases. Let's go to the actual implementation:

Create a class called CustomLayoutDecoratorMapper on src/groovy:
import javax.servlet.ServletContext
import javax.servlet.http.HttpServletRequest
import org.codehaus.groovy.grails.web.sitemesh.GrailsLayoutDecoratorMapper
import com.opensymphony.module.sitemesh.*
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
import org.codehaus.groovy.grails.web.metaclass.ControllerDynamicMethods

class CustomLayoutDecoratorMapper extends GrailsLayoutDecoratorMapper {

public Decorator getDecorator(HttpServletRequest request, Page page) {
Decorator decorator = super.getDecorator(request, page)
if (decorator == null) {
decorator = getNamedDecorator(request, "main")
}
return decorator
}
}


Then reference it on web-app/WEB-INF/sitemesh.xml, by changing the mapper tag, so that it looks like this: <mapper class="CustomLayoutDecoratorMapper">. Note that when running grails upgrade the file will be reverted to it's original form!.

Ready! No more need to declare the layout on every page. But, if the layout is declared, it will be honored.

But what about the Ajax requests? I can think of 2 approaches: The first one is easier for people using the Prototype framework. Just change the line:
if (decorator == null) {
to:
if (decorator == null && request.getHeader("X-Requested-With") != "XMLHttpRequest") {
Prototype adds the header X-Requested-With: XMLHttpRequest for Ajax requests. I don't know whether Dojo does something like that...

The second option is to declare an empty layout on Ajax pages with <meta name="layout" content="empty">, and create the layout called empty only with the tag <g:layoutBody>.

Hope this helps!

Um comentário:

blog disse...

Hi Luis,

I like your code samples, but I had trouble reading them because several of the lines were too wide for the column. One way to make the code easier to read would be to use Alex Gorbachev's SyntaxHighlighter. You can see a sample of Groovy in my blog post, Succinctly Groovy. In another post, I describe how to use the library on a Blogger blog.

--Matt