Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions flow-client/src/main/frontend/Flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,9 @@ export class Flow {
}
params['v-tn'] = themeName;

/* Web Share API support */
params['v-ns'] = !!navigator.share;

/* Stringify each value (they are parsed on the server side) */
const stringParams: Record<string, string> = {};
Object.keys(params).forEach((key) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1387,7 +1387,7 @@ public ExtendedClientDetails getExtendedClientDetails() {
// Create placeholder with default values
extendedClientDetails = new ExtendedClientDetails(ui, null, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null);
null, null, null, null, null, null, null);
}
return extendedClientDetails;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class ExtendedClientDetails implements Serializable {
private String navigatorPlatform;
private ColorScheme.Value colorScheme = ColorScheme.Value.NORMAL;
private String themeName;
private boolean webShareSupported;

/**
* For internal use only. Updates all properties in the class according to
Expand Down Expand Up @@ -104,14 +105,17 @@ public class ExtendedClientDetails implements Serializable {
* the current color scheme
* @param themeName
* the theme name (e.g., "lumo", "aura")
* @param webShareSupported
* whether the browser supports the Web Share API
*/
public ExtendedClientDetails(UI ui, String screenWidth, String screenHeight,
String windowInnerWidth, String windowInnerHeight,
String bodyClientWidth, String bodyClientHeight, String tzOffset,
String rawTzOffset, String dstShift, String dstInEffect,
String tzId, String curDate, String touchDevice,
String devicePixelRatio, String windowName,
String navigatorPlatform, String colorScheme, String themeName) {
String navigatorPlatform, String colorScheme, String themeName,
String webShareSupported) {
this.ui = ui;
if (screenWidth != null) {
try {
Expand Down Expand Up @@ -190,6 +194,9 @@ public ExtendedClientDetails(UI ui, String screenWidth, String screenHeight,
this.navigatorPlatform = navigatorPlatform;
setColorScheme(ColorScheme.Value.fromString(colorScheme));
this.themeName = themeName;
if (webShareSupported != null) {
this.webShareSupported = Boolean.parseBoolean(webShareSupported);
}
}

/**
Expand Down Expand Up @@ -429,6 +436,16 @@ public String getThemeName() {
return themeName;
}

/**
* Returns whether the browser supports the Web Share API
* ({@code navigator.share}).
*
* @return {@code true} if the browser supports the Web Share API
*/
public boolean isWebShareSupported() {
return webShareSupported;
}

/**
* Updates the color scheme. For internal use only.
*
Expand Down Expand Up @@ -491,7 +508,8 @@ public static ExtendedClientDetails fromJson(UI ui, JsonNode json) {
getStringElseNull.apply("v-wn"),
getStringElseNull.apply("v-np"),
getStringElseNull.apply("v-cs"),
getStringElseNull.apply("v-tn"));
getStringElseNull.apply("v-tn"),
getStringElseNull.apply("v-ns"));
}

/**
Expand Down
39 changes: 39 additions & 0 deletions flow-server/src/main/java/com/vaadin/flow/component/page/Page.java
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,45 @@ public void fetchPageDirection(SerializableConsumer<Direction> callback) {
});
}

/**
* Returns whether the browser supports the
* <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Share_API">
* Web Share API</a> ({@code navigator.share}).
*
* @return {@code true} if the browser supports the Web Share API
*/
public boolean isShareSupported() {
return getExtendedClientDetails().isWebShareSupported();
}

/**
* Invokes the browser's native share dialog using the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share"> Web
* Share API</a>.
*
* @param title
* the title to share
* @param text
* the text to share
* @param url
* the URL to share
* @return a pending result that resolves when the share completes or
* rejects if the user cancels or sharing fails
* @throws UnsupportedOperationException
* if the browser does not support the Web Share API
*/
public PendingJavaScriptResult share(String title, String text,
String url) {
if (!isShareSupported()) {
throw new UnsupportedOperationException(
"The browser does not support the Web Share API. "
+ "Check isShareSupported() before calling share().");
}
return executeJs(
"return navigator.share({title: $0, text: $1, url: $2})", title,
text, url);
}

private Direction getDirectionByClientName(String directionClientName) {
return Arrays.stream(Direction.values())
.filter(direction -> direction.getClientName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,10 @@ Please submit an issue to https://github.com/vaadin/flow-components/issues/new/c
if(navigator.platform) {
params['v-np'] = navigator.platform;
}


/* Web Share API support */
params['v-ns'] = !!navigator.share;

/* Stringify each value (they are parsed on the server side) */
Object.keys(params).forEach(function(key) {
var value = params[key];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
class ExtendedClientDetailsTest {

@AfterEach
public void tearDown() {

Check warning on line 33 in flow-server/src/test/java/com/vaadin/flow/component/page/ExtendedClientDetailsTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this 'public' modifier.

See more on https://sonarcloud.io/project/issues?id=vaadin_flow&issues=AZyBJbuSBTV5aL5ZjdPC&open=AZyBJbuSBTV5aL5ZjdPC&pullRequest=23613
CurrentInstance.clearAll();
}

Expand All @@ -56,6 +56,7 @@
assertFalse(details.isIPad());
assertEquals(ColorScheme.Value.LIGHT, details.getColorScheme());
assertEquals("aura", details.getThemeName());
assertTrue(details.isWebShareSupported());

// Don't test getCurrentDate() and time delta due to the dependency on
// server-side time
Expand Down Expand Up @@ -167,14 +168,16 @@
private String navigatorPlatform = "Linux i686";
private String colorScheme = "light";
private String themeName = "aura";
private String webShareSupported = "true";

public ExtendedClientDetails buildDetails() {
return new ExtendedClientDetails(null, screenWidth, screenHeight,
windowInnerWidth, windowInnerHeight, bodyClientWidth,
bodyClientHeight, timezoneOffset, rawTimezoneOffset,
dstSavings, dstInEffect, timeZoneId, clientServerTimeDelta,
touchDevice, devicePixelRatio, windowName,
navigatorPlatform, colorScheme, themeName);
navigatorPlatform, colorScheme, themeName,
webShareSupported);
}

public ExtendBuilder setScreenWidth(String screenWidth) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@
}

@Test
public void addJsModule_rejects_files() {

Check warning on line 243 in flow-server/src/test/java/com/vaadin/flow/component/page/PageTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this 'public' modifier.

See more on https://sonarcloud.io/project/issues?id=vaadin_flow&issues=AZyBJaQIBTV5aL5ZjdOg&open=AZyBJaQIBTV5aL5ZjdOg&pullRequest=23613
try {
page.addJsModule("mod.js");

Expand Down Expand Up @@ -464,20 +464,61 @@
// Set up ExtendedClientDetails with color scheme
ExtendedClientDetails details = new ExtendedClientDetails(mockUI, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, "dark", null);
null, null, null, null, null, "dark", null, null);
mockUI.getInternals().setExtendedClientDetails(details);

Page page = new Page(mockUI);
assertEquals(ColorScheme.Value.DARK, page.getColorScheme());
}

@Test
public void share_passesCorrectJsAndParameters() {
MockUI mockUI = new MockUI();
ExtendedClientDetails details = new ExtendedClientDetails(mockUI, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, "true");
mockUI.getInternals().setExtendedClientDetails(details);

TestPage sharePage = new TestPage(mockUI);
sharePage.share("My Title", "Some text", "https://example.com");

assertEquals("return navigator.share({title: $0, text: $1, url: $2})",
sharePage.expression);
assertEquals("My Title", sharePage.firstParam);
}

@Test
public void share_throwsWhenNotSupported() {
MockUI mockUI = new MockUI();
ExtendedClientDetails details = new ExtendedClientDetails(mockUI, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, "false");
mockUI.getInternals().setExtendedClientDetails(details);

Page sharePage = new Page(mockUI);
assertThrows(UnsupportedOperationException.class,
() -> sharePage.share("title", "text", "url"));
}

@Test
public void isShareSupported_delegatesToExtendedClientDetails() {
MockUI mockUI = new MockUI();
ExtendedClientDetails details = new ExtendedClientDetails(mockUI, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, "true");
mockUI.getInternals().setExtendedClientDetails(details);

Page page = new Page(mockUI);
assertTrue(page.isShareSupported());
}

@Test
public void setColorScheme_updatesGetColorScheme() {
MockUI mockUI = new MockUI();
// Set up ExtendedClientDetails
ExtendedClientDetails details = new ExtendedClientDetails(mockUI, null,
null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null);
null, null, null, null, null, null, null, null);
mockUI.getInternals().setExtendedClientDetails(details);

Page page = new Page(mockUI) {
Expand Down
Loading