Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions benchmarks/templates/benchmarks/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

<html lang="en">
<head>
<!-- Global Site Tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89541187-2"></script>
<!-- Google Analytics (GA4) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-RZ4VDQM08E"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());

gtag('config', 'UA-89541187-2');
gtag('config', 'G-RZ4VDQM08E');
</script>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
Expand Down
42 changes: 42 additions & 0 deletions benchmarks/templates/benchmarks/model.html
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,43 @@ <h4 class="subtitle is-4">
<i class="fa-brands fa-github"></i> Code examples
</a>
</div>
{% comment "BERG link + tooltip disabled in favor of the BERG info box below. To re-enable, remove comment tags and rename data-tooltip-html-disabled back to data-tooltip-html" %}
<div class="block">
<a href="https://gifale95.github.io/BERG/"
target="_blank"
id="berg-link"
data-tooltip-html-disabled="{% if model.domain == 'vision' %}Through the &lt;a href='https://gifale95.github.io/BERG/' target='_blank'&gt;Brain Encoding Response Generator (BERG)&lt;/a&gt; you can easily generate neural responses to images of your choice using any BrainScore vision model. For more information on how to use BERG, see the &lt;a href='https://brain-encoding-response-generator.readthedocs.io/en/latest/models/model_cards/brainscore_vision.html' target='_blank'&gt;documentation&lt;/a&gt; and &lt;a href='https://drive.google.com/file/d/1B-gRZmdN6ZhxUUgUXgxfTgJc344a8Z17/view?usp=sharing' target='_blank'&gt;tutorial&lt;/a&gt;.{% else %}Through the &lt;a href='https://gifale95.github.io/BERG/' target='_blank'&gt;Brain Encoding Response Generator (BERG)&lt;/a&gt; you can easily generate neural responses to text sentences of your choice using any BrainScore language model. For more information on how to use BERG, see the &lt;a href='https://brain-encoding-response-generator.readthedocs.io/en/latest/models/model_cards/brainscore_language.html' target='_blank'&gt;documentation&lt;/a&gt; and &lt;a href='https://drive.google.com/file/d/1B-gRZmdN6ZhxUUgUXgxfTgJc344a8Z17/view?usp=sharing' target='_blank'&gt;tutorial&lt;/a&gt;.{% endif %}"
data-tooltip-position="top">
<i class="fa-solid fa-brain"></i> Brain Encoding Response Generator
</a>
</div>
{% endcomment %}
</div>
</div>
</div>

