如何使用JSF打开弹出窗口而不会被浏览器阻止
我正在使用PrimeFaces 6.0,JSF 2.2(Mojarra 2.2.7)应用程序。如何使用JSF打开弹出窗口而不会被浏览器阻止
我需要从外部网站加载网页并突出显示一个DOM节点。我的方法是创建一个JavaScript函数来打开弹出窗口,通过servlet加载网页(以避免跨域问题)并突出显示节点。我发送给我的函数的参数是在托管bean中生成的。
我试图在两种不同的方式这样做:
- 在我的行动使用
RequestContext.getCurrentInstance().execute("myFunction(...)")
(是的,我使用PrimeFaces)。 - 在我的命令按钮上使用
oncomplete="#{myBean.myJsCall}"
。
呼叫被执行,呼叫是正确的,但我碰到我的浏览器(铬)弹出窗口拦截两种方式:
有没有办法打开弹出窗口在JSF中还是专门在PrimeFaces中不被阻止?
这并不真正相关,但这是我的JavaScript函数的简化版本。
我使用纯HTML和JS开发了这个脚本。它在那里打开弹出式窗口而没有阻挡者干扰。另外,在运行JSF应用程序时将调用粘贴到控制台时,弹出窗口会打开。
function myFunction(url, selector) {
var popup = window.open("", "popup", "height=500,width=700");
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.onreadystatechange = function() {
if (req.readyState === XMLHttpRequest.DONE) {
popup.document.open();
popup.document.write(req.responseText);
popup.document.close();
popup.document.addEventListener(
"DOMContentLoaded",
function() { /* Some code highlighting the selector */ },
false
);
}
}
req.send();
}
当您尝试打开在JavaScript中,不直接由用户触发的动作(如点击)一个新的窗口,但在例如回调触发执行JSF Ajax请求后,它被封锁浏览器。
在下列问题中描述了此行为:jquery window.open in ajax success being blocked。
作为解决方法,您可以在JSF ajax请求之前打开一个窗口。在使用JSF HTML标签可以做到这一点,通过使用命令按钮的情况下:
<h:commandButton ... onclick="prepareWindow()"/>
的onclick
将呈现为是。但是,如果你正在使用PrimeFaces,你不能使用:
<p:commandButton ... onclick="prepareWindow()"/>
PrimeFaces包装造成的间接执行onclick
,所以弹出被阻止。
无论如何,有了一些额外的黑客,你可以用某种按钮看起来像PrimeFaces按钮。但黑客的数量变得太多了。
我选择使用p:dialog
而不是iframe
。首先,如果您正在使用p:layout
,请勿将放置在任何布局单元中。
对话框:
<p:dialog header="Preview"
widgetVar="previewDlg" modal="true" width="1000" height="600"
dynamic="true">
<iframe src="about:blank"
class="previewIframe"
style="position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;border:0"></iframe>
</p:dialog>
按钮:
<p:commandButton value="Show"
...
onclick="PF('previewDlg').show()"
action="#{myBean.showPreview('previewIframe')}"/>
行动:
public void showPreview(String iframeClass)
{
...
RequestContext.getCurrentInstance().execute(js);
}
JavaScript函数:
function myFunction(iframeClass, url, selector) {
var iframe = $("iframe[class=" + iframeClass + "]")[0];
iframe.contentDocument.location = "about:blank";
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.onreadystatechange = function() {
if (req.readyState === XMLHttpRequest.DONE) {
iframe.contentDocument.open();
iframe.contentDocument.write(req.responseText);
iframe.contentDocument.close();
iframe.contentDocument.addEventListener(
"DOMContentLoaded",
function() { /* Some code highlighting the selector */ },
false
);
}
}
req.send();
}
有一个简单的出路。打开一个空弹出的onclick(直接由用户,因此不堵塞引起的)和重定向窗口更新后的模型ajax的数据提交后:
<p:commandButton value="open popup" process="@form"
onclick="myNamespace.openPreview()"
oncomplete="myNamespace.relocatePreview()"/>
这是你的JS应该是什么样子:
myNamespace.openPreview = function() {
myNamespace.prev = window.open('', '_blank');
}
myNamespace.relocatePreview = function() {
myNamespace.prev.location = 'preview.xhtml?faces-redirect=true';
}
你有试过吗?当我使用'onclick'时,它用PrimeFaces对象包装(请参阅问题和我的答案中的注释)。 –
这与JSF或PrimeFaces无关。这是一个纯粹的客户端html问题。在这种情况下最好使用PrimeFaces对话框 – Kukeltje
我使用纯HTML/JS开发了该脚本。它在那里工作。将调用粘贴到控制台也可以。当然,你不能“责怪”JSF,但我希望有一个“解决方法”。在这种情况下,对话框不可选。内容从外部网站加载,并希望CSS混合。 –
在没有用户交互的情况下从同一页面客户端打开多个弹出窗口/打开新窗口(这是您明确要做的)将导致这些响应(是我的经验)可能只是在几次呼叫之后。但是我怀疑你从服务器响应中直接得到这条消息。我看到的一个选择是使用普通的div并将其居中在屏幕上,并在其中显示“req.responseText”。但是,如果你特别需要一个新窗口,那么我不会想到一些事情。 – Kukeltje