Mostrando entradas con la etiqueta programación. Mostrar todas las entradas
Mostrando entradas con la etiqueta programación. Mostrar todas las entradas

viernes, 5 de junio de 2015

Página de configuración en portlet de Liferay

Varias veces he batallado para recordar y/o encontrar como crear una página de configuración en un portlet al estilo Liferay, así que dejare el proceso aquí para futuras referencias, o por si a alguien le sirve!
(Digo al estilo Liferay porque siempre puedes crear una pagina mas en tu portlet, que tenga acceso restringido para Admins, y manejar ahi las configuraciones del portlet. Pero los portlets de que trae Liferay de caja, no se configuran asi.)

Primero, creamos nuestro portlet.

Entramos al archivo liferay-portlet.xml, en este agregamos el configuration-action-class, usando la clase DefaultConfigurationAction. quedaria asi:

<portlet>
 <portlet-name>configtest</portlet-name>
 <icon>/icon.png</icon>
 <configuration-action-class>com.liferay.portal.kernel.portlet.DefaultConfigurationAction</configuration-action-class>
 <header-portlet-css>/css/main.css</header-portlet-css>
 <footer-portlet-javascript>/js/main.js</footer-portlet-javascript>
 <css-class-wrapper>configtest-portlet</css-class-wrapper>
</portlet>

Al agregar esto, liferay ya crea en las configuraciones del portlet una nueva pestaña llamada setup. Esta pestaña estara en blanco, ahora creemos la página para mostrar algo.

En el archivo de configuración del portlet, portlet.xml agregamos un parámetro de inicialización mas, para agregar el jsp.

<init-param>
 <name>view-template</name>
 <value>/view.jsp</value>
</init-param>
<init-param>
        <name>config-template</name>
        <value>/config.jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>

El nombre del parámetro debe ser config-template, así es como Liferay sabe que ese parámetro es para la configuración del portlet.

Agregamos la pagina config.jsp en este caso a la misma altura de view.jsp, que es la pagina que se crea automáticamente al generar el portlet.

En el view.jsp vamos a traer la configuración para pintarla.

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
<%
String message = portletPreferences.getValue("message", "hola mundo");
%>
<%=message %>.


Y en el config.jsp creamos una forma, con un textbox para poner el mensaje que queremos mostrar al usuario (en este caso).
<%@page import="com.liferay.portal.kernel.util.Constants"%>
<%@ taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui" %>
<%@ taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet" %>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<portlet:defineObjects />
<%
String message = portletPreferences.getValue("message", "hola mundo");
%>
<liferay-portlet:actionURL portletConfiguration="true" var="configURL"/>
<liferay-portlet:renderURL portletConfiguration="true" var="configRenderURL"/>

<aui:form action="<%=configURL %>" method="post" name="fm">
 <aui:input name="<%=Constants.CMD %>" type="hidden" value="<%=Constants.UPDATE %>" />
 <aui:input name="redirect" type="hidden" value="<%=configRenderURL %>" />
 <aui:fieldset>
  <aui:input name="preferences--message--" id="message" label="Welcome Message" value="<%=message %>" />
 </aui:fieldset>
 <aui:button-row>
  <aui:button type="submit"/>
 </aui:button-row>
</aui:form>


En el value del textbox, usamos en el name el doble guion para la propiedad message, que es la que utilizamos en el view.jsp para mostrar el mensaje que queremos que vea el usuario, esto es para que la clase DefaultConfigurationAction haga todo mágicamente, sin tener necesidad nosotros de mandarlo guardar o mandarlo traer de la base de datos en un Controller. Este método de guardado/extracción solo se usa en la forma, no al momento de ir por la propiedad en las preferencias del portlet.

Y listo! esto debe tener un portlet con una pagina de configuración al estilo Liferay!


Resultado final:



miércoles, 11 de junio de 2014

Cancelar transiciones en corona sdk

Hola,

Me topé con un problema en las transiciones de objetos infinita en corona sdk. Al salir del juego e ir al menú principal, o reiniciar el nivel, marcaba un error porque no se había terminado bien la transición de los objetos.

Los objetos en este ejemplo son nubes, que al salir de la pantalla vuelven a aparecer al inicio, cambiando su posición y velocidad aleatoria mente.

