Greasy Fork is available in English.

منظم جدول الجامعة الاسلامية

اضافة لتعديل مظهر الجدول بالجامعة الاسلامية الى جدول مرتب تبعا لايام الاسبوع بضغطة زر

// ==UserScript==
// @name منظم جدول الجامعة الاسلامية
// @description اضافة لتعديل مظهر الجدول بالجامعة الاسلامية الى جدول مرتب تبعا لايام الاسبوع بضغطة زر
// @name:en IU Table Organizer
// @description:en A script to order the lectures table according to weekdays on the Islamic University website
// @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 1.3.1
// @icon https://www.google.com/s2/favicons?domain=sso.iu.edu.sa
// @namespace https://greasyfork.org/users/814159
// @icon https://icons.iconarchive.com/icons/fatcow/farm-fresh/32/table-icon.png
// @license Mozilla Public License 2.0 
// ==/UserScript==


// Rows are within these 2 class elements
row1 = document.querySelectorAll(".ROW1");
row2 = document.querySelectorAll(".ROW2");
// Where we append the info of every row
let rows = [];
const originalTableNode = document.getElementById('scheduleFrm:studScheduleTable');
const days = ['الاحد','الاثنين','الثلاثاء','الاربعاء','الخميس'];
let newTable = {};
let newTableNode;
let sec_is_checked = false;
let on = false;
// This feature is not used yet
// The colors that will be used for each subject
let colors = ["Blue", "Black", "Crimson", "Green", "Grey", "OrangeRed", "Purple", "Red", "SpringGreen", "MediumTurquoise", "Navy", "GoldenRod"];
let subject_colors = {};
// Increases when a color is assigned to a subject
let color_index = 0;

// Recursive function that takes a node and returns the deepest text in that node
// By repetitively going into the first child of an element until an end road was found
function endText(node) {
    if (!node.firstElementChild) {
        return node.innerHTML;
    } else {
        return endText(node.firstElementChild);
    }
}

// Gathers the all the lectures and subjects info in an array called rows
function getTableInfo(nodes) {
    // For every row in 'nodes' elements
    for (let i = 0; i < nodes.length; i++) {
        // initialize an object for a row
        let row_obj = {};
        // Choose one element with class ROW1
        let row = nodes[i];
        let cells = row.children;
    
        // For every cell in the row
        for (let j = 0; j < cells.length; j++) {
            try {
                // If the cell is the messy one with 3 values at the same time
                if (cells[j].dataset.th.includes("القاعة")) {
                    // Get the names of the cells by splitting the string
                    let headers = cells[j].dataset.th.split(/\s+/);
                    // May look stupid but it's the best way to get the elements representing the lectures
                    let lectures = cells[j].firstElementChild.firstElementChild.children;
                    row_obj["محاضرات"] = [];
    
                    // For each lecture element
                    for (let k = 0; k < lectures.length; k++) {
                        let data = {};
                        // For every header representing values
                        for (let l = 0; l < headers.length; l++) {
                            let currentHeader = headers[l];
                            // add the header with its value in the lecture (depends on the data being consistent)
                            data[currentHeader] = endText(lectures[k].children[l]).trim();
                            // If the text has '&nbsp' which means it's the messy 'day' cell 
                            // then split it and get the part that has the number
                            if (data[currentHeader].includes("&nbsp")) {
                                data[currentHeader] = data[currentHeader].split('; ')[1].trim().split(' ');
                            }
                        }
                        // Apeend the object with lectures data to 'lectures' key in row_obj
                        row_obj["محاضرات"].push(data);
                    }
                } else {
                    // Else get the deepest text and give it to the name in the dataset th
                    let cellName = cells[j].dataset.th.trim();
                    row_obj[cellName] = endText(cells[j]).trim();
                    if (row_obj[cellName].includes("&nbsp")) {
                        row_obj[cellName] = row_obj[cellName].split('&')[0].trim();
                    }
                }
            } catch(err) {
                console.log(err)
            }
        }
        rows.push(row_obj);
        console.log(row_obj);
    }    
}

