Personnaliser l’expérience SharePoint à l’aide de SharePoint hébergés par un fournisseur

Cet article décrit des exemples qui montrent les meilleures pratiques de personnalisation SharePoint composants UX, y compris les scénarios suivants :

  • Manipulation de page (ajout et modification d’une page Wiki)

  • Affichage des modules et des données dans les boîtes de dialogue modales

  • Création d’éléments d’interface utilisateur personnalisés

  • Rendu côté client (déploiement de fichiers JSLink qui personnalisent le rendu des champs dans SharePoint listes)

  • Manipulation de partie Web Et de partie de add-in (mise en service à distance et exécuter un élément de script de add-in dans un add-in hébergé par un fournisseur)

  • Agrégation et mise en cache des données (à l’aide de stockage local HTML5 et de cookies HTTP pour réduire le nombre d’appels de service SharePoint)

Notes

Le code dans cet article est fourni tel quel, sans garantie d’aucune sorte, expresse ou implicite, y compris mais sans s’y limiter, aucune garantie implicite d’adéquation à un usage particulier, à une qualité marchande ou une absence de contrefaçon.

Manipulation de pages

L’exemple Core.ModifyPages inclut deux scénarios de manipulation de page :

  • Créez une page Wiki.
  • Modifiez la mise en page d’une page Wiki.

Cet exemple utilise la bibliothèque de pages de site par défaut et les dispositions pré-prêts à l’emploi existantes. Vous pouvez également la mettre à jour pour utiliser une bibliothèque de pages Wiki personnalisée et des mises en page personnalisées. L’interface utilisateur du add-in comprend deux boutons qui créent les deux pages Wiki et deux liens pour afficher les pages Wiki que vous créez.

Page de démarrage de l’exemple de manipulation de page

Page de lancement pour l’exemple de manipulation de page


L’exemple de code pour le premier scénario détermine si vous avez déjà créé la page Wiki. Si ce n’est pas le cas, il ajoute le fichier à la bibliothèque de pages du site et renvoie son URL.

var newpage = pageLibrary.RootFolder.Files.AddTemplateFile(newWikiPageUrl, TemplateFileType.WikiPage);
ctx.Load(newpage);
ctx.ExecuteQuery();
wikiPageUrl = String.Format("sitepages/{0}", wikiPageName);

Dans les deux scénarios, l’exemple ajoute le code HTML entré via la zone de texte de la page de démarrage à l’aide de la méthode AddHtmlToWikiPage dans une classe d’aide nommée LabHelper. Cette méthode insère le code HTML à partir du formulaire à l’intérieur du champ WikiField de la page Wiki.

public void AddHtmlToWikiPage(ClientContext ctx, Web web, string folder, string html, string page)
        {
            Microsoft.SharePoint.Client.Folder pagesLib = web.GetFolderByServerRelativeUrl(folder);
            ctx.Load(pagesLib.Files);
            ctx.ExecuteQuery();

            Microsoft.SharePoint.Client.File wikiPage = null;

            foreach (Microsoft.SharePoint.Client.File aspxFile in pagesLib.Files)
            {
                if (aspxFile.Name.Equals(page, StringComparison.InvariantCultureIgnoreCase))
                {
                    wikiPage = aspxFile;
                    break;
                }
            }

            if (wikiPage == null)
            {
                return;
            }

            ctx.Load(wikiPage);
            ctx.Load(wikiPage.ListItemAllFields);
            ctx.ExecuteQuery();

            string wikiField = (string)wikiPage.ListItemAllFields["WikiField"];

            Microsoft.SharePoint.Client.ListItem listItem = wikiPage.ListItemAllFields;
            listItem["WikiField"] = html;
            listItem.Update();
            ctx.ExecuteQuery();
        }

L’exemple de code pour le deuxième scénario crée une nouvelle instance WebPartEntity. Il utilise ensuite des méthodes dans une classe d’aide pour remplir le partie Web Part avec du XML. Le XML affiche une liste de liens promus, y compris les deux et la page d’accueil du référentiel Office 365 http://www.bing.com Developer Patterns and Practices GitHub.

WebPartEntity wp2 = new WebPartEntity();
wp2.WebPartXml = new LabHelper().WpPromotedLinks(linksID, string.Format("{0}/Lists/{1}", 
                                                                Request.QueryString["SPHostUrl"], "Links"), 
                                                                string.Format("{0}/{1}", Request.QueryString["SPHostUrl"], 
                                                                scenario2PageUrl), "$Resources:core,linksList");
wp2.WebPartIndex = 1;
wp2.WebPartTitle = "Links";

new LabHelper().AddWebPartToWikiPage(ctx, ctx.Web, "SitePages", wp2, scenario2Page, 2, 1, false);
new LabHelper().AddHtmlToWikiPage(ctx, ctx.Web, "SitePages", htmlEntry.Text, scenario2Page, 2, 2);

this.hplPage2.NavigateUrl = string.Format("{0}/{1}", Request.QueryString["SPHostUrl"], scenario2PageUrl);

Le code d’aide affiche les liens promus avec une table à l’intérieur d’un élément WebPart XsltListViewWebPart.

Deuxième page Wiki avec XsltListViewWebPart et table liens promus

Deuxième page wiki avec composant XsltListViewWeb et tableau de liens promus


L’objet WpPromotedLinks sur l’instance LabHelper contient du XML qui définit l’apparence du partie Web Qui sera incorporée dans la page Wiki. La méthode AddWebPartToWikiPage insère ensuite le nouveau site WebPart à l’intérieur d’une nouvelle div balise sur la page Wiki.

XmlDocument xd = new XmlDocument();
            xd.PreserveWhitespace = true;
            xd.LoadXml(wikiField);

            // Sometimes the wikifield content seems to be surrounded by an additional div. 
            XmlElement layoutsTable = xd.SelectSingleNode("div/div/table") as XmlElement;
            if (layoutsTable == null)
            {
                layoutsTable = xd.SelectSingleNode("div/table") as XmlElement;
            }

            XmlElement layoutsZoneInner = layoutsTable.SelectSingleNode(string.Format("tbody/tr[{0}]/td[{1}]/div/div", row, col)) as XmlElement;
            // - space element
            XmlElement space = xd.CreateElement("p");
            XmlText text = xd.CreateTextNode(" ");
            space.AppendChild(text);

            // - wpBoxDiv
            XmlElement wpBoxDiv = xd.CreateElement("div");
            layoutsZoneInner.AppendChild(wpBoxDiv);

            if (addSpace)
            {
                layoutsZoneInner.AppendChild(space);
            }

            XmlAttribute attribute = xd.CreateAttribute("class");
            wpBoxDiv.Attributes.Append(attribute);
            attribute.Value = "ms-rtestate-read ms-rte-wpbox";
            attribute = xd.CreateAttribute("contentEditable");
            wpBoxDiv.Attributes.Append(attribute);
            attribute.Value = "false";
            // - div1
            XmlElement div1 = xd.CreateElement("div");
            wpBoxDiv.AppendChild(div1);
            div1.IsEmpty = false;
            attribute = xd.CreateAttribute("class");
            div1.Attributes.Append(attribute);
            attribute.Value = "ms-rtestate-read " + wpdNew.Id.ToString("D");
            attribute = xd.CreateAttribute("id");
            div1.Attributes.Append(attribute);
            attribute.Value = "div_" + wpdNew.Id.ToString("D");
            // - div2
            XmlElement div2 = xd.CreateElement("div");
            wpBoxDiv.AppendChild(div2);
            div2.IsEmpty = false;
            attribute = xd.CreateAttribute("style");
            div2.Attributes.Append(attribute);
            attribute.Value = "display:none";
            attribute = xd.CreateAttribute("id");
            div2.Attributes.Append(attribute);
            attribute.Value = "vid_" + wpdNew.Id.ToString("D");

            ListItem listItem = webPartPage.ListItemAllFields;
            listItem["WikiField"] = xd.OuterXml;
            listItem.Update();
            ctx.ExecuteQuery();

Affichage des modules et des données dans les boîtes de dialogue modales

L’exemple Core.Dialog montre deux méthodes pour incorporer des liens de boîte de dialogue modale. Ces liens affichent une page de add-in hébergée par un fournisseur dans SharePoint site hôte. Le add-in utilise le modèle objet client (CSOM) pour créer l’action personnalisée et JavaScript pour démarrer et afficher des informations à l’intérieur de la boîte de dialogue. Étant donné que certaines de ces informations proviennent du site hôte, elles utilisent également le modèle objet JavaScript (JSOM) pour récupérer des informations à partir du site hôte. Et comme le module est en cours d’exécution dans un domaine différent du site hôte SharePoint, il utilise également la bibliothèque SharePoint pour effectuer les appels vers le site hôte.

Notes

Pour plus d’informations sur l’utilisation de la bibliothèque entre domaines dans ce scénario,voir Access SharePoint à partir de la bibliothèque entre domaines.

La page de démarrage est celle qui apparaît dans la boîte de dialogue. Pour gérer les différences d’affichage en raison du contexte d’affichage (boîte de dialogue et pleine page), le add-in détermine s’il est affiché dans une boîte de dialogue. Pour ce faire, il utilise un paramètre de chaîne de requête qui est transmis avec les liens qui démarrent les boîtes de dialogue.

private string SetIsDlg(string isDlgValue)
        {
            var urlParams = HttpUtility.ParseQueryString(Request.QueryString.ToString());
            urlParams.Set("IsDlg", isDlgValue);
            return string.Format("{0}://{1}:{2}{3}?{4}", Request.Url.Scheme, Request.Url.Host, Request.Url.Port, Request.Url.AbsolutePath, urlParams.ToString());
        }

Vous pouvez, par exemple, choisir d’afficher certains éléments d’interface utilisateur (tels que des boutons) ou même différentes mises en page, selon que le contenu est affiché ou non dans une boîte de dialogue.

L’interface utilisateur de la page de démarrage présente deux options pour créer des liens vers la boîte de dialogue, ainsi qu’une liste de toutes les listes sur le site web hôte. Il présente également les boutons OK et Annuler que vous pouvez utiliser dans le contexte de la boîte de dialogue pour fermer la boîte de dialogue et/ou inviter des actions supplémentaires dans le complément.

Lorsque vous choisissez le bouton Ajouter un élément de menu, le add-in crée un objet CustomActionEntity qui démarre la boîte de dialogue. Il utilise ensuite la méthode d’extension OfficeDevPnP Core nommée AddCustomAction pour ajouter la nouvelle action personnalisée au menu Site Paramètres.

StringBuilder modelDialogScript = new StringBuilder(10);
modelDialogScript.Append("javascript:var dlg=SP.UI.ModalDialog.showModalDialog({url: '");
modelDialogScript.Append(String.Format("{0}", SetIsDlg("1")));
modelDialogScript.Append("', dialogReturnValueCallback:function(res, val) {} });");       

// Create a custom action.
CustomActionEntity customAction = new CustomActionEntity()
{
  Title = "Office AMS Dialog sample",                
  Description = "Shows how to start an add-in inside a dialog box.",
  Location = "Microsoft.SharePoint.StandardMenu",
  Group = "SiteActions",
  Sequence = 10000,
  Url = modelDialogScript.ToString(),
};

// Add the custom action to the site.
cc.Web.AddCustomAction(customAction);

La méthode AddCustomAction ajoute l’action personnalisée à la collection UserCustomActions associée au site SharePoint site.

var newAction = existingActions.Add();
            newAction.Description = customAction.Description;
            newAction.Location = customAction.Location;
            if (customAction.Location == JavaScriptExtensions.SCRIPT_LOCATION)
            {
                newAction.ScriptBlock = customAction.ScriptBlock;
            }
            else
            {
                newAction.Sequence = customAction.Sequence;
                newAction.Url = customAction.Url;
                newAction.Group = customAction.Group;
                newAction.Title = customAction.Title;
                newAction.ImageUrl = customAction.ImageUrl;
                if (customAction.Rights != null)
                {
                    newAction.Rights = customAction.Rights;
                }
            }
            newAction.Update();
            web.Context.Load(web, w => w.UserCustomActions);
            web.Context.ExecuteQuery();

Lorsque vous choisissez le bouton Ajouter une page avec un éditeur de script, le add-in utilise les méthodes AddWikiPage et AddWebPartToWikiPage pour créer une page Wiki à l’intérieur de la bibliothèque de pages du site et ajouter un élément WebPart Éditeur de script configuré à la page.

string scenario1Page = String.Format("scenario1-{0}.aspx", DateTime.Now.Ticks);
string scenario1PageUrl = cc.Web.AddWikiPage("Site Pages", scenario1Page);
cc.Web.AddLayoutToWikiPage("SitePages", WikiPageLayout.OneColumn, scenario1Page);
WebPartEntity scriptEditorWp = new WebPartEntity();
scriptEditorWp.WebPartXml = ScriptEditorWebPart();
scriptEditorWp.WebPartIndex = 1;
scriptEditorWp.WebPartTitle = "Script editor test"; 
cc.Web.AddWebPartToWikiPage("SitePages", scriptEditorWp, scenario1Page, 1, 1, false);

La méthode AddWikiPage charge la bibliothèque de pages du site. Si la page Wiki spécifiée par le add-in OfficeDevPnP Core n’existe pas déjà, elle crée la page.

public static string AddWikiPage(this Web web, string wikiPageLibraryName, string wikiPageName)
        {
            string wikiPageUrl = "";


            var pageLibrary = web.Lists.GetByTitle(wikiPageLibraryName);

            web.Context.Load(pageLibrary.RootFolder, f => f.ServerRelativeUrl);
            web.Context.ExecuteQuery();

            var pageLibraryUrl = pageLibrary.RootFolder.ServerRelativeUrl;
            var newWikiPageUrl = pageLibraryUrl + "/" + wikiPageName;

            var currentPageFile = web.GetFileByServerRelativeUrl(newWikiPageUrl);

            web.Context.Load(currentPageFile, f => f.Exists);
            web.Context.ExecuteQuery();

            if (!currentPageFile.Exists)
            {
                var newpage = pageLibrary.RootFolder.Files.AddTemplateFile(newWikiPageUrl, TemplateFileType.WikiPage);

                web.Context.Load(newpage);
                web.Context.ExecuteQuery();

                wikiPageUrl = UrlUtility.Combine("sitepages", wikiPageName);
            }

            return wikiPageUrl;
        }

La méthode AddWebPartToWikiPage insère le nouveau site WebPart à l’intérieur d’une nouvelle <div> balise sur la page Wiki. Il utilise ensuite le JSOM et la bibliothèque entre domaines pour récupérer les informations qui remplit la liste des listes SharePoint sur le site web hôte.

function printAllListNamesFromHostWeb() {
        var context;
        var factory;
        var appContextSite;
        var collList;

        context = new SP.ClientContext(appWebUrl);
        factory = new SP.ProxyWebRequestExecutorFactory(appWebUrl);
        context.set_webRequestExecutorFactory(factory);
        appContextSite = new SP.AppContextSite(context, spHostUrl);

        this.web = appContextSite.get_web();
        collList = this.web.get_lists();
        context.load(collList);

        context.executeQueryAsync(
            Function.createDelegate(this, successHandler),
            Function.createDelegate(this, errorHandler)
        );

Éléments d’interface utilisateur personnalisés

L’exemple Branding.UIElementPersonalization montre comment utiliser javaScript incorporé et les valeurs stockées dans les profils utilisateur et les listes SharePoint pour personnaliser les éléments d’interface utilisateur sur le site web hôte. Il utilise également le stockage local HTML5 pour minimiser les appels au site hôte.

La page de démarrage de l’exemple vous invite à ajouter l’une des trois chaînes (XX, AA ou ZZ) à la section À propos de moi de votre page de profil utilisateur.

Le complément a déjà déployé trois images et une liste SharePoint qui contient des titres et des URL pour chaque image, ainsi qu’un champ supplémentaire qui lie chaque image à l’une des trois chaînes. Une fois que vous avez choisi le bouton De personnalisation Inject, le add-in incorpore le fichier personalize.js dans la collection d’actions personnalisées de l’utilisateur.

public void AddPersonalizeJsLink(ClientContext ctx, Web web)
        {
            string scenarioUrl = String.Format("{0}://{1}:{2}/Scripts", this.Request.Url.Scheme,
                                                this.Request.Url.DnsSafeHost, this.Request.Url.Port);
            string revision = Guid.NewGuid().ToString().Replace("-", "");
            string personalizeJsLink = string.Format("{0}/{1}?rev={2}", scenarioUrl, "personalize.js", revision);

            StringBuilder scripts = new StringBuilder(@"
                var headID = document.getElementsByTagName('head')[0]; 
                var");

            scripts.AppendFormat(@"
                newScript = document.createElement('script');
                newScript.type = 'text/javascript';
                newScript.src = '{0}';
                headID.appendChild(newScript);", personalizeJsLink);
            string scriptBlock = scripts.ToString();

            var existingActions = web.UserCustomActions;
            ctx.Load(existingActions);
            ctx.ExecuteQuery();

            var actions = existingActions.ToArray();
            foreach (var action in actions)
            {
                if (action.Description == "personalize" &amp;&amp;
                    action.Location == "ScriptLink")
                {
                    action.DeleteObject();
                    ctx.ExecuteQuery();
                }
            }

            var newAction = existingActions.Add();
            newAction.Description = "personalize";
            newAction.Location = "ScriptLink";
            
            newAction.ScriptBlock = scriptBlock;
            newAction.Update();
            ctx.Load(web, s => s.UserCustomActions);
            ctx.ExecuteQuery();
        }

Comme SharePoint sites d’équipe utilisent par défaut la stratégie de téléchargement minimal (MDS),le code du fichier personalize.js tente d’abord de s’inscrire auprès de MDS. Ainsi, lorsque vous chargez la page qui contient le javaScript, le moteur MDS démarre la fonction principale (RemoteManager_Inject). Si MDS est désactivé, cette fonction démarre immédiatement.

// Register script for MDS, if possible.
RegisterModuleInit("personalize.js", RemoteManager_Inject); //MDS registration
RemoteManager_Inject(); //non-MDS run

if (typeof (Sys) != "undefined" &amp;&amp; Boolean(Sys) &amp;&amp; Boolean(Sys.Application)) {
    Sys.Application.notifyScriptLoaded();h
}

if (typeof (NotifyScriptLoadedAndExecuteWaitingJobs) == "function") {
    NotifyScriptLoadedAndExecuteWaitingJobs("scenario1.js");
}
// The RemoteManager_Inject function is the entry point for loading the other scripts that perform the customizations. When a given script depends on another script, be sure to load the dependent script after the one on which it depends. This sample loads the JQuery library before the personalizeIt function that uses JQuery.
function RemoteManager_Inject() {

    var jQuery = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.2.min.js";

    // Load jQuery. 
    loadScript(jQuery, function () {

        personalizeIt();

    });
}

La fonction personalizeIt() vérifie le stockage local HTML5 avant de vérifier les informations de profil utilisateur. S’il est rendu aux informations de profil utilisateur, il stocke les informations qu’il récupère dans le stockage local HTML5.

function personalizeIt() {
    clientContext = SP.ClientContext.get_current();

    var fileref = document.createElement('script');
    fileref.setAttribute("type", "text/javascript");
    fileref.setAttribute("src", "/_layouts/15/SP.UserProfiles.js");
    document.getElementsByTagName("head")[0].appendChild(fileref);

    SP.SOD.executeOrDelayUntilScriptLoaded(function () {        

        // Get localstorage values if they exist.
        buCode = localStorage.getItem("bucode");
        buCodeTimeStamp = localStorage.getItem("buCodeTimeStamp");

        // Determine whether the page already has embedded personalized image.
        var pageTitle = $('#pageTitle')[0].innerHTML;
        if (pageTitle.indexOf("img") > -1) {
            personalized = true;
        }
        else {
            personalized = false;
        }        

        // If nothing is in localstorage, get profile data, which will also populate localstorage.
        if (buCode == "" || buCode == null) {
            getProfileData(clientContext);
            personalized = false;
        }
        else {
            // Check for expiration.            
            if (isKeyExpired("buCodeTimeStamp")) {                
                getProfileData(clientContext);

                if (buCode != "" || buCode != null) {
                    // Set timestamp for expiration.
                    currentTime = Math.floor((new Date().getTime()) / 1000);
                    localStorage.setItem("buCodeTimeStamp", currentTime);

                    // Set personalized to false so that the code can check for a new image in case buCode was updated.
                    personalized = false;
                }
            }            
        }

        // Load image or make sure it is current based on the value in AboutMe.
        if (!personalized) {
            loadPersonalizedImage(buCode);
        }


    }, 'SP.UserProfiles.js');
}

Le personalize.js contient également du code qui vérifie si la clé de stockage local a expiré. Il n’est pas intégré au stockage local HTML5.

// Check to see if the key has expired
function isKeyExpired(TimeStampKey) {

    // Retrieve the example setting for expiration in seconds.
    var expiryStamp = localStorage.getItem(TimeStampKey);

    if (expiryStamp != null &amp;&amp; cacheTimeout != null) {

        // Retrieve the timestamp and compare against specified cache timeout settings to see if it is expired.
        var currentTime = Math.floor((new Date().getTime()) / 1000);

        if (currentTime - parseInt(expiryStamp) > parseInt(cacheTimeout)) {
            return true; //Expired
        }
        else {
            return false;
        }
    }
    else {
        //default 
        return true;
    }
}

Affichage côté client

L’exemple Branding.ClientSideRendering montre comment utiliser un add-in hébergé par un fournisseur pour mettre en service à distance des artefacts SharePoint et des fichiers JSLink qui utilisent le rendu côté client pour personnaliser l’apparence et le comportement des champs de liste SharePoint. Les fichiers JSLink et le rendu côté client vous donnent le contrôle sur le rendu des contrôles sur une page SharePoint (affichages de liste, champs de liste et formulaires d’ajout et de modification). Ce contrôle peut réduire ou éliminer la nécessité de types de champs personnalisés. Le rendu côté client permet de contrôler à distance l’apparence des champs de liste à distance.

L’exemple combine les exemples JSLink des exemples de code de rendu côté client (JSLink) dans un seul et même application hébergée par un fournisseur pour SharePoint qui a mis en service les fichiers JSLink. Le rendu côté client vous permet d’utiliser des technologies web standard, telles que HTML et JavaScript, pour définir la logique de rendu des types de champs personnalisés et prédéfini.

Lorsque vous démarrez l’exemple, la page de démarrage vous invite à mettre en service tous les exemples.

Page de démarrage de l’exemple de rendu côté client

Page de lancement de l’échantillon de rendu côté client

Lorsque vous choisissez Exemples de mise en service, le add-in déploie une image ainsi que toutes les listes SharePoint, affichages de liste, éléments de liste, formulaires et fichiers JavaScript utilisés dans chaque exemple. Le add-in crée un dossier nommé JSLink-Samples dans la bibliothèque de styles, puis télécharge les fichiers JavaScript dans ce dossier. La méthode UploadFileToFolder s’charge du chargement et de l’enregistrement de chaque fichier JavaScript.

public static void UploadFileToFolder(Web web, string filePath, Folder folder)
        {
            using (FileStream fs = new FileStream(filePath, FileMode.Open))
            {
                FileCreationInformation flciNewFile = new FileCreationInformation();

                flciNewFile.ContentStream = fs;
                flciNewFile.Url = System.IO.Path.GetFileName(filePath);
                flciNewFile.Overwrite = true;

                Microsoft.SharePoint.Client.File uploadFile = folder.Files.Add(flciNewFile);
                uploadFile.CheckIn("CSR sample js file", CheckinType.MajorCheckIn);

                folder.Context.Load(uploadFile);
                folder.Context.ExecuteQuery();
            }
        }

Exemple 1 : Appliquer une mise en forme à une colonne de liste

L’exemple 1 montre comment appliquer une mise en forme à une colonne de liste en fonction de la valeur du champ. Les valeurs de champ de priorité 1 (élevée), 2 (normale) et 3 (faible) sont affichées en rouge, orange et jaune.

Affichage des champs de liste personnalisée

Affichage des champs de liste personnalisée

JavaScript suivant remplace l’affichage de champ par défaut et crée un modèle d’affichage pour le champ de liste Priorité. La technique dans la fonction anonyme qui charge les informations contextuelles sur le champ dont vous souhaitez remplacer l’affichage est utilisée dans tous les exemples.

(function () {

    // Create object that has the context information about the field that you want to render differently.
    var priorityFiledContext = {};
    priorityFiledContext.Templates = {};
    priorityFiledContext.Templates.Fields = {
        // Apply the new rendering for Priority field in List View.
        "Priority": { "View": priorityFiledTemplate }
    };

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(priorityFiledContext);

})();

// This function provides the rendering logic for list view.
function priorityFiledTemplate(ctx) {

    var priority = ctx.CurrentItem[ctx.CurrentFieldSchema.Name];

    // Return HTML element with appropriate color based on the Priority column's value.
    switch (priority) {
        case "(1) High":
            return "<span style='color :#f00'>" + priority + "</span>";
            break;
        case "(2) Normal":
            return "<span style='color :#ff6a00'>" + priority + "</span>";
            break;
        case "(3) Low":
            return "<span style='color :#cab023'>" + priority + "</span>";
    }
}

Exemple 2 : Raccourcir le texte long

L’exemple 2 vous montre comment tronque le texte long stocké dans le champ Corps d’une liste Annonces. Le texte intégral s’affiche sous la mesure d’une fenêtre popup qui s’affiche chaque fois que vous pointez sur un élément de liste, comme illustré dans la figure suivante.

Affichage de champ de liste raccourci affichant une fenêtre popup

Affichage des champs de liste tronqués avec le menu contextuel

Le javaScript suivant raccourcit le texte du champ Corps et fait apparaître le texte intégral sous la forme d’une fenêtre popup via l’attribut de titre sur la balise span.

function bodyFiledTemplate(ctx) {

    var bodyValue = ctx.CurrentItem[ctx.CurrentFieldSchema.Name];

    // This regex expression is used to delete HTML tags from the Body field.
    var regex = /(<([^>]+)>)/ig;

    bodyValue = bodyValue.replace(regex, "");

    var newBodyValue = bodyValue;

    if (bodyValue &amp;&amp; bodyValue.length >= 100)
    {
        newBodyValue = bodyValue.substring(0, 100) + " ...";
    }

    return "<span title='" + bodyValue + "'>" + newBodyValue + "</span>";

}

Exemple 3 : Afficher une image avec un nom de document

L’exemple 3 vous montre comment afficher une image à côté d’un nom de document dans une bibliothèque de documents. Un badge rouge s’affiche chaque fois que la valeur du champ Confidentiel est définie sur Oui.

Image affichée en regard du nom du document

Image affichée en regard du nom du document

JavaScript suivant vérifie la valeur du champ Confidentiel, puis personnalise l’affichage du champ Nom en fonction de la valeur d’un autre champ. L’exemple utilise l’image qui est téléchargée lorsque vous choisissez Exemples de mise en service.

function linkFilenameFiledTemplate(ctx) {

    var confidential = ctx.CurrentItem["Confidential"];
    var title = ctx.CurrentItem["FileLeafRef"];

    // This Regex expression is used to delete the extension (.docx, .pdf ...) from the file name.
    title = title.replace(/\.[^/.]+$/, "")

    // Check confidential field value.
    if (confidential &amp;&amp; confidential.toLowerCase() == 'yes') {
        // Render HTML that contains the file name and the confidential icon.
        return title + "&amp;nbsp;<img src= '" + _spPageContextInfo.siteServerRelativeUrl + "/Style%20Library/JSLink-Samples/imgs/Confidential.png' alt='Confidential Document' title='Confidential Document'/>";
    }
    else
    {
        return title;
    }
}

Exemple 4 : Afficher un graphique à barres

L’exemple 4 vous montre comment afficher un graphique à barres dans le champ % Achevé d’une liste de tâches. L’apparence du graphique à barres dépend de la valeur du champ % Achevé, comme illustré dans la figure suivante. Notez qu’un graphique à barres apparaît également dans les formulaires de création et de modification d’éléments de liste de tâches.

Diagramme à barres affiché dans le champ « % effectué »

Diagramme à barres affiché dans le champ « % effectué »

Le code suivant crée l’affichage du graphique à barres et l’associe aux formulaires d’affichage et d’affichage (percentCompleteViewFiledTemplate), puis aux formulaires nouveaux et de modification (percentCompleteEditFiledTemplate).

// This function provides the rendering logic for View and Display forms.
function percentCompleteViewFiledTemplate(ctx) {

    var percentComplete = ctx.CurrentItem[ctx.CurrentFieldSchema.Name];
    return "<div style='background-color: #e5e5e5; width: 100px;  display:inline-block;'> \
            <div style='width: " + percentComplete.replace(/\s+/g, '') + "; background-color: #0094ff;'> \
            &amp;nbsp;</div></div>&amp;nbsp;" + percentComplete;

}

// This function provides the rendering logic for New and Edit forms.
function percentCompleteEditFiledTemplate(ctx) {

    var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);

    // Register a callback just before submit.
    formCtx.registerGetValueCallback(formCtx.fieldName, function () {
        return document.getElementById('inpPercentComplete').value;
    });

    return "<input type='range' id='inpPercentComplete' name='inpPercentComplete' min='0' max='100' \
            oninput='outPercentComplete.value=inpPercentComplete.value' value='" + formCtx.fieldValue + "' /> \
            <output name='outPercentComplete' for='inpPercentComplete' >" + formCtx.fieldValue + "</output>%";
}

Exemple 5 : Modifier le modèle de rendu

L’exemple 5 vous montre comment modifier le modèle de rendu d’un affichage de liste. Cet affichage affiche les titres d’éléments de liste qui se développent comme des accordéons lorsque vous les sélectionnez. La vue étendue vous montre des champs d’élément de liste supplémentaires.

Vues des éléments dans les listes développées et réduites

Vues des éléments dans les listes développées et réduites

Le code suivant définit le modèle et l’enregistre avec le modèle de liste. Il définit la disposition globale, puis utilise le handler d’événements OnPostRender pour inscrire la fonction JavaScript qui s’exécute lorsque la liste est rendue. Cette fonction associe l’événement au CSS et à la gestion des événements qui implémente la fonctionnalité accordéon.

(function () {

    // jQuery library is required in this sample.
    // Fallback to loading jQuery from a CDN path if the local is unavailable.
    (window.jQuery || document.write('<script src="//ajax.aspnetcdn.com/ajax/jquery/jquery-1.10.0.min.js"><\/script>'));

    // Create object that has the context information about the field that you want to render differently.
    var accordionContext = {};
    accordionContext.Templates = {};

    // Be careful when adding the header for the template, because it will break the default list view render.
    accordionContext.Templates.Header = "<div class='accordion'>";
    accordionContext.Templates.Footer = "</div>";

    // Add OnPostRender event handler to add accordion click events and style.
    accordionContext.OnPostRender = accordionOnPostRender;

    // This line of code tells the TemplateManager that you want to change all the HTML for item row rendering.
    accordionContext.Templates.Item = accordionTemplate;

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(accordionContext);

})();

// This function provides the rendering logic.
function accordionTemplate(ctx) {
    var title = ctx.CurrentItem["Title"];
    var description = ctx.CurrentItem["Description"];

    // Return whole item html.
    return "<h2>" + title + "</h2><p>" + description + "</p><br/>";
}

function accordionOnPostRender() {

    // Register event to collapse and expand when selecting accordion header.
    $('.accordion h2').click(function () {
        $(this).next().slideToggle();
    }).next().hide();

    $('.accordion h2').css('cursor', 'pointer');
}

Exemple 6 : Valider les valeurs de champ

L’exemple 6 vous montre comment utiliser des expressions régulières pour valider les valeurs de champ fournies par l’utilisateur. Un message d’erreur rouge s’affiche lorsque l’utilisateur tape une adresse de messagerie non valide dans la zone de texte du champ Courrier électronique. Cela se produit lorsque l’utilisateur crée ou modifie un élément de liste.

Message d’erreur affiché en cas de saisie d’un texte non valide dans un champ

Message d’erreur affiché en cas de saisie d’un texte non valide dans un champ

Le code suivant définit le modèle avec un espace réservé pour afficher le message d’erreur et inscrit les fonctions de rappel qui se déclenchent chaque fois que l’utilisateur tente d’envoyer les formulaires. Le premier rappel renvoie la valeur de la colonne Email et le second utilise des expressions régulières pour valider la valeur de chaîne.

function emailFiledTemplate(ctx) {

    var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);

    // Register a callback just before submit.
    formCtx.registerGetValueCallback(formCtx.fieldName, function () {
        return document.getElementById('inpEmail').value;
    });

    // Create container for various validations.
    var validators = new SPClientForms.ClientValidation.ValidatorSet();
    validators.RegisterValidator(new emailValidator());

    // Validation failure handler.
    formCtx.registerValidationErrorCallback(formCtx.fieldName, emailOnError);

    formCtx.registerClientValidator(formCtx.fieldName, validators);

    return "<span dir='none'><input type='text' value='" + formCtx.fieldValue + "'  maxlength='255' id='inpEmail' class='ms-long'> \
            <br><span id='spnError' class='ms-formvalidation ms-csrformvalidation'></span></span>";
}

// Custom validation object to validate email format.
emailValidator = function () {
    emailValidator.prototype.Validate = function (value) {
        var isError = false;
        var errorMessage = "";

        //Email format Regex expression
        var emailRejex = /\S+@\S+\.\S+/;

        if (!emailRejex.test(value) &amp;&amp; value.trim()) {
            isError = true;
            errorMessage = "Invalid email address";
        }

        // Send error message to error callback function (emailOnError).
        return new SPClientForms.ClientValidation.ValidationResult(isError, errorMessage);
    };
};

// Add error message to spnError element under the input field element.
function emailOnError(error) {
    document.getElementById("spnError").innerHTML = "<span role='alert'>" + error.errorMessage + "</span>";
}

Exemple 7 : Faire en sorte que les champs de modification d’élément de liste sont en lecture seule

L’exemple 7 vous montre comment faire en sorte que les champs de formulaire de modification d’élément de liste sont en lecture seule. Les champs en lecture seule s’affiche sans contrôle d’édition.

Champ en lecture seule sur un formulaire de modification de liste personnalisé

Champs en lecture seule dans un formulaire de modification de liste personnalisée

L’exemple de code suivant modifie les champs Title, AssignedTo et Priority dans le formulaire de modification d’élément de liste afin qu’ils n’indiquent les valeurs de champ qu’avec aucun contrôle d’édition. Le code indique comment gérer les exigences d’une recherche pour différents types de champs.

function readonlyFieldTemplate(ctx) {

    // Reuse SharePoint JavaScript libraries.
    switch (ctx.CurrentFieldSchema.FieldType) {
        case "Text":
        case "Number":
        case "Integer":
        case "Currency":
        case "Choice":
        case "Computed":
            return SPField_FormDisplay_Default(ctx);

        case "MultiChoice":
            prepareMultiChoiceFieldValue(ctx);
            return SPField_FormDisplay_Default(ctx);

        case "Boolean":
            return SPField_FormDisplay_DefaultNoEncode(ctx);

        case "Note":
            prepareNoteFieldValue(ctx);
            return SPFieldNote_Display(ctx);

        case "File":
            return SPFieldFile_Display(ctx);

        case "Lookup":
        case "LookupMulti":
                return SPFieldLookup_Display(ctx);           

        case "URL":
            return RenderFieldValueDefault(ctx);

        case "User":
            prepareUserFieldValue(ctx);
            return SPFieldUser_Display(ctx);

        case "UserMulti":
            prepareUserFieldValue(ctx);
            return SPFieldUserMulti_Display(ctx);

        case "DateTime":
            return SPFieldDateTime_Display(ctx);

        case "Attachments":
            return SPFieldAttachments_Default(ctx);

        case "TaxonomyFieldType":
            //Re-use JavaScript from the sp.ui.taxonomy.js SharePoint JavaScript library.
            return SP.UI.Taxonomy.TaxonomyFieldTemplate.renderDisplayControl(ctx);
    }
}

// User control needs specific formatted value to render content correctly.
function prepareUserFieldValue(ctx) {
    var item = ctx['CurrentItem'];
    var userField = item[ctx.CurrentFieldSchema.Name];
    var fieldValue = "";

    for (var i = 0; i < userField.length; i++) {
        fieldValue += userField[i].EntityData.SPUserID + SPClientTemplates.Utility.UserLookupDelimitString + userField[i].DisplayText;

        if ((i + 1) != userField.length) {
            fieldValue += SPClientTemplates.Utility.UserLookupDelimitString
        }
    }

    ctx["CurrentFieldValue"] = fieldValue;
}

// Choice control needs specific formatted value to render content correctly.
function prepareMultiChoiceFieldValue(ctx) {

    if (ctx["CurrentFieldValue"]) {
        var fieldValue = ctx["CurrentFieldValue"];

        var find = ';#';
        var regExpObj = new RegExp(find, 'g');

        fieldValue = fieldValue.replace(regExpObj, '; ');
        fieldValue = fieldValue.replace(/^; /g, '');
        fieldValue = fieldValue.replace(/; $/g, '');

        ctx["CurrentFieldValue"] = fieldValue;
    }
}

// Note control needs specific formatted value to render content correctly.
function prepareNoteFieldValue(ctx) {

    if (ctx["CurrentFieldValue"]) {
        var fieldValue = ctx["CurrentFieldValue"];
        fieldValue = "<div>" + fieldValue.replace(/\n/g, '<br />'); + "</div>";

        ctx["CurrentFieldValue"] = fieldValue;
    }
} 

Exemple 8 : Masquer les champs

L’exemple 8 vous montre comment masquer des champs dans les nouveaux formulaires d’élément de liste et les modifier. L’exemple masque le champ Prédécesseurs lorsqu’un utilisateur crée ou modifie un élément de liste de tâches.

Cet exemple est déployé en tant que formulaire de modification et de nouveau formulaire pour une liste appelée liste CSR-Hide-Controls. Pour plus d’informations sur l’affichage du formulaire après le déploiement de l’exemple, voir Branding.ClientSideRendering.

Le code suivant recherche le champ Predecessors dans le code HTML du formulaire et le masque. Le champ reste présent dans le code HTML, mais l’utilisateur ne peut pas le voir dans le navigateur.

(function () {

    // jQuery library is required in this sample.
    // Fallback to loading jQuery from a CDN path if the local is unavailable.
    (window.jQuery || document.write('<script src="//ajax.aspnetcdn.com/ajax/jquery/jquery-1.10.0.min.js"><\/script>'));

    // Create object that has the context information about the field that we want to render differently.
    var hiddenFiledContext = {};
    hiddenFiledContext.Templates = {}; 
    hiddenFiledContext.Templates.OnPostRender = hiddenFiledOnPreRender;
    hiddenFiledContext.Templates.Fields = {
        // Apply the new rendering for Predecessors field in New and Edit forms.
        "Predecessors": {
            "NewForm": hiddenFiledTemplate,
            "EditForm": hiddenFiledTemplate
        }
    };

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(hiddenFiledContext);

})();


// This function provides the rendering logic.
function hiddenFiledTemplate() {
    return "<span class='csrHiddenField'></span>";
}

// This function provides the rendering logic.
function hiddenFiledOnPreRender(ctx) {
    jQuery(".csrHiddenField").closest("tr").hide();
}

Manipulation de partie Web Et de partie de add-in

L’exemple Core.AppScriptPart montre comment utiliser des composants de script de SharePoint pour incorporer des scripts en cours d’exécution dans un SharePoint fournisseur. Cet exemple montre comment modifier l’interface utilisateur d’une page sur le site hôte en déployant un élément de script de add-in et en l’ajoutant à une page SharePoint à partir de la galerie de sites Web.

Un élément de script de add-in est comme un élément WebPart dans la façon dont vous pouvez l’ajouter à une page SharePoint à partir de la galerie de sites WebPart, mais dans ce cas, le fichier .webpart incorpore un fichier JavaScript qui s’exécute à distance dans un add-in hébergé par un fournisseur. Le composant de script de composant de script de add-in s’exécute à l’intérieur d’une balise sur la page SharePoint et offre par conséquent une conception et une expérience plus réactives qu’avec les composants de composants de modules qui s’exécutent dans des <div> IFrames.

La page de démarrage inclut un bouton Scénario d’exécuter qui déploie le script de la partie de l’application dans la galerie de sites Web. L’exemple de code suivant construit une instance FileCreationInformationObject qui contient le contenu du fichier .webpart, puis télécharge le nouveau fichier dans la galerie de parties WebPart. Notez que vous pouvez également exécuter ce code automatiquement lors de l’installation du partie de add-in ou dans le cadre du processus de mise en service de la collection de sites.

var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);
using (var clientContext = spContext.CreateUserClientContextForSPHost())
{
    var folder = clientContext.Web.Lists.GetByTitle("Web Part Gallery").RootFolder;
    clientContext.Load(folder);
    clientContext.ExecuteQuery();

    // Upload the OneDrive for Business Usage Guidelines.docx.
    using (var stream = System.IO.File.OpenRead(Server.MapPath("~/userprofileinformation.webpart")))
    {
        FileCreationInformation fileInfo = new FileCreationInformation();
        fileInfo.ContentStream = stream;
        fileInfo.Overwrite = true;
        fileInfo.Url = "userprofileinformation.webpart";
        File file = folder.Files.Add(fileInfo);
        clientContext.ExecuteQuery();
    }

    // Update the group for uploaded web part.
    var list = clientContext.Web.Lists.GetByTitle("Web Part Gallery");
    CamlQuery camlQuery = CamlQuery.CreateAllItemsQuery(100);
    Microsoft.SharePoint.Client.ListItemCollection items = list.GetItems(camlQuery);
    clientContext.Load(items);
    clientContext.ExecuteQuery();
    foreach (var item in items)
    {
        // Random group name to differentiate it from the rest.
        if (item["FileLeafRef"].ToString().ToLowerInvariant() == "userprofileinformation.webpart")
        {
            item["Group"] = "add-in Script Part";
            item.Update();
            clientContext.ExecuteQuery();
        }
    }

    lblStatus.Text = string.Format("add-in script part has been added to Web Part Gallery. You can find 'User Profile Information' script part under 'Add-in Script Part' group in the <a href='{0}'>host web</a>.", spContext.SPHostUrl.ToString());
}

Une fois que vous avez terminé cette étape, vous pouvez localiser le partie de script du module complémentaire Informations sur le profil utilisateur à l’intérieur d’une nouvelle catégorie de partie de script de add-in dans la galerie de sites Web. Une fois que vous avez ajouté le script de la partie du module complémentaire à la page, l’exécution à distance de JavaScript contrôle l’affichage des informations sur la page.

Lorsque vous affichez le script de la partie de l’outil en mode édition, vous voyez qu’il incorpore le fichier JavaScript en cours d’exécution à distance. Le script userprofileinformation.js utilise le JSON pour obtenir des informations de profil utilisateur à partir du site hôte.

function sharePointReady() {
  clientContext = SP.ClientContext.get_current();

  var fileref = document.createElement('script');
  fileref.setAttribute("type", "text/javascript");
  fileref.setAttribute("src", "/_layouts/15/SP.UserProfiles.js");
  document.getElementsByTagName("head")[0].appendChild(fileref);

  SP.SOD.executeOrDelayUntilScriptLoaded(function () {

    //Get Instance of People Manager Class.       
    var peopleManager = new SP.UserProfiles.PeopleManager(clientContext);

    //Get properties of the current user.
    userProfileProperties = peopleManager.getMyProperties();
    clientContext.load(userProfileProperties);
    clientContext.executeQueryAsync(Function.createDelegate(this, function (sender, args) {
      var firstname = userProfileProperties.get_userProfileProperties()['FirstName'];
      var name = userProfileProperties.get_userProfileProperties()['PreferredName'];
      var title = userProfileProperties.get_userProfileProperties()['Title'];
      var aboutMe = userProfileProperties.get_userProfileProperties()['AboutMe'];
      var picture = userProfileProperties.get_userProfileProperties()['PictureURL'];

      var html = "<div><h2>Welcome " + firstname + "</h2></div><div><div style='float: left; margin-left:10px'><img style='float:left;margin-right:10px' src='" + picture + "' /><b>Name</b>: " + name + "<br /><b>Title</b>: " + title + "<br />" + aboutMe + "</div></div>";

      document.getElementById('UserProfileAboutMe').innerHTML = html;
    }), Function.createDelegate(this, function (sender, args) {
      console.log('The following error has occurred while loading user profile property: ' + args.get_message());
    }));
  }, 'SP.UserProfiles.js');
}

Mise en service des fonctionnalités de publication

L’exemple Provisioning.PublishingFeatures montre comment effectuer des tâches courantes avec des sites de publication hébergés sur Office 365; par exemple, la mise en service et l’utilisation de mises en page, de pages maîtres et de thèmes, ou l’incorporation de JavaScript dans les mises en page. Il montre également comment appliquer des filtres qui contrôlent les modèles de site disponibles pour les sous-sites et les mises en page disponibles sur le site web hôte.

Le add-in hébergé par un fournisseur utilise le modèle CSOM pour mettre en service des éléments d’interface utilisateur couramment utilisés sur les sites de publication, et utilise JavaScript pour créer des expériences plus dynamiques dans les mises en page que vous pouvez déployer sur des sites de publication. Il montre également les différences entre l’utilisation de pages maîtres et de thèmes dans les sites de publication.

Important

Pour que les fonctionnalités de cet exemple fonctionnent, vous devez activer les fonctionnalités de publication sur votre site. Pour plus d’informations, voir Activer les fonctionnalités de publication.

L’exemple de page de démarrage vous présente trois scénarios de personnalisation de l’interface utilisateur des sites de publication :

  • Déployer des mises en page.
  • Déployer des pages maîtres et des thèmes.
  • Filtrez les mises en page disponibles et les modèles de site sur le site hôte.

Scénario 1 : déployer des pages

Le scénario 1 vous montre comment déployer une mise en page personnalisée. Le bouton Déployer les mises en page illustré dans la figure suivante crée une mise en page et une page qui utilise cette mise en page.

Bouton pour déployer des mises en page

Bouton qui déploie les mises en page

Vous pouvez afficher la nouvelle page en allant à la page de démonstration nouvellement créée sur votre site hôte, qui contient javaScript incorporé et affiche les informations de profil utilisateur.

L’exemple affiche les informations de cet utilisateur sur la page. Il ajoute également une page, bien que dans ce cas, elle utilise un objet PublishingPageInformation pour créer la nouvelle page.

L’exemple ajoute une nouvelle mise en page en téléchargeant un fichier dans la galerie de pages maîtres et en lui attribuant le type de contenu de mise en page. Le code suivant prend le chemin d’accès à un fichier *.aspx (que vous pouvez déployer en tant que ressource dans votre projet Visual Studio) et l’ajoute en tant que mise en page dans la galerie de pages maîtres.

// Get the path to the file that you are about to deploy.
            List masterPageGallery = web.GetCatalog((int)ListTemplateType.MasterPageCatalog);
            Folder rootFolder = masterPageGallery.RootFolder;
            web.Context.Load(masterPageGallery);
            web.Context.Load(rootFolder);
            web.Context.ExecuteQuery();

            var fileBytes = System.IO.File.ReadAllBytes(sourceFilePath);

            // Use CSOM to upload the file.
            FileCreationInformation newFile = new FileCreationInformation();
            newFile.Content = fileBytes;
            newFile.Url = UrlUtility.Combine(rootFolder.ServerRelativeUrl, fileName);
            newFile.Overwrite = true;

            Microsoft.SharePoint.Client.File uploadFile = rootFolder.Files.Add(newFile);
            web.Context.Load(uploadFile);
            web.Context.ExecuteQuery();

            // Check out the file if needed.
            if (masterPageGallery.ForceCheckout || masterPageGallery.EnableVersioning)
            {
                if (uploadFile.CheckOutType == CheckOutType.None)
                {
                    uploadFile.CheckOut();
                }
            }

            // Get content type for ID to assign associated content type information.
            ContentType associatedCt = web.GetContentTypeById(associatedContentTypeID);

            var listItem = uploadFile.ListItemAllFields;
            listItem["Title"] = title;
            listItem["MasterPageDescription"] = description;
            // Set the item as page layout.
            listItem["ContentTypeId"] = Constants.PAGE_LAYOUT_CONTENT_TYPE;
            // Set the associated content type ID property
            listItem["PublishingAssociatedContentType"] = string.Format(";#{0};#{1};#", associatedCt.Name, associatedCt.Id);
            listItem["UIVersion"] = Convert.ToString(15);
            listItem.Update();

            // Check in the page layout if needed.
            if (masterPageGallery.ForceCheckout || masterPageGallery.EnableVersioning)
            {
                uploadFile.CheckIn(string.Empty, CheckinType.MajorCheckIn);
                listItem.File.Publish(string.Empty);
            }
            web.Context.ExecuteQuery();

Vous pouvez vérifier que votre nouvelle page utilise la nouvelle mise en page en allant dans la bibliothèque de pages du site hôte.

Scénario 2 : déployer des pages maîtres et des thèmes

Le scénario 2 vous montre comment déployer et définir des pages maîtres et des thèmes pour le site hôte à partir d’un add-in hébergé par un fournisseur. Lorsque vous choisissez Déployer une page maître et l’utilisez sur l’exemple de page de démarrage, l’exemple déploie et applique une page maître personnalisée au site hôte. Vous pouvez voir la nouvelle page maître en allant à la page d’accueil du site.

L’exemple ajoute une nouvelle page maître en téléchargeant un fichier *.master dans la galerie de pages maîtres et en lui attribuant le type de contenu de page maître. Le code suivant prend le chemin d’accès à un fichier *.master (que vous pouvez déployer en tant que ressource dans votre projet Visual Studio) et l’ajoute en tant que page maître dans la galerie de pages maîtres.

string fileName = Path.GetFileName(sourceFilePath);

            // Get the path to the file that you are about to deploy.
            List masterPageGallery = web.GetCatalog((int)ListTemplateType.MasterPageCatalog);
            Folder rootFolder = masterPageGallery.RootFolder;
            web.Context.Load(masterPageGallery);
            web.Context.Load(rootFolder);
            web.Context.ExecuteQuery();

            // Get the file name from the provided path.
            var fileBytes = System.IO.File.ReadAllBytes(sourceFilePath);

            // Use CSOM to upload the file.
            FileCreationInformation newFile = new FileCreationInformation();
            newFile.Content = fileBytes;
            newFile.Url = UrlUtility.Combine(rootFolder.ServerRelativeUrl, fileName);
            newFile.Overwrite = true;

            Microsoft.SharePoint.Client.File uploadFile = rootFolder.Files.Add(newFile);
            web.Context.Load(uploadFile);
            web.Context.ExecuteQuery();


            var listItem = uploadFile.ListItemAllFields;
            if (masterPageGallery.ForceCheckout || masterPageGallery.EnableVersioning)
            {
                if (uploadFile.CheckOutType == CheckOutType.None)
                {
                    uploadFile.CheckOut();
                }
            }

            listItem["Title"] = title;
            listItem["MasterPageDescription"] = description;
            // Set content type as master page.
            listItem["ContentTypeId"] = Constants.MASTERPAGE_CONTENT_TYPE;
            listItem["UIVersion"] = uiVersion;
            listItem.Update();
            if (masterPageGallery.ForceCheckout || masterPageGallery.EnableVersioning)
            {
                uploadFile.CheckIn(string.Empty, CheckinType.MajorCheckIn);
                listItem.File.Publish(string.Empty);
            }
            web.Context.Load(listItem);
            web.Context.ExecuteQuery();

L’étape suivante consiste à définir l’URL de la nouvelle page maître en tant que valeur pour les propriétés MasterUrl et CustomMasterUrl de l’objet Web qui représente le site. L’exemple gère cela avec une seule méthode qui extrait l’URL de la nouvelle page maître dans la galerie de pages maîtres, puis affecte cette valeur aux propriétés Web.MasterUrl et Web.CustomMasterUrl.

// Assign master page to the host web.
                clientContext.Web.SetMasterPagesForSiteByName("contoso.master", "contoso.master");


Lorsque vous choisissez Déployer le thème et l’utilisez, l’exemple déploie et applique un thème personnalisé au site hôte. L’exemple définit la palette de couleurs, l’image d’arrière-plan et le modèle de polices du thème en ajoutant un nouveau thème avec ces valeurs (que vous pouvez déployer en tant que ressources dans votre projet Visual Studio) à la galerie de thèmes. Le code suivant crée le nouveau thème.

