Xpoint
   [напомнить пароль]

[IE] Получить ссылку на document из Flash player, при загрузке SWF без HTML обёртки

Метки: [без меток]
2008-10-02 13:42:35 [обр] a_[w][досье]

Здрасте!
Сразу начну с объяснения, зачем это надо.
Я поставил себе цель, найти способ запускать флеш сайты без 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 мне не удалось.

Может кто нибудь из вас, знающих все прелести и нюансы работы с этим браузером, знает как можно получить доступ к нужному объекту?

спустя 5 минут [обр] a_[w][досье]
Извините, оговорился. К свойству objectSource можно получить доступ. Оно возвращает путь к SWF файлу.
спустя 19 часов [обр] Михаил(0/15)[досье]

Если я правильно вас понял, то вы неможете с помощью ЖС достучаться до флешки? Тогда вот код:

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>

спустя 1 час 5 минут [обр] a_[w][досье]

Михаил, проблема в этом, но Вы не так меня поняли. Суть проблемы в том, что я не использую 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
кнопка со стрелкой отображает предыдущий запрос.

спустя 43 минуты [обр] Михаил(0/15)[досье]
Для вашей пробелмы подойдет первый кусок кода, который я привел в своём сообщении. В ИЕ вам не нужно иметь доступ к document, чтобы "достучаться" до флешки. в ИЕ используйте: window[movieName]
спустя 4 часа 28 минут [обр] a_[w][досье]
Михаил, а как мне задать movieName флешке без HTML кода? Или браузер задаёт им сам какие-то значения по умолчанию, в случае их отсутствия?
спустя 1 час 41 минуту [обр] Михаил(0/15)[досье]
Вообще, имея доступ к windows можно добовлять любые JS объекты используя ExternalInterface.call("eval", "function somefunc(){}");
Если не получается в ИЕ добраться до document то попробуйте это сделать после какогонить таймаута. Как правило помогает.
И также к функциям созданным с помощью флеш ролика, возможно придется обращаться через таймаут, пусть даже и нулевой.
спустя 12 минут [обр] a_[w][досье]
Вообще, можно обойтись и без eval. В первом сообщении я привёл AS код тестовой флешки, которая вызывает в JS окружении анонимные функции. В подобной манере я их внедряю в документ. Пробовал через eval, пробовал через динамически заданное имя свойства, через дополнительные JS функции, но window.document не доступен. Таймауты тоже не помогают. Вы сам можете во всём убедиться с помощью http://actualwave.com/jsi/test.swf .
спустя 29 минут [обр] a_[w][досье]

Как довод, можете попробовать в моём тесте выполнить такой код(в IE, естественно):

setTimeout(function(){alert(window["parent"]);}, 50);

выдаёт алерт со строкой [object]
а вот такой код:

setTimeout(function(){alert(window["document"]);}, 50);

Вызывает ошибку "Отказано в доступе".

спустя 9 минут [обр] Михаил(0/15)[досье]
А что возвращает ExternalInterface.objectID ?
спустя 6 часов [обр] a_[w][досье]
Выдаёт null, как и положено.
спустя 1 год 3 месяца [обр] a_[w][досье]
Вот, решил добавить ссылку на проект, который я делал
http://code.google.com/p/jsinterface/
Бесплатный и для коммерческого использования, есть доки на русском.
Powered by POEM™ Engine Copyright © 2002-2005