Thursday, May 26, 2011

Auto sized jQuery UI dialogs and PrimeFaces

jQuery (modal) dialog causes some problems in Internet Explorer like scrollbars on page and not working auto width. See e.g. tickets http://bugs.jqueryui.com/ticket/3623 and http://bugs.jqueryui.com/ticket/4437. width:auto is very important for most dialogs because you often don't know how large the dialog's content is (think e.g. about multi-language labels). General you will not get problems with width:auto and can write
<div id="dialog" title="My dialog">
  ... content ...
</div>

$('#dialog').dialog({
    modal: true,
    height: 'auto',
    width: 'auto'
});
or define CSS class
.autoWidthDialog {
    width: auto !important;
}
and write in PrimeFaces
<p:dialog id="dialog" styleClass="autoWidthDialog" header="My dialog">
  ... content ...
</p:dialog>
Working well except one problem - broken dialog's header in IE7 and below. Titelbar is shrunk to the title text length. Unfortunately, jQuery team doesn't want to fix this issue and support flexible dialogs with width:auto, so that a workaround is needed. Annoying scrollbars on page for modal dialogs should be fixed too. I came up with the following solution:

Native jQuery UI dialog:
jQuery("#dialog").dialog({
    modal: true,
    height: 'auto',
    width: 'auto'
    ... other various options ...
}).bind("dialogopen", function(event, ui) {
    // fix for width:auto in IE
    var jqDialog = jQuery(this);
    var parent = jqDialog.parent();
    var contentWidth = jqDialog.width();
    parent.find('.ui-dialog-titlebar').each(function() {
        jQuery(this).width(contentWidth);
    });
    parent.width(contentWidth + 26);
    jqDialog.dialog('option', 'position', 'center');

    // fix for scrollbars in IE
    jQuery('body').css('overflow', 'hidden');
    jQuery('.ui-widget-overlay').css('width', '100%');
}).bind("dialogclose", function(event, ui) {
    // fix for width:auto in IE
    jQuery(this).parent().css("width", "auto");

    // fix for scrollbars in IE
    jQuery('body').css('overflow', 'auto');
});
PrimeFaces dialog built on the top of native one:
<p:dialog id="dialog" styleClass="autoWidthDialog"
          onShow="onShowAutoWidthDialog(this.jq);"
          onHide="onHideAutoWidthDialog(this.jq);">
  ... content ...
</p:dialog>
function onShowAutoWidthDialog(jqDialog) {
    // fix for auto width in IE
    var parent = jqDialog.parent();
    var contentWidth = jqDialog.width();
    parent.find('.ui-dialog-titlebar').each(function() {
        jQuery(this).width(contentWidth);

    });
    parent.removeClass("autoWidthDialog").width(contentWidth + 26);
    jqDialog.dialog('option', 'position', 'center');

    // fix for scrollbars in IE
    jQuery('body').css('overflow', 'hidden');
    jQuery('.ui-widget-overlay').css('width', '100%');
}

function onHideAutoWidthDialog(jqDialog) {
    // fix for auto width in IE
    var parent = jqDialog.parent();
    parent.find('.ui-dialog-titlebar').each(function() {
        // reset titlebar width
        jQuery(this).css('width', '');
    });
    parent.addClass("autoWidthDialog");

    // fix for scrollbars in IE
    jQuery('body').css('overflow', 'auto');
}
I use onShow / onHide client side callbacks. Settings onShow="onShowAutoWidthDialog(this.jq);" onHide="onHideAutoWidthDialog(this.jq);" fix mentioned above IE issues. Unfortunately, PrimeFaces p:confirmDialog doesn't have these attributes (why?), so that I had to add onShow / onHide to p:confirmDialog similar to p:dialog. Component / renderer classes can be easy extended and for JavaScript widget I can post the code if somebody needs it. :-)

Edit: There isn't cross-browser pure CSS solution; I didn't find it and didn't see anywhere.

4 comments:

  1. i want the code, thx!;-)

    ReplyDelete
  2. JavaScript widget ExtendedConfirmDialog is here http://paste.kde.org/77275/

    ReplyDelete
  3. After looking at a lot of approaches, I finally
    wrote my own sub classing system for jQuer4 UI.

    I can now freely manipulate any jQuery UI
    class or method to whatever ends I like.

    Probably my biggest desire right now is to impreove namespacing for the derrived subclasses. Other than that I'm happier
    than a big in slop.

    ReplyDelete
  4. Thanks for the fix, we still have 10% of our users on ie7!

    Ian

    ReplyDelete