/* (1) Load formations ---------------------------------------------------------*/ /* (1) Initialize list */ gstore.add('formations', []); /* (2) Get Formations */ api.call('GET formation', {}, function(rs){ // {1} If error -> abort // if( rs.error !== 0 ) return console.log('No formation found, error: '+rs.error); console.log(rs); // {2} Format UE filters // for( var i = 0 ; i < rs.formations.length ; i++ ) gstore.get.formations.push( rs.formations[i] ); }); /* (3) Get Formation label */ gstore.add('form_by_id', function(form_id){ /* (1) Abort if wrong form_id */ if( form_id == null ) return { idForm: null, labelForm: null }; /* (2.1) Find index in gstore */ var gi = gstore.get.formations.map( (data, i) => { return ( data.idForm && data.idForm == form_id ) ? i : ''; }).join(''); /* (2.2) Exit if not found */ if( isNaN(gi) ) return { idForm: null, labelForm: null }; return gstore.get.formations[gi]; }); /* (2) Load ues ---------------------------------------------------------*/ /* (1) Initialize list */ gstore.add('ues', []); /* (2) Get ues */ api.call('GET ue/', { vh: true }, function(rs){ // {1} If error -> abort // if( rs.error !== 0 )return console.log('No UE found, error: '+rs.error); console.log(rs); // {2} Store ues // gstore.get.ues = rs.ues; }); /* (2) Manage Instant Search (IS) ---------------------------------------------------------*/ /* (1) Define global timeout index */ gstore.add('is_to', null); /* (2) Define search value buffer */ gstore.add('is_buf', null); /* (3) Define instant search function */ gstore.add('is_handler', function(e){ /* (1) Remove last timeout */ if( gstore.get.is_to != null ) clearTimeout(gstore.get.is_to); /* (2) Store value in buffer */ gstore.get.is_buf = e.target.value.trim().toLowerCase(); /* (3) Launch timeout (wait 1s) before filtering */ gstore.get.is_to = setTimeout(function(){ // 1. Fetch elements var local_ptr = gstore.get.ues; var l = gstore.get.ues.length; // 2. For each element for( var e = 0 ; e < l ; e++ ){ // 2.1. Show by default var element = document.querySelector('section[data-id=\''+local_ptr[e].code+'\']'); if( !element ) continue; element.remClass('search-hidden'); // 2.2. Extract name components var code = local_ptr[e].code.trim().toLowerCase(); var label = local_ptr[e].label.trim().toLowerCase(); // 2.3. Hide if does not match var match_offset = gstore.get.is_buf.length == 0 || code.search(gstore.get.is_buf) + label.search(gstore.get.is_buf); if( match_offset <= -2 ) element.addClass('search-hidden'); } }, 250); }); /* (5) Manage instant create ---------------------------------------------------------*/ /* (1) Initialize toggle show */ gstore.add('create_card', false); /* (2) Initialize inputs */ gstore.add('create_form', '-'); gstore.add('create_label', ''); gstore.add('create_code', ''); gstore.add('create_vol', { c: '', td: '', tp: ''}); /* (3) Initialize error message */ gstore.add('create_err_valid', false); gstore.add('create_err', ''); /* (4) Define create handler */ gstore.add('ic_handler', function(){ /* (4.1) Trim text input */ gstore.get.create_label = gstore.get.create_label.trim(); gstore.get.create_code = gstore.get.create_code.trim().toUpperCase(); gstore.get.create_form = gstore.get.create_form.toString().trim(); gstore.get.create_vol.c = gstore.get.create_vol.c.toString().trim(); gstore.get.create_vol.td = gstore.get.create_vol.td.toString().trim(); gstore.get.create_vol.tp = gstore.get.create_vol.tp.toString().trim(); /* (5.4) Store values locally */ var form = gstore.get.create_form; var label = gstore.get.create_label; var code = gstore.get.create_code; var vco = gstore.get.create_vol.c; var vtd = gstore.get.create_vol.td; var vtp = gstore.get.create_vol.tp; /* (5.5) Init client-side check */ var errors = []; /* (5.5.1) Check formation */ if( isNaN(form) ) errors.push('La formation de l\'UE est manquante'); /* (5.5.2) Check label */ if( typeof label !== 'string' || label.length < 4 ) errors.push('Le label doit comprendre faire au moins 4 caractères'); /* (5.5.3) Check code */ if( !/^[A-Z0-9]{4,20}$/.test(code) ) errors.push('Le code doit comprendre de 4 à 20 lettres/chiffres'); /* (5.5.4) Check volumes */ if( vco === '' || isNaN(vco) || vco < 0 ) errors.push('Le volume horaire de cours doit être un entier positif.'); /* (5.5.5) Check TD */ if( vtd === '' || isNaN(vtd) || vtd < 0 ) errors.push('Le volume horaire de TD doit être un entier positif.'); /* (5.5.6) Check TP */ if( vtp === '' || isNaN(vtp) || vtp < 0 ) errors.push('Le volume horaire de TP doit être un entier positif.'); /* (4.4) Show first error only (for 2s) */ if( errors.length > 0 ){ gstore.get.create_err = errors[0]; return setTimeout(() => gstore.add('create_err', ''), 2000); } /* (4.5.1) Création de la requête */ var rq = { label: label, code: code, volumeCours: parseInt(vco), /*TODO*/ volumeTD: parseInt(vtd), /*TODO*/ volumeTP: parseInt(vtp), /*TODO*/ required: false, /*TODO*/ disabled: false /*TODO*/ }; // optional param if( form != -1 ) rq.defaultFormation = form; /* (4.5.2) Send request */ api.call('POST ue', rq, function(rs){ console.log(rs); /* (4.5.2.1) Manage 'already exist' error */ if( rs.error == 29 ){ gstore.get.create_err = 'Le code est déja utilisé.'; return setTimeout(() => gstore.add('create_err', ''), 2000); } /* (4.5.2.2) Manage other errors */ if( rs.error !== 0 ){ gstore.get.create_err = 'erreur ('+rs.error+') Impossible de créer l\'UE'; return setTimeout(() => gstore.add('create_err', ''), 2000); } /* (4.5.2.3) Show that user is created */ // display all is ok gstore.add('create_err_valid', true); gstore.add('create_err', 'L\'UE a été créé, elle s\'affichera au prochain rechargement'); // empty fields gstore.get.create_form = '-'; gstore.get.create_label = ''; gstore.get.create_code = ''; // gstore.get.create_h = ''; return setTimeout(() => { gstore.add('create_err', ''); gstore.add('create_err_valid', false); }, 2000); }); }); /* (6) Manage instant remove ---------------------------------------------------------*/ /* (1) Define remove handler */ gstore.add('ir_handler', function(ue_id){ /* (1) Abort if wrong ue_id */ if( ue_id == null ) return; /* (2.1) Find index in gstore */ var gi = gstore.get.ues.map( (data, i) => { return ( data.code && data.code == ue_id ) ? i : ''; }).join(''); /* (2.2) Exit if not found */ if( gi.length === 0 ) return; var local = gstore.get.ues[gi]; /* (3) Show popup */ (new Promise( (resolve, reject) => { popup.ask({ title: 'Confirmation de suppression', content: "La suppression de l'UE "+local.label+" ("+local.code+") est irréversible.

Voulez-vous lea supprimer définitivement ?", action: 'Supprimer', type: 'invalid' }, (popup_rs) => { popup_rs && resolve() }); /* (4) On pop-up confirmation */ })).then(function(){ return new Promise( (resolve, reject) => { /* (4.1) Delete UE */ api.call('DELETE ue/'+ue_id, {}, function(rs){ /* (4.1.1) Abort on error */ if( rs.error !== 0 || rs.deleted !== true ) return reject(rs.error); /* (4.1.2) Success */ resolve(); }); }); /* (5) On success */ }).then(function(){ /* remove from visible */ gstore.get.ues.splice(gi, 1); /* (6) On error */ }).catch(function(err_code){ popup.ask({ title: 'Error ('+err_code+')', content: 'La suppression a échouée. Veuillez réessayer ultérieurement.', action: 'OK', type: 'neutral' }, () => {}); }); }); /* (7) Manage instant edit ---------------------------------------------------------*/ /* (1) Init edit_mode */ gstore.add('edit_i', -1); /* (2) Initialize inputs */ gstore.add('edit_form', '-'); gstore.add('edit_label', ''); // gstore.add('edit_code', ''); gstore.add('edit_vol', { c: '', td: '', tp: ''}); /* (3) Initialize error message */ gstore.add('edit_err_valid', false); gstore.add('edit_err', ''); /* (4) Define toggle view */ gstore.add('ie_toggle', function(ue_i){ /* (4.1) Abort if wrong ue_i */ if( ue_i == null || isNaN(ue_i) || gstore.get.ues[ue_i] == null) return gstore.add('edit_i', -1); /* (4.2) Toggle current value */ var ue = gstore.get.ues[ue_i]; /* (4.3) Pre-fill edit values */ gstore.get.edit_form = ue.idForm; gstore.get.edit_label = ue.label; gstore.get.edit_code = ue.code; gstore.get.edit_vol.c = ue.volumeCours; gstore.get.edit_vol.td = ue.volumeTD; gstore.get.edit_vol.tp = ue.volumeTP; /* (4.4) Set card to edit mode */ gstore.get.edit_i = ue_i; }); /* (5) Confirm update */ gstore.add('ie_handler', function(ue_i){ /* (5.1) Abort if wrong ue_i */ if( ue_i == null || isNaN(ue_i) || gstore.get.ues[ue_i] == null) return; /* (5.2) Toggle current value */ var ue = gstore.get.ues[ue_i]; /* (5.3) Trim text input */ gstore.get.edit_label = gstore.get.edit_label.trim(); // gstore.get.edit_code = gstore.get.edit_code.toString().trim().toUpperCase(); gstore.get.edit_vol.c = gstore.get.edit_vol.c.toString().trim(); gstore.get.edit_vol.td = gstore.get.edit_vol.td.toString().trim(); gstore.get.edit_vol.tp = gstore.get.edit_vol.tp.toString().trim(); /* (5.4) Store values locally */ var form = gstore.get.edit_form; var label = gstore.get.edit_label; // var code = gstore.get.edit_code; var vco = gstore.get.edit_vol.c; var vtd = gstore.get.edit_vol.td; var vtp = gstore.get.edit_vol.tp; /* (5.5) Init client-side check */ var errors = []; /* (5.5.1) Check formation */ if( isNaN(form) ) errors.push('La formation de l\'UE est manquante'); /* (5.5.2) Check label */ if( typeof label !== 'string' || label.length < 4 ) errors.push('Le label doit comprendre faire au moins 4 caractères'); /* (5.5.3) Check code */ // if( !/^[A-Z0-9]{4,20}$/.test(code) ) // errors.push('Le code doit comprendre de 4 à 20 lettres/chiffres'); /* (5.5.4) Check volumes */ if( vco === '' || isNaN(vco) || vco < 0 ) errors.push('Le volume horaire de cours doit être un entier positif.'); /* (5.5.5) Check TD */ if( vtd === '' || isNaN(vtd) || vtd < 0 ) errors.push('Le volume horaire de TD doit être un entier positif.'); /* (5.5.6) Check TP */ if( vtp === '' || isNaN(vtp) || vtp < 0 ) errors.push('Le volume horaire de TP doit être un entier positif.'); /* (5.6) Show first error only (for 2s) */ if( errors.length > 0 ){ gstore.get.edit_err = errors[0]; return setTimeout(() => gstore.add('edit_err', ''), 2000); } /* (5.7) Création de la requête */ var rq = {}; ( label != ue.label ) && ( rq.label = label ); // ( code != ue.code ) && ( rq.code = code ); ( vco != ue.volumeCours ) && ( rq.volumeCours = parseInt(vco) ); ( vtd != ue.volumeTD ) && ( rq.volumeTD = parseInt(vtd) ); ( vtp != ue.volumeTP ) && ( rq.volumeTP = parseInt(vtp) ); ( form != ue.idForm ) && ( rq.defaultFormation = parseInt(form) ); (new Promise( (resolve, reject) => { popup.ask({ title: 'Confirmation de modification', content: `La modification de l'UE ${ue.label} (${ue.code}) est irréversible.

Voulez-vous la modifier ?`, action: 'Modifier', type: 'search' }, (popup_rs) => { popup_rs && resolve() }); /* (5.8) On pop-up confirmation */ })).then(function(){ return new Promise( (resolve, reject) => { /* (5.8.1) Update UE */ api.call(`PUT ue/${ue.code}`, rq, function(rs){ /* (5.8.1.1) Abort on error */ console.log(rq, rs.error != 0, rs.updated != true); if( rs.error != 0 || rs.updated != true ) return reject(rs.error); /* (5.8.1.2) Success */ resolve(); }); }); /* (5.9) On success */ }).then(function(){ /* (5.9.1) update VueJS element */ gstore.get.ues[ue_i].label = label; // gstore.get.ues[ue_i].code = code; gstore.get.ues[ue_i].idForm = parseInt(form); gstore.get.ues[ue_i].volumeCours = parseInt(vco); gstore.get.ues[ue_i].volumeTD = parseInt(vtd); gstore.get.ues[ue_i].volumeTP = parseInt(vtp); /* (5.9.2) Try to set the formation label */ var fi = gstore.get.formations.map( (data, i) => { return ( data.idForm && data.idForm == form ) ? i : ''; }).join(''); /* (5.9.3) Exit if not found */ if( isNaN(fi) ) return gstore.add('edit_i', -1); /* (5.9.4) If not found -> set default text */ if( !gstore.get.formations.hasOwnProperty(fi) ) gstore.get.ues[ue_i].labelForm = ''; /* (5.9.5) If found -> set formation label */ else gstore.get.ues[ue_i].labelForm = gstore.get.formations[fi].labelForm; /* (5.9.5) Remove edit mode */ gstore.add('edit_i', -1); /* (5.10) On error */ }).catch(function(err_code){ popup.ask({ title: 'Error ('+err_code+')', content: 'La modification a échouée. Veuillez réessayer ultérieurement.', action: 'OK', type: 'neutral' }, () => {}); }); }); /* (8) Manage instant admin ---------------------------------------------------------*/ /* (1) Define admin handler */ gstore.add('ia_handler', function(ue_i){ /* (1) Abort if wrong ue_i */ if( ue_i == null || isNaN(ue_i) || gstore.get.ues[ue_i] == null) return; /* (2) Toggle current value */ var local = gstore.get.ues[ue_i]; var is_disabled = local.disabled == '1' || local.disabled === true; var new_state = !is_disabled; /* (3.1) Update in database */ api.call('PUT ue/'+local.code, { disabled: new_state }, function(rs){ /* (3.1.1) Abort on error */ if( rs.error !== 0 || rs.updated !== true ) return console.log('Impossible de changer le status \'activée\', erreur '+rs.error); /* (3.1.2) Success */ gstore.get.ues[ue_i].disabled = new_state ? 1 : 0; }); }); /* (9) Manage 'manage' sub-page ---------------------------------------------------------*/ /* (1) Initialize current opened UE data */ gstore.add('manage', { cours: [], td: [], tp: [], prof: [] }); /* (2) Function to load UE data */ gstore.add('load_ue_groups', function(code, recur=0){ /* (1) If UE not already loaded -> wait for 200ms */ if( gstore.get.ues.length === 0 && recur > 0 ){ return new Promise( (rs, rj) => setTimeout( () => { return gstore.get.load_ue_groups(code, --recur).catch( (rj2) => rj(rj2) ); }, 200) ); } /* (2.1) Check that code is a valid existing UE code */ if( code == null ) return new Promise( (rs, rj) => rj({label: 'interne', code: -1}) ); /* (2.2) Find index in gstore */ var ue_i = gstore.get.ues.map( (data, i) => { return ( data.code && data.code == code ) ? i : ''; }).join(''); /* (2.3) Exit if not found */ if( ue_i.length === 0 ) return new Promise( (rs, rj) => rj({label: 'interne', code: -1}) ); /* (3) Ask for UE Cours data */ return new Promise( (resolve, reject) => { api.call(`GET ue/cours/${code}`, {}, function(rs){ // erase data gstore.get.manage.cours.splice(0); // reject on error if( rs.error !== 0 || !(rs['groups'] instanceof Array) ) return reject({ label: 'Cours', code: rs.error}); // store data // for each field add a 'add_form' for instant-adding formations afterwards for( var group of rs.groups ){ group.add_form = '-'; ( group.idProf == null ) && ( group.idProf = -1 ); gstore.get.manage.cours.push( group ); } // resolve data on success resolve(); }); /* (4) Ask for UE TD data */ }).then( () => { return new Promise( (resolve, reject) => { api.call(`GET ue/td/${code}`, {}, function(rs){ // erase data gstore.get.manage.td.splice(0); // reject on error if( rs.error !== 0 || !(rs['groups'] instanceof Array) ) return reject({ label: 'TD', code: rs.error}); // store data // for each field add a 'add_form' for instant-adding formations afterwards for( var group of rs.groups ){ group.add_form = '-'; ( group.idProf == null ) && ( group.idProf = -1 ); gstore.get.manage.td.push( group ); } // resolve data on success resolve(); }); }); /* (5) Ask for UE TP data */ }).then( () => { return new Promise( (resolve, reject) => { api.call(`GET ue/tp/${code}`, {}, function(rs){ // erase data gstore.get.manage.tp.splice(0); // reject on error if( rs.error !== 0 || !(rs['groups'] instanceof Array) ) return reject({ label: 'TP', code: rs.error}); // store data // for each field add a 'add_form' for instant-adding formations afterwards for( var group of rs.groups ){ group.add_form = '-'; ( group.idProf == null ) && ( group.idProf = -1 ); gstore.get.manage.tp.push( group ); } // resolve data on success resolve(); }); }); /* (6) Ask for professors data */ }).then( () => { return new Promise( (resolve, reject) => { // 1. if already downloaded if( gstore.get.manage.prof.length > 0 ) return resolve(); // 2. Else fetch from database api.call(`GET professor/0`, {}, function(rs){ // erase data gstore.get.manage.prof.splice(0); // reject on error if( rs.error !== 0 || !(rs['professors'] instanceof Array) ) return reject({ label: 'Professeurs', code: rs.error}); // store data gstore.get.manage.prof = rs.professors; // resolve data on success resolve(); }); }); }); }) /* (10) Manage navigation ---------------------------------------------------------*/ /* (1) Initialize current opened UE */ gstore.add('nav_anim', { in: false, out: false }); /* (2) Manage nav in */ gstore.add('nav_in', function(ue_i){ /* (1) Abort if wrong ue_i */ if( ue_i == null || isNaN(ue_i) || gstore.get.ues[ue_i] == null) return; /* 1. Start animation */ gstore.get.nav_anim.in = true; setTimeout( () => { /* 2. Load page */ gstore.get.router.push(`/ue/manage/${gstore.get.ues[ue_i].code}`); /* 3. Stop animation */ gstore.get.nav_anim.in = false; }, 500 ); }); /* (3) Manage nav out */ gstore.add('nav_out', function(){ /* 1. Start animation */ gstore.get.nav_anim.out = true; setTimeout( () => { /* 2. Load page */ gstore.get.router.push(`/ue/view/`); /* 3. Stop animation */ gstore.get.nav_anim.out = false; /* 4. Remove 'manage' data */ gstore.get.manage.cours.splice(); gstore.get.manage.td.splice(); gstore.get.manage.tp.splice(); }, 500 ); }); /* (11) Manage 'manage' formations add|rem ---------------------------------------------------------*/ /* (1) Remove a formation */ gstore.add('rem_form', function(type, res_i, id_form){ // 1. Check params types if( isNaN(type) || isNaN(res_i) || isNaN(id_form) ) return; // 2. Check @type param if( [0,1,2].indexOf(type) == -1 ) return; // 3. extract API resource from @type var res = [ 'cours', 'td', 'tp' ][type]; var resM = [ 'Cours', 'TD', 'TP' ][type]; // 4. Extract @resource from @res_i var resource = gstore.get.manage[res][res_i]; // 4- Manage unreachable resource if( resource == null ) return; // 5. Extract resource ID var res_id = resource[`id${resM}`]; // 6. Request to remove formation api.call(`PUT ue/${res}/${res_id}`, { rem_form: [id_form] }, (rs) => { // 6.1. Manage error if( rs.error !== 0 || rs.updated !== true ) return; // 6.2. Get reference of data in gstore (if Cours, TD, TP) var local = gstore.get.manage[res]; // 6.3. Unset formation to remove from view for( var f_index in resource.formations ){ // search its index // if found -> remove by index if( resource.formations[f_index] === id_form ){ resource.formations.splice(f_index, 1); break; } } }); }); /* (2) Add a formation */ gstore.add('add_form', function(type, res_i){ // 1. Check params types if( isNaN(type) || isNaN(res_i) ) return; // 2. Check @type param if( [0,1,2].indexOf(type) == -1 ) return; // 3. extract API resource from @type var res = [ 'cours', 'td', 'tp' ][type]; var resM = [ 'Cours', 'TD', 'TP' ][type]; // 4. Extract @resource from @res_i var resource = gstore.get.manage[res][res_i]; // 4- Manage unreachable resource if( resource == null ) return; // 5. Extract resource ID var res_id = resource[`id${resM}`]; // 6. Extract resource.add_form = '-'; // 7.3. Add formation to update VueJS resource.formations.push(id_form); }); }); /* (12) Manage 'prof' for Cours|TD|T{} ---------------------------------------------------------*/ /* (1) Update a prof (or unset) */ gstore.add('upd_prof', function(type, id_res, id_form){ // 1. Check params types if( isNaN(type) || isNaN(id_res) || isNaN(id_form) ) return; // 2. Check @type param if( [0,1,2].indexOf(type) == -1 ) return; // 3. extract API resource from @type var res = [ 'cours', 'td', 'tp' ][type]; var resM = [ 'Cours', 'TD', 'TP' ][type]; // 4. Request to remove formation api.call(`PUT ue/${res}/${id_res}`, { rem_form: [id_form] }, (rs) => { // 4.1. Manage error if( rs.error !== 0 || rs.updated !== true ) return; // 4.2. Get reference of data in gstore (if Cours, TD, TP) var local = gstore.get.manage[res]; // 4.3. Unset formation to remove from view for( var c in local ){ // find ressource (cours|td|tp) if( local[c][`id${resM}`] === id_res ){ // search for formation index for( var f_index in local[c].formations ){ // if found -> remove by index if( local[c].formations[f_index] === id_form ){ local[c].formations.splice(f_index, 1); break; } } break; } } }); });