CFS Policy Convergence Products Database - CFS Policy Convergence Products Database
The Committee on World Food Security (CFS) is the foremost inclusive international and intergovernmental platform for all stakeholders to work together to ensure food security and nutrition for all. This database provides easy access to CFS products, such as voluntary guidelines, policy recommendations and principles.
CFS Products Legend
PR
Policy Recommendations
VGGT
Voluntary Guidelines on the Responsible Governance of Tenure of Land, Fisheries, and Forests
RAI
Principles for Responsible Investment in Agriculture and Food Systems
FFA
Framework for Action for Food Security and Nutrition in Protracted Crises
RtF
Voluntary Guidelines - Right to Food
VGFSyN
Voluntary Guidelines on Food Systems and Nutrition
An error occurred while processing the template.
For "." left-hand operand: Expected a hash, but this has evaluated to a string (wrapper: f.t.SimpleScalar): ==> fileEntry [in template "JOURNAL_MACROS" at line 6, column 62] ---- FTL stack trace ("~" means nesting-related): - Failed at: #return themeDisplay.getPathContext()... [in template "JOURNAL_MACROS" in function "getFileEntryURL" at line 6, column 5] ----
1<#include "${templatesPath}/JOURNAL_MACROS" />
2
3<#assign assetEntryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") />
4<#assign keywords = searchResultsPortletDisplayContext.getKeywords() />
5
6<div class="search-total-label">
7 ${languageUtil.format(locale, "x-results-for-x", [searchContainer.getTotal(), "<strong>" + htmlUtil.escape(keywords) + "</strong>"], false)}
8</div>
9
10<div id="search-results-display-list" class="display-list">
11 <#if entries?has_content>
12 <#list entries as entry>
13 <#if !entry.isTemporarilyUnavailable()>
14 <#if entry.getClassName() == "com.liferay.journal.model.JournalArticle">
15
16 <#assign assetEntry = assetEntryLocalService.getEntry(entry.getClassName(), entry.getClassPK()) />
17
18 <#if assetEntry.getAssetRenderer().getArticle().getDDMStructure().getStructureKey() == "CFS-PRODUCT">
19 <#assign docXml = saxReaderUtil.read(assetEntry.getAssetRenderer().getArticle().getContent()) />
20
21 <#assign recommendation = docXml.valueOf("//dynamic-element[@name='Recommendation']/dynamic-content/text()") />
22 <#assign sessionNumber = docXml.valueOf("//dynamic-element[@name='SessionNumber']/dynamic-content/text()") />
23 <#assign year = docXml.valueOf("//dynamic-element[@name='Year']/dynamic-content/text()")?date("yyyy-MM-dd")?string("yyyy") />
24 <#assign titleOfDocument = docXml.valueOf("//dynamic-element[@name='TitleOfDocument']/dynamic-content/text()") />
25 <#assign fileJSON = docXml.valueOf("//dynamic-element[@name='RecommendationFile']/dynamic-content/text()") />
26 <#assign linkToPdf = docXml.valueOf("//dynamic-element[@name='LinkToPDF']/dynamic-content/text()") />
27 <#assign cfsProductType = docXml.valueOf("//dynamic-element[@name='CFSProductType']/dynamic-content/text()") />
28 <#assign principleNumber = docXml.valueOf("//dynamic-element[@name='PrincipleNumber']/dynamic-content/text()") />
29 <#assign pageNumber = docXml.valueOf("//dynamic-element[@name='PageNumber']/dynamic-content/text()") />
30
31 <#if validator.isNotNull(principleNumber)>
32 <#if cfsProductType == "VGGT">
33 <#assign titleOfDocument = "Guideline ${principleNumber} - ${titleOfDocument}" />
34 <#else>
35 <#assign titleOfDocument = "Principle ${principleNumber} - ${titleOfDocument}" />
36 </#if>
37 </#if>
38
39 <div class="autofit-col autofit-col-expand">
40 <section class="autofit-section">
41 <div class="card">
42 <div class="card-body">
43 <#if entry.isContentVisible()>
44 <div class="container">
45 <div class="row">
46
47 <#if validator.isNotNull(fileJSON)>
48 <#assign fileEntry = getFileEntry(fileJSON) />
49 <#assign fileEntryUrl = getFileEntryURL(fileEntry) />
50 <#else>
51 <#assign fileEntryUrl = linkToPdf />
52 </#if>
53
54 <#assign pageParam = "" />
55
56 <#if validator.isNotNull(pageNumber)>
57 <#assign pageParam = "#page=${pageNumber}" />
58 </#if>
59
60 <div class="col-md-2">
61 <#if validator.isNotNull(fileJSON)>
62
63 <a href="${fileEntryUrl}${pageParam}" target="_blank">
64 <img src="${getFileEntryThumbnailURL(fileEntry)}"
65 alt="PDF document thumbnail" class="img-fluid"
66 style="border: 1px #287D3B solid;"/>
67 <#-- TODO Move the style to CSS -->
68 </a>
69 <#else>
70 <img src="/documents/20124/0/sample_thumbnail.png/f616c342-90eb-957c-0240-5910a323a4f4?t=1583254566571"
71 alt="PDF document thumbnail"
72 style="border: 2px #287D3B solid;"/>
73 <#-- TODO Move thumbnail somewhere (theme?) -->
74 </#if>
75 </div>
76 <div class="col-md-10 container">
77 <div class="row">
78 <div class="col-md">
79 <#if validator.isNotNull(fileEntryUrl)>
80 <a href="${fileEntryUrl}${pageParam}" target="_blank">
81 <h2>${highlightKeywords(keywords, titleOfDocument, false)}</h2>
82 </a>
83 <#else >
84 <h2>${highlightKeywords(keywords, titleOfDocument, false)}</h2>
85 </#if>
86 </div>
87 </div>
88 <div class="row">
89 <div class="col-md">
90 <blockquote class="blockquote">
91 <#if cfsProductType == "PR">
92 <#assign smartHighlight = false />
93 <#else>
94 <#assign smartHighlight = true />
95 </#if>
96
97 <div>${highlightKeywords(keywords, recommendation, smartHighlight)}</div>
98 <footer class="blockquote-footer mt-2">
99 ${cfsProductType}, Year <em>${year}</em><#if validator.isNotNull(sessionNumber)>, Session
100 <em>${sessionNumber}</em></#if>
101 </footer>
102 </blockquote>
103 </div>
104 </div>
105 </div>
106 </div>
107 </div>
108 </#if>
109
110 <#if entry.isDocumentFormVisible()>
111 <h6 class="expand-details text-default">
112 <span class="list-group-text" style="">
113 <a href="javascript:;"><@liferay.language key="details" />...</a>
114 </span>
115 </h6>
116
117 <div class="hide search-results-list table-details table-responsive">
118 <table class="table">
119 <thead>
120 <tr>
121 <th class="key-column">
122 <@liferay.language key="key" />
123 </th>
124 <th>
125 <@liferay.language key="value" />
126 </th>
127 </tr>
128 </thead>
129
130 <tbody>
131 <#list entry.getDocumentFormFieldDisplayContexts() as fieldDisplayContext>
132 <tr>
133 <td class="key-column table-details-content">
134 <strong>${htmlUtil.escape(fieldDisplayContext.getName())}</strong>
135 </td>
136 <td class="table-details-content">
137 <code>
138 ${fieldDisplayContext.getValuesToString()}
139 </code>
140 </td>
141 </tr>
142 </#list>
143 </tbody>
144 </table>
145 </div>
146 </#if>
147 </div>
148 </div>
149 </section>
150 </div>
151 <#else>
152 <div class="autofit-col">
153 <div class="alert alert-danger">
154 This Web Content Type cannot be displayed with CFS Recommendations Template
155 </div>
156 </div>
157 </#if>
158 <#else>
159 <div class="autofit-col">
160 <div class="alert alert-danger">
161 This Asset Type cannot be displayed with CFS Recommendations Template
162 </div>
163 </div>
164 </#if>
165 <#else>
166 <div class="autofit-col">
167 <div class="alert alert-danger">
168 <@liferay.language_format
169 arguments="result"
170 key="is-temporarily-unavailable"
171 />
172 </div>
173 </div>
174 </#if>
175 </#list>
176 </#if>
177</div>
178
179<@liferay_aui.script use="aui-base">
180 A.one('#search-results-display-list').delegate(
181 'click', function(event) {
182 var currentTarget = event.currentTarget;
183 currentTarget.siblings('.search-results-list').toggleClass('hide');
184 },
185 '.expand-details'
186 );
187</@liferay_aui.script>
188
189<#function highlightKeywords keywords, content, smartHighlight>
190 <#assign processedContent = content />
191 <#assign processedKeywords = keywords />
192
193 <#assign processedKeywords = processedKeywords?replace("\"", "") />
194 <#assign processedKeywords = processedKeywords?replace(" {2,}", " ", "r") />
195
196 <#-- Apply highlighting -->
197 <#if validator.isNotNull(processedKeywords)>
198 <#list processedKeywords?split(" ") as keyword>
199 <#-- The trick with foundList has been implemented to improve case insensitive handling.
200 If we would use just "i" for a regex, we'd end up with displaying all highlighted words in lower case,
201 even though some of them might be written with first upper case.
202 That's why first we perform case-insensitive match which produces all the variants
203 (e.g. "sustainable", "Sustainable") and then iterate over them and replace with theirs highighted versions -->
204 <#assign foundList = content?matches(keyword, "i") >
205
206 <#assign alreadyHighlighted = [] />
207
208 <#list foundList as found>
209 <#if !alreadyHighlighted?seq_contains(found)>
210 <#assign processedContent = processedContent?replace(found, "<span class='highlight'>" + found + "</span>") />
211 <#assign alreadyHighlighted = alreadyHighlighted + [found] />
212 </#if>
213 </#list>
214 </#list>
215 </#if>
216
217 <#assign MAX_ARTICLE_LENGTH = 600 />
218
219 <#-- Narrow the recommendation test to highlighted keywords and their vicinity -->
220 <#if smartHighlight && (processedContent?length > MAX_ARTICLE_LENGTH)>
221 <#assign foundHighlights =
222 processedContent?matches("(\\p{Alnum}+[ .,:;'\"]{1,2}){0,10}<span class='highlight'>\\p{Alnum}+</span>([ .,:;'\"]{1,2}\\p{Alnum}+){0,10}")>
223
224 <#-- For debugging -->
225 <#--<#assign processedContent = "<p>FULL :: ${processedContent}</p><p>MATCHES :: ${foundHighlights?join(' ... ')}</p>" />-->
226
227 <#if (foundHighlights?size > 0)>
228 <#assign processedContent = "${foundHighlights?join(' ... ')} [...]" />
229 <#else>
230 <#assign processedContent = processedContent?truncate(MAX_ARTICLE_LENGTH) />
231 </#if>
232 </#if>
233
234 <#return processedContent />
235</#function>
Created and managed by IFAD