+
-
-
+
-
- {{ ue.code }}
- {{ ue.label }}
+
+
-
-
- {{ue.volumeCours}}
- heures de cours
-
-
- {{ue.volumeTD}}
- heures de TD
-
-
- {{ue.volumeTP}}
- heures de TP
-
-
+
- ZOU équivalents TD
+
-
-
-
+
+
+ ()
+
+
+
{{ gstore.create_err }}
+
+
+
+
+
+
+
+
+
diff --git a/webpack/data/ue.js b/webpack/data/ue.js
index 00d6875..e30b9f1 100644
--- a/webpack/data/ue.js
+++ b/webpack/data/ue.js
@@ -1,16 +1,467 @@
-/* (1) Load UEs
+/* (1) Load ues
---------------------------------------------------------*/
/* (1) Initialize list */
gstore.add('ues', []);
-/* (2) Get UEs */
-api.call('GET ue', { vh: true }, function(rs) {
+/* (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);
-
- // {2} Store UEs //
+ 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) 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] );
+
+});
+
+
+
+
+/* (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_h', '');
+
+/* (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();
+ gstore.get.create_form = gstore.get.create_form.trim();
+ // gstore.get.create_h = gstore.get.create_h.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 hour = gstore.get.create_h;
+
+ /* (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( !/^.{4,}$/.test(label) )
+ 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');
+
+ /* (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,
+ defaultFormation: form, // can be NULL
+ code: code,
+ volumeCours: null, /*TODO*/
+ volumeTD: null, /*TODO*/
+ volumeTP: null, /*TODO*/
+ required: false, /*TODO*/
+ disabled: false, /*TODO*/
+ };
+
+ /* (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 || isNaN(ue_id) )
+ 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( isNaN(gi) ) 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_h', '');
+
+/* (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_h = ue.hoursToDo.toString();
+
+ /* (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.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 hour = gstore.get.edit_h;
+
+ /* (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( !/^.{4,}$/.test(label) )
+ 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 hours */
+ // if( hour === '' || isNaN(hour) || hour < 0 )
+ // errors.push('Le nombre d\'heures 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 = {};
+ ( form != ue.idForm ) && ( rq.idForm = form );
+ ( label != ue.label ) && ( rq.label = label );
+ ( code != ue.code ) && ( rq.code = code );
+ // ( hour != ue.hoursToDo ) && ( rq.hoursToDo = hour );
+
+ (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 */
+ 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 = form;
+ // gstore.get.ues[ue_i].hoursToDo = hour;
+
+ /* (5.9.2) Try to set the formation label */
+ var fi = gstore.get.categories.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 found -> set formation label */
+ gstore.get.ues[ue_i].labelForm = gstore.get.categories[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;
+
+ });
+
+});
\ No newline at end of file
diff --git a/webpack/scss/container.scss b/webpack/scss/container.scss
index a956019..de5c09d 100644
--- a/webpack/scss/container.scss
+++ b/webpack/scss/container.scss
@@ -218,6 +218,7 @@
/* (2.1.1) lighter color on hover */
& > div.remove[data-remove],
& > div.edit[data-edit],
+ & > div.enabled[data-enabled],
& > div.admin[data-admin]{
background-color: darken(#fff, 12%);
@@ -232,6 +233,7 @@
/* (2.2) Design elements */
& > div.remove[data-remove],
& > div.edit[data-edit],
+ & > div.enabled[data-enabled],
& > div.admin[data-admin]{
display: inline-block;
position: absolute;
@@ -275,6 +277,15 @@
&[data-active='1']:hover{ background-image: url('/asset/svg/admin.svg@f4a118'); }
}
+ /* (2.3) DISABLED switch */
+ &.enabled[data-enabled]{
+ background-image: url('/asset/svg/bell.svg@aaaaaa');
+ z-index: 105;
+
+ &:hover{ background-image: url('/asset/svg/bell.svg@555555'); }
+ &[data-active='1']{ background-image: url('/asset/svg/bell.svg@f4bd18'); }
+ &[data-active='1']:hover{ background-image: url('/asset/svg/bell.svg@f4a118'); }
+ }
}