Uploading images and PDF files into Tridion is easy, but sometimes we want to restrict the size allowed for these uploads. For example, it’s not cool to upload a 5MB image to the homepage of our website. In this article I will present an approach using the Event System to give a warning message to users when the filesize is too big. The filesize is configured in the Publication Metadata and also a default one is set in the code.

Solution Overview

1. Capture the Save Event for a Component
2. If it is a Multimedia Component and an ‘Interesting Mime Type’ then continue
3. Try to get the Allowed Filesize for the items from the Publication Metadata. If not found, then use the defaults defined in the MaxFilesizeDef.cs file
4. If the file is too big, then throw a new WrongFileSizeException. For example, “Sorry, file exceeds the allowed size for PDF files. The allowed size is 10MB.”

The Code: https://github.com/rcurlette/MMFileSizeValidator#tridionimagesizechecker

Setting up the Publication Metadata Configuration

Create a new Metadata Schema or add the following fields to your existing Metadata Schema. This is not mandatory, but if you want to change the default filesize values, then it is recommended to do this. It also allows you to set very high values (or low values) for 1 Publication.

1. Create a new Schema, Configuration.
Fields:
– maxImageSize, Text
– maxPdfSize, Text
– maxMovieSize, Text
*These fields must be named like this

2. Create a Metadata Schema with 1 ComponentLink field, ‘Configuration’, linking to the Configuration Schema we created above in step 1

3. Add Configuration Schema to Publication and fill in values.

Configuring the Default Filesizes

The valdiation is enabled for all Publications. If the Metadata is set, it uses those values. However, if no Metadata configuration setting is found on the Publication then the defaults from the code are used. Here are the defaults:

  • Image: long _maxImageSize = 4194304; (4 MB)
  • PDF: long _maxPdfSize = 20971520; (20 MB)
  • Movie: long _maxMovieSize = 41943040; (40 MB)

Configuring the Cache Settings and Configuration Manager

The Configuration Manager class from Mihai comes with a nice XML configuration. See below for it. The filename I have is EventSystemComponentSave.dll.config. This must be the same as your Event System DLL.

<configuration>
  <appSettings>
    <!-- Amount of minutes to keep a loaded Configuration dictionary in the cache -->
    <add key="SystemComponentCacheMinutes" value="1"/>

    <!-- Where to read the System Component from (Publication, Current, TcmUri or WebDavUrl). Multiple values are comma separated -->
    <add key="SystemComponentLocation" value="Publication"/>

    <!-- Which metadata field contains a Component Link to the SystemComponent. Multiple fields separated by commas -->
    <add key="SystemComponentField" value="Configuration"/>

    <!-- Search for System Component recursively (going up into the parent Folder/SG)? -->
    <add key="SystemComponentRecursive" value="false"/>

    <!-- When merging several System Components, should it override values for the same key? -->
    <add key="SystemComponentOverride" value="false"/>
  </appSettings>
</configuration>

Installing

This is the same to install any Event System DLL on your Tridion 2009 / 2011 instance.
1. Compile the assembly (Add References to the Tridion\bin\client\Tridion.ContentManager.dll and Tridion\bin\client\Tridion.Common.dll )
2. Copy EventSystemComponentSave.dll to the Tridion\bin folder (or another folder of your choice).
3.  Copy the  EventSystemComponentSave.dll.config to the Tridion\bin folder (or another folder of your choice).

4. Register it in the Tridion.ContentManager.config

<add assemblyFileName="C:\Program Files (x86)\Tridion\bin\EventSystemComponentSave.dll" />

5. Open the Services.msc and restart the ‘Tridion Content Manager Service Host’ service.
6. Test by trying to upload a large Multimedia file

Credits and Thanks

I used Dominic Cronin’s excellent ‘Image Size Checker’ (height/width) Event System code for a starting point. https://code.google.com/p/tridion-practice/source/browse/#git%2FImageSizeChecker

I used Mihai’s great ConfigurationManager code to store and retrieve the Publication Metadata settings. https://code.google.com/p/yet-another-tridion-blog/source/browse/trunk/Yet+Another+Event+System/

Summary

