SharePoint: commonModalDialogClose не закрывает междоменный диалог - PullRequest
1 голос
/ 18 августа 2011

У меня есть страница, размещенная в домене 'virtualcasa1', открывающая модальное диалоговое окно:

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?

Большое спасибо!

Ответы [ 3 ]

3 голосов
/ 01 августа 2014

HTML5 postMessage ваш ответ.

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

Ваше родительское окно, которое запускает диалог, должно иметь следующий javascript:

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 для кнопок OK и Отмена во всплывающем окне:

<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 голосов
/ 01 февраля 2018

Ответ Аджая от 1 августа 2014 года хорош, но требует немного большего объяснения.Причина невозможности закрыть диалог проста.Функции безопасности межсайтовых сценариев современных браузеров запрещают несколько вещей, одной из которых является использование window.frameElement из рамочного окна.Это свойство доступно только для чтения в объекте окна, и ему присваивается значение null (или в IE оно фактически выдает исключение при попытке доступа к нему).Обычные обработчики событий Cancel в модальном диалоговом окне завершаются вызовом window.frameElement.cancelPopup ().Это не удастся, конечно.Обычный обработчик Save, где Save работал на стороне сервера, приводит к тому, что SharePoint отправляет обратно одну строку в качестве документа замены, который представляет собой скриптлет для вызова window.frameElement.commitPopup ().Это также не сработает, и это реальная боль, которую нужно преодолеть, потому что страница была перезагружена, и нет сценария для обработки чего-либо.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.Мы кратко переопределяем это при нажатии кнопки «Сохранить», а затем устанавливаем его обратно.

При любом событии нажатия кнопки «Сохранить» мы отменяем нормальное размещение формы и заменяем его идентичным запросом POST с использованием AJAX.Это позволяет нам отказаться от возвращенного скриптлета, когда форма была успешно размещена.Когда отправка формы не удалась, возможно, из-за пустых обязательных значений, мы просто публикуем форму правильно, чтобы позволить странице обновляться.Это нормально, так как форма не будет обработана.Более ранняя версия этого решения взяла полученный HTML-документ и заменила все содержимое страницы, но Internet Explorer это не нравится.

API FormData позволяет опубликовать форму как multipart-mime .Этот API имеет, по крайней мере, базовую поддержку во всех современных браузерах, и есть обходные пути для старых.

Еще одна вещь, которая, по-видимому, не работает в междоменном диалоговом окне, - это прокрутка окна контента.По какой-то причине высота не установлена ​​правильно в div с идентификатором s4-workspace, поэтому мы также установили это в решении.

РЕДАКТИРОВАТЬ: Почти забыл.Вам также может понадобиться добавить этот элемент управления на страницу ASPX в рамке, что можно сделать с помощью SharePoint Designer:

0 голосов
/ 10 ноября 2011

У меня точно такая же проблема - диалоговое окно, открывающее страницу просмотра для элемента, работает нормально при открытии из семейства сайтов в том же веб-приложении / домене, но кнопка Закрыть не работает при открытии того же элемента с сайтаКоллекция размещается в отдельном веб-приложении.Я предполагаю, что это междоменная вещь, поэтому я изменил решение, чтобы приспособиться к этому ограничению, однако я не на 100% доволен этим, так как это делает общее решение немного неудобным для использования пользователем.перспектива.Я отложил проблему в сторону из-за сроков проекта, но мне все еще интересно, почему.Единственное, о чем я могу думать, - это междоменная причина, вызывающая ее, и то, что, возможно, она создана специально для предотвращения дыр в безопасности XSS.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...