feat: add support for global and element-specific custom HTML attributes across editor plugins and page templates
This commit is contained in:
@@ -569,6 +569,18 @@ figure.table table tr:hover {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
|
||||
.rounded-lg {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.overview-wrapper-shadow {
|
||||
box-shadow: 0 0 30px #0000001a;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
5. Responsive Breakpoints — 3 Groups Only
|
||||
========================================================================== */
|
||||
@@ -1649,10 +1661,10 @@ Large Desktop (@media (min-width: 1366px)): Lines 1421 - 1481. */
|
||||
/* Hover 2 Active / Hover State */
|
||||
.sis-hover-card-v2:hover,
|
||||
.sis-hover-card-v2.active {
|
||||
background: linear-gradient(135deg, #0d71ba 0%, #003c7e 100%) !important;
|
||||
border-color: #359dfd !important;
|
||||
background: linear-gradient(135deg, var(--color-old-brick) 0%, #5a1212 100%) !important;
|
||||
border-color: var(--color-old-brick) !important;
|
||||
transform: translateY(-8px) scale(1.02) !important;
|
||||
box-shadow: 0 16px 36px rgba(13, 113, 186, 0.45) !important;
|
||||
box-shadow: 0 16px 36px rgba(136, 28, 28, 0.45) !important;
|
||||
}
|
||||
|
||||
.sis-hover-card-v2:hover .sis-hover-card__title,
|
||||
|
||||
@@ -21,7 +21,8 @@ class FlexTool {
|
||||
align: data.align || 'stretch',
|
||||
gap: data.gap || '3', // standard Bootstrap gap level
|
||||
globalClass: data.globalClass || '',
|
||||
globalId: data.globalId || ''
|
||||
globalId: data.globalId || '',
|
||||
globalAttributes: data.globalAttributes || data.attributes || ''
|
||||
};
|
||||
this.activeInstances = {};
|
||||
|
||||
@@ -35,6 +36,7 @@ class FlexTool {
|
||||
this.data[`accContent${i}`] = data[`accContent${i}`] || '';
|
||||
this.data[`class${i}`] = data[`class${i}`] || '';
|
||||
this.data[`id${i}`] = data[`id${i}`] || '';
|
||||
this.data[`attr${i}`] = data[`attr${i}`] || data[`attributes${i}`] || '';
|
||||
this.data[`width${i}`] = parseInt(data[`width${i}`]) || 0; // 0 means auto
|
||||
}
|
||||
this.wrapper = undefined;
|
||||
@@ -179,12 +181,12 @@ class FlexTool {
|
||||
|
||||
// 2. Global CSS Class
|
||||
const classDiv = document.createElement('div');
|
||||
classDiv.className = 'col-md-5 mb-2';
|
||||
classDiv.className = 'col-md-3 mb-2';
|
||||
classDiv.innerHTML = '<label class="small font-weight-bold text-secondary mb-1">Flex CSS Class(es)</label>';
|
||||
const classInput = document.createElement('input');
|
||||
classInput.type = 'text';
|
||||
classInput.className = 'form-control form-control-sm';
|
||||
classInput.placeholder = 'e.g. my-custom-flex';
|
||||
classInput.placeholder = 'e.g. my-flex-row';
|
||||
classInput.value = this.data.globalClass || '';
|
||||
if (this.readOnly) classInput.disabled = true;
|
||||
classInput.addEventListener('input', (e) => this.data.globalClass = e.target.value.trim());
|
||||
@@ -194,7 +196,7 @@ class FlexTool {
|
||||
|
||||
// 3. Global HTML ID
|
||||
const idDiv = document.createElement('div');
|
||||
idDiv.className = 'col-md-5 mb-2';
|
||||
idDiv.className = 'col-md-3 mb-2';
|
||||
idDiv.innerHTML = '<label class="small font-weight-bold text-secondary mb-1">Flex HTML ID</label>';
|
||||
const idInput = document.createElement('input');
|
||||
idInput.type = 'text';
|
||||
@@ -207,6 +209,21 @@ class FlexTool {
|
||||
idDiv.appendChild(idInput);
|
||||
bgSettingsRow.appendChild(idDiv);
|
||||
|
||||
// 4. Global Custom Attributes
|
||||
const attrDiv = document.createElement('div');
|
||||
attrDiv.className = 'col-md-4 mb-2';
|
||||
attrDiv.innerHTML = '<label class="small font-weight-bold text-secondary mb-1"><i class="fas fa-sliders-h"></i> Custom Attributes</label>';
|
||||
const attrInput = document.createElement('input');
|
||||
attrInput.type = 'text';
|
||||
attrInput.className = 'form-control form-control-sm';
|
||||
attrInput.placeholder = 'e.g. data-aos="fade-up" style="background:#fff"';
|
||||
attrInput.value = this.data.globalAttributes || '';
|
||||
if (this.readOnly) attrInput.disabled = true;
|
||||
attrInput.addEventListener('input', (e) => this.data.globalAttributes = e.target.value.trim());
|
||||
this.globalAttrInput = attrInput;
|
||||
attrDiv.appendChild(attrInput);
|
||||
bgSettingsRow.appendChild(attrDiv);
|
||||
|
||||
this.wrapper.appendChild(bgSettingsRow);
|
||||
|
||||
// Columns inputs container
|
||||
@@ -715,7 +732,8 @@ class FlexTool {
|
||||
align: this.data.align,
|
||||
gap: this.data.gap,
|
||||
globalClass: this.globalClassInput ? this.globalClassInput.value.trim() : (this.data.globalClass || ''),
|
||||
globalId: this.globalIdInput ? this.globalIdInput.value.trim() : (this.data.globalId || '')
|
||||
globalId: this.globalIdInput ? this.globalIdInput.value.trim() : (this.data.globalId || ''),
|
||||
globalAttributes: this.globalAttrInput ? this.globalAttrInput.value.trim() : (this.data.globalAttributes || '')
|
||||
};
|
||||
for (let i = 1; i <= this.data.cols; i++) {
|
||||
const type = this.data[`type${i}`] || 'html';
|
||||
@@ -740,6 +758,7 @@ class FlexTool {
|
||||
savedData[`accContent${i}`] = this.data[`accContent${i}`] || '';
|
||||
savedData[`class${i}`] = this.data[`class${i}`] || '';
|
||||
savedData[`id${i}`] = this.data[`id${i}`] || '';
|
||||
savedData[`attr${i}`] = this.data[`attr${i}`] || '';
|
||||
savedData[`width${i}`] = this.data[`width${i}`] || 0;
|
||||
}
|
||||
return savedData;
|
||||
|
||||
@@ -17,7 +17,8 @@ class GridTool {
|
||||
this.data = {
|
||||
cols: parseInt(data.cols) || 2,
|
||||
globalClass: data.globalClass || '',
|
||||
globalId: data.globalId || ''
|
||||
globalId: data.globalId || '',
|
||||
globalAttributes: data.globalAttributes || data.attributes || ''
|
||||
};
|
||||
this.activeInstances = {};
|
||||
|
||||
@@ -31,6 +32,7 @@ class GridTool {
|
||||
this.data[`accContent${i}`] = data[`accContent${i}`] || '';
|
||||
this.data[`class${i}`] = data[`class${i}`] || '';
|
||||
this.data[`id${i}`] = data[`id${i}`] || '';
|
||||
this.data[`attr${i}`] = data[`attr${i}`] || data[`attributes${i}`] || '';
|
||||
this.data[`width${i}`] = parseInt(data[`width${i}`]) || 0; // 0 means auto
|
||||
}
|
||||
this.wrapper = undefined;
|
||||
@@ -73,7 +75,7 @@ class GridTool {
|
||||
|
||||
// 2. Global CSS Class
|
||||
const classDiv = document.createElement('div');
|
||||
classDiv.className = 'col-md-5 mb-2';
|
||||
classDiv.className = 'col-md-3 mb-2';
|
||||
classDiv.innerHTML = '<label class="small font-weight-bold text-secondary mb-1">Grid CSS Class(es)</label>';
|
||||
const classInput = document.createElement('input');
|
||||
classInput.type = 'text';
|
||||
@@ -88,7 +90,7 @@ class GridTool {
|
||||
|
||||
// 3. Global HTML ID
|
||||
const idDiv = document.createElement('div');
|
||||
idDiv.className = 'col-md-5 mb-2';
|
||||
idDiv.className = 'col-md-3 mb-2';
|
||||
idDiv.innerHTML = '<label class="small font-weight-bold text-secondary mb-1">Grid HTML ID</label>';
|
||||
const idInput = document.createElement('input');
|
||||
idInput.type = 'text';
|
||||
@@ -101,6 +103,21 @@ class GridTool {
|
||||
idDiv.appendChild(idInput);
|
||||
settingsRow.appendChild(idDiv);
|
||||
|
||||
// 4. Global Custom Attributes
|
||||
const attrDiv = document.createElement('div');
|
||||
attrDiv.className = 'col-md-4 mb-2';
|
||||
attrDiv.innerHTML = '<label class="small font-weight-bold text-secondary mb-1"><i class="fas fa-sliders-h"></i> Custom Attributes</label>';
|
||||
const attrInput = document.createElement('input');
|
||||
attrInput.type = 'text';
|
||||
attrInput.className = 'form-control form-control-sm';
|
||||
attrInput.placeholder = 'e.g. data-aos="fade-up" style="background:#fff"';
|
||||
attrInput.value = this.data.globalAttributes || '';
|
||||
if (this.readOnly) attrInput.disabled = true;
|
||||
attrInput.addEventListener('input', (e) => this.data.globalAttributes = e.target.value.trim());
|
||||
this.globalAttrInput = attrInput;
|
||||
attrDiv.appendChild(attrInput);
|
||||
settingsRow.appendChild(attrDiv);
|
||||
|
||||
this.wrapper.appendChild(settingsRow);
|
||||
|
||||
// Columns inputs container
|
||||
@@ -607,7 +624,8 @@ class GridTool {
|
||||
const savedData = {
|
||||
cols: this.data.cols,
|
||||
globalClass: this.globalClassInput ? this.globalClassInput.value.trim() : (this.data.globalClass || ''),
|
||||
globalId: this.globalIdInput ? this.globalIdInput.value.trim() : (this.data.globalId || '')
|
||||
globalId: this.globalIdInput ? this.globalIdInput.value.trim() : (this.data.globalId || ''),
|
||||
globalAttributes: this.globalAttrInput ? this.globalAttrInput.value.trim() : (this.data.globalAttributes || '')
|
||||
};
|
||||
for (let i = 1; i <= this.data.cols; i++) {
|
||||
const type = this.data[`type${i}`] || 'html';
|
||||
@@ -632,6 +650,7 @@ class GridTool {
|
||||
savedData[`accContent${i}`] = this.data[`accContent${i}`] || '';
|
||||
savedData[`class${i}`] = this.data[`class${i}`] || '';
|
||||
savedData[`id${i}`] = this.data[`id${i}`] || '';
|
||||
savedData[`attr${i}`] = this.data[`attr${i}`] || '';
|
||||
savedData[`width${i}`] = this.data[`width${i}`] || 0;
|
||||
}
|
||||
return savedData;
|
||||
|
||||
@@ -19,6 +19,7 @@ class SISHoverCardTool {
|
||||
styleVariant: (data && data.styleVariant) || 'v1',
|
||||
globalClass: (data && data.globalClass) || 'sis-hover-card-section',
|
||||
globalId: (data && data.globalId) || '',
|
||||
globalAttributes: (data && data.globalAttributes) || (data && data.attributes) || '',
|
||||
items: (data && data.items && Array.isArray(data.items)) ? data.items : []
|
||||
};
|
||||
|
||||
@@ -98,7 +99,7 @@ class SISHoverCardTool {
|
||||
|
||||
// 2. Global CSS Class
|
||||
const classDiv = document.createElement('div');
|
||||
classDiv.className = 'col-md-5 mb-2';
|
||||
classDiv.className = 'col-md-3 mb-2';
|
||||
classDiv.innerHTML = '<label class="small font-weight-bold text-secondary mb-1">Global CSS Class(es)</label>';
|
||||
const classInput = document.createElement('input');
|
||||
classInput.type = 'text';
|
||||
@@ -113,7 +114,7 @@ class SISHoverCardTool {
|
||||
|
||||
// 3. Global HTML ID
|
||||
const idDiv = document.createElement('div');
|
||||
idDiv.className = 'col-md-4 mb-2';
|
||||
idDiv.className = 'col-md-3 mb-2';
|
||||
idDiv.innerHTML = '<label class="small font-weight-bold text-secondary mb-1">Global HTML ID</label>';
|
||||
const idInput = document.createElement('input');
|
||||
idInput.type = 'text';
|
||||
@@ -126,6 +127,21 @@ class SISHoverCardTool {
|
||||
idDiv.appendChild(idInput);
|
||||
settingsRow.appendChild(idDiv);
|
||||
|
||||
// 4. Global Custom Attributes
|
||||
const attrDiv = document.createElement('div');
|
||||
attrDiv.className = 'col-md-3 mb-2';
|
||||
attrDiv.innerHTML = '<label class="small font-weight-bold text-secondary mb-1"><i class="fas fa-sliders-h"></i> Custom Attributes</label>';
|
||||
const attrInput = document.createElement('input');
|
||||
attrInput.type = 'text';
|
||||
attrInput.className = 'form-control form-control-sm';
|
||||
attrInput.placeholder = 'e.g. data-aos="fade-up" style="..."';
|
||||
attrInput.value = this.data.globalAttributes || '';
|
||||
if (this.readOnly) attrInput.disabled = true;
|
||||
attrInput.addEventListener('input', (e) => this.data.globalAttributes = e.target.value.trim());
|
||||
this.globalAttrInput = attrInput;
|
||||
attrDiv.appendChild(attrInput);
|
||||
settingsRow.appendChild(attrDiv);
|
||||
|
||||
this.wrapper.appendChild(settingsRow);
|
||||
|
||||
// Cards items container
|
||||
@@ -380,7 +396,21 @@ class SISHoverCardTool {
|
||||
|
||||
hoverImgGroup.appendChild(hoverInputGroup);
|
||||
hoverImgGroup.appendChild(hoverPreviewContainer);
|
||||
itemBox.appendChild(hoverImgGroup);
|
||||
// Custom Attributes field for individual card
|
||||
const cardAttrDiv = document.createElement('div');
|
||||
cardAttrDiv.className = 'form-group mb-2';
|
||||
cardAttrDiv.innerHTML = '<label class="small font-weight-bold text-secondary mb-1"><i class="fas fa-sliders-h"></i> Card Custom Attributes</label>';
|
||||
const cardAttrInput = document.createElement('input');
|
||||
cardAttrInput.type = 'text';
|
||||
cardAttrInput.className = 'form-control form-control-sm';
|
||||
cardAttrInput.placeholder = 'e.g. data-aos="fade-up" style="background:#fff"';
|
||||
cardAttrInput.value = item.attributes || '';
|
||||
if (this.readOnly) cardAttrInput.disabled = true;
|
||||
cardAttrInput.addEventListener('input', (e) => {
|
||||
item.attributes = e.target.value.trim();
|
||||
});
|
||||
cardAttrDiv.appendChild(cardAttrInput);
|
||||
itemBox.appendChild(cardAttrDiv);
|
||||
|
||||
// Default Active Radio (Only 1 option active at a time)
|
||||
const activeRadioDiv = document.createElement('div');
|
||||
@@ -418,6 +448,7 @@ class SISHoverCardTool {
|
||||
styleVariant: this.variantSelect ? this.variantSelect.value : (this.data.styleVariant || 'v1'),
|
||||
globalClass: this.globalClassInput ? this.globalClassInput.value.trim() : (this.data.globalClass || 'sis-hover-card-section'),
|
||||
globalId: this.globalIdInput ? this.globalIdInput.value.trim() : (this.data.globalId || ''),
|
||||
globalAttributes: this.globalAttrInput ? this.globalAttrInput.value.trim() : (this.data.globalAttributes || ''),
|
||||
items: this.data.items || []
|
||||
};
|
||||
}
|
||||
|
||||
+17
-3
@@ -12,7 +12,8 @@ class HtmlSnippetTool {
|
||||
|
||||
constructor({ data, api }) {
|
||||
this.data = {
|
||||
id: data.id || ''
|
||||
id: data.id || '',
|
||||
globalAttributes: data.globalAttributes || data.attributes || ''
|
||||
};
|
||||
this.api = api;
|
||||
this.wrapper = undefined;
|
||||
@@ -39,7 +40,7 @@ class HtmlSnippetTool {
|
||||
title.style.marginTop = '0';
|
||||
title.style.marginBottom = '10px';
|
||||
title.style.padding = '15px 15px 0 15px';
|
||||
title.innerText = 'HTML Snippet ID:';
|
||||
title.innerText = 'HTML Snippet ID & Custom Attributes:';
|
||||
title.style.fontSize = '14px';
|
||||
title.style.color = '#333';
|
||||
|
||||
@@ -52,12 +53,24 @@ class HtmlSnippetTool {
|
||||
input.classList.add('ce-input');
|
||||
input.placeholder = 'Enter Snippet ID (e.g., test_banner)';
|
||||
input.value = this.data.id;
|
||||
input.style.flex = '1';
|
||||
|
||||
input.addEventListener('input', (e) => {
|
||||
this.data.id = e.target.value.trim();
|
||||
});
|
||||
|
||||
const attrInput = document.createElement('input');
|
||||
attrInput.classList.add('ce-input');
|
||||
attrInput.placeholder = 'Custom Attributes (e.g. data-aos="fade-up" style="...")';
|
||||
attrInput.value = this.data.globalAttributes || '';
|
||||
attrInput.style.flex = '1';
|
||||
|
||||
attrInput.addEventListener('input', (e) => {
|
||||
this.data.globalAttributes = e.target.value.trim();
|
||||
});
|
||||
|
||||
inputContainer.appendChild(input);
|
||||
inputContainer.appendChild(attrInput);
|
||||
|
||||
this.wrapper.appendChild(title);
|
||||
this.wrapper.appendChild(inputContainer);
|
||||
@@ -65,7 +78,8 @@ class HtmlSnippetTool {
|
||||
|
||||
save(blockContent) {
|
||||
return {
|
||||
id: this.data.id
|
||||
id: this.data.id,
|
||||
globalAttributes: this.data.globalAttributes || ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ class SISTimelineTool {
|
||||
this.api = api;
|
||||
this.readOnly = readOnly;
|
||||
this.data = {
|
||||
globalAttributes: (data && data.globalAttributes) || (data && data.attributes) || '',
|
||||
items: (data && data.items && Array.isArray(data.items)) ? data.items : []
|
||||
};
|
||||
// Add an initial empty item if list is empty
|
||||
@@ -29,10 +30,13 @@ class SISTimelineTool {
|
||||
this.wrapper.style.marginBottom = '12px';
|
||||
|
||||
const headerLabel = document.createElement('label');
|
||||
headerLabel.className = 'font-weight-bold text-primary small mb-3 d-block';
|
||||
headerLabel.className = 'font-weight-bold text-primary small mb-2 d-block';
|
||||
headerLabel.innerHTML = '<i class="fas fa-stream"></i> Timeline Group Settings';
|
||||
this.wrapper.appendChild(headerLabel);
|
||||
|
||||
const globalAttrGroup = this._createInput('e.g. data-aos="fade-up" style="..."', this.data.globalAttributes, 'global-attr', '<i class="fas fa-sliders-h"></i> Global Custom Attributes');
|
||||
this.wrapper.appendChild(globalAttrGroup);
|
||||
|
||||
this.itemsContainer = document.createElement('div');
|
||||
this.wrapper.appendChild(this.itemsContainer);
|
||||
|
||||
@@ -196,9 +200,12 @@ class SISTimelineTool {
|
||||
imageGroup.appendChild(inputRow);
|
||||
imageGroup.appendChild(imagePreview);
|
||||
|
||||
const attrGroup = this._createInput('e.g. data-aos="fade-right" style="..."', item.attributes, 'attr', '<i class="fas fa-sliders-h"></i> Step Custom Attributes');
|
||||
|
||||
itemBox.appendChild(dateGroup);
|
||||
itemBox.appendChild(descGroup);
|
||||
itemBox.appendChild(imageGroup);
|
||||
itemBox.appendChild(attrGroup);
|
||||
|
||||
this.itemsContainer.appendChild(itemBox);
|
||||
}
|
||||
@@ -254,11 +261,15 @@ class SISTimelineTool {
|
||||
const date = box.querySelector('.ce-timeline-input-date').value.trim();
|
||||
const desc = box.querySelector('.ce-timeline-input-desc').value.trim();
|
||||
const img = box.querySelector('.ce-timeline-input-image').value.trim();
|
||||
if (date || desc || img) {
|
||||
items.push({ date: date, description: desc, imageUrl: img });
|
||||
const attrEl = box.querySelector('.ce-timeline-input-attr');
|
||||
const attr = attrEl ? attrEl.value.trim() : '';
|
||||
if (date || desc || img || attr) {
|
||||
items.push({ date: date, description: desc, imageUrl: img, attributes: attr });
|
||||
}
|
||||
});
|
||||
const globalAttrEl = this.wrapper.querySelector('.ce-timeline-input-global-attr');
|
||||
return {
|
||||
globalAttributes: globalAttrEl ? globalAttrEl.value.trim() : (this.data.globalAttributes || ''),
|
||||
items: items
|
||||
};
|
||||
}
|
||||
|
||||
@@ -349,7 +349,8 @@
|
||||
<!-- 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: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'])}">
|
||||
@@ -357,6 +358,7 @@
|
||||
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>
|
||||
@@ -369,7 +371,8 @@
|
||||
<!-- 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: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;"
|
||||
@@ -380,6 +383,7 @@
|
||||
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>
|
||||
@@ -392,12 +396,14 @@
|
||||
<!-- 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: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' : ''))}">
|
||||
<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']}" />
|
||||
@@ -692,17 +698,42 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Interactive Hover Cards — Mouseenter transfers active class to hovered card
|
||||
document.querySelectorAll('.sis-hover-card').forEach(function (card) {
|
||||
card.addEventListener('mouseenter', function () {
|
||||
var parentRow = card.closest('.row');
|
||||
// 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').forEach(function (c) {
|
||||
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>
|
||||
|
||||
Reference in New Issue
Block a user