Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
cap:aurelia:memorama [2017/09/24 21:21]
user
cap:aurelia:memorama [2018/04/24 11:15] (actual)
cesar.vega
Línea 1: Línea 1:
 ======Aurelia.IO el framework ====== ======Aurelia.IO el framework ======
 +
 En estos tiempos es común acercarse a algún framework que nos facilite la interacción entre nuestra programación de JavaScript y el DOM, entre los mas populares están Angular, KnockOutJS, Ember, etc, pero existe uno que en lo personal me está gustando y se llama Aurelia.IO. En estos tiempos es común acercarse a algún framework que nos facilite la interacción entre nuestra programación de JavaScript y el DOM, entre los mas populares están Angular, KnockOutJS, Ember, etc, pero existe uno que en lo personal me está gustando y se llama Aurelia.IO.
  
 =====Pero... ¿Que es Aurelia.IO?​===== =====Pero... ¿Que es Aurelia.IO?​=====
 +
 Bueno Aurelia.IO es un MVVM el cual nos obliga a programar de una manera ordenada al separar la vista del modelo, como otros lenguajes lo hacen, entre las características que podemos ver están: Bueno Aurelia.IO es un MVVM el cual nos obliga a programar de una manera ordenada al separar la vista del modelo, como otros lenguajes lo hacen, entre las características que podemos ver están:
  
Línea 21: Línea 23:
  
 =====A prepararnos...===== =====A prepararnos...=====
 +
 Antes que nada quiero mencionar que todo esto está sobre Windows, Windows 10 para ser mas precisos, por lo tanto no daré instrucciones sobre otros sistemas operativos. Antes que nada quiero mencionar que todo esto está sobre Windows, Windows 10 para ser mas precisos, por lo tanto no daré instrucciones sobre otros sistemas operativos.
  
Línea 33: Línea 36:
  
 =====Manos a la obra...===== =====Manos a la obra...=====
 +
 Lo primero que haremos es instalar el Visual Studio ya que este es el mas tardado (por mucho) de instalarse, ahora bien, la razón de instalar este primero es que dependiendo la configuración que uses puedes instalar un NodeJs de versión anterior a la mas reciente. Lo primero que haremos es instalar el Visual Studio ya que este es el mas tardado (por mucho) de instalarse, ahora bien, la razón de instalar este primero es que dependiendo la configuración que uses puedes instalar un NodeJs de versión anterior a la mas reciente.
  
Línea 38: Línea 42:
 {{  VS01.png ​ }} {{  VS01.png ​ }}
 {{  VS02.png ​ }} {{  VS02.png ​ }}
 +
 Una vez instalado el VS2017, procedemos a instalar NodeJS, para esto ejecutamos el instalador y usamos la técnica legendaria del NEXT NEXT NEXT... Una vez instalado el VS2017, procedemos a instalar NodeJS, para esto ejecutamos el instalador y usamos la técnica legendaria del NEXT NEXT NEXT...
  
Línea 56: Línea 61:
   * Con este comando validaremos si Aurelia fue instalado al mostrarse un pantalla con algo similar a lo siguiente:   * Con este comando validaremos si Aurelia fue instalado al mostrarse un pantalla con algo similar a lo siguiente:
 {{  AU01.png ​ }} {{  AU01.png ​ }}
 +
 Ya que validamos que se encuentra instalado Aurelia-cli,​ entonces procederemos a crear nuestro proyecto. Ya que validamos que se encuentra instalado Aurelia-cli,​ entonces procederemos a crear nuestro proyecto.
  
 =====Creando el proyecto...===== =====Creando el proyecto...=====
 +
 Para crear el proyecto haremos lo siguiente: Para crear el proyecto haremos lo siguiente:
  
Línea 89: Línea 96:
 {{  au03.png ​ }} {{  au03.png ​ }}
 {{  au04.png ​ }} {{  au04.png ​ }}
 +
 Luego nos dice que estamos creando el proyecto sobre un directorio con archivos, nos pide confirmación para crear el proyecto en este directorio, le decimos que sí. Luego nos dice que estamos creando el proyecto sobre un directorio con archivos, nos pide confirmación para crear el proyecto en este directorio, le decimos que sí.
  
Línea 95: Línea 103:
 Cuando acabe Aurelia su configuración nos dirá Happy Codding :') Cuando acabe Aurelia su configuración nos dirá Happy Codding :')
 {{  au05.png ​ }} {{  au05.png ​ }}
 +
 Al final de la creación del proyecto, nos habrá creado muchas carpetas y archivos y estos ya estarán dentro de nuestro proyecto de VS2017. Al final de la creación del proyecto, nos habrá creado muchas carpetas y archivos y estos ya estarán dentro de nuestro proyecto de VS2017.
 {{  vs09.png ​ }} {{  vs09.png ​ }}
 +
 Todavía no acabamos, hay que hacer ciertas configuraciones extras, para que nuestro proyecto funcione adecuadamente. Todavía no acabamos, hay que hacer ciertas configuraciones extras, para que nuestro proyecto funcione adecuadamente.
 +
 En el raíz del proyecto, existe un archivo **tsconfig.json**,​ este archivo define la configuración sobre como VS2017 debe interpretar el typescript, en este archivo cambiaremos el valor de la propiedad **target** por **esnext**: En el raíz del proyecto, existe un archivo **tsconfig.json**,​ este archivo define la configuración sobre como VS2017 debe interpretar el typescript, en este archivo cambiaremos el valor de la propiedad **target** por **esnext**:
 <code javascript>​ <code javascript>​
Línea 115: Línea 126:
   },   },
 </​code>​ </​code>​
 +
 quedando así: quedando así:
 <code javascript>​ <code javascript>​
Línea 132: Línea 144:
   },   },
 </​code>​ </​code>​
 +
 Abrimos el archivo **aurelia_project\aurelia.json** y revisamos que en la sección **build\targets** esté de la siguiente manera: Abrimos el archivo **aurelia_project\aurelia.json** y revisamos que en la sección **build\targets** esté de la siguiente manera:
 <code javascript>​ <code javascript>​
Línea 146: Línea 159:
    ],    ],
 </​code>​ </​code>​
 +
 En caso de que no lo esté, hay que hacer las modificaciones correspondientes para que esté, con esto le decimos a Aurelia.IO que genere el proyecto en la misma ruta que usa el VS2017 que en este caso es la carpeta wwwroot del proyecto. En caso de que no lo esté, hay que hacer las modificaciones correspondientes para que esté, con esto le decimos a Aurelia.IO que genere el proyecto en la misma ruta que usa el VS2017 que en este caso es la carpeta wwwroot del proyecto.
  
Línea 152: Línea 166:
 Install-Package Microsoft.AspNetCore.StaticFiles -version 1.1.0 Install-Package Microsoft.AspNetCore.StaticFiles -version 1.1.0
 </​code>​ </​code>​
-Hay que tener noción de la versión de paquetes a instalar, en mi caso mi proyecto esta configurado con **.NetAppCore 1.1**, por eso instalo la versión 1.1.0 del paquete de StaticFiles,​ si quieres revisar que versión de Core es tu proyecto dar clic derecho sobre el proyecto y selecciona propiedades,​ en la ventana que te abre ve a la pestaña de **aplicación** y busca el valor de **Plataforma de Destino**: {{  + 
- VS10.png ​ }}+Hay que tener noción de la versión de paquetes a instalar, en mi caso mi proyecto esta configurado con **.NetAppCore 1.1**, por eso instalo la versión 1.1.0 del paquete de StaticFiles,​ si quieres revisar que versión de Core es tu proyecto dar clic derecho sobre el proyecto y selecciona propiedades,​ en la ventana que te abre ve a la pestaña de **aplicación** y busca el valor de **Plataforma de Destino**: ​ 
 +{{ VS10.png ​ }}
  
 Hay que seguir con las modificaciones,​ ahora le toca el turno al archivo **Startup.cs** en este archivo cambiaremos la configuración sobre como se levanta el servidor IIS, en ASP .NET Core, tiene una configuración distinta a los proyectos tradicionales,​ en este caso, el servidor web funciona como un módulo el cual se carga en el archivo **Program.cs** y en este módulo se le dice que use la configuración del archivo que vamos a modificar, entre esas configuraciones esta que cuando la aplicación se cargue escriba un Hello World, nuestra modificación consistirá en decirle que use los archivos para eso modificamos las siguientes líneas: Hay que seguir con las modificaciones,​ ahora le toca el turno al archivo **Startup.cs** en este archivo cambiaremos la configuración sobre como se levanta el servidor IIS, en ASP .NET Core, tiene una configuración distinta a los proyectos tradicionales,​ en este caso, el servidor web funciona como un módulo el cual se carga en el archivo **Program.cs** y en este módulo se le dice que use la configuración del archivo que vamos a modificar, entre esas configuraciones esta que cuando la aplicación se cargue escriba un Hello World, nuestra modificación consistirá en decirle que use los archivos para eso modificamos las siguientes líneas:
Línea 172: Línea 187:
 } }
 </​code>​ </​code>​
 +
 Por las siguientes: Por las siguientes:
 <code csharp> <code csharp>
Línea 189: Línea 205:
 <​note>​Es muy importante respetar el orden de los factores, en este caso de las instrucciones agregadas, ya que si se ponen al revés, el servidor no funcionará adecuadamente. <​note>​Es muy importante respetar el orden de los factores, en este caso de las instrucciones agregadas, ya que si se ponen al revés, el servidor no funcionará adecuadamente.
 </​note>​ </​note>​
 +
 Ahora bien nos queda generar un pequeño truco que también es parte de otros tutoriales, como ya mencionamos Aurelia.IO utiliza a NodeJS para generar el código que será reconocido por los navegadores,​ también levanta un servidor de NodeJS en el puerto 9000 donde la aplicación es ejecutada, y otro en el puerto 3001 donde levanta un componente para sincronizar el puerto 9000 en caso de que los fuentes cambien. Ahora bien nos queda generar un pequeño truco que también es parte de otros tutoriales, como ya mencionamos Aurelia.IO utiliza a NodeJS para generar el código que será reconocido por los navegadores,​ también levanta un servidor de NodeJS en el puerto 9000 donde la aplicación es ejecutada, y otro en el puerto 3001 donde levanta un componente para sincronizar el puerto 9000 en caso de que los fuentes cambien.
 +
 Explicando lo anterior de manera detallada sucede lo siguiente: Explicando lo anterior de manera detallada sucede lo siguiente:
   * Cuando ejecutamos la aplicación de aurelia, se transpilan los archivos de origen (.html, .js, .ts, .less, .css, .json, etc.) para generar los archivos de destino (.css, .js, .html) necesarios.   * Cuando ejecutamos la aplicación de aurelia, se transpilan los archivos de origen (.html, .js, .ts, .less, .css, .json, etc.) para generar los archivos de destino (.css, .js, .html) necesarios.
Línea 196: Línea 214:
   * Posterior a la generación de los archivos destinos son cargados por el navegador y voalá nuestra aplicación funciona.   * Posterior a la generación de los archivos destinos son cargados por el navegador y voalá nuestra aplicación funciona.
   * Una ventaja de Aurelia es que si modificamos los fuentes al momento de guardar automaticamente se vuelven a transpilar, volviendo a generar los archivos destinos y recargando el navegador con el nuevo cambio.   * Una ventaja de Aurelia es que si modificamos los fuentes al momento de guardar automaticamente se vuelven a transpilar, volviendo a generar los archivos destinos y recargando el navegador con el nuevo cambio.
 +
 En resumen a lo anterior es por eso que deshabilitamos el Compilador de TypeScript de VS y se lo dejamos a Aurelia, tambien por eso debemos hacer una configuración para que se levanten dos servidores, el de Aurelia y el ASP.NET Core, mientras que el de Aurelia transpilara los fuentes, el ASP.Net Core lo usaremos como servidor y para depuración. En resumen a lo anterior es por eso que deshabilitamos el Compilador de TypeScript de VS y se lo dejamos a Aurelia, tambien por eso debemos hacer una configuración para que se levanten dos servidores, el de Aurelia y el ASP.NET Core, mientras que el de Aurelia transpilara los fuentes, el ASP.Net Core lo usaremos como servidor y para depuración.
 +
 Para hacer la configuración para levantar ambos servidores haremos lo siguiente: Para hacer la configuración para levantar ambos servidores haremos lo siguiente:
   - Agregamos un nuevo archivo de texto en el raíz del proyecto, al cual llamaremos watch.cmd, esto lo hacemos dando clic derecho sobre el proyecto, seleccionando la opción Agregar y después seleccionamos Nuevo elemento... en la ventana que nos abre seleccionamos Archivo de texto, escribimos el nombre del archivo y le damos clic sobre Agregar.   - Agregamos un nuevo archivo de texto en el raíz del proyecto, al cual llamaremos watch.cmd, esto lo hacemos dando clic derecho sobre el proyecto, seleccionando la opción Agregar y después seleccionamos Nuevo elemento... en la ventana que nos abre seleccionamos Archivo de texto, escribimos el nombre del archivo y le damos clic sobre Agregar.
Línea 225: Línea 245:
 Si ejecutamos veremos la siguiente pantalla: Si ejecutamos veremos la siguiente pantalla:
 {{  ap01.png ​ }} {{  ap01.png ​ }}
-Ahora en plena ejecución, nosotros modificaremos el archivo **src\app.ts** dejándolo de la siguiente manera:<​code ​typoscript>+ 
 +Ahora en plena ejecución, nosotros modificaremos el archivo **src\app.ts** dejándolo de la siguiente manera:<​code ​javascript>
 export class App { export class App {
   message = '​Memorama!';​   message = '​Memorama!';​
 }</​code>​ }</​code>​
 +
 Después de guardar los cambios, esperamos unos segundos y actualizamos el navegador y veremos reflejado nuestro cambio: Después de guardar los cambios, esperamos unos segundos y actualizamos el navegador y veremos reflejado nuestro cambio:
 {{  ap02.png ​ }} {{  ap02.png ​ }}
 +
 Al detener la depuración se cerrará el servidor de Aurelia. Al detener la depuración se cerrará el servidor de Aurelia.
  
Línea 250: Línea 273:
       * **value-converters (carpeta)**:​ Son los componentes que se encargan de representar valores en otros formatos.       * **value-converters (carpeta)**:​ Son los componentes que se encargan de representar valores en otros formatos.
       * **index.ts (archivo)**:​ En este archivo le decimos a Aurelia, cuales son los recursos que tenemos disponibles,​ en la línea **"​config.globalResources"​** pero eso lo veremos mas adelante.       * **index.ts (archivo)**:​ En este archivo le decimos a Aurelia, cuales son los recursos que tenemos disponibles,​ en la línea **"​config.globalResources"​** pero eso lo veremos mas adelante.
 +
 En el directorio raíz tenemos diferentes archivos como son archivos de proyecto, de configuración,​ de paquete, de arranque de aplicación,​ entre otros. ​ En el directorio raíz tenemos diferentes archivos como son archivos de proyecto, de configuración,​ de paquete, de arranque de aplicación,​ entre otros. ​
 +
 Prácticamente nuestro trabajo estará en la carpeta src, y en una que otra ocasión modificaremos el archivo aurelia.json,​ para agregar alguna configuración adicional. ​ Prácticamente nuestro trabajo estará en la carpeta src, y en una que otra ocasión modificaremos el archivo aurelia.json,​ para agregar alguna configuración adicional. ​
 +
 Si no ves las carpetas dentro de la carpeta **src\resources** entonces debes hacer lo siguiente: Si no ves las carpetas dentro de la carpeta **src\resources** entonces debes hacer lo siguiente:
   - En el explorador de soluciones en la barra de herramientas que aparece en la parte superior buscamos y hacemos clic sobre el ícono que en su tooltip nos dice "​Mostrar todos los archivos":​ {{    - En el explorador de soluciones en la barra de herramientas que aparece en la parte superior buscamos y hacemos clic sobre el ícono que en su tooltip nos dice "​Mostrar todos los archivos":​ {{ 
Línea 257: Línea 283:
   - Con esto nos mostrará los archivos ocultos que existén, estos se mostraran sin color y con bordes punteados, seleccionamos las 4 carpetas dentro de resources y le damos clic derecho, despues seleccionamos la opción "​Incluir en el proyecto":​ {{  vs13.png ​ }}   - Con esto nos mostrará los archivos ocultos que existén, estos se mostraran sin color y con bordes punteados, seleccionamos las 4 carpetas dentro de resources y le damos clic derecho, despues seleccionamos la opción "​Incluir en el proyecto":​ {{  vs13.png ​ }}
   - Con esto, las carpetas se mostrarán de color normal y podemos dejar de ver los archivos ocultos haciendo clic en el mismo botón del paso 1.   - Con esto, las carpetas se mostrarán de color normal y podemos dejar de ver los archivos ocultos haciendo clic en el mismo botón del paso 1.
 +
 Con respecto a DotNet, solamente tendremos como regla no crear ningun elemento de DotNet, dentro de las carpetas wwwroot, aurelia_project y src, fuera de estas carpetas podemos generar las estructuras que nosotros deseemos. Con respecto a DotNet, solamente tendremos como regla no crear ningun elemento de DotNet, dentro de las carpetas wwwroot, aurelia_project y src, fuera de estas carpetas podemos generar las estructuras que nosotros deseemos.
  
Línea 262: Línea 289:
  
 Empezaremos por definir la aplicación a crear y las reglas que contendrá, lo que haremos será un memorama. Empezaremos por definir la aplicación a crear y las reglas que contendrá, lo que haremos será un memorama.
 +
 Las reglas que contendrá son las siguientes: Las reglas que contendrá son las siguientes:
   - El memorama tendrá un botón para generar nuevo juego.   - El memorama tendrá un botón para generar nuevo juego.
Línea 273: Línea 301:
   - El juego termina una vez que se hayan acertado todos los pares.   - El juego termina una vez que se hayan acertado todos los pares.
   - Al terminar el juego se almacenará en una lista con los tiempos del cual se mostrarán los mejores 20 en orden ascendente, siendo el de menor tiempo el mejor.   - Al terminar el juego se almacenará en una lista con los tiempos del cual se mostrarán los mejores 20 en orden ascendente, siendo el de menor tiempo el mejor.
 +
 Una vez definida las reglas tenemos que analizar un poco y separar las responsabilidades,​ en este caso tenemos el memorama, pero para enfocarlo mas a la vida real, lo llamare la mesa, también tenemos a la carta, tenemos la partida (que es el juego en curso), y la lista de posiciones. Una vez definida las reglas tenemos que analizar un poco y separar las responsabilidades,​ en este caso tenemos el memorama, pero para enfocarlo mas a la vida real, lo llamare la mesa, también tenemos a la carta, tenemos la partida (que es el juego en curso), y la lista de posiciones.
 +
 Dejaremos las responsabilidades de la siguiente manera: Dejaremos las responsabilidades de la siguiente manera:
   * La mesa tiene como responsabilidades:​   * La mesa tiene como responsabilidades:​
Línea 295: Línea 325:
  
 En la fea se programaría de la siguiente manera: crearía una vista y un modelo, en la vista pondría toda la estructura html que necesitara, mientras que en el modelo pondría toda la programación necesaria para que la aplicación funcione. {{  img01.png ​ }} En la fea se programaría de la siguiente manera: crearía una vista y un modelo, en la vista pondría toda la estructura html que necesitara, mientras que en el modelo pondría toda la programación necesaria para que la aplicación funcione. {{  img01.png ​ }}
 +
 En la mala se programaría de la siguiente manera: crearía una vista, un modelo, varias clases, en la vista pondría toda la estructura html que necesitara, en las clases pondría los métodos según sus responsabilidades,​ en el modelo referenciaría todas las clases y después haría todos los bindings en la vista. {{ img02.png }} En la mala se programaría de la siguiente manera: crearía una vista, un modelo, varias clases, en la vista pondría toda la estructura html que necesitara, en las clases pondría los métodos según sus responsabilidades,​ en el modelo referenciaría todas las clases y después haría todos los bindings en la vista. {{ img02.png }}
 +
 En la buena se programaría de la siguiente manera: crearía varias vistas, varios modelos, cada uno con sus responsabilidades debidamente definidas y sus bindings correspondientes. {{ img03.png }} En la buena se programaría de la siguiente manera: crearía varias vistas, varios modelos, cada uno con sus responsabilidades debidamente definidas y sus bindings correspondientes. {{ img03.png }}
 +
 Vamos a programar usando la buena y tratando de poner buenas practicas, y explicando cada punto para que quede claro. Vamos a programar usando la buena y tratando de poner buenas practicas, y explicando cada punto para que quede claro.
  
Línea 322: Línea 355:
      |      |
      +- carta.ts ​  ​(+)</​code>​      +- carta.ts ​  ​(+)</​code>​
 +
 En el archivo carta.ts escribiremos el siguiente código: ​ En el archivo carta.ts escribiremos el siguiente código: ​
-<​code ​typoscript>+<​code ​javascript>
 export class Carta { export class Carta {
    
Línea 338: Línea 372:
     }     }
 }</​code>​ }</​code>​
 +
 El archivo contiene las clase Carta, la cual contiene dos métodos uno para abrir y otro para cerrar, estos métodos harán la acción de voltear la carta para que sea visible y cerrarla para que no sea visible. El archivo contiene las clase Carta, la cual contiene dos métodos uno para abrir y otro para cerrar, estos métodos harán la acción de voltear la carta para que sea visible y cerrarla para que no sea visible.
  
 Para controlar la acción de abrir y cerrar aplicamos encapsulamiento,​ es decir, manejaremos una variable privada la cual nos indicará si la carta esta abierta o no, y esta variable solamente podrá ser modificada por los métodos abrir y cerrar, nuestro código debería quedar así: Para controlar la acción de abrir y cerrar aplicamos encapsulamiento,​ es decir, manejaremos una variable privada la cual nos indicará si la carta esta abierta o no, y esta variable solamente podrá ser modificada por los métodos abrir y cerrar, nuestro código debería quedar así:
-<​code ​typoscript>+<​code ​javascript>
 export class Carta { export class Carta {
    
Línea 358: Línea 393:
     }     }
 }</​code>​ }</​code>​
 +
 Nuestra carta ya controla su estado, pero este no es visible al ser privada, por lo tanto ocupamos un mecanismo para que la vista conozca el estado, agregaremos un método el cual en base a la variable privada nos regresara una clase la cual nos indicará el estatus de la carta, nuestro código debería quedar así: Nuestra carta ya controla su estado, pero este no es visible al ser privada, por lo tanto ocupamos un mecanismo para que la vista conozca el estado, agregaremos un método el cual en base a la variable privada nos regresara una clase la cual nos indicará el estatus de la carta, nuestro código debería quedar así:
-<​code ​typoscript>+<​code ​javascript>
 export class Carta { export class Carta {
    
Línea 380: Línea 416:
     }     }
 }</​code>​ }</​code>​
 +
 Ahora nos falta la información,​ la carta hará referencia a una imagen, por lo tanto deberá tener una propiedad en la cual nos diga el nombre de la imagen, y otra propiedad, la cual nos de un identificador de carta, nuestro código debería quedar así: Ahora nos falta la información,​ la carta hará referencia a una imagen, por lo tanto deberá tener una propiedad en la cual nos diga el nombre de la imagen, y otra propiedad, la cual nos de un identificador de carta, nuestro código debería quedar así:
-<​code ​typoscript>+<​code ​javascript>
 export class Carta { export class Carta {
    
Línea 404: Línea 441:
     }     }
 }</​code>​ }</​code>​
 +
 Por último, nuestra carta nos debe decir que imagen debemos mostrar, pero no siempre lo debe hacer, o dicho de otra forma, solo nos mostrará la imagen si la carta esta abierta, en caso contrario nos deberá mostrar una imagen genérica, nuestro código debería quedar así: Por último, nuestra carta nos debe decir que imagen debemos mostrar, pero no siempre lo debe hacer, o dicho de otra forma, solo nos mostrará la imagen si la carta esta abierta, en caso contrario nos deberá mostrar una imagen genérica, nuestro código debería quedar así:
-<​code ​typoscript>+<​code ​javascript>
 export class Carta { export class Carta {
    
Línea 434: Línea 472:
 }</​code>​ }</​code>​
 <​note>​Cuando se declara un método con la palabra reservada get, realmente estamos declarando una propiedad de solo lectura, o una propiedad calculada.</​note>​ <​note>​Cuando se declara un método con la palabra reservada get, realmente estamos declarando una propiedad de solo lectura, o una propiedad calculada.</​note>​
 +
 En el archivo **src\modelos\carta.html**,​ borraremos el contenido actual y en su lugar escribiremos el siguiente código: En el archivo **src\modelos\carta.html**,​ borraremos el contenido actual y en su lugar escribiremos el siguiente código:
 <code html5> <code html5>
Línea 462: Línea 501:
      |      |
      +- mesa.ts ​  ​(+)</​code>​      +- mesa.ts ​  ​(+)</​code>​
 +
 En el archivo mesa.ts escribiremos el siguiente código: En el archivo mesa.ts escribiremos el siguiente código:
-<​code ​typoscript>+<​code ​javascript>
 export class Mesa { export class Mesa {
    
Línea 491: Línea 531:
  
 Este archivo tendrá el papel de servirnos las cartas, asumiendo que estas se obtienen desde un origen remoto, por lo tanto tendremos en nuestro código de la siguiente manera: Este archivo tendrá el papel de servirnos las cartas, asumiendo que estas se obtienen desde un origen remoto, por lo tanto tendremos en nuestro código de la siguiente manera:
-<​code ​typoscript>+<​code ​javascript>
 export class WebApi { export class WebApi {
     constructor() {     constructor() {
Línea 508: Línea 548:
  
 La nomenclatura nos facilitará la creación de un algoritmo que nos generará las cartas de manera rápida sin que tengamos que registrarlas una a una. nuestro código del **src\componentes\archivo web-api.ts** debería quedar así: La nomenclatura nos facilitará la creación de un algoritmo que nos generará las cartas de manera rápida sin que tengamos que registrarlas una a una. nuestro código del **src\componentes\archivo web-api.ts** debería quedar así:
-<​code ​typoscript>+<​code ​javascript>
 export class WebApi { export class WebApi {
     constructor() {     constructor() {
Línea 532: Línea 572:
 } }
 </​code>​ </​code>​
 +
 Como ya tenemos nuestro arreglo de cartas, nuestro siguiente paso es obtener las cartas de manera desordenada,​ para que estas puedan ser mostradas en la mesa, para esto nuestro código debería quedar así: Como ya tenemos nuestro arreglo de cartas, nuestro siguiente paso es obtener las cartas de manera desordenada,​ para que estas puedan ser mostradas en la mesa, para esto nuestro código debería quedar así:
-<​code ​typoscript>+<​code ​javascript>
 export class WebApi { export class WebApi {
     constructor() {     constructor() {
Línea 561: Línea 602:
 } }
 </​code>​ </​code>​
 +
 Lo que se hizo dentro del método obtenerCartas fue lo siguiente: Lo que se hizo dentro del método obtenerCartas fue lo siguiente:
  
Línea 572: Línea 614:
  
 De vuelta al archivo **src\modelos\mesa.ts**,​ haremos la llamada para obtener las cartas, para esto, deberemos importar la clase del archivo web-api, la inyectaremos en nuestra clase Mesa, y la usaremos en el método **nuevoJuego**,​ cuando la obtención de cartas termine las pasaremos a una propiedad de la clase Mesa, nuestro código debería quedar así: De vuelta al archivo **src\modelos\mesa.ts**,​ haremos la llamada para obtener las cartas, para esto, deberemos importar la clase del archivo web-api, la inyectaremos en nuestra clase Mesa, y la usaremos en el método **nuevoJuego**,​ cuando la obtención de cartas termine las pasaremos a una propiedad de la clase Mesa, nuestro código debería quedar así:
-<​code ​typoscript>+<​code ​javascript>
 import { WebApi } from '​../​componentes/​web-api';​ import { WebApi } from '​../​componentes/​web-api';​
    
Línea 597: Línea 639:
 } }
 </​code>​ </​code>​
 +
   * Línea 4, es un mecanismo que nos ofrece Aurelia.IO para hacer inyección de dependencias,​ se ejecuta de manera automática generando una instancia del tipo WebApi y colocando la instancia generada en el parámetro del constructor de la línea 8.   * Línea 4, es un mecanismo que nos ofrece Aurelia.IO para hacer inyección de dependencias,​ se ejecuta de manera automática generando una instancia del tipo WebApi y colocando la instancia generada en el parámetro del constructor de la línea 8.
   * Línea 8, al declarar el parámetro con la palabra reservada private, le estamos diciendo que ese parámetro también es una variable privada de la clase.   * Línea 8, al declarar el parámetro con la palabra reservada private, le estamos diciendo que ese parámetro también es una variable privada de la clase.
Línea 642: Línea 685:
  
 Ahora que tenemos nuestras imágenes, yo he decidido ponerle a la imágen que servirá como reverso **carta_00.png**,​ así que modificaré el archivo **src\modelos\carta.ts**,​ para hacer referencia a esta imagen, el código lo vemos así: Ahora que tenemos nuestras imágenes, yo he decidido ponerle a la imágen que servirá como reverso **carta_00.png**,​ así que modificaré el archivo **src\modelos\carta.ts**,​ para hacer referencia a esta imagen, el código lo vemos así:
-<​code ​typoscript>+<​code ​javascript>
 export class Carta { export class Carta {
    
Línea 678: Línea 721:
  
 Si ya ejecutaron el código, se habrán dado cuenta que cuando le damos nuevo juego después de haber abierto todas las cartas, algunas cartas se mantienen abierta, no estoy seguro, pero creo que esto se debe al paso de objetos y que estos quedan como referencia y no como valor, para corregir este detalle abriremos nuestro archivo **src\componentes\web-api.ts**,​ dejando el siguiente código: Si ya ejecutaron el código, se habrán dado cuenta que cuando le damos nuevo juego después de haber abierto todas las cartas, algunas cartas se mantienen abierta, no estoy seguro, pero creo que esto se debe al paso de objetos y que estos quedan como referencia y no como valor, para corregir este detalle abriremos nuestro archivo **src\componentes\web-api.ts**,​ dejando el siguiente código:
-<​code ​typoscript>+<​code ​javascript>
 export class WebApi { export class WebApi {
     constructor() {     constructor() {
Línea 685: Línea 728:
    
     obtenerCartas(numPares:​ number): Promise<​any>​ {     obtenerCartas(numPares:​ number): Promise<​any>​ {
-        return new Promise<​any>​(resolve =&​gt; ​+        return new Promise<​any>​(resolve =
-            let cartasDesordenadas = cartas.sort(c =&​gt; ​Math.random() - 0.364);+            let cartasDesordenadas = cartas.sort(c =Math.random() - 0.364);
             let cartasSeleccionadas = cartasDesordenadas.slice(0,​ numPares);             let cartasSeleccionadas = cartasDesordenadas.slice(0,​ numPares);
             cartasSeleccionadas = cartasSeleccionadas.concat(cartasSeleccionadas);​             cartasSeleccionadas = cartasSeleccionadas.concat(cartasSeleccionadas);​
-            cartasDesordenadas = cartasSeleccionadas.sort(c =&​gt; ​Math.random() - 0.472);+            cartasDesordenadas = cartasSeleccionadas.sort(c =Math.random() - 0.472);
             resolve(JSON.parse(JSON.stringify(cartasDesordenadas)));​             resolve(JSON.parse(JSON.stringify(cartasDesordenadas)));​
         });         });
Línea 698: Línea 741:
 let cartas = []; let cartas = [];
    
-for (var i = 1; i &​lt; ​numCartas; i++) {+for (var i = 1; i numCartas; i++) {
     let carta = {     let carta = {
         id: i,         id: i,
Línea 712: Línea 755:
 <code html> <code html>
 <​template>​ <​template>​
-  <require from="​./​carta"​&​gt;&​lt;​/​require>​+  <require from="​./​carta"​></​require>​
   <button click.delegate="​nuevoJuego()"​ type="​button">​Nuevo Juego</​button>​   <button click.delegate="​nuevoJuego()"​ type="​button">​Nuevo Juego</​button>​
   <ul>   <ul>
Línea 748: Línea 791:
 </​code>​ </​code>​
  
-En el archivo src\modelos\partida.ts escribiremos el siguiente código: +En el archivo ​**src\modelos\partida.ts** escribiremos el siguiente código: 
-<​code ​typoscript>+<​code ​javascript>
 export class Partida { export class Partida {
     constructor() {     constructor() {
Línea 817: Línea 860:
   }   }
    
-  aurelia.start().then(() =&​gt; ​aurelia.setRoot());​+  aurelia.start().then(() =aurelia.setRoot());​
 }</​code>​ }</​code>​
  
Línea 844: Línea 887:
 }</​code>​ }</​code>​
  
-Línea 1, importamos el del paquete moment, el cual contienen la clase moment que nos ayuda a manipular las fechas. +  * Línea 1, importamos el del paquete moment, el cual contienen la clase moment que nos ayuda a manipular las fechas. 
-Línea 13, generamos una instancia de moment con la hora inicial. +  ​* ​Línea 13, generamos una instancia de moment con la hora inicial. 
-Línea 14, generamos una instancia de moment con la hora final, si la hora final no existe tomamos la hora actual. +  ​* ​Línea 14, generamos una instancia de moment con la hora final, si la hora final no existe tomamos la hora actual. 
-Línea 15, sacamos la diferencia entre la hora final y la inicial, convertimos a utc para evitar el desfase horario y le damos el formato definido. +  ​* ​Línea 15, sacamos la diferencia entre la hora final y la inicial, convertimos a utc para evitar el desfase horario y le damos el formato definido. 
-Comunicación efectiva...+ 
 +===== Comunicación efectiva...=====
  
 Ahora tenemos que hacer que los parámetros de la partida tengan vida, para esto vamos a entrar a las notificaciones de Aurelia.IO. Ahora tenemos que hacer que los parámetros de la partida tengan vida, para esto vamos a entrar a las notificaciones de Aurelia.IO.
Línea 857: Línea 901:
  
 Para usar las notificaciones de Aurelia.IO, haremos lo siguiente: Para usar las notificaciones de Aurelia.IO, haremos lo siguiente:
-Crear clases que servirán como los delegados de las notificaciones. + 
-Importar la clase EventAggregator del paquete aurelia-event-aggregator en los lugares donde se harán las suscripciones y publicaciones. +  - Crear clases que servirán como los delegados de las notificaciones. 
-Importar las clases que servirán como delegados en los lugares donde se harán las suscripciones y publicaciones. +  ​- ​Importar la clase **EventAggregator** del paquete aurelia-event-aggregator en los lugares donde se harán las suscripciones y publicaciones. 
-Inyectar la clase EventAggregator en las clases donde haremos las suscripciones y publicaciones. +  ​- ​Importar las clases que servirán como delegados en los lugares donde se harán las suscripciones y publicaciones. 
-Hacer las suscripciones y/o publicaciones. +  ​- ​Inyectar la clase **EventAggregator** en las clases donde haremos las suscripciones y publicaciones. 
-En la carpeta src\componentes crearemos un nuevo archivo que le llamaremos eventos.ts, agregaremos algunas clases: +  ​- ​Hacer las suscripciones y/o publicaciones. 
-Una clase que nos servirá para indicar que el juego inició. +  ​- ​En la carpeta ​**src\componentes** crearemos un nuevo archivo que le llamaremos ​**eventos.ts**, agregaremos algunas clases: 
-Una clase que nos servirá para indicar que el juego finalizó. +  ​- ​Una clase que nos servirá para indicar que el juego inició. 
-Una clase que nos servirá para indicar cuando un par se ha acertado.+  ​- ​Una clase que nos servirá para indicar que el juego finalizó. 
 +  ​- ​Una clase que nos servirá para indicar cuando un par se ha acertado. 
 Nuestro código debería quedar así: Nuestro código debería quedar así:
-+<code javascript>​
-+
-+
-+
-+
-+
-+
-+
-+
-+
-10 +
-11 +
-12 +
-13 +
-14 +
-15 +
-16 +
-17+
 export class JuegoIniciado { export class JuegoIniciado {
     constructor() {     constructor() {
Línea 902: Línea 931:
     }     }
 } }
 +</​code>​
  
-Ahora necesitamos hacer la suscripción para saber cuando inició un juego, adicional a esto también necesitamos hacer otra suscripción para saber cuando un par es acertado, por ultimo necesitamos hacer una publicación para informar cuando el juego se haya finalizado, esto lo haremos en la partida, en el archivo src\modelos\partida.ts,​ y nuestro código debería quedar así: +Ahora necesitamos hacer la suscripción para saber cuando inició un juego, adicional a esto también necesitamos hacer otra suscripción para saber cuando un par es acertado, por ultimo necesitamos hacer una publicación para informar cuando el juego se haya finalizado, esto lo haremos en la partida, en el archivo ​**src\modelos\partida.ts**, y nuestro código debería quedar así: 
-+<code javascript>​
-+
-+
-+
-+
-+
-+
-+
-+
-+
-10 +
-11 +
-12 +
-13 +
-14 +
-15 +
-16 +
-17 +
-18 +
-19 +
-20 +
-21 +
-22 +
-23 +
-24 +
-25 +
-26 +
-27 +
-28 +
-29 +
-30 +
-31+
 import * as moment from '​moment';​ import * as moment from '​moment';​
 import { EventAggregator } from '​aurelia-event-aggregator';​ import { EventAggregator } from '​aurelia-event-aggregator';​
Línea 948: Línea 947:
    
     constructor(private ea: EventAggregator) {     constructor(private ea: EventAggregator) {
-        this.ea.subscribe(eventos.JuegoIniciado,​ msg =&​gt; ​{+        this.ea.subscribe(eventos.JuegoIniciado,​ msg ={
             this.horaInicio = new Date();             this.horaInicio = new Date();
             this.horaFin = null;             this.horaFin = null;
         });         });
-        this.ea.subscribe(eventos.ParAcertado,​ msg =&​gt; ​{+        this.ea.subscribe(eventos.ParAcertado,​ msg ={
             this.paresAcertados++;​             this.paresAcertados++;​
             if (this.paresAcertados == 8) {             if (this.paresAcertados == 8) {
Línea 966: Línea 965:
         return moment(_horaFin.diff(_horaInicio)).utc().format("​HH:​mm:​ss.SSS"​);​         return moment(_horaFin.diff(_horaInicio)).utc().format("​HH:​mm:​ss.SSS"​);​
     }     }
-+}</​code>​ 
-Línea 2, importamos la clase EventAggregator. + 
-Línea 3, importamos todas las clases del archivo de eventos. +  * Línea 2, importamos la clase **EventAggregator**
-Línea 10, establecemos la función para inyectar la clase EventAggregator. +  ​* ​Línea 3, importamos todas las clases del archivo de eventos. 
-Línea 12, recibimos la inyección en el constructor. +  ​* ​Línea 10, establecemos la función para inyectar la clase EventAggregator. 
-Línea 13-16, nos suscribimos a la clase JuegoIniciado,​ cuando recibamos una notificación de esta clase, estableceremos la hora actual como la hora de inicio, y limpiaremos el valor de la hora de fin. +  ​* ​Línea 12, recibimos la inyección en el constructor. 
-Línea 17-18, nos suscribimos a la clase ParAcertado,​ cuando recibamos una notificación de esta clase, incrementamos el valor de los pares acertados. +  ​* ​Línea 13-16, nos suscribimos a la clase **JuegoIniciado**, cuando recibamos una notificación de esta clase, estableceremos la hora actual como la hora de inicio, y limpiaremos el valor de la hora de fin. 
-Línea 19-20, si los pares acertados son igual a 8, entonces se establece la hora actual como hora de fin del juego. +  ​* ​Línea 17-18, nos suscribimos a la clase **ParAcertado**, cuando recibamos una notificación de esta clase, incrementamos el valor de los pares acertados. 
-Línea 21, hacemos una publicación de la clase JuegoFinalizado para notificar que el juego ha finalizado. +  ​* ​Línea 19-20, si los pares acertados son igual a 8, entonces se establece la hora actual como hora de fin del juego. 
-Ahora solo nos queda definir la vista de la partida, por lo tanto abrimos el archivo src\modelos\partida.html,​ nuestro código deberá quedar así: +  ​* ​Línea 21, hacemos una publicación de la clase **JuegoFinalizado** para notificar que el juego ha finalizado. 
-+ 
-+Ahora solo nos queda definir la vista de la partida, por lo tanto abrimos el archivo ​**src\modelos\partida.html**, nuestro código deberá quedar así: 
-+<code html>
-+
-+
-+
-+
-+
-8+
 <​template>​ <​template>​
    <​dl>​    <​dl>​
Línea 993: Línea 986:
   </dl>   </dl>
 </​template>​ </​template>​
 +</​code>​
  
-Ahora necesitamos hacer una publicación para informar que el juego ha iniciado, adicional a esto también necesitamos hacer una publicación para informar que un par ha sido acertado y por último necesitamos hacer una suscripción para saber cuando el juego ha finalizado, esto lo haremos en la mesa, por lo tanto abrimos el archivo src\modelos\mesa.ts,​ nuestro código debería quedar así: +Ahora necesitamos hacer una publicación para informar que el juego ha iniciado, adicional a esto también necesitamos hacer una publicación para informar que un par ha sido acertado y por último necesitamos hacer una suscripción para saber cuando el juego ha finalizado, esto lo haremos en la mesa, por lo tanto abrimos el archivo ​**src\modelos\mesa.ts**, nuestro código debería quedar así: 
-+<code javascript>​
-+
-+
-+
-+
-+
-+
-+
-+
-+
-10 +
-11 +
-12 +
-13 +
-14 +
-15 +
-16 +
-17 +
-18 +
-19 +
-20 +
-21 +
-22 +
-23 +
-24 +
-25 +
-26 +
-27 +
-28 +
-29+
 import { WebApi } from '​../​componentes/​web-api';​ import { WebApi } from '​../​componentes/​web-api';​
 import { EventAggregator } from '​aurelia-event-aggregator';​ import { EventAggregator } from '​aurelia-event-aggregator';​
Línea 1036: Línea 1001:
    
     constructor(private api: WebApi, private ea: EventAggregator) {     constructor(private api: WebApi, private ea: EventAggregator) {
-        this.ea.subscribe(eventos.JuegoFinalizado,​ msg =&​gt; ​{+        this.ea.subscribe(eventos.JuegoFinalizado,​ msg ={
             this.juegoIniciado = false;             this.juegoIniciado = false;
         });         });
Línea 1044: Línea 1009:
         this.juegoIniciado = false;         this.juegoIniciado = false;
         this.api.obtenerCartas(this.numPares)         this.api.obtenerCartas(this.numPares)
-            .then(_cartas =&​gt; ​{+            .then(_cartas ={
                 this.cartas.length = 0;                 this.cartas.length = 0;
                 this.cartas = _cartas;                 this.cartas = _cartas;
Línea 1053: Línea 1018:
    
     }     }
-+}</​code>​ 
-Línea 2, importamos la clase EventAggregator. + 
-Línea 3, importamos todas las clases del archivo de eventos. +  * Línea 2, importamos la clase **EventAggregator**
-Línea 6, agregamos la clase EventAggregator en el método de inyección. +  ​* ​Línea 3, importamos todas las clases del archivo de eventos. 
-Línea 9, declaramos una variable para detectar la primera vez que se abra una carta. +  ​* ​Línea 6, agregamos la clase **EventAggregator** en el método de inyección. 
-Línea 11, hacemos la inyección. +  ​* ​Línea 9, declaramos una variable para detectar la primera vez que se abra una carta. 
-Línea 12-14, nos suscribimos a la clase JuegoFinalizado,​ cuando recibimos una notificación de la esta clase, establecemos el valor de la variable juegoIniciado como falso. +  ​* ​Línea 11, hacemos la inyección. 
-Línea 18, establecemos el valor de la variable juegoIniciado en falso.+  ​* ​Línea 12-14, nos suscribimos a la clase **JuegoFinalizado**, cuando recibimos una notificación de la esta clase, establecemos el valor de la variable ​**juegoIniciado** como falso. 
 +  ​* ​Línea 18, establecemos el valor de la variable ​**juegoIniciado** en falso. 
 Ahora bien todavía tenemos cabos sueltos, para atar estos cabos, tenemos que hacer lo siguiente: Ahora bien todavía tenemos cabos sueltos, para atar estos cabos, tenemos que hacer lo siguiente:
-Notificar cuando abrimos una carta. + 
-Notificar cuando estamos o dejamos de validar un par. +  - Notificar cuando abrimos una carta. 
-Notificar cuando una nueva partida ha sido iniciada. +  ​- ​Notificar cuando estamos o dejamos de validar un par. 
-De nueva cuenta modificaremos el archivo src\componentes\eventos.ts para agregar las nuevas clases, nuestro código quedaría así: +  ​- ​Notificar cuando una nueva partida ha sido iniciada. 
-+ 
-+De nueva cuenta modificaremos el archivo ​**src\componentes\eventos.ts** para agregar las nuevas clases, nuestro código quedaría así: 
-+<code javascript>​
-+
-+
-+
-+
-+
-+
-+
-10 +
-11 +
-12 +
-13 +
-14 +
-15 +
-16 +
-17 +
-18 +
-19 +
-20 +
-21 +
-22 +
-23 +
-24 +
-25 +
-26 +
-27 +
-28 +
-29 +
-30 +
-31 +
-32 +
-33 +
-34 +
-35 +
-36 +
-37+
 import { Carta } from '​../​modelos/​carta';​ import { Carta } from '​../​modelos/​carta';​
    
Línea 1141: Línea 1073:
     }     }
 } }
-Línea 1, importamos la clase Carta ya que la utilizaremos en una de las clases que declararemos. +</​code>​ 
-Línea 21-25, declaramos la clase CartaAbierta la cual servirá para notificar la carta que ha sido abierta, en el constructor declaramos una propiedad pública llamada carta, la cual será la carta abierta. + 
-Línea 27-31, declaramos la clase ValidandoPar la cual servirá para notificar el inicio y el fin de la validación de un par,  en el constructor declaramos una propiedad publica llamada validando, la cual nos indicará si está validando o no. +  * Línea 1, importamos la clase Carta ya que la utilizaremos en una de las clases que declararemos. 
-Línea 33-37, declaramos la clase NuevaPartida la cual servirá para notificar cuando una nueva partida se haya convocado. +  ​* ​Línea 21-25, declaramos la clase **CartaAbierta** la cual servirá para notificar la carta que ha sido abierta, en el constructor declaramos una propiedad pública llamada carta, la cual será la carta abierta. 
-Ahora necesitamos hacer una suscripción para saber cuando el proceso de validación de par este activo o inactivo, también necesitamos controlar la acción para impedir que se abra una carta si el proceso de validación esta activo, y por último necesitamos publicar la carta que se ha abierto, esto lo haremos en la carta, por lo tanto abrimos nuestro archivo src\modelos\carta.ts y nuestro código debería quedar así: +  ​* ​Línea 27-31, declaramos la clase **ValidandoPar** la cual servirá para notificar el inicio y el fin de la validación de un par,  en el constructor declaramos una propiedad publica llamada validando, la cual nos indicará si está validando o no. 
-+  ​* ​Línea 33-37, declaramos la clase **NuevaPartida** la cual servirá para notificar cuando una nueva partida se haya convocado. 
-+ 
-+Ahora necesitamos hacer una suscripción para saber cuando el proceso de validación de par este activo o inactivo, también necesitamos controlar la acción para impedir que se abra una carta si el proceso de validación esta activo, y por último necesitamos publicar la carta que se ha abierto, esto lo haremos en la carta, por lo tanto abrimos nuestro archivo ​**src\modelos\carta.ts** y nuestro código debería quedar así: 
-+<code javascript>​
-+
-+
-+
-+
-+
-+
-10 +
-11 +
-12 +
-13 +
-14 +
-15 +
-16 +
-17 +
-18 +
-19 +
-20 +
-21 +
-22 +
-23 +
-24 +
-25 +
-26 +
-27 +
-28 +
-29 +
-30 +
-31 +
-32 +
-33 +
-34 +
-35 +
-36 +
-37 +
-38 +
-39 +
-40 +
-41+
 import { EventAggregator } from '​aurelia-event-aggregator';​ import { EventAggregator } from '​aurelia-event-aggregator';​
 import * as eventos from '​../​componentes/​eventos';​ import * as eventos from '​../​componentes/​eventos';​
Línea 1200: Línea 1094:
    
     constructor(private ea: EventAggregator) {     constructor(private ea: EventAggregator) {
-        this.ea.subscribe(eventos.ValidandoPar,​ msg =&​gt; ​{+        this.ea.subscribe(eventos.ValidandoPar,​ msg ={
             this.estaValidando = msg.validando;​             this.estaValidando = msg.validando;​
         });         });
Línea 1228: Línea 1122:
         this.imagen = bindingContext.carta.imagen;​         this.imagen = bindingContext.carta.imagen;​
     }     }
-+}</​code>​ 
-Línea 1, importamos la clase EventAggregator. + 
-Línea 2, importamos todas las clases del archivo de eventos. +  * Línea 1, importamos la clase **EventAggregator**
-Línea 9, agregamos el método para inyectar la clase EventAggregator. +  ​* ​Línea 2, importamos todas las clases del archivo de eventos. 
-Línea 10, declaramos una variable privada para saber si se esta validando un par. +  ​* ​Línea 9, agregamos el método para inyectar la clase **EventAggregator**
-Línea 12, se agrega la inyección al constructor. +  ​* ​Línea 10, declaramos una variable privada para saber si se esta validando un par. 
-Línea 13-14, nos suscribimos a la clase ValidandoPar y cuando recibamos una notificación de esta clase, pasaremos el valor que nos trae a la variable declarada en la línea 10. +  ​* ​Línea 12, se agrega la inyección al constructor. 
-Línea 19, establecemos una condición en la cual solo se seguirá con el proceso de abrir la carta si esta no esta no está abierta y no existe un proceso de validación. +  ​* ​Línea 13-14, nos suscribimos a la clase **ValidandoPar** y cuando recibamos una notificación de esta clase, pasaremos el valor que nos trae a la variable declarada en la línea 10. 
-Línea 21, hacemos una publicación de la clase CartaAbierta informando que la carta actual ha sido abierta. +  ​* ​Línea 19, establecemos una condición en la cual solo se seguirá con el proceso de abrir la carta si esta no esta no está abierta y no existe un proceso de validación. 
-Ahora necesitamos suscribirnos para saber cuando una carta haya sido abierta, también necesitamos publicar cuando iniciamos y terminemos una validación,​ y por último publicar cuando una nueva partida haya sido iniciada, esto lo haremos en la mesa, abrimos el archivo src\modelos\mesa.ts y nuestro código debería quedar así: +  ​* ​Línea 21, hacemos una publicación de la clase **CartaAbierta** informando que la carta actual ha sido abierta. 
-+ 
-+Ahora necesitamos suscribirnos para saber cuando una carta haya sido abierta, también necesitamos publicar cuando iniciamos y terminemos una validación,​ y por último publicar cuando una nueva partida haya sido iniciada, esto lo haremos en la mesa, abrimos el archivo ​**src\modelos\mesa.ts** y nuestro código debería quedar así: 
-+<code javascript>​
-+
-+
-+
-+
-+
-+
-+
-10 +
-11 +
-12 +
-13 +
-14 +
-15 +
-16 +
-17 +
-18 +
-19 +
-20 +
-21 +
-22 +
-23 +
-24 +
-25 +
-26 +
-27 +
-28 +
-29 +
-30 +
-31 +
-32 +
-33 +
-34 +
-35 +
-36 +
-37 +
-38 +
-39 +
-40 +
-41 +
-42 +
-43 +
-44 +
-45 +
-46 +
-47 +
-48 +
-49 +
-50 +
-51 +
-52 +
-53 +
-54+
 import { WebApi } from '​../​componentes/​web-api';​ import { WebApi } from '​../​componentes/​web-api';​
 import { EventAggregator } from '​aurelia-event-aggregator';​ import { EventAggregator } from '​aurelia-event-aggregator';​
Línea 1306: Línea 1148:
    
     constructor(private api: WebApi, private ea: EventAggregator) {     constructor(private api: WebApi, private ea: EventAggregator) {
-        this.ea.subscribe(eventos.JuegoFinalizado,​ msg =&​gt; ​{+        this.ea.subscribe(eventos.JuegoFinalizado,​ msg ={
             this.juegoIniciado = false;             this.juegoIniciado = false;
         });         });
-        this.ea.subscribe(eventos.CartaAbierta,​ msg =&​gt; ​{+        this.ea.subscribe(eventos.CartaAbierta,​ msg ={
             if (!this.juegoIniciado) {             if (!this.juegoIniciado) {
                 this.juegoIniciado = true;                 this.juegoIniciado = true;
Línea 1326: Línea 1168:
         this.juegoIniciado = false;         this.juegoIniciado = false;
         this.api.obtenerCartas(this.numPares)         this.api.obtenerCartas(this.numPares)
-            .then(_cartas =&​gt; ​{+            .then(_cartas ={
                 this.cartasAbieras.length = 0;                 this.cartasAbieras.length = 0;
                 this.cartas.length = 0;                 this.cartas.length = 0;
Línea 1340: Línea 1182:
             this.ea.publish(new eventos.ValidandoPar(false));​             this.ea.publish(new eventos.ValidandoPar(false));​
         } else {         } else {
-            setTimeout(e =&​gt; ​+            setTimeout(e =
-                pares.map(carta =&​gt; ​carta.cerrar());​+                pares.map(carta =carta.cerrar());​
                 this.ea.publish(new eventos.ValidandoPar(false));​                 this.ea.publish(new eventos.ValidandoPar(false));​
             }, 1000);             }, 1000);
         }         }
     }     }
-+}</​code>​ 
-Línea 4, importamos la clase Carta. + 
-Línea 11, declaramos un arreglo que contendrá las cartas que se vayan abriendo. +  * Línea 4, importamos la clase **Carta**
-Línea 17, nos suscribimos a la clase CartaAbierta. +  ​* ​Línea 11, declaramos un arreglo que contendrá las cartas que se vayan abriendo. 
-Línea 18-20, en caso de que el juego no haya sido iniciado, marcaremos como iniciado el juego, después publicaremos con la clase JuegoIniciado que se ha iniciado el juego, esto solo sucede con la primera carta que se abre. +  ​* ​Línea 17, nos suscribimos a la clase **CartaAbierta**
-Línea 23, la carta abierta la agregamos al arreglo de cartas abiertas. +  ​* ​Línea 18-20, en caso de que el juego no haya sido iniciado, marcaremos como iniciado el juego, después publicaremos con la clase **JuegoIniciado** que se ha iniciado el juego, esto solo sucede con la primera carta que se abre. 
-Línea 24-26, cuando dos cartas se hayan abierto procederemos a validar el par. +  ​* ​Línea 23, la carta abierta la agregamos al arreglo de cartas abiertas. 
-Línea 31, cuando iniciemos un nuevo juego publicaremos con la clase NuevaPartida que una nueva partida se ha convocado. +  ​* ​Línea 24-26, cuando dos cartas se hayan abierto procederemos a validar el par. 
-Línea 35, después de obtener las cartas vaciaremos el arreglo de cartas abiertas. +  ​* ​Línea 31, cuando iniciemos un nuevo juego publicaremos con la clase **NuevaPartida** que una nueva partida se ha convocado. 
-Línea 42, cuando iniciamos la validación del par publicamos con la clase ValidandoPar que estamos en un proceso de validación con el parámetro true. +  ​* ​Línea 35, después de obtener las cartas vaciaremos el arreglo de cartas abiertas. 
-Línea 43, quitamos del arreglo de cartas abiertas el par de cartas. +  ​* ​Línea 42, cuando iniciamos la validación del par publicamos con la clase **ValidandoPar** que estamos en un proceso de validación con el parámetro true. 
-Línea 44, comparamos si las cartas son iguales. +  ​* ​Línea 43, quitamos del arreglo de cartas abiertas el par de cartas. 
-Línea 45, en caso de que las cartas sean iguales publicamos con la clase ParAcertado que se ha encontrado un par. +  ​* ​Línea 44, comparamos si las cartas son iguales. 
-Línea 46, publicamos con la clase ValidandoPar que hemos finalizado el proceso de validación con el parámetro false. +  ​* ​Línea 45, en caso de que las cartas sean iguales publicamos con la clase **ParAcertado** que se ha encontrado un par. 
-Línea 48, en caso de que no sean cartas iguales iniciamos y temporizador de 1 segundo. +  ​* ​Línea 46, publicamos con la clase **ValidandoPar** que hemos finalizado el proceso de validación con el parámetro false. 
-Línea 49, después de que ha transcurrido el segundo, cerramos las cartas. +  ​* ​Línea 48, en caso de que no sean cartas iguales iniciamos y temporizador de 1 segundo. 
-Línea 50, publicamos con la clase ValidandoPar que hemos finalizado el proceso de validación con el parámetro false.  +  ​* ​Línea 49, después de que ha transcurrido el segundo, cerramos las cartas. 
-Por último nos hace falta suscribirnos para saber cuando una nueva partida haya sido convocada y poder preparar los datos para la nueva partida, esto lo haremos en la partida, por lo tanto en src\modelos\partida.ts,​ deberíamos tener el siguiente código: +  ​* ​Línea 50, publicamos con la clase **ValidandoPar** que hemos finalizado el proceso de validación con el parámetro false. ​ 
-+ 
-+Por último nos hace falta suscribirnos para saber cuando una nueva partida haya sido convocada y poder preparar los datos para la nueva partida, esto lo haremos en la partida, por lo tanto en **src\modelos\partida.ts**, deberíamos tener el siguiente código: 
-+<code javascript>​
-+
-+
-+
-+
-+
-+
-+
-10 +
-11 +
-12 +
-13 +
-14 +
-15 +
-16 +
-17 +
-18 +
-19 +
-20 +
-21 +
-22 +
-23 +
-24 +
-25 +
-26 +
-27 +
-28 +
-29 +
-30 +
-31 +
-32 +
-33 +
-34 +
-35+
 import * as moment from '​moment';​ import * as moment from '​moment';​
 import { EventAggregator } from '​aurelia-event-aggregator';​ import { EventAggregator } from '​aurelia-event-aggregator';​
Línea 1412: Línea 1221:
    
     constructor(private ea: EventAggregator) {     constructor(private ea: EventAggregator) {
-        this.ea.subscribe(eventos.NuevaPartida,​ msg =&​gt; ​{+        this.ea.subscribe(eventos.NuevaPartida,​ msg ={
             this.horaFin = this.horaInicio = null;             this.horaFin = this.horaInicio = null;
             this.paresAcertados = 0;             this.paresAcertados = 0;
         });         });
-        this.ea.subscribe(eventos.JuegoIniciado,​ msg =&​gt; ​{+        this.ea.subscribe(eventos.JuegoIniciado,​ msg ={
             this.horaInicio = new Date();             this.horaInicio = new Date();
             this.horaFin = null;             this.horaFin = null;
         });         });
-        this.ea.subscribe(eventos.ParAcertado,​ msg =&​gt; ​{+        this.ea.subscribe(eventos.ParAcertado,​ msg ={
             this.paresAcertados++;​             this.paresAcertados++;​
             if (this.paresAcertados == 8) {             if (this.paresAcertados == 8) {
Línea 1434: Línea 1243:
         return moment(_horaFin.diff(_horaInicio)).utc().format("​HH:​mm:​ss.SSS"​);​         return moment(_horaFin.diff(_horaInicio)).utc().format("​HH:​mm:​ss.SSS"​);​
     }     }
-}+}</​code>​
  
-Línea 13, nos suscribimos a la clase NuevaPartida para saber cuando la nueva partida haya sido convocada. +  * Línea 13, nos suscribimos a la clase **NuevaPartida** para saber cuando la nueva partida haya sido convocada. 
-Línea 14, cuando recibamos la notificación de nueva partida establecemos los valores de la hora de inicio y de la hora de fin en nulos. +  ​* ​Línea 14, cuando recibamos la notificación de nueva partida establecemos los valores de la hora de inicio y de la hora de fin en nulos. 
-Línea 15, establecemos el valor de los pares acertados en 0.  +  ​* ​Línea 15, establecemos el valor de los pares acertados en 0.  
-Estamos a 2 pasos de acabar, y como primer paso modificaremos el archivo src\app.html quedando nuestro código de la siguiente manera: + 
-+Estamos a 2 pasos de acabar, y como primer paso modificaremos el archivo ​**src\app.html** quedando nuestro código de la siguiente manera: 
-+<code html>
-+
-+
-+
-+
-+
-7+
 <​template>​ <​template>​
   <require from="​./​modelos/​mesa"></​require>​   <require from="​./​modelos/​mesa"></​require>​
Línea 1455: Línea 1258:
   <​mesa></​mesa>​   <​mesa></​mesa>​
 </​template>​ </​template>​
 +</​code>​
  
 Hasta aquí se ve funcional, pero la apariencia deja que desear, así que agregaremos algunos cuantos estilos. Hasta aquí se ve funcional, pero la apariencia deja que desear, así que agregaremos algunos cuantos estilos.
  
-En la carpeta src, agregamos un archivo app.css: +En la carpeta ​**src**, agregamos un archivo ​**app.css**
-+<code bash>
-+
-+
-+
-+
-+
-+
-7+
 - src - src
   |   |
Línea 1474: Línea 1271:
   |   |
   +- app.css (+)   +- app.css (+)
 +</​code>​
  
-Después volvemos a abrimos la vista de app src\app.html y agregamos la referencia a la hoja de estilo: +Después volvemos a abrimos la vista de app **src\app.html** y agregamos la referencia a la hoja de estilo: 
-+<code html>
-+
-+
-+
-+
-+
-+
-+
-8+
 <​template>​ <​template>​
   <require from="​./​app.css"></​require>​   <require from="​./​app.css"></​require>​
Línea 1493: Línea 1283:
   <​mesa></​mesa>​   <​mesa></​mesa>​
 </​template>​ </​template>​
 +</​code>​
  
 Y vamos meter algunos estilos. ​ Y vamos meter algunos estilos. ​
  
 1. Al elemento body le vamos a ocultar la barra de desplazamiento vertical, esto lo hacemos así: 1. Al elemento body le vamos a ocultar la barra de desplazamiento vertical, esto lo hacemos así:
-+<code css>
-+
-+
-3+
 body {  body { 
   overflow-y: hidden;   overflow-y: hidden;
 } }
 +</​code>​
  
 2. A la partida la vamos hacer flotante con alineación a la izquierda y de un ancho fijo de 200px, esto lo hacemos así: 2. A la partida la vamos hacer flotante con alineación a la izquierda y de un ancho fijo de 200px, esto lo hacemos así:
-+<code css>
-+
-+
-+
-4+
 partida { partida {
   float: left;   float: left;
   width: 200px;   width: 200px;
 } }
 +</​code>​
  
 3. La mesa tiene varios puntos, empezaremos dando una posición absoluta y pegada al tope de la pantalla, y a 205px de la izquierda, esto lo hacemos así: 3. La mesa tiene varios puntos, empezaremos dando una posición absoluta y pegada al tope de la pantalla, y a 205px de la izquierda, esto lo hacemos así:
-+<code css>
-+
-+
-+
-+
-5+
 mesa { mesa {
   position: absolute;   position: absolute;
Línea 1529: Línea 1309:
   left: 205px;   left: 205px;
 } }
 +</​code>​
  
 3.1 Al botón de nuevo juego, lo vamos a posicionar abajo de los datos de la partida, esto lo hacemos así: 3.1 Al botón de nuevo juego, lo vamos a posicionar abajo de los datos de la partida, esto lo hacemos así:
-+<code css>
-+
-+
-+
-+
-5+
 mesa button { mesa button {
   position: absolute;   position: absolute;
Línea 1542: Línea 1318:
   left: -150px;   left: -150px;
 } }
 +</​code>​
  
 3.2 A la lista de la mesa le vamos a eliminar el estilo de lista, le daremos un margen de -1% para que nos de un poco de espacio, y le daremos un espaciado interno de 20px para no perderle de vista, esto lo hacemos así: 3.2 A la lista de la mesa le vamos a eliminar el estilo de lista, le daremos un margen de -1% para que nos de un poco de espacio, y le daremos un espaciado interno de 20px para no perderle de vista, esto lo hacemos así:
-+<code css>
-+
-+
-+
-+
-5+
 mesa ul { mesa ul {
   margin: -1%;   margin: -1%;
Línea 1555: Línea 1327:
   list-style: none;   list-style: none;
 } }
 +</​code>​
  
 4. A la carta pero al elemento li de la carta le daremos un acomodo para que se nos muestre en una matriz de 4 x 4, esto lo hacemos así: 4. A la carta pero al elemento li de la carta le daremos un acomodo para que se nos muestre en una matriz de 4 x 4, esto lo hacemos así:
-+<code css>
-+
-+
-+
-+
-+
-6+
 carta li { carta li {
   float: right;   float: right;
Línea 1570: Línea 1337:
   width: 16vw;   width: 16vw;
 } }
 +</​code>​
  
 4.1 Por ultimo a la imagen dentro de la carta le damos las mismas dimensiones:​ 4.1 Por ultimo a la imagen dentro de la carta le damos las mismas dimensiones:​
-+<code css>
-+
-+
-+
-4+
 carta img { carta img {
   height: 21vh;   height: 21vh;
   width: 16vw;   width: 16vw;
 } }
 +</​code>​
  
-NOTA: Desconozco bien como funcionan los puntos 4, es parte del esoterismo del CSS.+<​note>​Desconozco bien como funcionan los puntos 4, es parte del esoterismo del CSS.</​note>​
  
 Hasta este punto ya tenemos funcional el memorama, ya podemos jugar con el y ver que tan buena memoria tenemos, podemos iniciar nuevos juegos y ver el tiempo transcurrido,​ que por cierto explicaré lo del tiempo transcurrido. Hasta este punto ya tenemos funcional el memorama, ya podemos jugar con el y ver que tan buena memoria tenemos, podemos iniciar nuevos juegos y ver el tiempo transcurrido,​ que por cierto explicaré lo del tiempo transcurrido.
Línea 1591: Línea 1356:
  
 👍 👍
 +
 +Para terminar el tutorial haremos el consumo de las posiciones por medio de una API la cual vamos a desarrollar en ASP.NET Core usando WebApi, esta API nos servirá para obtener la lista de posiciones y para registrar nuevas posiciones.
 +
 +Las posiciones las vamos a registrar en un archivo en el servidor, pero para hacerlo mas interesante vamos a utilizar inyección de dependencias por si en un futuro queremos cambiar por algún gestor de bases de datos.
 +
 +Para registrar una posición necesitamos saber quien es el jugar de la partida, y para esto lo haremos por medio del plug-in Dialog que nos ofrece Aurelia.IO, sin mas que agregar, empezemos.
 +
 +===== La API =====
 +
 +Para agregar la API primero tendremos que configurar nuestro proyecto, pero con VS2017 es muy sencillo, basta con:
 +
 +  - Agregaremos en la raíz del proyecto una carpeta de nombre **api**: <code bash>- api</​code>​
 +  - Dentro de la carpeta agregaremos un nuevo controlador:​ {{ VS14.png }}
 +   - Nos saldrá una ventana y seleccionaremos dependencias minimas: {{ VS15.png }}
 +   - Al terminar la configuración nos saldra un archivo de texto, habrá que seguir esas instrucciones para que quede configurado.
 +    - Para el paso 1, copiamos el texto y descargamos el proyecto haciendo clic derecho sobre el mismo, y seleccionando la opción **Descargar el proyecto**.
 + - Hacemos clic derecho sobre el proyecto y seleccionaremos **Editar {nombre del proyecto}.csproj**.
 + - Nos vamos al final del archivo y antes de la cierre del elemento **Project** pegamos el texto copiado. {{ VS18.png }}
 + - Guardamos el archivo y lo cerramos.
 + - Hacemos clic derecho sobre el proyecto y seleccionaremos la opción **Volver a cargar el proyecto**.
 + - Para el paso 2.1, despues de pegar el texto es probable que algunas instrucciones las remarque con rojo.
 + - Ponemos el cursor sobre el texto y presionamos las teclas **CTRL + .**
 + - Del menú contextual seleccionaremos <​code>​using Microsoft.Extensions.Configuration;</​code>​
 +   - La instrucción del punto 2.3 la vamos a modificar un poco, ya que nosotros solo usaremos la WebApi y no nos interesa el ruteo tradicional del MVC, nuestro código quedaría asi: <code csharp>​app.UseMvc();</​code>​
 +  - La primera vez que agregamos el controlador realmente nos configura el proyecto, por lo tanto haremos de nueva cuenta el agregado del controlador,​ haciendo los mismos pasos: {{ VS14.png }}
 +  - En esta ocasión la ventana que nos abre es distinta, en ella seleccionaremos **Controlador de API: en blanco**: {{ VS16.png }}
 +  - Pondremos de nombre ListaPosicionesController y le damos **Agregar**:​ {{ VS17.png }}
 +
 +Ahora agregaremos la clase Posicion la cual tendra el nombre de la persona y el tiempo en el que completó el memorama, para eso haremos lo siguiente:
 +
 +  - Agregamos una nueva carpeta en la raíz del proyecto llamada **modelos**:​ <code bash> - modelos </​code>​
 +  - Dentro de la carpeta agregaremos una nueva clase de nombre **Posicion**. {{ VS19.png }}
 +
 +Ahora aplicaremos lo necesario para hacer la inyección de dependencias,​ primero tendremos que crear una carpeta donde pondremos nuestra interface y la clase que va implementar la interface, despues habra que hacer la configuración.
 +
 +==== El repositorio ====
 +
 +El repositorio es la clase la cual nos servirá para almacenar las posiciones en el archivo de texto, para hacer que funcione dentro de la inyección de dependencias vamos aplicar el patrón de repositorio,​ para hacer esto haremos lo siguiente:
 +
 +1. Crearemos una carpeta en la raíz del proyecto y le llamaremos **repositorios**.
 +<code bash>
 +- repositorios
 +</​code>​
 +
 +2. Agregamos una interface llamada **IPosicionRepositorio** en la carpeta **\repositorios**:​
 +<code csharp>
 +using System;
 +using System.Collections.Generic;​
 +using System.Linq;​
 +using System.Threading.Tasks;​
 +
 +namespace memorama.repositorios
 +{
 +  public interface IPosicionRepositorio
 +  {
 +    List<​modelos.Posicion>​ ObtenerPosiciones();​
 +    void GuardarPosicion(modelos.Posicion posicion);
 +  }
 +}
 +</​code>​
 +
 +3. Agregamos una clase llamada **PosicionArchivoRepositorio** ​ en la misma carpeta:
 +<code csharp>
 +using System;
 +using System.Collections.Generic;​
 +using System.Linq;​
 +using System.Threading.Tasks;​
 +using memorama.modelos;​
 +
 +namespace memorama.repositorios
 +{
 +  public class PosicionArchivoRepositorio : IPosicionRepositorio
 +  {
 +    public void GuardarPosicion(Posicion posicion)
 +    {
 +      throw new NotImplementedException();​
 +    }
 +
 +    public List<​Posicion>​ ObtenerPosiciones()
 +    {
 +      throw new NotImplementedException();​
 +    }
 +  }
 +}
 +</​code>​
 +