W3C implementation of IE's onmouseleave event

How can I track when a mouse leaves an element? An unmodified onmouseout doesn't exactly fit the bill since if my mouse leaves C (a child node of B) the onmouseout of B gets called even when the mouse comes to rest within B. It turns out that this event bubbling is useful in simulating the onmouseleave event anyhow.

If you wish to capture onmouseleave for leaves you in a predicament of having to do an costly ancestor search. What if you added a special attribute to all child elements of B? Say you added an attribute called logicalParent which referenced B to all of them. This would allow you to check event.currentTarget (or event.toElement in IE) and if the logicalParent attribute is missing or is not equal to the event.currentTarget (or sender/event.srcElement in IE) you have a mouse leave event!

Here's a W3C (Firefox/Safari/Opera implementation):

function addOnMouseLeave(
  /*DOMElement*/element, /*Function*/onmouseleave)
  // summary: add an onMouseLeave handler to an element
  // element: DOMElement
  //   element for which the onMouseLeave is desired
  if (!element.id) element.id = ["onmouseleaveId",Math.random()].join("");
  setLogicalParent(element, element);
  element.onmouseout = function(evt)
    var toElem = evt.relatedTarget;
    if (evt.relatedTarget == evt.currentTarget) return;
    var logicalParentId = toElem.getAttribute("logicalParentId");
    if (!logicalParentId || logicalParentId != element.id)
      // call the onmouseleave handler with element as this
      // and pass it the event object
      onmouseleave.apply(element, [evt]);
function setLogicalParent(
  /*DOMElement*/root, /*DOMElement*/logicalParent)
  // summary: set the logicalParent of an entire DOM subtree
  // root: DOMElement
  //   topmost element in the DOM subtree
  // logicalParent: DOMElement
  //   element which will be referenced by all in the subtree
  var children=root.childNodes;
  if (!children) return;
  for (var i=0, count=children.length; i<count; i++)
    var child = children[i];
    if (!child.setAttribute) continue;
    child.setAttribute("logicalParentId", logicalParent.id);
    setLogicalParent(child, logicalParent);
function onmouseleave(evt)
  alert("onmouseleave:" + evt.currentTarget.id);