2011-08-18 105 views
1

我有一个网页服务器是在“virtualcasa1”域打开一个模态对话框:的SharePoint:commonModalDialogClose不会关闭跨域对话

var options = { 
    title: "Repro", 
    width: 400, 
    height: 600, 
    url: http://domain2:999/sites/blank/_layouts/XDomainTest/XDomainTestTarget.aspx //[1] 
    //url: http://virtualcasa1/sites/blank/_layouts/XDomainTest/XDomainTestTarget.aspx [2] 
}; 
SP.UI.ModalDialog.showModalDialog(options); 

而且我有这样的代码,将其关闭:

alert(document.domain); 
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancelled clicked'); 

如果两者都在同一个域中(上面的情况[2]),对话框关闭,没有问题。

但是 - 如果目标页面的对话框中托管的(情况[1]以上),对话框不会关闭:-(

上述document.domain的表示在页面存在正确的域

我怀疑我在这里面临的一个跨域问题(废话),但如何解决它还是我错了,问题不XDomain相关

感谢很多

回答

0

我有完全一样的问题?!​​ - 打开一个项目的视图页面的对话框在从站点公司打开时工作正常在同一个网络应用程序/域中选择,但在从单独的Web应用程序中托管的网站集中打开相同的项目时,“关闭”按钮无法工作。我假设它是一个跨域的东西,所以我已经改变了解决方案以适应这个限制,但是,我并不是100%满意,因为它确实使整体解决方案在用户使用时有点尴尬,透视。由于项目时间表的原因,我已经将问题放在了一边,但我仍然很好奇为什么。我能想到的唯一的事情就是整个跨域的事情,并且可能是通过设计来防止XSS安全漏洞。

3

HTML5的postMessage是你的答案。

function listener(event) { 
    //alert(event.data); 
    if (event.data == 'Cancel') { 
    SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancel clicked'); 
    } 
    else { 
    SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, event.data); 
    } 
} 

if (window.addEventListener) { 
    addEventListener("message", listener, false) 
} else { 
    attachEvent("onmessage", listener) 
} 

JavaScript来确定,在弹出取消按钮:从

<input type="button" value="OK" onclick="parent.postMessage('Message to be displayed by the parent', '*');" class="ms-ButtonHeightWidth" /> 
<input type="button" value="Cancel" onclick="parent.postMessage('Cancel', '*');" class="ms-ButtonHeightWidth" /> 
0

阿贾伊的回答

https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage

发起的对话必须有以下的javascript你的父窗口2014年8月1日是好的,但它需要更多的解释。未能关闭对话框的原因很简单。现代浏览器的跨站点脚本安全功能不允许使用一些东西,其中之一是在框架窗口内使用window.frameElement。这是窗口对象的只读属性,它被设置为null(或者用IE,当你试图访问它时,它实际上会引发异常)。模态对话框中的普通的Cancel事件处理程序以对window.frameElement.cancelPopup()的调用结束。这当然会失败。 Save在服务器端工作的普通保存处理程序导致SharePoint将单行作为替换文档发送回来,该替换文档是调用window.frameElement.commitPopup()的scriptlet。这也是行不通的,这是一个真正的痛苦,因为页面已经被重新加载,并且没有脚本可用于处理任何事情。 XSS不会让我们访问调用页面中的框架DOM。

为了使跨域托管窗体无缝工作,您需要将脚本添加到打开对话框的页面和框架页面。在打开对话框的页面中,按照Ajay的建议设置消息侦听器。在框架表单页面中,您需要如下所示的内容:

(function() { 
    $(document).ready(function() { 
     var frameElement = null; 
     // Try/catch to overcome IE Access Denied exception on window.frameElement 
     try { 
      frameElement = window.frameElement; 
     } catch (Exception) {} 

     // Determine that the page is hosted in a dialog from a different domain 
     if (window.parent && !frameElement) { 
      // Set the correct height for #s4-workspace 
      var frameHeight = $(window).height(); 
      var ribbonHeight = $('#s4-ribbonrow').height(); 
      $('#s4-workspace').height(frameHeight - ribbonHeight); 

      // Finds the Save and Cancel buttons and hijacks the onclick 
      function applyClickHandlers(theDocument) { 
       $(theDocument).find('input[value="Cancel"]').removeAttr('onclick').on('click', doTheClose); 
       $(theDocument).find('a[id="Ribbon.ListForm.Edit.Commit.Cancel-Large"]').removeAttr('onclick').removeAttr('href').on('click', doTheClose); 
       $(theDocument).find('input[value="Save"]').removeAttr('onclick').on('click', doTheCommit); 
       $(theDocument).find('a[id="Ribbon.ListForm.Edit.Commit.Publish-Large"]').removeAttr('onclick').removeAttr('href').on('click', doTheCommit); 
      } 

      // Function to perform onclick for Cancel 
      function doTheClose(evt) { 
       evt.preventDefault(); 
       parent.postMessage('Cancel', '*'); 
      } 

      // Function to perform onclick for Save 
      function doTheCommit(evt) { 
       evt.preventDefault(); 

       if (!PreSaveItem()) return false; 
       var targetName = $('input[value="Save"]').attr('name'); 
       var oldOnSubmit = WebForm_OnSubmit; 
       WebForm_OnSubmit = function() { 
        var retVal = oldOnSubmit.call(this); 
        if (retVal) { 
         var theForm = $('#aspnetForm'); 
         // not sure whether following line is needed, 
         // but doesn't hurt 
         $('#__EVENTTARGET').val(targetName); 
         var formData = new FormData(theForm[0]); 
         $.ajax(
         { 
          url: theForm.attr('action'), 
          data: formData, 
          cache: false, 
          contentType: false, 
          processData: false, 
          method: 'POST', 
          type: 'POST', // For jQuery < 1.9 
          success: function(data, status, transport) { 
           console.log(arguments); 
           // hijack the response if it's just script to 
           // commit the popup (which will break) 
           if (data.startsWith('<script') && 
            data.indexOf('.commitPopup()') > -1) 
           { 
            parent.postMessage('OK', '*'); 
            return; 
           } 

           // popup not being committed, so actually 
           // submit the form and replace the page. 
           theForm.submit(); 
          } 
         }).fail(function() { 
          console.log('Ajax post failed.'); 
          console.log(arguments); 
         }); 
        } 

        return false; 
       } 
       WebForm_DoPostBackWithOptions(
        new WebForm_PostBackOptions(targetName, 
               "", 
               true, 
               "", 
               "", 
               false, 
               true) 
       ); 
       WebForm_OnSubmit = oldOnSubmit; 
      } 

      applyClickHandlers(document); 
     } 
    }); 
})(); 

此解决方案利用了我们组织广泛使用的jQuery库。这是我们首选的框架(由我选择)。我相信有人很聪明可以在没有这种依赖的情况下重写,但这是一个很好的起点。我希望有人发现它很有用,因为它代表了两天的工作。有些事情要注意:

SharePoint会对页面上的各种事件进行回发,包括将页面置于编辑模式。因此,在表单和功能区中捕获特定按钮点击更有意义,而不是全面重新定义全局WebForm_OnSubmit函数。我们简单地覆盖保存点击,然后将其设置回来。

在任何保存点击事件中,我们打败了表单的正常发布,并使用AJAX将其替换为相同的POST请求。这使我们能够在表单成功发布时放弃返回的scriptlet。当表单提交不成功时,可能是因为需要空白值,我们只是正确发布表单以允许更新页面。这很好,因为表单不会被处理。此解决方案的早期版本将生成的HTML文档替换为所有页面内容,但Internet Explorer不喜欢这样。

FormData API允许我们post the form as multipart-mime。这个api至少在所有现代浏览器中都有基本的支持,并且对于较老的浏览器有解决方法。

在跨域托管对话框中似乎失败的另一件事是滚动内容窗口。无论出于何种原因,使用id s4-workspace的div的高度设置不正确,因此我们也在解决方案中设置了该高度。编辑: 差点忘了。您可能还需要将此控件添加到您的框架ASPX页面,它可以与SharePoint设计来完成:

< WebPartPages:AllowFraming RUNAT =“服务器”/>