Thursday, September 22, 2011

Fixing EPiServer's context menu bug in Google Chrome

As all of you using Google Chrome on an EPiServer website, know that the right click menu isn't opening correctly in your browser. The problem appears when you have scrolled down on a page and try to open the context menu - the menu will open at the top of the page as if you had not scrolled the page.

After having to endure this bug for a long time and knowing it would take a while for EPiServer to release a new version that fixes it - I chose to try and fix it myself, figuring it would only be a small fix.

Later, after a bit of investigation, I landed in the contextmenu.js file located in C:\Program Files (x86)\EPiServer\CMS\6.1.379.0\Application\Util\javascript. The problem lied in the _ScrollPosition method where it is calling win.document.documentElement.scrollLeft. This property always returns zero in Google Chrome. To solve this we can use the win.document.body.scrollLeft property instead which returns the correct value. Using the OR ( || ) operator we can make the browser choose the property that returns a value other than zero.

The final method will look like this after fixing the bug (green is the changed code):

  1. ContextMenu.prototype._ScrollPosition = function(win)
  2. {
  3.     var scrollX = 0;
  4.     var scrollY = 0;
  5.     if (!this._IsCrossSite(win.top) && win.top.document.documentElement.scrollTop != null)
  6.     {
  7.         scrollX = win.document.documentElement.scrollLeft || win.document.body.scrollLeft;
  8.         scrollY = win.document.documentElement.scrollTop || win.document.body.scrollTop;
  9.     }
  10.     else if (win.pageYOffset != null)
  11.     {
  12.         scrollX = win.pageXOffset;
  13.         scrollY = win.pageYOffset;
  14.     }  
  15.     
  16.     return [scrollX, scrollY];
  17. }

Modifiying EPiServer's files might break the support and is at your own risk. I have however not found any problems with it so far.

If you want to include this for all editors of your site you can add the following code in your MasterPage which will replace the EPiServer-method with the bug-fixed one:

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    if (Request.IsAuthenticated && CurrentPage.QueryDistinctAccess(AccessLevel.Publish))
        EPiServer.ClientScript.ScriptManager.Current.AddEventListener("window", "load", "function(){ContextMenu.prototype._ScrollPosition=function(win){var scrollX=0;var scrollY=0;if(!this._IsCrossSite(win.top)&&win.top.document.documentElement.scrollTop!=null){scrollX=win.document.documentElement.scrollLeft||win.document.body.scrollLeft;scrollY=win.document.documentElement.scrollTop||win.document.body.scrollTop}else if(win.pageYOffset!=null){scrollX=win.pageXOffset;scrollY=win.pageYOffset}return[scrollX,scrollY]}}");
}

Let me know if you find any problems with it!