Notícias

Destaques
Um erro ocorreu enquanto processava o modelo.
The following has evaluated to null or missing:
==> imageDescription  [in template "20095#20121#NOTICIA-EM-DESTAQUE" at line 112, column 37]

----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----

----
FTL stack trace ("~" means nesting-related):
	- Failed at: ${imageDescription}  [in template "20095#20121#NOTICIA-EM-DESTAQUE" at line 112, column 35]
----
1<#assign prefix = 'psp' /> 
2<#assign articleId = .vars['reserved-article-id'].data /> 
3<#assign title = title???then(title.getData(), .vars["reserved-article-title"].data) /> 
4<#assign categories = restClient.get('/headless-delivery/v1.0/sites/' + groupId + '/structured-contents/by-key/' + articleId + '?fields=taxonomyCategoryBriefs')![] /> 
5 
6<#-- Suporta tanto videoLink (novo) quanto youtubeLink (retrocompatibilidade) --> 
7<#assign videoUrl = '' /> 
8<#if videoLink?? && videoLink.getData()?has_content> 
9    <#assign videoUrl = videoLink.getData() /> 
10<#elseif youtubeLink?? && youtubeLink.getData()?has_content> 
11    <#assign videoUrl = youtubeLink.getData() /> 
12</#if> 
13 
14<#assign isVideo = videoUrl?has_content /> 
15 
16<#assign imageUrl = (image?? && image.getData()?has_content)?then(image.getData(), '') /> 
17<#if imageUrl?has_content> 
18    <#assign imageFileEntryId = image.getAttribute("fileEntryId") /> 
19    <#assign imageDescription = image.getAttribute('alt')?has_content?then(image.getAttribute('alt'), 'Imagem de notícia') /> 
20</#if> 
21 
22<style> 
23.psp-highlighted-new--capital p.psp-highlighted-new__title { 
24    font-size: 1rem; 
25    line-height: 1rem; 
26    font-weight: var(--font-weight-semi-bold); 
27    color: var(--white); 
28} 
29 
30@media (min-width: 768px) { 
31    .psp-highlighted-new--capital p.psp-highlighted-new__title { 
32        font-size: 1.575rem; 
33        letter-spacing: -1px; 
34        font-weight: bold; 
35        line-height: 1.575rem; 
36        margin-top: 0; 
37    } 
38} 
39 
40.psp-highlighted-new--capital .psp-image-container--highlighted-new { 
41    border-radius: 10px !important; 
42    position: relative; 
43    overflow: hidden; 
44} 
45 
46.psp-highlighted-new--video { 
47    border-radius: 10px; 
48    display: flex; 
49    align-items: center; 
50    height: 85px; 
51} 
52 
53.psp-highlighted-new--capital .psp-highlighted-new__text-outer-container { 
54    display: flex; 
55    justify-content: center; 
56    align-items: center; 
57} 
58 
59.psp-highlighted-new--capital .psp-highlighted-new__text-inner-container { 
60    max-height: 75px; 
61    min-width: 100%; 
62} 
63 
64@media (min-width: 768px) { 
65    html.contrast .psp-highlighted-new--capital p.psp-highlighted-new__title { 
66        text-shadow: none; 
67    } 
68} 
69 
70.psp-scroll-capital__container { 
71  overflow-y: auto; 
72} 
73.psp-scroll-capital__container::-webkit-scrollbar { 
74  width: 5px; 
75} 
76.psp-scroll-capital__container::-webkit-scrollbar-thumb { 
77  background: #EC6608; 
78  border-radius: 0.25rem; 
79} 
80.psp-scroll-capital__container--light { 
81  overflow-y: auto; 
82} 
83.psp-scroll-capital__container--light::-webkit-scrollbar { 
84  width: 5px; 
85} 
86.psp-scroll-capital__container--light::-webkit-scrollbar-thumb { 
87  background: #fff; 
88  border-radius: 0.25rem; 
89} 
90</style> 
91 
92<#-- ============================================ --> 
93<#-- SEÇÃO DE NOTÍCIAS (NÃO-VÍDEO) --> 
94<#-- ============================================ --> 
95<#if !isVideo> 
96 
97    <#assign description = (description?? && description.getData()?has_content)?then(description.getData(), '') > 
98 
99    <#macro categoriesMarkup prefix categories> 
100        <#list categories as key, value> 
101            <#list value as category> 
102                <span class="${prefix}-badge text-2 font-weight-semi-bold font-base"> 
103                    ${category.taxonomyCategoryName} 
104                </span> 
105            </#list> 
106        </#list> 
107    </#macro> 
108 
109    <a class="${prefix}-highlighted-new ${prefix}-highlighted-new--capital ${prefix}-highlighted-new--${articleId}" href="${friendlyURL}" draggable="false"> 
110        <#-- ID Adicionado no container da imagem para injeção via JS --> 
111        <div class="${prefix}-image-container ${prefix}-image-container--highlighted-new" id="psp-image-container-${articleId}"> 
112            <span class="sr-only">${imageDescription}</span> 
113             
114            <#if imageUrl?has_content> 
115            <img class="${prefix}-image-container__image" src="${imageUrl}" data-fileentryid="${imageFileEntryId}" alt="${imageDescription}" loading="lazy" draggable="false" /> 
116            </#if> 
117        </div> 
118 
119        <#assign isTextAndDescriptionHidden = (hideTitleAndDescription?? && hideTitleAndDescription.getData()?has_content)?then(getterUtil.getBoolean(hideTitleAndDescription.getData()), false) > 
120 
121        <#if !isTextAndDescriptionHidden> 
122            <div class="${prefix}-highlighted-new__text-outer-container p-2 mt-2" style="background: var(--primary);"> 
123             
124                <div class="${prefix}-badge__container"> 
125                    <@categoriesMarkup prefix categories /> 
126                </div> 
127                 
128                <div class="${prefix}-highlighted-new__text-inner-container pl-1 pl-md-2 ${prefix}-scroll-capital__container--light"> 
129                    <p class="${prefix}-highlighted-new__title mb-0 font-base line-clamp-2"> 
130                        <#if altTitle?? && altTitle.getData()?has_content> 
131                            ${altTitle.getData()} 
132                        <#else> 
133                            ${title}     
134                        </#if> 
135                    </p> 
136                </div> 
137            </div> 
138        </#if> 
139    </a> 
140 
141    <#-- SCRIPT DO SLIDER ANTES/DEPOIS PARA O CARD --> 
142    <script> 
143        (function() { 
144            const articleId = '${articleId}'; 
145            const groupId = themeDisplay.getSiteGroupId(); 
146            const container = document.getElementById('psp-image-container-' + articleId); 
147             
148            if (!container) return; 
149 
150            fetch('/o/headless-delivery/v1.0/sites/' + groupId + '/structured-contents/by-key/' + articleId) 
151                .then(response => response.json()) 
152                .then(data => { 
153                    if (data.relatedContents && data.relatedContents.length > 0) { 
154                        const imagePromises = data.relatedContents.map(content =>  
155                            fetch('/o/headless-delivery/v1.0/documents/' + content.id).then(res => res.json()) 
156                        ); 
157                         
158                        Promise.all(imagePromises).then(documents => { 
159                            let imgAntes = ''; 
160                            let imgDepois = ''; 
161                             
162                            documents.forEach(doc => { 
163                                if (doc.contentUrl) { 
164                                    const title = (doc.title || '').toLowerCase(); 
165                                    const url = doc.contentUrl.replace(/(\?|&)download=true/g, '$1download=false'); 
166                                     
167                                    if (title.includes('slider-antes')) imgAntes = url; 
168                                    if (title.includes('slider-depois')) imgDepois = url; 
169                                } 
170                            }); 
171 
172                            if (imgAntes && imgDepois) { 
173                                // Substitui a imagem estática pela estrutura do Slider, bloqueando comportamentos nativos de drag 
174                                container.innerHTML = ` 
175                                    <div class="cx-slider-wrapper" style="width: 100%; height: 100%; position: absolute; inset: 0;" draggable="false" ondragstart="return false;"> 
176                                        <style> 
177                                            .cx-slider-container-${articleId} { --pos: 50%; position: relative; width: 100%; height: 100%; overflow: hidden; display: flex; user-select: none; -webkit-user-drag: none; } 
178                                            .cx-img-panel-${articleId} { position: absolute; inset: 0; width: 100%; height: 100%; } 
179                                            .cx-img-panel-${articleId} img { width: 100%; height: 100%; object-fit: cover; pointer-events: none; display: block; -webkit-user-drag: none; } 
180                                            .cx-img-before-${articleId} { clip-path: polygon(0 0, var(--pos) 0, var(--pos) 100%, 0 100%); z-index: 2; } 
181                                            .cx-img-after-${articleId} { clip-path: polygon(var(--pos) 0, 100% 0, 100% 100%, var(--pos) 100%); z-index: 1; } 
182                                            .cx-label-${articleId} { position: absolute; top: 10px; padding: 4px 10px; background: rgba(0,0,0,0.6); color: #fff; border-radius: 12px; font-family: sans-serif; font-size: 11px; font-weight: bold; pointer-events: none; z-index: 5; } 
183                                            .cx-label-before-${articleId} { left: 10px; } 
184                                            .cx-label-after-${articleId} { right: 10px; } 
185                                            .cx-slider-${articleId} { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; z-index: 10; cursor: ew-resize; margin: 0; } 
186                                            .cx-handle-${articleId} { position: absolute; top: 0; bottom: 0; left: var(--pos); width: 3px; background: #fff; transform: translateX(-50%); pointer-events: none; z-index: 8; box-shadow: 0 0 5px rgba(0,0,0,0.5); } 
187                                            .cx-handle-btn-${articleId} { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 30px; height: 30px; background: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 5px rgba(0,0,0,0.3); } 
188                                            .cx-handle-btn-${articleId} svg { width: 18px; height: 18px; color: #333; } 
189                                        </style> 
190                                        <div class="cx-slider-container-${articleId}" style="--pos: 50%;"> 
191                                            <div class="cx-img-panel-${articleId} cx-img-after-${articleId}"> 
192                                                <img src="` + imgDepois + `" alt="Depois" draggable="false" /> 
193                                                <span class="cx-label-${articleId} cx-label-after-${articleId}">Depois</span> 
194                                            </div> 
195                                            <div class="cx-img-panel-${articleId} cx-img-before-${articleId}"> 
196                                                <img src="` + imgAntes + `" alt="Antes" draggable="false" /> 
197                                                <span class="cx-label-${articleId} cx-label-before-${articleId}">Antes</span> 
198                                            </div> 
199                                            <input type="range" min="0" max="100" value="50" class="cx-slider-${articleId}" oninput="this.parentElement.style.setProperty('--pos', this.value + '%')" draggable="false" ondragstart="return false;"> 
200                                            <div class="cx-handle-${articleId}"> 
201                                                <div class="cx-handle-btn-${articleId}"> 
202                                                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"> 
203                                                        <path d="M10 16l-4-4 4-4M14 8l4 4-4 4" /> 
204                                                    </svg> 
205                                                </div> 
206                                            </div> 
207                                        </div> 
208                                    </div> 
209                                `; 
210 
211                                // O pulo do gato: Interceptando e parando a propagação de TODOS os eventos do slider 
212                                // Isso impede que clicar e arrastar a barra acione a tag <a> (Link) ou arraste a imagem 
213                                const rangeInput = container.querySelector('.cx-slider-' + articleId); 
214                                if(rangeInput) { 
215                                    const stopEvents = ['click', 'mousedown', 'mousemove', 'mouseup', 'touchstart', 'touchmove', 'touchend', 'dragstart']; 
216                                     
217                                    stopEvents.forEach(evt => { 
218                                        rangeInput.addEventListener(evt, function(e) { 
219                                            e.stopPropagation(); 
220                                            // Se for clique ou tentativa de drag, evita o comportamento padrão do navegador 
221                                            if (evt === 'dragstart' || evt === 'click') { 
222                                                e.preventDefault(); 
223                                            } 
224                                        }, { passive: false }); 
225                                    }); 
226                                } 
227                            } 
228                        }); 
229                    } 
230                }) 
231                .catch(err => console.error("Erro ao carregar slider antes/depois no card:", err)); 
232        })(); 
233    </script> 
234 
235<#-- ============================================ --> 
236<#-- SEÇÃO DE VÍDEOS (UNIVERSAL COM AUTO-DETECÇÃO) --> 
237<#-- ============================================ --> 
238<#else> 
239 
240    <#-- ========================================== --> 
241    <#-- FUNÇÃO PARA ADICIONAR PARÂMETROS NA URL --> 
242    <#-- ========================================== --> 
243    <#function addUrlParameter url paramName paramValue> 
244        <#if url?contains("?")> 
245            <#-- URL já tem parâmetros, adiciona com & --> 
246            <#if url?contains(paramName + "=")> 
247                <#-- Parâmetro já existe, não adiciona duplicado --> 
248                <#return url /> 
249            <#else> 
250                <#return url + "&" + paramName + "=" + paramValue /> 
251            </#if> 
252        <#else> 
253            <#-- URL não tem parâmetros, adiciona com ? --> 
254            <#return url + "?" + paramName + "=" + paramValue /> 
255        </#if> 
256    </#function> 
257 
258    <#-- ========================================== --> 
259    <#-- PROCESSAMENTO DA URL COM PARÂMETROS --> 
260    <#-- ========================================== --> 
261    <#assign processedUrl = videoUrl /> 
262     
263    <#-- Detecta e processa YouTube --> 
264    <#if videoUrl?contains("youtube.com") || videoUrl?contains("youtu.be") || videoUrl?contains("youtube-nocookie.com")> 
265        <#assign processedUrl = addUrlParameter(processedUrl, "autoplay", "1") /> 
266                <#assign processedUrl = addUrlParameter(processedUrl, "mute", "0") /> 
267        <#assign processedUrl = addUrlParameter(processedUrl, "rel", "0") /> 
268        <#assign processedUrl = addUrlParameter(processedUrl, "controls", "0") /> 
269        <#assign processedUrl = addUrlParameter(processedUrl, "modestbranding", "1") /> 
270     
271    <#-- Detecta e processa Vimeo --> 
272    <#elseif videoUrl?contains("vimeo.com")> 
273        <#assign processedUrl = addUrlParameter(processedUrl, "autoplay", "1") /> 
274        <#assign processedUrl = addUrlParameter(processedUrl, "title", "0") /> 
275        <#assign processedUrl = addUrlParameter(processedUrl, "byline", "0") /> 
276        <#assign processedUrl = addUrlParameter(processedUrl, "portrait", "0") /> 
277     
278    <#-- Detecta e processa Dailymotion --> 
279    <#elseif videoUrl?contains("dailymotion.com")> 
280        <#assign processedUrl = addUrlParameter(processedUrl, "autoplay", "1") /> 
281        <#assign processedUrl = addUrlParameter(processedUrl, "ui-start-screen-info", "0") /> 
282        <#assign processedUrl = addUrlParameter(processedUrl, "sharing-enable", "0") /> 
283     
284    <#-- Detecta e processa Wistia --> 
285    <#elseif videoUrl?contains("wistia.com") || videoUrl?contains("wistia.net")> 
286        <#assign processedUrl = addUrlParameter(processedUrl, "autoPlay", "1") /> 
287        <#assign processedUrl = addUrlParameter(processedUrl, "controlsVisibleOnLoad", "true") /> 
288     
289    <#-- Detecta e processa Facebook Video --> 
290    <#elseif videoUrl?contains("facebook.com")> 
291        <#assign processedUrl = addUrlParameter(processedUrl, "autoplay", "1") /> 
292        <#assign processedUrl = addUrlParameter(processedUrl, "show_text", "0") /> 
293     
294    <#-- Detecta e processa Twitch --> 
295    <#elseif videoUrl?contains("twitch.tv")> 
296        <#assign processedUrl = addUrlParameter(processedUrl, "autoplay", "true") /> 
297        <#assign processedUrl = addUrlParameter(processedUrl, "parent", "localhost") /> 
298     
299    <#-- Para outras plataformas, tenta adicionar autoplay genérico --> 
300    <#else> 
301        <#assign processedUrl = addUrlParameter(processedUrl, "autoplay", "1") /> 
302    </#if> 
303 
304    <#-- ========================================== --> 
305    <#-- RENDERIZAÇÃO DO VÍDEO --> 
306    <#-- ========================================== --> 
307 
308    <div class="${prefix}-highlighted-new ${prefix}-highlighted-new--capital ${prefix}-highlighted-new--${articleId}"> 
309        <div class="${prefix}-image-container ${prefix}-image-container--highlighted-new"> 
310 
311            <#-- Exibe imagem customizada se existir, senão exibe um placeholder --> 
312            <#if imageUrl?has_content> 
313                <img class="${prefix}-image-container__image" src="${imageUrl}" data-fileentryid="${imageFileEntryId}" alt="${imageDescription}" loading="lazy" style="border-radius: 10px" /> 
314            <#else> 
315                <div class="${prefix}-image-container__image" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 10px; min-height: 200px; display: flex; align-items: center; justify-content: center;"> 
316                    <svg width="80" height="80" viewBox="0 0 24 24" fill="white" opacity="0.8"> 
317                        <path d="M8 5v14l11-7z"/> 
318                    </svg> 
319                </div> 
320            </#if> 
321 
322            <div class="${prefix}-image-container__content justify-content-end"> 
323                <#-- Botão de Play --> 
324                <a title="Executar vídeo" id="video-play-button-${randomNamespace}" href="#" onclick="event.preventDefault(); playVideo${randomNamespace}()" class="position-absolute top-0 left-0 w-100 h-100 d-flex align-items-center justify-content-center z-index-1" style="background-color: rgba(0,0,0,0.35); border-radius:10px"> 
325                    <span class="sr-only">Executar vídeo</span> 
326                    <svg class="d-none d-md-block" fill="#FFFFFF" height="160" width="160" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60"> 
327                        <g> 
328                            <path d="M45.563,29.174l-22-15c-0.307-0.208-0.703-0.231-1.031-0.058C22.205,14.289,22,14.629,22,15v30 c0,0.371,0.205,0.711,0.533,0.884C22.679,45.962,22.84,46,23,46c0.197,0,0.394-0.059,0.563-0.174l22-15 C45.836,30.64,46,30.331,46,30S45.836,29.36,45.563,29.174z M24,43.107V16.893L43.225,30L24,43.107z"></path> 
329                            <path d="M30,0C13.458,0,0,13.458,0,30s13.458,30,30,30s30-13.458,30-30S46.542,0,30,0z M30,58C14.561,58,2,45.439,2,30 S14.561,2,30,2s28,12.561,28,28S45.439,58,30,58z"></path> 
330                        </g> 
331                    </svg> 
332                    <svg class="d-md-none" fill="#FFFFFF" height="60" width="60" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60"> 
333                        <g> 
334                            <path d="M45.563,29.174l-22-15c-0.307-0.208-0.703-0.231-1.031-0.058C22.205,14.289,22,14.629,22,15v30 c0,0.371,0.205,0.711,0.533,0.884C22.679,45.962,22.84,46,23,46c0.197,0,0.394-0.059,0.563-0.174l22-15 C45.836,30.64,46,30.331,46,30S45.836,29.36,45.563,29.174z M24,43.107V16.893L43.225,30L24,43.107z"></path> 
335                            <path d="M30,0C13.458,0,0,13.458,0,30s13.458,30,30,30s30-13.458,30-30S46.542,0,30,0z M30,58C14.561,58,2,45.439,2,30 S14.561,2,30,2s28,12.561,28,28S45.439,58,30,58z"></path> 
336                        </g> 
337                    </svg> 
338                </a> 
339 
340                <#-- Iframe universal com URL processada --> 
341                <iframe id="iframe-video-${randomNamespace}"  
342                        class="d-none border-none w-100 h-100"  
343                        data-src="${processedUrl}"  
344                        title="Vídeo - ${title}"  
345                        frameborder="0"  
346                        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"  
347                        referrerpolicy="strict-origin-when-cross-origin"  
348                        allowfullscreen> 
349                </iframe> 
350            </div> 
351        </div> 
352 
353        <#assign isTextHidden = (hideTitle?? && hideTitle.getData()?has_content)?then(getterUtil.getBoolean(hideTitle.getData()), false) > 
354        <#assign linkDirecionamento = (linkDirecionamentoVideo?? && linkDirecionamentoVideo.getData()?has_content)?then(linkDirecionamentoVideo.getData(), '') > 
355        <#assign hasLink = linkDirecionamento?has_content > 
356 
357        <#if !isTextHidden> 
358            <div id="video-title-${randomNamespace}" class="${prefix}-highlighted-new--video p-2 mt-2 z-index-1" style="background: var(--primary);"> 
359                <div class="pl-1 pl-md-2"> 
360                    <#if hasLink> 
361                        <a href="${linkDirecionamento}" class="text-decoration-none" target="_blank" rel="noopener noreferrer"> 
362                            <p class="${prefix}-highlighted-new__title mb-0 font-base line-clamp-2"> 
363                                <#if altTitle?? && altTitle.getData()?has_content> 
364                                    ${altTitle.getData()} 
365                                <#else>  
366                                    ${title}   
367                                </#if> 
368                            </p> 
369                        </a> 
370                    <#else> 
371                        <p class="${prefix}-highlighted-new__title mb-0 font-base line-clamp-2"> 
372                            <#if altTitle?? && altTitle.getData()?has_content> 
373                                ${altTitle.getData()} 
374                            <#else>  
375                                ${title}   
376                            </#if> 
377                        </p> 
378                    </#if> 
379                </div> 
380            </div> 
381        </#if> 
382    </div> 
383 
384    <#-- Scripts de controle de vídeo --> 
385    <script> 
386        function playVideo${randomNamespace}() { 
387            let swiper = document.querySelector(".psp-news-highlighter > .swiper").swiper; 
388            let $iframe = document.getElementById('iframe-video-${randomNamespace}'); 
389            let $title = document.getElementById('video-title-${randomNamespace}'); 
390            let $playButton = document.getElementById('video-play-button-${randomNamespace}'); 
391             
392            // Exibe o iframe e carrega a URL do vídeo 
393            $iframe.classList.remove('d-none'); 
394            $iframe.setAttribute('src', $iframe.getAttribute('data-src')); 
395             
396            // Oculta o botão de play 
397            $playButton.classList.add('d-none'); 
398            $playButton.classList.remove('d-flex'); 
399 
400            // Para o autoplay do carrossel 
401            if (swiper && swiper.autoplay) { 
402                swiper.autoplay.stop();             
403                swiper.on('slideChange', stopVideo${randomNamespace}); 
404            } 
405        } 
406 
407        function stopVideo${randomNamespace}() { 
408            let swiper = document.querySelector(".psp-news-highlighter > .swiper").swiper; 
409            let $iframe = document.getElementById('iframe-video-${randomNamespace}'); 
410            let $title = document.getElementById('video-title-${randomNamespace}'); 
411            let $playButton = document.getElementById('video-play-button-${randomNamespace}'); 
412             
413            // Oculta o iframe e remove a source (para o vídeo) 
414            $iframe.classList.add('d-none'); 
415            $iframe.setAttribute('src', ''); 
416             
417            // Mostra o botão de play novamente 
418            $playButton.classList.remove('d-none'); 
419            $playButton.classList.add('d-flex'); 
420             
421            // Reinicia o autoplay do carrossel 
422            if (swiper && swiper.autoplay) { 
423                swiper.autoplay.start(); 
424                swiper.on('slideChange', function() {}); 
425            } 
426        } 
427    </script> 
428 
429</#if> 
Vídeos
Publicações diárias
Todas notícias chevron_right
Encontre publicações por data