Trieur Organisé de Solutions et de Ressources Informatiques

logo du site TOSRI

Développement › Javascript

Article(s) du 4 mars 2011

Niveau : personne ayant des bases en informatique (terminologie, principe)

Calendrier perpétuel

Temps : 30min

Qui n'a jamais rêvé d'un beau calendrier sur son site internet ?

On va en cherché vite vite sur internet !!

Mais quel jour tombe la St Valentin en 2025 (un jeudi pour info) ?!?

On prend des scripts déjà fait et ça marche très bien. Il existe pourtant un fait qui titille les codeurs fous (pourquoi vous me regardez tous ?...). Les calendriers et systèmes de dates sont basés sur le temps des machines informatiques. Celles-ci prennent pour la plupart comme référence le Jeudi 1er Janvier 1970. Donc les dates antérieures peuvent aller se gratter. ^^

Cependant il existe ce que l'on appelle des calendriers perpétuels, des algorithmes capables de donner le jour sans avoir de référence initiale (comme le samedi 1er janvier 2000 par exemple).

Durant mes recherches de codes je suis tombé sur ce site internet http://cosmos2000.chez.com/ et plus particulièrement sur cet article : http://cosmos2000.chez.com/Vendredi13/CalendrierArlot.html que je vous invite à lire. Le tableau affiché, que je remet ici, m'a donné envie de le transformer en algorithme que je vais vous présenter. Il est vrai que le site en question propose plusieurs vérificateurs que vous pouvez utiliser pour vérifier vos dates, moi je vous propose un algorithme personnel.

Tableau :

INDICE
ANNÉES

MOISQUANTIÈMES(4)
ou jour
en nombre
(1er au 31)
JOURS
CENTAINESDIZAINESUNITÉS
Cas de
dizaine:
Calendrier
julien(1)
Calendrier
grégorien(2)
PaireImpairePaireImpaire
14   1115 19 23 27 31...2 55Mai1 8 15 22 29Lun.
23   10 610   60Août Fév. B(3)2 9 16 23 30Mar.
32   918 22 26 30 34... 51   71   6Fév. Mars Nov.3 10 17 24 31Mer.
41   8   15 0927Juin4 11 18 25Jeu.
50   7   1417 21 25 29 33...4 3   82   8Sep. Déc.5 12 19 26Ven.
66   13 8393   9Avr. Juil. Jan. B(3)6 13 20 27Sam.
05   1216 20 24 28 32... 744Jan. Oct.7 14 21 28Dim.

(1) Jusqu'au 4 oct. 1582    (2) À partir du 15 oct. 1582; progression annuelle "..." par multiples de 4
(3) Jan. B et Fév. B liés aux années bissextiles (4) Progression par multiples de 7 (jours de semaine)

A présent voyons l'algorithme Javascript complet et commenté s'il vous plait :

3 fonctions obligatoires :

// retourne vrai si l'année est bissextile (surprenant n'est-ce pas ?)
function anneeBissext(a){
    return ( (a % 100 != 0 && a % 4 == 0) || (a % 400 == 0) );
}

// retourne trois caractères possible : 'G'regorien, 'J'ulien, ''aucun
function estJulGreg(siecle, annee, mois, jour){
    var estJul = (siecle <= 15);
    if(siecle == 15){
        estJul = (annee <= 82);
        if(annee == 82){
            estJul = (mois <= 10);
            if(mois == 10){
                estJul = (jour <= 4);
            }
        }
    }

    var estGreg = (siecle >= 15);
    if(siecle == 15){
        estGreg = (annee >= 82);
        if(annee == 82){
            estGreg = (mois >= 10);
            if(mois == 10){
                estGreg = (jour <= 15);
            }
        }
    }

    return (estGreg) ? "G" : ((estJul) ? "J" : "");
}

