How can I use a filter as a method in template toolkit? - template-toolkit

I am trying to use the truncate filter on 2 variables (rsstitle and rssdescription), and assign the truncated version to a new variable (rsstitletrunc and rssdescriptiontrunc). I am relatively new to Template Toolkit, and dont understand why this code wont work (the SETs and IF/ELSE/END):
[% FOREACH feed IN rss_feeds %]
<div class="rssfeed">
<a class="rsstitle" href="[% feed.link | html %]">[% feed.title %]</a>
<div class="rssdescription">[% feed.description %]</div>
[% SET rsstitle = feed.title %]
[% SET rsstitleclean = rsstitle | truncate(10) %]
[% SET rssdescription = feed.description %]
[% SET rssdescriptionclean = rssdescription | truncate(10) %]
[% IF rssdescriptionclean == rsstitleclean %]
<div class="rssdescription">Same: [% rsstitleclean %] | [% rssdescriptionclean %]</div>
[% ELSE %]
<div class="rssdescription">Differs: [% rsstitleclean %] | [% rssdescriptionclean %]</div>
[% END %]
</div>
[% END %]
rsstitleclean returns the value of rsstitle (not truncated). rssdescriptionclean returns the value of rssdescription (not truncated). It seems I cant use filters on variables and declare the filtered value to another variable. Or can I?

I found out what I should've been doing. The code I ended up with is:
[% FOREACH feed IN rss_feeds %]
<div class="rssfeed">
<a class="rsstitle" href="[% feed.link | html %]">[% feed.title %]</a>
[% USE String %]
[% SET rsstitle = String.new(feed.title) %]
[% SET rssdescription = String.new(feed.description) %]
[% IF rsstitle.truncate(10) != rssdescription.truncate(10) %]
<div class="rssdescription">[% feed.description %]</div>
[% END %]
</div>
[% END %]
I had to declare the hash key as a new string, and then I was able to truncate and compare the variables. From what I can tell, it is NOT possible to run a filter as a method. Hope this helps someone!

Related

Thymeleaf replace navbar with switch conditions

Users with different roles need to have different navbars at the top of the webpage. My topnavs are th:fragments, written in separate file, and that part of code works fine.
But when I use th:switch and th:replace, all topnavs are shown in the webpage instead of just one.
I was looking these questions for solutions, but with no help:
Thymleaf switch statement with multiple case
How to use thymeleaf conditions - if - elseif - else
Things I tried:
<span th:if = "${role.value} == 'role1' " th:replace = "fragments/topnav :: navbar_role1"></span>
<span th:if = "${role.value} == 'role2' " th:replace = "fragments/topnav :: navbar_role2"></span>
#2
<span th:if = "${role} == 'role1' " th:replace = "fragments/topnav :: navbar_role1"></span>
<span th:if = "${role} == 'role2' " th:replace = "fragments/topnav :: navbar_role2"></span>
#3
<span th:if = "${role} eq 'role1' " th:replace = "fragments/topnav :: navbar_role1"></span>
<span th:if = "${role} eq 'role2' " th:replace = "fragments/topnav :: navbar_role2"></span
#4
<th:block th:switch = "${role}">
<div th:case = "${role} eq 'role1' " th:replace = "fragments/topnav :: navbar_role1"></div>
<div th:case = "${role} eq 'role2' " th:replace = "fragments/topnav :: navbar_role2"></div>
</th:block>
In debugger I can see in Java code that field role of type String has value role2. Instead of just second navbar, it shows both navbars.
It must be that I missed something in Thymeleaf syntax?
The target fragment needs to be in a child element, in this case, for the replace to work as intended.
Assume we have the following fragments in fragments/topnav.html:
<div th:fragment="navbar_role1">
<div>This is navbar role 1</div>
</div>
<div th:fragment="navbar_role2">
<div>This is navbar role 2</div>
</div>
Then your main page can be structured as follows:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Switch Demo</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<th:block th:switch="${role}">
<th:block th:case="'role1'">
<div th:replace="fragments/topnav :: navbar_role1"></div>
</th:block>
<th:block th:case="'role2'">
<div th:replace="fragments/topnav :: navbar_role2"></div>
</th:block>
</th:block>
</body>
</html>
You can obviously use th:block elements or something else such as <div> elements, depending on what you want the final structure to look like.
Note also that you do not need the following when using a th:switch:
th:case="${role} eq 'role1'" // NOT needed
You can simply use the value itself:
th:case="'role1'"
That is one of the benefits of using switch statements here.

Nokogiri how to get the img src

