Nibble

Extending Umbraco Contour 2.0 for Umbraco 5, creating a custom field type 3

Like mentioned in the previous post there are some changes in Contour 2.0 when creating custom field types for Contour running on Umbraco v5. So in this post I’ll show a first complete example.

A custom field type consists of 2 main things:

  • A class containing the definition
  • The view that will be used to render the fields of the custom field types

Fieldtype class

So similar to how it is when extending Contour 1.x you’ll need a class that inherits from Umbraco.Forms.Core.FieldType (need to reference Umbraco.Forms.Core).

public class CustomFieldType: FieldType


In the constructor you’ll need to set the id of the provider.

this.Id = new Guid("4EF14104-2334-42F4-85D2-C426CA2800C8");


And some stuff that will be used by the form designer, the name (will appear in the field type selector of the form designer), the icon (also shown in the form designer).

this.Name = "Custom fieldtype";
this.Icon = "../../../../ExampleFieldType/Content/Images/custom.png";


Will result in the following (assuming that the icon is located at \App_Plugins\Packages\ExampleFieldType\Content\Images~\custom.png

image

You’ll also have to specify the html code that will be shown as a preview in the form designer

 public override string RenderPreview()
{
    return "<input type=\"text\" class=\"textfield\" value=\"custom preview\" />";
 }

Will result in the following preview shown on the form designer:

image

Here is the full code snippet (you can download the source at the bottom of this post)

using System;
using System.Collections.Generic;
using Umbraco.Forms.Core;
 
namespace ContourV5.ExampleFieldType
{
    public class CustomFieldType: FieldType
    {
        public CustomFieldType()
        {
            this.Id = new Guid("4EF14104-2334-42F4-85D2-C426CA2800C8");
            this.Name = "Custom fieldtype";
            this.Description = "Renders an example fieldtype";
 
            this.Icon = "../../../../ExampleFieldType/Content/Images/custom.png";
            this.DataType = FieldDataType.LongString;
        }
 
        public override string RenderPreview()
        {
            return "<input type=\"text\" class=\"textfield\" value=\"custom preview\" />";
        }
 
        public override string RenderPreviewWithPrevalues(List<object> prevalues)
        {
            return RenderPreview();
        }
 
 
    }
}

 

Fieldtype view

Another part that is needed is a view that will be used to output the fields of your custom fieldtype.

The minimum, so important here is to use the FieldViewModel (need to reference Umbraco.Forms.MVC) and that the name of the input is set to @Model.Name since this will be used to fetch and save the value.

@model Umbraco.Forms.MVC.Models.FieldViewModel
 
@{
    Layout = null;
}
 
<input type="text" name="@Model.Name" id="@Model.Id" class="text" value="" />

 

If you also want to support record editing and showing the stored value when moving back and forth in multi step forms you’ll need to check if there are already record values and then set the value of your control

@model Umbraco.Forms.MVC.Models.FieldViewModel
 
@{
    Layout = null;
 
    string val = string.Empty;
   
    if(Model.RecordValues != null)
    {
        val = Model.RecordValues.First().ToString();
    }
}
 
<input type="text" name="@Model.Name" id="@Model.Id" class="text" value="@val" />

 

And in order to support client side validation there are also some additions to be made (extra attributes)

@model Umbraco.Forms.MVC.Models.FieldViewModel
 
@{
    Layout = null;
 
    string val = string.Empty;
   
    if(Model.RecordValues != null)
    {
        val = Model.RecordValues.First().ToString();
    }
}
 
<input type="text" name="@Model.Name" id="@Model.Id" class="text" value="@val"
@{if(Model.Field.Mandatory) 
{
      <text>data-val="true" data-val-required="@Model.RequiredErrorMessage"</text>
}
}
/>

 

Adding the custom fieldtype

You’ll of course need to have Contour installed first, once that is installed you can add your custom fieldtype. To keep a clean overview of the extensions installed on your Umbraco v5 site simply create a new folder in the /App_Plugins/Packages directory

image

Once that is created drop your assembly in the lib subfolder (create it first)

image

You can then drop other resources like the field type icon in your custom directory (make sure this matches the path of the icon property on your fieldtype).

image

The view however needs to go in the

/App_Plugins/Packages/Contour/Views/Partial/ directory and needs to be named following the convention FieldType.FieldTypeClassName.cshtml

image

Porting existing fieldtypes to Contour 2.0 for Umbraco v5

Basically you’ll just have to create the view and if you want to do some additional processing of the value(s) also override the ProcessValue method on your field type class.

Download the example project

Extending Umbraco Contour 2.0 for Umbraco 5 1

Like it’s possible to extend Contour for Umbraco v4 with custom providers you can of course also do this with Contour 2.0 for Umbraco v5.

Since the engine behind Contour is still the same there are a lot of things that also stayed the same. There is no difference in creating custom data source types, prevalue source types, workflow types, export types, record action types, recordset action types for Contour on v4 or v5 of Umbaco. So if you already have custom ones running on Contour 1.x you should be able to reuse those instantly on Contour 2.0.

The 2 things that will be a bit different are creating custom field types and custom field setting types I’ll get some examples up of those in one of the next blog posts.

Introducing the AssemblyContainsContourProviders attribute

A small difference is that you’ll need to mark your assembly with a specific attribute if it contains Contour providers. This will make sure Contour only looks in the marked assemblies for plugins (performance boost).

So basically you’ll need to add the following line to your AssemblyInfo.cs of the project containing the Contour providers

[assembly: Umbraco.Forms.Core.Attributes.AssemblyContainsContourProviders]

Adding comment functionality to your Umbraco v5 site with Contour 0

Contour v2.0 for Umbraco v5 ships with a couple of methods that makes it really easy to fetch and output Contour records on your site as a quick example here is how you would add a comment form and a list of comments to your Umbraco v5 site with Contour.

Step 1: Creating the form

Go to the Contour section (of course you’ll need to install Contour first) and bring up the create page for Forms.

image

Give the form a name and select Comment Form as a template, this will already populate your form with the necessary fields.

image

After hitting the next button you should end up with a comment form

image

Step 2: Placing the form on your template

Navigate to the settings section and select the template where you want to place the comment form (I’m using the v5 starter kit and placing it on the textpage template).

image

Hit the insert macro button on the template editor toolbar

image

Select the ‘insert form from umbraco contour’ macro

image

Then select the Comment form and hit ok

image

You should now end up with an extra line in your template similar to:

@Umbraco.RenderMacro("contourForm", new { formId = "b32ef480-003f-4e93-9641-f60042a0bc33" })

After saving the template you should have a comment form on the pages that use the template with the macro on it.

image

And you can submit new comments…

Step 3: Adding the code that will output the comments

To output we’ll add some additional logic to the template

First a using statement

@using Umbraco.Forms.Core.DynamicObjects;

This is the namespace that contains the dynamic object we’ll be using to make it easy to output our Contour records.

Now to fetch the records we’ll use the method GetApprovedRecordsFromPage feeding it the current page id.

This methods returns a dynamic record list, so it’s easy to access fields on those records simply by using the dot notation like .Comment, .Name, … (depending on your field captions)

Here is the full snippet:

<ul id="comments">
@foreach (dynamic record in Library
           .GetApprovedRecordsFromPage(DynamicModel.Id))
  {
     <li>
          @record.Created.ToString("dd MMMM yyy")
          @if(string.IsNullOrEmpty(record.Website)){
             <strong>@record.Name</strong>
          }
          else{
             <strong>
               <a href="@record.Website" target="_blank">@record.Name</a>
             </strong>
          }
         <span>said</span>
        <p>@record.Comment</p>
     </li>
  }
</ul>

The end result:

image

Want to give this a try, go download Contour RC

Custom markup on your contour forms 5

The last couple of months I’ve been working on the v5 port of Umbraco’s official form builder Contour, today the RC version is out and it won’t be long now before the actual release.

A big plus compared to the v4 webforms version is that it’s possible to have complete control of the form markup that Contour will generate (a much requested feature that was super easy to add due to the move to the MVC framework).

To try this I downloaded a website template that contains a contact form, the contact form page looks like this:

StaticTemplate

You can check out the html here . As you’ll see the form html is pretty simple and different to what Contour normally generates but now you are able to mimic this with Contour.

Step 1: Creating the form

Of course you’ll need to install Contour first and then create a form that has the fields you want (in this case that’s name, email, subject and message).

CreateForm

Step 2; Replacing the static html with the Contour form

If I then place the Contour macro in place of the static form markup I get the following result

ContourFormWithDefaultMarkupAndStylesheet

Because the form markup generated by Contour is different from the form html in the template I get a strange result. Of course you could add additional css rules to make it look the same but I want to output the same html as the static html template

Step 3: Customizing the form markup

As outlined in the RC blogpost you can either choose to customize all your forms at once or you can do this for a specific form.

Do customize it for a single form we need to know the form id, the id is available on the settings tab of the form designer.

FormId

Now in order to control the generated html we’ll need to create the folder:

~/App_Plugins/Packages/Contour/Views/Forms/2f2d7355-2a0d-416e-b36f-99d331b163cf/

2f2d7355-2a0d-416e-b36f-99d331b163cf being the form id

There we’ll copy the default form view from

~/\App_Plugins\Packages\Contour\Views\MacroPartials\ContourForm.cshtml

to

~/App_Plugins/Packages/Contour/Views/Forms/2f2d7355-2a0d-416e-b36f-99d331b163cf/ContourForm.cshtml

This shouldn’t result in any changes yet but if you now make changes to the ContourForm.cshtml view you’ll notice these in the output.

If you then want to make changes to a specific fieldtype it’s just a mather of copying the default views to the form directory and making your changes…

CopyFieldTypeViews

End result

Once the changes have been made I’m outputting the same html,my form is styled correctly and I have a working form!

EndResult

To give this a try go test the Contour v2.0 RC

UPDATE
If you want to take a look at the customized views you can download them here:
http://dl.dropbox.com/u/886345/UpdatedViews.zip

Contour member tools 36

After the previous post on contour and members I got several requests asking how you could use contour for a registration form so here are the details. I make use of some additional fieldtypes and workflow types so to make it easy to get started I also packaged those up (download details at the bottom). The package will add some extensions to contour that make it possible to create registration and profile forms.

Overview of what it will add:

  • Member Login fieldtype
  • Compare textbox fieldtype
  • Add member to membergroup workflow type
  • Save as umbraco member workflow type
  • Update umbraco member workflow type

Setting up a registration form

The registration form will be creating umbraco members so first make sure you have a member type. In this example I’ll be using a member type with 2 custom properties, first name and last name but it’s of course possible to add more …

image

Once the member type is setup we’ll create a registration form in Contour. Making use of the 2 additional field types.

image

The email address will be used as a unique identifier for our members (and also as the loginname). So the type of the email address field is set to ‘Member Login’.

image

The type of the password field is set to ‘Compare textbox’

image

Both fields are also set to mandatory.

Once the registration form is designed we’ll need to attach the workflow that will perform the actual registration. The type is called ‘Save as umbraco member’

image

The workflow has 3 settings, the member type of the member that will be created, an optional membergroup to add the member to and an option to immediately login the member after registation.

Once a membertype has been chosen it’s possible to map the properties of the type to the fields on the form. Name, login and email are all set the the email field since the email will be used as the unique identifier.

image

If you also want to add the newly created member to a group it’s possible by setting the membergroup setting.

image

It’s also possible to directly login the member after registration

image

You can then add other workflows that sends an email to the site administator, a welcome email to the new member….

image

Once the registration form is submitted a new member is created with the supplied details

image

image

The Member Login field type also makes sure that the login (email) is unique. It uses a little bit if jQuery for it so make sure jQuery is available where you place the registration form. If you enter an email address that is already in use you’ll get notified. This check also occurs when the form is submitted so it’s not possible to end up with duplicate emails.

image

Setting up an edit profile form

To create the profile form we’ll make use of the bracket syntax to fill the fields with member values and again use a workflow to update the member. This is already outlined in a previous post: Contour forms and umbraco members

Going further

To get a login form, logout button you can simply make use of the standard .net login controls. And with the public access dialog you can setup role based protection. Details on how to do that can be found in the members umbraco.tv tutorial 

Download

The Contour member tools Package is available on the project page on our.umbraco.org . Make sure to be running at least version 1.1.9 of Umbraco Contour.

Contour forms and Umbraco members 30

Contour 1.1.9 has just been shipped. It’s a minor release, but it adds a nifty little feature making it super easy to work with member data. Default values and workflow settings bracket syntax has now been updated to support member values.

Member values as default field values

Say that you have a comment form on your website with the standard fields (name, email, website and comment).

clip_image002

In the case when an Umbraco member is currently logged in and you want to pre-populate the name and email fields with the values from the logged in member, it’s now just a matter of setting the default value using the bracket syntax.

image

You can access: member.id, member.loginname, member.email and for custom properties simply use the alias member.customalias.

Full details on the syntax can be found in the Contour developer documentation.

Member values in workflow settings

Of course it’s also possible to use this syntax in workflow settings. For example, sending an email to the current member when a form has been submitted, just set the email setting to {member.email}

clip_image006

Member profile editor

Combine the default values with a workflow that will update the member details and you have a member profile editor.

Let’s start with a simple member type with just a single property with the alias custom.
clip_image008

I want the members to be able to edit their email and the value for the custom property so I’ll create a form with 2 fields (email address and custom property).

clip_image010

The default value of the email field has been set to {member.email}

clip_image012

And the one for custom property has been set to {member.custom}

clip_image014

So now if I request the form when I’m logged in as an Umbraco member, the fields should be populated with the current member values.

clip_image016

The next step is to make sure the member values get updated when the form is submitted. This can be done with a workflow (workflow is part of the contour strikes again project).

clip_image018

The workflow simply maps the member type properties to the contour form fields. When the form is submitted the member properties will be updated. Once this is in place you have a working profile editor.

Make sure you have at least Contour version 1.1.9 in order to use these features. Install and upgrade instructions can be found on the contour project page.

Branch/shop/… locator for Umbraco Razor style 7

A while ago I created a locator package for umbraco that made it pretty easy to add find nearest branch/shop/dealer/… functionality to your umbraco site.

To sharpen my razor skills I thought it would be great to try to port this from xslt to razor and turns out this was pretty easy (feel the power of the dark side).

Another update is that it now uses the google maps api v3 so no more need for api keys

It works in combination with the google maps datatype so you’ll need to make sure that your documents have coordinates stored before you are able to search (so a property of the type google maps using the google maps datatype).

image

Once the documents you want to search through have a long/lat stored you can use the locator macro.

image

The macro has 4 parameters

  • Document type alias of the documents you want to search through
  • Property alias of the property containing the coordinates
  • If you want the units in miles instead of km
  • Number of results to display

If you have the macro on a page/template you’ll need to provide it with a search location. So posting to that page with a querystring variable s will do the trick like ?s=gentbrugge

The default output is pretty simple,

  • Search location
  • Map with markers
  • Unordered list of results ordered by distance from search location

image

But that can be updated to your needs. There is some stuff going on in the locator assembly but the output can be completely customized by updating the razor script.

@inherits umbraco.MacroEngines.DynamicNodeContext
@using Locator
@using Locator.GeoCoding
@using Locator.GeoCoding.Services.Google
@using umbraco.MacroEngines;
 
@{
 
   @* Select the nodes you want to search through, defaults to children *@
   var nodesToSearchThrough = string.IsNullOrEmpty(Parameter.DocTypeAlias) ?
        Model.Children.Where("Visible"): Model.AncestorOrSelf(1).Descendants(Parameter.DocTypeAlias).Where("Visible");
   
   @* Alias of the property containing the long/lat, defaults to location *@
   string locationPropAlias = string.IsNullOrEmpty(Parameter.LocationPropAlias) ? 
        "location" : Parameter.locationPropAlias;
   
   @* Number of results, defaults to 5 *@
   int numberOfSearchResults = string.IsNullOrEmpty(Parameter.NumberOfResults)|| Parameter.NumberOfResults == "0" ? 
        5 : int.Parse(Parameter.NumberOfResults);
  
   @* Distance unit, defaults to km *@
   DistanceUnits distanceunit = Parameter.UnitInMiles == "1" ? 
        DistanceUnits.Miles : DistanceUnits.Kilometers;
  
   List<GeoItem> items = new List<GeoItem>();
   Location searchLocation = new Location();
  
   if(string.IsNullOrEmpty(Request["s"]))
   {
       @* Search term not provided *@ 
       <p>Please provide a search term</p>
   }
   else 
   {
      @* Lookup search location coordinates *@ 
      GeoResponse r = GoogleGeoCoder.CallGeoWS(Request["s"]);
    
      if(r.Results.Length == 0)
      {
        @* Location not found *@ 
        <p>Location not found:  @Request["s"]</p>
      }
      else
      {
        @* build up list of results *@       
        searchLocation = new Location(r.Results[0].Geometry.Location.Lat, r.Results[0].Geometry.Location.Lng);
       
        foreach (var node in nodesToSearchThrough) {
                         
              Location itemLocation = new Location(
                    Convert.ToDouble(node.GetProperty(locationPropAlias).ToString().Split(‘,’)[0], Utility.NumberFormatInfo),
                    Convert.ToDouble(node.GetProperty(locationPropAlias).ToString().Split(‘,’)[1], Utility.NumberFormatInfo));  
              
              items.Add(new GeoItem(node,itemLocation,searchLocation.DistanceBetween(itemLocation,distanceunit)));
                                                                                       
        }
        @* sort based on distance *@
        items.Sort(new GeoItemComparer());
       
      }
   }
}
@if(items.Count > 0)
{
@* Output Results *@ 
 
<p>Result for: @Request["s"]</p>
  
@* Output Map *@
 
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false">
</script>
 
<div id="map_canvas" style="width:500px; height:500px"></div>
 
<script type="text/javascript">
  function initialize() {
    var latlng = new google.maps.LatLng(
                    @searchLocation.Latitude.ToString(Utility.NumberFormatInfo), 
                    @searchLocation.Longitude.ToString(Utility.NumberFormatInfo));
    var myOptions = {
      zoom: 8,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map(document.getElementById("map_canvas"),
        myOptions);
    @{int c = 1;}                      
    @foreach(GeoItem geo in items.Take(numberOfSearchResults)){
        dynamic node = ((DynamicNode)geo.Node);    
                                                          
        <text>
          var mLatlng@(c) = new google.maps.LatLng(
                                      @geo.Location.Latitude.ToString(Utility.NumberFormatInfo),
                                      @geo.Location.Longitude.ToString(Utility.NumberFormatInfo));
          var marker@(c) = new google.maps.Marker({
              position: mLatlng@(c) , 
              map: map, 
              title:"@node.Name"
          });                                                              
         </text>
        c++;                                                  
   }
  }
  initialize();
</script>
 
 
@* Output list *@
<ul>
@foreach(GeoItem geo in items.Take(numberOfSearchResults)){ 
  dynamic node = ((DynamicNode)geo.Node);                                                
  <li><a href="@node.Url">@node.Name - @geo.Distance.ToString("0.00") km</a></li>                               
}
</ul>
}

Package can be downloaded on the project page: http://our.umbraco.org/projects/developer-tools/locator-razor-style

A First look at Property Editors in Umbraco v5 0

Umbraco v5 introduces a new definition: Property Editor

From the wiki: A Property Editor is the editor that a Data Type references. In Umbraco versions previous to version 5, there was no official name given to the editor that a Data Type referenced and it was also known as a Data Type. In version 5 we differentiate between the 2 aspects of Umbraco. A Data Type is defined by the Administrator of Umbraco which references a Property Editor. A Property Editor on the other hand is defined by a developer and compiled into a DLL.

So where in previous umbraco versions we talked about creating custom datatypes this will be know as property editors in v5.

On this blog I always used the same example when creating custom datatypes, a textarea where you can set a limit on the amount of characters (like in this post).

image

So as a first attempt at creating a property editor for umbraco v5 I created the same control. Of course this is build against the CTP release so there might be changes by the time v5 is released (if so I’ll do some follow up posts)

To get started with creating property editors, take a look at the v5 Wiki: Developing Property Editors

We’ll need to implement 3 classes, PropertyEditor, EditorModel and PrevalueModel (and in this case I’ll also have a razor view for my content editor control).

image

 

Property Editor

Core class which defines the Property Editor

using Umbraco.Cms.Model.BackOffice.PropertyEditors;
 
namespace Umbraco.Addons.PropertyEditors.CharLimit
{
    [PropertyEditor("E3FAF03B-C3A5-4630-B917-9B6D9F645833", 
        "CharLimit", "Text Area with character limit")]
    public class CharLimitEditor : PropertyEditor<CharLimitEditorModel, CharLimitPreValueModel>
    {
        public CharLimitEditor()
        {       
        }
 
        public override CharLimitEditorModel CreateEditorModel(CharLimitPreValueModel preValues)
        {
            return new CharLimitEditorModel(preValues);
        }
 
        public override CharLimitPreValueModel CreatePreValueEditorModel(string preValues)
        {
            return new CharLimitPreValueModel(preValues);
        }
    }
}

 

PreValueModel

Used to provide configuration settings for the Property Editor

using Umbraco.Cms.Model.BackOffice.PropertyEditors;
using Umbraco.Cms.Model.BackOffice.Editors;
 
namespace Umbraco.Addons.PropertyEditors.CharLimit
{
    public class CharLimitPreValueModel : PreValueModel
    {
        public CharLimitPreValueModel(string preValues)
            : base(preValues)
        { }
 
        public int CharacterLimit { get; set; }
 
        [AllowDocumentTypePropertyOverride]
        public bool IsRequired { get; set; }
 
        [AllowDocumentTypePropertyOverride]
        public string RegexValidationStatement { get; set; }
 
    }
}

image

An awesome improvement here is that you can mark settings with the AllowDocumentTypePropertyOverride, doing so will make them available on the add / edit property form of the document type

image

EditorModel

The EditorModel class is the class with the properties that a CMS editor will see

using System.Collections.Generic;
using Umbraco.Cms.Model.BackOffice.PropertyEditors;
using System.ComponentModel.DataAnnotations;
using Umbraco.Cms.Model.BackOffice;
using System.Text.RegularExpressions;
using Umbraco.Cms.Web.EmbeddedViewEngine;
 
namespace Umbraco.Addons.PropertyEditors.CharLimit
{
    [EmbeddedView("Umbraco.Addons.PropertyEditors.CharLimit.Views.CharLimitEditor.cshtml", 
        "Umbraco.Addons.PropertyEditors")]
    public class CharLimitEditorModel : EditorModel<CharLimitPreValueModel>, IValidatableObject
    {
 
        public CharLimitEditorModel(CharLimitPreValueModel preValueModel)
            : base(preValueModel)
        {
            
        }
 
        [DisplayFormat(ConvertEmptyStringToNull = false)]
        [ShowLabel(false)]
        public string Value { get; set; }
 
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            //ensure the string is empty and never ‘null’
            if (string.IsNullOrEmpty(Value)) Value = string.Empty;
 
            if (PreValueModel.IsRequired && string.IsNullOrEmpty(Value))
            {
                yield return new ValidationResult(
                    "Value is required", new[] { "Value" });
            }
            else if (!string.IsNullOrEmpty(PreValueModel.RegexValidationStatement) && 
                !Regex.IsMatch(Value, PreValueModel.RegexValidationStatement))
            {
                yield return new ValidationResult(
                    "Value does not match the required pattern", new[] { "Value" });
            }
        }
    }
}

 

note here that you have much more control over the validation

View

@inherits System.Web.Mvc.WebViewPage<Umbraco.Addons.PropertyEditors.CharLimit.CharLimitEditorModel>
@using System.Web.Helpers;
@using System.Web.Mvc;
@using System.Web.Mvc.Ajax;
@using System.Web.Mvc.Html;
@using System.Web.Routing;
@using System.Web.WebPages;
@using Microsoft.Web.Mvc;
@using ClientDependency.Core;
@using ClientDependency.Core.Mvc;
@using Umbraco.Cms.Web;
@using Umbraco.Cms.Web.Editors;
@using Umbraco.Addons.PropertyEditors.CharLimit;
 
@Html.ValidationMessageFor(x => Model.Value)
 
@Html.TextAreaFor(x => Model.Value)
 
@if (Model.PreValueModel.CharacterLimit > 0)
{     
    <br/><span class=’limitstatus’></span>
 
    <script type="text/javascript">
    (function ($) {
        $(document).ready(function () {  
            $(‘#@Html.IdFor(x => Model.Value)’).keyup(function () {
               
                var limit = @Model.PreValueModel.CharacterLimit.ToString();
                if ($(this).val().length > limit) {
                        $(‘.limitstatus’, $(this).parent()).html(‘You cannot write more then ‘ + limit + ‘ characters!’);
                    $(this).val($(this).val().substr(0, limit));
                }
                else {
                        $(‘.limitstatus’, $(this).parent()).html(‘You have ‘ + (limit - $(this).val().length) + ‘ characters left.’);
                }
            });
        });
    })(jQuery);
    </script>
}
 

