Search code examples
gwtcss3pie

Why do GWT PopupPanels and DialogBox not like CSS3Pie?


I am trying to get my fancy CSS3 redesign working for a GWT app, but none of the CSS3Pie vml objects seems to be displaying correctly when they are applied to a GWT DialogBox Caption. Furthermore, any content inside a DialogBox or PopupPanel, such as a GwtButton, are not getting their CSS3Pie properly applied (even though those same GwtButtons work just fine everywhere but popups).

My assumption is that the way that GWT manipulates the DOM and the CSS styles for the popup is causing all the styles to get fubared. CSS3Pie is definitely properly getting attached to those elements, as the background colour and border styles are being removed, and the css3-container elements are being added.

Here is the CSS that is applied to the DialogBox

.gwt-PopupPanel,.gwt-DecoratedPopupPanel,.gwt-DialogBox,.gwt-SuggestBoxPopup
    {
    z-index: 999;
}

.gwt-PopupPanelGlass {
    background: #000;
    opacity: 0.3;
    filter: alpha(opacity = 30);
    z-index: 990;
}

.gwt-DialogBox .dialogTopCenterInner{
}

/** Copied from titled region **/
.gwt-DialogBox .Caption {
    padding: 8px 0 0 14px;
    background: #6c6d70;
    background: -moz-linear-gradient(#6c6d70, #595a5c);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#6c6d70), color-stop(100%,#595a5c));
    background: -webkit-linear-gradient(#6c6d70, #595a5c);
    background: -o-linear-gradient(#6c6d70, #595a5c);
    background: -ms-linear-gradient(#6c6d70, #595a5c);
    background: linear-gradient(#6c6d70, #595a5c);
    height: 25px;
    border: 1px solid #4a4a4a;
    -webkit-border-radius: 5px 5px 0 0;
    -moz-border-radius: 5px 5px 0 0;
    border-radius: 5px 5px 0 0;
    -webkit-box-shadow: inset 0 1px 1px #8e8f93;
    -moz-box-shadow: inset 0 1px 1px #8e8f93;
    box-shadow: inset 0 1px 1px #8e8f93;
    color: #fff;
    font-size: 14px;
    font-weight: bold;
    cursor: move;

    -pie-background: linear-gradient(#6c6d70, #595a5c);
    position: relative;
    behavior: url(/resources/css/PIE.htc);
}

.gwt-DialogBox .dialogContent {
    border: 1px solid #6a6a6a;
    border-top: none;
    background: #f9f9f9;
    padding: 10px;
}

And here is the generated HTML for the dialog box, taken from IE Developer Toolbar.

<DIV style="CLIP: rect(auto,auto,auto,auto); POSITION: absolute; VISIBILITY: visible; OVERFLOW: visible; TOP: 374px; LEFT: 743px" class=gwt-DialogBox __eventBits="124"><DIV>
<TABLE cellSpacing=0 cellPadding=0>
<TBODY>
<TR class=dialogTop>
<TD class=dialogTopLeft>
<DIV class=dialogTopLeftInner></DIV></TD>
<TD class=dialogTopCenter>
<DIV class=dialogTopCenterInner>
<css3-container style="Z-INDEX: auto; POSITION: absolute; DIRECTION: ltr; TOP: 0px; LEFT: 0px"><background style="POSITION: absolute; TOP: 0px; LEFT: 0px"><group2><?xml:namespace prefix = css3vml ns = "urn:schemas-microsoft-com:vml" /><css3vml:shape style="POSITION: absolute; WIDTH: 413px; HEIGHT: 35px; BEHAVIOR: url(#default#VML); TOP: 0px; LEFT: 0px" coordsize = "826,70" coordorigin = "1,1" fillcolor = "#6c6d70" stroked = "f" path = " m0,10 qy10,0 l816,0 qx826,10 l826,70 qy826,70 l0,70 qx0,70 x e"><css3vml:fill></css3vml:fill><css3vml:fill></css3vml:fill></css3vml:shape></group2></background><border style="POSITION: absolute; TOP: 0px; LEFT: 0px"><css3vml:shape style="POSITION: absolute; WIDTH: 413px; HEIGHT: 35px; BEHAVIOR: url(#default#VML); TOP: 0px; LEFT: 0px" coordsize = "826,70" coordorigin = "1,1" filled = "f" stroked = "t" strokecolor = "#4a4a4a" strokeweight = ".75pt" path = " m1,10 qy10,1 l816,1 qx825,10 l825,70 qy826,69 l0,69 qx1,70 x e"><css3vml:stroke></css3vml:stroke><css3vml:stroke></css3vml:stroke></css3vml:shape></border></css3-container>
<DIV class="Caption pie_first-child pie_first-child" _pieId="_208">Change Region</DIV></DIV></TD>
<TD class=dialogTopRight>
<DIV class=dialogTopRightInner></DIV></TD></TR>
<TR class=dialogMiddle>
<TD class=dialogMiddleLeft>
<DIV class=dialogMiddleLeftInner></DIV></TD>
<TD class=dialogMiddleCenter>
<DIV class="dialogMiddleCenterInner dialogContent">
    Fancy content here.
</DIV>
</TD>
<TD class=dialogMiddleRight>
<DIV class=dialogMiddleRightInner></DIV></TD></TR>
<TR class=dialogBottom>
<TD class=dialogBottomLeft>
<DIV class=dialogBottomLeftInner></DIV></TD>
<TD class=dialogBottomCenter>
<DIV class=dialogBottomCenterInner></DIV></TD>
<TD class=dialogBottomRight>
<DIV class=dialogBottomRightInner></DIV></TD></TR></TBODY></TABLE></DIV></DIV>

Here are some things I have tried:

  • Copying and pasting the HTML into the page instead of letting GWT manipulate the DOM css3 properties work
  • Custom popups that use absolute positioning and custom hide/show code css3 properties work
  • Applying position:relative has fixed some css3pie properties in other places, but has no effect here

Has anyone successfully got GWT PopupPanel and DialogBox to work with CSS3Pie? This project seems to indicate that someone has. What am I missing?


Solution

  • I have tracked down the problem to the way that PopupPanel shows/hides itself, which affects the other subclasses (like DialogBox). It uses the CSS property "visibility" to toggle hiding and showing itself. So it makes itself visibility:hidden; to hide and visibility:visible; to show.

    Unfortunately, this doesn't play nice with the Internet Explorer event model. When a parent's visibility css property is changed, internet explorer doesn't notify its children about the property change events. CSS3Pie adds onPropertyChange handlers to the elements that its working with, and expects that when a style changes, it will be notified. Since the internet explorer doesn't propagate the event to the child, there is no way for CSS3Pie to know about the change, it no way for it to update its rendering.

    You can manually override this by the following:

    1. Create a DialogBox with a rounded-border div to it
    2. Call DialogBox#show#
    3. The dialog box should be shown, but the CSS3 rounder-border will be missing
    4. Open Internet Explorer developer tools (Press F12)
    5. Refresh the IE developer tools (took me awhile to figure this out)
    6. Inspect the rounded-border box, and uncheck the "behavior" property
    7. CSS3Pie detaches, and non-rounded borders should appear
    8. Re-enable the "behavior" property
    9. Fixed! CSS3Pie re-renders the display value

    You can call this static method on a PopupPanel to get CSS3Pie to re-render all its children, and fix the problem once and for all.

    public static void resetChildrenCss3PieBehaviour(final Element e) {
        // Only run this for IE 8 and 9
        String userAgent = Navigator.getUserAgent().toLowerCase();
        if (userAgent.contains("msie")) {
            NodeList<Node> childNodes = e.getChildNodes();
            int length = childNodes.getLength();
            for (int i = 0; i < length; i++) {
                Node node = childNodes.getItem(i);
                if (node instanceof Element) {
                    final Element child = (Element) node;
                    // Recursive part happens here
                    resetChildrenCss3PieBehaviour(child);
                }
            }
    
            // Refresh the CSS3Pie behavior
            e.getStyle().setProperty("behavior", "none !important");
            Scheduler.get().scheduleDeferred(new Command() {
                @Override
                public void execute() {
                    e.getStyle().setProperty("behavior", Css3Pie.getPieCssProp());
                }
            });
    
        }
    }
    

    For your code, if you can use display:none; instead of visibility:hidden;, then IE plays nicely with event propagation, and this kind of hack isn't needed.