// 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); } })();