theme/templates/blocks/B51_search_results/B51_search_results.default.html.twig line 1

Open in your IDE?
  1. {% if hasGeneralSearch %}
  2.     {% import 'blocks\\macros.html.twig' as macros %}
  3.     <section class="block-search-results" {{ macros.getBlockDataAttributes(_context) }}>
  4.         <div class="container">
  5.             {% if values|length == 0 %}
  6.                 {{ 'zerorecords'|trans([],'studio') }}
  7.             {% else %}
  8.                 {# ---------------------------------------------- #}
  9.                 {# Prepare data: items collection & type counts   #}
  10.                 {# ---------------------------------------------- #}
  11.                 {% set resultsMeta = results is defined ? results : {
  12.                     'items': values.items is defined ? values.items : values,
  13.                     'counts': {'news':0,'news_reports':0,'programs':0,'event':0,'all':0},
  14.                     'currentType': app.request.query.get('type')|default('all'),
  15.                     'order': app.request.query.get('order')|default('relevance'),
  16.                     'page': (app.request.query.get('page')|default(1)) + 0,
  17.                     'pageSize': 15,
  18.                     'pageCount': 1,
  19.                     'nextPage': 0,
  20.                     'total': (values.items is defined ? values.items|length : values|length),
  21.                     'totalAll': (values.items is defined ? values.items|length : values|length)
  22.                 } %}
  23.                 {% set items = resultsMeta.items %}
  24.                 {% set counts = resultsMeta.counts %}
  25.                 {% set currentType = resultsMeta.currentType %}
  26.                 {% set order = resultsMeta.order %}
  27.                 {% set route = app.request.attributes.get('_route') %}
  28.                 {% set routeParams = app.request.attributes.get('_route_params')|default({}) %}
  29.                 {% set currentPage = resultsMeta.page %}
  30.                 {% set pageSize = resultsMeta.pageSize %}
  31.                 {% set pageCount = resultsMeta.pageCount %}
  32.                 {% set nextPage = resultsMeta.nextPage %}
  33.                 {% set totalItems = resultsMeta.total %}
  34.                 {% set pageItems = items %}
  35.                 {# --- Server-side filtering (tags[]=machine, themes[]=label) --- #}
  36.                 {# Backend now applies tags[] and themes[] filtering; template no longer re-filters #}
  37.                 {# ---------------------------------------------- #}
  38.                 {# Results header (counts + ordering)             #}
  39.                 {# ---------------------------------------------- #}
  40.                 {% if app.request.query.get('p') %}
  41.                     {% set resultString = '<h1 class="results-title">Conta lá <span>' ~ app.request.query.get('p') ~ '</span></h1>' %}
  42.                 {% elseif app.request.query.get('themes') %}
  43.                     {% set themes = app.request.query.get('themes') %}
  44.                     {% set resultString = '<h1 class="results-title">Conta lá <span>' ~ (themes|length == 1 ? themes[0] : themes|join(', ')) ~ '</span></h1>' %}
  45.                 {% endif %}
  46.                 {{ resultString|default|raw }}
  47.                 <div class="results-bar mb-4" data-current-page="{{ currentPage }}" data-page-count="{{ pageCount }}"
  48.                      data-page-size="{{ pageSize }}"
  49.                      data-total-all="{{ resultsMeta.totalAll is defined ? resultsMeta.totalAll : (total is defined ? total : totalItems) }}">
  50.                     <div class="results-bar-top d-flex flex-column flex-md-row justify-content-between align-items-md-center gap-3">
  51.                         <div class="results-stats">
  52.                             <span class="results-found-prefix">Encontrados</span>
  53.                             <span class="results-total">{{ resultsMeta.totalAll is defined ? resultsMeta.totalAll : (total is defined ? total : totalItems) }}</span>
  54.                             <span class="results-found-suffix">{{ 'results'|trans ({},'geral') }}</span>
  55.                         </div>
  56.                     </div>
  57.                     {# Tabs #}
  58.                     <nav class="results-tabs mt-3">
  59.                         <ul class="results-tab-list list-unstyled d-flex mb-0 p-0 gap-1">
  60.                             {% set tabMap = {
  61.                                 'all': 'Todos',
  62.                                 'news': 'Notícias',
  63.                                 'news_reports': 'Reportagens',
  64.                                 'programs': 'Programas',
  65.                                 'event': 'Eventos'
  66.                             } %}
  67.                             {# Define the order we want to display tabs #}
  68.                             {% set tabOrder = ['all', 'news', 'news_reports', 'programs', 'event'] %}
  69.                             {# restrict by content_type[] when provided #}
  70.                             {% set ctParam = app.request.query.get('content_type') %}
  71.                             {% set selectedTypes = ctParam is iterable ? ctParam : (ctParam ? [ctParam] : []) %}
  72.                             {% set selected = [] %}
  73.                             {% for ct in selectedTypes %}
  74.                                 {% set selected = selected|merge([ct|lower]) %}
  75.                             {% endfor %}
  76.                             {# build tab objects in the specified order, showing all tabs #}
  77.                             {% set tabs = [] %}
  78.                             {% for tKey in tabOrder %}
  79.                                 {% if tabMap[tKey] is defined %}
  80.                                     {% set tLabel = tabMap[tKey] %}
  81.                                     {% set cnt = counts[tKey]|default(0) %}
  82.                                     {# Always add the tab, regardless of count or selection #}
  83.                                     {% set tabs = tabs|merge([{'key': tKey, 'label': tLabel, 'count': cnt}]) %}
  84.                                 {% endif %}
  85.                             {% endfor %}
  86.                             {# Find the first tab with count > 0 to auto-select if current type has no results #}
  87.                             {% set firstTabWithResults = 'all' %}
  88.                             {% for tab in tabs %}
  89.                                 {% if tab.count > 0 and firstTabWithResults == 'all' and tab.key != 'all' %}
  90.                                     {% set firstTabWithResults = tab.key %}
  91.                                 {% endif %}
  92.                             {% endfor %}
  93.                             {# Auto-select "Todos" tab by default, or first tab with results if "Todos" has no results #}
  94.                             {% set currentTypeCount = counts[currentType]|default(0) %}
  95.                             {# Don't override currentType if it's already set correctly by the backend #}
  96.                             {% if currentTypeCount == 0 and currentType != 'all' and counts['all']|default(0) > 0 %}
  97.                                 {% set currentType = 'all' %}
  98.                             {% elseif currentTypeCount == 0 and counts['all']|default(0) == 0 %}
  99.                                 {% set currentType = firstTabWithResults %}
  100.                             {% endif %}
  101.                             {% for tab in tabs %}
  102.                                 {% set tKey = tab.key %}
  103.                                 {% set tLabel = tab.label %}
  104.                                 {% set linkParams = routeParams|merge(app.request.query.all)|merge({'type': tKey, 'page': 1}) %}
  105.                                 {% set isDisabled = tab.count == 0 %}
  106.                                 <li class="results-tab-item{% if currentType == tKey %} active{% endif %}{% if isDisabled %} disabled{% endif %}">
  107.                                     {% if route and not isDisabled %}
  108.                                         <a class="results-tab-link d-inline-block p-3{% if currentType == tKey %} active{% endif %}"
  109.                                            href="{{ path(route, linkParams) }}">
  110.                                             <span class="results-tab-text">{{ tLabel }}</span>
  111.                                             <span class="results-tab-count">({{ tab.count }})</span>
  112.                                         </a>
  113.                                     {% else %}
  114.                                         <span class="results-tab-link d-inline-block p-3{% if currentType == tKey %} active{% endif %}">
  115.                                             <span class="results-tab-text">{{ tLabel }}</span>
  116.                                             <span class="results-tab-count">({{ tab.count }})</span>
  117.                                         </span>
  118.                                     {% endif %}
  119.                                 </li>
  120.                             {% endfor %}
  121.                         </ul>
  122.                     </nav>
  123.                     {# Ordering form #}
  124.                     <form class="results-order-form d-flex align-items-center mt-4" method="get">
  125.                         {# preserve all current query params except order #}
  126.                         {% for key,value in app.request.query.all %}
  127.                             {% if key not in ['order'] %}
  128.                                 {% if value is iterable %}
  129.                                     {% for v in value %}<input type="hidden" name="{{ key }}[]" value="{{ v }}">{% endfor %}
  130.                                 {% else %}
  131.                                     <input type="hidden" name="{{ key }}" value="{{ value }}">
  132.                                 {% endif %}
  133.                             {% endif %}
  134.                         {% endfor %}
  135.                         <label for="order_select" class="mb-0 small">Ordenar por</label>
  136.                         <div class="select-wrapper">
  137.                             <select id="order_select" name="order" class="form-select form-select-sm" onchange="this.form.submit()">
  138.                                 <option value="relevance" {{ order == 'relevance' ? 'selected' }}>Relevância</option>
  139.                                 <option value="newest" {{ order == 'newest' ? 'selected' }}>Mais recentes</option>
  140.                                 <option value="popular" {{ order == 'popular' ? 'selected' }}>Populares</option>
  141.                             </select>
  142.                             <i class="fa-solid fa-chevron-down"></i>
  143.                         </div>
  144.                     </form>
  145.                 </div>
  146.                 {# ---------------------------------------------- #}
  147.                 {# Results grid list                                #}
  148.                 {# ---------------------------------------------- #}
  149.                 {# Results list wrapper (AJAX will append <li> items) #}
  150.                 <ul id="js-search-results-list" class="search-results list-search-result">
  151.                     {% set delay = 0 %}
  152.                     {% for item in pageItems %}
  153.                         {% set pageInfotitle = item.title|default %}
  154.                         {% set pageInfourl = item.url|default %}
  155.                         {% set pageInfovideo = item.content.video|default %}
  156.                         {% set pageInfovideo_mobile = item.content.video_mobile|default %}
  157.                         {% set pageInfotext = item.content.short_text|default %}
  158.                         {% set pageInfoimage = item.content.default_image|default %}
  159.                         {% set pageInfoimagemobile = item.content.default_image_mobile|default %}
  160.                         {% set pageInfocategories = item.categories|default %}
  161.                         {% set territory = item.content.territory|default %}
  162.                         {% set date = item.content.date|default %}
  163.                         {% set start_date = item.content.start_date|default %}
  164.                         {# Collect tag machines (fallback to id) for filtering #}
  165.                         {% set tagMachines = [] %}
  166.                         {% if item.tags is defined and item.tags is not empty %}
  167.                             {% for tag in item.tags %}
  168.                                 {% set machine = tag.machineName|default(tag.machine|default(tag.slug|default(tag))) %}
  169.                                 {% set tagMachines = tagMachines|merge([ machine ]) %}
  170.                             {% endfor %}
  171.                         {% endif %}
  172.                         {# Get categories (Temas) for this item #}
  173.                         {% set pageId = item.pageId is defined and item.pageId ? item.pageId.id : null %}
  174.                         {% set pageInfo = pageId ? get_page_info(app.request.locale, pageId, true, "Temas")|default(null) : null %}
  175.                         {% set categories = (pageInfo is not null and pageInfo.categories is defined) ? pageInfo.categories : [] %}
  176.                         {% set exclusiveTag = pageInfo and pageInfo.page.tags is defined ? pageInfo.page.tags|filter(t => t.domainValue.type.name == 'Exclusive')|first|default(null) : null %}
  177.                         {% set maxVisible = 1 %}
  178.                         <li {% if settings.is_animated|default %}data-aos="{{ settings.animation_type|default("fade") }}"
  179.                             data-aos-delay="{{ delay }}"{% endif %} class="item"
  180.                             data-type="{{ item.getNormalizedContentTypeKey is defined ? item.getNormalizedContentTypeKey() : (item.getNormalizedContentTypeKey() ?? '') }}"
  181.                             data-tags="{{ tagMachines|join(',') }}">
  182.                             <a href="{{ item.canonicalUrl|default('#') }}">
  183.                                 <div class="image-container event-card-carousel">
  184.                                     <picture>
  185.                                         {% set image = pageInfoimage|default(null) %}
  186.                                         {% if image is empty %}
  187.                                             {% set image = '/uploads/system/placeholder-vertical.png' %}
  188.                                         {% endif %}
  189.                                             <img src="{{ (image)|imagine_filter('poster')|urldecode }}"
  190.                                                 loading="lazy"
  191.                                                 alt="{{ item.title|default('') }}"
  192.                                                 title="{{ item.image_title|default(item.title|default('')) }}">
  193.                                     </picture>
  194.                                     {# <form>
  195.                                         <input type="hidden" name="highlight_id">
  196.                                         <button type="submit" class="favorites-button js-favorites-button">
  197.                                             {{ file_get_contents(asset('custom/favorites-icon.svg', 'global'))|raw }}
  198.                                         </button>
  199.                                     </form> #}
  200.                                     {% if pageInfovideo %}
  201.                                         <div class="card card-blur icon">
  202.                                             {{ file_get_contents(asset('custom/player-icon.svg', 'global'))|raw }}
  203.                                         </div>
  204.                                     {% endif %}
  205.                                 </div>
  206.                                 <div class="caption">
  207.                                     <h3 class="card-title">
  208.                                         {{ item.title is defined and item.title is not empty
  209.                                         ? (item.title|length <= 80
  210.                                         ? item.title
  211.                                         : item.title|slice(0, 80) ~ '...')
  212.                                         : 'Event Title ' ~ i }}
  213.                                     </h3>
  214.                                     {% if pageInfovideo %}
  215.                                         <div class="category">
  216.                                             {{ item.category|default('') }}
  217.                                         </div>
  218.                                     {% endif %}
  219.                                     {# temas #}
  220.                                     {{ macros.renderCategoryPopover(categories, maxVisible, false, exclusiveTag, languagecode, 'categories-list') }}
  221.                                     
  222.                                     {# date #}
  223.                                     <div class="date" title="{{ start_date ? start_date|date('d/m/Y') : date|date('d/m/Y') }}">
  224.                                         {% set tz = 'Europe/Lisbon' %}
  225.                                         {% set dateValue = start_date ? start_date : date %}
  226.                                         {% set fmt = app.request.locale starts with('en') ? 'MMM d yyyy' : 'd MMM Y' %}
  227.                                         {{ file_get_contents(asset('custom/time-icon.svg', 'global'))|raw }}
  228.                                         {{ dateValue|localizeddate('none', 'none', app.request.locale, tz, fmt) }}
  229.                                     </div>
  230.                                     
  231.                                 </div>
  232.                             </a>
  233.                         </li>
  234.                         {% set delay = delay + 150 %}
  235.                     {% endfor %}
  236.                 </ul>
  237.                 {% if app.request.query.get('isajax') != '1' and nextPage > 0 %}
  238.                     <div class="load-more-wrapper text-center mt-4">
  239.                         <button id="js-load-more-results"
  240.                                 class="btn-primary btn-style-1 btn-load-more"
  241.                                 data-current-page="{{ currentPage }}"
  242.                                 data-total-pages="{{ pageCount }}"
  243.                                 data-next-page="{{ nextPage }}"
  244.                                 type="button">
  245.                             <span class="label">{{ 'see_more'|trans({}, 'custom')|default('Ver mais') }}</span>
  246.                             <span class="spinner d-none" aria-hidden="true"></span>
  247.                         </button>
  248.                     </div>
  249.                     <script>
  250.                         (function () {
  251.                             const btn = document.getElementById('js-load-more-results');
  252.                             const list = document.getElementById('js-search-results-list');
  253.                             if (!btn || !list) return;
  254.                             let loading = false;
  255.                             function buildUrl(p) {
  256.                                 const url = new URL(window.location.href);
  257.                                 url.searchParams.set('page', p);
  258.                                 url.searchParams.set('isajax', '1');
  259.                                 return url.toString();
  260.                             }
  261.                             function show() {
  262.                                 btn.disabled = true;
  263.                                 btn.classList.add('is-loading');
  264.                                 const sp = btn.querySelector('.spinner');
  265.                                 sp && sp.classList.remove('d-none');
  266.                             }
  267.                             function hide() {
  268.                                 btn.disabled = false;
  269.                                 btn.classList.remove('is-loading');
  270.                                 const sp = btn.querySelector('.spinner');
  271.                                 sp && sp.classList.add('d-none');
  272.                             }
  273.                             async function load() {
  274.                                 if (loading) return;
  275.                                 loading = true;
  276.                                 show();
  277.                                 const next = parseInt(btn.getAttribute('data-next-page'), 10);
  278.                                 const total = parseInt(btn.getAttribute('data-total-pages'), 10);
  279.                                 try {
  280.                                     const r = await fetch(buildUrl(next), {headers: {'X-Requested-With': 'XMLHttpRequest'}});
  281.                                     if (!r.ok) throw new Error(r.status);
  282.                                     const html = await r.text();
  283.                                     const tmp = document.createElement('div');
  284.                                     tmp.innerHTML = html;
  285.                                     const fragUl = tmp.querySelector('#js-search-results-list');
  286.                                     const items = fragUl ? fragUl.querySelectorAll('li') : tmp.querySelectorAll('li.item');
  287.                                     items.forEach(li => {
  288.                                         const id = li.getAttribute('data-id');
  289.                                         if (!list.querySelector(`[data-id="${id}"]`)) {
  290.                                             li.classList.add('appended');
  291.                                             list.appendChild(li);
  292.                                         }
  293.                                     });
  294.                                     if (next >= total) {
  295.                                         btn.remove();
  296.                                     } else {
  297.                                         btn.setAttribute('data-current-page', String(next));
  298.                                         btn.setAttribute('data-next-page', String(next + 1));
  299.                                     }
  300.                                 } catch (e) {
  301.                                     console.error('Load more failed', e);
  302.                                     btn.classList.add('error');
  303.                                 } finally {
  304.                                     hide();
  305.                                     loading = false;
  306.                                 }
  307.                             }
  308.                             btn.addEventListener('click', function (e) {
  309.                                 e.preventDefault();
  310.                                 load();
  311.                             });
  312.                         })();
  313.                     </script>
  314.                 {% endif %}
  315.             {% endif %}
  316.         </div>
  317.     </section>
  318. {% endif %}