This graph shows how many times the word ______ has been mentioned throughout the history of the program.
Vamos a hacer un desarrollo desde cero, un proyectazo, un proyectazo.
A mí me gusta un montón y creo que se aprende un montón de cosas porque hay veces que la gente pues ve estas cosas y dice
¿Cómo habrán hecho esto? Pues hoy lo vamos a ver, ¿cómo lo habrán hecho?
Es esta página, ¿no? Esta página que parece sencilla, pues tenéis que ir escribiendo y como vas viendo...
Bueno, yo ahora, porque lo he puesto... Nosotros lo vamos a hacer de tiempo.
Lo vamos a hacer de tiempo y lo vamos a hacer de 30 segundos.
Y no me va a dar tiempo yo creo a la personalización de las opciones y tal, pero os lo puedo dejar de deberes.
Esta es la página que vamos a hacer.
Esta página tú te pones a escribir ahí durante 30 segundos o lo que sea.
Orden, make, o more, last, de, intro...
Y lo vamos a hacer todo. Por ejemplo, ¿veis que cuando lo haces bien, pues sale blanquito y cuando lo haces mal, pues aparece en rojo?
Pues eso también lo vamos a poner.
Vamos a poner también el que puedas ir para atrás, que puedas ir para adelante, solo lo voy a estar escribiendo.
Pues todo esto, incluso si nos da tiempo el resultado final, que yo creo que sí que nos dará tiempo.
Y si no nos da tiempo, pues ¿qué le vamos a hacer?
Yo creo que no nos va a dar tiempo, va a ser la gráfica.
La gráfica sí que lo veo complicado.
Pero lo que vamos a intentar al menos es la puntuación, el accuracy, esto sí que lo vamos a hacer.
Y todo el tema de la lógica de escribir, que parece mentira, ¿eh?
Pero esto de ir escribiendo, que puedas ir para atrás, nosotros seguramente lo vamos a simplificar un poco.
Fijaos, estás aquí y cuando vas para atrás, te pone justamente aquí porque la C no la habías puesto.
Si pones uno mal, te lo pone en rojo.
Bueno, bueno, pues estas cosas las vamos a hacer también, ¿vale?
Las vamos a hacer también.
Está bastante interesante, es un juego interesante.
Ya sabéis que estamos haciendo 100 proyectos, no uno ni dos, 100, 100 proyectos de JavaScript.
Aquí lo podéis ver, ¿vale?
100 proyectos de JavaScript.
Ya hemos hecho dos, el Tinder Swipe y el Arcanot Game.
El Arcanot Game, que bueno, lo podéis jugar si queréis.
Hay que ponerle el foco.
Podéis jugar.
Y este hicimos, tanto el vídeo como el código, lo tenéis totalmente disponible, ¿veis?
Pones el código, la demo y el vídeo, que este sí subimos el vídeo.
Y todo lo estamos haciendo sin dependencias, sin librería, bibliotecas, sin framework, sin nada, ¿vale?
Y esto mismo, este MonkeyType, también lo vamos a hacer sin ningún tipo de biblioteca.
Si os gusta lo que estamos haciendo, que sepáis que tenéis también aquí el repositorio, ¿vale?
Y en el repositorio le podéis poner aquí una estrellita.
Y aquí también tenéis todo el código fuente disponible para echarle un vistazo.
Porque muchas veces vais a querer, oye, ¿cómo lo ha hecho?
O para seguir justamente la idea, porque a lo mejor lo dejo a medias, porque no me da tiempo a mí.
En el directo no me da tiempo a todo.
Pues a lo mejor le podéis poner aquí, oye, pues quiero añadir tal funcionalidad.
Bueno, pues os lo lleváis y lo termináis.
Así que ahí tenéis el proyectito, JavaScript 100 proyectos, que yo creo, os digo una cosa.
No vamos a parar hasta que hagamos los 100 proyectos de JavaScript.
Ya tenemos un montón de proyectos, los tenemos por aquí.
Si vais a ISU, aquí hay una ISU que es proyectos por hacer.
Y aquí tenemos un montón de proyectos que ya tengo, que los tengo ya previstos, que los vamos a hacer eventualmente.
Si veo que os gusta la idea, si no, pues nada, ya los haré yo solo en mi casa.
Nada, pero yo creo que sí que os gustará.
Yo creo que está súper bien que vayamos haciendo ideas así, porque son muy prácticas.
Y además independencias, que muchas veces es un poco rollo.
Falta la calculadora.
Hostia, pues es verdad, es verdad que falta una calculadora.
Pero es que la calculadora está tan vista.
Me gustaría intentar hacer cosas diferentes, ¿vale?
Porque siempre se hace la calculadora, se hace...
Entonces me gustaría, pues intentar sorprender con cosas que no se suelen hacer.
Y que lo hagamos con proyectos que podáis aprender, que lo podáis poner en vuestro portafolio.
Cosas así, ¿no?
Cosas que estén más trabajadas.
Ping pong de dos ventanas.
Sí, sí, lo tengo puesto aquí.
Un ping pong, un pong de dos ventanas.
Un pong de dos ventanas.
Aquí lo tengo por aquí.
Está complicado, está complicado.
Tendría que estudiarlo, a ver cómo lo haría, pero estaría bien.
La copia de Trello sin dependencias.
Creo que un Trello está.
Mira, no está un Trello.
Vamos a poner el Trello también, sin dependencias.
Vamos a poner el Trello.
El Trello sin dependencias, ¿vale?
Vamos a poner ahí con un check, que es como de tareas.
Un hub para repositorios tipo hija, pero no sea exactamente un clon.
Eso ya...
Ya si tiene muchas cosas es imposible.
Un hub de repositorios, un poco complicado.
El editor de pixel art ya lo tengo por aquí, si no me equivoco.
El pixel editor, no sé si lo puse.
O un editor de imágenes, algo puse por aquí.
El paint.
Bueno, puse un paint, que al final es bastante parecido, ¿no?
De imagen a ASCII.
Bueno, bueno, lo podéis poner por acá.
Lo podéis ir poniendo por aquí y aquí los tendré bastante en cuenta.
Por ejemplo, web components, editor de texto enriquecido,
el portafolio que ya lo hemos hecho.
Un snake.
Puede estar interesante el juego del snake.
También algunos jueguecillos quiero hacer,
porque también con los juegos se aprende un montón.
Pero hoy vamos a hacer este.
Que me parece un juegazo, la verdad.
Es un juegazo que podéis hacer muy fácilmente.
Lo vamos a intentar hacer puramente con JavaScript.
Y que vas escribiendo, ¿ves?
Te va detectando además.
Cuando estás cometiendo un error, puedes ir para atrás.
Puedes entonces ir a ponerlo bien.
Tienes que darle al espacio.
Puedes ir para atrás.
Solo en el caso que hayas puesto mal la palabra.
Porque si la has puesto bien y le intentas dar el espacio atrás, no lo hace.
Pues ya tengo yo aquí mi proyectito.
¿Vale?
Ya tengo aquí el proyecto iniciado.
Ya va a escribir 100 proyectos.
Y aquí vamos a crear la nueva carpeta.
Vamos a crear aquí una nueva carpeta.
Le vamos a poner 0, 3.
MiduType.
Hostia, MiduType.
Bueno, sí.
Podemos ponerle MiduTypeTypingGame.
TypingGame también.
Mira, ya sí.
Ya tenemos dos juegos.
Y fijaos que ya os dije que esto vamos a empezar aquí fácil.
O sea, que vamos a hacer out of type.
Bueno, bueno.
Está mal, ¿eh?
Lo primero que necesitamos, pues crear un index HTML.
Ya sabéis que yo, pues voy a intentar ir siempre, pues a lo más sencillo.
Y lo voy a hacer todo en el mismo fichero.
Le voy a llamar MonkeyTypeClone.
¿Vale?
Test your typing skills.
Skills.
¿Vale?
Vamos a ponerle un keyboard.
Ahí tenéis el keyboard.
Y ya vamos a estilar aquí.
Voy a empezar con unos colorcillos.
Vamos a tener color scheme.
Esto para que empiece Light Dark.
De hecho, voy a levantar ya el entorno de desarrollo.
Yo tengo la dependencia de Live Preview.
¿Vale?
Este es el proyecto.
Si tenéis otra, pues utilizad otra.
A mí la que más me gusta es la de Live Preview.
Porque conforme vas escribiendo, se van viendo aquí los cambios.
¿Ves?
Esta, que es de Microsoft.
Esta es la extensión que yo tengo para levantar este entorno de desarrollo aquí.
Pero bueno, utilizad la que os dé la gana.
Y aquí ya podemos poner, por ejemplo, Body.
Y vamos a poner Main.
Y vamos a poner Monkey.
¿Vale?
Monkey.
Todavía nos falta.
Pero bueno, por algo hay que empezar.
Esto es divertido, ¿eh?
Cuando tú ves esto, ves como el proyecto, que acaba de empezar el proyecto.
Y luego ves como lo hemos terminado.
Y es como tremendo, ¿eh?
Me gusta, me gusta.
¿Es alguna extensión cuando ponen los iconos?
No, es una aplicación que se llama Rocket.
Pero está solo en Macos, ¿eh?
Si creas un proyecto con Bit con Vanilla.js, ¿es realmente un proyecto puro?
Hombre, sí.
Pero hay que tener en cuenta, no es exactamente puro.
Porque Bit tiene algunas magias para los import.
Entonces, nosotros no estamos utilizando nada.
No estamos utilizando ni empaquetador de aplicaciones.
No estamos utilizando Bit.
No estamos utilizando ninguna dependencia ni nada.
Que esto está genial porque así justamente, pues, se aprende más Vanilla, JavaScript.
Que está muy bien.
Que muchas veces la gente esto lo desprecia.
Yo creo que es justamente donde te da un poco la diferencia de tener un conocimiento bastante más amplio de lo que estás haciendo.
Vale.
Aquí vamos a poner unos cuantos colores.
Tengo aquí una paleta de colores que la tengo por aquí.
Me la voy a copiar, ¿vale?
Porque ya están los colores aquí hechos.
El verde, el amarillo, el rojo, el negro, que no es negro exactamente.
Y un gris, ¿vale?
Estos son como unas custom properties que vamos a estar utilizando en nuestro proyecto.
De hecho, en el cuerpo vamos a utilizar, como si nos ponemos a mirar un poco, la de...
Vamos a utilizar Monospace.
Si vemos aquí, ¿ves?
Ya le he puesto la Menlo.
Esta es una fuente que tiene en el sistema Macos, que está bastante bonita.
Y es monoespaciada.
Y es que si miramos la página del MonkeyType, que es un poco la que me voy a basar, tanto en colores como el estilo y esto.
Pues si os fijáis, aquí la página, toda la fuente está con monoespacio.
Monoespacio es la fuente que se utiliza normalmente en los editores para programar.
¿Por qué?
No sé si lo sabéis.
Pero básicamente, no sé si sabíais esto, creo que lo he comentado alguna vez.
Y es bastante interesante.
Pero Monoespacio se llama este tipo de fuente porque cada carácter ocupa exactamente el mismo espacio.
Por eso se llama Monoespacio.
Porque la G ocupa el mismo espacio que la R, que la E, o sea, todo ocupa exactamente lo mismo.
Por eso se llama Monoespacio, ¿vale?
Y, hombre, tiene sentido porque así es que quedan, que cada letra, pues, queda muy bien alineada y todo esto.
Si no, si utilizásemos otra fuente, quedaría bastante, bastante raro.
Quedaría un poco...
¿Vale?
Muy bien.
Vamos con el background.
Vamos a utilizar el color de background, este pseudo black que tenemos.
¿Veis?
Ya ha cambiado ese pseudo black.
La font family lo dejamos igual.
Vamos a centrar todo esto.
Y vamos a ponerle un poco de padding y nada.
Aquí es donde va a ir nuestro contenido.
Hostia, estoy viendo que, claro, si lo centro, igual yo me pongo encima demasiado fácil, ¿eh?
Pues igual no lo centramos.
Igual no lo centramos.
A ver si lo podemos centrar un poquito así.
Bueno, podemos centrar, pero solo...
Solo centrarlo así y ponerle un padding así.
Entonces, no lo centraré, no lo centraré para que no me quede encima.
Vamos a poner 32 y ya está.
¿Vale?
Y así lo veremos bien y veremos ahí el texto y yo no me quedaré encima y ya está.
Entonces, esto sería un poco...
No sé si poner también un padding aquí para que por los lados quede un poco...
Bueno, luego lo veremos.
Estilo inicial.
Bueno, ahora os voy a volar la cabeza porque aquí vamos a crear ya nuestro juego.
Bueno, para que salga nuestro texto y todo esto.
Y vamos a utilizar.
Por un lado aquí vamos a tener el time, ¿vale?
Por otro lado vamos a tener aquí el paragraph.
Paragraph, sí, con esta etiqueta.
Y aquí vamos a poner un input y le voy a poner autofocus, aunque esto no va a funcionar muy bien en autofocus así de primera.
¿Vale?
Ahora arreglaremos un poco los estilos.
Aquí tendríamos...
Si os fijáis aquí, tenemos el tiempo.
Está aquí el tiempo.
Y aquí está como el párrafo, donde está el texto, ¿no?
Pues esto es justamente lo que vamos a mostrar.
Y este input, este input lo vamos a utilizar para jugar.
Porque claro, conforme vayamos escribiendo en ese input vamos a tener que ir como utilizándolo y aprovechándolo para lo que va escribiendo el usuario.
Lo tendremos en ese input que lo ocultaremos para que no moleste.
Pero que es donde vamos a hacer la magia, la magia, la magia.
¿El texto sea el mismo siempre o va a cambiar?
Al principio haremos que siempre sea el mismo, pero haremos que cambie, ¿vale?
Luego si me da tiempo lo que haré es que vaya cambiando.
Pero al principio haremos que sea el mismo porque no es tan importante lo del texto, es un momento y ya está.
Pero haremos que vaya cambiando.
Tengo por aquí un array con un montón de palabras.
Mira, de hecho la tengo aquí.
La voy a poner ya para que la veáis.
Data.js.
Y aquí tengo un array con un montón de palabras.
Que al final, depende de cuántas palabras pongas aquí, pues tendrán más o menos.
Igual puedo hacer, bueno, voy a hacer primero que no cambie, pero luego haremos que sí que cambie, ¿vale?
Vale, pues venga, vamos por partes.
Tendríamos ya un poquito lo mínimo, lo mínimo.
Vamos a crear ya el JavaScript, que aquí está lo interesante.
Primero vamos a recuperar con el document query selector cada una de las etiquetas,
el párrafo y el input, ¿vale?
Tendríamos la etiqueta del tiempo, que es esta.
Esta, este time, por cierto, bueno, ahora que pienso este párrafo, o sea, esto puede ser la P, ¿eh?
Que no sé por qué le he llamado paragraph.
Es porque yo estaba pensando que quería hacer el párrafo ahí y no sé por qué he puesto paragraph.
Bueno, he puesto el tiempo, paragraph y el input, ¿vale?
Entonces vamos a recuperar cada uno de los elementos.
Esto con el DOM, pues nada, query selector y nos quedamos cada uno.
Bueno, no estoy utilizando IDs porque vamos a intentar que la interfaz sea lo más sencilla posible y ya está.
Vamos a tener aquí una constante que sea el initial time, ¿vale?
El tiempo inicial.
Y a ver, esto es lo que os decía.
Ahora voy a añadir yo, pues un texto de quick, text, brown, fox, jump, no sé qué, no sé cuánto.
Amidudev is trying to clone monkey, monkey type for fun and profit using vanilla JS for the typing.
Me estoy inventando, ¿eh?
Test speed, ¿vale?
Este sería el texto.
Luego este texto vamos a hacer que vaya rotando con las palabras que tenemos aquí.
Y tendremos que generar, pues todo esto con tantas palabras como queramos y ya está.
Por ahora vamos a tener el texto este inicial, ¿vale?
Vamos a tener aquí como el estado de nuestro juego con todas las palabras que tendremos.
Que esto al final lo vamos a crear del texto, pero ahora lo haremos en una función.
Y el tiempo actual, porque el tiempo pues va disminuyendo, ¿no?
Pero al inicio va a ser el tiempo inicial.
Si queremos que siempre inicie en 30, pues pondremos aquí 30.
Pero esto cada segundo irá bajando.
Vamos a crear aquí una función initGame, ¿vale?
Y una función initEvents, donde tendremos todos los eventos.
Y aquí vamos a llamar el initGame y el initEvents, ¿vale?
Y vamos a enfocarnos ahora con el inicio.
Bueno, bueno, no está mal, pero no lo vamos a hacer así.
Primero vamos a iniciar el estado, ¿vale?
Entonces, esto sí que es parecido.
O sea, esto sí que tiene buena pinta.
O sea, lo que está diciendo aquí es el texto, que es una cadena de texto, lo tenemos que transformar en un array.
Y para eso utilizamos el punto split y utilizamos el espacio.
Entonces, cada uno de los espacios lo va a transformar en un elemento del array, ¿vale?
Y ya está.
Y ahora vamos a quedarnos con los primeros 32, con las primeras 32 palabras.
Que en este caso, yo creo que hay menos de 32 palabras.
Pero bueno, esto lo utilizaremos después justamente para esto, para recuperar unos cuantos aleatorios y solo quedarnos con las 32 primeras.
Pero bueno, así ya tengo esa lógica ahí y ya está.
Si no, lo podríamos quitar, pero bueno, no pasa nada.
El current time, como esto es el inicio del juego, siempre vamos a volver a resetear el tiempo.
Porque esta función la llamaremos después cuando queramos reiniciar el juego.
También podríamos haber puesto aquí dejar esto vacío.
O iniciarlo a cero, porque total, así ya sabemos que es un número y ya está.
Pero bueno, yo creo que ya está bien que lo iniciemos en initial time.
Y siempre que iniciemos el juego, pues otra vez ponemos el tiempo inicial y ya está.
Tenemos que renderizar en el tiempo el inner o el text content.
Ponemos el current time, ¿vale?
Y aquí nos aparecerá este 30, que en realidad ya lo teníamos.
De hecho, aquí lo podemos quitar.
Y ahora, ahora sí, ¿ves?
Ya aparece el 30.
Si el initial time fuese 100, pues nos aparecerá aquí 100.
Este es el que vamos a ir actualizando cada segundo que vaya pasando.
Este sería el current time.
Y ahora, del paragraph, lo que vamos a hacer, paragraph, es el inner, que aquí, sí, innerHTML, ¿vale?
Vamos a hacer algo.
Vamos a hacer que el párrafo, que tenemos ahora mismo aquí vacío, se llene de nuestras palabras.
Lo fácil sería pensar.
Lo que pasa es que, claro, alguien diría, bueno, pues ¿por qué no haces como me estaba diciendo aquí esto, no?
Que me estaba diciendo algo como esto, ¿no?
Hacer algo así.
Y ya está, ya tenemos ahí el texto, fantástico, perfecto.
Esto, funcionar funciona, porque así vemos aquí todo el texto y todo esto, pero no nos va a permitir hacer las magias, que tiene bastante magia, de esto de escribir, ir para atrás, si te equivocas ponerlo en rojo, ir al siguiente y poner esto así.
O sea, necesitamos aquí un montón de elementos HTML que nos van a dar la magia para permitir hacer esto, ¿no?
O sea, que va a ser bastante, bastante, bastante más complicado, ¿eh?
¿Se invocan antes de crearlas?
Sí, no hay ningún problema.
Las funciones en estas, en estas, se pueden invocar antes de crearlas.
Porque las funciones, lo que estamos haciendo en JavaScript cuando utilizas las funciones, es que esto se está creando en memoria y ya están disponibles desde el principio.
Esto es una cosa que ocurre con las funciones, pero si utilizas una constante, por ejemplo, se quejará, ¿eh?
Si utilizas una constante, sí que te dirá, estás utilizando la constante antes de inicializarla.
Por eso utiliza las function, y las pongo ahí debajo, pero ya lo deberíais saber que esto, que las funciones, las puedes utilizar antes porque la invocación, la posibilidad de que la función la puedas utilizar es ya desde el mismo scope donde esté creada, ¿vale?
Hay gente que dice que se crean arriba del todo, pero no es exactamente que se crean, o sea, el hosting no es que se creen arriba del todo, sino que es verdad que ya está reservando en memoria el espacio de la función.
Por eso lo está haciendo, ¿no?
¿Por qué el dólar? Bueno, el dólar que estoy utilizando aquí, esto básicamente lo utilizo para los elementos del DOM.
El árbol de elementos, cuando hago un query selector, me gusta diferenciarlos de alguna forma.
Y así lo que hago es decir, vale, sé que esto es un elemento del DOM porque tiene el dólar.
Si no os gusta así, pues podéis utilizar time element o algo así, pero claro, piensa que si pongo time va a parecer que sea como que estoy hablando del valor del tiempo.
Y no es el caso, ¿no? Y así pues es más fácil quedarme con que es el elemento que quiero del DOM, ¿vale?
Bueno, pues lo que os decía, esto lo vamos a tener que complicar un poquito.
A ver, está bien, ¿no? Porque nos está enseñando lo que queremos, pero vamos a tener que complicarlo.
Y lo que vamos a hacer aquí es inventarnos nuestros propios elementos HTML.
Esto está muy chulo. Que hay gente que dirá, esto no, no sé qué. Bueno, pues bien que lo estoy haciendo.
Ven aquí a pararme los pies, si quieres. Ven aquí a pararme los pies.
Bueno, ¿qué es lo que vamos a hacer aquí dentro? Lo que vamos a hacer primero es que de cada palabra que tenemos en el array,
lo primero que vamos a hacer es sacar las letras. Entonces, words.split.
Y esto utilizamos el split aquí con vacío, una cadena de texto vacía, para que cada palabra, por ejemplo, pues esta,
me la divida en un array de tres elementos. Y ahora que tengo las letras, lo que vamos a hacer es devolver este HTML.
Un HTML donde vamos a tener una etiqueta palabra. Esto se podría hacer perfectamente con un span.
Pero ahora os explicaré por qué voy a utilizar word, primero porque me hace ilusión, y luego porque no hay ningún problema, ¿vale?
Entonces, de cada letra, dentro de la etiqueta palabra, de cada letra, lo que vamos a hacer es transformar la letra,
letter, ¿vale? Y aquí vamos a poner la letra. Ahí está. Vamos a hacer esto, dentro la letra, y esto para que se vea bien,
vamos a ponerlo así, ¿ok? ¿Qué es lo que estoy haciendo aquí? Estamos creando una etiqueta palabra,
y dentro le estamos metiendo cada una de las letras. Y estamos mapeando las letras, ¿vale?
Tenemos aquí la letra y tal. Tenemos que hacer el join para quitar la coma, porque si hacemos esto,
vais a ver que queda un poco raro. De hecho, lo vamos a tener que hacer aquí también.
Y ahora, el problema de que no sale es porque aquí está utilizando el text content,
y aquí tendría que utilizar innerHTML, ¿vale? Y ahora vamos a ver por qué esto no funciona,
porque veo que no me lo está haciendo, y puede ser que sea una tontería.
Vamos a ir a nuestro aquí. Debe ser una tontería, que algo se me ha perdido aquí.
Vamos a la consola.
Words.split is not a function. Words.split, porque es word. ¿Vale? Ya está.
Vale. Ahora visualmente parece lo mismo. Visualmente parece lo mismo.
Pero fíjate, vamos a ir aquí, y fíjate lo que ha pasado aquí.
Vale, tenemos el párrafo, y por cada párrafo tenemos una palabra,
y de cada palabra tenemos un letter. Ahora, ¿esto está bien?
Es polémico. Es polémico. A ver, no pasa nada, no pasa nada en el sentido de que
estas etiquetas no existen. Pero es verdad que podría ser un poco polémico.
Para mí está bien. Sí. A ver, podríamos utilizar spans. ¿Qué es lo que pasa?
Si tú utilizas una etiqueta HTML que no existe, ¿vale? Si tú utilizas una etiqueta HTML que no existe,
no pasa nada. HTML lo que hace es tratarlo como que no tiene semántica.
En realidad lo que está pasando aquí es que los está tratando como si fuesen spans.
Entonces, pues podemos hacer aquí span, ¿vale? Y aquí span, ¿vale?
Y podríamos utilizar una clase que aquí fuese word, y aquí pues fuese letter.
Esto también estaría bien, no habría ningún problema. Lo podríamos hacer así,
y tendría, sería exactamente lo mismo, ¿no? Sería esto.
Bueno, ¿por qué lo estoy haciendo de la otra forma? Primero, porque creo que queda
mucho más legible rápidamente, porque no hay ningún problema en que utilicemos esta etiqueta,
porque no existe en HTML y se va a comportar exactamente como un span,
y por lo tanto nos va a ayudar un poquito más visualmente a verlo rápidamente en el DOM.
Pero si por lo que sea a ti te molesta o lo que sea, pues utiliza una etiqueta en condiciones.
Otra cosa que podemos hacer justamente también sería evitar utilizar una etiqueta de una sola palabra,
que puede ser un poco más problemático, y podríamos utilizar algo así,
mword o xword, ¿vale? Y esto sí que es totalmente aceptable.
Y os voy a explicar por qué esto sí que es totalmente aceptable.
Esto que estamos haciendo aquí de poner x-word o cualquier prefijo, ¿eh?
El prefijo que tú quieras, el que tú prefieras.
Esto es correcto semánticamente en HTML porque puedes crear tus propias etiquetas en HTML.
Se llama un custom elements. Esto es totalmente correcto.
Que nadie te diga, te estás inventando...
No, no es que te estés inventando nada.
Es que HTML te permite crear tus propias etiquetas siempre y cuando utilices un prefijo.
Entonces, lo podrías utilizar así.
Y esto es válido 100%.
Sí que es más polémico esto, ¿vale?
Esto sí que puede ser más polémico, ¿por qué?
Porque el día de mañana HTML puede añadir esto.
¿Y qué si te lo inventas?
Bueno, no pasa nada.
Esto sí que es un problema porque el día de mañana, igual HTML, pues dice,
ah, pues voy a crear la etiqueta Word.
Y entonces sí que se rompería la compatibilidad.
Pero si le pones x-guión, ya no tiene ningún problema porque HTML, ya os digo yo,
que esto lo permite y es totalmente válido.
Y esto se le llaman custom elements.
Que además le podéis añadir JavaScript y un montón de cosas, ¿eh?
Pero yo me la voy a jugar y voy a poner Word y Letter y vamos a ir así y ya está.
Entonces, una vez que ya tenemos esto, ya tenemos el Join, pues ya me aparece aquí.
Parece igual que antes, pero fijaos que ahora, si vamos, tenemos cada una de las letras,
las tenemos separadas.
Así que va pintando bien.
Voy a estilar un poco esto, ¿vale?
Vamos a poner un main.
Vamos a ponerle un poquito aquí de padding.
Padding 16.
El display flex.
A ver, no sé si poner un display flex.
Direction, column.
He puesto el main aquí.
Bueno, claro, es que he puesto aquí el game.
Claro que el game...
Igual tendría que ser el section esto, ¿no?
Igual tendría que estar en el section.
Bueno, no pasa nada.
Le vamos a poner gap 8.
¿Qué estoy pensando?
Bueno.
Yo estoy pensando ya en los resultados, ¿sabes?
La madre que me parió.
Vale, vamos a poner aquí el color amarillo.
Vamos a poner el color amarillo, que es más o menos como el color que tiene.
El input.
Ya os digo yo que este input no es visible para el usuario.
Pero nosotros por ahora vamos a hacer, para poder depurar rápidamente lo que vamos haciendo,
voy a quitarlo del medio.
Lo voy a poner arriba a la izquierda, ¿vale?
Y así lo tenemos aquí.
Y luego lo que vamos a hacer más adelante...
Pointer events none.
Lo que vamos a hacer también será esto.
Opacidad cero.
Y lo quitaremos.
O sea, esto es lo que vamos a querer hacer.
Pero por ahora, lo voy a poner aquí para que podamos ir viendo qué es lo que va haciendo, ¿vale?
Y aquí vamos a poner la P del párrafo.
Display flex, ¿vale?
Vamos a poner el flex grab grab.
¿Vale?
Ahora veis que sale ahí todo junto, pero nada.
Le ponemos unas separaciones a las letras y ya está.
Esto básicamente es para que tengamos un mejor control de cómo queremos separarlos y todo esto.
Por si le queremos dar más separación o menos.
Ya os digo que yo creo que algo así, algo así es como está en la página web, más o menos, ¿vale?
Entonces, ya tenemos lo más básico, pero ahora empieza...
Bueno, voy a hacer el timer primero, que es más fácil.
Porque luego todo esto de aquí dentro, esto es muy interesante.
El hecho de tener el...
Aquí, ¿cómo se tienen que ir moviendo las letras de ir atrás y todo esto?
Parecer que estás escribiendo ahí.
Bueno, bueno.
Eso va a ser un temazo.
Un temazo.
Así que por ahora vamos a poner aquí el intervalo de la cuenta atrás, ¿vale?
Set interval.
Aquí vamos a poner que cada segundo que pase, vamos a ir actualizando el tiempo, ¿vale?
Y vamos a ir actualizando el time.textContent con el nuevo tiempo.
Y ahora aquí deberíamos tener la cuenta atrás.
Bueno, podemos decir que si el tiempo llega a cero, pues esto sería ya el game over.
Vamos a poner un console.log game over.
Y deberíamos también limpiar el intervalo.
Porque si no, esto llegará a menos uno, menos dos.
De hecho, lo podemos ver, ¿eh?
Si no hacemos esto y le digo que el tiempo inicial sea uno, pues pondrá cero, menos uno, menos dos.
Entonces, queremos que cuando llegue a cero, también pare de esto, ¿vale?
Y ahora se quedará así.
Limpia el intervalo y ya esto lo cancela.
Si no, se quedaría ahí ad infinitum y no tiene mucho sentido.
Y ya que estamos por aquí, voy a crear la función game over, que será cuando termine el juego.
Y la vamos a llamar aquí.
Y ya llamaremos siempre al game over cuando necesitemos, ¿vale?
Por ahora pongo un console.log y ya está.
Voy a volver a poner los 30 segundos y perfecto, ¿vale?
Pues ya tendríamos el timer.
El timer está como muy separado o es cosa mía.
A ver, aquí... ¿Por qué está tan separado?
Porque este section... Ah, porque le he puesto este gap.
Y porque este párrafo... Vale.
El párrafo este tiene aquí un margen que se lo vamos a quitar.
Y este section... Le he puesto aquí un gap que le vamos a poner menos.
Entonces, ya tendríamos esto, pero ahora nos falta mostrar la primera palabra activa.
Cuando empezamos en el juego, aquí...
Fijaos que está ya el cursor, ¿no?
O sea, que ya deberíamos tener una palabra activa.
O sea, ya está esperando a como que hagamos algo.
Vale. Pues lo que vamos a hacer cuando empezamos el juego, aquí, vamos a buscar en el párrafo la primera palabra que encontremos
y le vamos a añadir una clase y le vamos a decir la palabra active.
¿Esto cómo va a funcionar?
Esto va a buscar el párrafo, ¿vale?
Que es el párrafo que tenemos aquí.
Y dentro tenemos las palabras.
Como estamos utilizando el query selector, es que esto es un error muy común que veo que está muy interesante, ¿vale?
Para que lo tengáis en cuenta.
Y no lo cometáis vosotros.
Sí, ya ahora está corriendo el tiempo, ¿eh? Totalmente.
Mirad.
El tema es...
Mucha gente aquí lo que hace...
Mira, lo voy a hacer aquí para que lo veáis.
Lo que hace es decir document.queryselector.all.
No, word, ¿no?
Y esto es lo que te devuelve son todos los elementos con esta etiqueta, con este selector.
Y aquí dicen, vale, pues me quedo con el cero.
Esto no tiene sentido.
Esto no tiene sentido, ¿vale?
Porque es innecesario.
Si te vas a quedar con el primer resultado, lo mejor que puedes hacer, document.queryselector.org.
Esto lo que hace es...
¿Ves?
Que se está ya pillando el primero.
Y es mucho, mucho más rápido.
No tiene sentido, si te vas a quedar con el primer resultado, ¿vale?
Que los pidas todos.
Que digas, ah, voy a hacer un queryselector.
Los voy a pedir todos y me quedo con el primero.
No tiene sentido, ¿vale?
No tiene sentido.
Si vas a quedarte con el primero y ya sabes que quieres el primero,
lo mejor que puedes hacer es document.queryselector y ya está.
Y punto.
No tiene ningún...
No tiene sentido que busque todos, que te devuelva la rey y que te quedes con el...
O sea, solo con el primer resultado, ¿vale?
Es mucho más rápido.
Y esto nos vamos...
Vas a ver que hoy lo vamos a hacer diferentes formas.
O sea, diferentes veces.
Vamos a aprovecharnos de esto unas cuantas veces.
Y aquí lo mismo.
Por ejemplo, una vez que ya tenemos el párrafo, o sea, podríamos buscar la primera palabra.
Ahora, podríamos hacer aquí first word, ¿vale?
La primera palabra sería esta.
Y entonces la guardamos aquí.
La primera palabra la activamos.
Y ahora, de la primera palabra, vamos a buscar la primera letra.
Y hacemos otra vez lo mismo.
Class list, punto add, active.
Y esto ahora, visualmente, no debería haber ninguna diferencia, ¿vale?
Pero aquí sí que hay una diferencia.
Y es que, ¿ves?
Active y active.
La primera palabra y la primera letra ya las tenemos activadas.
Vámonos a los estilos.
Tú, tú, tú.
Y aquí vamos a estirar la letra.
Vamos a ponerle...
Vamos a poner otro gris.
Ah, mira, ya tengo un gris ahí.
Vale, verdad.
Bar.
Vamos a poner este gris.
¿Vale?
Para que tenga ese estilo, vamos a poner que si la palabra está activa,
vamos a poner un content.
Vamos a hacer...
Vale, ¿veis?
Que ya tiene ahí eso.
Pues eso es justamente lo que queremos.
Solo que, claro, si hago que el color sea amarillo, el problema...
Este es el...
¿Cómo se llama esto?
Cursor.
No sé si llamarle cursor.
¿Cómo le llamo a esto?
No sé si llamarle cursor, el puntero...
No sé cómo le queráis llamar.
Pero algo así.
Lo voy a hacer un poquito más pequeño.
De hecho, no sé si...
A ver, vamos a poner...
Claro.
Fijaos que está ocupando un espacio.
Como si fuese una letra.
Eso no lo vamos a querer.
Vamos a querer que sea position absolute para que no ocupe espacio.
¿Veis?
Que sea así.
Para que no ocupe espacio.
Lo que pasa es que está mal colocado.
Así que vamos a poner que left sea menos 50%.
Vale.
Y ahora ha desaparecido.
¿Por qué ha desaparecido?
Porque...
Vale.
Fijaos.
Si le pongo left 0, fijaos dónde me la ha dejado.
Necesitamos que la letra tenga un position relative.
Para que la posición absoluta de este elemento sea relativa al padre.
Las posiciones absolutas lo que funcionan es mirando a sus padres a ver cuál es el primero que tiene el relative.
Para saber cuál es la posición relativa.
Y si no, utiliza la del body.
Que es lo que está pasando aquí.
Así que con esto ya lo tendríamos.
Ahora, aquí vamos a poner menos 65 píxeles.
¡Hostia!
Demasiado.
Bueno, en lugar de píxeles vamos a utilizar el tanto por ciento.
Un poquito más.
Vale.
Yo creo que ahí...
Ahí está.
¿Vale?
Más o menos.
A ver, la idea es que se vea más o menos.
Que no sea tampoco mega perfecto porque si no le voy a hacer el juego.
¿Vale?
Blink.
Infinite.
Vamos a hacer el parpadeo en un momento.
Is in out.
Para el parpadeo, para tener ahí el cursor, añadimos los keyframes con el blink.
0 y 50 por ciento la opacidad a 1.
¿Vale?
Y cuando esté al 100 por ciento la opacidad a 0.
Bueno, más o menos.
Más o menos.
Infinity.
Vale.
Pues más o menos, ¿no?
No sé si voy a hacer 25, 75.
A ver.
Creo que mejor, ¿no?
Que queda más natural.
Es que el otro queda como que hace un...
¿Qué os parece?
Ya tenemos el...
Que no está mal, ¿eh?
No está mal, no está mal.
Vale.
Entonces ya tenemos al menos como el cursor.
Ahora el problema del cursor es que se tiene que ir moviendo, ¿vale?
Así que vamos a ver esto que esto va a ser un temazo.
Esto de que se vaya moviendo el cursor.
A ver.
Ya tenemos el cursor.
Ahora necesitaríamos empezar ya con los eventos del teclado.
Para iniciar los eventos del teclado, aquí en el init events, vamos a pillar.
Por un lado, primero, cuando en el...
Vale.
Primero, el input.
Ya le he puesto el autofocus.
Vale.
Esto es importante para intentar que haga un foco nada más entrar en la página.
El problema es que...
¿Veis que aquí sí que me hace el foco?
Y si me pongo a escribir, ya escribe.
Claro.
Pero aquí en el editor no lo hace.
¿Veis que nada más entrar no me está haciendo el foco?
Esto seguramente es por alguna limitación de cómo funciona integrado el editor o el navegador dentro del editor.
Entonces, voy a hacer o voy a intentar para arreglar esto aquí, que cuando en el document hagamos un keydown, ¿vale?
Cuando escribamos en el documento, voy a hacer que el input reciba el foco.
Entonces, entiendo...
¿Ves?
Ahora sí que ha funcionado.
Ahora, cuando escribo, sí que funciona.
Fijaos la diferencia.
Que si esto lo quito e intento escribir...
¿Ves?
No lo está pillando el foco.
No lo pilla.
Y debería pillarlo automáticamente.
Entonces, vamos a hacer esta trampa para que cuando en el documento hagamos keydown, pues escriba.
¿Vale?
Entonces, ya tenemos esto.
Perfecto.
Y ahora, tendríamos que cuando en el input hagamos el keydown, vamos a hacer on keydown, ¿vale?
O sea, cada vez que dentro del input, pues pulsemos una tecla, vamos a llamar a esta función.
Y cada vez que dentro del input soltemos una tecla, vamos a llamar a esta función.
Y esto es importante porque vamos a querer separar cuando el usuario le está dando a teclas normales
o cuando el on keyup es cuando sueltan la tecla.
Y eso va a ser interesante para las teclas normales.
Pero el keydown va a ser importante para las teclas especiales, como por ejemplo el espacio
o por ejemplo el retroceso.
Esas dos las vamos a querer controlar antes del keyup.
Porque si no, sería demasiado tarde.
En el keyup es como que ya ha ocurrido.
Ya lo ha puesto en el input.
Y en el keydown es que vamos todavía a poder evitar el comportamiento por defecto.
Así que eso lo vamos a querer arreglar.
Voy a poner aquí las dos funciones.
On keydown, ¿vale?
Function, on keyup.
¿Ok? Vale.
Ya lo tendríamos.
Y ahora empezamos con la de on keyup, que creo que va a ser la más divertida.
También para la tecla de tilde.
Bueno, todavía no vamos a hacer las tildes.
Y de hecho, las tildes también podríamos hacerlo de otra forma.
No sería tan poco complicado.
O sea, no habría ningún problema hacerla.
No habría problema porque al final la tilde se pone aquí normal.
Y la podríamos comparar, ¿ves?
O sea, es que está ahí.
Y ahí podríamos comparar exactamente cómo funciona.
O sea, que eso lo podríamos arreglar.
Pero por ahora nos vamos a enfocar en cómo lo hace el monkey type,
que al final no tiene ni mayúsculas.
Y ya más adelante lo podéis iterar tantas veces como queráis vosotros.
Y llevarlo al nivel de detalle que vosotros queráis.
Es imposible que yo haga todo el producto del monkey type en menos de dos horas.
No me daría la vida.
No me daría la vida.
Y lo que queremos son resultados.
Así que nada, recuperamos los elementos actuales.
Vamos a pillar primero cuál es la palabra actual.
Vamos a mover esto.
Vamos a hacerlo un poco más pequeño.
¿Cuál es la palabra actual que está activa?
Así que vamos a pillar la palabra activa.
Y vamos a pillar cuál es la letra actual que está activa.
De la palabra actual buscamos la letra activa actual.
Siempre va a haber una palabra activa y una letra activa.
No puede haber dos letras activas o dos palabras activas.
Así que es súper importante que constantemente estemos mirando que solo hay una activa.
Y que estemos limpiando constantemente las clases.
Ahora, lo que podemos hacer es recuperar cuál es la palabra actual.
Pues nada, en el current word vamos a entrar al inner text y vamos a eliminar los espacios que yo creo que esto no es necesario.
Pero esto, el current word, ahora mismo debería ser...
Uy, current word.
Voy a poner aquí una consola.
Debería ser este, de.
Si nos vamos aquí y miro en la consola y le doy...
¿Vale? ¿Veis?
La palabra actual que estoy intentando escribir es de.
Y ahora que ya en el input tengo lo que he escrito, aquí puedo escribir lo que quiera.
Vamos a recuperar tanto lo que tenemos...
Mira, podríamos recuperar lo que tenemos...
Voy a hacer eso.
Voy a hacer el value, es el input value.
Y tendríamos aquí el current word.
¿Vale?
Y así lo veremos más fácil.
Problemas que tenemos aquí.
Fijaos en los problemas que tenemos aquí.
Voy a hacer esto un poco más grande.
Para que lo veamos bien.
¿Vale?
Cuando tú escribes aquí...
¿Vale?
Fijaos.
Este sería el valor del input y este la palabra actual que estamos mirando, que la tengo aquí.
Primer problema.
Que aquí puedes escribir tanto como quieras.
¿Vale?
Entonces, ¿qué vamos a hacer?
Vamos a hacer que cuando soltemos la letra, cuando soltemos una letra,
vamos a limitar las posibilidades del input
y le vamos a cambiar la longitud máxima por la longitud máxima de la letra actual.
O sea, de la palabra actual.
Así, lo único que podremos escribir aquí será...
Uy, la he liado ahí.
Ahora.
Solo podemos escribir tres letras máximo.
¿Vale?
Así compararemos más fácil.
Porque si yo le dejo ahí que me escriba lo que quiera,
pues va a ser mucho más fácil, mucho más difícil.
Vamos a limitar el número de letras que se pueden escribir en el input.
¿Vale?
Esto es lo primero.
Ahora vamos a ampliar un poquito más la lógica.
Lo que vamos a hacer es recuperar el input, el valor del input.
Vamos a hacer un split para tener también en un array.
Y para cada una de esas letras, cada una de las letras,
vamos a estar comparando lo que tenemos en el input con la letra que tenemos.
¿Vale?
Entonces, vamos a buscar esta letra.
Mira, ¿ves?
Mira, esta es otra forma interesante de cómo lo dice...
Voy a quitar esto.
Esto es como lo dice Gijacopilot.
¿Vale?
Que no está mal, no es mala idea.
El hecho de recuperar la letra utilizando currentWord.
¿Esto podría ser buena idea?
¿Esto no sería mala idea?
Mira, os voy a explicar cómo yo lo había pensado.
Yo lo había pensado hacer así.
CurrentWord.querySelector.
Y recuperar la letra que sea la número y le pasarle aquí el index.
¿Vale?
Aquí lo puedo hacer así con un templateString.
Y así solo recuperaría exactamente la letra que queremos.
¿Vale?
Y así la podemos comparar exactamente.
Esta sería la letra que queremos comparar.
¿Qué es lo bueno y lo malo?
Lo bueno de esta...
Bueno, lo bueno es que la recupera todas, pero se queda con un índice.
Y esta, lo bueno que tiene es que solo recupera una letra.
Que tiene más sentido.
Porque hacer esto, un forEach y recuperando todo el rato todas las letras es un poco raro.
Lo que se podría hacer es la de arriba, que es la que ha hecho GeekHackoPilot.
Pero guardando las letras.
Entonces aquí tienes all letters.
Quitamos esto.
¿Vale?
Y en lugar de hacer esto, que a lo mejor era un selector más complicado.
Aquí sacar la letra una vez.
Y así la sacamos una vez.
¿Vale?
Ya tenemos aquí cacheado esto.
Y en las iteraciones lo único que hacemos es sacar del índice la letra que nos interesa.
Y ahora sí es que podemos chequear cuál es la letra.
Podemos decir, ¿cuál es la letra chequear?
Pues de la palabra actual, el índice.
Y fijaos que ya tenemos la letra, el elemento de la letra.
Y la letra de la palabra actual que tenemos que chequear.
Y ahora ya sabremos cuál es la clase que tenemos que ver.
O sea, tenemos que ver si es correcto.
¿No?
Si la letra que tenemos en el input es igual a la letra que hay que chequear.
¿Vale?
Pues será correcto.
Y si es correcto, pues ya le podemos aplicar diferentes clases.
Si es correcto o incorrecto.
Estoy pensando aquí cuál es la clase que...
O sea, cómo...
Bueno, vamos a poner letter class.
Si es correcto, pues le vamos a poner correct.
Vamos a hacerlo sencillo porque si no...
Correcto.
Y si no, pues es incorrecto.
Punto.
Ya está.
Y ahora solo tenemos que decir que al elemento le añadimos esta clase.
Ahora visualmente no veremos nada.
Pero si vamos aquí a los elementos.
Si me pongo a escribir.
¿Veis?
He escrito ASD incorrect, incorrect, incorrect.
La he puesto tres veces mal.
No se ha movido el cursor porque todavía no lo hemos movido.
Pero al menos, fijaos...
Vale.
Además hay que limpiar...
¿Veis que se ha quedado el incorrect?
Esto es porque tenemos que limpiar las letras antes de...
De hecho, lo vamos a hacer...
All letters.
Vale.
Como tenemos aquí el all letters, tendríamos que limpiar...
Remove.
Vamos a limpiar el correct.
Y el incorrect.
¿Vale?
Porque como esto lo vamos a estar haciendo constantemente...
Midu, ¿podría poner el query selectorial fuera de la función?
Fuera de esta función, no.
Fuera de esta función, no.
Porque esta función siempre va a ser las letras de la palabra activa.
Y no sabes cuál es la palabra activa hasta que no escriba aquí.
Entonces, yo creo que tiene sentido dejarlo aquí.
Podríamos hacerlo un poco más complicado.
Pero...
Me parece que no es necesario.
O sea, creo que no tiene un impacto muy bestia.
Vamos a ver.
Ahora ya se supone que podemos escribir.
¿Veis?
Me dice, correcto, correcto, correcto.
¿Puedo borrar?
Y fijaos que...
O sea, ya con lo que hemos hecho.
Ya con lo que hemos hecho.
Fijaos que ya puedo poner...
Bueno, es que le voy a dar los estilos.
Y vas a decir, menos mal que he venido.
Vais a ver.
Vais a decir, menos mal, menos mal que he venido.
Mira, a las correctas le vamos a poner el color green.
Y a las incorrectas le vamos a poner el color rojo.
Y vas a decir, ¿qué magia negra es esta?
¿Qué magia negra es esta?
Que ya estamos empezando a hacer magia.
¿Qué está pasando?
¿Qué está pasando?
A ver, todavía nos faltan cositas porque, obviamente, tenemos que hacer el espacio y ir a la siguiente, ¿no?
Pero fijaos que ahora tenemos el input aquí, que vamos escribiendo.
Voy borrando y automáticamente aquí desaparece, ¿vale?
Y escribo ASD, que están mal.
Incluso si hago una que esté bien.
AHE, fijaos.
O A.
Fijaos que aquí tenemos estas y estas aquí.
O sea, que se están...
Se está sincronizando, ¿no?
El si está bien o está mal, se está sincronizando.
Vamos a seguir haciendo magia.
Para seguir haciendo magia, creo que tenemos que mover el cursor, ¿no?
Porque el cursor queda raro que se quede ahí.
Vamos a mover el cursor.
Y el cursor...
Vale.
Iniciamos el evento.
Cuando hacemos el input...
Vale.
O sea, justo después.
Una vez que hacemos esto, primero, en la letra actual, la quitamos de activa.
Current Letter.
Vamos a quitar.
Vamos a quitar que esté activa, ¿vale?
Eso es lo primero, porque tiene que dejar de estar activa.
Entonces, ahora cuando escriba, desaparecerá.
Vale.
Tiene sentido.
Lo que necesitamos es saber cuál es la que está activa.
Entonces, vamos a buscar el...
Vamos a buscar el input length.
¿Que el input length, en realidad, lo he usado antes?
Es que estoy mirando para...
No.
He usado el max length.
Vale.
Para no repetir, que estoy repitiendo ahí todo el rato.
Input.value.length.
Vamos a recuperar la longitud del input.
Y a través de la longitud del input, vamos a...
Vamos a...
Como tenemos aquí todas las letras, lo único que tendríamos que hacer es, de todas las
letras, la longitud del input, le ponemos que sea la letra activa.
Y con esto...
Vale.
Ahí hay un problemilla.
No pasa nada.
Porque ahora os explicaré por qué.
Pero al menos...
¿Veis?
Podemos ir para adelante.
Podemos ir para atrás.
Y ya está, ¿eh?
O sea, no está mal.
¿Pero no sería mejor no dejar avanzar si letter no corresponde?
No.
Porque, a ver.
Eso es...
Ya es subjetivo tuyo, ¿eh?
Pero yo estoy intentando...
Por ejemplo.
¿Ves?
Aquí es como funciona.
Te deja avanzar.
A ver.
Como tú quieras.
Yo lo hago como está en monkey type.
Y creo que tiene sentido.
El hecho de que te dice cuál está mal.
Tú avanzas, pero te ha dejado el error ahí.
No tendría mucho sentido no dejarte avanzar.
Porque imagínate que no te deja avanzar.
Si no te deja avanzar, el problema es que no vas a mejorar en el teclado.
Porque no te deja avanzar y ya todas las demás...
No te vas a enterar que las has hecho mal y tal.
O sea, yo creo que tiene más sentido que te deja avanzar.
Te des...
Metes ese error y ya está.
Y ya tomas por saco.
Porque si no es un poco...
Lo que sí que es verdad que una cosa que hace monkey type que a mí no me gusta mucho
es el hecho de que puedes poner más letras después.
Yo, la verdad, esto a mí no me termina de gustar tanto.
Esto sí que no lo vamos a hacer porque me parece un poco más exagerado.
Ya, pero bueno, que es una cosa que podéis añadir si os gusta.
Yo no lo voy a añadir en esto.
Lo voy a limitar para simplificarlo.
Pero bueno, que al menos...
Bueno, vamos a hacer ahora que cuando...
Fíjate que cuando ponga la última, desaparece.
Esto es porque no hay una siguiente letra y el cursor no sabe dónde ponerse.
Fijaos aquí.
De hecho, es raro que no...
Ah, ¿ves?
Digo, ¿ves?
Me está fallando aquí en la consola.
Me dice, es que estoy intentando leer la propiedad undefined de classlist.
Que debe ser este, ¿no?
Claro.
Entonces, lo que deberíamos poner aquí...
Deberíamos hacer un check extra.
Aquí, ¿no?
Tenemos que saber si es la última letra.
O podemos mirar si es la última letra.
Podríamos buscar si esta letra existe.
O sea, podríamos poner aquí last letter, no.
New o next active letter, ¿vale?
Podríamos hacer algo así, que sería esta letra.
Y que si hay una next active letter, hacemos esto.
Vamos a quitar esto para next active letter.
Vamos a utilizar esto para también saber que es un elemento del DOM.
¿Vale?
Si tenemos una siguiente letra, hacemos esto.
Y si no tenemos una siguiente letra, pues ya tendríamos que hacer una cosa distinta.
¿Qué podríamos hacer?
Pues le podríamos indicar que la letra actual, no solo le vamos a añadir que está activa,
sino que vamos a ponerle como otra clase para decir que es la última.
Porque así lo que hacemos es mover el cursor a la derecha.
Y esto también...
Esto...
Lo vamos a poner por aquí.
Vamos a meterle los estilos de...
No sé si poner aquí.
Punto...
No sé si cómo ponerlo si...
Lo voy a poner todo así a lo bestia.
Is last before...
¿Vale?
En lugar de esto, vamos a poner el left.
Lo vamos a poner al otro lado.
65% para la derecha.
Y con esto...
Me desaparece.
Vale, vamos a ver.
Que aquí hay algún problema.
Vale, se me ha olvidado ahí poner un dólar.
Este dólar se me ha olvidado.
¿Vale?
Ahí está.
Y borramos.
Vale, hay un error.
Hay un error ahí raro, pero ahora lo miramos.
Pero al menos cuando entramos por primera vez, ¿veis?
Ahora se pone a la derecha que justamente es como funciona aquí.
Que tú escribes y va y se queda aquí.
Esperando que le des al espacio.
Y eso es lo que tenemos que hacer ahora.
Que tiene que ir al espacio.
El tema es...
¿Por qué el is last este?
Ah, puede ser porque no lo quitamos aquí.
No, claro.
Tenemos que limpiar todos...
Esta clase también antes.
¿No?
O sea, habría que limpiar las clases.
Ahora sí.
Ahora sí.
Ahora sí.
Vale, vale.
Pues ya tenemos el movimiento en la palabra.
¿Vale?
Ya tenemos el movimiento del cursor en la misma palabra.
Ahí lo tenemos.
Perfecto.
Muy bien.
Pues con esto...
A ver.
Aquí además deberíamos hacerlo el game over.
Que si aquí hemos llegado a la última palabra...
O sea, básicamente...
Si...
Si tiene...
Esto es si tiene siguiente letra.
Claro.
Aquí...
Entiendo que aquí...
Si...
Game over.
Si no hay...
Próxima palabra.
Claro.
Si no hay una próxima palabra...
Aquí deberíamos hacer un game over.
Voy a poner el to do.
¿Vale?
Por ahora.
Y luego lo...
Luego lo arreglo.
El backspace funciona.
O sea, que el backspace no nos tenemos que preocupar tanto.
Pero sí que nos faltaría el espacio.
Para que al darle al espacio...
Vaya la siguiente palabra.
Eso...
Va a estar interesante.
A ver.
Vamos a ver.
OnKeyDown.
Vale.
Ya teníamos aquí el evento...
De que cuando...
Cuando hacemos KeyDown.
O sea, cuando pulsamos la tecla...
Llamamos a la función OnKeyDown.
Esto recibe un evento...
Y aquí en el evento podemos sacar la Key.
Y aquí en la Key...
Podemos mirar qué es lo que está haciendo.
Y si hago de espacio...
Fijaos que la Key del espacio es un espacio.
Literal.
¿Sabes?
Es un poco...
Es un poco así de...
De friki.
Así que vamos a hacer eso.
Que si la Key es igual a un espacio...
Pues ahí estamos en el espacio.
¿Vale?
O sea, en el espacio.
No estamos en el espacio.
Es que hemos hecho un espacio.
No que estamos en un espacio.
Eso es en el caso que nos hayamos fumado algo muy raro.
Vamos a hacer un PreventDefault para...
Para como parar el comportamiento por defecto que tendría en el evento.
El evento por defecto sería utilizar el Input y poner el espacio en el Input.
Y esto lo que estamos haciendo es decirle...
No, no.
Si le das al espacio...
Haz un PreventDefault.
Para que lo vean más claro.
Si quito esto y yo aquí hago A espacio A...
¿Veis que me ha puesto aquí el espacio?
Ahora, si le dejo aquí el PreventDefault...
Como estoy capturando este evento y le estoy diciendo...
No, no.
Pero quiero que evites el comportamiento por defecto de este Input.
Fíjate que aquí...
Si hago...
Ahora, espérate.
Ahora...
A espacio A...
¿Ves?
Aquí no me ha puesto el espacio.
Porque le he dicho...
No, no.
Si haces un espacio, no lo pongas.
Porque me quiero ocupar yo.
Porque fijaos que también ellos...
Lo que hacen aquí...
Es que si tú pones...
Y le das a la F...
Espacio...
Ya va a la siguiente palabra.
Claro.
Y te dice...
Oye, que esta palabra está mal.
Pero tú puedes seguir...
¿Ves?
Y cada vez que haces espacio...
Ya salta la siguiente.
Eso es lo que vamos a hacer nosotros también.
¿Vale?
Vamos a intentarlo.
Vamos a recuperar aquí.
También, para tenerlo todo...
Vamos a pillar la palabra actual...
¿Vale?
Que esto es una cosa que podríamos guardar en un estado...
Constantemente.
La palabra actual y tal.
Pero bueno.
Por ahora vamos a dejar así.
¿Vale?
Tendríamos aquí la palabra actual y la letra actual.
Que fijaos que es exactamente lo mismo que tenemos aquí.
Bueno.
Por ahora lo hacemos así.
Luego si veo que tiene sentido sacarlo en un estado...
De que sea una variable que está fuera...
Pues lo haremos.
¿Vale?
Entonces, lo que vamos a hacer cuando tenemos un espacio es ver cuál es la siguiente letra.
Para recuperar la siguiente letra a partir de la actual, lo único que tendríamos que averiguar es...
Tengo esta palabra.
La tengo aquí.
Pues si tengo esta palabra quiero esta.
Si tengo esta, quiero esta.
Y en JavaScript...
Bueno.
En el DOM tenemos una forma muy sencilla de recuperar esto.
Que básicamente...
Vamos a crear aquí Next Word.
Y vamos a decirle...
Vale.
Pues del Current Word quiero que me saques el Next Element Sibling.
Esto es el siguiente elemento que es hermano.
Y con esto recuperamos el siguiente elemento.
Y es que el siguiente elemento tiene que ser o puede ser una palabra.
Ahora, es posible que no haya una palabra porque si es la última.
Y esto nos va a ayudar justamente a cuando vayamos a terminar el juego para saber si es un Game Over.
O para saltar directamente y decir, bueno, pues ha terminado.
Pero por ahora vamos a recuperar la siguiente palabra.
Y lo mismo con la siguiente letra.
Vamos a pillar Next Letter y pillamos la siguiente letra.
Ahora que tenemos la siguiente palabra y la siguiente letra...
La siguiente letra siempre va a ser la primera de la siguiente palabra.
Por eso, Query Selector, Letter.
¿Vale?
Eliminamos las clases.
De la palabra actual le quitamos.
Ya no es la activa, la palabra actual.
Vamos a pasar a la siguiente.
Y lo mismo con la letra actual.
¿Vale?
Le quitamos que están activas.
Ya no están activas.
Las que van a estar activas va a ser la siguiente palabra.
¿Vale?
ClassListAddActive.
Y la siguiente letra.
Esto ahora ya veréis que tiene más miga.
Pero esto es para simplificar y para que empecemos por algo.
Y una cosa importante es que una vez que pasemos a la siguiente palabra,
vamos a resetear el input.
Porque el input que lo tenemos aquí...
Claro, fijaos que tengo este input, pero este input es para esta palabra.
Cuando vayamos a la siguiente, cuando le dé a espacio,
que lo ha hecho bastante bien, que estoy flipando, que ha ido ahí.
Ahora...
¡Hostia, pues ya está!
Bueno.
¡Madre mía!
Vale, vale, vale.
O sea, ha funcionado mucho mejor de lo que esperaba, ¿eh?
Ha funcionado mucho mejor de lo que esperaba esto.
Bueno.
Pues ya está hecho.
Ya está hecho.
Hostia, yo pensaba que iba a estar ahí con esto.
¡Hostia!
A ver, a ver, algo...
A ver.
Falta el backspace, que tiene bastante...
Pero, bueno.
O sea, el espacio ya funciona bastante bien.
¿Vale?
The lazy dog and middle deaf is trying to clone monkey type for fun.
¡Madre mía!
Nada, pero quedan cositas.
Quedan cositas porque tendíamos primero aquí...
¡Ah, mira!
Sí que va a la siguiente.
Sí que va a la siguiente.
¡Hostia!
Bueno, bueno.
Yo pensaba...
Yo pensaba que nos faltaría...
A ver.
Una cosa que sí que tenemos que hacer es que cuando...
Nos falta el backspace, que es el más complicado.
Ya lo digo yo.
Pero sí que es verdad que lo que nos faltaría es que cuando le damos al espacio, marquemos la palabra.
Fijaos aquí que cuando estamos aquí y le damos al espacio, ¿veis aquí que marca esto como que está mal?
Pues eso hay que arreglarlo.
Entonces, tú, tú, tú...
Para esto, lo que tendríamos que detectar es si una vez que ya hemos arreglado todo, una vez que hemos pasado a la siguiente, vamos a marcar la anterior.
Vamos a decir, vale, tenía letras...
¿Nos hemos...
¿Han faltado letras?
Si la palabra actual...
No, la palabra actual no.
Sí, sí.
Si la palabra actual...
Si la palabra actual no tiene todas las letras correctas, ¿vale?
O sea, por ejemplo aquí...
Si miramos aquí, fijaos aquí...
¿Ves?
Correcto, correcto, correcto.
Vale, esta, esta es toda correcta, perfecto, pero esta, la segunda, esta, incorrecto, incorrecto y tal.
Vale, si no están todas las letras, podemos hacer eso.
QuerySelectorAll.
Todas las letras que no sean...
Not correcto.
Ah, es porque lo he puesto así.
Vamos a ponerlo así.
Vale.
Vamos a pillar todas las letras que no sean correctas.
Y si la longitud es mayor a cero, es que hay alguna letra que nos ha faltado.
Si tenemos letras que nos han faltado, entonces al current world...
Vamos a hacer class list at market, ¿vale?
Lo vamos a marcar.
Y si no...
Y si no, vamos a hacer...
Aparte de eso, ¿sí?
Vamos a hacer que es correcta, correcta.
Claro, ¿dónde quitamos el marked?
Deberíamos quitar también las marcas.
Estoy pensando sobre la marca esta que también la deberíamos quitar.
Estoy pensando...
Bueno, a ver, no pasa nada.
No, no sé qué pasa.
Tenemos que quitar esta marca.
Vale.
Voy a quitarla primero.
Entonces, current world, remove...
Vale, aquí como estamos quitando el active, yo entiendo que también tenemos que quitar el marked por si acaso lo hemos arreglado.
Y aquí voy a arreglar esto.
Vamos a poner class for...
Class world...
Class to add...
Vale, esto es lo que quiero.
Y así queda más fácil.
¿Vale?
Así marcamos la letra o no.
Y ahora le vamos a poner un estilo que...
Nada.
Ponemos un border bottom ahí en la letra.
Ah, en la letra no, en la palabra.
¿Vale?
Esta es la letra.
Y aquí vamos a poner que si está marcada...
Vamos a poner border bottom, 2 pixels, solid...
Y utilizamos el rojo.
¿Vale?
Y...
Claro, esto va a quedar un poco raro.
Va a dar brincos.
Vale.
No me lo ha marcado.
Vale.
Not correct.
It's not a valid selector.
A ver, que me he inventado.
Me he inventado ya aquí algo.
Me he inventado ya aquí algo.
A ver, ¿cuál es selector not correct?
Pero esto está bien, ¿no?
¿Puede ser que sobre esto?
Claro, puede ser que sobre esto.
A ver.
Vale.
Vale, ahora sí que la está marcando.
¿Vale?
¿Veis que ahora sí que lo está marcando?
Si falta, si están bien...
Si están bien, no hace nada.
Pero con que tengas una mal, ya lo marca.
El problema es que da un brinco.
Si os fijáis, cuando lo añade...
Fijaos que va a dar un brinco.
¡Pling!
Pega un brinco el texto.
Mira.
Verás que el doc se va para abajo.
Ah, bueno, ahora ya no, porque ya tenemos uno.
Cuando ya tenemos uno, ya se arregla.
Bueno, para arreglar esto, lo que vamos a hacer es, con los estilos...
Vamos a hacer que siempre tenga un borde la palabra.
Pero vamos a hacer que esté transparente.
Y lo único que vamos a hacer aquí sería...
No sé si...
Creo que sí que se puede...
Transition...
Creo que sí que se pone el border color.
Sí que se puede hacer.
Entonces, lo que vamos a hacer es cambiar solo el color del borde.
Al rojo.
Y ahora encima, con ese efectillo...
Mejor, ¿no?
Como que queda más...
No sé si dos píxeles es demasiado.
¿Qué?
¿Qué ha pasado?
Ahora.
Pero ahora ya sí que está marcando correctamente esto, ¿eh?
¿Te gusta dos píxeles?
Underline no es una buena opción.
A ver, podríamos utilizar Underline.
Lo que pasa es que Underline es menos personalizable que el borde, ¿no?
Y...
1.5.
Vale, 1.5.
Madre mía, qué pejigueros, tío.
1.5.
1.5.
A ver, 1.5.
Hala, ahí lo tenéis.
Vale.
Pues nada, ya lo tenemos.
Ya tenemos...
Tú, tú, tú.
Y ahí, pues ya está saltando de uno a otro.
Perfecto.
Vale.
¿Y si en lugar de teclar el espacio tecla una letra, no marca el error?
Sí.
Claro que sí.
Mira.
Ah, ¿ves?
Ahí está marcando los errores.
Ahí está marcando los errores.
Tú, tú, tú, tú.
Marca errores de todo, ¿no?
Marca el error de la letra y el del espacio también.
Entonces, ahora...
Ahora nos falta lo más complicado.
Yo creo que es lo más complicado.
Ahora lo que nos falta es el Backspace.
O sea, el retroceso.
Porque aquí, fijaos que en MonkeyType, si tú estás escribiendo, buy, son, begin y te equivocas,
si le das al retroceso, puedes volver y escribirla bien.
Ay, amigo.
Y lo peor es cuando haces espacio y retroceso y va para atrás.
Pero el retroceso tiene sus límites porque, fíjate, si has puesto bien la letra, la palabra, no puedes volver para atrás.
Le estoy dando el retroceso y no me deja volver porque dice, esta letra está bien, ¿para qué vais a ir atrás a arreglarla?
Entonces, tiene sus límites.
Solo es si hay algo que esté mal detrás.
Así que vamos a tenerlo en cuenta también.
Y para hacer eso, vamos a...
OnKeyUp, ¿vale?
OnKeyUp.
GameOver, si no hay próxima palabra...
Vale.
En el...
Aquí.
Aquí deberíamos...
A ver, podemos poner aquí un retro y así lo simplificaremos.
Y si esto es...
Creo que es Backspace.
No me acuerdo si es Backspace así en...
No sé si es en CamelCase o en...
A ver, Backspace.
Es que no me acuerdo.
Console.log.key.
No me...
Key.
No me acuerdo cómo es el...
¿Ves?
No sé por qué pensaba que era CamelCase, pero no.
Es así, ¿vale?
Seguro que me lo habéis dicho en el chat, pero pensad que va con retardo, entonces he aprovechado ya directamente.
Entonces, el Backspace es similar al espacio, pero hacia atrás.
Entonces, en lugar de recuperar la siguiente y la siguiente letra, la siguiente palabra, lo que vamos a hacer es la anterior.
Entonces, ojo a esta cosa tan rata que voy a hacer.
Básicamente he cambiado todo el Next por el Pref y ya está.
Lo primero, el más fácil es que si estamos en la primera letra, en la primera palabra, ¿vale?
Si...
O sea, para saber esto es si no tenemos una palabra anterior y no tenemos una letra anterior, pues aquí hacemos un Return y hacemos un Prevent Default, básicamente para evitar que falle alguna cosa que vamos a hacer más adelante.
O tener que estar revisando o lo que sea.
Así ya nos olvidamos.
Oye, si no hay nada detrás, pues no pasa nada.
Ahora, ahora lo que tenemos que mirar es revisar si estamos en la primera letra.
O...
Vale.
Total, el Backspace...
Estoy pensando si el Backspace...
Primero vamos a hacer...
Primero...
Claro, es que el Backspace ya funciona realmente.
Hostia, espérate que aquí hay un error.
A ver.
PrefLetter, o sea, como Backspace, QuerySelectorLetter, PrefWord...
Vale, porque me dice...
Me dice este.
Claro, porque no hay anterior.
O sea, que aquí tenemos que hacer esto, por si acaso.
Por si acaso.
Vale, para que no pete.
Pero...
Ah, claro.
Claro.
Es que así no me deja ir para atrás, que tiene sentido también.
A ver.
TheKickBrownFox...
Vale.
Y ahora ya, si está bien, pues ya no me deja ir para atrás.
Vale.
Pero, si esto lo hago mal, tampoco me está dejando ir para atrás.
Ahora, ¿por qué no me funciona...?
¿Ves?
Que no me está dejando ir para atrás.
¿Por qué no me deja ir para atrás?
¿Por qué no me deja ir para atrás?
Porque este PreventDefault lo estamos haciendo...
A ver, esto no es...
Estoy pensando, ¿eh?
Si quito esto...
Vale.
Ahí sí que me está dejando ir para atrás.
Me dice, si no tiene PrefWord y no tiene Pref...
Ah, porque está entrando aquí.
No, pero si estoy con el An.
Si estoy con el An.
Ah, pero claro.
Como no tiene PrefWord...
Ah, hostia.
¿Ves?
La...
La he liado.
La he liado.
Esto es...
La decía yo.
Esto es Current Letter, ¿no?
O sea, esto es la letra...
Claro.
Como estoy haciendo Backspace, esto debería ser la Current Letter.
La letra actual.
Porque, claro, puede ser...
Ahora, ahora.
Ahora.
¿Ves cómo os decía que tenía su historia?
No, pues todavía sigue sin...
Sigue sin funcionarme.
A ver, ¿dónde la estoy liando ahora?
A ver si me lo decía.
La PrefLetter es la Current World.
La PrefLetter es la Current World.
A ver.
La PrefLetter es la Current World.
Ah, yo creo que primero esto, ¿no?
Esto es que...
Esto me pasa...
Esto me pasa por ir de listo.
De...
Voy a intentar escribir poco código.
Y no, no.
Y no es eso.
No es eso.
Es que primero.
Vamos por partes.
Lo primero.
Esto es CurrentWorld.previousElementSibling.
Esto seguro.
Y luego aquí, del CurrentLetter, no hay que buscar la Letter.
Es que hay que buscar el PreviousElementSibling también.
Claro, de la letra actual, tenemos que buscar la anterior.
Eso me pasa por listo.
Eso me pasa...
Cuando hacen las cosas sin pensar, ya la lía a esparda.
Ahora sí.
Ahora sí.
¿Veis?
Ahora sí.
Ahora sí.
Hay que ver cómo la liamos.
Es que yo ahí me he dicho...
No, esto va a quedar en un momento, no sé qué.
Y al final me ha salido peor.
Ay, bueno.
En fin.
Ahora sí que al menos tenemos esto.
Lo que ahora deberíamos hacer...
Porque en la misma letra, ¿sabes?
En la misma palabra no tenemos problema.
Hasta que no demos espacio, no hay ningún problema.
Ahora sí.
Cuando ya estamos en la siguiente palabra, aquí es donde deberíamos mirar si puede ir para atrás.
Entonces, para saber si puede ir para atrás, lo único que tenemos que hacer es saber, ¿vale?
Si tengo una...
Si no hay una letra...
Si estoy aquí en la primera, si estoy en esta posición y le doy atrás, ¿qué es lo que tiene que ocurrir?
Ese es el tema.
Eso es lo único que tenemos que hacer es preocuparnos en esa.
Y es básicamente esto.
También, si no tengo Previous World...
Es que estoy pensando...
Si no tengo Previous World y tal.
Si no tengo Previous...
Y no tengo Previous Letter.
A ver, si no tiene Previous World o no tiene...
Es que creo que esto podría ser así.
Creo que eso podría ser así.
No.
No, no.
A ver.
Da igual.
Voy por lo fácil y luego ya me preocupo.
Si no tengo una letra anterior, ¿vale?
Si no tengo una letra anterior, significa que estoy en la primera posición de la siguiente palabra.
¿Vale?
Entonces, ahora, aquí vamos a hacer un Prevent Default.
Porque ya no quiero liarla con el Input ni nada.
Quiero que se quede tranquilo.
Ahora, vamos a buscar si tenemos alguna palabra marcada.
¿Vale?
World Mark.
Y para esto, pues nada.
En el párrafo vamos a buscar si tenemos una palabra que tenga el Mark.
El Mark que hemos marcado antes.
¿Cómo se marcan las palabras?
Pues básicamente cuando haces esto...
Espérate.
Esto.
¿Ves?
Esto es una palabra marcada.
Si tenemos una palabra marcada, tenemos que permitirle ir atrás.
Porque la va a querer solucionar.
La va a querer arreglar.
Entonces, buscamos el World Mark.
Si tenemos una palabra marcada, ¿vale?
Que esto al final también lo podríamos hacer...
Si no tenemos...
Vamos a hacer esto aquí.
Si tenemos World Mark y tenemos una letra...
Y si no tenemos una letra anterior, entonces accedemos el Prevent Default.
¿Vale?
Y ahora es que tenemos que decirle...
Vale.
Pues entonces, la letra anterior vamos a quitarle la marca porque es la que vas a arreglar.
Y además vamos a decir que sea la activa.
¿Vale?
La vamos a activar.
Vale.
Vale.
Es que estoy pensando.
¿Cómo saber a qué letra tiene que ir?
A ver.
Es que esto es un poco complicado.
No pasa nada.
Lo vamos a hacer.
No os preocupéis.
Yo lo voy a explicar.
Pero imaginad...
Voy a poner otra palabra aquí que sea más interesante.
Quick.
¿Vale?
Vale.
Tenemos Quick.
Aquí hay diferentes cosas que pueden pasar.
Si pongo la Q y la U y le doy al espacio, fijaos que estas letras no las he puesto.
Solo he puesto estas dos.
Por lo tanto, cuando le dé a volver atrás, debería volver aquí.
No debería volver al final.
¿Vale?
Entonces, tenemos que saber a qué letra tenemos que ir.
Tenemos que ir a la última, que es la que estaba mal.
¿Sabes?
Joder.
Tenemos que volver a la última, que es la que estaba mal.
Entonces, volver atrás y volver a la primera.
Tendríamos que volver a la que lo ha dejado a medias.
Según cómo lo tienen ellos, claro, si hago PL, espacio, y le doy atrás, ¿veis?
Vuelve a la última que escribió.
Claro que tiene sentido.
Por lo tanto, vamos a buscar la primera letra.
Vamos a buscar primero la primera letra que no sea correcta o incorrecta y si no existe, a la última letra.
Eso vamos a hacer.
Entonces, ¿a qué letra tenemos que ir?
Letter to go.
¿A qué letra tenemos que ir?
Pues nada.
De la palabra anterior, ¿ves?
Esto sería lo fácil.
Esto sería lo fácil.
Ir a la última.
Es decir, bueno, pues voy a la última y ya está.
O sea, si ya la letra que tengo...
Mira, voy a empezar con esto solo para que lo tengamos y luego ya la letra que tengo que ir, pues nada.
Voy a la última.
Aquí, la letra actual, le quitamos el active y a la letra que tengo que ir le ponemos el active y ya está, ¿no?
Esta sería la fácil.
Esta sería la fácil.
Ponemos esto así.
Y vale.
Se ha vuelto al principio, no sé por qué.
Letter last child.
Letter...
Es que no sé si es el last child.
Letter last child.
No sé si letter last child me está dando el último.
Letter to go.
Hay un problema.
¿Sabéis por qué me hace esto?
Por el input.
Por el input.
Cuando he escrito si vuelvo para atrás, sí que es verdad que está volviendo atrás,
pero tendríamos que actualizar el input antes de que haga el chequeo del onKeyUp.
Porque el onKeyDown está pasando antes.
Joder, cuántas cosas hay que tener en cuenta aquí.
Bueno, pasa nada.
Input.value.
Aquí tendríamos que actualizar el input con la información correcta.
Y aquí lo que tendríamos que hacer es recuperar todas las letras que ha puesto el usuario.
De la palabra anterior tendríamos que hacer un query selector all con todas las letras correctas.
Y no sé si aquí...
Letter incorrect.
¿Vale?
Todas las letras correctas e incorrectas.
¿Vale?
Punto map.
Lo estoy haciendo así porque esto...
A ver, os voy a explicar esto porque esto es un poco tricky.
O lo puedo hacer fuera, pero tal.
A ver, el tema es que el query selector all no devuelve un array, aunque lo parece, pero no devuelve un array.
Si nosotros aquí hacemos document.querySelectorAllLetter, ¿vale?
¿Veis?
Parece un array, porque parece un array, pero ¿qué pone aquí?
NodeList.
Y el problema de esto es que si aquí probamos y ponemos un punto map...
Ah, vale.
Pues mira, falla.
¿Ves?
Es que no es un array y no tiene el punto map, el punto forEach y todo esto.
No lo tiene.
Entonces, lo que tenemos que hacer, el document.querySelectorAll, lo tenemos que transformar en un array.
¿Veis?
Entonces, al transformarlo en un array, ahora sí, en este array, vamos a poder utilizar el punto map.
Ahora me pondrá que es una función.
Esto es un error que me he comido tantas veces que ya lo tengo interiorizado y que por eso directamente he puesto el array porque ya sabía que tenía que hacer esto.
Por eso había hecho esto, para transformar el QuerySelectorAll en un array y ahora sí poder mapear correctamente que cada elemento, pues vamos a sacar el innerText y lo transformamos en un string así.
Y así nos aseguramos que el inputValue va a tener el input correcto.
Y entiendo que ahora, si hacemos esto...
Bueno, no sé...
¿Y por qué la Q?
A ver, a ver.
¿Qué ha pasado aquí?
A ver.
Claro.
Es que la he puesto...
La he puesto mal.
¡Ah!
Claro, claro, claro.
A ver, ¿tiene sentido?
No, no, ¿tiene sentido o no?
A ver, ¿sabes qué estoy pensando?
Es que este es complicado, ¿eh?
Te pone el correcto porque estás colocando todas las letras.
Sí, sí, tenéis razón.
Porque estamos colocando todas las letras.
Pero el tema es...
Tendríamos que colocar solo...
No solo las letras correctas.
Ay, está complicada, ¿eh?
Letter correct y letter incorrect.
Estamos colocando todas las letras.
Claro, lo bueno es que esto funcionar, funcionará aquí cuando hagamos esto.
Aquí funciona regular porque me está dejando...
Me está poniendo las letras correctas.
Pero acá no debería colocarse porque no tiene la clase.
Una nueva clase para las letras ya pasadas.
A ver, ¿qué estoy pensando?
Guardar el estado de cada palabra como la ha escribido el usuario.
Es que da igual como la ha escribido el usuario.
Lo importante es que...
Claro, como la ha puesto bien, en input value...
En input value nos ha puesto todas bien.
A ver, lo que podríamos hacer...
Lo que podríamos hacer básicamente es que si...
Claro, claro.
A ver, las sustituimos por un carácter diferente y ya está.
O sea, las que sean incorrectas, aquí, ¿vale?
Lo que vamos a hacer...
Es muy interesante, ¿eh?
Este ejercicio para mejorar lógica de programación es muy chulo, tío.
Luego...
Y es que la lógica de programación y tal.
Pues este me parece un ejercicio buenísimo de lógica de programación.
Luego, ¿cómo mejoro mi lógica de programación?
Pues aquí lo tienes.
A ver, lo que vamos a hacer es...
Vamos a devolver que si el L contains classlist...
Contains correct, tal.
Y si no, lo que podemos hacer es poner aquí un...
Másterisco, en el caso de que...
Vamos a ver si con esto...
Algo así.
Vale.
A ver, he puesto este horiscopo por poner algo.
Emoji no, porque es más de uno, ¿eh?
Espacio.
Espacio no, que ya es un poco problemático.
Podemos poner un símbolo, pero que ocupe una sola...
Es que lo malo de los emojis es que ocupa más de uno.
Más de una...
El length no es uno, es más de uno.
Entonces, tiene que ser algo que sepamos que ocupe uno.
Y a ver, yo que sé, puede ser algo...
Mientras sea algo que ocupe uno, ya nos vendría bien.
Mira, podemos ponerle la X esta.
A ver, vamos a ver si esto ocupa uno.
Es que hay algunos Unicodes que aunque tú parece que ocupa solo uno, en realidad ocupa más de un espacio.
Y hay que tener cuidado.
¿Ves?
Como este.
Este ocupa dos espacios.
Y ya nos jodería...
Nos jodería muchas historias.
Entonces, tenemos que buscar algo que...
Vamos a poner la C rota, tío.
La C rota sería interesante porque esta sí que es verdad.
Que ocupa un espacio.
Y que esa no la vamos a utilizar en ningún momento.
Exclamación es que puede ser...
¿Por qué no el asterisco?
Puede ser el asterisco.
El asterisco puede ser.
En nuestro caso, el asterisco va bien.
No hay problema.
Vamos a utilizar el asterisco.
Pero es verdad que hay algunas funciones que se puede hacer que sean más complicadas.
Vamos a poner el asterisco que total.
Es un símbolo que ya está bien.
Vale.
Entonces, con esto ya tendríamos esa parte.
Pero nos faltaría todavía el letter to go.
Porque fijaos que cuando hacemos aquí esto y si le doy al espacio, al volver atrás...
Ah, coño, pero al volver atrás ahora ha vuelto a la correcta, ¿no?
Bueno, pues ya está.
O sea, ya lo tenemos.
O sea, esto sería ya correcto.
Dice a la última letra que tiene que ir.
Dice letter to go.
Claro, como estamos actualizando el input.
Claro, el letter to go...
Es que en realidad estoy pensando si todo esto no es necesario, tío.
Porque...
No, no.
Sí que puede ser necesario.
Puede ser.
Current letter...
Sí, porque claro.
Hay ahí en alguna que tenemos que activar la letra actual.
Lo que yo a lo mejor no es necesario...
Ah, sí, sí, sí que es necesario porque tiene que saber cuál es la letra actual, al menos.
Sí que tiene que saber cuál es la letra actual.
Pero si no, o sea, si estoy dejando esa, no debería ya saber cuál es la actual.
No está en ningún sitio la actual.
A ver...
Pone active, espacio.
Aquí tenemos la letra active.
No.
Y se va...
Y se le va.
Yo creo que ahí alguna cosa...
Alguna cosilla se puede arreglar todavía.
Alguna cosa.
Brown, Fox, Jumps.
¿Vale?
Y se puede volver para atrás.
Y te lo deja ahí.
¿Vale?
Brown.
¿Vale?
Y ahí la he dejado mal porque justamente la primera está mal.
Y ahora la puedes escribir bien.
¿Vale?
Mira, me he saltado esta.
Pensaba que había un error, pero no.
Es que me he saltado...
¿Vale?
Ahí.
Ahora.
¿Ves?
Te la puedes saltar toda si quieres.
¿Vale?
¿Vale?
Pues con esto ya tendríamos básicamente esto.
Ahora lo que necesitaríamos ya es más trabajar el tema del game over.
Que podemos tener aquí dos secciones.
Section y the results.
Aquí poner lo que serían los...
Voy a poner los resultados.
Game.
Results.
Display none.
Y aquí tendríamos el display block.
¿Vale?
Bueno.
Que era flex en realidad.
Ya el input lo podemos ocultar porque lo teníamos ahí para un poquito más de tema de que se viese cómo funcionaba y eso.
¿Vale?
Y cuando terminemos, vamos a poner aquí menos tiempo para que podamos ver constantemente que está terminando.
Y os he dicho que íbamos a hacer lo del data, que tenemos aquí un montón de palabras.
Así que lo vamos a hacer un momento porque me parece fácil y es interesante.
Vamos a poner esto que sea del tipo módulo para poder hacer aquí el import de las palabras que tenemos en el punto data.js.
¿Vale?
Esto es un array con palabras que tenemos por aquí.
En lugar de aquí vamos a poner initial words.
Esto lo tenemos que nombrar así.
Y estas palabras iniciales, que ahora habíamos utilizado siempre esta frase, que es un poco...
Bueno.
Vamos a poner aquí...
Claro, podemos poner initial words.
No necesitaremos split.
Si hacemos esto, siempre serían las mismas.
Pero lo que podemos hacer es ordenarlo con el toSorted, no con el sort, porque con el sort lo estaríamos mutando.
¿Vale?
Más random 0.5.
Y ahora cada vez tendremos aquí unas palabras diferentes.
Cada vez que esté ahí entrando, ya tenemos aquí unas palabras diferentes.
Y además debería ser las que queramos.
32.
Aquí hay 32 palabras.
A mí me parece que hay menos.
0.
32.
3.
4.
5.
6.
Ah, puede ser.
Puede ser.
6.
12.
12.
Sí, sí, sí que puede ser.
6.
12.
Puede ser.
Puede ser.
Pues nada.
Pues 32 palabras.
A ver, podéis poner más.
Si se quedan cortas pueden ser 48.
Las que veáis.
O 50.
Ya al final.
Y qué más.
Incluso podéis detectar si necesitáis más palabras e ir poniéndolas.
Que esa también puede ser interesante.
Y entonces.
Tu, tu, tu.
El game over este.
Vamos a poner H3.
Esto sería vacío.
H2.
Aquí el accuracy.
Aquí sí que necesitaríamos.
Claro, para accuracy necesitaríamos ir contando cuántas veces se han puesto mal.
Porque si no, luego se pierde esa información.
Pero bueno, ahora lo podemos hacer más o menos.
Y luego para entrar más al detalle lo que podemos hacer es buscar el cálculo idóneo para hacer esto.
Cuando terminemos en el game over, que lo teníamos por aquí, game over.
Vamos a, primero, recuperamos aquí el resultado, WPM, el accuracy y el game también necesitamos.
Game.
De hecho, esto lo vamos a sacar aquí.
Vamos a sacarlo aquí.
Para tener todos los elementos en un solo sitio.
Vale.
Tu, tu, tu, tu, tu, tu.
Y así no nos tenemos que preocupar aquí.
El game.style.display ponemos a non.
El results sí que lo enseñamos.
Y aquí tendríamos que empezar a calcular cómo nos ha ido la cosa.
Bueno, ahora aparece así.
Aparece raro.
Pero ahora lo arreglamos.
¿Vale?
¿Qué tenemos que hacer?
Aparte de esto, pues contar las palabras correctas.
No tanto las letras, las letras correctas que más da, ¿no?
Ah, no.
Porque, claro, puede ser interesante, ¿no?
Sí, sí que puede ser.
Sí que puede ser interesante las letras correctas.
Porque para saber cuántas veces ha puesto bien o mal, ¿no?
Ahí tendríamos...
Claro, tiene sentido.
Las letras totales serían las correctas más las incorrectas.
Estas serían las que habría que contar que ha hecho el usuario.
Esto lo podemos sumar tal cual, sin esto.
Y la...
Y esto sería...
¿Cuántas ha hecho bien?
Pues si todas las letras son mayores a cero, porque, claro, si no, vamos a dividir entre cero y es un poco raro.
Pues esto.
Las letras correctas entre el total por cien.
¿Y cómo calculamos las letras por minuto?
¿Cuántas que hemos hecho de letras por minuto?
¿Cuántas letras por minuto?
Claro, tendríamos que dividir, ¿no?
¿Cuántas letras hemos hecho en...?
Tendríamos que hacer una regla de tres.
Claro, las letras correctas entre el tiempo inicial...
Pero claro, esto es por minuto.
Si esto es...
Habría que hacer una regla de tres.
Si...
A ver, ¿cómo sería?
Sería...
Sería...
Si hemos hecho dos en diez, ¿cuántas hubiéramos hecho en sesenta?
¿Vale?
Entonces, si hemos hecho correcta tal por sesenta, entonces, divide dos entre diez.
Y ahí tenemos las por minuto.
¡Madre mía, las matemáticas!
¡Matemáticas!
Venga, aquí ya tendríamos esto.
Le podemos poner el to fix.
Lo vamos a poner con el tanto por ciento.
Tanto por ciento.
Aquí.
Y esto...
Así.
Y el accuracy también.
Lo ponemos aquí.
Ah, bueno, este no hace falta ponerlo con un tanto por ciento.
El tanto por ciento lo quería poner abajo.
Es verdad.
Aquí.
Esto.
Así.
Y a ver.
Ahora nos saldría cero.
Vale, cero, cero.
Vale.
Pero mira, ya tenemos ahí...
Ya tenemos datos.
Ya tenemos datos.
Datos, datos.
Ahora, para mejorar un poquito los estilos, tampoco hace falta que hagamos una cosa muy loca.
Pero vamos a poner que el H2...
Vamos a ponerle que sea más pequeño porque está como muy bestia.
Lo ponemos un poco oscurito.
Le quitamos el margen.
Y lo hacemos un poco más pequeño.
Y el H3, pues nada, también le ponemos ahí el margen este.
A ver cómo va quedando.
Vale.
Le quitamos el margen.
Lo vamos a poner más grande.
Y el color...
Le vamos a poner el amarillo.
Vale.
Y...
Place a one...
Bueno.
A ver.
No está mal.
Dentro de que...
Display...
Results...
Y ahora lo que necesitaríamos ya es un botón para reiniciar.
¿Vale?
Botón para reiniciar.
Pero eso ya os lo voy a dejar a vosotros también para que lo tengáis.
Acure-Sy 100%.
Hostia, pues...
Claro.
Si se ha saltado alguna...
Bueno, sí, claro.
Si he escrito bien, sí.
Pero si escribo mal, debería parecer que está mal, ¿no?
También.
O sea, que ya lo tendríamos.
Luego, el reload.
Sí, no.
Faltaría el reload.
El reload no debería ser...
A ver.
No es muy complicado.
De hecho, para darle un poquito de...
Lo podemos poner por aquí.
El reload.
Reload.
Reload.
Reload.
Vamos a poner el botón aquí.
Button.
Vamos a Tablet Icons.
Aquí.
Reload.
Este reload me gusta.
Vamos a poner un poquito más pequeñito esto.
Copiamos el SVG.
Nos lo pegamos aquí.
Quitamos esto.
Y quitamos esta clase.
Y el botón, pues nada.
Ya lo podemos poner aquí.
Const.
Button.
Document.
Query.
Selector.
Button.
Solo hay un botón.
A ver.
Podríamos poner, en realidad...
Reload Button.
Le voy a poner una idea porque, hombre, más botones es bastante fácil.
Es bastante fácil que lo hagamos.
Entonces, vamos a estilar.
Background.
Transparent.
Border 0.
Margin Top 16 píxeles.
O 32 píxeles.
Padding 16 píxeles.
¿Vale?
A ver cómo sale el botoncito.
Bueno, vamos a ponerle una opacidad.
4.
Y ya le ponemos aquí un hover.
Tengo opacidad 1.
Y además, le vamos a poner un scale.
110%.
Display.
Inline Block.
Transition.
Opacity.
Y transform.
¿Vale?
Ahora debería salir ahí nuestro botoncito.
Vale.
Falta un cursor.
Pointer.
Y background.
Que sea...
Un poquito más...
Para que sea un poquito más clarito.
Y ahí llamaremos ya a el init...
Bueno.
Border.
Radius.
Esto ya es entrando ahí para nota, ¿eh?
Para nota.
Para tenerlo ahí...
Para tenerlo ahí fino.
Vale.
Y una vez que ya tenemos esto...
Oye, ¿por qué esto no le gusta?
Es por la...
¿Veis este background?
Que me sale así como clarito.
Vale.
A ver.
Se podría ajustar un poco más.
Me gustaría que quedase cuadrado.
Pero bueno.
No pasa nada.
Entonces...
Una vez que le damos a este botón...
Que teníamos aquí el init events...
¿Vale?
Pues ya tendríamos aquí el botón...
AtvListener.
Y cuando hagamos click...
Pues...
Iniciamos el juego.
Lo único que tendríamos que tener cuidado aquí al iniciar el juego...
¿Vale?
Vamos a ver qué es algo que no le gusta por aquí.
Pi, pi, pi.
Vamos a ver qué le pasa.
No puede leer de null.
Vale.
Debe ser accuracy.
¿Cuál es el null?
El accuracy.
O sea que este elemento que me está diciendo por aquí...
¿Por qué me está diciendo que esté null?
Si en algún momento...
Ah, no.
Lo que me está diciendo que es null es este.
Dice...
Si es mayor que cero y hace esto...
To fix...
Pero esto no puede ser null de ninguna forma, ¿no?
Total letter cero.
Si no es cero.
Si no esto...
Sí que es verdad que esto podría ser null en el caso de que funcionase mal.
Pero total letters no debe ser...
Total letters no debe ser esto...
A ver.
Voy a poner...
Vamos a dejar esto que esté bien.
Mientras.
Pero sí.
Total letter cero.
Setting text content.
Ah, no, no, no.
Es esta.
¿Ves?
Es la parte de la izquierda.
Es la parte de la izquierda.
Ya sabía yo que era la de la izquierda.
Me he dejado...
Resultados.
Last child.
Ah, por culpa del last child.
¿Veis?
Eso pasa por...
Results...
Eso me pasa por...
Results...
Eso me pasa por utilizar etiquetas ahí como si no eran mañana.
Eso me pasa por utilizar las etiquetas como si no eran mañana.
Results...
Ahora, esto sí que estará.
Y vamos a ver.
Vale.
Sigue sin funcionar el click.
Vamos a ver ahora qué es lo que le pasa.
El click...
Tu, tu, tu, tu, tu, tu, tu.
El botón...
Cuando hacemos click...
A TV listener.
Init game.
A ver si me lo decís.
Amante del scale.
Me encanta el scale.
Te ha dejado el pen jarcodeado a 10 segundos en lugar de initial time.
Vale.
Gracias.
A 10 segundos.
¿Dónde he dejado 10 segundos?
¿Dónde he dejado?
Ah, coño.
Gracias.
Gracias, gracias.
Que eso se nos ha dejado.
Para alguna vez tienes que usar initial time.
Gracias, gracias.
Gracias.
Que se me había olvidado eso.
Pero me falta todavía el...
Me falta...
Me falta...
Lo del botón.
¿Qué le pasa al botón?
Este init game...
Aquí no está entrando.
¿Por qué no está entrando en el init game?
¿No?
Cuando esto...
Vale, aquí sí que entra.
Ya lo sé.
Ah, sí que entra.
Sí que entra.
Claro.
Es lo que os decía.
Claro, cuando entra, tenemos que ocultar las secciones.
Otra vez.
Ahí está.
Y ahora sí.
Vale.
Y otra cosa que tendríamos que tener en cuenta para evitar problemas...
Es que tendríamos que resetear también el input.
Porque puede ser que hayamos dejado del anterior.
Y así nos aseguramos que el input esté correctamente.
Y ahora sí.
Begin...
Do she about...
¿Vale?
Es verdad que, por ejemplo...
Deberíamos...
Deberíamos contar los espacios.
¿Ves?
Este espacio...
Claro, pone accuracy 100%, pero no tiene sentido.
Porque ahí ha habido un error.
Ahí me he dejado una palabrita.
Around...
It...
May...
Large...
Claro, si me dejo algunas palabritas...
Ahí esas letras que han quedado colgadas, habría que hacer alguna cosa.
Pero bueno...
Al menos...
Add data and...
Project 03.
Vale.
Sincronizamos...
Y ya está.
Muy bien.
Pues ya tenemos el tercer proyecto.
A ver...
Voy a poner que Initial Time sea algo en condiciones.
Que ahora mismo es como muy poquito.
Initial Time...
Que hemos puesto 3, pero vamos a ponerle 30.
Y ahora ya lo tenéis para jugar.
A both...
Time...
Other...
Need...
She...
Give...
Match...
In...
Hostia, no sé si es que estoy fallando mucho...
O que hay algo ahí raro.
¿Ves?
No sé si me estoy dejando siempre la última por algo...
O si hay algo raro.
¿Puede ser que hay algo raro que ahí se nos ha escapado?
¿O soy yo que me estoy...
Mmm...
No sé, eh?
No sé.
Sí que nos falta ahí lo de la puntuación.
¿Pero hay algo raro con la última?
¿O soy yo que estoy torpe?
Una de dos.
Una de dos.
Mmm...
Igual hay una Race Condition con la última.
Si vas muy rápido.
Puede ser, eh.
Puede ser.
Puede ser.
Con el espacio.
Es la del espacio, ¿no?
A ver, la del espacio, que es esta.
Si hay un espacio, no sé qué.
Y aquí hace un return.
Mmm...
Mmm...
Mmm...
Mmm...
Mmm...
Aquí está haciendo el Input Value.
Y lo está dejando vacío.
Claro, pero el Input Value...
Que lo está haciendo vacío...
Si, claro, lo está dejando vacío antes...
Pero claro, esto tendría que pasar...
Da igual que esto.
Esto diría...
Y aquí tiene el Prevent Default.
Mmm...
Pues tengo dudas, eh.
Ahí de si pasa algo o...
Porque es verdad que...
A veces sí que funciona.
Pero no sé...
¿Ves?
Y no sé si es que me da la sensación que a veces lo veo...
Lo veo puesto y que luego se pone...
No sé, no sé.
Ah, tengo dudas.
Tengo dudas.
Tengo dudas.
Igual hay alguna Race Condition ahí, ¿no?
Bueno, os lo dejaré de deberes para que le echéis un vistazo.
A ver si lo encontráis.
Fix Initial Time.
Y ahí tenemos el proyectazo.
Bueno, amigos.
Pues os dejo.
Os dejo y os dejo ahí el código.