zenith: 2006年9月アーカイブ

URLVariables は扱えない変数名がある

URLVariables クラスは、クラスが実装する変数、プロパティ、メソッドの名前と重複する名前でデータを持てない。以下のコードを実行すると ReferenceError 例外が発生する。

var variables:URLVariables = new URLVariables("toString=123");

toString は親クラスの Object で定義されている Object.toString() メソッドと衝突しちゃう。定義されているキー名が予め分かっていれば回避可能、と言っても、将来ライブラリのバージョンが上がって新しいプロパティやメソッドが追加された時に衝突してしまう事も考えられる。

そもそも URLVariables クラスがデータ コンテナを用意せず自身を結合配列のように扱っているせいだけど、なぜこういう仕様にしたんだろう?過去の ActionScript で同じように使われていた LoadVars クラスを引き継いでいるようにも見える…。この辺りリファレンス マニュアルにも書かれていない、要調査。

flash.external.ExternalInterface クラスを使用する

flash.external.ExternalInterface は Flash Player とそのコンテナ(ブラウザなど)間で通信する為のクラス。ブラウザの HTML ドキュメントに Flash Player からちょっかいだしたり出されたりできる。

使い道

例えばシステムのフォントを列挙して JavaScript で利用する。サンプルはこちらscreenshot.png

使用した MXML ファイル

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="this.applicationCompleteEventHandler(event);" layout="absolute" width="400" height="200" fontSize="12">
    <mx:Script>
        <![CDATA[
            import flash.external.ExternalInterface;
            import mx.events.FlexEvent;

            protected function applicationCompleteEventHandler(event:FlexEvent):void
            {
                var available:Boolean = ExternalInterface.available;
                this.availableLabel.text = "外部インターフェイス: "
                    + (available ? "利用可能" : "利用不可");

                if (available)
                {
                    ExternalInterface.addCallback("enumerateFont", this.enumerateFont);
                }
            }
            
            public function enumerateFont():Array
            {
                if (ExternalInterface.available)
                {
                    var fontNames:Array = new Array();
                    var fonts:Array = Font.enumerateFonts(true);
                    
                    for each (var font:Font in fonts)
                    {
                        fontNames.push(font.fontName);
                    }

                    return fontNames;
                }
                
                return null;
            }
        ]]>
    </mx:Script>
    
    <mx:Panel layout="vertical" title="フォント列挙" x="10" y="10" horizontalAlign="center" paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10">
        <mx:Label id="availableLabel"/>
    </mx:Panel>
</mx:Application>

FREEDOMYahoo!動画で公開

FREEDOM Yahoo!動画オリジナルバージョンが24日までの期間限定で公開中。

外で食うと美味いんだよ

umai.jpg 外で食べるとおいしいなんて、おにぎりだけの専売特許じゃねぇんだ!というロックな心情を感じさせるこのセリフ。発売から135年(舞台は西暦2105年)たっても本社がなくなっても(この時地球は死の星になっている)伝統と化学調味料の味を守り続けて行くぞという意気込みがひしひしと伝わってくる。やるぜ日清。

昭和47年の浅間山荘事件で、機動隊が携帯口糧として食べるシーンが流れ一躍有名になったこのカップラーメン。ヒットの切欠がまさに外で食べるだったんだなぁ。

中学校で一緒だったO君は、家出総時間12時間というフリーダムを樹立したのだけど、そのフリーダムが崩壊した原因が「カップヌードルの自販機で食べている所を家の人に見付かった」というなんとも締まらない話だった。ちなみにその自販機は学校から200m離れた交差点にあった。いまだにカップヌードルの話になると彼の武勇伝に華が咲く。

iTunes でおなじみの検索ボックス スタイル

勉強しないとだめなのについ掃除を始めちゃう、そんな気分なので、こんなの preview.png を CSS で再現しちゃう。

こうしちゃう

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
  <head>
    <title>検索ボックス</title>

    
    <style type="text/css">
      #search input.word
      {
        margin: 0;
        padding: 0.4em 0.4em 0.4em 24px;
        width: 16em;
        border: 1px solid silver;
        background-color: white;
        background-image: url("search.gif");
        background-position: 4px center;
        background-repeat: no-repeat;
      }

      #search input.active
      {
        color: black;
      }

      #search input.passive
      {
        color: gray;
      }
    </style>
    
    <script type="text/javascript">
      this.onload = function ()
      {
        var word = this.document.forms.search.word;
        
        word.onfocus = function ()
        {
          if (this.value == this.defaultValue)
          {
            this.value = '';
            this.className = 'word active';
          }
        }
        
        word.onblur = function ()
        {
          if (this.value == '')
          {
            this.value = this.defaultValue;
            this.className = 'word passive';
          }
        }
        
        word.onkeydown = function (event)
        {
          var e = event || window.event;
          
          if (e.keyCode == 13)
          {
            if (this.value != '')
            {
              this.form.submit();
            }
          }
        }
        
        word.onfocus();
        word.onblur();
      }
    </script>
  </head>

  
  <body>
    <form id="search" action="#dummy">
      <p>
        <input type="text" name="word" value="検索キーワードを入力して下さい" class="word" tabindex="1" accesskey="F" />
      </p>
    </form>

  </body>
</html>

こうなった

