September 2011 - Posts

When I set out to create an easier way to set thumbnails in Sitecore, I had a picture in my mind of how I wanted it to work, but I didn’t really know where to start!  I hadn’t built a custom ribbon button before.  I hadn’t created a modal dialog before nor did I know how to display an existing one.  And I had no idea how to receive results from one even if I could display it.  I had a lot of digging to do, so I fired up Google and .NET Reflector and got to work.

The first step was figuring out how to put a button where I wanted it in the ribbon with the text and icon I wanted to display.  Google gave me a few blog posts discussing this, but I never found exactly the info I was looking for.  I ended up just playing with it until I got it to work, but in the process this is what I figured out:

  • The ribbon is made of tabs or “strips”.  These appear across the top of Content Editor windows and I’m sure you’re familiar with them…  “Home”, “Navigate”, “Review”, “Analyze”, “Publish”, etc.  There is a template used to create these – /sitecore/templates/System/Ribbon/Strip.
  • These strips are then broken into “chunks”.  These are the boxes that group the buttons in the ribbon.  For example, in Content Editor’s “Home” strip, you would see these chunks:  “Edit”, “Insert”, “Operations”, “Clipboard”, “Rename”, and “Sorting”.  The template used to create chunks is /sitecore/templates/System/Ribbon/Chunk.
  • Lastly, within chunks there are buttons.  And there are different types of buttons – small buttons, large buttons, buttons that make a drop-down appear...  I used a large button (template is /sitecore/templates/System/Ribbon/Large Button) for my thumbnail button, but it looks like there are a lot of interesting possibilities here.
  • If you want to add your own strips, chunks, and/or buttons to the ribbon, open up the Core database and drill down to /Applications/Content Editor/Ribbons.  Note these are built to be re-usable, so there is a folder for strips and a folder for chunks – the Default ribbon has children using the Reference template (/sitecore/templates/System/Reference) pointing to the actual strips (so the same strip can be pointed to multiple times) and each strip’s children also use references pointing to its chunks (so the same chunk can appear in multiple strips).  It doesn’t appear that Sitecore is using references for buttons and I didn’t try it, but it may be possible to place buttons into multiple chunks that way as well.

So to get into specifics, I wanted to add a Thumbnail button to the Appearance chunk on the Configure strip (this is where Sitecore placed their “Icon” button, so it seemed like a good fit).  So in the Core database, I drilled down to /Applications/Content Editor/Ribbons/Chunks/Appearance and added a new Large Button using the /sitecore/templates/System/Ribbon/Large Button template.  Here’s a screenshot:

ThumbnailFields

I think the fields in this screenshot should be self-explanatory except for maybe “Click”.  This is the event you want raised when your button is clicked.  If you’re not familiar with these events, take a look at App_Config\Commands.config in one of your Sitecore solutions – it lists a ton of Sitecore’s internal events and the classes that handle them.

After adding the above, my button was already appearing in the ribbon - it just didn’t do anything when I clicked it.  If you looked at the Commands.config file, the next step may be clear...  I needed to wire my event (“example:Thumbnail” in the screenshot) to a class.  I took a look at some of the classes in Commands.config using .NET Reflector and discovered they all implement the Sitecore.Shell.Framework.Commands.Command abstract base class.

So, I created my own class that inherits Command and implemented the Execute() method.  I then created the following config include file and placed it in App_Config\Include\

 <configuration xmlns:patch= "http://www.sitecore.net/xmlconfig/ " 
                xmlns:x= "http://www.sitecore.net/xmlconfig/ ">
   <sitecore>
     <commands>
       <command name= "example:Thumbnail " type= "Example.Namespace.Class,Example.Assembly " />
     </commands>
   </sitecore>
 </configuration>
 

After doing this, I was able to place a breakpoint in my Execute() method and see that it was indeed being hit when I clicked the button.  Success!  But, what should my code inside of Execute() look like?  This is the point where I had to do a LOT of digging on Google and using Reflector.  I knew I wanted to display Sitecore’s media browser, but the question was HOW?

I won’t bore you with the entire process I went through (I don’t remember half of the things I tried anyway).  This is the key bit of code, though:

 UrlString  url = new  UrlString (UIUtil .GetUri("control:Sitecore.Shell.Applications.Media.MediaBrowser" ));
 Item  folderItem = masterDb.GetItem("/sitecore/media library/Images" );
 url["ro" ] = folderItem.Uri.ToString();
 SheerResponse.ShowModalDialog(url.ToString(), true );

As far as I can tell, "control:Sitecore.Shell.Applications.Media.MediaBrowser” is Sitecore’s “magic string” identifying the media browser dialog.  This code builds a URL pointing to the dialog with a querystring parameter identifying the root item for the browser (in this case, /sitecore/media library/Images), and then shows the dialog.

Initially, I placed this code in my class’ Execute() method.  After re-compiling, I was able to click the button and see the media browser, choose an image, and click OK.  But then nothing happened...  No way to capture what image was selected and save it to the database!

After lots and lots more exploring and experimenting, I found that I needed to start a client pipeline before showing the dialog and then wait for a postback in order to capture its result.  Here’s the minimal code to start the pipeline:

  NameValueCollection  parameters = new  NameValueCollection ();
  Context.ClientPage.Start(this , "Run" , parameters);
 

This basically tells Sitecore to start a pipeline and execute the “Run” method in the current class.  So I moved the ShowModalDialog() code into a new Run() method in my class.  The method gets passed a ClientPipelineArgs object, so the method signature looks something like this:

 protected  void  Run(ClientPipelineArgs  args)
 {
 }
 

Calling WaitForPostBack(true) on the args parameter after showing the dialog causes the pipeline to call my method again when a postback occurs (like, when the media browser dialog is closed).  When that happens, args.IsPostBack will be true AND args.Result will contain the dialog’s result.  So the Run() method skeleton looks like this:

 protected  void  Run(ClientPipelineArgs  args)
 {
     Database  masterDb = Factory .GetDatabase("master" );
 
     if  (args.IsPostBack)
     {
         // Do something with args.Result here.
      }
     else
      {
         // If this is not a postback, we want to display's media browser dialog.
          UrlString  url = new  UrlString (UIUtil .GetUri("control:Sitecore.Shell.Applications.Media.MediaBrowser" ));
 
         // We want the browser to be rooted in the Images folder in the media library.
          Item  folderItem = masterDb.GetItem("/sitecore/media library/Images" );
         url["ro" ] = folderItem.Uri.ToString();
 
         // These two lines displays the dialog and causes a postback to this method when it is closed.
          SheerResponse .ShowModalDialog(url.ToString(), true );
         args.WaitForPostBack(true );
     }
 }
 

One last thing I want to cover.  I wanted to limit when my button would appear (it doesn’t make sense to set a Thumbnail for items other than renderings and templates, I don’t think).  Luckily, this is pretty easy.  In your Command class, you can override the QueryState() method and have it return a CommandState telling Sitecore if your button should be enabled, disabled, or hidden.  It receives a CommandContext object that can be used to find out what the current item is in the Content Editor.

I’ll take this opportunity to once again link my full Thumbnail Button Module ThumbnailButtonModule-1.zip which contains the full source.  In addition to what I’ve covered here, it contains the QueryState() code, the code to update the Thumbnail field on the current item, and some code that passes the existing thumbnail in to the media browser so that it’s pre-selected when the dialog opens.

Being able to display Sitecore’s media browser dialog to allow a user to choose or upload an image will come in handy for other projects, so I’m really glad I put the effort into figuring out how to make it work.  Hopefully, I’ve been able to share this knowledge here and other people will be able to take advantage of it as well!  If you have any questions, comments, critiques, etc – please post a comment here on the blog or reach out to me via Twitter – @williamsk000.

with 2 comment(s)
Filed under:

ThumbnailModule

