Nibble

Archive for the 'C#' Category


Adding a new/custom section to umbraco, sample project 8

Simon Justesen, has a great post describing how to add new sections and trees inside umbraco (part 1, part 2).

To make it easier to get started, I thought I would provide some starter sourcecode for a demo custom section.

You can download the sourcecode here

Steps to get this running on your umbraco installation:

- Copy the assembly (CustomUmbracoSection.dll) to the \bin directory

- Copy the file custom.gif to \umbraco\images\tray\ directory

- Make a ‘custom’ directory in \umbraco and copy the editCustom.aspx page to \umbraco\custom directory

- Insert a new row in the umbracoApp table

INSERT INTO [umbracoApp]
           ([sortOrder]
           ,[appAlias]
           ,[appIcon]
           ,[appName])
     VALUES
           (9
           ,‘custom’
           ,‘custom.gif’
           ,‘custom’)

- Insert a new row in to umbracoAppTree table

INSERT INTO [umbracoAppTree]
           ([treeSilent]
           ,[treeInitialize]
           ,[treeSortOrder]
           ,[appAlias]
           ,[treeAlias]
           ,[treeTitle]
           ,[treeIconClosed]
           ,[treeIconOpen]
           ,[treeHandlerAssembly]
           ,[treeHandlerType])
     VALUES
           (0
           ,1
           ,0
           ,‘custom’
           ,‘custom’
           ,‘custom’
           ,‘.sprTreeFolder’
           ,‘.sprTreeFolder_o’
           ,‘CustomUmbracoSection’
           ,‘Trees.LoadCustomTree’)

- Update the \umbraco\config\create\UI.xml file, add:

  <nodeType alias=”initcustom”>
      <header>Custom</header>
      <usercontrol>/create/simple.ascx</usercontrol>
      <tasks>
        <create assembly=”CustomUmbracoSection” type=”Tasks.CustomTasks” />
        <delete assembly=”CustomUmbracoSection” type=”Tasks.CustomTasks” />
      </tasks>
  </nodeType>

After these steps are completed you will have to enable the new section for your user.

image

Then it should show up as the last icon in the sections (called custom, with a HAL’s camera eye icon).

image

In the custom section you’ll find this:

image

So just a sample node that will open a demo edit page.

Only log in umbraco members when they have been approved 14

A common thing when dealing with members on your site is that they need to be approved after registration before they can access the protected area on your site.

This post describes a simple way of doing that.

On the umbraco member type I have a True/false property with the alias active. If this is set to true on the member he is an ‘active’ member and is allowed to log in.

activeproperty

 

The only thing that is needed is to override the ValidateUser method of the UmbracoMembershipProvider. So make a custom class, inherit from umbraco.providers.members.UmbracoMembershipProvider and override the method (make sure to reference umbraco.providers).

Instead of just checking if there is a member with the supplied loginname and password we’ll add some extra code that will check if the member has his active property set to true. If that is the case we return true, in all other cases we return false.

 

namespace Nibble
{
    public class CustomMemberShipProvider : umbraco.providers.members.UmbracoMembershipProvider
    {
        public override bool ValidateUser(string username, string password)
        {
            umbraco.cms.businesslogic.member.Member m =
                umbraco.cms.businesslogic.member.Member.GetMemberFromLoginNameAndPassword(
                username, EncodePassword(password));
 
            if (m == null)
            {
                return false;
            }
            else
            {
                try
                {
                    if (m.getProperty(“active”).Value.ToString() == “1″)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
 
                }
                catch
                {
                    return false;
                }
             
            }
            return (m != null);
        }
    }
}

 

Final step is to modify the web.config so that our custom membership provider is used instead of the default umbraco one. So Just change the type attribute on the umbraco membership provider to the type of the custom membership provider.

<add name=”UmbracoMembershipProvider” type=”Nibble.CustomMemberShipProvider”
 enablePasswordRetrieval=”false” enablePasswordReset=”false” requiresQuestionAndAnswer=”false”
 defaultMemberTypeAlias=”CobraMember” passwordFormat=”Hashed” />

 

That’s it, now the asp:login control will only login the member if he has his active property set to true.

Creating custom umbraco datatypes revisited 3

Umbraco v4.0.1 introduces the abstract dataeditor class to make it easier to build custom datatypes.

So I tried to port the char limit datatype that I showed in the ‘creating custom umbraco datatypes’.

This is how it looks:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
 
namespace charLimitAbstractDataEditor
{
    public class DataType: umbraco.cms.businesslogic.datatype.AbstractDataEditor
    {
 
