quick_search/assets/app.js

233 lines
7.5 KiB
JavaScript
Raw Normal View History

// QuickSearch Application JavaScript
// Enhanced UI interactions
document.addEventListener('DOMContentLoaded', function() {
console.log('QuickSearch UI loaded');
// Add loading states to buttons
function addLoadingState(button, originalText) {
button.disabled = true;
button.innerHTML = '<span class="loading"></span>' + originalText;
}
function removeLoadingState(button, originalText) {
button.disabled = false;
button.innerHTML = originalText;
}
// Enhanced form interactions
const forms = document.querySelectorAll('form');
forms.forEach(form => {
form.addEventListener('submit', function(e) {
const submitButton = form.querySelector('button[type="submit"]');
if (submitButton) {
addLoadingState(submitButton, submitButton.textContent);
}
});
});
// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
// Ctrl+F to focus search
if (e.ctrlKey && e.key === 'f') {
e.preventDefault();
const searchInput = document.querySelector('input[type="text"]');
if (searchInput) {
searchInput.focus();
searchInput.select();
}
}
// Escape to clear search
if (e.key === 'Escape') {
const searchInput = document.querySelector('input[type="text"]');
if (searchInput && searchInput === document.activeElement) {
searchInput.value = '';
searchInput.blur();
}
}
});
// Enhanced table interactions
function enhanceTable(table) {
// Add click-to-copy functionality for table cells
const cells = table.querySelectorAll('td');
cells.forEach(cell => {
cell.addEventListener('click', function() {
const text = cell.textContent.trim();
if (text && navigator.clipboard) {
navigator.clipboard.writeText(text).then(() => {
// Visual feedback
cell.style.backgroundColor = '#4CAF50';
cell.style.color = 'white';
setTimeout(() => {
cell.style.backgroundColor = '';
cell.style.color = '';
}, 200);
});
}
});
});
// Add sortable columns (basic implementation)
const headers = table.querySelectorAll('th');
headers.forEach((header, index) => {
header.style.cursor = 'pointer';
header.addEventListener('click', () => sortTable(table, index));
});
}
// Simple table sorting
function sortTable(table, columnIndex) {
const tbody = table.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
rows.sort((a, b) => {
const aVal = a.cells[columnIndex]?.textContent.trim() || '';
const bVal = b.cells[columnIndex]?.textContent.trim() || '';
// Try numeric sort first
const aNum = parseFloat(aVal);
const bNum = parseFloat(bVal);
if (!isNaN(aNum) && !isNaN(bNum)) {
return aNum - bNum;
}
// Fall back to string sort
return aVal.localeCompare(bVal);
});
// Clear tbody and re-append sorted rows
tbody.innerHTML = '';
rows.forEach(row => tbody.appendChild(row));
}
// Auto-enhance any tables that appear
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
mutation.addedNodes.forEach(function(node) {
if (node.nodeType === 1) { // Element node
const tables = node.querySelectorAll ? node.querySelectorAll('table') : [];
tables.forEach(enhanceTable);
if (node.tagName === 'TABLE') {
enhanceTable(node);
}
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
// Enhance existing tables
document.querySelectorAll('table').forEach(enhanceTable);
});
// Utility functions for Rust integration
window.QuickSearch = {
// Function to show toast notifications
showToast: function(message, type = 'info') {
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.textContent = message;
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 12px 20px;
border-radius: 6px;
color: white;
font-weight: 600;
z-index: 2000;
animation: slideIn 0.3s ease;
`;
// Set background based on type
const colors = {
info: '#2196F3',
success: '#4CAF50',
warning: '#FF9800',
error: '#f44336'
};
toast.style.backgroundColor = colors[type] || colors.info;
document.body.appendChild(toast);
setTimeout(() => {
toast.style.animation = 'slideOut 0.3s ease';
setTimeout(() => {
document.body.removeChild(toast);
}, 300);
}, 3000);
},
// Function to update status display
updateStatus: function(status) {
const statusDisplay = document.querySelector('.status-display');
if (statusDisplay) {
statusDisplay.textContent = status;
}
},
// Function to highlight search terms in results
highlightSearchTerms: function(searchTerm, container) {
if (!searchTerm || !container) return;
const walker = document.createTreeWalker(
container,
NodeFilter.SHOW_TEXT,
null,
false
);
const textNodes = [];
let node;
while (node = walker.nextNode()) {
textNodes.push(node);
}
textNodes.forEach(textNode => {
const parent = textNode.parentNode;
if (parent.tagName === 'B') return; // Skip already highlighted
const text = textNode.textContent;
const regex = new RegExp(`(${searchTerm})`, 'gi');
if (regex.test(text)) {
const highlightedHTML = text.replace(regex, '<mark>$1</mark>');
const wrapper = document.createElement('span');
wrapper.innerHTML = highlightedHTML;
parent.replaceChild(wrapper, textNode);
}
});
}
};
// Add custom CSS for toasts and animations
const style = document.createElement('style');
style.textContent = `
@keyframes slideIn {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slideOut {
from { transform: translateX(0); opacity: 1; }
to { transform: translateX(100%); opacity: 0; }
}
mark {
background: #ffeb3b;
padding: 2px 4px;
border-radius: 3px;
font-weight: bold;
}
.toast {
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
`;
document.head.appendChild(style);