Java Freemarker macro with optional css classes - java

I'm trying to do a macro on freemarker, but I'm having problems to implement css class as parameter.
My object have some default css classes and I would like to add optional classes.
<#macro Button href extra...>
<a href="${href}" class="ui-button"
<#list extra?keys as attr>
${attr}="${extra[attr]?html}"
</#list>
>Anchor Button</a>
</#macro>
1) <#Button href="link.html"></#Button>
2) <#Button href="link.html" id="button1" class="marginrightnone"></#Button>
The line 2) only is rendering the "id" parameter. If I delete class="ui-button" of the macro, then it renders correctly.
What I could to do to render two or more class parameters???

You need to construct a string containing all the class parameters and use that as the value of a single HTML class attribute in the template.
You can't have an arbitrary number of class attribute/value pairs and still be legal HTML.
The simplest that would be basically what you have now would be to create a local with the "ui-button" value in it. As you iterate over extra?keys check for a "class" key and if found, append it to the local class (along with a leading space). The template would use that constructed value:
<a href="${href}" classes="${local_classes}"

Related

FreeMarker : diplay tag on condition without if block

I am looking for a way to avoid using this in a FreeMarker template :
<#if getName()??>
<Name>getName()</Name>
</#if>
Because I need to test many things.
Is there any way to do it by using, for example, a parameter in the tag?
I don't want the tag to be written at all if the value is null. (So exclamation mark is not enough)
If all your tags follow the same basic structure:
<Tag>value</Tag>
you can use a macro, to save yourself some typing:
<#macro optional tag value=[]>
<#if value?has_content>
<${tag}>${value}</${tag}>
</#if>
</#macro>
and then apply it like this:
<#optional tag='User' value=user/>
<#optional tag='Name' value=name/>
resulting in the following output code:
<User>myuser</User>
<Name>myname</User>
if one of the properties is not defined the whole tag will be omitted from the output.

Extract DOM property value using Selenium

In Firebug and other DevTools you can get the DOM properties and values corresponding to an HTML element.
How can such values be extracted using selenium-java code?
I had tried getAttribute(), but it seems to be working only for HTML attributes and not for DOM properties like "value" or "spellcheck" etc.
The reason I went for this approach is that the value associated with the <input> text field (snippet below) is run-time generated and data is bound to it using Knockout. And hence it's not possible to capture them with standard approaches like getText(), getAttribute("value"), getAttribute("text"), getAttribute("innerHTML"), getAttribute("innertext"), etc.
HTML snippet for the HTML element:
<input class="form-control" type="text" style="cursor: text" readonly="readonly" data-bind="textInput: url">
I know this is an old question but it might give someone else a hand out
Use this in the console
$$("input.form-control").value
if it returns the required you will have to execute the Javascript using WebDriver i.e.
driver.ExecuteScript("var data = arguments[0].value; return data;", (Element as RemoteWebElement)
According to the Selenium documentation, there is only the getAttribute() function, which is described as follows:
Get the value of a the given attribute of the element. Will return the current value, even if this has been modified after the page has been loaded. More exactly, this method will return the value of the given attribute, unless that attribute is not present, in which case the value of the property with the same name is returned (for example for the "value" property of a textarea element). If neither value is set, null is returned. ...
According to this, getAttribute("value") should return the DOM property value in case there is no HTML attribute named value.
If that's not the case, it may be a timing issue. I.e. the value is read by Selenium before it gets set.
In Selenium 4 use getDomAttribute() and getDomProperty().

Using variables in #{select} tag attributes

I have a page in my app with a dynamically-generated form, in which I need a number of <select> elements. Since I don't know in advance how many there will be, I need to put an ID number in the name attribute of each <select>. I'm trying to use the built-in #{select} tag (documentation here) like so:
#{ select 'select_' + ${IDnum}}
...options, etc...
#{/select}
When I do that I get a MissingMethodException:
No signature of method: Template_1009.$() is applicable for argument types:
(Template_1009$_run_closure1_closure2_closure3) values:
[Template_1009$_run_closure1_closure2_closure3#ad2388] Possible solutions:
_(java.lang.String), is(java.lang.Object), run(), run(), any(), get(java.lang.String).
When I instead do:
#{ select 'select_${IDnum}'}
the page renders correctly, but the select element renders like this in view-source:
<select name="select_${IDnum}" size="1" >
So, how do I get the value of ${IDnum} into the name attribute? I can do this with normal HTML <select> tags, but I'll need to write some Javascript to emulate Play's value:${x} functionality that I really don't want to bother with.
Thanks!
Try this :
#{select 'select_'+IDNum}

Does ServletRequest.setAttribute permit key names with periods?

I have a java webapp with a Struts 1 action that has the following code:
request.setAttribute("cat.sound", "meow");
On my jsp page, I have the following tag:
<c:out value="${cat.sound}" />
However, "meow" is never printed on the JSP page. This might work if I had an object of type "cat" to do something like:
request.setAttribute("cat", cat);
Unfortunately, this webapp does not have any object defined for the cats and the jsp pages are frozen (no changes allowed).
So is it possible to use request.setAttribute with a key name containing periods/dots? How would the JSP page need to reference the set parameter?
You can avoid having to create a Cat class if you set cat to a map with a String key "sound":
request.setAttribute("cat", Collections.singletonMap("sound", "meow"));
Collections#singletonMap() gives you a nice, succinct way to create a map with one entry.

Velocity #parse but assign it to a variable

Say you have a standard template with included (parsed) header, body, footer templates.
In the body template a variable like $subject is defined and you want that also displayed in the header template.
In some other template languages like HTML::Mason(perl based) you would evaluate the body template first to pick up the $subject variable but store it's output temporarily in a variable so your final output could end up in the correct order (header, body, footer)
In velocity it would look something like
set ($body=#parse("body.vm"))
parse("header.vm")
${body}
parse("footer.vm")
This however doesn't seem to work, any thoughts on how to do this?
Either of the two solutions above would work. The VelocityLayoutServlet solution requires an extra package (also from Velocity) called Velocity Tools. I'm partial to this approach (and variants) myself.
A third method is simply to put the #parse within quotes:
set ($body="#parse('body.vm')")
Within a #set, anything in double quotes is evaluated. Strings within single quotes are passed in literally.
You can do this using VelocityLayoutServlet which is part of VelocityTools.
This allows you to define a layout for your application -- let's call it application.vm -- in which you can parse in headers, footers etc and declare where the main body content is placed using the screen_content declaration, e.g:
<html>
<head>
<title>$subject</title>
</head>
<body>
#parse("header.vm")
$screen_content
#parse("footer.vm")
</body>
</html>
VelocityLayoutServlet will evalulate the templates (and, hence, variables) before rendering which allows you to set a $subject variable in your body template, e.g:
#set($subject = "My Subject")
<div id="content">
</div>
More detailed information can be found in the Velocity documentation.
If I understand you correctly, you want to have a Velocity variable named $subject interpolated into the header.vm and the body.vm templates. Right now, the variable is defined in the body.vm template, so you cannot refer to it in the earlier template header.vm.
Why don't you abstract out the definition of $subject into its own template snippet, called globals.vm say, then include that in the top-level template. So you'd have:
#parse("globals.vm")
#parse("header.vm")
#parse("body.vm")
#parse("footer.vm")

Categories