        private charLimitPrevalueEditor _prevalueeditor;
      
        private CharlimitControl m_control = new CharlimitControl();
 
 
        public override Guid Id
        {
            get
            {
                return new Guid(“a5dd5b89-74f5-4ed3-b855-f98ae07ea1ec”);
            }
        }
        public override string DataTypeName
        {
            get
            {
                return “CharLimit (AbstractDataEditor)”;
            }
        }
 
        public override umbraco.interfaces.IDataPrevalue PrevalueEditor
        {
            get
            {
                if (_prevalueeditor == null)
                    _prevalueeditor = new charLimitPrevalueEditor(this);
                return _prevalueeditor;
            }
        }
        public DataType()
        {
 
            base.RenderControl = m_control;
            m_control.Init += new EventHandler(m_control_Init);
            base.DataEditorControl.OnSave += new umbraco.cms.businesslogic.datatype.AbstractDataEditorControl.SaveEventHandler(DataEditorControl_OnSave);
        }
 
        void m_control_Init(object sender, EventArgs e)
        {
            m_control.Text = base.Data.Value != null ? base.Data.Value.ToString() : “”;
            m_control.Limit = Convert.ToInt32(((charLimitPrevalueEditor)PrevalueEditor).Configuration);
            
        }
 
        void DataEditorControl_OnSave(EventArgs e)
        {
            base.Data.Value = m_control.Text;
        }
       
    }
}

 

So you just need to inherit from umbraco.cms.businesslogic.datatype.AbstractDataEditor and override the Guid and the DataTypeName property.

If you also need a custom PrevalueEditor (datatype settings) you will also need to override the PrevalueEditor property.

Next step is to set the RenderControl in the constructor, the rendercontrol is just a custom control.

In this case it’s the CharLimitControl

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI;
 
namespace charLimitAbstractDataEditor
{
    public class CharlimitControl: System.Web.UI.WebControls.Panel
    {
        private TextBox txtCharLimit;
        private Label lblLimitInfo;
 
        protected override void OnInit(EventArgs e)
        {
 
            base.OnInit(e);
 
            txtCharLimit.Text = this.Text;
            txtCharLimit.TextMode = TextBoxMode.MultiLine;
            txtCharLimit.Rows = 10;
            txtCharLimit.Columns = 40;
            txtCharLimit.CssClass = “umbEditorTextFieldMultiple”;
            txtCharLimit.Attributes.Add(“onkeyup”, string.Format(“limitChars(this, {1}, ‘{0}’)”, “charlimitstatus” + this.ClientID, Limit.ToString()));
 
            lblLimitInfo = new Label();
 
            lblLimitInfo.Attributes.Add(“id”, “charlimitstatus” + this.ClientID);
 
 
            this.Controls.Add(txtCharLimit);
 
            this.Controls.Add(new LiteralControl(“<br/>”));
            this.Controls.Add(lblLimitInfo);
 
 
            string functionlimit = “function limitChars(textarea, limit, infodiv)”;
            functionlimit += “{”;
            functionlimit += “var text = textarea.value;”;
            functionlimit += “var textlength = text.length;”;
            functionlimit += “var info = document.getElementById(infodiv);”;
 
            functionlimit += “if(textlength > limit)”;
            functionlimit += “{”;
            functionlimit += “info.innerHTML = ‘You cannot write more then ‘+limit+’ characters!’;”;
            functionlimit += “textarea.value = text.substr(0,limit);”;
            functionlimit += “return false;”;
            functionlimit += “}”;
            functionlimit += “else”;
            functionlimit += “{”;
            functionlimit += “info.innerHTML = ‘You have ‘+ (limit - textlength) +’ characters left.’;”;
            functionlimit += “return true;”;
            functionlimit += “}”;
            functionlimit += “}”;
 
            ScriptManager.RegisterClientScriptBlock(this.Page, this.GetType(), “limitChars”, functionlimit, true);
        }
 
        private int _limit;
        public int Limit
        {
            get
            {
                return _limit;
            }
            set
            {
                _limit = value;
            }
 
 
 
        }
 
        public string _text;
        public string Text
        {
            get
            {
                return txtCharLimit.Text;
            }
            set
            {
                if (txtCharLimit == null)
                    txtCharLimit = new TextBox();
                txtCharLimit.Text = value;
            }
        }
    }
}

 

On init I just pass the stored value and the prevalue editor configuration to the custom control.

        void m_control_Init(object sender, EventArgs e)
        {
            m_control.Text = base.Data.Value != null ? base.Data.Value.ToString() : “”;
            m_control.Limit = Convert.ToInt32(((charLimitPrevalueEditor)PrevalueEditor).Configuration);
            
        }

 

