您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A script to order the lectures table according to weekdays on the Islamic University website
当前为
// ==UserScript== // @name IU Table Organizer // @description A script to order the lectures table according to weekdays on the Islamic University website // @name:en IU Table Organizer // @description:en A script to order the lectures table according to weekdays on the Islamic University website // @name:ar منظم جدول الجامعة الاسلامية // @description:ar اضافة لتعديل مظهر الجدول بالجامعة الاسلامية الى جدول مرتب تبعا لايام الاسبوع بضغطة زر // @include https://eduportal.iu.edu.sa/iu/ui/student/homeIndex.faces // @include https://eduportal.iu.edu.sa/iu/ui/student/*/*/* // @include http://eduportal.iu.edu.sa/iu/ui/student/* // @include https://eduportal.iu.edu.sa/iu/ui/student/student_schedule/index/studentScheduleIndex.faces // @version 4.1 // @icon https://www.google.com/s2/favicons?domain=sso.iu.edu.sa // @namespace https://greasyfork.runtimutd.eu.org/users/814159 // @icon https://icons.iconarchive.com/icons/fatcow/farm-fresh/32/table-icon.png // @license Mozilla Public License 2.0 // @grant GM_addStyle // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/html2canvas.min.js // ==/UserScript== (function() {{ 'use strict'; // Add styles GM_addStyle(`#newTable { border-collapse: collapse; margin: 15px auto; font-size: 0.9em; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); background: white; width: 98%; min-width: 1400px; table-layout: fixed; } #newTable thead tr { background: linear-gradient(135deg, #1a237e 0%, #0d47a1 100%); color: #ffffff; text-align: center; font-weight: bold; height: 60px; position: relative; box-shadow: 0 3px 6px rgba(0,0,0,0.1); font-feature-settings: "kern", "liga", "clig", "calt", "arab"; -webkit-font-feature-settings: "kern", "liga", "clig", "calt", "arab"; font-family: "Segoe UI", "Traditional Arabic", Tahoma, Geneva, Verdana, sans-serif; direction: rtl; } #newTable th { width: 20%; padding: 12px; position: relative; font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; border-left: 1px solid rgba(255,255,255,0.15); transition: background-color 0.3s ease; } #newTable th:last-child { border-left: none; } #newTable th::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 3px; background: rgba(255,255,255,0.1); transform: scaleX(0.7); transition: transform 0.3s ease; } #newTable th:hover::after { transform: scaleX(1); } #newTable th .day-name { font-size: 1.3em; font-weight: 600; margin-bottom: 2px; text-shadow: 1px 1px 2px rgba(0,0,0,0.2); text-align: center; direction: rtl; font-family: "Noto Kufi Arabic", "Segoe UI", sans-serif; font-feature-settings: "kern", "liga", "clig", "calt"; -webkit-font-feature-settings: "kern", "liga", "clig", "calt"; } #newTable th .day-name-en { font-size: 0.75em; opacity: 0.8; font-weight: normal; display: block; letter-spacing: 1px; } #newTable td { padding: 8px; text-align: center; vertical-align: middle; height: auto; width: 20%; font-size: 0.85em; } #newTable td:empty { padding: 0; height: 0; } #newTable tbody tr { border-bottom: 1px solid #e0e0e0; transition: background-color 0.3s ease; } #newTable tbody tr:hover { background-color: #f5f5f5; } .break-cell { background: linear-gradient(135deg, #f5f5f5 0%, #ffffff 100%); color: #424242; font-style: italic; padding: 8px; border-radius: 6px; margin: 4px; font-size: 1.3em; box-shadow: 0 1px 3px rgba(0,0,0,0.1); text-align: center; border: 1px solid #e0e0e0; } .lecture-cell { border-left: 4px solid; padding: 8px; background: #fff; border-radius: 6px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin: 4px; transition: all 0.2s ease; } .lecture-cell:hover { transform: translateX(-2px); } .lecture-cell strong { display: block; margin-bottom: 1px; font-size: 0.95em; } .lecture-cell div { margin: 0; line-height: 1.2; } .schedule-summary { background: linear-gradient(45deg, #f5f5f5, #fff); border-radius: 8px; padding: 20px; margin: 15px auto; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border: 1px solid #e0e0e0; width: 98%; box-sizing: border-box; min-width: 1400px; } .schedule-summary > div { display: flex; align-items: center; justify-content: center; gap: 20px; flex-wrap: wrap; width: 100%; box-sizing: border-box; } .schedule-summary div > div { flex: 0 1 auto; min-width: fit-content; white-space: nowrap; } .control-buttons { display: flex; gap: 10px; margin: 10px 0; } .control-button { display: inline-flex; align-items: center; justify-content: center; padding: 10px 20px; border-radius: 12px; font-family: "Segoe UI", "Traditional Arabic", Tahoma, Geneva, Verdana, sans-serif; font-size: 0.95em; font-weight: 600; text-align: center; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); border: none; background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%); box-shadow: 0 2px 4px rgba(37, 99, 235, 0.2), 0 4px 8px rgba(37, 99, 235, 0.1), inset 0 2px 4px rgba(255, 255, 255, 0.1); text-decoration: none; margin: 4px 8px; min-width: 120px; white-space: nowrap; line-height: 1.5; cursor: pointer; color: white; position: relative; overflow: hidden; } .control-button::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0)); opacity: 0; transition: opacity 0.3s ease; } .control-button:hover { transform: translateY(-2px) scale(1.02); box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3), 0 8px 16px rgba(37, 99, 235, 0.2), inset 0 2px 4px rgba(255, 255, 255, 0.2); } .control-button:hover::before { opacity: 1; } .control-button:active { transform: translateY(1px) scale(0.98); box-shadow: 0 2px 4px rgba(37, 99, 235, 0.2), inset 0 2px 4px rgba(0, 0, 0, 0.1); } .control-button.active { background: linear-gradient(135deg, #059669 0%, #10b981 100%); box-shadow: 0 2px 4px rgba(5, 150, 105, 0.2), 0 4px 8px rgba(5, 150, 105, 0.1), inset 0 2px 4px rgba(255, 255, 255, 0.1); } /* Theme buttons specific styles */ .theme-btn { min-width: 100px; backdrop-filter: blur(8px); } #lightThemeBtn { background: linear-gradient(135deg, #d97706 0%, #f59e0b 100%); box-shadow: 0 2px 4px rgba(217, 119, 6, 0.2), 0 4px 8px rgba(217, 119, 6, 0.1), inset 0 2px 4px rgba(255, 255, 255, 0.1); } #lightThemeBtn:hover { box-shadow: 0 4px 12px rgba(217, 119, 6, 0.3), 0 8px 16px rgba(217, 119, 6, 0.2), inset 0 2px 4px rgba(255, 255, 255, 0.2); } #darkThemeBtn { background: linear-gradient(135deg, #4f46e5 0%, #6366f1 100%); box-shadow: 0 2px 4px rgba(79, 70, 229, 0.2), 0 4px 8px rgba(79, 70, 229, 0.1), inset 0 2px 4px rgba(255, 255, 255, 0.1); } #darkThemeBtn:hover { box-shadow: 0 4px 12px rgba(79, 70, 229, 0.3), 0 8px 16px rgba(79, 70, 229, 0.2), inset 0 2px 4px rgba(255, 255, 255, 0.2); } #downloadButton { background: linear-gradient(135deg, #0d9488 0%, #14b8a6 100%); box-shadow: 0 2px 4px rgba(13, 148, 136, 0.2), 0 4px 8px rgba(13, 148, 136, 0.1), inset 0 2px 4px rgba(255, 255, 255, 0.1); } #downloadButton:hover { box-shadow: 0 4px 12px rgba(13, 148, 136, 0.3), 0 8px 16px rgba(13, 148, 136, 0.2), inset 0 2px 4px rgba(255, 255, 255, 0.2); } #ramadanBtn { background: linear-gradient(135deg, #7c3aed 0%, #8b5cf6 100%); box-shadow: 0 2px 4px rgba(124, 58, 237, 0.2), 0 4px 8px rgba(124, 58, 237, 0.1), inset 0 2px 4px rgba(255, 255, 255, 0.1); } #ramadanBtn:hover { box-shadow: 0 4px 12px rgba(124, 58, 237, 0.3), 0 8px 16px rgba(124, 58, 237, 0.2), inset 0 2px 4px rgba(255, 255, 255, 0.2); } /* Dark theme support for control buttons */ .theme-dark .control-button { background: linear-gradient(135deg, #2d3a6a 0%, #3d4a8a 100%); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3), 0 4px 8px rgba(0, 0, 0, 0.2), inset 0 1px 1px rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.05); color: #e0e0ff; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .theme-dark .control-button:hover { transform: translateY(-2px) scale(1.02); background: linear-gradient(135deg, #3d4a8a 0%, #4d5aaa 100%); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), 0 8px 16px rgba(0, 0, 0, 0.3), inset 0 1px 2px rgba(255, 255, 255, 0.2); border-color: rgba(255, 255, 255, 0.1); } .theme-dark .control-button:active { transform: translateY(1px) scale(0.98); background: linear-gradient(135deg, #2d3a6a 0%, #3d4a8a 100%); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3), inset 0 1px 2px rgba(0, 0, 0, 0.2); } .theme-dark .control-button.active { background: linear-gradient(135deg, #2d6a3a 0%, #3d8a4a 100%); border-color: rgba(255, 255, 255, 0.1); } .theme-dark #lightThemeBtn { background: linear-gradient(135deg, #6a4a2d 0%, #8a5a3d 100%); } .theme-dark #darkThemeBtn { background: linear-gradient(135deg, #2d3a6a 0%, #3d4a8a 100%); } .theme-dark #downloadButton { background: linear-gradient(135deg, #2d6a6a 0%, #3d8a8a 100%); } .theme-dark #ramadanBtn { background: linear-gradient(135deg, #4a2d6a 0%, #5a3d8a 100%); } .schedule-organizer-btn { display: inline-flex; align-items: center; justify-content: center; padding: 10px 28px; background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%); color: white; border-radius: 12px; font-family: "Segoe UI", "Traditional Arabic", Tahoma, Geneva, Verdana, sans-serif; font-size: 1.1em; font-weight: 600; text-align: center; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); border: none; box-shadow: 0 2px 4px rgba(37, 99, 235, 0.2), 0 4px 8px rgba(37, 99, 235, 0.1), inset 0 2px 4px rgba(255, 255, 255, 0.1); text-decoration: none; margin: 6px; min-width: 160px; white-space: nowrap; line-height: 1.5; cursor: pointer; position: relative; overflow: hidden; } .schedule-organizer-btn::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0)); opacity: 0; transition: opacity 0.3s ease; } .schedule-organizer-btn:hover { transform: translateY(-2px) scale(1.02); box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3), 0 8px 16px rgba(37, 99, 235, 0.2), inset 0 2px 4px rgba(255, 255, 255, 0.2); } .schedule-organizer-btn:hover::before { opacity: 1; } .schedule-organizer-btn:active { transform: translateY(1px) scale(0.98); box-shadow: 0 2px 4px rgba(37, 99, 235, 0.2), inset 0 2px 4px rgba(0, 0, 0, 0.1); } .schedule-organizer-btn.active { background: linear-gradient(135deg, #dc2626 0%, #ef4444 100%); box-shadow: 0 2px 4px rgba(220, 38, 38, 0.2), 0 4px 8px rgba(220, 38, 38, 0.1), inset 0 2px 4px rgba(255, 255, 255, 0.1); } /* Dark theme support */ .theme-dark .schedule-organizer-btn { background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); box-shadow: 0 2px 4px rgba(30, 64, 175, 0.3), 0 4px 8px rgba(30, 64, 175, 0.2), inset 0 2px 4px rgba(255, 255, 255, 0.05); } .theme-dark .schedule-organizer-btn:hover { box-shadow: 0 4px 12px rgba(30, 64, 175, 0.4), 0 8px 16px rgba(30, 64, 175, 0.3), inset 0 2px 4px rgba(255, 255, 255, 0.1); } .theme-dark .schedule-organizer-btn.active { background: linear-gradient(135deg, #b91c1c 0%, #dc2626 100%); } .lecture-hall { display: block; background: #e8f5e9; padding: 6px 10px; border-radius: 6px; font-size: 1.2em; color: #2e7d32; margin-top: 5px; font-weight: 500; border: 1px solid #c8e6c9; text-align: center; } /* Loading Overlay Styles */ .loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, rgba(255, 255, 255, 0.98), rgba(240, 240, 255, 0.98)); display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 999999; direction: rtl; opacity: 0; animation: fadeIn 0.3s ease-out forwards; animation-fill-mode: forwards; backdrop-filter: blur(5px); } .loading-content { background: white; padding: 30px 40px; border-radius: 16px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; align-items: center; gap: 20px; transform: translateY(20px); animation: slideUp 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards; animation-fill-mode: forwards; animation-delay: 0.1s; } .loading-spinner { width: 60px; height: 60px; border: 4px solid rgba(52, 152, 219, 0.2); border-top: 4px solid #3498db; border-radius: 50%; animation: spin 1s cubic-bezier(0.4, 0, 0.2, 1) infinite; } .loading-text { font-size: 20px; color: #2c3e50; font-weight: 500; animation: fadeInOut 2s ease-in-out infinite; animation-fill-mode: both; } .loading-subtext { font-size: 14px; color: #7f8c8d; text-align: center; opacity: 0.8; animation: fadeIn 0.5s ease-out forwards; animation-delay: 0.3s; animation-fill-mode: forwards; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes fadeInOut { 0%, 100% { opacity: 0.8; transform: translateY(0); } 50% { opacity: 1; transform: translateY(-2px); } } .schedule-summary div { font-size: 1.1em; padding: 10px 20px; } /* Dark Theme Styles */ #newTable.theme-dark { background: #1a1a2e; border-color: #2e2e4a; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); } #newTable.theme-dark thead tr { background: linear-gradient(135deg, #1e2a4a 0%, #2d3a6a 100%); color: #ffffff; box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2); } #newTable.theme-dark th { border-left: 1px solid rgba(255,255,255,0.1); } #newTable.theme-dark tbody tr { border-bottom: 1px solid #2e2e4a; transition: background-color 0.3s ease; } #newTable.theme-dark tbody tr:hover { background-color: #232338; } #newTable.theme-dark td { color: #e4e4e7; } #newTable.theme-dark .break-cell { background: #232338; color: #b0b0c0; border-color: #2e2e4a; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } #newTable.theme-dark .lecture-cell { background: #232338; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); border-width: 0 0 0 4px; } #newTable.theme-dark .lecture-hall { background: #1e2a4a; color: #a0b8ff; border-color: #2e3f6a; } .schedule-summary.theme-dark { background: linear-gradient(45deg, #1a1a2e, #232338); border-color: #2e2e4a; color: #e0e0ff; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); } /* Dark theme loading overlay */ .theme-dark .loading-overlay { background: linear-gradient(135deg, rgba(18, 18, 18, 0.98), rgba(30, 30, 46, 0.98)); } .theme-dark .loading-content { background: #1e1e2e; color: #e4e4e7; } .theme-dark .loading-text { color: #e4e4e7; } .theme-dark .loading-subtext { color: #a0a0a7; } #newTable.theme-dark th.HEADING { background: linear-gradient(135deg, #1a2b3f 0%, #2d4258 100%) !important; color: #ffffff; }`); // Global variables let rows = []; const days = ['الأحد','الإثنين','الثلاثاء','الأربعاء','الخميس']; let newTable = {}; let newTableNode; let on = false; let ramadanMode = false; let colors = ["Blue", "Black", "Crimson", "Green", "Grey", "OrangeRed", "Purple", "Red", "SpringGreen", "MediumTurquoise", "Navy", "GoldenRod"]; let subject_colors = {}; let color_index = 0; let currentTheme = 'light'; let includeSummaryInDownload = false; // Time conversion functions function convertToRamadanTime(timeStr) { // Split the time range const [startTime, endTime] = timeStr.split(' - '); // Helper function to parse time function parseTime(time) { const [timeComponent, period] = time.trim().split(' '); const [hourStr, minuteStr] = timeComponent.split(':'); let hour = parseInt(hourStr); const minute = parseInt(minuteStr); const isPM = period === 'م'; if (isPM && hour !== 12) hour += 12; if (!isPM && hour === 12) hour = 0; return { hour, minute, period }; } // Parse start and end times to detect practical sessions const start = parseTime(startTime); const end = parseTime(endTime); // Determine if it's a practical session based on duration (80 minutes) const duration = ((end.hour - start.hour) * 60 + (end.minute - start.minute)); const isPractical = Math.abs(duration - 80) <= 5; // Allow 5-minute flexibility // Theoretical lecture time mappings const theoreticalMap = { '08:00 ص': { start: '09:30 ص', end: '10:05 ص' }, '09:00 ص': { start: '10:10 ص', end: '10:45 ص' }, '10:00 ص': { start: '10:50 ص', end: '11:25 ص' }, '11:00 ص': { start: '11:30 ص', end: '12:05 م' }, '12:00 م': { start: '12:10 م', end: '12:45 م' }, '01:00 م': { start: '01:05 م', end: '01:40 م' }, '02:00 م': { start: '01:45 م', end: '02:20 م' }, '03:00 م': { start: '02:25 م', end: '03:00 م' }, '04:00 م': { start: '03:05 م', end: '03:40 م' }, '05:00 م': { start: '03:45 م', end: '04:20 م' }, '06:00 م': 'غير مستخدم', '07:00 م': { start: '04:40 م', end: '05:15 م' } }; // Practical session time mappings const practicalMap = { '08:00 ص': { start: '09:30 ص', end: '10:20 ص' }, '09:30 ص': { start: '10:25 ص', end: '11:15 ص' }, '11:00 ص': { start: '11:20 ص', end: '12:10 م' }, '12:30 م': { start: '12:15 م', end: '01:05 م' }, '02:00 م': { start: '01:30 م', end: '02:20 م' }, '03:30 م': { start: '02:25 م', end: '03:15 م' }, '05:00 م': { start: '03:20 م', end: '04:10 م' } }; // Get the mapped time based on session type const timeMap = isPractical ? practicalMap : theoreticalMap; const mappedTime = timeMap[startTime]; // Handle "not in use" case if (mappedTime === 'غير مستخدم') { return 'غير مستخدم'; } // If no mapping found, return original time if (!mappedTime) { return timeStr; } return `${mappedTime.start} - ${mappedTime.end}`; } // Main initialization function function waitForElement(selector, callback, maxTries = 100) { if (maxTries <= 0) { console.log('Element not found: ' + selector); return; } const element = document.getElementById(selector); if (element) { callback(element); return; } setTimeout(() => { waitForElement(selector, callback, maxTries - 1); }, 100); } // Remove the DOMContentLoaded listener and replace with this: function init() { waitForElement('scheduleFrm:studScheduleTable', (element) => { try { initializeTableOrganizer(); } catch (error) { console.error('Error initializing table organizer:', error); } }); } // Add error handling to the table check function initializeTableOrganizer() { const originalTableNode = document.getElementById('scheduleFrm:studScheduleTable'); if (!originalTableNode) { console.log('Schedule table not found'); return; } // Create control button let button = document.createElement('span'); let cell = document.createElement('td'); button.classList.add("schedule-organizer-btn"); if (on) { button.classList.add("active"); button.innerHTML = "الجدول الاصلي"; originalTableNode.style.display = 'none'; if (newTableNode) { newTableNode.style.display = null; } else { getTableInfo(); getNewTable(); appendTable(); } } else { button.innerHTML = "نظم الجدول"; if (newTableNode) { newTableNode.style.display = 'none'; } } cell.appendChild(button); const printLink = document.getElementById("scheduleFrm:printLink"); if (printLink && printLink.parentElement && printLink.parentElement.parentElement) { printLink.parentElement.parentElement.appendChild(cell); } button.onclick = function() { if (on) { on = false; button.classList.remove("active"); button.innerHTML = "نظم الجدول"; originalTableNode.style.display = null; newTableNode.style.display = 'none'; document.querySelectorAll('.schedule-summary').forEach(el => el.remove()); } else { on = true; button.classList.add("active"); button.innerHTML = "الجدول الاصلي"; originalTableNode.style.display = 'none'; if (newTableNode) { newTableNode.style.display = null; document.querySelectorAll('.schedule-summary').forEach(el => el.remove()); let summary = createSummary(); originalTableNode.insertAdjacentElement('afterend', summary); } else { if (rows.length == 0) { getTableInfo(); } getNewTable(); appendTable(); } } }; } // Helper function to get deepest text function endText(node) { if (!node.firstElementChild) { return node.innerHTML; } else { return endText(node.firstElementChild); } } // Get table information function getTableInfo() { const row1 = document.querySelectorAll(".ROW1"); const row2 = document.querySelectorAll(".ROW2"); function processRows(nodes) { for (let i = 0; i < nodes.length; i++) { let row_obj = {}; let row = nodes[i]; let cells = row.children; for (let j = 0; j < cells.length; j++) { try { if (cells[j].dataset.th.includes("القاعة")) { let headers = cells[j].dataset.th.split(/\s+/); let lectures = cells[j].firstElementChild.firstElementChild.children; row_obj["محاضرات"] = []; for (let k = 0; k < lectures.length; k++) { let data = {}; for (let l = 0; l < headers.length; l++) { let currentHeader = headers[l]; data[currentHeader] = endText(lectures[k].children[l]).trim(); if (data[currentHeader].includes(" ")) { data[currentHeader] = data[currentHeader].split('; ')[1].trim().split(' '); } } row_obj["محاضرات"].push(data); } } else { let cellName = cells[j].dataset.th.trim(); row_obj[cellName] = endText(cells[j]).trim(); if (row_obj[cellName].includes(" ")) { row_obj[cellName] = row_obj[cellName].split('&')[0].trim(); } } } catch(err) { console.log(err); } } rows.push(row_obj); } } processRows(row1); processRows(row2); } // Rest of your functions (getNewTable, appendTable, etc.) go here... // [Previous functions remain mostly unchanged, just remove the styles injection part] // Start initialization if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } function getNewTable() { try { // Populate the new table with the days and their lectures for (i in days) { newTable[days[i]] = []; } for (i in rows) { let subjectLectures = rows[i]['محاضرات']; for (j in subjectLectures) { let lecture = subjectLectures[j]; let time = lecture['الوقت']; // Convert time to Ramadan schedule if ramadanMode is enabled if (ramadanMode) { time = convertToRamadanTime(time); } function value(t) { let hour = parseInt(t.slice(0, 2), 10); let minutes = parseInt(t.slice(3, 5), 10); let total = (hour * 60) + minutes; if (t.slice(0, 10).includes('م') && hour != 12) { total += 720; } return total; } function getLectureEndTime(timeStr) { let parts = timeStr.split(' - '); return value(parts[1]); } function getLectureStartTime(timeStr) { let parts = timeStr.split(' - '); return value(parts[0]); } for (k in lecture["اليوم"]) { let day = days[parseInt(lecture["اليوم"][k])-1]; newTable[day].push({ subject: rows[i]['اسم المقرر'], activity: rows[i]['النشاط'], time: time, place: lecture['القاعة'], section: rows[i]['الشعبة'], value: value(time), endTime: getLectureEndTime(time), startTime: getLectureStartTime(time) }); if (!(rows[i]['اسم المقرر'] in subject_colors)){ subject_colors[rows[i]['اسم المقرر']] = colors[color_index]; color_index++; } } } } // Sort lectures by time for (i in newTable) { newTable[i].sort((a, b) => a.startTime - b.startTime); } // Helper function to insert after index function insert_after(element, array, index) { let new_array = []; for (i = 0; i < array.length; i++) { if (i == index+1) { new_array.push(element); } new_array.push(array[i]); } return new_array; } // Add breaks between lectures for (d = 0; d < days.length; d++) { let edited_day = JSON.parse(JSON.stringify(newTable[days[d]])); let uni_day = newTable[days[d]]; let skip = 0; for (l = 0; l < uni_day.length - 1; l++) { let currentLectureEnd = uni_day[l].endTime; let nextLectureStart = uni_day[l+1].startTime; let breakTime = nextLectureStart - currentLectureEnd; if (breakTime > 10) { // Only show breaks longer than 10 minutes let break_obj = { subject: null, activity: "break", time: null, place: null, value: breakTime }; edited_day = insert_after(break_obj, edited_day, l+skip); skip++; } } newTable[days[d]] = edited_day; } } catch(err) { console.log(err); } } function getBreakText(hrs) { const getBreakIcon = (hrs) => { if (hrs >= 2) return '☕'; if (hrs >= 1) return '⏰'; return '⌛'; }; // Round down if extra minutes are 10 or less const wholeHours = Math.floor(hrs); const extraMinutes = Math.round((hrs - wholeHours) * 60); const roundedHours = extraMinutes <= 10 ? wholeHours : hrs; const icon = getBreakIcon(roundedHours); let duration; if (roundedHours === 2) { duration = 'ساعتين'; } else if (roundedHours > 2) { duration = `${Math.floor(roundedHours)} ساعات`; } else if (roundedHours >= 1) { duration = 'ساعة'; if (roundedHours > 1) { const minutes = Math.round((roundedHours - 1) * 60); if (minutes > 10) { // Only show minutes if more than 10 duration += ` و ${minutes} دقيقة`; } } } else { const minutes = Math.round(roundedHours * 60); duration = `${minutes} دقيقة`; } return `<div class="break-content">${icon} ${duration} استراحة</div>`; } function getActivityIcon(activity) { if (activity.includes('عملي')) return '🔬'; if (activity.includes('نظري')) return '📚'; return '📖'; } function getActivityStyle(activity) { if (activity.includes('عملي')) return 'background: #9c27b0; color: white; border-radius: 4px; padding: 2px 6px;'; if (activity.includes('نظري')) return 'background: #1976d2; color: white; border-radius: 4px; padding: 2px 6px;'; return 'background: #757575; color: white; border-radius: 4px; padding: 2px 6px;'; } function downloadAsPNG(event) { if (event) { event.preventDefault(); } //Create and show loading overlay const loadingOverlay = document.createElement('div'); loadingOverlay.className = 'loading-notification'; loadingOverlay.innerHTML = ` <div class="notification-content"> <div class="modern-spinner"></div> <div class="notification-text"> <div class="notification-title">جار تحميل الصورة...</div> <div class="notification-subtitle">يرجى الانتظار بينما نقوم بمعالجة الجدول</div> </div> </div> `; // Add styles for the notification const style = document.createElement('style'); style.textContent = ` .loading-notification { position: fixed; top: 20px; right: 20px; background: ${currentTheme === 'dark' ? '#1a1a1a' : '#ffffff'}; border: 1px solid ${currentTheme === 'dark' ? '#333' : '#e0e0e0'}; border-radius: 12px; padding: 16px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); z-index: 10000; max-width: 300px; animation: slideIn 0.3s ease-out; backdrop-filter: blur(10px); } .notification-content { display: flex; align-items: center; gap: 12px; } .notification-text { flex: 1; } .notification-title { color: ${currentTheme === 'dark' ? '#ffffff' : '#000000'}; font-weight: 600; margin-bottom: 4px; } .notification-subtitle { color: ${currentTheme === 'dark' ? '#888' : '#666'}; font-size: 0.9em; } .modern-spinner { width: 24px; height: 24px; border: 3px solid ${currentTheme === 'dark' ? '#333' : '#f0f0f0'}; border-top: 3px solid ${currentTheme === 'dark' ? '#4CAF50' : '#2196F3'}; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes slideIn { from { opacity: 0; transform: translateX(100px); } to { opacity: 1; transform: translateX(0); } } @keyframes slideOut { from { opacity: 1; transform: translateX(0); } to { opacity: 0; transform: translateX(100px); } } `; document.head.appendChild(style); document.body.appendChild(loadingOverlay); const element = document.getElementById('newTable'); const summary = document.querySelector('.schedule-summary'); // Create filename based on mode const filename = ramadanMode ? 'الجدول_الدراسي_توقيت_رمضان.png' : 'الجدول_الدراسي.png'; // Calculate the maximum width needed const tableWidth = element.offsetWidth; const summaryWidth = summary ? summary.offsetWidth : 0; const maxWidth = Math.max(tableWidth, summaryWidth); const wrapper = document.createElement('div'); wrapper.style.cssText = ` background: ${currentTheme === 'dark' ? '#1a1a1a' : '#ffffff'}; direction: rtl; width: ${maxWidth}px; margin: 0; border-radius: 0; display: flex; flex-direction: column; align-items: stretch; position: relative; `; // Only include summary if checkbox is checked if (includeSummaryInDownload && summary) { const summaryClone = summary.cloneNode(true); // Remove control buttons from summary clone const controlButtons = summaryClone.querySelector('.control-buttons'); if (controlButtons) controlButtons.remove(); // Remove theme buttons and download button summaryClone.querySelectorAll('.control-button, .theme-btn, label').forEach(btn => btn.remove()); // Ensure summary maintains consistent width summaryClone.style.cssText = ` width: ${maxWidth}px; margin: 0; box-sizing: border-box; background: ${currentTheme === 'dark' ? '#1a1a1a' : '#ffffff'}; `; wrapper.appendChild(summaryClone); } const tableClone = element.cloneNode(true); // If in Ramadan mode, find a suitable cell for the indicator if (ramadanMode) { // Try to find an empty or break cell in the middle of the table const rows = tableClone.querySelectorAll('tbody tr'); let indicatorPlaced = false; // Calculate middle row const middleRowIndex = Math.floor(rows.length / 2); // First try: Look in the middle row if (rows[middleRowIndex]) { const cells = rows[middleRowIndex].children; for (let cell of cells) { if (!cell.innerHTML.trim() || cell.innerHTML.includes('استراحة')) { const ramadanIndicator = ` <div style=" background: ${currentTheme === 'dark' ? 'linear-gradient(135deg, #2d1f3d 0%, #1a1a2e 100%)' : 'linear-gradient(135deg, #f3e5f5 0%, #e8eaf6 100%)' }; padding: 12px 24px; border-radius: 12px; display: flex; align-items: center; justify-content: center; gap: 12px; font-size: 1.2em; box-shadow: ${currentTheme === 'dark' ? '0 4px 15px rgba(123, 97, 255, 0.2), 0 0 20px rgba(123, 97, 255, 0.1)' : '0 4px 15px rgba(156, 39, 176, 0.1), 0 0 20px rgba(156, 39, 176, 0.05)' }; margin: 10px auto; width: fit-content; border: 2px solid ${currentTheme === 'dark' ? '#4a3f6b' : '#e1bee7'}; animation: ramadanGlow 2s ease-in-out infinite; "> <span style="font-size: 1.4em;">🌙</span> <span style=" color: ${currentTheme === 'dark' ? '#fff' : '#000'}; font-weight: 500; ">توقيت رمضان</span> </div> <style> @keyframes ramadanGlow { 0%, 100% { box-shadow: ${currentTheme === 'dark' ? '0 4px 15px rgba(123, 97, 255, 0.2), 0 0 20px rgba(123, 97, 255, 0.1)' : '0 4px 15px rgba(156, 39, 176, 0.1), 0 0 20px rgba(156, 39, 176, 0.05)' }; } 50% { box-shadow: ${currentTheme === 'dark' ? '0 4px 20px rgba(123, 97, 255, 0.3), 0 0 30px rgba(123, 97, 255, 0.2)' : '0 4px 20px rgba(156, 39, 176, 0.2), 0 0 30px rgba(156, 39, 176, 0.1)' }; } } </style> `; cell.innerHTML = ramadanIndicator; indicatorPlaced = true; break; } } } // Second try: Look in adjacent rows if middle row didn't work if (!indicatorPlaced) { for (let offset = 1; offset <= 2; offset++) { const rowsToTry = [ rows[middleRowIndex - offset], rows[middleRowIndex + offset] ]; for (const row of rowsToTry) { if (!row) continue; const cells = row.children; for (let cell of cells) { if (!cell.innerHTML.trim() || cell.innerHTML.includes('استراحة')) { const ramadanIndicator = ` <div style=" background: ${currentTheme === 'dark' ? 'linear-gradient(135deg, #2d1f3d 0%, #1a1a2e 100%)' : 'linear-gradient(135deg, #f3e5f5 0%, #e8eaf6 100%)' }; padding: 12px 24px; border-radius: 12px; display: flex; align-items: center; justify-content: center; gap: 12px; font-size: 1.2em; box-shadow: ${currentTheme === 'dark' ? '0 4px 15px rgba(123, 97, 255, 0.2), 0 0 20px rgba(123, 97, 255, 0.1)' : '0 4px 15px rgba(156, 39, 176, 0.1), 0 0 20px rgba(156, 39, 176, 0.05)' }; margin: 10px auto; width: fit-content; border: 2px solid ${currentTheme === 'dark' ? '#4a3f6b' : '#e1bee7'}; animation: ramadanGlow 2s ease-in-out infinite; "> <span style="font-size: 1.4em;">🌙</span> <span style=" color: ${currentTheme === 'dark' ? '#fff' : '#000'}; font-weight: 500; ">توقيت رمضان</span> </div> <style> @keyframes ramadanGlow { 0%, 100% { box-shadow: ${currentTheme === 'dark' ? '0 4px 15px rgba(123, 97, 255, 0.2), 0 0 20px rgba(123, 97, 255, 0.1)' : '0 4px 15px rgba(156, 39, 176, 0.1), 0 0 20px rgba(156, 39, 176, 0.05)' }; } 50% { box-shadow: ${currentTheme === 'dark' ? '0 4px 20px rgba(123, 97, 255, 0.3), 0 0 30px rgba(123, 97, 255, 0.2)' : '0 4px 20px rgba(156, 39, 176, 0.2), 0 0 30px rgba(156, 39, 176, 0.1)' }; } } </style> `; cell.innerHTML = ramadanIndicator; indicatorPlaced = true; break; } } if (indicatorPlaced) break; } if (indicatorPlaced) break; } } } wrapper.appendChild(tableClone); document.body.appendChild(wrapper); // Enhanced style preservation const preserveStyles = (element) => { const computedStyle = window.getComputedStyle(element); const importantStyles = [ 'font-family', 'font-size', 'font-weight', 'color', 'background', 'padding', 'margin', 'border', 'text-align', 'direction', 'display', 'width', 'height', 'border-radius', 'box-shadow', 'grid-template-columns', 'gap', 'background-color', 'border-color', 'border-width', 'border-style', 'line-height', 'letter-spacing', 'text-decoration', 'text-transform', 'vertical-align', 'position', 'top', 'left', 'right', 'bottom', 'z-index', 'opacity', 'transform', 'transition', 'box-sizing', 'overflow' ]; let styleString = importantStyles.map(property => `${property}:${computedStyle.getPropertyValue(property)}` ).join(';'); // Preserve existing inline styles if (element.style.cssText) { styleString += ';' + element.style.cssText; } element.style.cssText = styleString; Array.from(element.children).forEach(preserveStyles); }; preserveStyles(wrapper); // Use fixed scale of 7 const scale = 7; html2canvas(wrapper, { backgroundColor: '#ffffff', scale: scale, logging: false, useCORS: true, allowTaint: true, width: wrapper.offsetWidth, height: wrapper.offsetHeight, onclone: function(clonedDoc) { const clonedWrapper = clonedDoc.body.lastChild; preserveStyles(clonedWrapper); } }).then(canvas => { wrapper.remove(); // Add slide out animation before removing loadingOverlay.style.animation = 'slideOut 0.3s ease-in'; setTimeout(() => { loadingOverlay.remove(); style.remove(); }, 300); try { const image = canvas.toDataURL('image/png', 1.0); const link = document.createElement('a'); link.download = filename; // Use the new filename link.href = image; document.body.appendChild(link); link.click(); document.body.removeChild(link); } catch (error) { console.error('Error saving image:', error); alert('خطأ في حفظ الصورة. يرجى المحاولة مرة أخرى.'); } }).catch(error => { console.error('Error generating PNG:', error); // Add slide out animation before removing loadingOverlay.style.animation = 'slideOut 0.3s ease-in'; setTimeout(() => { loadingOverlay.remove(); style.remove(); }, 300); if (error.message.includes('memory')) { alert('خطأ: الصورة كبيرة جداً. جاري المحاولة بجودة أقل...'); setTimeout(() => { html2canvas(wrapper, { backgroundColor: '#ffffff', scale: 6, logging: false, useCORS: true, allowTaint: true, width: wrapper.offsetWidth, height: wrapper.offsetHeight }).then(canvas => { const image = canvas.toDataURL('image/png', 1.0); const link = document.createElement('a'); link.download = filename; // Use the new filename link.href = image; document.body.appendChild(link); link.click(); document.body.removeChild(link); }); }, 100); } else { alert('حدث خطأ أثناء إنشاء الصورة. يرجى المحاولة مرة أخرى.'); } wrapper.remove(); }); } function toggleTheme(theme) { currentTheme = theme; const table = document.getElementById('newTable'); if (!table) return; table.classList.remove('theme-light', 'theme-dark'); table.classList.add(`theme-${theme}`); // Update summary section theme const summary = document.querySelector('.schedule-summary'); if (summary) { summary.classList.remove('theme-light', 'theme-dark'); summary.classList.add(`theme-${theme}`); } // Apply theme-specific styles if (theme === 'dark') { table.style.backgroundColor = '#1a1a1a'; table.style.color = '#ffffff'; } else { table.style.backgroundColor = ''; table.style.color = ''; } } function createSummary() { let summary = document.createElement('div'); summary.classList.add('schedule-summary', `theme-${currentTheme}`); let totalHours = 0; let subjectCount = new Set(); let daysWithClasses = new Set(); let maxLectures = 0; let busyDays = []; for (let day in newTable) { let dayLectures = newTable[day].filter(slot => slot.activity !== "break"); if (dayLectures.length > 0) { daysWithClasses.add(day); if (dayLectures.length > maxLectures) { maxLectures = dayLectures.length; busyDays = [day]; } else if (dayLectures.length === maxLectures) { busyDays.push(day); } } dayLectures.forEach(slot => { totalHours += (slot.time ? 1 : 0); subjectCount.add(slot.subject); }); } summary.innerHTML = ` <div style="display: flex; align-items: center; justify-content: center; gap: 20px; flex-wrap: wrap;"> <div style="display: flex; align-items: center; gap: 4px; background: ${currentTheme === 'dark' ? '#1a2f4d' : '#e3f2fd'}; padding: 8px 16px; border-radius: 8px;"> <span style="font-weight: 500;">📚 المواد:</span> <span>${subjectCount.size}</span> </div> <div style="display: flex; align-items: center; gap: 4px; background: ${currentTheme === 'dark' ? '#2d1f3d' : '#f3e5f5'}; padding: 8px 16px; border-radius: 8px;"> <span style="font-weight: 500;">⏰ الساعات:</span> <span>${totalHours}</span> </div> <div style="display: flex; align-items: center; gap: 4px; background: ${currentTheme === 'dark' ? '#1f3d2d' : '#e8f5e9'}; padding: 8px 16px; border-radius: 8px;"> <span style="font-weight: 500;">📅 أيام الدراسة:</span> <span>${daysWithClasses.size}</span> </div> <div style="display: flex; align-items: center; gap: 4px; background: ${currentTheme === 'dark' ? '#3d2d1f' : '#fff3e0'}; padding: 8px 16px; border-radius: 8px;"> <span style="font-weight: 500;">📊 اليوم الأكثر:</span> <span>${busyDays.join(', ')} (${maxLectures})</span> </div> <div style="display: flex; gap: 8px; align-items: center;"> <button class="control-button theme-btn" id="lightThemeBtn" style="background: ${currentTheme === 'light' ? '#4CAF50' : '#666'};"> ☀️ فاتح </button> <button class="control-button theme-btn" id="darkThemeBtn" style="background: ${currentTheme === 'dark' ? '#4CAF50' : '#666'};"> 🌙 داكن </button> <button class="control-button" id="ramadanBtn" style="background: ${ramadanMode ? '#4CAF50' : '#666'};"> 🕌 توقيت رمضان </button> <div class="download-group" style=" display: flex; align-items: center; gap: 8px; background: ${currentTheme === 'dark' ? '#1f1f1f' : '#f0f0f0'}; padding: 4px; border-radius: 12px; border: 1px solid ${currentTheme === 'dark' ? '#333' : '#e0e0e0'}; "> <button class="control-button" id="downloadButton" style="margin: 0;"> 💾 تحميل كصورة </button> <label class="custom-checkbox-container" style=" display: flex; align-items: center; gap: 8px; background: ${currentTheme === 'dark' ? '#2d2d2d' : '#f5f5f5'}; padding: 8px 16px; border-radius: 8px; cursor: pointer; transition: all 0.3s ease; margin: 0; "> <div class="checkbox-wrapper" style="position: relative; width: 18px; height: 18px;"> <input type="checkbox" id="includeSummaryCheckbox" ${includeSummaryInDownload ? 'checked' : ''} style=" position: absolute; opacity: 0; cursor: pointer; height: 0; width: 0; "> <span class="checkmark" style=" position: absolute; top: 0; left: 0; height: 18px; width: 18px; background-color: ${currentTheme === 'dark' ? '#404040' : '#ffffff'}; border: 2px solid ${currentTheme === 'dark' ? '#666' : '#ccc'}; border-radius: 4px; transition: all 0.2s ease; "></span> </div> <span style="color: ${currentTheme === 'dark' ? '#fff' : '#000'}; user-select: none;">تضمين الملخص</span> </label> </div> <style> .custom-checkbox-container:hover .checkmark { border-color: ${currentTheme === 'dark' ? '#888' : '#4CAF50'} !important; } .custom-checkbox-container input:checked ~ .checkmark { background-color: #4CAF50 !important; border-color: #4CAF50 !important; } .custom-checkbox-container input:checked ~ .checkmark:after { content: ''; position: absolute; left: 5px; top: 2px; width: 4px; height: 8px; border: solid white; border-width: 0 2px 2px 0; transform: rotate(45deg); } .custom-checkbox-container:hover { background: ${currentTheme === 'dark' ? '#363636' : '#e8e8e8'} !important; } .download-group:hover { border-color: ${currentTheme === 'dark' ? '#444' : '#ccc'}; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } </style> </div> </div> `; setTimeout(() => { const downloadButton = summary.querySelector('#downloadButton'); const lightThemeBtn = summary.querySelector('#lightThemeBtn'); const darkThemeBtn = summary.querySelector('#darkThemeBtn'); const ramadanBtn = summary.querySelector('#ramadanBtn'); const includeSummaryCheckbox = summary.querySelector('#includeSummaryCheckbox'); if (downloadButton) { downloadButton.addEventListener('click', downloadAsPNG); } if (lightThemeBtn) { lightThemeBtn.addEventListener('click', () => { toggleTheme('light'); appendTable(); }); } if (darkThemeBtn) { darkThemeBtn.addEventListener('click', () => { toggleTheme('dark'); appendTable(); }); } if (ramadanBtn) { ramadanBtn.addEventListener('click', () => { ramadanMode = !ramadanMode; ramadanBtn.style.background = ramadanMode ? '#4CAF50' : '#666'; getNewTable(); appendTable(); }); } if (includeSummaryCheckbox) { includeSummaryCheckbox.addEventListener('change', (e) => { includeSummaryInDownload = e.target.checked; }); } }, 0); return summary; } function appendTable() { // Remove any existing organized tables and summaries if (newTableNode) { newTableNode.remove(); } document.querySelectorAll('.schedule-summary').forEach(el => el.remove()); const originalTableNode = document.getElementById('scheduleFrm:studScheduleTable'); let table = document.createElement('table'); table.id = "newTable"; table.classList.add('rowFlow', `theme-${currentTheme}`); table.width = "100%"; table.cellPadding = '0'; table.cellSpacing = '0'; table.border = '1'; originalTableNode.insertAdjacentElement('afterend', table); let thead = document.createElement('thead'); let tbody = document.createElement('tbody') table.appendChild(thead); table.appendChild(tbody); const dayNamesEn = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday']; days.forEach((day, i) => { let th = document.createElement('th'); th.innerHTML = ` <div class="day-name">${day}</div> `; th.classList.add('HEADING'); th.scope = "col"; thead.appendChild(th); }); function maxDayLength(obj) { return Math.max(...Object.values(obj).map(day => day.length)); } const maxLength = maxDayLength(newTable); // Create empty rows for (let i = 0; i < maxLength; i++) { let tr = document.createElement('tr'); tbody.appendChild(tr); for (let j = 0; j < days.length; j++) { let td = document.createElement('td'); tr.appendChild(td); } } let trs = tbody.children; days.forEach((day, i) => { let currentDay = newTable[day]; currentDay.forEach((lecture, j) => { if (lecture.activity == "break") { let hrs = lecture.value/60; trs[j].children[i].innerHTML = `<div class="break-cell">${getBreakText(hrs)}</div>`; } else { let subjectColor = subject_colors[lecture.subject]; // Adjust color for dark mode if needed if (currentTheme === 'dark') { // Make the color more visible in dark mode subjectColor = adjustColorForDarkMode(subjectColor); } let activityStyle = getActivityStyle(lecture.activity); if (currentTheme === 'dark') { activityStyle = activityStyle.replace('background: #9c27b0', 'background: #4a1259') .replace('background: #1976d2', 'background: #1a3f6b') .replace('background: #757575', 'background: #3d3d3d'); } let content = `<div style="margin-bottom: 3px;"> <strong style="font-size: 1.1em; color: ${currentTheme === 'dark' ? '#e4e4e7' : 'inherit'}">${lecture.subject}</strong> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 8px;"> <div style="text-align: right;"> <div style="${activityStyle}"> ${getActivityIcon(lecture.activity)} ${lecture.activity} </div> <div style="background: ${currentTheme === 'dark' ? '#1a2f3a' : '#e8eaf6'}; border-radius: 6px; padding: 4px 8px; color: ${currentTheme === 'dark' ? '#8ebbff' : '#283593'}; display: inline-block; margin-top: 5px;"> 🔢 الشعبة: ${lecture.section} </div> </div> <div style="text-align: left;"> <div style="font-weight: bold; color: ${currentTheme === 'dark' ? '#8ebbff' : '#1a237e'}">${lecture.time}</div> <div class="lecture-hall">🏛️ ${lecture.place}</div> </div> </div> </div>`; trs[j].children[i].innerHTML = `<div class="lecture-cell" style="border-left-color: ${subjectColor};">${content}</div>`; } }); }); newTableNode = table; let summary = createSummary(); originalTableNode.insertAdjacentElement('afterend', summary); } // Helper function to adjust colors for dark mode function adjustColorForDarkMode(color) { // Convert color to RGB if it's a named color let tempDiv = document.createElement('div'); tempDiv.style.color = color; document.body.appendChild(tempDiv); let rgbColor = window.getComputedStyle(tempDiv).color; document.body.removeChild(tempDiv); // Parse RGB values let rgb = rgbColor.match(/\d+/g).map(Number); // Calculate luminance let luminance = (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]) / 255; // For very dark colors (especially black or near-black) if (luminance < 0.2) { // Convert to a light gray-blue tint return `rgb(176, 196, 222)`; // Light steel blue } // For dark colors if (luminance < 0.5) { // Increase brightness more significantly let adjustedRgb = rgb.map(value => { return Math.min(255, value + 80); }); return `rgb(${adjustedRgb.join(',')})`; } // For already light colors, just slight adjustment let adjustedRgb = rgb.map(value => { return Math.min(255, value + 40); }); return `rgb(${adjustedRgb.join(',')})`; } }})();