26

Thursday, January 26, 2012 by Niels Hartvig

It's weird how something that seems to be perfect, can slowly turn into a monster. For me it often happens just as I dare to lean back in the chair, take a deep breath of satisfaction and pat my own back thinking, "nailed it". Maybe it's because you're exhausted, maybe because you get lazy or maybe it's because you start "choosing your battles". Prioritizing if you will. Maybe even maturing.

My number one pet - the Umbraco community - has certainly matured. What started out as a crazy dream by a selected few is now the daily life of thousands. And during the journey - which is seven years in a few weeks - we've all been doing a great job of adjusting. What seemed right in 2005 may not be that great in 2012!

Why all this rambling? Well, because it's time to make an adjustment of what I thought was an evergreen in the Umbraco community - the MVP program - our "Most Valued People". It was started in 2007 as a way to recognize the selected few who really made a difference. The crazy ones. It was easy then because there weren't more than a few to pick from and I knew what every one had done. Read every post, tried every package.

As time went on and things grew, I couldn't keep up. Who could? So in 2010 I moved the responsibility to nominate the MVPs to the collective intelligence of the community. Based on the 20 community members who had the most karma, the community voted and the top five were honored with the recognition of being an MVP. Over five years Casey, Doug, Jesper, Per, Thomas, Warren, Dirk, Morten, Paul, Tim, Lee, Richard, Darren, Matt, Sebastiaan and Jan wrote a little bit of Umbraco history as the Umbraco MVPs.

We've been blessed with this fantastic bunch of people who were crazy enough to believe in an unknown project like Umbraco, crazy enough to help because it came naturally to them and crazy enough to share their work for free because it felt right.

Because it felt right. Not because they searched for recognition. Not because they wanted a badge, an honor, an ego boost. But simply because it was the building blocks Umbraco is made of. And the MVPs that followed went in the footsteps of what became known as the Umbraco culture - we really became the friendly cms. These are our roots.

Our culture is fragile, yet it's our most important asset and what really sets us apart. Our culture is about helping and sharing because it's the most natural thing to do and because we can't help it. Not because we strive for recognition. Before that becomes the norm, I've decided to close the MVP program. It's not worth striving for. What is worth striving for - while much harder - is a community that helps each other despite not getting anything tangible in return.

So the MVPs of 2011 will be the last ones. There won't be any voting this year nor the years that follow. The MVP program is history and we'll only miss it because it never got devalued. Kudos to the MVPs who brought us here and created a culture that made recognition obsolete. What a community!

"The unselfish effort to bring cheer to others will be the beginning of a happier life for ourselves.", Helen Keller

Thursday, January 26, 2012 by Warren Buckley

Hi there, I wanted to tell you about my experiences of creating a package for the upcoming brand new version, version 5 of Umbraco. Which has been rewritten from the ground up to use ASP.NET MVC 3 and the Razor View Engine.

First, a quick bit about my background, just in case you don't already know me. My technical knowledge is more of a front-ender who loves to work with markup, CSS and JavaScript and implementing sites into Umbraco. When some of more technical guys at the Umbraco HQ such as Alex, Matt & Shannon who have been working hard building and architecting V5, talk to me about certain code. I have no clue what they are talking about and just politely smile and nod as if I understood everything they say, well sometimes I understand them :)

However I wanted to write this blog post and tell you how incredibly easy it is to build a custom property editor and put in a package for the rest of the community to use. If I can build a Property Editor as a package, then I am sure you can do too!

The Basics

Lets start off with some of the basics, such as a quick glossary of terms as in V5 a few terms have been changed:

Property Editor
A PropertyEditor is a new term in version 5 of Umbraco. In version 4 of Umbraco this was known as the render control for a DataType in Umbraco. So for example you could create multiple DataTypes in Umbraco that all use the Rich Text Editor render control or as it is now known as, PropertyEditor. So a DataType allows you to create variations of a PropertyEditor by changing the settings for that PropertyEditor.