Once I discovered how helpful it was to present thumbnails to content authors in the Page Editor, I started adding them to all of the templates and renderings that I created.  Very quickly, I started to get frustrated with the process (see my part 1 post for the details)...  I don’t like to leave standard fields visible all of the time, so having to turn those on and off and having to dig through them to find the Thumbnail field got old fast.  So I had an idea – add a custom button to the ribbon that would let me choose a thumbnail quickly without all of that hassle. 

The process of building a custom ribbon button, making it pop open the media browser dialog, handling the result, and updating the item’s thumbnail was rather complex and involved a bit of a learning curve for me.  So I’ve decided to leave the in-depth discussion for another blog post and just give the final solution here.

So, may I present - ThumbnailButtonModule-1.zip

The zip file contains a ready-to-go Sitecore package ZIP that you can install using Sitecore’s package installation wizard as well as the source code if you want to see how it was done.  If you compile the source yourself, you will need to update the namespace, class, and assembly name in the config file before placing it in your site’s App_Config\Include directory.  Also, if you don’t install the package then you will need to add the button to the ribbon in the Core database yourself.

I’m already working on another post for later today detailing how I built this module, so if you’re interested in the gory details - I'll have something for you soon!  And if you have any questions or comments or critiques, please let me know either in comments here or via Twitter @williamsk000.

with no comments
Filed under:

With Sitecore 6.4 and 6.5, the new unified Page Editor is wonderful for giving content authors a friendlier experience and more control over their page layouts.  I was never a fan of the page designer in previous 6.x releases, so I was thrilled to see the Page Editor changes.  One of the coolest parts, in my opinion, is the support for thumbnails when inserting new components or pages.  If you’re not familiar with them, here are a couple of screenshots.

InsertPage InsertRendering

Template and Rendering Select Dialogs with Thumbnails Provided

Now I may not be using it exactly as intended (anyone who knows for sure, feel free to comment), but I think this is a great opportunity to give content authors a more friendly interface for choosing what rendering to stick in a given placeholder or what type of page they want to create.

So how do you do it?  Today, I’ll show you the hard way using built-in Sitecore functionality.  Then tomorrow I’ll introduce a module I came up with to make the process much more streamlined (how the module was built deserves a blog post all to itself).  Let’s get started...

The key here is a new standard field named __Thumbnail.  It is in the Appearance section on all items deriving from Standard Template.  This is the “hard way” because that section is not visible within Content Editor by default, so you have to turn on visibility of Standard Fields.  I’ll walk you through the process for a template:

  1. Open Template Manager and navigate to the template you want to provide a thumbnail for.
  2. In the Ribbon, click on the View tab.
  3. In the View chunk, check the checkbox next to “Standard Fields”

    StandardFields
    Standard Fields Checkbox
  4. Switch to the “Content” tab for the template.

    ContentTab
    Content Tab
  5. Scroll down to the “Appearance” section (you may have to expand it) and look for the Thumbnail field.

    ThumbnailField
    Thumbnail Field
  6. Choose an image in this field and it will be displayed in the Insert dialog in the Page Editor.  You might want to use a screenshot from a comp or an actual page on the site instead of the lame wireframe I created for this post – it’s up to you.  Be sure to save your changes to the template!

This same process works for Branch Templates, XSL Renderings, and Sublayouts as well.  Note, to get renderings and sublayouts to appear in the Insert Renderings dialog, you will have to add them to the Allowed Controls on a placeholder settings item.  If you don’t know how that works and want me to post about it too, send me a message on Twitter or post a comment here.

Sitecore’s thumbnail feature is a great usability improvement in recent releases and can really help to guide a content author when making decisions about what type of page to create or which rendering to stick in a given placeholder.  Unfortunately, the field is a little difficult to get to in Sitecore’s default interface.  Tomorrow, I’ll post about a module I have created that adds a “Thumbnail” button to the ribbon to give you a convenient shortcut to assigning thumbnails.

One quick comment to the Sitecore guys regarding the unified Page Editor.  It’s bounds ahead of the old page designer, but I recently had an opportunity to work with Sitefinity 4.  Their drag-and-drop interface is even more intuitive – I would love to see something like that come to Sitecore!

with no comments
Filed under: ,