miércoles, 26 de noviembre de 2014

Cómo solventar la limitación del “wait for X to equal” en SPD 2013

Anteriormente publiqué un post sobre algunas de las incoherencias que había detectado en los flujos de SharePoint Designer en 2013. Una de ellas es la de que en SPD 2013 la acción de esperar hasta que cambie el valor de un campo de la lista había pasado de ser muy flexible en 2010 (to equal, to not equal, to be not empty, to begin with…) a extremadamente inflexible en 2013 (única y exclusivamente “to equal”).

En SPD 2010         En SPD 2013
[image%255B8%255D.png]       [image%255B11%255D.png]

Así pues, si tenemos un flujo de trabajo que está esperando una validación, y el resultado de la validación puede ser tanto “Aprobada” como “Rechazada”, ¿Cómo lo hacemos?

En su momento apunté la posibilidad de invocar un flujo en 2010 que lo solucionara (cosa que me provoca picores en todo el cuerpo), pero hoy os planteo otra posible solución que (mientras no contemple un número muy elevado de posibles respuestas) es más “polite” y debería darnos menos dolores de cabeza.

La solución no es otra que la de diseñar pasos en ejecución paralela. Es decir, allí donde queramos introducir la instrucción de esperar a que el campo tome uno de los posibles valores (en este ejemplo “rejected” o “approved”), tendremos que:

1.- Introducir un bloque de ejecución en paralelo.image
2.- Crear tantos “steps” dentro del bloque de ejecución en paralelo como posibles respuestas podamos obtener. En este caso 2, una para rechazo y otra para validación.
image
image
A partir de aquí rellenar las acciones necesarias para cada respuesta, teniendo en cuenta que únicamente será posible ejecutar una de ellas (o hay validación o hay rechazo). Si hubieran acciones comunes en todos los casos, estas se pueden poner fuera y al después de la ejecución paralela, ya que se ejecutarían una vez uno de los pasos dejara de estar en modo de espera y avanzara en el flujo.
Como resultado obtendríamos un flujo más o menos con la siguiente pinta:
image
¡Pues ya lo tenemos! Una vez más sorteando las “piedras” en el camino de la implementación de SharePoint. Confiemos en que SharePoint 2015 aporte muchas más mejoras y muchas menos limitaciones y bugs… ¡¡Soñar es gratis!! Guiño

domingo, 23 de noviembre de 2014

SP 2013: Cómo crear una alerta con parpadeo de imagen (Javascript)

Los que conocen este blog sabrán que siempre he tirado más por la vertiente de IT Pro (administrator/power user) y resolver las trabas de SharePoint mediante trucos OOB o SharePoint Designer y otras herramientas zero code. Pero últimamente he estado trabajando en un proyecto de SharePoint sobre el que básicamente hemos tenido que utilizar Javascript y jQuery para implantar todos los requerimientos del cliente, y como “me ha entrado el gusanillo”, hoy vamos a explicar un ejemplo práctico de jQuery que he utilizado recientemente en un portal corporativo.

Partimos del requerimiento de que tenemos una página de SharePoint con un webpart de tipo biblioteca de documentos. En concreto se trata de una biblioteca de Currículums Vitae en el que cada usuario solo ve sus currículos y versiones del mismo en diversos idiomas. Lo que queremos conseguir es que si un usuario lleva más de 5 meses sin actualizar uno de sus CV’s, este se ponga a “parpadear” en rojo chillón y aparezca un mensaje del tipo “¡¡Actualízame ya!!”. Como comprenderéis, si os pasan un requerimiento similar, difícilmente lo podréis implantar sin el uso de código, y lo cierto es que el ejemplo viene que ni pintado para el uso de javascript.
Los pasos que vamos a seguir son:
  1. Definir un estilo para el parpadeo
  2. Obtener la fecha actual y darle un formato que permita compararse con otra fecha
  3. Buscar los valores de la columna de tipo fecha a comparar en el WebPart específico
  4. Para cada uno de los resultados (ficheros):
    1. Darle un formato a la fecha permita compararse con la fecha actual
    2. Restar la fecha actual con la fecha de modifiación
    3. Pasar el resultado a días
    4. Si los días superan los requeridos (en el ejemplo 150), asignar el estilo “parpadeo” al elemento y añadirle un aviso.
Antes de empezar debéis aseguraros de tener jquery subido como fichero en alguna biblioteca documental del SharePoint, por ejemplo en “/SiteAssets/”. Jquery lo podéis descargar de forma totalmente gratuita aquí.

Lo siguiente será ir a la página de SharePoint que contenga nuestro WebPart y añadir un WebPart de Script Editor que encontraremos en la categoría de “Media and Content”. Este WP será una tontería, pero a mí me tiene loco en 2013 y creo que es el que más uso para ir compensando “alguna que otra” carencia de SP 2013…

