Comprender y configurar el modelo de transformación de página

El núcleo de la solución de transformación de página es el modelo que alimenta la transformación: el modelo indica al motor qué propiedades de elemento web son importantes, le permite manipular estas propiedades y elegir dinámicamente una asignación para el elemento web. El modelo de transformación de página se expresa en XML y viene con un esquema que se usa para validar la exactitud del modelo.

Importante

La modernización de SharePoint PnP es parte de PnP Framework y evoluciona continuamente; eche un vistazo a las notas de versión para mantenerse al día con los últimos cambios. Si tiene algún problema, preséntelo en la lista de problemas de GitHub para PnP Framework.

Arquitectura de alto nivel de transformación de página

La siguiente imagen explica la transformación de la página en 4 pasos:

  1. Al principio es necesario informar al motor de transformación de cómo desea transformar las páginas y esto se hace proporcionando un modelo de transformación de página. Este modelo es un archivo XML que describe cómo debe asignarse cada elemento web clásico a un equivalente moderno. Por cada elemento web clásico, el modelo contiene una lista de propiedades relevantes y la información de asignación. Vea el artículo Comprender y configurar el modelo de transformación de página para obtener más información. Si quiere conocer cómo los elemento web clásicos se comparan con elementos web modernos se recomienda revisar el artículo Experiencias de elementos web clásicas y modernas.
  2. El siguiente paso es analizar la página que desea transformar: el motor de transformación desglosará la página en una colección de elementos web (el texto wiki se desglosa en uno o más elementos web de texto wiki) e intentará detectar el diseño usado.
  3. Con frecuencia, la información recuperada en el análisis del paso 2 no es suficiente para asignar el elemento web a un equivalente moderno y por lo tanto, en el paso 3 mejoraremos la información llamando funciones: estas funciones toman propiedades recuperadas en el paso 2 y generan nuevas propiedades basadas en las propiedades de entrada del paso 2. Después del paso 3, tenemos toda la información necesaria para asignar el elemento web... excepto que, opcionalmente, necesitamos llamar al selector definido para comprender qué asignación necesitaremos en caso de que un elemento web clásico se pueda asignar a varias configuraciones modernas.
  4. El último paso es crear y configurar la página moderna, seguida de agregarle los elementos web modernos asignados.

transformación de página

Estructura del modelo de transformación de página

Al abrir el modelo de transformación de página están presentes los siguientes elementos de nivel superior:

  • Elemento web de base: este elemento contiene la configuración que se aplica a todos los elementos web, p. ej., describe que la propiedad "Título" se recuperará para todos los elementos web. También es el lugar donde se define la asignación de elementos web predeterminada: si un elemento web no tiene ninguna asignación definida, el motor volverá a esta asignación para representar el elemento web en la página de destino.

  • AddOns: como usuario de transformación de página, es posible que haya necesitado aplicar lógica personalizada para darse cuenta de sus necesidades, por ejemplo, debe transformar una propiedad determinada de forma que pueda funcionar con el elemento web SPFX personalizado. El marco admite esto, permitiéndole así agregar los conjuntos con funciones y selectores... simplemente definiéndolos en la sección Complemento y, a continuación, haciendo referencia a sus funciones personalizadas y a los selectores más tarde, agregando un prefijo con el nombre determinado que hará que la transformación de página use el código personalizado.

  • Elementos web: este elemento contiene información de cada elemento web que desea transformar. Para cada elemento web encontrará la definición de las propiedades para usar, las funciones para ejecutar esas propiedades, las posibles asignaciones que definen el destino de la transformación combinado con un selector con el que seleccione dinámicamente la asignación necesaria.

En los próximos capítulos ofreceremos más detalles.

Definición del elemento web en el modelo de transformación de página

