1 package org
.argeo
.app
.ux
.js
;
3 import java
.util
.Arrays
;
4 import java
.util
.Locale
;
6 import java
.util
.StringJoiner
;
7 import java
.util
.concurrent
.CompletionStage
;
8 import java
.util
.function
.Function
;
11 * A remote JavaScript view (typically in a web browser) which is tightly
12 * integrated with a local UX part.
14 public interface JsClient
{
21 * Execute this JavaScript on the client side after making sure that the page
22 * has been loaded and the map object has been created.
24 * @param js the JavaScript code, possibly formatted according to
25 * {@link String#format}, with {@link Locale#ROOT} as locale (for
26 * stability of decimal separator, as expected by JavaScript.
27 * @param args the optional arguments of
28 * {@link String#format(String, Object...)}
30 Object
evaluate(String js
, Object
... args
);
33 * Executes this JavaScript without expecting a return value.
35 * @param js the JavaScript code, possibly formatted according to
36 * {@link String#format}, with {@link Locale#ROOT} as locale (for
37 * stability of decimal separator, as expected by JavaScript.
38 * @param args the optional arguments of
39 * {@link String#format(String, Object...)}
41 void execute(String js
, Object
... args
);
43 /** @return the globally usable function name. */
44 String
createJsFunction(String name
, Function
<Object
[], Object
> toDo
);
46 /** Get a global variable name. */
47 public String
getJsVarName(String name
);
50 * Completion stage when the client is ready (typically the page has loaded in
53 CompletionStage
<Boolean
> getReadyStage();
59 default Object
callMethod(String jsObject
, String methodCall
, Object
... args
) {
60 return evaluate(jsObject
+ '.' + methodCall
, args
);
63 default void executeMethod(String jsObject
, String methodCall
, Object
... args
) {
64 execute(jsObject
+ '.' + methodCall
, args
);
67 default boolean isInstanceOf(String reference
, String jsClass
) {
68 return (Boolean
) evaluate(getJsVarName(reference
) + " instanceof " + jsClass
);
75 static String
toJsValue(Object o
) {
76 if (o
instanceof CharSequence
)
77 return '\'' + o
.toString() + '\'';
78 else if (o
instanceof Number
)
80 else if (o
instanceof Boolean
)
82 else if (o
instanceof Map map
)
84 else if (o
instanceof Object
[] arr
)
85 return toJsArray(arr
);
86 else if (o
instanceof int[] arr
)
87 return toJsArray(arr
);
88 else if (o
instanceof long[] arr
)
89 return toJsArray(arr
);
90 else if (o
instanceof double[] arr
)
91 return toJsArray(arr
);
92 else if (o
instanceof AbstractJsObject jsObject
) {
94 return jsObject
.newJs();
96 return jsObject
.getJsReference();
97 } else if (o
instanceof JsReference jsReference
) {
98 return jsReference
.get();
100 return '\'' + o
.toString() + '\'';
103 static String
toJsArgs(Object
... arr
) {
104 StringJoiner sj
= new StringJoiner(",");
105 for (Object o
: arr
) {
106 sj
.add(toJsValue(o
));
108 return sj
.toString();
111 static String
toJsArray(Object
... arr
) {
112 StringJoiner sj
= new StringJoiner(",", "[", "]");
113 for (Object o
: arr
) {
114 sj
.add(toJsValue(o
));
116 return sj
.toString();
119 static String
toJsArray(String
... arr
) {
120 return toJsArray((Object
[]) arr
);
123 static String
toJsArray(double... arr
) {
124 return Arrays
.toString(arr
);
127 static String
toJsArray(long... arr
) {
128 return Arrays
.toString(arr
);
131 static String
toJsArray(int... arr
) {
132 return Arrays
.toString(arr
);
135 static String
toJsMap(Map
<?
, ?
> map
) {
136 StringJoiner sj
= new StringJoiner(",", "{", "}");
137 // TODO escape forbidden characters
138 for (Object key
: map
.keySet()) {
139 sj
.add("'" + key
+ "':" + toJsValue(map
.get(key
)));
141 return sj
.toString();
144 static String
escapeQuotes(String str
) {
145 return str
.replace("'", "\\'").replace("\"", "\\\"");