image

Seguidamente, iremos al WebPart recién añadido y pulsaremos en “Edit snippet” para añadir el código deseado en la página.

image
Una vez puestos en situación, vamos a empezar definiendo un style de CSS que permita visualizar su contenido en forma de parpadeo. Comentar aquí que algún navegador como firefox no aceptaba antes del CSS3 el estilo “animation”, así que usaremos aquí el –webkit-animation-duration de CSS. Para navegadores con CSS2 usaremos el animation, pero será inevitable que en algunos (firefox antiguos, por ejemplo) no funcione.

<style>
    @keyframes blink {from { opacity: 1.0; }  to { opacity: 0.0;}}
    @-webkit-keyframes blinker {from { opacity: 1.0; }  to { opacity: 0.0;}}
    .parpadeo{
         color: red;
         font-weight: bold;
         -webkit-animation-name: blinker; 
         -webkit-animation-iteration-count: infinite; 
         -webkit-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
         -webkit-animation-duration: 1s;
         animation: blink 1s steps(2, start) infinite;
    }
</style>


Evidentemente, podéis sustituir tranquilamente el “color:red” por el color que más os apetezca.
A continuación hacemos la invocación a jquery, cambiando la URL relativa por aquella en la que tengais cargado vuestro fichero jquery, y indicando la versión que ser corresponda con la vuestra.
<script type="text/javascript"  src="/SiteAssets/jquery-1.11.1.js"> </script>
iniciamos ya nuestro script de javascript definiendo una función que se ejecute justo después de que se carguen todos los elementos de la página (es importante, ya que de lo contrario podría ser que el script todavía no encontrara los elemento estamos referenciando).

