views:

615

answers:

2

I'm working with IE7 and some jQuery dialogs and I'm running into about a 6meg leak per dialog opened. I'm assuming it's to do with closures, but so far everything I've done to remove them haven't helped. At this point I think I've taken care of all the closures except on for a callback function I pass in, but it's still leaking 6 megs even after the dialog is closed and removed. The relevant source code is:

function DialogDestroyAndRemove(event) {
    $(event.target).dialog("destroy").remove();
}

function CallbackAndCloseDialog(event) {
    if (event.data.callback != undefined) {
        event.data.callback(event.data.callbackResponse);
    }
    $("#" + event.data.dialogId).unbind('dialogbeforeclose').dialog('close');
}

// alert dialog modal with ok button
function AlertDialog(dialogTitle, dialogText, callbackFunction) {
    // dynamically generate and add a div so we can create the pop-up
    $('body').append("<div id=\"alertDialog\" style=\"display:none;\" title=\"" + dialogTitle + "\">" + dialogText + "</div>");

    // define/configure the modal pop-up
    $("#alertDialog").dialog({
        draggable: false,
        resizable: false,
        modal: true,
        autoOpen: true,
        open: function() {
            $("#alertDialog").parents('.ui-dialog-buttonpane button:eq(0)')
            .focus() //focus so the button is highlighted by default
            .bind('click', {
                callback: callbackFunction,
                callbackResponse: 'OK',
                dialogId: 'alertDialog'
            }, CallbackAndCloseDialog);
        },
        overlay: { backgroundColor: '#000', opacity: 0.5 },
        buttons: { 'OK': function() { } }
    }).bind('dialogbeforeclose', function(event, ui) {
        // Close (X) button was clicked; NOT the OK button
        if (callbackFunction != undefined) {
            callbackFunction('cancel');
        }
        callbackFunction = null;
    }).bind('dialogclose', DialogDestroyAndRemove);
}

One thing I did above that I'm not sure if it's needed was instead of defining the callback for the OK button when it's defined (and therefore having a closure since it's referencing the callback) to define it using a .bind once the dialog is open. I was hoping that being able to pass the callback as part of the data to the click event might help remove the closure.

Any ideas what else I can change to get rid of this leak?

+2  A: 

It actually ended up being caused by how the jQuery UI framework deals with graying out the background when displaying a modal. If I remove the modal = true and the overlay attributes the memory leak goes down to ~100k.

To get around this I had to make the dialog without the modal option, and then add a div myself to the page (fixed position top, left, bottom, right all 0 with a alternating gray pixel then transparent pixel background) and showing and hiding that with a zindex just under the dialog.

While it isn't ideal (the default modal overlay was nice and smooth looking) it's better than leaking that much memory per dialog I pop up.

Parrots
This has to do with how IE handles PNG transparency, which is...horribly. If you go with a simple colored IE filter instead of an image, you can get some effect without the memory hit. In your jQuery.UI.css change the `.ui-widget-overlay` class and remove everythig from `url(` forward in the `background:` declaration, this will result in a single color translucent overlay.
Nick Craver
Seems to be with how IE deals with transparency in general. I removed the URL aspect of the background (leaving just the solid color) and it still did it. It wasn't until I remove the opacity filter that it went away.
Parrots
A: 

Hope this helps, I created an extension for this issue where I use the jQuery tools (flowplayer) expose plugin when modal = true for the jQuery UI dialog.

I would include the following code in a separate .js file and make sure to include the jQuery tools expose plugin prior, from this site...http://flowplayer.org/tools/download.html.

(function($) { var _init = $.ui.dialog.prototype._init; $.ui.dialog.prototype._init = function() { var self = this; _init.apply(this, arguments);

    // Remove the default modal behavior and exhibit the new one
    if (self.options.modal) {
        self.options.modal = false;
        self.options.isModal = true;
    }

    this.uiDialog.bind('dialogopen', function(event, ui) {
        if (self.options.isModal) {
            if ($(this).expose == null)
                window.alert("Dialog box depends on the expose plugin to be modal. Please include the jquery tools Javascript include.");
            else {
                $(this).expose({ opacity: 0.3
                            , color: '#CCCCCC'
                            , loadSpeed: 0
                            , closeSpeed: 0
                            , closeOnClick: false
                            , closeOnEsc: false
                            , api: true
                }).load();
            }
        }
    });

    this.uiDialog.bind('dialogfocus', function(event, ui) {
        if (self.options.isModal) {
            $(this).css('z-index', '9999');
        }
    });

    this.uiDialog.bind('dialogclose', function(event, ui) {
        if (self.options.isModal) {
            if ($(this).expose != null) {
                $(this).expose({ api: true }).close();
            }
        }
    });
};

$.ui.dialog.defaults.isModal = false;

})(jQuery);

Michael Ritchson