viernes, 20 de febrero de 2009

Aplicar un mismo tema a todos los sitios de una colección

Desde que comencé a trabajar con SharePoint me especialicé en portales públicos, en multilenguaje, extensibilidad, integración con otros productos, etc. y dejé un poco de lado la parte más estándard del producto. Evidentemente era algo que siempre estaba ahí, y que en cierta manera formaba parte de mi día a día, pero a lo que nunca di especial importancia. De un tiempo a esta parte me he interesado más por esta parte de MOSS, pudiendo descubrir las grandes funcionalidades que nos ofrece de serie, y aquellas cosas que, por extraño que pueda parecer, no están ahí. Una de las primeras cosas que me llamó la atención, no tanto por lo necesario de la funcionalidad sino por lo simple que resultaría tenerla, era la imposibilidad de aplicar un tema de sitio a todos los sitios de una colección de sitios. Tras un par de horas de trabajo, obtuve la funcionalidad de la siguiente manera:

Lo primero era pensar lo que se quería obtener. Me gustaría tener un enlace en la sección de apariencia de la configuración del sitio que, al acceder, me mostrase una lista de temas como en la página que ya existe para cambiar el tema a un sitio. Al aplicar el tema, automáticamente se debería replicar en todos los sitios de la colección de sitios.

Una vez decidido el funcionamiento, el primer punto a obtener era la nueva acción en la configuración del sitio. Para ello, se crea una característica de la siguiente manera:

<?xml version="1.0" encoding="utf-8"?>
<Feature  Id="5150eba6-eaf0-4cc6-95de-71629956d623"
          Version="1.0.0.0"
          DefaultResourceFile="_Res"
          Title="$Resources:feature_title;"
          Description="$Resources:feature_description;"
          Hidden="FALSE"
          Scope="Site"
          xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/>    
  </ElementManifests>
</Feature>

El menifiesto elements.xml contendría algo similar a:

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction
     Id="Namespace.Class"
     GroupId="Customization"
     Location="Microsoft.SharePoint.SiteSettings"
     Sequence="1000"
     Title="$Resources:sitetheme_title;">
    <UrlAction Url="/_layouts/themesite.aspx"/>
  </CustomAction>
 
</Elements>

(*) Nótese que todos los literales van asociados a un fichero de recursos. Me tendréis que perdonar pero es un vicio que se adquiere al trabajar constantemente en soluciones multilenguaje. Evidentemente no es necesario.

De acuerdo, una vez hecho esto, activar la característica en una colección de sitios nos daría el nuevo enlace que, como puede apreciarse en el segundo listado, apuntaría a una página llamada /_layouts/themesite.aspx. Esta página no existe pero, como hemos dicho antes, queremos algo muy similar a la página themeweb.aspx que se encuentra en la carpeta 12\TEMPLATE\LAYOUTS. Lo que yo hice es crear en esa misma carpeta una copia de esa página con el nombre indicado más arriba. En mi copia hice básicamente dos modificaciones. La primera, al principio de la página, cambiando el nombre de la clase que representará a mi página y el ensamblado en el cual se encontrará.

<%@ Assembly Name="MyNamespace.ApplicationPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=df46e276333b170c"%>
<%@ Page Language="C#" Inherits="MyNamespace.ApplicationPages.ThemeSiteForm" MasterPageFile="~/_layouts/application.master"      %>

La segunda, al final de la página, cambiando el apuntador a la llamada de servidor del botón de aceptar.

<TABLE border="0" cellspacing="0" cellpadding="0" class="ms-propertysheet" width="100%">
   <wssuc:ButtonSection runat="server">
       <Template_Buttons>
           <INPUT type=submit class="ms-ButtonHeightWidth" value="<%$Resources:wss,themeweb_apply%>" id=Submit2 name=Submit2 ACCESSKEY="S" OnServerClick="Submit2_Click" onclick="checkSelection()" runat="server"/>
       </Template_Buttons>
   </wssuc:ButtonSection>
</Table>

Hecho esto, sólo me quedaba crear mi clase y desarrollar el comportamiento del botón de aceptar.

namespace MyNamespace.ApplicationPages
{
    public class ThemeSiteForm : ThemeWebForm
    {
        private void RecursivelyApplyTheme(SPWeb web, string theme)
        {
            foreach (SPWeb child in web.Webs)
            {
                RecursivelyApplyTheme(child, theme);
            }
            web.ApplyTheme(theme);
        }
 
        public void Submit2_Click(object sender, EventArgs e)
        {
            int index = Convert.ToInt32(this.themes.Value);
            if (index >= 0)
            {
                SPWeb web = base.Web;
                RecursivelyApplyTheme(web, this.sc[index]);
 
                SPUtility.Redirect("settings.aspx", SPRedirectFlags.RelativeToLayoutsPage, HttpContext.Current);
            }
        }
 
    }
    
}

Como se puede apreciar, mi página hereda de la página original de cambio de tema de SharePoint y tiene un único método para el botón de aceptar. Una vez compilada la DLL que contiene esta clase y subida a la GAC ya puedo probar el funcionamiento del cambio recursivo de tema.

Evidentemente el trabajo no acaba aquí. Realizar cambios bajo la carpeta 12 no se puede hacer a la ligera. Es imprescindible crear un fichero de solución WSP que empaquete toda tu funcionalidad y la despliegue de manera correcta en una granja de servidores MOSS. Pero eso ya lo escribiré en otro post. También hay que tener en cuenta las limitaciones de este desarrollo. Por ejemplo, no tiene previsto qué pasará con sitios que se creen a posteriori; será necesario aplicar un tema a la colección de sitios cada vez que se desee. Tampoco tiene en cuenta la posibilidad de aplicar un tema recursivamente a partir de una ubicación concreta, que se podría realizar de manera sencilla cambiando el scope de la característica. Si os interesa puedo colgar el paquete de instalación para que lo podáis probar vosotros mismos.

0 comentarios: