This is a small example of how to create a context-menu extension to copy the URI of a Tridion Item.  

Getting Started

The most important and also difficult part of every GUI Extension is the configuration file.  It’s best to start with a previous working example.  For this article I used the classic 8 Steps post from Yoav Nirlan.

Create the Directory

Create a new Folder in:
C:\Program Files (x86)\Tridion\web\WebUI\Editors\CopyUri

Configuration File

I started with the configuration file from the Tutorial and also loaded the Schemas into Visual Studio from Tridion.  This was a very important step because Tridion 2011 SP1 has a slightly different XML Schema for the Context Menu than Yoav’s sample does.  I relied on the intellisenne in Visual Studio and the XML Schema to get a properly formatted Configuration file.  In the future I will start with this updated config file below for Context-menu extensions.

Save it as CopyUri.config in the folder created above.

<?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="Extensions.Resources.CopyUri" merger="Tridion.Web.UI.Core.Configuration.Resources.CommandGroupProcessor" merge="always">
        <cfg:fileset>
          <cfg:file type="script">/Commands/CopyUriCommand.js</cfg:file>
          <cfg:file type="reference">2011Extensions.Commands.CopyUri</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:editorextensions>
      <ext:editorextension target="CME">
        <ext:editurls />
        <ext:listdefinitions/>
        <ext:taskbars/>
        <ext:commands />
        <ext:commandextensions/>
        <ext:contextmenus>
          <ext:add>
            <ext:extension name="CopyUriExtension" assignid="ext_copyuri" insertbefore="cm_refresh">
              <ext:menudeclaration externaldefinition="">
                <cmenu:ContextMenuItem id="ext_CopyUri" name="Copy URI" command="CopyUri"/>
              </ext:menudeclaration>
              <ext:dependencies>
                <cfg:dependency>Extensions.Resources.CopyUri</cfg:dependency>
              </ext:dependencies>
              <ext:apply>
                <ext:view name="DashboardView"/>
              </ext:apply>
            </ext:extension>
          </ext:add>
        </ext:contextmenus>
        <ext:lists/>
        <ext:tabpages/>
        <ext:toolbars/>
        <ext:ribbontoolbars/>
      </ext:editorextension>
    </ext:editorextensions>
    <ext:dataextenders/>
  </extensions>
  <commands>
    <cfg:commandset id="2011Extensions.Commands.CopyUri">
    <cfg:command name="CopyUri" implementation="Extensions.CopyUri"/>
    <cfg:dependencies>
    <cfg:dependency>Extensions.Resources.Base</cfg:dependency>
    </cfg:dependencies>
    </cfg:commandset>
  </commands>
  <contextmenus/>
  <localization/>
  <settings>
    <defaultpage>/Views/Default.aspx</defaultpage>
    <navigatorurl>/Views/Default.aspx</navigatorurl>
    <editurls/>
    <listdefinitions/>
    <itemicons/>
    <theme>
      <path/>
    </theme>
    <customconfiguration/>
  </settings>
</Configuration>

Important parts of the Configuration File

Location of the command in the Context Menu:

insertbefore="cm_refresh"

Text of the menu item:

name="Copy URI"

Important info for the JavaScript in the next part:
1.  Command name
2.  Implementation

<cfg:command name="CopyUri" implementation="Extensions.CopyUri"/>

The command name is also used here:

<cmenu:ContextMenuItem id="ext_CopyUri" name="Copy URI" command="CopyUri"/>

The Commands are in the xml root ‘commands’ node, not the ‘ext:commands’.

 </extensions>
  <commands>
    <cfg:commandset id="2011Extensions.Commands.CopyUri">
    <cfg:command name="CopyUri" implementation="Extensions.CopyUri"/>
    <cfg:dependencies>
    <cfg:dependency>Extensions.Resources.Base</cfg:dependency>
    </cfg:dependencies>
    </cfg:commandset>
  </commands>
  <contextmenus/>

No Ribbon button was added in this demo.

JavaScript Code

1.  Create a new folder ‘Commands’.
2.  Create a new file called CopyUriCommand.js

Type.registerNamespace("Extensions");

Extensions.CopyUri = function Extensions$CopyUri() {
    Type.enableInterface(this, "Extensions.CopyUri");
    this.addInterface("Tridion.Cme.Command", ["CopyUri"]);
};

Extensions.CopyUri.prototype.isAvailable = function CopyUri$isAvailable(selection) {
    return true;
}

Extensions.CopyUri.prototype.isEnabled = function CopyUri$isEnabled(selection) {
    if (selection.getItems().length > 1)
        return false;
    else
        return true;
}

Extensions.CopyUri.prototype._execute = function CopyUri$_execute(selection) {
    selectedItem = selection.getItems()[0];
    prompt("Copy the Item ID using Ctrl/Cmd + C:", selection.getItems()[0]);
}

 Code Explained:

1.  The isEnabled method tells the GUI if the menu option is enabled or disabled.  This extension shows the URI for only one item, so I only enable the extension if one item is selected.
2.  The execute method does the action.  We have available all methods and objects in the Tridion Anguilla framework.  The getItem method returns null but we are lucky that getItems returns whatever is selected in the GUI.  We use the prompt method of JavaScript to provide a nice small window to copy the URI from.

Creating the Virtual Directory in IIS

Create a new Virtual Directory in WebUI/Editors called CopyUri.  This name needs to be the same as the VDIR in the config from the next step.  You may need to update the Security settings for the folder and allow the Network Service user read access.  Use the ‘Test’ button after setting up and you should have a checkmark next to the first test.  The second test will fail and this is normal.

Enabling the Extension

Open the System.config file located at:  <Tridion_home>\web\WebUI\WebRoot\Configuration

Add the following to ‘turn on’ the Extension.  If your Tridion GUI stops working – comment out the following line and it should return to normal.  Double-check your config and settings.

<editor name="CopyUri" xmlns="http://www.sdltridion.com/2009/GUI/Configuration">
	<installpath xmlns="http://www.sdltridion.com/2009/GUI/Configuration">C:\Program Files (x86)\Tridion\web\WebUI\Editors\CopyUri\</installpath>
		  <configuration xmlns="http://www.sdltridion.com/2009/GUI/Configuration">CopyUri.config</configuration>
		  <vdir xmlns="http://www.sdltridion.com/2009/GUI/Configuration">CopyUri</vdir>
</editor>

Copying the WebDav URL

Big thanks to Alex Klock from Tridion Community for answering my question about getting the WebDavURL in Anguilla.  Here is the code we could add to the execute method above to show the WebDav URL instead of URI.

var item = $models.getItem(selectedItem),
    webDavUrl = item.getWebDavUrl();

if (!webDavUrl) {
    // WebDavUrl for cached item hasn't been loaded yet, so lets load it.
    $evt.addEventHandler(item, "loadwebdavurl", function (event) {
        webDavUrl = item.getWebDavUrl(); // also could do event.source.getWebDavUrl()
    });
    item.loadWebDavUrl();
}

Summary

This is a simple GUI Extension but it highlights some basics we need to know when developing a GUI Extension.  The Developer Console in the Chrome Browser was a big help while debugging and writing the JavaScript code.  A big thanks to Hristo Chakarov for his help with the JavaScript development in this post.

If we want to execute some code for Staging but not for the Live Publish Target we need to detect the target title during Publish Time.  In this article I will show how to get the Publish Target Title in VBScript, Razor and C#.

A long long time ago in a land far away….Publication Target Title in VBScript

Before we had the power of .NET we used VBScript (or XSLT) to render our beautiful content from Tridion.  The VBScript rendering engine has the TcmScriptAssistant class to provide handy methods like WriteOut and also objects such as PublicationTarget and PublicationTargetId.  To get the PublicationTarget Title in VBScript we typed:

[% =PublicationTarget.Title %]

Getting the Publication Target Title with a Razor TBB

Today we have the powerful Razor Meditator for rendering our .NET and Razor code since the TcmScriptAssistant is no longer available in our Compound Templates.  So, how do we get the Publication Target Title?

@{
var engine = TridionHelper.Engine;
var publishContext = engine.PublishingContext;
var pubTargetTitle = publishContext.PublicationTarget.Title;
}

Getting the Publication Target Title in a C# TBB

We might be using DWT TBBs and want access to the Publication Target Title.  In this case, we could create a C# TBB, get the Publication Target Title and push it into the Package.

PublishingContext publishContext = engine.PublishingContext;
pubTargetTitle = publishContext.PublicationTarget.Title;
log.Info("PubTargetTitle = " + pubTargetTitle);

Summary
Using the engine object we can get more info about our publishing environment and access properties related to the processing of the item, including publishing context details.   The Publication Target Title is still there and with a bit of looking it is not too hard to find.  Big thanks to Alex Klock for writing the Razor Mediator and keeping up with the bug fixes and feature requests.

In Tridion 2011 we have the opportunity to write C# templates with .NET 4.0.  If you reference an external DLL or another Visual Studio project from your template project the DLL needs to be registered in the GAC.   Follow this short guide to help you get started with registering your external DLLs to reference from your templates.

1. Sign the Assembly in Visual Studio if your external DLL is a Visual Studio project.   Otherwise, you should generate an snk file for your existing external DLL.
http://msdn.microsoft.com/en-us/library/ms247123.aspx

2. Compile Project and copy the DLL to the Tridion Bin folder or another Folder on the CMS server.

3. Use Gacutil to register external DLL.  If you have VS 2010 SP 1 installed it is located in ‘C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools’

"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools\gacutil.exe" /i file.dll

http://social.msdn.microsoft.com/Forums/mr/netfxgeneralprerelease/thread/b0591260-20a5-48af-99d5-55eca6e9e2e9

4. Verify it is in the GAC:

"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\NETFX 4.0 Tools\gacutil.exe" /l > gac.txt

Open gac.txt in a text editor

5. Compile and Build the Compound Template to deploy the DLL Templates

6. Open Template Builder and Preview the Template.  Use the Logger to write to the log file.

In this post we’ll continue Nuno’s series on Content Validation and create a GUI Extension using the Anguilla framework to validate a Component’s field content while exploring little-seen Anguilla JavaScript methods to inspect the field content and validate the Save events from the GUI.  Big thanks to Nuno Linhares for writing this article and allowing me to be the Editor.

Solution on Github:  https://github.com/rcurlette/ValidateTitleFieldPart2/

Summary:  Validate that the Component Title field contains an Uppercase letter as the first character after pressing the Save button and show a warning message if a number or lowercase letter is the first character.  We will use Anguilla JavaScript for the field validation.  The estimated time to complete this tutorial is around 90 minutes.  Here is what it will look like in the end:

Overview

  1. Create the Visual Studio Project , Folders and Files (empty)
  2. Create the GUI Extension configuration and setup IIS
  3. Add the Anguilla JavaScript code to Validate the Title Field
  4. Debugging

Create the Visual Studio Project and setup the file structure

We’re going to do this using the CME API (Anguilla) with a javascript alert, and we will extend the following 3 CME commands: “Save”, “Save and Close” and “Save and New”.
Let’s start by creating a Visual Studio Project for our requirements. I tend to start with an Empty Solution, then add the the “Editor” project.  In the next part of this tutorial we will also use a  “Model” project but not in this tutorial. (note that I use the project type “ASP.NET Empty Web Application”).

Delete the first project that Visual Studio always creates.

Now add 1 new project: ValidateTitleFieldEditor

Again, use the “Empty ASP.NET solution” template.

Let’s create the skeleton of our extension. In the Editor project, add the following folders:

  • Commands
  • Config

Under commands, let’s create a file named “ValidateTitleFieldCommand.js” – Visual Studio seems to believe people still use Jscript, let’s not get bothered by it.

Under Config create a file named “ValidateTitleFieldEditor.config”.  This will be used to configure our GUI Extension to ‘listen’ to the Save events.

You should have something similar to this in your project now:

Create the GUI Extension configuration and setup IIS

Here we will add the configuration to the ValidateTitleFieldEditor.config and much of it will not make any sense.  Please follow along and we will be at the fun part in no time.

Open the Configuration ValidateTitleFieldEditor.js file.

If you haven’t learned how to yet, make sure you add the Tridion Schemas to this editor. Right click anywhere on the config file, select properties.

Click on the … button for the Schemas, and add all schemas from [Tridion]\Web\WebUi\Core\Schemas

Tip: you may want to add these schemas to the default Visual Studio schemas, under “C:\Program Files (x86)\Microsoft Visual Studio 10.0\Xml\Schemas”

Let’s build our configuration file with the following:

<?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="ValidateTitleField.CommandSet">
        <cfg:fileset>
          <cfg:file type="script">/Commands/ValidateTitleFieldCommand.js</cfg:file>
          <cfg:file type="reference">ValidateTitleField.Interface</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:commands>
            <ext:command name="Save" extendingcommand="ValidateTitleField"/>
          </ext:commands>
          <ext:dependencies>
            <cfg:dependency>ValidateTitleField.CommandSet</cfg:dependency>
          </ext:dependencies>
        </ext:commandextensions>
        <ext:contextmenus />
        <ext:lists />
        <ext:tabpages />
        <ext:toolbars />
        <ext:ribbontoolbars />
      </ext:editorextension>
    </ext:editorextensions>
  </extensions>
  <commands>
    <cfg:commandset id="ValidateTitleField.Interface">
      <cfg:command name="ValidateTitleField" implementation="Company.Extensions.ValidateTitleFieldCommand"/>
    </cfg:commandset>
  </commands>
  <contextmenus />
  <localization />
  <settings>
    <defaultpage />
    <editurls />
    <listdefinitions />
    <itemicons />
    <theme>
      <path />
    </theme>
    <customconfiguration>
    </customconfiguration>
  </settings>
</Configuration>

What are we doing in this configuration?

We’re defining 1 group of files:

<cfg:group name="ValidateTitleField.CommandSet">
        <cfg:fileset>
          <cfg:file type="script">/Commands/ValidateTitleFieldCommand.js</cfg:file>
          <cfg:file type="reference">ValidateTitleField.Interface</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>

The group is a “CommandSet” and we’re basically telling Tridion to treat these files as a group, and that the files have dependencies on other Tridion items.

We’re also saying that this extension targets an existing editor: CME

<ext:editorextension target="CME">

 

And within this, we’re extending the “Save” Command with our own CommandSet.  Note:  This is where we wire up to the Save, Save and Close, and Save and New commands.

<ext:commandextensions>
          <ext:commands>
            <ext:command name="Save" extendingcommand="ValidateTitleField"/>
	    <ext:command name="SaveClose" extendingcommand="ValidateTitleField"/>
	    <ext:command name="SaveNew" extendingcommand="ValidateTitleField"/>
          </ext:commands>
          <ext:dependencies>
            <cfg:dependency>ValidateTitleField.CommandSet</cfg:dependency>
          </ext:dependencies>
        </ext:commandextensions>

 

And finally we’re registering a new CME Command:

<commands>
    <cfg:commandset id="ValidateTitleField.Interface">
      <cfg:command name="ValidateTitleField" implementation="Company.Extensions.ValidateTitleFieldCommand"/>
    </cfg:commandset>
  </commands>

That “implementation” attribute is the name of the Anguilla Class that we will use to implement the command.

 

Adding the extension to IIS and registering in Tridion

Let’s add our extension as a Virtual Directory to the CME’s “Editors” folder. I tend to point these directly to my development folder so that all code changes are immediate.

As you can see in the screenshot, the physical path should match the start of your “Editor” project.

Tridion Content Manager Explorer Configuration
The Tridion CME uses a file to hold all the editor and model configurations (plus quite a lot of other settings). You will find this file under [Tridion]\Web\WebUI\WebRoot\Configuration\System.Config

1. Make a backup copy of this file, and edit it with a proper XML Editor (like Visual Studio).
2. Find the Element named “<editors default=”CME”>” (around line 1000 in my system.config).
3. Add one editor configuration element with YOUR values to change the path:

<editor name="ValidateTitleFieldEditor">
      <installpath>D:\Tridion 2011\ValidateTitleField\ValidateTitleFieldEditor</installpath>
      <configuration>Config\ValidateTitleFieldEditor.config</configuration>
      <vdir>ValidateTitleField</vdir>
    </editor>

4. Restart IIS (iisreset) and reload the Tridion Content Manager Explorer.

Summary
We’re done with the boring part.  Now we can have some fun with the JavaScript action and doing something in the GUI.

 

Creating the JavaScript  for the Anguilla Save Event – The Command

Let’s create our Command. Open the “ValidateTitleFieldCommand.js” file.

For now, all that we want is to get our extension loading (and being able to verify it), so let’s add the following code:

Type.registerNamespace("Company.Extensions");

Company.Extensions.ValidateTitleFieldCommand = function ValidateTitleFieldCommand() {
    Type.enableInterface(this, "Company.Extensions.ValidateTitleFieldCommand");
    this.addInterface("Tridion.Cme.Command", ["ValidateTitleFieldCommand"]);
};

Company.Extensions.ValidateTitleFieldCommand.prototype._isAvailable = function ValidateTitleFieldCommand$_isAvailable(selection) {
    console.debug("Is Available called");
    return $cme.getCommand("Save")._isAvailable(selection);
};

Company.Extensions.ValidateTitleFieldCommand.prototype._isEnabled = function ValidateTitleFieldCommand$_isEnabled(selection) {
    console.debug("Is Enabled called");
    return $cme.getCommand("Save")._isEnabled(selection);
};

Company.Extensions.ValidateTitleFieldCommand.prototype._execute = function ValidateTitleFieldCommand$_execute(selection, pipeline) {
    console.debug("Execute called");
    return $cme.getCommand("Save")._execute(selection, pipeline);
};

This implements the _isAvailable, _isEnabled, and _execute functions required for every command. As you can see, all we’re doing is logging that the code was invoked (so we can verify it was loaded) and telling Tridion to go ahead and execute the “Save” Command.  The console.debug statement will write the output the the Firebug Console window or Console window in the Chrome Developer Tools.

We should now have enough to register this (Editor) extension with Tridion. To do this, we need to tell Tridion that we are an extension, and where the configuration for the extension is.

How do I know it’s working?

Well, there’s a few easy ways to do this. If you messed up something, chances are that your CME will look like this:

Open a Javascript console (Firebug is best here) and you’re likely to see this error:
Uncaught ReferenceError: Tridion is not defined

This is very generic, but usually comes with a very useful URL just before it:
http://t2011guruv3/WebUI/Editors/CME/Views/Dashboard/Dashboard_v6.1.0.55920.11_.aspx?mode=js
or http://$$SERVERNAME$$/WebUI/Editors/CME/Views/Dashboard/Dashboard_v$$TRIDION_CME_VERSION$$.$$CONFIGURATION_VERSION$$.aspx?mode=js

URL in FireBug GUI:

Open this url in your browser and you might have a lot more information (Chrome does not show the URL):

In this case, the error is caused because my Editor configuration in System.Config points to a vdir named “ValidateTitleFieldEditor” but the Virtual Directory in IIS is called “ValidateTitleField”. Changing the configuration to specify the correct vdir will fix the issue. If you had a different issue, chances are that opening this url in a browser will give you concrete error messages that should guide you into fixing your problem.

Once you fix your issue you should be able to load both the CME and the JS file:

Tip – if your Javascript is loading minified/obfuscated, you can change this setting.

If you were paying attention to any of this, you should know how to test if your command is being called. If you weren’t, here’s how.

  1. We configured our command as an extension to the “Save” Command (in ValidateTitleFieldEditor.config)
  2. We added 3 functions to our JS – _isAvailable, _isEnabled and _execute
  3. We added a “console.debug” instruction to all those functions.

So basically now we just need to:

  1. Clear your browser cache
  2. Reload the CME
  3. Open a Javascript debug console (I recommend chrome)
  4. Go somewhere in the CME where the Save command would be available (open a page or a component)

If you now open the console you should be able to see something like this:

This confirms our command is being called and our GUI Extension is working.

Now let’s tell our users about their mistake with a popup.  In the popup we will show them a message that the title field needs to start with a Captial letter.  This involves using the Anguilla API to inspect the field’s value when the Save, Save and Close, or Save and New button.

Before moving on, let’s do ‘Save All’ in Visual Studio.  Here’s a neat trick that might help you moving forward.  Instead of opening the project as we have defined now, try doing the following:

  1. Open Visual Studio
  2. Select File -> Open -> Website
  3. Select “Local IIS” on the left side, then search for the “SDL Tridion 2011″ website, expand it and select “WebUI”.

Visual Studio is going to ask you if you want to upgrade your configuration to ASP.NET 2.0 – Select ‘No’ – do not ever say yes, unless you can safely claim you know what you’re doing.  If you have not yet saved all files, the first popup will ask if you want to ave files – for this select ‘yes’

Once it’s open you should now see your editor under “Editors”:

This loads the rest of the Tridion CME as well, which will:

  1. Make visual studio pretty slow at times
  2. Give you some small help with some IntelliSense (though you can’t trust the whole of it)

Now that we’re here, we’re going to try reading the current value of the “Title” field in the component you’re trying to save. So, just like with any other Tridion Extension, the first thing we’ll do is make sure we should be executing _at all_.

Conditions for executing are:

  1. Item you’re editing is a component
  2. Current component’s schema has a field named “Title”
  3. Value of this field does not start with an Uppercase letter.

Open the ValidateTitleFieldCommand.js file and modify the _execute method to determine if we should execute:

Company.Extensions.ValidateTitleFieldCommand.prototype._execute = function ValidateTitleFieldCommand$_execute(selection, pipeline) {
    console.debug("Execute called");
    var p = this.properties;
    var item = $display.getItem();
    if (item) {
        if (item.getItemType() == "tcm:16") {
            // We know it's a component
            var fieldBuilder = $display.getView().properties.controls.fieldBuilder;
            if (fieldBuilder.getField("Title")) {
                // We have a field named Title
                var titleField = fieldBuilder.getField("Title");
                if (titleField.getValues().length > 0) {
                    var fieldValue = titleField.getValues()[0];
                    console.debug("Current title value is " + fieldValue);
                    // Voodoo magic
                    var firstCharacter = fieldValue.substring(0, 1);
                    if (isNaN(firstCharacter)) {
                        if (firstCharacter != firstCharacter.toUpperCase()) {
                            console.debug("First character is NOT uppercase");
                        } else {
                            console.debug("First character is uppercase");
                        }
                    } else {
                        // Interestingly isNaN returns false on a space. Good to know, I guess
                        console.debug("First character is a number!");
                    }
                }
            }
        }
    }
    return $cme.getCommand("Save")._execute(selection, pipeline);
};

The fieldBuilder is the magic here that provides us the ability to read fields in the Tridion GUI.  Using the JavaScript FireBug Console we can set a breakpoint on this line and then go to the Console window and inspect the object for other properties and methods.

Also, notice the return statement where we allow the GUI to continue saving.

At this point we can start thinking about the real solution. You could, for instance, add an alert(“First letter of title must be Upper Case”) to your code and stop the execution of the Save command (commented the changes to the code):

Company.Extensions.ValidateTitleFieldCommand.prototype._execute = function ValidateTitleFieldCommand$_execute(selection, pipeline) {
    console.debug("Execute called");
    var item = $display.getItem();
    var failed = false;  // ** Added
    if (item) {
        if (item.getItemType() == "tcm:16") {
            // We know it's a component
            var fieldBuilder = $display.getView().properties.controls.fieldBuilder;
            if (fieldBuilder.getField("Title")) {
                // We have a field named Title
                var titleField = fieldBuilder.getField("Title");
                if (titleField.getValues().length > 0) {
                    var fieldValue = titleField.getValues()[0];
                    console.debug("Current title value is " + fieldValue);
                    // Voodoo magic
                    var firstCharacter = fieldValue.substring(0, 1);
                    if (isNaN(firstCharacter)) {
                        if (firstCharacter != firstCharacter.toUpperCase()) {
                            console.debug("First character is NOT uppercase");
                            // *** Show popup
                            alert("First character of 'Title' field must be uppercase");
                            failed = true;
                        } else {
                            console.debug("First character is uppercase");
                        }
                    } else {
                        // Interestingly isNaN returns false on a space. Good to know, I guess
                        console.debug("First character is a number!");
                        // *** Show popup
                        alert("First character of 'Title' field cannot be a number.");
                        failed = true;  // *** Stop save action
                    }
                }
            }
        }
    }
    if(!failed)
        // *** Continue saving
        return $cme.getCommand("Save")._execute(selection, pipeline);
};

Which would result in something like this showing up to your editors.  We did it!  Congratulations for making it this far!

Debugging

Let’s see if our GUI Extension code is firing:
– Open Firefox, FireBug, Script Tab
– Open a Component

Search for ‘ValidateTitleFieldCommand’ and around line 96404 you will see our new GUI Extension JavaScript code.  Here I place a breakpoint and then with pressing the Save button I can step through the code.

While stepping through code I can also go to the Console Window and see the other methods  and properties that are available for these objects.

Summary

The Tridion 2011 Anguilla Framework gives us the opportunity to provide friendlier feedback to the user and also increase the quality of content entered into Tridion by enforcing editorial guidelines.  We’ve used the Anguilla Framework to access the fieldBuilder object in the Tridion GUI and inspect the field contents, showing a warning if they do not meet our requirements.  In the next post we’ll update the popup and allow users to make changes to the content in the popup window itself.  Thanks again to Nuno for creating this awesome post.

Solution on Github:  https://github.com/rcurlette/ValidateTitleFieldPart2/

The Tridion 2011 GUI contains HTML ID attributes for many elements and lets our GUI Extension JavaScript to hook into these elements to hide, show, or manipulate their appearance. I use a wide-screen monitor and prefer to re-size my tree window pane when I’m doing lots of navigation in the Tridion tree. In this article I will show how a simple JavaScript GUI extension can re-size the tree navigation pane with one keystroke.

Making the tree pane wider

I found myself resizing the Tridion tree every time I used the GUI and decided to make a small shortcut that could set it to my desired width using 1 keystroke. With some research I found the ID tag for the Navigation Tree and was easily able to set the width using a JavaScript GUI Extension. Of course, if we know the ID of the element we can get it and perform other actions as well – such as hiding it or adding extra info to the GUI beside it. As with all GUI Extensions this requires the utmost care and consideration and should not be attempted at home without parental supervision. Using a shortcut hotkey to trigger the JavaScript call makes it less invasive than re-writing the GUI behavior by default.

Re-sizing the tree pane is accomplished with this bit of JavaScript to modify the width attribute:

$j('#NavigationPanel').width('350');

The $j maps to jQuery. At the end of my jQuery min js file I add:

window.$j = jQuery.noConflict(true);

This is needed since Tridion internally uses $ and from Jaime’s recent post it also uses $$. Interesting.

Enabling with shortcuts

To implement this tweak I put them in a JavaScript file that is loaded into Tridion using a GUI Extension. Not just any GUI Extension, however, but the Shortcut keys extension I wrote about earlier that allow us to define our own Shortcut key combination and execute JavaScript. This allows us to toggle when we want to activate these settings – since maybe other users like the default settings. You could also have multiple settings and use different hotkeys to enable them.

shortcuts.js

//If you only want your code to affect certain screens/views, you should listen to Anguilla events like this:
$evt.addEventHandler($display, "start", onDisplayStarted);

// This callback is called when any view has finished loading
function onDisplayStarted() {

	// Open Publish Queue dialog
	Mousetrap.bind('q', function() {
			//var popup = $popup.create($cme.Popups.PUBLISH_QUEUE.URL, $cme.Popups.PUBLISH_QUEUE.FEATURES);
			//popup.open();
			$commands.executeCommand('PublishingQueue')
	});

	Mousetrap.bind('w', function() {
		// make tree pane wider - must click mouse in the ribbon or breadcrumb area before activating
		// - will not work if focus is in tree or content pane
		$j('#NavigationPanel').width('350');
	});

    $evt.removeEventHandler($display, "start", onDisplayStarted);
}

Testing

Place the focus of your cursor to the breadcrumbs pane or the ribbon pane and make sure nothing is selected.  Then press the hotkey ‘w’ and witness the tree menu width being reset to your dimensions in the shortcuts.js file.  The mousetrap library does not enable shortcuts if any element is selected on the screen.  You could, of course, move the jQuery call to modify the width outside the shortcuts key, but then it would always be enabled for all users.

Installing

  1. Create Folder for Extension: C:\Program Files\Tridion\web\WebUI\Editors\Shortcuts
  2. Add the Shortcuts.config file to the folder Shortcuts
  3. In Shortcuts create a js folder. Path is: C:\Program Files\Tridion\web\WebUI\Editors\Shortcuts\js
  4. Copy 3 javascript files to the js folder.
  5. - mousetrap.js – javascript shortcut library
  6. - shortcuts.js – our Tridion GUI Extension shortcuts actions
  7. - jquery-1.7.2.min.js – jQuery library with the j$ noConflict specified
  8. Open IIS and create a Virtual Dir at SDL Tridion 2011/WebUI/Editors/Shortcuts. Point the home dir to the Editors\Shortcuts dir
  9. Open the GUI Configuration,   C:\Program Files\Tridion\web\WebUI\WebRoot\Configuration, and add the new GUI Extension.
<editor name="Shortcuts">
 <installpath>C:\Program Files\Tridion\web\WebUI\Editors\Shortcuts\</installpath>
 <configuration>Shortcuts.config</configuration>
 <vdir>Shortcuts</vdir>
 </editor>

Code here:
https://github.com/rcurlette/TridionBrowserDefaults

The SDL Tridion World Server connector bridges the world of Content Management and Translation Management.  Providing an easy to use interface that allows the author to directly send items for translation and review the translation process brings a boost in productivity and efficiency to multi-lingual websites.  In addition, it eliminates the overhead of creating and assigning tickets internally as the content items enter into workflow without any additional work.  Recently I had the opportunity to implement the SDL World Server connector and was impressed with the tight integration between the two platforms. In this article I will discuss installing, configuring and using the World Server connector. I will not go into any advanced topics such as using the Event System with World Server.

Tridion’s strength is the management of content across languages and sites using the BluePrint technology built into the core of the product. SDL bought Tridion in 2007 and integrated Tridion into its’ suite of translation products, introducing a Tridion connector for both World Server and the Translation Management Server. These products were made for each other – and putting them together feels like it was always meant to be.

Using the Tridion WorldServer Connector

Starting the Translation is as simple as right-clicking the content item and selecting Translate.  This creates a new Translation Job.

Creating a Translation Job

Adding another item to the translation job is easy

The translation job ends up in the ‘Translation Jobs’ section of the ‘Shortcuts’ menu.

We send the translation job out from the Translation Jobs menu.

Or the Ribbon

Once it has been accepted and started, we can track the progress from within the Tridion CMS. The listview has a % Complete column and opening a translation job shows which step of the workflow it is in. This is an amazing feature that allows our content managers can keep an overview of exactly where items are at in translation directly from Tridion – no need to go into SDL or other interfaces.  Finally, when content is translated and received back a Publication-configured email address is mailed that the item is back from translation.

 

Installing the World Server Connector

Installing the World Server connector involves 3 steps.  The CMS will store the translation jobs in a new database and use a Web Service to communicate with the World Server instance.

1.  Create the Translation Manager Server Database using the Tridion Database Manager tool

2.  Run the World Server Connector Install Wizard.  Next, go to SDL Tridion World and download the World Server hotfix rollup.  If you are using secure sessions in World Server you’ll need an additional hotfix from SDL to enable Tridion to talk to the secure connection on World Server.

3.  Create a repository in World Server and configure World Server for Tridion.
There are special permissions that the World Server user is required to have and these are documented in the Tridion Live Documentation site.  In addition to user permissions there are some specific settings the World Server Administrator must configure to have Tridion able to send translation jobs.

4.  Validating configuration and testing – Open the Publication Langauge Parent and tell it to connect to World Server.  This will use the settings in the configuration file and attempt to connect to World Server.  It will take a few minutes – but if it does not connect the ‘loading’ message will stay on the screen.  This likely means that the configuration is not valid.  Best to look at the configuration file and remote into your CMS and confirm that you can access the World Server URL from the CMS.  Also, you can run Fiddler on the CMS to see which ports the Tridion Web Service is using to talk with World Server.  Once connected configure the Parent Publication to the World Server equivalent.  Now, open a Child Publication and do the same, pointing to the World Server repository for the child language.

Summary

The World Server Connector is the ‘holy grail’ for large companies with multi-lingual websites.  Being able to send content for translation directly from the GUI and then leverage your existing Translation Network and Workflow is extremely efficient and time-saving.  The installation is fairly quick and with your local World Server administrator you should have it up and running without too much effort. The World Server configuration is very specific and needs to be carefully setup according to SDL’s requirements.  I hope this article gives you an idea of how this works.

 

All episodes of the Tridion Talk podcast are now available at TridionDialog.com. I sit down and talk with Quirijn Slings and many more Tridion experts about DD4T and many other topics in Tridion powered websites. This is my first time creating a podcast and it was a lot more work than I expected! I was also surprised how much I enjoyed editing the audio and learning this new domain of audio editing and encoding knowledge. Please take a moment, or more, to listen to the episode and let me know what you think!

 