Pre Values
This may be a new term to you, but Pre Values are the default settings and configurations that allow you to configure a PropertyEditor.

Plugin
A plugin is a single item that extends Umbraco. For example each one of these would be a separate plugin:

  • PropertyEditor
  • Tree
  • Context Menu Items

There are more plugin types available, but I won't cover that here in this post. I recommend you take a look through the list of resources at the bottom of the post to know what is possible.

Package
The term for a package has not really changed, but you may package up one or more plugins to create your package.

What Did I Make?

For my first package I decided to build a property editor that I could use in a new simple starter website kit I am attempting to make. I decided to build an RGBA colour picker that allows a content editor to save a colour to change in the front end of the website.

Below you can see the initial idea sketch I had for creating a very simple property editor, which involves four jQuery UI sliders that allow the user to control the individual values that make up a RGBA colour.

rgba-picker-sketch

When I was sketching the property editor out, I thought it would be a good idea to put in some safe guards for the property editor, as not all browsers support RGBA I decided it would be a good idea to have two fallbacks of RGB and then a Hexadecimal colour such as #FFF000

Before I even started writing any code specific to Umbraco. I wanted to create a static HTML page along with the JavaScript I needed to write in order to see how easy or hard it was to achieve my idea. I created my prototype fairly quickly and was happy for me to try and attempt this as a PropertyEditor.

rgba-prototype

And finally below is the end result of the property editor inside an Umbraco 5 install.

Disclaimer: The video above is using an old version of Umbraco 5 and does not reflect the speed of V5 RC3 and newer

How to Create a PropertyEditor

First things first you will need Visual Studio installed. If you don't have Visual Studio installed, you can download a simpler free version of Visual Studio called: Visual Web Developer 2010 Express.

Before we start doing any coding, if you are new to ASP.NET MVC then I highly recommend you learn the fundamentals as this will help you to understand a lot better what is going on. However with that said it is not required that you know ASP.NET MVC to work with Umbraco V5.

One video series I can highly recommend is this series from PluralSight - Introduction to ASP.NET MVC3  You can watch the entire series for free, as they have a 10 day trial but I must admit it converted me into a paid subscriber.

Now that we have got a basic understanding of MVC, lets get to work...
Firstly download a copy of the source code of my RGBA PropertyEditor from the Umbraco5Contrib project on CodePlex, as we will need this to copy some files and for you to use a guide.

  • Create a new project in Visual Studio of the project type Class Library using C#
  • Name your project RGBA.Umbraco.PropertyEditor
  • Create a folder called Resources This is where we will put our CSS and JavaScript needed for our RGBA PropertyEditor. Copy the JS, CSS and PNG from the source on CodePlex into this folder.
  • Next create a folder called Views This is where will store the Razor View file for our PropertyEditor, which allows us to write our HTML markup for. Copy the RGBAPickerEditor.cshtml file into this folder.
  • Next at the root of the project create three new class files called and it is important you keep to naming conventions here as this helps to wire everything up in MVC automatically.
    • RGBAPickerEditor.cs
    • RGBAPickerEditorModel.cs
    • RGBAPickerPreValueModel.cs

Before we continue I need to explain to you what Embedded Resources are. An embedded resource allows you to embed a file, such as a JavaScript file or a CSS file inside the binary DLL for the class project. So why this is useful for our plugin development is that we only have to deploy one DLL for our plugin to work as we can embedded any other items into that file.

The files that we need to have as embedded resources are:

  • Resources/RGBAPicker.css
  • Resources/RGBAPicker.js
  • Resources/transparent-grid.png
  • Views/RGBAPickerEditor.cshtml

To embed a resource you need to select the file from the Solution Explorer window (normally on the right hand side of the Visual Studio application) and from the properties window below find the row labelled Build Action and choose the option labelled Embedded Resource

embedded-resource

Now when you build your project all those items will be available inside the DLL.

