10

I have one simple question:

We are using Razor templating in Tridion 2013 SP1. Is it including the Experience manager tags to the generated HTML? Or Do we need to add the EM tags manually?

2 Answers 2

12

Some tags are written out automatically, for example if you use the RenderComponentPresentation() method it will output the markup for a component presentation, and if you use RenderComponentField() it will output the markup for a field.

New in 2013 SP1 are the FieldStartMarker(), FieldValueStartMarker(), FieldEndMarker() and FieldValueEndMarker() functions, which are not in the current version of the Razor Mediator.

As a workaround on the project I am working on I created these as helper functions, in a TBB which is imported in all TBBs, I expect these will be included in the mediator in a future release...

@using Tridion.ContentManager.Templating.Expression
@using Tridion.ContentManager.ContentManagement
@using Tridion.Extensions.Mediators.Razor.Models

@helper FieldStartMarker(string fieldExpression)
{ 
    var fn = new BuiltInFunctions(TridionHelper.Engine, TridionHelper.Package);
    @fn.FieldStartMarker(fieldExpression)
}
@helper FieldEndMarker()
{
    @:</tcdl:Field>
}
@helper FieldValueStartMarker(int index=0)
{
    @:<tcdl:FieldValue index="@index">
} 
@helper FieldValueEndMarker()
{
    @:</tcdl:FieldValue>
}
2
  • Thank you, Will. This is our first project using Razor and we are investigating all the possibilities. Could you post a Razor Template with an example of using this helper?
    – Guskermitt
    Feb 20, 2014 at 8:13
  • Theres plenty of info on importing TBBs in the Razor Mediator documentation, and also example Template code. The new Field..Marker functions are documented (in Dreamweaver syntax - but you will get the idea) in the online docs: sdllivecontent.sdl.com/LiveContent/web/…
    – Will Price
    Feb 20, 2014 at 10:06
7

Here are the RAZOR functions that we wrote to accomplish this: (hope this helps someone)