// The part where everything about the original schedule is formatted and stored
try {
    // Make a button to activate the table or deactivate it
    let button = document.createElement('span');
    let cell = document.createElement('td');
    button.classList.add("BUTTON_LINK");
    button.style.cursor = "pointer";
    // The saving button
    let save = document.createElement('span');
    save.style.cursor = "pointer";
    save.innerHTML = `<i class="fa fa-save" style="color: Black; font-size: 20px;"></i>`;
    let save_td = document.createElement('td');
    // the section button
    let sec = document.createElement('td');
    let sec_span = document.createElement('span');
    let sec_inp = document.createElement('input');
    sec_inp.setAttribute("type", "checkbox");
    sec_inp.setAttribute("id", "sec");
    sec_inp.setAttribute("name", "sec");
    let sec_label = document.createElement('label');
    sec_label.setAttribute("for", "sec");
    sec_label.innerHTML = "إظهار الشعب";
    sec_span.appendChild(sec_inp);
    sec_span.appendChild(sec_label);
    sec.appendChild(sec_span);
    sec.style.paddingRight = "10px";
    sec.style.whiteSpace = "nowrap";

    // Remember the last choice
    if (on) {
        button.style.backgroundColor = "firebrick";
        button.innerHTML = "الجدول&nbspالاصلي";
        originalTableNode.style.display = 'none';
        save.style.display = null;
        sec.style.display = null;

        if (newTableNode) {
            newTableNode.style.display = null;
        } else {
            getTableInfo(row1);
            getTableInfo(row2);
            // console.log(rows);
            getNewTable();
            appendTable();
        }
    } else {
        // button.style.backgroundColor = "rgb(1, 130, 165)";
        button.innerHTML = "نظم&nbspالجدول";
        save.style.display = 'none';
        sec.style.display = 'none';
        if (newTableNode){
            newTableNode.style.display = 'none';
        }
    }

    // Append the button to the DOM
    cell.appendChild(button);
    save_td.appendChild(save);
    document.getElementById("scheduleFrm:printLink").parentElement.parentElement.appendChild(cell);
    document.getElementById("scheduleFrm:printLink").parentElement.parentElement.appendChild(save_td);
    document.getElementById("scheduleFrm:printLink").parentElement.parentElement.appendChild(sec);

    button.onclick = function() {
        if (on) {
            on = false;
            button.style.backgroundColor = null;
            button.innerHTML = "نظم&nbspالجدول";
            save.style.display = 'none';
            sec.style.display = 'none';
            originalTableNode.style.display = null;
            newTableNode.style.display = 'none';
        } else {
            on = true;
            button.style.backgroundColor = "firebrick";
            button.innerHTML = "الجدول&nbspالاصلي";
            save.style.display = null;
            sec.style.display = null;
            // Hide the original table
            originalTableNode.style.display = 'none';
            if (newTableNode) {
                newTableNode.style.display = null;
            } else {
                if (rows.length == 0) {
                    getTableInfo(row1);
                    getTableInfo(row2);
                }
                getNewTable();
                appendTable();
            }
        }
    }

    sec_inp.onchange = function() {
        if (sec_inp.checked){
            sec_is_checked = true;
        } else {
            sec_is_checked = false;
        }
        let old = document.getElementById('newTable');
        old.remove();
        appendTable();
    }

    // Printing the schedule
    function Popup(data)
    {
        var mywindow = window.open('', 'my div', 'height=800,width=1200');
        mywindow.document.write('<html><head><title></title>');
        /*optional stylesheet*/ //mywindow.document.write('<link rel="stylesheet" href="main.css" type="text/css" />');
        mywindow.document.write('</head><body style="direction:rtl;"><pre>');
        mywindow.document.write(data);
        mywindow.document.write('</pre></body></html>');
        mywindow.document.close();
        mywindow.print();
        return true;
    }

    save.onclick = function() {
        let wrap = document.createElement('div');
        wrap.appendChild(newTableNode.cloneNode(true));
        Popup(wrap.innerHTML);
    }
} catch(err) {
    console.log(err);
}

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['الوقت'];

                function value(t) {
                    // Give a numerical value for the time of the day the lecture is at
                    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;
                }

                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)});
                    // Assigining a color to each subject
                    if (!(rows[i]['اسم المقرر'] in subject_colors)){
                        subject_colors[rows[i]['اسم المقرر']] = colors[color_index];
                        color_index++;
                    }
                }
            }
        }

        // Sort the lectures according to their time values
        for (i in newTable) {
            newTable[i].sort(function(a, b) {
                return a.value - b.value;
              });
        }

        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 the breaks between lectures
        for (d = 0; d < days.length; d++) {
            // New deep copy for day lectures
            let edited_day = JSON.parse(JSON.stringify(newTable[days[d]]));
            let uni_day = newTable[days[d]];
            // Skip value is how many indexes to skip due to previously added breaks
            let skip = 0;
            //console.log("lectures of a day",uni_day, uni_day.length);
            for (l = 0; l < uni_day.length - 1; l++) {
                let difference = uni_day[l+1].value - uni_day[l].value;
                // console.log(`the difference between ${uni_day[l+1].subject} and ${uni_day[l].subject}`, difference);
                if (difference > 60) {
                    let break_obj = {subject: null, activity: "break", time: null, place: null, value: difference - 60};
                    edited_day = insert_after(break_obj, edited_day, l+skip);
                    skip++;
                }
            }
            newTable[days[d]] = edited_day;
        }
        // console.log(newTable);
        // console.log(subject_colors);
        // console.log(newTable);
    } catch(err) {
        console.log(err);
    }
}


