prevent encoding of taglib output - grails

In my Grails app, I've defined the following tag which outputs a Map
class DataBindingTagLib {
static namespace = "bind"
def domainParamList = { attrs ->
def params = [:]
// put stuff in the map
return params
}
}
When I call this tag and store the result in a variable
<g:set var="chartParams" value="${bind.domainParamList([:])}"/>
If I inspect the type of this variable, it's a StreamCharBuffer. So it seems that the value output by the taglib is automatically being converted to this type. I tried to prevent this by changing the line above to
<g:set var="chartParams" value="${raw(bind.domainParamList([:]))}"/>
But it made no difference. Is there a way to prevent this from happening such that I can store the Map instance returned by the tag in the chartParams GSP variable? I'm not sure if this is relevant, but I have the following automatic encodings defined in Config.groovy
grails {
views {
gsp {
encoding = 'UTF-8'
htmlcodec = 'xml' // use xml escaping instead of HTML4 escaping
codecs {
expression = 'html' // escapes values inside ${}
scriptlet = 'none' // escapes output from scriptlets in GSPs
taglib = 'none' // escapes output from taglibs
staticparts = 'none' // escapes output from static template parts
}
}
}
}

You need to instruct your tag library to return an object as a result, by default tag libraries are expected to modify the output stream.
First, let the tag library know you need this particular method/closure to return an object by using the returnObjectForTags static hint. Then, simply modify the method/closure to return your object instead of modifying out. With these two changes your tag will return an object and you can use it as such.
class DataBindingTagLib {
static namespace = "bind"
static returnObjectForTags = ['domainParamList']
def domainParamList = { attrs ->
def params = [:]
// put stuff in the map
return params
}
}

Related

Grails: Returning parameters from a taglib