// http://cosmos2000.chez.com/Vendredi13/CalendrierArlot.html
// Calendrier perpétuel J.E. ARLOT
function calculJour(siecle, annee, mois, jour){

    // le but est de faire une somme d'indice avec le siècle, la dizaine d'année, l'unité d'année
    // le mois et le jour. On déclare donc autant de variables.
    var sommeIndices = 0, indiceS = 0, indiceAD = 0, indiceAU = 0, indiceM = 0, indiceJ = 0;

    // on calcul la dizaine et l'unité d'année
    var dizaineAnnee = Math.floor(annee / 10), uniteAnnee = annee - (dizaineAnnee * 10);

    // l'indice des siècles dépend du type de calendrier
    if(estJulGreg(siecle, annee, mois, jour) == "J"){
        // calendrier Julien
        switch(siecle){
        case 4: case 11: indiceS += 1; break;
        case 3: case 10: indiceS += 2; break;
        case 2: case  9: indiceS += 3; break;
        case 1: case  8: case 15: indiceS += 4; break;
        case 0: case  7: case 14: indiceS += 5; break;
        case 6: case 13: indiceS += 6; break;
        case 5: case 12: indiceS += 0; break;
        }
    }else if(estJulGreg(siecle, annee, mois, jour) == "J"){
        // calendrier Gregorien
        switch((siecle - 15) % 4){
        case 0: indiceS += 1; break;    // siecle 15 19 23 27 31...
        case 1: indiceS += 0; break;    // siecle 16 20 24 28 32...
        case 2: indiceS += 5; break;    // siecle 17 21 25 29 33...
        case 3: indiceS += 3; break;    // siecle 18 22 26 30 34...
        }
    }
    // on vient de traiter les colonnes 2 et 3 du tableau

    // on traite la dizaine d'année
    switch(dizaineAnnee){
    case 0: indiceAD += 4; break;
    case 1: indiceAD += 2; break;
    case 2: indiceAD += 1; break;
    case 3: indiceAD += 6; break;
    case 4: indiceAD += 5; break;
    case 5: indiceAD += 3; break;
    case 6: indiceAD += 2; break;
    case 7: indiceAD += 0; break;
    case 8: indiceAD += 6; break;
    case 9: indiceAD += 4; break;
    }
    // on vient de traiter les colonnes 4 et 5 du tableau

    // on traite l'unité d'année avec la parité de la dizaine d'année
    var pair = (dizaineAnnee % 2 == 0);
    switch(uniteAnnee){
    case 0: indiceAU += 2;    break;
    case 1: indiceAU += 3;    break;
    case 2: indiceAU += (pair) ? 4 : 5;    break;
    case 3: indiceAU += (pair) ? 5 : 6;    break;
    case 4: indiceAU += 0;    break;
    case 5: indiceAU += 1;    break;
    case 6: indiceAU += (pair) ? 2 : 3;    break;
    case 7: indiceAU += (pair) ? 3 : 4;    break;
    case 8: indiceAU += 5;    break;
    case 9: indiceAU += 6;    break;
    }
    // on vient de traiter les colonnes 6 et 7 du tableau

    // on traite le mois avec les années bissextiles ou non
    switch(mois){
    case  1: indiceM += (anneeBissext(siecle * 100 + annee)) ? 6 : 0;    break;
    case  2: indiceM += (anneeBissext(siecle * 100 + annee)) ? 2 : 3;    break;
    case  3: indiceM += 3;    break;
    case  4: indiceM += 6;    break;
    case  5: indiceM += 1;    break;
    case  6: indiceM += 4;    break;
    case  7: indiceM += 6;    break;
    case  8: indiceM += 2;    break;
    case  9: indiceM += 5;    break;
    case 10: indiceM += 0;    break;
    case 11: indiceM += 3;    break;
    case 12: indiceM += 5;    break;
    }
    // on vient de traiter la colonnes 8 du tableau

    // on traite le jour
    indiceJ += (jour % 7 != 0) ? (jour % 7) : 7;
    // il y a un test couplé au modulo pour avoir 7 au lieu de 0
    // car le 0 n'existe pas dans un mois et que nous avons bien le 7, le 14, le 21 et le 28
    // et que faire un modulo 7 ne donnera toujours que : 0, 1, 2, 3, 4, 5, 6

    // on finit faire la somme de tous ces indices et on fait un dernier modulo 7
    sommeIndices = indiceS + indiceAD + indiceAU + indiceM + indiceJ;
    // on obtient un indice de semaine de 0 (Dim.) à 6 (Sam.)
    return sommeIndices % 7;
}

