Как с помощью jQuery сделать флеш-ролик резиновым.

To view this page ensure that Adobe Flash Player version 10.0.0 or greater is installed.


Во флеш-роликах фиксированного размера мало пользы в резиновых сайтах. А ведь сайтов, растягивающихся по ширине экрана - пожалуй побольше, чем сайтов с фиксированной шириной. А это значит, что растяжка флеш-ролика по ширине - это самая первая практическая задачка при программировании большинства Flex-приложений.

При освоении Flex-платформы я приобрел несколько отличных книг с рецептами Flex-программирования - при возникновении вопроса о ресайзе я бегло просмотрел их и, увы, совершенно не обнаружил в них рецепта, который бы растягивал ролики в сайтах с резиновым дизайном. Поэтому я решил это как сумел - буквально за пять минут. Но я подумал, что мое решение может быть полезно и другим Flex-программистам.

Для того, чтобы растягивать ролик, его надо в html-верстке вложить в любой контейнер, который займет свое место в сайте, обычно в виде такого контейнера используется DIV или TD. И далее сообщить в ActionScript текущий размер html-контейнера.

Резиновые сайты устроены примерно так: у сайта есть левое фиксированное поле для рекламы <td width="100px">, затем идет растягивающаяся по ширине полоса с флеш-роликом <td id="ContentContainer" width="100%"> далее собственно флеш-ролик <div id="flashContent" /> и далее правое рекламное поле сайта <td width="100px"> - так устроено огромное большинство сайтов, например тот же http://www.votpusk.ru.

Я мог бы обрезинить ролик с помощью ЯзваСкрипта, но я применил jQuery, которая скрывает различия браузеров. Для этого я использовал самую минимальную версию jQuery размером 79 кб. Собственно исходный код этой странички, на которой вы видите резиновый ролик выглядит вот так:


   1:  <head>
   2:  ...
   3:   
   4:      <script type="text/javascript" src="history/history.js"></script>
   5:      <script type="text/javascript" src="jquery-1.4.4.min.js"></script>
   6:      <script type="text/javascript" src="swfobject.js"></script>
   7:   
   8:  ...
   9:   
  10:      <script type="text/javascript">
  11:          $(document).ready(function () {
  12:               $(window).resize(flashresize);
  13:           })
  14:      </script>
  15:   
  16:      <script type="text/javascript">
  17:              function flashresize () {
  18:                  var ContentContainer = $("#ContentContainer")[0];
  19:                  var Votpusk_Image_Slider = $("#Votpusk_Image_Slider")[0];
  20:                  Votpusk_Image_Slider.containerresize(ContentContainer.clientWidth, ContentContainer.clientHeight);
  21:              }
  22:      </script>
  23:   
  24:      <script type="text/javascript">
  25:              var swfVersionStr = "10.0.0";
  26:              var xiSwfUrlStr = "playerProductInstall.swf";
  27:              var flashvars = {};
  28:              flashvars.BestFotoNumber="http://foto.votpusk.ru/BestFotoNumber.ashx";
  29:              flashvars.DebugService="0";
  30:              flashvars.BaseUrl="http://foto.votpusk.ru/GetImage.ashx?w=100%26j=";
  31:              flashvars.ClickBaseUrl="http://foto.votpusk.ru/foto_slide.aspx";
  32:              var params = {};
  33:              params.quality = "high";
  34:              params.bgcolor = "#ffffff";
  35:              params.allowscriptaccess = "always";
  36:              params.allowfullscreen = "true";
  37:              var attributes = {};
  38:              attributes.id = "Votpusk_Image_Slider";
  39:              attributes.name = "Votpusk_Image_Slider";
  40:              attributes.align = "middle";
  41:              swfobject.embedSWF(
  42:                  "Votpusk_Image_Slider.swf", "flashContent",
  43:                  "100%", "126px",
  44:                  swfVersionStr, xiSwfUrlStr, 
  45:                  flashvars, params, attributes);
  46:              swfobject.createCSS("#flashContent", "display:block;text-align:left;");
  47:      </script>
  48:   
  49:  ...
  50:   
  51:  </head>
  52:  <body>
  53:   
  54:  ...
  55:   
  56:      <table cellpadding="0" cellspacing="0" border="0" style="width: 100%; height: 262px;">
  57:          <tr>
  58:              <td>
  59:                  <img src="100.gif">
  60:              </td>
  61:              <td id="ContentContainer" style="width: 100%; height: 262px;">
  62:                  <div id="flashContent">
  63:                      <p>
  64:                          To view this page ensure that Adobe Flash Player version 10.0.0 or greater is installed.
  65:                      </p>
  66:                      <script type="text/javascript">
  67:                          var pageHost = ((document.location.protocol == "https:") ? "https://" : "http://");
  68:                          document.write("<a href='http://www.adobe.com/go/getflashplayer'><img src='"
  69:                                  + pageHost + "www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' /></a>"); 
  70:                      </script>
  71:                  </div>
  72:                  <noscript>
  73:                      <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"
  74:                          id="Votpusk_Image_Slider">
  75:                          <param name="movie" value="Votpusk_Image_Slider.swf" />
  76:                          <param name="FlashVars" value="BestFotoNumber='http://foto.votpusk.ru/BestFotoNumber.ashx'&DebugService='0'&BaseUrl='http://foto.votpusk.ru/GetImage.ashx?w=100%26j='&ClickBaseUrl='http://foto.votpusk.ru/foto_slide.aspx'" />
  77:                          <param name="quality" value="high" />
  78:                          <param name="bgcolor" value="#ffffff" />
  79:                          <param name="allowScriptAccess" value="always" />
  80:                          <param name="allowFullScreen" value="true" />
  81:                          <!--[if !IE]>-->
  82:                          <object type="application/x-shockwave-flash" data="Votpusk_Image_Slider.swf" width="100%"
  83:                              height="100%">
  84:                              <param name="quality" value="high" />
  85:                              <param name="bgcolor" value="#ffffff" />
  86:                              <param name="allowScriptAccess" value="always" />
  87:                              <param name="allowFullScreen" value="true" />
  88:                              <!--<![endif]-->
  89:                              <!--[if gte IE 6]>-->
  90:                              <p>
  91:                                  Either scripts and active content are not permitted to run or Adobe Flash Player
  92:                                  version 10.0.0 or greater is not installed.
  93:                              </p>
  94:                              <!--<![endif]-->
  95:                              <a href="http://www.adobe.com/go/getflashplayer">
  96:                                  <img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif"
  97:                                      alt="Get Adobe Flash Player" />
  98:                              </a>
  99:                              <!--[if !IE]>-->
 100:                          </object>
 101:                          <!--<![endif]-->
 102:                      </object>
 103:                  </noscript>
 104:              </td>
 105:              <td>
 106:                  <img src="100.gif">
 107:              </td>
 108:          </tr>
 109:      </table>
 110:  ...
 111:   
 112:  </body>