Last step is to subscribe to the base.DataEditorControl.OnSave event and set the base.Data.Value (in this case to the custom control Text property)

        void DataEditorControl_OnSave(EventArgs e)
        {
            base.Data.Value = m_control.Text;
        }

 

Download sourcecode

/config/xsltExtensions.config 3

Another config file (check here for /config/Dashboard.config) that can be found in the /config folder of umbraco is the xslExtensions.config.

This file can be used to setup custom xslt extensions.

If you are not familiar with xslt extensions here is a brief intro:

With xslt extensions you can call static .net methods from xslt.

When editing an xslt file and inserting a value.

xsltextensions1

You get the option to “get extensions”.

xsltextensions2

Hitting the button will display a new modal that will list all xslt extensions and their methods.

Default umbraco has a couple of xslt extensions .

xsltextensions3

The most used one would probably be umbraco.library:NiceUrl(Int32 nodeID) , this takes a node id and will output the url of that node.

xsltextensions4

 

Using /config/xslExtensions.config you can also add custom xslt extensions.

Lets look at an example, the blog package for umbraco 4 comes with an xslt extension to get the gravatar image based on an email address.

So step 1 is to write the .net code that can be used. This is just a static method.

 

using System;
using System.Collections.Generic;
using System.Web;
 
namespace Umlaut.Umb.Blog
{
    public class BlogLibrary
    {
        /// <summary>
        /// Gets the gravatar.
        /// </summary>
        /// <param name=”email”>The email.</param>
        /// <param name=”size”>The size.</param>
        /// <param name=”defaultImage”>The default image.</param>
        /// <returns></returns>
        public static string getGravatar(string email, int size, string defaultImage)
        {
            System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash(System.Text.Encoding.ASCII.GetBytes(email));
 
            System.Text.StringBuilder hash = new System.Text.StringBuilder();
            for (int i = 0; i < result.Length; i++)
                hash.Append(result[i].ToString(“x2″));
 
            System.Text.StringBuilder image = new System.Text.StringBuilder();
 
            image.Append(“http://www.gravatar.com/avatar.php?”);
            image.Append(“gravatar_id=” + hash.ToString());
            image.Append(“&amp;rating=G”);
            image.Append(“&amp;size=” + size.ToString());
            image.Append(“&amp;default=”);
            image.Append(System.Web.HttpContext.Current.Server.UrlEncode(defaultImage));
           
 
            return image.ToString();
        }
    }
}

 

Next step (after dropping the assembly in the bin) is to setup the xslExtensions.config file.

<?xml version=”1.0″ encoding=”utf-8″?>
<XsltExtensions>
  <ext assembly=”\bin\Umlaut.Umb.Blog” type=”Umlaut.Umb.Blog.BlogLibrary” alias=”BlogLibrary”>
  </ext>
</XsltExtensions>

So you need a new ‘ext’ node with the following attributes:

  • assembly
  • type
  • alias

If the settings are correct it should appear (with the alias setup in the config file) in the xslt extensions modal

xsltextensions5

Last thing todo before you can use it is to declare the namespace.

<xsl:stylesheet 
    version=”1.0″ 
    xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” 
    xmlns:msxml=”urn:schemas-microsoft-com:xslt”
    xmlns:umbraco.library=”urn:umbraco.library”
    xmlns:BlogLibrary=”urn:BlogLibrary”
    exclude-result-prefixes=”msxml umbraco.library BlogLibrary”>

Fetching the nodeid in a custom datatype 2

Just a quick tip following the custom datatypes posts (Creating custom umbraco datatypes , Storing parseable xml data in a datatype ).

When creating a datatype you might at some point need to have the current document’s nodeid. Like if you want to insert some extra data in a custom table.

Since the datatypes are also used by autoform/doc2form , liveediting and not only in the umbraco backend the best approach is to fetch it like this:

((umbraco.cms.businesslogic.datatype.DefaultData)_data).NodeId

Storing parseable xml data in a datatype 6

As a follow up on the creating custom umbraco datatypes post I’ll show how to store parseable xml data in a datatype.

By default all propertry values get saved inside a cdata section(in the /data/umbraco.config file, wich has all published content).

Like in this example, a property with the alias test will look like this.

<data alias=”test”><![CDATA[1051;1052;1054]]></data>

But in some cases you would want to override this behavior, especially when you want to store xlm data.

Like the related links datatype in umbraco v4. This will store it’s links as child nodes of the data node.

<data alias=”links”>
        <links>
          <link title=”Same page” link=”http://www.google.com” type=”external” newwindow=”1″ />
          <link title=”Other page” link=”1051″ type=”internal” newwindow=”0″ />
        </links>
</data>

To do this the first step is to create a new class that inherits from umbraco.cms.businesslogic.datatype.DefaultData and overrides the ToXMl method.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
 
namespace umbraco.editorControls.relatedlinks
{
    public class RelatedLinksData : umbraco.cms.businesslogic.datatype.DefaultData
    {
        public RelatedLinksData(umbraco.cms.businesslogic.datatype.BaseDataType DataType) : base(DataType) { }
 
        public override System.Xml.XmlNode ToXMl(System.Xml.XmlDocument data)
        {
            if (this.Value != null) {
                XmlDocument xd = new XmlDocument();
                xd.LoadXml(this.Value.ToString());
                return data.ImportNode(xd.DocumentElement, true);
            } else {
                return base.ToXMl(data);
            }
        }
 
    }
}

 

Final step is to alter the class that implements the umbraco.interfaces.IDataType interface (the one with the guid) so that the new class is used instead of the default one. So just change

public override umbraco.interfaces.IData Data
        {
            get
            {
                if (_baseData == null)
                    _baseData = new umbraco.cms.businesslogic.datatype.DefaultData(this);
                return _baseData;
            }
        }

   

To (depending on how the class is named, in this case it’s RelatedLinksData)

public override umbraco.interfaces.IData Data
        {
            get
            {
                if (_baseData == null)
                    _baseData = new RelatedLinksData(this);
                return _baseData;
            }
        }

Creating custom umbraco datatypes 21

A couple of months ago I did a blog post about Creating custom datatypes using the umbraco usercontrol wrapper , I mentioned in that post that there was also an other way of creating a custom datatype. So in this post I’ll try to show you how to create a datatype using the 3 classes way. One of the main differences between this approach and the wrapper is that you’ll be able to have settings for your datatype.

I made a very basic datatype, the char limit datatype I’ll just show how I created that one.

First step would be to create a new project in visual studio (I tend to start a new class library, but web application should also be fine) and reference the necessary umbraco assemblies (so make sure you have those, just download v4).

Here is how the solution explorer looks when the char limit solution is opened.

customdatatype

The umbraco assemblies that needs to be referenced are businesslogic, cms, interfaces, umbraco.Datalayer and umbraco.editorControls (you can find these in the bin directory of umbraco).

As you can notice in the solution explorer the projects contains 3 files.

  • charLimitDataEditor.cs
  • charLimitDataType.cs
  • charLimitPrevalueEditor.cs

These are 3 classes (that’s wy I call it the 3 classes way) implementing the necessary umbraco interfaces.

I’ll start by showing the contents of charLimitDataType.cs

using System;
using System.Collections.Generic;
using System.Text;
 
namespace Nibble.Umb.Datatypes.CharLimit
{
    public class charLimitDataType : umbraco.cms.businesslogic.datatype.BaseDataType, umbraco.interfaces.IDataType
    {
        private umbraco.interfaces.IDataEditor _Editor;
        private umbraco.interfaces.IData _baseData;
        private charLimitPrevalueEditor _prevalueeditor;
 
        public override umbraco.interfaces.IDataEditor DataEditor
        {
            get
            {
                if (_Editor == null)
                    _Editor = new charLimitDataEditor(Data, ((charLimitPrevalueEditor)PrevalueEditor).Configuration);
                return _Editor;
            }
        }
 
        public override umbraco.interfaces.IData Data
        {
            get
            {
                if (_baseData == null)
                    _baseData = new umbraco.cms.businesslogic.datatype.DefaultData(this);
                return _baseData;
            }
        }
        public override Guid Id
        {
            get { return new Guid(“71518B4E-B1A5-11DD-A22C-8AAA56D89593″); }
        }
 
        public override string DataTypeName
        {
            get { return “Char Limit Textarea”; }
        }
 
        public override umbraco.interfaces.IDataPrevalue PrevalueEditor
        {
            get
            {
                if (_prevalueeditor == null)
                    _prevalueeditor = new charLimitPrevalueEditor(this);
                return _prevalueeditor;
            }
        }
    }
}

 

This is basicly where you give the datatype it’s name and unique id. The name will show up in the rendercontrol dropdown of the edit datatype page.

customdatatype2

Each datatype needs to have a guid, when creating a new datatype make sure you change this to a unique one.

Next is the charLimitPrevalueEditor.cs file

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using umbraco.DataLayer;
using umbraco.BusinessLogic;
using umbraco.editorControls;
 
namespace Nibble.Umb.Datatypes.CharLimit
{
    public class charLimitPrevalueEditor : System.Web.UI.WebControls.PlaceHolder, umbraco.interfaces.IDataPrevalue
    {
        #region IDataPrevalue Members
 
