Fixes poke-through scrollbars on Firefox/Mac. Issue: 410 Patch by: rdayal,jgw Review by: jgw,scottb,bobv git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1152 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/Popup.gwt.xml b/user/src/com/google/gwt/user/Popup.gwt.xml index 58f328c..b5d06bf 100644 --- a/user/src/com/google/gwt/user/Popup.gwt.xml +++ b/user/src/com/google/gwt/user/Popup.gwt.xml
@@ -17,17 +17,26 @@ <!-- This module is typically inherited via com.google.gwt.user.User --> <!-- --> <module> - <inherits name="com.google.gwt.core.Core"/> - <inherits name="com.google.gwt.user.UserAgent"/> + <inherits name="com.google.gwt.core.Core"/> + <inherits name="com.google.gwt.user.UserAgent"/> - <!-- Fall through to this rule is the browser isn't IE --> - <replace-with class="com.google.gwt.user.client.ui.impl.PopupImpl"> - <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl"/> - </replace-with> + <!-- Fall through to this rule is the browser isn't IE or Mozilla --> + <replace-with class="com.google.gwt.user.client.ui.impl.PopupImpl"> + <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl"/> + </replace-with> - <!-- IE has a completely different popup implementation --> - <replace-with class="com.google.gwt.user.client.ui.impl.PopupImplIE6"> - <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl"/> - <when-property-is name="user.agent" value="ie6"/> - </replace-with> + <!-- Mozilla needs a different implementation due to issue #410 --> + <replace-with class="com.google.gwt.user.client.ui.impl.PopupImplMozilla"> + <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl"/> + <any> + <when-property-is name="user.agent" value="gecko"/> + <when-property-is name="user.agent" value="gecko1_8"/> + </any> + </replace-with> + + <!-- IE has a completely different popup implementation --> + <replace-with class="com.google.gwt.user.client.ui.impl.PopupImplIE6"> + <when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl"/> + <when-property-is name="user.agent" value="ie6"/> + </replace-with> </module>
diff --git a/user/src/com/google/gwt/user/client/ui/PopupPanel.java b/user/src/com/google/gwt/user/client/ui/PopupPanel.java index 18cf9d3..eb7d149 100644 --- a/user/src/com/google/gwt/user/client/ui/PopupPanel.java +++ b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
@@ -26,7 +26,11 @@ /** * A panel that can "pop up" over other widgets. It overlays the browser's * client area (and any previously-created popups). - * + * <p/> + * The width and height of the PopupPanel cannot be explicitly set; they are + * determined by the PopupPanel's widget. Calls to {@link #setWidth(String)} and + * {@link #setHeight(String)} will call these methods on the PopupPanel's + * widget. * <p> * <img class='gallery' src='PopupPanel.png'/> * </p> @@ -121,6 +125,10 @@ return DOM.getElementPropertyInt(getElement(), "offsetTop"); } + public String getTitle() { + return DOM.getElementProperty(getContainerElement(), "title"); + } + /** * Hides the popup. This has no effect if it is not currently visible. */ @@ -190,7 +198,7 @@ } } - return !modal || (modal && eventTargetsPopup); + return !modal || eventTargetsPopup; } /** @@ -233,10 +241,7 @@ } public boolean remove(Widget w) { - if (!super.remove(w)) { - return false; - } - return true; + return super.remove(w); } public void removePopupListener(PopupListener listener) { @@ -246,6 +251,19 @@ } /** + * Calls {@link Widget#setHeight(String)} on this panel's widget. If this panel + * does not have a widget, then this call does nothing. + * + * @param height the new height of this panel's widget, in CSS units (e.g. "10px", "1em") + */ + public void setHeight(String height) { + Widget childWidget = getWidget(); + if (childWidget != null) { + childWidget.setHeight(height); + } + } + + /** * Sets the popup's position relative to the browser's client area. The * popup's position may be set before calling {@link #show()}. * @@ -292,6 +310,19 @@ } /** + * Calls {@link Widget#setWidth(String)} on this panel's widget. If this panel + * does not have a widget, then this call does nothing. + * + * @param width the new width of this panel's widget, in CSS units (e.g. "10px", "1em") + */ + public void setWidth(String width) { + Widget childWidget = getWidget(); + if (childWidget != null) { + childWidget.setWidth(width); + } + } + + /** * Shows the popup. It must have a child widget before this method is called. */ public void show() { @@ -306,6 +337,14 @@ impl.onShow(getElement()); } + protected Element getContainerElement() { + return impl.getContainerElement(getElement()); + } + + protected Element getStyleElement() { + return impl.getContainerElement(getElement()); + } + /** * This method is called when a widget is detached from the browser's * document. To receive notification before the PopupPanel is removed from the @@ -339,4 +378,14 @@ popupListeners.firePopupClosed(this, autoClosed); } } + + public void setTitle(String title) { + Element containerElement = getContainerElement(); + if (title == null || title.length() == 0) { + DOM.removeElementAttribute(containerElement, "title"); + } else { + DOM.setElementAttribute(containerElement, "title", title); + } + } } +
diff --git a/user/src/com/google/gwt/user/client/ui/UIObject.java b/user/src/com/google/gwt/user/client/ui/UIObject.java index 676d8ac..11d7f74 100644 --- a/user/src/com/google/gwt/user/client/ui/UIObject.java +++ b/user/src/com/google/gwt/user/client/ui/UIObject.java
@@ -319,7 +319,7 @@ * @see #removeStyleName(String) */ public void addStyleName(String style) { - setStyleName(element, style, true); + setStyleName(getStyleElement(), style, true); } /** @@ -380,7 +380,7 @@ * @see #removeStyleName(String) */ public String getStyleName() { - String fullClassName = ensurePrimaryStyleName(element); + String fullClassName = ensurePrimaryStyleName(getStyleElement()); // The base style name is always the first token of the full CSS class // name. There can be no leading whitespace in the class name, so it's not @@ -418,7 +418,7 @@ * @see #addStyleName(String) */ public void removeStyleName(String style) { - setStyleName(element, style, false); + setStyleName(getStyleElement(), style, false); } /** @@ -430,7 +430,8 @@ public void setHeight(String height) { // This exists to deal with an inconsistency in IE's implementation where // it won't accept negative numbers in length measurements - assert extractLengthValue(height.trim().toLowerCase()) >= 0 : "CSS heights should not be negative"; + assert extractLengthValue(height.trim().toLowerCase()) >= 0 : + "CSS heights should not be negative"; DOM.setStyleAttribute(element, "height", height); } @@ -470,7 +471,7 @@ * @see #removeStyleName(String) */ public void setStyleName(String style) { - resetStyleName(element, style); + resetStyleName(getStyleElement(), style); } /** @@ -506,7 +507,8 @@ public void setWidth(String width) { // This exists to deal with an inconsistency in IE's implementation where // it won't accept negative numbers in length measurements - assert extractLengthValue(width.trim().toLowerCase()) >= 0 : "CSS widths should not be negative"; + assert extractLengthValue(width.trim().toLowerCase()) >= 0 : + "CSS widths should not be negative"; DOM.setStyleAttribute(element, "width", width); } @@ -551,6 +553,17 @@ } /** + * Template method that returns the element to which style names will be + * applied. By default it returns the root element, but this method may be + * overridden to apply styles to a child element. + * + * @return the element to which style names will be applied + */ + protected Element getStyleElement() { + return element; + } + + /** * Sets this object's browser element. UIObject subclasses must call this * method before attempting to call any other methods. * @@ -567,7 +580,7 @@ } this.element = elem; - + // We do not actually force the creation of a primary style name here. // Instead, we do it lazily -- when it is aboslutely required -- // in getStyleName(), addStyleName(), and removeStyleName().
diff --git a/user/src/com/google/gwt/user/client/ui/impl/PopupImplMozilla.java b/user/src/com/google/gwt/user/client/ui/impl/PopupImplMozilla.java new file mode 100644 index 0000000..0b338d1 --- /dev/null +++ b/user/src/com/google/gwt/user/client/ui/impl/PopupImplMozilla.java
@@ -0,0 +1,97 @@ +/* + * Copyright 2007 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * 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.user.client.ui.impl; + +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.DeferredCommand; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; + +/** + * Implementation class used by {@link com.google.gwt.user.client.ui.PopupPanel}. + * This implementation is identical to the implementation provided by + * {@link com.google.gwt.user.client.ui.impl.PopupImpl} in the case where + * Mozilla is NOT running on the Mac. + * <p/> + * A different implemention is provided for the Mac in order to prevent + * scrollbars underneath the PopupPanel from being rendered on top of the + * PopupPanel (issue #410). Unfortunately, the solution that fixes this + * problem for the Mac causes a problem with dragging a + * {@link com.google.gwt.user.client.ui.DialogBox} on Linux. While dragging + * the DialogBox (especially diagonally), it jitters significantly. + * <p/> + * We did not introduce a deferred binding rule for Mozilla on the Mac because + * this is the first instance in which we have a Mozilla-related bug fix which + * does not work on all platforms. + * <p/> + * This implementation can be simplified in the event that the jittering + * problem on Linux is fixed, or the scrollbar rendering problem on the Mac + * is fixed. + */ +public class PopupImplMozilla extends PopupImpl { + + private Element containerElement = null; + + public Element createElement() { + final Element outerElem = DOM.createDiv(); + + if (isMac()) { + // To solve the scrollbar rendering problem on the Mac, we have to make + // the PopupPanel a 'heavyweight' element by setting a style of + // 'overflow:auto' on the outermost div. This ensures that all of the + // elements that are children of this div will be rendered on top of + // any underlying scrollbars. + + // Unfortunately, if we add a border to the outer div (which has + // a style of 'overflow:auto'), the border will not be rendered on top + // of underlying scrollbars. To get around this problem, we introduce an + // inner div which acts as the new containing element for the PopupPanel, + // and this element is the one to which all styling is applied to. + DOM.setInnerHTML(outerElem, "<div></div>"); + + // Mozilla determines the default stacking order for heavyweight elements + // by their order on the page. If the PopupPanel is declared before another + // heavyweight element on the page, then the scrollbars of the heavyweight + // element will still shine through the PopupPanel. By setting + // 'overflow:auto' after all of the elements on the page have been rendered, + // the PopupPanel becomes the highest element in the stacking order. + DeferredCommand.addCommand(new Command() { + public void execute() { + DOM.setStyleAttribute(outerElem, "overflow", "auto"); + } + }); + + // Keep a reference to the container element in order to avoid further + // calls to isMac() in getContainerElement(). + containerElement = DOM.getFirstChild(outerElem); + } else { + containerElement = outerElem; + } + + return outerElem; + } + + public Element getContainerElement(Element popup) { + return containerElement; + } + + private native boolean isMac() /*-{ + if (navigator.userAgent.indexOf("Macintosh") != -1) { + return true; + } + return false; + }-*/; +}