Tridion GUI Extension: Adding a new Tab to the Edit Window

May 31st, 2012 | Posted by Robert Curlette in GUI Extension | Tridion

Adding a new Tab to the Tridion Edit window is a powerful and easy GUI Extension to implement. The tab will show in all Edit windows or only the ComponentEdit “view”. SDL recently used this approach to integrate the Translation Management System (TMS) and World Server into the interface – great example of the extension! 🙂 In this tutorial we will create a ‘Hello There’ GUI Extension and explain the concepts behind adding an extra tab to the edit screen.

Getting Started
We’ll need the following:

  • Filesystem access to your Tridion 2011 CMS Server (Program Files\Tridion\)
  • Editor for XML, HTML, and ASCX files
  • A Tridion CMS system with no other users logged in (since we will most likely break the GUI at some point)

Summary, we will:
In Visual Studio, create a new project and an ASCX control

In a JavaScript editor, create a simple JavaScript GUI Extension

In an XML editor, create a HelloTab.config file and configure IIS

Copy files to a new folder on the server C:\Program Files (x86)\Tridion\web\WebUI\Editors\HelloTab and update the System.config file

Tips for working with Anguilla Framework

Part 1: Create the GUI Extension Project and add the User Control ASCX File

1. Open Visual Studio 2010 and create a new Project, ASP.NET Empty Web Project.
2. Add a new Web User Control (ascx file) to the project. Name it HelloTab.ascx
3. Add a literal control to the ascx page and in the code behind set the text property to ‘Hello world’.

* Note: I could have created an HTML page, but instead wanted to use an ASCX page to show where the DLL from the bin folder would end up. In real life I prefer to keep the client simple with HTML and jQuery and the heavy lifting in a Web Services layer powered by ServiceStack.net.

HelloTab.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="HelloTab.ascx.cs" Inherits="HelloTab.HelloTab" %>
<asp:Literal ID="output" runat="server"></asp:Literal>
<div id="compUri"></div>

HelloTab.ascx.cs

protected void Page_Load(object sender, EventArgs e)
{
    output.Text = "Hello world";
}

Compile and Build the Solution. The DLL will be copied to C:\Program Files (x86)\Tridion\web\WebUI\WebRoot\bin

Part 2: Create the JavaScript

Type.registerNamespace("RC");

RC.HelloTab = function RC$HelloTab$HelloTab(element) {
    console.log('Constructor');
    Tridion.OO.enableInterface(this, "RC.HelloTab");
    this.addInterface("Tridion.Controls.DeckPage", [element]); //My extension is like this
};

RC.HelloTab.prototype.initialize = function HelloTab$initialize()
{
    console.log('init');
    this.callBase("Tridion.Controls.DeckPage", "initialize");
    $evt.addEventHandler($display.getItem(), "load", this.getDelegate(this.updateView));
};

RC.HelloTab.prototype.select = function HelloTab$select() {
    var c = $display.getItem();
    $j("#compUri").text(c.getId());
    console.log('select');
    this.callBase("Tridion.Controls.DeckPage", "select");
    this.updateView();
};

RC.HelloTab.prototype.updateView = function HelloTab$updateView()
{
    console.log('update');
    if (this.isSelected())
    {
        console.log('selected')
    }
};

Tridion.Controls.Deck.registerPageType(RC.HelloTab, "RC.HelloTab");

Order of Events:

  • constructor
  • select
  • initialize
  • updateView
  • selected

Part 3: GUI Extension Configuration and Setup IIS Copy files to server

Creating the config file HellotTab.config:

Create a new file called HelloTab.config. In this example the JavaScript, CSS, and ASPX files are all in the same folder, HelloTab. Here is the source:

<?xml version="1.0"?>
<Configuration xmlns="http://www.sdltridion.com/2009/GUI/Configuration/Merge"
               xmlns:cfg="http://www.sdltridion.com/2009/GUI/Configuration"
							 xmlns:ext="http://www.sdltridion.com/2009/GUI/extensions"
               xmlns:cmenu="http://www.sdltridion.com/2009/GUI/extensions/ContextMenu">

  <resources cache="true">
    <cfg:filters />
    <cfg:groups>
      <cfg:group name="RC.HelloTab" merge="always">
        <cfg:fileset>
          <cfg:file type="script">/HelloTab.js</cfg:file>
          <cfg:file type="script">/jquery.js</cfg:file>
        </cfg:fileset>
        <cfg:dependencies>
          <cfg:dependency>Tridion.Web.UI.Editors.CME</cfg:dependency>
          <cfg:dependency>Tridion.Web.UI.Editors.CME.commands</cfg:dependency>
        </cfg:dependencies>
      </cfg:group>
    </cfg:groups>
  </resources>
  <definitionfiles />
  <extensions>
    <ext:dataextenders/>
    <ext:editorextensions>
      <ext:editorextension target="CME">
        <ext:editurls/>
        <ext:listdefinitions/>
        <ext:taskbars/>
        <ext:commands/>
        <ext:commandextensions/>
        <ext:contextmenus/>
        <ext:lists />
        <ext:tabpages>
          <ext:add>
            <ext:extension assignid="HelloTab" name="Hi There!" insertbefore="InfoTab">
              <ext:control>~/HelloTab.ascx</ext:control>
              <ext:pagetype>RC.HelloTab</ext:pagetype>
              <ext:dependencies>
                <cfg:dependency>RC.HelloTab</cfg:dependency>
              </ext:dependencies>
              <ext:apply>
                <ext:view name="ComponentView">
                  <ext:control id="MasterTabControl"/>
                </ext:view>
              </ext:apply>
            </ext:extension>
          </ext:add>
        </ext:tabpages>
        <ext:toolbars/>
        <ext:ribbontoolbars/>
      </ext:editorextension>
    </ext:editorextensions>
  </extensions>
  <commands/>
  <contextmenus />
  <localization />
  <settings>
    <defaultpage/>
    <navigatorurl/>
    <editurls/>
    <listdefinitions />
    <itemicons/>
    <theme>
      <path>theme/</path>
    </theme>
    <customconfiguration />
  </settings>
</Configuration>

A few things to highlight:

Name the config group:

cfg:group name="RC.HelloTab"

Specify any js or css files needed by the extension:

<cfg:fileset>
  <cfg:file type="script">/HelloTab.js</cfg:file>
</cfg:fileset>

Define standard dependencies:

<cfg:dependencies>
  <cfg:dependency>Tridion.Web.UI.Editors.CME</cfg:dependency>
  <cfg:dependency>Tridion.Web.UI.Editors.CME.commands</cfg:dependency>
</cfg:dependencies>

Define the ID, text for the tab, and location:

<ext:extension assignid="HelloTab" name="Hi There!" insertbefore="InfoTab">

The GUI ASCX control with HTML for the tab:

<ext:control>~/HelloTab.ascx</ext:control>

Define the Namespace and method for the JS file. I missed this the first time and my JS file would not load. Thanks to the StackOverflow post here for the help.

<ext:dependencies>
    <cfg:dependency>RC.HelloTab</cfg:dependency>
</ext:dependencies>

Specify the Edit view the Tab will appear on:

<ext:apply>
    <ext:view name="ComponentView">
      <ext:control id="MasterTabControl"/>
    </ext:view>
</ext:apply>

More about the Views option
Views – Which edit screen we load our GUI Extension
We can tell Tridion to only load our new Tab when we are editing a Component and not when editing a Template. To do this we’ll need to add a magic View name to the

The Tridion GUI Views are stored on the server at C:\Program Files (x86)\Tridion\web\WebUI\Editors\CME\Views.

The views folder contains some obvious ones like PageView and ComponentView. However, I am not sure about the DashboardView or CustomPageView – and hope that the Tridion Documentation team might come to our rescue here and weed out the ones that are not valid.

  • BluePrintViewerView
  • CategoryView
  • ComponentView
  • ComponentTemplateView
  • CustomPageView
  • DashboardView
  • FolderView
  • KeywordView
  • ListFiltersView
  • MultimediaTypeView
  • PageView
  • PageTemplateView
  • PopupsView
  • PublicationView
  • PublicationTargetView
  • SchemaView
  • SplashScreenView
  • StructureGroupView
  • TargetGroupView
  • TargetTypeView
  • TemplateBuildingBlockView
  • TridionDashboardView
  • UserAccountsView
  • VirtualFolderView
  • WorkflowProcessView

Save the config file. Create a JS file HelloTab.js for the interaction with the Tridion GUI and Anguilla API. Below is a basic example:

Setup Virtual Directory in IIS
– Add VDIR to IIS, point to HelloTab Editor folder
– The name of the VDIR should match the VDIR node in the system.config file.

Part 4: Copy files to Server and update System.config

Create folder and copy files
– Create a new Folder in the Editors folder called ‘HelloTab’. Full path is ‘C:\Program Files (x86)\Tridion\web\WebUI\Editors\HelloTab’
– Copy HelloTab.ascx, HelloTab.js, and HelloTab.config files
– Copy the DLL file from the build output to ‘C:\Program Files (x86)\Tridion\web\WebUI\WebRoot\bin’. This is the location where all the DLLs associated with a GUI Extension are deployed. If you register the DLLs in the GAC then you could place them in another location.

Add Extension to System.config:

<editor name="HelloTab">
  <installpath>C:\Program Files (x86)\Tridion\web\WebUI\Editors\HelloTab\</installpath>
  <configuration>HelloTab.config</configuration>
  <vdir>HelloTab</vdir>
</editor>

Test
The new Tab should appear in the ComponentEdit screen. Great! But, we still need to do something in the tab.  Let’s add some JavaScript and talk with the Anguilla API.

Part 5: Working with the JS Anguilla API