Malgré tout cette fonction ne teste pas la validité de la date, il faut donc la précéder d'une fonction de vérification et en utilisant la fonction "estJulGreg" vous pourrez savoir si la date est dans l'intervalle des quelques jours manquants dans notre calendrier (transition entre Grégorien et Julien).

Donc j'attends vos propositions de scripts à coupler avec mes fonctions pour avoir un beau résultat, mais nan je plaisante.
(Cela dit si vous avez des propositions à faire je suis preneur.)

Ce code étant simple vous pourrez facilement l'adapter à de nombreux langages de programmation.


Article(s) du 23 octobre 2010

Niveau : personne ayant des bases en informatique (terminologie, principe)

AJAX : simplifions la manipulation

Obligatoire : l'AJAX s'utilise sur un serveur pour pouvoir utiliser le PHP

introduction

AJAX ce n'est pas de la lessive, il faut arrêter de faire cette blague, elle est de plus en plus lourde. C'est une technologie basée sur le javascript et qui, pour faire simple, sert à faire des trucs de fous. Comme par exemple un changement de contenu de page sans la recharger en ayant exécuté du PHP. Pour ceux qui ne connaissent pas, ça ne veut rien dire, pour ceux qui connaissent c'est génial !!

Je vais donc vous donner 4 fichiers : 1 fichier HTML d'exemple, 1 fichier JavaScript lié à l'exemple, 1 fichier JavaScript qui utilise de l'AJAX et 1 fichier PHP qui est lié à l'exemple. Ces fichiers sont téléchargeables en pièces jointes à l'article.

Le principe de cet exemple est le suivant :

Nous avons une page web contenant un formulaire sur un serveur, jusque là tout va bien. Ce que nous allons faire c'est qu'à la validation du formulaire (via le submit classique) nous allons exécuter une fonction javascript qui fera appel à de l'AJAX et qui bloquera le transfert classique des variables avec la redirection puis qui remplacera le contenu d'une DIV par un message avec les valeurs du formulaire.

En gros voyez ça comme si vous récupériez les variables du formulaire, vous les envoyez vous-même à un script PHP qui les traite et vous les renvoie sans que vous rechargiez la page. Ensuite vous bloquez le formulaire pour que la page ne change pas. Magique non !?

L'AJAX ne sert pas que pour les formulaires, mais cet exemple comme son nom l'indique est un exemple ...

ajax.js

Ce fichier comprend 3 fonctions. La 1ere est intéressante, mais y toucher serait dangereux ... Elle sert à créer des objets spéciaux utilisés pour AJAX. La seconde fonction est celle que vous allez le plus utiliser et son nom la rend assez explicite : executerAjax ...
Elle prend plusieurs valeurs en paramètres :

  1. les options, ou plutôt variables sous la forme d'une chaine de caractères du type "variable1=contenu1&variable2=contenu2"
  2. le chemin du fichier PHP à exécuter
  3. une fonction javascript à vous ; elle doit prendre une variable en paramètre et il ne sert à rien de lui donner une valeur de retour ; lorsque le PHP sera exécuté, votre fonction sera appelée avec les données reçues
  4. la méthode d'envoi des variables 'get' ou 'post', ce n'est pas obligatoire, si vous ne le mettez pas 'get' sera pris
3eme fonction : getVarsFromForm
Je l'ai rajoutée, car elle peut être assez utile. Ce qu'elle fait ?
  1. elle prends le nom du formulaire que vous lui avez donné
  2. trouve le formulaire associé
  3. fait la liste de tous les champs qu'il contient
  4. prends le name des champs et le couple avec leurs valeurs
  5. retourne la chaine de caractères
Cette fonction sert surtout à éviter de galérer à récupérer toutes les valeurs de champs à la main.
Car après tout c'est bien connu les codeurs sont des feignants, donc ils codent encore plus pour moins se prendre la tête !! logique non ?