Next you will need to reference the Umbraco V5 DLLs for your project, you can retrieve these from the source code of the project if needed.

Rather than explain what code you need to type in, let's paste in the example code from the source code of the RGBA Picker project we downloaded from CodePlex and then we can look at parts of the files below to dissect them and understand what is going on.

Note: That some of the snippets below have been shortened to save space in this post, I recommend you refer to the source code for the original files.

RGBAPickerEditor.cs
At the top of this file you can see we are saying that our RGBA property editor needs to use the files from the Resources folder. It's important to note this is the full namespace of the file. So the name of our project followed by the resources folder then the filename. The extra parameter for the CSS file of PerformSubstitution allows us to use a similar web resource url for a background image  of a DOM element.

Next you will also notice above the class is a PropertyEditor attribute, which we use to say this class is a PropertyEditor and then we pass in some parameters.

The first is a unique GUID string which is the ID of our package, make sure this is unique as if you were to copy this ID and someone else developed a plugin with the same GUID there would be a conflict. To create your own GUID you can either use the tools inside Visual Studio or simply visit this website - http://createguid.com

The second parameter is the alias of the property editor and the third parameter is the friendly name of the property editor, that will displayed in the dropdown list when creating a new data type.


//Using statements go here - see source code from original on Codeplex

[assembly: WebResource("RGBA.Umbraco.PropertyEditor.Resources.RGBAPicker.js", "application/x-javascript")]
[assembly: WebResource("RGBA.Umbraco.PropertyEditor.Resources.RGBAPicker.css", "text/css", PerformSubstitution = true)]
[assembly: WebResource("RGBA.Umbraco.PropertyEditor.Resources.transparent-grid.png", "image/png")]
 
namespace RGBA.Umbraco.PropertyEditor
{
    [PropertyEditor("04B0F923-E780-42DA-869E-32C118E12364", "RGBA.Umbraco.PropertyEditor", "RGBA Picker")]
    public class RGBAPickerEditor : PropertyEditor<RGBAPickerEditorModel, RGBAPickerPreValueModel>
    {
        public override RGBAPickerEditorModel CreateEditorModel(RGBAPickerPreValueModel preValues)
        {
            return new RGBAPickerEditorModel(preValues);
        }
 
        public override RGBAPickerPreValueModel CreatePreValueEditorModel()
        {
            return new RGBAPickerPreValueModel();
        }
    }
}

RGBAPickerEditorModel.cs
This class file is where we define the properties of our model. In this case the values we want to store when a content editor uses our property editor and that the same values can be used to be output them into our templates. Here you can see I have created seven properties to store the values

  • Red
  • Green
  • Blue
  • Alpha
  • Hex
  • RGB
  • RGBA

If you notice I am using ASP.NET MVC Data Annotations to allow me to put validation on these fields very simply and very quickly. Here you can see I use the required and range annotations. It's literally that simple to do validation in Umbraco with MVC.

Inside the RGBAPropertyEditorModel stub you can see that we set the default values for the property editor when no values have yet been saved as the prevalues from the configuration of the property editor.

Finally the GetSerializedValue stub allows me to concatenate the values from Red, Green, Blue and Alpha to populate the values for RGB and RGBA when the user saves the content node.

Also on the class you can see we have embedded the view which is the HTML output for our property editor, which will contain our sliders etc...


//Using statements go here - see source code from original on Codeplex
 
namespace RGBA.Umbraco.PropertyEditor
{
    [EmbeddedView("RGBA.Umbraco.PropertyEditor.Views.RGBAPickerEditor.cshtml", "RGBA.Umbraco.PropertyEditor")]
    public class RGBAPickerEditorModel : EditorModel<RGBAPickerPreValueModel>
    {
        public RGBAPickerEditorModel(RGBAPickerPreValueModel preValues) : base(preValues)
        {
            //Use prevalues as the default values until it's saved
            //Tip from Shannon's CG11 Plugin talk...
            Red     = preValues.initRed;
            Green   = preValues.initGreen;
            Blue    = preValues.initBlue;
            Alpha   = preValues.initAlpha;
        }
 
