Mostrando las entradas con la etiqueta javascript. Mostrar todas las entradas
Mostrando las entradas con la etiqueta javascript. Mostrar todas las entradas

viernes, junio 13, 2014

Building an Application with CoffeeScript [Video Serie] - Review (en español)

Estimad@s,

durante esta semana he tenido la oportunidad de revisar un buen material sobre CoffeeScript, se trata de la serie de videos "Building an Application with CoffeeScript" publicado por Packt Publising  y cuyo autor Darko Bozhinovski vuelca su experiencia en este curso.

Pueden ver una demo aquí.

El curso tiene una duración aproximada de 1 hora y 40 minutos, en los cuales no solo aprenderemos las particularidades de CoffeeScript sino también a crear una aplicación funcional, si bien es necesario poseer conocimientos de javascript, no es requisito que los conocimientos sea profundos, el autor va introduciendo de a poco al espectador en la programación y buenas prácticas.

Si bien no llega a un nivel avanzado (difícil en el tiempo que dura el curso), lo que obtendrá el espectador es una muy buena idea de como llevar adelante la construcción de una aplicación utilizando CofeeScript y tecnologías de punta, sumado a ello, el autor insiste en las buenas prácticas de la programación apoyado siempre en la documentación.

Particularmente, me ha resultado de mucha utilidad, me ha parecido un buen curso, los contendidos son expuestos de forma muy clara y con la cadencia adecuada. Los ejemplos son claros y concretos.

Recomiendo este video curso.

El contenido completo del video curso es:

CoffeeScript 101 [13:33 minutes]
  • A Taste of CoffeeScript
  • Concepts and Usage
  • Tools and Extras
Head-first Application Development [13:52 minutes]
  • Basics of Object-oriented Programming
  • MVC and Using It in Our Project
  • Inheritance and Keeping Classes Simple
The Storage Layer – Models and Data Persistence [14:12 minutes]
  • Models and Storage Basics
  • Models in Our Application
Routing and Views [12:23 minutes]
  • Introduction to Routing, Controllers, and Views
  • Routing and Controllers
  • The View Layer
Interactions and Event Handling – Using JQuery with CoffeeScript [11:24 minutes]
  • Local Events
  • Global Events
Extending Our Application – Manipulating Stored Data [13:07 minutes]
  • Organizing Application Data
  • Extending the Document Classes
  • Making Our App More Usable
Extending Our Application – Add an External Library [11:10 minutes]
  • Adding External Libraries
  • Modifying Our App for Rich Text Editing
  • Exporting Our Documents to PDF
Publishing and Real-world Usage for Our Documents [11:01 minutes]
  • Using Our Documents Offline
  • Publishing Files
  • What's Next?
Saludos

Mariano

martes, septiembre 03, 2013

Seminario: Introducción a METEOR.JS

Martes 10 y miércoles 11 de setiembre. Laboratorio B - Facultad de Ingeniería del Instituto Universitario Aeronáutico
CUPOS LIMITADOS!
Seminario: "INTRODUCCION A METEOR.JS"


- Fecha: 10 y 11 de setiembre, 18 a 22 hs.
- Director: Ing. Mariano GARCÍA MATTÍO.

DESTINATARIOS: Alumnos, docentes, investigadores de las carreras de Sistemas, Informática y afines. Los interesados deberán poseer preferentemente conocimientos de HTML, CSS, Javascript y algoritmia.
OBJETIVOS:
Acercar a los asistentes a las nuevas tecnologías cliente/servidor basadas en Chrome V8 Javascript, particularmente Meteor
- Instalar y ejecutar y realizar tareas rutinarias con Meteor;
- Lograr discriminar componentes del lado del cliente y servidor en Meteor
- Comprender como implementar la programación reactiva en Meteor;
- Comprender el sistema de persistencia de Meteor;
- Generar una aplicación paso a paso en Meteor, en otras palabras, que los asistentes realicen una práctica guiada.
PROGRAMA
Parte I
- Qué es y que podemos hacer con Meteor.js
- Un poco de historia
- Los siete principios de Meteor
- Plantillas y funciones
- Meteor y su base de datos (MongoDB)
- Vistas, planillas y fuentes de datos
- Estilos (Twitter Bootstrap)
Parte II
- Variables de estado y getters para plantillas
- Implementación de la operación CRUD Create
- Eventos
- Relacionar plantillas (master-detail)
- Implementación de la operación CRUD Remove
- Estados de las vistas
- Implementación de la operación CRUD Update
Parte III
- MongoDB embebido en Meteor
- Autopublicacion
- Configuracion de pub/sub
Parte IV
- Estructura de la aplicación Meteor
- Estructura de carpetas
- Seguridad
- Autenticación
- Personalizar resultados
- Modificación de publicación
- Múltiples Cuentas
Parte V
- Paquetes de terceros
- Empaquetado de aplicaciones
- Publicación de aplicaciones en la Web
Certificados: Se entregarán certificados, y para lograr esta certificación los cursantes deberán contar con el 80% o más de asistencia al curso, y haber rendido y aprobado la evaluación final. El curso otorgará 1 crédito para los alumnos de la Facultad de Ingeniería (para todas las carreras) que aprueban el mismo. Los alumnos que deseen la certificación deberán abonar un costo de $65 por certificado.

jueves, agosto 15, 2013

Un Chat con Meteor.js (sí, uno más!)

Hola gente,

vamos a desarrollar un chat utilizando Meteor.js

Soy consciente que existen varios ejemplos sobre esto en la web, éste es uno más.
Me he propuesto realizar un chat minimalista que sirva como base para practicar.
Lo sobresaliente de este ejemplo es el poco código que posee.

Iniciamos el proyecto:

mrt create magmchat
cd magmchat
rm magmchat.*
mkdir client server public


Agregamos los paquetes que utilizaremos:

meteor add bootstrap
meteor add accounts-ui
meteor add accounts-base
meteor add accounts-password


Esquema de la página:

A continuación un esquema simple de como se verá la página, es buena práctica definir estos esquemas antes de comenzar a trabajar, luego se simplifica la tarea.



Implementación del esquema:

Archivo: client/magmchat.html

<head></head>
<body>
  <div class="navbar navbar-static-top">
    <div class="navbar-inner">
      <a class="brand" href="http://blog.magm.com.ar" target="_blank">Magm's Chat</a>
      <ul class="nav navbar-nav pull-right">
        <li><a href="#">{{loginButtons align="right"}}</a></li>
      </ul>
    </div>
  </div>
  {{> inicio}}
</body>

El código anterior define la barra de navegación y la posición de widget {{loginButtons}}, al final se renderizará la plantilla {{> inicio}}, en la cual se definirá el resto de la página.

