747 lines
46 KiB
HTML
747 lines
46 KiB
HTML
<!doctype html>
|
|
<html
|
|
lang="en"
|
|
xmlns:th="http://www.thymeleaf.org"
|
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
layout:decorate="~{themes/__${activeTheme}__/layout}"
|
|
>
|
|
<head>
|
|
<title th:text="${page.title}">Bệnh Viện S.I.S Cần Thơ</title>
|
|
<!-- Add Meta Description for SEO -->
|
|
<meta name="description" th:if="${page.metaDescription != null}" th:content="${page.metaDescription}" />
|
|
|
|
<!-- Load lightweight Bootstrap Grid CSS to support grid/flex block layouts without overriding theme styles -->
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap-grid.min.css" />
|
|
|
|
<!-- Customizer CSS overrides -->
|
|
<style th:inline="css">
|
|
body {
|
|
font-family: /*[[${themeModFontFamily}]]*/ sans-serif !important;
|
|
}
|
|
/* Inject Customizer Primary Color dynamically */
|
|
a,
|
|
.text-primary {
|
|
color: /*[[${themeModPrimaryColor}]]*/ #007bff !important;
|
|
}
|
|
/*[[${themeModCustomCss}]]*/
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<!-- Render Editor.js Blocks -->
|
|
<div layout:fragment="content">
|
|
<!-- Dedicated Page Custom CSS -->
|
|
<style th:if="${page != null and page.customCss != null and !page.customCss.empty}" th:utext="${page.customCss}"></style>
|
|
<th:block th:each="block : ${blocks}">
|
|
<div
|
|
th:class="${(block.data != null and block.data['stretched'] == true) or (block.data != null and block.data['stretched'] == null and block['stretched'] == true) ? 'sis-fullwidth-breakout' : ''}"
|
|
>
|
|
<!-- 1. HTML Snippet Block (Custom) -->
|
|
<th:block th:if="${block['type'] == 'snippet'}">
|
|
<div th:utext="${block.data['htmlContent']}" th:remove="tag"></div>
|
|
</th:block>
|
|
|
|
<!-- 2. Header Block -->
|
|
<th:block th:if="${block['type'] == 'header'}">
|
|
<th:block th:switch="${block.data['level']}">
|
|
<h1 th:case="1" th:utext="${block.data['text']}"></h1>
|
|
<h2 th:case="2" th:utext="${block.data['text']}"></h2>
|
|
<h3 th:case="3" th:utext="${block.data['text']}"></h3>
|
|
<h4 th:case="4" th:utext="${block.data['text']}"></h4>
|
|
<h5 th:case="5" th:utext="${block.data['text']}"></h5>
|
|
<h6 th:case="6" th:utext="${block.data['text']}"></h6>
|
|
<h2 th:case="*" th:utext="${block.data['text']}"></h2>
|
|
</th:block>
|
|
</th:block>
|
|
|
|
<!-- 3. Paragraph Block -->
|
|
<th:block th:if="${block['type'] == 'paragraph'}">
|
|
<p th:utext="${block.data['text']}"></p>
|
|
</th:block>
|
|
|
|
<!-- 4. List Block -->
|
|
<th:block th:if="${block['type'] == 'list'}">
|
|
<ul th:if="${block.data['style'] == 'unordered'}">
|
|
<li th:each="item : ${block.data['items']}" th:utext="${item}"></li>
|
|
</ul>
|
|
<ol th:if="${block.data['style'] == 'ordered'}">
|
|
<li th:each="item : ${block.data['items']}" th:utext="${item}"></li>
|
|
</ol>
|
|
</th:block>
|
|
|
|
<!-- 5. Image Block -->
|
|
<th:block th:if="${block['type'] == 'image'}">
|
|
<img th:if="${block.data['file'] != null}" th:src="${block.data['file']['url']}" th:alt="${block.data['caption']}" />
|
|
<p th:if="${block.data['caption']}" th:utext="${block.data['caption']}"></p>
|
|
</th:block>
|
|
|
|
<!-- 6. Quote Block -->
|
|
<th:block th:if="${block['type'] == 'quote'}">
|
|
<blockquote>
|
|
<p th:utext="${block.data['text']}"></p>
|
|
<footer th:if="${block.data['caption']}" th:utext="${block.data['caption']}"></footer>
|
|
</blockquote>
|
|
</th:block>
|
|
|
|
<!-- 7. Delimiter Block -->
|
|
<th:block th:if="${block['type'] == 'delimiter'}">
|
|
<hr />
|
|
</th:block>
|
|
|
|
<!-- 8. Table Block -->
|
|
<th:block th:if="${block['type'] == 'table'}">
|
|
<table>
|
|
<tbody>
|
|
<tr th:each="row, rowStat : ${block.data['content']}">
|
|
<th:block th:if="${block.data['withHeadings'] == true and rowStat.index == 0}">
|
|
<th th:each="cell : ${row}" th:utext="${cell}"></th>
|
|
</th:block>
|
|
<th:block th:unless="${block.data['withHeadings'] == true and rowStat.index == 0}">
|
|
<td th:each="cell : ${row}" th:utext="${cell}"></td>
|
|
</th:block>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</th:block>
|
|
|
|
<!-- 9. Raw HTML Block (Fallback/WordPress Imports) -->
|
|
<th:block th:if="${block['type'] == 'raw'}">
|
|
<div th:utext="${block.data['html']}" th:remove="tag"></div>
|
|
</th:block>
|
|
|
|
<!-- 10. Accordion Block -->
|
|
<th:block th:if="${block['type'] == 'accordion'}">
|
|
<details class="sis-accordion-item mb-3" th:open="${block.data['isOpen'] == true}">
|
|
<summary class="sis-accordion-title font-weight-bold p-3 bg-light border rounded" style="cursor: pointer; user-select: none">
|
|
<span th:utext="${block.data['title']}">Accordion Title</span>
|
|
</summary>
|
|
<div class="sis-accordion-body p-3 border border-top-0 rounded-bottom">
|
|
<div th:utext="${block.data['content']}">Accordion Content</div>
|
|
</div>
|
|
</details>
|
|
</th:block>
|
|
|
|
<!-- 11. YouTube Video Block -->
|
|
<th:block th:if="${block['type'] == 'youtube'}">
|
|
<div class="sis-youtube-container my-4 text-center">
|
|
<div
|
|
class="sis-yt-thumb-wrapper"
|
|
th:data-embed-url="${block.data['url']}"
|
|
th:data-custom-thumb="${block.data['thumbnailUrl'] != null ? block.data['thumbnailUrl'] : ''}"
|
|
style="
|
|
position: relative;
|
|
padding-bottom: 56.25%;
|
|
height: 0;
|
|
overflow: hidden;
|
|
border-radius: 8px;
|
|
background-color: #111;
|
|
background-position: center;
|
|
background-size: cover;
|
|
background-repeat: no-repeat;
|
|
margin: 0 auto;
|
|
cursor: pointer;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
"
|
|
th:styleappend="${(block.data['thumbnailUrl'] != null and !#strings.isEmpty(block.data['thumbnailUrl'])) ? 'background-image: url(' + block.data['thumbnailUrl'] + ');' : ((block.data['url'] != null and #strings.contains(block.data['url'], 'youtu.be/')) ? 'background-image: url(https://img.youtube.com/vi/' + #strings.substringAfter(block.data['url'], 'youtu.be/') + '/hqdefault.jpg);' : ((block.data['url'] != null and #strings.contains(block.data['url'], 'v=')) ? 'background-image: url(https://img.youtube.com/vi/' + #strings.substringBefore(#strings.substringAfter(block.data['url'], 'v='), '&') + '/hqdefault.jpg);' : ((block.data['url'] != null and #strings.contains(block.data['url'], 'embed/')) ? 'background-image: url(https://img.youtube.com/vi/' + #strings.substringBefore(#strings.substringAfter(block.data['url'], 'embed/'), '?') + '/hqdefault.jpg);' : '')))}"
|
|
>
|
|
<div
|
|
class="sis-yt-play-btn"
|
|
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); transition: transform 0.2s ease"
|
|
>
|
|
<svg width="68" height="48" viewBox="0 0 68 48">
|
|
<path
|
|
d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z"
|
|
fill="#ff0000"
|
|
/>
|
|
<path d="M45 24L27 14v20z" fill="#ffffff" />
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<p
|
|
class="small text-muted mt-2"
|
|
th:if="${block.data['caption'] != null and !#strings.isEmpty(block.data['caption'])}"
|
|
th:utext="${block.data['caption']}"
|
|
></p>
|
|
</div>
|
|
</th:block>
|
|
|
|
<!-- 12. Hero Banner Block -->
|
|
<th:block th:if="${block['type'] == 'hero'}">
|
|
<div
|
|
class="sis-hero-banner text-white py-5 px-3 rounded shadow-sm text-center"
|
|
style="
|
|
position: relative;
|
|
overflow: hidden;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-size: cover;
|
|
background-position: center;
|
|
background-color: #002554;
|
|
"
|
|
th:styleappend="${'min-height: ' + (block.data['height'] != null and !#strings.isEmpty(block.data['height']) ? block.data['height'] : '350px') + ';' + ((block.data['bgImage'] != null and !#strings.isEmpty(block.data['bgImage'])) ? 'background-image: url(' + block.data['bgImage'] + ');' : 'background: linear-gradient(135deg, #002554 0%, #881C1C 100%);')}"
|
|
>
|
|
<div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.4); z-index: 1"></div>
|
|
<div class="container" style="position: relative; z-index: 2">
|
|
<h1
|
|
class="display-4 font-weight-bold text-white mb-3"
|
|
th:if="${block.data['title'] != null and !#strings.isEmpty(block.data['title'])}"
|
|
th:utext="${block.data['title']}"
|
|
>
|
|
Hero Banner Title
|
|
</h1>
|
|
<p
|
|
class="lead text-light mb-4"
|
|
th:if="${block.data['subtitle'] != null and !#strings.isEmpty(block.data['subtitle'])}"
|
|
th:utext="${block.data['subtitle']}"
|
|
></p>
|
|
<a
|
|
th:if="${block.data['btnText'] != null and !#strings.isEmpty(block.data['btnText'])}"
|
|
th:href="${(block.data['btnLink'] != null and !#strings.isEmpty(block.data['btnLink'])) ? block.data['btnLink'] : '#'}"
|
|
class="btn btn-danger btn-lg font-weight-bold px-4 py-2 shadow"
|
|
th:utext="${block.data['btnText']}"
|
|
>
|
|
Click Here
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
|
|
<!-- 13. Sticky Nav / Sub-menu Block (UMass Theme mc--info-menu style) -->
|
|
<th:block th:if="${block['type'] == 'stickyNav' or block['type'] == 'nav'}">
|
|
<nav
|
|
th:id="${block.data['globalId'] != null and !#strings.isEmpty(block.data['globalId']) ? block.data['globalId'] : null}"
|
|
class="mc--menu mc--info-menu sis-sticky-nav my-3"
|
|
th:classappend="${(block.data['globalClass'] != null and !#strings.isEmpty(block.data['globalClass']) ? (block.data['globalClass'] + ' ') : '') + (block.data['stretched'] == true ? 'sis-fullwidth-breakout ' : '') + (block.data['sticky'] == true or block.data['sticky'] == null ? 'is-sticky ' : '') + (block.data['bgColor'] == '#ffffff' ? 'sis-nav-light ' : '')}"
|
|
th:style="${'background-color: ' + (block.data['bgColor'] != null ? block.data['bgColor'] : '#002554') + ' !important;'}"
|
|
th:data-custom-attrs="${block.data['globalAttributes'] != null and !#strings.isEmpty(block.data['globalAttributes']) ? block.data['globalAttributes'] : (block.data['attributes'] != null and !#strings.isEmpty(block.data['attributes']) ? block.data['attributes'] : null)}"
|
|
>
|
|
<ul class="menu m--menu m--info-menu">
|
|
<li class="menu-item menu-item--expanded">
|
|
<details class="utility-button-wrapper mc--info-menu-container mobile-only">
|
|
<summary
|
|
type="button"
|
|
class="utility-button arrow-toggle information-for-toggle"
|
|
aria-label="Display submenu"
|
|
aria-expanded="false"
|
|
aria-haspopup="true"
|
|
>
|
|
<span
|
|
th:text="${block.data['title'] != null and !#strings.isEmpty(block.data['title']) ? block.data['title'] : 'Điều hướng nhanh'}"
|
|
>Điều hướng nhanh</span
|
|
>
|
|
<svg
|
|
version="1.1"
|
|
class="arrow"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
x="0px"
|
|
y="0px"
|
|
viewBox="0 0 16 7"
|
|
enable-background="new 0 0 16 7"
|
|
xml:space="preserve"
|
|
width="16"
|
|
height="7"
|
|
>
|
|
<polygon fill-rule="evenodd" clip-rule="evenodd" fill="#ffffff" points="7,7 0,0 16,0 "></polygon>
|
|
</svg>
|
|
</summary>
|
|
<div class="submenu-wrapper">
|
|
<ul class="submenu">
|
|
<li class="menu-item" th:each="item : ${block.data['items']}">
|
|
<a th:href="${item['link']}" th:utext="${item['label']}">Nav Link</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</details>
|
|
<div class="submenu-wrapper-desktop">
|
|
<ul class="submenu">
|
|
<li class="menu-item" th:each="item : ${block.data['items']}">
|
|
<a th:href="${item['link']}" th:utext="${item['label']}">Nav Link</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</th:block>
|
|
|
|
<!-- 14. Timeline Block (Group) -->
|
|
<th:block th:if="${block['type'] == 'timeline' and block.data['items'] != null}">
|
|
<section class="sis-timeline" th:id="'timeline-' + ${stat != null ? stat.index : 0}">
|
|
<div class="sis-timeline__grid">
|
|
<!-- Text Column (Left) -->
|
|
<div class="sis-timeline__text-col">
|
|
<div class="sis-timeline__line"></div>
|
|
<th:block th:each="item : ${block.data['items']}">
|
|
<div class="sis-timeline__entry">
|
|
<div class="sis-timeline__dot"></div>
|
|
<div class="sis-timeline__entry-content">
|
|
<div class="sis-timeline__date" th:utext="${item['date']}"></div>
|
|
<div class="sis-timeline__desc" th:utext="${item['description']}"></div>
|
|
<!-- Mobile image -->
|
|
<div class="sis-timeline__mobile-img" th:if="${item['imageUrl'] != null and !#strings.isEmpty(item['imageUrl'])}">
|
|
<img th:src="${item['imageUrl']}" alt="Timeline Image" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
</div>
|
|
<!-- Image Column (Right) -->
|
|
<div class="sis-timeline__img-col">
|
|
<th:block th:each="item : ${block.data['items']}">
|
|
<div class="sis-timeline__img-slot" th:if="${item['imageUrl'] != null and !#strings.isEmpty(item['imageUrl'])}">
|
|
<div class="sis-timeline__img-wrapper">
|
|
<img th:src="${item['imageUrl']}" alt="Timeline Image" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
<div
|
|
class="sis-timeline__img-slot sis-timeline__img-slot-empty"
|
|
th:unless="${item['imageUrl'] != null and !#strings.isEmpty(item['imageUrl'])}"
|
|
></div>
|
|
</th:block>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<script th:inline="javascript">
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const syncTimelineHeights = () => {
|
|
if (window.innerWidth < 1024) {
|
|
document.querySelectorAll('.sis-timeline__entry, .sis-timeline__img-slot').forEach(el => {
|
|
el.style.minHeight = '';
|
|
el.style.marginBottom = '';
|
|
});
|
|
return;
|
|
}
|
|
// Use the specific timeline section ID in case there are multiple
|
|
const section = document.querySelector('#timeline-[[${stat != null ? stat.index : 0}]]');
|
|
if (!section) return;
|
|
const texts = section.querySelectorAll('.sis-timeline__entry');
|
|
const imgs = section.querySelectorAll('.sis-timeline__img-slot');
|
|
|
|
for (let i = 0; i < texts.length; i++) {
|
|
if (imgs[i]) {
|
|
// reset inline styles first to measure natural height
|
|
texts[i].style.minHeight = '';
|
|
texts[i].style.marginBottom = '';
|
|
imgs[i].style.minHeight = '';
|
|
imgs[i].style.marginBottom = '';
|
|
|
|
const textH = texts[i].getBoundingClientRect().height;
|
|
const imgH = imgs[i].getBoundingClientRect().height;
|
|
const maxH = Math.max(textH, imgH);
|
|
|
|
texts[i].style.minHeight = maxH + 'px';
|
|
imgs[i].style.minHeight = maxH + 'px';
|
|
|
|
// sync bottom margin so they space out identically
|
|
texts[i].style.marginBottom = '4rem';
|
|
imgs[i].style.marginBottom = '4rem';
|
|
}
|
|
}
|
|
};
|
|
syncTimelineHeights();
|
|
window.addEventListener('resize', syncTimelineHeights);
|
|
// Run once more after images load
|
|
window.addEventListener('load', syncTimelineHeights);
|
|
});
|
|
</script>
|
|
</th:block>
|
|
|
|
<!-- 15. Grid / Columns Block -->
|
|
<th:block th:if="${block['type'] == 'grid'}">
|
|
<div th:id="${block.data['globalId'] != null and !#strings.isEmpty(block.data['globalId']) ? block.data['globalId'] : null}"
|
|
th:class="${block.data['globalClass'] != null and !#strings.isEmpty(block.data['globalClass']) ? block.data['globalClass'] : null}"
|
|
th:data-custom-attrs="${block.data['globalAttributes'] != null and !#strings.isEmpty(block.data['globalAttributes']) ? block.data['globalAttributes'] : (block.data['attributes'] != null and !#strings.isEmpty(block.data['attributes']) ? block.data['attributes'] : null)}">
|
|
<div class="container py-4">
|
|
<div class="row">
|
|
<th:block th:each="i : ${#numbers.sequence(1, block.data['cols'])}">
|
|
<div
|
|
th:id="${block.data['id' + i] != null and !#strings.isEmpty(block.data['id' + i]) ? block.data['id' + i] : null}"
|
|
th:class="${(block.data['width' + i] != null and block.data['width' + i] gt 0) ? ('col-lg-' + block.data['width' + i] + ' col-md-6 col-12 mb-4') : (block.data['cols'] == 1 ? 'col-12 mb-4' : (block.data['cols'] == 2 ? 'col-md-6 col-12 mb-4' : (block.data['cols'] == 3 ? 'col-lg-4 col-md-6 col-12 mb-4' : (block.data['cols'] == 4 ? 'col-lg-3 col-md-6 col-12 mb-4' : 'col-lg col-md-6 col-12 mb-4'))))}"
|
|
th:classappend="${block.data['class' + i] != null and !#strings.isEmpty(block.data['class' + i]) ? block.data['class' + i] : ''}"
|
|
th:data-custom-attrs="${block.data['attr' + i] != null and !#strings.isEmpty(block.data['attr' + i]) ? block.data['attr' + i] : null}"
|
|
>
|
|
<div th:replace=":: renderCell(type=${block.data['type' + i]}, i=${i}, blockData=${block.data})"></div>
|
|
</div>
|
|
</th:block>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
|
|
<!-- 16. Flex Layout Block -->
|
|
<th:block th:if="${block['type'] == 'flex'}">
|
|
<div th:id="${block.data['globalId'] != null and !#strings.isEmpty(block.data['globalId']) ? block.data['globalId'] : null}"
|
|
th:class="${block.data['globalClass'] != null and !#strings.isEmpty(block.data['globalClass']) ? block.data['globalClass'] : null}"
|
|
th:data-custom-attrs="${block.data['globalAttributes'] != null and !#strings.isEmpty(block.data['globalAttributes']) ? block.data['globalAttributes'] : (block.data['attributes'] != null and !#strings.isEmpty(block.data['attributes']) ? block.data['attributes'] : null)}">
|
|
<div class="container py-4">
|
|
<div
|
|
style="display: flex; flex-wrap: wrap;"
|
|
th:styleappend="${'flex-direction: ' + (block.data['direction'] != null ? block.data['direction'] : 'row') + '; justify-content: ' + (block.data['justify'] == 'start' ? 'flex-start' : (block.data['justify'] == 'end' ? 'flex-end' : (block.data['justify'] == 'between' ? 'space-between' : (block.data['justify'] == 'around' ? 'space-around' : (block.data['justify'] == 'evenly' ? 'space-evenly' : 'center'))))) + '; align-items: ' + (block.data['align'] == 'start' ? 'flex-start' : (block.data['align'] == 'end' ? 'flex-end' : (block.data['align'] != null ? block.data['align'] : 'stretch'))) + '; gap: ' + (block.data['gap'] == '0' ? '0' : (block.data['gap'] == '1' ? '0.25rem' : (block.data['gap'] == '2' ? '0.5rem' : (block.data['gap'] == '3' ? '1rem' : (block.data['gap'] == '4' ? '1.5rem' : (block.data['gap'] == '5' ? '2rem' : '1rem')))))) + ';'}"
|
|
>
|
|
<th:block th:each="i : ${#numbers.sequence(1, block.data['cols'])}">
|
|
<div
|
|
th:id="${block.data['id' + i] != null and !#strings.isEmpty(block.data['id' + i]) ? block.data['id' + i] : null}"
|
|
th:class="${(block.data['width' + i] != null and block.data['width' + i] gt 0) ? ('col-lg-' + block.data['width' + i] + ' col-md-6 col-12 mb-4') : (block.data['cols'] == 1 ? 'col-12 mb-4' : (block.data['cols'] == 2 ? 'col-md-6 col-12 mb-4' : (block.data['cols'] == 3 ? 'col-lg-4 col-md-6 col-12 mb-4' : (block.data['cols'] == 4 ? 'col-lg-3 col-md-6 col-12 mb-4' : 'col-lg col-md-6 col-12 mb-4'))))}"
|
|
th:classappend="${block.data['class' + i] != null and !#strings.isEmpty(block.data['class' + i]) ? block.data['class' + i] : ''}"
|
|
th:data-custom-attrs="${block.data['attr' + i] != null and !#strings.isEmpty(block.data['attr' + i]) ? block.data['attr' + i] : null}"
|
|
>
|
|
<div th:replace=":: renderCell(type=${block.data['type' + i]}, i=${i}, blockData=${block.data})"></div>
|
|
</div>
|
|
</th:block>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
|
|
<!-- 17. Dedicated Hover Cards Block -->
|
|
<th:block th:if="${block['type'] == 'hovercard' or block['type'] == 'hover-card' or block['type'] == 'hoverCard'}">
|
|
<div th:id="${block.data['globalId'] != null and !#strings.isEmpty(block.data['globalId']) ? block.data['globalId'] : null}"
|
|
th:class="${(block.data['styleVariant'] == 'v2' or (block.data['globalClass'] != null and block.data['globalClass'].contains('v2'))) ? ('sis-hover-card-v2-section ' + (block.data['globalClass'] != null ? block.data['globalClass'] : '')) : ('sis-hover-card-section ' + (block.data['globalClass'] != null ? block.data['globalClass'] : ''))}"
|
|
th:data-custom-attrs="${block.data['globalAttributes'] != null and !#strings.isEmpty(block.data['globalAttributes']) ? block.data['globalAttributes'] : (block.data['attributes'] != null and !#strings.isEmpty(block.data['attributes']) ? block.data['attributes'] : null)}">
|
|
<div class="container py-4">
|
|
<div class="row align-items-center">
|
|
<th:block th:each="item, iterStat : ${block.data['items']}">
|
|
<div th:class="${block.data['cols'] == 1 ? 'col-12 mb-4' : (block.data['cols'] == 2 ? 'col-md-6 col-12 mb-4' : (block.data['cols'] == 3 ? 'col-lg-4 col-md-6 col-12 mb-4' : (block.data['cols'] == 6 ? 'col-lg-2 col-md-4 col-6 mb-4' : 'col-lg-3 col-md-6 col-12 mb-4')))}">
|
|
<div th:class="${(block.data['styleVariant'] == 'v2' or (block.data['globalClass'] != null and block.data['globalClass'].contains('v2'))) ? ('sis-hover-card sis-hover-card-v2 ' + ((item['active'] == true or (item['active'] == null and iterStat.first)) ? 'active' : '')) : ('sis-hover-card ' + ((item['active'] == true or (item['active'] == null and iterStat.first)) ? 'active' : ''))}"
|
|
th:data-custom-attrs="${item['attributes'] != null and !#strings.isEmpty(item['attributes']) ? item['attributes'] : null}">
|
|
<div class="w-full flex flex-col items-center justify-center transition-all duration-500">
|
|
<div class="sis-hover-card__icon" th:if="${item['imageUrl'] != null and !#strings.isEmpty(item['imageUrl'])}">
|
|
<img th:src="${item['imageUrl']}" class="sis-hover-card__img-main" th:alt="${item['title']}" />
|
|
<img th:if="${item['hoverImageUrl'] != null and !#strings.isEmpty(item['hoverImageUrl'])}" th:src="${item['hoverImageUrl']}" class="sis-hover-card__img-hover" th:alt="${item['title']}" />
|
|
</div>
|
|
<h3 class="sis-hover-card__title" th:utext="${item['title']}">Title</h3>
|
|
</div>
|
|
<p class="sis-hover-card__desc" th:utext="${item['description']}">Description</p>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
|
|
<!-- 18. Custom HTML Tag Block (Opening or Closing Tag) -->
|
|
<th:block th:if="${block['type'] == 'tag'}">
|
|
<th:block th:if="${block.data['rawHtmlTag'] != null and !#strings.isEmpty(block.data['rawHtmlTag'])}"
|
|
th:utext="${block.data['rawHtmlTag']}"></th:block>
|
|
</th:block>
|
|
|
|
<!-- Shared Cell Content Renderer Fragment -->
|
|
<th:block th:fragment="renderCell(type, i, blockData)">
|
|
<!-- Type 1: HTML / Text -->
|
|
<th:block th:if="${type == null or type == 'html'}" th:utext="${blockData != null ? blockData['col' + i] : ''}"></th:block>
|
|
|
|
<!-- Type 2: Image -->
|
|
<th:block th:if="${type == 'image'}">
|
|
<div class="sis-grid-image-wrapper text-center">
|
|
<!-- Native Image Plugin structure -->
|
|
<th:block th:if="${blockData != null and blockData['col' + i] != null and blockData['col' + i] != '' and blockData['col' + i]['file'] != null}">
|
|
<img th:src="${blockData['col' + i]['file']['url']}" class="img-fluid rounded shadow-sm" th:alt="${blockData['col' + i]['caption']}" />
|
|
</th:block>
|
|
<!-- Custom imgUrl fallback -->
|
|
<th:block th:unless="${blockData != null and blockData['col' + i] != null and blockData['col' + i] != '' and blockData['col' + i]['file'] != null}">
|
|
<img th:if="${blockData != null and blockData['imgUrl' + i] != null and !#strings.isEmpty(blockData['imgUrl' + i])}" th:src="${blockData['imgUrl' + i]}" class="img-fluid rounded shadow-sm" alt="Grid Image" />
|
|
</th:block>
|
|
</div>
|
|
</th:block>
|
|
|
|
<!-- Type 3: YouTube Video -->
|
|
<th:block th:if="${type == 'youtube'}">
|
|
<div class="sis-youtube-container text-center">
|
|
<div
|
|
class="sis-yt-thumb-wrapper"
|
|
th:data-embed-url="${blockData != null ? blockData['ytUrl' + i] : ''}"
|
|
style="
|
|
position: relative;
|
|
padding-bottom: 56.25%;
|
|
height: 0;
|
|
overflow: hidden;
|
|
border-radius: 8px;
|
|
background-color: #111;
|
|
background-position: center;
|
|
background-size: cover;
|
|
background-repeat: no-repeat;
|
|
margin: 0 auto;
|
|
cursor: pointer;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
"
|
|
th:styleappend="${blockData != null and blockData['ytUrl' + i] != null ? ((#strings.contains(blockData['ytUrl' + i], 'youtu.be/')) ? 'background-image: url(' + 'https://img.youtube.com/vi/' + #strings.substringAfter(blockData['ytUrl' + i], 'youtu.be/') + '/hqdefault.jpg' + ');' : ((#strings.contains(blockData['ytUrl' + i], 'v=')) ? 'background-image: url(' + 'https://img.youtube.com/vi/' + #strings.substringBefore(#strings.substringAfter(blockData['ytUrl' + i], 'v='), '&') + '/hqdefault.jpg' + ');' : ((#strings.contains(blockData['ytUrl' + i], 'embed/')) ? 'background-image: url(' + 'https://img.youtube.com/vi/' + #strings.substringBefore(#strings.substringAfter(blockData['ytUrl' + i], 'embed/'), '?') + '/hqdefault.jpg' + ');' : ''))) : ''}"
|
|
>
|
|
<div class="sis-yt-play-btn" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); transition: transform 0.2s ease">
|
|
<svg width="68" height="48" viewBox="0 0 68 48">
|
|
<path d="M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55c-2.93.78-4.63 3.26-5.42 6.19C.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24s-.06-10.95-1.48-16.26z" fill="#f00"></path>
|
|
<polygon points="26,12 26,36 48,24" fill="#fff"></polygon>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
|
|
<!-- Type 4: Accordion -->
|
|
<th:block th:if="${type == 'accordion'}">
|
|
<details class="sis-accordion-item mb-3">
|
|
<summary class="sis-accordion-title font-weight-bold p-3 bg-light border rounded" style="cursor: pointer; user-select: none">
|
|
<span th:utext="${blockData != null ? blockData['accTitle' + i] : ''}">Accordion Title</span>
|
|
</summary>
|
|
<div class="sis-accordion-body p-3 border border-top-0 rounded-bottom" th:utext="${blockData != null ? blockData['accContent' + i] : ''}"></div>
|
|
</details>
|
|
</th:block>
|
|
|
|
<!-- Nested Plugin: html-snippet -->
|
|
<th:block th:if="${type == 'html-snippet' and blockData != null and blockData['col' + i] != null and blockData['col' + i] != '' and blockData['col' + i]['id'] != null}">
|
|
<div th:replace="~{fragments/snippets :: snippet(id=${blockData['col' + i]['id']})}"></div>
|
|
</th:block>
|
|
|
|
<!-- Nested Plugin: timeline -->
|
|
<th:block th:if="${type == 'timeline' and blockData != null and blockData['col' + i] != null and blockData['col' + i] != '' and blockData['col' + i]['items'] != null}">
|
|
<section class="sis-timeline">
|
|
<div class="sis-timeline__grid">
|
|
<div class="sis-timeline__text-col" style="width: 100%;">
|
|
<div class="sis-timeline__line"></div>
|
|
<th:block th:each="item : ${blockData['col' + i]['items']}">
|
|
<div class="sis-timeline__entry">
|
|
<div class="sis-timeline__dot"></div>
|
|
<div class="sis-timeline__entry-content">
|
|
<div class="sis-timeline__date" th:utext="${item['date']}"></div>
|
|
<div class="sis-timeline__desc" th:utext="${item['description']}"></div>
|
|
<div class="sis-timeline__mobile-img" th:if="${item['imageUrl'] != null and !#strings.isEmpty(item['imageUrl'])}">
|
|
<img th:src="${item['imageUrl']}" alt="Timeline Image" loading="lazy" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</th:block>
|
|
|
|
<!-- Nested Plugin: hovercard -->
|
|
<th:block th:if="${(type == 'hovercard' or type == 'hover-card' or type == 'hoverCard') and blockData != null and blockData['col' + i] != null and blockData['col' + i] != '' and blockData['col' + i]['items'] != null}">
|
|
<div th:id="${blockData['col' + i]['globalId'] != null and !#strings.isEmpty(blockData['col' + i]['globalId']) ? blockData['col' + i]['globalId'] : null}"
|
|
th:class="${(blockData['col' + i]['styleVariant'] == 'v2' or (blockData['col' + i]['globalClass'] != null and blockData['col' + i]['globalClass'].contains('v2'))) ? ('sis-hover-card-v2-section ' + (blockData['col' + i]['globalClass'] != null ? blockData['col' + i]['globalClass'] : '')) : ('sis-hover-card-section ' + (blockData['col' + i]['globalClass'] != null ? blockData['col' + i]['globalClass'] : ''))}">
|
|
<div class="container-fluid p-0">
|
|
<div class="row align-items-center">
|
|
<th:block th:each="item, iterStat : ${blockData['col' + i]['items']}">
|
|
<div th:class="${blockData['col' + i]['cols'] == 1 ? 'col-12 mb-4' : (blockData['col' + i]['cols'] == 2 ? 'col-md-6 col-12 mb-4' : (blockData['col' + i]['cols'] == 3 ? 'col-lg-4 col-md-6 col-12 mb-4' : (blockData['col' + i]['cols'] == 6 ? 'col-lg-2 col-md-4 col-6 mb-4' : 'col-lg-3 col-md-6 col-12 mb-4')))}">
|
|
<div th:class="${(blockData['col' + i]['styleVariant'] == 'v2' or (blockData['col' + i]['globalClass'] != null and blockData['col' + i]['globalClass'].contains('v2'))) ? ('sis-hover-card sis-hover-card-v2 ' + ((item['active'] == true or (item['active'] == null and iterStat.first)) ? 'active' : '')) : ('sis-hover-card ' + ((item['active'] == true or (item['active'] == null and iterStat.first)) ? 'active' : ''))}">
|
|
<div class="w-full flex flex-col items-center justify-center transition-all duration-500">
|
|
<div class="sis-hover-card__icon" th:if="${item['imageUrl'] != null and !#strings.isEmpty(item['imageUrl'])}">
|
|
<img th:src="${item['imageUrl']}" class="sis-hover-card__img-main" th:alt="${item['title']}" />
|
|
<img th:if="${item['hoverImageUrl'] != null and !#strings.isEmpty(item['hoverImageUrl'])}" th:src="${item['hoverImageUrl']}" class="sis-hover-card__img-hover" th:alt="${item['title']}" />
|
|
</div>
|
|
<h3 class="sis-hover-card__title" th:utext="${item['title']}">Title</h3>
|
|
</div>
|
|
<p class="sis-hover-card__desc" th:utext="${item['description']}">Description</p>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
|
|
<!-- Nested Plugin: tag -->
|
|
<th:block th:if="${type == 'tag' and blockData != null and blockData['col' + i] != null}">
|
|
<th:block th:if="${blockData['col' + i]['rawHtmlTag'] != null and !#strings.isEmpty(blockData['col' + i]['rawHtmlTag'])}"
|
|
th:utext="${blockData['col' + i]['rawHtmlTag']}"></th:block>
|
|
</th:block>
|
|
|
|
<!-- Nested Plugin: grid (Recursive) -->
|
|
<th:block th:if="${type == 'grid' and blockData != null and blockData['col' + i] != null and blockData['col' + i] != '' and blockData['col' + i]['cols'] != null}">
|
|
<div th:id="${blockData['col' + i]['globalId'] != null and !#strings.isEmpty(blockData['col' + i]['globalId']) ? blockData['col' + i]['globalId'] : null}"
|
|
th:class="${blockData['col' + i]['globalClass'] != null and !#strings.isEmpty(blockData['col' + i]['globalClass']) ? blockData['col' + i]['globalClass'] : null}">
|
|
<div class="container-fluid p-0">
|
|
<div class="row">
|
|
<th:block th:each="nestedI : ${#numbers.sequence(1, blockData['col' + i]['cols'])}">
|
|
<div
|
|
th:id="${blockData['col' + i]['id' + nestedI] != null and !#strings.isEmpty(blockData['col' + i]['id' + nestedI]) ? blockData['col' + i]['id' + nestedI] : null}"
|
|
th:class="${(blockData['col' + i]['width' + nestedI] != null and blockData['col' + i]['width' + nestedI] gt 0) ? ('col-lg-' + blockData['col' + i]['width' + nestedI] + ' col-md-6 col-12 mb-4') : (blockData['col' + i]['cols'] == 1 ? 'col-12 mb-4' : (blockData['col' + i]['cols'] == 2 ? 'col-md-6 col-12 mb-4' : (blockData['col' + i]['cols'] == 3 ? 'col-lg-4 col-md-6 col-12 mb-4' : (blockData['col' + i]['cols'] == 4 ? 'col-lg-3 col-md-6 col-12 mb-4' : 'col-lg col-md-6 col-12 mb-4'))))}"
|
|
th:classappend="${blockData['col' + i]['class' + nestedI] != null and !#strings.isEmpty(blockData['col' + i]['class' + nestedI]) ? blockData['col' + i]['class' + nestedI] : ''}"
|
|
>
|
|
<div th:replace=":: renderCell(type=${blockData['col' + i]['type' + nestedI]}, i=${nestedI}, blockData=${blockData['col' + i]})"></div>
|
|
</div>
|
|
</th:block>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
|
|
<!-- Nested Plugin: flex (Recursive) -->
|
|
<th:block th:if="${type == 'flex' and blockData != null and blockData['col' + i] != null and blockData['col' + i] != '' and blockData['col' + i]['cols'] != null}">
|
|
<div th:id="${blockData['col' + i]['globalId'] != null and !#strings.isEmpty(blockData['col' + i]['globalId']) ? blockData['col' + i]['globalId'] : null}"
|
|
th:class="${blockData['col' + i]['globalClass'] != null and !#strings.isEmpty(blockData['col' + i]['globalClass']) ? blockData['col' + i]['globalClass'] : null}">
|
|
<div class="container-fluid p-0">
|
|
<div
|
|
style="display: flex; flex-wrap: wrap;"
|
|
th:styleappend="${'flex-direction: ' + (blockData['col' + i]['direction'] != null ? blockData['col' + i]['direction'] : 'row') + '; justify-content: ' + (blockData['col' + i]['justify'] == 'start' ? 'flex-start' : (blockData['col' + i]['justify'] == 'end' ? 'flex-end' : (blockData['col' + i]['justify'] == 'between' ? 'space-between' : (blockData['col' + i]['justify'] == 'around' ? 'space-around' : (blockData['col' + i]['justify'] == 'evenly' ? 'space-evenly' : 'center'))))) + '; align-items: ' + (blockData['col' + i]['align'] == 'start' ? 'flex-start' : (blockData['col' + i]['align'] == 'end' ? 'flex-end' : (blockData['col' + i]['align'] != null ? blockData['col' + i]['align'] : 'stretch'))) + '; gap: ' + (blockData['col' + i]['gap'] == '0' ? '0' : (blockData['col' + i]['gap'] == '1' ? '0.25rem' : (blockData['col' + i]['gap'] == '2' ? '0.5rem' : (blockData['col' + i]['gap'] == '3' ? '1rem' : (blockData['col' + i]['gap'] == '4' ? '1.5rem' : (blockData['col' + i]['gap'] == '5' ? '2rem' : '1rem')))))) + ';'}"
|
|
>
|
|
<th:block th:each="nestedI : ${#numbers.sequence(1, blockData['col' + i]['cols'])}">
|
|
<div
|
|
th:id="${blockData['col' + i]['id' + nestedI] != null and !#strings.isEmpty(blockData['col' + i]['id' + nestedI]) ? blockData['col' + i]['id' + nestedI] : null}"
|
|
th:class="${(blockData['col' + i]['width' + nestedI] != null and blockData['col' + i]['width' + nestedI] gt 0) ? ('col-lg-' + blockData['col' + i]['width' + nestedI] + ' col-md-6 col-12 mb-4') : (blockData['col' + i]['cols'] == 1 ? 'col-12 mb-4' : (blockData['col' + i]['cols'] == 2 ? 'col-md-6 col-12 mb-4' : (blockData['col' + i]['cols'] == 3 ? 'col-lg-4 col-md-6 col-12 mb-4' : (blockData['col' + i]['cols'] == 4 ? 'col-lg-3 col-md-6 col-12 mb-4' : 'col-lg col-md-6 col-12 mb-4'))))}"
|
|
th:classappend="${blockData['col' + i]['class' + nestedI] != null and !#strings.isEmpty(blockData['col' + i]['class' + nestedI]) ? blockData['col' + i]['class' + nestedI] : ''}"
|
|
>
|
|
<div th:replace=":: renderCell(type=${blockData['col' + i]['type' + nestedI]}, i=${nestedI}, blockData=${blockData['col' + i]})"></div>
|
|
</div>
|
|
</th:block>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</th:block>
|
|
</th:block>
|
|
<style>
|
|
html {
|
|
scroll-behavior: smooth;
|
|
}
|
|
[id] {
|
|
scroll-margin-top: 80px;
|
|
}
|
|
|
|
.sis-sticky-nav .menu-item--expanded,
|
|
.sis-sticky-nav .submenu-wrapper-desktop,
|
|
.sis-sticky-nav .submenu-wrapper {
|
|
background-color: inherit !important;
|
|
}
|
|
.sis-sticky-nav.sis-nav-light a,
|
|
.sis-sticky-nav.sis-nav-light summary span {
|
|
color: #002554 !important;
|
|
}
|
|
.sis-sticky-nav.sis-nav-light summary polygon {
|
|
fill: #002554 !important;
|
|
}
|
|
.sis-fullwidth-breakout {
|
|
width: 100vw !important;
|
|
position: relative !important;
|
|
left: 50% !important;
|
|
right: 50% !important;
|
|
margin-left: -50vw !important;
|
|
margin-right: -50vw !important;
|
|
max-width: 100vw !important;
|
|
box-sizing: border-box !important;
|
|
}
|
|
.ckeditor-accordion dt {
|
|
cursor: pointer;
|
|
font-weight: 600;
|
|
padding: 12px 16px;
|
|
background: #ffffff;
|
|
border: 1px solid #e3e6f0;
|
|
border-radius: 6px;
|
|
margin-top: 10px;
|
|
margin-bottom: 0;
|
|
user-select: none;
|
|
}
|
|
.ckeditor-accordion dt:hover {
|
|
background: #eaecf4;
|
|
}
|
|
.ckeditor-accordion dd {
|
|
padding: 16px;
|
|
border: 1px solid #e3e6f0;
|
|
border-top: none;
|
|
border-radius: 0 0 6px 6px;
|
|
background: #fff;
|
|
margin-bottom: 15px;
|
|
}
|
|
details.mc--info-menu-container {
|
|
border: unset;
|
|
}
|
|
nav.sis-sticky-nav ul.menu {
|
|
max-width: 1280px;
|
|
margin: auto !important;
|
|
}
|
|
</style>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
document.querySelectorAll('.ckeditor-accordion dt').forEach(function (dt) {
|
|
dt.addEventListener('click', function () {
|
|
var dd = this.nextElementSibling;
|
|
if (dd && dd.tagName.toLowerCase() === 'dd') {
|
|
if (dd.style.display === 'none' || getComputedStyle(dd).display === 'none') {
|
|
dd.style.display = 'block';
|
|
} else {
|
|
dd.style.display = 'none';
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// YouTube Thumbnail Preview Click-to-Play
|
|
document.querySelectorAll('.sis-yt-thumb-wrapper').forEach(function (wrapper) {
|
|
var embedUrl = wrapper.getAttribute('data-embed-url');
|
|
var customThumb = wrapper.getAttribute('data-custom-thumb');
|
|
if (embedUrl) {
|
|
var regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
|
|
var match = embedUrl.match(regExp);
|
|
var videoId = match && match[2].length === 11 ? match[2] : embedUrl.length === 11 ? embedUrl : '';
|
|
var thumbUrl =
|
|
customThumb && customThumb.trim() !== ''
|
|
? customThumb.trim()
|
|
: videoId
|
|
? 'https://img.youtube.com/vi/' + videoId + '/hqdefault.jpg'
|
|
: '';
|
|
if (thumbUrl && !wrapper.style.backgroundImage) {
|
|
wrapper.style.backgroundImage = 'url("' + thumbUrl + '")';
|
|
}
|
|
|
|
var isLoaded = false;
|
|
wrapper.addEventListener('click', function () {
|
|
if (isLoaded) return;
|
|
isLoaded = true;
|
|
|
|
var baseUrl = videoId ? 'https://www.youtube.com/embed/' + videoId : embedUrl;
|
|
var finalSrc = baseUrl + (baseUrl.includes('?') ? '&' : '?') + 'autoplay=1';
|
|
|
|
wrapper.innerHTML =
|
|
'<iframe src="' +
|
|
finalSrc +
|
|
'" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>';
|
|
});
|
|
}
|
|
});
|
|
|
|
// Interactive Hover Cards — Mouseover event delegation to apply active class dynamically
|
|
document.addEventListener('mouseover', function (e) {
|
|
var card = e.target.closest('.sis-hover-card, .sis-hover-card-v2');
|
|
if (card && !card.classList.contains('active')) {
|
|
var parentRow = card.closest('.row') || card.parentElement;
|
|
if (parentRow) {
|
|
parentRow.querySelectorAll('.sis-hover-card, .sis-hover-card-v2').forEach(function (c) {
|
|
c.classList.remove('active');
|
|
});
|
|
}
|
|
card.classList.add('active');
|
|
}
|
|
});
|
|
|
|
// Apply Custom Attributes (e.g. data-aos="fade-up" style="background:#fff") dynamically
|
|
document.querySelectorAll('[data-custom-attrs]').forEach(function (el) {
|
|
var attrStr = el.getAttribute('data-custom-attrs');
|
|
if (attrStr && attrStr.trim() !== '') {
|
|
var tempDiv = document.createElement('div');
|
|
tempDiv.innerHTML = '<div ' + attrStr + '></div>';
|
|
var tempEl = tempDiv.firstElementChild;
|
|
if (tempEl) {
|
|
Array.from(tempEl.attributes).forEach(function (attr) {
|
|
if (attr.name === 'class') {
|
|
attr.value.split(/\s+/).filter(Boolean).forEach(function (c) {
|
|
el.classList.add(c);
|
|
});
|
|
} else if (attr.name === 'style') {
|
|
el.style.cssText += ';' + attr.value;
|
|
} else {
|
|
el.setAttribute(attr.name, attr.value);
|
|
}
|
|
});
|
|
}
|
|
el.removeAttribute('data-custom-attrs');
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
<!-- Dedicated Page Custom JS -->
|
|
<script th:if="${page != null and page.customJs != null and !page.customJs.empty}" th:utext="${page.customJs}"></script>
|
|
</div>
|
|
</body>
|
|
</html>
|