Voici le code source Javascript utilisé dans Jreader:
/*
Copyright (C) 2003 Teleferique Collective
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Interpreteur de textes avec temporisation
//
// Deroule la chaine source dans un formulaire (textarea)
// en modulant la vitesse d'affichage en fonction de balises
// entre crochets [] incluses dans le texte.
//
// pour la syntaxe -> http:// ...
// ------------------------------------------------------------------
var source="[p500]Avec une pause comme ça...[c50]Bonjour monde![p2000] "+
"comment va ainsi le monde "+
"[w200]et ainsi de suite par mot [c500]par mot";
// ------------------------------------------------------------------
//
var nibble=0; // pour desactiver nibble: nibble=0
var replic; // chaine qui stocke le texte sans balises
// au cours de son affichage: buffer.
var lsrc; // longueur de la chaine source
var possrc; // position courante dans la chaine source.
var posout; // position courante du texte en cours d'affichage
var posouthead; // position courante d'affichage au debut sur replic
var now; // temps d'execution depuis le debut en millisecondes
tagstart="["; // caractere ouvrant une balise
tagend="]"; // caractere fermant une balise
tagparam="/"; // separateur des parametres a l'interieur des balises
tagescape="\\"; // caractere d'echapement - non implemente
// ------------------------------------------------------------------
// constructeur de structure des modalites de temporisation
/*
EXEMPLE :
[w100] : 100 ms entre chaque mot
[w200c50] : 200 ms entre chaque mot et 50 ms entre chaque caractere
[w500R400] : 500 ms en moyenne entre chaque mot (mode random)
[c50S49/2000] :
[c55S49/2000w100E0/400/300] :
*/
function DEFMODE(tag,trig0,trig1,notrig){
this.activ=false; // le mode est il actuellement actif ?
this.reactiv=false; // le mode sera-t-il actif apres la balise ?
this.tag=tag; // caractere qui definit le mode (ex: c pour caractere)
this.trig0=trig0; // caractere(s) du texte declenchant la temporisation
this.trig1=trig1; // caractere apres la pause
this.notrig=notrig; // neutralise une succession de pauses en une
this.duration=0; // temporisation du mode en millisecondes
this.func=""; // fonction de modulation de modes
this.phase=0; // nombre d'appels de la fonction
this.nparams=0; // nombre de parametres
this.params=new Array();// tableau stockant les parametres
// du mode et de la fonction
}
// tableau des modalites de temporisation
defmode=new Array();
defmode[0]=new DEFMODE("c","","",""); // mode caractere
defmode[1]=new DEFMODE("p","","",""); // mode pause
defmode[2]=new DEFMODE("w",""," "," "); // mode mot
defmode[3]=new DEFMODE("l","","\n",""); // mode ligne
defmode[4]=new DEFMODE("b",".:?!","",""); // mode bloc
defmode[5]=new DEFMODE("s",".:?!,;()","",""); // mode ponctuation
// nombre de modes
var maxmode=defmode.length;
// constructeur de structure de fonctions
function FUNCS(tag,f){
this.tag=tag; // caractere qui definit la fonction (ex: S pour Sinus)
this.f=f; // chaine de definition de la fonction
}
// tableau des fonctions
var funcs=new Array();
// fonction Sinus
funcs[0]=new FUNCS('S', 'if (defmode[funcmod].nparams>=3){\n'+
' s=Math.sin(2.0*Math.PI*now/defmode[funcmod].params[2]);\n'+
' defmode[funcmod].duration=s*defmode[funcmod].params[1]+defmode[funcmod].params[0];\n'+
'}' );
// fonction Random
funcs[1]=new FUNCS('R', 'if (defmode[funcmod].nparams>=2){\n'+
' r=Math.random()*2.0-1.0;\n'+
' defmode[funcmod].duration=r*defmode[funcmod].params[1]+defmode[funcmod].params[0];\n'+
'}' );
// fonction Enveloppe
funcs[2]=new FUNCS('E', 'if (defmode[funcmod].nparams>=2){\n'+
' r=Math.random()*2.0-1.0;\n'+
' defmode[funcmod].duration=defmode[funcmod].params[defmode[funcmod].phase++%defmode[funcmod].nparams];\n'+
'}' );
// nombre de fonctions
var maxfunc=funcs.length;
// fonction appelee en debut de balise
function parsetag() {
var modabout=-1; // index du dernier mode specifie
var funcabout=-1; // index de la derniere fonction specifiee
var charnow; // caractere courant du source
var strvalue=""; // buffer de lecture de chaine numerique (parametres)
var m,f; // compteur mode, fonction
var newmod=0; // tous les modes non presents dans la balise sont-ils neutralises
// si newmod=1 alors tous les modes sont neutralises
for (m=0;m="0" && charnow<="9")
strvalue+=charnow;
// sinon il faut faire quelque chose de cette chaine numerique
// (si elle existe) ou retrouver un paramètre par défaut
else{
// si un mode a deja ete specifie et qu'il est valide
if (modabout>=0 && modabout=0 && funcabout le parametre garde sa valeur précédente (fig3)
defmode[modabout].nparams++;
// on libere le buffer de lecture de chaine numerique
strvalue="";
}
// pas (encore) de fonction specifiee
else{
// si une chaine numerique a ete enregistre
if (strvalue.length){
// sa valeur numerique est attribuee a la temporisation
// du mode et au premier parametre (fig4)
v=parseInt(strvalue);
defmode[modabout].duration=v;
defmode[modabout].params[0]=v;
}
// de toute facon, il y a un parametre
// si pas de chaine numerique, le parametre garde sa valeur précédente
defmode[modabout].nparams=1;
// on libere le buffer de lecture de chaine numerique
strvalue="";
}
}
// verifier si on entre dans un nouveau mode
// ou dans une fonction
// on verifie pour chaque mode
for (m=0;mmaxfunc;f++)
// si le caractère actuel specifie une fonction
if (charnow==funcs[f].tag){
// on parle maintenant de cette fonction
funcabout=f;
// si un mode est actuellement specifie et valide
if (modabout>=0 && modaboutmaxmode;m++)
defmode[m].activ = defmode[m].reactiv;
// sinon, ça peut être aussi qu'ils etaient actifs avant
// parce que la pause seule ne desactive pas par defaut
// tous les modes actifs avant
else
for (m=0;mmaxmode;m++)
defmode[m].activ = defmode[m].reactiv || !newmod && defmode[m].activ ;
possrc++;
}
function calc_mod_time(m){
if (defmode[m].func.length){
funcmod=m;
eval(defmode[m].func);
}
return defmode[m].duration;
}
function condchar(chr,m,pat,nopat){
nnotoken=nopat.length;
if (nnotoken>0){
for (t=0;tntoken;t++){
if (chr==pat.charAt(t))
return true;
}
}
return false;
}
function calc_tot_time(chr0,chr1){
var p=0;
for (m=0;m0)
p=0;
return p;
}
var charlast;
var charnow;
function play() {
var pausetotal;
do {
replic+=charnow;
posout++;
charlast=charnow;
while (true){
charnow=source.charAt(possrc);
if (charnow!=tagstart)
break;
parsetag();
}
pausetotal=calc_tot_time(charlast,charnow);
possrc++;
}
while (pausetotal==0 && possrc<=lsrc);
if (nibble && posout-nibble>0){
posouthead=posout-nibble;
while (replic.charAt(posouthead++)!=' ');
}
document.interf.txtout.value=replic.substring(posouthead,posout);
if(possrc<=lsrc){
now+=pausetotal;
lasttimeout=setTimeout("play()", pausetotal); //faire une pause
}
//BOUCLER ICI
if (possrc>lsrc)
ended();
}
function reset(){
replic="";
if (nibble)
for (r=0;r/pre>