I've been trying to get the image's "src" attribute in this loop but can't figure out why it's not returning anything:
require 'nokogiri'
require 'open-uri'
url = "https://marketplace.asos.com/boutiques/independent-label"
doc = Nokogiri::HTML(open(url))
label = doc.css('#boutiqueList')
label.css('#boutiqueList img').attr('src').each do |l|
p l
end
This is the HTML:
<ul class="itemList boutiques" id="boutiqueList">
<li class="">
<div class="item landscapemedium" rel="sisterhood">
<div class="image">
<a href="/boutique/sisterhood" class="view-collection">
<img alt="" src="https://marketplace-images.asos.com/2016/12/23/0d664728-f484-447d-b927-679f55f24c1a_medium.jpg" class="">
Check for the src attribute inside every element, this way:
label.css('#boutiqueList img').each { |l| p l.attr('src') }
"https://marketplace-images.asos.com/2016/12/23/0d664728-f484-447d-b927-679f55f24c1a_medium.jpg"
"https://marketplace-images.asos.com/2017/02/03/f6322297-4400-4f18-b76e-66eedfc3f620_medium.jpg"
"https://marketplace-images.asos.com/2016/10/12/2d556841-7c0c-436a-a6fd-37b333c04cfe_medium.jpg"
...
=> 0
As what you want to do is to get an array with all the src attributes that match with '#boutiqueList img', then you can use map instead of each:
label.css('#boutiqueList img').map { |l| p l.attr('src') }
=> ["https://marketplace-images.asos.com/2016/12/23/0d664728-f484-447d-b927-679f55f24c1a_medium.jpg", ...]

How to set first item as selected in listview kendoui

#:CustomerVersion#
#:Rank#
#:AccountType#
By default, the first list item should be selected on load of the page. How to achieve this?
<script type="text/x-kendo-tmpl" id="template">
<div class="product">
<h3>#:CustomerVersion#</h3>
<h5>#:Rank#</h5>
<h3>#:AccountType#</h3>
</div>
</script>
<div class="demo-section">
#Code Dim listName = "List" Dim listViewRankBar = Html.Kendo().ListView(Of RankBarModel)() With listViewRankBar .Name(listName) .TagName("div") .ClientTemplateId("template") .DataSource(Sub(datasource) datasource.Read(Sub(read) read.Action("Products_Read",
"RankBar")) datasource.PageSize(15) End Sub) .Selectable(Sub(selectable) selectable.Enabled(True) selectable.Mode(ListViewSelectionMode.Single) End Sub) .Events(Sub(events) events.Change("onChange").DataBound("onDataBound") End Sub) '.Pageable() End
With End Code #listViewRankBar
</div>
function listRankBarOnDataBound(arg) {
//Fires when the list view has received data from the data source and it is already rendered.
// get a reference to the list view widget
var listView = $("#ListRankBar").data("kendoListView");
// selects first list view item
listView.select(listView.element.children().first());
}

How do I add a value for a <textarea> using Nokogiri?

I want to add content in a textarea while parsing HTML using Nokogiri:
<textarea placeholder="Describe" title="Describe" name="Describe" value=""></textarea>
Here is my code where I set the value for the textarea:
doc = Nokogiri::HTML( html_content )
textareas = doc.xpath("//textarea")
textareas.each do |r|
r.set_attribute("value","Its my content")
end
Here is the output:
<textarea placeholder="Describe" title="Describe" name="Describe" value="Its my content"></textarea>
I want output like this:
<textarea placeholder="Describe" title="Describe" name="Describe" value=""> Its my content </textarea>
You can try:
doc = Nokogiri::HTML( html_content )
textareas = doc.xpath("//textarea")
textareas.each do |r|
r.content = "Its my content"
end

How to do a grails while loop a certain number of times

How can I kick a while loop only n times in grails/groovy in side the gsp?
This is my current approach:
%{-- <%= "It's groovy, man".take(88) %> --}%
<g:set var="i" value="${messages.size()}"/>
<g:set var="x" value="<%= i - 3 %>/>"
<g:while test="${i > x}">
<g:set var="i" value="${i-1}"/>
... fancy html here
<%= messages[i].name %>
</g:while>
Solution:
<g:set var="i" value="${messages.size()}"/>
<g:set var="k" value="${i-3}"/>
<g:while test="${i > k}">
So here is what I would do. This is assuming you want to get the last X items in a list, which is what I THINK you are asking, although it isn't very clear. This is also assuming messages is a list.
<g:set var="length" value="${messages.size()}" />
<g:each in="${messages.getAt((Math.min(length,3)*-1)..-1)}" var="message">
... fancy html here
<%= message.name %>
</g:each>
Here were the tests I did to confirm this:
def list = [1,2]
def x = list.size()
assert [1,2] == list.getAt((Math.min(x,3)*-1)..-1)
list = [1,2,3]
x = list.size()
assert [1,2,3] == list.getAt((Math.min(x,3)*-1)..-1)
list = [1,2,3,4]
x = list.size()
assert [2,3,4] == list.getAt((Math.min(x,3)*-1)..-1)
You can also do:
<g:each var="foo" in="${ ((i-k)..k) }">
...
</g:each>

Resources