サンプルはこちらです。

問題点

  • CSS のサポートが控え目なブラウザでは控え目なスタイルに。
  • JavaScript を切ってたら Firefox 等で送信できない。これは type="submit" な INPUT 要素を追加して CSS で見えなくするべきかしら?

更に問題点

間に合わなくなった。

イベントの流れ

| | コメント(0)

イベントの発生順序

Flex ではイベントは DOM Level3 Event Model に沿った実装になっており、イベントの流れを3つの段階に分けて考えられます。発生順序もこの通り。

  1. キャプチャ段階
  2. ターゲット段階
  3. バブリング段階

それぞれの段階の違い

Flex アプリケーションでは全ての視覚オブジェクト (DisplayObject) は木構造になっています。イベントは親要素から子要素、またはその逆を辿り伝わっていきます。

キャプチャ段階
ルート要素から子要素へイベントが発生していく。イベント発生要素に辿り付くまでの段階
ターゲット段階
イベント発生要素でイベントが発生した段階。
バブリング段階
イベント発生要素の親要素からルート要素へ、キャプチャ段階の逆の順序で発生して行く。

tree.jpg

このアプリケーションの Button オブジェクトで click イベントが発生した場合、イベントは次のように発生します。

  1. キャプチャ段階
    1. Application
    2. Panel
    3. TitleWindow
    4. Accordion
    5. Canvas
  2. ターゲット段階
    1. Button
  3. キャプチャ段階
    1. Canvas
    2. Accordion
    3. TitleWindow
    4. Panel
    5. Application

実例

Panel コンテナ内をクリックすると、イベントを発生順に表示します。(要 Flash Player 9 以降)

使用した MXML コード

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="this.creationCompleteEventHandler(event);" layout="absolute" >
  <mx:Script>
    <![CDATA[
      import mx.collections.ArrayCollection;

      private var eventCount:int;
      private var eventPhaseTextTable:Object;
      
      protected function creationCompleteEventHandler(event:Event):void
      {
        // イベント ハンドラを登録する。
        this.panel.addEventListener(MouseEvent.CLICK, this.clickEventHandler);
        this.titleWindow.addEventListener(MouseEvent.CLICK, this.clickEventHandler);
        this.accordion.addEventListener(MouseEvent.CLICK, this.clickEventHandler);
        this.canvas.addEventListener(MouseEvent.CLICK, this.clickEventHandler);
        this.button.addEventListener(MouseEvent.CLICK, this.clickEventHandler);

        // キャプチャ段階のイベント ハンドラを登録する。
        this.panel.addEventListener(MouseEvent.CLICK, this.clickEventHandler, true);
        this.titleWindow.addEventListener(MouseEvent.CLICK, this.clickEventHandler, true);
        this.accordion.addEventListener(MouseEvent.CLICK, this.clickEventHandler, true);
        this.canvas.addEventListener(MouseEvent.CLICK, this.clickEventHandler, true);
        this.button.addEventListener(MouseEvent.CLICK, this.clickEventHandler, true);

        // イベントの結果表示を初期化する為のハンドラ。
        this.panel.addEventListener(MouseEvent.MOUSE_DOWN, this.mouseDownEventHandler);
        
        // イベント フェーズの文字列変換テーブル。
        this.eventPhaseTextTable = {
          (EventPhase.AT_TARGET.toString()) : "Target",
          (EventPhase.BUBBLING_PHASE.toString()) : "Bubbling",
          (EventPhase.CAPTURING_PHASE.toString()) : "Capturing"
        };
      }
      
      protected function mouseDownEventHandler(event:MouseEvent):void
      {
        this.eventCount = 1;
        this.dataGrid.dataProvider = new ArrayCollection();
      }
      
      protected function clickEventHandler(event:Event):void
      {
        var dataProvider:ArrayCollection = this.dataGrid.dataProvider as ArrayCollection;
        var item:Object = {
            "no" : this.eventCount,
            "target" : event.currentTarget.className,
            "phase" : this.eventPhaseTextTable[event.eventPhase]
        };
        dataProvider.addItem(item);
        this.eventCount++;
      }
    ]]>
  </mx:Script>

  <mx:Panel layout="absolute" title="Panel" top="10" left="10" right="10" id="panel" height="182">
    <mx:TitleWindow layout="absolute" left="10" top="10" bottom="10" right="10" showCloseButton="true" title="TitleWindow" id="titleWindow">
      <mx:Accordion id="accordion" left="10" top="10" bottom="10" right="10">
        <mx:Canvas label="Canvas" width="100%" height="100%" id="canvas">
          <mx:Button x="10" y="10" label="Click this" id="button"/>
        </mx:Canvas>

      </mx:Accordion>
    </mx:TitleWindow>
  </mx:Panel>
  <mx:Panel layout="absolute" left="10" top="200" bottom="10" right="10" title="Events">
    <mx:DataGrid id="dataGrid" top="10" left="10" right="10" bottom="10">
      <mx:columns>

        <mx:DataGridColumn width="50" dataField="no" headerText="No"/>
        <mx:DataGridColumn dataField="target" headerText="Target"/>
        <mx:DataGridColumn dataField="phase" headerText="Phase"/>
      </mx:columns>
    </mx:DataGrid>
  </mx:Panel>

</mx:Application>