Anguilla is the powerful Tridion JavaScript framework that makes the magic in the Tridion 2011 GUI possible.  Unfortunately, it is not well known and not too many code samples are available yet.  Some hints of methods and objects can be found in the Tridion 2011 Views folder at C:\Program Files (x86)\Tridion\web\WebUI\Editors\CME\Views. The Tridion 2011 PowerTools also use the Anguilla framework and provide additional opportunities to gain hints. SDL Tridion World has the Anguilla documentation available for download in the Documentation downloads section. With all that said – most Tridion developers that I know have a background in server-side Web development and writing OO JavaScript is not in the comfort zone of many, including me.  We have the option to do the minimum in Anguilla and then run to the Core Service to do the heavy lifting – but I hope in the future we can use more of the built-in methods in Anguilla.

Trick for jQuery

Tridion PowerTools use jQuery and have a trick to load it so it does not conflict with Outbound Email. Clever! After adding this then we use $j for our jQuery magic.

var addJquery = function ()
{
    // ... jQuery here ...
    //YM: to avoid conflict with the Outbound Email extension, we define a new shorthand for jQuery
	window.$j = jQuery.noConflict(true);
};
addJquery();

Using jQuery in the JS code:

 $j("#compUri").text("tcm:0-0-0");

Displaying the URI in the Tab

var c = $display.getItem();
$j("#compUri").text(c.getId());

Fun with the Chrome Developer Console and Anguilla:

  1. Set a breakpoint on the line after the var c =
  2. Open the Chrome Debugger
  3. Scripts tab
  4. Component…aspx script
  5. Scroll to bottom of script and find your code. Alternative use the find feature of Chrome. You should see console.log(‘select’);
  6. Add a breakpoint by clicking on the line #
  7. Now refresh and it will stop on that line when you’ve seelcted the new tab. Don’t hit continue yet.
  8. Go to the Console tab, hit c. and amaze at the amount of methods we have available – via the Anguilla JavaScript Framework – at our disposal.

The Tridion Live Documentation contains a very quick guide to Tab GUI Extensions here. Don’t forget to login first before clicking the link.

Summary

This GUI Extension is a simple one and is intended to give you the ideas and some confidence with creating your first one. With the Component URI and the power of the Anguilla Framework you can already do some magic via JavaScript in the tab with this example. However, it is also possible to make a webservice call from the js and do more server-side api work there. I hope you were able to follow along and that this inspires you to create your own extensions. A big thanks to the Tridion community on StackOverflow – without you the article would not be possible.

Get the code

https://github.com/rcurlette/GuiExtensionHelloTab

You can follow any responses to this entry through the RSS 2.0 You can leave a response, or trackback.

7 Responses

  • Frank van Puffelen says:

    Hey Robert,

    To prevent the first-log-on-and-only-then-click-the-link syndrome for getting to the live documentation, you can get a link from the breadcrumb trail at the top of each topic as documented here (http://sdllivecontent.sdl.com/LiveContent/content/en-US/SDL_Tridion_2011_SPONE/concept_274AF392F99B4571814FA892BB282F5B).

    That link will both be shorter (that’s the reason I always use them), but will also correctly redirect to the topic after you log on (something I just learnt from our tech writers).

    Thanks for the great article (as usual),

    Frank

  • robert curlette says:

    Hi Frank,

    Thanks for the great feedback. I really appreciate the tip on the Live Documentation URLs! Will definitely improve the user experience for everyone and I will start using it in the future. Will also help my own personal bookmarks too! 🙂

    Robert

  • Peter Kjaer says:

    Great post – thanks Robert!

    I’m not sure what the deal is about JQuery and Outbound E-mail conflicts. OE doesn’t use JQuery so I’m not sure what the workaround is supposed to solve.

    I’ll have to take a look at that the next time I work on the PowerTools 🙂

  • Sadasivam says:

    Hi Robert,

    I tried to add a tab in the formView by following your article, i could see the Tab coming up in the component edit view but the component is not loading completely. It just loads all the tabs and it shows the loading message in the Schema dropdown and freezes there.

    i cross verified all the configs and commented out the code part in JS file as well but nothing helped.

    I have cleared the cache and updated the modification attribute as well. Nothing helped.

    Any suggestions will help

    Thanks,
    Sadasivam

  • Sadasivam says:

    Sorry .. the issue is fixed. It was a syntax error in the Js file. I found it using firebug.

    Thanks Robert

  • Thanks for this post Rob, just helped me troubleshoot an issue.

    In my .select, I didn’t call the base:

    this.callBase(“Tridion.Controls.DeckPage”, “select”);

    miss that and the whole thing vanishes / doesn’t even hit the init method.

  • keirthana says:

    I have implemented this but I have 2 action items stuck up:

    1. I need this tab control to come up only for a particular publication.
    2. For that publication, the fields in the custom tab are mandatory and I need a way to validate them.

    Can you please guide how I can achieve this?



Leave a Reply

Your email address will not be published. Required fields are marked *