index.html

Dans ce fichier d'exemple qu'est-ce qui est important ?

D'abord, ceci :

<script type="text/javascript" src="ajax.js"></script>
<script type="text/javascript" src="script.js"></script>


Ces deux lignes servent à dire "d'abord j'inclus les fonctions qui vont utiliser AJAX, puis j'inclus le fichier qui contient le javascript général de la page".

Ensuite :

<form name="form_test" action="script.php" method="post">

La définition du formulaire est importante :

  • le nom "form_test" sert d'identification pour les fonctions javascript
  • l'action "script.php" s'il y a une erreur pour une raison quelconque et que le formulaire se valide on va quand même l'envoyer vers le traitement PHP
  • la méthode d'envoi "post" pour la même raison que ci-dessus


A titre de remarque :
<select id="civilite" name="civilite">
Le formulaire n'a qu'un seul champ : une liste sélection dont le nom est "civilite"

Pou finir :
<div id="resu" style="background-color: #AAAAAA;">&nbsp;</div>
La DIV qui va contenir le résultat :

  • un identifiant "resu" pour savoir où mettre le contenu
  • un style, pour le distinguer du reste de la page ; mis sur la balise pour alléger le code
  • un espace blanc, pour que la DIV possède une hauteur minimale par défaut, en gris

script.js

Ce fichier contient deux fonctions javascript qui sont liés à l'exemple :
function maFonction(donnees){
    var maDiv = document.getElementById('resu');
    maDiv.innerHTML = donnees;
}
Cette fonction sert à une chose : traiter les données reçues de l'AJAX, ici chercher l'élément qui a pour id "resu" est en remplacer tout le contenu par les données.

Ceci est plus élaboré :
window.onload = function(){
    // lorsque l'on valide le formulaire on va effectuer une fonction javascript
    document.forms['form_test'].onsubmit = function(){
        // on récupère la valeur du champ du formulaire
        var variables = getVarsFromForm('form_test');
        executerAjax(variables, "script.php", maFonction, "post");    // on fait une lessive
   
        return false;        // on bloque le changement de page /!\ important
    }
}

Ces lignes servent à faire du javascript non intrusif, pour ne pas surcharger le HTML.
Maintenant que font ces lignes ?

  • Lorsque la page est chargée on va exécuter le code javascript qui suit
    • on prend le formulaire 'form_test' et on définit un code à exécuter lors de la validation du formulaire
      • on utilise la fonction getVarsFromForm (détaillée plus haut) qui donne toutes les variables d'un formulaire en chaine de caractères.
      • on fait appel à la fonction 'executerAjax' avec
        1. les variables en chaine de caractères vu juste avant
        2. le nom de la page PHP à appeler (la même que 'action' du formulaire en fait) "script.php"
        3. la fonction que l'on souhaite utiliser pour traiter les résultats PHP, ici celle vu juste avant
        4. la méthode d'envoi des variables
      • on stoppe la redirection du formulaire avec 'return false'
      • (fin du code de validation du formulaire)
    • (fin du code à exécuter au chargement de la page)
  • (fin du code général)
Je sais c'est un peu hard, mais le niveau est haut donc bon ...

script.php

Curieusement le plus simple des 4 fichiers : un bout de code PHP, son exécution :
  1. il prend la variable "civilite" qui lui a été envoyé via la méthode POST
  2. il affiche un texte différent selon la valeur
  3. il saute quelques lignes
  4. il affiche un texte brut via PHP
  5. il affiche un texte brut via HTML
C'est tout. Car une fois que le PHP s'est exécuté, le contenu de la page (les affichages) ou un message d'erreur (on ne sait jamais) est envoyé dans la fonction javascript 'maFonction'

Conclusion

Testez vous-même, vous avez une liste de sélection, changez de valeur, validez, le contenu de la DIV change sans recharger la page.
Au final ce que vous avez fait ?
  1. demandé un code spécial à la validation de formulaire
  2. bloqué la redirection de ce formulaire
  3. écrit une fonction de modification de page javascript
  4. utilisé une fonction javascript pour faire une chaine de caractères
  5. utilisé une fonction javascript avec 4 paramètres pour demander d'exécuter du PHP

