Code preview + sample app for 361: Modal PopupPanel/DialogBox

42 views
Skip to first unread message

BobV

unread,
Apr 18, 2007, 9:58:59 PM4/18/07
to Google Web Toolkit Contributors, Joel Webber, Kelly Norton
This patch adds support for creating modal popups (i.e. popups that
cancel events to elements that are not a child of the popup). The
PopupPanel.onEventPreview() method is modified to be greedier when the
modal flag is set.

There is also the source to a sample application (hacked-up Hello
sample) as well as a compiled version attached. I have verified that
stacks of modal dialogs behave as expected.

Current caveats:
- On OSX Opera, backspace events in the textbox don't get canceled
as expected so text can be deleted, but not added to.
- Whether or not UI elements are focusable also varies between
browsers. FF does the right thing, IE allows the text box to be
focused, although you can't enter data into it.

diffstat:
DialogBox.java | 27 20 + 7 - 0 !
PopupPanel.java | 76 46 + 30 - 0 !
2 files changed, 66 insertions(+), 37 deletions(-)

--
Bob Vawter
Google Web Toolkit Team

modal_r913.patch
modal_test.tgz
Hello.java

Fred Sauer

unread,
Apr 18, 2007, 10:16:18 PM4/18/07
to Google-Web-Tool...@googlegroups.com
Bob,

What if you were to simply add a transparent DIV (which covers the entire browser document with "width: 100%; height: 100%") between the popup layer and the rest of the document. That would obscure prevent users from interacting with any of the underlying UI elements. As a side benefit, that DIV can have a CSS class name so that folks can style it to be only semi-transparent, graying out the rest of the UI automatically when there is a modal dialog.

Fred


* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.sample.hello.client ;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.*;

/**
* HelloWorld application.
*/
public class Hello implements EntryPoint {

  public void onModuleLoad() {
    HorizontalPanel h = new HorizontalPanel();

    Button modal = new Button("Modal", new ClickListener() {
      public void onClick(Widget sender) {
        createDialog(false, true).show();
      }
    });

    Button modalAutoHide = new Button("Modal + autohide", new ClickListener() {
      public void onClick(Widget sender) {
        createDialog(true, true).show();
      }
    });

    Button nonModal = new Button("non-Modal", new ClickListener() {
      public void onClick(Widget sender) {
        createDialog(false, false).show();
      }
    });

    h.add (modal);
    h.add(modalAutoHide);
    h.add(nonModal);
    h.add(new TextBox());
    h.add(new CheckBox());

    RootPanel.get().add(h);
  }

  private DialogBox createDialog(boolean autoHide, boolean modal) {
    final DialogBox toReturn = new DialogBox(autoHide, modal);

    final Button close = new Button("close", new ClickListener() {
        public void onClick(Widget w) {
          toReturn.hide();
    }});

    final Button modal2 = new Button("Create modal", new ClickListener() {
        public void onClick(Widget w) {
          createDialog(false, true).show();
    }});

    VerticalPanel p = new VerticalPanel();
    p.add(new Label("Value of modal: " + modal));
    p.add(close);
    p.add(modal2);

    toReturn.setWidget(p);
    toReturn.setText("text title");

    return toReturn;
  }
}





--
Fred Sauer
fr...@allen-sauer.com

BobV

unread,
Apr 18, 2007, 11:24:08 PM4/18/07
to Google-Web-Tool...@googlegroups.com
On 4/18/07, Fred Sauer <fr...@allen-sauer.com> wrote:
> What if you were to simply add a transparent DIV (which covers the entire
> browser document with "width: 100%; height: 100%") between the popup layer
> and the rest of the document. That would obscure prevent users from
> interacting with any of the underlying UI elements. As a side benefit, that
> DIV can have a CSS class name so that folks can style it to be only
> semi-transparent, graying out the rest of the UI automatically when there is
> a modal dialog.

There isn't a popup layer per-se unless the developer adds z-index CSS
rules, so I'm wary of adding that to PopupPanel. It doesn't seem like
the right solution to have the PopupPanel make structural changes to
the DOM beyond creating its own container. I haven't yet investigated
browser-specific alternatives to capturing/disabling focus, so it may
just be another method to add to the existent PopupImpl deferred
binding classes.

Do the contributors think it would be worthwhile to add a dedicated
GlassPanel for 1.4? It would behave in the manner that Fred describes
and would have the usual well-known CSS rule names to allow for the
cool effects.

Fred Sauer

unread,
Apr 19, 2007, 12:11:42 AM4/19/07
to Google-Web-Tool...@googlegroups.com
Bob,

I understand your hesitations.

