2011-08-18 103 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 =「服務器」/>