【问题标题】:How to open a pop-up using JSF without it being blocked by the browser如何使用 JSF 打开弹出窗口而不被浏览器阻止
【发布时间】:2016-12-10 09:14:27
【问题描述】:

我正在开发 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();
}

【问题讨论】:

  • 这与 JSF 或 PrimeFaces 无关。这是一个纯粹的客户端 html 问题。在这种情况下最好使用 PrimeFaces 对话框
  • 我使用纯 HTML / JS 开发了脚本。它在那里工作。将调用粘贴到控制台也可以。当然,您不能为此“责备” JSF,但我希望有一个“解决方法”。在这种情况下,对话框不是选项。内容是从外部站点加载的,它希望与 CSS 混合。
  • 在没有用户交互的情况下从同一页面客户端打开多个弹出窗口/打开新窗口(这是您明确执行的操作)将导致这些响应(是我的经验)可能仅在几个电话。但是我怀疑您在从服务器响应中执行时会直接收到此消息。我看到的一种选择是使用普通的 div 并将其置于屏幕中心并在其中显示req.responseText。但是,如果您特别需要一个新窗口,那么我不会想到什么。
  • 好的,谢谢。我会将我的一些操作逻辑复制到 JavaScript 并读取那里的值,以便我可以使用它onclick。这与我在纯 HTML / JS 中遇到的情况相同。
  • 好好调查!!!

标签: javascript jsf primefaces popup popup-blocker


【解决方案1】:

当您尝试在 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:dialogiframe。首先,如果您使用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();
}

【讨论】:

    【解决方案2】:

    有一个简单的出路。在 ajax 数据提交后打开一个空的 onclick 弹出窗口(由用户直接诱导,因此不会被阻止)并将窗口重定向到更新的模型:

    <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 对象包裹(请参阅问题中的 cmets 和我的答案)。
    猜你喜欢
    • 2015-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    • 2010-11-05
    • 2010-09-05
    • 2011-10-31
    • 1970-01-01
    相关资源
    最近更新 更多