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>