-
Notifications
You must be signed in to change notification settings - Fork 187
Implement ClickEvent.getRelativeX() and getRelativeY() methods #21820
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f218078
ce9a405
64d223d
ae3d665
e1ddc6f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
* Copyright 2000-2025 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.flow.component; | ||
|
||
import org.junit.Assert; | ||
import org.junit.Test; | ||
|
||
import com.vaadin.flow.dom.Element; | ||
|
||
public class ClickEventTest { | ||
|
||
@Test | ||
public void serverSideConstructor() { | ||
Component component = new Component(new Element("div")) {}; | ||
ClickEvent<Component> event = new ClickEvent<>(component); | ||
|
||
Assert.assertEquals(component, event.getSource()); | ||
Assert.assertFalse(event.isFromClient()); | ||
|
||
// All coordinates should be -1 for server-side events | ||
Assert.assertEquals(-1, event.getScreenX()); | ||
Assert.assertEquals(-1, event.getScreenY()); | ||
Assert.assertEquals(-1, event.getClientX()); | ||
Assert.assertEquals(-1, event.getClientY()); | ||
Assert.assertEquals(-1, event.getRelativeX()); | ||
Assert.assertEquals(-1, event.getRelativeY()); | ||
|
||
Assert.assertEquals(1, event.getClickCount()); | ||
Assert.assertEquals(-1, event.getButton()); | ||
Assert.assertFalse(event.isCtrlKey()); | ||
Assert.assertFalse(event.isShiftKey()); | ||
Assert.assertFalse(event.isAltKey()); | ||
Assert.assertFalse(event.isMetaKey()); | ||
} | ||
|
||
@Test | ||
public void clientSideConstructor() { | ||
Component component = new Component(new Element("div")) {}; | ||
ClickEvent<Component> event = new ClickEvent<>(component, true, | ||
100, 200, // screen coordinates | ||
150, 250, // client coordinates | ||
10, 20, // relative coordinates | ||
2, // click count | ||
0, // button (left mouse button) | ||
true, false, true, false); // modifier keys | ||
|
||
Assert.assertEquals(component, event.getSource()); | ||
Assert.assertTrue(event.isFromClient()); | ||
|
||
Assert.assertEquals(100, event.getScreenX()); | ||
Assert.assertEquals(200, event.getScreenY()); | ||
Assert.assertEquals(150, event.getClientX()); | ||
Assert.assertEquals(250, event.getClientY()); | ||
Assert.assertEquals(10, event.getRelativeX()); | ||
Assert.assertEquals(20, event.getRelativeY()); | ||
|
||
Assert.assertEquals(2, event.getClickCount()); | ||
Assert.assertEquals(0, event.getButton()); | ||
Assert.assertTrue(event.isCtrlKey()); | ||
Assert.assertFalse(event.isShiftKey()); | ||
Assert.assertTrue(event.isAltKey()); | ||
Assert.assertFalse(event.isMetaKey()); | ||
} | ||
|
||
@Test | ||
public void oldClientSideConstructorBackwardCompatibility() { | ||
Component component = new Component(new Element("div")) {}; | ||
// Test the old constructor without relative coordinates | ||
ClickEvent<Component> event = new ClickEvent<>(component, true, | ||
100, 200, // screen coordinates | ||
150, 250, // client coordinates | ||
2, // click count | ||
0, // button (left mouse button) | ||
true, false, true, false); // modifier keys | ||
|
||
Assert.assertEquals(component, event.getSource()); | ||
Assert.assertTrue(event.isFromClient()); | ||
|
||
Assert.assertEquals(100, event.getScreenX()); | ||
Assert.assertEquals(200, event.getScreenY()); | ||
Assert.assertEquals(150, event.getClientX()); | ||
Assert.assertEquals(250, event.getClientY()); | ||
|
||
// Relative coordinates should be -1 when using old constructor | ||
Assert.assertEquals(-1, event.getRelativeX()); | ||
Assert.assertEquals(-1, event.getRelativeY()); | ||
|
||
Assert.assertEquals(2, event.getClickCount()); | ||
Assert.assertEquals(0, event.getButton()); | ||
Assert.assertTrue(event.isCtrlKey()); | ||
Assert.assertFalse(event.isShiftKey()); | ||
Assert.assertTrue(event.isAltKey()); | ||
Assert.assertFalse(event.isMetaKey()); | ||
} | ||
|
||
@Test | ||
public void relativeCoordinatesAreDistinctFromOtherCoordinates() { | ||
Component component = new Component(new Element("div")) {}; | ||
ClickEvent<Component> event = new ClickEvent<>(component, true, | ||
100, 200, // screen coordinates | ||
150, 250, // client coordinates | ||
10, 20, // relative coordinates (different from screen/client) | ||
1, 0, false, false, false, false); | ||
|
||
// Verify that relative coordinates are different from screen and client coordinates | ||
Assert.assertNotEquals(event.getScreenX(), event.getRelativeX()); | ||
Assert.assertNotEquals(event.getScreenY(), event.getRelativeY()); | ||
Assert.assertNotEquals(event.getClientX(), event.getRelativeX()); | ||
Assert.assertNotEquals(event.getClientY(), event.getRelativeY()); | ||
|
||
// Verify the actual values | ||
Assert.assertEquals(10, event.getRelativeX()); | ||
Assert.assertEquals(20, event.getRelativeY()); | ||
} | ||
Comment on lines
+109
to
+127
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't get the purpose of this test - it compares semantically different coordinates and no doubt they are different if different values are assigned. Requesting to delete this test. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* Copyright 2000-2025 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.flow.uitest.ui; | ||
|
||
import com.vaadin.flow.component.ClickEvent; | ||
import com.vaadin.flow.component.html.Div; | ||
import com.vaadin.flow.component.html.Span; | ||
import com.vaadin.flow.router.Route; | ||
import com.vaadin.flow.uitest.servlet.ViewTestLayout; | ||
|
||
@Route(value = "com.vaadin.flow.uitest.ui.RelativeCoordinatesView", layout = ViewTestLayout.class) | ||
public class RelativeCoordinatesView extends Div { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Create a new test class RelativeCoordinatesIT that uses TestBench API for checking that the "output" element has the expected text (coordinates). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created RelativeCoordinatesIT TestBench test class that verifies the output element contains expected coordinate text after clicking the click area. The test validates the coordinate format and ensures relative coordinates are within reasonable bounds. Committed in e1ddc6f. |
||
|
||
public static final String CLICK_AREA_ID = "click-area"; | ||
public static final String OUTPUT_ID = "output"; | ||
|
||
public RelativeCoordinatesView() { | ||
Div clickArea = new Div(); | ||
clickArea.setId(CLICK_AREA_ID); | ||
clickArea.setText("Click anywhere on this area to see relative coordinates"); | ||
clickArea.getStyle() | ||
.set("background-color", "#f0f0f0") | ||
.set("border", "2px solid #ccc") | ||
.set("padding", "50px") | ||
.set("margin", "20px") | ||
.set("width", "400px") | ||
.set("height", "200px") | ||
.set("cursor", "pointer"); | ||
|
||
Span output = new Span(); | ||
output.setId(OUTPUT_ID); | ||
output.setText("Click on the area above to see coordinates"); | ||
|
||
clickArea.addClickListener(this::handleClick); | ||
|
||
add(clickArea, output); | ||
} | ||
|
||
private void handleClick(ClickEvent<Div> event) { | ||
String coordinates = String.format( | ||
"Screen: (%d, %d), Client: (%d, %d), Relative: (%d, %d)", | ||
event.getScreenX(), event.getScreenY(), | ||
event.getClientX(), event.getClientY(), | ||
event.getRelativeX(), event.getRelativeY() | ||
); | ||
|
||
Span output = (Span) getChildren() | ||
.filter(component -> OUTPUT_ID.equals(component.getId().orElse(""))) | ||
.findFirst() | ||
.orElse(null); | ||
|
||
if (output != null) { | ||
output.setText(coordinates); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/* | ||
* Copyright 2000-2025 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.flow.uitest.ui; | ||
|
||
import org.junit.Assert; | ||
import org.junit.Test; | ||
import org.openqa.selenium.By; | ||
import org.openqa.selenium.WebElement; | ||
|
||
import com.vaadin.flow.testutil.ChromeBrowserTest; | ||
|
||
public class RelativeCoordinatesIT extends ChromeBrowserTest { | ||
|
||
@Test | ||
public void clickShowsRelativeCoordinates() { | ||
open(); | ||
|
||
WebElement clickArea = findElement(By.id(RelativeCoordinatesView.CLICK_AREA_ID)); | ||
WebElement output = findElement(By.id(RelativeCoordinatesView.OUTPUT_ID)); | ||
|
||
// Verify initial state | ||
Assert.assertEquals("Click on the area above to see coordinates", output.getText()); | ||
|
||
// Click on the click area | ||
clickArea.click(); | ||
|
||
// Verify output contains expected coordinate format | ||
String outputText = output.getText(); | ||
Assert.assertTrue("Output should contain coordinate information", | ||
outputText.contains("Screen:") && outputText.contains("Client:") && outputText.contains("Relative:")); | ||
|
||
// Verify the format matches the expected pattern | ||
String expectedPattern = "Screen: \\(\\d+, \\d+\\), Client: \\(\\d+, \\d+\\), Relative: \\(\\d+, \\d+\\)"; | ||
Assert.assertTrue("Output should match coordinate pattern: " + outputText, | ||
outputText.matches(expectedPattern)); | ||
|
||
// Verify relative coordinates are reasonable (non-negative and within bounds) | ||
String[] parts = outputText.split(", Relative: \\("); | ||
if (parts.length >= 2) { | ||
String relativePart = parts[1].replace(")", ""); | ||
String[] coords = relativePart.split(", "); | ||
if (coords.length == 2) { | ||
int relativeX = Integer.parseInt(coords[0]); | ||
int relativeY = Integer.parseInt(coords[1]); | ||
|
||
Assert.assertTrue("Relative X should be non-negative", relativeX >= 0); | ||
Assert.assertTrue("Relative Y should be non-negative", relativeY >= 0); | ||
// The click area has width 400px and height 200px + padding, so coordinates should be reasonable | ||
Assert.assertTrue("Relative X should be within reasonable bounds", relativeX < 600); | ||
Assert.assertTrue("Relative Y should be within reasonable bounds", relativeY < 400); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep the old constructor that doesn't have these two new coordinates parameters and create a new one with these two parameters. This is for backwards compatibility.
The old constructor can delegate to the new one with giving "-1" values to the new fields.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added backward compatibility by keeping the original constructor without relativeX and relativeY parameters. The old constructor delegates to the new one with -1 values for the relative coordinates, ensuring all existing code continues to work unchanged. Committed in ae3d665.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This perhaps not that easy, because
DomEvent
andEventData
require a special single constructor where the framework injects JS values. I.e. having two constructors would not work. This means we have to revert to original version with one constructor and admit that this is a breaking change.