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
- Create the Visual Studio Project , Folders and Files (empty)
- Create the GUI Extension configuration and setup IIS
- Add the Anguilla JavaScript code to Validate the Title Field
- 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:
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.
- We configured our command as an extension to the “Save” Command (in ValidateTitleFieldEditor.config)
- We added 3 functions to our JS – _isAvailable, _isEnabled and _execute
- We added a “console.debug” instruction to all those functions.
So basically now we just need to:
- Clear your browser cache
- Reload the CME
- Open a Javascript debug console (I recommend chrome)
- 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:
- Open Visual Studio
- Select File -> Open -> Website
- 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:
- Make visual studio pretty slow at times
- 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:
- Item you’re editing is a component
- Current component’s schema has a field named “Title”
- 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/