195 lines
6.4 KiB
JavaScript
195 lines
6.4 KiB
JavaScript
/**
|
|
* Table Navigation Dropdown - JavaScript Only Solution for Mojolicious Sites
|
|
*
|
|
* This script automatically creates a dropdown menu to navigate between tables
|
|
* on a page without requiring any HTML modifications.
|
|
*
|
|
* Compatible with all modern browsers and IE11+.
|
|
*
|
|
* How to use:
|
|
* 1. Add this script to your Mojolicious site using a <script> tag
|
|
* 2. The script will automatically run when the page loads
|
|
* 3. A dropdown menu will be created at the top of the page
|
|
*/
|
|
|
|
(function() {
|
|
// Function to run when DOM is fully loaded
|
|
function initTableNavigation() {
|
|
// Find all tables with class 'node' (based on your HTML structure)
|
|
var tables = document.querySelectorAll('table.node');
|
|
|
|
if (!tables || tables.length === 0) {
|
|
console.log('No tables found with class "node"');
|
|
return;
|
|
}
|
|
|
|
// Create container for the dropdown
|
|
var navContainer = document.createElement('div');
|
|
navContainer.style.position = 'sticky';
|
|
navContainer.style.top = '0';
|
|
navContainer.style.backgroundColor = '#fff';
|
|
navContainer.style.padding = '10px 0';
|
|
navContainer.style.marginBottom = '20px';
|
|
navContainer.style.zIndex = '100';
|
|
navContainer.style.borderBottom = '1px solid #ddd';
|
|
navContainer.style.width = '300px';
|
|
|
|
// Create the select element
|
|
var select = document.createElement('select');
|
|
select.style.width = '100%';
|
|
select.style.padding = '10px';
|
|
select.style.fontSize = '16px';
|
|
select.style.border = '1px solid #ddd';
|
|
select.style.borderRadius = '4px';
|
|
select.style.backgroundColor = '#f8f8f8';
|
|
select.style.cursor = 'pointer';
|
|
|
|
// Add default option
|
|
var defaultOption = document.createElement('option');
|
|
defaultOption.value = '';
|
|
defaultOption.textContent = '-- Jump to a table --';
|
|
select.appendChild(defaultOption);
|
|
|
|
// Process each table and add to dropdown
|
|
for (var i = 0; i < tables.length; i++) {
|
|
var table = tables[i];
|
|
|
|
// Try to get table ID from the first row if it contains "id:"
|
|
var tableId = 'table-' + i;
|
|
var tableName = 'Table ' + (i + 1);
|
|
|
|
// Look for the ID in the table header
|
|
var idCell = table.querySelector('thead td.first');
|
|
var idValue = table.querySelector('thead td.second');
|
|
|
|
if (idCell && idValue && idCell.textContent.trim().toLowerCase() === 'id:') {
|
|
// Get the ID value (might be in a div with class 'id')
|
|
var idDiv = idValue.querySelector('.id');
|
|
if (idDiv) {
|
|
tableId = idDiv.textContent.trim();
|
|
tableName = tableId;
|
|
} else if (idValue.textContent.trim()) {
|
|
tableId = idValue.textContent.trim();
|
|
tableName = tableId;
|
|
}
|
|
}
|
|
|
|
// Try to get a better name from the description if available
|
|
var descRows = table.querySelectorAll('tbody tr');
|
|
for (var j = 0; j < descRows.length; j++) {
|
|
var descRow = descRows[j];
|
|
var descCell = descRow.querySelector('td.first');
|
|
var descValue = descRow.querySelector('td.second');
|
|
|
|
if (descCell && descValue &&
|
|
descCell.textContent.trim().toLowerCase().includes('description') &&
|
|
descValue.textContent.trim()) {
|
|
tableName = descValue.textContent.trim() + ' (' + tableName + ')';
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Create a unique ID for the table if it doesn't have one
|
|
if (!table.id) {
|
|
// Clean the ID to make it valid for HTML
|
|
var safeId = tableId.replace(/[^a-z0-9]/gi, '_').toLowerCase();
|
|
table.id = safeId;
|
|
}
|
|
|
|
// Add option to dropdown
|
|
var option = document.createElement('option');
|
|
option.value = table.id;
|
|
option.textContent = tableName;
|
|
select.appendChild(option);
|
|
|
|
// Add scroll margin to the table
|
|
table.style.scrollMarginTop = '70px';
|
|
}
|
|
|
|
// Add event listener to the select element
|
|
if (select.addEventListener) {
|
|
// Modern browsers
|
|
select.addEventListener('change', handleSelectChange);
|
|
} else if (select.attachEvent) {
|
|
// IE8 and below
|
|
select.attachEvent('onchange', handleSelectChange);
|
|
}
|
|
|
|
// Add the select to the container
|
|
navContainer.appendChild(select);
|
|
|
|
// Insert the container at the top of the body or after the first heading
|
|
var heading = document.querySelector('h1, h2');
|
|
if (heading && heading.parentNode) {
|
|
heading.parentNode.insertBefore(navContainer, heading.nextSibling);
|
|
} else {
|
|
var body = document.body;
|
|
if (body.firstChild) {
|
|
body.insertBefore(navContainer, body.firstChild);
|
|
} else {
|
|
body.appendChild(navContainer);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Function to handle select change
|
|
function handleSelectChange() {
|
|
var selectedValue = this.value;
|
|
if (selectedValue) {
|
|
var element = document.getElementById(selectedValue);
|
|
if (element) {
|
|
// Scroll to the selected element
|
|
scrollToElement(element);
|
|
|
|
// Highlight the selected table briefly
|
|
var originalBackground = element.style.backgroundColor || '';
|
|
element.style.backgroundColor = '#ffffd0';
|
|
|
|
// Use setTimeout for the highlight effect
|
|
setTimeout(function() {
|
|
element.style.backgroundColor = originalBackground;
|
|
}, 1500);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cross-browser scroll function
|
|
function scrollToElement(element) {
|
|
// Check if scrollIntoView is supported
|
|
if (element.scrollIntoView) {
|
|
// Try smooth scrolling if supported
|
|
try {
|
|
element.scrollIntoView({ behavior: 'smooth' });
|
|
} catch (error) {
|
|
// Fallback for browsers that don't support smooth scrolling
|
|
element.scrollIntoView();
|
|
}
|
|
} else {
|
|
// Manual scroll fallback
|
|
var rect = element.getBoundingClientRect();
|
|
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
var targetY = rect.top + scrollTop - 70; // 70px offset for the sticky header
|
|
|
|
window.scrollTo(0, targetY);
|
|
}
|
|
}
|
|
|
|
// Cross-browser DOM ready function
|
|
function ready(fn) {
|
|
if (document.readyState !== 'loading') {
|
|
fn();
|
|
} else if (document.addEventListener) {
|
|
document.addEventListener('DOMContentLoaded', fn);
|
|
} else {
|
|
document.attachEvent('onreadystatechange', function() {
|
|
if (document.readyState !== 'loading') {
|
|
fn();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Initialize when DOM is ready
|
|
ready(initTableNavigation);
|
|
})();
|