Modèles de pages de webpart

Cet article donne une méthode pour ajouter des modèles de pages de webpart personalisés à vos besoins.

1 Introduction

Lorsqu’il s’agit de personnaliser un site internet ou intranet qui se base sur WSS, vous allez être confronté à un grand nombre d’étapes parmi lesquelles :

· Création / Modification de master page

· Création / Modification de feuille de styles

· Développement de contrôles utilisateur pour agir sur le contenu des pages

· Utilisation du SDK pour manipuler les données

· Ajout de pages avec des nouvelles dispositions

· Création / Modification de modèles de sites et de listes adaptés aux besoins

· Packaging et déploiement des nouvelles solutions sous forme de « Features »

Dans cet article je vais commencer en abordant la création de modèles supplémentaires de pages de webparts permettant d’offrir aux utilisateurs des nouvelles dispositions des zones de webparts afin qu’ils puissent disposer les différentes webparts selon la mise en page dont ils ont besoin.

Les pré-requis :

· Disposer d’une installation standard de WSS3

· Connaitre son utilisation

· Minimum de connaissances sur le développement ASP.NET 2.0

· Droits d’accès en Lecture/Ecriture au système de fichier du serveur WSS.

· Visual studio 2005 ou Express édition installé (de préférence sur le serveur mais pas obligatoire)

2 Principe

Un site collaboratif SharePoint vous propose de créer un certain nombre d’éléments en standard : liste de document, d’annonces, de liens, etc.. Ainsi que de créer des pages de webparts. Ces pages seront stockées dans une liste de documents, et vont vous permettre de disposer les contenus du site sous différentes formes. Ces pages sont très utiles lorsque le site contient beaucoup d’informations et qu’on ne veut pas tout mettre sur la page principale du site.

Par défaut, vous disposez de 8 modèles de mise en page :

image

Cette page ci-dessus permet de choisir le modèle de votre choix parmi les modèles standard et réalise la création de la page et son enregistrement dans la bibliothèque de document de votre choix.

L’objectif est simple : nous allons créer une nouvelle page aspx qui va faire le même travail mais va utiliser nos propres modèles. Pour aller jusqu’au bout de l’exemple trois étapes sont nécessaires :

· Créer des modèles adaptés à nos besoins

· Créer une nouvelle page de création des pages de webparts

· Ajouter un lien dans le site pour permettre aux utilisateurs de créer des pages en passant par notre nouvelle page de création.

3 Création des modèles

Pour créer de nouveaux modèles, le plus simple est de partir de modèles fournis en standard. Ceux-ci se trouvent dans le répertoire : C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\1033\STS\DOCTEMP\SMARTPGS\ (pour une installation par défaut de WSS) :

image

Je vais donc me baser sur le plus simple de ces fichier : spstd1.aspx et faire un simple copier/coller en le renommant en customWPP1.aspx.

A noter : si vous utilisez une master page modifiée, il faudra prendre en charge les ContentPlaceHolder supplémentaires que vous avez éventuellement ajoutés, et donc ce modèle de base ne vous conviendra peut être pas au mieux. L’important c’est de partir d’une page qui contient l’essentiel des éléments nécessaires au bon affichage de votre page.

Il est temps maintenant d’éditer ce fichier dans Visual studio et de mettre en place la mise en page désirée. Ici il s’agit plus de faire du html qu’autre chose donc en principe rien de plus simple.

Commencez par repérer le « Content » qui permet de remplir le ContentPlaceHolderMain. Toute la mise en page est en principe faite uniquement dans ce place holder. Le code ci-dessous montre le fichier d’origine. Une simple table html à une ligne et une colonne qui contient une zone de webparts :

<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
        <table cellpadding="4" cellspacing="0" border="0" width="100%">
        <tr>
        <td id="_invisibleIfEmpty" name="_invisibleIfEmpty" valign="top" width="100%">
        <WebPartPages:WebPartZone runat="server" Title="loc:FullPage" ID="FullPage" FrameType="TitleBarOnly"/>
        </td>
        </tr>
        <script language="javascript">if(typeof(MSOLayout_MakeInvisibleIfEmpty) == "function") {MSOLayout_MakeInvisibleIfEmpty();}</script>
        </table>
        </asp:Content>
        

