Syntax coloring

quinta-feira, 27 de março de 2008

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.

Nenhum comentário: