• Comunicación escena-html usando Descartes Java

    En la versión 3 de Descartes se incluyó un sistema de comunicación o interfaz público de programación (API: Application Programming Interface). El objetivo pedagógico de la interfaz pública de Descartes era y es la creación de páginas web que posibiliten modificar dinámicamente la configuración de un applet Descartes, por ejemplo, de acuerdo con las respuestas dadas por un alumno a un conjunto de preguntas se presenta una escena diferente.

    Ese API puede consultarse en la documentación de la versión 4 de Descartes, pero para evitar el bloqueo de las escenas ahí incluidas necesitará usar Linux con Open Java o bien una máquina virtual como se indica en el artículo «Bloqueo de escenas en Java«.

    En este enlace tiene la documentación técnica de dicho API.

  • Comunicación escena-html usando DescartesJS

    Comunicación entre una escena de Descartes con la página HTML madre o con la página HTML hija

    Con el intérprete DescartesJS, una escena de Descartes puede comunicarse con la página HTML que le da soporte siempre que la escena esté embebida mediante un iframe, y también puede comunicarse con una página HTML que haya sido abierta por ella a través de un espacio HTMLIframe.

    En la imagen siguiente tenemos en el <body> de una página html un <iframe> a través del cual se embebe un fichero html ( en este caso ese archivo se denomina comunicacion_Descartes.html), el cual contiene una escena de Descartes.

    escenaEnIframe

    código iframe para embeber una escena en una página html

    Para que una pagina html, que es madre de una escena de Descartes a través de un iframe o que es hija de ella mediante un espacio HTMLIframe, pueda recibir los mensajes que envía la escena Descartes mediante las funciones para la comunicación, necesita tener un manejador de eventos

    elemento.addEventListener(«message», funcionQueManejaLosMensajes)

    donde elemento es elemento de la página al que se le asocia el manejador de los eventos que sobre él acontecen y la función funcionQueManejaLosMensajes sirve para gestionar el evento. A continuación se refleja un esquema de esa función donde se controla que el mensaje sea tipo set o update. En lugar del evento «message» pueden contemplarse otros.

    __________________________________________________

    function funcionQueManejaLosMensajes(evt) {

    var data = evt.data;

     // se maneja un mensaje del tipo set

    // data.name es el nombre de la variable
    // data.value es el valor de la variable

    if (data.type === «set») {

    // incluir código deseado

    }

     // se maneja un mensaje del tipo update
    else if (data.type === «update») {

    // incluir código deseado

    }

    }

    ___________________________________________________________________

    Comunicación de la página HTML madre con la escena de Descartes

    Para enviar información desde una pagina html, madre de una escena Descartes mediante iframe, a la escena de Descartes se utiliza la interfaz de comunicación window.postMessage de JavaScript, donde los mensajes son de la siguiente forma:

    referenciaAlIframe.contentWindow.postMessage({ type: «update» }, ‘*’);
    referenciaAlIframe.contentWindow.postMessage({ type: «set», name: varName, value: value }, ‘*’);

    donde varName es una cadena con el nombre de la variable que se le quiere pasar a Descartes y value es el valor de la variable.

    Nota: Como se ha indicado en los párrafos anteriores en DescartesJS, no hay un API como tal, porque la función funcionQueManejaLosMensajes debe ser implementada de acuerdo a las necesidades del programa. Tal vez, para enviar mensajes hacia Descartes sería conveniente tener un API, pero la forma de enviar los mensajes es tan simple que quizás no merezca la pena su elaboración. El sistema de comunicación es muy sencillo, el único inconveniente es la necesidad de saber el nombre de las variables que la pagina HTML espera recibir, así como el de las variables que usa internamente la escena de Descartes.
     
     

    Podemos ver un ejemplo a continuación:
    (Puede descargar  esta escena desde este enlace)
     

    El esquema lógico-funcional de la escena anterior es el siguiente:

    1. Para comunicar el html con la escena de Descartes que está embebida en un iframe de id «el_iframe»
    <iframe id=»el_iframe» src=»comunicacion_Descartes.html» width=640 height=480 frameborder=0 seamless scrolling=»no»></iframe>
    se cuenta en el body con un campo de texto de id «texto_a_enviar»
    <input id=»texto_a_enviar» type=»text» />
     
    y un botón de id «enviar»
    <input id=»enviar» type=»button» value=»enviar»> <br />
    y en head se cuenta con el siguiente código
    var contenido = document.getElementById(«texto_a_enviar»);
    var boton = document.getElementById(«enviar»);
    var iframe = document.getElementById(«el_iframe»);
    boton.addEventListener(«click», function(evt) {
    iframe.contentWindow.postMessage({ type: «set», name: «unaVariable», value: contenido.value }, ‘*’);
    iframe.contentWindow.postMessage({ type: «update» }, ‘*’);
    });
    donde se identifica el campo de texto, el botón y el iframe mediante sus id respectivos y se define un manejador de eventos ligado al botón ligado al evento «click», de manera que cuando el usuario hace click sobre el botón se envía un mensaje tipo set al iframe con el contenido del campo de texto y ligado a una variable que en la escena tendrá que tener el nombre «unaVariable» y un mensaje tipo update.
    En la escena ejemplo se cuenta con un gráfico tipo de texto en el que se observa la variable «unaVariable»
    <param name=»G_01″ value=»espacio=’E1′ tipo=’texto’ expresión='[20,20]’ texto='[unaVariable]’ fuente=’SansSerif,PLAIN,22′ fijo=’sí'»>
    que refleja el valor recibido.
    2. Para comunicar la escena con el html madre, en la primera se cuenta con un control tipo campo de texto de id «texto» que recogerá el valor a enviar
    <param name=»C_01″ value=»id=’texto’ tipo=’numérico’ interfaz=’campo de texto’ solo_texto=’sí’ espacio=’E1′ nombre=’texto’ valor=’&squot;un texto&squot;’ fijo=’sí’ visible=’sí'»>
    y otro tipo botón que al pulsarlo tiene una acción calcular en la que se asigna el valor de texto a una variable de id «variableEnviada» en el html madre  mediante la función parent.set(‘variableEnviada’,texto)
    <param name=»C_02″ value=»id=’enviar’ tipo=’numérico’ interfaz=’botón’ espacio=’E1′ nombre=’enviar texto’ fijo=’sí’ visible=’sí’ acción=’calcular’ parámetro=’parent.set(&squot;variableEnviada&squot;,texto)'»>
    Y en el html madre  se ha definido un manejador de eventos para el evento «message»
    window.addEventListener(«message», funcionQueManejaLosMensajes);
    function funcionQueManejaLosMensajes(evt) {
    var data = evt.data;
    // se maneja un mensaje del tipo set
    if (data.type === «set») {
    // data.name es el nombre de la variable
    // data.value es el valor de la variable
    document.getElementById(«textoRecibido»).textContent = data.value; // este es solo un ejemplo de lo que se     puede hacer con los mensajes
    }
    }
    En él se asigna al elemento html de id «textoRecibido» en valor enviado desde la escena
    El texto recibido desde la escena de Descartes es: <span id=»textoRecibido»></span>
     
     
    En el ejemplo siguiente se ha modificado el código para que la comunicación se produzca automáticamente cuando los campos de texto cambian, evitando tener que contar con botones de envío:
    (Puede descargar  esta escena desde este enlace)
    Lo que se ha rrealizado es cambiar el evento «click» por el evento «change» y asociar el manejador de eventos al campo de texto de id «texto_a_enviar»
    var contenido = document.getElementById(«texto_a_enviar»);
    var iframe = document.getElementById(«el_iframe»);
    contenido.addEventListener(«change«, function(evt) {
    iframe.contentWindow.postMessage({ type: «set», name: «unaVariable», value: contenido.value }, ‘*’);
    iframe.contentWindow.postMessage({ type: «update» }, ‘*’);
    });
     
  • Comunicación de una escena con el html embebido en un HTMLIframe

    En el siguiente ejemplo contamos con una escena “madre” que incluye un espacio HTMLIframe que sirve para embeber una página html. En ella podemos distinguir y observar:

    1. La escena madre tienes tres controles n1, n2 y n3 y cuando cambian los valores de estos controles los envía respectivamente hacia un elemento del código html, hacia un campo de texto editable y hacia un área de texto, los cuales quedan actualizados. Hay una comunicación unidireccional de escena a html embebido en un espacio HTMLIframe.
    2. Por otro lado, en el html embebido hay otro campo de texto y otro área de texto y cuando se modifica su valor se actualizan dos variables de la escena madre y se muestra en dos gráficos de texto de esa escena. Hay una comunicación unidireccional desde el html embebido a la escena madre.

    Puede descargar esta escena desde este enlace.

    El esquema lógico-funcional de este objeto es el siguiente:

    1. Una escena que contiene un espacio HTMLIframe con id E2 y que usamos para embeber una página html que hemos denominado EscenaHtmlHija.html.
    2. En la escena, el control n1 tienen asociada la acción calcular en la que se ejecuta la función de comunicación set mediante la expresión E2.set(‘n1’,n1), es decir se asigna el valor del control n1 a la variable n1 en E2 (este n1 es lo que aparece entre comillas en la función set, podríamos llamarlo de otra forma, pero por comodidad le hemos dado igual nombre). Análogo se hace con los controles n2 y n3.
    3. En el fichero html  EscenaHtmlHija.html es necesario utilizar el manejador de eventos de javascript para que detecte el mensaje enviado por la escena a través de la función set y actúe de acuerdo a nuestro deseo. Obviamente esto es algo ajeno a Descartes y nos adentramos en la programación con javascript para controlar eventos, si bien para nuestro fin basta que reproduzcamos adecuadamente el código que ahora describiremos y que mostramos en la siguiente imagen:
      • En la imagen, la línea incluida en el primer recuadro lo que hace es añadir un manejador (listener –oyente–) de eventos que actúa en este caso cuando se genera un mensaje (evento message) ejecutando la función que hemos llamado funcionQueManejaLosMensajes. Ésta comienza a describirse en el segundo recuadro rojo de la imagen.
      • En los tres recuadros siguientes observamos cómo se gestiona respectivamente el evento mensaje generado por los controles n1, n2 y n3 mediante la función set (en este ejemplo el mensaje generado por update() no realiza nada, pues no se usa en la escena).
      • En los tres casos, en la condición lógica de la instrucción if, se identifica que data.type sea «set» y qué control ha sido el activado comparando data.value con «n1», «n2» o «n3» (estos son los nombres que se ponen entre comillas en el primer parámetro de la función set). A continuación se actúa de acuerdo a lo especificado en cada caso. Esa acción se inicia capturando el elemento de la página html cuyo id coincide con el indicado en document.getElementById(«desdeCampoDeTexto»), en este caso «desdeCampoDeTexto» se corresponde con el id de un input tipo texto según podemos ver en el código incluido en el <body> y que se refleja en la siguiente imagen.
        Id en los elementos incluidos en el código HTML
      • Una vez  identificado se procede a modificar alguna propiedad de ese elemento, por ejemplo al especificar document.getElementById(«desdeCampoDeTexto»).value=data.value modificamos su valor con el valor (data.value) enviado en el mensaje. O bien modificar el propio código html con la propiedad innerHTML, o cualquier otra propiedad que se desee.
    4. El proceso inverso, es decir, enviar desde la página EscenaHtmlHija.html algún valor a la escena, se realiza utilizando la interfaz de comunicación dada por JavaScript window.parent.postMessage. En este ejemplo contamos con un texto cuyo id es «unCampoDeTexto» y un área de texto de id «textarea» (ver imagen anterior) y en la imagen siguiente observamos el código para manejar los eventos generados.
      manejaeventos2

      En ellos, el evento que se gestiona es «change», de manera que cuando cambia el valor en ese elemento. Así pues para «unCampoDeTexto» lo que se hace es enviar el valor actual de ese elemento a la variable de la escena cuyo nombre es «variableEnviada», y en el caso del elemento cuyo id es «textarea» su valor es enviado a la variable de la escena denominada «taenviado». Obviamente en lugar del evento «change» si se desea puede gestionarse cualquier otro que acontezca en esa página.

    En el ejemplo anterior la comunicación que se ha planteado en unidireccional, de escena a html o viceversa, pero la comunicación se puede realizar de manera bidireccional sobre cualquier elemento, no hay más que programar la gestión de los dos eventos actuando sobre los elementos que se quieren relacionar. Ello es lo que hemos hecho en la siguiente escena, que se puede descargar desde este enlace.

  • Funciones para la comunicación

    Se dispone de dos funciones que permiten el envío/recepción de los valores de una variable hacia/desde una escena o hacia/desde la página html que contiene una escena o hacia/desde la página html contenida en un espacio HTMLIframe. En estos dos últimos casos es necesario combinarlo con el manejador de eventos y el interfaz de comunicación de javascript. En otros artículos se detalla cada una de estas situaciones.

    Las funciones indicadas son:

    Sintaxis  Descripción Ejemplo
    Id.set(‘variable_a_actualizar,variable_que _actualiza Asigna a la variable denominada variable_a_actualizar en el espacio de identificador Id el valor actual de la variable denominada variable_que_actualiza en la escena que incluye la llamada a esta función.Si en Id se indica parent con ello se estará indicando que la variable_a_actualizar se ubica en la escena padre, es decir, aquella que ha abierto a la escena que incluye esta llamada.Obviamente la necesidad de esta función acontece cuando una escena padre lleva embebida a través de un espacio HTMLIframe otra escena. Dentro de una escena la asignación de valores es mediante el operador de asignación = E1.set(‘v1’, v2)A la variable v1 del espacio E1 se le asigna el valor de la variable v2.
    Id.update() En el espacio de identificador Id se actualizan los valores asignados previamente mediante la función set.Puede utilizarse el identificador parent. E1.update()Actualiza en el espacio E1 las variables previamente asignadas con set

    Un ejemplo de utilización de estas funciones puede observarse en la siguiente escena (puede consultarse este artículo) donde tenemos una escena madre que contiene dos espacios HTMLIframe y en cada uno de ellos se tiene una escena de Descartes (Escena hija 1 y Escena hija 2). Puede comprobarse como al cambiar el valor de var1 en la Escena hija 1 se actualiza el valor en la Escena hija 2, y análogamente ocurre con var2.

  • Comunicación entre escenas en espacios HTMLIframe

    En el siguiente ejemplo contamos con una escena «madre» que contiene dos escenas «hijas» ubicadas cada una de ellas en un espacio HTMLIframe. Cada hija manda a la madre los valores que modifica y esta última se encarga de mantener actualizadas a las hijas. Ello se logra mediante las funciones id.set(variable,valor) e id.update(), la primera asigna a la variable el valor indicado y la segunda actualiza. Van precedidas del prefijo que indica el id del espacio o bien puede indicarse parent para la escena «madre». Puede descargar esta escena desde este enlace.

    El esquema de esta escena es el siguiente:

    1. Una escena madre incluida en la página denominada madre.html que incluye:
      • Dos espacios HTMLIframe denominados con los identificadores H1 y H2 y que abren respectivamente las páginas hija1.html e hija2.html.
      • En el algoritmo CALCULOS se especifica H1.set(‘var2’,var2);H1.update();H2.set(‘var1’,var1);H2.update();
    2. En la página hija1.html una escena que incluye:
      • Un control var1 con una acción calcular que especifica parent.set(‘var1’,var1);parent.update()
      • Dos gráficos tipo texto que muestran el valor de las variables var1 y var2
    3. En la página hija2.html una escena que incluye:
      • Un control var2 con una acción calcular que especifica parent.set(‘var2’,var2);parent.update()
      • Dos gráficos tipo texto que muestran el valor de las variables var1 y var2

    Así pues el esquema lógico-funcional es el siguiente:

    a) Si se cambia el valor del control var1 en la escena hija 1, la acción calcular parent.set(‘var1’,var1), asigna a la variable denominada var1 en la escena madre (parent) el valor del control var1 de la escena hija 1. Entre comillas simples es el identificador de la variable a actualizar y sin comillas la que actualiza. En este caso, se le ha dado el mismo id con objeto de identificar con el mismo nombre a esa variable en todos los contextos que se consideran, pero pueden ponerse nombres diferentes. Posteriormente en esa misma acción calcular se realiza la actualización de la variable var1 en la escena madre con la función parent.update()

    b) En la escena madre, el algoritmo CALCULOS, al ejecutar H2.set(‘var1’,var1) asigna a la variable var1 (escrita entre comillas simples) del espacio H2 el valor actual de la variable var1 de esta escena madre. De nuevo estamos usando por comodidad el mismo nombre para identificar a las variables que intervienen en diferentes contextos. Con H2.update() se efectúa la actualización en el espacio H2 de la variable var1.

    c) La escena hija2.html muestra el valor actual de la variable var1, que después de la actualización realizada en el paso anterior es el valor procedente de la escena madre y el de ésta el procedente de la escena hija1.

    De manera análoga se procede para pasar el valor del control var2 de la escena hija 2 a la escena madre y de ésta a la escena hija1.