Как вы видите, здесь в строках 24-47 вызывается стандартный скрипт, создаваемый FlexBuilder - а вот в строках 10-22 - та самая хитрость на jQuery, которую я докрутил в стандартый шаблон Flex-проекта.


Обратите внимание, что выше вы видите ИТОГОВЫЙ текст, сгенерировнный FlexBuilder по команде Export Release Build - а ИСХОДНЫЙ текст строк 16-22 (который подается на вход FlexBuilder в файле index.template.html) - состоит из адской смеси кода jQuery и шаблонов ANT) и выглядит совершенно вот так:


  16:      <script type="text/javascript">
  17:              function flashresize () {
  18:                  var ContentContainer = $("#ContentContainer")[0];
  19:                  var ${application} = $("#${application}")[0];
  20:                  ${application}.containerresize(ContentContainer.clientWidth, ContentContainer.clientHeight);
  21:              }
  22:      </script>

Итак, в строке 5 подключается jQuery, в строках 10-14 добавляется слушатель событий изменения размера html-элемента ContentContainer, а в строках 16-22 он срабатывает при ресайзе и вызывает функцию containerresize html-обьекта c именем Votpusk_Image_Slider, в котором лежит байт-код SWF-файла (и в котором Flash-плеер, исполняя этот байт-код) создал функцию containerresize.

Надо понимать, что при загрузке страницы html-обьекта c именем Votpusk_Image_Slider не существует, есть только div c именем flashContent, на месте коротого скрипт swfobject создаст или тег object:


   1:      <object width="100%" height="126px" align="middle" type="application/x-shockwave-flash"
   2:          id="Votpusk_Image_Slider" name="Votpusk_Image_Slider" data="Votpusk_Image_Slider.swf">
   3:          <param name="quality" value="high">
   4:          <param name="bgcolor" value="#ffffff">
   5:          <param name="allowscriptaccess" value="always">
   6:          <param name="allowfullscreen" value="true">
   7:          <param name="flashvars" value="BestFotoNumber=http://foto.votpusk.ru/BestFotoNumber.ashx&amp;DebugService=0&amp;BaseUrl=http://foto.votpusk.ru/GetImage.ashx?w=100%26j=&amp;ClickBaseUrl=http://foto.votpusk.ru/foto_slide.aspx">
   8:      </object>

