fmegahed's picture
Rework extraction app for practitioner use (v3.0.0)
bff537e
Raw History Blame Contribute Delete
5.28 kB
// Client-side behaviour: input tabs, the video dialog, and the copy buttons.
(function() {
var INPUT_TABS = ['demo', 'paste', 'textfile', 'pdf', 'scanned', 'image'];
var currentTab = 'demo';
// ---- Input tabs ----------------------------------------------------------
function sendInputMethod() {
if (window.Shiny && Shiny.setInputValue) {
Shiny.setInputValue('input_method', currentTab);
}
}
function switchInputTab(tab, moveFocus) {
if (INPUT_TABS.indexOf(tab) === -1) return;
currentTab = tab;
INPUT_TABS.forEach(function(t) {
var tabEl = document.getElementById('tab-' + t);
var panelEl = document.getElementById('panel-' + t);
if (!tabEl || !panelEl) return;
var selected = (t === tab);
tabEl.classList.toggle('active', selected);
tabEl.setAttribute('aria-selected', selected ? 'true' : 'false');
tabEl.setAttribute('tabindex', selected ? '0' : '-1');
panelEl.style.display = selected ? 'block' : 'none';
if (selected && moveFocus) tabEl.focus();
});
sendInputMethod();
// Let Shiny render outputs in the panel that just became visible
if (window.jQuery) window.jQuery('#panel-' + tab).trigger('shown');
}
window.switchInputTab = switchInputTab;
function onTabKeydown(event) {
var index = INPUT_TABS.indexOf(currentTab);
var next = null;
if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {
next = INPUT_TABS[(index + 1) % INPUT_TABS.length];
} else if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {
next = INPUT_TABS[(index + INPUT_TABS.length - 1) % INPUT_TABS.length];
} else if (event.key === 'Home') {
next = INPUT_TABS[0];
} else if (event.key === 'End') {
next = INPUT_TABS[INPUT_TABS.length - 1];
}
if (next !== null) {
event.preventDefault();
switchInputTab(next, true);
}
}
// ---- Video dialog --------------------------------------------------------
var videoUrl = 'https://www.youtube.com/embed/y6Uit4Drf9w';
var lastFocused = null;
function videoModal() { return document.getElementById('video-modal'); }
function openVideo() {
var modal = videoModal();
lastFocused = document.activeElement;
document.getElementById('tutorial-video').src = videoUrl;
modal.style.display = 'flex';
document.getElementById('close-video-modal').focus();
}
function closeVideo() {
var modal = videoModal();
if (modal.style.display !== 'flex') return;
modal.style.display = 'none';
document.getElementById('tutorial-video').src = '';
if (lastFocused && lastFocused.focus) lastFocused.focus();
}
// Keep keyboard focus inside the open dialog
function trapVideoFocus(event) {
if (event.key !== 'Tab') return;
var closeBtn = document.getElementById('close-video-modal');
var iframe = document.getElementById('tutorial-video');
if (event.shiftKey && document.activeElement === closeBtn) {
event.preventDefault();
iframe.focus();
} else if (!event.shiftKey && document.activeElement === iframe) {
event.preventDefault();
closeBtn.focus();
}
}
// ---- Copy buttons --------------------------------------------------------
function copyFrom(button) {
var target = document.getElementById(button.getAttribute('data-target'));
if (!target) return;
var text = target.textContent;
var label = button.getAttribute('data-label') || button.textContent;
button.setAttribute('data-label', label);
function done(message) {
button.textContent = message;
window.setTimeout(function() { button.textContent = label; }, 2000);
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(
function() { done('Copied'); },
function() { done('Copy failed. Select the code and copy it manually.'); }
);
} else {
done('Copy is not available. Select the code and copy it manually.');
}
}
// ---- Wiring --------------------------------------------------------------
document.addEventListener('DOMContentLoaded', function() {
INPUT_TABS.forEach(function(t) {
var tabEl = document.getElementById('tab-' + t);
if (!tabEl) return;
tabEl.addEventListener('click', function() { switchInputTab(t, false); });
tabEl.addEventListener('keydown', onTabKeydown);
});
var modal = videoModal();
document.getElementById('open-video-modal').addEventListener('click', openVideo);
document.getElementById('close-video-modal').addEventListener('click', closeVideo);
modal.addEventListener('click', function(event) {
if (event.target === modal) closeVideo();
});
modal.addEventListener('keydown', trapVideoFocus);
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape') closeVideo();
});
document.addEventListener('click', function(event) {
var button = event.target.closest ? event.target.closest('.copy-btn') : null;
if (button) copyFrom(button);
});
});
// Tell the server which tab is open as soon as the session starts
if (window.jQuery) {
window.jQuery(document).on('shiny:connected', sendInputMethod);
}
})();