Предыстория
Небольшое вступление для понимания “зачем мне это надо”. Так получилось, что организация, в которой я работаю, выпускает несколько продуктов, результатом работы одного из них является HTML документ. Продукты десктопные, и HTML документ приходится открывать в WEB-браузере с локального диска. Всё бы ничего, если бы не ограничения браузеров, которые работают на “движке” Chromium. В моём случае в “хроме” нельзя из одного iframe изменить src другого iframe. Вернее это ограничение можно обойти, если “хром” запустить с ключом: chrome.exe – allow-file-access-from-files. Но, к сожалению, это срабатывает только в том случае, если ни одной копии “хрома” не загружено. Всё это накладывает ограничения или, вернее, неудобства при работе с документами.
Решаем проблему
Позаимствуем понятие instance (экземпляр) у ООП, для простоты описания. Здесь инстанс будет означать окно с документом, либо это окно основного документа, либо окно документа внедренного при помощи iframe.
Далее опишу как это работает.
Имеем 3 инстанса: index.html — основной, стартовый, center.html и bottom.html – внедрённые при помощи iframe.
На самом деле наш документ значительно сложнее, для понимания, привожу пример в конце статьи.
Задача – динамически управлять загрузкой контента в bottomFrame из centerFrame, и в centerFrame из indexLeftPanel. Поскольку два внедренных инстанса напрямую друг с другом ничего сделать не могут, то напишем «диспетчер сообщений» в основном инстансе index.html. Т.е. главный инстанс будет при загрузке «регистрироваться» (на рисунке стрелка № 1) во внедрённом и у них появится возможность обмена сообщениями. Таким образом у внедрённых документов, появляется возможность, управлять другими документами (стрелки №2, 3).
Для начала подгрузим center.html в centerFrame, для этого нажимаем “Change HTML in center frame”.
Тут всё штатно, смена centerFrame.src происходит обычным образом из mainlayout.js, загруженного в index.html, поскольку это происходит в одном инстансе — index.html:
listeners: { click: function () { var mainFrame = document.getElementById("centerFrame"); mainFrame.src = 'layout/center.html'; } }
Для обмена сообщениями между окнами из разных инстансов необходимо проделать ряд телодвижений. Готовим index.html:
<script type="text/javascript"> if (window.addEventListener) { window.addEventListener("message", listener, false); } else { window.attachEvent("onmessage", listener); } function listener(event) { var sO = event.data; if (sO) { if (sO.action == acNavigate) { var iframe = document.getElementById(sO.frame); if (iframe) iframe.src = sO.source; } } } </script>
В функцию function listener(event) будут приходить сообщения из center.html.
Готовим center.html:
<iframe id="centerFrame" src="" width="100%" height="100%" frameborder="0" onload="loadPage_centerFrame()"></iframe> function loadPage_centerFrame() { var centerFrame = document.getElementById("centerFrame"); if (centerFrame) { var sO = sendObject; sO.action = acInit; centerFrame.contentWindow.postMessage(sO, '*'); } }
Этот код должен выполниться в инстансе index.html.
Функция loadPage_centerFrame() выполнится позже назначения обработчика события в инстнсе center.html:
if (window.addEventListener) { window.addEventListener("message", listener, false); } else { window.attachEvent("onmessage", listener); }
Благодаря этому, инстанс center.html получит ссылку на окно index.html и запомнит её в переменную mainWindow:
var mainWindow = null; function listener(event) { mainWindow = event.source; }
Всё готово.
Да, в функцию loadPage_centerFrame() передаётся запись sendObject, на самом деле в прототипе эта запись не используется, в отличии от реальной доки, в которой эта запись служит для передачи служебной информации.
Теперь загрузим bottom.html в bottomFrame кликнув на ссылку “Change HTML in bottom frame” из center.html. При нажатии на ссылку вызывается функция из crossdocmess.js:
function linkclick(frame, link) { if (mainWindow) { var sO = sendObject; sO.action = acNavigate; sO.frame = frame; sO.source = link; mainWindow.postMessage(sO, "*"); } }
При помощи полей записи sendObject можно реализовать различный функционал. В данном примере реализована навигация, т.е. передаём какому внедрённому iframe какой документ назначить.