И лишь после создания этого обьекта, с помощью jQuery этому обьекту будут добавлен слушатель события resize. Конечно, по хорошему, здесь надо добавлять таймаут странички хотя бы на 0,5 секунды и лишь после таймаута добавлять слушатель событий. Но этим моментом с пренебрег - поэтому мое решение может порождать при загрузке странички ошибку (которая уходит как только swfobject закончит работу и будет создан тег, на который jQuery создает слушатель события).


Теперь пойдем внутрь байт-кода и посмотрим каким образом попросить виртуальную машину флеш-плеера создать у html-обьекта фукнцию containerresize.


   1:  <?xml version="1.0" encoding="utf-8"?>
   2:  <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
   3:                 xmlns:s="library://ns.adobe.com/flex/spark" 
   4:                 xmlns:mx="library://ns.adobe.com/flex/mx"
   5:                 applicationComplete="application1_applicationCompleteHandler(event)" 
   6:                 minWidth.Image_Load="712" minHeight.Image_Load="125" 
   7:                 width.Image_Load="712" height.Image_Load="125" 
   8:                 minWidth.Debug="500" minHeight.Debug="500" >
   9:      
  10:      <fx:Script>
  11:          
  12:          <![CDATA[
  ...          
  28:              protected function application1_applicationCompleteHandler(event:FlexEvent):void
  29:              {
  30:                  try    {
  31:                      ExternalInterface.addCallback("containerresize", FlashContainerResize);
  32:                  }
  33:                  catch (error:SecurityError){
  34:                  }
  35:                  
  ...          
  57:                  try    {
  58:                  ExternalInterface.call("flashresize");
  59:                  }
  60:                  catch (error:SecurityError){
  61:                  }
  62:              }
  ...          
 244:          ]]>
 245:      </fx:Script>
  ...          
 283:  </s:Application>

Здесь вы видите, что стартовой функцией по завершении создания Flex-приложения назначена функция, определенная в строке 28. Эта функция сразу же создает у html-обьекта javascript-функцию containerresize, на которую jQuery мапирует событие rezise обьекта ContentContainer.

По завершению этой процедуры ролик занимает тот размер, который ему положено в данный момент (а не тот размер, который ему определен в дизайн-тайме). Эта операция вызывается в строке 58.


Как же распорядится в коде размерами, которые нам пробросил jQuery из контейнера на внешний интерфейс виртуальной машины и которые в итоге попадают во внутренню функцию флекса - flashresize?

В этом коде я распорядился полученной информацией простейшим образом - выстроил по этому размеру контейнер Hbox - а мог бы например и убрать частично отображаемый рисунок (и подогнать интервалы между рисунками);


  64:              private function FlashContainerResize (width:int,heigth:int):void {
  65:                  HGroup1.width=width-2;
  66:                  //Alert.show(width.toString() + ":" + heigth.toString());
  67:              }

Надеюсь теперь все понятно. Теперь пару заморочек, которые могут возникать при общении байт-кода виртуальной машины с внешним кодом странички. Вообще-говоря, это запрещено. При попытках этого общения возникают замечательные сообщения "SecurityError: Error #2060: Security sandbox violation: ExternalInterface caller" :



С этой проблемой безопасности есть много механизмов борьбы. Прежде всего allowScriptAccess установлено в true в html-коде в строках 35, 79, 86 именно для этого. Но к сожалению, и это не всегда помогает. Чтобы виртуальная машина не падала окончательно в случае этой проблемы безопасности - необходимо брать в скобочки try обращения к внешнему интерфейсу виртуальной машины - как я это сделал в строках 30 и 57 флекс-кода.

Ну вот вроде бы и все, что можно сказать о резиновых Flash-роликах. Надеюсь чтение было полезным.


Еще пару примеров применения jQuery вы можете посмотреть на страничках - AJAX подсказка/автозаполнение на jQuery, Как сделать простейший Web-handler - формирующий XML или JSON, Заполнение связанных списков на MS AJAX и jQuery.

Про Flex вы можете почитать на страничке //www.vb-net.com/Flex/index.htm.



Comments ( )
Link to this page: //www.vb-net.com/Flex_Resize/index.htm
< THANKS ME>