aboutsummaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorJohn Ahlroos <john@vaadin.com>2014-08-07 16:32:23 +0300
committerJohn Ahlroos <john@vaadin.com>2014-08-07 16:35:06 +0300
commitecff9648d1cb3d5cc4bd54d2b1e1c6357429792f (patch)
treeb21f4b599183c157900b0f24d41c94e6af3b08a7 /client
parente5230e6a2433f5c8a74c66b73e96d0454866d316 (diff)
parentff47bdd97b03a42dfc812b4dc9ad71fa45ce3827 (diff)
downloadvaadin-framework-ecff9648d1cb3d5cc4bd54d2b1e1c6357429792f.tar.gz
vaadin-framework-ecff9648d1cb3d5cc4bd54d2b1e1c6357429792f.zip
Merge remote-tracking branch 'origin/master' into grid
Conflicts: WebContent/release-notes.html Change-Id: Ie05bea7142134a7a9d655fcdf6ca232fd13c742b
Diffstat (limited to 'client')
-rw-r--r--client/src/com/vaadin/client/ApplicationConfiguration.java17
-rw-r--r--client/src/com/vaadin/client/ApplicationConnection.java48
-rw-r--r--client/src/com/vaadin/client/DeferredWorker.java30
-rw-r--r--client/src/com/vaadin/client/ResourceLoader.java23
-rw-r--r--client/src/com/vaadin/client/Util.java286
-rw-r--r--client/src/com/vaadin/client/communication/Heartbeat.java4
-rw-r--r--client/src/com/vaadin/client/communication/TranslatedURLReference.java45
-rw-r--r--client/src/com/vaadin/client/communication/URLReference_Serializer.java12
-rw-r--r--client/src/com/vaadin/client/componentlocator/LocatorStrategy.java6
-rw-r--r--client/src/com/vaadin/client/debug/internal/HierarchySection.java6
-rw-r--r--client/src/com/vaadin/client/debug/internal/InfoSection.java2
-rw-r--r--client/src/com/vaadin/client/debug/internal/SelectConnectorListener.java3
-rw-r--r--client/src/com/vaadin/client/ui/AbstractConnector.java24
-rw-r--r--client/src/com/vaadin/client/ui/VCalendarPanel.java20
-rw-r--r--client/src/com/vaadin/client/ui/VFilterSelect.java398
-rw-r--r--client/src/com/vaadin/client/ui/VGridLayout.java20
-rw-r--r--client/src/com/vaadin/client/ui/VNativeButton.java4
-rw-r--r--client/src/com/vaadin/client/ui/VOverlay.java12
-rw-r--r--client/src/com/vaadin/client/ui/VPopupCalendar.java2
-rw-r--r--client/src/com/vaadin/client/ui/VScrollTable.java73
-rw-r--r--client/src/com/vaadin/client/ui/VUI.java25
-rw-r--r--client/src/com/vaadin/client/ui/VWindow.java98
-rw-r--r--client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java39
-rw-r--r--client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java6
-rw-r--r--client/src/com/vaadin/client/ui/dd/DDUtil.java3
-rw-r--r--client/src/com/vaadin/client/ui/dd/DragImageModifier.java3
-rw-r--r--client/src/com/vaadin/client/ui/menubar/MenuBar.java108
-rw-r--r--client/src/com/vaadin/client/ui/table/TableConnector.java24
-rw-r--r--client/src/com/vaadin/client/ui/textarea/TextAreaConnector.java60
-rw-r--r--client/src/com/vaadin/client/ui/ui/UIConnector.java307
30 files changed, 1317 insertions, 391 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java
index 3ccbeba6f3..87c8ea465f 100644
--- a/client/src/com/vaadin/client/ApplicationConfiguration.java
+++ b/client/src/com/vaadin/client/ApplicationConfiguration.java
@@ -51,6 +51,7 @@ import com.vaadin.client.metadata.ConnectorBundleLoader;
import com.vaadin.client.metadata.NoDataException;
import com.vaadin.client.metadata.TypeData;
import com.vaadin.client.ui.UnknownComponentConnector;
+import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.ui.ui.UIConstants;
@@ -84,7 +85,7 @@ public class ApplicationConfiguration implements EntryPoint {
return null;
} else {
return value +"";
- }
+ }
}-*/;
/**
@@ -105,7 +106,7 @@ public class ApplicationConfiguration implements EntryPoint {
} else {
// $entry not needed as function is not exported
return @java.lang.Boolean::valueOf(Z)(value);
- }
+ }
}-*/;
/**
@@ -126,7 +127,7 @@ public class ApplicationConfiguration implements EntryPoint {
} else {
// $entry not needed as function is not exported
return @java.lang.Integer::valueOf(I)(value);
- }
+ }
}-*/;
/**
@@ -285,14 +286,16 @@ public class ApplicationConfiguration implements EntryPoint {
return serviceUrl;
}
+ /**
+ * @return the theme name used when initializing the application
+ * @deprecated as of 7.3. Use {@link UIConnector#getActiveTheme()} to get
+ * the theme currently in use
+ */
+ @Deprecated
public String getThemeName() {
return getJsoConfiguration(id).getConfigString("theme");
}
- public String getThemeUri() {
- return getVaadinDirUrl() + "themes/" + getThemeName();
- }
-
/**
* Gets the URL of the VAADIN directory on the server.
*
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index 6abcdac487..90aa0a14d6 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -66,7 +66,6 @@ import com.google.gwt.user.client.Window.ClosingHandler;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConfiguration.ErrorMessage;
-import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent;
import com.vaadin.client.ResourceLoader.ResourceLoadEvent;
import com.vaadin.client.ResourceLoader.ResourceLoadListener;
import com.vaadin.client.communication.HasJavaScriptConnectorHelper;
@@ -599,14 +598,23 @@ public class ApplicationConnection implements HasHandlers {
}
}
+ /**
+ * Checks if there is some work to be done on the client side
+ *
+ * @return true if the client has some work to be done, false otherwise
+ */
+ private boolean isActive() {
+ return isWorkPending() || hasActiveRequest()
+ || isExecutingDeferredCommands();
+ }
+
private native void initializeTestbenchHooks(
ComponentLocator componentLocator, String TTAppId)
/*-{
var ap = this;
var client = {};
client.isActive = $entry(function() {
- return ap.@com.vaadin.client.ApplicationConnection::hasActiveRequest()()
- || ap.@com.vaadin.client.ApplicationConnection::isExecutingDeferredCommands()();
+ return ap.@com.vaadin.client.ApplicationConnection::isActive()();
});
var vi = ap.@com.vaadin.client.ApplicationConnection::getVersionInfo()();
if (vi) {
@@ -810,7 +818,8 @@ public class ApplicationConnection implements HasHandlers {
startRequest();
JSONObject payload = new JSONObject();
- if (!getCsrfToken().equals(ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE)) {
+ if (!getCsrfToken().equals(
+ ApplicationConstants.CSRF_TOKEN_DEFAULT_VALUE)) {
payload.put(ApplicationConstants.CSRF_TOKEN, new JSONString(
getCsrfToken()));
}
@@ -1320,6 +1329,30 @@ public class ApplicationConnection implements HasHandlers {
}
/**
+ * Checks if the client has running or scheduled commands
+ */
+ private boolean isWorkPending() {
+ ConnectorMap connectorMap = getConnectorMap();
+ JsArrayObject<ServerConnector> connectors = connectorMap
+ .getConnectorsAsJsArray();
+ int size = connectors.size();
+ for (int i = 0; i < size; i++) {
+ ServerConnector conn = connectors.get(i);
+ ComponentConnector compConn = null;
+ if (conn instanceof ComponentConnector) {
+ compConn = (ComponentConnector) conn;
+ Widget wgt = compConn.getWidget();
+ if (wgt instanceof DeferredWorker) {
+ if (((DeferredWorker) wgt).isWorkPending()) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* Checks if deferred commands are (potentially) still being executed as a
* result of an update from the server. Returns true if a deferred command
* might still be executing, false otherwise. This will not work correctly
@@ -1483,6 +1516,7 @@ public class ApplicationConnection implements HasHandlers {
if (json.containsKey("typeMappings")) {
configuration.addComponentMappings(
json.getValueMap("typeMappings"), widgetSet);
+
}
VConsole.log("Handling resource dependencies");
@@ -1717,6 +1751,7 @@ public class ApplicationConnection implements HasHandlers {
for (int i = 0; i < needsUpdateLength; i++) {
String childId = dump.get(i);
ServerConnector child = connectorMap.getConnector(childId);
+
if (child instanceof ComponentConnector
&& ((ComponentConnector) child)
.delegateCaptionHandling()) {
@@ -3110,7 +3145,7 @@ public class ApplicationConnection implements HasHandlers {
return null;
}
if (uidlUri.startsWith("theme://")) {
- final String themeUri = configuration.getThemeUri();
+ final String themeUri = getThemeUri();
if (themeUri == null) {
VConsole.error("Theme not set: ThemeResource will not be found. ("
+ uidlUri + ")");
@@ -3176,7 +3211,8 @@ public class ApplicationConnection implements HasHandlers {
* @return URI to the current theme
*/
public String getThemeUri() {
- return configuration.getThemeUri();
+ return configuration.getVaadinDirUrl() + "themes/"
+ + getUIConnector().getActiveTheme();
}
/**
diff --git a/client/src/com/vaadin/client/DeferredWorker.java b/client/src/com/vaadin/client/DeferredWorker.java
new file mode 100644
index 0000000000..53f7c79fe6
--- /dev/null
+++ b/client/src/com/vaadin/client/DeferredWorker.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * 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.vaadin.client;
+
+/**
+ * Give widgets the possibility to indicate to the framework that there is work
+ * scheduled to be executed in the near future and that the framework should
+ * wait for this work to complete before assuming the UI has reached a steady
+ * state.
+ */
+public interface DeferredWorker {
+ /**
+ * @returns true, if there are operations pending which must be executed
+ * before reaching a steady state
+ */
+ public boolean isWorkPending();
+}
diff --git a/client/src/com/vaadin/client/ResourceLoader.java b/client/src/com/vaadin/client/ResourceLoader.java
index 68a16e8162..ceede263fc 100644
--- a/client/src/com/vaadin/client/ResourceLoader.java
+++ b/client/src/com/vaadin/client/ResourceLoader.java
@@ -375,7 +375,20 @@ public class ResourceLoader {
}
}
- private native void addOnloadHandler(Element element,
+ /**
+ * Adds an onload listener to the given element, which should be a link or a
+ * script tag. The listener is called whenever loading is complete or an
+ * error occurred.
+ *
+ * @since 7.3
+ * @param element
+ * the element to attach a listener to
+ * @param listener
+ * the listener to call
+ * @param event
+ * the event passed to the listener
+ */
+ public static native void addOnloadHandler(Element element,
ResourceLoadListener listener, ResourceLoadEvent event)
/*-{
element.onload = $entry(function() {
@@ -390,11 +403,11 @@ public class ResourceLoader {
element.onreadystatechange = null;
listener.@com.vaadin.client.ResourceLoader.ResourceLoadListener::onError(Lcom/vaadin/client/ResourceLoader$ResourceLoadEvent;)(event);
});
- element.onreadystatechange = function() {
+ element.onreadystatechange = function() {
if ("loaded" === element.readyState || "complete" === element.readyState ) {
element.onload(arguments[0]);
}
- };
+ };
}-*/;
/**
@@ -520,12 +533,12 @@ public class ResourceLoader {
if (rules === undefined) {
rules = sheet.rules;
}
-
+
if (rules === null) {
// Style sheet loaded, but can't access length because of XSS -> assume there's something there
return 1;
}
-
+
// Return length so we can distinguish 0 (probably 404 error) from normal case.
return rules.length;
} catch (err) {
diff --git a/client/src/com/vaadin/client/Util.java b/client/src/com/vaadin/client/Util.java
index f175bbe714..49c862006b 100644
--- a/client/src/com/vaadin/client/Util.java
+++ b/client/src/com/vaadin/client/Util.java
@@ -1,12 +1,12 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
- *
+ *
* 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
@@ -16,11 +16,14 @@
package com.vaadin.client;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
@@ -36,6 +39,8 @@ import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.dom.client.KeyEvent;
+import com.google.gwt.regexp.shared.MatchResult;
+import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
@@ -56,9 +61,9 @@ public class Util {
/**
* Helper method for debugging purposes.
- *
+ *
* Stops execution on firefox browsers on a breakpoint.
- *
+ *
*/
public static native void browserDebugger()
/*-{
@@ -86,10 +91,10 @@ public class Util {
/**
*
* Returns the topmost element of from given coordinates.
- *
+ *
* TODO fix crossplat issues clientX vs pageX. See quircksmode. Not critical
* for vaadin as we scroll div istead of page.
- *
+ *
* @param x
* @param y
* @return the element at given coordinates
@@ -98,7 +103,7 @@ public class Util {
int clientX, int clientY)
/*-{
var el = $wnd.document.elementFromPoint(clientX, clientY);
- // Call elementFromPoint two times to make sure IE8 also returns something sensible if the application is running in an iframe
+ // Call elementFromPoint two times to make sure IE8 also returns something sensible if the application is running in an iframe
el = $wnd.document.elementFromPoint(clientX, clientY);
if(el != null && el.nodeType == 3) {
el = el.parentNode;
@@ -110,18 +115,18 @@ public class Util {
* This helper method can be called if components size have been changed
* outside rendering phase. It notifies components parent about the size
* change so it can react.
- *
+ *
* When using this method, developer should consider if size changes could
* be notified lazily. If lazy flag is true, method will save widget and
* wait for a moment until it notifies parents in chunks. This may vastly
* optimize layout in various situation. Example: if component have a lot of
* images their onload events may fire "layout phase" many times in a short
* period.
- *
+ *
* @param widget
* @param lazy
* run componentSizeUpdated lazyly
- *
+ *
* @deprecated As of 7.0, use
* {@link LayoutManager#setNeedsMeasure(ComponentConnector)}
* instead
@@ -171,7 +176,7 @@ public class Util {
/**
* Converts html entities to text.
- *
+ *
* @param html
* @return escaped string presentation of given html
*/
@@ -189,7 +194,7 @@ public class Util {
/**
* Escapes the string so it is safe to write inside an HTML attribute.
- *
+ *
* @param attribute
* The string to escape
* @return An escaped version of <literal>attribute</literal>.
@@ -208,9 +213,9 @@ public class Util {
/**
* Clones given element as in JavaScript.
- *
+ *
* Deprecate this if there appears similar method into GWT someday.
- *
+ *
* @param element
* @param deep
* clone child tree also
@@ -469,10 +474,28 @@ public class Util {
}
/**
- * Run workaround for webkits overflow auto issue.
+ * Defers the execution of {@link #runWebkitOverflowAutoFix(Element)}
*
+ * @since
+ * @param elem
+ * with overflow auto
+ */
+ public static void runWebkitOverflowAutoFixDeferred(final Element elem) {
+ Scheduler.get().scheduleDeferred(new Command() {
+
+ @Override
+ public void execute() {
+ Util.runWebkitOverflowAutoFix(elem);
+ }
+ });
+
+ }
+
+ /**
+ * Run workaround for webkits overflow auto issue.
+ *
* See: our bug #2138 and https://bugs.webkit.org/show_bug.cgi?id=21462
- *
+ *
* @param elem
* with overflow auto
*/
@@ -543,7 +566,7 @@ public class Util {
* dimension is not specified as relative it will return -1. If the shared
* state does not contain width or height specifications this will return
* null.
- *
+ *
* @param state
* @return
*/
@@ -576,7 +599,7 @@ public class Util {
* Checks if a and b are equals using {@link #equals(Object)}. Handles null
* values as well. Does not ensure that objects are of the same type.
* Assumes that the first object's equals method handle equals properly.
- *
+ *
* @param a
* The first value to compare
* @param b
@@ -597,7 +620,7 @@ public class Util {
/**
* Gets the border-box width for the given element, i.e. element width +
* border + padding. Always rounds up to nearest integer.
- *
+ *
* @param element
* The element to check
* @return The border-box width for the element
@@ -622,7 +645,7 @@ public class Util {
/**
* Gets the border-box height for the given element, i.e. element height +
* border + padding. Always rounds up to nearest integer.
- *
+ *
* @param element
* The element to check
* @return The border-box height for the element
@@ -669,7 +692,7 @@ public class Util {
var borderBottomPx = cs.borderBottom;
var paddingTopPx = cs.paddingTop;
var paddingBottomPx = cs.paddingBottom;
-
+
var height = heightPx.substring(0,heightPx.length-2);
var border = borderTopPx.substring(0,borderTopPx.length-2)+borderBottomPx.substring(0,borderBottomPx.length-2);
var padding = paddingTopPx.substring(0,paddingTopPx.length-2)+paddingBottomPx.substring(0,paddingBottomPx.length-2);
@@ -689,7 +712,7 @@ public class Util {
var borderRightPx = cs.borderRight;
var paddingLeftPx = cs.paddingLeft;
var paddingRightPx = cs.paddingRight;
-
+
var width = widthPx.substring(0,widthPx.length-2);
var border = borderLeftPx.substring(0,borderLeftPx.length-2)+borderRightPx.substring(0,borderRightPx.length-2);
var padding = paddingLeftPx.substring(0,paddingLeftPx.length-2)+paddingRightPx.substring(0,paddingRightPx.length-2);
@@ -719,7 +742,7 @@ public class Util {
/**
* Detects what is currently the overflow style attribute in given element.
- *
+ *
* @param pe
* the element to detect
* @return true if auto or scroll
@@ -741,7 +764,7 @@ public class Util {
* A simple helper method to detect "computed style" (aka style sheets +
* element styles). Values returned differ a lot depending on browsers.
* Always be very careful when using this.
- *
+ *
* @param el
* the element from which the style property is detected
* @param p
@@ -752,7 +775,7 @@ public class Util {
com.google.gwt.dom.client.Element el, String p)
/*-{
try {
-
+
if (el.currentStyle) {
// IE
return el.currentStyle[p];
@@ -776,9 +799,9 @@ public class Util {
* also returned if "element" is part of its caption. If
* <literal>element</literal> is not part of any child component, null is
* returned.
- *
+ *
* This method returns the deepest nested VPaintableWidget.
- *
+ *
* @param client
* A reference to ApplicationConnection
* @param parent
@@ -836,7 +859,7 @@ public class Util {
/**
* Will (attempt) to focus the given DOM Element.
- *
+ *
* @param el
* the element to focus
*/
@@ -852,7 +875,7 @@ public class Util {
/**
* Helper method to find the nearest parent paintable instance by traversing
* the DOM upwards from given element.
- *
+ *
* @param element
* the element to start from
*/
@@ -870,7 +893,7 @@ public class Util {
/**
* Helper method to find first instance of given Widget type found by
* traversing DOM upwards from given element.
- *
+ *
* @param element
* the element where to start seeking of Widget
* @param class1
@@ -907,7 +930,7 @@ public class Util {
/**
* Force webkit to redraw an element
- *
+ *
* @param element
* The element that should be redrawn
*/
@@ -953,9 +976,9 @@ public class Util {
/**
* Detaches and re-attaches the element from its parent. The element is
* reattached at the same position in the DOM as it was before.
- *
+ *
* Does nothing if the element is not attached to the DOM.
- *
+ *
* @param element
* The element to detach and re-attach
*/
@@ -990,7 +1013,7 @@ public class Util {
/**
* Returns the index of the childElement within its parent.
- *
+ *
* @param subElement
* @return
*/
@@ -1066,7 +1089,7 @@ public class Util {
* Temporarily sets the {@code styleProperty} to {@code tempValue} and then
* resets it to its current value. Used mainly to work around rendering
* issues in IE (and possibly in other browsers)
- *
+ *
* @param element
* The target element
* @param styleProperty
@@ -1089,7 +1112,7 @@ public class Util {
* A helper method to return the client position from an event. Returns
* position from either first changed touch (if touch event) or from the
* event itself.
- *
+ *
* @param event
* @return
*/
@@ -1105,7 +1128,7 @@ public class Util {
* Find the element corresponding to the coordinates in the passed mouse
* event. Please note that this is not always the same as the target of the
* event e.g. if event capture is used.
- *
+ *
* @param event
* the mouse event to get coordinates from
* @return the element at the coordinates of the event
@@ -1122,7 +1145,7 @@ public class Util {
* A helper method to return the client position from an event. Returns
* position from either first changed touch (if touch event) or from the
* event itself.
- *
+ *
* @param event
* @return
*/
@@ -1135,7 +1158,7 @@ public class Util {
}
/**
- *
+ *
* @see #getTouchOrMouseClientY(Event)
* @param currentGwtEvent
* @return
@@ -1146,7 +1169,7 @@ public class Util {
/**
* @see #getTouchOrMouseClientX(Event)
- *
+ *
* @param event
* @return
*/
@@ -1215,7 +1238,7 @@ public class Util {
/**
* Gets the currently focused element.
- *
+ *
* @return The active element or null if no active element could be found.
*/
public native static com.google.gwt.user.client.Element getFocusedElement()
@@ -1223,13 +1246,13 @@ public class Util {
if ($wnd.document.activeElement) {
return $wnd.document.activeElement;
}
-
+
return null;
}-*/;
/**
* Gets the currently focused element for Internet Explorer.
- *
+ *
* @return The currently focused element
* @deprecated Use #getFocusedElement instead
*/
@@ -1243,7 +1266,7 @@ public class Util {
* this method checks that this widget nor any of its parents is hidden. Can
* be e.g used to check whether component should react to some events or
* not.
- *
+ *
* @param widget
* @return true if attached and displayed
*/
@@ -1276,7 +1299,7 @@ public class Util {
/**
* Scrolls an element into view vertically only. Modified version of
* Element.scrollIntoView.
- *
+ *
* @param elem
* The element to scroll into view
*/
@@ -1284,11 +1307,11 @@ public class Util {
/*-{
var top = elem.offsetTop;
var height = elem.offsetHeight;
-
+
if (elem.parentNode != elem.offsetParent) {
top -= elem.parentNode.offsetTop;
}
-
+
var cur = elem.parentNode;
while (cur && (cur.nodeType == 1)) {
if (top < cur.scrollTop) {
@@ -1297,12 +1320,12 @@ public class Util {
if (top + height > cur.scrollTop + cur.clientHeight) {
cur.scrollTop = (top + height) - cur.clientHeight;
}
-
+
var offsetTop = cur.offsetTop;
if (cur.parentNode != cur.offsetParent) {
offsetTop -= cur.parentNode.offsetTop;
}
-
+
top += offsetTop - cur.scrollTop;
cur = cur.parentNode;
}
@@ -1311,7 +1334,7 @@ public class Util {
/**
* Checks if the given event is either a touch event or caused by the left
* mouse button
- *
+ *
* @param event
* @return true if the event is a touch event or caused by the left mouse
* button, false otherwise
@@ -1323,7 +1346,7 @@ public class Util {
/**
* Performs a shallow comparison of the collections.
- *
+ *
* @param collection1
* The first collection
* @param collection2
@@ -1369,7 +1392,7 @@ public class Util {
/**
* Resolve a relative URL to an absolute URL based on the current document's
* location.
- *
+ *
* @param url
* a string with the relative URL to resolve
* @return the corresponding absolute URL as a string
@@ -1396,4 +1419,161 @@ public class Util {
}
}
+ /**
+ * Wrap a css size value and its unit and translate back and forth to the
+ * string representation.<br/>
+ * Eg. 50%, 123px, ...
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+ @SuppressWarnings("serial")
+ public static class CssSize implements Serializable {
+
+ /*
+ * Map the size units with their type.
+ */
+ private static Map<String, Unit> type2Unit = new HashMap<String, Style.Unit>();
+ static {
+ for (Unit unit : Unit.values()) {
+ type2Unit.put(unit.getType(), unit);
+ }
+ }
+
+ /**
+ * Gets the unit value by its type.
+ *
+ * @since
+ * @param type
+ * the type of the unit as found in the style.
+ * @return the unit value.
+ */
+ public static Unit unitByType(String type) {
+ return type2Unit.get(type);
+ }
+
+ /*
+ * Regex to parse the size.
+ */
+ private static final RegExp sizePattern = RegExp
+ .compile(SharedUtil.SIZE_PATTERN);
+
+ /**
+ * Parse the size from string format to {@link CssSize}.
+ *
+ * @param s
+ * the size as string.
+ * @return a {@link CssSize} object.
+ */
+ public static CssSize fromString(String s) {
+ if (s == null) {
+ return null;
+ }
+
+ s = s.trim();
+ if ("".equals(s)) {
+ return null;
+ }
+
+ float size = 0;
+ Unit unit = null;
+
+ MatchResult matcher = sizePattern.exec(s);
+ if (matcher.getGroupCount() > 1) {
+
+ size = Float.parseFloat(matcher.getGroup(1));
+ if (size < 0) {
+ size = -1;
+ unit = Unit.PX;
+
+ } else {
+ String symbol = matcher.getGroup(2);
+ unit = unitByType(symbol);
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid size argument: \""
+ + s + "\" (should match " + sizePattern.getSource()
+ + ")");
+ }
+ return new CssSize(size, unit);
+ }
+
+ /**
+ * Creates a {@link CssSize} using a value and its measurement unit.
+ *
+ * @since
+ * @param value
+ * the value.
+ * @param unit
+ * the unit.
+ * @return the {@link CssSize} object.
+ */
+ public static CssSize fromValueUnit(float value, Unit unit) {
+ return new CssSize(value, unit);
+ }
+
+ /*
+ * The value.
+ */
+ private final float value;
+
+ /*
+ * The measure unit.
+ */
+ private final Unit unit;
+
+ private CssSize(float value, Unit unit) {
+ this.value = value;
+ this.unit = unit;
+ }
+
+ /**
+ * Gets the value for this css size.
+ *
+ * @return the value.
+ */
+ public float getValue() {
+ return value;
+ }
+
+ /**
+ * Gets the measurement unit for this css size.
+ *
+ * @return the unit.
+ */
+ public Unit getUnit() {
+ return unit;
+ }
+
+ @Override
+ public String toString() {
+ return value + unit.getType();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof CssSize) {
+ CssSize size = (CssSize) obj;
+ return size.value == value && size.unit == unit;
+ }
+
+ return false;
+ }
+
+ /**
+ * Check whether the two sizes are equals.
+ *
+ * @since
+ * @param cssSize1
+ * the first size to compare.
+ * @param cssSize2
+ * the other size to compare with the first one.
+ * @return true if the two sizes are equals, otherwise false.
+ */
+ public static boolean equals(String cssSize1, String cssSize2) {
+ return CssSize.fromString(cssSize1).equals(CssSize.fromString(cssSize2));
+ }
+
+ }
+
}
diff --git a/client/src/com/vaadin/client/communication/Heartbeat.java b/client/src/com/vaadin/client/communication/Heartbeat.java
index 1ff0825f0e..b9493d4520 100644
--- a/client/src/com/vaadin/client/communication/Heartbeat.java
+++ b/client/src/com/vaadin/client/communication/Heartbeat.java
@@ -124,7 +124,9 @@ public class Heartbeat {
@Override
public void onError(Request request, Throwable exception) {
- getLogger().severe("Exception sending heartbeat: " + exception.getMessage());
+ getLogger().severe(
+ "Exception sending heartbeat: "
+ + exception.getMessage());
// Notify network observers about response status
connection.fireEvent(new ConnectionStatusEvent(0));
// Don't break the loop
diff --git a/client/src/com/vaadin/client/communication/TranslatedURLReference.java b/client/src/com/vaadin/client/communication/TranslatedURLReference.java
new file mode 100644
index 0000000000..b99f4c6e32
--- /dev/null
+++ b/client/src/com/vaadin/client/communication/TranslatedURLReference.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * 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.vaadin.client.communication;
+
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.shared.communication.URLReference;
+
+/**
+ * A URLReference implementation which does late URL translation to be able to
+ * re-translate URLs if e.g. the theme changes
+ *
+ * @since 7.3
+ * @author Vaadin Ltd
+ */
+public class TranslatedURLReference extends URLReference {
+
+ private ApplicationConnection connection;
+
+ /**
+ * @param connection
+ * the connection to set
+ */
+ public void setConnection(ApplicationConnection connection) {
+ this.connection = connection;
+ }
+
+ @Override
+ public String getURL() {
+ return connection.translateVaadinUri(super.getURL());
+ }
+
+}
diff --git a/client/src/com/vaadin/client/communication/URLReference_Serializer.java b/client/src/com/vaadin/client/communication/URLReference_Serializer.java
index 586dd626f0..4ecdc606d2 100644
--- a/client/src/com/vaadin/client/communication/URLReference_Serializer.java
+++ b/client/src/com/vaadin/client/communication/URLReference_Serializer.java
@@ -1,12 +1,12 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
- *
+ *
* 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
@@ -30,14 +30,16 @@ public class URLReference_Serializer implements JSONSerializer<URLReference> {
@Override
public URLReference deserialize(Type type, JSONValue jsonValue,
ApplicationConnection connection) {
- URLReference reference = GWT.create(URLReference.class);
+ TranslatedURLReference reference = GWT
+ .create(TranslatedURLReference.class);
+ reference.setConnection(connection);
JSONObject json = (JSONObject) jsonValue;
if (json.containsKey(URL_FIELD)) {
JSONValue jsonURL = json.get(URL_FIELD);
String URL = (String) JsonDecoder.decodeValue(
new Type(String.class.getName(), null), jsonURL, null,
connection);
- reference.setURL(connection.translateVaadinUri(URL));
+ reference.setURL(URL);
}
return reference;
}
diff --git a/client/src/com/vaadin/client/componentlocator/LocatorStrategy.java b/client/src/com/vaadin/client/componentlocator/LocatorStrategy.java
index 6eb732bf46..15a156a815 100644
--- a/client/src/com/vaadin/client/componentlocator/LocatorStrategy.java
+++ b/client/src/com/vaadin/client/componentlocator/LocatorStrategy.java
@@ -87,8 +87,7 @@ public interface LocatorStrategy {
* @return The DOM element identified by {@code path} or null if the element
* could not be located.
*/
- Element getElementByPathStartingAt(String path,
- Element root);
+ Element getElementByPathStartingAt(String path, Element root);
/**
* Locates all elements that match a String locator (path) which identifies
@@ -119,6 +118,5 @@ public interface LocatorStrategy {
* found.
*/
- List<Element> getElementsByPathStartingAt(
- String path, Element root);
+ List<Element> getElementsByPathStartingAt(String path, Element root);
}
diff --git a/client/src/com/vaadin/client/debug/internal/HierarchySection.java b/client/src/com/vaadin/client/debug/internal/HierarchySection.java
index 1eacf286e8..404ac430df 100644
--- a/client/src/com/vaadin/client/debug/internal/HierarchySection.java
+++ b/client/src/com/vaadin/client/debug/internal/HierarchySection.java
@@ -108,16 +108,14 @@ public class HierarchySection implements Section {
hierarchyPanel.addListener(new SelectConnectorListener() {
@Override
- public void select(ServerConnector connector,
- Element element) {
+ public void select(ServerConnector connector, Element element) {
printState(connector, true);
}
});
analyzeLayoutsPanel.addListener(new SelectConnectorListener() {
@Override
- public void select(ServerConnector connector,
- Element element) {
+ public void select(ServerConnector connector, Element element) {
printState(connector, true);
}
});
diff --git a/client/src/com/vaadin/client/debug/internal/InfoSection.java b/client/src/com/vaadin/client/debug/internal/InfoSection.java
index 23b77a94db..a7a84f5f8f 100644
--- a/client/src/com/vaadin/client/debug/internal/InfoSection.java
+++ b/client/src/com/vaadin/client/debug/internal/InfoSection.java
@@ -163,7 +163,7 @@ public class InfoSection implements Section {
addVersionInfo(configuration);
addRow("Widget set", GWT.getModuleName());
- addRow("Theme", connection.getConfiguration().getThemeName());
+ addRow("Theme", connection.getUIConnector().getActiveTheme());
String communicationMethodInfo = connection
.getCommunicationMethodName();
diff --git a/client/src/com/vaadin/client/debug/internal/SelectConnectorListener.java b/client/src/com/vaadin/client/debug/internal/SelectConnectorListener.java
index c3652c78e8..46c8070b30 100644
--- a/client/src/com/vaadin/client/debug/internal/SelectConnectorListener.java
+++ b/client/src/com/vaadin/client/debug/internal/SelectConnectorListener.java
@@ -33,6 +33,5 @@ public interface SelectConnectorListener {
* @param element
* selected element of the connector or null if unknown
*/
- public void select(ServerConnector connector,
- Element element);
+ public void select(ServerConnector connector, Element element);
}
diff --git a/client/src/com/vaadin/client/ui/AbstractConnector.java b/client/src/com/vaadin/client/ui/AbstractConnector.java
index a2e0d9cd54..e93ea0f507 100644
--- a/client/src/com/vaadin/client/ui/AbstractConnector.java
+++ b/client/src/com/vaadin/client/ui/AbstractConnector.java
@@ -28,6 +28,7 @@ import com.google.gwt.event.shared.HandlerManager;
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.FastStringMap;
+import com.vaadin.client.FastStringSet;
import com.vaadin.client.JsArrayObject;
import com.vaadin.client.Profiler;
import com.vaadin.client.ServerConnector;
@@ -479,4 +480,27 @@ public abstract class AbstractConnector implements ServerConnector,
Set<String> reg = getState().registeredEventListeners;
return (reg != null && reg.contains(eventIdentifier));
}
+
+ /**
+ * Force the connector to recheck its state variables as the variables or
+ * their meaning might have changed.
+ *
+ * @since 7.3
+ */
+ public void forceStateChange() {
+ StateChangeEvent event = new FullStateChangeEvent(this);
+ fireEvent(event);
+ }
+
+ private static class FullStateChangeEvent extends StateChangeEvent {
+ public FullStateChangeEvent(ServerConnector connector) {
+ super(connector, FastStringSet.create());
+ }
+
+ @Override
+ public boolean hasPropertyChanged(String property) {
+ return true;
+ }
+
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VCalendarPanel.java b/client/src/com/vaadin/client/ui/VCalendarPanel.java
index eaa2292c69..6fc06bb153 100644
--- a/client/src/com/vaadin/client/ui/VCalendarPanel.java
+++ b/client/src/com/vaadin/client/ui/VCalendarPanel.java
@@ -786,6 +786,21 @@ public class VCalendarPanel extends FocusableFlexTable implements
* Updates the calendar and text field with the selected dates.
*/
public void renderCalendar() {
+ renderCalendar(true);
+ }
+
+ /**
+ * For internal use only. May be removed or replaced in the future.
+ *
+ * Updates the calendar and text field with the selected dates.
+ *
+ * @param updateDate
+ * The value false prevents setting the selected date of the
+ * calendar based on focusedDate. That can be used when only the
+ * resolution of the calendar is changed and no date has been
+ * selected.
+ */
+ public void renderCalendar(boolean updateDate) {
super.setStylePrimaryName(parent.getStylePrimaryName()
+ "-calendarpanel");
@@ -798,8 +813,9 @@ public class VCalendarPanel extends FocusableFlexTable implements
displayedMonth = new FocusedDate(now.getYear(), now.getMonth(), 1);
}
- if (getResolution().getCalendarField() <= Resolution.MONTH
- .getCalendarField() && focusChangeListener != null) {
+ if (updateDate
+ && getResolution().getCalendarField() <= Resolution.MONTH
+ .getCalendarField() && focusChangeListener != null) {
focusChangeListener.focusChanged(new Date(focusedDate.getTime()));
}
diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java
index 7f67c39500..6ba0785acc 100644
--- a/client/src/com/vaadin/client/ui/VFilterSelect.java
+++ b/client/src/com/vaadin/client/ui/VFilterSelect.java
@@ -46,6 +46,7 @@ import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.i18n.client.HasDirection.Direction;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
@@ -62,6 +63,7 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ComputedStyle;
import com.vaadin.client.ConnectorMap;
import com.vaadin.client.Focusable;
import com.vaadin.client.UIDL;
@@ -252,7 +254,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Shows the popup where the user can see the filtered options
- *
+ *
* @param currentSuggestions
* The filtered suggestions
* @param currentPage
@@ -264,10 +266,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
final Collection<FilterSelectSuggestion> currentSuggestions,
final int currentPage, final int totalSuggestions) {
- if (enableDebug) {
- debug("VFS.SP: showSuggestions(" + currentSuggestions + ", "
- + currentPage + ", " + totalSuggestions + ")");
- }
+ debug("VFS.SP: showSuggestions(" + currentSuggestions + ", "
+ + currentPage + ", " + totalSuggestions + ")");
/*
* We need to defer the opening of the popup so that the parent DOM
@@ -316,8 +316,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
status.setInnerText("");
}
// We don't need to show arrows or statusbar if there is
- // only one
- // page
+ // only one page
if (totalSuggestions <= pageLength || pageLength == 0) {
setPagingEnabled(false);
} else {
@@ -346,7 +345,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Should the next page button be visible to the user?
- *
+ *
* @param active
*/
private void setNextButtonActive(boolean active) {
@@ -366,7 +365,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Should the previous page button be visible to the user
- *
+ *
* @param active
*/
private void setPrevButtonActive(boolean active) {
@@ -391,18 +390,13 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
*/
public void selectNextItem() {
debug("VFS.SP: selectNextItem()");
- final MenuItem cur = menu.getSelectedItem();
- final int index = 1 + menu.getItems().indexOf(cur);
+
+ final int index = menu.getSelectedIndex() + 1;
if (menu.getItems().size() > index) {
- final MenuItem newSelectedItem = menu.getItems().get(index);
- menu.selectItem(newSelectedItem);
- tb.setText(newSelectedItem.getText());
- tb.setSelectionRange(lastFilter.length(), newSelectedItem
- .getText().length() - lastFilter.length());
-
- } else if (hasNextPage()) {
- selectPopupItemWhenResponseIsReceived = Select.FIRST;
- filterOptions(currentPage + 1, lastFilter);
+ selectItem(menu.getItems().get(index));
+
+ } else {
+ selectNextPage();
}
}
@@ -411,29 +405,59 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
*/
public void selectPrevItem() {
debug("VFS.SP: selectPrevItem()");
- final MenuItem cur = menu.getSelectedItem();
- final int index = -1 + menu.getItems().indexOf(cur);
+
+ final int index = menu.getSelectedIndex() - 1;
if (index > -1) {
- final MenuItem newSelectedItem = menu.getItems().get(index);
- menu.selectItem(newSelectedItem);
- tb.setText(newSelectedItem.getText());
- tb.setSelectionRange(lastFilter.length(), newSelectedItem
- .getText().length() - lastFilter.length());
+ selectItem(menu.getItems().get(index));
+
} else if (index == -1) {
- if (currentPage > 0) {
- selectPopupItemWhenResponseIsReceived = Select.LAST;
- filterOptions(currentPage - 1, lastFilter);
- }
+ selectPrevPage();
+
} else {
- final MenuItem newSelectedItem = menu.getItems().get(
- menu.getItems().size() - 1);
- menu.selectItem(newSelectedItem);
- tb.setText(newSelectedItem.getText());
- tb.setSelectionRange(lastFilter.length(), newSelectedItem
- .getText().length() - lastFilter.length());
+ selectItem(menu.getItems().get(menu.getItems().size() - 1));
}
}
+ /**
+ * Select the first item of the suggestions list popup.
+ *
+ * @since
+ */
+ public void selectFirstItem() {
+ debug("VFS.SP: selectFirstItem()");
+ selectItem(menu.getFirstItem());
+ }
+
+ /**
+ * Select the last item of the suggestions list popup.
+ *
+ * @since
+ */
+ public void selectLastItem() {
+ debug("VFS.SP: selectLastItem()");
+ selectItem(menu.getLastItem());
+ }
+
+ /*
+ * Sets the selected item in the popup menu.
+ */
+ private void selectItem(final MenuItem newSelectedItem) {
+ menu.selectItem(newSelectedItem);
+
+ String text = newSelectedItem != null ? newSelectedItem.getText()
+ : "";
+
+ // Set the icon.
+ FilterSelectSuggestion suggestion = (FilterSelectSuggestion) newSelectedItem
+ .getCommand();
+ setSelectedItemIcon(suggestion.getIconUri());
+
+ // Set the text.
+ setText(text);
+
+ menu.updateKeyboardSelectedItem();
+ }
+
/*
* Using a timer to scroll up or down the pages so when we receive lots
* of consecutive mouse wheel events the pages does not flicker.
@@ -486,17 +510,10 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
}
}
- /*
- * (non-Javadoc)
- *
- * @see
- * com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt
- * .user.client.Event)
- */
-
@Override
public void onBrowserEvent(Event event) {
debug("VFS.SP: onBrowserEvent()");
+
if (event.getTypeInt() == Event.ONCLICK) {
final Element target = DOM.eventGetTarget(event);
if (target == up || target == DOM.getChild(up, 0)) {
@@ -504,12 +521,24 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
} else if (target == down || target == DOM.getChild(down, 0)) {
lazyPageScroller.scrollDown();
}
+
} else if (event.getTypeInt() == Event.ONMOUSEWHEEL) {
- int velocity = event.getMouseWheelVelocityY();
- if (velocity > 0) {
- lazyPageScroller.scrollDown();
- } else {
- lazyPageScroller.scrollUp();
+
+ boolean scrollNotActive = !menu.isScrollActive();
+
+ debug("VFS.SP: onBrowserEvent() scrollNotActive: "
+ + scrollNotActive);
+
+ if (scrollNotActive) {
+ int velocity = event.getMouseWheelVelocityY();
+
+ debug("VFS.SP: onBrowserEvent() velocity: " + velocity);
+
+ if (velocity > 0) {
+ lazyPageScroller.scrollDown();
+ } else {
+ lazyPageScroller.scrollUp();
+ }
}
}
@@ -525,7 +554,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* amount of items are visible at a time and a scrollbar or buttons are
* visible to change page. If paging is turned of then all options are
* rendered into the popup menu.
- *
+ *
* @param paging
* Should the paging be turned on?
*/
@@ -546,32 +575,29 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
isPagingEnabled = paging;
}
- /*
- * (non-Javadoc)
- *
- * @see
- * com.google.gwt.user.client.ui.PopupPanel$PositionCallback#setPosition
- * (int, int)
- */
-
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
- debug("VFS.SP: setPosition()");
+ debug("VFS.SP: setPosition(" + offsetWidth + ", " + offsetHeight
+ + ")");
- int top = -1;
- int left = -1;
+ int top = topPosition;
+ int left = getPopupLeft();
// reset menu size and retrieve its "natural" size
menu.setHeight("");
- if (currentPage > 0) {
+ if (currentPage > 0 && !hasNextPage()) {
// fix height to avoid height change when getting to last page
menu.fixHeightTo(pageLength);
}
- offsetHeight = getOffsetHeight();
+ final int desiredHeight = offsetHeight = getOffsetHeight();
final int desiredWidth = getMainWidth();
+
+ debug("VFS.SP: desired[" + desiredWidth + ", " + desiredHeight
+ + "]");
+
Element menuFirstChild = menu.getElement().getFirstChildElement();
- int naturalMenuWidth = menuFirstChild.getOffsetWidth();
+ final int naturalMenuWidth = menuFirstChild.getOffsetWidth();
if (popupOuterPadding == -1) {
popupOuterPadding = Util.measureHorizontalPaddingAndBorder(
@@ -581,7 +607,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
if (naturalMenuWidth < desiredWidth) {
menu.setWidth((desiredWidth - popupOuterPadding) + "px");
menuFirstChild.getStyle().setWidth(100, Unit.PCT);
- naturalMenuWidth = desiredWidth;
}
if (BrowserInfo.get().isIE()) {
@@ -589,48 +614,72 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* IE requires us to specify the width for the container
* element. Otherwise it will be 100% wide
*/
- int rootWidth = naturalMenuWidth - popupOuterPadding;
+ int rootWidth = Math.max(desiredWidth, naturalMenuWidth)
+ - popupOuterPadding;
getContainerElement().getStyle().setWidth(rootWidth, Unit.PX);
}
- if (offsetHeight + getPopupTop() > Window.getClientHeight()
- + Window.getScrollTop()) {
+ final int vfsHeight = VFilterSelect.this.getOffsetHeight();
+ final int spaceAvailableAbove = top - vfsHeight;
+ final int spaceAvailableBelow = Window.getClientHeight() - top;
+ if (spaceAvailableBelow < offsetHeight
+ && spaceAvailableBelow < spaceAvailableAbove) {
// popup on top of input instead
- top = getPopupTop() - offsetHeight
- - VFilterSelect.this.getOffsetHeight();
+ top -= offsetHeight + vfsHeight;
if (top < 0) {
+ offsetHeight += top;
top = 0;
}
} else {
- top = getPopupTop();
- /*
- * Take popup top margin into account. getPopupTop() returns the
- * top value including the margin but the value we give must not
- * include the margin.
- */
- int topMargin = (top - topPosition);
- top -= topMargin;
+ offsetHeight = Math.min(offsetHeight, spaceAvailableBelow);
}
// fetch real width (mac FF bugs here due GWT popups overflow:auto )
offsetWidth = menuFirstChild.getOffsetWidth();
- if (offsetWidth + getPopupLeft() > Window.getClientWidth()
- + Window.getScrollLeft()) {
+
+ if (offsetHeight < desiredHeight) {
+ int menuHeight = offsetHeight;
+ if (isPagingEnabled) {
+ menuHeight -= up.getOffsetHeight() + down.getOffsetHeight()
+ + status.getOffsetHeight();
+ } else {
+ final ComputedStyle s = new ComputedStyle(menu.getElement());
+ menuHeight -= s.getIntProperty("marginBottom")
+ + s.getIntProperty("marginTop");
+ }
+
+ // If the available page height is really tiny then this will be
+ // negative and an exception will be thrown on setHeight.
+ int menuElementHeight = menu.getItemOffsetHeight();
+ if (menuHeight < menuElementHeight) {
+ menuHeight = menuElementHeight;
+ }
+
+ menu.setHeight(menuHeight + "px");
+
+ final int naturalMenuWidthPlusScrollBar = naturalMenuWidth
+ + Util.getNativeScrollbarSize();
+ if (offsetWidth < naturalMenuWidthPlusScrollBar) {
+ menu.setWidth(naturalMenuWidthPlusScrollBar + "px");
+ }
+ }
+
+ if (offsetWidth + left > Window.getClientWidth()) {
left = VFilterSelect.this.getAbsoluteLeft()
- + VFilterSelect.this.getOffsetWidth()
- + Window.getScrollLeft() - offsetWidth;
+ + VFilterSelect.this.getOffsetWidth() - offsetWidth;
if (left < 0) {
left = 0;
+ menu.setWidth(Window.getClientWidth() + "px");
}
- } else {
- left = getPopupLeft();
}
+
setPopupPosition(left, top);
+ menu.scrollSelectionIntoView();
}
/**
* Was the popup just closed?
- *
+ *
* @return true if popup was just closed
*/
public boolean isJustClosed() {
@@ -659,7 +708,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Updates style names in suggestion popup to help theme building.
- *
+ *
* @param uidl
* UIDL for the whole combo box
* @param componentState
@@ -723,23 +772,34 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
super(true);
debug("VFS.SM: constructor()");
addDomHandler(this, LoadEvent.getType());
+
+ setScrollEnabled(true);
}
/**
* Fixes menus height to use same space as full page would use. Needed
- * to avoid height changes when quickly "scrolling" to last page
+ * to avoid height changes when quickly "scrolling" to last page.
*/
- public void fixHeightTo(int pagelenth) {
+ public void fixHeightTo(int pageItemsCount) {
+ setHeight(getPreferredHeight(pageItemsCount));
+ }
+
+ /*
+ * Gets the preferred height of the menu including pageItemsCount items.
+ */
+ String getPreferredHeight(int pageItemsCount) {
if (currentSuggestions.size() > 0) {
- final int pixels = pagelenth * (getOffsetHeight() - 2)
- / currentSuggestions.size();
- setHeight((pixels + 2) + "px");
+ final int pixels = (getPreferredHeight() / currentSuggestions
+ .size()) * pageItemsCount;
+ return pixels + "px";
+ } else {
+ return "";
}
}
/**
* Sets the suggestions rendered in the menu
- *
+ *
* @param suggestions
* The suggestions to be rendered in the menu
*/
@@ -789,6 +849,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
client.updateVariable(paintableId, "page", 0, false);
client.updateVariable(paintableId, "selected", new String[] {},
immediate);
+ afterUpdateClientVariables();
+
suggestionPopup.hide();
return;
}
@@ -837,6 +899,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
lastNewItemString = enteredItemValue;
client.updateVariable(paintableId, "newitem",
enteredItemValue, immediate);
+ afterUpdateClientVariables();
}
} else if (item != null
&& !"".equals(lastFilter)
@@ -852,11 +915,11 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
&& !currentSuggestion.key.equals("")) {
// An item (not null) selected
String text = currentSuggestion.getReplacementString();
- tb.setText(text);
+ setText(text);
selectedOptionKey = currentSuggestion.key;
} else {
// Null selected
- tb.setText("");
+ setText("");
selectedOptionKey = null;
}
}
@@ -909,26 +972,75 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
}
- public void selectFirstItem() {
- debug("VFS.SM: selectFirstItem()");
- MenuItem firstItem = getItems().get(0);
- selectItem(firstItem);
- }
-
private MenuItem getKeyboardSelectedItem() {
return keyboardSelectedItem;
}
- public void setKeyboardSelectedItem(MenuItem firstItem) {
- keyboardSelectedItem = firstItem;
+ public void setKeyboardSelectedItem(MenuItem menuItem) {
+ keyboardSelectedItem = menuItem;
}
+ /**
+ * @deprecated use {@link SuggestionPopup#selectFirstItem()} instead.
+ */
+ @Deprecated
+ public void selectFirstItem() {
+ debug("VFS.SM: selectFirstItem()");
+ MenuItem firstItem = getItems().get(0);
+ selectItem(firstItem);
+ }
+
+ /**
+ * @deprecated use {@link SuggestionPopup#selectLastItem()} instead.
+ */
+ @Deprecated
public void selectLastItem() {
debug("VFS.SM: selectLastItem()");
List<MenuItem> items = getItems();
MenuItem lastItem = items.get(items.size() - 1);
selectItem(lastItem);
}
+
+ /*
+ * Sets the keyboard item as the current selected one.
+ */
+ void updateKeyboardSelectedItem() {
+ setKeyboardSelectedItem(getSelectedItem());
+ }
+
+ /*
+ * Gets the height of one menu item.
+ */
+ int getItemOffsetHeight() {
+ List<MenuItem> items = getItems();
+ return items != null && items.size() > 0 ? items.get(0)
+ .getOffsetHeight() : 0;
+ }
+
+ /*
+ * Gets the width of one menu item.
+ */
+ int getItemOffsetWidth() {
+ List<MenuItem> items = getItems();
+ return items != null && items.size() > 0 ? items.get(0)
+ .getOffsetWidth() : 0;
+ }
+
+ /**
+ * Returns true if the scroll is active on the menu element or if the
+ * menu currently displays the last page with less items then the
+ * maximum visibility (in which case the scroll is not active, but the
+ * scroll is active for any other page in general).
+ */
+ @Override
+ public boolean isScrollActive() {
+ String height = getElement().getStyle().getHeight();
+ String preferredHeight = getPreferredHeight(pageLength);
+
+ return !(height == null || height.length() == 0 || height
+ .equals(preferredHeight));
+ }
+
}
/**
@@ -947,7 +1059,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
if (textInputEnabled) {
super.setSelectionRange(pos, length);
} else {
- super.setSelectionRange(getValue().length(), 0);
+ super.setSelectionRange(0, getValue().length());
}
}
}
@@ -1273,10 +1385,9 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* Whether to send the options request immediately
*/
private void filterOptions(int page, String filter, boolean immediate) {
- if (enableDebug) {
- debug("VFS: filterOptions(" + page + ", " + filter + ", "
- + immediate + ")");
- }
+ debug("VFS: filterOptions(" + page + ", " + filter + ", " + immediate
+ + ")");
+
if (filter.equals(lastFilter) && currentPage == page) {
if (!suggestionPopup.isAttached()) {
suggestionPopup.showSuggestions(currentSuggestions,
@@ -1297,8 +1408,11 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
waitingForFilteringResponse = true;
client.updateVariable(paintableId, "filter", filter, false);
client.updateVariable(paintableId, "page", page, immediate);
+ afterUpdateClientVariables();
+
lastFilter = filter;
currentPage = page;
+
}
/** For internal use only. May be removed or replaced in the future. */
@@ -1337,7 +1451,19 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
if (enableDebug) {
debug("VFS: setTextboxText(" + text + ")");
}
+ setText(text);
+ }
+
+ private void setText(final String text) {
+ /**
+ * To leave caret in the beginning of the line.
+ * SetSelectionRange wouldn't work on IE
+ * (see #13477)
+ */
+ Direction previousDirection = tb.getDirection();
+ tb.setDirection(Direction.RTL);
tb.setText(text);
+ tb.setDirection(previousDirection);
}
/**
@@ -1401,10 +1527,13 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
setPromptingOff(text);
}
setSelectedItemIcon(suggestion.getIconUri());
+
if (!(newKey.equals(selectedOptionKey) || ("".equals(newKey) && selectedOptionKey == null))) {
selectedOptionKey = newKey;
client.updateVariable(paintableId, "selected",
new String[] { selectedOptionKey }, immediate);
+ afterUpdateClientVariables();
+
// currentPage = -1; // forget the page
}
suggestionPopup.hide();
@@ -1597,28 +1726,22 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
switch (event.getNativeKeyCode()) {
case KeyCodes.KEY_DOWN:
suggestionPopup.selectNextItem();
- suggestionPopup.menu.setKeyboardSelectedItem(suggestionPopup.menu
- .getSelectedItem());
+
DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
event.stopPropagation();
break;
case KeyCodes.KEY_UP:
suggestionPopup.selectPrevItem();
- suggestionPopup.menu.setKeyboardSelectedItem(suggestionPopup.menu
- .getSelectedItem());
+
DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
event.stopPropagation();
break;
case KeyCodes.KEY_PAGEDOWN:
- if (hasNextPage()) {
- filterOptions(currentPage + 1, lastFilter);
- }
+ selectNextPage();
event.stopPropagation();
break;
case KeyCodes.KEY_PAGEUP:
- if (currentPage > 0) {
- filterOptions(currentPage - 1, lastFilter);
- }
+ selectPrevPage();
event.stopPropagation();
break;
case KeyCodes.KEY_TAB:
@@ -1664,6 +1787,26 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
}
+ /*
+ * Show the prev page.
+ */
+ private void selectPrevPage() {
+ if (currentPage > 0) {
+ filterOptions(currentPage - 1, lastFilter);
+ selectPopupItemWhenResponseIsReceived = Select.LAST;
+ }
+ }
+
+ /*
+ * Show the next page.
+ */
+ private void selectNextPage() {
+ if (hasNextPage()) {
+ filterOptions(currentPage + 1, lastFilter);
+ selectPopupItemWhenResponseIsReceived = Select.FIRST;
+ }
+ }
+
/**
* Triggered when a key was depressed
*
@@ -1707,15 +1850,21 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
if (currentSuggestion != null) {
String text = currentSuggestion.getReplacementString();
setPromptingOff(text);
+ setSelectedItemIcon(currentSuggestion.getIconUri());
+
selectedOptionKey = currentSuggestion.key;
+
} else {
if (focused || readonly || !enabled) {
setPromptingOff("");
} else {
setPromptingOn();
}
+ setSelectedItemIcon(null);
+
selectedOptionKey = null;
}
+
lastFilter = "";
suggestionPopup.hide();
}
@@ -1837,6 +1986,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
if (client.hasEventListeners(this, EventId.FOCUS)) {
client.updateVariable(paintableId, EventId.FOCUS, "", true);
+ afterUpdateClientVariables();
}
ComponentConnector connector = ConnectorMap.get(client).getConnector(
@@ -1913,6 +2063,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
if (client.hasEventListeners(this, EventId.BLUR)) {
client.updateVariable(paintableId, EventId.BLUR, "", true);
+ afterUpdateClientVariables();
}
}
@@ -2091,4 +2242,15 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
com.google.gwt.user.client.Element captionElement) {
AriaHelper.bindCaption(tb, captionElement);
}
+
+ /*
+ * Anything that should be set after the client updates the server.
+ */
+ private void afterUpdateClientVariables() {
+ // We need this here to be consistent with the all the calls.
+ // Then set your specific selection type only after
+ // client.updateVariable() method call.
+ selectPopupItemWhenResponseIsReceived = Select.NONE;
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/VGridLayout.java b/client/src/com/vaadin/client/ui/VGridLayout.java
index 10e5c00a38..17131ce63b 100644
--- a/client/src/com/vaadin/client/ui/VGridLayout.java
+++ b/client/src/com/vaadin/client/ui/VGridLayout.java
@@ -95,7 +95,7 @@ public class VGridLayout extends ComplexPanel {
/**
* Returns the column widths measured in pixels
- *
+ *
* @return
*/
protected int[] getColumnWidths() {
@@ -104,7 +104,7 @@ public class VGridLayout extends ComplexPanel {
/**
* Returns the row heights measured in pixels
- *
+ *
* @return
*/
protected int[] getRowHeights() {
@@ -113,7 +113,7 @@ public class VGridLayout extends ComplexPanel {
/**
* Returns the spacing between the cells horizontally in pixels
- *
+ *
* @return
*/
protected int getHorizontalSpacing() {
@@ -122,7 +122,7 @@ public class VGridLayout extends ComplexPanel {
/**
* Returns the spacing between the cells vertically in pixels
- *
+ *
* @return
*/
protected int getVerticalSpacing() {
@@ -271,7 +271,7 @@ public class VGridLayout extends ComplexPanel {
}
for (SpanList l : rowSpans) {
for (Cell cell : l.cells) {
- if (cell.row >= i && i < cell.row + cell.rowspan) {
+ if (cell.row <= i && i < cell.row + cell.rowspan) {
return true;
}
}
@@ -287,7 +287,7 @@ public class VGridLayout extends ComplexPanel {
}
for (SpanList l : colSpans) {
for (Cell cell : l.cells) {
- if (cell.col >= i && i < cell.col + cell.colspan) {
+ if (cell.col <= i && i < cell.col + cell.colspan) {
return true;
}
}
@@ -751,7 +751,7 @@ public class VGridLayout extends ComplexPanel {
* Creates a new Cell with the given coordinates.
* <p>
* For internal use only. May be removed or replaced in the future.
- *
+ *
* @param row
* @param col
* @return
@@ -767,7 +767,7 @@ public class VGridLayout extends ComplexPanel {
* child component is also returned if "element" is part of its caption.
* <p>
* For internal use only. May be removed or replaced in the future.
- *
+ *
* @param element
* An element that is a nested sub element of the root element in
* this layout
@@ -788,13 +788,13 @@ public class VGridLayout extends ComplexPanel {
* child component is also returned if "element" is part of its caption.
* <p>
* For internal use only. May be removed or replaced in the future.
- *
+ *
* @param element
* An element that is a nested sub element of the root element in
* this layout
* @return The Paintable which the element is a part of. Null if the element
* belongs to the layout and not to a child.
- *
+ *
* @since 7.2
*/
public ComponentConnector getComponent(Element element) {
diff --git a/client/src/com/vaadin/client/ui/VNativeButton.java b/client/src/com/vaadin/client/ui/VNativeButton.java
index 93d8d958d6..8e0dd2bce1 100644
--- a/client/src/com/vaadin/client/ui/VNativeButton.java
+++ b/client/src/com/vaadin/client/ui/VNativeButton.java
@@ -104,7 +104,9 @@ public class VNativeButton extends Button implements ClickHandler {
}
clickPending = false;
} else if (event.getTypeInt() == Event.ONFOCUS) {
- if (BrowserInfo.get().isIE() && clickPending) {
+ if (BrowserInfo.get().isIE()
+ && BrowserInfo.get().getBrowserMajorVersion() < 11
+ && clickPending) {
/*
* The focus event will mess up IE and IE will not trigger the
* mouse up event (which in turn triggers the click event) until
diff --git a/client/src/com/vaadin/client/ui/VOverlay.java b/client/src/com/vaadin/client/ui/VOverlay.java
index d2c3ee2dae..afa13dc337 100644
--- a/client/src/com/vaadin/client/ui/VOverlay.java
+++ b/client/src/com/vaadin/client/ui/VOverlay.java
@@ -444,7 +444,7 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
* A "thread local" of sorts, set temporarily so that VOverlayImpl knows
* which VOverlay is using it, so that it can be attached to the correct
* overlay container.
- *
+ *
* TODO this is a strange pattern that we should get rid of when possible.
*/
protected static VOverlay current;
@@ -881,7 +881,9 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
container.setId(id);
String styles = ac.getUIConnector().getWidget().getParent()
.getStyleName();
- container.addClassName(styles);
+ if (styles != null && !styles.equals("")) {
+ container.addClassName(styles);
+ }
container.addClassName(CLASSNAME_CONTAINER);
RootPanel.get().getElement().appendChild(container);
}
@@ -971,7 +973,7 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
/*
* (non-Javadoc)
- *
+ *
* @see com.google.gwt.user.client.ui.PopupPanel#hide()
*/
@Override
@@ -981,7 +983,7 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
/*
* (non-Javadoc)
- *
+ *
* @see com.google.gwt.user.client.ui.PopupPanel#hide(boolean)
*/
@Override
@@ -1059,4 +1061,4 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
}
}
}
-} \ No newline at end of file
+}
diff --git a/client/src/com/vaadin/client/ui/VPopupCalendar.java b/client/src/com/vaadin/client/ui/VPopupCalendar.java
index 7dea959bb4..1474ad3b71 100644
--- a/client/src/com/vaadin/client/ui/VPopupCalendar.java
+++ b/client/src/com/vaadin/client/ui/VPopupCalendar.java
@@ -145,7 +145,7 @@ public class VPopupCalendar extends VTextualDate implements Field,
}
});
- popup = new VOverlay(true, true, true);
+ popup = new VOverlay(true, false, true);
popup.setOwner(this);
FlowPanel wrapper = new FlowPanel();
diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java
index d88f7426ef..6a1e8664ed 100644
--- a/client/src/com/vaadin/client/ui/VScrollTable.java
+++ b/client/src/com/vaadin/client/ui/VScrollTable.java
@@ -80,6 +80,7 @@ import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorMap;
+import com.vaadin.client.DeferredWorker;
import com.vaadin.client.Focusable;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.StyleConstants;
@@ -126,7 +127,7 @@ import com.vaadin.shared.ui.table.TableConstants;
*/
public class VScrollTable extends FlowPanel implements HasWidgets,
ScrollHandler, VHasDropHandler, FocusHandler, BlurHandler, Focusable,
- ActionOwner, SubPartAware {
+ ActionOwner, SubPartAware, DeferredWorker {
public static final String STYLENAME = "v-table";
@@ -195,6 +196,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/** For internal use only. May be removed or replaced in the future. */
public boolean immediate;
+ private boolean updatedReqRows = true;
+
private boolean nullSelectionAllowed = true;
private SelectMode selectMode = SelectMode.NONE;
@@ -1177,7 +1180,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
@Override
public void execute() {
- if (firstvisible > 0) {
+ if (firstvisible >= 0) {
firstRowInViewPort = firstvisible;
if (firstvisibleOnLastPage > -1) {
scrollBodyPanel
@@ -2251,13 +2254,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Ensures the column alignments are correct at initial loading. <br/>
* (child components widths are correct)
*/
- Scheduler.get().scheduleDeferred(new Command() {
-
- @Override
- public void execute() {
- Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
- }
- });
+ Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement());
hadScrollBars = willHaveScrollbarz;
}
@@ -2398,10 +2395,32 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
// if client connection is busy, don't bother loading it more
VConsole.log("Postponed rowfetch");
schedule(250);
+ } else if (!updatedReqRows && allRenderedRowsAreNew()) {
+
+ /*
+ * If all rows are new, there might have been a server-side call
+ * to Table.setCurrentPageFirstItemIndex(int) In this case,
+ * scrolling event takes way too late, and all the rows from
+ * previous viewport to this one were requested.
+ *
+ * This should prevent requesting unneeded rows by updating
+ * reqFirstRow and reqRows before needing them. See (#14135)
+ */
+
+ setReqFirstRow((firstRowInViewPort - (int) (pageLength * cache_rate)));
+ int last = firstRowInViewPort + (int) (cache_rate * pageLength)
+ + pageLength - 1;
+ if (last >= totalRows) {
+ last = totalRows - 1;
+ }
+ setReqRows(last - getReqFirstRow() + 1);
+ updatedReqRows = true;
+ schedule(250);
} else {
int firstRendered = scrollBody.getFirstRendered();
int lastRendered = scrollBody.getLastRendered();
+
if (lastRendered > totalRows) {
lastRendered = totalRows - 1;
}
@@ -6272,6 +6291,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
public Widget getWidgetForPaintable() {
return this;
}
+
}
protected class VScrollTableGeneratedRow extends VScrollTableRow {
@@ -6720,13 +6740,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
Util.notifyParentOfSizeChange(VScrollTable.this, rendering);
}
}
- Scheduler.get().scheduleDeferred(new Command() {
- @Override
- public void execute() {
- Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
- }
- });
+ Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement());
forceRealignColumnHeaders();
}
@@ -6863,13 +6878,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
// We must run the fix as a deferred command to prevent it from
// overwriting the scroll position with an outdated value, see
// #7607.
- Scheduler.get().scheduleDeferred(new Command() {
-
- @Override
- public void execute() {
- Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
- }
- });
+ Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement());
}
triggerLazyColumnAdjustment(false);
@@ -7014,8 +7023,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return;
}
- if (firstRowInViewPort - pageLength * cache_rate > lastRendered
- || firstRowInViewPort + pageLength + pageLength * cache_rate < firstRendered) {
+ if (allRenderedRowsAreNew()) {
// need a totally new set of rows
rowRequestHandler
.setReqFirstRow((firstRowInViewPort - (int) (pageLength * cache_rate)));
@@ -7026,6 +7034,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
rowRequestHandler.setReqRows(last
- rowRequestHandler.getReqFirstRow() + 1);
+ updatedReqRows = false;
rowRequestHandler.deferRowFetch();
return;
}
@@ -7048,6 +7057,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
}
+ private boolean allRenderedRowsAreNew() {
+ int firstRowInViewPort = calcFirstRowInViewPort();
+ int firstRendered = scrollBody.getFirstRendered();
+ int lastRendered = scrollBody.getLastRendered();
+ return (firstRowInViewPort - pageLength * cache_rate > lastRendered || firstRowInViewPort
+ + pageLength + pageLength * cache_rate < firstRendered);
+ }
+
protected int calcFirstRowInViewPort() {
return (int) Math.ceil(scrollTop / scrollBody.getRowHeight());
}
@@ -7941,4 +7958,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
addCloseHandler.removeHandler();
}
}
+
+ /*
+ * Return true if component need to perform some work and false otherwise.
+ */
+ @Override
+ public boolean isWorkPending() {
+ return lazyAdjustColumnWidths.isRunning();
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VUI.java b/client/src/com/vaadin/client/ui/VUI.java
index df24c3b1c7..eae4f6319d 100644
--- a/client/src/com/vaadin/client/ui/VUI.java
+++ b/client/src/com/vaadin/client/ui/VUI.java
@@ -48,11 +48,12 @@ import com.vaadin.client.Util;
import com.vaadin.client.VConsole;
import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
+import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.ui.ui.UIConstants;
/**
- *
+ *
*/
public class VUI extends SimplePanel implements ResizeHandler,
Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable,
@@ -62,9 +63,6 @@ public class VUI extends SimplePanel implements ResizeHandler,
private static int MONITOR_PARENT_TIMER_INTERVAL = 1000;
/** For internal use only. May be removed or replaced in the future. */
- public String theme;
-
- /** For internal use only. May be removed or replaced in the future. */
public String id;
/** For internal use only. May be removed or replaced in the future. */
@@ -319,19 +317,15 @@ public class VUI extends SimplePanel implements ResizeHandler,
}
}
- public String getTheme() {
- return theme;
- }
-
/**
- * Used to reload host page on theme changes.
- * <p>
- * For internal use only. May be removed or replaced in the future.
+ * @return the name of the theme in use by this UI.
+ * @deprecated as of 7.3. Use {@link UIConnector#getActiveTheme()} instead.
*/
- public static native void reloadHostPage()
- /*-{
- $wnd.location.reload();
- }-*/;
+ @Deprecated
+ public String getTheme() {
+ return ((UIConnector) ConnectorMap.get(connection).getConnector(this))
+ .getActiveTheme();
+ }
/**
* Returns true if the body is NOT generated, i.e if someone else has made
@@ -530,4 +524,5 @@ public class VUI extends SimplePanel implements ResizeHandler,
});
}
}
+
}
diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java
index 1cee727bc9..495e230156 100644
--- a/client/src/com/vaadin/client/ui/VWindow.java
+++ b/client/src/com/vaadin/client/ui/VWindow.java
@@ -1,12 +1,12 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
- *
+ *
* 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
@@ -73,7 +73,7 @@ import com.vaadin.shared.ui.window.WindowRole;
/**
* "Sub window" component.
- *
+ *
* @author Vaadin Ltd
*/
public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
@@ -233,7 +233,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/*
* Stores the element that has focus in the application UI when the
* window is opened, so it can be restored when the window closes.
- *
+ *
* This is currently implemented for the case when one non-modal window
* can be open at the same time, and the focus is not changed while the
* window is open.
@@ -253,7 +253,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/*
* Restores the previously stored focused element.
- *
+ *
* When the focus was changed outside the window while the window was
* open, the originally stored element is restored.
*/
@@ -295,7 +295,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Returns true if this window is the topmost VWindow
- *
+ *
* @return
*/
private boolean isActive() {
@@ -437,7 +437,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* is prevented.
* <p>
* This message is not visible on the screen.
- *
+ *
* @param topMessage
* String provided when the user navigates with Shift-Tab keys to
* the top of the window
@@ -452,7 +452,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* key is prevented.
* <p>
* This message is not visible on the screen.
- *
+ *
* @param bottomMessage
* String provided when the user navigates with the Tab key to
* the bottom of the window
@@ -465,7 +465,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* Gets the message that is provided to users of assistive devices when the
* user reaches the top of the window when leaving a window with the tab key
* is prevented.
- *
+ *
* @return the top message
*/
public String getTabStopTopAssistiveText() {
@@ -476,7 +476,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* Gets the message that is provided to users of assistive devices when the
* user reaches the bottom of the window when leaving a window with the tab
* key is prevented.
- *
+ *
* @return the bottom message
*/
public String getTabStopBottomAssistiveText() {
@@ -554,41 +554,11 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/*
* Shake up the DOM a bit to make the window shed unnecessary
- * scrollbars and resize correctly afterwards. This resulting code
- * took over a week to summon forth, and involved some pretty hairy
- * black magic. Don't touch it unless you know what you're doing!
- * Fixes ticket #11994
+ * scrollbars and resize correctly afterwards. The version fixing
+ * ticket #11994 which was changing the size to 110% was replaced
+ * with this due to ticket #12943
*/
- Scheduler.get().scheduleFinally(new ScheduledCommand() {
- @Override
- public void execute() {
- final com.google.gwt.dom.client.Element scrollable = contents
- .getFirstChildElement();
-
- // Adjusting the width or height may change the scroll
- // position, so store the current position
- int horizontalScrollPosition = scrollable.getScrollLeft();
- int verticalScrollPosition = scrollable.getScrollTop();
-
- final String oldWidth = scrollable.getStyle().getWidth();
- final String oldHeight = scrollable.getStyle().getHeight();
-
- scrollable.getStyle().setWidth(110, Unit.PCT);
- scrollable.getOffsetWidth();
- scrollable.getStyle().setProperty("width", oldWidth);
-
- scrollable.getStyle().setHeight(110, Unit.PCT);
- scrollable.getOffsetHeight();
- scrollable.getStyle().setProperty("height", oldHeight);
-
- // Restore the scroll position
- scrollable.setScrollLeft(horizontalScrollPosition);
- scrollable.setScrollTop(verticalScrollPosition);
-
- updateContentsSize();
- positionOrSizeUpdated();
- }
- });
+ Util.runWebkitOverflowAutoFix(contents.getFirstChildElement());
}
}
@@ -616,7 +586,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Sets the closable state of the window. Additionally hides/shows the close
* button according to the new state.
- *
+ *
* @param closable
* true if the window can be closed by the user
*/
@@ -638,7 +608,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* Returns the closable state of the sub window. If the sub window is
* closable a decoration (typically an X) is shown to the user. By clicking
* on the X the user can close the window.
- *
+ *
* @return true if the sub window is closable
*/
protected boolean isClosable() {
@@ -670,7 +640,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* correctly if clicking on the "close" button in the window header but
* closing the window from a button for example in the window will fail.
* Symptom described in #10776
- *
+ *
* The problematic part is that for the focus to be returned correctly
* an input element needs to be focused in the root panel. Focusing some
* other element apparently won't work.
@@ -902,7 +872,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Setter for the text for assistive devices the window caption is prefixed
* with.
- *
+ *
* @param assistivePrefix
* the assistivePrefix to set
*/
@@ -913,7 +883,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Getter for the text for assistive devices the window caption is prefixed
* with.
- *
+ *
* @return the assistivePrefix
*/
public String getAssistivePrefix() {
@@ -923,7 +893,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Setter for the text for assistive devices the window caption is postfixed
* with.
- *
+ *
* @param assistivePostfix
* the assistivePostfix to set
*/
@@ -934,7 +904,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Getter for the text for assistive devices the window caption is postfixed
* with.
- *
+ *
* @return the assistivePostfix
*/
public String getAssistivePostfix() {
@@ -1086,14 +1056,14 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* TODO check if we need to support this with touch based devices.
- *
+ *
* Checks if the cursor was inside the browser content area when the event
* happened.
- *
+ *
* @param event
* The event to be checked
* @return true, if the cursor is inside the browser content area
- *
+ *
* false, otherwise
*/
private boolean cursorInsideBrowserContentArea(Event event) {
@@ -1382,7 +1352,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* assistive devices when it is opened.
* <p>
* When the provided array is empty, an existing description is removed.
- *
+ *
* @param connectors
* with the connectors of the widgets to use as description
*/
@@ -1420,7 +1390,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* Gets the connectors that are used as assistive description. Text
* contained in these connectors will be read by assistive devices when the
* window is opened.
- *
+ *
* @return list of previously set connectors
*/
public List<Connector> getAssistiveDescription() {
@@ -1429,19 +1399,19 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Sets the WAI-ARIA role the window.
- *
+ *
* This role defines how an assistive device handles a window. Available
* roles are alertdialog and dialog (@see <a
* href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
* Model</a>).
- *
+ *
* The default role is dialog.
- *
+ *
* @param role
* WAI-ARIA role to set for the window
*/
public void setWaiAriaRole(WindowRole role) {
- if ("alertdialog".equals(role)) {
+ if (role == WindowRole.ALERTDIALOG) {
Roles.getAlertdialogRole().set(getElement());
} else {
Roles.getDialogRole().set(getElement());
@@ -1455,7 +1425,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* The value of the parameter doTabStop is stored and used for non-modal
* windows. For modal windows, the handlers are always registered, while
* preserving the stored value.
- *
+ *
* @param doTabStop
* true to prevent leaving the window, false to allow leaving the
* window for non modal windows
@@ -1472,9 +1442,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Adds a Handler for when user moves the window.
- *
+ *
* @since 7.1.9
- *
+ *
* @return {@link HandlerRegistration} used to remove the handler
*/
public HandlerRegistration addMoveHandler(WindowMoveHandler handler) {
diff --git a/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java b/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java
index 78505d034c..8feb349a9e 100644
--- a/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java
+++ b/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java
@@ -28,7 +28,6 @@ import com.vaadin.client.ui.AbstractFieldConnector;
import com.vaadin.client.ui.SimpleManagedLayout;
import com.vaadin.client.ui.VFilterSelect;
import com.vaadin.client.ui.VFilterSelect.FilterSelectSuggestion;
-import com.vaadin.client.ui.menubar.MenuItem;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.combobox.ComboBoxConstants;
import com.vaadin.shared.ui.combobox.ComboBoxState;
@@ -157,7 +156,15 @@ public class ComboBoxConnector extends AbstractFieldConnector implements
}
// handle selection (null or a single value)
- if (uidl.hasVariable("selected")) {
+ if (uidl.hasVariable("selected")
+
+ // In case we're switching page no need to update the selection as the
+ // selection process didn't finish.
+ // && getWidget().selectPopupItemWhenResponseIsReceived ==
+ // VFilterSelect.Select.NONE
+ //
+ ) {
+
String[] selectedKeys = uidl.getStringArrayVariable("selected");
if (selectedKeys.length > 0) {
performSelection(selectedKeys[0]);
@@ -169,12 +176,16 @@ public class ComboBoxConnector extends AbstractFieldConnector implements
if ((getWidget().waitingForFilteringResponse && getWidget().lastFilter
.toLowerCase().equals(uidl.getStringVariable("filter")))
|| popupOpenAndCleared) {
+
getWidget().suggestionPopup.showSuggestions(
getWidget().currentSuggestions, getWidget().currentPage,
getWidget().totalMatches);
+
getWidget().waitingForFilteringResponse = false;
+
if (!getWidget().popupOpenerClicked
&& getWidget().selectPopupItemWhenResponseIsReceived != VFilterSelect.Select.NONE) {
+
// we're paging w/ arrows
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
@@ -222,26 +233,16 @@ public class ComboBoxConnector extends AbstractFieldConnector implements
*/
private void navigateItemAfterPageChange() {
if (getWidget().selectPopupItemWhenResponseIsReceived == VFilterSelect.Select.LAST) {
- getWidget().suggestionPopup.menu.selectLastItem();
+ getWidget().suggestionPopup.selectLastItem();
} else {
- getWidget().suggestionPopup.menu.selectFirstItem();
+ getWidget().suggestionPopup.selectFirstItem();
}
- // This is used for paging so we update the keyboard selection
- // variable as well.
- MenuItem activeMenuItem = getWidget().suggestionPopup.menu
- .getSelectedItem();
- getWidget().suggestionPopup.menu
- .setKeyboardSelectedItem(activeMenuItem);
-
- // Update text field to contain the correct text
- getWidget().setTextboxText(activeMenuItem.getText());
- getWidget().tb.setSelectionRange(
- getWidget().lastFilter.length(),
- activeMenuItem.getText().length()
- - getWidget().lastFilter.length());
-
- getWidget().selectPopupItemWhenResponseIsReceived = VFilterSelect.Select.NONE; // reset
+ // If you're in between 2 requests both changing the page back and
+ // forth, you don't want this here, instead you need it before any
+ // other request.
+ // getWidget().selectPopupItemWhenResponseIsReceived =
+ // VFilterSelect.Select.NONE; // reset
}
private void performSelection(String selectedKey) {
diff --git a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java
index a349eb2993..6f059a7c16 100644
--- a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java
+++ b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java
@@ -87,15 +87,17 @@ public class PopupDateFieldConnector extends TextualDateConnector {
.isShowISOWeekNumbers());
if (getWidget().calendar.getResolution() != getWidget()
.getCurrentResolution()) {
+ boolean hasSelectedDate = false;
getWidget().calendar.setResolution(getWidget()
.getCurrentResolution());
if (getWidget().calendar.getDate() != null
&& getWidget().getCurrentDate() != null) {
+ hasSelectedDate = true;
getWidget().calendar.setDate((Date) getWidget()
.getCurrentDate().clone());
- // force re-render when changing resolution only
- getWidget().calendar.renderCalendar();
}
+ // force re-render when changing resolution only
+ getWidget().calendar.renderCalendar(hasSelectedDate);
}
// Force re-render of calendar if locale has changed (#12153)
diff --git a/client/src/com/vaadin/client/ui/dd/DDUtil.java b/client/src/com/vaadin/client/ui/dd/DDUtil.java
index dfdafe1352..77de1f9b1a 100644
--- a/client/src/com/vaadin/client/ui/dd/DDUtil.java
+++ b/client/src/com/vaadin/client/ui/dd/DDUtil.java
@@ -58,8 +58,7 @@ public class DDUtil {
}
public static HorizontalDropLocation getHorizontalDropLocation(
- Element element, NativeEvent event,
- double leftRightRatio) {
+ Element element, NativeEvent event, double leftRightRatio) {
int clientX = Util.getTouchOrMouseClientX(event);
// Event coordinates are relative to the viewport, element absolute
diff --git a/client/src/com/vaadin/client/ui/dd/DragImageModifier.java b/client/src/com/vaadin/client/ui/dd/DragImageModifier.java
index f08c082a70..45ab5d9bb3 100644
--- a/client/src/com/vaadin/client/ui/dd/DragImageModifier.java
+++ b/client/src/com/vaadin/client/ui/dd/DragImageModifier.java
@@ -20,7 +20,8 @@ import com.google.gwt.dom.client.Element;
/**
* Interface implemented by widgets if the drag image used for drag'n'drop
* requires additional initialization/configuration. The method
- * {@link #modifyDragImage(Element)} is called for each element in the automatically generated drag image.
+ * {@link #modifyDragImage(Element)} is called for each element in the
+ * automatically generated drag image.
*
* @since 7.2
* @author Vaadin Ltd
diff --git a/client/src/com/vaadin/client/ui/menubar/MenuBar.java b/client/src/com/vaadin/client/ui/menubar/MenuBar.java
index b00665e766..726defafd5 100644
--- a/client/src/com/vaadin/client/ui/menubar/MenuBar.java
+++ b/client/src/com/vaadin/client/ui/menubar/MenuBar.java
@@ -38,6 +38,7 @@ import java.util.List;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
@@ -74,6 +75,9 @@ import com.vaadin.client.ui.VOverlay;
public class MenuBar extends Widget implements PopupListener {
private final Element body;
+ private final Element table;
+ private final Element outer;
+
private final ArrayList<MenuItem> items = new ArrayList<MenuItem>();
private MenuBar parentMenu;
private PopupPanel popup;
@@ -98,7 +102,7 @@ public class MenuBar extends Widget implements PopupListener {
public MenuBar(boolean vertical) {
super();
- final Element table = DOM.createTable();
+ table = DOM.createTable();
body = DOM.createTBody();
DOM.appendChild(table, body);
@@ -109,7 +113,7 @@ public class MenuBar extends Widget implements PopupListener {
this.vertical = vertical;
- final Element outer = DOM.createDiv();
+ outer = DOM.createDiv();
DOM.appendChild(outer, table);
setElement(outer);
@@ -324,6 +328,37 @@ public class MenuBar extends Widget implements PopupListener {
return selectedItem;
}
+ /**
+ * Gets the first item from the menu or null if no items.
+ *
+ * @since
+ * @return the first item from the menu or null if no items.
+ */
+ public MenuItem getFirstItem() {
+ return items != null && items.size() > 0 ? items.get(0) : null;
+ }
+
+ /**
+ * Gest the last item from the menu or null if no items.
+ *
+ * @since
+ * @return the last item from the menu or null if no items.
+ */
+ public MenuItem getLastItem() {
+ return items != null && items.size() > 0 ? items.get(items.size() - 1)
+ : null;
+ }
+
+ /**
+ * Gets the index of the selected item.
+ *
+ * @since
+ * @return the index of the selected item.
+ */
+ public int getSelectedIndex() {
+ return items != null ? items.indexOf(getSelectedItem()) : -1;
+ }
+
@Override
protected void onDetach() {
// When the menu is detached, make sure to close all of its children.
@@ -468,6 +503,7 @@ public class MenuBar extends Widget implements PopupListener {
public void selectItem(MenuItem item) {
if (item == selectedItem) {
+ scrollItemIntoView(item);
return;
}
@@ -480,6 +516,74 @@ public class MenuBar extends Widget implements PopupListener {
}
selectedItem = item;
+
+ scrollItemIntoView(item);
+ }
+
+ /*
+ * Scroll the specified item into view.
+ */
+ private void scrollItemIntoView(MenuItem item) {
+ if (item != null) {
+ item.getElement().scrollIntoView();
+ }
+ }
+
+ /**
+ * Scroll the selected item into view.
+ *
+ * @since
+ */
+ public void scrollSelectionIntoView() {
+ scrollItemIntoView(selectedItem);
+ }
+
+ /**
+ * Sets the menu scroll enabled or disabled.
+ *
+ * @since
+ * @param enabled
+ * the enabled state of the scroll.
+ */
+ public void setScrollEnabled(boolean enabled) {
+ if (enabled) {
+ if (vertical) {
+ outer.getStyle().setOverflowY(Overflow.AUTO);
+ } else {
+ outer.getStyle().setOverflowX(Overflow.AUTO);
+ }
+
+ } else {
+ if (vertical) {
+ outer.getStyle().clearOverflowY();
+ } else {
+ outer.getStyle().clearOverflowX();
+ }
+ }
+ }
+
+ /**
+ * Gets whether the scroll is activate for this menu.
+ *
+ * @since
+ * @return true if the scroll is active, otherwise false.
+ */
+ public boolean isScrollActive() {
+ // Element element = getElement();
+ // return element.getOffsetHeight() > DOM.getChild(element, 0)
+ // .getOffsetHeight();
+ int outerHeight = outer.getOffsetHeight();
+ int tableHeight = table.getOffsetHeight();
+ return outerHeight < tableHeight;
+ }
+
+ /**
+ * Gets the preferred height of the menu.
+ *
+ * @since
+ */
+ protected int getPreferredHeight() {
+ return table.getOffsetHeight();
}
/**
diff --git a/client/src/com/vaadin/client/ui/table/TableConnector.java b/client/src/com/vaadin/client/ui/table/TableConnector.java
index 017d1d1024..56b35cce56 100644
--- a/client/src/com/vaadin/client/ui/table/TableConnector.java
+++ b/client/src/com/vaadin/client/ui/table/TableConnector.java
@@ -1,12 +1,12 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
- *
+ *
* 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
@@ -21,7 +21,6 @@ import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Position;
-import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
@@ -65,7 +64,7 @@ public class TableConnector extends AbstractHasComponentsConnector implements
/*
* (non-Javadoc)
- *
+ *
* @see com.vaadin.client.Paintable#updateFromUIDL(com.vaadin.client.UIDL,
* com.vaadin.client.ApplicationConnection)
*/
@@ -122,7 +121,7 @@ public class TableConnector extends AbstractHasComponentsConnector implements
int previousTotalRows = getWidget().totalRows;
getWidget().updateTotalRows(uidl);
- boolean totalRowsChanged = (getWidget().totalRows != previousTotalRows);
+ boolean totalRowsHaveChanged = (getWidget().totalRows != previousTotalRows);
getWidget().updateDragMode(uidl);
@@ -200,7 +199,7 @@ public class TableConnector extends AbstractHasComponentsConnector implements
if (getWidget().headerChangedDuringUpdate) {
getWidget().triggerLazyColumnAdjustment(true);
} else if (!getWidget().isScrollPositionVisible()
- || totalRowsChanged
+ || totalRowsHaveChanged
|| getWidget().lastRenderedHeight != getWidget().scrollBody
.getOffsetHeight()) {
// webkits may still bug with their disturbing scrollbar
@@ -210,13 +209,8 @@ public class TableConnector extends AbstractHasComponentsConnector implements
// by changing overflows as the length of the contents
// *shouldn't* have changed (unless the number of rows
// or the height of the widget has also changed)
- Scheduler.get().scheduleDeferred(new Command() {
- @Override
- public void execute() {
- Util.runWebkitOverflowAutoFix(getWidget().scrollBodyPanel
- .getElement());
- }
- });
+ Util.runWebkitOverflowAutoFixDeferred(getWidget().scrollBodyPanel
+ .getElement());
}
} else {
getWidget().initializeRows(uidl, rowData);
@@ -390,7 +384,7 @@ public class TableConnector extends AbstractHasComponentsConnector implements
/**
* Shows a saved row context menu if the row for the context menu is still
* visible. Does nothing if a context menu has not been saved.
- *
+ *
* @param savedContextMenu
*/
public void showSavedContextMenu(ContextMenuDetails savedContextMenu) {
diff --git a/client/src/com/vaadin/client/ui/textarea/TextAreaConnector.java b/client/src/com/vaadin/client/ui/textarea/TextAreaConnector.java
index e406ff5459..e9dc3e1dd7 100644
--- a/client/src/com/vaadin/client/ui/textarea/TextAreaConnector.java
+++ b/client/src/com/vaadin/client/ui/textarea/TextAreaConnector.java
@@ -1,12 +1,12 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
- *
+ *
* 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
@@ -16,6 +16,10 @@
package com.vaadin.client.ui.textarea;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.event.dom.client.MouseUpEvent;
+import com.google.gwt.event.dom.client.MouseUpHandler;
+import com.vaadin.client.Util.CssSize;
import com.vaadin.client.ui.VTextArea;
import com.vaadin.client.ui.textfield.TextFieldConnector;
import com.vaadin.shared.ui.Connect;
@@ -34,4 +38,54 @@ public class TextAreaConnector extends TextFieldConnector {
public VTextArea getWidget() {
return (VTextArea) super.getWidget();
}
+
+ @Override
+ protected void init() {
+ super.init();
+
+ getWidget().addMouseUpHandler(new ResizeMouseUpHandler());
+ }
+
+ /*
+ * Workaround to handle the resize on the mouse up.
+ */
+ private class ResizeMouseUpHandler implements MouseUpHandler {
+
+ @Override
+ public void onMouseUp(MouseUpEvent event) {
+ Element element = getWidget().getElement();
+
+ updateSize(element.getStyle().getHeight(), getState().height,
+ "height");
+ updateSize(element.getStyle().getWidth(), getState().width, "width");
+ }
+
+ /*
+ * Update the specified size on the server.
+ */
+ private void updateSize(String sizeText, String stateSizeText,
+ String sizeType) {
+
+ CssSize stateSize = CssSize.fromString(stateSizeText);
+ CssSize newSize = CssSize.fromString(sizeText);
+
+ if (stateSize == null && newSize == null) {
+ return;
+
+ } else if (newSize == null) {
+ sizeText = "";
+
+ // Else, if the current stateSize is null, just go ahead and set
+ // the newSize, so no check on stateSize is needed.
+
+ } else if (stateSize != null && stateSize.equals(newSize)) {
+ return;
+ }
+
+ getConnection().updateVariable(getConnectorId(), sizeType,
+ sizeText, false);
+ }
+
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java
index 1d2a49cbd1..c88fd23eca 100644
--- a/client/src/com/vaadin/client/ui/ui/UIConnector.java
+++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java
@@ -1,12 +1,12 @@
/*
* Copyright 2000-2014 Vaadin Ltd.
- *
+ *
* 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
@@ -18,6 +18,7 @@ package com.vaadin.client.ui.ui;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.logging.Logger;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
@@ -26,8 +27,10 @@ import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.HeadElement;
import com.google.gwt.dom.client.LinkElement;
import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.dom.client.StyleElement;
import com.google.gwt.dom.client.StyleInjector;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
@@ -51,12 +54,17 @@ import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.Focusable;
import com.vaadin.client.Paintable;
+import com.vaadin.client.ResourceLoader;
+import com.vaadin.client.ResourceLoader.ResourceLoadEvent;
+import com.vaadin.client.ResourceLoader.ResourceLoadListener;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.UIDL;
import com.vaadin.client.VConsole;
import com.vaadin.client.ValueMap;
+import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
+import com.vaadin.client.ui.AbstractConnector;
import com.vaadin.client.ui.AbstractSingleComponentContainerConnector;
import com.vaadin.client.ui.ClickEventHandler;
import com.vaadin.client.ui.ShortcutActionHandler;
@@ -66,6 +74,7 @@ import com.vaadin.client.ui.VUI;
import com.vaadin.client.ui.layout.MayScrollChildren;
import com.vaadin.client.ui.window.WindowConnector;
import com.vaadin.server.Page.Styles;
+import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.ui.ComponentStateUtil;
@@ -80,6 +89,7 @@ import com.vaadin.shared.ui.ui.UIClientRpc;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.shared.ui.ui.UIServerRpc;
import com.vaadin.shared.ui.ui.UIState;
+import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.UI;
@Connect(value = UI.class, loadStyle = LoadStyle.EAGER)
@@ -88,6 +98,8 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
private HandlerRegistration childStateChangeHandlerRegistration;
+ private String activeTheme = null;
+
private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() {
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
@@ -197,14 +209,6 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
getWidget().immediate = getState().immediate;
getWidget().resizeLazy = uidl.hasAttribute(UIConstants.RESIZE_LAZY);
- String newTheme = uidl.getStringAttribute("theme");
- if (getWidget().theme != null && !newTheme.equals(getWidget().theme)) {
- // Complete page refresh is needed due css can affect layout
- // calculations etc
- getWidget().reloadHostPage();
- } else {
- getWidget().theme = newTheme;
- }
// this also implicitly removes old styles
String styles = "";
styles += getWidget().getStylePrimaryName() + " ";
@@ -405,9 +409,6 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
*/
private void injectCSS(UIDL uidl) {
- final HeadElement head = HeadElement.as(Document.get()
- .getElementsByTagName(HeadElement.TAG).getItem(0));
-
/*
* Search the UIDL stream for CSS resources and strings to be injected.
*/
@@ -424,8 +425,7 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
link.setRel("stylesheet");
link.setHref(url);
link.setType("text/css");
- head.appendChild(link);
-
+ getHead().appendChild(link);
// Check if we have CSS string to inject
} else if (cssInjectionsUidl.getTag().equals("css-string")) {
for (Iterator<?> it2 = cssInjectionsUidl.getChildIterator(); it2
@@ -437,8 +437,54 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
}
}
+ /**
+ * Internal helper to get the <head> tag of the page
+ *
+ * @since 7.3
+ * @return the head element
+ */
+ private HeadElement getHead() {
+ return HeadElement.as(Document.get()
+ .getElementsByTagName(HeadElement.TAG).getItem(0));
+ }
+
+ /**
+ * Internal helper for removing any stylesheet with the given URL
+ *
+ * @since 7.3
+ * @param url
+ * the url to match with existing stylesheets
+ */
+ private void removeStylesheet(String url) {
+ NodeList<Element> linkTags = getHead().getElementsByTagName(
+ LinkElement.TAG);
+ for (int i = 0; i < linkTags.getLength(); i++) {
+ LinkElement link = LinkElement.as(linkTags.getItem(i));
+ if (!"stylesheet".equals(link.getRel())) {
+ continue;
+ }
+ if (!"text/css".equals(link.getType())) {
+ continue;
+ }
+ if (url.equals(link.getHref())) {
+ getHead().removeChild(link);
+ }
+ }
+ }
+
public void init(String rootPanelId,
ApplicationConnection applicationConnection) {
+ // Create a style tag for style injections so they don't end up in
+ // the theme tag in IE8-IE10 (we don't want to wipe them out if we
+ // change theme).
+ // StyleInjectorImplIE always injects to the last style tag on the page.
+ if (BrowserInfo.get().isIE()
+ && BrowserInfo.get().getBrowserMajorVersion() < 11) {
+ StyleElement style = Document.get().createStyleElement();
+ style.setType("text/css");
+ getHead().appendChild(style);
+ }
+
DOM.sinkEvents(getWidget().getElement(), Event.ONKEYDOWN
| Event.ONSCROLL);
@@ -448,9 +494,7 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
// the user
root.getElement().setInnerHTML("");
- String themeName = applicationConnection.getConfiguration()
- .getThemeName();
- root.addStyleName(themeName);
+ activeTheme = applicationConnection.getConfiguration().getThemeName();
root.add(getWidget());
@@ -760,4 +804,229 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
getRpcProxy(DebugWindowServerRpc.class).showServerDebugInfo(
serverConnector);
}
+
+ @OnStateChange("theme")
+ void onThemeChange() {
+ final String oldTheme = activeTheme;
+ final String newTheme = getState().theme;
+ final String oldThemeUrl = getThemeUrl(oldTheme);
+ final String newThemeUrl = getThemeUrl(newTheme);
+
+ if (SharedUtil.equals(oldTheme, newTheme)) {
+ // This should only happen on the initial load when activeTheme has
+ // been updated in init.
+
+ if (newTheme == null) {
+ return;
+ }
+
+ // For the embedded case we cannot be 100% sure that the theme has
+ // been loaded and that the style names have been set.
+
+ if (findStylesheetTag(oldThemeUrl) == null) {
+ // If there is no style tag, load it the normal way (the class
+ // name will be added when theme has been loaded)
+ replaceTheme(null, newTheme, null, newThemeUrl);
+ } else if (!getWidget().getParent().getElement()
+ .hasClassName(newTheme)) {
+ // If only the class name is missing, add that
+ activateTheme(newTheme);
+ }
+ return;
+ }
+
+ getLogger().info("Changing theme from " + oldTheme + " to " + newTheme);
+ replaceTheme(oldTheme, newTheme, oldThemeUrl, newThemeUrl);
+ }
+
+ /**
+ * Loads the new theme and removes references to the old theme
+ *
+ * @param oldTheme
+ * The name of the old theme
+ * @param newTheme
+ * The name of the new theme
+ * @param oldThemeUrl
+ * The url of the old theme
+ * @param newThemeUrl
+ * The url of the new theme
+ */
+ private void replaceTheme(final String oldTheme, final String newTheme,
+ String oldThemeUrl, final String newThemeUrl) {
+
+ LinkElement tagToReplace = null;
+
+ if (oldTheme != null) {
+ tagToReplace = findStylesheetTag(oldThemeUrl);
+
+ if (tagToReplace == null) {
+ getLogger()
+ .warning(
+ "Did not find the link tag for the old theme ("
+ + oldThemeUrl
+ + "), adding a new stylesheet for the new theme ("
+ + newThemeUrl + ")");
+ }
+ }
+
+ if (newTheme != null) {
+ loadTheme(newTheme, newThemeUrl, tagToReplace);
+ } else {
+ if (tagToReplace != null) {
+ tagToReplace.getParentElement().removeChild(tagToReplace);
+ }
+
+ activateTheme(null);
+ }
+
+ }
+
+ /**
+ * Finds a link tag for a style sheet with the given URL
+ *
+ * @since 7.3
+ * @param url
+ * the URL of the style sheet
+ * @return the link tag or null if no matching link tag was found
+ */
+ private LinkElement findStylesheetTag(String url) {
+ NodeList<Element> linkTags = getHead().getElementsByTagName(
+ LinkElement.TAG);
+ for (int i = 0; i < linkTags.getLength(); i++) {
+ final LinkElement link = LinkElement.as(linkTags.getItem(i));
+ if ("stylesheet".equals(link.getRel())
+ && "text/css".equals(link.getType())
+ && url.equals(link.getHref())) {
+ return link;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Loads the given theme and replaces the given link element with the new
+ * theme link element.
+ *
+ * @param newTheme
+ * The name of the new theme
+ * @param newThemeUrl
+ * The url of the new theme
+ * @param tagToReplace
+ * The link element to replace. If null, then the new link
+ * element is added at the end.
+ */
+ private void loadTheme(final String newTheme, final String newThemeUrl,
+ final LinkElement tagToReplace) {
+ LinkElement newThemeLinkElement = Document.get().createLinkElement();
+ newThemeLinkElement.setRel("stylesheet");
+ newThemeLinkElement.setType("text/css");
+ newThemeLinkElement.setHref(newThemeUrl);
+ ResourceLoader.addOnloadHandler(newThemeLinkElement,
+ new ResourceLoadListener() {
+
+ @Override
+ public void onLoad(ResourceLoadEvent event) {
+ getLogger().info(
+ "Loading of " + newTheme + " from "
+ + newThemeUrl + " completed");
+
+ if (tagToReplace != null) {
+ tagToReplace.getParentElement().removeChild(
+ tagToReplace);
+ }
+ activateTheme(newTheme);
+ }
+
+ @Override
+ public void onError(ResourceLoadEvent event) {
+ getLogger().warning(
+ "Could not load theme from "
+ + getThemeUrl(newTheme));
+ }
+ }, null);
+
+ if (tagToReplace != null) {
+ getHead().insertBefore(newThemeLinkElement, tagToReplace);
+ } else {
+ getHead().appendChild(newThemeLinkElement);
+ }
+ }
+
+ /**
+ * Activates the new theme. Assumes the theme has been loaded and taken into
+ * use in the browser.
+ *
+ * @since 7.3
+ * @param newTheme
+ */
+ private void activateTheme(String newTheme) {
+ if (activeTheme != null) {
+ getWidget().getParent().removeStyleName(activeTheme);
+ VOverlay.getOverlayContainer(getConnection()).removeClassName(
+ activeTheme);
+ }
+
+ activeTheme = newTheme;
+
+ if (newTheme != null) {
+ getWidget().getParent().addStyleName(newTheme);
+ VOverlay.getOverlayContainer(getConnection()).addClassName(
+ activeTheme);
+ }
+
+ forceStateChangeRecursively(UIConnector.this);
+ getLayoutManager().forceLayout();
+ }
+
+ /**
+ * Force a full recursive recheck of every connector's state variables.
+ *
+ * @see #forceStateChange()
+ *
+ * @since 7.3
+ */
+ protected static void forceStateChangeRecursively(
+ AbstractConnector connector) {
+ connector.forceStateChange();
+
+ for (ServerConnector child : connector.getChildren()) {
+ if (child instanceof AbstractConnector) {
+ forceStateChangeRecursively((AbstractConnector) child);
+ } else {
+ getLogger().warning(
+ "Could not force state change for unknown connector type: "
+ + child.getClass().getName());
+ }
+ }
+
+ }
+
+ /**
+ * Internal helper to get the theme URL for a given theme
+ *
+ * @since 7.3
+ * @param theme
+ * the name of the theme
+ * @return The URL the theme can be loaded from
+ */
+ private String getThemeUrl(String theme) {
+ return getConnection().translateVaadinUri(
+ ApplicationConstants.VAADIN_PROTOCOL_PREFIX + "themes/" + theme
+ + "/styles" + ".css");
+ }
+
+ /**
+ * Returns the name of the theme currently in used by the UI
+ *
+ * @since 7.3
+ * @return the theme name used by this UI
+ */
+ public String getActiveTheme() {
+ return activeTheme;
+ }
+
+ private static Logger getLogger() {
+ return Logger.getLogger(UIConnector.class.getName());
+ }
+
}