You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
691 lines
23 KiB
691 lines
23 KiB
package com.fr.design.jxbrowser; |
|
|
|
import com.fr.concurrent.NamedThreadFactory; |
|
import com.fr.design.DesignerEnvManager; |
|
import com.fr.design.gui.ibutton.UIButton; |
|
import com.fr.design.gui.itoolbar.UIToolbar; |
|
import com.fr.design.i18n.Toolkit; |
|
import com.fr.design.ui.ModernUIConstants; |
|
import com.fr.design.ui.ModernUIPane; |
|
import com.fr.stable.StringUtils; |
|
import com.fr.stable.collections.combination.Pair; |
|
import com.fr.stable.os.OperatingSystem; |
|
import com.fr.web.struct.AssembleComponent; |
|
import com.teamdev.jxbrowser.browser.Browser; |
|
import com.teamdev.jxbrowser.browser.callback.CertificateErrorCallback; |
|
import com.teamdev.jxbrowser.browser.callback.InjectJsCallback; |
|
import com.teamdev.jxbrowser.event.Observer; |
|
import com.teamdev.jxbrowser.frame.Frame; |
|
import com.teamdev.jxbrowser.js.JsObject; |
|
import com.teamdev.jxbrowser.net.callback.BeforeStartTransactionCallback; |
|
import com.teamdev.jxbrowser.view.swing.BrowserView; |
|
import org.jetbrains.annotations.NotNull; |
|
import org.jetbrains.annotations.Nullable; |
|
|
|
import javax.swing.JProgressBar; |
|
import javax.swing.SwingUtilities; |
|
import javax.swing.SwingWorker; |
|
import java.awt.BorderLayout; |
|
import java.awt.Desktop; |
|
import java.util.HashMap; |
|
import java.util.Map; |
|
import java.util.Objects; |
|
import java.util.Optional; |
|
import java.util.concurrent.ExecutionException; |
|
import java.util.concurrent.ExecutorService; |
|
import java.util.concurrent.Executors; |
|
import java.util.function.Consumer; |
|
|
|
import static com.fine.swing.ui.layout.Layouts.cell; |
|
import static com.fine.swing.ui.layout.Layouts.column; |
|
import static com.fine.swing.ui.layout.Layouts.flex; |
|
import static com.fine.swing.ui.layout.Layouts.row; |
|
import static com.fr.design.ui.ModernUIConstants.COMPONENT_TAG; |
|
import static com.fr.design.ui.ModernUIConstants.DEFAULT_EXPRESSION; |
|
import static com.fr.design.ui.ModernUIConstants.DEFAULT_NAMESPACE; |
|
import static com.fr.design.ui.ModernUIConstants.DEFAULT_VARIABLE; |
|
import static com.fr.design.ui.ModernUIConstants.DOT; |
|
import static com.fr.design.ui.ModernUIConstants.EMB_TAG; |
|
import static com.fr.design.ui.ModernUIConstants.SCHEME_HEADER; |
|
import static com.fr.design.ui.ModernUIConstants.WINDOW; |
|
|
|
/** |
|
* 基于v7 jxbrowser 实现 |
|
* 用于加载 html5 的Swing容器,可以在设计选项设置中打开调试窗口, |
|
* 示例可查看:com.fr.design.ui.JxUIPaneTest |
|
* |
|
* @author vito |
|
* @since 11.0 |
|
* Created on 2023-06-12 |
|
*/ |
|
public class JxUIPane<T> extends ModernUIPane<T> { |
|
|
|
public static final ExecutorService DEFAULT_EXECUTOR = |
|
Executors.newSingleThreadExecutor(new NamedThreadFactory("jx-simple", true)); |
|
|
|
/** |
|
* 冒号 |
|
*/ |
|
public static final String COLON = ":"; |
|
private static final String COLON_ESCAPE = "\\:"; |
|
private Browser browser; |
|
private String namespace = "Pool"; |
|
private String variable = "data"; |
|
private String expression = "update()"; |
|
private final JxEngine jxEngine; |
|
private Consumer<Browser> initCallback = null; |
|
|
|
private JxUIPane(JxEngine jxEngine) { |
|
this.jxEngine = jxEngine; |
|
} |
|
|
|
private void initialize(Consumer<Browser> consumer) { |
|
setLayout(new BorderLayout()); |
|
if (browser != null) { |
|
return; |
|
} |
|
hackInITInnovationLinuxDesktop(); |
|
initCallback = consumer; |
|
initDebugIfNeeded(); |
|
asyncInitBrowser(); |
|
} |
|
|
|
/** |
|
* 启动 jxbrowser 引擎,过程包含解压文件等过程,异步操作。 |
|
*/ |
|
private void asyncInitBrowser() { |
|
JProgressBar jProgressBar = showProgressBar(); |
|
new SwingWorker<Browser, Void>() { |
|
|
|
@Override |
|
protected Browser doInBackground() { |
|
browser = jxEngine.getEngine().newBrowser(); |
|
if (jxEngine.isDisableWebSecurity()) { |
|
// 忽略证书验证,兼容有些情况下自定义证书与实际域名不匹配的情况。 |
|
// 虽然不是个正确的方式,但真有这么用的还是兼容一下 |
|
browser.set(CertificateErrorCallback.class, (params, action) -> action.allow()); |
|
} |
|
return browser; |
|
} |
|
|
|
@Override |
|
protected void done() { |
|
jProgressBar.setVisible(false); |
|
try { |
|
Browser mBrowser = get(); |
|
add(BrowserView.newInstance(mBrowser), BorderLayout.CENTER); |
|
if (initCallback != null) { |
|
initCallback.accept(mBrowser); |
|
} |
|
initCallback = null; |
|
revalidate(); |
|
} catch (InterruptedException | ExecutionException e) { |
|
throw new RuntimeException(e); |
|
} |
|
} |
|
}.execute(); |
|
} |
|
|
|
/** |
|
* hack:部分 Linux 信创桌面打开需要先初始化 Desktop |
|
*/ |
|
private static void hackInITInnovationLinuxDesktop() { |
|
if (OperatingSystem.isLinux()) { |
|
Desktop.getDesktop(); |
|
} |
|
} |
|
|
|
/** |
|
* 加载组件时显示一个进度条 |
|
*/ |
|
private @NotNull JProgressBar showProgressBar() { |
|
JProgressBar jProgressBar = new JProgressBar(); |
|
jProgressBar.setIndeterminate(true); |
|
add(row( |
|
flex(), |
|
column(flex(), cell(jProgressBar), flex()), |
|
flex() |
|
).getComponent(), BorderLayout.CENTER); |
|
return jProgressBar; |
|
} |
|
|
|
/** |
|
* 添加自定义XHR请求头,只在自定义引擎下生效, |
|
* 公共引擎暂不支持 |
|
* |
|
* @param headers 自定义头 |
|
*/ |
|
public void addXHRHeaders(Map<String, String> headers) { |
|
warpCallback(browser -> { |
|
if (JxEngine.getInstance() != jxEngine) { |
|
jxEngine.addXHRHeaders(headers); |
|
} |
|
}); |
|
} |
|
|
|
/** |
|
* 异步链式调用 |
|
* |
|
* @param then 后续任务 |
|
*/ |
|
private void warpCallback(Consumer<Browser> then) { |
|
if (initCallback != null) { |
|
initCallback = initCallback.andThen(then); |
|
} else { |
|
then.accept(browser); |
|
} |
|
} |
|
|
|
/** |
|
* 按需初始化debug界面UI |
|
*/ |
|
private void initDebugIfNeeded() { |
|
if (DesignerEnvManager.getEnvManager().isOpenDebug()) { |
|
UIToolbar toolbar = new UIToolbar(); |
|
add(toolbar, BorderLayout.NORTH); |
|
UIButton openDebugButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Open_Debug_Window")); |
|
openDebugButton.addActionListener(e -> browser.devTools().show()); |
|
toolbar.add(openDebugButton); |
|
UIButton reloadButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Reload")); |
|
reloadButton.addActionListener(e -> browser.navigation().reloadIgnoringCache()); |
|
toolbar.add(reloadButton); |
|
UIButton closeButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Close_Window")); |
|
closeButton.addActionListener(e -> SwingUtilities.getWindowAncestor(JxUIPane.this).setVisible(false)); |
|
toolbar.add(closeButton); |
|
} |
|
} |
|
|
|
/** |
|
* 在初始化时进行注入JS的方法,只被build调用 |
|
* |
|
* @param injectJsCallback 回调 |
|
*/ |
|
private void initInjectJs(InjectJsCallback injectJsCallback) { |
|
browser.set(InjectJsCallback.class, params -> { |
|
// 初始化的时候,就把命名空间对象初始化好,确保window.a.b.c("a.b.c"为命名空间)对象都是初始化过的 |
|
params.frame().executeJavaScript(String.format(ModernUIConstants.SCRIPT_INIT_NAME_SPACE, namespace)); |
|
return injectJsCallback.on(params); |
|
}); |
|
} |
|
|
|
/** |
|
* 设置 InjectJsCallback。 |
|
* 这个方法解决重复InjectJsCallback被覆盖的问题。 |
|
* 用于本类内部方法使用,如{@link #populate(Object)} |
|
* |
|
* @param injectJsCallback 回调 |
|
*/ |
|
private synchronized void setInjectJsCallback(InjectJsCallback injectJsCallback) { |
|
Optional<InjectJsCallback> callback = browser.get(InjectJsCallback.class); |
|
if (callback.isPresent()) { |
|
browser.set(InjectJsCallback.class, params -> { |
|
callback.get().on(params); |
|
return injectJsCallback.on(params); |
|
}); |
|
} else { |
|
browser.set(InjectJsCallback.class, injectJsCallback); |
|
} |
|
} |
|
|
|
|
|
/** |
|
* 转向一个新的地址,相当于重新加载 |
|
* |
|
* @param url 新的地址 |
|
*/ |
|
public void redirect(String url) { |
|
warpCallback(browser -> browser.navigation().loadUrl(encodeWindowsPath(url))); |
|
} |
|
|
|
/** |
|
* 转向一个新的地址,相当于重新加载 |
|
* |
|
* @param url 新的地址 |
|
* @param map 初始化参数 |
|
*/ |
|
public void redirect(String url, Map<String, String> map) { |
|
setMap(map); |
|
warpCallback(browser -> browser.navigation().loadUrl(encodeWindowsPath(url))); |
|
} |
|
|
|
private void setMap(Map<String, String> map) { |
|
jxEngine.setMap(map); |
|
} |
|
|
|
private void setComponent(AssembleComponent component) { |
|
jxEngine.setComponent(component); |
|
} |
|
|
|
@Override |
|
protected String title4PopupWindow() { |
|
return "ModernUI7"; |
|
} |
|
|
|
|
|
/** |
|
* 更新数据到界面 |
|
* |
|
* @param t 数据类 |
|
*/ |
|
public void populate(final T t) { |
|
warpCallback(browser -> setInjectJsCallback(params -> { |
|
executeJsObject(params.frame(), WINDOW + DOT + namespace) |
|
.ifPresent(ns -> ns.putProperty(variable, t)); |
|
return InjectJsCallback.Response.proceed(); |
|
})); |
|
} |
|
|
|
@Nullable |
|
public T update() { |
|
if (browser.mainFrame().isPresent()) { |
|
return browser.mainFrame().get().executeJavaScript(WINDOW + DOT + namespace + DOT + expression); |
|
} |
|
return null; |
|
} |
|
|
|
/** |
|
* 关闭浏览器 |
|
*/ |
|
public void disposeBrowser() { |
|
if (browser != null) { |
|
browser.close(); |
|
browser = null; |
|
jxEngine.clearMap(); |
|
jxEngine.clearComponent(); |
|
jxEngine.getEngine().network().remove(BeforeStartTransactionCallback.class); |
|
} |
|
} |
|
|
|
/** |
|
* 清理浏览器缓存 |
|
*/ |
|
public void clearCache() { |
|
if (browser != null) { |
|
browser.engine().httpCache().clear(); |
|
} |
|
} |
|
|
|
/** |
|
* 执行一段js |
|
* |
|
* @param javaScript 待执行的js脚本 |
|
* @see JxUIPane#executeJS(String) |
|
*/ |
|
public void executeJavaScript(String javaScript) { |
|
if (browser != null) { |
|
browser.mainFrame().ifPresent(frame -> frame.executeJavaScript(javaScript)); |
|
} |
|
} |
|
|
|
/** |
|
* 执行一段js |
|
* |
|
* @param javaScript 待执行的js脚本 |
|
* @see JxUIPane#executeJS(String) |
|
*/ |
|
public <T> void executeJavaScript(String javaScript, Consumer<T> consumer) { |
|
if (browser != null) { |
|
browser.mainFrame().ifPresent(frame -> frame.executeJavaScript(javaScript, consumer)); |
|
} |
|
} |
|
|
|
/** |
|
* 获取js对象 |
|
* 注意:类内部使用,用于简化编码,提供 Optional 包装 |
|
* |
|
* @param frame 页面frame对象 |
|
* @param name 变量命名 |
|
* @return js对象 |
|
*/ |
|
private static Optional<JsObject> executeJsObject(Frame frame, String name) { |
|
return Optional.ofNullable(frame.executeJavaScript(name)); |
|
} |
|
|
|
/** |
|
* 执行js脚本并返回,使用范围包含{@link JxUIPane#executeJavaScript(String)},可以代替使用 |
|
* |
|
* @param name 变量命名 |
|
* @return js对象 |
|
*/ |
|
public <P> Optional<P> executeJS(String name) { |
|
if (browser != null) { |
|
Optional<Frame> frame = browser.mainFrame(); |
|
if (frame.isPresent()) { |
|
return Optional.ofNullable(frame.get().executeJavaScript(name)); |
|
} |
|
} |
|
return Optional.empty(); |
|
} |
|
|
|
/** |
|
* 由于自定义scheme目前走的是url,因此路径会被自动转化,比如windows路径下对冒号问题 |
|
* C:\\abc 变成 /C/abc,这里对冒号进行编码转义 |
|
*/ |
|
private static String encodeWindowsPath(String path) { |
|
if (OperatingSystem.isWindows() && path.startsWith(EMB_TAG + SCHEME_HEADER)) { |
|
String s = path.split(EMB_TAG + SCHEME_HEADER)[1]; |
|
return EMB_TAG + SCHEME_HEADER + s.replace(COLON, COLON_ESCAPE); |
|
} |
|
return path; |
|
} |
|
|
|
/** |
|
* JxUIPane 的建造者 |
|
* |
|
* @param <T> 参数 |
|
*/ |
|
public static class Builder<T> extends ModernUIPane.Builder<T> { |
|
private JxEngine jxEngine; |
|
private String namespace; |
|
private String variable; |
|
private String expression; |
|
private InjectJsCallback callback; |
|
|
|
private Pair<Class, Observer> listenerPair; |
|
private final Map<String, Object> namespacePropertyMap; |
|
private final Map<String, Object> propertyMap; |
|
|
|
private final Map<String, PropertyBuild> buildPropertyMap; |
|
private Object variableProperty; |
|
private Map<String, String> parameterMap; |
|
private AssembleComponent component; |
|
private String url; |
|
private String html; |
|
|
|
public Builder() { |
|
// 为了兼容继承关系,但又不允许创建,用这个方式先处理一下 |
|
super((ModernUIPane<T>) null); |
|
this.jxEngine = JxEngine.getInstance(); |
|
this.namespace = DEFAULT_NAMESPACE; |
|
this.variable = DEFAULT_VARIABLE; |
|
this.expression = DEFAULT_EXPRESSION; |
|
this.callback = null; |
|
this.listenerPair = null; |
|
this.namespacePropertyMap = new HashMap<>(); |
|
this.propertyMap = new HashMap<>(); |
|
this.buildPropertyMap = new HashMap<>(); |
|
this.variableProperty = null; |
|
this.parameterMap = null; |
|
this.component = null; |
|
this.url = StringUtils.EMPTY; |
|
this.html = StringUtils.EMPTY; |
|
} |
|
|
|
/** |
|
* 自定义引擎 |
|
* |
|
* @param jxEngine 引擎 |
|
* @return builder |
|
*/ |
|
public Builder<T> engine(JxEngine jxEngine) { |
|
this.jxEngine = jxEngine; |
|
return this; |
|
} |
|
|
|
/** |
|
* 注入一个回调,回调的js会在初始化进行执行 |
|
* |
|
* @param callback 回调 |
|
* @return builder |
|
*/ |
|
public Builder<T> prepare(InjectJsCallback callback) { |
|
this.callback = callback; |
|
return this; |
|
} |
|
|
|
/** |
|
* 注册一个监听器 |
|
* |
|
* @param event 事件 |
|
* @param listener 监听器 |
|
* @return builder |
|
*/ |
|
public JxUIPane.Builder<T> prepare(Class event, Observer listener) { |
|
listenerPair = new Pair<>(event, listener); |
|
return this; |
|
} |
|
|
|
/** |
|
* 加载jar包中的资源 |
|
* |
|
* @param path 资源路径 |
|
*/ |
|
public JxUIPane.Builder<T> withEMB(final String path) { |
|
this.url = EMB_TAG + SCHEME_HEADER + path; |
|
return this; |
|
} |
|
|
|
/** |
|
* 加载jar包中的资源 |
|
* |
|
* @param path 资源路径 |
|
*/ |
|
public JxUIPane.Builder<T> withEMB(final String path, Map<String, String> map) { |
|
this.parameterMap = map; |
|
this.url = EMB_TAG + SCHEME_HEADER + path; |
|
return this; |
|
} |
|
|
|
/** |
|
* 加载url指向的资源 |
|
* |
|
* @param url 文件的地址 |
|
*/ |
|
public JxUIPane.Builder<T> withURL(final String url) { |
|
this.url = url; |
|
return this; |
|
} |
|
|
|
/** |
|
* 加载url指向的资源 |
|
* |
|
* @param url 文件的地址 |
|
*/ |
|
public JxUIPane.Builder<T> withURL(final String url, Map<String, String> map) { |
|
this.parameterMap = map; |
|
this.url = url; |
|
return this; |
|
} |
|
|
|
/** |
|
* 加载Atom组件 |
|
* |
|
* @param component Atom组件 |
|
*/ |
|
public JxUIPane.Builder<T> withComponent(AssembleComponent component) { |
|
return withComponent(component, null); |
|
} |
|
|
|
/** |
|
* 加载Atom组件 |
|
* |
|
* @param component Atom组件 |
|
*/ |
|
public JxUIPane.Builder<T> withComponent(AssembleComponent component, Map<String, String> map) { |
|
this.parameterMap = map; |
|
this.component = component; |
|
this.url = COMPONENT_TAG; |
|
return this; |
|
} |
|
|
|
|
|
/** |
|
* 加载html文本内容 |
|
* |
|
* @param html 要加载html文本内容 |
|
*/ |
|
public JxUIPane.Builder<T> withHTML(String html) { |
|
this.html = html; |
|
return this; |
|
} |
|
|
|
/** |
|
* 设置该前端页面做数据交换所使用的对象 |
|
* 相当于: |
|
* const namespace = "Pool"; |
|
* 调用: |
|
* window[namespace]; |
|
* 默认下结构如: |
|
* window.Pool |
|
* |
|
* @param namespace 对象名 |
|
*/ |
|
public JxUIPane.Builder<T> namespace(String namespace) { |
|
this.namespace = namespace; |
|
return this; |
|
} |
|
|
|
/** |
|
* java端往js端传数据时使用的变量名字 |
|
* 默认值为 data |
|
* 相当于: |
|
* const variable = "data"; |
|
* 调用: |
|
* window[namespace][variable]; |
|
* 默认下结构如: |
|
* window.Pool.data |
|
* |
|
* @param name 变量的名字 |
|
*/ |
|
public JxUIPane.Builder<T> variable(String name) { |
|
this.variable = name; |
|
return this; |
|
} |
|
|
|
/** |
|
* js端往java端传数据时执行的函数表达式 |
|
* |
|
* @param expression 函数表达式 |
|
*/ |
|
public JxUIPane.Builder<T> expression(String expression) { |
|
this.expression = expression; |
|
return this; |
|
} |
|
|
|
/** |
|
* 注入一个java对象到js中,绑定在全局变量window的指定变量variable。 |
|
* variable 可由 {@link #namespace(String)} 设置,默认值为 data |
|
* 这个方法仅在在加载的网页上执行 JavaScript 之前注入 |
|
* 相当于: |
|
* window[namespace][property] = javaObject |
|
* 默认下: |
|
* window.Pool[property] = javaObject |
|
* |
|
* @param obj java对象 |
|
* @return 链式对象 |
|
*/ |
|
public JxUIPane.Builder<T> bindNamespace(String property, @Nullable Object obj) { |
|
this.namespacePropertyMap.put(property, obj); |
|
return this; |
|
} |
|
|
|
/** |
|
* 注入一个java对象到js中,绑定在全局变量window的指定变量variable。 |
|
* variable 可由 {@link #variable(String)} 设置,默认值为 data |
|
* 这个方法仅在在加载的网页上执行 JavaScript 之前注入 |
|
* 相当于: |
|
* window[namespace][variable] = javaObject |
|
* 默认下: |
|
* window.Pool.data = javaObject |
|
* |
|
* @param obj java对象 |
|
* @return 链式对象 |
|
*/ |
|
public JxUIPane.Builder<T> bindVariable(@NotNull Object obj) { |
|
this.variableProperty = obj; |
|
return this; |
|
} |
|
|
|
/** |
|
* 注入一个java对象到js中,绑定在全局变量 window的 |
|
* property指定的变量。这个方法仅在在加载的网页上执 |
|
* 行 JavaScript 之前注入 |
|
* 相当于: |
|
* window[property] = javaObject |
|
* |
|
* @param property 属性 |
|
* @param obj java对象 |
|
* @return 链式对象 |
|
* @see #bindWindow(String, PropertyBuild) |
|
*/ |
|
public JxUIPane.Builder<T> bindWindow(String property, @Nullable Object obj) { |
|
this.propertyMap.put(property, obj); |
|
return this; |
|
} |
|
|
|
/** |
|
* 注入一个java对象到js中。绑定在全局变量 window的property指定的变量。 |
|
* PropertyBuild用于动态生成绑定属性。个方法仅在在加载的网页上执行 |
|
* JavaScript 之前注入 |
|
* 相当于: |
|
* window[property] = javaObject |
|
* |
|
* @param property 属性构建器 |
|
* @param obj java对象 |
|
* @return 链式对象 |
|
* @see #bindWindow(String, Object) |
|
*/ |
|
public JxUIPane.Builder<T> bindWindow(String property, PropertyBuild obj) { |
|
buildPropertyMap.put(property, obj); |
|
return this; |
|
} |
|
|
|
/** |
|
* 构建 |
|
*/ |
|
public JxUIPane<T> build() { |
|
JxUIPane<T> pane = new JxUIPane<>(jxEngine); |
|
pane.namespace = namespace; |
|
pane.variable = variable; |
|
pane.expression = expression; |
|
pane.setMap(parameterMap); |
|
pane.setComponent(component); |
|
pane.initialize(browser -> { |
|
injectJs(pane); |
|
if (!Objects.isNull(listenerPair)) { |
|
browser.navigation().on(listenerPair.getFirst(), listenerPair.getSecond()); |
|
} |
|
if (StringUtils.isNotEmpty(url)) { |
|
browser.navigation().loadUrl(encodeWindowsPath(url)); |
|
} else if (StringUtils.isNotEmpty(html)) { |
|
browser.mainFrame().ifPresent(f -> f.loadHtml(html)); |
|
} |
|
}); |
|
return pane; |
|
} |
|
|
|
/** |
|
* 由于 InjectJsCallback 的回调机制,在初始化期间,只有 |
|
* 在 InjectJsCallback 中 putProperty 才能生效。 |
|
* 因此,嵌套回调分别做默认初始化、putProperty、外置初始化 |
|
*/ |
|
private void injectJs(JxUIPane<T> pane) { |
|
pane.initInjectJs(params -> { |
|
Frame frame = params.frame(); |
|
if (!propertyMap.isEmpty()) { |
|
propertyMap.forEach((key, value) -> |
|
executeJsObject(frame, WINDOW) |
|
.ifPresent(window -> window.putProperty(key, value))); |
|
} |
|
if (!buildPropertyMap.isEmpty()) { |
|
buildPropertyMap.forEach((key, value) -> |
|
executeJsObject(frame, WINDOW) |
|
.ifPresent(window -> window.putProperty(key, value.build(window)))); |
|
} |
|
if (!namespacePropertyMap.isEmpty()) { |
|
namespacePropertyMap.forEach((key, value) -> |
|
executeJsObject(frame, WINDOW + DOT + namespace) |
|
.ifPresent(pool -> pool.putProperty(key, value))); |
|
} |
|
if (variableProperty != null) { |
|
executeJsObject(frame, WINDOW + DOT + namespace) |
|
.ifPresent(pool -> pool.putProperty(variable, variableProperty)); |
|
} |
|
if (callback != null) { |
|
return callback.on(params); |
|
} |
|
return InjectJsCallback.Response.proceed(); |
|
}); |
|
} |
|
} |
|
}
|
|
|