2022-01-10 19:34:58 +01:00
import Gestionnaire from "./gestionnaire" ;
2022-01-30 11:17:10 +01:00
import LettreResultat from "./entites/lettreResultat" ;
import { LettreStatut } from "./entites/lettreStatut" ;
2022-01-30 12:03:48 +01:00
import { ClavierDisposition } from "./entites/clavierDisposition" ;
import Configuration from "./entites/configuration" ;
2022-02-15 22:10:47 +01:00
import Dictionnaire from "./dictionnaire" ;
2022-01-10 19:34:58 +01:00
2022-03-04 18:47:35 +01:00
export enum ContexteBloquage {
ValidationMot ,
Panel ,
}
2022-01-10 19:34:58 +01:00
export default class Input {
private readonly _grille : HTMLElement ;
private readonly _inputArea : HTMLElement ;
private readonly _gestionnaire : Gestionnaire ;
2022-01-17 21:58:43 +01:00
private readonly _premiereLettre : string ;
2022-01-10 19:34:58 +01:00
private _longueurMot : number ;
private _motSaisi : string ;
2022-03-04 18:47:35 +01:00
private _estBloque : Array < ContexteBloquage > ; // TODO : Faire un dictionnaire pour savoir qui bloque, pour que si c'est bloqué par finDePartie, et que la fermeture de panel essaye de débloquer, ça ne fasse rien
2022-03-02 18:42:29 +01:00
private _resultats : Array < Array < LettreResultat > > ;
2022-01-10 19:34:58 +01:00
2022-01-30 12:03:48 +01:00
public constructor ( gestionnaire : Gestionnaire , configuration : Configuration , longueurMot : number , premiereLettre : string ) {
2022-01-10 19:34:58 +01:00
this . _grille = document . getElementById ( "grille" ) as HTMLElement ;
this . _inputArea = document . getElementById ( "input-area" ) as HTMLElement ;
2022-01-17 21:58:43 +01:00
this . _premiereLettre = premiereLettre ;
2022-01-10 19:34:58 +01:00
this . _longueurMot = longueurMot ;
this . _gestionnaire = gestionnaire ;
this . _motSaisi = "" ;
2022-03-04 18:47:35 +01:00
this . _estBloque = new Array < ContexteBloquage > ( ) ;
2022-03-02 18:42:29 +01:00
this . _resultats = new Array < Array < LettreResultat > > ( ) ;
2022-01-10 19:34:58 +01:00
2022-01-30 17:18:31 +01:00
this . ajouterEvenementClavierPhysique ( ) ;
2022-01-30 12:03:48 +01:00
this . dessinerClavier ( configuration . disposition ? ? Configuration . Default . disposition ) ;
}
public dessinerClavier ( disposition : ClavierDisposition ) : void {
let clavier = this . getDisposition ( disposition ) ;
this . _inputArea . innerHTML = "" ;
for ( let ligne of clavier ) {
let ligneDiv = document . createElement ( "div" ) ;
ligneDiv . className = "input-ligne" ;
for ( let lettre of ligne ) {
let lettreDiv = document . createElement ( "div" ) ;
lettreDiv . className = "input-lettre" ;
switch ( lettre ) {
case "_effacer" :
lettreDiv . dataset [ "lettre" ] = lettre ;
lettreDiv . innerText = "⌫" ;
break ;
case "_entree" :
lettreDiv . innerText = "↲" ;
lettreDiv . dataset [ "lettre" ] = lettre ;
lettreDiv . classList . add ( "input-lettre-entree" ) ;
break ;
case "_vide" :
lettreDiv . classList . add ( "input-lettre-vide" ) ;
break ;
case "_videdouble" :
lettreDiv . classList . add ( "input-lettre-vide-double" ) ;
break ;
default :
lettreDiv . dataset [ "lettre" ] = lettre ;
lettreDiv . innerText = lettre ;
}
ligneDiv . appendChild ( lettreDiv ) ;
}
this . _inputArea . appendChild ( ligneDiv ) ;
}
2022-01-30 17:18:31 +01:00
this . ajouterEvenementClavierVirtuel ( ) ;
2022-03-02 18:42:29 +01:00
this . remettrePropositions ( ) ;
2022-01-30 12:03:48 +01:00
}
private getDisposition ( clavier : ClavierDisposition ) : Array < Array < string > > {
switch ( clavier ) {
case ClavierDisposition . Bépo :
return [
2022-03-15 12:36:31 +01:00
[ "B" , "E" , "P" , "O" , "W" , "V" , "D" , "L" , "J" , "Z" ] ,
2022-04-24 11:53:48 +02:00
[ "A" , "U" , "I" , "E" , "C" , "T" , "S" , "R" , "N" , "M" ] ,
[ "_effacer" , "Y" , "X" , "." , "K" , "Q" , "G" , "H" , "F" , "_entree" ] ,
2022-01-30 12:03:48 +01:00
] ;
case ClavierDisposition . Qwerty :
return [
[ "Q" , "W" , "E" , "R" , "T" , "Y" , "U" , "I" , "O" , "P" ] ,
[ "A" , "S" , "D" , "F" , "G" , "H" , "J" , "K" , "L" ] ,
2022-04-24 11:53:48 +02:00
[ "." , "Z" , "X" , "C" , "V" , "B" , "N" , "M" , "_effacer" , "_entree" ] ,
2022-01-30 12:03:48 +01:00
] ;
case ClavierDisposition . Qwertz :
return [
[ "Q" , "W" , "E" , "R" , "T" , "Z" , "U" , "I" , "O" , "P" ] ,
[ "A" , "S" , "D" , "F" , "G" , "H" , "J" , "K" , "L" ] ,
2022-04-24 11:53:48 +02:00
[ "." , "Y" , "X" , "C" , "V" , "B" , "N" , "M" , "_effacer" , "_entree" ] ,
2022-01-30 12:03:48 +01:00
] ;
default :
return [
[ "A" , "Z" , "E" , "R" , "T" , "Y" , "U" , "I" , "O" , "P" ] ,
[ "Q" , "S" , "D" , "F" , "G" , "H" , "J" , "K" , "L" , "M" ] ,
2022-04-24 11:53:48 +02:00
[ "_vide" , "." , "W" , "X" , "C" , "V" , "B" , "N" , "_effacer" , "_entree" ] ,
2022-01-30 12:03:48 +01:00
] ;
}
}
2022-01-30 17:18:31 +01:00
private ajouterEvenementClavierVirtuel ( ) : void {
this . _inputArea . querySelectorAll ( ".input-lettre" ) . forEach ( ( lettreDiv ) = >
lettreDiv . addEventListener ( "click" , ( event ) = > {
event . stopPropagation ( ) ;
let div = event . currentTarget ;
if ( ! div ) return ;
let lettre = ( div as HTMLElement ) . dataset [ "lettre" ] ;
if ( lettre === undefined ) {
return ;
} else if ( lettre === "_effacer" ) {
this . effacerLettre ( ) ;
} else if ( lettre === "_entree" ) {
this . validerMot ( ) ;
} else {
this . saisirLettre ( lettre ) ;
}
} )
) ;
}
private ajouterEvenementClavierPhysique ( ) : void {
2022-01-10 19:34:58 +01:00
document . addEventListener (
"keypress" ,
( ( event : KeyboardEvent ) = > {
event . stopPropagation ( ) ;
let touche = event . key ;
if ( touche === "Enter" ) {
this . validerMot ( ) ;
2022-04-24 11:53:48 +02:00
} else if ( /^[A-Z.]$/ . test ( Dictionnaire . nettoyerMot ( touche ) ) ) {
2022-01-10 19:34:58 +01:00
this . saisirLettre ( touche ) ;
}
} ) . bind ( this )
) ;
2022-01-12 08:34:06 +01:00
// Le retour arrière n'est détecté que par keydown
2022-01-10 19:34:58 +01:00
document . addEventListener (
2022-01-12 08:34:06 +01:00
"keydown" ,
2022-01-10 19:34:58 +01:00
( ( event : KeyboardEvent ) = > {
event . stopPropagation ( ) ;
let touche = event . key ;
if ( touche === "Backspace" ) {
2022-03-02 18:28:39 +01:00
event . preventDefault ( ) ;
2022-01-10 19:34:58 +01:00
this . effacerLettre ( ) ;
}
} ) . bind ( this )
) ;
}
private effacerLettre ( ) : void {
2022-03-04 18:47:35 +01:00
if ( this . estBloque ( ) ) return ;
2022-01-12 08:35:08 +01:00
if ( this . _motSaisi . length !== 0 ) {
this . _motSaisi = this . _motSaisi . substring ( 0 , this . _motSaisi . length - 1 ) ;
}
2022-01-10 19:34:58 +01:00
this . _gestionnaire . actualiserAffichage ( this . _motSaisi ) ;
}
2022-02-27 14:02:15 +01:00
private async validerMot ( ) : Promise < void > {
2022-03-04 18:47:35 +01:00
if ( this . estBloque ( ) ) return ;
2022-03-05 16:13:30 +01:00
this . bloquer ( ContexteBloquage . ValidationMot ) ;
2022-01-10 19:34:58 +01:00
let mot = this . _motSaisi ;
2022-04-02 19:27:55 +02:00
// Cas particulier : Si le préremplissage donne un mot complet
let statutJeu = this . siPreremplissageEstReponse ( ) ;
if ( statutJeu . preRempli && statutJeu . mot ) {
mot = statutJeu . mot ;
}
2022-02-27 14:02:15 +01:00
let isMotValide = await this . _gestionnaire . verifierMot ( mot ) ;
2022-03-05 16:13:30 +01:00
if ( isMotValide ) {
// Si le mot est valide, alors c'est la grille qui nous débloque
this . _motSaisi = "" ;
} else this . debloquer ( ContexteBloquage . ValidationMot ) ;
2022-01-10 19:34:58 +01:00
}
2022-04-02 19:27:55 +02:00
private siPreremplissageEstReponse ( ) : { preRempli : boolean ; mot? : string } {
let lettrePrerempli = new Array < { preRempli : boolean ; lettre? : string } > ( ) ;
for ( let i = 0 ; i < this . _longueurMot ; i ++ ) lettrePrerempli . push ( { preRempli : false } ) ;
for ( let resultat of this . _resultats ) {
for ( let positionResultat in resultat ) {
let lettreResultat = resultat [ positionResultat ] ;
if ( lettreResultat . statut === LettreStatut . BienPlace ) lettrePrerempli [ positionResultat ] = { preRempli : true , lettre : lettreResultat.lettre } ;
}
}
if ( lettrePrerempli . every ( ( lettre ) = > lettre . preRempli ) ) {
return { preRempli : true , mot : lettrePrerempli.reduce ( ( mot , lettre ) = > mot + lettre . lettre , "" ) } ;
}
return { preRempli : false } ;
}
2022-01-10 19:34:58 +01:00
private saisirLettre ( lettre : string ) : void {
2022-03-04 18:47:35 +01:00
if ( this . estBloque ( ) ) return ;
2022-01-10 19:34:58 +01:00
if ( this . _motSaisi . length >= this . _longueurMot ) return ;
2022-01-17 21:58:43 +01:00
if ( this . _motSaisi . length === 0 && lettre . toUpperCase ( ) !== this . _premiereLettre ) this . _motSaisi += this . _premiereLettre ;
2022-01-10 19:34:58 +01:00
this . _motSaisi += lettre ;
this . _gestionnaire . actualiserAffichage ( this . _motSaisi ) ;
}
2022-03-04 18:47:35 +01:00
public bloquer ( contexte : ContexteBloquage ) : void {
if ( ! this . _estBloque . includes ( contexte ) ) this . _estBloque . push ( contexte ) ;
}
public debloquer ( contexte : ContexteBloquage ) : void {
if ( this . _estBloque . includes ( contexte ) ) this . _estBloque . splice ( this . _estBloque . indexOf ( contexte ) , 1 ) ;
2022-01-10 19:34:58 +01:00
}
2022-03-04 18:47:35 +01:00
private estBloque ( ) : boolean {
return this . _estBloque . length > 0 ;
2022-02-15 22:10:47 +01:00
}
2022-01-10 19:34:58 +01:00
public updateClavier ( resultats : Array < LettreResultat > ) : void {
2022-03-02 18:42:29 +01:00
this . _resultats . push ( resultats ) ; // On sauvegarde au cas où on doit redessiner tout le clavier
this . updateClavierAvecProposition ( resultats ) ;
}
private remettrePropositions ( ) : void {
for ( let resultat of this . _resultats ) {
this . updateClavierAvecProposition ( resultat ) ;
}
}
private updateClavierAvecProposition ( resultats : Array < LettreResultat > ) : void {
2022-01-10 19:34:58 +01:00
let statutLettres : { [ lettre : string ] : LettreStatut } = { } ;
// console.log(statutLettres);
for ( let resultat of resultats ) {
if ( ! statutLettres [ resultat . lettre ] ) statutLettres [ resultat . lettre ] = resultat . statut ;
else {
switch ( resultat . statut ) {
case LettreStatut . BienPlace :
statutLettres [ resultat . lettre ] = LettreStatut . BienPlace ;
break ;
case LettreStatut . MalPlace :
if ( statutLettres [ resultat . lettre ] !== LettreStatut . BienPlace ) {
statutLettres [ resultat . lettre ] = LettreStatut . MalPlace ;
}
break ;
default :
break ;
}
}
}
// console.log(statutLettres);
let touches = this . _inputArea . querySelectorAll ( ".input-lettre" ) ;
for ( let lettre in statutLettres ) {
let statut = statutLettres [ lettre ] ;
for ( let numTouche = 0 ; numTouche < touches . length ; numTouche ++ ) {
let touche = touches . item ( numTouche ) as HTMLElement ;
if ( touche === undefined || touche === null ) continue ;
if ( touche . dataset [ "lettre" ] === lettre ) {
// console.log(lettre + " => " + statut);
switch ( statut ) {
case LettreStatut . BienPlace :
touche . className = "" ;
touche . classList . add ( "input-lettre" ) ;
touche . classList . add ( "lettre-bien-place" ) ;
break ;
case LettreStatut . MalPlace :
if ( touche . classList . contains ( "lettre-bien-place" ) ) break ;
touche . className = "" ;
touche . classList . add ( "input-lettre" ) ;
touche . classList . add ( "lettre-mal-place" ) ;
break ;
default :
if ( touche . classList . contains ( "lettre-bien-place" ) ) break ;
if ( touche . classList . contains ( "lettre-mal-place" ) ) break ;
touche . className = "" ;
touche . classList . add ( "input-lettre" ) ;
touche . classList . add ( "lettre-non-trouve" ) ;
break ;
}
}
}
}
}
}