Bootstrap Modal Iframe Костыль


«Не надо, я сам»
Хромой Итальянец

Постановка задачи


Предлагается следующий сценарий: заказчик хочет разместить на сайтах своих партнёров небольшой горизонтальный динамический баннер с некой бизнес логикой, несложная калькуляция, табличка, локализация. Помимо этого, требуется всплывающее окно с крупной картинкой и контентом, которые по высоте больше чем родительский баннер.

Сразу дали понять, что партнёры, хоть и партнёры, но размещать у себя что-либо сложное не будут, то есть про 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, "*");
});


Полноэкранный результат, но надо снова
убрать bootply iframe.



Вывод



HTML5 подарил нам вполне рабочий костыль применимый в живом бизнес сценарии, где конечный пользователь сможет детально изучить предлагаемый ему товар, а торговая федерация заказчика с его партнёрами предположительно повысит динамику накопления фин ресурсов.
Share post

Similar posts

Comments 17

    +2
    Что-то с картинками.
      0
      Уф, трудно сказать, что именно поставило картинки на место, то, что я в 101 раз нажал кнопку пере-опубликовать статью или письмо в поддержку. Но картинки теперь там, где они должны быть.
      +1
      Эпичное у вас название поста :)
        0
        Habrastorage меняет линки на картинки, вообще можно им пользоваться?
          0
            0
            Спасибо, действительно если убрать эти две буквы, то работает, но я уже залил картинки на внешний сторадж, теперь не могу опубликовать, в предпросмотре статьи всё ок, картинки на месте, публикую — на месте, обновляю, ссылки обратно меняются на хабрасторадж с нерабочим адресом. Какой-то мини ад.
              0
              Да и с аватаркой у вас не всё в порядке :)

              Скрытый текст


              Failed to load resource: the server responded with a status of 404 (Not Found)
              http://alpha.hstor.org/storage/habramedia/images/thumbs/avatars/29/90/08/110549/small_110549.jpg
                0
                Да, это как символ проигранной борьбы с картинками. Мне вот интересно по теме ни у кого вопросов нет? Там можно ли сделать, чтобы плавно увеличивалось или про вертикальный вариант.
                  0
                  Основная проблема реализации – всплывающее окно из iframe перекрывающее по высоте родителя. На своём сайте можно спокойно вызвать Modal через parent iframe’а, но в данном случает домен у iframe другой и браузер будет защищаться.

                  Но ведь с помощью postMessage можно послать те же данные в parent, поймать на той стороне сообщение и показать тот самый Modal так же спокойно, или я ошибаюсь? Рассматривался такой вариант? Плюсы — баннер не меняет размер, минусы — нужно тщательно защищать стили модального окна от переопределения их стилями сайта партнёра.
                    +1
                    Вариант рассматривался, но не прошёл по пункту настороженности партнёров, одно дело привычный resize другое дело запуск из скрипта окошек. Хотя плюс запуска Modal, с parent в лице основного окна, конечно манит. Фактически надо сделать полный рендер окошка в строку и этот string передать через postMessage. Отдельной песней пойдёт возврат ввода пользователя из такого Modal.
          0
          Соррь, хотел посмотреть оценку поста, ( ткнул на минус

          Как Вариант можно втыкать данные во фрейм через атрибут name,
          либо через добавку hash к линку фрейма типо:
          'http://habrahabr.ru/post/212347/#'+encodeURIComponent(Данные с сайта)
          Ну или если всё на латинице: 'http://habrahabr.ru/post/212347/#?=param1&=param2&=param3...'
            0
            Ок, спасибо за вариант, в какой именно фрейм предлагается передавать данные в виде параметров URL: на партнёрский сайт, наш iframe или модальное окошко?

            'http://habrahabr.ru/post/212347/#?=param1&=param2&=param3...'

            "#" в предложенном URL идёт как указатель фрагмента схемы? Тогда он должен быть правее блока query (с параметрами):
            'http://habrahabr.ru/post/212347/?field1=value1&field2=value2&field3=value3… #fragment'
              0
              Да вообщем пофег как сделаете, через соль или hash, поскольку такого реального hash не будет, то просто регуляркой вырезать и распарсить параметры во фрейме
              Ну например дано:
              var frameLink = «habrahabr.ru/post/212347/#=param1&=param2&=param3»
              тогда массив параметров:
              var arrParam = ('&'+frameLink.split(/[?#]/ig)[1]).split(/&=/);

                0
                ок ок, меня смутил "?" в начале строки передаваемой через #
            0
            Можно исполнить флешем, которым управлять из фрейма
              0
              Интересно, как примерно будет выглядеть код для запуска Флэш на стороне Партнёрского сайта, который решает проблему CORS?
              0
              Флешу корс пофег, внутри фрейма ставим свой флеш, который связывается с вашей же флешкой, установленной вслед за iframe, а размеры флеша могут меняться
              И имхо во фрейме вроде как размеры флеша могут выходить поверх окна фрейма( но тут не уверен)
              2. Есть хак «alert» для ИЕ ( т.е можно на его основе свое модальное окно выстроить, которое вылазит из фрейма, для остальных браузеров вроде как нельзя…

              Only users with full accounts can post comments. Log in, please.