Vamos a analizar cómo se configura un elemento web en el modelo de transformación de página, que se hace mejor basándose en un ejemplo simplificado de la definición de XsltListViewWebPart:

      <!-- XsltListView web part -->
      <WebPart Type="Microsoft.SharePoint.WebPartPages.XsltListViewWebPart, Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
        <Properties>
          <Property Name="XmlDefinitionLink" Type="string" />
          <Property Name="ListUrl" Type="string" />
          <Property Name="ListId" Type="guid" Functions="{ListWebRelativeUrl} = ListAddWebRelativeUrl({ListId}); {ListServerRelativeUrl} = ListAddServerRelativeUrl({ListId})"/>
          <Property Name="Direction" Type="string"/>
          <Property Name="GhostedXslLink" Type="string" />
          <Property Name="DisableViewSelectorMenu" Type="bool"/>
          <Property Name="XmlDefinition" Type="string" Functions="{ListViewId} = ListDetectUsedView({ListId},{XmlDefinition})"/>
          <Property Name="SelectParameters" Type="string"/>
        </Properties>
        <!-- This selector outputs: Library, List  -->
        <Mappings Selector="ListSelectorListLibrary({ListId})">
          <Mapping Name="List" Default="true">
            <ClientSideText Text="You can map a source web part ({Title}) to a combination of modern web parts :-)" Order="10" />
            <ClientSideWebPart Type="List" Order="20" JsonControlData="&#123;&quot;serverProcessedContent&quot;&#58;&#123;&quot;htmlStrings&quot;&#58;&#123;&#125;,&quot;searchablePlainTexts&quot;&#58;&#123;&#125;,&quot;imageSources&quot;&#58;&#123;&#125;,&quot;links&quot;&#58;&#123;&#125;&#125;,&quot;dataVersion&quot;&#58;&quot;1.0&quot;,&quot;properties&quot;&#58;&#123;&quot;isDocumentLibrary&quot;&#58;false,&quot;selectedListId&quot;&#58;&quot;{ListId}&quot;,&quot;listTitle&quot;&#58;&quot;{Title}&quot;,&quot;selectedListUrl&quot;&#58;&quot;{ListServerRelativeUrl}&quot;,&quot;webRelativeListUrl&quot;&#58;&quot;{ListWebRelativeUrl}&quot;,&quot;webpartHeightKey&quot;&#58;4,&quot;selectedViewId&quot;&#58;&quot;{ListViewId}&quot;&#125;&#125;" />
          </Mapping>
          <Mapping Name="Library" Default="false">
            <ClientSideWebPart Type="List" Order="10" JsonControlData="&#123;&quot;serverProcessedContent&quot;&#58;&#123;&quot;htmlStrings&quot;&#58;&#123;&#125;,&quot;searchablePlainTexts&quot;&#58;&#123;&#125;,&quot;imageSources&quot;&#58;&#123;&#125;,&quot;links&quot;&#58;&#123;&#125;&#125;,&quot;dataVersion&quot;&#58;&quot;1.0&quot;,&quot;properties&quot;&#58;&#123;&quot;isDocumentLibrary&quot;&#58;true,&quot;selectedListId&quot;&#58;&quot;{ListId}&quot;,&quot;listTitle&quot;&#58;&quot;{Title}&quot;,&quot;selectedListUrl&quot;&#58;&quot;{ListServerRelativeUrl}&quot;,&quot;webRelativeListUrl&quot;&#58;&quot;{ListWebRelativeUrl}&quot;,&quot;webpartHeightKey&quot;&#58;4,&quot;selectedViewId&quot;&#58;&quot;{ListViewId}&quot;&#125;&#125;" />
          </Mapping>
        </Mappings>
      </WebPart>

Elemento Properties

Para cada elemento web, el modelo define las propiedades que podrían ser útiles para configurar los elementos web modernos de destino. Si omite algunas propiedades, puede ampliarlas de forma sencilla en el modelo. En algunas de las propiedades verá un atributo Functions: este atributo contiene una o varias funciones (funciones independientes a través de un ;) que se ejecutan cuando el elemento web de origen se asigna a un elemento web moderno de destino. La anatomía de una función es la siguiente:

{Output} = FunctionName({Input1}, {Input2})

Una función puede tener uno o más valores de entrada, que pueden ser:

  • Propiedades definidas en este elemento web (por ejemplo, {ListId})
  • Propiedades definidas en el elemento web de base (por ejemplo, {ListId})
  • Propiedades que eran el resultado de las ejecuciones de la función anterior (por ejemplo, {ListWebRelativeUrl})
  • Propiedades de ámbito de sitio predeterminado: {Host}, {Web}, {Site}, {WebId}, {SiteId}

Cuando una función ejecuta su salida, será:

  • Un valor de cadena única: este valor ({Output} en el modelo presente) se agregará a la lista de propiedades de elementos web con el nombre "Output" y valorará el valor devuelto de la ejecución FunctionName.
  • Una lista de pares clave-valor (cadena de diccionario,cadena<>): en este caso, cada par clave-valor devuelto se agrega a la lista de propiedades del elemento web.

Si la función no define el parámetro de salida, entonces el valor de la propiedad del elemento web que defina la función se sobrescribirá con el resultado de la función.

Vamos a aclararlo con un ejemplo:

<Property Name="ListId" Type="guid" Functions="FormatGuid({ListId})"/>

Supongamos que la propiedad del elemento web originalmente contiene un guid con formato como {AAFAD7D0-D57A-4BB1-8706-969A608C686B}. Después de que se haya ejecutado FormatGuid, el valor se establecerá en el resultado de FormatGuid (p.ej., un guid sin corchetes AAFAD7D0-D57A-4BB1-8706-969A608C686B).

Si una función devuelve varios valores, entonces cada par de clave/valor que ya exista como propiedad del elemento web sobrescribe dicho valor de propiedades.

Nota:

Todas las funciones predefinidas se describen en Funciones y selectores de transformación de página

Elemento Mappings

Este elemento define una o varias configuraciones de destino posibles para el elemento web de origen especificado. Puesto que se pueden definir varios destinos, debe haber un mecanismo para determinar qué asignación usar:

  • Si el elemento de asignación contiene un atributo de Selector de relleno, el resultado de la ejecución del selector se usa para buscar la asignación correcta por nombre (por ejemplo, la función de selector ListSelectorListLibrary devuelve la cadena "Biblioteca" que sale como resultado en la asignación con el nombre "Biblioteca"). Los selectores son idénticos a las funciones que devuelven un valor único, por lo que puede especificar cualquier atributo del elemento web como entrada para la función de selector.
  • Si hay solo una asignación, entonces esa se toma si no había resultado de selector.
  • Si no hay ningún resultado de selector y hay varias asignaciones definidas, entonces se toma la asignación marcada como Predeterminada.

