Selection Problem with Custom Media Type Content in Umbraco 4

by Shannon Deminick 4. March 2009 13:41

[Entry migrated from suite101.thefarmdigital.com.au]

The Problem

You have a custom media type. You want to add a link to it in the WYSIWYG editor. 

You go to add a link as normal, except in the "Insert/Edit Link" pop up, you click on the "Media" tab. You notice that when you click on it, no url is inserted in the Url field. 

 

The problem is due to this method in the Umbraco source:

private static string findMediaLink(Media dd, string nodeLink)
{
  Guid uploadGuid = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c");
  foreach (Property p in dd.getProperties)
  {
    if (p.PropertyType.DataTypeDefinition.DataType.Id == uploadGuid 
	&& !String.IsNullOrEmpty(p.Value.ToString()))
    {
      return p.Value.ToString();
    }
  }
  return "";
}

This method is called from the overrided Render(ref XmlTree tree) method in Umbraco's loadMedia class. Here is the code block: 

string nodeLink = findMediaLink(dd, dd.Id.ToString());
if (!String.IsNullOrEmpty(nodeLink))
{
    xNode.Action = "javascript:openMedia('" + nodeLink + "');";
}
else
{
    xNode.Action = null;
    xNode.DimNode();
}

Notice that when findMediaLink() is called, your custom media type is never going to return  "5032a6e6-69e3-491d-bb28-cd31cd11086c" as a Guid. So your media type never gets assiged it's openMedia action, and xNode.DimNode() will always be called.

 

The Work Around

You must replace the Umbraco media tree handler with your own one. We called ours "MediaTree".

Here's how:

  • Create a class (eg. MediaTree) that inherits from loadMedia (see code below)
  • Copy and paste the Render(ref XmlTree tree), and findMediaLink(Media dd, string nodeLink) methods from loadMedia.cs into your new class
  • Modify the findMediaLink(Media dd, string nodeLink) method to get the Guid from your custom media type, and check if it is equal to p.PropertyType.DataTypeDefinition.DataType.Id (see code below)

 

Here's the class:

public class MediaTree : loadMedia
{
    public MediaTree(string application) : base(application) { }

    public override void Render(ref XmlTree tree)
    {
        Media[] docs;

        if (m_id == -1)
            docs = Media.GetRootMedias();
        else
            docs = new Media(m_id).Children;

        foreach (Media dd in docs)
        {
            XmlTreeNode xNode = XmlTreeNode.Create(this);
            xNode.NodeID = dd.Id.ToString();
            xNode.Text = dd.Text;

            // Check for dialog behaviour
            if (!this.IsDialog)
            {
                if (!this.ShowContextMenu)
                    xNode.Menu = null;
                xNode.Action = "javascript:openMedia(" + dd.Id + ");";
            }
            else
            {
                if (this.ShowContextMenu)
                    xNode.Menu = new List(new IAction[] { ActionRefresh.Instance });
                else
                    xNode.Menu = null;
                if (this.DialogMode == TreeDialogModes.fulllink)
                {
                    string nodeLink = findMediaLink(dd, dd.Id.ToString());
                    if (!String.IsNullOrEmpty(nodeLink))
                    {
                        xNode.Action = "javascript:openMedia('" + nodeLink + "');";
                    }
                    else
                    {
                        xNode.Action = null;
                        xNode.DimNode();
                    }
                }
                else
                {
                    xNode.Action = "javascript:openMedia('" + dd.Id.ToString() + "');";
                }
            }
            xNode.HasChildren = dd.HasChildren;

            if (this.IsDialog)
                xNode.Source = GetTreeDialogUrl(dd.Id);
            else
                xNode.Source = GetTreeServiceUrl(dd.Id);

            if (dd.ContentType != null)
            {
                xNode.Icon = dd.ContentType.IconUrl;
                xNode.OpenIcon = dd.ContentType.IconUrl;
            }

            tree.Add(xNode);
        }
    }

    private static string findMediaLink(Media dd, string nodeLink)
    {
        TheFarm.Umbraco.Controls.MultiMediaUploadDT mmDT = 
		new TheFarm.Umbraco.Controls.MultiMediaUploadDT();
        Guid farmUpload = mmDT.Id;

        Guid uploadGuid = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c");
        foreach (Property p in dd.getProperties)
        {
            if ((p.PropertyType.DataTypeDefinition.DataType.Id == uploadGuid || 
		p.PropertyType.DataTypeDefinition.DataType.Id == farmUpload) 
		&& !String.IsNullOrEmpty(p.Value.ToString()))
            {
                return p.Value.ToString();
            }
        }
        return "";
    }

}

Note: For this to work your custom media class must contain a Guid.

eg.

public override Guid Id 
{ 
    get { return new Guid("{12345678-ABCD-EFGH-IJKLM-NOPQRSTUVWX}"); } 
} 

Now go to the database and edit the umbracoAppTree table.

public override Guid Id 
{ 
    get { return new Guid("{12345678-ABCD-EFGH-IJKLM-NOPQRSTUVWX}"); } 
} 

That's it.

Tags: ,
Categories: .Net | Umbraco

Comments

3/5/2009 8:41:46 AM #

Funny, have run into same issue while building a 'protected media' package.

It's just annoying the FindMediaLink is private to the original class, as it would make lot more sense to just override that behaviour in your class.

Cheers,
Dirk

Dirk

3/19/2009 8:17:30 AM #

A fix for this has been committed to the Umbraco core.
The method:

private static string findMediaLink(Media dd, string nodeLink)

has been changed to not be a static method and has been declared virtual so that inheritors can simply override only this method.

But better yet, a static method has been added to the loadMedia class so that you can simply add in your custom data types to match on application startup (i.e. global.asax), this way you don't actually have to create your tree class, modify the database or anything.

Shannon Deminick