Index: modules/overlay/overlay-parent.js
===================================================================
RCS file: /cvs/drupal/drupal/modules/overlay/overlay-parent.js,v
retrieving revision 1.11
diff -u -r1.11 overlay-parent.js
--- modules/overlay/overlay-parent.js	25 Dec 2009 10:15:23 -0000	1.11
+++ modules/overlay/overlay-parent.js	26 Dec 2009 12:02:30 -0000
@@ -7,58 +7,23 @@
  */
 Drupal.behaviors.overlayParent = {
   attach: function (context, settings) {
-    var $window = $(window);
-
-    // Alter all admin links so that they will open in the overlay.
-    $('a', context).filter(function () {
-      return Drupal.overlay.isAdminLink(this.href);
-    })
-    .once('overlay')
-    .each(function () {
-      // Move the link destination to a URL fragment.
-      this.href = Drupal.overlay.fragmentizeLink(this);
-    });
-
-    // Simulate the native click event for all links that appear outside the
-    // overlay. jQuery UI Dialog prevents all clicks outside a modal dialog.
-    $('.overlay-displace-top a:not(.overlay-displace-no-click)', context)
-    .add('.overlay-displace-bottom a:not(.overlay-displace-no-click)', context)
-    .click(function () {
-      window.location.href = this.href;
-    });
-
-    // Resize the overlay when the toolbar drawer is toggled.
-    $('#toolbar a.toggle', context).once('overlay').click(function () {
-      setTimeout(function () {
-        // Resize the overlay, if it's open.
-        if (Drupal.overlay.isOpen) {
-          Drupal.overlay.outerResize();
-        }
-      }, 10);
-    });
-
     // Make sure the onhashchange handling below is only processed once.
     if (this.processed) {
       return;
     }
     this.processed = true;
 
+    // Bind event handlers to the parent window.
+    $(window)
     // When the hash (URL fragment) changes, open the overlay if needed.
-    $window.bind('hashchange', function (e) {
-      // If we changed the hash to reflect an internal redirect in the overlay,
-      // its location has already been changed, so don't do anything.
-      if ($.data(window.location, window.location.href) === 'redirect') {
-        $.data(window.location, window.location.href, null);
-      }
-      // Otherwise, change the contents of the overlay to reflect the new hash.
-      else {
-        Drupal.overlay.trigger();
-      }
-    });
-
+    .bind('hashchange', Drupal.overlay.hashchangeHandler)
     // Trigger the hashchange event once, after the page is loaded, so that
     // permalinks open the overlay.
-    $window.trigger('hashchange');
+    .trigger('hashchange');
+    // Instead of binding a click event handler to every link we bind one to the
+    // document and only handle events that bubble up. This allows other scripts
+    // to bind their own handlers to links and also to prevent overlay's handling.
+    $(document).click(Drupal.overlay.clickHandler);
   }
 };
 
@@ -545,7 +510,7 @@
     clearTimeout(self.resizeTimeoutID);
     self.resizeTimeoutID = setTimeout(delayedResize, 150);
   }
-  
+
   // Scroll to anchor in overlay. This needs to be done after delayedResize().
   if (iframeWindow.document.location.hash) {
     window.scrollTo(0, self.$iframeWindow(iframeWindow.document.location.hash).position().top);
@@ -707,9 +672,101 @@
 };
 
 /**
+ * Click event handler.
+ *
+ * Instead of binding a click event handler to every link we bound one to the
+ * document and handle events that bubble up. This allows other scripts to bind
+ * their own handlers to links and also to prevent overlay's handling.
+ *
+ * This handler makes links in displaced regions work correctly, even when the
+ * overlay is open.
+ *
+ * This handler also is being used by the overlay iframe.
+ *
+ * @see Drupal.overlayChild.behaviors.addClickHandler (overlay-child.js)
+ */
+Drupal.overlay.clickHandler = function (event) {
+  var self = Drupal.overlay;
+
+  var $target = $(event.target);
+
+  if (self.isOpen && $target.closest('.overlay-displace-top, .overlay-displace-bottom').length) {
+    // jQuery UI Dialog prevents all clicks outside a modal dialog. It checks
+    // if target is inside a dialog and compares its z-index against this
+    // variable. By setting it to -1, jQuery UI Dialog let the event propagate.
+    $.ui.dialog.overlay.maxZ = -1;
+    // Click events in displaced regions could potentionally change the size of
+    // that region (e.g. the toggle button of the toolbar module). Trigger the
+    // resize event to force a recalculation of overlay's size/position.
+    $(window).triggerHandler('resize');
+  }
+
+  // Only continue when it regards a standard 'click', usually left button.
+  if (event.button != 0) {
+    return;
+  }
+
+  // Only continue if clicked target (or one of its parents) is a link.
+  if (!$target.is('a') || $target.hasClass('overlay-exclude')) {
+    $target = $target.closest('a');
+    if (!$target.length) {
+      return;
+    }
+  }
+
+  var href = $target.attr('href');
+  // Only continue if link has an href attribute and user is not pressing the
+  // ALT, CTRL, META (Command key on the Macintosh keyboard) or SHIFT key.
+  if (!event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey && href != undefined) {
+    // Open admin links in the overlay.
+    if (self.isAdminLink(href)) {
+      // Redirect to a fragmentized href. This will trigger a hashchange event.
+      href = self.fragmentizeLink($target.get(0));
+      self.redirect(href);
+      // Prevent default action and further propagation of the event.
+      return false;
+    }
+    // Open external links in a new window.
+    else if (href.indexOf('http') == 0) {
+      // Add a target attribute to the clicked link. This is being picked up by
+      // the default action handler.
+      $target.attr('target', '_new');
+    }
+    // Non-admin links should close the overlay and open in the main window.
+    // Only handle them if the overlay is open and the clicked link is inside
+    // the overlay iframe, else default action will do fine.
+    else if (self.isOpen) {
+      var inFrame = false;
+      // W3C: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-UIEvent-view
+      if (event.view && event.view.frameElement != null) {
+        inFrame = true;
+      }
+      // IE: http://msdn.microsoft.com/en-us/library/ms534331%28VS.85%29.aspx
+      else if (event.target.ownerDocument.parentWindow && event.target.ownerDocument.parentWindow.frameElement != null) {
+        inFrame = true;
+      }
+
+      // Add a target attribute to the clicked link. This is being picked up by
+      // the default action handler.
+      if (inFrame) {
+        // Make the link to be opening in the immediate parent of the frame.
+        $target.attr('target', '_parent');
+      }
+    }
+  }
+};
+
+/**
  * Open, reload, or close the overlay, based on the current URL fragment.
  */
