/* * Online study plan agreement generator * * version: 0.5 * authors: Daniel Tenbrinck * Shreya Rajesh More * * date: 21.10.2023 */ // enable debugging messages var debug = true // define a global array to keep track of the number of rows - we initialize with two rows as headings and one data row var number_of_rows = [3, 3, 3, 3, 3, 3, 3]; // define the relevant tables and their identifiers var module_groups_data = []; module_groups_data.push(['core', myData_core]); module_groups_data.push(['major', myData_major]); module_groups_data.push(['minor', myData_minor]); module_groups_data.push(['app', myData_app]); module_groups_data.push(['techqual', myData_techqual]); module_groups_data.push(['seminar', null]); module_groups_data.push(['thesis', null]); //////////////////////////////////// // Called when document is loaded // //////////////////////////////////// $(document).ready(function() { // create an event listener that changes the semesters based on a change in the chosen first semester document.getElementById("sem_first").addEventListener("change", function() { // console output for debugging if (debug) { console.log("Selection for first semester changed. Resetting all tables.") } // reset tables in form reconfigureTables(); }); // iterate over all defined tables, populate the first row and add functionality to buttons for (let i = 0; i < module_groups_data.length; i++) { // console output for debugging if (debug) { console.log("--- Populating fields for table " + module_groups_data[i][0] + " and configuring buttons.") } ////////// POPULATE EXISTING ROWS // populate dropdown element for semester choice (winter/summer semester) populateDropDown(document.getElementById("sem_" + module_groups_data[i][0]), getUniqueValues(myData_Sem, 0)); // populate dropdown element for ects choice if (module_groups_data[i][0] != 'thesis' && module_groups_data[i][0] != 'seminar') { populateDropDown(document.getElementById("selectStyle_ects_" + module_groups_data[i][0]), ['Make a selection', '2.5', '5', '7.5', '10', '12.5', '15']); } // populate dropdown element for module group choice if (module_groups_data[i][0] == 'major' || module_groups_data[i][0] == 'minor') { populateDropDown(document.getElementById("selectStyle_mod_" + module_groups_data[i][0]), getUniqueValues(myData_major, 1)); } else if (module_groups_data[i][0] == 'app') { populateDropDown(document.getElementById("selectStyle_mod_" + module_groups_data[i][0]), getUniqueValues(myData_app, 1)); } //////// CONFIGURE BUTTONS // define functionality for ADD button in the current table $('#add_' + module_groups_data[i][0]).click(function() { // add a new row to the table and increase row counter addTableRow(i, module_groups_data[i], ++number_of_rows[i]); // User output for debugging if (debug) { console.log("This table now has " + number_of_rows[i] + " rows."); } }); ///////// CONFIGURE EVENT LISTENERS // configure event listeners for selection elements configureEventListeners(i, module_groups_data[i], 3, 3); } }); /////// Returns a specified row element for a given table id function getTableRow(table_id, row_number) { // get the last row of table return $(table_id).find("tbody").find("tr")[row_number - 1]; } /////// Returns last row element for a given table id function getLastTableRow(table_id) { // get the table body $tableBody = $(table_id).find("tbody"); // get the last row of table return $tableBody.find("tr:last"); } /////// Returns first row element for a given table id function getFirstTableRow(table_id) { // get the table body $tableBody = $(table_id).find("tbody"); // get the last row of table return $tableBody.find("tr:first"); } ////// Configures events listeners for changes in certain selection fields in a table row function configureEventListeners(table_number, module_data, row_number, row_id) { // generate the table id let table_id = '#table_data_' + module_data[0]; // get present row of table let $tableRow = getTableRow(table_id, row_number); // console output for debugging if (debug) { console.log("Configuring event listener for selection field " + $tableRow.children[0].children[0].id + " for changing the semester.") } // create an event listener that changes the available modules and available semester numbers based on a change in the chosen semester $tableRow.children[0].children[0].addEventListener("change", function() { //table_id = '#table_data_' + module_data[0]; // needed due to some weird local/global variable scope problem configureDropdownsPerRow(table_number, table_id, module_data[1], row_id, true); }); if (table_id == '#table_data_major' || table_id == "#table_data_minor" || table_id == "#table_data_app") { // create an event listener that changes the available modules based on a change in the chosen module group (if dropdown exists) $tableRow.children[2].children[0].addEventListener("change", function() { configureDropdownsPerRow(table_number, table_id, module_data[1], row_id, false); }); // create an event listener that changes the ECTS field on a change in the chosen module field $tableRow.children[3].children[0].addEventListener("change", function() { let semester_choice = $tableRow.children[0].children[0].value; // get module group choice let module_group_choice = $tableRow.children[2].children[0].value; // get module selection element (4th field) let module_choice = $tableRow.children[3].children[0].value; // set filter array accordingly let filterAsArray = [semester_choice, module_group_choice, module_choice]; const filteredArray = filterArray(module_data[1], filterAsArray); const uniqueList = getUniqueValues(filteredArray, filterAsArray.length); $tableRow.children[4].children[0].value = uniqueList[0]; }); } else if (table_id == '#table_data_core' || table_id == "#table_data_techqual") { // create an event listener that changes the ECTS field on a change in the chosen module field $tableRow.children[2].children[0].addEventListener("change", function() { // get semester selection let semester_choice = $tableRow.children[0].children[0].value; // get module selection (3th field) let module_choice = $tableRow.children[2].children[0].value; // set filter array accordingly let filterAsArray = [semester_choice, module_choice]; const filteredArray = filterArray(module_data[1], filterAsArray); const uniqueList = getUniqueValues(filteredArray, filterAsArray.length); $tableRow.children[3].children[0].value = uniqueList[0]; }); } // create an event listener that changes the module selection field to a text field if 'Other' is selected if (table_id != '#table_data_seminar' && table_id != "#table_data_thesis") { var $selectField; if (table_id == '#table_data_core' || table_id == "#table_data_techqual") { $selectField = $tableRow.children[2]; } else { $selectField = $tableRow.children[3]; } $selectField.addEventListener("change", function() { if (table_id == '#table_data_core' || table_id == "#table_data_techqual") { $selectField = $tableRow.children[2]; } else { $selectField = $tableRow.children[3]; } if ($selectField.children[0].value == "Other") { //$selectField.children[0].replaceWith(''); $($selectField.children[0]).replaceWith(decodeURI('')); } }); // define functionality for REMOVE button in the current table elemEventHandler = function() { if (number_of_rows[table_number] > 3) { // User output for debugging if (debug) { console.log("Removing row " + (row_id + 2) + " of table " + module_data[0] + "."); } //$('#remove_' + module_data[0] + '_' + row_id).parent().parent().remove(); $(this).parent().parent().remove(); // reduce the row number of all subsequent elements and remove buttons for (laterRow = row_id + 1; laterRow <= number_of_rows[table_number]; laterRow++) { // get table row let curTableRow = getTableRowByID(table_number, table_id, laterRow); // adapt row number in id of this row let newRow = laterRow - 1; let newId = table_id + "_row_" + newRow; curTableRow.id = newId.slice(1); // adapt row number in remove button of this row curTableRow.lastElementChild.children[0].id = curTableRow.lastElementChild.children[0].id.slice(0, -1) + newRow; } --number_of_rows[table_number]; } } // add remove functionality to button $('#remove_' + module_data[0] + '_' + row_id).on('click', elemEventHandler); } } function getTableRowByID(table_number, table_id, row_id) { //$(table_id).find("tbody").children[row_number].remove(); pattern = new RegExp("_" + row_id + "$") for (row = 0; row < number_of_rows[table_number]; row++) { $tableRow = $(table_id).find("tbody")[0].rows[row]; if ($tableRow.id.search(pattern) != -1) { return $tableRow } } } /////// Adds a new row to the table by cloning the last row function addTableRow(table_number, group_data, row_number) { // generate the table id table_id = 'table_data_' + group_data[0]; // get the table body via its id $tableBody = $(table_id).find("tbody"); // get the last table row $trLast = getLastTableRow('#' + table_id) //getFirstTableRow(table_id); // get last row number via regular expression lastRowID = Number($trLast[0].id.match(/\d+$/)[0]) + 1; // generate a table row based on the type of module group // TODO: ugly implemented! if (group_data[0] == 'core' || group_data[0] == 'techqual') { $tableBody.append( '' + '' + '' + '' + '' + '' + '' ); } else if (group_data[0] == 'major' || group_data[0] == 'minor') { $tableBody.append( '' + ' ' + '' + '' + ' ' + '' + '' + '' ); } else { $tableBody.append( '' + ' ' + '' + '' + ' ' + '' + '' + '' ); } // configure event listeners for the new table row configureEventListeners(table_number, group_data, row_number, lastRowID); } // Checks if all mandatory fields are completed // ToDo: Put in all fields! function validateForm() { let a = document.forms["studyplan"]["fname"].value; if (a == "") { alert("First Name must be filled out"); return false; } let b = document.forms["studyplan"]["name"].value; if (b == "") { alert("Name must be filled out"); return false; } } ////// Fills in data in the selection dropdown fields in a given table row function configureDropdownsPerRow(table_number, table_id, module_group_data, row_id, change_semester_numbers) { // get current value of semester options for the specified row, i.e., summer or winter semester const $table_row = getTableRowByID(table_number, table_id, row_id) const semester_choice = $table_row.children[0].children[0].value; // initialize variables var filterArray = []; var module_dropdown_element = null; // check if we process the core or technical qualifications module groups, which have one field less if (table_id == '#table_data_major' || table_id == "#table_data_minor" || table_id == "#table_data_app") { // get module group choice module_group_choice = $table_row.children[2].children[0].value; // set filter array accordingly filterArray = [semester_choice, module_group_choice]; // get module selection element (4th field) module_dropdown_element = $table_row.children[3].children[0]; // get ects selection element (5th element) ects_dropdown_element = $table_row.children[4].children[0]; // total_ects = 0 // for (i = 1; $table_row.length; i++) { // total_ects = total_ects + ects_dropdown_element // //console.log(total_ects) // } } else if (table_id == '#table_data_core' || table_id == "#table_data_techqual") { // set filter array accordingly filterArray = [semester_choice]; // get module selection element (3rd field) module_dropdown_element = $table_row.children[2].children[0]; } // check if we process the seminar or thesis module groups, which have one field less if (table_id != '#table_data_seminar' && table_id != "#table_data_thesis") { // populate selection dropdown field for modules makeDropDown(module_group_data, filterArray, module_dropdown_element); } // check if semester numbers have to be adapted if (change_semester_numbers) { // get choice of the first semester field at the top of the form const first_semester = document.getElementById("sem_first").value; // get the semester selection dropdown element for this row const semester_dropdown_element = $table_row.children[1].children[0]; // populate selection dropdown field for semester numbers makeDropDown(myData_Sem, [first_semester, semester_choice], semester_dropdown_element); } } ////// Resets all table data. Is only called when the first semester field is changed function reconfigureTables() { // iterate over all defined tables for (let i = 0; i < module_groups_data.length; i++) { // configure event listeners for selection elements table_id = '#table_data_' + module_groups_data[i][0]; // iterate over all rows in the current table for (let j = 3; j <= number_of_rows[i]; j++) { // get the row element row_id = $(table_id).find("tbody").find("tr")[j - 1].id.search(/\d+$/); // populate the selection dropdown fields for this row configureDropdownsPerRow(i, table_id, module_groups_data[i][1], row_id, true); } } } function getUniqueValues(data, index) { const uniqueOptions = new Set(); data.forEach(r => uniqueOptions.add(r[index])); return [...uniqueOptions]; } function populateDropDown(el, listAsArray) { // console output for debugging if (debug) { console.log("Populating field " + el.id + " with the following data: " + listAsArray) } el.innerHTML = ""; listAsArray.forEach(item => { const option = document.createElement("option"); option.textContent = item; el.appendChild(option); }); } function makeDropDown(selectionList, filtersAsArray, targetElement) { const filteredArray = filterArray(selectionList, filtersAsArray); const uniqueList = getUniqueValues(filteredArray, filtersAsArray.length); populateDropDown(targetElement, uniqueList); } function filterArray(data, filtersAsArray) { return data.filter(r => filtersAsArray.every((item, i) => item === r[i])); } ///////////////////////////////////////////////////////////////////////////////// // function CheckEcts(table_number, table_id, module_group_data,row_id){ // if (table_id != '#table_data_core' && table_id != "#table_data_techqual") { // }}