阿贾伊的回答
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 =“服务器”/>