How do I return values from a taglib that has been called in a controller action such that it automatically retains the full type structure of the values setup in the taglib?
I can use the out << approach but this returns strings or array of strings.
I have tried to use a [] mapping as used transfer a set of values at the end of an action to its view.
I have also tried a return statement again unsuccessfully - besides I need to return more than one set of values.
-mike
from the top of the documentation http://grails.org/doc/latest/guide/theWebLayer.html#tagReturnValue
class ObjectReturningTagLib {
static returnObjectForTags = ['content']
def content = { attrs, body ->
someValue()
}
}
I think this could solve your problem
package com.campaign
import java.util.*;
class UserDetailsTagLib {
def springSecurityService
static namespace = "jft"
#here we are defining that this getPrincipal and getArrayListAsObj tag used to return object
static returnObjectForTags = ['getPrincipal','getArrayListAsObj']
#this tag will return obj
def getPrincipal = {
return springSecurityService.principal
}
# this tag is used to return the array list of string
def getArrayListAsObj = { attrs , body ->
ArrayList arrayList = new ArrayList();
arrayList.add("C");
arrayList.add("A");
arrayList.add("E");
arrayList.add("B");
arrayList.add("D");
arrayList.add("F");
return arrayList
}
}
I understand your problem. If you want to have the Intellisense on the var you got from a taglib, the only thing you can have is this (it's a little redundant)
In a gsp for example, if you have a TagLib with namespace myTaglib:
First call the action of your taglib to set the value of a var:
<myTaglib:person var="currentUserFromTaglib" />
Where the person tag in the myTaglib is just for this purpose:
def person = { attrs ->
this.pageScope."$attrs.var" = new Person(name:'Giuseppe', surname:'Iacobucci')
}
After this, you need to write:
<g:set var="currentUser" value="${currentUserFromTaglib as Person}"/>
And include in you gsp:
<%# page import="your.package.Person" %>
After that, in the gsp currentUser is recognized as type Person.
In a controller, you simply call the myTaglib and cast the result like so:
def myvar = myTaglib.person() as Person
Obviously if you need more a complex object as I read from your comments, then create a plain UI object with all information you need inside and do the same trick.

decorate Grails tag

The taglib provided by the Grails bean fields plugin uses a naming convention to determine the label key that should be used for each <input> element it generates. I would like to change the details of this convention without changing the plugin's source code directly.
The approach I'm considering is to create my own tag lib
class MyBeanTagLib {
static namespace = 'mybean'
private void setLabelKey (attrs) {
if (!attrs.labelKey) {
// in reality calculation of the default key is a bit more complicated :)
attrs.labelKey = 'my.default.key'
}
return attrs
}
// renders a combo box
def select = { attrs ->
attrs = setLabelKey(attrs)
// Now call the bean-fields select tag, passing along attrs
}
// renders a datePicker
def date = { attrs -
attrs = setLabelKey(attrs)
// Now call the bean-fields date tag, passing along attrs
}
}
My first question is how to invoke the tag I'm trying to decorate. In other words, what code should replace the comment
// Now call the bean-fields...
I could do this:
new BeanTagLib().select(attrs)
But I doubt this is the correct way to invoke one taglib from another.
Secondly, is there a more elegant way to decorate a taglib than this? In reality there are a lot more tags than just select and date that I need to decorate and the code in each decorating tag will be almost identical. I'd like to eliminate this duplication if possible?
Invoke other taglibs' tags by their namespace, like g.link([controller: 'one'], { 'link text' }), or bean.select(attrs).
You can try writing getProperty in your taglib and return proper closures - I'm not sure.

How do I inject new tags into a TagLib?

Lets assume that I have the following configuration in my conf/InjectionConfig.groovy file:
x {
a = { attrs, body -> out << "hello" }
b = { attrs, body -> out << "goodbye" }
}
and that I have a simple taglib such as
class XTagLib {
static namespace = "x"
}
What I want to do is that when I type <x:a /> to any of my views, it would print hello. I've already tried to inject these to the metaclass of the taglib as both property and method but neither seem to work. As an example, here's basically what I'm doing right now in a service:
public void afterPropertiesSet() throws Exception {
GroovyClassLoader classLoader = new GroovyClassLoader(getClass().classLoader)
def slurper = new ConfigSlurper(GrailsUtil.environment)
ConfigObject xConfig
try {
xConfig = slurper.parse(classLoader.loadClass('InjectionConfig'))
}
catch (e) {
e.printStackTrace()
}
xConfig.x.each({
if ( !XTagLib.metaClass.hasMetaProperty(it.key) ) {
XTagLib.metaClass.registerBeanProperty(it.key, { args ->
def attrs = args[0], body = args[1]
it.value.call(attrs, body)
}
}
})
}
Am I just doing it wrong or is this even possible currently?
Well, this
def shell = new GroovyShell() // or get a GroovyClassLoader
Class yTagLibClass = shell.evaluate("class YTagLib { static namespace = 'x' }; return YTagLib")
yTagLibClass.metaClass.a = { attrs, body -> delegate.out << 'blabla' }
grailsApplication.addArtefact(TagLibArtefactHandler.TYPE, yTagLibClass)
<x:a/> nearly worked for me - registered a tag, except for it didn't output anything. You still need to make the closure resolve out against Grails' taglib's out property.
I don't see a pretty way to do it, as there's no access to instance variables, and out is an instance variable. See Grails source, JspInvokeGrailsTagLibTag.doStartTagInternal() - you might find a way.
EDIT: I added delegate. prefix that should resolve out property of target object. Now I believe I deserve an acceptance :)
What I want to do is that when I type
to any of my views, it would
print hello
I think there's an alternative way to do what you intend: combine template & tagLib. First, create a template, then add it in your TagLib (with no complex configuration).
In my opinion, it's more simple than your approach.
Please take a look at this tutorial:
http://jan-so.blogspot.com/2008/02/example-of-template-and-taglib-with.html

Is possible to overwrite the behaviour of the methods **CreateLink** and **CreateLinkTo**?

Is possible to overwrite the behaviour of the methods CreateLink and CreateLinkTo?
You could use meta programming to replace the closure on ApplicationTaglib.
ApplicationTagLib.metaClass.getCreateLink = {->
return {attrs->
// your code here
}
}
I've never tried it but it might work :)
All you need to do is create a taglib of your own and define the tags yourself ie
class MyTabLib {
def createLink = {attrs, body ->
.... etc ....
}
def createLinkTo = {attrs, body ->
.... etc ....
}
}
Grails will use your taglib first.
Hope this Helps!
This is a little late, but the solutions above didn't work for me. I was able to successfully do this, though:
public class MyTagLib extends ApplicationTagLib {
def oldResource
public MyTagLib() {
// save the old 'resource' value
oldResource = resource;
resource = staticResource;
}
def staticResource = { attrs ->
// dork with whatever you want here ...
// ...
out << oldResource(attrs);
}
}
you're basically extending the original tag lib. Since the 'resource' tag is a property of the object (and not a method) I don't think you can actually override it. Instead, just save the original value and call it after you've make your changes to the tag request.

Grails UrlMappings with parameter values containing "."

Given this UrlMapping:
"/foo/$foobar" {
controller = "foo"
action = "foo"
constraints {
}
}
Combined with this controller:
class FooController {
def foo = {
def foobar = params.foobar
println "foobar=" + foobar
}
}
And with these requests:
http://localhost:8080/app/foo/example.com give the output "foobar=example"
http://localhost:8080/app/foo/examplecom give the output "foobar=examplecom"
It seems like Grails cuts the "foobar" parameter at the first dot ("."). Is this intentional? Is there a work-around if I want to use parameters containing dots in my URL mappings?
This can be solved by setting ...
grails.mime.file.extensions = false
... in Config.groovy.
It seems like Grails is trying to do some MIME magic behind the scene based on the file name suffix.
Updated: Some additional info from the Grails JIRA.
This is the offending code in UrlMappingsFilter.java:
if(WebUtils.areFileExtensionsEnabled()) {
String format = WebUtils.getFormatFromURI(uri);
if(format!=null) {
MimeType[] configuredMimes = MimeType.getConfiguredMimeTypes();
// only remove the file extension if its one of the configured mimes in Config.groovy
for (MimeType configuredMime : configuredMimes) {
if (configuredMime.getExtension().equals(format)) {
request.setAttribute(GrailsApplicationAttributes.CONTENT_FORMAT, format);
uri = uri.substring(0, (uri.length() - format.length() - 1));
break;
}
}
}
}
WebUtils.areFileExtensionsEnabled() returns the value of the "grails.mime.file.extensions" setting configured in Config.groovy.

Resources