So for the content editor control I created a razor view, since I’ll need to output a textarea but also some javascript

Want to see more examples of v5 property editors, make sure to take a look at the v5 sourcecode:

http://umbraco.codeplex.com/SourceControl/list/changesets

Transfering Umbraco Contour forms with Courier 2 10

Last week Courier 2 was released, Courier 2 makes it possible to compare and transfer content, doc types, templates, media, … between umbraco instances in a couple of clicks (saving you loads of time when working with multiple environments since it will detect all dependencies, and you won’t have to care about ID conflicts since that is simply handled by courier). You can read more details on it here: http://umbraco.com/products/more-add-ons/courier-2 

But it doesn’t stop with the standard umbraco parts like doc types and templates,… Courier comes with an API that enables you to also support custom data.

Details on how to get started with a custom provider can be found in the sample item provider docs: http://nightly.umbraco.org/UmbracoCourier/Sample%20Itemprovider.pdf
and sample sourcecode
http://nightly.umbraco.org/UmbracoCourier/Sample%20ItemProvider%20Source.zip

So wouldn’t it be great to be able to transfer Contour forms with Courier

image

Based on the sample item provider documentation I wrote a provider for Contour, you can download the assembly here: http://contourprovcourier.codeplex.com/releases/view/67524

Make sure you have Courier 2 and Contour installed on both source and target installation, then simply drop the assembly in the bin directory of both installations.

And you should now be able to transfer forms and changes to forms between instances. Courier will also be able to pick up any dependencies you might have to Contour form, if you are transferring a content node that has a form inside the rte or a template with a form macro on it Courier will know and also transfer the form.

Check it out:

Umbraco Contour and Razor 9

Want to output Contour records with razor instead of xslt well I’ve created some dynamic objects you can use to do so (please note that this is just a primary version of the dynamic objects, this will be improved in a next Contour release)

Here is an example:

@using Contour.Addons.DynamicObjects
 
<ul id="comments">
 @foreach (dynamic record in Library
           .GetApprovedRecordsFromPage(@Model.Id).OrderBy("Created"))
 {
     <li>
          @record.Created.ToString("dd MMMM yyy")
          @if(string.IsNullOrEmpty(record.Website)){
             <strong>@record.Name</strong>
          }
          else{
             <strong>
               <a href="@record.Website" target="_blank">@record.Name</a>
             </strong>
          }
         <span>said</span>
        <p>@record.Comment</p>
     </li>
  }
</ul>

 

This example uses the comment form created from the comment form template and then simply outputs all comments submitted on the current page. To access the field values you can simply use the dot notation (.FieldCaption like @record.Comment)

Download the assembly here: (simply unzip and drop in your bin directory)

Contour.Addons.DynamicObjects.dll.zip

Make sure you are running at least version 4.7 of umbraco since it won’t work on older version and of course have Contour installed.

« Previous PageNext Page »