        // referenced datatype
        private umbraco.cms.businesslogic.datatype.BaseDataType _datatype;
 
      
        private TextBox _txtLimit;
 
        public charLimitPrevalueEditor(umbraco.cms.businesslogic.datatype.BaseDataType DataType)
        {
 
            _datatype = DataType;
            setupChildControls();
 
        }
 
        private void setupChildControls()
        {
            
            _txtLimit = new TextBox();
            _txtLimit.ID = “txtLimit”;
            _txtLimit.CssClass = “umbEditorTextField”;
 
 
            Controls.Add(_txtLimit);
 
        }
 
 
 
        public Control Editor
        {
            get
            {
                return this;
            }
        }
 
 
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (!Page.IsPostBack)
            {
                
                if (Configuration.Length > 0)
                {
 
                    _txtLimit.Text = Configuration;
 
                }
                else
                {
                    _txtLimit.Text = “100″;
                }
 
 
            }
 
 
        }
 
        public void Save()
        {
            _datatype.DBType = (umbraco.cms.businesslogic.datatype.DBTypes)Enum.Parse(typeof(umbraco.cms.businesslogic.datatype.DBTypes), DBTypes.Ntext.ToString(), true);
 
 
            string data = _txtLimit.Text;
 
            SqlHelper.ExecuteNonQuery(“delete from cmsDataTypePreValues where datatypenodeid = @dtdefid”, 
                    SqlHelper.CreateParameter(“@dtdefid”, _datatype.DataTypeDefinitionId));
            SqlHelper.ExecuteNonQuery(“insert into cmsDataTypePreValues (datatypenodeid,[value],sortorder,alias) values (@dtdefid,@value,0,”)”, 
                    SqlHelper.CreateParameter(“@dtdefid”, _datatype.DataTypeDefinitionId), SqlHelper.CreateParameter(“@value”, data));
 
        }
 
        protected override void Render(HtmlTextWriter writer)
        {
            writer.WriteLine(“<table>”);
            writer.Write(“<tr><th>Character Limit:</th><td>”);
            _txtLimit.RenderControl(writer);
            writer.Write(“</td></tr>”);
            writer.Write(“</table>”);
        }
 
        public string Configuration
        {
            get
            {
                object conf =
                   SqlHelper.ExecuteScalar<object>(“select value from cmsDataTypePreValues where datatypenodeid = @datatypenodeid”,
                                           SqlHelper.CreateParameter(“@datatypenodeid”, _datatype.DataTypeDefinitionId));
 
                if (conf != null)
                    return conf.ToString();
                else
                    return “”;
 
            }
        }
 
        #endregion
 
        public static ISqlHelper SqlHelper
        {
            get
            {
                return Application.SqlHelper;
            }
        }
    }
}

This class is used to setup the datatype settings (something you can’t do when using the wrapper method). In this case it shows a textbox wich will be used to set the character limit. On save it will store this value (using the datalayer) in the database.

customdatatypes3

Last one is charLimitDataEditor.cs

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using umbraco.interfaces;
 
namespace Nibble.Umb.Datatypes.CharLimit
{
    public class charLimitDataEditor : System.Web.UI.UpdatePanel, umbraco.interfaces.IDataEditor
    {
 
        private umbraco.interfaces.IData _data;
           
        private string CharLimit;
 
        private TextBox txtCharLimit;
        private Label lblLimitInfo;
 
        public charLimitDataEditor(umbraco.interfaces.IData Data, string Configuration)
        {
            _data = Data;
 
            if (Configuration.Length > 0)
            {
                CharLimit = Configuration;
            }
            else
            {
                CharLimit = “100″;
            }
        }
 
        public virtual bool TreatAsRichTextEditor
        {
            get { return false; }
        }
 
        public bool ShowLabel
        {
            get { return true; }
        }
 
        public Control Editor { get { return this; } }
 
        public void Save()
        {
 
            this._data.Value = txtCharLimit.Text;
            
        }
 
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
 
 
            txtCharLimit = new TextBox();
 
