Merge de @wrapper_backup sur le design de @dev_flat
This commit is contained in:
parent
d7c9b0d3d8
commit
7a8131cfba
|
@ -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<Object> l'objet passé en JSON à API.php
|
||||||
|
* @param pHandler<Function> fonction qui s'éxécutera lors de la réponse (1 argument -> réponse<Object>)
|
||||||
|
*
|
||||||
|
* @return answer<Object> 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 );
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,99 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/* GESTION DE L'AUTHENTIFICATION - SI L'UTILISATEUR EST CONNECTÉ */
|
||||||
|
|
||||||
|
// A faire
|
||||||
|
/* si l'utilisateur est connecté */
|
||||||
|
if( true ){
|
||||||
|
|
||||||
|
$answer = new stdClass(); // on initialise la réponse (Objet vide)
|
||||||
|
|
||||||
|
/* si $_POST['json'] existe */
|
||||||
|
if( !empty($_POST) && isset($_POST['json']) ){
|
||||||
|
|
||||||
|
$request = json_decode( $_POST['json'] ); // on décode la requête
|
||||||
|
|
||||||
|
|
||||||
|
/* si le JSON n'est pas corrompu (décodable) */
|
||||||
|
if( $request != null ){ // si le json n'est pas corrompu
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ROUTAGE (niveau 0) */
|
||||||
|
switch( $request->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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -1,4 +1,4 @@
|
||||||
#CONTAINER div{
|
#CONTAINER section{
|
||||||
/* position */
|
/* position */
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -17,4 +17,4 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#CONTAINER div.active{ z-index: 8; }
|
#CONTAINER section.active{ z-index: 8; }
|
42
css/menu.css
42
css/menu.css
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#MENU a{
|
#MENU span{
|
||||||
/* position */
|
/* position */
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -79,8 +79,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#MENU a:hover,
|
#MENU span:hover,
|
||||||
#MENU a.active{
|
#MENU span.active{
|
||||||
background: #233342 url(../src/menu_icon/home_grayscale.svg) left 1em center no-repeat;
|
background: #233342 url(../src/menu_icon/home_grayscale.svg) left 1em center no-repeat;
|
||||||
background-size: 1.7em;
|
background-size: 1.7em;
|
||||||
|
|
||||||
|
@ -89,24 +89,24 @@
|
||||||
|
|
||||||
|
|
||||||
/* gestion des différentes icônes */
|
/* gestion des différentes icônes */
|
||||||
#MENU a:nth-child(2){ background-image: url(../src/menu/menu_icon/home.svg); }
|
#MENU span: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 span: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 span: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 span: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 span: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(7){ background-image: url(../src/menu/menu_icon/settings.svg); }
|
||||||
|
|
||||||
|
|
||||||
/* gestion de l'activation des différentes icônes */
|
/* gestion de l'activation des différentes icônes */
|
||||||
#MENU a:nth-child(2):hover,
|
#MENU span:nth-child(2):hover,
|
||||||
#MENU a:nth-child(2).active{ background-image: url(../src/menu/menu_icon/home@hover.svg); }
|
#MENU span:nth-child(2).active{ background-image: url(../src/menu/menu_icon/home@hover.svg); }
|
||||||
#MENU a:nth-child(3):hover,
|
#MENU span:nth-child(3):hover,
|
||||||
#MENU a:nth-child(3).active{ background-image: url(../src/menu/menu_icon/groups@hover.svg); }
|
#MENU span:nth-child(3).active{ background-image: url(../src/menu/menu_icon/groups@hover.svg); }
|
||||||
#MENU a:nth-child(4):hover,
|
#MENU span:nth-child(4):hover,
|
||||||
#MENU a:nth-child(4).active{ background-image: url(../src/menu/menu_icon/ue@hover.svg); }
|
#MENU span:nth-child(4).active{ background-image: url(../src/menu/menu_icon/ue@hover.svg); }
|
||||||
#MENU a:nth-child(5):hover,
|
#MENU span:nth-child(5):hover,
|
||||||
#MENU a:nth-child(5).active{ background-image: url(../src/menu/menu_icon/modules@hover.svg); }
|
#MENU span:nth-child(5).active{ background-image: url(../src/menu/menu_icon/modules@hover.svg); }
|
||||||
#MENU a:nth-child(6):hover,
|
#MENU span:nth-child(6):hover,
|
||||||
#MENU a:nth-child(6).active{ background-image: url(../src/menu/menu_icon/marks@hover.svg); }
|
#MENU span:nth-child(6).active{ background-image: url(../src/menu/menu_icon/marks@hover.svg); }
|
||||||
#MENU a:nth-child(7):hover,
|
#MENU span:nth-child(7):hover,
|
||||||
#MENU a:nth-child(7).active{ background-image: url(../src/menu/menu_icon/settings@hover.svg); }
|
#MENU span:nth-child(7).active{ background-image: url(../src/menu/menu_icon/settings@hover.svg); }
|
||||||
|
|
20
index.php
20
index.php
|
@ -54,6 +54,8 @@ $notifNotifNum = 5;
|
||||||
|
|
||||||
|
|
||||||
<!-- Dépendences Javascript -->
|
<!-- Dépendences Javascript -->
|
||||||
|
<script type='text/javascript' src='API.js' ></script> <!-- Gestion des raccourcis clavier -->
|
||||||
|
<script type='text/javascript' src='js/pageManager.js' ></script> <!-- Gestion des raccourcis clavier -->
|
||||||
<script type='text/javascript' src='js/shortcut.js' ></script> <!-- Gestion des raccourcis clavier -->
|
<script type='text/javascript' src='js/shortcut.js' ></script> <!-- Gestion des raccourcis clavier -->
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
@ -65,12 +67,12 @@ $notifNotifNum = 5;
|
||||||
<!-- MENU DE LA PAGE -->
|
<!-- MENU DE LA PAGE -->
|
||||||
<nav id='MENU'>
|
<nav id='MENU'>
|
||||||
<div class='userdata M'>mrd1609a</div>
|
<div class='userdata M'>mrd1609a</div>
|
||||||
<a href='index.php' class='active'>Accueil </a>
|
<span data-link='home' >Accueil </span>
|
||||||
<a href='groups.php' >Groupes </a>
|
<span data-link='groups' >Groupes </span>
|
||||||
<a href='ue.php' >Suivi </a>
|
<span data-link='ue' >Suivi </span>
|
||||||
<a href='modules.php' >Modules </a>
|
<span data-link='modules' >Modules </span>
|
||||||
<a href='marks.php' >Notes </a>
|
<span data-link='marks' >Notes </span>
|
||||||
<a href='settings.php'>Paramètres </a>
|
<span data-link='settings'>Paramètres</span>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- HEADER DE LA PAGE -->
|
<!-- HEADER DE LA PAGE -->
|
||||||
|
@ -109,11 +111,7 @@ $notifNotifNum = 5;
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- CONTENEUR DE LA PAGE -->
|
<!-- CONTENEUR DE LA PAGE -->
|
||||||
<div id='CONTAINER'>
|
<div id='CONTAINER'></div>
|
||||||
<div name='home'>Contenu de la section #HOME</div>
|
|
||||||
<div name='groups'>Contenu de la section #GROUPES</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 = {
|
var DOM = {
|
||||||
WRAPPER : document.querySelector('#WRAPPER'),
|
WRAPPER : document.querySelector('#WRAPPER'),
|
||||||
MENU : document.querySelector('#MENU'),
|
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
|
/* [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<Element> 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 <Element> de type <li> 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+")");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
/* 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<Element> 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 <Element> de type HGROUP [ET]
|
||||||
|
if( subSection instanceof Element && subSection.tagName == 'SPAN' && subSection.dataset.hasOwnProperty('sectname') ){
|
||||||
|
|
||||||
// on essaie de récupérer l'ancien "lien"
|
// on essaie de récupérer l'ancien "lien"
|
||||||
var lastActive = document.querySelector('#SUBHEADER > nav > span.active');
|
var lastActive = document.querySelector('#SUBHEADER > nav > span.active');
|
||||||
if( lastActive != null ) // si on a trouvé qqch
|
if( lastActive != null ) // si on a trouvé qqch
|
||||||
lastActive.className = ''; // on le désactive
|
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
|
// on essaie de récupérer l'ancienne section active
|
||||||
var lastSection = document.querySelector('#CONTAINER div.active');
|
var lastSection = document.querySelector('#CONTAINER section.active');
|
||||||
if( lastSection != null ) // si on a trouvé qqch
|
if( lastSection != null ) // si on a trouvé qqch
|
||||||
lastSection.className = ''; // on la désactive
|
lastSection.className = ''; // on la désactive
|
||||||
|
|
||||||
// on active la page associée
|
// on active la page associée
|
||||||
var target = document.querySelector('#CONTAINER > div[name='+e.target.dataset.sectname+']');
|
console.log( document.querySelector('#CONTAINER section[name=home]') );
|
||||||
|
var target = document.querySelector('#CONTAINER section[name='+subSection.dataset.sectname+']');
|
||||||
if( target != null )
|
if( target != null )
|
||||||
target.className = 'active';
|
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<Element> le formulaire cible
|
||||||
|
* @param pHandler<Function> 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
|
||||||
|
*
|
||||||
|
* <form id='nomFormulaire'>
|
||||||
|
*
|
||||||
|
* <input type='text' name='nomDuChamp1' value='valeurDuChamp1'>
|
||||||
|
* <input type='mail' name='nomduChamp2' value='valeurDuChamp2'>
|
||||||
|
*
|
||||||
|
* <input type='submit' value='VALIDER'>
|
||||||
|
*
|
||||||
|
* </form>
|
||||||
|
*
|
||||||
|
* @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);
|
}, false);
|
||||||
|
|
||||||
/* on active la section au chargement */
|
// on définit l'évènement de l'appui sur la touche [ENTRER]
|
||||||
// on essaie de récupérer le lien actif
|
pForm.addEventListener('keydown', function(e){
|
||||||
var lastActive = document.querySelector('#SUBHEADER > nav > span.active');
|
if(e.keyCode==13) submitEvent(e.target); // si c'est la bonne touche, on submit le formulaire
|
||||||
if( lastActive != null ){ // si on trouve qqch
|
}, 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<string> le lien à charger
|
||||||
|
- pHandler<function> 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<string> type de méthode, vaut 'POST' ou 'GET' et vaut 'POST' par défaut ou s'il n'est pas renseigné
|
||||||
|
- pForm<FormData> 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 <head>, 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<string> le nom de la page à charger (lettres, chiffres, underscore) (*)
|
||||||
|
- pPath<string> chemin (relatif ou absolu) du dossier contenant les pages de même nom de fichier que le nom (extension .php)
|
||||||
|
- pContainer<Element> l'élément du DOM qui contiendra la page chargée (**)
|
||||||
|
- pPageList<Array<string>> 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');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<keyCode> ; f<eventIndex> ; h<handler()> */
|
||||||
|
// 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é'); }
|
||||||
|
// );
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class DataBase{
|
||||||
|
|
||||||
|
/* ATTRIBUTS */
|
||||||
|
private $host;
|
||||||
|
private $dbname;
|
||||||
|
private $username;
|
||||||
|
private $password;
|
||||||
|
|
||||||
|
private $connection;
|
||||||
|
|
||||||
|
public function __construct($host, $dbname, $username, $password){
|
||||||
|
this->connection = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************
|
||||||
|
* *
|
||||||
|
* MANAGER DE SECURITE GENERALE ET SPECIFIQUE *
|
||||||
|
* *
|
||||||
|
************************************************************
|
||||||
|
* *
|
||||||
|
* [0] Constantes *
|
||||||
|
* [1] Session & redirection *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
***********************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* [0] CONSTANTES
|
||||||
|
============================================================*/
|
||||||
|
function getPermissions(){ return array('student', 'teacher', 'master', 'admin'); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* [1] SESSIONS & REDIRECTION
|
||||||
|
============================================================*/
|
||||||
|
|
||||||
|
|
||||||
|
/* ETABLIT UNE SESSION SÉCURISÉE
|
||||||
|
*
|
||||||
|
* [1] Définit un id_session (PHPSESSID) unique et propre à une connection
|
||||||
|
* + propre à un navigateur (navigateur, version, OS, système X, ...)
|
||||||
|
* + propre à un accès (ip publique = box)
|
||||||
|
*
|
||||||
|
* [2] Démarre la session
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function session_init(){
|
||||||
|
session_id( // on définit le session id
|
||||||
|
sha1( // qui est un Hash MD5
|
||||||
|
$_SERVER['HTTP_USER_AGENT']. // qui correspond aux infos système disponibles de l'utilisateur
|
||||||
|
$_SERVER['REMOTE_ADDR'] // et de son ip publique
|
||||||
|
)
|
||||||
|
);
|
||||||
|
session_start(); // on démarre la session
|
||||||
|
|
||||||
|
$PERMISSIONS = getPermissions();
|
||||||
|
|
||||||
|
// on vérifie l'intégrité des variables session
|
||||||
|
$usernameDefinedProperly = isset($_SESSION['username']) && !empty($_SESSION['username']) && gettype($_SESSION['username']) == 'string' && strlen($_SESSION['username']) > 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,135 @@
|
||||||
|
<?php require('manager/security.php'); session_init();
|
||||||
|
|
||||||
|
/***********************************************************
|
||||||
|
* *
|
||||||
|
* MANAGER DES UTILISATEURS *
|
||||||
|
* *
|
||||||
|
************************************************************
|
||||||
|
* *
|
||||||
|
* [0] Constantes *
|
||||||
|
* [1] ROUTAGE de niveau 1 *
|
||||||
|
* [2] Authentification *
|
||||||
|
* [a] userlist *
|
||||||
|
* [b] connection *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
* *
|
||||||
|
***********************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* [1] ROUTAGE DE NIVEAU 1
|
||||||
|
============================================================*/
|
||||||
|
function user_switch_level_1($request, $answer){
|
||||||
|
|
||||||
|
switch( $request->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<String> Identifiant de l'utilisateur
|
||||||
|
* @param password<String> 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';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
|
@ -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); });
|
||||||
|
}
|
||||||
|
);
|
|
@ -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(){} );
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php require('../manager/security.php'); session_init();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/****************************/
|
||||||
|
/* FORMULAIRE DE CONNECTION */
|
||||||
|
/****************************/
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<hgroup class='active'>Connection</hgroup>
|
||||||
|
<section>
|
||||||
|
|
||||||
|
<form id='user' style='width: 20em; margin-left: calc(50% - 20em/2);'>
|
||||||
|
<input type='text' name='username' placeholder='username' class='user' style='width:calc( 100% - 2*1.8em );'>
|
||||||
|
<input type='password' name='password' placeholder='password' style='width:calc( 100% - 2*1.8em );'>
|
||||||
|
<input type='button' name='submit' value='Connection' style='width:50%;margin-left: 25%;'>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<?php
|
||||||
|
/***************************/
|
||||||
|
/* VISUALISATION DU PROFIL */
|
||||||
|
/***************************/
|
||||||
|
|
||||||
|
|
||||||
|
if( isset($_SESSION['permissions']) && $_SESSION['permissions'] != null ){ ?>
|
||||||
|
|
||||||
|
|
||||||
|
<hgroup>Mon Profil</hgroup>
|
||||||
|
<section>
|
||||||
|
|
||||||
|
username = <?php echo $_SESSION['username']; ?><br>
|
||||||
|
droits = <?php echo $_SESSION['permissions']; ?>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<?php } ?>
|
|
@ -0,0 +1 @@
|
||||||
|
career.php
|
|
@ -0,0 +1,145 @@
|
||||||
|
<?php require('../manager/security.php'); session_init();
|
||||||
|
|
||||||
|
/****************************************
|
||||||
|
* *
|
||||||
|
* SECTION "GROUPES" *
|
||||||
|
* *
|
||||||
|
*****************************************
|
||||||
|
*
|
||||||
|
* [1] Mon Groupe (studend + prof)
|
||||||
|
* [2] Tout les groupes (tous connecté)
|
||||||
|
* [3] Modifier les groupes (admin)
|
||||||
|
* [4] Répartir les élèves (admin)
|
||||||
|
*
|
||||||
|
*****************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* [1] Mon Groupe (eleve)
|
||||||
|
============================================*/
|
||||||
|
if( $_SESSION['permissions'] == 'student' ){ ?>
|
||||||
|
<hgroup class='active'>Mon Groupe</hgroup>
|
||||||
|
<section>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Nom</th>
|
||||||
|
<th>Prénom</th>
|
||||||
|
<th>Blablabla</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>001</td>
|
||||||
|
<td>002</td>
|
||||||
|
<td>003</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>001</td>
|
||||||
|
<td>002</td>
|
||||||
|
<td>003</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>001</td>
|
||||||
|
<td>002</td>
|
||||||
|
<td>003</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>001</td>
|
||||||
|
<td>002</td>
|
||||||
|
<td>003</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>001</td>
|
||||||
|
<td>002</td>
|
||||||
|
<td>003</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>001</td>
|
||||||
|
<td>002</td>
|
||||||
|
<td>003</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>001</td>
|
||||||
|
<td>002</td>
|
||||||
|
<td>003</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>001</td>
|
||||||
|
<td>002</td>
|
||||||
|
<td>003</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>001</td>
|
||||||
|
<td>002</td>
|
||||||
|
<td>003</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>001</td>
|
||||||
|
<td>002</td>
|
||||||
|
<td>003</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
<?php } ?>
|
||||||
|
|
||||||
|
|
||||||
|
<?php if( $_SESSION['permissions'] == 'teacher' ){ ?>
|
||||||
|
<hgroup class='active'>Mes Groupe</hgroup>
|
||||||
|
<section>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Nom du groupe</th>
|
||||||
|
<th>Nombre d'élèves</th>
|
||||||
|
<th>Nombre de modules</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>A</td>
|
||||||
|
<td>30</td>
|
||||||
|
<td>2</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>B</td>
|
||||||
|
<td>28</td>
|
||||||
|
<td>3</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>D</td>
|
||||||
|
<td>32</td>
|
||||||
|
<td>1</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>F</td>
|
||||||
|
<td>21</td>
|
||||||
|
<td>2</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
<?php } ?>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<hgroup>Tout les groupes</hgroup>
|
||||||
|
<section>
|
||||||
|
Tout les groupes<br/>
|
||||||
|
bla<br/>
|
||||||
|
bla<br/>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<hgroup>Mon Groupe 2</hgroup>
|
||||||
|
<section>
|
||||||
|
Mon Groupe 2<br/>
|
||||||
|
bla<br/>
|
||||||
|
bla<br/>
|
||||||
|
</section>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php require('../manager/security.php'); session_init();
|
||||||
|
|
||||||
|
/****************************************
|
||||||
|
* *
|
||||||
|
* SECTION "GROUPES" *
|
||||||
|
* *
|
||||||
|
*****************************************
|
||||||
|
*
|
||||||
|
* [1] Présentation (studend + prof)
|
||||||
|
* [2] Tout les groupes (tous connecté)
|
||||||
|
* [3] Modifier les groupes (admin)
|
||||||
|
* [4] Répartir les élèves (admin)
|
||||||
|
*
|
||||||
|
*****************************************/
|
||||||
|
|
||||||
|
?>
|
||||||
|
<section name='home'>Contenu de la section #HOME</section>
|
||||||
|
<section name='groups'>Contenu de la section #GROUPES</section>
|
|
@ -0,0 +1 @@
|
||||||
|
Notes ici !!!
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php require('../manager/security.php'); session_init(); ?>
|
||||||
|
|
||||||
|
|
||||||
|
modules.php
|
|
@ -0,0 +1 @@
|
||||||
|
semestre.php
|
|
@ -0,0 +1 @@
|
||||||
|
settings.php
|
|
@ -0,0 +1 @@
|
||||||
|
ue.php
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue