diff --git a/static/css/attendance_fullscreen.css b/static/css/attendance_fullscreen.css index fa5eefe..f4f200f 100644 --- a/static/css/attendance_fullscreen.css +++ b/static/css/attendance_fullscreen.css @@ -4,7 +4,9 @@ * static/css/attendance_fullscreen.css */ -/* Fullscreen Toggle Button */ +/* =========================== + FULLSCREEN TOGGLE BUTTON + =========================== */ .fullscreen-toggle-btn { position: fixed; top: 20px; @@ -35,21 +37,29 @@ transform: scale(0.95); } -/* Fullscreen Mode Styles */ +/* =========================== + FULLSCREEN MODE BASE + =========================== */ .fullscreen-mode { - position: fixed; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - background: #f8fafc; - z-index: 9998; - overflow: auto; - padding: 20px; - box-sizing: border-box; + position: fixed !important; + top: 0 !important; + left: 0 !important; + width: 100vw !important; + height: 100vh !important; + max-width: 100vw !important; + margin: 0 !important; + background: #f8fafc !important; + z-index: 9998 !important; + overflow: auto !important; + padding: 20px !important; + box-sizing: border-box !important; } -/* Hide sidebar and other UI elements in fullscreen */ +/* =========================== + HIDE UI ELEMENTS IN FULLSCREEN + =========================== */ + +/* Hide sidebar and overlays */ .fullscreen-mode ~ #sidebar, .fullscreen-mode ~ .sidebar-overlay, body.fullscreen-active #sidebar, @@ -57,237 +67,533 @@ body.fullscreen-active .sidebar-overlay { display: none !important; } -/* Adjust main wrapper in fullscreen */ +/* Adjust main wrapper */ body.fullscreen-active .main-wrapper { margin-left: 0 !important; width: 100% !important; } -/* Compact header in fullscreen mode */ -.fullscreen-mode .attendance-header { - padding: 1rem 1.5rem; - margin-bottom: 1rem; - background: white; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); +/* Hide header completely */ +.fullscreen-mode .attendance-header, +.fullscreen-mode > .attendance-header { + display: none !important; + visibility: hidden !important; + height: 0 !important; + overflow: hidden !important; + margin: 0 !important; + padding: 0 !important; } -.fullscreen-mode .attendance-header h1 { - font-size: 1.5rem; - margin-bottom: 0.25rem; +/* Hide ALL stats sections with various possible class names */ +.fullscreen-mode .stats-section, +.fullscreen-mode > .stats-section, +.fullscreen-mode .stats-overview, +.fullscreen-mode > .stats-overview, +.fullscreen-mode .statistics-section, +.fullscreen-mode > .statistics-section, +.fullscreen-mode [class*="stat"][class*="section"], +.fullscreen-mode div[class*="stat-"] { + display: none !important; + visibility: hidden !important; + height: 0 !important; + overflow: hidden !important; + margin: 0 !important; + padding: 0 !important; } -.fullscreen-mode .attendance-header p { - font-size: 0.875rem; - margin: 0; +/* Exception: Keep stat cards inside table section visible */ +.fullscreen-mode .attendance-table-section .stat-card, +.fullscreen-mode .table-section .stat-card { + display: flex !important; + visibility: visible !important; + height: auto !important; } -/* Compact stats in fullscreen */ -.fullscreen-mode .stats-section { - margin-bottom: 1rem; -} - -.fullscreen-mode .stat-card { - padding: 1rem; -} - -.fullscreen-mode .stat-icon { - width: 50px; - height: 50px; - font-size: 1.25rem; -} - -.fullscreen-mode .stat-content h3 { - font-size: 1.5rem; -} - -.fullscreen-mode .stat-content p { - font-size: 0.875rem; -} - -.fullscreen-mode .stat-trend { - font-size: 0.75rem; -} - -/* Compact filters in fullscreen */ +/* =========================== + COMPACT FILTERS IN FULLSCREEN + =========================== */ .fullscreen-mode .filters-section { - margin-bottom: 1rem; + margin-bottom: 1rem !important; + margin-top: 0 !important; +} + +.fullscreen-mode .filters-card { + border-radius: 8px !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important; } .fullscreen-mode .filters-header { - padding: 1rem 1.5rem; + padding: 0.75rem 1.5rem !important; + background: #f8fafc !important; + border-bottom: 1px solid #e2e8f0 !important; } .fullscreen-mode .filters-header h3 { - font-size: 1.125rem; + font-size: 1rem !important; + font-weight: 600 !important; + margin: 0 !important; } .fullscreen-mode .filters-form { - padding: 1rem 1.5rem; + padding: 1rem 1.5rem !important; } .fullscreen-mode .filter-row { - gap: 0.75rem; + display: grid !important; + grid-template-columns: repeat(5, 1fr) !important; + gap: 0.75rem !important; + align-items: end !important; + margin-bottom: 0 !important; +} + +.fullscreen-mode .filter-group { + display: flex !important; + flex-direction: column !important; + gap: 0.25rem !important; + min-width: 0 !important; } .fullscreen-mode .filter-group label { - font-size: 0.8125rem; - margin-bottom: 0.25rem; + font-size: 0.75rem !important; + margin-bottom: 0.25rem !important; + font-weight: 600 !important; + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + color: #374151 !important; } .fullscreen-mode .filter-group input, .fullscreen-mode .filter-group select { - padding: 0.5rem 0.75rem; - font-size: 0.875rem; + padding: 0.5rem 0.75rem !important; + font-size: 0.875rem !important; + height: 38px !important; + border: 2px solid #e2e8f0 !important; + border-radius: 6px !important; + width: 100% !important; + box-sizing: border-box !important; + background: white !important; } -/* Optimized table for fullscreen */ +.fullscreen-mode .filter-group input:focus, +.fullscreen-mode .filter-group select:focus { + border-color: #2563eb !important; + outline: none !important; + box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1) !important; +} + +.fullscreen-mode .filter-actions { + grid-column: 1 / -1 !important; + display: flex !important; + gap: 0.75rem !important; + justify-content: flex-start !important; + margin-top: 0.5rem !important; +} + +.fullscreen-mode .filter-actions .btn { + padding: 0.5rem 1rem !important; + font-size: 0.875rem !important; + height: 38px !important; + display: inline-flex !important; + align-items: center !important; + gap: 0.5rem !important; +} + +/* =========================== + TABLE SECTION IN FULLSCREEN + =========================== */ .fullscreen-mode .attendance-table-section { - margin-bottom: 1rem; + margin-bottom: 0 !important; + margin-top: 0 !important; + background: white !important; + border-radius: 8px !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important; + overflow: hidden !important; } .fullscreen-mode .table-header { - padding: 1rem 1.5rem; + padding: 0.75rem 1.5rem !important; + background: #f8fafc !important; + border-bottom: 1px solid #e2e8f0 !important; + display: flex !important; + justify-content: space-between !important; + align-items: center !important; } .fullscreen-mode .table-header h3 { - font-size: 1.125rem; + font-size: 1rem !important; + font-weight: 600 !important; + margin: 0 !important; +} + +.fullscreen-mode .table-controls { + display: flex !important; + align-items: center !important; + gap: 0.5rem !important; +} + +.fullscreen-mode .table-container { + max-height: calc(100vh - 280px) !important; + overflow-y: auto !important; + overflow-x: auto !important; } .fullscreen-mode .attendance-table { - font-size: 0.875rem; + font-size: 0.8125rem !important; + width: 100% !important; } .fullscreen-mode .attendance-table th, .fullscreen-mode .attendance-table td { - padding: 0.75rem 0.5rem; + padding: 0.625rem 0.5rem !important; + white-space: nowrap !important; } -.fullscreen-mode .employee-id { - font-size: 0.875rem; +.fullscreen-mode .attendance-table th { + position: sticky !important; + top: 0 !important; + background: #f8fafc !important; + z-index: 10 !important; + font-size: 0.75rem !important; + font-weight: 600 !important; + text-transform: uppercase !important; + letter-spacing: 0.025em !important; } +/* =========================== + TABLE COLUMN OPTIMIZATION + =========================== */ + +/* Prevent text overlap - allow wrapping for long content */ +.fullscreen-mode .attendance-table td { + white-space: normal !important; + word-wrap: break-word !important; + word-break: break-word !important; + max-width: 200px !important; + overflow: hidden !important; +} + +/* Keep headers on single line */ +.fullscreen-mode .attendance-table th { + white-space: nowrap !important; +} + +/* Specific column width optimizations */ +.fullscreen-mode .attendance-table th:nth-child(1), +.fullscreen-mode .attendance-table td:nth-child(1) { + /* # column */ + width: 40px !important; + min-width: 40px !important; + max-width: 40px !important; + white-space: nowrap !important; +} + +.fullscreen-mode .attendance-table th:nth-child(2), +.fullscreen-mode .attendance-table td:nth-child(2) { + /* Employee ID */ + width: 80px !important; + min-width: 80px !important; + max-width: 80px !important; + white-space: nowrap !important; +} + +.fullscreen-mode .attendance-table th:nth-child(3), +.fullscreen-mode .attendance-table td:nth-child(3) { + /* Employee Name */ + width: 120px !important; + min-width: 120px !important; + max-width: 120px !important; +} + +.fullscreen-mode .attendance-table th:nth-child(4), +.fullscreen-mode .attendance-table td:nth-child(4) { + /* Location */ + width: 150px !important; + min-width: 150px !important; + max-width: 150px !important; +} + +.fullscreen-mode .attendance-table th:nth-child(5), +.fullscreen-mode .attendance-table td:nth-child(5) { + /* Event */ + width: 80px !important; + min-width: 80px !important; + max-width: 80px !important; + white-space: nowrap !important; +} + +.fullscreen-mode .attendance-table th:nth-child(6), +.fullscreen-mode .attendance-table td:nth-child(6) { + /* Date */ + width: 100px !important; + min-width: 100px !important; + max-width: 100px !important; + white-space: nowrap !important; +} + +.fullscreen-mode .attendance-table th:nth-child(7), +.fullscreen-mode .attendance-table td:nth-child(7) { + /* Time */ + width: 80px !important; + min-width: 80px !important; + max-width: 80px !important; + white-space: nowrap !important; +} + +.fullscreen-mode .attendance-table th:nth-child(8), +.fullscreen-mode .attendance-table td:nth-child(8) { + /* QR Address */ + width: 180px !important; + min-width: 180px !important; + max-width: 180px !important; +} + +.fullscreen-mode .attendance-table th:nth-child(9), +.fullscreen-mode .attendance-table td:nth-child(9) { + /* Check-in Address */ + width: 180px !important; + min-width: 180px !important; + max-width: 180px !important; +} + +.fullscreen-mode .attendance-table th:nth-child(10), +.fullscreen-mode .attendance-table td:nth-child(10) { + /* Location Accuracy */ + width: 100px !important; + min-width: 100px !important; + max-width: 100px !important; + white-space: nowrap !important; + text-align: center !important; +} + +.fullscreen-mode .attendance-table th:nth-child(11), +.fullscreen-mode .attendance-table td:nth-child(11) { + /* Device */ + width: 100px !important; + min-width: 100px !important; + max-width: 100px !important; +} + +.fullscreen-mode .attendance-table th:nth-child(12), +.fullscreen-mode .attendance-table td:nth-child(12) { + /* Actions */ + width: 80px !important; + min-width: 80px !important; + max-width: 80px !important; + white-space: nowrap !important; + text-align: center !important; +} + +/* Address columns - allow text to wrap within container */ +.fullscreen-mode .address-column, +.fullscreen-mode .attendance-table td:nth-child(8), +.fullscreen-mode .attendance-table td:nth-child(9) { + font-size: 0.75rem !important; + line-height: 1.3 !important; + padding: 0.5rem 0.375rem !important; +} + +/* Location accuracy badge styling */ +.fullscreen-mode .location-accuracy-badge, +.fullscreen-mode .accuracy-badge { + display: inline-block !important; + padding: 0.25rem 0.5rem !important; + border-radius: 4px !important; + font-size: 0.7rem !important; + white-space: nowrap !important; +} + +/* Device info */ +.fullscreen-mode .device-info { + font-size: 0.75rem !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + display: block !important; +} + +/* Employee info styling */ +.fullscreen-mode .employee-id, +.fullscreen-mode .employee-name { + font-size: 0.8125rem !important; + font-weight: 500 !important; +} + +/* Location and event info */ +.fullscreen-mode .location-info, +.fullscreen-mode .event-info { + font-size: 0.75rem !important; + display: flex !important; + align-items: center !important; + gap: 0.25rem !important; +} + +.fullscreen-mode .location-info i, +.fullscreen-mode .event-info i { + flex-shrink: 0 !important; + font-size: 0.7rem !important; +} + +/* Address info containers */ +.fullscreen-mode .address-info { + display: flex !important; + align-items: flex-start !important; + gap: 0.25rem !important; + word-break: break-word !important; +} + +.fullscreen-mode .address-info i { + flex-shrink: 0 !important; + margin-top: 0.125rem !important; + font-size: 0.7rem !important; +} + +/* Time display */ .fullscreen-mode .time-info { - font-size: 0.8125rem; - padding: 0.25rem 0.5rem; + font-size: 0.75rem !important; + padding: 0.25rem 0.5rem !important; + background: #f1f5f9 !important; + border-radius: 4px !important; + display: inline-block !important; +} + +/* Action buttons */ +.fullscreen-mode .record-actions { + display: flex !important; + gap: 0.25rem !important; + justify-content: center !important; + align-items: center !important; } .fullscreen-mode .action-btn { - width: 30px; - height: 30px; - font-size: 0.75rem; + width: 28px !important; + height: 28px !important; + font-size: 0.7rem !important; + padding: 0 !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; } -/* iPad Landscape Optimization */ +/* Table layout */ +.fullscreen-mode .attendance-table { + table-layout: fixed !important; + width: 100% !important; +} + +/* Ensure table container allows horizontal scroll if needed */ +.fullscreen-mode .table-container { + overflow-x: auto !important; + -webkit-overflow-scrolling: touch !important; +} + +/* =========================== + RESPONSIVE BREAKPOINTS + =========================== */ + +/* iPad Landscape */ @media (min-width: 768px) and (max-width: 1024px) and (orientation: landscape) { .fullscreen-mode { - padding: 15px; - } - - .fullscreen-mode .stats-grid { - grid-template-columns: repeat(4, 1fr); - gap: 1rem; + padding: 12px !important; } .fullscreen-mode .filter-row { - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(3, 1fr) !important; + gap: 0.5rem !important; } .fullscreen-mode .filter-actions { - grid-column: 1 / -1; + grid-column: 1 / -1 !important; } .fullscreen-mode .attendance-table { - font-size: 0.8125rem; - } -} - -/* iPad Portrait Optimization */ -@media (min-width: 768px) and (max-width: 1024px) and (orientation: portrait) { - .fullscreen-mode { - padding: 15px; + font-size: 0.7rem !important; } - .fullscreen-mode .stats-grid { - grid-template-columns: repeat(2, 1fr); - gap: 1rem; + .fullscreen-mode .attendance-table th, + .fullscreen-mode .attendance-table td { + padding: 0.5rem 0.375rem !important; } - .fullscreen-mode .filter-row { - grid-template-columns: repeat(2, 1fr); - } - - .fullscreen-mode .attendance-table { - font-size: 0.8125rem; - } - - /* Hide less important columns on iPad portrait */ + /* Adjust column widths for iPad landscape */ .fullscreen-mode .attendance-table th:nth-child(8), .fullscreen-mode .attendance-table td:nth-child(8), .fullscreen-mode .attendance-table th:nth-child(9), .fullscreen-mode .attendance-table td:nth-child(9) { - display: none; + width: 150px !important; + min-width: 150px !important; + max-width: 150px !important; } } -/* Small tablets and large phones */ -@media (max-width: 767px) { - .fullscreen-toggle-btn { - width: 45px; - height: 45px; - top: 15px; - right: 15px; - font-size: 1.125rem; - } - +/* iPad Portrait */ +@media (min-width: 768px) and (max-width: 1024px) and (orientation: portrait) { .fullscreen-mode { - padding: 10px; - } - - .fullscreen-mode .attendance-header { - padding: 1rem; - } - - .fullscreen-mode .stats-grid { - grid-template-columns: 1fr; - gap: 0.75rem; + padding: 12px !important; } .fullscreen-mode .filter-row { - grid-template-columns: 1fr; - gap: 0.5rem; + grid-template-columns: repeat(2, 1fr) !important; + gap: 0.5rem !important; } .fullscreen-mode .filter-actions { - grid-column: 1; - flex-direction: column; + grid-column: 1 / -1 !important; } - .fullscreen-mode .filter-actions .btn { - width: 100%; + .fullscreen-mode .attendance-table { + font-size: 0.7rem !important; + } + + /* Hide less important columns on iPad portrait */ + .fullscreen-mode .attendance-table th:nth-child(11), + .fullscreen-mode .attendance-table td:nth-child(11) { + display: none !important; + } + + /* Adjust remaining column widths */ + .fullscreen-mode .attendance-table th:nth-child(8), + .fullscreen-mode .attendance-table td:nth-child(8), + .fullscreen-mode .attendance-table th:nth-child(9), + .fullscreen-mode .attendance-table td:nth-child(9) { + width: 140px !important; + min-width: 140px !important; + max-width: 140px !important; + } +} + +/* Mobile */ +@media (max-width: 767px) { + .fullscreen-toggle-btn { + width: 45px !important; + height: 45px !important; + top: 15px !important; + right: 15px !important; + } + + .fullscreen-mode { + padding: 10px !important; + } + + .fullscreen-mode .filter-row { + grid-template-columns: 1fr !important; } /* Show only essential columns on mobile */ - .fullscreen-mode .attendance-table th:nth-child(4), - .fullscreen-mode .attendance-table td:nth-child(4), - .fullscreen-mode .attendance-table th:nth-child(5), - .fullscreen-mode .attendance-table td:nth-child(5), .fullscreen-mode .attendance-table th:nth-child(8), .fullscreen-mode .attendance-table td:nth-child(8), .fullscreen-mode .attendance-table th:nth-child(9), .fullscreen-mode .attendance-table td:nth-child(9), + .fullscreen-mode .attendance-table th:nth-child(10), + .fullscreen-mode .attendance-table td:nth-child(10), .fullscreen-mode .attendance-table th:nth-child(11), .fullscreen-mode .attendance-table td:nth-child(11) { - display: none; + display: none !important; } } -/* Smooth transitions */ -.fullscreen-transition { - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -/* Scrollbar styling for fullscreen mode */ +/* =========================== + SCROLLBAR STYLING + =========================== */ .fullscreen-mode::-webkit-scrollbar { width: 10px; } @@ -306,87 +612,31 @@ body.fullscreen-active .main-wrapper { background: #94a3b8; } -/* Focus states for accessibility */ -.fullscreen-toggle-btn:focus { - outline: 3px solid rgba(37, 99, 235, 0.5); - outline-offset: 2px; -} - -/* Animation for entering/exiting fullscreen */ -@keyframes fadeInFullscreen { - from { - opacity: 0; - transform: scale(0.98); - } - to { - opacity: 1; - transform: scale(1); - } -} - +/* =========================== + OVERSCROLL PREVENTION + =========================== */ .fullscreen-mode { - animation: fadeInFullscreen 0.3s ease-out; + overscroll-behavior: none !important; + -webkit-overflow-scrolling: touch !important; } -/* Print styles - hide fullscreen button when printing */ +body.fullscreen-active { + overscroll-behavior: none !important; + overflow: hidden !important; +} + +/* =========================== + PRINT STYLES + =========================== */ @media print { .fullscreen-toggle-btn { display: none !important; } .fullscreen-mode { - position: static; - width: 100%; - height: auto; - padding: 0; + position: static !important; + width: 100% !important; + height: auto !important; + padding: 0 !important; } -} - -/* High contrast mode support */ -@media (prefers-contrast: high) { - .fullscreen-toggle-btn { - border: 2px solid white; - } - - .fullscreen-mode { - border: 2px solid #000; - } -} - -/* Reduced motion support */ -@media (prefers-reduced-motion: reduce) { - .fullscreen-toggle-btn, - .fullscreen-mode, - .fullscreen-transition { - animation: none !important; - transition: none !important; - } -} - -/* Prevent pull-to-refresh and overscroll on touch devices in fullscreen */ -.fullscreen-mode { - overscroll-behavior: none; - -webkit-overflow-scrolling: touch; -} - -body.fullscreen-active { - overscroll-behavior: none; - position: fixed; - width: 100%; - height: 100%; - overflow: hidden; -} - -/* Ensure content is scrollable within fullscreen container */ -.fullscreen-mode { - overflow-y: auto; - overflow-x: hidden; - -webkit-overflow-scrolling: touch; -} - -/* Prevent iOS Safari bounce effect */ -.fullscreen-mode, -.fullscreen-mode * { - -webkit-transform: translateZ(0); - transform: translateZ(0); } \ No newline at end of file diff --git a/static/js/attendance_fullscreen.js b/static/js/attendance_fullscreen.js index c7e2b3a..28edcd6 100644 --- a/static/js/attendance_fullscreen.js +++ b/static/js/attendance_fullscreen.js @@ -7,6 +7,10 @@ // Fullscreen state management let isFullscreen = false; +// Touch event handlers +let touchStartY = 0; +let touchStartX = 0; + /** * Toggle fullscreen mode for attendance report */ @@ -32,6 +36,75 @@ function toggleFullscreen() { logFullscreenAction(isFullscreen ? 'enter' : 'exit'); } +/** + * Prevent swipe gestures from interfering with fullscreen on touch devices + */ +function preventSwipeGestures(container, enable) { + if (enable) { + // Prevent pull-to-refresh and other touch gestures + container.addEventListener('touchstart', handleTouchStart, { passive: false }); + container.addEventListener('touchmove', handleTouchMove, { passive: false }); + container.addEventListener('touchend', handleTouchEnd, { passive: false }); + + // Prevent overscroll + document.body.style.overscrollBehavior = 'none'; + container.style.overscrollBehavior = 'none'; + + console.log('Swipe gestures prevented for fullscreen mode'); + } else { + // Re-enable normal touch behavior + container.removeEventListener('touchstart', handleTouchStart); + container.removeEventListener('touchmove', handleTouchMove); + container.removeEventListener('touchend', handleTouchEnd); + + // Restore overscroll + document.body.style.overscrollBehavior = ''; + container.style.overscrollBehavior = ''; + + console.log('Swipe gestures re-enabled'); + } +} + +function handleTouchStart(e) { + touchStartY = e.touches[0].clientY; + touchStartX = e.touches[0].clientX; +} + +function handleTouchMove(e) { + if (!isFullscreen) return; + + const touchY = e.touches[0].clientY; + const touchX = e.touches[0].clientX; + const deltaY = touchY - touchStartY; + const deltaX = touchX - touchStartX; + + const container = document.getElementById('attendanceReportContainer'); + const scrollTop = container.scrollTop; + const scrollHeight = container.scrollHeight; + const clientHeight = container.clientHeight; + const isAtTop = scrollTop === 0; + const isAtBottom = scrollTop + clientHeight >= scrollHeight - 1; + + // Prevent pull-down-to-refresh when at top + if (isAtTop && deltaY > 0) { + e.preventDefault(); + return false; + } + + // Prevent overscroll at bottom + if (isAtBottom && deltaY < 0) { + e.preventDefault(); + return false; + } + + // Allow normal scrolling within the container +} + +function handleTouchEnd(e) { + touchStartY = 0; + touchStartX = 0; +} + /** * Enter fullscreen mode */ @@ -129,80 +202,6 @@ function exitFullscreen(container, icon, body) { } } - /** - * Prevent swipe gestures from interfering with fullscreen on touch devices - */ -function preventSwipeGestures(container, enable) { - if (enable) { - // Prevent pull-to-refresh and other touch gestures - container.addEventListener('touchstart', handleTouchStart, { passive: false }); - container.addEventListener('touchmove', handleTouchMove, { passive: false }); - container.addEventListener('touchend', handleTouchEnd, { passive: false }); - - // Prevent overscroll - document.body.style.overscrollBehavior = 'none'; - container.style.overscrollBehavior = 'none'; - - console.log('Swipe gestures prevented for fullscreen mode'); - } else { - // Re-enable normal touch behavior - container.removeEventListener('touchstart', handleTouchStart); - container.removeEventListener('touchmove', handleTouchMove); - container.removeEventListener('touchend', handleTouchEnd); - - // Restore overscroll - document.body.style.overscrollBehavior = ''; - container.style.overscrollBehavior = ''; - - console.log('Swipe gestures re-enabled'); - } -} - -// Touch event handlers -let touchStartY = 0; -let touchStartX = 0; - -function handleTouchStart(e) { - touchStartY = e.touches[0].clientY; - touchStartX = e.touches[0].clientX; -} - -function handleTouchMove(e) { - if (!isFullscreen) return; - - const touchY = e.touches[0].clientY; - const touchX = e.touches[0].clientX; - const deltaY = touchY - touchStartY; - const deltaX = touchX - touchStartX; - - const container = document.getElementById('attendanceReportContainer'); - const scrollTop = container.scrollTop; - const scrollHeight = container.scrollHeight; - const clientHeight = container.clientHeight; - const isAtTop = scrollTop === 0; - const isAtBottom = scrollTop + clientHeight >= scrollHeight - 1; - - // Prevent pull-down-to-refresh when at top - if (isAtTop && deltaY > 0) { - e.preventDefault(); - return false; - } - - // Prevent overscroll at bottom - if (isAtBottom && deltaY < 0) { - e.preventDefault(); - return false; - } - - // Allow normal scrolling within the container - // Don't prevent default for vertical scrolling when not at boundaries -} - -function handleTouchEnd(e) { - touchStartY = 0; - touchStartX = 0; -} - // Restore table layout adjustTableForFullscreen(false); @@ -237,11 +236,19 @@ function adjustTableForFullscreen(isFullscreen) { } /** - * Save fullscreen preference to localStorage + * Save fullscreen preference to localStorage and URL */ function saveFullscreenPreference(isFullscreen) { try { localStorage.setItem('attendance_fullscreen_preference', isFullscreen ? 'true' : 'false'); + + // Also update the hidden form field if it exists + const fullscreenInput = document.getElementById('fullscreenState'); + if (fullscreenInput) { + fullscreenInput.value = isFullscreen ? '1' : ''; + } + + console.log('Fullscreen preference saved:', isFullscreen); } catch (e) { console.warn('Could not save fullscreen preference:', e); } @@ -338,7 +345,7 @@ function handleKeyboardShortcuts(event) { */ function detectAndOptimizeForIPad() { const isIPad = /iPad/.test(navigator.userAgent) || - (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1); + (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 0); if (isIPad) { console.log('iPad detected - optimizing UI'); @@ -352,6 +359,48 @@ function detectAndOptimizeForIPad() { } } +/** + * Restore fullscreen state from URL (CSS-only, no native fullscreen) + */ +function restoreFullscreenFromURL() { + const urlParams = new URLSearchParams(window.location.search); + const fullscreenParam = urlParams.get('fullscreen'); + + if (fullscreenParam === '1' && !isFullscreen) { + console.log('Restoring fullscreen mode from URL parameter (CSS-only)'); + + // Use CSS-only fullscreen (no native fullscreen API call) + const container = document.getElementById('attendanceReportContainer'); + const icon = document.getElementById('fullscreenIcon'); + const body = document.body; + + if (container && icon) { + // Manually set fullscreen state without calling native API + isFullscreen = true; + container.classList.add('fullscreen-mode'); + body.classList.add('fullscreen-active'); + + // Update icon + icon.classList.remove('fa-expand'); + icon.classList.add('fa-compress'); + + // Update button + const button = document.getElementById('fullscreenToggle'); + if (button) { + button.setAttribute('title', 'Exit Fullscreen'); + } + + // Apply touch gesture prevention + preventSwipeGestures(container, true); + + // Save preference + saveFullscreenPreference(true); + + console.log('Fullscreen restored successfully (CSS-only mode)'); + } + } +} + /** * Initialize fullscreen functionality */ @@ -361,7 +410,7 @@ function initializeFullscreen() { // Detect iPad detectAndOptimizeForIPad(); - // Add event listeners for native fullscreen changes + // Add event listeners for native fullscreen changes (desktop only) document.addEventListener('fullscreenchange', handleFullscreenChange); document.addEventListener('webkitfullscreenchange', handleFullscreenChange); document.addEventListener('mozfullscreenchange', handleFullscreenChange); @@ -370,12 +419,16 @@ function initializeFullscreen() { // Add keyboard shortcuts document.addEventListener('keydown', handleKeyboardShortcuts); - // Load saved preference - const savedPreference = loadFullscreenPreference(); - if (savedPreference) { - console.log('Restoring fullscreen preference'); - // Optional: Auto-enter fullscreen if user had it enabled last time - // toggleFullscreen(); + // Intercept filter form submission to preserve fullscreen state + const filterForm = document.getElementById('filterForm'); + if (filterForm) { + filterForm.addEventListener('submit', function(e) { + const fullscreenInput = document.getElementById('fullscreenState'); + if (fullscreenInput) { + fullscreenInput.value = isFullscreen ? '1' : ''; + console.log('Filter form submitted with fullscreen state:', isFullscreen); + } + }); } // Handle orientation changes @@ -397,6 +450,12 @@ function initializeFullscreen() { }, 250); }); + // Restore fullscreen state from URL if present + // Use setTimeout to ensure DOM is fully loaded + setTimeout(function() { + restoreFullscreenFromURL(); + }, 100); + console.log('Fullscreen functionality initialized'); } diff --git a/templates/attendance_report.html b/templates/attendance_report.html index a8ae4f8..5a6c627 100644 --- a/templates/attendance_report.html +++ b/templates/attendance_report.html @@ -59,6 +59,8 @@
+ +
@@ -410,11 +412,33 @@ const hasEditPermission = ['admin'].includes(userRole); const hasLocationAccuracy = {{ 'true' if has_location_accuracy_feature else 'false' }}; function clearFilters() { - window.location.href = "{{ url_for('attendance_report') }}"; + // Get current fullscreen state + const fullscreenState = window.isAttendanceFullscreen && window.isAttendanceFullscreen() ? '1' : ''; + + // Redirect to clean URL with only fullscreen parameter if active + if (fullscreenState === '1') { + window.location.href = '{{ url_for('attendance_report') }}?fullscreen=1'; + } else { + window.location.href = '{{ url_for('attendance_report') }}'; + } } function refreshReport() { - window.location.reload(); + // Get current fullscreen state + const fullscreenState = window.isAttendanceFullscreen && window.isAttendanceFullscreen() ? '1' : ''; + + // Build URL with current filters and fullscreen state + const params = new URLSearchParams(window.location.search); + + // Add or update fullscreen parameter + if (fullscreenState === '1') { + params.set('fullscreen', '1'); + } else { + params.delete('fullscreen'); + } + + // Reload with preserved state + window.location.href = window.location.pathname + '?' + params.toString(); } function showLocationMap(recordId) { @@ -651,6 +675,15 @@ document.addEventListener('DOMContentLoaded', function() { initializeFullscreen(); console.log('Fullscreen functionality initialized for attendance report'); } + + // Check if we should restore fullscreen from URL parameter + const urlParams = new URLSearchParams(window.location.search); + const shouldBeFullscreen = urlParams.get('fullscreen') === '1'; + + if (shouldBeFullscreen) { + console.log('URL indicates fullscreen should be active'); + // The initializeFullscreen function will handle restoration + } }); {% endblock %} \ No newline at end of file