            txtCharLimit.Text = _data.Value.ToString();
            txtCharLimit.TextMode = TextBoxMode.MultiLine;
            txtCharLimit.Rows = 10;
            txtCharLimit.Columns = 40;
            txtCharLimit.CssClass = “umbEditorTextFieldMultiple”;
            txtCharLimit.Attributes.Add(“onkeyup”, string.Format(“limitChars(this, {1}, ‘{0}’)”, “charlimitstatus” + base.ClientID, CharLimit));
 
           
 
 
            lblLimitInfo = new Label();
            
            lblLimitInfo.Attributes.Add(“id”, “charlimitstatus” + base.ClientID);
            
 
            base.ContentTemplateContainer.Controls.Add(txtCharLimit);
 
            base.ContentTemplateContainer.Controls.Add(new LiteralControl(“<br/>”));
            base.ContentTemplateContainer.Controls.Add(lblLimitInfo);
 
 
            string functionlimit = “function limitChars(textarea, limit, infodiv)”;
            functionlimit += “{”;
            functionlimit += “var text = textarea.value;”;
            functionlimit += “var textlength = text.length;”;
            functionlimit += “var info = document.getElementById(infodiv);”;
 
            functionlimit += “if(textlength > limit)”;
            functionlimit += “{”;
            functionlimit += “info.innerHTML = ‘You cannot write more then ‘+limit+’ characters!’;”;
            functionlimit += “textarea.value = text.substr(0,limit);”;
            functionlimit += “return false;”;
            functionlimit += “}”;
            functionlimit += “else”;
            functionlimit += “{”;
            functionlimit += “info.innerHTML = ‘You have ‘+ (limit - textlength) +’ characters left.’;”;
            functionlimit += “return true;”;
            functionlimit += “}”;
            functionlimit += “}”;
 
            ScriptManager.RegisterClientScriptBlock(this.Page, this.GetType(), “limitChars”, functionlimit, true);
 
        }
      
    }
}

This one is used for the actual datatype dataeditor, so the control you will get in the content section of umbraco.

customdatatypes4

This class inherits from the updatepanel class and implements the umbraco.interfaces.IDataEditor. So on init you need to add the controls, in this case a textbox and a literal (for the info text on character limit) and fetch the saved data. And in the save method you can set what value needs to be saved.

Feel free to experiment with the sourcecode.

Download sourcecode

Creating a youtube macro for umbraco (with xslt extension) 19

I got this request from Bernie.

