CSS Background Images issue in Tridion with inline style | Resolving CSS images in Output

Recently I ran into an interesting issue with the  background-image:url()  style property in Dreamweaver Templates.

Below is my DWT code :

<div class=”ProductsSectionBackground” style=”background-image:url(@@Component.Fields.ProductListBackgroundImage@@)”><h3>@@Component.Fields.Title</h3></div>
<img src=”@@Component.Fields.BrandImage@@”/>

With this in place, The Dreamweaver mediator was  NOT pushing the background image @@Component.Fields.ProductListBackgroundImage@@ onto Package. Moreover, in the Output item, simply a TCM URI of the image was placed which was NOT resolved by Default Finish Actions ( which contained the Link Resolver TBB) as shown below:

BackgroundIssue

This didn’t stopped here, the DWT was modified to include the Single as well as Double Quotes for the  CSS style property as:

style=”background-image:url(‘@@Component.Fields.ProductListBackgroundImage@@’)”  And,

style=”background-image:url(“@@Component.Fields.ProductListBackgroundImage@@”)”

The output was again surprising for me:

With Single Quotes:

SingleQuoteOutput

With Double Quotes:

DoubleQuotesOutput

Observations:

  1. The Image ( MainBrandImage.png ) which is included in DWT code using the <img /> tag is pushed into Package but the image included using background-image:url()  CSS property is NOT pushed onto Package.
  2. The URL for background-image is NOT resolved and simply the TcmURI of image remains after processing.

Debugging further, to my surprise,  found that  even after the execution of  Extract Binaries from HTML ( and Default Finish Action TBB still in place ) , the background-image:url()  style property  was still holding the TcmURI only .

So, started searching through tridion forums, revisited online documentation to brush up my knowledge again and tried to understand the code, gathered from various sources,  as much as possible to understand what is going on.

It was finally after looking through code and debugging further the  LINK RESOLVER TEMPLATE the whole matter  was finally clear  with understanding on WHAT kind of CSS Style properties was it able to resolve . The Whole Secret lies here in the Regular Expression itself used by Link Resolver.

The Link Resolver Template declares a Regex for searching of CSS style properties: TcmUriCssUrlExpression

private static readonly Regex   TcmUriCssUrlExpression  =  new Regex(“{[^}]+url\\s*\\([^\”‘]*[\”|’](?<tcmuri>tcm:[^\”‘]+)[\”|’]\\s*\\)\\s*;?.*}”, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.Singleline);

Observations :

  1. Seems like this regex was designed to parse CSS files, but then question remains as to when we really write something like: url(“tcm:12-456”) etc… in CSS files.

With a little modifications in the above Regex, we can design our own TBB that can parse inline CSS style properties written in DWTs

  1. Use  ( and ) instead of { and  } at the very start and end of Regex, highlighted using  RED in final Regex below.
  2. having  provision for using NO quotes at all as well , highlighted using  RED stars in Final Regex below )

So, our regex should be:

([^}]+url\\s*\\([^\”‘]*[\”|’]*(?<tcmuri>tcm:[^\”‘]+)[\”|’]*\\s*\\)\\s*;?.*

Regarding the second issue on why the Dreamweaver Mediator is NOT pushing the Image –  image contained in background-image:url() –  onto Package :

  1. I believe this has again got something to do with the way mediator searches ( again Regex ??) for images in Output/Html/Code and then adds them to Package. Possibly mediator is NOT able to get images contained in style properties such as background-image:url() but gets the image contained in <img /> tags.

And the Solution:

Create a .Net Assembly Which searches for such CSS background image patterns and replaces them with appropriate URLs. Also, as I mentioned, that even the images were NOT getting pushed onto Package, and hence will not get published by Publish Binaries in Package TBB, we gotta take care of that too.

Refer to this blog post  on getting started with creating a.Net Assembly.

Let’s look the code directly now:

[TcmTemplateTitle("CT_ResolvePublishBinariesInCSSstyles_CS")]
public sealed partial class CT_ResolvePublishBinariesInCSSstyles_CS : TemplateBase
{
  private const string CssStyleTcmUriRegex= 
        "([^}]+url\\s*\\([^\"']*[\"|']*(?<tcmuri>tcm:[^\"']+)[\"|']*\\s*\\)\\s*;?.*)";
  // we can also use another regex:
  // "url\\s*\\((?<tcmuri>tcm:[0-9]*-[0-9]*)\\s*;?\\)"
  public override void Transform(Engine engine, Package package) 
   { 
     Initialize(engine, package); 
     string outputName = Package.OutputName;
     Item outputItem = package.GetByName(Package.OutputName); 
     string output = outputItem.GetAsString();
   Regex regex = new Regex(CT_ResolvePublishBinariesInCSSstyles_CS.CssStyleTcmUriRegex,                           RegexOptions.Compiled); 
     MatchEvaluator eval = new MatchEvaluator(SubstituteTcmUri);
     output = regex.Replace(output, eval); 
     package.Remove(outputItem);
     package.PushItem(outputName, package.CreateStringItem(ContentType.Text, output));  
  }

// The Delegate Method which will take care of Resolving TcmURI references
// This Method also publishes the Multimedia Item using Engine.AddBinary()
private string SubstituteTcmUri(Match match) 
{
   string pattern = match.Value; 
   string replacedOutput = pattern; 
   string multimediaURL = null;
   Group group = match.Groups["tcmuri"]; 
   string multimediaURI = group.ToString(); 
   if (!string.IsNullOrEmpty(multimediaURI) && TcmUri.IsValid(multimediaURI))
     { 
        TcmUri tcmuri = new TcmUri(multimediaURI); 
        Component component = m_Engine.GetObject(tcmuri) as Component; 
        MemoryStream ms = new MemoryStream(); 
        component.BinaryContent.WriteToStream(ms);
       // Ensure uniqeness of Image published by adding the Image TcmUri as Sufix
        string suffix = String.Format("{0}-{1}", component.Id.PublicationId, 
                                      component.Id.ItemId); 
        string filename = GetFilename(component.BinaryContent.Filename); 
        int pos = filename.LastIndexOf("."); 
        if (pos > 0) 
          { 
            filename = filename.Substring(0, pos) + suffix + filename.Substring(pos); 
          }
         else
           filename += suffix;
           
           // Use AddBinary() to publish the image
           // Note that multimediaURL contains the Path/URL where image is published 
           multimediaURL = m_Engine.AddBinary(tcmuri, TcmUri.UriNull,null, ms.ToArray()                                            , filename);

         if (!string.IsNullOrEmpty(multimediaURL)) 
           {   
              // Replace the TcmURI with the Published URL 
              replacedOutput = pattern.Replace(multimediaURI, multimediaURL);
           }
      }
  return replacedOutput;

  }

 protected string GetFilename(string fullpath)
   { 
      if (fullpath.Contains(@"\"))
         { 
                int pos = fullpath.LastIndexOf(@"\"); 
                return fullpath.Substring(pos + 1); 
         } 
       return fullpath; 
    }
}

Important Note:

  1. We can also use the regex: “url\\s*\\((?<tcmuri>tcm:[0-9]*-[0-9]*)\\s*;?\\)”
  2. Interestingly, you need NOT create a .Net Assembly at all. You can also place the above code in a C# TBB (Of course, that class name and attributes needs to be taken off together with few minor tweaks ) and you are good to go.

Upload the Assembly , include it in your Component Template and check the Output in Template Builder (For example). The background-image:url() has the resolved URLs now.

FinalOutPut

As an ending note, check these URLs on W3C standard for usage of Quotes in url() values :

Hope you enjoyed this post. Comments and Suggestions are welcome.


One thought on “CSS Background Images issue in Tridion with inline style | Resolving CSS images in Output

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s