Adding content validation rules to the Event System is easy and also provides a better QA for the quality of content being uploaded to our website. In this example we saw how we can easily restrict the filesizes of Multimedia items being uploaded into Tridion. We also saw how easy it is to use a Configuration schema in our code and use the Configuration Manager to cache these settings. I hope this article gives you some new ideas and helps you keep the file sizes under reasonable limits in your Tridion system.

Are you manually setting up a Tridion Deployer and using a guide such as Nuno’s excellent post titled Manually configuring a Tridion 2011 .NET Content Deployer Instance? Is it working? If so, move on, this article is not for you. If not, or you would like to learn how to troubleshoot a Deployer to publish to the Broker Database – read on.

Deployer debugging overview

The Deployer can run as a Windows service or a Website. In this article I discuss the option to run it as a website. I prefer this option as it allows me to run multiple Deployers on 1 machine and I also feel I have more control over it. Read Nuno’s post above for details about how to setup a manual Deployer. I’m going to highlight a way to debug the Deployer and describe one tiny issue that costs me hours of frustration.

I’m using IIS and in the end of the article I have my file setup. Notice I have a logs folder in there. The location of this folder is configured in the logback.xml file. Snippet from logback.xml:

  <property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
    <property name="log.history" value="7"/>
    <property name="log.folder" value="c:/tridion/deployer-Broker/log"/>
    <property name="log.level" value="Info"/>
    <property name="log.encoding" value="UTF-8"/>

This tells my Deployer to put the logs for it (and not for anything else) in the log folder. This is not the default setting and I do suggest you change it to a specific folder per Deployer. After changing any config file we need to restart the Deployer. This can be done by recycling the App Pool or simply doing an ‘iisreset’ if you’re on your own local dev machine.

The other thing to notice is my license file is in the config folder. And here was my fatal mistake – my license file was called ‘cd_license.xml’ and Tridion assumes it is called ‘cd_licenses.xml’ or I can manually put the name in on the bottom of the cd_storage_conf.xml config file. Big thanks to Mihai Cădariu for Yet Another Tridion answer that saved me time and my sanity.

The solution

Tridion uses Filesystem bindings (and not the DB ones in the config file you specified) as a fallback and default when it cannot find or load the cd_licenses.xml file. It logs this in the cd_core.log file and not the cd_deployer.log file. In fact, the cd_deployer.log file looks normal and doesn’t give us any clues it’s using the fallback Filesystem Deployer due to a license issue.

Summary

Tridion deployment is at the heart of every Tridion implementation. Setting up and configuring a Deployer is a task often done by Developers on a new system, such as my Azure Tridion 2013 SP1 instance (Medium instance, SQL Server 2012 instance type, runs great!). Following Nuno’s guide we can quickly get one setup. However, debugging it and finding small problems is sometimes not so easy. I hope this small tip helps show some insight into one potential issue and how to solve it.

