sábado, 1 de noviembre de 2008

Error javascript "object required" al arrastrar webparts de una zona a otra

Tras trabajar en varios portales públicos desarrollados sobre Sharepoint, he de decir que una de las cosas más frecuentes y molestas, y a la vez más olvidadas, son los errores de javascript. Nunca sabes a partir de qué momento, intentas utilizar la interfaz de usuario de MOSS para arrastrar webparts de una zona a otra, o para importar un nuevo webpart a la página y comienzan a aparecer errores de javascript en los ficheros ie55up.js, o cmssummarylinks.js. Normalmente, al ver que el error se encuentra en uno de los ficheros internos de Sharepoint, y que lo que necesitas hacer se puede hacer por otras vías, tiendes a aparcar el problema para cuando tengas algo de tiempo y, a la postre, lo acabas olvidando. Pues bien, al final he decidido buscar ese tiempo y acabar de solucionar de una vez por todas ese problema.

Tras investigar un poco en los ficheros javascripts que he mencionado, acabé viendo que el origen de todos los problemas estaba en la función MSOLayout_GetRealOffset del fichero ie55up.js. Tras revisar esta función, observé que el problema radicaba en el hecho de utilizar posicionamiento relativo en tus maquetaciones. Después de pensarlo unos segundos y, teniendo en cuenta sobretodo que la maquetación es una de las muchas cosas que no se me dan nada bien, decidí buscar una solución alternativa que funcionase con cualquier diseño de página y con cualquier tipo de posicionamiento.

Lo primero que se me ocurrió fue modificar la función que me daba problemas y, contra cualquier buena práctica que se os puede pasar por la cabeza, busqué el fichero dentro de la carpeta 12 y lo modifiqué. Bueno por lo menos hice una copia de seguridad del fichero en cuestión. El caso es que tras un poquito de prueba-y-error di con las modificaciones adecuadas:

function MSOLayout_GetRealOffset(StartingObject, OffsetType, EndParent)
{               
    var realOff = 0;              
    if (!EndParent)
      EndParent = document.body;
       
    for (var currObj = StartingObject; currObj && currObj != EndParent && currObj != document.body; currObj=currObj.offsetParent)         
    {             
        var currOff = eval('currObj.offset' + OffsetType);      
        if (currOff)
          realOff+=currOff ;        
    }         
 
    return realOff ;       
} 

Claro que, el trabajo no estaba acabado. Está claro que modificar un fichero interno de Sharepoint es algo a evitar en ma medida de lo posible, teniendo en cuenta sobretodo la dificultad para el despliegue del cambio y la poca solidez ante una eventual actualización del producto. En este caso, sin embargo, todo resulta mucho más fácil de lo que parece. Una de las características de javascript es que puedes redefinir cualquier funcion siempre y cuando la nueva función aparezca después de la suplantada. Bien, teniendo eso en cuenta probé a definir la función en la página maestra de mi sitio, tras el objeto SPWebPartManager, y dentro del tag Form HTML y, tras restaurar el fichero javascript original, todo funcionó correctamente.

Espero que os ayude.

martes, 28 de octubre de 2008

Office System 2007 SP2

Microsoft ha anunciado que el SP2 para Office System 2007 verá la luz entre febrero y abril de 2009. El paquete afectará tanto a las herramientas clientes de Office como a las herramientas de servidor.

Algunas de las novedades que Microsoft desvela sobre este nuevo service pack relativas a MOSS son:

  • Mejoras de rendimiento y gestión de variaciones en ECM, incluyendo comandos STSADM para reparar enlaces entre páginas origen y destino.
  • Mejoras sobre procesado de aprovaciones de estado en Project Server
  • Mejoras en bases de datos de sólo lectura y timer jobs de recreación de índices

A partir de ahora algunos equipos de producto irán haciendo públicas las mejoras que han añadido dentro de este service pack.

Si queréis más información al respecto, podéis encontrarla aquí:

http://blogs.technet.com/office_sustained_engineering/archive/2008/10/22/announcing-service-pack-2-sp2-for-the-2007-microsoft-office-system.aspx

lunes, 27 de octubre de 2008

Integridad referencial en MOSS

Cuando hablamos de integridad referencial (i.e. control de relaciones entre diferentes entidades) y de MOSS lo primero que nos viene a la cabeza es el concepto Lookup Columns (o columnas de búsqueda). Con ellas podemos crear columnas de sitio que hagan referencia a una lista concreta y que luego, al ser añadidas a un tipo de contenido conseguirían el efecto de lo que siempre hemos denominado Relación 1-N. Con el uso de estas columnas especiales podemos obtener algo similar a integridad referencial y, con un poco de trabajo y algún event handler podríamos afinarlo hasta el punto que quisiéramos.

Ahora bien, ¿qué sucedería si quisiéramos utilizar este concepto mezclado con un portal de publicación con variaciones? Un caso bastante normal con el que nos encontramos al trabajar en portales públicos en varios idiomas es el siguiente: contenido principal (producto) que está relacionado con contenido secundario (artículo relacionado). Como no podía ser de otra manera, tanto el producto como sus artículos relacionados deben visualizarse en diferentes idiomas y, por lo tanto, utilizamos variaciones de sitio. Si aplicamos el concepto mencionado anteriormente, podríamos crear una columna de sitio relacionada con productos y añadirla al tipo de contenido artículo relacionado. Tras muchas pruebas, veríamos como al generarse las variaciones este tipo de columna nos iba a causar muchísimos problemas. Acabaríamos intentando interceptar el evento de generación de variaciones de página para modificar su comportamiento y, en el mejor de los casos, acabaríamos creando una estructura de datos satélite y desarrollando todos los webparts necesarios para simular el comportamiento deseado. Los resultados de todo esto serían:

  • Gran cantidad de código a generar, con las implicaciones en tiempo y esfuerzo que esto atañe.
  • Poca posibilidad de reutilizar los desarrollos realizados
  • Poco aprovechamiento de las características estándard de SharePoint.

Yo no soy partidario de ninguna de estas tres consecuencias y, por tanto, decidí darle algunas vueltas y plantear una solución alternativa, genérica y muy en línea con las capacidades del producto. A continuación enumeraré los puntos claves de esta solución:

  1. Añadir a todos los tipos de contenido personalizados una columna, que llamaremos PK y que, mediante un event handler asociado a dichos tipos de contenido, se inicializará con un valor único (GUID) en el momento de creación.
  2. Añadir campos a los tipos de contenido relacionados para alojar las relaciones. En el caso que nos ocupa, crearíamos un campo Producto en el tipo de contenido Artículo.
  3. Crear un control genérico que permite crear contenidos de un tipo determinado, desde la página de detalle de otro contenido relacionado. En nuestro ejemplo, añadiríamos el control dentro de la página de detalle de producto y lo configuraríamos para que generase artículos con el campo Producto rellenado automáticamente con el valor PK del producto que estamos visualizando y nos llevase a la página de detalle de dicho artículo.

Como podéis ver, dos desarrollos simples que pueden ser reutilizados en cualquier proyecto si se realizan convenientemente. Y lo que hace que todo resulte aún más simple es el hecho que, en el momento en que se creen variaciones de alguno de estos contenidos, los campos PK y Producto mantendrán sus valores sin necesidad de intervención alguna.