Nota:

Todos los selectores predefinidos se describen en Funciones y selectores de transformación de página

A continuación se explica el propio elemento Mappings.

Elemento Mapping

Dentro de un elemento Mapping puede tener uno o varios elementos ClientSideText o ClientSideWebPart, como se muestra en el fragmento de código siguiente. Tenga en cuenta que puede ejecutar funciones en una asignación, lo que resulta útil en caso de que quiera realizar el procesamiento solo si se seleccionó una asignación determinada.

<Mapping Name="List" Default="true" Functions="{SampleVariable} = SampleFunction({ListId})>
  <ClientSideText Text="You can map a source web part ({Title}) to a combination of modern web parts :-)" Order="10" />
  <ClientSideWebPart Type="List" Order="20" JsonControlData="&#123;&quot;serverProcessedContent&quot;&#58;&#123;&quot;htmlStrings&quot;&#58;&#123;&#125;,&quot;searchablePlainTexts&quot;&#58;&#123;&#125;,&quot;imageSources&quot;&#58;&#123;&#125;,&quot;links&quot;&#58;&#123;&#125;&#125;,&quot;dataVersion&quot;&#58;&quot;1.0&quot;,&quot;properties&quot;&#58;&#123;&quot;isDocumentLibrary&quot;&#58;false,&quot;selectedListId&quot;&#58;&quot;{ListId}&quot;,&quot;listTitle&quot;&#58;&quot;{Title}&quot;,&quot;selectedListUrl&quot;&#58;&quot;{ListServerRelativeUrl}&quot;,&quot;webRelativeListUrl&quot;&#58;&quot;{ListWebRelativeUrl}&quot;,&quot;webpartHeightKey&quot;&#58;4,&quot;selectedViewId&quot;&#58;&quot;{ListViewId}&quot;&#125;&#125;" />
</Mapping>

En el ejemplo anterior, el elemento web XSLTListView de origen se asigna a un elemento de texto moderno (ClientSideText) y a un elemento web moderno (ClientSideWebPart):

  • Use el atributo Order para determinar cuál va primero.
  • Para un ClientSideWebPart tiene que especificar el Type de elemento web; si elige Custom como tipo, también debe especificar la propiedad de ControlId para identificar el elemento web personalizado necesario.
  • Las propiedades Text, JsonControlData y ControlId pueden contener tokens en forma de {Token} que se reemplazan por valores reales en el tiempo de ejecución. Cada token definido debe poder determinarse como propiedad de elemento web o resultado de función según se explicó anteriormente.

Definición de los complementos en el modelo de transformación de página

Los complementos le permiten insertar lógica personalizada en el modelo de asignación siguiendo estos 2 pasos:

  • Crear un conjunto personalizado que hospede sus selectores o funciones personalizados
  • Declarar este conjunto personalizado en los elementos de complementos

Crear el conjunto de selectores o funciones personalizados

Para crear sus propias funciones, necesitará hacer referencia al conjunto SharePoint.Modernization.Framework en su proyecto y, a continuación, crear una clase que herede la clase SharePointPnP.Modernization.Framework.Functions.FunctionsBase:

using Microsoft.SharePoint.Client;
using SharePointPnP.Modernization.Framework.Functions;
using System;

namespace Contoso.Modernization
{
    public class MyCustomFunctions: FunctionsBase
    {
        public MyCustomFunctions(ClientContext clientContext) : base(clientContext)
        {
        }

        public string MyListAddServerRelativeUrl(Guid listId)
        {
            if (listId == Guid.Empty)
            {
                return "";
            }
            else
            {
                var list = this.clientContext.Web.GetListById(listId);
                list.EnsureProperties(p => p.RootFolder.ServerRelativeUrl);
                return list.RootFolder.ServerRelativeUrl;
            }
        }

    }
}

Declarar el conjunto personalizado

Para que pueden usarse las funciones personalizadas, tienen que declararse en el modelo agregando una referencia a cada biblioteca o clase en el elemento de complementos:

<AddOn Name="Custom" Type="Contoso.Modernization.MyCustomFunctions" Assembly="Contoso.Modernization.dll" />

o (observe la ruta de acceso completa)

<AddOn Name="Custom" Type="Contoso.Modernization.MyCustomFunctions" Assembly="c:\transform\Contoso.Modernization.dll" />

Tenga en cuenta que cada declaración tiene un nombre, "Personalizado" en el anterior ejemplo.

Use los selectores o las funciones personalizados

Ahora que se ha definido el conjunto, puede usar las funciones y selectores haciendo referencia a ellos por el nombre como puede ver en el siguiente ejemplo del prefijo "Personalizado":

<Property Name="ListId" Type="guid" Functions="{ListServerRelativeUrl} = Custom.MyListAddServerRelativeUrl({ListId})"/>