Directory: C:\tridion\deployer-Broker

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         3/17/2014   3:12 PM            bin
d----         3/17/2014  10:20 AM            log
-a---         3/17/2014   3:13 PM          0 dir.txt
-a---        11/10/2013   9:29 PM        121 HTTPUpload.aspx                                                           

    Directory: C:\tridion\deployer-Broker\bin

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         3/17/2014   8:55 AM            config
d----         3/17/2014   3:12 PM            lib
-a---        11/10/2013   9:29 PM     172032 netrtsn.dll
-a---        11/10/2013   9:29 PM      22528 Tridion.ContentDelivery.Configuration.dll
-a---        11/10/2013   9:29 PM     114688 Tridion.ContentDelivery.dll
-a---        11/10/2013   9:29 PM    1323008 Tridion.ContentDelivery.Interop.dll
-a---        11/10/2013   9:29 PM    1149952 xmogrt.dll                                                                

    Directory: C:\tridion\deployer-Broker\bin\config

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        11/10/2013   9:29 PM       8057 cd_deployer_conf.xml
-a---          3/6/2014   4:57 PM       3896 cd_license.xml
-a---         3/17/2014   3:00 PM      18233 cd_storage_conf.xml
-a---         3/17/2014   8:58 AM       4552 logback.xml                                                               

    Directory: C:\tridion\deployer-Broker\bin\lib

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        11/10/2013   9:29 PM      62983 activation.jar
-a---        11/10/2013   9:29 PM     445288 antlr.jar
-a---        11/10/2013   9:29 PM       4467 aopalliance.jar
-a---        11/10/2013   9:29 PM      68851 cd_ambient.jar
-a---        11/10/2013   9:29 PM     261870 cd_broker.jar
-a---        11/10/2013   9:29 PM      71286 cd_cache.jar
-a---        11/10/2013   9:29 PM     288893 cd_core.jar
-a---        11/10/2013   9:29 PM     577390 cd_datalayer.jar
-a---        11/10/2013   9:29 PM     153291 cd_deployer.jar
-a---        11/10/2013   9:29 PM     125330 cd_dynamic.jar
-a---        11/10/2013   9:29 PM      30301 cd_linking.jar
-a---        11/10/2013   9:29 PM     231515 cd_model.jar
-a---        11/10/2013   9:29 PM     115099 cd_tcdl.jar
-a---        11/10/2013   9:29 PM     154957 cd_undo.jar
-a---        11/10/2013   9:29 PM      82881 cd_wai.jar
-a---        11/10/2013   9:29 PM      16130 cd_wrapper.jar
-a---        11/10/2013   9:29 PM     575389 commons-collections.jar
-a---        11/10/2013   9:29 PM     160519 commons-dbcp.jar
-a---        11/10/2013   9:29 PM      96203 commons-pool.jar
-a---        11/10/2013   9:29 PM     313898 dom4j.jar
-a---        11/10/2013   9:29 PM      38643 easylicense.jar
-a---        11/10/2013   9:29 PM    2189117 guava.jar
-a---        11/10/2013   9:29 PM      81271 hibernate-commons-annotations.jar
-a---        11/10/2013   9:29 PM    4253629 hibernate-core.jar
-a---        11/10/2013   9:29 PM     475305 hibernate-entitymanager.jar
-a---        11/10/2013   9:29 PM     102661 hibernate-jpa-2.0-api.jar
-a---        11/10/2013   9:29 PM     648253 javassist.jar
-a---        11/10/2013   9:29 PM      89967 jaxb-api.jar
-a---        11/10/2013   9:29 PM     867801 jaxb-impl.jar
-a---        11/10/2013   9:29 PM      60768 jboss-logging.jar
-a---        11/10/2013   9:29 PM      11209 jboss-transaction-api_1.1_spec.jar
-a---        11/10/2013   9:29 PM      17308 jcl-over-slf4j.jar
-a---        11/10/2013   9:29 PM      19146 jdbcpool.jar
-a---        11/10/2013   9:29 PM      51484 json-smart.jar
-a---        11/10/2013   9:29 PM     246709 logback-classic.jar
-a---        11/10/2013   9:29 PM     327911 logback-core.jar
-a---        11/10/2013   9:29 PM     278281 serializer.jar
-a---        11/10/2013   9:29 PM      25962 slf4j-api.jar
-a---        11/10/2013   9:29 PM     331474 spring-aop.jar
-a---        11/10/2013   9:29 PM      53079 spring-asm.jar
-a---        11/10/2013   9:29 PM     589253 spring-beans.jar
-a---        11/10/2013   9:29 PM     106819 spring-context-support.jar
-a---        11/10/2013   9:29 PM     829601 spring-context.jar
-a---        11/10/2013   9:29 PM     442400 spring-core.jar
-a---        11/10/2013   9:29 PM     176283 spring-expression.jar
-a---        11/10/2013   9:29 PM     401762 spring-jdbc.jar
-a---        11/10/2013   9:29 PM     378235 spring-orm.jar
-a---        11/10/2013   9:29 PM     246036 spring-tx.jar
-a---         2/17/2012  11:45 AM     584207 sqljdbc4.jar
-a---        11/10/2013   9:29 PM      23346 stax-api.jar
-a---        11/10/2013   9:29 PM    3176148 xalan.jar                                                                 

    Directory: C:\tridion\deployer-Broker\log

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         3/17/2014   2:56 PM    1284686 cd_core.2014-03-17.log
-a---         3/17/2014   2:56 PM     394916 cd_deployer.2014-03-17.log
-a---         3/17/2014   2:56 PM       3442 cd_monitor.2014-03-17.log
-a---         3/17/2014  10:20 AM          0 cd_preview.2014-03-17.log
-a---         3/17/2014   2:56 PM      14790 cd_transport.2014-03-17.log

