Alfresco unordered list web script - freemarker

I need to build an unordered list starting from an Alfresco Space:
I found this working template:
<#macro recurse_macro node depth>
<#if node.isContainer>
<tr>
<td align='left'>(${depth})
<#if (depth>0) >
<#list 1..depth as i>.</#list>
</#if>
<img src="/alfresco${node.icon16}"> ${node.properties.name}
</td>
</tr>
<#list node.children as child>
<#if child.isContainer && node.children?size != 0 >
<#recurse_macro node=child depth=depth+1/>
</#if>
</#list>
</#if>
</#macro>
<b>Recursive Listing of Spaces:</b>
<table border="1" celpadding="1" cellspacing="1">
<tr><th> Name Space </th></tr>
<#recurse_macro node=companyhome depth=0/>
</table>
What I need is to modify this template to render the space content as un unordered list:
<ul id="0" >
<li id="1">Content_one
<ul>
<li id="2">Content_two
<ul>
<li id="3">Content_three</li>
<li id="4">Content_four</li>
</ul>
</li>
<li id="5">Content_five</li>
</ul>
</li>
</ul>
Any help will be appreciated.
Thanks

Well, you need to add a < li> tag everywhere where you list a node, for one:
First replace the table tags with < ul id=0> and < /ul>.
Then, in the #macro - you need to list the content name but without the < td> part. so delete the < td> and < /td> tags. Also, you don't need the dots, so remove the <#if (depth>0) > block.
You need a counter. So have an <#assign counter = 0/> just before you enter the recurse macro for the first time.And increment the counter every time you enter the macro (so on line two of the macro: <#assign counter = counter+1/>
You also need < li> tags around the line where your actual document name is.
So enclose the < img /> and < a> < /a> blocks in a < li id="${counter}"> and close it with < /li>
Now, you will also need a new set of < ul> tags when you do a recurse.
To do it, you need to change the
<
#if child.isContainer && node.children?size != 0 >
<#recurse_macro node=child depth=depth+1/>
</#if>
block. Enclose the tag with your < ul> and < /ul> tags.
That should do it.

Related

How to write a clean code with free-marker template in multiple if and else blocks?

