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.