I changed the port # my Tridion CMS uses for the backend GUI then received the following error:

Unable to connect to remote server error

at System.Net.HttpWebRequest.GetRequestStream(TransportContext&amp; context) at System.Net.HttpWebRequest.GetRequestStream() at System.ServiceModel.Channels.HttpOutput.WebRequestHttpOutput.GetOutputStream()

&nbsp;

Tridion uses the WCF-based Core Service to retrieve items from the GUI. To solve the issue follow the steps in this post which describes how to change the WCF port number in the web.config

Today I installed Tridion 2013 SP1 using my MVP Tridion license with 1 named user.  The first time I loaded the UI I received this message:  “Can not continue due to license violation. The number of named users in your system (1) exceeds the limit specified in the license: 1.”

This is a known issue and to solve it you can download hotfix 87411 from this link after logging into TridionWorld  download  https://www.sdltridionworld.com/images/CM_2013.1.0.87500_tcm89-21270.zip   Special thanks to Raimond Kempees for the information about this hotfix.

I am using a Windows 2012 SQL Server server instance on Windows Azure.  The location where the Tridion.ContentManager.dll file needs to be copied is different than the readme.  The location is C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Tridion.ContentManager\v4.0_7.1.0.1290__360aac4d3354074b

I removed the old DLL and put the new one in, started my Tridion services and CMS website up and was ready to rock and roll.

Now it’s time to get my Blueprint created, starting with my Empty Master!

 

Today the best and quickest way to get an answer to your Tridion question is at the Tridion StackExchange site. StackOverflow was created in 2008 and shortly after in 2009 they opened up the platform for other topics to have their own Q&A site.

In 2009 the only place for having Tridion questions answered was the password-protected Tridion forum. Created in 2001 the forum was a great place for asking and answering questions in the small but active Tridion community. However, over time it got a little slow and more difficult to find answers to questions. It was also only open to those who had a login from Tridion Customer Support.

Realizing the potential of StackExchange to help power the active Tridion community, Dave Houlker proposed the Tridion StackExchange forum in 2011 and info about it can be found here.  As of March, 2014 it boasts the following statistics:

  • 643 visits a day
  • 4.6 questions a day
  • 98% answered
  • 834 total users, 153 avid users