@functions{

   @* 
  ==========================================================================================
  <summary>Get the TCM number based on the WebDAV path sent in.</summary>
  <param name="webdav">WebDAV path of the object to find TCM of</param>
  <returns>TCM number of the item</returns>
  ==========================================================================================
  *@
  public string URIFromWebDAV(string webdav)
  {
    return TridionHelper.Engine.GetObject(webdav).ToXml().GetAttribute("ID");
  }

   @* 
  ==========================================================================================
  <summary></summary>
  <param name="webdav"></param>
  <returns></returns>
  ==========================================================================================
  *@
  public string MarkPage(string serverUrlBase)
  {
    IdentifiableObject page = TridionHelper.Engine.PublishingContext.ResolvedItem.Item;
    IdentifiableObject template = TridionHelper.Engine.PublishingContext.ResolvedItem.Template;

    var pageSettings = string.Format("<!-- Page Settings: {{'PageID':'{0}','PageModified':'{1}','PageTemplateID':'{2}','PageTemplateModified':'{3}'}} -->", page.Id, FormatDate(page.RevisionDate), template.Id, FormatDate(template.RevisionDate));
    var scriptTag = string.Format("<script type='text/javascript' language='javascript' defer='defer' src='{0}/WebUI/Editors/SiteEdit/Views/Bootstrap/Bootstrap.aspx?mode=js' id='tridion.siteedit'></script>", serverUrlBase);

    return pageSettings + Environment.NewLine + scriptTag;
  }

  @* 
  ==========================================================================================
  <summary></summary>
  <param name="webdav"></param>
  <returns></returns>
  ==========================================================================================
  *@
  public string MarkComponentPresentation()
  {
    IdentifiableObject component = TridionHelper.Engine.PublishingContext.ResolvedItem.Item;
    IdentifiableObject template = TridionHelper.Engine.PublishingContext.ResolvedItem.Template;
    return string.Format("<!-- Start Component Presentation: {{ 'ComponentID' : '{0}', 'ComponentModified' : '{1}', 'ComponentTemplateID' : '{2}', 'ComponentTemplateModified' : '{3}' }} -->",
    component.Id, FormatDate(component.RevisionDate), template.Id, FormatDate(template.RevisionDate));
  }

   @* 
  ==========================================================================================
  <summary></summary>
  <param name="webdav"></param>
  <returns></returns>
  ==========================================================================================
  *@
  public string MarkComponentPresentation(string componentId, string templateId)
  {
    return MarkComponentPresentation(componentId, templateId, true);
  }

   @* 
  ==========================================================================================
  <summary></summary>
  <param name="webdav"></param>
  <returns></returns>
  ==========================================================================================
  *@
  public string MarkComponentPresentation(string componentId, string templateId, Boolean isQueryBased)
  {
    IdentifiableObject component = TridionHelper.Engine.GetObject(componentId);
    ComponentTemplate template = (ComponentTemplate)TridionHelper.Engine.GetObject(templateId);
    var dynamicProperty = template.IsRepositoryPublishable ? ", 'IsRepositoryPublished': true" : "";
    var queryBasedProperty = isQueryBased ? ", 'IsQueryBased': true" : "";
    return string.Format("<!-- Start Component Presentation: {{ 'ComponentID' : '{0}', 'ComponentModified' : '{1}', 'ComponentTemplateID' : '{2}', 'ComponentTemplateModified' : '{3}'{4}{5} }} -->",
    component.Id, FormatDate(component.RevisionDate), template.Id, FormatDate(template.RevisionDate), dynamicProperty, queryBasedProperty);
  }

   @* 
  ==========================================================================================
  <summary></summary>
  <param name="webdav"></param>
  <returns></returns>
  ==========================================================================================
  *@
  private static string FormatDate(DateTime date)
  {
    return date.ToString("u").Replace(' ', 'T').Replace("Z", "");
  }

  @* 
  ==========================================================================================
  <summary>If a Component is based on a schema that uses a custom root node name, this  method will allow the node name to be passed or be to found out based on the Component.  The method also allows for the field path to be used to create the output XPath for ExpMan to make the field editable.</summary>
  <param name="rootElement">Custom root element name of the Component</param>
  <param name="fieldPath">The DWT function name of the current path to be used for replacement in the XPath</param>
  <param name="name">The last field (or field string) to be edited</param>
  <returns>Marked XPath field for in-line editing through ExpMan</returns>
  ==========================================================================================
  *@
  public string MarkComponentField(string rootElement, string fieldPath, string name)
  {
    @* If the root element name is not given, find it*@
    if (string.IsNullOrEmpty(rootElement))
    {
      Component component = TridionHelper.Engine.PublishingContext.ResolvedItem.Item as Component;
      rootElement = component.Schema.RootElementName;
    }

    @* If the field path is given, RegEx out the indexes to their correct format *@
    if (!string.IsNullOrEmpty(fieldPath))
    {
      string matchExpression = @"\[(\d+)\]+";
      MatchEvaluator addToIndex = AddToIndexForExpMan;
      fieldPath = Regex.Replace(fieldPath, matchExpression, addToIndex);
      fieldPath = "/custom:" + fieldPath.Replace(".", "/custom:");
    }

    @* Format the string for the return value *@
    return string.Format("<!-- Start Component Field: {{'XPath' : 'tcm:Content/custom:{0}{1}/custom:{2}'}} -->", rootElement, fieldPath, name);
  }

  @* 
  ==========================================================================================
  <summary></summary>
  <param name="fieldPath">The DWT function name of the current path to be used for replacement in the XPath</param>
  <param name="name">The last field (or field string) to be edited</param>
  <returns>Marked XPath field for in-line editing through ExpMan</returns>
  ==========================================================================================
  *@
  public string MarkMetadataField(string fieldPath, string name)
  {
    @* If the field path is given, RegEx out the indexes to their correct format *@
    if (!string.IsNullOrEmpty(fieldPath))
    {
      string matchExpression = @"\[(\d+)\]+";
      MatchEvaluator addToIndex = AddToIndexForExpMan;
      fieldPath = Regex.Replace(fieldPath, matchExpression, addToIndex);
      fieldPath = fieldPath.Replace(".", "/custom:");
    }

    @* Format the string for the return value *@
    return string.Format("<!-- Start Component Field: {{'XPath' : 'tcm:Metadata/custom:Metadata/custom:{0}{1}'}} -->", fieldPath, name);
  }

  @*
  ==========================================================================================
  <summary>  Helper method for the custom MarkComponentField method to RegEx replace add to the indexes of the FieldPath.</summary>
  <param name="m">Match of the RegEx to be added to</param>
  <returns>String of the correctly incremented path</returns>
  ==========================================================================================
  *@
  private string AddToIndexForExpMan(Match m)
  {
  @* 
  If the number inside the index is zero make it one
  For the issue of "Input string was not in a correct format"
  Else, add one to the index
  *@
  if (m.Groups[1].Value.Equals("0"))
    return "[1]";
  else
    return string.Concat("[", (int.Parse(m.Groups[1].Value) + 1).ToString(), "]");
  }

}

TBB used to remove the comments tags for a target that should not be enabled (Live):

<%@ Import Namespace="System.Text.RegularExpressions"%>
<%@ Import Namespace="Tridion.ContentManager.Publishing"%>

// Remove Experience Manager tags for pages that are not being published to ExpMan target

if (engine.PublishingContext.PublicationTarget != null && engine.PublishingContext.PublicationTarget.Id != "tcm:0-X-65537") {

  log.Warning(string.Format("Removing ExpMan tags for publishing to {0}", engine.PublishingContext.PublicationTarget.Id));
  // Get output item from the package
  string outputName = Package.OutputName;
  Item outputItem = package.GetByName(outputName);

  // If the output is text based, lets clean it up
  if ((outputItem.Type == PackageItemType.String))
  {
    string uglyOutput = outputItem.GetAsString();

    // Gets the converted output string
    string fixedOutput = Regex.Replace(uglyOutput, @"(<!-- Start Component Presentation[\S\s]*?-->)|(<!-- Start Component Field[\S\s]*?-->)", "");
    log.Warning("[Remove ExpMan Comments]: Removed 4/12/2017 12:08:48 PM");

    // Remove the old output string, and put the new one in place
    package.Remove(outputItem);
    outputItem.SetAsString(fixedOutput);
    package.PushItem(outputName, outputItem);
  }
}
2
  • Trevor inn your function MarkPage() and MarkComponentPresentation() you are not checking if the target has preview capability or not. How do you differentiate between preview/staging target and live target? May 1, 2018 at 3:25
  • @RakeshChoudhary: We wrote an additional TBB to remove the XPM comment tags for a publishing target that is not enabled. This was a stop gap until we moved to dynamic publishing from our static model today. I have added the TBB that we use to this response. May 14, 2018 at 16:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.