2016-08-04 105 views
1

我正在使用PrimeFaces 6.0,JSF 2.2(Mojarra 2.2.7)应用程序。如何使用JSF打开弹出窗口而不会被浏览器阻止

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

我试图在两种不同的方式这样做:

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

呼叫被执行,呼叫是正确的,但我碰到我的浏览器(铬)弹出窗口拦截两种方式:

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(); 
} 
+0

这与JSF或PrimeFaces无关。这是一个纯粹的客户端html问题。在这种情况下最好使用PrimeFaces对话框 – Kukeltje

+0

我使用纯HTML/JS开发了该脚本。它在那里工作。将调用粘贴到控制台也可以。当然,你不能“责怪”JSF,但我希望有一个“解决方法”。在这种情况下,对话框不可选。内容从外部网站加载,并希望CSS混合。 –

+1

在没有用户交互的情况下从同一页面客户端打开多个弹出窗口/打开新窗口(这是您明确要做的)将导致这些响应(是我的经验)可能只是在几次呼叫之后。但是我怀疑你从服务器响应中直接得到这条消息。我看到的一个选择是使用普通的div并将其居中在屏幕上,并在其中显示“req.responseText”。但是,如果你特别需要一个新窗口,那么我不会想到一些事情。 – Kukeltje

回答

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按钮。但黑客的数量变得太多了。

我选择使用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(); 
} 
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'; 
} 
+0

你有试过吗?当我使用'onclick'时,它用PrimeFaces对象包装(请参阅问题和我的答案中的注释)。 –

相关问题