Tridion 2011 Search Hacks

August 16th, 2012 | Posted by Robert Curlette in Tridion 2011 - (0 Comments)

If you recently upgraded to Tridion 2011 and your search results are not what you expected please read on – with a few simple tips your search results will improve and you’ll stop singing that U2 song ‘I Still Haven’t Found What I’m Looking For’.

Tridion 2011 comes with the super-powered Solr search engine – this is an open-source search engine from the Apache project built on top of Lucene; new in Tridion 2011.  Previous versions used Verity.

The search box on the dashboard works as advertised – it searches within the current context for matches – in all types of items from Components to Templates to Schemas.  Context is important here.  And you can still type Tridion TCM URIs in the box and open the item directly.

Wildcards are your friend

What makes the difference from a few items found and many are the wildcards you use.  Simply place a * before the word and after and your chances for finding matches increases exponentially.  This is especially true when searching in template code.

For example, if I want to find where the field intro_text is used in a template I can use *intro_text*.

Other wildcard combinations are possible with the ? character, saying to use any character.  For example te?t will match test and text.  Although probably not as useful as the * keyword – it is possible.  Solr is built on top of Lucene – meaning it uses the Lucene search engine and adds additional features such as facets and an http-based API.  For additional search help see http://lucene.apache.org/core/3_6_1/queryparsersyntax.html

Advanced Options

Using the Advanced search window you can increase the amount of items returned (default is 50) and filter the types of items searched.  Perhaps the most important setting is the amount of items returned.

 

Populating the search index

After upgrading your existing installation to Tridion 2011 you will need to populate the Solr Search index first before search results are returned.  You can do this with the  TcmReIndex.exe tool located in the Tridion/bin folder.  Without running this tool your search index is empty.  Afterwards, whenever a user saves any item in Tridion the Seach Service populates the Tridion search index with that items’ content.

Summary
Tridion did a good job of including the powerful Solr search engine with Tridion 2011.  With the new engine we have faster searches and more possibilities.  With a little bit of luck your searches will help you find what you’re looking for.

Tridion 2011 brought us the ability to change the users experience in the GUI. This is something I wanted (and needed) to do for the last 10 years – but was not allowed to but was not comfortable doing with the lack of documentation and support. The ability to officially modify the Tridion GUI and modify the default experience for users arrived in Tridion 2011 Tridion 5.2 and was continually expanded on until fully embraced in 2011. Before 2011 it was possible, but the official response from Tridion was ‘It’s not supported’ and if a customer called Tridion with a modified GUI Tridion ASP system files and would not receive support.  Needless to say, we never modified the GUI as a general practice as part of an implementation – it felt too unsupported and undocumented.

This changed in Tridion 2011. One of the features added was to write our own ‘GUI Extensions’ and these new extensions were supported – and documented. Not only that, but we had a brand new javascript framework called Anguilla that we have available to use for extending the GUI. Next to the Anguilla framework we also have the ability to add buttons to the GUI, extra columns to the list view and even tabs to the Edit windows of item types. This is revolutionary in the Tridion world, where previously our GUI was locked down by R & D generally not open to edit except for specific extension points, and then not documented as in 2011, and I instantly fell in love with this new concept. After attempting to create my own extensions using existing blog posts and documentation I quickly got stuck – all guides showed how to add the buttons, etc – but what about functionality with Tridion? I found some great code samples on Tridion World – but no explanations. So, I decided to spend some serious quality time and dig into the Anguilla framework and GUI Extension technology. I was very lucky to have the full support of the Tridion Community and before too long I had a working GUI extension and started to make sense of the madness. I did it – and decided to share my newfound love with the world. What followed was a series of blog posts about creating GUI extensions. I tried to fill the gap between what documentation was available and what was possible. I tried to give a code sample and explanation for each type of new extension. I did this with the thought that everyone should be able to write this code, and do it with a good understanding of what it does.

Now Alvin wrote his post and it made me think – is it now understood as a common step in an implementation to modify the GUI? For me writing custom pages and modifying the GUI are always part of an implementation, but a small part with a big impact on daily usability, often saving users hours of time per week. Another way to save users time each week is to have a well-defined Schema, clear folder structure, solid Blueprint, and clear instructions. This is Alvin’s point and I 100% agree – this is the main goal of every implementation – clean, well-defined, and clear. These goals do not require GUI Extensions but they require a clear understanding of the business requirements and an architecture design that enables ease of use in the Tridion system. Indeed, Tridion is an open box and everything is possible- allowing customers and partners to misuse various features or not use them to full effect. An amazing GUI Extension will not compensate for this basic lack of a solid foundation.  GUI Extensions are the whipped cream on top. Not all implementations need it – but when it is there it gives a very nice finish to an already great product.

Tridion 2011 provides shortcuts for several actions to navigate the tree view in the GUI and open items.  However, many other operations do not have a hotkey available, such as the Publish Queue.  During a normal day I open the Publish Queue many times, often from a Component or Page view.  I also have minimized the ribbon toolbar and finding the Publish Queue button is still an effort.  I wanted a shortcut key to assign to the Publish Queue to bring it up.  In this post I’ll explain how I added the hotkey to the Tridion GUI using a GUI Extension and provide a way for you to further customize it with your own hotkeys.

Code published at https://github.com/rcurlette/Publish-Queue-Shortcut

Update:  Big thanks to @puf for the comments.  Code is updated to reflect them.

Step 1:  Create the Folder for the GUI Extension.  I created the folder for the GUI Extension:  C:\Program Files\Tridion\web\WebUI\Editors\Shortcuts

