Manual, Processes and Guides

This is description for the Manual, Processes and Guides Asset Publisher. This is description for the Manual, Processes and Guides Asset Publisher.This is description for the Manual, Processes and Guides Asset Publisher.This is description for the Manual, Processes and Guides Asset Publisher.This is description for the Manual, Processes and Guides Asset Publisher.

An error occurred while processing the template.
For "...[...]" left-hand operand: Expected a sequence or string or something automatically convertible to string (number, date or boolean), but this has evaluated to an extended_hash (wrapper: f.c.HashLiteral$SequenceHash):
==> categoriesByType  [in template "20157#20197#377829" at line 75, column 38]

----
Tip: You had a numberical value inside the []. Currently that's only supported for sequences (lists) and strings. To get a Map item with a non-string key, use myMap?api.get(myKey).
----

----
FTL stack trace ("~" means nesting-related):
	- Failed at: #assign defaultCategory = categoriesB...  [in template "20157#20197#377829" at line 75, column 13]
----
1<#assign dlFileEntryUtil=serviceLocator.findService("com.liferay.document.library.kernel.service.DLFileEntryLocalService")> 
2<#assign dlFileEntryClass="com.liferay.document.library.kernel.model.DLFileEntry"> 
3<#assign portletTitle="${portletDisplay.getTitle()}"> 
4<#assign portletID="${themeDisplay.getPortletDisplay().getId()}"> 
5<#assign customTagID="ap_"> 
6<#assign currentUrl = themeDisplay.getURLCurrent()!""> 
7<#if currentUrl?matches(".*[?&]type=([^&]+).*")> 
8 <#assign urlType = "ap_" + currentUrl?matches(".*[?&]type=([^&]+).*")?groups[1]!""/> 
9<#else> 
10 <#assign urlType = "ap_"/> 
11</#if> 
12							 
13<!--Type of Document--> 
14<div class="container no-padding"> 
15    <div class="row"> 
16        <div class="col-md-12" style="padding: 0px;"> 
17            <#assign types=[]> 
18            <#assign categories={}> 
19            <#assign categoriesByType={}> 
20 
21            <#list entries as curEntry> 
22                <#if curEntry.getClassName()==dlFileEntryClass> 
23                    <#assign dlFileEntry=dlFileEntryUtil.getFileEntry(curEntry.getClassPK())> 
24                    <#assign entryTypes=curEntry.getTags()> 
25                    <#assign entryCategories=curEntry.getCategories()> 
26 
27                    <!-- Type --> 
28                    <#list entryTypes as type> 
29                        <#list type.name?split(",") as typeName> 
30                            <#if typeName?matches("^" + customTagID + ".*")> 
31                                <#assign typeTag=typeName?trim> 
32                                <#if !types?seq_contains(typeTag)> 
33                                    <#assign types=(types + [typeTag])> 
34                                </#if> 
35                            </#if> 
36                        </#list> 
37                    </#list> 
38 
39                    <!-- Category --> 
40                    <#list entryCategories as category> 
41                        <#list category.name?split(",") as categoryName> 
42							<#assign categoryTag=categoryName?trim>    
43							<#if !categoryTag?matches("^LH.*")> 
44                                <#if categoriesByType[typeTag]?? && !categoriesByType[typeTag]?seq_contains(categoryTag)> 
45                                    <#assign categoriesByType = categoriesByType + {typeTag: categoriesByType[typeTag] + [categoryTag]} /> 
46                                <#elseif !(categoriesByType[typeTag]??)> 
47                                    <#assign categoriesByType = categoriesByType + {typeTag: [categoryTag]} /> 
48                                </#if>  
49							    <#if (category.description?split(",")[0]?trim?length gt 0)> 
50                                    <#assign categoryDescription=category.description?split(",")[0]?trim?substring(132, category.description?length - 28)?trim> 
51                                <#else> 
52								    <#assign categoryDescription=categoryTag> 
53								</#if> 
54                                <#assign categories = categories + {categoryTag: categoryDescription} /> 
55                            </#if> 
56                        </#list> 
57                    </#list>                       
58                </#if> 
59            </#list> 
60 
61            <!-- Sort Categories --> 
62            <#assign sortedCategoriesByType = {}> 
63            <#list categoriesByType?keys?sort as typeTag> 
64                <#assign sortedCategories = categoriesByType[typeTag]?sort> 
65                <#assign sortedCategoriesByType = sortedCategoriesByType + {typeTag: sortedCategories} /> 
66            </#list> 
67			<#assign categoriesByType = sortedCategoriesByType> 
68 
69            <!-- Default Type and Category --> 
70            <#if urlType == 'ap_'> 
71                <#assign defaultType = 0> 
72            <#else> 
73                <#assign defaultType = urlType> 
74			</#if> 
75            <#assign defaultCategory=categoriesByType[defaultType]?first> 
76 
77            <!-- Type of Documents Filters --> 
78            <div class="type-buttons"> 
79                <#list types as type> 
80                    <#assign typeTitle = type?replace(customTagID, "")?replace("_", " ")?split(" ")?map(x -> (x == 'and')?string("and", x?cap_first))?join(" ")> 
81                    <#if type == defaultType> 
82                        <button class="type-btn active" id="typeBtn_${type}" data-type="${type}"> 
83                            ${typeTitle} 
84                        </button> 
85                    <#else> 
86                        <button class="type-btn" id="typeBtn_${type}" data-type="${type}"> 
87                            ${typeTitle} 
88                        </button> 
89                    </#if> 
90                </#list> 
91            </div>             
92        </div> 
93    </div> 
94</div> 
95 
96<!-- Type of Document Title --> 
97<div class="container"> 
98    <div class="row"> 
99        <a class="col-md-12 main-title type-title" id="type-title">${defaultType?replace(customTagID, "")?replace("_", " ")?split(" ")?map(x -> (x == 'and')?string("and", x?cap_first))?join(" ")} 
100        </a> 
101    </div> 
102</div> 
103 
104<!-- Category of Document || Documents --> 
105<div class="container"> 
106    <div class="row"> 
107        <div class="filters-title"> 
108            Filters 
109        </div> 
110        <!-- Category of Documents Filters --> 
111        <div class="col-md-3 category-filters" id="categories_${portletID}">             
112        <#list categoriesByType[defaultType] as category> 
113            <#assign categoryTitle = categories[category]> 
114            <label class="category-label custom-checkbox"> 
115                <#if category == defaultCategory>  
116                        <input class="category-btn" type="checkbox" value="${category}" checked> 
117                <#else> 
118                    <input class="category-btn" type="checkbox" value="${category}"> 
119                </#if> 
120                <span class="custom-checkmark"></span> 
121                <a class="category-text">${categoryTitle}</a> 
122            </label> 
123        </#list> 
124    </div> 
125        <!-- Documents --> 
126        <div class="col-md-7 multiple-documents-files" style="padding-bottom: 30px">   
127            <div class="tiles-container"> 
128                <#if entries?has_content> 
129                    <#list entries as curEntry> 
130                        <#if curEntry.getClassName()==dlFileEntryClass> 
131                            <#assign dlFileEntry=dlFileEntryUtil.getFileEntry(curEntry.getClassPK())> 
132                            <#assign entryTypes=curEntry.getTags()> 
133                            <#assign entryCategories=curEntry.getCategories()> 
134                            <#assign classTypes=""> 
135                            <#assign classCategories=""> 
136                            <#list entryTypes as type> 
137                                <#list type.name?split(",") as typeName> 
138                                    <#assign classTypes=classTypes + " " + typeName?trim> 
139                                </#list> 
140                            </#list> 
141                                <#list entryCategories as category> 
142                                <#list category.name?split(",") as categoryName> 
143                                    <#assign classCategories=classCategories + " " + categoryName?trim> 
144                                </#list> 
145                            </#list> 
146                            <div class="multiple-documents-tile small-box-shadow-containers ${portletID} ${classTypes} ${classCategories}"> 
147                                <div class="multiple-documents-tile-text"> 
148                                    ${curEntry.getDescription(locale)} 
149                                </div> 
150                                <div class="multiple-documents-tile-download"> 
151                                    <a href="${curEntry.getAssetRenderer().getURLDownload(themeDisplay)}" target="_blank"> 
152                                        Download 
153                                    </a> 
154                                </div> 
155                            </div> 
156                        </#if> 
157                    </#list> 
158                </#if> 
159                <a class="anchor" id="${themeDisplay.getPortletDisplay().title}" name="${themeDisplay.getPortletDisplay().title}"></a> 
160            </div> 
161            <!--PAGINATION--> 
162            <div class="asset-pagination"> 
163                <div class="asset-pagination-showing"> 
164                    Showing <span id="startResults_${portletID}">1</span> to <span id="endResults_${portletID}">10</span> of <span id="totalResults_${portletID}">25</span> results 
165                </div> 
166                <div class="asset-pagination-btns"> 
167                    <button class="asset-pagination-btn" id="prevBtn_${portletID}"> <i class="fa-solid fa-arrow-left"></i> </button> 
168                    <button class="asset-pagination-btn active" id="firstBtn_${portletID}">1</button> 
169                    <button class="asset-pagination-btn" id="secondBtn_${portletID}">2</button> 
170                    <button class="asset-pagination-btn" id="thirdBtn_${portletID}">3</button> 
171                    <button class="asset-pagination-btn" id="fourthBtn_${portletID}">4</button> 
172                    <button class="asset-pagination-btn" id="nextBtn_${portletID}"><i class="fa-solid fa-arrow-right"></i></button> 
173                </div> 
174            </div> 
175        </div> 
176    </div> 
177</div> 
178 
179 
180<script> 
181(function() { 
182    var titleID = "${portletID}"; 
183    var currentType = "${defaultType}"; 
184    var currentCategory = "${defaultCategory}"; 
185    var itemsPerPage = isMobileDevice() ? 3 : 10; 
186    var currentPage = 0; 
187    var nextPage = 0; 
188    var taggedRows = []; 
189    var startPagination = 1; 
190    var rows = []; 
191    var totalTaggedRows = 0; 
192    var totalPages = 0; 
193    var nextStart = 0; 
194    var nextEnd = 0; 
195    var allCategoriesByType = { 
196        <#list categoriesByType as type, typeCategories> 
197            "${type}": [<#list typeCategories as category>"${category}"<#if category_has_next>,</#if></#list>] 
198            <#if type_has_next>,</#if> 
199        </#list> 
200    }; 
201    var allCategories = { 
202        <#list categories as categoryName, categoryDescription> 
203            "${categoryName}": "${categoryDescription}" 
204            <#if categoryName_has_next>,</#if> 
205        </#list> 
206    }; 
207 
208    function isMobileDevice() { 
209        const userAgent = navigator.userAgent || navigator.vendor || window.opera; 
210 
211        if (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent) ||  
212        ('ontouchstart' in window && (window.innerWidth <= 800 || window.innerHeight <= 600))) { 
213            return true; 
214
215 
216        return false; 
217    }    
218 
219    // Update Type 
220    function updateType(event) { 
221        var selectedType = event.target.getAttribute('data-type'); 
222        currentType = selectedType; 
223         
224        document.querySelectorAll('.type-btn').forEach(function(button) { 
225            button.classList.remove('active'); 
226        }); 
227        event.target.classList.add('active'); 
228 
229        var currentTypeTitle = currentType.replace("ap_", "").replace(/_/g, " ").split(" ")    .map(x => x.toLowerCase() === "and" ? "and" : x.charAt(0).toUpperCase() + x.slice(1)).join(" "); 
230        document.getElementById("type-title").text = currentTypeTitle; 
231 
232        updateCategories(currentType); 
233
234    
235    // Update Category based on type 
236    function updateCategories(type) { 
237        var categoryContainer = document.getElementById(`categories_${portletID}`); 
238        categoryContainer.innerHTML = ''; 
239 
240        var categories = allCategoriesByType[type] || []; 
241        categories.forEach(function(category) { 
242            var label = document.createElement("label"); 
243            label.classList.add("category-label", "custom-checkbox"); 
244 
245            var checkbox = document.createElement("input"); 
246            checkbox.type = 'checkbox'; 
247            checkbox.name = 'category'; 
248            checkbox.value = category; 
249            checkbox.classList.add("category-btn"); 
250 
251            if (category === categories[0]) { 
252                checkbox.checked = true; 
253                currentCategory = category; 
254
255 
256            var customCheckmark = document.createElement("span"); 
257            customCheckmark.classList.add("custom-checkmark"); 
258 
259            var categoryTitle = allCategories[category]; 
260            var categoryText = document.createElement("a"); 
261            categoryText.classList.add("category-text"); 
262            categoryText.textContent = categoryTitle; 
263 
264            label.appendChild(checkbox); 
265            label.appendChild(customCheckmark); 
266            label.appendChild(categoryText); 
267 
268            categoryContainer.appendChild(label); 
269        }); 
270 
271        document.querySelectorAll('.category-btn').forEach(function(checkbox) { 
272            checkbox.addEventListener('click', updateCategory); 
273        }); 
274 
275        updateRows(currentCategory); 
276
277 
278    function updateCategory(event) { 
279        var selectedCategory = event.target.getAttribute('value'); 
280        currentCategory = selectedCategory; 
281         
282        document.querySelectorAll('.category-btn').forEach(function(button) { 
283            button.checked = false; 
284        }); 
285        event.target.checked = true; 
286        updateRows(currentCategory); 
287
288    
289 
290     // Update Rows based on Type and Category 
291    function updateRows(category) { 
292        currentCategory = category; 
293         
294        rows = document.querySelectorAll(".multiple-documents-tile." + titleID); 
295        taggedRows = []; 
296        rows.forEach(function(row) { 
297            var tags = Array.from(row.classList); 
298            var categories = Array.from(row.classList); 
299 
300            // Check if row matches selected type and category 
301            if (tags.includes(currentType) && categories.includes(currentCategory)) { 
302                taggedRows.push(row); 
303
304 
305            // Hide all -> pagination will show 
306            if (!row.classList.contains("assetHidden")) { 
307                row.classList.add("assetHidden"); 
308
309        }); 
310        handlePaginationChange("0"); 
311
312 
313    //EVENT LISTENERS // 
314    // On load 
315    function initialHandle() { 
316        updateCategories("${defaultType}"); 
317
318    window.onload = initialHandle(); 
319    // Type 
320    document.querySelectorAll('.type-btn').forEach(function(button) { 
321        button.addEventListener('click', updateType); 
322    }); 
323    // Category 
324     document.addEventListener('DOMContentLoaded', function() { 
325        document.querySelectorAll('.category-btn').forEach(function(checkbox) { 
326            checkbox.addEventListener('click', updateCategory); 
327        }); 
328    }); 
329    // 
330 
331    //Pagination 
332    function handlePaginationChange(page) { 
333        totalTaggedRows = taggedRows.length; 
334        totalPages = Math.ceil((totalTaggedRows / itemsPerPage)); 
335        nextPage = 0; 
336        // defines what is the next page 
337        if (page === 'prev') { 
338            nextPage = currentPage - 1 < 0 ? currentPage : currentPage - 1; 
339            if (currentPage == nextPage) return; 
340        } else if (page === 'next') { 
341            nextPage = currentPage + 1 < totalPages ? currentPage + 1 : currentPage; 
342            if (currentPage == nextPage) return; 
343        } else { 
344            nextPage = parseInt(page, 10) + (startPagination - 1); 
345
346        nextStart = (nextPage) * itemsPerPage; 
347        nextEnd = nextStart + itemsPerPage; 
348        //hides current reports and shows reports for the next page 
349        handlePaginationReports(); 
350        //changes numbers in Showing x to y of z results 
351        handleShowingResults(); 
352        //updates the pagination labels 
353        handlePaginationButtons(); 
354        //update current page 
355        currentPage = nextPage; 
356
357 
358    function handlePaginationReports() { 
359        //hides current page reports 
360        var curStart = (currentPage) * itemsPerPage; 
361        var curEnd = curStart + itemsPerPage; 
362        for (let r = curStart; r < curEnd && r < totalTaggedRows; r++) { 
363            if (!taggedRows[r].classList.contains("assetHidden")) { 
364                taggedRows[r].classList.add("assetHidden"); 
365
366
367        //shows next page reports 
368        var nextStart = (nextPage) * itemsPerPage; 
369        var nextEnd = nextStart + itemsPerPage; 
370        for (let r = nextStart; r < nextEnd && r < totalTaggedRows; r++) { 
371            if (taggedRows[r].classList.contains("assetHidden")) { 
372                taggedRows[r].classList.remove("assetHidden"); 
373
374
375
376 
377    function handleShowingResults() { 
378        const startResultsLabel = document.getElementById('startResults_${portletID}'); 
379        startResultsLabel.innerText = nextStart + 1; 
380        const endResultsLabel = document.getElementById('endResults_${portletID}'); 
381        endResultsLabel.innerText = nextEnd < totalTaggedRows ? nextEnd : totalTaggedRows; 
382        const totalResultsLabel = document.getElementById('totalResults_${portletID}'); 
383        totalResultsLabel.innerText = totalTaggedRows; 
384
385 
386    function handlePaginationButtons() { 
387        var currentPageNumber = nextPage + 1; 
388        // numbered buttons 
389        const firstBtn = document.getElementById('firstBtn_${portletID}'); 
390        const secondBtn = document.getElementById('secondBtn_${portletID}'); 
391        const thirdBtn = document.getElementById('thirdBtn_${portletID}'); 
392        const fourthBtn = document.getElementById('fourthBtn_${portletID}'); 
393        if (totalPages <= 4 || currentPageNumber == 1 || currentPageNumber == 2 || currentPageNumber == 3) { 
394            updateButton(firstBtn, currentPageNumber, 1); 
395            updateButton(secondBtn, currentPageNumber, 2); 
396            updateButton(thirdBtn, currentPageNumber, 3); 
397            updateButton(fourthBtn, currentPageNumber, 4); 
398            startPagination = 1; 
399        } else if (currentPageNumber == totalPages) { 
400            updateButton(firstBtn, currentPageNumber, currentPageNumber - 3); 
401            updateButton(secondBtn, currentPageNumber, currentPageNumber - 2); 
402            updateButton(thirdBtn, currentPageNumber, currentPageNumber - 1); 
403            updateButton(fourthBtn, currentPageNumber, currentPageNumber); 
404            startPagination = currentPageNumber - 3; 
405        } else if (currentPageNumber == totalPages - 1) { 
406            updateButton(firstBtn, currentPageNumber, currentPageNumber - 2); 
407            updateButton(secondBtn, currentPageNumber, currentPageNumber - 1); 
408            updateButton(thirdBtn, currentPageNumber, currentPageNumber); 
409            updateButton(fourthBtn, currentPageNumber, currentPageNumber + 1); 
410            startPagination = currentPageNumber - 2; 
411        } else if (currentPageNumber > 3) { 
412            updateButton(firstBtn, currentPageNumber, currentPageNumber - 2); 
413            updateButton(secondBtn, currentPageNumber, currentPageNumber - 1); 
414            updateButton(thirdBtn, currentPageNumber, currentPageNumber); 
415            updateButton(fourthBtn, currentPageNumber, currentPageNumber + 1); 
416            startPagination = currentPageNumber - 2; 
417
418        // prev and next buttons 
419        const prevBtn = document.getElementById('prevBtn_${portletID}'); 
420        const nextBtn = document.getElementById('nextBtn_${portletID}'); 
421        if (currentPageNumber == 1) { 
422            prevBtn.classList.add('disabled'); 
423        } else { 
424            prevBtn.classList.remove('disabled'); 
425
426        if (currentPageNumber == totalPages) { 
427            nextBtn.classList.add('disabled'); 
428        } else { 
429            nextBtn.classList.remove('disabled'); 
430
431
432 
433    function updateButton(button, currentPageNumber, label) { 
434        // active 
435        if (currentPageNumber == label) { 
436            button.classList.add('active'); 
437        } else { 
438            button.classList.remove('active'); 
439
440        // label + visibility 
441        if (totalPages >= label && currentPageNumber <= totalPages) { 
442            button.classList.remove('assetHidden'); 
443            button.innerText = label; 
444        } else { 
445            button.classList.add('assetHidden'); 
446
447
448    // 
449    //EVENT LISTENERS // 
450    // Pagination event listener 
451    var prevBtn = document.getElementById(`prevBtn_${portletID}`); 
452    prevBtn.addEventListener('click', function(event) { 
453        handlePaginationChange("prev"); 
454    }); 
455    var firstBtn = document.getElementById(`firstBtn_${portletID}`); 
456    firstBtn.addEventListener('click', function(event) { 
457        handlePaginationChange("0"); 
458    }); 
459    var secondBtn = document.getElementById(`secondBtn_${portletID}`); 
460    secondBtn.addEventListener('click', function(event) { 
461        handlePaginationChange("1"); 
462    }); 
463    var thirdBtn = document.getElementById(`thirdBtn_${portletID}`); 
464    thirdBtn.addEventListener('click', function(event) { 
465        handlePaginationChange("2"); 
466    }); 
467    var fourthBtn = document.getElementById(`fourthBtn_${portletID}`); 
468    fourthBtn.addEventListener('click', function(event) { 
469        handlePaginationChange("3"); 
470    }); 
471    var nextBtn = document.getElementById(`nextBtn_${portletID}`); 
472    nextBtn.addEventListener('click', function(event) { 
473        handlePaginationChange("next"); 
474    }); 
475    /////////////////////// 
476})(); 
477</script>