Just as an implementation point: my experience has been that you do not need z-index to accomplish this. Browsers draw the elements in DOM order (which is what we expect). So, popup panel always end up on top, without necessitating a z-index. Similarly adding a glass panel and then adding a popup panel should automatically layer the two just right.

Fred

On 4/18/07, BobV <bo...@google.com> wrote:

BobV

unread,
Apr 19, 2007, 11:58:45 AM4/19/07
to Google-Web-Tool...@googlegroups.com
On 4/18/07, Fred Sauer <fr...@allen-sauer.com> wrote:
> Just as an implementation point: my experience has been that you do not need
> z-index to accomplish this. Browsers draw the elements in DOM order (which
> is what we expect). So, popup panel always end up on top, without
> necessitating a z-index. Similarly adding a glass panel and then adding a
> popup panel should automatically layer the two just right.

That's true if they're in the same stacking context. The attached
file shows two div's that appear before and after the "glass panel" in
the DOM order.

z-index.html

Joel Webber

unread,
Apr 19, 2007, 3:08:40 PM4/19/07
to Google-Web-Tool...@googlegroups.com
My 2 cents worth here is that these are two problems that ought to be solved, but independently. I'd really like the modal dialogbox/popup code to work properly *without* a glass panel, but I'd also like there to *be* a glass panel at some point, because that's just really cool.

Fred: does height:100% actually work across all supported browsers? My experience has been otherwise, but maybe it does in this case. I haven't checked out your GlassPanel code yet, so if the answer's obvious from that, please feel free to point me there.

joel.

This should appear underneath
This will appear on top
This is the glass panel.
This will appear on top


BobV

unread,
Apr 19, 2007, 4:17:21 PM4/19/07
to Google-Web-Tool...@googlegroups.com
On 4/19/07, Joel Webber <j...@google.com> wrote:
> My 2 cents worth here is that these are two problems that ought to be
> solved, but independently. I'd really like the modal dialogbox/popup code to
> work properly *without* a glass panel, but I'd also like there to *be* a
> glass panel at some point, because that's just really cool.

The attached patch amends PopupPanel to listen for Event.ONFOCUS
events to blur any widgets not contained by the PopupPanel that get
focus. This makes the app work like you would expect in IE.

modal_r923.patch
modal_test.tgz

Fred Sauer

unread,
Apr 19, 2007, 4:28:55 PM4/19/07
to Google-Web-Tool...@googlegroups.com
Joel,

I think with regards to "height:100%" you're probably thinking about standard mode mostly ignoring this for block level elements, which includes the document BODY. However, for a widget (a glass panel) which was added to the document body at (0,0), the "height:100%" appears to have the desired effect.

Surprisingly, the real problem appears to be "width:100%" in IE quirks mode, where the BODY padding and margin are not included, while (0,0) means top-left of the browser window, not the top-left of the BODY client area. This means your glass panel ends up not being wide enough if the BODY has either margin or padding.

In FF the width/height:100% seems to work fine in both quirks and standard mode.



Conclusion: for a glass panel you will need to at least calculate an exact pixel width for the browser document (to support IE quirks mode). Once you do that, I think you might as well calculate the height as well, and then use that implementation across all browsers if possible.

Fred

On 4/19/07, Joel Webber <j...@google.com> wrote:



--
Fred Sauer
fr...@allen-sauer.com

Joel Webber

unread,
Apr 20, 2007, 10:14:08 AM4/20/07
to Google-Web-Tool...@googlegroups.com
Fred,

Thanks for the info. I'm glad you've already worked through this so I don't have to :)

I also seem to recall someone already having implemented this, but can't remember where. Anyone remember?

Thanks,
joel.

rb

unread,
Apr 20, 2007, 11:49:21 AM4/20/07
to Google Web Toolkit Contributors
Mat Gessel has a Glass Panel implementation.

http://www.asquare.net/gwttk/

Dialog Demos:
http://www.asquare.net/gwttk/apps/demo/Demo.html#dialogs


On Apr 20, 10:14 am, "Joel Webber" <j...@google.com> wrote:
> Fred,
>
> Thanks for the info. I'm glad you've already worked through this so I don't
> have to :)
>
> I also seem to recall someone already having implemented this, but can't
> remember where. Anyone remember?
>
> Thanks,
> joel.
>

> > > On 4/19/07, BobV < b...@google.com> wrote:


>
> > > > On 4/18/07, Fred Sauer <f...@allen-sauer.com> wrote:
> > > > > Just as an implementation point: my experience has been that you do
> > > > not need
> > > > > z-index to accomplish this. Browsers draw the elements in DOM order
> > > > (which
> > > > > is what we expect). So, popup panel always end up on top, without
> > > > > necessitating a z-index. Similarly adding a glass panel and then
> > > > adding a
> > > > > popup panel should automatically layer the two just right.
>
> > > > That's true if they're in the same stacking context. The attached
> > > > file shows two div's that appear before and after the "glass panel" in
> > > > the DOM order.
>
> > > > --
> > > > Bob Vawter
> > > > Google Web Toolkit Team
>
> > > > This should appear underneath
> > > > This will appear on top
> > > > This is the glass panel.
> > > > This will appear on top
>
> > --
> > Fred Sauer

> > f...@allen-sauer.com- Hide quoted text -
>
> - Show quoted text -

Joel Webber

unread,
Apr 20, 2007, 12:31:16 PM4/20/07
to Google-Web-Tool...@googlegroups.com
That's the one I was trying to remember. Thanks!

Joel Webber

unread,
Apr 23, 2007, 11:02:27 AM4/23/07
to Google-Web-Tool...@googlegroups.com
Bob,

Excellent patch. I'm surprised that anyone can muck through this weird code without getting confused :) After a couple of small changes below, LGTM.

PopupPanel.java
- FocusImpl: I know it looks like the right thing to do here, but FocusImpl's methods actually only work on elements created using FocusImpl.createFocusable(). This is used for things like the Tree widget and FocusPanel, where it needs to get a focusable container element. There are two options here:
  - Do what FocusWidget (the base class for 'naturally' focusable widgets such as Button) does, and create a FocusImpl directly (not using GWT.create()), which always gets the base implementation. But I think this was a bad design decision on my part and wouldn't recommend it. Or...
  - Just write a JSNI method to do the focusing. We can find a better place to put these methods later.
- 164: Could you add an extra set of parens here, just so I don't go cross-eyed trying to remember what it will do (it is, of course, correct as is).

On 4/19/07, BobV <bo...@google.com> wrote:

BobV

unread,
Apr 23, 2007, 12:38:26 PM4/23/07
to Google-Web-Tool...@googlegroups.com
On 4/23/07, Joel Webber <j...@google.com> wrote:
> PopupPanel.java
> - FocusImpl: I know it looks like the right thing to do here, but
> FocusImpl's methods actually only work on elements created using
> FocusImpl.createFocusable(). This is used for things like the Tree widget
> and FocusPanel, where it needs to get a focusable container element. There
> are two options here:
> - Do what FocusWidget (the base class for 'naturally' focusable widgets
> such as Button) does, and create a FocusImpl directly (not using
> GWT.create()), which always gets the base implementation. But I think this
> was a bad design decision on my part and wouldn't recommend it. Or...
> - Just write a JSNI method to do the focusing. We can find a better place
> to put these methods later.

I added a blur() method to PopupPanel and removed the reference to FocusImpl.

> - 164: Could you add an extra set of parens here, just so I don't go
> cross-eyed trying to remember what it will do (it is, of course, correct as
> is).

Done.

modal_r942.patch

Joel Webber

unread,
Apr 23, 2007, 2:06:04 PM4/23/07
to Google-Web-Tool...@googlegroups.com
Thanks, bob. Committed as r948 (removed one unused import before committing).

Fred Sauer

unread,
Apr 24, 2007, 11:50:46 PM4/24/07
to Google-Web-Tool...@googlegroups.com
Joel,

I wanted to follow up on the CSS height:100% issue, which I believe stems from  http://www.w3.org/TR/REC-CSS2/visudet.html#the-height-property, specifically:

The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), the value is interpreted like 'auto'.

In quirks mode setting the body height:100% fills the entire page height. In standard mode it does not. This is not because the CSS height is ignored, but because the surrounding element (= the HTML document element) essentially has height:100% in quirks mode and height:auto in standard mode.


So, where one would in quirks mode write
body{height:100%}

you would need this in standard mode for the same effect:
html,body{height:100%}

Also, if you want any given block level element (usually a DIV based widget within a table) to have 100% height to say fill the table cell vertically (or any height greater than what is required to fill the contents of that block), you must walk up the DOM tree from that widget and either:
  • set an absolute height, such as height:300px or height:10em
  • set a percentage based height (height:100%), and then repeat with the widgets parent
Your goal is to have an unbroken chain of percentage heights from some ancestor which has an absolute height. For this purpose body (quirks mode) or html (standard mode) has an absolute height.


Hope that helps anyone running into height: 100% issues.

Fred


On 4/19/07, Fred Sauer < fr...@allen-sauer.com > wrote:



--
Fred Sauer
fr...@allen-sauer.com
Reply all
Reply to author
Forward
0 new messages