Skip to content
Snippets Groups Projects
suivi.js 21.29 KiB
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Handle add/remove competency links.
 *
 * @module     format_iena/suivi
 * @package    format_iena
 * @copyright  2021 Myriam Delaruelle
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
define(['jquery', 'core/ajax', 'core/templates', 'core/str'],
       function($, ajax, templates, str) {
       	var all_selected=false;
       	var data=[];

       	return{
       		
       		registerFilters:function(){
       			
	    		$("#group-select").on('change', function(e){
	    			changeGroup();
	    		});
	    		
       		},
       		
       		registerSubmit:function(infos){
       			data=infos;
       			$("#id_submit_iena").on('click', function(e){
	    			triggerAction(e);
	    		});
	    		$("#section-select").on('change', function(){
	    			changeSection();
	    		});
	    		$("#filter-select").on('change', function(){
	    			changeCompletion();
	    		});
	    		$("#symbol-select").on('change', function(){
	    			changeCompletion();
	    		});
                $('.dropdown-menu-form').on('click', function (e) {
                   e.stopPropagation();
                });
               
	    		
	    		
                //registerSelectAllActivitiesFilter();
       		}, 

       		//Evenement pour le selectall : créé une seule fois au chargement de la page
		    registerSelectAllActivitiesFilter:function(){
		        $('.selectallactivities').click(function() {
		            if ($(".selectallactivities").is(':checked')) {
		                checkAllActivitiesFilter();
		                displayActivities();
		            } else {
		                $('.option').prop('checked', false);
		                var message=str.get_string('selectedActivities', 'format_iena');
		                $.when(message).done(function(localizedEditString) {
		                    $(".dropdown-text").html('0 '+localizedEditString);
		                }); 
		                $(".select-text").html(' Select');
		                displayActivities();
		            }
		        });
		        //initActivityFilter();
		    },
		    registerSelectAllGroupsFilter:function(){
		    	checkAllGroupsFilter();
		    	$('.selectallgroups').click(function() {
		            if ($(".selectallgroups").is(':checked')) {
		                checkAllGroupsFilter();
		            } else {
		                $('.group-option').prop('checked', false);
		                displayTotalGroupsFilter(); 
		            	
		            }
		            changeGroup();
		        });
		    },
		    initTable:function(){
		    	initActivityFilter(false);
		    	displayTotalActivitiesFilter(false);
		    	displayTotalGroupsFilter(false);
        		displayActivities(false);
        		initGroupFilter(false);
        		registerGroupFilter();
        		changeSection(false);
        		reloadTable(data);

		    }
       		

       		
       		
       	}

    function initHeaders(){

    	var nb_counts=$(".th-rotate").length;

		$(".th-rotate").each(function(index, element){

			$( element ).css("zIndex",nb_counts-index);
		})
    }

    function getCompleteUrl(){
    	url=window.location.search;
    	urlParams = new URLSearchParams(url);
    	courseid=urlParams.get('courseid');
    	groupid=$("#group-select").val();
    	sectionid=$("#section-select").val();
    	filter=$("#symbol-select").val() + $("#filter-select").val();
    	completeUrl='suivi_unit.php?courseid='+courseid;
    	if(sectionid){
    		completeUrl+='&sectionid='+sectionid;
    	}
    	if(groupid){
    		completeUrl+="&groupid="+groupid;
    	}
    	if(filter){
    		completeUrl+="&filter="+filter;
    	}
    	return completeUrl;
    }

    function changeGroup(){
    	var completeUrl=getCompleteUrl();
    	var groupscheckboxes= $('input[name="groupoptions[]"]:checked');
    	var groupsid=[];
    	for (var i = 0; i < groupscheckboxes.length; i++) {
    		groupsid.push(groupscheckboxes[i].value);
    	}
    	loadMessage("loading");
    	if(groupsid.length==0){
    		groupsid.push(-2);
    	}
    	$.ajax({ url: completeUrl,
        	data: {action: 'fetchgroups', groupsid:groupsid},
        	type: 'post',
        	success: function(request) { 
        		data=calcPercentage(JSON.parse(request));
        		//initGroupFilter();
        		changeSection();
        		if(data.students.length<1000){
        			
        			localStorage.setItem("groups",request);
        		}
        		
        		displayTotalGroupsFilter(false);
			}
		});
    }

  
    function changeCompletion(changefilter=true){
    	symbol=$("#symbol-select").val();
    	filter=$("#filter-select").val();
    	data.count_results=0;
    	for(var i=0; i<data.students.length; i++){
    		if(data.display_groups==1){
    			data.students[i].display_groups=true;
    		}

    		
    		if(symbol=="<"){
    			if(data.students[i].percentage < filter){
    				data.count_results++;
    				data.students[i].visible=true;
    			}
    			else{
					data.students[i].visible=false;
    			}
    		}
    		else if(symbol==">"){
    			if(data.students[i].percentage > filter){
    				data.count_results++;
    				data.students[i].visible=true;
    			}
    			else{
					data.students[i].visible=false;
    			}
    		}
    		else if(symbol=="≤"){
    			if(data.students[i].percentage <= filter){
    				data.count_results++;
    				data.students[i].visible=true;
    			}
    			else{
					data.students[i].visible=false;
    			}
    		}
    		else if(symbol == "≥"){
    			if(data.students[i].percentage >= filter){
    				data.count_results++;
    				data.students[i].visible=true;
    			}
    			else{
					data.students[i].visible=false;
    			}
    		}
    		else{
    			if(data.students[i].percentage == filter){
    				data.count_results++;
    				data.students[i].visible=true;
    			}
    			else{
					data.students[i].visible=false;
    			}
    		}
    		
    	}
    	if(changefilter==true){
    		reloadTable(data);
    	}
    	
    }

    //on va devoir calculer le pourcentage, check la completion et reload la table à chaque fois

    function changeSection(changefilter=true){
    	loadMessage("loading");
    	sectionid=$("#section-select").val();
    	data.count_results=0;
    	for(var i = 0; i<data.modules.length; i++){
    		if(data.modules[i].section == sectionid || sectionid == 0){
    			data.modules[i].visible=true;
    			data.count_results++;
    			for(var j = 0; j<data.students.length; j++){
    				var prog=data.students[j].progress.find(progress => progress.idmodule === data.modules[i].id);
					prog.visible=true;
    			}
    		}
    		else{
    			data.modules[i].visible=false;
    			for(var j = 0; j<data.students.length; j++){
    				data.students[j].progress.find(progress => progress.idmodule === data.modules[i].id).visible=false;
    			}
    		}
    	}
    	
    	if(data.count_results==0 && changefilter ==true){
    		reloadTable(data);
    	}
    	else{
    		data=calcPercentage(data);
    		changeCompletion(changefilter);
    	}
        changeActivitiesDropdown(data.modules);
    }

    //Charge les activités dynamiquement en fonction de la section choisie
    function changeActivitiesDropdown(modules){
        //html='<li><label class="checkbox"><input type="checkbox" class="selectall" value="all" checked>Toutes les activités</label></li><li class="divider"></li>';
        html="";
        for (var i = 0; i<modules.length;i++){
            if(modules[i].visible){
                html+='<li><label class="checkbox"><input type="checkbox" name="options[]" checked value='+modules[i].id+' class="option justone-activity">'+modules[i].displayname+'</label></li>';

            }
        }
        $(".iena-dynamic-activities").html(html);
        registerActivityFilter();
        checkAllActivitiesFilter();
    }

    function displayActivities(changefilter=true){
        var arrayActivitiesID=[];
        var activitiesToStore=[];
        var activities = $('input[name="options[]"]');
        for(var i=0; i<activities.length;i++){

            prog=data.modules.find(element => element.id === activities[i].value);
            if(activities[i].checked){
                prog.visible=true;
                for(var j = 0; j<data.students.length; j++){
                    data.students[j].progress.find(progress => progress.idmodule === activities[i].value).visible=true;
                }
                activitiesToStore.push(activities[i].value);
            }
            else{
                prog.visible=false;
                for(var j = 0; j<data.students.length; j++){
                    data.students[j].progress.find(progress => progress.idmodule === activities[i].value).visible=false;
                }
            }
           
          
        }
        if(data.students.length<1000){
        	localStorage.setItem("activities",JSON.stringify(activitiesToStore));
        }
        
        if(changefilter==true){
        	reloadTable(data);
        }
        
    }



    function loadMessage(type){
    	if(type=="loading"){
    		var message = str.get_string('loadingResults', 'format_iena');
	    	
    	}
    	else if(type=="error"){
			var message = str.get_string('errorLoadingResults', 'format_iena');
    	}

    	$.when(message).done(function(localizedEditString) {
		    $("#partial-table").html("<div class='alert alert-primary' role='alert'>"+localizedEditString+"</div>");
		});	
    }

    //Reload table with nex parameters.
    function reloadTable(params){
    	url=getCompleteUrl();
    	templates.render('format_iena/suivi-table', params)
     	.done(function(html, js){
     		 $("#partial-table").html(html);
     		 templates.runTemplateJS(js);
     		 window.history.pushState('suivi',"", url);
     		 initHeaders();
             
     	})
        .fail(function(){
        	loadMessage("error");
        });	
    }




	function getSelectedStudents(){
		var selectedChecks=$("#table-body input:checked");
		var students=[];
		for(var i=0; i < selectedChecks.length; i++){
			
			students.push(selectedChecks[i].value);
		}
	
		return students;

	}

	//Si on veut envoyer un message à tout le monde on ajoute deux champs cachés :
	//La liste des étudiants (array d'id)
	//L'url de retour pour revenir sur le tableau de suivi
	function triggerAction(e){
		value=$("#select-actions-suivi-iena").val();
		
		if(value=="msg"){
			url=window.location.search;
    		urlParams = new URLSearchParams(url);
    		courseid=urlParams.get('courseid');
			students=getSelectedStudents();
			var form=$("#form_send_message_iena");
			form.attr("action", "send_message.php?courseid="+courseid);
			var field=$("<input></input>");
			field.attr("type", "hidden");
        	field.attr("name", "students");
        	field.attr("value", students.toString());
        	form.append(field);
        	var fieldUrl=$("<input></input>");
			fieldUrl.attr("type", "hidden");
        	fieldUrl.attr("name", "back_url");
        	fieldUrl.attr("value", url);
        	form.append(fieldUrl);
        	$(document.body).append(form);
    		form.submit();
		}
		else if(value=="download"){
			table_download(data);
		}
	}


	function slug_it(str) {
		return str.toString().toLowerCase().trim()
		.replace(/\s+/g, '-')           /* Replace spaces with - */
		.replace(/&/g, '-and-')         /* Replace & with 'and' */
		.replace(/[^\w\-]+/g, '')       /* Remove all non-word chars */
		.replace(/\-\-+/g, '-');        /* Replace multiple - with single - */
	}


	function padLeft(date){
		
		return String(date).length > 1? date : '0'+date ;
	}

	


	function table_download() {
		
		var students=getSelectedStudents();
		var csvContent = "data:text/csv;charset=utf-8,";
		var head = ['Moodle_id', 'Prénom', 'Nom', 'Groupe', 'Complétion (en %)'];
		data.active_section_id=$("#section-select").val();
		for ( var m = 0; m < data.modules.length; m++ ) {
			if ( data.active_section_id != data.modules[m].section && data.active_section_id != 0 ) {
				continue;
			}
			head.push('"'+data.modules[m].displayname.replace(',', '')+'"');
		}


		csvContent += head.join(",");
		csvContent += "\n";
		
		/* Pour chaque étudiant */
		
		for ( var s = 0; s < data.students.length; s++ ) {
			if(students.includes(data.students[s].id)){
				var arr_cpl = [];

				/* Pour chaque activité du cours */
				var activities_nbr = 0;
				var done_activities_nbr = 0;
				

				for ( var mod = 0; mod < data.modules.length; mod++ ) {
					/* Si le module n'est pas dans la section actuellement filtrée */
					
					if ( data.active_section_id != data.modules[mod].section && data.active_section_id != 0 ) {
						continue;
					}
					var stud_progress = data.students[s].progress
					/* Si l'étudiant n'a pas de progres*/
					if ( stud_progress.length == 0 ) {
						arr_cpl.push(0);
					} else {
						// var prog = 0;
						/* Pour chaque trace d'achèvement */
						var cpl = 0;
						for (var i =0; i<stud_progress.length; i++) {
							
							/* Quand l'index de progression correspond à l'id du module */
							if ( data.modules[mod].id == stud_progress[i].idmodule ) {
								cpl = stud_progress[i].completionstate;
								if (cpl == 3) {
									cpl = 0.5;
									cpl = '"' + cpl.toLocaleString() + '"';
								}
							}
						}
						
						if (cpl == 1 || cpl == 2) {
							done_activities_nbr++;
						}
						arr_cpl.push(cpl);
					}
					activities_nbr++;
				}
				var perc = Math.round(100 * 100 * done_activities_nbr / activities_nbr) / 100;
				var groups = '"';
				active_group_id=$('#group-select').val();
				data.active_group_name=$('#group-select').find('option:selected').html()

				if ( data.active_group_name != "" && active_group_id != 0 ) {
					groups += data.active_group_name.replace('"', '');
				} else {
					groups += data.students[s].groups.replace('"', '');
				}
				groups += '"';
				var arr = [
				data.students[s].id,
				data.students[s].firstname,
				data.students[s].lastname,
				groups,
				'"'+perc.toLocaleString()+'"',
				arr_cpl
				];
				var dataString = arr.join(",");
				csvContent += dataString + "\n";
			}
		}
		
		var encodedUri = encodeURI(csvContent);

		var section_name = data.active_section_id;
		if ( section_name == 0 ) {
			section_name = "cours-complet";
		} else {
			section_name = slug_it($('#section-select').find('option:selected').html()).substring(0, 20);
		}
		var d = new Date;
		month = d.getMonth()+1;


		date = d.getFullYear() +"."+ padLeft(month) +"."+ padLeft(d.getDate()) +"-"+ padLeft(d.getHours()) +"."+ padLeft(d.getMinutes()) +"."+ padLeft(d.getSeconds());
		
		var link = document.createElement("a");
		link.setAttribute("href", encodedUri);
		link.setAttribute("download", "report-"+section_name+"-"+ date +".csv");
		document.body.appendChild(link);
		link.click();
		document.body.removeChild(link); 
	}


	//Pour chaque module non caché, on va regarder pour chaque étudiant 
	function calcPercentage(data){
		for (var i = 0; i < data.students.length; i++) {
			data.students[i].percentage=0;
			var done=0;
			var nb_modules=0;
			for(var j=0; j < data.students[i].progress.length;j++){
				if(data.modules.find(module => module.id === data.students[i].progress[j].idmodule).visible){
					nb_modules++;
					if(data.students[i].progress[j].completionstate == 1 || data.students[i].progress[j].completionstate ==2){
						done++;
					}
				}
			}
			data.students[i].percentage=Math.floor(100 * done / nb_modules);
		}
		return data;
	}


    //On va recharger dynamiquement les options donc on doit recréer les événements à chaque fois qu'on change de section
    function registerActivityFilter(){
        $("input[type='checkbox'].justone-activity").on('click', function(e){
            e.stopPropagation();
             var a = $("input[type='checkbox'].justone-activity");
            if(a.length == a.filter(":checked").length){
                $('.selectallactivities').prop('checked', true);
                $(".select-text").html(' Deselect');
            }
            else {

                $('.selectallactivities').prop('checked', false);
                $(".select-text").html(' Select');
            }
            displayTotalActivitiesFilter();
            displayActivities();
        });

        
    }

    //Update activities filter label
    function displayTotalActivitiesFilter(){
        var total = $('input[name="options[]"]:checked').length;
        if(total == $('input[name="options[]"]').length){
            var message=str.get_string('allActivities', 'format_iena');
            $.when(message).done(function(localizedEditString) {
                $(".dropdown-text").html(localizedEditString);
            }); 
        }
        else{
            var message=str.get_string('selectedActivities', 'format_iena');
            $.when(message).done(function(localizedEditString) {
                $(".dropdown-text").html(total + ' '+localizedEditString);
            }); 
        }
    }
  
    //Stocke le filtre des activités en localStorage pour ne pas avoir 50 id dans l'url
    //On fait bien attention à rétablir cocher le selectall si toutes les activités sont bien cochées
    function initActivityFilter(){
        if(localStorage.activities){
            var checkedActivities=JSON.parse(localStorage.activities);
            var activities=$("input[type='checkbox'].justone-activity");
            if($("input[type='checkbox'].justone-activity[value="+checkedActivities[0]+"]").length > 0){
            	if(activities.length===checkedActivities.length ){
	                $(".selectallactivities").prop("checked", true);
	                $("input[type='checkbox'].justone-activity").prop("checked", true);
	            }
	            else{
	                $(".selectallactivities").prop("checked", false);
	                for(var i=0; i<activities.length; i++){
	                    if(checkedActivities.includes(activities[i].value)){
	                        activities[i].checked=true;
	                    }
	                    else{
	                        activities[i].checked=false;
	                    }
	                }
	            }
            }
            

        }
        //displayTotalActivitiesFilter();
        //displayActivities();
    }

    //Coche toutes les activités quand on change de section
    function checkAllActivitiesFilter(){
        $('.selectallactivities').prop('checked', true);
        $('.option').prop('checked', true);
        displayTotalActivitiesFilter();
        $(".select-text").html(' Deselect');
        
    }

    function registerGroupFilter(){
        $("input[type='checkbox'].justone-group").on('click', function(e){
            e.stopPropagation();
             var a = $("input[type='checkbox'].justone-group");
            if(a.length == a.filter(":checked").length){
                $('.selectallgroups').prop('checked', true);
            }
            else {
                $('.selectallgroups').prop('checked', false);
            }
            displayTotalActivitiesFilter();
            //displayActivities();
        });

        
    }
     function initGroupFilter(){
        if(localStorage.groups){
            var checkedGroups=JSON.parse(localStorage.groups);
            var groups=$("input[type='checkbox'].justone-group");

            if($("input[type='checkbox'].justone-group[value="+checkedGroups[0]+"]").length > 0){
            	if(groups.length===checkedGroups.length ){
	                $(".selectallgroups").prop("checked", true);
	                $("input[type='checkbox'].justone-group").prop("checked", true);
	            }
	            else{
	                $(".selectallgroups").prop("checked", false);
	                for(var i=0; i<groups.length; i++){
	                    if(checkedGroups.includes(groups[i].value)){
	                        groups[i].checked=true;
	                    }
	                    else{
	                        groups[i].checked=false;
	                    }
	                }
	            }
            }
        }
        else{
        	checkAllGroupsFilter();
        }
        displayTotalActivitiesFilter();
        //displayActivities();
    }

    //Coche tous les groupes quand le select all est coché
    function checkAllGroupsFilter(){
        $('.selectallgroups').prop('checked', true);
        $('.group-option').prop('checked', true);
        //changeGroup();
        $(".select-text").html(' Deselect');
        
    }


    //Update activities filter label
    function displayTotalGroupsFilter(){
        var total = $('input[name="groupoptions[]"]:checked').length;
        if(total == $('input[name="groupoptions[]"]').length){
            var message=str.get_string('allGroups', 'format_iena');
            $.when(message).done(function(localizedEditString) {
                $(".dropdown-text-group").html(localizedEditString);
            }); 
        }
        else{
            var message=str.get_string('selectedGroups', 'format_iena');
            $.when(message).done(function(localizedEditString) {
                $(".dropdown-text-group").html(total + ' '+localizedEditString);
            }); 
        }
    }
  


  
});