«Не надо, я сам»
Хромой Итальянец
Постановка задачи
Предлагается следующий сценарий: заказчик хочет разместить на сайтах своих партнёров небольшой горизонтальный динамический баннер с некой бизнес логикой, несложная калькуляция, табличка, локализация. Помимо этого, требуется всплывающее окно с крупной картинкой и контентом, которые по высоте больше чем родительский баннер.
Сразу дали понять, что партнёры, хоть и партнёры, но размещать у себя что-либо сложное не будут, то есть про jQuery забыли. Стандартное решение – iframe с минимальной функцией resize на голом JavaScript.
Баннер при вызове всплывающего окна:
В качестве backend ASP.NET MVC всё в Azure, картинки в Storage, таблички в SQL. Последнее время Редмонд активно рекомендует в качестве frontend шаблон Bootstrap. Собственно, никто и не против, так как по сравнение с тем, что предлагалось раньше, Bootstrap это просто праздник.
Основная проблема реализации – всплывающее окно из iframe перекрывающее по высоте родителя. На своём сайте можно спокойно вызвать Modal через parent iframe’а, но в данном случает домен у iframe другой и браузер будет защищаться. То есть CORS. Партнёры весело и дружно правящие конфигурации на своих веб серверах постановкой задачи не предполагаются.
Если нельзя трогать партнёрские сайты, то можно трогать наш iframe.
Решение
Костыль: в фоне под открывшимся Modal окошком увечить высоту iframe так, чтобы Modal помещался целиком или почти целиком.
Реализация
На HTML5 API window.postMessage. Есть несколько библиотек на jQuery, декларирующих динамический resize ifram’а. Но, во-первых, это предполагает подключение библиотек на стороне партнёрских сайтов, во-вторых в данной задаче надо совсем немного, а в-третьих, при проверки эти библиотеки не справились с учётом Modal окошка.
HTML нашего iframe’a
<div class="container" id="mainContent">
<div class="row"><h1>Some iframe</h1></div>
…
<a href="#" class="btn btn-default" id="openBtn">Open modal</a>
</div>
<!--Большое Modal окно-->
<div id="myModal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content" id="myModalContent">
…
</div>
</div>
</div>
JavaScript iframe’a onLoad
//Запуск Modal окошка
$('#openBtn').click(function () {
$('#myModal').modal({ show: true })
});
//При открытии Modal окна отправляется сообщение с высотой Modal окна
$('#myModal').on('shown.bs.modal', function (e) {
/*Звёздочку * здесь надо ставить, так как домен партнёрской страницы нам не известен и передаётся не секретная высота окна*/
parent.postMessage($("#myModalContent").height(), "*");
});
//При закрытии Modal окна отправляется сообщение с высотой без Modal окна
$('#myModal').on('hidden.bs.modal', function (e) {
parent.postMessage($("#mainContent").height() + 1, "*");
});
//Установка начальной высоты iframe (+1 – на поля)
parent.postMessage($("#mainContent").height() + 1, "*");
Полный код для iframe на Bootply
HTML на стороне партнёров
<iframe id="myIframe" src="http://bootply.com/render/112265" width="100%" scrolling="no"></iframe>
JavaScript на стороне партнёров вот тут товарищ сделал компактно
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
eventer(messageEvent, function (e) {
//проверка на соответствие домена
if (e.origin !== "http://www.bootply.com")
retrurn;
//непосредственно resize
document.getElementById('myIframe').style.height = e.data + 'px';
}, false);
Полный код на стороне партнёров на Jsfiddle
На Jsfiddle подгружается iframe из Bootply, но Bootply заворачивает в ещё один iframe, который надо убрать (см. рисунок).
Неплохо также добавить общий resize:
$(window).resize(function () {
//но с проверкой на открытый Modal
if ($('#myModal').hasClass('in') == false)
parent.postMessage($("#mainContent").height() + 1, "*");
});