// Append the new table info to the DOM
function appendTable() {
    // Creating the table with its attributes and children
    let table = document.createElement('table');
    table.id = "newTable";
    table.classList.add('rowFlow');
    table.width = "100%";
    table.cellPadding = '0';
    table.cellPadding = '0';
    table.border = '1';
    originalTableNode.insertAdjacentElement('afterend', table);

    let thead = document.createElement('thead');
    let tbody = document.createElement('tbody')
    table.appendChild(thead);
    table.appendChild(tbody);

    // Append days as table headers
    for(i in days) {
        let th = document.createElement('th');
        th.innerHTML = days[i];
        th.classList.add('HEADING');
        th.scope = "col";
        thead.appendChild(th);
    }

    function maxDayLength(obj) {
        // Returns the highest number of lictures in one day
        let max;
        for (i in obj) {
            if (obj[i].length > max) {
                max = obj[i].length;
            } else if (!max) {
                max = obj[i].length;
            } else {
                continue
            }
        }
        return max;
    }

    const maxLength = maxDayLength(newTable);

    // append empty cells as many as the number of lectures during the busiest day
    for (let i = 0; i < maxLength; i++) {
        let tr = document.createElement('tr');
        tbody.appendChild(tr);
        for (j in days) {
            let td = document.createElement('td');
            tr.appendChild(td);
        }
    }

    // trs are table rows
    let trs = tbody.children;
    for (i in days) {
        // For each day of the weekdays get the info of that day
        let currentDay = newTable[days[i]];
        
        // For each lecture in that day
        for (j in currentDay) {
            // Add it as a break if it is
            if (currentDay[j].activity == "break") {
                let hrs = currentDay[j].value/60;
                let text;
                let color = "Grey";
                if (hrs > 10){
                    trs[j].children[i].innerHTML = `<strong style="color:${color}">&nbsp;&nbsp;&nbsp;&nbsp;${currentDay[j].value/60} ساعة راحة</strong>`;
                } else if (hrs > 2) {
                    trs[j].children[i].innerHTML = `<strong style="color:${color}">&nbsp;&nbsp;&nbsp;&nbsp;${currentDay[j].value/60} ساعات راحة</strong>`;
                } else if (hrs == 2) {
                    trs[j].children[i].innerHTML = `<strong style="color:${color}">&nbsp;&nbsp;&nbsp;&nbsp;ساعتين راحة</strong>`;
                } else if (hrs == 1) {
                    trs[j].children[i].innerHTML = `<strong style="color:${color}">&nbsp;&nbsp;&nbsp;&nbsp;ساعة راحة</strong>`;
                }
                continue;
            }
            // Insert the info in the following way
            if (sec_is_checked) {
                trs[j].children[i].innerHTML = `<strong style="color:Black">${currentDay[j].subject}</strong> ${currentDay[j].activity}<br>
                                                الشعبة: ${currentDay[j].section}<br>
                                                ${currentDay[j].time}<br>
                                                القاعة: ${currentDay[j].place}`;
            } else {
                trs[j].children[i].innerHTML = `<strong style="color:Black">${currentDay[j].subject}</strong> ${currentDay[j].activity}<br>
                                                ${currentDay[j].time}<br>
                                                القاعة: ${currentDay[j].place}`;
            }
        }
    }
    // To make this new node global
    newTableNode = table;
}