Super easy jQuery events

by Shannon Deminick 25. March 2009 18:08

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

 

I've been using jQuery for a while but haven't really been using it much in the form of building custom classes or libraries. I've been working on re-developing Umbraco's JavaScript tree using jsTree (which is great by the way!) and have been writing a JavaScript library to support it. As with most code libraries, events play an important role in writing clean and effective code. In the past I've always used simple callback methods for "event handling" in JavaScript, but this isn't really an event system since it doesn't allow more than one subscriber. After some quick research, jQuery has this all built into the core, and by adding a couple very simple methods to your JavaScript classes, they will instantly support an event model!

Quick example: 

var myObject = {
	addEventHandler: function(fnName, fn) {
		$(this).bind(fnName, fn);
	},
	removeEventHandler: function(fnName, fn) {
		$(this).unbind(fnName, fn);
	},
	doSomething: function() {
		$.event.trigger("somethingHappening", [this, "myEventArgs"]);
	}
}

The above example is an object defining 2 functions to manage it's event model and another method which raises an event called "somethingHappened" with an array of arguments that will get bubbled to the event handlers.

To subscribe to the events is easy:

function onSomethingHappening(EV, args) {
	alert("something happened!");
	alert("sender: " + args[0]);
	alert("e: " + args[1]);
}
//subscribe to the event:
myObject.addEventHandler("somethingHappening", onSomethingHappening);

You'll notice that the above event handler function has 2 arguments, one called "EV" and one called "args". The EV parameters is the jQuery event object and the second one is the custom arguments object that was created when raising the event.

Since Umbraco's admin section uses an iframe approach, i though that managing events between the iframes would be an issue since they are all using seperate jQuery instantiations, but by raising and consuming events with the above method, this is no problem.

Categories: JavaScript

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