...
| HTML |
|---|
<!-- JS: Alexandr Petrunin-->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Handle collapse functionality
document.querySelectorAll('[data-bs-toggle="collapse"]').forEach(trigger => {
trigger.addEventListener('click', function(e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('data-bs-target'));
// If there's a parent accordion, hide other panels
const parent = document.querySelector(target.getAttribute('data-bs-parent'));
if (parent) {
parent.querySelectorAll('.collapse.show').forEach(el => {
if (el !== target) {
el.classList.remove('show');
}
});
}
// Toggle target panel
target.classList.toggle('show');
});
});
// Handle list/tab functionality
document.querySelectorAll('[data-bs-toggle="list"]').forEach(trigger => {
trigger.addEventListener('click', function(e) {
e.preventDefault();
// Remove active class from all tabs in group
const listGroup = this.closest('.list-group');
listGroup.querySelectorAll('.active').forEach(el => {
el.classList.remove('active');
});
// Add active class to clicked tab
this.classList.add('active');
// Show corresponding content
const target = document.querySelector(this.getAttribute('href'));
const tabContent = target.closest('.tab-content');
tabContent.querySelectorAll('.tab-pane').forEach(pane => {
pane.classList.remove('show', 'active');
});
target.classList.add('show', 'active');
});
});
});
// Add required CSS if not already present
const style = document.createElement('style');
style.textContent = `
.collapse:not(.show) {
display: none;
}
.collapse.show {
display: block;
}
.tab-content > .tab-pane {
display: none;
}
.tab-content > .active {
display: block;
}
`;
document.head.appendChild(style);
</script>
<!-- Activate tooltips -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Find all elements with tooltip
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(element => {
const title = element.getAttribute('title');
// Create tooltip element
const tooltip = document.createElement('div');
tooltip.className = 'custom-tooltip';
tooltip.textContent = title;
document.body.appendChild(tooltip);
// Show tooltip
element.addEventListener('mouseenter', e => {
const bounds = element.getBoundingClientRect();
tooltip.style.display = 'block';
// Position tooltip above the element
tooltip.style.left = bounds.left + (bounds.width - tooltip.offsetWidth) / 2 + 'px';
tooltip.style.top = bounds.top - tooltip.offsetHeight - 5 + 'px';
});
// Hide tooltip
element.addEventListener('mouseleave', () => {
tooltip.style.display = 'none';
});
// Remove title attribute to prevent default browser tooltip
element.removeAttribute('title');
});
});
// Add required CSS
const tooltipStyle = document.createElement('style');
tooltipStyle.textContent = `
.custom-tooltip {
display: none;
position: fixed;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 5px 10px;
border-radius: 4px;
font-size: 14px;
z-index: 1000;
pointer-events: none;
}
.custom-tooltip::after {
content: '';
position: absolute;
bottom: -5px;
left: 50%;
transform: translateX(-50%);
border-width: 5px 5px 0;
border-style: solid;
border-color: rgba(0, 0, 0, 0.8) transparent transparent;
}
`;
document.head.appendChild(tooltipStyle);
</script>
<!-- Filter bar -->
<script>
functionfunction extractTags(raw) {
return raw
// extract "cycle N" first (keeps them intact)
.replace(/cycle\s+(\d+)/gi, 'cycle-$1')
// split on whitespace/newlines
.trim()
.toLowerCase()
.split(/\s+/)
// convert cycle-N back to "cycle N"
.map(tag => tag.replace(/cycle-(\d+)/, 'cycle $1'))
.filter(Boolean);
}
function searchActivities() {
const cards = document.querySelectorAll('#card-grid .card');
const filter = {
text: document.getElementById('card-filter-text').value.trim().toLowerCase(),
topic: document.getElementById('card-filter-topic').value.trim().toLowerCase(),
cycle: document.getElementById('card-filter-cycle').value.trim().toLowerCase(),
deliverable: document.getElementById('card-filter-deliverable').value.trim().toLowerCase(),
};
cards.forEach(card => {
const title = card.querySelector('.card-title').innerText.trim().toLowerCase();
const rawTags = card.querySelector('.tags').innerText.trim().toLowerCase();
// Universal parsing for both “identity completed cycle 6” and multi-span tags
const tagList = rawTags
.match(/cycle \d+|identity|security|standards|completed|tim|service|community|external/g)
|| [];
extractTags(rawTags);
const matches = (filterValueval) => {
if (!filterValue) return true;
return !val || tagList.includes(filterValueval);
};
const show =
title.includes(filter.text) &&
matches(filter.topic) &&
matches(filter.cycle) &&
matches(filter.deliverable);
card.style.display = show ? "" : "none";
});
}
</script> |