I am new to free-marker template and in my template its seems that I might have to repeat a lot of if and else blocks with repetition of same if condition.
Is there a more convenient or cleaner way of writing this if block or instead of repeating them.
<span > </span>
<#elseif section.role?has_content && section.person?has_content && section.organisation??>
<span > </span>
<#elseif section.role?has_content && section.organisation?has_content && section.person??>
<span > </span>
<#elseif section.person?has_content && section.organisation?has_content && section.role??>
<span > </span>
<#elseif section.person?has_content && section.role?? && section.organisation??>
<span > </span>
<#elseif section.organisation?has_content && section.role?? && section.person??>
<span > </span>
<#elseif section.role?has_content && section.organisation?? && section.person??>
<span > </span>
</#if>
I think you can do something like this in freemaker which is much cleaner then repeating the conditions.
Instead of repeating this section.role?has_content multiple times you can assign this condition value in a variable and use it later like this <#assign hasRole = section.role?has_content />
<#assign hasRole = section.role?has_content />
<#assign hasOrganisation = section.organisation?has_content />
<span >
<#if section.person?has_content><span ></span><#if section.role?has_content><span ></span></#if></#if>
<#if section.role?has_content><span ></span><#if section.organisation?has_content><span ></span></#if></#if>
<#if section.organisation?has_content>
<span ></span>
</#if>
</span>```
You can check all in a single if statement:
<#if section.person?? && section.role?? && section.organisation?? &&
(section.person?has_content || section.organisation?has_content || section.role?has_content)>
<span ></span>
</#if>
Actually, you can use <#switch> tag in order to handle multiple cases as in classic proggraming languages. Here is an example from freemarker.apache.org:
<#switch animal.size>
<#case "small">
This will be processed if it is small
<#break>
<#case "medium">
This will be processed if it is medium
<#break>
<#case "large">
This will be processed if it is large
<#break>
<#default>
This will be processed if it is neither
</#switch>
In your example, as I can see, you can accurately wrap your statements in multiple switch-cases, and use variables like Adam suggests you

How do I get the inner html content in this xpath expression?

I have some HTML code
<li><h3>Number Theory - Even Factors</h3>
<p lang="title">Number N = 2<sup>6</sup> * 5<sup>5</sup> * 7<sup>6</sup> * 10<sup>7</sup>; how many factors of N are even numbers?</p>
<ol class="xyz">
<li>1183</li>
<li>1200</li>
<li>1050</li>
<li>840</li>
</ol>
<ul class="exp">
<li class="grey fleft">
<span class="qlabs_tooltip_bottom qlabs_tooltip_style_33" style="cursor:pointer;">
<span>
<strong>Correct Answer</strong>
Choice (A).</br>1183
</span>
Correct answer
</span>
</li>
<li class="primary fleft">
Explanatory Answer
</li>
<li class="grey1 fleft">Factors - Even numbers</li>
<li class="orange flrt">Medium</li>
</ul>
</li>
In the HTML snippet above, I am trying to extract the <p lang="title"> Notice how it has <sup></sup> and <sub></sub> tags being used inside.
My Xpath expression .//p[#lang="title"]/text() does not retrieve the sub and sup contents. How do I get this output below
Desired Output
Number N = 2<sup>6</sup>*5<sup>5</sup> * 7<sup>6</sup> * 10<sup>7</sup>; how many factors of N are even numbers?
XPath
You can simply get innerHTML with node() as below:
//p[#lang="title"]/node()
Note that it returns an array of nodes
Python
You can get required innerHTML with below Python code
from BeautifulSoup import BeautifulSoup
def innerHTML(element):
"Function that receives element and returns its innerHTML"
return element.decode_contents(formatter="html")
html = """<html>
<head>...
<body>...
Your HTML source code
..."""
soup = BeautifulSoup(html)
paragraph = soup.find('p', { "lang" : "title" })
print(innerHTML(paragraph))
Output:
'Number N = 2<sup>6</sup> * 5<sup>5</sup> * 7<sup>6</sup> * 10<sup>7</sup>; how many factors of N are even numbers?'

getSiblings() and sort_by error

I am working in Liferay with structure (XML) and template (FTL).
My problem is that I do not get how I can use a sort_by() together with getSiblings().
This code does not work, as an example:
<ul id="emedia-categories">
<#list category?sort_by('linktext').getSiblings() as cat>
<li>
<a href="${cat.path.getData()}" title="${cat.title.getData()}">
<h3>
${cat.linktext.getData()}
</h3>
<img src="${cat.image.getData()}" alt="image-alt">
</a>
</li>
</#list>
</ul>
The error I get is the following:
Expected sequence. category evaluated instead to com.liferay.portal.freemarker.LiferayTemplateModel on line 2, column 16 in 14868#14904#131571.
What I want to achieve is to loop over all data and while doing it, I want it to be sorted on the string which is inside each cat.linktext. So the result comes out like: A, B, C, D, E...
Instead of: D, B, E, A, C...
This is my only working variant, but it does not have any sort on linktext, it just loop data in the order it is entered (probably by id):
<ul id="emedia-categories">
<#list category.getSiblings() as cat>
<li>
<a href="${cat.path.getData()}" title="${cat.title.getData()}">
<h3>
${cat.linktext.getData()}
</h3>
<img src="${cat.image.getData()}" alt="image-alt">
</a>
</li>
</#list>
</ul>
The error message is quite clear: You are trying to sort the category, which is not a sequence (= a list or array).
You want to sort the siblings, which is a sequence (= a list), by the attribute linktext.data:
<#list category.siblings?sort_by(['linktext', 'data']) as cat>
...
<#/list>

NetSuite Advanced PDF Template - Freemarker syntax

I have a custom body field custbody_deposit_number that may have 2 values separated by a comma. I need to understand the syntax of the freemarker ?split built in. This is what the freemarker site says about ?split:
<#list "someMOOtestMOOtext"?split("MOO") as x>
- ${x}
</#list>
Prints
some
test
text
can anyone provide help on how to implement my field in the ?split syntax?
Like this:
<#list custbody_deposit_number?split(',') as x>
- ${x}
</#list>
You may also want to remove space around the commas, either via ${x?trim} or using ?split(r'\s*,\s*', 'r')
this is how we finally solved this issue:
<#if record.custbody_deposit_numbers?has_content>
<#list record.custbody_deposit_numbers?string?split(",") as x>
<tr>
<td align="center">${x}</td>
<td align="center">
<#assign depositdate = record.custbody_deposit_dates?string?split(",")[x_index]>
${depositdate}
</td>
<td align="right">
<#assign depositAmt = record.custbody_deposit_amount?string?split(",")[x_index]>
<#assign depositAmt1 = depositAmt?number>
${depositAmt1?string.currency}
</td>
</tr>
</#list>

xpath for locating li with text does not work

Using the xpath //ul//li[contains(text(),"outer")] to find a li in the outer ul does not work
<ul>
<li>
<span> not unique text, </span>
<span> not unique text, </span>
outer ul li 1
<ul >
<li> inner ul li 1 </li>
<li> inner ul li 2 </li>
</ul>
</li>
<li>
<span> not unique text, </span>
<span> not unique text, </span>
outer ul li 2
<ul >
<li> inner ul li 1 </li>
<li> inner ul li 2 </li>
</ul>
</li>
</ul>
Any idea how to find a li with a specific text in the outer ul?
Thank you
This will work for you //ul//li[contains(.,"outer")]
I would expect that you only like to consider the text nodes which are direct child of the li. Therefore you are right with using text() (if you use contains(.,"outer") this will consider text form any children of li).
Therefore try this:
//ul/li[text()[contains(.,'outer')]]
Running this with Saxon, the original XPath expression gives:
XPTY0004: A sequence of more than one item is not allowed as the first argument of
contains() ("", "", ...)
Now, I guess Selenium is probably using XPath 1.0 rather than XPath 2.0, and in 1.0 the contains() function has "first item semantics" - it converts its argument to a string, which if the argument is a node-set containing more than one node, involves considering only the first node. And the first text node is probably whitespace.
If you want to test whether some child text node contains "outer", use
//ul//li[text()[contains(.,"outer")]]
Another reason for switching to XPath 2.0...
For above issue -
This solution will work
//ul//li[contains(.,"outer")]
"." Selects the current node

Resources