Favoritas Globales
Consulta los cambios en el portafolio de Favoritas Globales, con una selección de empresas relevantes en el S&P 500.
Se ha producido un error al procesar la plantilla.
Failed to "?eval" string with this error:
---begin-message---
Syntax error in ?eval-ed string in line 1, column 48:
Lexical error: encountered "u" (117), after "\"Favoritas Globales \\".
---end-message---
The failing expression:
==> imageValue?eval [in template "20101#20128#10741808" at line 174, column 58]
----
FTL stack trace ("~" means nesting-related):
- Failed at: #assign imageJSON = imageValue?eval [in template "20101#20128#10741808" at line 174, column 37]
---- 1<#-- Vertical List Template with Infinite Scroll for Asset Publisher - Blog Entries --> 2<#if entries?has_content> 3 <style> 4 5 :root { 6 --brand: #1A2433; 7 --muted: #314566; 8 } 9 10 .reports-list-container { 11 font-family: "Poppins"; 12 padding: 10px 0; 13 } 14 15 /* List Item Styles */ 16 .report-list-item { 17 display: flex; 18 align-items: flex-start; 19 gap: 24px; 20 padding: 20px 0; 21 border-bottom: 1px solid #CCC; 22 } 23 .clickeable { 24 text-decoration: none; 25 } 26 .clickeable:hover { 27 text-decoration: none; 28 } 29 30 .report-list-item:first-child { 31 padding-top: 0; 32 } 33 34 .report-list-item:last-child { 35 border-bottom: none; 36 } 37 38 .report-item-image-container { 39 flex-shrink: 0; 40 width: 300px; 41 height: 200px; 42 overflow: hidden; 43 display: flex; 44 align-items: center; 45 justify-content: center; 46 } 47 48 .report-item-image { 49 width: 100%; 50 height: 100%; 51 object-fit: cover; 52 transition: transform 0.6s ease; 53 } 54 55 .report-list-item:hover .report-item-image { 56 transform: scale(1.08); 57 } 58 59 .report-item-body { 60 flex-grow: 1; 61 flex-direction: column; 62 align-content: space-between; 63 } 64 65 .report-item-title { 66 color: var(--brand) !important; 67 font-weight: 700; 68 line-height: 1.25; 69 font-size: clamp(1.2rem, 2.5vw, 1.4rem); 70 margin: 0 0 10px 0; 71 } 72 73 .report-item-date { 74 font-family: "Poppins"; 75 color: var(--muted) !important; 76 font-weight: 600; 77 line-height: 1.5; 78 font-size: clamp(0.9rem, 2vw, 1rem); 79 margin: 0 0 10px 0; 80 } 81 82 .report-item-description { 83 font-family: "Poppins"; 84 color: var(--muted); 85 line-height: 1.5; 86 font-size: clamp(.9rem, 2vw, 1rem); 87 margin: 0 0 15px 0; 88 } 89 90 .report-link { 91 background-color: #FFF !important; 92 font-family: "Poppins" !important; 93 color: var(--brand) !important; 94 font-weight: 600; 95 font-size: clamp(1.1rem, 2vw, 1.2rem); 96 border-radius: 6px; 97 text-decoration: none; 98 display: inline-flex; 99 align-items: center; 100 gap: 8px; 101 transition: background-color .18s ease, color .18s ease, transform .12s ease, box-shadow .12s ease; 102 align-self: flex-start; 103 } 104 105 .report-link:hover { 106 text-decoration: none; 107 transform: translateY(-2px); 108 } 109 110 /* Loading indicator */ 111 .loading-indicator { 112 text-align: center; 113 padding: 20px; 114 color: var(--muted); 115 font-style: italic; 116 } 117 118 /* Responsive Styles */ 119 @media (max-width: 768px) { 120 .report-list-item { 121 flex-direction: column; 122 gap: 16px; 123 } 124 125 .report-item-image-container { 126 width: 100%; 127 height: 200px; 128 } 129 } 130 </style> 131 132 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"> 133 134 <div class="reports-list-container"> 135 <#assign PAGE_SIZE = 10> 136 <#list entries as entry> 137 <#assign currentIndex = entry?index> 138 <#assign isHidden = currentIndex gte PAGE_SIZE> 139 <div class="report-list-item" data-index="${currentIndex}" style="display: ${isHidden?string('none', 'flex')};"> 140 <#assign assetRenderer = entry.getAssetRenderer() /> 141 <#if assetRenderer.getBlogsEntry??> 142 <#assign blogEntry = assetRenderer.getBlogsEntry() /> 143 <#else> 144 <#assign blogEntry = assetRenderer.getAssetObject() /> 145 </#if> 146 147 <#-- Get field values for blog entries --> 148 <#assign description = entry.getDescription(locale) /> 149 <#if !description?has_content && blogEntry.getContent??> 150 <#assign description = blogEntry.getContent() /> 151 </#if> 152 153 <#assign viewURL = assetPublisherHelper.getAssetViewURL(renderRequest, renderResponse, entry) /> 154 <#assign viewURL = assetRenderer.getURLViewInContext(renderRequest, renderResponse, viewURL) /> 155 156 <a class="clickeable" href="${viewURL}"> 157 158 <#-- Image --> 159 <div class="report-item-image-container"> 160 <#assign imageURL = "" /> 161 <#assign fileEntryId = "" /> 162 163 <#-- Get the Web Content article and its DDM form values --> 164 <#if assetRenderer.getClassName() == "com.liferay.journal.model.JournalArticle"> 165 <#assign journalArticle = assetRenderer.getArticle() /> 166 <#assign ddmFormValues = journalArticle.getDDMFormValues() /> 167 <#assign ddmFields = ddmFormValues.getDDMFormFieldValues() /> 168 169 <#-- Loop through fields to find the image field by reference --> 170 <#list ddmFields as field> 171 <#if field.getFieldReference() == "image"> 172 <#assign imageValue = field.getValue().getString(locale) /> 173 <#if imageValue?has_content> 174 <#assign imageJSON = imageValue?eval /> 175 <#assign fileEntryId = imageJSON.fileEntryId!"" /> 176 <#assign groupId = imageJSON.groupId!"" /> 177 <#assign uuid = imageJSON.uuid!"" /> 178 <#assign title = imageJSON.title!"" /> 179 180 <#-- Construct image URL --> 181 <#assign imageURL = "/documents/" + groupId + "/0/" + title + "/" + uuid + "?t=" + .now?long /> 182 </#if> 183 <#break> 184 </#if> 185 </#list> 186 </#if> 187 188 <#if imageURL?has_content> 189 <img class="report-item-image" data-fileentryid="${fileEntryId}" src="${imageURL}" alt="${entry.getTitle(locale)}"> 190 <#else> 191 <img class="report-item-image" src="https://via.placeholder.com/300x200" alt="No image available"> 192 </#if> 193 </div> 194 195 <div class="report-item-body"> 196 <#-- Title --> 197 <h2 class="report-item-title">${entry.getTitle(locale)}</h2> 198 199 <#-- Date --> 200 <#assign dateValue = entry.getCreateDate() /> 201 <#if blogEntry.getDisplayDate??> 202 <#attempt> 203 <#assign dateValue = blogEntry.getDisplayDate() /> 204 <#recover> 205 <#assign dateValue = entry.getCreateDate() /> 206 </#attempt> 207 </#if> 208 <div class="report-item-date"> 209 <span> 210 <i class="far fa-calendar-alt mr-1"></i> ${dateValue?string("MMM dd, yyyy")} 211 </span> 212 </div> 213 214 <#-- Description --> 215 <#if description?has_content> 216 <#assign plainDescription = description?replace("<[^>]*>", "", "r") /> 217 <p class="report-item-description"> 218 <#if plainDescription?length gt 400> 219 ${plainDescription?substring(0, 400)}... 220 <#else> 221 ${plainDescription} 222 </#if> 223 </p> 224 <#else> 225 <p class="report-item-description">No description available.</p> 226 </#if> 227 228 <#-- Link --> 229 <a href="${viewURL}" class="report-link" title="Leer entrada"> 230 Leer entrada 231 </a> 232 </div> 233 </a> 234 </div> 235 </#list> 236 237 <#if entries?size gt PAGE_SIZE> 238 <div class="loading-indicator">Cargando más entradas...</div> 239 </#if> 240 </div> 241 242 <script> 243 document.addEventListener("DOMContentLoaded", function() { 244 const container = document.querySelector(".reports-list-container"); 245 const items = document.querySelectorAll(".report-list-item"); 246 const loadingIndicator = document.querySelector(".loading-indicator"); 247 const pageSize = 10; 248 let currentItemIndex = pageSize; 249 250 function showNextItems() { 251 const totalItems = items.length; 252 if (currentItemIndex >= totalItems) { 253 loadingIndicator.style.display = "none"; 254 return; 255 } 256 257 const itemsToShow = Math.min(currentItemIndex + pageSize, totalItems); 258 259 for (let i = currentItemIndex; i < itemsToShow; i++) { 260 items[i].style.display = "flex"; 261 } 262 263 currentItemIndex = itemsToShow; 264 } 265 266 function handleScroll() { 267 // Get the distance from the bottom of the page to the bottom of the viewport 268 const containerBottom = container.getBoundingClientRect().bottom; 269 const windowHeight = window.innerHeight; 270 271 // Load more content when the user scrolls near the bottom of the container 272 if (containerBottom <= windowHeight + 100) { 273 showNextItems(); 274 } 275 } 276 277 // Initial check in case the content is shorter than the viewport 278 showNextItems(); 279 280 // Add scroll event listener to the window 281 window.addEventListener("scroll", handleScroll); 282 283 // Hide the loading indicator if there are no more items to load 284 if (items.length <= pageSize) { 285 loadingIndicator.style.display = "none"; 286 } 287 }); 288 </script> 289</#if>