        [Range(0, 255, ErrorMessage = "Please select the Red value of 0 - 255")]
        [Required]
        [DisplayName("Red")]
        public int Red { get; set; }
 
        [Range(0, 255, ErrorMessage = "Please select the Red value of 0 - 255")]
        [Required]
        [DisplayName("Green")]
        public int Green { get; set; }
 
        [Range(0, 255, ErrorMessage = "Please select the Red value of 0 - 255")]
        [Required]
        [DisplayName("Blue")]
        public int Blue { get; set; }
 
        [Range(0, 100, ErrorMessage = "Please select the Alpha % of 0 - 100")]
        [Required]
        [DisplayName("Alpha")]
        public int Alpha { get; set; }
 
        [HiddenInput]
        public string Hex { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public string RGB { get; set; }
 
        [HiddenInput(DisplayValue = false)]
        public string RGBA { get; set; }
 
 
        public override IDictionary<string, object> GetSerializedValue()
        {
            //RGB
            RGB = string.Concat(Red, ",", Green, ",", Blue);
 
            //RGBA
            //Convert alpha to decimal
            var AlphaDecimal = Convert.ToDecimal(Alpha) / 100;
            RGBA = string.Concat(Red, ",", Green, ",", Blue, ",", AlphaDecimal);
            
            return base.GetSerializedValue();
        }
    }
}

RGBAPreValueModel.cs
This class file stores the PreValues properties, so these will be the items that you will be able to configure for your property editor, along with validation again.

A new annotion you can see is the AllowDocumentTypePropertyOverride which is very useful as this allows us to say this prevalue item can be configured on the data type but also when you add the data type to a document type, you are able to override the values used in the prevalues and change them. This stops you from creating a duplicate data type to only change one small prevalue.


//Using statements go here - see source code from original on Codeplex
 
namespace RGBA.Umbraco.PropertyEditor
{
    public class RGBAPickerPreValueModel : PreValueModel
    {
        [AllowDocumentTypePropertyOverride]
        [Range(0,255, ErrorMessage = "Please select the Red value of 0 - 255")]
        [Required]
        [DisplayName("Red")]
        public int initRed { get; set; }
 
        [AllowDocumentTypePropertyOverride]
        [Range(0, 255, ErrorMessage = "Please select the Red value of 0 - 255")]
        [Required]
        [DisplayName("Green")]
        public int initGreen { get; set; }
 
        [AllowDocumentTypePropertyOverride]
        [Range(0, 255, ErrorMessage = "Please select the Red value of 0 - 255")]
        [Required]
        [DisplayName("Blue")]
        public int initBlue { get; set; }
 
