26 March, 2009 / ASP.NET 2.0 AJAX, Safari and Scroll Offset Tricks


Couple days ago, I faced odd bug with DragDropManager at Microsoft.Web.Preview.dll. It doesn’t work correctly if the page is scrolled down in Chrome and Safari browsers. Google did not help. Debugging did not help as well (DragDropManager file is really huge). The last way was to use reflector tool to dig into sources.

The first odd thing was classes hierarchy. Two classes were the most interesting to me: Sys.Preview.UI.IEDragDropManager and Sys.Preview.UI.GenericDragDropManager.

And the following declarations:

Sys.Preview.UI.IEDragDropManager.registerClass('Sys.Preview.UI.IEDragDropManager', Sys.Component); Sys.Preview.UI.GenericDragDropManager.registerClass('Sys.Preview.UI.GenericDragDropManager', Sys.Preview.UI.IEDragDropManager);

The fuzzy thing is that GenericDragDropManager derives IEDragDropManager . It sounds like abstract class derives from concrete class. I truly believe such naming obscures readability. Gutting the code, I figured out that getScrollOffset method is overridden in for Safari browser (and it means for Chrome as well).

if (Sys.Browser.agent === Sys.Browser.Safari) {
    Sys.Preview.UI.GenericDragDropManager.__loadSafariCompatLayer = 
        function Sys$Preview$UI$GenericDragDropManager$__loadSafariCompatLayer(ddm) {
            ddm._getScrollOffset = ddm.getScrollOffset;

            ddm.getScrollOffset = function ddm$getScrollOffset(element, recursive) {
                return { x: 0, y: 0 };

Sounds like code owners just didn’t care about scroll offset. What to do? All what I needed to do is just to prohibit override for Safari to allow base class IEDragDropManager to handle the scroll offset for Safari.

Sys.Preview.UI.IEDragDropManager.prototype.getScrollOffset = function () {
        var left = element.scrollLeft;
        var top = element.scrollTop;
        if (recursive) {
            var parent = element.parentNode;
            while (parent != null && parent.scrollLeft != null) {
                left += parent.scrollLeft;
                top += parent.scrollTop;
                                if (parent == document.body && (left != 0 && top != 0))
                parent = parent.parentNode;
        return { x: left, y: top };

The hack:

Sys.Preview.UI.DragDropManager._getInstance().getScrollOffset = Sys.Preview.UI.IEDragDropManager.prototype.getScrollOffset

Another annoying issue is auto scroll to the top during drag operation. The hack is as trivial as just an empty handler:

Sys.Preview.UI.DragDropManager._getInstance()._autoScroll = function() { }

The full hack for both issues looks quite strange:

if (Sys.Browser.agent === Sys.Browser.Safari) { 
 Sys.Preview.UI.DragDropManager._getInstance().getScrollOffset =  
 Sys.Preview.UI.DragDropManager._getInstance()._autoScroll = function() { } 

The only excuse to ASP.NET Ajax development team is that it was RC build...

Labels: , ,


At March 26, 2009 1:48 PM, Anonymous Anonymous said...

Nice fix, You should share it with MS developers.


Post a Comment

Links to this post:

Create a Link

<< Home


We are developing TargetProcess agile project management software and blogging about our progress.

Subscribe to the RSS feed
Stay tuned by having the latest updates via RSS
Follow TargetProcess on Twitter
Get in touch with our team

Try TargetProcess
TargetProcess quick tour