2016-02-01 22:09:35 +00:00
/***************************************/
/* */
/* GESTIONNAIRE D'OPTIMISATION DES */
/* RESSOURCES ET DE */
/* NAVIGATION EN AJAX */
/* */
/* Développé par {xdrm} */
/* */
/* GITHUB github.com/xdrm-brackets/ */
/* */
/***************************************/
2016-10-18 14:03:03 +00:00
function pageManagerClass ( ) { }
2016-02-01 22:09:35 +00:00
var ptrPageManagerClass ; // pointeur global pour l'utilisation de fonctions de fonctions
pageManagerClass . prototype = {
2016-10-18 14:03:03 +00:00
loaded : null , // la page chargée en ce moment
2016-02-01 22:09:35 +00:00
depJS : null , // la dépendance javascript
depCSS : null , // la dépendance css
xhr : [ ] , // tableau d'objets pour les requêtes ajax
2016-02-03 09:53:41 +00:00
activeXHR : null , // Contiendra l'instance XHR (ajax) en cours
2016-02-01 22:09:35 +00:00
page : null , // l'indice de la page courante dans pagelist
vars : [ ] , // les variables suivant le nom de la page dans l'URL
2016-10-18 14:03:03 +00:00
root : '' , // Racine du projet
2016-02-01 22:09:35 +00:00
path : '' , // le chemin du dossier contenant les pages (.php)
2016-02-14 19:37:41 +00:00
jsPath : 'js' , // le chemin du dossier contenant les scripts (.js)
cssPath : 'css' , // le chemin du dossier contenant les feuilles de style (.css)
2016-02-01 22:09:35 +00:00
pagelist : null , // la liste des pages pouvant être chargées
container : null , // élément DOM qui contiendra le contenu des pages à charger
2017-01-08 10:53:52 +00:00
refresher : function ( ) { } , // function appelée après refresh
2016-02-01 22:09:35 +00:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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
2016-10-18 14:03:03 +00:00
// for( var i = 0 ; i < this.xhr.length ; i++ ){
// this.xhr = this.xhr.splice(i, 1); // suppression entrée
// }
2016-02-01 22:09:35 +00:00
var index ;
2016-10-18 14:03:03 +00:00
// IE7+, Firefox, Chrome, Opera, Safari
// IE5, IE6
index = this . xhr . push ( window . XMLHttpRequest ? new XMLHttpRequest ( ) : new ActiveXObject ( 'Microsoft.XMLHttpRequest' ) ) - 1 ;
2016-02-01 22:09:35 +00:00
2016-02-03 09:53:41 +00:00
// On definit un pointeur sur l'instance XHR active (ajax)
this . activeXHR = this . xhr [ index ] ;
2016-10-18 14:03:03 +00:00
this . xhr [ index ] . addEventListener ( 'readystatechange' , function ( i ) {
// si la requete a ete supprimee, on quitte
if ( this . xhr [ i ] == undefined )
return ;
// Si la requête est terminée
if ( this . xhr [ i ] . readyState === 4 ) { // si la requête est terminée
if ( [ 0 , 200 ] . indexOf ( this . xhr [ i ] . status ) > - 1 ) // si fichier existe et reçu
pHandler ( this . xhr [ i ] . responseText ) ;
2016-02-01 22:09:35 +00:00
else // si code d'erreur retourne null
pHandler ( ) ;
2016-10-18 14:03:03 +00:00
// On supprime la requête
this . xhr [ i ] = null ;
// S'il n'y a plus de requête active, on supprime tout
var empty = true ;
for ( var i = 0 ; i < this . xhr . length ; i ++ )
if ( this . xhr [ i ] !== null ) {
empty = false ;
break ;
}
// Si tout est vide, on efface
empty && ( this . xhr = [ ] ) ;
}
} . bind ( this , index ) , false ) ;
2016-02-01 22:09:35 +00:00
// 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 [ index ] . open ( method , pLink , true ) ;
this . xhr [ index ] . send ( form ) ;
2016-02-02 13:03:22 +00:00
return this ;
2016-02-01 22:09:35 +00:00
} ,
/***************************************************** [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
2016-07-02 15:10:41 +00:00
2016-02-01 22:09:35 +00:00
// 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
2017-01-08 10:53:52 +00:00
if ( this . pagelist != null && /^(?:(?:https?:\/\/)?[^\/]+)\/([a-z0-9_]+)(?:\/|((?:\/\w+)+)\/?)?(#.*)?$/i . test ( url _data ) ) {
2016-02-01 22:09:35 +00:00
// si la page récupérée dans l'url est dans la liste => renvoi de l'objet [sinon] null
2017-01-08 10:53:52 +00:00
// on supprime la première entrée vide
var vars = RegExp . $2 . split ( '/' ) . slice ( 1 ) ;
console . log ( vars ) ;
2016-02-01 22:09:35 +00:00
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 ) ;
// si le fichier css existe
2016-10-18 14:03:03 +00:00
this . ajax ( this . root + this . path + '/' + this . cssPath + '/' + this . page + '.css' , function ( e ) {
2016-02-01 22:09:35 +00:00
if ( e != null ) { // on charge la dépendance CSS si le fichier existe
2016-10-18 14:03:03 +00:00
this . depCSS = document . createElement ( 'link' ) ;
this . depCSS . rel = 'stylesheet' ;
this . depCSS . type = 'text/css' ;
this . depCSS . href = this . root + this . path + '/' + this . cssPath + '/' + this . page + '.css' ;
document . head . appendChild ( this . depCSS ) ;
2016-02-01 22:09:35 +00:00
} else
2016-10-18 14:03:03 +00:00
console . warn ( '[loadDependencies_Error] - (' + this . root + this . path + '/' + this . cssPath + '/' + this . page + '.css)' ) ;
} . bind ( this ) ) ;
2016-02-01 22:09:35 +00:00
// si le fichier js existe
2016-10-18 14:03:03 +00:00
this . ajax ( this . root + this . path + '/' + this . jsPath + '/' + this . page + '.js' , function ( e ) {
2016-02-01 22:09:35 +00:00
if ( e != null ) { // on charge la dépendance JS si le fichier existe
2016-10-18 14:03:03 +00:00
this . depJS = document . createElement ( 'script' ) ;
this . depJS . type = 'text/javascript' ;
this . depJS . src = this . root + this . path + '/' + this . jsPath + '/' + this . page + '.js' ;
document . head . appendChild ( this . depJS ) ;
2016-02-01 22:09:35 +00:00
} else
2016-10-18 14:03:03 +00:00
console . warn ( '[loadDependencies_Error] - (' + this . root + this . path + '/' + this . jsPath + '/' + this . page + '.js)' ) ;
} . bind ( this ) ) ;
2016-02-01 22:09:35 +00:00
} ,
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2016-07-02 15:10:41 +00:00
Met à jour l ' URL de la page en fonction de la page chargée et des
2016-02-01 22:09:35 +00:00
variables associées ( ne recharge aucune ressource )
=== === === === === === === === === === === === === === === === === === === === === === === == * /
updateURL : function ( ) {
if ( this . vars . length > 0 ) // si il y a des variables
2016-10-18 14:03:03 +00:00
window . history . pushState ( this . page , this . page , this . root + '/' + this . page + '/' + this . vars . join ( '/' ) + '/' ) ;
2016-02-01 22:09:35 +00:00
else // s'il n'y en a pas
2016-10-18 14:03:03 +00:00
window . history . pushState ( this . page , this . page , this . root + '/' + this . page + '/' ) ;
2016-02-01 22:09:35 +00:00
// on peut récupérer le nom de la page (quand on fait retour en arrière de l'historique)
// dans la variable : window.history.state
} ,
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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
2016-07-02 15:10:41 +00:00
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
2016-02-01 22:09:35 +00:00
* * 1. pPageList et pContainer doivent être mis en paramètres uniquement à la première utilisation
2016-07-02 15:10:41 +00:00
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
2016-02-01 22:09:35 +00:00
* * * la première page du tableau est la page par défaut ( qui est chargée si l ' URL ne contient
2016-07-02 15:10:41 +00:00
pas la page ou si la page de l ' URL ne correspond à aucune page de la liste )
2016-02-01 22:09:35 +00:00
=== === === === === === === === === === === === === === === === === === === === === === === === == * /
2016-10-18 14:03:03 +00:00
setPage : function ( pName , pPath , pContainer , pPageList , pRoot ) {
2016-02-01 22:09:35 +00:00
// 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)
2016-10-18 14:03:03 +00:00
// this.page = this.pagelist[0];
// Gestion de pRoot si racine autre que racine du vhost
this . root = ( typeof pRoot == 'string' ) ? pRoot : this . root ;
2016-02-01 22:09:35 +00:00
// 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 ;
2016-10-18 14:03:03 +00:00
// si this.pagelist && this.container ne sont pas null
2017-01-08 10:53:52 +00:00
if ( this . pagelist && this . container ) {
// Si on veut just `refresh` la page
if ( pName === true ) {
this . ajax ( this . root + this . path + '/' + this . page + '.php' , function ( e ) {
this . container . innerHTML = e ;
this . loadDependencies ( ) ;
this . refresher . apply ( this ) ;
} . bind ( this ) , 'POST' , fd ) ;
return this ;
2016-10-18 14:03:03 +00:00
2016-02-01 22:09:35 +00:00
// si le pName est renseigné et qu'il est dans pagelist
2017-01-08 10:53:52 +00:00
} else if ( typeof pName == 'string' && this . pagelist . indexOf ( pName ) > - 1 ) {
2016-02-01 22:09:35 +00:00
// affecte pName à l'attribut page
this . page = pName ;
// formulaire POST
var fd = new FormData ( ) ;
for ( var i = 0 ; i < this . vars . length ; i ++ )
fd . append ( this . vars [ i ] , null ) ;
2016-07-02 15:10:41 +00:00
2016-10-18 14:03:03 +00:00
this . ajax ( this . root + this . path + '/' + this . page + '.php' , function ( e ) {
this . container . innerHTML = e ;
this . loadDependencies ( ) ;
} . bind ( this ) , 'POST' , fd ) ;
2016-02-01 22:09:35 +00:00
// change l'URL en conséquences(stateObj, titre, url)
this . updateURL ( ) ;
2016-07-02 15:10:41 +00:00
2016-02-01 22:09:35 +00:00
} 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 ) {
// 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 ) ;
}
2016-10-18 14:03:03 +00:00
// si différent de la page actuelle, on charge la page
if ( urlGet . page == this . page ) {
return this ;
}
this . page = urlGet . page ;
this . ajax ( this . root + this . path + '/' + this . page + '.php' , function ( e ) {
this . container . innerHTML = e ;
this . loadDependencies ( ) ;
} . bind ( this ) , 'POST' , fd ) ;
2016-02-01 22:09:35 +00:00
// change l'URL en conséquences(stateObj, titre, url)
this . updateURL ( ) ;
2016-07-02 15:10:41 +00:00
2016-02-01 22:09:35 +00:00
} else // si l'url ne contient rien, on charge la page par défaut
this . setPage ( this . pagelist [ 0 ] ) ;
}
} else
2016-02-02 10:09:48 +00:00
console . warn ( 'pagelist et container manquant' ) ;
2016-02-02 13:03:22 +00:00
return this ;
2016-02-02 10:09:48 +00:00
} ,
/ * R e c h a r g e m e n t d e l a p a g e c o u r a n t e
*
* @ action Recharge la page en cours en conservant les variables
*
* /
2017-01-08 10:53:52 +00:00
refresh : function ( refresher ) {
if ( refresher instanceof Function ) {
this . refresher = refresher ;
return ;
} else {
return this . setPage ( true ) ;
}
2016-02-02 13:03:22 +00:00
2016-02-01 22:09:35 +00:00
}
2016-10-18 14:03:03 +00:00
} ;