On peut donc ajouter autant de zones de webparts que l’on souhaite, sachant qu’il faut faire attention de bien mettre un ID unique à chacune. L’attribut Title permet de choisir le texte qui s’affichera dans la page en mode design (lorsque l’utilisateur sera en train d’ajouter des webparts), enfin l’attribut FrameType va permettre d’assigner une valeur par défaut à cette même propriété des webparts qui seront placés dedans. (Attention aux valeurs, vous ne pouvez pas mettre ce que vous voulez pour ces propriétés : pas de caractères spéciaux par exemple)

Pour l’exemple, j’ai fait un modèle qui contient 3 lignes et 3 colonnes avec une zone de webpart dans chacune sauf celle du centre où j’ai placé une image. (C’est un exemple comme un autre, dans cet article je ne m’attarderai pas sur le html utilisé, ce n’est pas la sujet.) :

<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">
        <table cellpadding="4" cellspacing="0" border="0" width="100%">
        <tr>
        <td valign="top" width="50%">
        <WebPartPages:WebPartZone runat="server" Title="haut gauche" ID="haut_gauche" FrameType="TitleBarOnly" />
        </td>
        <td align="top">
        <WebPartPages:WebPartZone runat="server" Title="haut milieu" ID="haut_milieu" FrameType="TitleBarOnly" />
        </td>
        <td valign="top" width="50%">
        <WebPartPages:WebPartZone runat="server" Title="haut droite" ID="haut_droite" FrameType="TitleBarOnly" />
        </td>
        </tr>
        <tr>
        <td valign="top" width="50%">
        <WebPartPages:WebPartZone runat="server" Title="milieu gauche" ID="milieu_gauche"
        FrameType="TitleBarOnly" />
        </td>
        <td align="top">
        <img src="http://www.bewise.fr/bdc2007/img/logo.gif" />
        </td>
        <td valign="top" width="50%">
        <WebPartPages:WebPartZone runat="server" Title="milieu droite" ID="milieu_droite"
        FrameType="TitleBarOnly" />
        </td>
        </tr>
        <tr>
        <td valign="top" width="50%">
        <WebPartPages:WebPartZone runat="server" Title="bas gauche" ID="bas_gauche" FrameType="TitleBarOnly" />
        </td>
        <td align="top">
        <WebPartPages:WebPartZone runat="server" Title="bas milieu" ID="bas_milieu" FrameType="TitleBarOnly" />
        </td>
        <td valign="top" width="50%">
        <WebPartPages:WebPartZone runat="server" Title="bas droite" ID="bas_droite" FrameType="TitleBarOnly" />
        </td>
        </tr>
        </table>
        </asp:Content>
        

Si vous voulez voir ce que donne votre page avant de passer à l’étape suivante ou avant de faire vos autres modèles, vous pouvez tout simplement lui donner le nom « spstd1.aspx » tout en prenant soin de sauvegarder la page standard (histoire de conserver le modèle original) et d’aller sur le site et de créer une nouvelle pages de webparts en utilisant le premier modèle.

Il vous reste donc à créer tout les modèles dont vous avez besoin avant de passer à l’étape suivante.

4 Page de création des pages de webparts

La page utilisée en standard est sur l’url « /_layouts/spcf.aspx » et physiquement dans le répertoire « C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS ». Je vais donc partir de cette page et encore une fois par un simple copier/coller je vais créer ma page « customspcf.aspx ».

Il faut réaliser deux modifications dans cette page :

· Changer l’affichage de la liste des modèles

· Ecrire le code pour créer les nouvelles pages avec nos modèles.

Le contenu de cette page va peut être vous paraitre trop complexe ou très touffu, mais pas d’inquiétude, les modifications sont assez simples.

4.1 Modification de la liste des modèles

Commencez par repérer le bloc asp qui correspond au contrôle qui va faire le rendu de la liste de sélection des modèles. Un commentaire html « < !– Layout — > » en indique le début :

 

<!-- Layout -->
        <wssuc:InputFormSection runat="server" Title="<%$Resources:wss,webpagecreation_layout_title%>">
        <template_description>
        (…)
        </template_description>
        <template_inputformcontrols>
        <wssuc:InputFormControl runat="server"				LabelText="<%$Resources:wss,webpagecreation_layout_choosetemplate%>">
        <Template_Control>
        <SELECT id="onetidWebPartPageTemplate" name="WebPartPageTemplate" size="8" onchange="DoTemplateOptionChange()">
        <OPTION value="1"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,webpagecreation_layout_option1%>" EncodeMethod='HtmlEncode'/></OPTION>
        <OPTION value="3"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,webpagecreation_layout_option3%>" EncodeMethod='HtmlEncode'/></OPTION>
        <OPTION value="4"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,webpagecreation_layout_option4%>" EncodeMethod='HtmlEncode'/></OPTION>
        <OPTION value="2" selected="true"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,webpagecreation_layout_option2%>" EncodeMethod='HtmlEncode'/></OPTION>
        <OPTION value="5"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,webpagecreation_layout_option5%>" EncodeMethod='HtmlEncode'/></OPTION>
        <OPTION value="6"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,webpagecreation_layout_option6%>" EncodeMethod='HtmlEncode'/></OPTION>
        <OPTION value="7"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,webpagecreation_layout_option7%>" EncodeMethod='HtmlEncode'/></OPTION>
        <OPTION value="8"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,webpagecreation_layout_option8%>" EncodeMethod='HtmlEncode'/></OPTION>
        </SELECT>
        </Template_Control>
        </wssuc:InputFormControl>
        </template_inputformcontrols>
        </wssuc:InputFormSection>
        

Et oui, vous ne rêvez pas ! Le code des 8 options est bel et bien en dur, et la liste des modèles n’est pas construite dynamiquement en fonction des fichiers ou de la base de données.

Je vais donc simplement remplacer ce code asp (uniquement la partie template_control) par mon code html présentant mes modèles, et aussi pourquoi pas, reprenant les modèles standard qui peuvent m’intéresser. Je vous épargne le début du code html permettant d’afficher un texte d’explication à destination de l’utilisateur, ce qui est important c’est le code de la liste de choix :

 

<Template_Control>
        <select id="onetidWebPartPageTemplate" name="WebPartPageTemplate" size="3" onchange="DoTemplateOptionChange()">
        <option value="customWPP1">mon modele 1</option>
        <option value="spstd1">modele standard pleine page</option>
        <option value="spstd2">modele standard 2</option>
        </select>
        </Template_Control>
        

Vous l’aurez remarqué, pour faire simple j’ai donné en « value » à mes différentes options le nom du fichier modèle. Ainsi pour créer la nouvelle page de webparts à partir de ce fichier, je n’aurais plus qu’à utiliser cette valeur directement pour recomposer le chemin du fichier modèle.

4.2 Modification du code de création du modèle

La deuxième étape consiste à rajouter le code C# qui va nous permettre de récupérer le fichier modèle, et de l’ajouter dans la bibliothèque de documents sélectionnée. Une bonne partie du code est réutilisable tel quel concernant la vérification des champs saisis et l’existence de la bibliothèque de destination.

Il faut juste « intercepter » l’appel qui est déclenché par le click sur « ok » dans une des fonctions JavaScript et ensuite intervenir au niveau du « Load » de la page en cas de «Post-Back ».

En effet la fonction JavaScript change l’action de la balise « form » et poste donc le formulaire sur l’isapi de WSS (owssrv.dll) et je veux bien sûr bloquer cet appel. Du coup la page va être rechargée et incluant mon code que dans le cas d’un post-back, je pourrais réaliser la création de la page moi-même.

Commencez donc par repérer la fonction JavaScript « _spFormOnSubmit() » et commentez la deuxième ligne de code qui change l’attribut « action » du formulaire, comme ci-dessous :

 

function _spFormOnSubmit()
        {
        var frmWebPage = document.forms.<%SPHttpUtility.NoEncode(Form.ClientID,Response.Output);%>;
        //frmWebPage.action=<% SPHttpUtility.AddQuote(SPHttpUtility.UrlPathEncode(strHttpPath,true),Response.Output); %>;
        return DoValidateAndSubmit();
        }
        

Ensuite remontez dans la page jusque dans la méthode « OnLoad » qui est « inline » dans l’asp, en début de page. En toute fin de fonction, on va rajouter le code qui permet de créer la nouvelle page de webparts. Les actions à réaliser sont :

· Recomposer le chemin du fichier modèle sélectionné et récupérer sont contenu

· Recomposer le chemin de destination à l’aide d’une instance de « List ». Pour cela on utilise le guid qui se trouve dans les champs de formulaire

· Ajouter le fichier dans la liste à l’aide d’une instance de « SPWeb » Le code en début de « PageLoad » se charge déjà de récupérer cette instance, donc on utilise directement la variable.

· Rediriger l’utilisateur sur la page ainsi crée.

if (Page.IsPostBack)
        {
        //Le chemin du modèle est recomposé en utilisant la "value" de l'option selectionnée
        string sourceFilePath = SPUtility.GetGenericSetupPath("TEMPLATE\\1033\\STS\\DOCTEMP\\SMARTPGS\\");
        sourceFilePath = string.Concat(sourceFilePath, Request.Form["WebPartPageTemplate"], ".aspx");
        //recupération du contenu
        System.IO.TextReader sourceFile = System.IO.File.OpenText(sourceFilePath);

        //on recupère une instance de List
        Guid idList = new Guid(Request.Form["List"]);
        SPList listDest = spWeb.Lists[idList];
        //on defini le chemin de destination en le positionnant à la racine de la liste, et en utilisant le nom saisi par l'utilisateur
        string destFile = string.Concat(listDest.RootFolder.Url, "/", Request.Form["Title"], ".aspx");

        //prise en charge de l'ecrasement si existant
        bool overwrite = Boolean.Parse(Request.Form["Overwrite"]);
        try
        {
        //ajout du flux binaire dans la liste en passant par le SPWeb disponible.
        spWeb.Files.Add(destFile, System.Text.Encoding.UTF8.GetBytes(sourceFile.ReadToEnd()), overwrite);

        //redirection de l'utilisateur sur la page crée, en mode design
        Response.Redirect(string.Concat(spWeb.Url , "/" , destFile , "?PageView=Shared&ToolPaneView=2"));
        }
        catch
        {
        errorString = "<table><tr><td><h3><font color=red>This page already exists. You have to overwrite it.</font></h3></td></tr></table>";
        }
        }
        

Il faut aussi prévoir un message d’erreur si l’utilisateur n’a pas choisi d’écraser le fichier existant (si il en est un). Pour cela j’ai opté pour une solution simple qui consiste à déclarer une variable errorString et de la remplir en cas d’erreur d’un message. Cette variable est ensuite incluse dans un des ContentPlaceHolders en début de page :

<asp:Content ID="Content3" ContentPlaceHolderID="PlaceHolderPageDescription" runat="server">
        <%=errorString %>
        <SharePoint:EncodedLiteral ID="EncodedLiteral3" runat="server" Text="<%$Resources:wss,webpagecreation_newwp_pagedescription%>"
        EncodeMethod='HtmlEncode' />
        </asp:Content>
        

4.3 Modification de l’affichage des images du modèle

Il reste encore une petite modification à faire sur cette page pour que ce soit plus « visuelle » : elle consiste à modifier la fonction JavaScript qui affiche l’image de la mise en page sélectionnée. En effet cette fonction JavaScript se base sur l’id sélectionné dans la liste d’options.

Commencez par repérer la fonction « DoTemplateOptionChange » ci-dessous :

 

function DoTemplateOptionChange()
        {
        var frmWebPage = document.forms.<%SPHttpUtility.NoEncode(Form.ClientID,Response.Output);%>;
        var index = frmWebPage.WebPartPageTemplate.selectedIndex;
        frmWebPage.PreviewImage.src = strImagePath + "spstd" + frmWebPage.WebPartPageTemplate.options[index].value + ".gif";
        frmWebPage.PreviewImage.alt = frmWebPage.WebPartPageTemplate.options[index].text;
        }
        