Usando storyboard, el código seria de esta manera:
Tenemos la generación de las nubes y su transición, al terminarla, se vuelve a generar el objeto con el mismo id y a iniciar la transición, para así continuar de manera infinita, todo esto lo tengo dentro del método scene:createScene del storyboard.

   
      clouds ={  
       {getImage = "images/cloud01.png"},   
       {getImage = "images/cloud02.png"},  
       {getImage = "images/cloud03.png"}  
      }  
      local returnClouds = function( obj )  
        if ( obj.moveTrans ) then  
                transition.cancel( obj.moveTrans )  
                obj.moveTrans = nil  
                makeClouds(obj.id)  
           end  
      end  
      function makeClouds(id)  
           imagesId = math.random (1,3)  
           local cloud = display.newImage(clouds[imagesId].getImage  )  
           cloud.x = math.random (display.screenOriginX , centerX )  
           cloud.y = math.random (topScrn + cloud.height, centerY)  
           cloud.alpha = 0.7  
           cloud.id=id  
           group:insert(cloud)  
           allClouds[id] = cloud  
           cloud.moveTrans = transition.to( cloud, {time = math.random (30000 , 120000), x = w + 300, onComplete=returnClouds } )  
      end  
      for i=0,2 do  
           makeClouds(i)  
      end  

El método de returnClouds es donde se cancela la transición, en este caso para iniciarla nuevamente.

La variable de allClouds se agrego como variable global, al inicio del proyecto, para así poder tener todas las nubes en el método de scene:exitScene del storyboard.

 local allClouds = {}  

Esto genera las nubes, su transición y el reinicio al llegar al final de la pantalla. Ahora para la cancelación de la transición y que no genere problemas, debe cancelarse en el método de scene:exitScene del storyboard.
El código para este ejemplo seria:

 -- Called when scene is about to move offscreen:  
 function scene:exitScene( event )  
      local group = self.view  

      for i = 0, #allClouds do  
           local obj = allClouds[i]  
           if ( obj.moveTrans ) then  
                transition.cancel( obj.moveTrans )  
                obj.moveTrans = nil  
           end  
      end  
      -- INSERT code here (e.g. stop timers, remove listeners, unload sounds, etc.)  
      -- Remove listeners attached to the Runtime, timers, transitions, audio tracks  
 end  

Espero les pueda ayudar en algo!

El código de la generación de nubes esta basado en el utilizado en este blog:
http://www.christianpeeters.com/rolly-bear-world/
Recomendado por cierto!

martes, 6 de mayo de 2014

Ordenar objeto JSON alfabéticamente por cualquier atributo

Me topé con una situación en la que necesitaba ordenar un JSON alfabéticamente, una vez mas, StackOverflow me sacó del apuro.
La opción mas votada esta muy buena, puedes ordenar por cualquier atributo y en cualquier orden.
Les dejo el link a esta respuesta:
http://stackoverflow.com/a/4698083

 function sortJsonArrayByProperty(objArray, prop, direction){  
   if (arguments.length<2) throw new Error("sortJsonArrayByProp requires 2 arguments");  
   var direct = arguments.length>2 ? arguments[2] : 1; //Default to ascending  
   if (objArray && objArray.constructor===Array){  
     var propPath = (prop.constructor===Array) ? prop : prop.split(".");  
     objArray.sort(function(a,b){  
       for (var p in propPath){  
         if (a[propPath[p]] && b[propPath[p]]){  
           a = a[propPath[p]];  
           b = b[propPath[p]];  
         }  
       }  
       // convert numeric strings to integers  
       a = a.match(/^\d+$/) ? +a : a;  
       b = b.match(/^\d+$/) ? +b : b;  
       return ( (a < b) ? -1*direct : ((a > b) ? 1*direct : 0) );  
     });  
   }  
 }  
 sortJsonArrayByProperty(results, 'attributes.OBJECTID');  
 sortJsonArrayByProperty(results, 'attributes.OBJECTID', -1);  
En las ultimas 2 lineas se manda llamar la funcion de orden ascendente y descendente, ordenandolo por el OBJECTID

Teniendo el JSON de ejemplo:

 {"results": [  
  {  
   "layerId": 5,  
   "layerName": "Pharmaceutical Entities",  
   "attributes": {  
    "OBJECTID": "35",  
    "FACILITYTYPE": "Pharmacy",  
    "FACILITYSUBTYPE": "24 Hr Pharmacy",  
    "COMMERCIALNAME_E": "SADD MAARAB PHARMACY",  
    },  
   "geometryType": "esriGeometryPoint",  
   },  
  {  
   "layerId": 5,  
   "layerName": "Pharmaceutical Entities",  
   "attributes": {  
    "OBJECTID": "1",  
    "FACILITYTYPE": "Pharmacy",  
    "FACILITYSUBTYPE": "24 Hr Pharmacy",  
    "COMMERCIALNAME_E": "GAYATHY HOSPITAL PHARMACY",  
   },  
   "geometryType": "esriGeometryPoint",  
  },  
    {  
   "layerId": 5,  
   "layerName": "Pharmaceutical Entities",  
   "attributes": {  
    "OBJECTID": "255",  
    "FACILITYTYPE": "Pharmacy",  
    "FACILITYSUBTYPE": "24 Hr Pharmacy",  
    "COMMERCIALNAME_E": "AL DEWAN PHARMACY",  
    },  
   "geometryType": "esriGeometryPoint",  
   }  
 ]}