Fixes #10854tags/8.10.0.beta1
@@ -126,15 +126,31 @@ public class ShortcutActionHandler { | |||
target = Util.findPaintable(client, et); | |||
} | |||
final ComponentConnector finalTarget = target; | |||
event.preventDefault(); | |||
/* | |||
* The focused component might have unpublished changes, try to | |||
* synchronize them before firing shortcut action. | |||
*/ | |||
client.flushActiveConnector(); | |||
/* | |||
* Legacy components don't have built-in logic for flushing, they need a | |||
* workaround with blur and focus to trigger the value change. | |||
*/ | |||
ComponentConnector activeConnector = getActiveConnector(client); | |||
if (activeConnector != null) { | |||
Class<?> clz = activeConnector.getClass(); | |||
while (clz != null) { | |||
if (clz.getName().equals( | |||
"com.vaadin.v7.client.ui.AbstractLegacyComponentConnector")) { | |||
shakeTarget(et); | |||
Scheduler.get().scheduleDeferred(() -> { | |||
shakeTarget(et); | |||
}); | |||
break; | |||
} | |||
clz = clz.getSuperclass(); | |||
} | |||
} | |||
Scheduler.get().scheduleDeferred(() -> { | |||
if (finalTarget != null) { | |||
client.updateVariable(paintableId, "actiontarget", finalTarget, | |||
@@ -144,6 +160,26 @@ public class ShortcutActionHandler { | |||
}); | |||
} | |||
/** | |||
* We try to fire value change in the component the key combination was | |||
* typed. E.g. TextField may contain newly typed text that is expected to be | |||
* sent to server before the shortcut action is triggered. This is done by | |||
* removing focus and then returning it immediately back to target element. | |||
* <p> | |||
* This is a hack copied over from V7 in order to keep the compatibility | |||
* classes working. Main V8 classes don't require shaking. | |||
*/ | |||
private static void shakeTarget(final Element e) { | |||
blur(e); | |||
focus(e); | |||
} | |||
private static native ComponentConnector getActiveConnector( | |||
ApplicationConnection ac) | |||
/*-{ | |||
return ac.@com.vaadin.client.ApplicationConnection::getActiveConnector()(); | |||
}-*/; | |||
private static native void blur(Element e) | |||
/*-{ | |||
if (e.blur) { |
@@ -0,0 +1,47 @@ | |||
package com.vaadin.tests.components.datefield; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Date; | |||
import com.vaadin.event.ShortcutAction.KeyCode; | |||
import com.vaadin.event.ShortcutListener; | |||
import com.vaadin.server.VaadinRequest; | |||
import com.vaadin.tests.components.AbstractTestUI; | |||
import com.vaadin.ui.Notification; | |||
import com.vaadin.v7.ui.DateField; | |||
@SuppressWarnings("deprecation") | |||
public class CompatibilityDateFieldShortcut extends AbstractTestUI { | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
String dateFormat = "dd/MM/yyyy"; | |||
DateField dateField = new DateField(); | |||
dateField.setValue(new Date(2018 - 1900, 0, 11)); | |||
dateField.setDateFormat(dateFormat); | |||
dateField.addShortcutListener( | |||
new ShortcutListener("Enter", KeyCode.ENTER, null) { | |||
@Override | |||
public void handleAction(Object sender, Object target) { | |||
SimpleDateFormat df = new SimpleDateFormat(dateFormat); | |||
Notification.show(df.format(dateField.getValue())); | |||
} | |||
}); | |||
addComponent(dateField); | |||
} | |||
@Override | |||
protected String getTestDescription() { | |||
return "Modify the date manually (without using the popup element) and" | |||
+ " then press Enter. The notification should show the modified" | |||
+ " value instead of the old value."; | |||
} | |||
@Override | |||
protected Integer getTicketNumber() { | |||
return 10854; | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
package com.vaadin.tests.components.datefield; | |||
import static org.junit.Assert.assertEquals; | |||
import org.junit.Test; | |||
import org.openqa.selenium.By; | |||
import org.openqa.selenium.Keys; | |||
import org.openqa.selenium.WebElement; | |||
import com.vaadin.testbench.elements.DateFieldElement; | |||
import com.vaadin.testbench.elements.NotificationElement; | |||
import com.vaadin.tests.tb3.SingleBrowserTest; | |||
public class CompatibilityDateFieldShortcutTest extends SingleBrowserTest { | |||
private static final String DATEFIELD_VALUE_ORIGINAL = "11/01/2018"; | |||
private static final String DATEFIELD_VALUE_MODIFIED = "21/01/2018"; | |||
@Test | |||
public void modifyValueAndPressEnter() { | |||
openTestURL(); | |||
DateFieldElement dateField = $(DateFieldElement.class).first(); | |||
WebElement dateFieldText = dateField.findElement(By.tagName("input")); | |||
assertEquals("DateField value should be \"" + DATEFIELD_VALUE_ORIGINAL | |||
+ "\"", DATEFIELD_VALUE_ORIGINAL, dateField.getValue()); | |||
dateFieldText.click(); | |||
dateFieldText.sendKeys(Keys.HOME, Keys.DELETE, "2"); | |||
dateFieldText.sendKeys(Keys.ENTER); | |||
assertEquals("DateField value should be \"" + DATEFIELD_VALUE_MODIFIED | |||
+ "\"", DATEFIELD_VALUE_MODIFIED, dateField.getValue()); | |||
assertEquals(DATEFIELD_VALUE_MODIFIED, | |||
$(NotificationElement.class).first().getCaption()); | |||
} | |||
} |