From 7a8131cfba2f27e9a404f8617e0e8b3f91a68b6f Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Wed, 21 Oct 2015 22:56:56 +0200 Subject: [PATCH] Merge de @wrapper_backup sur le design de @dev_flat --- API.js | 77 +++++++++++++ API.php | 99 +++++++++++++++++ css/container.css | 4 +- css/menu.css | 42 ++++---- index.php | 22 ++-- js/actionScript.js | 250 +++++++++++++++++++++++++++++++++++++------ js/pageManager.js | 237 ++++++++++++++++++++++++++++++++++++++++ js/shortcut.js | 145 +++++++++++++++++++++++++ manager/database.php | 18 ++++ manager/security.php | 76 +++++++++++++ manager/user.php | 135 +++++++++++++++++++++++ page/_JS/auth.js | 80 ++++++++++++++ page/_JS/groups.js | 43 ++++++++ page/auth.php | 42 ++++++++ page/career.php | 1 + page/groups.php | 145 +++++++++++++++++++++++++ page/home.php | 18 ++++ page/marks.php | 1 + page/modules.php | 4 + page/semestre.php | 1 + page/settings.php | 1 + page/ue.php | 1 + src/userlist.json | 32 ++++++ 23 files changed, 1409 insertions(+), 65 deletions(-) create mode 100755 API.js create mode 100755 API.php create mode 100644 js/pageManager.js create mode 100644 js/shortcut.js create mode 100755 manager/database.php create mode 100755 manager/security.php create mode 100755 manager/user.php create mode 100755 page/_JS/auth.js create mode 100755 page/_JS/groups.js create mode 100755 page/auth.php create mode 100755 page/career.php create mode 100755 page/groups.php create mode 100755 page/home.php create mode 100755 page/marks.php create mode 100755 page/modules.php create mode 100755 page/semestre.php create mode 100755 page/settings.php create mode 100755 page/ue.php create mode 100755 src/userlist.json diff --git a/API.js b/API.js new file mode 100755 index 0000000..d5b8def --- /dev/null +++ b/API.js @@ -0,0 +1,77 @@ +/* classe API */ +function APIClass(){}; + +APIClass.prototype = { + xhr: [], // tableau d'objets pour les requêtes ajax + + + + /* transaction avec le serveur (API.php) + * + * @param pRequest l'objet passé en JSON à API.php + * @param pHandler fonction qui s'éxécutera lors de la réponse (1 argument -> réponse) + * + * @return answer l'objet retourné par API.php via pHandler (1er argument) + * + *************************************************************************************************** + * + * @usecase + * 1. var answerObject = sendRequest( + * 2. { var1: "exemple", var2: 198294 }, + * 3. function(rep){ alert(rep); } + * 4. ); + * @explain + * 1. on appelle la fonction <=> on créé la requête + * 2. on passe l'objet qui sera envoyé + * 3. on passe une fonction qui utilise un argument (sera la réponse de API.php) (sous forme d'objet) + * + */ + send: function(pRequest, pHandler){ + + // on efface les requêtes qui sont terminées (toutes celles de this.xhr) + for( var i = 0 ; i < this.xhr.length ; i++ ){ + if( this.xhr[i].readyState == 4 ) // si terminée + this.xhr = this.xhr.slice(0,i-1).concat(this.xhr.slice(i,this.xhr.length-1)); // suppression entrée + } + + // on créé une nouvelle entrée + this.xhr.push(null); + i = this.xhr.length-1; + + // création de l'objet AJAX + if(window.XMLHttpRequest) // IE7+, Firefox, Chrome, Opera, Safari + this.xhr[i] = new XMLHttpRequest(); + else // IE5, IE6 + this.xhr[i] = new ActiveXObject('Microsoft.XMLHttpRequest'); + + console.log(pRequest); + + var ptrAPI = this; + this.xhr[i].onreadystatechange = function(){ + if( ptrAPI.xhr[i].readyState == 4 ){ // si la requête est terminée + + /* DEBUG : affiche la réponse BRUTE de API.php */ + // console.log('API.php => '+ptrAPI.xhr[i].responseText); + console.log(JSON.parse(ptrAPI.xhr[i].responseText) ); + + /* si success de requête */ + if( [0,200].indexOf(ptrAPI.xhr[i].status) > -1 ){ // si fichier existe et reçu + try{ pHandler( JSON.parse(ptrAPI.xhr[i].responseText) ); } // si on peut parser, on envoie + catch(e){ pHandler({request:'corrupted'}); } // sinon on envoie obj.request = 'corrupted' + } + /* sinon retourne obj.request = 'unreachable' */ + else + pHandler({request: 'unreachable'}); + + } + } + + // on créé un formulaire POST (virtuel) + var form = new FormData(); + form.append('json', JSON.stringify(pRequest) ); // on créé la variable $_POST['json']=>request + + this.xhr[i].open('POST', 'API.php', true); + this.xhr[i].send( form ); + + } +}; diff --git a/API.php b/API.php new file mode 100755 index 0000000..08d527c --- /dev/null +++ b/API.php @@ -0,0 +1,99 @@ +level_0 ){ + + /***************/ + /* UTILISATEUR */ + /***************/ + case 'user': + if( isset($request->level_1) ){ include 'manager/user.php'; user_switch_level_1($request, $answer); } + else { $answer->request = 'missing_level_1'; } + break; + + + /***********/ + /* GROUPES */ + /***********/ + case 'groups': + $answer->type = "group"; + break; + + + /******/ + /* UE */ + /******/ + case 'ues': + break; + + + /**********/ + /* MODULE */ + /**********/ + case 'modules': + break; + + + /************/ + /* CONTRÔLE */ + /************/ + case 'tests': + break; + + + /**************/ + /* PARAMETRES */ + /**************/ + case 'settings': + break; + + + /***********/ + /* DEFAULT */ + /***********/ + default: + $answer->request = 'unknown_level_0'; + break; + } + + + if( $answer == null ) + $answer->request = 'no_level_0'; + + + + }else // si json corrompu (undécodable) + $answer->request = 'jsoncorrupted'; + + }else // $_POST vide [OU] $_POST['json'] pas défini + $answer->request = 'nopost'; + + + // on envoie (affiche) l'objet en JSON + echo json_encode($answer); + + } + +?> \ No newline at end of file diff --git a/css/container.css b/css/container.css index 2b84c3d..c444f80 100755 --- a/css/container.css +++ b/css/container.css @@ -1,4 +1,4 @@ -#CONTAINER div{ +#CONTAINER section{ /* position */ display: block; position: absolute; @@ -17,4 +17,4 @@ -#CONTAINER div.active{ z-index: 8; } \ No newline at end of file +#CONTAINER section.active{ z-index: 8; } \ No newline at end of file diff --git a/css/menu.css b/css/menu.css index 426a2f2..053743d 100755 --- a/css/menu.css +++ b/css/menu.css @@ -38,7 +38,7 @@ -#MENU a{ +#MENU span{ /* position */ display: block; position: relative; @@ -79,8 +79,8 @@ } -#MENU a:hover, -#MENU a.active{ +#MENU span:hover, +#MENU span.active{ background: #233342 url(../src/menu_icon/home_grayscale.svg) left 1em center no-repeat; background-size: 1.7em; @@ -89,24 +89,24 @@ /* gestion des différentes icônes */ -#MENU a:nth-child(2){ background-image: url(../src/menu/menu_icon/home.svg); } -#MENU a:nth-child(3){ background-image: url(../src/menu/menu_icon/groups.svg); } -#MENU a:nth-child(4){ background-image: url(../src/menu/menu_icon/ue.svg); } -#MENU a:nth-child(5){ background-image: url(../src/menu/menu_icon/modules.svg); } -#MENU a:nth-child(6){ background-image: url(../src/menu/menu_icon/marks.svg); } -#MENU a:nth-child(7){ background-image: url(../src/menu/menu_icon/settings.svg); } +#MENU span:nth-child(2){ background-image: url(../src/menu/menu_icon/home.svg); } +#MENU span:nth-child(3){ background-image: url(../src/menu/menu_icon/groups.svg); } +#MENU span:nth-child(4){ background-image: url(../src/menu/menu_icon/ue.svg); } +#MENU span:nth-child(5){ background-image: url(../src/menu/menu_icon/modules.svg); } +#MENU span:nth-child(6){ background-image: url(../src/menu/menu_icon/marks.svg); } +#MENU span:nth-child(7){ background-image: url(../src/menu/menu_icon/settings.svg); } /* gestion de l'activation des différentes icônes */ -#MENU a:nth-child(2):hover, -#MENU a:nth-child(2).active{ background-image: url(../src/menu/menu_icon/home@hover.svg); } -#MENU a:nth-child(3):hover, -#MENU a:nth-child(3).active{ background-image: url(../src/menu/menu_icon/groups@hover.svg); } -#MENU a:nth-child(4):hover, -#MENU a:nth-child(4).active{ background-image: url(../src/menu/menu_icon/ue@hover.svg); } -#MENU a:nth-child(5):hover, -#MENU a:nth-child(5).active{ background-image: url(../src/menu/menu_icon/modules@hover.svg); } -#MENU a:nth-child(6):hover, -#MENU a:nth-child(6).active{ background-image: url(../src/menu/menu_icon/marks@hover.svg); } -#MENU a:nth-child(7):hover, -#MENU a:nth-child(7).active{ background-image: url(../src/menu/menu_icon/settings@hover.svg); } +#MENU span:nth-child(2):hover, +#MENU span:nth-child(2).active{ background-image: url(../src/menu/menu_icon/home@hover.svg); } +#MENU span:nth-child(3):hover, +#MENU span:nth-child(3).active{ background-image: url(../src/menu/menu_icon/groups@hover.svg); } +#MENU span:nth-child(4):hover, +#MENU span:nth-child(4).active{ background-image: url(../src/menu/menu_icon/ue@hover.svg); } +#MENU span:nth-child(5):hover, +#MENU span:nth-child(5).active{ background-image: url(../src/menu/menu_icon/modules@hover.svg); } +#MENU span:nth-child(6):hover, +#MENU span:nth-child(6).active{ background-image: url(../src/menu/menu_icon/marks@hover.svg); } +#MENU span:nth-child(7):hover, +#MENU span:nth-child(7).active{ background-image: url(../src/menu/menu_icon/settings@hover.svg); } diff --git a/index.php b/index.php index 53382a4..968a11a 100755 --- a/index.php +++ b/index.php @@ -54,7 +54,9 @@ $notifNotifNum = 5; - + + + @@ -65,12 +67,12 @@ $notifNotifNum = 5; @@ -109,11 +111,7 @@ $notifNotifNum = 5; -
-
Contenu de la section #HOME
-
Contenu de la section #GROUPES
- -
+
diff --git a/js/actionScript.js b/js/actionScript.js index c72963e..a6b75d6 100755 --- a/js/actionScript.js +++ b/js/actionScript.js @@ -1,4 +1,38 @@ -/* VARIABLES */ + + /*********************************************************** + * * + * SCRIPT POST-HTML - SCRIPT PRINCIPAL * + * * + ************************************************************ + * * + * [0] Variables * + * [1] Gestionnaires de navigation * + * [a] pageManager.js * + * [b] API.js * + * [2] Gestion des liens * + * [a] catégories * + * [b] sous-parties * + * [3] Gestion des formulaires * + * * + * * + * * + * * + * * + * * + * * + * * + * * + ***********************************************************/ + + +/* [0] VARIABLES +==============================================================*/ +/* pageManager */ +var pageM; +/* API */ +var API; + +/* Structure de la page */ var DOM = { WRAPPER : document.querySelector('#WRAPPER'), MENU : document.querySelector('#MENU'), @@ -9,38 +43,194 @@ var DOM = { }; -/* GESTION DES SOUS-PARTIES */ -DOM.SUBSECTIONS.addEventListener('click', function(e){ - - if( e.target.tagName == 'SPAN' ){ // s'il s'agit bien d'un élément de nav - - // on essaie de récupérer l'ancien "lien" - var lastActive = document.querySelector('#SUBHEADER > nav > span.active'); - if( lastActive != null ) // si on a trouvé qqch - lastActive.className = ''; // on le désactive - e.target.className = 'active'; // on signale celui cliqué comme "actif" - - // on essaie de récupérer l'ancienne section active - var lastSection = document.querySelector('#CONTAINER div.active'); - if( lastSection != null ) // si on a trouvé qqch - lastSection.className = ''; // on la désactive +/* [1] GESTIONNAIRES DE NAVIGATION +==============================================================*/ + + + /* [a] pageManager.js + ==============================================================*/ + pageM = new pageManager(); // instance principale + + /* initialisation du gestionnaire */ + pageM.setPage(null, 'page', DOM.CONTAINER, ['home', 'groups', 'ue', 'modules', 'marks', 'auth', 'settings'] ); + + + /* [b] API.js + ==============================================================*/ + API = new APIClass(); + + + + +/* [2] GESTION DES LIENS +==============================================================*/ + + + /* [a] CATÉGORIES + ==============================================================*/ + /* GESTION DES CATEGORIES (SECTIONS) + * + * @param section l'élément à activer + * + * [1] selectionne l'élément, l'affichage de la page associée est géré par pageManager.js + * [2] déselectionne l'élément précédemment selectioné + * + */ + function selectSection(section){ + + // si @subSection est un de type
  • qui a la propriété "data-link" [ET] section pas déjà active + if( section instanceof Element && section.tagName == 'SPAN' && section.dataset.hasOwnProperty('link') ){ + + // on charge la page + pageM.setPage( section.dataset.link ); + + /* on active les sous-parties */ + pageM.xhr[pageM.xhr.length-1].onload = function(){ + selectSubSection( document.querySelector('#SUBHEADER > nav > span.active') ); + }; + // on récupère la section déja selectionnée si elle existe + var last = document.querySelector('#MENU span.active'); + + if( last != null ) // si une section est déjà activée + last.className = ''; // on désactive la courante + + section.className = 'active'; // on active @section + + }else // sinon on affiche l'erreur + console.log("[selectSection_Error] - ("+section+")"); - // on active la page associée - var target = document.querySelector('#CONTAINER > div[name='+e.target.dataset.sectname+']'); - if( target != null ) - target.className = 'active'; } -}, false); + /* activation au chargement en fonction de la page courante de pageManager.js */ + var lastSection = document.querySelector('#MENU span[data-link='+pageM.page+']'); + if( lastSection != null ) + selectSection(lastSection); // on l'active -/* on active la section au chargement */ -// on essaie de récupérer le lien actif -var lastActive = document.querySelector('#SUBHEADER > nav > span.active'); -if( lastActive != null ){ // si on trouve qqch + /* Gestion des liens du menu */ + DOM.MENU.addEventListener('click', function(e){ selectSection( e.target ); }, false); + + + + + + + /* [b] SOUS-PARTIES + ==============================================================*/ + /* GESTION DES SOUS-PARTIES (SOUS-CATÉGORIES) + * + * @param subSection l'élément à activer + * + * [1] selectionne l'élément, l'affichage de la page associée est géré en CSS3 + * [2] déselectionne l'élément précédemment selectioné + * + */ + function selectSubSection(subSection){ + + // si @subSection est un de type HGROUP [ET] + if( subSection instanceof Element && subSection.tagName == 'SPAN' && subSection.dataset.hasOwnProperty('sectname') ){ + + // on essaie de récupérer l'ancien "lien" + var lastActive = document.querySelector('#SUBHEADER > nav > span.active'); + if( lastActive != null ) // si on a trouvé qqch + lastActive.className = ''; // on le désactive + + // on essaie de récupérer l'ancienne section active + var lastSection = document.querySelector('#CONTAINER section.active'); + if( lastSection != null ) // si on a trouvé qqch + lastSection.className = ''; // on la désactive + + // on active la page associée + console.log( document.querySelector('#CONTAINER section[name=home]') ); + var target = document.querySelector('#CONTAINER section[name='+subSection.dataset.sectname+']'); + if( target != null ) + target.className = 'active'; + + subSection.className = 'active'; // on active @subSection + } + + } + + /* gestion du clic sur les sous-parties */ + DOM.SUBSECTIONS.addEventListener('click', function(e){ selectSubSection(e.target); }, false); + + + +/* [3] GESTION DES FORMULAIRES +==============================================================*/ +/* INITIALISE UN FORMULAIRE POUR QU'IL INTERPRETE UN OBJET LORS DE SA SOUMISSIONS +* +* @param pForm le formulaire cible +* @param pHandler fonction exécutée lors de la soumission du formulaire +* +* [1] parcourt les élements du formulaire @pForm et active un évènement lors du "submit" +* [2] retourne l'objet à @pHandler lors du "submit" +* +* +* @example +* +*
    +* +* +* +* +* +* +*
    +* +* @explaination +* +* Lors du clic sur le bouton [VALIDER], la fonction @pHandler s'exécutera avec pour paramètre un objet +* OBJ{ id: nomFormulaire, nomDuChamp1: valeurDuChamp1, nomDuChamp2: valeurDuChamp2 } +* +*/ +function initForm(pForm, pHandler){ + + // vérification des arguments + var isForm = pForm instanceof Element && pForm.tagName == 'FORM'; + var isFunc = pHandler instanceof Function; + + // si les arguments sont corrects + if( pForm instanceof Element && pForm.tagName == 'FORM' ){ + + var submitButton = null; // contiendra le bouton d'envoi du formulaire + + for( var i = 0 ; i < pForm.children.length ; i++ ) + if( pForm.children[i].type == 'button' && pForm.children[i].name == 'submit' ){ + submitButton = pForm.children[i]; // on définit le bouton + break; // on sort du for + } + + + // on définit l'évènement de validation du formulaie + function submitEvent(){ + + var obj = {} // on créé l'objet qui va être envoyé + + for( var i = 0 ; i < pForm.children.length ; i++ ) // on parcourt les enfants + if( pForm.children[i].tagName == 'INPUT' && pForm.children[i].name != 'submit' ) // si c'est un champ et que c'est pas le bouton + obj[pForm.children[i].name] = pForm.children[i].value; // alors on enregistre le champ dans l'objet + + // on exécute la fonction @pHandler en lui envoyant les arguments + pHandler(obj); + + } + + // on définit l'évènement du clic sur le bouton + submitButton.addEventListener('click', function(e){ + submitEvent(e.target.parentNode); // on envoie le formulaire + }, false); + + // on définit l'évènement de l'appui sur la touche [ENTRER] + pForm.addEventListener('keydown', function(e){ + if(e.keyCode==13) submitEvent(e.target); // si c'est la bonne touche, on submit le formulaire + }, false); + + + + }else + console.log('[initForm_Error] - ('+pForm+', '+pHandler+')'); + + +} - // on cherche la section associée - var target = document.querySelector('#CONTAINER > div[name='+lastActive.dataset.sectname+']'); - if( target != null ) // si on a trouvé qqch - target.className = 'active'; // on l'active -} \ No newline at end of file diff --git a/js/pageManager.js b/js/pageManager.js new file mode 100644 index 0000000..44ce627 --- /dev/null +++ b/js/pageManager.js @@ -0,0 +1,237 @@ +function pageManager(){}; + +var ptrPageManager; // pointeur global pour l'utilisation de fonctions de fonctions + +pageManager.prototype = { + depJS: null, // la dépendance javascript + depCSS: null, // la dépendance css + xhr: [], // tableau d'objets pour les requêtes ajax + page: null, // l'indice de la page courante dans pagelist + vars: [], // les variables suivant le nom de la page dans l'URL + path: '', // le chemin du dossier contenant les pages (.php) + pagelist: null, // la liste des pages pouvant être chargées + container: null, // élément DOM qui contiendra le contenu des pages à charger + /* ======================================================================= + Cette fonction effectue une requête Ajax (compatible à partir de IE5) + PARAMETRES: + - pLink le lien à charger + - pHandler une fonction qui s'éxécutera avec la réponse de la requête passée en paramètre (voir exemples dessous pour pHandler) + - pMethod type de méthode, vaut 'POST' ou 'GET' et vaut 'POST' par défaut ou s'il n'est pas renseigné + - pForm formulaire de type FormData() contenant les données à envoyer (uniquement en POST), si pForm vaut GET les données doivent être passées dans l'URL + ========================================================================== */ + ajax: function(pLink, pHandler, pMethod, pForm){ + // on efface les requêtes qui sont terminées et on push une nouvelle + for( var i = 0 ; i < this.xhr.length ; i++ ){ + if( this.xhr[i].readyState == 4 ) // si terminée + this.xhr = this.xhr.slice(0,i-1).concat(this.xhr.slice(i,this.xhr.length-1)); // suppression entrée + } + + this.xhr.push(true); + i = this.xhr.length-1; + + if(window.XMLHttpRequest) // IE7+, Firefox, Chrome, Opera, Safari + this.xhr[i] = new XMLHttpRequest(); + else // IE5, IE6 + this.xhr[i] = new ActiveXObject('Microsoft.XMLHttpRequest'); + + var ptrPageManager = this; + this.xhr[i].onreadystatechange = function(){ + if( ptrPageManager.xhr[i].readyState == 4 ) // si la requête est terminée + if( [0,200].indexOf(ptrPageManager.xhr[i].status) > -1 ) // si fichier existe et reçu + pHandler(ptrPageManager.xhr[i].responseText); + else // si code d'erreur retourne null + pHandler(); + } + + // gestion de la méthode + var method = ( typeof pMethod == 'string' && /^POST|GET$/i.test(pMethod) ) ? pMethod.toUpperCase() : 'POST'; + + // gestion du formulaire si la méthode est POST + var form = ( method == 'POST' && typeof pForm == 'object' && pForm instanceof FormData ) ? pForm : null; + + this.xhr[i].open( method, pLink, true); + this.xhr[i].send( form ); + }, + /***************************************************** [APPLICATION] Ajax() ******************************************************/ + // EXEMPLES DE FONCTIONS POUR pHandler // + // 1. var a = function(param){ alert(param); } // les deux notations 1 et 2 sont équivalents + // 2. function a(param){ alert(param); } // les deux notations 1 et 2 sont équivalents + + // ajax( 'index.php', a ); // utilisation d'une fonction définie + + // ajax( 'index.php', alert ); // utilisation d'une fonction prédéfinie + // ajax( 'index.php', alert, 'GET' ); // utilisation de méthode + + // var fd = new FormData(); // création d'un formulaire + // fd.append('var', 100); // ajout de la variable VAR qui vaut 100 + + // ajax( 'index.php', alert, null, fd ); // saut de paramètre avec null + envoi formulaire + // ajax( 'index.php?var=10', alert, 'GET' ); // envoi formulaire en GET (dans l'url) + // ajax( 'index.php?var=10', alert, 'POST', fd ); // envoi formulaire en GET (dans l'url) + en POST via le formulaire FD + + + /* ======================================================================= + Cette fonction effectue une décomposition de l'URL sur le shéma spécifié dessous + Renvoie pour http://www.exemple.com/dirA/dirB/#/NOMPAGE/VARPAGE + - null si la page n'est pas référencée dans le tableau PAGELIST + - null si le lien ne contient pas /#/NOMPAGE à la fin + - null si NOMPAGE ne contient pas uniquement : lettres, chiffres, underscore + - null si VARPAGE ne contient pas uniquement : lettres, chiffres, underscore + - un objet contenant {page: valeur, var: valeur} + ========================================================================== */ + explodeURL: function(url_data){ + url_data = (arguments.length >= 1) ? url_data : document.URL; + // si pageList est correct et que l'URL correspond à un schéma de page => continue [sinon] return null + if( this.pagelist != null && /^(?:.+)\/#\/([a-z0-9_]+)\/?(?:\/((?:[a-z0-9_]+\/)+)\/?)?$/i.test(url_data) ){ + // si la page récupérée dans l'url est dans la liste => renvoi de l'objet [sinon] null + var vars = RegExp.$2.split('/'); + while( vars[vars.length-1] == '' ) // on supprime les dernières entrées vides + vars.pop(); + + return ( this.pagelist.indexOf(RegExp.$1) > -1 ) ? {page: RegExp.$1, var: vars} : null; + }else + return null; + }, + /* ======================================================================= + Cette fonction ajoute des dépendances (un js et un css) situés dans le répertoire des pages. + pageDir/ + _JS/ + page1.js + page2.js + _CSS/ + page1.css + page2.css + ========================================================================== */ + loadDependencies: function(){ + // si depCSS est un élément du DOM c'est à dire qu'il contient le fichier de la page précédente et qu'il est enfant de , on le détruit + if( typeof this.depCSS == 'object' && this.depCSS instanceof Element && this.depCSS.parentNode == document.head ) + document.head.removeChild( this.depCSS ); + + // si depJS est un élément du DOM c'est à dire qu'il contient le fichier de la page précédente, on le détruit + if( typeof this.depJS == 'object' && this.depJS instanceof Element && this.depJS.parentNode == document.head ) + document.head.removeChild( this.depJS ); + + ptrPageManager = this; + // si le fichier css existe + this.ajax(this.path+'/'+'_CSS'+'/'+this.page+'.css', function(e){ + if( e != null ){ // on charge la dépendance CSS si le fichier existe + ptrPageManager.depCSS = document.createElement('link'); + ptrPageManager.depCSS.rel = 'stylesheet'; + ptrPageManager.depCSS.type = 'text/css'; + ptrPageManager.depCSS.href = ptrPageManager.path+'/'+'_CSS'+'/'+ptrPageManager.page+'.css'; + document.head.appendChild(ptrPageManager.depCSS); + }else + console.log('[loadDependencies_Error] - ('+ptrPageManager.path+'/'+'_CSS'+'/'+ptrPageManager.page+'.css'+')'); + }); + + // si le fichier js existe + this.ajax(this.path+'/'+'_JS'+'/'+this.page+'.js', function(e){ + if( e != null ){ // on charge la dépendance JS si le fichier existe + ptrPageManager.depJS = document.createElement('script'); + ptrPageManager.depJS.type = 'text/javascript'; + ptrPageManager.depJS.src = ptrPageManager.path+'/'+'_JS'+'/'+ptrPageManager.page+'.js'; + document.head.appendChild(ptrPageManager.depJS); + }else + console.log('[loadDependencies_Error] - ('+ptrPageManager.path+'/'+'_JS'+'/'+ptrPageManager.page+'.js'+')'); + }); + }, + + /* ======================================================================= + Cette fonction est celle qui gère les 2 autres et celle que l'utilisateur utilisera + PARAMETRES: + - pName le nom de la page à charger (lettres, chiffres, underscore) (*) + - pPath chemin (relatif ou absolu) du dossier contenant les pages de même nom de fichier que le nom (extension .php) + - pContainer l'élément du DOM qui contiendra la page chargée (**) + - pPageList> tableau contenant la liste des pages sous forme de chaînes de caractères (**) (***) + * Le chemin du dossier sans le '/' final si c'est le dossier actuel le chemin est une chaîne vide + Si le dossier est 'page' et que l'on cherche la page 'accUe1l', la requête sera vers 'page/accUe1l.php' + le nom de la page est sensible à la casse + ** 1. pPageList et pContainer doivent être mis en paramètres uniquement à la première utilisation + et la première utilisation doit se faire au chargement de la page car elle permetra + de mettre l'URL à jour et/ou charger la page de l'URL + *** la première page du tableau est la page par défaut (qui est chargée si l'URL ne contient + pas la page ou si la page de l'URL ne correspond à aucune page de la liste) + ========================================================================== */ + setPage: function(pName, pPath, pContainer, pPageList){ + + // liste de pages si c'est un tableau + var pageList = ( typeof pPageList == 'object' && pPageList instanceof Array ) ? pPageList : null; // si this.pagelist n'est pas overwrite il vaut null + + if( pageList != null ){ // si c'est un tableau + for( var i = 0 ; i < pageList.length ; i++ ){ // on parcourt tout les éléments pour vérifier que chaque élément ne contient que : lettres, chiffres, underscore [non]> pageList = null + pageList = ( typeof pageList[i] == 'string' && /^[a-z0-9_]+$/i.test(pageList[i]) ) ? pageList : null; + if( pageList == null ) break; // si le tableau est null stoppe la boucle + } + } + /* on attribue la variable temporaire pageList à l'attribut de l'objet si la variable pageList temporaire n'est pas nulle */ + this.pagelist = ( pageList != null ) ? pageList : this.pagelist; + // affecte à l'attribut page la page par défaut (premier élément de pagelist) + this.page = this.pagelist[0]; + // affecte pPath à l'attribut path s'il est renseigné + this.path = ( typeof pPath == 'string' ) ? pPath : this.path; + /* on attribue le paramètre pContainer à l'attribut si il est spécifié */ + this.container = ( typeof pContainer == 'object' && pContainer instanceof Element ) ? pContainer : this.container; + + // si this.pagelist && this.container ne sont pas null && + if( this.pagelist != null && this.container != null ){ + // si le pName est renseigné et qu'il est dans pagelist + if( typeof pName == 'string' && this.pagelist.indexOf(pName) > -1 ){ + // affecte pName à l'attribut page + this.page = pName; + + // charge le contenu de la page dans le container + var ptrPageManager = this; + + // formulaire POST + var fd = new FormData(); + for( var i = 0 ; i < this.vars.length ; i++ ) + fd.append(this.vars[i], null); + + this.ajax(this.path+'/'+this.page+'.php', function(e){ + ptrPageManager.container.innerHTML = e; + ptrPageManager.loadDependencies(); + }, 'POST', fd); + + // change l'URL en conséquences(stateObj, titre, url) + if( this.vars.length > 0 ) // si il y a des variables + window.history.pushState(null, this.page, '#/'+this.page+'/'+this.vars.join('/')+'/'); + else // s'il n'y en a pas + window.history.pushState(null, this.page, '#/'+this.page+'/'); + + }else{ // si la page n'est pas spécifiée ou qu'elle n'est pas dans la liste des pages + var urlGet = this.explodeURL(); + + // si on a récupéré le numéro de la page dans l'URL et qu'elle fait partie de la liste des pages + if( urlGet != null ){ + this.page = urlGet.page; + // charge le contenu de la page dans le container + var ptrThis = this; + + // formulaire POST + var fd = new FormData(); + this.vars.length = 0; + + for( var i = 0 ; i < urlGet.var.length ; i++ ){ // replacing object variables with explodeURL variables + this.vars[i] = urlGet.var[i]; + fd.append(this.vars[i], null); + } + + this.ajax(this.path+'/'+this.page+'.php', function(e){ + ptrThis.container.innerHTML = e; + ptrThis.loadDependencies(); + }, 'POST', fd); + + // change l'URL en conséquences(stateObj, titre, url) + if( this.vars.length > 0 ) // si il y a des variables + window.history.pushState(null, this.page, '#/'+this.page+'/'+this.vars.join('/')+'/'); + else // s'il n'y en a pas + window.history.pushState(null, this.page, '#/'+this.page+'/'); + + }else // si l'url ne contient rien, on charge la page par défaut + this.setPage(this.pagelist[0]); + } + }else + console.log('pagelist et container manquant'); + } + +} \ No newline at end of file diff --git a/js/shortcut.js b/js/shortcut.js new file mode 100644 index 0000000..b032b03 --- /dev/null +++ b/js/shortcut.js @@ -0,0 +1,145 @@ +/* Retourne le keyCode correspondant à la chaîne +* +* @param keyStore enchaînement de touches sous forme de string +* @param handler function qui s'éxécute lors du raccourci +* +* return keyCode le code de la touche correspondante +*/ +function strToKeyCode(str){ + // on enregistre le keyCode du premier caractère + var keyCode = str.toUpperCase().charCodeAt(0); + + // s'il s'agit d'un caractère uniquement (entre "a" et "z") + if( str.length == 1 && keyCode >= 65 && keyCode <= 90 ) + return keyCode; // on retourne le keyCode associé + else + switch( str ){ + case 'ctrl': return 17; break; + case 'maj': return 16; break; + case 'alt': return 18; break; + case 'tab': return 9; break; + } + + return null; +} + + + + +var shortcutList = []; // contient les combinaisons de touches +var shortcutStep = []; // contient l'avancée d'un raccourcis + +/* Gestion des raccourcis claviers +* +* @param keyStore enchaînement de touches sous forme de string +* @param handler function qui s'éxécute lors du raccourci +* +*/ +function Shortcut(keyStore, handler){ + + var splittedString = keyStore.toLowerCase().split('+'), // découpe la chaîne (en minuscule) par "+" + splittedKeyCode = new Array(); // contiendra les keyCode de chaque touche + + + // pour chaque touche, on récupère le keyCode + for( var i = 0 ; i < splittedString.length ; i++ ) + splittedKeyCode[i] = strToKeyCode( splittedString[i] ); // on enregistre le keyCode correspondant + + + // on ajout à la liste globale + eventIndex = shortcutList.length; + shortcutList.push( splittedKeyCode ); + + // on initialise l'avancement + shortcutStep[eventIndex] = 0; + + + + // creation de la fonction d'évènement + shortcutList[eventIndex].push( function(k, f, h){ /* k ; f ; h */ + // on cherche l'avancée + var step = shortcutStep[f]; + + // on regarde si la touche est bonne + if( shortcutList[f][step] == k ){ // si c'est la touche suivante + + if( step >= shortcutList[f].length-2 ){ // si c'était la dernière touche + + // on initialise le tableau + for( var i = 0 ; i < shortcutStep[f].length ; i++ ) + shortcutStep[f][i] = 0; + + h(); // EXECUTION DE : handler(); + + }else // sinon on incrémente l'avancée + shortcutStep[f]++; + + }else // si c'est pas la bonne touche, on réinitialise le tableau + shortcutStep[f] = 0; + + }); + + console.log( shortcutList ); + + + // création de l'évènement + window.addEventListener( + 'keydown', + function(e){ e.preventDefault(); shortcutList[eventIndex][shortcutList[eventIndex].length-1](e.keyCode, eventIndex, handler); }, + false + ); + +} + +/* quand on lâche une touche, tout les raccourcis s'effacent */ +window.addEventListener('keyup', function(){ + for( var i = 0 ; i < shortcutStep.length ; i++ ) + shortcutStep[i] = 0; +}, false); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/*** UTILISATION ***/ + +// Shortcut( +// 'ctrl+s', +// function(){ alert('sauvegardé'); } +// ); \ No newline at end of file diff --git a/manager/database.php b/manager/database.php new file mode 100755 index 0000000..5b4c2cb --- /dev/null +++ b/manager/database.php @@ -0,0 +1,18 @@ +connection = new PDO("mysql:host=$host;dbname=$dbname", $username, $password); + } +} + +?> \ No newline at end of file diff --git a/manager/security.php b/manager/security.php new file mode 100755 index 0000000..6781c74 --- /dev/null +++ b/manager/security.php @@ -0,0 +1,76 @@ + 0; + $permissionsDefinedProperly = isset($_SESSION['permissions']) && !empty($_SESSION['permissions']) && gettype($_SESSION['permissions']) == 'string' && strlen($_SESSION['permissions']) > 0; + + // si les variables sessions ne sont pas toutes les 2 correctes + if( !($usernameDefinedProperly && $permissionsDefinedProperly) ){ + $_SESSION['username'] = null; // on les initialise à NULL + $_SESSION['permissions'] = null; + } + } + + + + + + + +?> \ No newline at end of file diff --git a/manager/user.php b/manager/user.php new file mode 100755 index 0000000..0d37fe9 --- /dev/null +++ b/manager/user.php @@ -0,0 +1,135 @@ +level_1 ){ + + /****************************/ + /* authentification (login) */ + /****************************/ + case 'authentification': + $areSetParam = isset($request->username) && isset($request->password); // les arguments existent + $typeOkParam = $areSetParam && is_string($request->username) && is_string($request->password); // ils sont tous 2 des string + $nEmptyParam = $typeOkParam && strlen($request->username) > 0 && strlen($request->password) > 0; // d'au moins 1 caractère + + if( $areSetParam && $typeOkParam && $nEmptyParam ) + $answer->request = user_authentification($request->username, $request->password); + else{ + if ( !$areSetParam ) $answer->request= 'missing_param'; + elseif( !$typeOkParam ) $answer->request = 'wrong_type'; + else $answer->request = 'empty_param'; + } + break; + + + + /***********/ + /* DEFAULT */ + /***********/ + default: + $answer->request = 'unknown_level_1'; + break; + } + + } + + + + + + + + + + + + + + + + + + + /* [2] AUTHENTIFICATION + ============================================================*/ + + /* [a] userlist */ + function user_getUserList(){ + $userlistFile = file_get_contents("src/userlist.json"); + return json_decode( $userlistFile ); + } + + + /* [b] CONNECTION + ========================================================*/ + /* GESTION DE L'AUTHENTIFICATION D'UN UTILISATEUR + * + * @param username Identifiant de l'utilisateur + * @param password Mot de passe de l'utilisateur + * + * si @username est référencé et que le mot de passe associé vaut @password + * alors @return TRUE sinon FALSE + * + mise ajout à @answer + * + * Les variables sessions suivantes sont définies : + * - $_SESSION['permissions'] + * - $_SESSION['userid'] + * - $_SESSION['username'] + * + * @return Boolean true si l'utilisateur est ok + */ + function user_authentification($username, $password){ + + // [1] On récupère la liste d'utilisateurs (/src/userlist.json) + $userList = user_getUserList(); + + // [2] On check l'existence de l'utilisateur + if( isset($userList->{$username}) ){ + + // [3] On check le mot de passe + if( $userList->{$username}->password == $password ){ + // on définit les variables session + $_SESSION['username'] = $username; + $_SESSION['permissions'] = $userList->{$username}->permissions; + return 'success'; + }else + return 'wrong_password'; + + }else + return 'unknown_user'; + } + + +?> \ No newline at end of file diff --git a/page/_JS/auth.js b/page/_JS/auth.js new file mode 100755 index 0000000..7e95c72 --- /dev/null +++ b/page/_JS/auth.js @@ -0,0 +1,80 @@ + + /*********************************************************** + * * + * SCRIPT LOCAL DE LA PAGE D'AUTHENTIFICATION * + * * + ************************************************************ + * * + * [0] Variables * + * [1] Gestion des formulaires * + * [a] Gestion des réponses * + * [b] Initialisation des formulaires * + * * + * * + * * + * * + * * + * * + * * + * * + * * + ***********************************************************/ + + /* [0] Variables + ==============================================================*/ + var subSections = document.querySelectorAll('hgroup'); + + + /* [1] Gestion des formulaires + ==============================================================*/ + + + /* [a] Gestion des réponses + ==============================================================*/ + /* GESTION DU COMPORTEMENT EN FONCTION DE LA REPONSE POUR LE [LOGIN] + * + * @param response + * + * Gestion de toutes les réponse possibles avec une "messageBox" ou de redirection + * + */ + function manageAuthentificationResponse(response){ + switch( response.request ){ + + case 'success': + messageBox('Vous êtes maintenant connecté', 'success'); // on affiche le message + selectSection( document.querySelector('#MENU li:first-child') ); // on redirige vers la page d'accueil + break; + + // case 'missing_param': messageBox('Un des champs requis n\'est pas présent', 'warning'); break; + // case 'empty_param': messageBox('Un des champs requis est vide', 'warning'); break; + // case 'unknown_user': messageBox('Nom d\'utilisateur inconnu', 'error'); break; + // case 'wrong_password': messageBox('Mot de passe incorrect', 'error'); break; + + + case 'empty_param': case 'missing_param': case 'unknown_user': case 'wrong_password': + messageBox('Identifiants incorrects', 'error'); + break; + + default: + messageBox('Erreur interne', 'error'); + break; + + } + } + + + + + /* [b] Initialisation des formulaires + ==============================================================*/ + initForm( // initialisation du formulaire de connection + document.querySelector('#user'), // formulaire (élément DOM) + function(request){ // handler + // ajout d'informations à la requête + request.level_0 = 'user'; + request.level_1 = 'authentification'; + + API.send(request, function(response){ manageAuthentificationResponse(response); }); + } + ); diff --git a/page/_JS/groups.js b/page/_JS/groups.js new file mode 100755 index 0000000..65848f2 --- /dev/null +++ b/page/_JS/groups.js @@ -0,0 +1,43 @@ +var subSections = document.querySelectorAll('hgroup'); + + + + +// si aucune sous-partie n'est active, on active la première +if( document.querySelector('#CONTAINER hgroup.active') == null ) + selectSubSection( document.querySelector('#CONTAINER hgroup') ); + + + + + + + + + + + + + + + + + +/*************************************************/ +/****************** EXEMPLE API ******************/ +/*************************************************/ + +/* objet envoyé à API.php */ +var request = { + level_0: 'groups', + level_1: 'visualiser', + group : 'ego' +}; + +// console.log( request ); + +// envoi de la requête +// @ on envoie l'objet +// @ quand réception: affichage de l'objet reçu +// +API.send(request, function(){} ); diff --git a/page/auth.php b/page/auth.php new file mode 100755 index 0000000..d0847f8 --- /dev/null +++ b/page/auth.php @@ -0,0 +1,42 @@ + + +
    Connection
    +
    + +
    + + + +
    + +
    + + + + + + +
    Mon Profil
    +
    + + username =
    + droits = + +
    + + + \ No newline at end of file diff --git a/page/career.php b/page/career.php new file mode 100755 index 0000000..12bea97 --- /dev/null +++ b/page/career.php @@ -0,0 +1 @@ +career.php \ No newline at end of file diff --git a/page/groups.php b/page/groups.php new file mode 100755 index 0000000..6420150 --- /dev/null +++ b/page/groups.php @@ -0,0 +1,145 @@ + +
    Mon Groupe
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NomPrénomBlablabla
    001002003
    001002003
    001002003
    001002003
    001002003
    001002003
    001002003
    001002003
    001002003
    001002003
    + +
    + + + + +
    Mes Groupe
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Nom du groupeNombre d'élèvesNombre de modules
    A302
    B283
    D321
    F212
    + +
    + + + + +
    Tout les groupes
    +
    + Tout les groupes
    + bla
    + bla
    +
    + + + + +
    Mon Groupe 2
    +
    + Mon Groupe 2
    + bla
    + bla
    +
    \ No newline at end of file diff --git a/page/home.php b/page/home.php new file mode 100755 index 0000000..9b11b0c --- /dev/null +++ b/page/home.php @@ -0,0 +1,18 @@ + +
    Contenu de la section #HOME
    +
    Contenu de la section #GROUPES
    \ No newline at end of file diff --git a/page/marks.php b/page/marks.php new file mode 100755 index 0000000..58569ea --- /dev/null +++ b/page/marks.php @@ -0,0 +1 @@ +Notes ici !!! \ No newline at end of file diff --git a/page/modules.php b/page/modules.php new file mode 100755 index 0000000..de1673c --- /dev/null +++ b/page/modules.php @@ -0,0 +1,4 @@ + + + +modules.php \ No newline at end of file diff --git a/page/semestre.php b/page/semestre.php new file mode 100755 index 0000000..83d0be7 --- /dev/null +++ b/page/semestre.php @@ -0,0 +1 @@ +semestre.php \ No newline at end of file diff --git a/page/settings.php b/page/settings.php new file mode 100755 index 0000000..3dd1e75 --- /dev/null +++ b/page/settings.php @@ -0,0 +1 @@ +settings.php \ No newline at end of file diff --git a/page/ue.php b/page/ue.php new file mode 100755 index 0000000..49446a4 --- /dev/null +++ b/page/ue.php @@ -0,0 +1 @@ +ue.php \ No newline at end of file diff --git a/src/userlist.json b/src/userlist.json new file mode 100755 index 0000000..5b1059e --- /dev/null +++ b/src/userlist.json @@ -0,0 +1,32 @@ +{ + "eleve1": { + "permissions": "student", + "password" : "eleve1password" + }, + + "eleve2": { + "permissions": "student", + "password" : "eleve2password" + }, + + "prof1": { + "permissions": "teacher", + "password" : "prof1password" + }, + + "prof2": { + "permissions": "master", + "password" : "prof2password" + }, + + "admin1": { + "permissions": "admin", + "password" : "admin1password" + }, + + "admin2": { + "permissions": "admin", + "password" : "admin2password" + } + +} \ No newline at end of file