        [AllowDocumentTypePropertyOverride]
        [Range(0, 100, ErrorMessage = "Please select the Alpha % of 0 - 100")]
        [Required]
        [DisplayName("Alpha")]
        public int initAlpha { get; set; }
    }
}

Views/RGBAPickerEditor.cshtml
As you can see below the Razor view is heavily commented to explain what it is doing, but this is the HTML markup that will be generated for each RGBA Picker on a content node.


@inherits WebViewPage<RGBA.Umbraco.PropertyEditor.RGBAPickerEditorModel>

//Using statements go here - see source code from original on Codeplex
 
@{
    //Create a unique GUID so that this property has a unique ID for the <div>
    var uniqueID = Guid.NewGuid().ToString();
    var pickerID = "rgba-" + uniqueID; 
}
 
<script type="text/javascript">
    $(document).ready(function () {
 
        //Call the plugin with our options
        //Pass in the HTML ID's of the hidden input boxes
        //So our JS can update these boxes with the new values to save
        $('#@pickerID').rgbaPicker({
            redID:      '#@Html.IdFor(x => Model.Red)',
            blueID:     '#@Html.IdFor(x => Model.Blue)',
            greenID:    '#@Html.IdFor(x => Model.Green)',
            alphaID:    '#@Html.IdFor(x => Model.Alpha)',
            hexID:      '#@Html.IdFor(x => Model.Hex)'
        });
    });
</script>
 
 
@{
    //Here we need to say we want to use the CSS & JS file in our view
    Html
    .RequiresJsResource(typeof(RGBAPickerEditor), "RGBA.Umbraco.PropertyEditor.Resources.RGBAPicker.js")
    .RequiresCssResource(typeof(RGBAPickerEditor), "RGBA.Umbraco.PropertyEditor.Resources.RGBAPicker.css");
}
 
 
<!-- We give this div the unique pickerID -->
<div id="@pickerID" class="rgbaPicker">
    <div class="sliders">
        <div class="item">
            <!-- CSS classes used to easily target in JS to update -->
            <label>Red: <span class="redDisplay"></span></label>
            <div class="redSlider"></div>
            <!-- 
            Hidden textbox for the Red value we want to save.
            The value gets updated by the JS
             -->
            @Html.HiddenFor(x => Model.Red)
        </div>
 
        <div class="item">
            <!-- CSS classes used to easily target in JS to update -->
            <label>Green: <span class="greenDisplay"></span></label>
            <div class="greenSlider"></div>
            <!-- 
            Hidden textbox for the Green value we want to save.
            The value gets updated by the JS
             -->
            @Html.HiddenFor(x => Model.Green)
        </div>
 
        <div class="item">
            <!-- CSS classes used to easily target in JS to update -->
            <label>Blue: <span class="blueDisplay"></span></label>
            <div class="blueSlider"></div>
            <!-- 
            Hidden textbox for the Blue value we want to save.
            The value gets updated by the JS
             -->
            @Html.HiddenFor(x => Model.Blue)
        </div>
 
        <div class="item">
            <!-- CSS classes used to easily target in JS to update -->
            <label>Alpha: <span class="alphaDisplay"></span>%</label>
            <div class="alphaSlider"></div>
            <!-- 
            Hidden textbox for the Alpha value we want to save.
            The value gets updated by the JS
             -->
            @Html.HiddenFor(x => Model.Alpha)
        </div>
        
        <div>
            <!-- Disabled input for Hex # colour -->
            @Html.LabelFor(x => Model.Hex)
            @Html.TextBoxFor(x => Model.Hex, new { @class = "hex",  @readonly = "readonly" })
        </div>
    </div>
 