<template name="inicio">
  {{#if currentUser}}
    <div class="row vspace">
      <div class="offset4 span4 text-center">
        <textarea id="texto" rows="5"></textarea>
      </div>
      <div class="span4">
        Instrucciones:
        <ul>
          <li><span class="label label-success">Enter</span>=enviar texto</li>
          <li><span class="label label-success">Ctrl+Enter</span>=nueva línea</li>
          <li>Puede utilizar código html, por ejemplo: Hola &lt;b&gt;Meteor&lt;/b&gt;</li>
        </ul>
      </div>
    </div>
    <hr/>
    <div class="row">
      <div class="offset2 span8">
        {{> chatItems}}
      </div>
    </div>
  {{/if}}
</template>

El código anterior implementa la plantilla inicio, solo se generará contenido si hay un usuario autenticado, a eso lo determina {{#if currentUser}}. El contenido que se crea consta del área de texto con id="texto", el texto de ayuda y finalmente en una nueva fila (en la parte de abajo) se renderiza la plantilla {{> chatItems}}.

<template name="chatItems">
  <ul>
    {{#each entradas}}
      <li class="itemchat">
        <b>{{nombre}}: </b>{{{texto}}}
      </li>
    {{/each}}
  </ul>
</template>

Finalmente la plantilla chatItems en la cual se creará una lista con el contenido del chat. Esta plantilla contiene un bucle each que itera sobre la fuente de datos entradas de la cual hablaremos en breve. La fuente de datos contiene objetos que representan las entradas de chat, cada objeto posee la siguiente estructura:
{
  nombre: 'usuario',
  texto: 'texto de chat',
  timestamp: estampaDeTiempoDeLaEntrada
}
Puede observarse que se muestra el nombre en negrita <b>{{nombre}}: </b> y luego el texto está rodeado por tres llaves {{{texto}}} esto hace que si lo que se mostrará contiene código html, el browser lo interprete como tal.

Estilos personales:

Archivo: client/magmchat.css

textarea{ 
  resize:none; 
  width:100%;
  margin-bottom:10px; 
}

.vspace {
  margin-top:20px; 
}
Se definen las propiedades del área de texto, lo más importante es que ocupa el 100% del espacio horizontal. Luego se crea una clase que impone un espacio de 20 pixeles al objeto al que se le asigne, en nuestro caso se utiliza para crear un separador entre la barra de opciones y el área de texto.

/* para que los items vayan apareciendo en fade */
.itemchat{
  list-style:none;
  margin:0;
  padding:0;
  animation: fadein 1s;
  -moz-animation: fadein 1s; /* Firefox */
  -webkit-animation: fadein 1s; /* Safari and Chrome */
  -o-animation: fadein 1s; /* Opera */
}
@keyframes fadein {
  from {
    opacity:0;
  }
  to {
    opacity:1;
  }
}
@-moz-keyframes fadein { /* Firefox */
  from {
    opacity:0;
  }
  to {
    opacity:1;
  }
}
@-webkit-keyframes fadein { /* Safari and Chrome */
  from {
    opacity:0;
  }
  to {
    opacity:1;
  }
}
@-o-keyframes fadein { /* Opera */
  from {
    opacity:0;
  }
  to {
    opacity: 1;
  }
}​
Finalmente se crea una clase que permite a los items de chat aparecer de forma gradual o fadein, la cantidad de texto es para dar soporte a varios navegadores, las reglas   from { opacity:0; } to { opacity:1; } definen el grado de transparencia y de opacidad de inicio y fin, en la clase se define el tiempo, que en este caso es de 1 segundo.

Definición de la Colección (la base de datos):

Archivo: /chat.js

chat = new Meteor.Collection("chat");

Con este simple código que es compartido por cliente y servidor ya que se encuentra en la carpeta raíz /, creamos una colección que Meteor se encarga de persistir y que además informar los cambios a todos los clientes para que aquellas plantillas que la utilicen se actualicen automáticamente, esto es parte de la reactividad.

El código del cliente:

Archivo: client/magmchat.js

Accounts.ui.config({
  passwordSignupFields: 'USERNAME_ONLY'
}); 

El código anterior configura el paquete accounts para que el sistema de login requiera como datos de cuenta un usuario y su contraseña, el almacenamiento y administración es local.

Template.chatItems.entradas = function () {
  return chat.find({}, {sort: {timestamp: -1}, limit: 10});
};

El código anterior define la fuente de datos entradas que se itera en la plantilla chatItems. Solo destacaré que se buscan todas las entradas sin filtro alguno y que se retornan ordenadas por estampa de tiempo descendente, solo se retornan las últimas 10 entradas.

Template.inicio.events({
  "keyup #texto": function (evt, tpl) {
    if (evt.ctrlKey && evt.keyCode == 13) {
      $("#texto").val($("#texto").val()+"\n");
    } else if (evt.keyCode == 13) {
      var val=$("#texto").val();
      if (val.trim().length==0) {
        $("#texto").val("");
        return;
      }
      val = val.replace(/(\r\n|\n|\r)/gm,"<br/>");
      Meteor.call('enviarTexto',Meteor.user().username,val,
        function (error, result) { 
          if (error) {
            console.log(error);
          }
        }
      );
      $("#texto").val("");
    }
  }
});

Finalmente, la última porción de código, es la más extensa, pero no reviste complejidad. Se trata del único evento que se es observado, evento keyup de la caja de texto, si se presiona Ctrl+Enter, se agrega un retorno de carro al texto '\n' y nada más. Si solo se presiona Enter, se obtiene el texto ingresado, si se ha ingresado un texto válido, se reemplazan los caracteres de retorno de carro por la marca html que lo representa <br/>,  luego se llama a un método remoto llamado enviarTexto que recibe como parámetros el nombre del usuario logueado (Meteor.user().username) y el texto. A continuación analizamos la complementación del método remoto.

El código del server:

Archivo: server/metodos.js

Meteor.startup(function () {
  Meteor.methods({
    enviarTexto: function (usuario, txt) {
      chat.insert({
         nombre: usuario,
         texto: txt,
         timestamp: new Date()
      });
    }
  })
});

Como puede observarse, el método es de lo más sencillo, solo inserta en la colección un nuevo objeto con los datos que recibe como parámetros y genera un valor para la estampa de tiempo, este es el motivo principal por el cual se implementa el método en el server, para que la estampa de tiempo sea coherente y no dependa de los valores de tiempo de cada cliente.

Así es como ve:



Conclusión

Eso es todo, con poco código hemos creado un char totalmente funcional, el poder de Meteor para abstraernos de problemas de sincronización y comunicaciones en tiempo real es realmente impresionante.

Pueden descargarse el código fuente desde: https://github.com/magm3333/magmchat
Pueden probarlo en funcionamiento en: magmchat.meteor.com

Espero les sea de utilidad

Mariano

viernes, junio 21, 2013

Personalizar autenticación de Google para aplicaciones Meteor

Hola nuevamente,

seguimos son la autenticación de Google en aplicaciones Meteor, esta vez lo que haremos será personalizar el inicio y cierre se sesión, en otras palabras, nosotros decidiremos cómo y cuando iniciar y cerrar sesión, por ende ya no nos hará falta el módulo accounts-ui

Creamos el proyecto y la infraestructura

Crearemos el proyecto:
meteor create loginConGoogleCustom 
loginConGoogleCustom: created. To run your new app: 
 cd loginConGoogleCustom 
 meteor

Eliminamos todos los archivos del proyecto:
cd loginConGoogleCustom
rm *.js *.css *.html


Creamos la estructura de directorios para componentes de nuestra aplicación:
mkdir client 
mkdir server

Instalamos el módulo de contiene la lógica para trabajar con cuentas de google:
meteor add accounts-google
accounts-google: Login service for Google accounts

Instalamos el módulo que contiene bootstrap: 
meteor add bootstrap
bootstrap: Front-end framework from Twitter 


Creamos los componentes del cliente: 
touch client/index.html 
touch client/index.js 

Creamos los componentes del server: 
touch server/configuracion.js (este archivo es idéntico que el que utilizamos anteriormente)

Iniciamos Meteor: 
meteor 

[[[[[ ~/loginConGoogleCustom ]]]]] 

Initializing mongo database... this may take a moment. 
=> Meteor server running on: http://localhost:3000/

Creamos la configuración
Abrimos el archivo server/configuracion.js y agregamos el siguiente código (este código es idéntico al del post anterior, solo hay que cambiar el clientId y el secret según los datos de cada cuenta):

//Quitamos cualquier configuración para 
//cuentas de Google 
Accounts.loginServiceConfiguration.remove({ 
  service: "google" 
}); 

//Agregamos la configuración con los datos que obtubimos de Google 
//campo clientId <-- Client ID 
//campo secret <-- Client Secret 
Accounts.loginServiceConfiguration.insert({ 
  service: "google", 
  clientId: "441624260670-5p0k5et2ns9pnlm8cgtp8bsdf.apps.googleusercontent.com",   secret: "3LMwasdfIOXfPqGhyeH4asdf3h
});

Creamos la vista (archivo client/index.html)
<head>
  <title>Login con Google</title>
</head>
<body>
  {{> inicial}}
</body>

<template name="inicial">
  {{#if currentUser}}
    {{> usuarioAutenticado}}
  {{else}}
    {{> usuarioNoAutenticado}}
  {{/if}}
</template>

<template name="usuarioAutenticado">
  <div class="navbar">
    <div class="navbar-inner">
      <div class="container pull-right">
        <span class="text-success">{{currentUser.profile.name}}</span>
        <img class="img-rounded" 
             style="height: 32px; margin-top: 4px;" 
             src="{{currentUser.services.google.picture}}"/>
        <div id="cerrarSesion" class="btn btn-primary">Cerrar Sesión</div>
      </div>
    </div>
  </div>
  {{> contenido}}
</template>

<template name="usuarioNoAutenticado">
  <div class="alert">
    <span class="icon-exclamation-sign"/> Debe Autenticarse!
    <div id="iniciarSesion" class="btn btn-info">Iniciar Sesión</div>
  </div>
</template>

<template name="contenido">
  <iframe width="100%" height="500px" src="http://www.meteor.com"></iframe>
</template>

A diferencia de la implementación anterior, esta es más prolija, la página web se limita al siguiente código:
<head>
  <title>Login con Google</title>
</head>
<body>
  {{> inicial}}
</body>

La plantila {{> inicial}} renderiza contenido en base a si el usuario actual está logueado o no.
  {{#if currentUser}}
    {{> usuarioAutenticado}}
  {{else}}
    {{> usuarioNoAutenticado}}
  {{/if}}

La plantilla {{> usuarioAutenticado}} mostrará una barra de navegación que a la derecha contendrá el nombre del usuario logueado, su avatar y un botón que permitirá cerrar la sesión, luego se mostrará el contenido de la página web. El botón cerrar sesión es nuestro componente personalizado y lo que más nos interesa es su id, ya que lo utilizaremos para programarle la escucha de eventos.
La barra de navegación debería verse más o menos así:



La plantilla {{> usuarioNoAutenticado}} mostrará un alerta que indicará la necesidad de iniciar sesión a la izquierda de la pantalla. El mensaje de alerta contiene además un botón que permite inicar la sesión, este es nuestro componente personalizado y su id es "iniciarSesion". El mensaje de alerta debería verse más o menos así:


Programación de eventos (archivo client/index.js)
Solo nos resta programar la interacción del usuario, en otras palabras, definir lo que ocurrirá cuando el usuario haga click en el botón "iniciar Sesión" o en el botón "Cerrar Sesión". Copiamos el siguiente código:

Template.usuarioAutenticado.events({
  "click #cerrarSesion":function(event,template){
    Meteor.logout(function(err){
      if(err){
        // manejar error
      }else{
        // todo ok
      }
    });
  }
});

Template.usuarioNoAutenticado.events({
  "click #iniciarSesion":function(event,template){
    Meteor.loginWithGoogle({
      requestPermissions: ['profile']
    }, function(err){
      if(err){
        // manejar error
      }else{
        // todo ok
      }
    });
  }
});

La programación o definicion de eventos en Meteor es muy simple y autodescriptiva. Los evenetos se programan en el ámbito de una plantilla, luego se define el evento y luego la regla de búsqueda de componentes a los cuales se les programará el evento.
En nuestro caso, en la plantilla usuarioAutenticado al hacer click en el botón con id cerrarSesion llamamos al método Meteor.logout el cual solo recibe como parámetro una función de retrollamada la cual nos permite manejar el resultado de la operación mediante el parámetro err.

Para el caso de la plantilla usuarioNoAutenticado  al hacer click en el botón con id iniciarSesion llamamos al método Meteor.loginWithGoogle el cual recibe como primer parámetro un arreglo llamado requestPermissions en el cual definimos los permisos que kle requerimos a google, en este caso solo hemos requerido el permiso profile el cual nos permitirá acceder a información básica de la cuenta, como segundo parámetro una función de retrollamada la cual nos permite manejar el resultado de la operación mediante el parámetro err.

Bien, eso es todo, espero les sea de utilidad.

Saludos

Mariano

miércoles, diciembre 05, 2012

Expandir Colapsar con Pentaho Reporting salida HTML

Estimad@s,

esta vez escribo para compartir con ustedes algunos experimentos con Pentaho Reporting (PRD).

El caso es que viendo los ejemplos avanzados de PRD y tratando de mejorarlos en algunos casos, salen cosas como lo que les voy a contar en este post. Se trata de un método para expandir y colapsar cabeceras de grupo y detalles de forma muy sencilla.
Este ejemplo tiene como idea inicial, la propuesta por el ejemplo "HTML Actions.prpt", ejemplo que pueden encontrar si seleccionan del menú principal:
Help / Sample Reports / Advanced / HTML Actions

En el editor se ve así:


Ejecutándose en vista HTML así:


La verdad, muy bueno!, les recomiendo que lo vean.

Es la posibilidad de ocultar partes de la jerarquía lo que me llamó la atención y en lo que me puse a experimentar. De los experimentos salió una pequeña serie de funciones javascript genéricas que permiten trabajar con hasta 9 niveles jerárquicos siguiendo dos simples pasos por cabecera de grupo. En este post explicaré en detalle como hacerlo. Ahora veamos el resultado final:




Bien, aquellos que tengan un poco de curiosidad sigan adelante, el resto puede obviar de aquí en adelante.

Partimos de un reporte inicial que tiene muy poco, solo la fuente de datos (se trata de una tabla estática embebida en el reporte) y las librerías javascript necesarias ya embebidas, explicaré en que lugar y como hacerlo. Al reporte inicial lo pueden descargar desde aquí.


Para este caso he utilizado la versión experimental de PRD 4, la pueden descargar desde aquí, aunque se puede hacer sin problema con versiones anteriores (no se con exactitud a partir de cual).

Así se ve el reporte inicial en PRD:


Como pueden ver he ocultado todas las bandas que no son necesarias en el reporte.

Los datos que contiene la tabla forman una jerarquía que puede verse en la imagen anterior y que reproduzco a continuación:


Zona
  Año
    ( Cliente | Importe )

Una Zona tiene varios Años y en un Año por Zona pueden existir varios hechos, cada hecho es un importe de venta a un cliente determinado. La cardinalidad es uno a muchos de zona hacia año y de uno a muchos de zona/año hacia los hechos. Los datos están ordenados con el criterio de agrupamiento, esto es: Zona+Año, se puede agregar el cliente y/o el importe, aunque esto último es anecdótico.

La siguiente es una captura de la tabla:


Luego tenemos las librerías javascript requeridas, a estas librerías y/o reglas de estilo CSS, las agregamos en el header del documento principal, a esto lo hacemos editando el atributo append-header de Master Report. Lo anterior se traduce en algo tan sencillo como que se agregará ese snippet al header del documento HTML cuando el reporte se exporte a ese formato.
Respecto a JQuery, solo descarguen la versión mínima, la abren con un editor de textos, seleccionan todo, copian y lo pegan en esta sección (debe ser lo primero) rodeado de tags < script >

A continuación una captura de como acceder a esta característica en el reporte:


Impresionante las posibilidades que brinda PRD no?

No entraré en detalle de las funciones que he creado, si algun@ está interesad@, solo debe hacer el comentario pertinente. Sin duda que valoraré cualquier aporte o mejora al código.

Teniendo en claro esto, manos a la obra, ahora la parte más sencilla, desarrollar el reporte.


Luego completar los datos del grupo.


Debemos definir ahora el grupo principal, para hacerlo debemos:


Luego completamos los datos:


Hasta aquí, la estructura del reporte debería quedar así:


Ahora coloquemos los elementos en el reporte.

El Detalle:

Primero un rectángulo, le damos el color (pueden usar el selector de combinación de color que está en la barra de herramientas) y las dimensiones. Luego arrastramos el campo cliente y el campo importe al detalle dentro del rectángulo. Será necesario darle una combinación de colores a los campos también. Pueden ver los detalles en la siguiente figura:




Los Grupos:

Como en el caso anterior, primero arrastramos un rectángulo en cada uno de las cabeceras de grupo. La cabecera de grupo que se encuentra en la parte superior pertenece al grupo de mayor jerarquía, en este caso se trata de zona. Luego de colocarlos en su lugar, habrá que asignar un color a cada rectángulo.


Procedemos ahora a colocar sobre los rectángulos los elementos que aportarán los datos, arrastraremos dos elementos Message, uno sobre cada rectángulo, le asignamos la combinación de color y establecemos el atributo value para cada uno.


Valores de value para:
zona: - Zona $(zona)
año- Año $(año)

Bueno, hasta aquí nada nuevo bajo el sol, verdad?
Es una de las cosas que más me gusta de esto, la simpleza.
Lo que sigue es lo que le da dinamismo al reporte y permite u otorga la posibilidad de expandir/colapsar datos.

Implementación de la funcionanlidad de expandir/colapsar:

Solo tres atributos hay que configurar por grupo, dos de los cuales implementan la funcionalidad, el tercero es solo adorno visual.

El primer atributo que configuraremos será xml-id, este atributo se transforma luego en un atributo id para el elemento HTML que renderiza el elemento Message, particularmente se trata de un elemento td.
Veamos en una imagen como hacerlo y que valor colocar para el grupo año.


El valor del atributo xml-id para este caso es =CONCATENATE("j2_";[zona];"_";[año]), esta expresión data como resultado para la zona Este y el año 2012 "j2_Este_2012", esto generará un valor único para cada grupo, muy importante comprender el concepto.

La primera parte de la cadena "j2_" es parte de la implementación, 2 significa que el grupo está 2do en la jerarquía, en este caso el 1ero será el grupo zona.

El render HTML generará algo así:


< td id="j2_Este_2010" colspan="3" > - Año: 2012 < / td >

Si se comprendió lo anterior, se puede deducir el valor para el atributo xml-id de zona=CONCATENATE("j1_";[zona])

Bien, si hasta aquí se comprendió, ya está, lo que resta es mecánico y muy simple.

Vamos a establecer el valor al atributo on-click de los elementos Message que representan los grupos.


En este caso, en la figura anterior, se muestra como establecer el valor para el grupo zona. El valor asignado es: ="expandCollapse(this, true)", esto es siempre igual, solo vale la pena aclarar que el segundo parámetro (valor true) implica que los valores de los grupos contienen como primer caracter un "+", esto será cambiado automáticamente por un "-" al expandir y vuelta al "+" al colapsar (and so on...).
Recuerden asignar el mismo valor al grupo año.

[Nota mental: estaría muy bueno poder enviar como parámetro el nombre de las clases CSS que deben ser asignadas al grupo cuando está colapsado y cuando está expandido. ¿Alguien se anima a aportar esta característica?]

El reporte ya posee la característica de expandir/colapsar en render HTML. Solo resta mejorar la apariencia en la interacción, hablo de que cuando el usuario pase el mouse por encima del grupo vea un cursor más acorde a lo que el grupo permite hacer. Lo haremos usando una clase CSS que ya está entre los snippets de los que hablamos al inicio. La clase se llama mouse y el código CSS es el siguiente:


.mouse {
      cursor: pointer;
}


Bien, ahora solo debemos establecer la clase mouse a los elementos Message que representan los grupos del reporte. Veamos esto en una figura para el grupo año:


Repetir esto con el grupo zona y listo!

Para probarlo solo debemos seleccionar la vista previa en HTML:


Bien, hemos finalizado, espero que les sea de utilidad.

Pueden descargar la versión final desde aquí.

Saludos

Mariano

Etiquetas

pentaho (45) java (35) eclipse (23) jdbc (14) curso (13) tomcat (13) primefaces (12) db2 (11) mondrian (10) review (10) jsf (9) openI (9) pdi (9) prd (9) libro (8) plugin (8) musql (7) struts (7) javascript (6) spring (6) cdf (5) ctools (5) instalar (5) linux (5) mysql (5) data studio (4) hibernate (4) ireport (4) jasper (4) meteor (4) videocurso (4) eglu (3) eglubi (3) elearning (3) graphite (3) grupo eglu (3) jboos tools (3) mexico (3) openbits (3) packt (3) python (3) undec (3) websphere (3) applet (2) cde (2) dao (2) db2university (2) exelearning (2) flexigrid (2) hadoop (2) iua (2) kettle (2) moodle (2) node (2) olap (2) osbi (2) pivot4j (2) scorm (2) sql (2) stpivot (2) actionscript (1) amazon (1) autenticacion (1) avanzado (1) base de datos (1) big data (1) bigdata (1) bodoc (1) cambiar (1) ccc (1) cdc (1) chat (1) cloud (1) coffeescript (1) control de acceso (1) corti (1) csv (1) cuba (1) curso meteor undec (1) dashboard (1) datamart (1) dataptix.tv (1) datasource (1) datatable (1) db2 ExpressC (1) demonio (1) distancia (1) driver (1) driver jdbc (1) eglufiltertwolist (1) encapsulamiento (1) especialización (1) etl (1) excepciones (1) export (1) faces (1) federación (1) filas afectadas (1) filtertwolist (1) filtrado (1) flegrid (1) flex (1) google (1) google viz (1) hostname (1) html (1) i18n (1) ibm (1) identidad (1) indignación (1) instancias (1) inteligencia de negocios (1) jee (1) jpivot (1) l10n (1) la azada (1) la zaga de los confines (1) layout (1) liberado (1) libre (1) libro promoción (1) lob (1) marktplace (1) menu (1) meteor node javascript google oauth autenticacion (1) mobile (1) mongoDB (1) node.js (1) oauth (1) olap4j (1) open source (1) orm (1) persistencia (1) personalizada (1) prd5 (1) psw (1) publicidad (1) rad6 (1) recursividad (1) reporting (1) rock (1) saiku (1) script (1) servicio (1) sessiontimeout (1) sourceforge (1) spinneta (1) sqlserver (1) ssl (1) taller (1) troyanx (1) ubuntu (1) ucc (1) ui (1) web (1) web console (1) xampp (1) xml (1) xpath (1)

Seguidores