如何在不被浏览器阻止的情况下使用JSF打开弹出窗口

时间:2016-08-04 09:53:54

标签: javascript jsf primefaces popup popup-blocker

我正在使用PrimeFaces 6.0,JSF 2.2(Mojarra 2.2.7)应用程序。

我需要从外部网站加载网页并突出显示DOM节点。我的方法是创建一个JavaScript函数来打开一个弹出窗口,通过servlet加载网页(以避免跨域问题)并突出显示该节点。我发送给我的函数的参数是在托管bean中生成的。

我尝试以两种不同的方式这样做:

  1. 在我的操作中使用RequestContext.getCurrentInstance().execute("myFunction(...)")(是的,我使用的是PrimeFaces)。
  2. 在我的命令按钮上使用oncomplete="#{myBean.myJsCall}"
  3. 执行呼叫和呼叫都是正确的两种方式,但我遇到了我的浏览器(Chromium)弹出窗口阻止程序:

    The following pop-ups were blocked on this page

    有没有办法在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();
    }
    

2 个答案:

答案 0 :(得分:2)

当您尝试在JavaScript中打开一个新窗口时,该窗口不是由用户操作(如点击)直接触发,而是例如在执行JSF ajax请求后触发的回调,它会被浏览器阻止。 / p>

以下问题描述了此行为: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();
}

答案 1 :(得分:0)

有一个简单的方法。打开一个空的弹出窗口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';
}