-Drupal.overlay.trigger = function () {
+Drupal.overlay.hashchangeHandler = function (event) {
+  // If we changed the hash to reflect an internal redirect in the overlay,
+  // its location has already been changed, so don't do anything.
+  if ($.data(window.location, window.location.href) === 'redirect') {
+    $.data(window.location, window.location.href, null);
+    return;
+  }
+
   // Get the overlay URL from the current URL fragment.
   var state = $.bbq.getState('overlay');
   if (state) {
Index: modules/overlay/overlay-child.js
===================================================================
RCS file: /cvs/drupal/drupal/modules/overlay/overlay-child.js,v
retrieving revision 1.3
diff -u -r1.3 overlay-child.js
--- modules/overlay/overlay-child.js	23 Dec 2009 21:33:52 -0000	1.3
+++ modules/overlay/overlay-child.js	26 Dec 2009 12:02:30 -0000
@@ -87,54 +87,21 @@
 };
 
 /**
- * Modify links and forms depending on their relation to the overlay.
- *
- * By default, forms and links are assumed to keep the flow in the overlay.
- * Thus their action and href attributes respectively get a ?render=overlay
- * suffix. Non-administrative links should however close the overlay and
- * redirect the parent page to the given link. This would include links in a
- * content listing, where administration options are mixed with links to the
- * actual content to be shown on the site out of the overlay.
- *
- * @see Drupal.overlay.isAdminLink()
+ * Instead of binding a click event handler to every link we bind one to the
+ * document and handle events that bubble up. This also allows other scripts
+ * to bind their own handlers to links and also to prevent overlay's handling.
  */
-Drupal.overlayChild.behaviors.parseLinks = function (context, settings) {
-  var closeAndRedirectOnClick = function (event) {
-    // We need to store the parent variable locally because it will
-    // disappear as soon as we close the iframe.
-    var parentWindow = parent;
-    if (parentWindow.Drupal.overlay.close(false)) {
-      parentWindow.Drupal.overlay.redirect($(this).attr('href'));
-    }
-    return false;
-  };
-  var redirectOnClick = function (event) {
-    parent.Drupal.overlay.redirect($(this).attr('href'));
-    return false;
-  };
-
-  $('a:not(.overlay-exclude)', context).once('overlay', function () {
-    var href = $(this).attr('href');
-    // Skip links that don't have an href attribute.
-    if (href == undefined) {
-      return;
-    }
-    // Non-admin links should close the overlay and open in the main window.
-    else if (!parent.Drupal.overlay.isAdminLink(href)) {
-      $(this).click(closeAndRedirectOnClick);
-    }
-    // Open external links in a new window.
-    else if (href.indexOf('http') > 0 || href.indexOf('https') > 0) {
-      $(this).attr('target', '_new');
-    }
-    // Open admin links in the overlay.
-    else {
-      $(this)
-        .attr('href', parent.Drupal.overlay.fragmentizeLink(this))
-        .click(redirectOnClick);
-    }
-  });
+Drupal.overlayChild.behaviors.addClickHandler = function (context, settings) {
+  $(document).bind('click', parent.Drupal.overlay.clickHandler);
+};
 
+/**
+ * Modify forms depending on their relation to the overlay.
+ *
+ * By default, forms are assumed to keep the flow in the overlay. Thus their
+ * action attribute get a ?render=overlay suffix.
+ */
+Drupal.overlayChild.behaviors.parseForms = function (context, settings) {
   $('form', context).once('overlay', function () {
     // Obtain the action attribute of the form.
     var action = $(this).attr('action');
Index: modules/toolbar/toolbar.js
===================================================================
RCS file: /cvs/drupal/drupal/modules/toolbar/toolbar.js,v
retrieving revision 1.10
diff -u -r1.10 toolbar.js
--- modules/toolbar/toolbar.js	2 Dec 2009 07:28:22 -0000	1.10
+++ modules/toolbar/toolbar.js	26 Dec 2009 12:02:30 -0000
@@ -11,9 +11,11 @@
     $('#toolbar', context).once('toolbar', Drupal.admin.toolbar.init);
 
     // Toggling toolbar drawer.
-    $('#toolbar a.toggle', context).once('toolbar-toggle').click(function() {
+    $('#toolbar a.toggle', context).once('toolbar-toggle').click(function(e) {
       Drupal.admin.toolbar.toggle();
-      return false;
+      // Allow other scripts to bind their own handlers, but prevent default
+      // action.
+      e.preventDefault();
     });
 
     // Set the most recently clicked item as active.