{# BERG info box #}
<div class="box" id="berg-box">
<h4 class="subtitle is-4">
Brain Encoding Response Generator (BERG)
</h4>
<p>
Through the
<a href="https://gifale95.github.io/BERG/" target="_blank"
class="berg-box-link" data-berg-label="box_berg">BERG</a>
you can easily generate neural responses to
{% if model.domain == 'vision' %}images of your choice using any Brain-Score vision model.{% else %}text sentences of your choice using any Brain-Score language model.{% endif %}
</p>
<p>
For more information on how to use BERG, see the
<a href="https://brain-encoding-response-generator.readthedocs.io/en/latest/models/model_cards/brainscore_{{ model.domain }}.html"
target="_blank" class="berg-box-link" data-berg-label="box_documentation">documentation</a>
and
<a href="https://drive.google.com/file/d/1B-gRZmdN6ZhxUUgUXgxfTgJc344a8Z17/view?usp=sharing"
target="_blank" class="berg-box-link" data-berg-label="box_tutorial">tutorial</a>.
</p>
</div>

{# Benchmarks bibtex #}
<div class="box">
<h2 class="subtitle is-4">
Expand All @@ -282,4 +315,13 @@ <h2 class="subtitle is-4">
</div>
</div>
</section>
<script src="{% static 'benchmarks/js/components/tooltip.js' %}"></script>
<script src="{% static 'benchmarks/js/link-tracking.js' %}"></script>
<script>
trackLinks({
selectors: {
'.berg-box-link': { category: 'BERG', labelAttr: 'data-berg-label' }
}
});
</script>
{% endblock %}
16 changes: 16 additions & 0 deletions static/benchmarks/css/components/tooltip.sass
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@
&::after
border-top-color: #333

// Multi-line tooltip (for HTML content)
&.tooltip-multiline
white-space: normal
max-width: 400px
text-align: left
line-height: 1.5
padding: 12px 16px
pointer-events: auto

a
color: #90cdf4
text-decoration: underline

&:hover
color: white

// Tooltip fade-in animation
@keyframes tooltipFadeIn
from
Expand Down
66 changes: 49 additions & 17 deletions static/benchmarks/js/components/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@
* @param {string} options.position - Tooltip position: 'top', 'bottom', 'left', 'right' (default: 'top')
* @param {number} options.duration - Auto-hide duration in ms (default: 2500)
* @param {number} options.offset - Distance from element in pixels (default: 10)
* @param {boolean} options.html - If true, render message as HTML instead of plain text (default: false)
* @returns {Object|null} Object with `element` and `remove()` method, or null if element is invalid
*/
function createTooltip(element, message, options = {}) {
const {
type = 'info',
position = 'top',
duration = 2500,
offset = 10
offset = 10,
html = false
} = options;

if (!element) return null;
Expand All @@ -41,7 +43,12 @@ function createTooltip(element, message, options = {}) {
if (position !== 'top') {
tooltip.classList.add(`tooltip-${position}`);
}
tooltip.textContent = message;
if (html) {
tooltip.innerHTML = message;
tooltip.classList.add('tooltip-multiline');
} else {
tooltip.textContent = message;
}

// Position tooltip
const rect = element.getBoundingClientRect();
Expand Down Expand Up @@ -109,22 +116,40 @@ function showTooltip(elementId, message, type = 'info') {
*/
function addHoverTooltip(element, message, options = {}) {
if (!element) return;

let currentTooltip = null;

element.addEventListener('mouseenter', () => {
currentTooltip = createTooltip(element, message, {
...options,
duration: 999999 // Don't auto-hide on hover
});
});

element.addEventListener('mouseleave', () => {
if (currentTooltip) {
currentTooltip.remove();
currentTooltip = null;
let hideTimeout = null;

function show() {
if (hideTimeout) { clearTimeout(hideTimeout); hideTimeout = null; }
if (!currentTooltip) {
currentTooltip = createTooltip(element, message, {
...options,
duration: 999999
});
if (currentTooltip && options.html) {
currentTooltip.element.addEventListener('mouseenter', function() {
if (hideTimeout) { clearTimeout(hideTimeout); hideTimeout = null; }
});
currentTooltip.element.addEventListener('mouseleave', function() {
hide();
});
}
}
});
}

function hide() {
var delay = options.html ? 200 : 0;
hideTimeout = setTimeout(function() {
if (currentTooltip) {
currentTooltip.remove();
currentTooltip = null;
}
}, delay);
}

element.addEventListener('mouseenter', show);
element.addEventListener('mouseleave', hide);
}

/**
Expand All @@ -136,9 +161,16 @@ function initializeDataTooltips() {
const message = element.getAttribute('data-tooltip');
const type = element.getAttribute('data-tooltip-type') || 'info';
const position = element.getAttribute('data-tooltip-position') || 'top';

addHoverTooltip(element, message, { type, position });
});
document.querySelectorAll('[data-tooltip-html]').forEach(element => {
const message = element.getAttribute('data-tooltip-html');
const type = element.getAttribute('data-tooltip-type') || 'info';
const position = element.getAttribute('data-tooltip-position') || 'bottom';

addHoverTooltip(element, message, { type, position, html: true });
});
}

// Auto-initialize data tooltips when DOM is ready
Expand Down
90 changes: 90 additions & 0 deletions static/benchmarks/js/link-tracking.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Generic link click tracking for Google Analytics (gtag).
*
* Usage:
* trackLinks({
* // Track a single element by ID
* ids: {
* 'berg-link': { category: 'BERG', label: 'main_link' }
* },
* // Track elements matching a CSS selector, reading the label from a data attribute
* selectors: {
* '.berg-box-link': { category: 'BERG', labelAttr: 'data-berg-label' }
* },
* // Delegated tracking: clicks inside a container, mapped by URL substring
* delegated: {
* '.tooltip-multiline a': {
* category: 'BERG',
* urlMap: {
* 'gifale95.github.io/BERG': 'tooltip_berg',
* 'readthedocs': 'tooltip_documentation',
* 'drive.google.com': 'tooltip_tutorial'
* },
* fallbackLabel: 'unknown'
* }
* }
* });
*/
function trackLinks(config) {
if (typeof gtag === 'undefined') return;

// Track by element ID
if (config.ids) {
Object.keys(config.ids).forEach(function(id) {
var el = document.getElementById(id);
if (!el) return;
var opts = config.ids[id];
el.addEventListener('click', function() {
gtag('event', 'click', {
event_category: opts.category,
event_label: opts.label,
transport_type: 'beacon'
});
});
});
}

// Track by CSS selector, with label from a data attribute or a fixed string
if (config.selectors) {
Object.keys(config.selectors).forEach(function(selector) {
var opts = config.selectors[selector];
document.querySelectorAll(selector).forEach(function(el) {
el.addEventListener('click', function() {
var label = opts.labelAttr
? this.getAttribute(opts.labelAttr)
: opts.label;
gtag('event', 'click', {
event_category: opts.category,
event_label: label,
transport_type: 'beacon'
});
});
});
});
}

// Delegated click tracking: match clicked links by URL substring
if (config.delegated) {
Object.keys(config.delegated).forEach(function(selector) {
var opts = config.delegated[selector];
document.addEventListener('click', function(e) {
var link = e.target.closest(selector);
if (!link) return;
var href = link.getAttribute('href') || '';
var label = opts.fallbackLabel || 'unknown';
var urls = Object.keys(opts.urlMap);
for (var i = 0; i < urls.length; i++) {
if (href.indexOf(urls[i]) !== -1) {
label = opts.urlMap[urls[i]];
break;
}
}
gtag('event', 'click', {
event_category: opts.category,
event_label: label,
transport_type: 'beacon'
});
});
});
}
}