Step 2:  Add the js files

For this extension I am using an external js library called Mousetrap, http://craig.is/killing/mice.  It is an excellent library, stand-alone, no dependencies, and only 1.6kb when minified.  This is important to know because the js library will load on every GUI view.

Create a js folder in the Shortcuts folder and put the mousetrap.min.js file there.

Step 3:  Adding our shortcut

Create another js file and call it mousekeys.js.  This is the place we’ll define our shortcuts and map them to GUI Javascript calls.

The below code was borrowed and adapted  from Albert Romkes excellent post about adding js files without showing a GUI element.   http://albertromkes.com/2012/01/30/tridion-gui-extensions-how-to-load-a-javascript-without-showing-a-gui-element/

/js/mousekeys.js

//If you only want your code to affect certain screens/views, you should listen to Anguilla events like this:
$evt.addEventHandler($display, "start", onDisplayStarted);

// This callback is called when any view has finished loading
function onDisplayStarted() {

	// Open Publish Queue dialog
	Mousetrap.bind('q', function() {
	                // UPDATE:  Below is the easy way to do it.  Make sure to update your Shortcuts.config to include the CME dependencies.  Big thanks to Frank van Puffelen (@puf) for the suggestion!
                        $commands.executeCommand('PublishingQueue')

			//var popup = $popup.create($cme.Popups.PUBLISH_QUEUE.URL, $cme.Popups.PUBLISH_QUEUE.FEATURES);
			//popup.open();
	});

    $evt.removeEventHandler($display, "start", onDisplayStarted);

    //alert($display.getView().getId());

   //if ($display.getView().getId() == "ComponentView") {
		//alert('comp view');
   //}
}

Step 4:  Finding the js call for the Tridion functionality

Using Firebug I inspected the Publish Queue button and then searched through the GUI js using Firebug Script window and found the code to open the Publish Dialog.  I feel lucky to have found it and that it worked.  :)  This is not always so easy and you might want to do some research before planning on mapping a shortcut to a favorite functionality, like checking-in or checking-out TBBs.  (if you do figure out how to do this pls leave a comment!)  :)  What other hotkey mappings would you like to see?

Step 5:  Create the config file for the extension

For me this was the first time using the domain model element within the config node.  It is a distinct difference between the normal method of having the cfg:file set node under the cfg:group node.

Shortcuts.config

<?xml version="1.0" ?>
<!--
    Tridion Hotkeys Extension

    Copyright (C) 2012 Robert Curlette
-->
<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="Curlette.Shortcuts" merger="Tridion.Web.UI.Core.Configuration.Resources.CommandGroupProcessor" merge="always">
          <cfg:domainmodel name="MousetrapDomain">
            <cfg:fileset>
              <cfg:file type="script" id="mousetrapLib">/js/mousetrap.min.js</cfg:file>
              <cfg:file type="script" id="mouseKeys">/js/mousekeys.js</cfg:file>
            </cfg:fileset>
            <cfg:services />
          </cfg:domainmodel>
          <cfg:dependencies>
            <cfg:dependency>Tridion.Web.UI.Editors.CME2010</cfg:dependency>
            <cfg:dependency>Tridion.Web.UI.Editors.CME2010.commands</cfg:dependency>
          </cfg:dependencies>
      </cfg:group>
    </cfg:groups>
  </resources>
  <definitionfiles/>
  <extensions>
    <ext:editorextensions>
      <ext:editorextension target="CME">
        <ext:editurls/>
        <ext:listdefinitions/>
        <ext:taskbars/>
        <ext:commands/>
        <ext:commandextensions/>
        <ext:contextmenus />
        <ext:lists/>
        <ext:tabpages/>
        <ext:toolbars/>
        <ext:ribbontoolbars/>
      </ext:editorextension>
    </ext:editorextensions>
    <ext:dataextenders/>
  </extensions>
  <commands/>
  <contextmenus/>
  <localization/>
  <settings>
    <defaultpage/><!--/Views/Default.aspx</defaultpage>-->
    <navigatorurl/><!--/Views/Default.aspx</navigatorurl>-->
    <editurls/>
    <listdefinitions/>
    <itemicons/>
    <theme>
      <path/><!--/CSS/</path>-->
    </theme>
    <customconfiguration/>
  </settings>
</Configuration>

Step 6:  Add the GUI Extension to the GUI
C:\Program Files\Tridion\web\WebUI\WebRoot\Configuration\System.config

<editor name="TridionShortcuts" xmlns="http://www.sdltridion.com/2009/GUI/Configuration">
<installpath xmlns="http://www.sdltridion.com/2009/GUI/Configuration">C:\Program Files\Tridion\web\WebUI\Editors\Shortcuts</installpath>
      <configuration xmlns="http://www.sdltridion.com/2009/GUI/Configuration">Shortcuts.config</configuration>
      <vdir xmlns="http://www.sdltridion.com/2009/GUI/Configuration">Shortcuts</vdir>
</editor>

Step 7:  Flush browser cache and try it.

Press the ‘q’ key in any window.  The moustrap js library does not work if you are in a text box or an input element, even if you use the ctrl-q key instead of ‘q’ as a hokey.

Code published at https://github.com/rcurlette/Publish-Queue-Shortcut

Summary

The GUI Extension framework allows us to easily enhance and enrich the User Experience using existing js libraries.  However, we should use care when adding libraries since they will be loaded with each GUI View and any errors in the js code will break the GUI.  To find out if your extension is breaking the gUI you can quicly comment it out in the System.config file and be back to normal very quickly.  I hope you enjoy using this and it makes it easier and quicker to view the Publish Queue.