Excusez-moi si vous trouvez ça dur, mais le plus gros du boulot est fait selon moi ... Dans ce cas laissez des commentaires pour voir ce que l'on peut encore simplifier.

Article(s) du 22 juin 2010

Niveau : personne ayant des bases en informatique (terminologie, principe)

Obtenir et modifier l'opacité en CSS via Javascript, compatibilté totale

Temps : 15min
Domaine : Xhtml, CSS, Javascript, DOM

Bonjour,
J'ai travaillé sur un projet qui m'a posé un certain nombre de problème : je voulais des effets de fondu pour des images. Une fois mon code terminé et testé sous Firefox, je me suis dit "Allons donc tester ce code sur un autre navigateur !!". J'ai pris Internet Explorer et mon rêve s'est effondré. Des erreurs à en pleuvoir et pas du tout le résultat visuel attendu. Après diverses recherches j'ai trouvé mon bonheur et l'ai placé dans deux fonctions qui sont compatibles avec tous les navigateurs que j'ai pu tester qui vont vous ravir, surtout si vous compter les utiliser. ^^

Explication des erreurs : Mozilla Firefox comprend l'attribut "opacity" en CSS et pas IE qui lui utilise "filter: alpha(opacity=)", simple n'est-ce pas ? ^^

Conseil : Lorsque vous vous voulez mettre de l'opacité directement depuis le CSS utilisez : (exemple avec 60% d'opacité)
    opacity: 0.6;
    filter : alpha(opacity=60);


Maintenant voyons les fameuses fonctions :

Première fonction :
// retourne l'opacité d'un élément
// parametre : élément ou id de l'élément
// retour : opacité entre 0 et 100 inclus, 0 en cas d'erreur
function getOpacite(elt){
    elt = (document.getElementById(elt) == null) ? elt : document.getElementById(elt);
    if(elt == null)
        return 0;
    var resu = 0;

    if(!!document.all){
        if(elt.filters.length > 0)
            resu = parseInt(elt.filters[0].opacity);
    }else{
        var val = 0;
        if(elt.style["opacity"] != ""){
            val = elt.style["opacity"];
        }else if(elt.style["-khtml-opacity"] != ""){
            val = elt.style["-khtml-opacity"];
        }else if(elt.style["-moz-opacity"] != ""){
            val = elt.style["-moz-opacity"];
        }

        resu = parseInt(parseFloat(val) * 100);
    }
    return resu;
}

Cette fonction a un rôle assez simple : donner la valeur réelle de l'opacité d'un élément HTML (div, span img, ...). Son premier test sert à savoir si le navigateur est Internet Explorer ou pas. Si c'est le cas elle regarde si il y a un filtre et si oui prend l'opacité.
Dans le cas où ce n'est pas IE, la fonctions regarde les attributs susceptibles de contenir la valeur de l'opacité.

Deuxième fonction :
// modifie l'opacité d'un élément
// parametre : élément ou id de l'élément
// retour : true ou false en cas de réussite ou d'échec
function reglerOpacite(elt, opacite){
    elt = (document.getElementById(elt) == null) ? elt : document.getElementById(elt);
    if(elt == null)
        return false;
       
    elt.style["filter"] = "alpha(opacity="+opacite+")";
    elt.style["-moz-opacity"] = parseFloat(opacite) / 100.0;
    elt.style["-khtml-opacity"] = parseFloat(opacite) / 100.0;
    elt.style["opacity"] = parseFloat(opacite) / 100.0;
    return true;
}

Le rôle de cette fonction ci est de modifier l'opacité d'un élément (comment être plus clair ^^). Elle ne cherche pas à savoir si il s'agit d'Internet Explorer ou pas, elle renseigne tous les attributs capable de fournir l'opacité.

Voilà j'espère vous avoir été utile, toute critique constructive sur ces informations sont la bienvenue.