    <!-- Colour is previewed here -->
    <div class="livePreview"><span></span></div>
</div>

Resources/RGBAPicker.js
I won't copy and paste the source for this file here in the post, but if you take a look at the source code you will be able to figure out easily what is going on, as the code is heavily commented.

But in a nutshell the Javascript is doing the following, wiring up the jQuery UI slider divs and updating the value in the hidden textboxes and labels. In addition when the slider is moved the live preview <div> is getting updated to preview the colour along with a JS function being calculated to generate the hexadecimal colour as well. As long as the values in the hidden textboxes are updated with our new values then when the user presses save the values are saved back to Umbraco automatically. I have not had to worry about writing complex code to save the values back to the database, all of this hard work is done for me magically. Those V5 devs are a clever bunch, aren't they!

Now that we have all the parts in place inside our class project we can build our project and have it compile to a single DLL, as we are using embedded resources.

To test your property editor I was copying the DLL and placing it inside the bin folder of my Umbraco V5 website. Then I was able to go to the developer section and create a new data type with my RGBA Picker property editor and test it out on a document type.

Outputting the Values

So now that we have our property editor inside Umbraco and setup on a content type and tested out our property editor, we will want to output those values into a template. I liked the idea of overriding elements in my main CSS file to allow me to change colour of certain elements.

So in my template I have the following code that outputs the values from a property with the alias of sidebarColour


<style type="text/css">
    /* Overrides */
    aside 
    {
       /* Safe fallbacks to RGB then fallback to solid Hex */
        background-color: @DynamicModel.sidebarColour.Hex;
        background-color: rgb(@DynamicModel.sidebarColour.RGB);
        background-color: rgba(@DynamicModel.sidebarColour.RGBA);
    }
</style>

Once you are happy with the results, it's time to package it up so you can share it with the community and just generally re-use a component for other sites you will build with Umbraco.

How to Create the Package

Packages in Umbraco use a package format that is fairly new to ASP.NET which is called Nuget. But to create our property editor package for Umbraco, you will need to download the Nuget GUI tool.

Once you have it installed, open the program and choose the create a new package option. Next we need to edit the metadata for our package. You can do this by finding the option Edit Package Metadata in the application menu. Here you will need to supply a unique ID for the package, but for best practises I would recommend you use the same alias as you used for the property editor in RGBAPickerEditor.cs. However if the package contained more than one plugins this won't apply. Just choose a sensible name that would be unique, such as CompanyName.PluginName

Before we add our DLL to our package, we need to make one small modification to the project. If you open the file AssemblyInfo.cs found under the Properties folder. We need to add one line of code to the file along with adding a using statement. What this does, is let Umbraco know that this DLL contains plugins that need to be installed. If we don't do this Umbraco won't pick up our DLL, as when a package is installed the files do not get copied to the bin folder but instead get installed to /App_Plugins/Packages/PackageID


using Umbraco.Cms.Web;
[assembly: AssemblyContainsPlugins]

After adding in this change you will need to rebuild your project to ensure this change is made to the DLL.

The final step for creating our package, is to add the single DLL for our property editor that needs to be installed. If you drag the DLL into the middle column of the Nuget Package tool. You will be prompted with a dialog box. Make sure you say yes to add it to the lib folder.

nuget-dialog

Once your done, your nuget package should look something like below.

rgba-package-meta

Save the package to a convenient location and it's time to test out your package. I would recommend you test your package in a clean install of Umbraco 5, as if you use the same install as for your previous test. You will need to delete the property of the document type along with the data type and then finally remove the DLL from the Bin folder otherwise it will cause a conflict.

Volia one property editor package, now you can install it into an Umbraco 5 website to test out your work.

Resources

Here are some useful resources that I recommend you take a look through:

Shannon Deminick's Blog Post Series on Plugins
http://shazwazza.com/post/Umbraco-Jupiter-Plugins-Part-1.aspx
http://shazwazza.com/post/Umbraco-Jupiter-Plugins-Part-2-Routing.aspx
http://shazwazza.com/post/Umbraco-Jupiter-Plugins-Part-3-Trees.aspx
http://shazwazza.com/post/Umbraco-Jupiter-Plugins-Part-4-Editors.aspx
http://shazwazza.com/post/Umbraco-Jupiter-Plugins-Part-5-Surface-Controllers.aspx

Shannon Deminick's CodeGarden 11 Session on Plugins Video
http://codegarden11.com/sessions/day-1/slot-two/get-plugged-in-to-umbraco-jupiter.aspx

The Umbraco V5 Contrib Project
http://umbraco5contrib.codeplex.com

Work in Progress: Estate Agent Starter Website
https://bitbucket.org/warrenbuckley/estate-agents-starter-site

The End Result

So what have we covered? Well I have shown you from initial sketch all the way upto a working PropertyEditor package for Umbraco 5 and how easy it is to do. Remember if I can do it then certainly you clever lot can!

You can download the RGBA Property Editor from our.umbraco.org along with another property editor I made which was the Bing Maps property editor.

http://our.umbraco.org/projects/backoffice-extensions/rgba-property-editor
http://our.umbraco.org/projects/backoffice-extensions/bing-maps-property-editor

Got any questions, just leave a comment and I will get back to you.

Cheers,
Warren - The friendly front end dev!