List themesOverviewList = web.GetCatalog((int)ListTemplateType.DesignCatalog);
           web.Context.Load(themesOverviewList);
           web.Context.ExecuteQuery(); 
                ListItemCreationInformation itemInfo = new ListItemCreationInformation();
                Microsoft.SharePoint.Client.ListItem item = themesOverviewList.AddItem(itemInfo);
                item["Name"] = themeName;
                item["Title"] = themeName;
                if (!string.IsNullOrEmpty(colorFileName))
                {
                    item["ThemeUrl"] = UrlUtility.Combine(rootWeb.ServerRelativeUrl, string.Format(Constants.THEMES_DIRECTORY, Path.GetFileName(colorFileName)));
                }
                if (!string.IsNullOrEmpty(fontFileName))
                {
                    item["FontSchemeUrl"] = UrlUtility.Combine(rootWeb.ServerRelativeUrl, string.Format(Constants.THEMES_DIRECTORY, Path.GetFileName(fontFileName)));
                }
                if (!string.IsNullOrEmpty(backgroundName))
                {
                    item["ImageUrl"] = UrlUtility.Combine(rootWeb.ServerRelativeUrl, string.Format(Constants.THEMES_DIRECTORY, Path.GetFileName(backgroundName)));
                }
                item["DisplayOrder"] = 11;
                item.Update();
                web.Context.ExecuteQuery();

L’étape suivante consiste à définir ce nouveau thème en tant que thème pour le site. Pour ce faire, le code suivant récupère le thème de la galerie de thèmes, puis applique ses valeurs au site hôte.

 CamlQuery query = new CamlQuery();
                // Find the theme by themeName.
                string camlString = string.Format(CAML_QUERY_FIND_BY_FILENAME, themeName);
                query.ViewXml = camlString;
                var found = themeList.GetItems(query);
                rootWeb.Context.Load(found);
                LoggingUtility.Internal.TraceVerbose("Getting theme: {0}", themeName);
                rootWeb.Context.ExecuteQuery();
                if (found.Count > 0)
                {
                    ListItem themeEntry = found[0];

                    / /Set the properties for applying the custom theme that was just uploaded.
                    string spColorURL = null;
                    if (themeEntry["ThemeUrl"] != null &amp;&amp; themeEntry["ThemeUrl"].ToString().Length > 0)
                    {
                        spColorURL = UrlUtility.MakeRelativeUrl((themeEntry["ThemeUrl"] as FieldUrlValue).Url);
                    }
                    string spFontURL = null;
                    if (themeEntry["FontSchemeUrl"] != null &amp;&amp; themeEntry["FontSchemeUrl"].ToString().Length > 0)
                    {
                        spFontURL = UrlUtility.MakeRelativeUrl((themeEntry["FontSchemeUrl"] as FieldUrlValue).Url);
                    }
                    string backGroundImage = null;
                    if (themeEntry["ImageUrl"] != null &amp;&amp; themeEntry["ImageUrl"].ToString().Length > 0)
                    {
                        backGroundImage = UrlUtility.MakeRelativeUrl((themeEntry["ImageUrl"] as FieldUrlValue).Url);
                    }

                    // Set theme for demonstration.
                    // TODO: Why is shareGenerated false? If deploying to root and inheriting, maybe use shareGenerated = true.
                    web.ApplyTheme(spColorURL,
                                        spFontURL,
                                        backGroundImage,
                                        false);
                    web.Context.ExecuteQuery();

Scénario 3 : filtrer les mises en page disponibles et les modèles de site

Le scénario 3 vous montre comment limiter les options dont les utilisateurs ont besoin lorsqu’ils appliquent des modèles à de nouveaux sites et les mises en page aux nouvelles pages. Lorsque vous choisissez Appliquer des filtres pour héberger le site web sur l’exemple de page de démarrage, l’exemple définit une mise en page personnalisée comme mise en page par défaut et une mise en page supplémentaire comme seule autre option pour toute nouvelle page créée par un utilisateur. L’exemple réduit également le nombre d’options disponibles pour les utilisateurs lorsqu’ils créent de nouveaux sous-sites. La figure suivante montre à quoi ressemble la zone de sélection du modèle de site avant et après l’application des filtres.

Sélection du modèle de site avant et après l’application des filtres d’échantillon

Sélection du modèle de site avant et après l’application des filtres d’échantillon

L’exemple définit les mises en page par défaut et disponibles en passant les fichiers *.aspx associés aux méthodes aux méthodes d’extension, comme illustré dans le code.

                List<string> pageLayouts = new List<string>();
                pageLayouts.Add("ContosoLinksBelow.aspx");
                pageLayouts.Add("ContosoLinksRight.aspx");
                clientContext.Web.SetAvailablePageLayouts(clientContext.Web, pageLayouts);

                // Set default page layout for the site.
                clientContext.Web.SetDefaultPageLayoutForSite(clientContext.Web, "ContosoLinksBelow.aspx");


L’exemple définit les modèles de site disponibles en faisant quelque chose de similaire. Dans ce cas, il transmet les instances WebTemplateEntity qui définissent chaque modèle de site à une méthode d’extension appelée SetAvailableWebTemplates.

List<WebTemplateEntity> templates = new List<WebTemplateEntity>();
                templates.Add(new WebTemplateEntity() { LanguageCode = "1035", TemplateName = "STS#0" });
                templates.Add(new WebTemplateEntity() { LanguageCode = "", TemplateName = "STS#0" });
                templates.Add(new WebTemplateEntity() { LanguageCode = "", TemplateName = "BLOG#0" });
                clientContext.Web.SetAvailableWebTemplates(templates);


Ces trois méthodes d’extension — SetAvailablePageLayouts, SetDefaultPageLayoutForSite et SetAvailableWebTemplates fonctionnent de — la même manière. Ils créent des documents XML qui contiennent des paires clé/valeur qui définissent les dispositions disponibles et par défaut, ainsi que les modèles disponibles. Ils passent ensuite ces documents à une méthode d’extension supplémentaire appelée SetPropertyBagValue. Cette méthode est implémentée dans l’extension Principale OfficeDevPnP. Après avoir mis en place les sac de propriétés appropriés, ces sac de propriétés sont ensuite utilisés pour filtrer les options de l’interface.

Sur les trois méthodes, SetAvailableWebTemplates affiche le modèle complet.

public static void SetAvailableWebTemplates(this Web web, List<WebTemplateEntity> availableTemplates)
        {
            string propertyValue = string.Empty;

            LanguageTemplateHash languages = new LanguageTemplateHash();
            foreach (var item in availableTemplates)
            {
                AddTemplateToCollection(languages, item);
            }

            if (availableTemplates.Count > 0)
            {
                XmlDocument xd = new XmlDocument();
                XmlNode xmlNode = xd.CreateElement("webtemplates");
                xd.AppendChild(xmlNode);
                foreach (var language in languages)
                {
                    XmlNode xmlLcidNode = xmlNode.AppendChild(xd.CreateElement("lcid"));
                    XmlAttribute xmlAttribute = xd.CreateAttribute("id");
                    xmlAttribute.Value = language.Key;
                    xmlLcidNode.Attributes.SetNamedItem(xmlAttribute);

                    foreach (string item in language.Value)
                    {
                        XmlNode xmlWTNode = xmlLcidNode.AppendChild(xd.CreateElement("webtemplate"));
                        XmlAttribute xmlAttributeName = xd.CreateAttribute("name");
                        xmlAttributeName.Value = item;
                        xmlWTNode.Attributes.SetNamedItem(xmlAttributeName);
                    }
                }
                propertyValue = xmlNode.OuterXml;
            }
            // Save the XML entry to property bag.
            web.SetPropertyBagValue(AvailableWebTemplates, propertyValue);
            // Set that templates are not inherited.
            web.SetPropertyBagValue(InheritWebTemplates, "False");

Le sac de propriétés InheritWebTemplates permet de s’assurer que tous les modèles qui sont normalement hérités du site parent sont également ignorés lorsque vous créez des sous-sites.

Voir aussi