[IE] Получить ссылку на document из Flash player, при загрузке SWF без HTML обёртки
Здрасте!
Сразу начну с объяснения, зачем это надо.
Я поставил себе цель, найти способ запускать флеш сайты без HTML/SWFObject, по моему убеждению, абсолютно лишних обёрток.
Этот способ нашёлся быстро, но в таком случае, разработчик теряет много возможностей, которые были ему доступны через JavaScript. И вот я решил написать набор классов JSInterface, которые работали бы с DOM структурой документа и позволяли создавать JavaScript объекты, и манипулировать ими, подписыватся на JS события и т.д. Во Flash Player действует достаточно суровая политика безопасности, которая позволяет загружать данные с других доменов, только при наличии специального файла crossdomain.xml, а с помощью XmlHTTPRequest, моджно было бы грузить данные откуда угодно(поправьте меня, если я ошибаюсь).
Как я это всё делаю.
Весь код находится в SWF файле, при инициализации JSInterface делает injection в JavaScript среду(обёртку Flash Player'а) посредством ExternalInterface. Внедряются только самые необходимые средства. Но для решения большинства задач, мне необходимо иметь ссылку на объект содержащий информацию о экземпляре Flash Player'а, который находится на данной странице и инициализировал это соединение. Я использую либо document.getElementById или document.getElementsByTagName.
Проблема.
Во все браузерах через ExternalInterface я могу получить доступ к любому объекту доступному через JavaScript. Но в Internet Explorer, если загружать SWF файл напрямую, нет доступа к объекту document и я не знаю, как получить доступ к экземпляру флеш плеера.
Я подготовил специальную флешку, чтоб вы могли посмотреть на окружение и проверить свои теории:
http://actualwave.com/jsi/test.swf
Код флешки такой:
import flash.events.Event;
import flash.text.TextField;
import flash.events.MouseEvent;
import flash.display.SimpleButton;
btn.addEventListener(MouseEvent.CLICK, this.clickHandler);
back.addEventListener(MouseEvent.CLICK, this.backClickHandler);
props.addEventListener(MouseEvent.CLICK, this.propsClickHandler);
txt.text = 'alert(window);';
var list:Array = [];
function clickHandler(e:Event):void{
var str:String = this.txt.text;
list.push(str);
ExternalInterface.call('(function(){'+str+'})()');
}
function backClickHandler(e:Event):void{
if(this.list.length) this.txt.text = list.pop();
}
function propsClickHandler(e:Event):void{
ExternalInterface.call('(function(){var r=\'\';for(var p in '+this.txt.text+'){r += p+\'\\n\';};alert(r);})()');
}
Получается так, что все браузеры при загрузке напрямую SWF файла создают базовую структуру HTML объектов для отображения SWF файла внутри их. Приблезительно она такая:
<html>
<head>
</head>
<body>
<embed width=100% height=100% src="....swf"/>
</body>
</html>
Но Internet Explorer делает это по своему. Он вешает хендлер на window.onload:
function anonymous(){
ObjectLoad();
}
Где вызывается фушкция ObjectLoad:
function ObjectLoad(){
if(objectSource){
objectDestination.outerHTML = "<embed width=100% height=100% fullscreen=yes src=\"" + objectSource + "\" />";
}
}
Получить доступ к свойствам objectSource и objectDestination мне не удалось.
Может кто нибудь из вас, знающих все прелести и нюансы работы с этим браузером, знает как можно получить доступ к нужному объекту?
Если я правильно вас понял, то вы неможете с помощью ЖС достучаться до флешки? Тогда вот код:
function thisMovie(movieName)
{
var isIE = navigator.appName.indexOf("Microsoft") != -1;
return (isIE) ? window[movieName] : document[movieName];
}
var s = thisMovie('idMoveContainer');
Другая проблема, с embed. В IE если я ничего не путаю, он не нужен. Для IE нужно использовать <object>
Я вот так делаю, чтобы работало и "там и сям":
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="https://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="1" height="1" id="zzz2" align="middle"> <param name="allowScriptAccess" value="always" /> <param name="allowFullScreen" value="false" /> <param name="swLiveConnect" value="true"> <param name="movie" value="flash.swf" /> <param name="quality" value="high" /> <param name="bgcolor" value="#ffffff" /> <embed src="flash.swf" quality="high" bgcolor="#ffffff" width="1" height="1" name="zzz2" id="zzz2" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="https://www.macromedia.com/go/getflashplayer" /> </object>
Если генерить это динамически, с помощью JS, то <embed> для IE не нужно генерить, он ругается, и говорит что ошибка. Возможно есть решения этой проблемы, но думаю не так важно это решать, потому что IE всё равно не использует тег <embed>
Михаил, проблема в этом, но Вы не так меня поняли. Суть проблемы в том, что я не использую HTML код для внедрения SWF файла в страничку - SWF файл и есть эта страничка. Поэтому ему не нужны теги OBJECT и EMBED, хотя бы потому, что их некуда вставлять. Если вам интересна эта тема, то можете ещё раз перечитать моё первое сообщение.
А я покопался ещё и обнаружил странный баг - при первой загрузке флешки document НЕ доступен, но стоит обновить страничку(F5) и свойство document становится доступным. И я уже подумал о заклёпке, которая бы обновляла страничку один раз, если document НЕ доступен, есть ли метод аналог кнопки Refresh в IE? Пробовал переопределить window.location.href, но это не даёт такого эффекта.
Вот, я создал ещё одну флешку:
http://actualwave.com/jsi/testdoc.swf - если загорается зелёный, то window.document доступен, если крассный - не доступен.
Ещё, оказалось, что при загрузке SWF файла напрямую, создаётся такая структура документа:
<html>
<head>
<script src="res://mshtml.dll/objectembed.js">
</script>
<script language="javascript">
var objectSource="http://localhost/flex3tests/JSInterfaceTest/test/test.swf";
</script>
</head>
<body onload="ObjectLoad();" leftmargin=0 topmargin=0 scroll=no>
<form id="objectDestination"></form>
</body>
</html>
Функцию ObjectLoad можно посмотреть в первом сообщении.
После её выполнения HTML окружение приобретает такой вид:
<HTML>
<HEAD>
<SCRIPT src="res://mshtml.dll/objectembed.js"></SCRIPT>
<SCRIPT language=javascript>
var objectSource="http://localhost/flex3tests/JSInterfaceTest/test/test.swf";
</SCRIPT>
</HEAD>
<BODY leftMargin=0 topMargin=0 scroll=no onload=ObjectLoad();>
<EMBED src=http://localhost/flex3tests/JSInterfaceTest/test/test.swf width="100%" height="100%" type=application/x-shockwave-flash fullscreen="yes">
</BODY>
</HTML>
Как видите, объект с id=objectDestination удаляется, соответственно пытатся получить к нему доступ бесмысленно. Значит нужно получить доступ либо к объекту window.document, либу к любому узлу DOM структуры документа.
Кстати, я забыл сказать - во флешке
http://actualwave.com/jsi/test.swf
кнопка "Выполнить" просто выполняет код
кнопка "Свойства" выводит все свойства объекта доступные в цикле for...in
кнопка со стрелкой отображает предыдущий запрос.
window[movieName]
ExternalInterface.call("eval", "function somefunc(){}");Если не получается в ИЕ добраться до document то попробуйте это сделать после какогонить таймаута. Как правило помогает.
И также к функциям созданным с помощью флеш ролика, возможно придется обращаться через таймаут, пусть даже и нулевой.
Как довод, можете попробовать в моём тесте выполнить такой код(в IE, естественно):
setTimeout(function(){alert(window["parent"]);}, 50);
выдаёт алерт со строкой [object]
а вот такой код:
setTimeout(function(){alert(window["document"]);}, 50);
Вызывает ошибку "Отказано в доступе".
http://code.google.com/p/jsinterface/
Бесплатный и для коммерческого использования, есть доки на русском.
![[logo]](/site/images/logo.jpg)