<script type="text/javascript">
    $(document).ready(function() {

Lo primero que vamos a hacer en nuestra función es obtener la data actual, y darle el formato apropiado para poder compararla con la fecha de modificación del fichero.

        var TodayFull= new Date();
        var Today = TodayFull.getDate()+ "/" +(TodayFull.getMonth() +1) + "/" + TodayFull.getFullYear();
        var TodaySplit = Today.split('/');
        var TodayDate = Date.UTC(TodaySplit [2],TodaySplit [1]-1,TodaySplit [0]);

Un vez hecho esto el siguiente paso es obtener la fecha de modificación de cada CV (pueden haber múltiples). Para ello hay que encontrar una forma única de identificar el campo “Modified” que contiene la fecha de la última modificación del fichero. Aquí os recomiendo que tiréis del F12 y en el panel de Developer Tools, mediante la herramienta de selección de elementos...

image

...y pulséis encima del campo de fecha que os interese, (en mi caso “Modified”) y observéis si dicho campo (o alguno de sus “padres”) contiene una clase o id que os sirva para identificarlo de forma concreta.
image

En este caso vemos que la fecha se contiene en un ‘span’ que está dentro de un ‘td’ con un estilo ‘td.ms-vb-lastCell’. En este caso, la siguiente sentencia servirá para obtener todos los campos ‘Modified’ del WP con título “KEEP YOUR CV UPDATED”. Tened en cuenta que en mi ejemplo tan solo hay una columna de tipo fecha. En caso de existir múltiples de ellas, posiblemente tendríamos que afinar más la siguiente línea a fin de asegurarnos de que atacamos el campo que queremos comparar y no otra fecha existente en el listado.

$("span:contains('KEEP YOUR CV UPDATED')").parent().parent().find('td.ms-vb-lastCell span').each(function(index) {

Por favor, sustituid los parámetros de nombre del WP y nombre del campo por los vuestros propios para que os funcione correctamente. Quizás a algunos les pueda resultar un tanto compleja, así que paso a explicarla por partes:

$("span:contains('KEEP YOUR CV UPDATED')") –> Nos sitúa dentro del WP con ese título. Sustituidlo por el nombre de vuestro propio WP

.parent().parent() –> Nos sitúa en el <div> que contiene todo el código del WP, para poder seguir buscando nuestra columna “Modified” (el span anterior no la contenía).

find('td.ms-vb-lastCell span') –> Nos sitúa sobre los diversos valores del campo Modified (contiene todos los ficheros existentes).

each(function(index) { –> Para cada uno de los valores retornados (cada fichero), ejecutamos la siguiente función

El siguiente paso (a partir de aquí ya lo haremos para cada uno de los ficheros a comprobar), será aplicar el mismo procedimiento a la fecha obtenida por el campo Modified que el que le hicimos pasar a la fecha actual. Transformamos el campo en el formato adecuado para la comparación entre fechas:           
            var Modified = $(this).html().substring(0,10);
            var ModifiedSplit = Modified.split('/');
            var ModifiedDate = Date.UTC(ModifiedSplit [2],ModifiedSplit [1]-1,ModifiedSplit [0]);

Ahora ya estamos en disposición de restar directamente la fecha de hoy con la de creación del documento:

var dif = TodayDate - ModifiedDate;

El resultado obtenido tenemos que convertirlo a días mediante la siguiente fórmula:

var dias = Math.floor(dif / (1000 * 60 * 60 * 24));

Ahora ya podemos establecer la causa condicionas, indicando lo que vamos a hacer si han pasado x días (en mi caso 150, pero sustituidlo por vuestro propio valor)

if (dias >150) {

Cuando un documento esté "caducado", primero vamos a hacer que aparezca parpadeando, asignándole el estilo que creamos para ello:

$(this).addClass("parpadeo");

También, opcionalmente, podemos agregar un comentario para hacer todavía más llamativa la urgencia de actualizar el fichero:

$(this).append ( "¡¡UPDATE NOW YOUR CV!!");

¡Y ya solo nos queda cerrar el condicional, cerrar la función del each, la función principal y el tag de script!
            }
        });
    });
</script>

 Como resumen, el código debería haber quedado muy similar al siguiente (modificando el nombre del WebPart y los días necesarios para considerar un documento caduco).

<style>
    @keyframes blink {from { opacity: 1.0; }  to { opacity: 0.0;}}
    @-webkit-keyframes blinker {from { opacity: 1.0; }  to { opacity: 0.0;}}

    .parpadeo{
         color: red;
         font-weight: bold;
         -webkit-animation-name: blinker; 
         -webkit-animation-iteration-count: infinite; 
         -webkit-animation-timing-function: cubic-bezier(1.0,0,0,1.0);
         -webkit-animation-duration: 1s;
         animation: blink 1s steps(2, start) infinite;
    }
</style>

<script type="text/javascript"  src="/SiteAssets/jquery-1.11.1.js"> </script>
<script type="text/javascript">
    $(document).ready(function() {
        //obtenemos la fecha actual y le damos el formato adecuado para poderla comparar
        var TodayFull= new Date();
        var Today = TodayFull.getDate()+ "/" +(TodayFull.getMonth() +1) + "/" + TodayFull.getFullYear();
        var TodaySplit = Today.split('/');
        var TodayDate = Date.UTC(TodaySplit [2],TodaySplit [1]-1,TodaySplit [0]);
        //obtenemos la fecha del campo mostrado en pantalla y le damos el formato adecuado para poderla comparar
        $("span:contains('KEEP YOUR CV UPDATED')").parent().parent().find('td.ms-vb-lastCell span').each(function(index) {
            var Modified = $(this).html().substring(0,10);
            var ModifiedSplit = Modified.split('/');
            var ModifiedDate = Date.UTC(ModifiedSplit [2],ModifiedSplit [1]-1,ModifiedSplit [0]);
            //comparamos las 2 fechas obtenidas
            var dif = TodayDate - ModifiedDate;
            //pasamos el resultado a días reales
            var dias = Math.floor(dif / (1000 * 60 * 60 * 24));
            if (dias >150 {
                $(this).addClass("parpadeo"); //asignamos el style definido de parpadeo
                $(this).append ( "¡¡UPDATE NOW YOUR CV!!"); //añadimos una frase con 'gancho' para atraer la atención del usuario
            }
        });
    });

</script>
Veremos que si tenemos, por ejemplo, 2 documentos desactualizados, el resultado que veríamos en pantalla sería algo parecido a lo siguiente:

image

En el momento que actualicemos uno de ambos documentos, el estilo aplicado sería el normal y veríamos algo similar a lo siguiente:

image

El script que he insertado de demostración, debería valer para cualquier página, únicamente modificando el nombre del WebPart. Eso sí, tened en cuenta que podría no funcionar en listados con más de un campo de tipo fecha (se debería afinar en ese caso la localización de la columna específica a comparar) y exploradores sin CSS3 o que no admitan el estilo ‘animation’ (caso de firefox antiguos, por ejemplo).

El texto parpadeando puede parecer muy "retro" y típico de las webs de los años 90, pero en determinados casos, cuando el usuario ve en rojo chillón parpadeante que tiene que actualizar un documento, tenemos más probabilidades de que decida actualizarlo... ¡¡Al menos eso quiero creer!!

Pues nada más por hoy Sharepointer@s, es posible que en el futuro vuelva a postear un ejemplo práctico de aplicación del JavaScript en el SharePoint... aunque, ¡Cuidado! ¡¡Al final uno le puede coger el gusto y hay que controlarse para no meterlo en todas partes!!

;-D