1

我正在开发 PrimeFaces 6.0、JSF 2.2 (Mojarra 2.2.7) 应用程序。

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

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

  1. 在我的行动中使用RequestContext.getCurrentInstance().execute("myFunction(...)")(是的,我正在使用 PrimeFaces)。
  2. oncomplete="#{myBean.myJsCall}"在我的命令按钮上使用。

两种方式都执行调用并且调用都是正确的,但是我遇到了浏览器的(Chromium)弹出窗口阻止程序:

此页面上阻止了以下弹出窗口

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

2 回答 2

2

当您尝试在 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 按钮的按钮来完成这项工作。但是黑客的数量越来越多。

我选择使用 ap: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();
}
于 2016-08-31T08:30:48.470 回答
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';
}
于 2016-10-28T08:22:42.980 回答