Syntax coloring

Mostrando postagens com marcador layout. Mostrar todas as postagens
Mostrando postagens com marcador layout. Mostrar todas as postagens

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!

Layout principal por convenção no Grails

O Grails suporta a seleção do layout da página usando usando uma tag , ou por convenção para casos onde o layout é grails-app/views/layouts/CONTROLLER.gsp ou grails-app/views/layouts/CONTROLLER/ACTION.gsp.

Mas me perguntei algumas vezes porque ele não suporta um layout principal por convenção? Talvez por causa das requisições por ajax (como o com a tag %lt;g:remoteLink>), que retorna uma página parcial. Mas mesmo assim poderia usar um layout principal usando alguma heurística para esse caso. Vamos à implementação:

Crie uma classe chamada CustomLayoutDecoratorMapper no 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

/**
* Decorador de layout para permitir o uso de um layout global
*/
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
}
}


Depois referencie essa classe no web-app/WEB-INF/sitemesh.xml, alterando a tag mapper para que ela fique assim: <mapper class="CustomLayoutDecoratorMapper">.

Pronto! Não precisa mais declarar o layout em cada página. Mas caso isso seja feito, será respeitado o layout definido.

Mas e os casos de requisições Ajax? Há duas abordagens. A primeira é mais fácil para quem usa o Prototype: Basta alterar a linha
if (decorator == null) {
para:
if (decorator == null && request.getHeader("X-Requested-With") != "XMLHttpRequest") {
Isso porque o prototype adiciona o cabeçalho X-Requested-With: XMLHttpRequest para requisições Ajax. Não sei se o Dojo faz algo do tipo...

A segunda opção é declarar um layout vazio em cada página parcial usar a <meta name="layout" content="empty">, e criar um arquivo de layout apenas com a tag <g:layoutBody>.

Espero que tenha ajudado!

Esta postagem também está disponível em inglês.