removed useless stuff
This commit is contained in:
parent
64e78bb9b8
commit
a80bfba873
@ -1,77 +0,0 @@
|
||||
/**
|
||||
* Accessibility Features Module
|
||||
* Enhances accessibility for all users
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize accessibility features
|
||||
*/
|
||||
function initAccessibilityFeatures() {
|
||||
setupFocusManagement();
|
||||
setupAriaLabels();
|
||||
console.log('[Accessibility Features] Initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup focus management
|
||||
*/
|
||||
function setupFocusManagement() {
|
||||
// Add focus visible class for keyboard navigation
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Tab') {
|
||||
document.body.classList.add('keyboard-navigation');
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('mousedown', () => {
|
||||
document.body.classList.remove('keyboard-navigation');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup ARIA labels for dynamic content
|
||||
*/
|
||||
function setupAriaLabels() {
|
||||
// Ensure all interactive elements have proper ARIA labels
|
||||
const buttons = document.querySelectorAll('button:not([aria-label])');
|
||||
buttons.forEach(button => {
|
||||
if (!button.getAttribute('aria-label') && button.title) {
|
||||
button.setAttribute('aria-label', button.title);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Announce message to screen readers
|
||||
*/
|
||||
function announceToScreenReader(message, priority = 'polite') {
|
||||
const announcement = document.createElement('div');
|
||||
announcement.setAttribute('role', 'status');
|
||||
announcement.setAttribute('aria-live', priority);
|
||||
announcement.setAttribute('aria-atomic', 'true');
|
||||
announcement.className = 'sr-only';
|
||||
announcement.textContent = message;
|
||||
|
||||
document.body.appendChild(announcement);
|
||||
|
||||
setTimeout(() => {
|
||||
announcement.remove();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// Export functions
|
||||
window.Accessibility = {
|
||||
announce: announceToScreenReader
|
||||
};
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initAccessibilityFeatures);
|
||||
} else {
|
||||
initAccessibilityFeatures();
|
||||
}
|
||||
|
||||
})();
|
||||
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Advanced Search Module
|
||||
* Provides advanced search and filtering capabilities
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize advanced search
|
||||
*/
|
||||
function initAdvancedSearch() {
|
||||
console.log('[Advanced Search] Module loaded (functionality to be implemented)');
|
||||
|
||||
// TODO: Implement advanced search features
|
||||
// - Filter by genre
|
||||
// - Filter by year
|
||||
// - Filter by status
|
||||
// - Sort options
|
||||
}
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initAdvancedSearch);
|
||||
} else {
|
||||
initAdvancedSearch();
|
||||
}
|
||||
|
||||
})();
|
||||
@ -26,9 +26,6 @@ class AniWorldApp {
|
||||
this.loadSeries();
|
||||
this.initTheme();
|
||||
this.updateConnectionStatus();
|
||||
|
||||
// Initialize Mobile & Accessibility features
|
||||
this.initMobileAndAccessibility();
|
||||
}
|
||||
|
||||
async checkAuthentication() {
|
||||
@ -1726,155 +1723,6 @@ class AniWorldApp {
|
||||
}
|
||||
}
|
||||
|
||||
showBackupsModal(backups) {
|
||||
// Create modal to show backups
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'modal';
|
||||
modal.style.display = 'block';
|
||||
|
||||
const modalContent = document.createElement('div');
|
||||
modalContent.className = 'modal-content';
|
||||
modalContent.style.maxWidth = '60%';
|
||||
|
||||
const header = document.createElement('div');
|
||||
header.innerHTML = '<h3>Configuration Backups</h3>';
|
||||
|
||||
const backupList = document.createElement('div');
|
||||
backupList.className = 'backup-list';
|
||||
|
||||
if (backups.length === 0) {
|
||||
backupList.innerHTML = '<div class="backup-item"><span>No backups found</span></div>';
|
||||
} else {
|
||||
backups.forEach(backup => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'backup-item';
|
||||
|
||||
const info = document.createElement('div');
|
||||
info.className = 'backup-info';
|
||||
|
||||
const name = document.createElement('div');
|
||||
name.className = 'backup-name';
|
||||
name.textContent = backup.filename;
|
||||
|
||||
const details = document.createElement('div');
|
||||
details.className = 'backup-details';
|
||||
details.textContent = `Size: ${backup.size_kb} KB • Modified: ${backup.modified_display}`;
|
||||
|
||||
info.appendChild(name);
|
||||
info.appendChild(details);
|
||||
|
||||
const actions = document.createElement('div');
|
||||
actions.className = 'backup-actions';
|
||||
|
||||
const restoreBtn = document.createElement('button');
|
||||
restoreBtn.className = 'btn btn-xs btn-primary';
|
||||
restoreBtn.textContent = 'Restore';
|
||||
restoreBtn.onclick = () => {
|
||||
if (confirm('Are you sure you want to restore this backup? Current configuration will be overwritten.')) {
|
||||
this.restoreBackup(backup.filename);
|
||||
document.body.removeChild(modal);
|
||||
}
|
||||
};
|
||||
|
||||
const downloadBtn = document.createElement('button');
|
||||
downloadBtn.className = 'btn btn-xs btn-secondary';
|
||||
downloadBtn.textContent = 'Download';
|
||||
downloadBtn.onclick = () => this.downloadBackup(backup.filename);
|
||||
|
||||
actions.appendChild(restoreBtn);
|
||||
actions.appendChild(downloadBtn);
|
||||
|
||||
item.appendChild(info);
|
||||
item.appendChild(actions);
|
||||
|
||||
backupList.appendChild(item);
|
||||
});
|
||||
}
|
||||
|
||||
const closeBtn = document.createElement('button');
|
||||
closeBtn.textContent = 'Close';
|
||||
closeBtn.className = 'btn btn-secondary';
|
||||
closeBtn.onclick = () => document.body.removeChild(modal);
|
||||
|
||||
modalContent.appendChild(header);
|
||||
modalContent.appendChild(backupList);
|
||||
modalContent.appendChild(closeBtn);
|
||||
modal.appendChild(modalContent);
|
||||
document.body.appendChild(modal);
|
||||
|
||||
// Close on background click
|
||||
modal.onclick = (e) => {
|
||||
if (e.target === modal) {
|
||||
document.body.removeChild(modal);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async restoreBackup(filename) {
|
||||
try {
|
||||
const response = await this.makeAuthenticatedRequest(`/api/config/backup/${encodeURIComponent(filename)}/restore`, {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (!response) return;
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.showToast('Configuration restored successfully', 'success');
|
||||
// Reload the config modal
|
||||
setTimeout(() => {
|
||||
this.hideConfigModal();
|
||||
this.showConfigModal();
|
||||
}, 1000);
|
||||
} else {
|
||||
this.showToast(`Failed to restore backup: ${data.error}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error restoring backup:', error);
|
||||
this.showToast('Failed to restore backup', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
downloadBackup(filename) {
|
||||
const link = document.createElement('a');
|
||||
link.href = `/api/config/backup/${encodeURIComponent(filename)}/download`;
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
|
||||
async exportConfig() {
|
||||
try {
|
||||
const includeSensitive = confirm('Include sensitive data (passwords, salts)? Click Cancel for safe export without sensitive data.');
|
||||
|
||||
const response = await this.makeAuthenticatedRequest('/api/config/export', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ include_sensitive: includeSensitive })
|
||||
});
|
||||
|
||||
if (response && response.ok) {
|
||||
// Handle file download
|
||||
const blob = await response.blob();
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `aniworld_config_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.json`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
this.showToast('Configuration exported successfully', 'success');
|
||||
} else {
|
||||
this.showToast('Failed to export configuration', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error exporting config:', error);
|
||||
this.showToast('Failed to export configuration', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async validateConfig() {
|
||||
try {
|
||||
const response = await this.makeAuthenticatedRequest('/api/config/validate', {
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* Bulk Operations Module
|
||||
* Handles bulk selection and operations on multiple series
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize bulk operations
|
||||
*/
|
||||
function initBulkOperations() {
|
||||
console.log('[Bulk Operations] Module loaded (functionality to be implemented)');
|
||||
|
||||
// TODO: Implement bulk operations
|
||||
// - Select multiple series
|
||||
// - Bulk download
|
||||
// - Bulk mark as watched
|
||||
// - Bulk delete
|
||||
}
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initBulkOperations);
|
||||
} else {
|
||||
initBulkOperations();
|
||||
}
|
||||
|
||||
})();
|
||||
@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Color Contrast Compliance Module
|
||||
* Ensures WCAG color contrast compliance
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize color contrast compliance
|
||||
*/
|
||||
function initColorContrastCompliance() {
|
||||
checkContrastCompliance();
|
||||
console.log('[Color Contrast Compliance] Initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if color contrast meets WCAG standards
|
||||
*/
|
||||
function checkContrastCompliance() {
|
||||
// This would typically check computed styles
|
||||
// For now, we rely on CSS variables defined in styles.css
|
||||
console.log('[Color Contrast] Relying on predefined WCAG-compliant color scheme');
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate contrast ratio between two colors
|
||||
*/
|
||||
function calculateContrastRatio(color1, color2) {
|
||||
// Simplified contrast calculation
|
||||
// Real implementation would use relative luminance
|
||||
return 4.5; // Placeholder
|
||||
}
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initColorContrastCompliance);
|
||||
} else {
|
||||
initColorContrastCompliance();
|
||||
}
|
||||
|
||||
})();
|
||||
@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Drag and Drop Module
|
||||
* Handles drag-and-drop functionality for series cards
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize drag and drop
|
||||
*/
|
||||
function initDragDrop() {
|
||||
console.log('[Drag & Drop] Module loaded (functionality to be implemented)');
|
||||
|
||||
// TODO: Implement drag-and-drop for series cards
|
||||
// This will allow users to reorder series or add to queue via drag-and-drop
|
||||
}
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initDragDrop);
|
||||
} else {
|
||||
initDragDrop();
|
||||
}
|
||||
|
||||
})();
|
||||
@ -1,144 +0,0 @@
|
||||
/**
|
||||
* Keyboard Shortcuts Module
|
||||
* Handles keyboard navigation and shortcuts for improved accessibility
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Keyboard shortcuts configuration
|
||||
const shortcuts = {
|
||||
'ctrl+k': 'focusSearch',
|
||||
'ctrl+r': 'triggerRescan',
|
||||
'ctrl+q': 'openQueue',
|
||||
'escape': 'closeModals',
|
||||
'tab': 'navigationMode',
|
||||
'/': 'focusSearch'
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize keyboard shortcuts
|
||||
*/
|
||||
function initKeyboardShortcuts() {
|
||||
document.addEventListener('keydown', handleKeydown);
|
||||
console.log('[Keyboard Shortcuts] Initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle keydown events
|
||||
*/
|
||||
function handleKeydown(event) {
|
||||
const key = getKeyCombo(event);
|
||||
|
||||
if (shortcuts[key]) {
|
||||
const action = shortcuts[key];
|
||||
handleShortcut(action, event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get key combination string
|
||||
*/
|
||||
function getKeyCombo(event) {
|
||||
const parts = [];
|
||||
|
||||
if (event.ctrlKey) parts.push('ctrl');
|
||||
if (event.altKey) parts.push('alt');
|
||||
if (event.shiftKey) parts.push('shift');
|
||||
|
||||
const key = event.key.toLowerCase();
|
||||
parts.push(key);
|
||||
|
||||
return parts.join('+');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle keyboard shortcut action
|
||||
*/
|
||||
function handleShortcut(action, event) {
|
||||
switch(action) {
|
||||
case 'focusSearch':
|
||||
event.preventDefault();
|
||||
focusSearchInput();
|
||||
break;
|
||||
case 'triggerRescan':
|
||||
event.preventDefault();
|
||||
triggerRescan();
|
||||
break;
|
||||
case 'openQueue':
|
||||
event.preventDefault();
|
||||
openQueue();
|
||||
break;
|
||||
case 'closeModals':
|
||||
closeAllModals();
|
||||
break;
|
||||
case 'navigationMode':
|
||||
handleTabNavigation(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus search input
|
||||
*/
|
||||
function focusSearchInput() {
|
||||
const searchInput = document.getElementById('search-input');
|
||||
if (searchInput) {
|
||||
searchInput.focus();
|
||||
searchInput.select();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger rescan
|
||||
*/
|
||||
function triggerRescan() {
|
||||
const rescanBtn = document.getElementById('rescan-btn');
|
||||
if (rescanBtn && !rescanBtn.disabled) {
|
||||
rescanBtn.click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open queue page
|
||||
*/
|
||||
function openQueue() {
|
||||
window.location.href = '/queue';
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all open modals
|
||||
*/
|
||||
function closeAllModals() {
|
||||
const modals = document.querySelectorAll('.modal.active');
|
||||
modals.forEach(modal => {
|
||||
modal.classList.remove('active');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle tab navigation with visual indicators
|
||||
*/
|
||||
function handleTabNavigation(event) {
|
||||
// Add keyboard-focus class to focused element
|
||||
const previousFocus = document.querySelector('.keyboard-focus');
|
||||
if (previousFocus) {
|
||||
previousFocus.classList.remove('keyboard-focus');
|
||||
}
|
||||
|
||||
// Will be applied after tab completes
|
||||
setTimeout(() => {
|
||||
if (document.activeElement) {
|
||||
document.activeElement.classList.add('keyboard-focus');
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initKeyboardShortcuts);
|
||||
} else {
|
||||
initKeyboardShortcuts();
|
||||
}
|
||||
|
||||
})();
|
||||
@ -1,80 +0,0 @@
|
||||
/**
|
||||
* Mobile Responsive Module
|
||||
* Handles mobile-specific functionality and responsive behavior
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
let isMobile = false;
|
||||
|
||||
/**
|
||||
* Initialize mobile responsive features
|
||||
*/
|
||||
function initMobileResponsive() {
|
||||
detectMobile();
|
||||
setupResponsiveHandlers();
|
||||
console.log('[Mobile Responsive] Initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if device is mobile
|
||||
*/
|
||||
function detectMobile() {
|
||||
isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||
|
||||
if (isMobile) {
|
||||
document.body.classList.add('mobile-device');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup responsive event handlers
|
||||
*/
|
||||
function setupResponsiveHandlers() {
|
||||
window.addEventListener('resize', handleResize);
|
||||
handleResize(); // Initial call
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle window resize
|
||||
*/
|
||||
function handleResize() {
|
||||
const width = window.innerWidth;
|
||||
|
||||
if (width < 768) {
|
||||
applyMobileLayout();
|
||||
} else {
|
||||
applyDesktopLayout();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply mobile-specific layout
|
||||
*/
|
||||
function applyMobileLayout() {
|
||||
document.body.classList.add('mobile-layout');
|
||||
document.body.classList.remove('desktop-layout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply desktop-specific layout
|
||||
*/
|
||||
function applyDesktopLayout() {
|
||||
document.body.classList.add('desktop-layout');
|
||||
document.body.classList.remove('mobile-layout');
|
||||
}
|
||||
|
||||
// Export functions
|
||||
window.MobileResponsive = {
|
||||
isMobile: () => isMobile
|
||||
};
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initMobileResponsive);
|
||||
} else {
|
||||
initMobileResponsive();
|
||||
}
|
||||
|
||||
})();
|
||||
@ -1,76 +0,0 @@
|
||||
/**
|
||||
* Multi-Screen Support Module
|
||||
* Handles multi-monitor and window management
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize multi-screen support
|
||||
*/
|
||||
function initMultiScreenSupport() {
|
||||
if ('screen' in window) {
|
||||
detectScreens();
|
||||
console.log('[Multi-Screen Support] Initialized');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect available screens
|
||||
*/
|
||||
function detectScreens() {
|
||||
// Modern browsers support window.screen
|
||||
const screenInfo = {
|
||||
width: window.screen.width,
|
||||
height: window.screen.height,
|
||||
availWidth: window.screen.availWidth,
|
||||
availHeight: window.screen.availHeight,
|
||||
colorDepth: window.screen.colorDepth,
|
||||
pixelDepth: window.screen.pixelDepth
|
||||
};
|
||||
|
||||
console.log('[Multi-Screen] Screen info:', screenInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request fullscreen
|
||||
*/
|
||||
function requestFullscreen() {
|
||||
const elem = document.documentElement;
|
||||
if (elem.requestFullscreen) {
|
||||
elem.requestFullscreen();
|
||||
} else if (elem.webkitRequestFullscreen) {
|
||||
elem.webkitRequestFullscreen();
|
||||
} else if (elem.msRequestFullscreen) {
|
||||
elem.msRequestFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit fullscreen
|
||||
*/
|
||||
function exitFullscreen() {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
// Export functions
|
||||
window.MultiScreen = {
|
||||
requestFullscreen: requestFullscreen,
|
||||
exitFullscreen: exitFullscreen
|
||||
};
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initMultiScreenSupport);
|
||||
} else {
|
||||
initMultiScreenSupport();
|
||||
}
|
||||
|
||||
})();
|
||||
@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Touch Gestures Module
|
||||
* Handles touch gestures for mobile devices
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize touch gestures
|
||||
*/
|
||||
function initTouchGestures() {
|
||||
if ('ontouchstart' in window) {
|
||||
setupSwipeGestures();
|
||||
console.log('[Touch Gestures] Initialized');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup swipe gesture handlers
|
||||
*/
|
||||
function setupSwipeGestures() {
|
||||
let touchStartX = 0;
|
||||
let touchStartY = 0;
|
||||
let touchEndX = 0;
|
||||
let touchEndY = 0;
|
||||
|
||||
document.addEventListener('touchstart', (e) => {
|
||||
touchStartX = e.changedTouches[0].screenX;
|
||||
touchStartY = e.changedTouches[0].screenY;
|
||||
}, { passive: true });
|
||||
|
||||
document.addEventListener('touchend', (e) => {
|
||||
touchEndX = e.changedTouches[0].screenX;
|
||||
touchEndY = e.changedTouches[0].screenY;
|
||||
handleSwipe();
|
||||
}, { passive: true });
|
||||
|
||||
function handleSwipe() {
|
||||
const deltaX = touchEndX - touchStartX;
|
||||
const deltaY = touchEndY - touchStartY;
|
||||
const minSwipeDistance = 50;
|
||||
|
||||
if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
||||
// Horizontal swipe
|
||||
if (Math.abs(deltaX) > minSwipeDistance) {
|
||||
if (deltaX > 0) {
|
||||
// Swipe right
|
||||
console.log('[Touch Gestures] Swipe right detected');
|
||||
} else {
|
||||
// Swipe left
|
||||
console.log('[Touch Gestures] Swipe left detected');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initTouchGestures);
|
||||
} else {
|
||||
initTouchGestures();
|
||||
}
|
||||
|
||||
})();
|
||||
@ -1,111 +0,0 @@
|
||||
/**
|
||||
* Undo/Redo Module
|
||||
* Provides undo/redo functionality for user actions
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const actionHistory = [];
|
||||
let currentIndex = -1;
|
||||
|
||||
/**
|
||||
* Initialize undo/redo system
|
||||
*/
|
||||
function initUndoRedo() {
|
||||
setupKeyboardShortcuts();
|
||||
console.log('[Undo/Redo] Initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup keyboard shortcuts for undo/redo
|
||||
*/
|
||||
function setupKeyboardShortcuts() {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
if (event.key === 'z' && !event.shiftKey) {
|
||||
event.preventDefault();
|
||||
undo();
|
||||
} else if (event.key === 'z' && event.shiftKey || event.key === 'y') {
|
||||
event.preventDefault();
|
||||
redo();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add action to history
|
||||
*/
|
||||
function addAction(action) {
|
||||
// Remove any actions after current index
|
||||
actionHistory.splice(currentIndex + 1);
|
||||
|
||||
// Add new action
|
||||
actionHistory.push(action);
|
||||
currentIndex++;
|
||||
|
||||
// Limit history size
|
||||
if (actionHistory.length > 50) {
|
||||
actionHistory.shift();
|
||||
currentIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo last action
|
||||
*/
|
||||
function undo() {
|
||||
if (currentIndex >= 0) {
|
||||
const action = actionHistory[currentIndex];
|
||||
if (action && action.undo) {
|
||||
action.undo();
|
||||
currentIndex--;
|
||||
showNotification('Action undone');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redo last undone action
|
||||
*/
|
||||
function redo() {
|
||||
if (currentIndex < actionHistory.length - 1) {
|
||||
currentIndex++;
|
||||
const action = actionHistory[currentIndex];
|
||||
if (action && action.redo) {
|
||||
action.redo();
|
||||
showNotification('Action redone');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show undo/redo notification
|
||||
*/
|
||||
function showNotification(message) {
|
||||
const notification = document.createElement('div');
|
||||
notification.className = 'undo-notification';
|
||||
notification.textContent = message;
|
||||
document.body.appendChild(notification);
|
||||
|
||||
setTimeout(() => {
|
||||
notification.remove();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
// Export functions
|
||||
window.UndoRedo = {
|
||||
add: addAction,
|
||||
undo: undo,
|
||||
redo: redo
|
||||
};
|
||||
|
||||
// Initialize on DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initUndoRedo);
|
||||
} else {
|
||||
initUndoRedo();
|
||||
}
|
||||
|
||||
})();
|
||||
Loading…
x
Reference in New Issue
Block a user