It’s possible to configure StackOverflow to send us an email when a new question arrives.  Some people keep the Tridion StackExchange site open in a tab (and the # of new questions shows immediately), however, I prefer to use the email method.  Over the Christmas holidays I disabled all my auto-emailing scripts and until now have not had it enabled.  I noticed I visited the site a lot less, and also answered a lot less questions.  Enabling the email trigger is not so straight forward and here I want to describe how to set it.

  1. Select edit, Advanced from the Favorite Tag menu
  2. Configure the tag subscription

I have the website send me an email 15 minutes with the new questions and this helps me to answer faster and also keep up to speed on topics related to Tridion.

I am a big fan of automation and the email filter was the best way to stay on top of the forum and also answer more questions (= more points).  However, recently it got disabled and as a result I stopped visiting so frequently and also my points started to lag.

I hope you enjoy this tip.  I also like to automate the opening of my timesheet (and other routine tasks) and previously wrote an article about automating Firefox to open at the same time every day to my timesheet site.

Good luck with automating these tasks to make them painless.

Tridion Developer Summit

February 26th, 2014 | Posted by Robert Curlette in Tridion - (0 Comments)

The first Tridion Developer Summit will be held on 15 May in Amsterdam at the Undercurrent. We have 8 sponsors, more than 15 speakers and expect around 100 developers to attend. It’s less than 80 days before the event starts and I thought I would give some info and background about the event and how the ideas came together.

The idea for the summit started last year around the time of the Tridion MVP summit in October. I thought it would be great to have a lot of Tridion developers in one place, for us to share our ideas and experiences together. To create a unique and fun experience for everyone. I wanted to have it in October, but realized there was not enough time to organize it and instead arranged a Tridion reunion for my former colleagues and I to meet and share some drinks.

After the successful reunion I had more confidence about organizing an event and I decided to explore the idea of a Tridion Programming conference. I discussed the idea with Quirijn Slings, Ron Grisnich, Nuno Linhares, Dominic Cronin, and Minko Scheltinga. We all agreed it was a great idea and we got started on the planning. After a short while I was knee-deep in venue options, dates, schedules and speakers. I needed to decide on a place and a date, and quickly, because many places were booked for months or years in advance. After much discussion with many places and dates, but without much luck, Minko and Quirijn suggested an area in Amsterdam North filled with old warehouses and artist studios. Here we found our ideal venue – big, authentic, ‘urban chic’ and right on the water – actually, the venue is floating on the water. And, the manager of the venue called me right away and seemed to really understand the unique experience I was hoping to create for the conference. To top it off, we can arrive by boat in the morning and depart by boat in the evening. The next step was the agenda and sponsors.

I contacted several Tridion developers and asked if they would like to give a talk at the Summit. They all replied with an enthusiastic ‘Yes!’. This is one of the things I love about the Tridion community – it is small, but filled with great individuals that really like to participate and help others. With the speaker list and agenda starting to take shape I contacted several Tridion partners to ask for sponsorship – and just like the speakers – everyone was very positive and most agreed to sponsor. Although it is an independent event, SDL immediately offered their support and we’ll have the Friday workshops at the SDL offices and also have the SDL film crew with us on the event day. From SDL I am happy to have the help of Nuno Linhares, Ericka Marquez and Jeff Hora. Check the sponsors page to see our great sponsors. With the venue, speakers and sponsors in place I was left to find a name for the conference and also get the website up.

The name Tridion Developer Summit is a wordplay on the old ‘TDS’ object we would often use in the templates to get objects from the system. Originally TDS stood for ‘Tridion Dialog Server’ and was the name of the product when I joined Tridion in 2000.

Ron Grisnich of Trivident took the lead for the Facebook page and before I knew it he had it set up and also tweeted the event.

For the website I decided to use an existing Event theme from WordPress instead of designing and developing the event site from scratch. After all, there is a lot of time and effort needed in all the things to organize the event itself, and I decided not to spend time programming the event website.

Hendrik Beenker from Indivirtual contacted me right away and asked if I needed any design help for the site. I said I would like help with the logo. He understood the requirements and very soon I heard that Robin Bes, a senior visual designer at Indivirtual, was available to help us. After a couple of iterations we decided on the current Tridion Developer Summit logo, and I can say I am very happy with the results. He managed to incorporate the SDL logo, old Tridion boomerang, and also it appears as a mountain, or summit. Well done!

And that takes me to where we are today. We’re fine tuning the schedule, have a great list of speakers and are still looking for few more sponsors to help us make the event a big success.

We are planning to arrive at the venue in the morning by boat from central Amsterdam to dock at the venue, but we also have 600 parking spots for those by car. We’ll have a prize giveaway at the end, based on some trivia questions. We’re also planning the pre-event evening (most likely a boat ride through Amsterdam) and Tahzoo offered to sponsor the drinks after the event. And, who knows, maybe some live music from the Tridion community as well.

Thanks a lot to everyone so far for your support. I am really excited about the event and looking forward to an amazing day. Follow us on twitter @TridionSummit and also on our facebook page. You can register on the Tridion Developer Summit website if you would like to participate in the Tridion Developer Summit 2014.

Update 17 June, 2014:

The event was a big success!  See these links below:

The Tridion MVP retreat is hosted by SDL to honor those who share the most with the community throughout the year. I was lucky enough to be part of this group for my efforts in 2012.

One thing not known by many first-timers like myself is that the event is full of surprises. In this short post I will reveal some of the surprises that were in store for us during the 3 days.

Surprise 1:  Take your laptops with you to breakfast.  What?!

Turns out that after our 1 hour bus ride and for some people a 15 hour flight we would not have the luxury to relax, check in to our rooms, and get comfortable.  After a delicious breakfast buffet we headed straight to our working quarters – a large meeting room with a glass wall overlooking the beautiful valley and swimming pool.  The wireless, projector, and places were all arranged and waiting for us.  Nuno started off with an inspirational talk about how successful we were at sharing last year (hundreds of blog posts between the 20 of us) and also shared some secrets about the next version of Tridion and where the product is heading.

After his talk we had 1 hour to form teams, think of what idea we will finish programming within 2 days and launch it to the community as open source.  I joined the GUI Extension team and we decided to extend the Schema Edit screen and created the Field Behavior Injector to allow other field attributes, based on some previous code by Jaime Santos.  Bart Koopman has a nice article here about it.

Surprise 2:  Quickest way to the castle is by horse

Several of us gathered around the lobby wondering what surprise waited for us next.  We weren’t asked to bring laptops, so no surprise work awaited.  Hearing jingling bells in the distance we were all surprised when some horses and carriages appeared and this was our transportation to dinner – in the ancient castle at the top of the hill!

Surprise 3:  The local drink of Obidos is made from Cherries

Before dinner we were lucky to enjoy some drinks in the lobby and sampled some of the local digestive made from cherries – it was delicious, but a bit too sweet for a pre-dinner drink.  The bartender was very good and offered us local port and also his own Martini recipe.  Saturday we would take a trip to the local factory that produces this delicious drink – and who would have guessed that the quickest way is by off-road 4×4 vehicles driving through the Portugese countryside?

Surprise 4:  MVPs are a musical troupe

In the evenings we were surprised to learn that Quirijn Slings is a Ukelele master and has a slew of songs in his repertoire and Dominic Cronin plays a mean Harmonica.  Once the music started playing various MVPs showed off their musical talents and we had many sing-a-longs to share more with the local community.

Surprise 5:  It’s all about sharing

As soon as we started programming we also started discussing how to share what we were making.  Bart Koopman blogged about using Resource strings in GUI Extensions and John Winter wrote the first post about what our teams were building – while we were still building it.  Alvin Reyes had our Google Code site up and running with an introduction and overview immediately – preparing the location for our code the next day.  And I dug into building a GUI Extensions installer with Powershell that creates the required files, folders, IIS Settings, and config file updates.

Surprise 6:  We start everyday at 9:00 sharp in the meeting room

Despite the food and beverages consumed the previous night we were all expected to be present at the meeting room at 9:00 to begin the next days’ hacking session.  Surprisingly, it took little effort or time for us all to get sunk into hacking code and soon a strange intensity was building up in the room, and before we knew it we were making great progress on our new projects.

Surprise 7:  Your drinks are being served by the local Mayor

Our last dinner was held at an incredible local eco restaurant where they have created everything from local and sustainable materials.  It is owned by the local Mayor and he was on hand to serve drinks and invite us to taste his local specialties!  They were very delicious and he was a great host.

Surprise 8:  It’s over!

After 3 intense days we were already saying goodbyes and pushing each other to share more so we will see everyone again next year.  But, I have a feeling some of us won’t be there next year and also that some new faces might join the musical troupe to create some new songs to carry us through the night.

 

 

The Tridion GUI is powered by JavaScript while the backend is powered by .Net and sending a (nice) message from .Net to the GUI has been very challenging – until now. Using SignalR, an open-source product from Microsoft, it is possible to show or ‘echo’ the message from the .Net Event System, Templates or Customer Resolvers and show them in the GUI. Check out the tutorial that Will Price and I wrote published on SDL Tridion World to find out how to implement this yourself. Special thanks to SDL’s Bart Koopman for helping get the article online and embracing the GitHub Gist embed for source code.

Tridion C# TBB Upload Tip

June 10th, 2013 | Posted by Robert Curlette in .NET | Tridion - (0 Comments)

When saving a C# TBB I recently had the error message ‘Error 1 Invalid URI: The format of the URI could not be determined.’?

My first thought was to check the URI in the AssemblyInfo.cs file – was it the correct folder URI?  Did I have a typo?  Did the folder exist?  But, all was fine.

Then I recalled seeing this error before and it is related to the config.xml file that we create using TcmUploadAssembly.exe to upload the TBB.  In this file we must specify the URL of the server, which is, of course, also a URI.

The wrong value was:  <targetURL>localhost</targetURL>

Correct:  <targetURL>http://localhost</targetURL>

So, just in case you ever hit this error I hope this little tip can save you some time.

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/