Cette fonction utilise l’id sélectionné, le concatène avec « spstd » à gauche et « .gif » à droite. On peut donc comprendre que les images associées aux templates portent tout simplement le même nom que les fichiers aspx, sont au format gif et placées dans le répertoire « \Layouts\<LCID>\images\ ». Or nous avons modifié notre template pour la liste déroulante, et nos id d’option contiennent déjà le nom du fichier template. Le plus simple est donc de supprimer le « + « spstd » » dans la fonction. Ainsi pour un template standard, on récupère bien son image, et en plaçant nos images au format gif dans le bon répertoire, avec le nom de nos templates on aura un fonctionnement idéal. Il faut aussi ajouter 2 lignes de codes à la fonction JavaScript « _spBodyOnLoad » pour sélectionner un des éléments de la liste et appeler la fonction de mise à jour de l’image (voir ci-dessous les 2 lignes en gras).

 

function DoTemplateOptionChange()
        {
        var frmWebPage = document.forms.<%SPHttpUtility.NoEncode(Form.ClientID,Response.Output);%>;
        var index = frmWebPage.WebPartPageTemplate.selectedIndex;
        frmWebPage.PreviewImage.src = strImagePath + frmWebPage.WebPartPageTemplate.options[index].value + ".gif";
        frmWebPage.PreviewImage.alt = frmWebPage.WebPartPageTemplate.options[index].text;
        }

        function _spBodyOnLoad()
        {
        var frmWebPage = document.forms.<%SPHttpUtility.NoEncode(Form.ClientID,Response.Output);%>;
        try{window.focus();frmWebPage['Title'].focus(); DoTemplateOptionChange();}catch(e){}
        frmWebPage.WebPartPageTemplate.selectedIndex = 0;
        DoTemplateOptionChange();
        }
        

On peut d’ores et déjà tester si tout fonctionne bien en appelant directement l’url de notre page de création sur un site de test : http://site/web/_layouts/customspcf.aspx

image

Résultat :

image

5 Ajout du lien pour accéder à notre page de création

La première méthode simple pour rendre notre page accessible consisterai à modifier la page « create.aspx » qui se trouve toujours dans le même répertoire « Layouts » pour y ajouter le lien à l’endroit voulu. Mais ATTENTION cela n’est pas autorisé, et entrainera immédiatement la perte du support de la part de Microsoft.

Une méthode plus jolie consiste à ajouter une « CustomAction » qui permet de rajouter des éléments aux menus de WSS, comme par exemple dans le menu « SiteActions » qui permet d’accéder à la page de settings et de création, ou encore au menu « New » dans les bibliothèques de documents.

Cependant le déploiement de ces CustomActions nécessite de passer par une « FEATURE ».

Et comme le sujet est vaste sur les customs actions, et d’autant plus sur les features et leur déploiement je vous proposerai en second article les différentes méthodes de déploiement en abordant l’approche manuelle, l’utilisation de Visual studio ou encore l’utilisation de WSPBuilder et SharePointInstaller, deux outils bien pratiques de CodePlex.

En attendant voici quelques exemples de ce qu’on peut obtenir avec les customs actions :

Sur le menu « New » des la bibliothèque de documents :

image

Sur le menu Site Actions :

image

6 Conclusion

L’ajout de modèles supplémentaires est finalement une chose simple en réutilisant un maximum l’existant. Ce n’est pas forcement la méthode la plus belle, mais l’avantage c’est que la réalisation est rapide. La partie la plus longue du travail restant la réalisation des différents modèles, ce qui tient plus du design.

Il nous reste encore à découvrir bien des façons de personnaliser notre intranet :)…

 

Remerciements à Laurent Cotton et à Alexandre Barbier pour leur revue de l’article.

Publié dans SharePoint Tagués avec : , , , , ,

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Verifions que vous êtes un humain * Time limit is exhausted. Please reload CAPTCHA.

Archives

Social

  • Twitter
  • LinkedIn
  • Flux RSS
  • mvp
  • technet
  • Google+