He wanted a way to insert youtube videos into the richtexteditor by only supplying the link to the video (like http://www.youtube.com/watch?v=fruHQhNe-UM)

When inserting the macro you would get this screen, only asking for the link.

image

After hitting ok it will insert the embed code and the video will be visible on the page.

I’ll go through the different steps I did to develop this macro.

First take a look at the embed code supplied by youtube.

<object width=”425″ height=”344″>
<param name=”movie” value=”http://www.youtube.com/v/fruHQhNe-UM&hl=en&fs=1″></param>
<param name=”allowFullScreen” value=”true”></param>
<embed src=”http://www.youtube.com/v/fruHQhNe-UM&hl=en&fs=1″ 
type=”application/x-shockwave-flash” allowfullscreen=”true” width=”425″ height=”344″>
</embed>
</object>

The src attibute of the embed tag will contain the location of the video. When you compare this to the url

url: http://www.youtube.com/watch?v=fruHQhNe-UM

src: http://www.youtube.com/v/fruHQhNe-UM&hl=en&fs=1

You’ll notice that the important part is the video id. So we will need to get the video id out of the url and insert this into the src attribute of the embed code.

I did this by creating an xslt extension ( you can probably do this without the extension but this was the fastes way for me).

So I made a youtube class

public class YouTube
    {
        public static string getVideoId(string url)
        {
            Regex testYouTube = new Regex(@”(\?v=)(\w[\w|-]*)”);
 
           
            foreach (Match tempMatch in testYouTube.Matches(url))
            {
               
                return(tempMatch.Value.Substring(3, tempMatch.Value.Length - 3));
            }
 
            return “”;
        }
    }

 

And hooked this up in umbraco so I could use it as an xslt extension ( you do this by exposing your class in the \config\xsltExtensions.config file ).

With that in place it’s time to create the xslt file ( with macro )

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE xsl:Stylesheet [ &lt;!ENTITY nbsp “&#x00A0;”> ]>
<xsl:stylesheet 
    version=”1.0″ 
    xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” 
    xmlns:msxml=”urn:schemas-microsoft-com:xslt”
                xmlns:YouTube=”urn:YouTube”
    xmlns:umbraco.library=”urn:umbraco.library”
    exclude-result-prefixes=”msxml umbraco.library YouTube”>
 
 
<xsl:output method=”xml” omit-xml-declaration=”yes”/>
 
<xsl:param name=”currentPage”/>
<xsl:variable name=”url” select=”//YoutubeUrl”/>
<xsl:template match=”/”>
 
 
<object width=”425″ height=”355″>
<param name=”movie” value=”http://www.youtube.com/v/{YouTube:getVideoId($url)}&amp;hl=en”></param>
<param name=”wmode” value=”transparent”></param>
<embed src=”http://www.youtube.com/v/{YouTube:getVideoId($url)}&amp;hl=en” type=”application/x-shockwave-flash” wmode=”transparent” width=”425″ height=”355″></embed>
</object>
 
</xsl:template>
 
</xsl:stylesheet>

 

This will return the embed code and get the video id from the url (wich is a parameter of the macro ) by calling the xslt extension.

Macro parameters look like this:

image

Creating packages for umbraco, usercontrol that fires as last step of installation 2

Thanks to Per’s packager (which will be integrated in v4) creating packages for umbraco is a very simple thing. The only part that can get a little tricky is if you need to update the database, or one of the config files.

The way to do this is to create a custom usercontrol, and this usercontrol gets fired at the last step of the package installation (you need to set this up in the package.xml file). I’ve created several packages so I thought I would just show the way I did these things.

 

Executing a SQL statement ( to create new tables )

StreamReader reader = new StreamReader(base.Server.MapPath(“/umbraco/plugins/nibble/demo/installer/demo.sql”));
string sqlStatement = reader.ReadToEnd();
reader.Close();
SqlHelper.ExecuteNonQuery(GlobalSettings.DbDSN, CommandType.Text, sqlStatement);

In this sample the statement is stored in a .sql file, then it is just read in and executed.

 

Updating xsltExtensions.config ( for xslt extensions )

XmlDocument document = new XmlDocument();
document.Load(base.Server.MapPath(“/config/xsltExtensions.config”));
XmlNode node = document.SelectSingleNode(“/XsltExtensions”);
if (node.SelectNodes(“/ext [@assembly = ‘/bin/Jesper.GoogleMaps’]”).Count == 0)
{
    XmlNode newChild = document.CreateElement(“ext”);
    XmlAttribute attribute = document.CreateAttribute(“assembly”);
    attribute.Value = “/bin/Jesper.GoogleMaps”;
    newChild.Attributes.Append(attribute);
    XmlAttribute attribute2 = document.CreateAttribute(“type”);
    attribute2.Value = “Jesper.GoogleMaps.Library”;
    newChild.Attributes.Append(attribute2);
    XmlAttribute attribute3 = document.CreateAttribute(“alias”);
    attribute3.Value = “GoogleMaps.Library”;
    newChild.Attributes.Append(attribute3);
    node.AppendChild(newChild);
    document.Save(base.Server.MapPath(“/config/xsltExtensions.config”));
}

this sample will add

<ext assembly=”/bin/Jesper.GoogleMaps” type=”Jesper.GoogleMaps.Library” alias=”GoogleMaps.Library” />

to the /config/xsltExtensions.config file

 

Updating restExtensions.config ( for base )

XmlDocument document = new XmlDocument();            
document.Load(Server.MapPath(“/config/”) + “restExtensions.config”);
XmlNode newChild = document.CreateElement(“ext”);
 
 
XmlAttribute AtAssembly = document.CreateAttribute(“assembly”);
AtAssembly.Value = “/bin/xtraUmbracoStarRating”;
newChild.Attributes.Append(AtAssembly);
 
XmlAttribute atType = document.CreateAttribute(“type”);
atType.Value = “xtraUmbracoStarRating.StarRating”;
newChild.Attributes.Append(atType);
 
XmlAttribute atAlias = document.CreateAttribute(“alias”);
atAlias.Value = “StarRating”;
newChild.Attributes.Append(atAlias);
 
XmlNode permissionNode = document.CreateElement(“permission”);
newChild.AppendChild(permissionNode);
 
XmlAttribute atMethod = document.CreateAttribute(“method”);
atMethod.Value = “update”;
permissionNode.Attributes.Append(atMethod);
 
XmlAttribute atAllowAll = document.CreateAttribute(“allowAll”);
atAllowAll.Value = “true”;
permissionNode.Attributes.Append(atAllowAll);
 
document.DocumentElement.AppendChild(newChild);
 
document.Save(Server.MapPath(“/config/”) + “restExtensions.config”);

this sample will add

<ext assembly=”/bin/xtraUmbracoStarRating” type=”xtraUmbracoStarRating.StarRating” alias=”StarRating”>
    <permission method=”update” allowAll=”true” />
</ext>

to the /config/restExtensions.config file

 

Updating dashboard.config ( to add usercontrols on the dashboard )

XmlDocument document = new XmlDocument();
document.Load(base.Server.MapPath(“/config/Dashboard.config”));
XmlNode node = document.SelectSingleNode(“/dashBoard”);
 
XmlNode sectionChild = document.CreateElement(“section”);
XmlNode areasChild = document.CreateElement(“areas”);
XmlNode areaChild = document.CreateElement(“area”);
 
areaChild.InnerText = “developer”;
 
XmlNode tabChild = document.CreateElement(“tab”);
 
XmlAttribute attribute = document.CreateAttribute(“caption”);
attribute.Value = “Nibble FX”;
tabChild.Attributes.Append(attribute);
 
XmlNode controlChild = document.CreateElement(“control”);
 
controlChild.InnerText = “/usercontrols/Nibble/NibbleFX.ascx”;
 
               
tabChild.AppendChild(controlChild);
areasChild.AppendChild(areaChild);
sectionChild.AppendChild(areasChild);
sectionChild.AppendChild(tabChild);
node.AppendChild(sectionChild);
document.Save(base.Server.MapPath(“/config/Dashboard.config”));

this sample will add

  <section>
    <areas>
      <area>developer</area>
    </areas>
    <tab caption=”Nibble FX”>
      <control>/usercontrols/Nibble/NibbleFX.ascx</control>
    </tab>
  </section>

to the /config/dashboard.config file

Creating custom datatypes using the umbraco usercontrol wrapper 23

I showed how easy it is to add custom .net usercontrols to your umbraco site frontend (http://www.nibble.be/?p=12). It is also very easy to add .net usercontrols wich you can use as custom datatypes. There are 2 ways of doing this, one being the umbraco usercontrol wrapper wich I will explain in this post.

Why add custom datatypes ? Default umbraco has around 20 datatypes, including true/false, simple editor, richtext editor,…everything for managing a basic site, but sometimes you might need to do something that you can’t do with the default datatypes.

An example shown at codegarden 07 was an ftp datatype. Other examples could be: a dropdown wich lists all files found in a specific folder, a dropdown listing data from another database, …

So how do we do this ? First reference the umbraco.editorControls assembly (can be found in the bin directory of umbraco). Then create a new usercontrol.

Your usercontrol will need to implement the umbraco.editorControls.userControlGrapper.IUsercontrolDataEditor interface

public partial class Demo : System.Web.UI.UserControl, umbraco.editorControls.userControlGrapper.IUsercontrolDataEditor  

You will need to implement the interface member value.

namespace UmbracoCreateCustomDatatypeWithWrapper
{
    public partial class Demo : System.Web.UI.UserControl, umbraco.editorControls.userControlGrapper.IUsercontrolDataEditor  
    {
        public string umbracoValue;
 
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack)
            {
                
            }
        }
 
        public object value
        {
            get
            {
                return umbracoValue;
            }
            set
            {
                umbracoValue = value.ToString();
            }
        }
    }
}

 

Now you can add controls and logic to your usercontrol. One important thing you need to know is that the umbraco save action will trigger a postback. So you will need to set the umbracovalue on postback. Just take a look at the ftp datatype…

protected void Page_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack)
            {
                if (!String.IsNullOrEmpty(uploadFile.FileName))
                {
                    string file = Server.MapPath(“/media/ftp/” + uploadFile.FileName);
                    uploadFile.SaveAs(file);
                    FileInfo fi = new FileInfo(file);
                    UploadFile(fi,
                        ConfigurationManager.AppSettings[“ftpDataTypeUser”],
                                                ConfigurationManager.AppSettings[“ftpDataTypePassword”],
                        ConfigurationManager.AppSettings[“ftpDataTypeServer”]);
                    File.Delete(file);
                    umbracoValue = “http://” + ConfigurationManager.AppSettings[“ftpDataTypeServer”] + “/” + uploadFile.FileName;
                }
            }
 
            FileName.Text = umbracoValue;
        }

Adding this usercontrol as a datatype can be done a a few simple steps, first copy the assembly to the bin directory and copy the usercontrol to the usercontrols directory.

Now login to the umbraco backend and go to the developer section.

image

There you will need to create a new datatype.

Then select umbraco usercontrol wrapper as rendercontrol and hit save.

image

You will have to choose the usercontrol ( the one just uploaded )  and the database datatype ( depending on the type of object you are returning as umbracovalue ).

Demo project: download

Next Page »