OSDN Git Service

Modify the _parse method
[sie/sie.git] / org / w3c / dom / smil.js
index bb7f5e8..b85c60f 100644 (file)
@@ -117,6 +117,20 @@ base("$frame").mix ( {
        value: Number.MAX_VALUE\r
     },\r
     \r
+    addBeginList: function (num) {\r
+      return ( this.beginList = {\r
+                  value: num,\r
+                  next: this.beginList\r
+                } );\r
+    },\r
+    \r
+    addEndList: function (num) {\r
+      return ( this.endList = {\r
+                  value: num,\r
+                  next: this.endList\r
+                } );\r
+    },\r
+    \r
     /*引数に渡された時刻リストの中から、現在フレームf以下の、最大値を求めるメソッド\r
      * -1を返したときはリストの中にf以下の値がないことを示す*/\r
     getMaxList: function (f, list) {\r
@@ -162,8 +176,7 @@ base("$frame").mix ( {
           begin = /*this.BEGINNING*/ 1,\r
           play = /*this.PLAYING*/ 2,\r
           end = /*this.ENDING*/ 3,\r
-          post = /*this.POSTWAITING*/ 4,\r
-          isWait = (state === wait) || (state === post);\r
+          post = /*this.POSTWAITING*/ 4;\r
       /*beginListプロパティと、endListプロパティの中で、\r
        * 現在フレーム数 f より大きい数値は、更新できる条件と無関係なので、除外しておく\r
        * また、f以下の値の中から、最大値を探して、\r
@@ -171,7 +184,7 @@ base("$frame").mix ( {
       var startTime = this.getMaxList(f, this.beginList),\r
           endTime = this.getMaxList(f, this.endList),\r
           cacheBegin = this.begin;\r
-      if (isWait) {\r
+      if ( (state === wait) || (state === post) ) {\r
         if (startTime > cacheBegin) {\r
           this.state = begin;\r
           /*beginプロパティに開始時刻をキャッシュ用に保存*/\r
@@ -179,8 +192,6 @@ base("$frame").mix ( {
         } else if (!f && !startTime) {\r
           /*開始時刻が0ならば、アニメーションを開始*/\r
           this.state = begin;\r
-        } else  {\r
-          return this;\r
         }\r
       } else if (state === begin) {\r
         this.state = play;\r
@@ -188,8 +199,6 @@ base("$frame").mix ( {
         if ( (endTime >= cacheBegin) || (startTime > cacheBegin) ) {\r
           /*終了時刻に到達したか、再び開始イベントが発火されたとき*/\r
           this.state = end;\r
-        } else {\r
-          return this;\r
         }\r
       } else if (state === end) {\r
         if (endTime >= cacheBegin) {\r
@@ -206,22 +215,52 @@ base("$frame").mix ( {
       return this;\r
     },\r
     \r
+    /*addEventメソッドで使われるイベントリスト(開始時に登録されたリスナー関数が呼び出される)*/\r
+    _beginListenerList: [],\r
+    \r
+    /*addEventメソッドで使われるイベントリスト(終了時に登録されたリスナー関数が呼び出される)*/\r
+    _endListenerList: [],\r
+    \r
+    /*addEventメソッドで使われるイベントリスト(再生時に登録されたリスナー関数が呼び出される)*/\r
+    _playListenerList: [],\r
+    \r
+    /*開始と再生と終了時に発火されるイベントリスナーを登録するメソッド*/\r
+    addEvent: function ( /*string*/ eventName, /*fnction*/ listener) {\r
+      this["_" +eventName+ "ListenerList"].push(listener);\r
+    },\r
+    \r
     /*入力されたフレーム数fの場面に切り替えるメソッド*/\r
     setFrame: function( /*number*/ f) {\r
       this.currentFrame = f;\r
       var state = this.updateState(f).state;\r
-      /*開始と終了状態のときに、beginイベントとendイベントを呼び出しておいて、\r
-       * 次の状態に遷移する*/\r
-      if (state === /*this.BEGINNING*/ 1) {\r
+      /*アニメーション開始と再生と、終了状態のときに、beginとplayとendイベントを呼び出しておいて、\r
+       * 次の状態(再生状態)に遷移する*/\r
+      if (state === /*this.PLAYING*/ 2) {\r
+        var list = this._playListenerList;\r
+        for (var i=0;i<list.length;++i) {\r
+          list[i](this);\r
+        }\r
+      } else if (state === /*this.BEGINNING*/ 1) {\r
+        list = this._beginListenerList;\r
+        for (var i=0;i<list.length;++i) {\r
+          list[i](this);\r
+        }\r
         this.updateState(f);\r
       } else if (state === /*this.ENDING*/ 3) {\r
+        list = this._endListenerList;\r
+        for (var i=0;i<list.length;++i) {\r
+          list[i](this);\r
+        }\r
         if (this.updateState(f).state === /*this.BEGINNING*/ 1) {\r
-          /*å\86\8dç\94\9f中ã\81 ã\81£た場合*/\r
+          /*å\86\8dç\94\9f中ã\81«beginã\82¤ã\83\99ã\83³ã\83\88ã\81\8cå\91¼ã\81³å\87ºã\81\95ã\82\8cた場合*/\r
           this.updateState(f);\r
         }\r
       }\r
-      state = void 0;\r
+      state = list = void 0;\r
     }\r
+  } ).mix( function() {\r
+    /*後述の$beginや$endで使うメソッド*/\r
+    this.addList = this.addBeginList;\r
   } );\r
   \r
   /*$endFrame オブジェクト\r
@@ -314,19 +353,22 @@ base("$frame").mix ( {
           event: str\r
         };\r
       }\r
-    },\r
+    }, \r
     \r
-    /*parse メソッド\r
-     * stringプロパティを解析して、フレーム数を算出し、結果を$frame.beginプロパティに出力\r
+    /*_parse メソッド\r
+     * 引数の文字列を解析して、フレーム数を算出し、結果を$frame.beginプロパティに出力\r
      * また、イベントリスナーに登録をしておく*/\r
-    parse: function() {\r
-      /*初期値を設定*/\r
-      this.begin = 0;\r
-      this.isResolved = false;\r
-      var str = this.trim(this.string),\r
-          plusminus = str.search(/[\+\-]/),\r
+    _parse: function (str) {\r
+      var plusminus = str.search(/[\+\-]/),\r
           event = null,\r
-          ele;\r
+          ele,\r
+          /*endListのvalueプロパティには、活動継続フレーム数と開始フレーム数を足したものが入る*/\r
+          endList = this.$list.addEndList(Number.MAX_VALUE);\r
+      if (this.$end) {\r
+        /*$endオブジェクトを継承していた場合、\r
+         *活動継続フレーム数関連のリストは無効とする*/\r
+        endList = { value: 0};\r
+      }\r
       if (str === "indefinite") {\r
         this.begin = Number.MAX_VALUE;\r
       } else if (plusminus > 0) {\r
@@ -353,30 +395,65 @@ base("$frame").mix ( {
       } else if (event) {\r
         ele = event.id ? this.eventTarget.ownerDocument.getElementById(event.id)\r
                         : this.eventTarget;\r
-        /*イベントの時間差を設定しておく*/\r
-        this.eventOffset = this.begin;\r
+        /*イベントの時間差を設定しておく\r
+         * eventOffsetとobjListの変数はクロージャとしてlistener関数で使われる*/\r
+        var eventOffset = this.begin,\r
+            /*objListのvalueプロパティはあとで書き換えられる(イベントの場合のみ)*/\r
+            objList = this.$list.addList(Number.MAX_VALUE),\r
+        /*イベントのリスナーとして使う*/\r
+            listener = function(evt) {\r
+              objList.value = this.begin = eventOffset + this.$frame.currentFrame;\r
+              endList.value = this.$list.begin + this.activeTime;\r
+              this.isResolved = true;\r
+            };\r
+        this.eventOffset = eventOffset;\r
         if (this.repeat > 0) {\r
           ele && ele.addEventListener("repeatEvent", (function(evt) {\r
             if (evt.detail === this.repeat) {\r
-              this.listener(evt);\r
+              listener.call(this, evt);\r
             } }).bind(this), true);\r
         } else if (this.accessKey) {\r
           document.documentElement.addEventListener("keydown", (function(evt) {\r
             if (evt.char === this.accessKey) {\r
-                this.listener(evt);\r
+                listener.call(this, evt);\r
               } }).bind(this), false);\r
         } else {\r
           var evtName = /^(?:begin|end|repeat)$/.test(event.event) ? event.event + "Event"\r
                           : event.event;\r
-          ele && ele.addEventListener(evtName, this.listener.bind(this), false);\r
+          ele && ele.addEventListener(evtName, listener.bind(this), false);\r
         }\r
       } else {\r
-        /*イベントの影響を防ぐため\r
-         * すでに、フレームオブジェクトのタイムラインには登録済みなので、\r
-         * フレームではなく、自分独自のタイムラインに登録しておけばよい*/\r
-        this.$frame = this;\r
+        /*開始リストに登録しておく($endの場合は終了リストに登録)*/\r
+        this.$list.addList(this.begin);\r
+        /*活動継続時間から算出される終了フレーム数は、終了リストに入れておく*/\r
+        endList.value = this.begin + this.activeTime;\r
       }\r
       s = event = str = plusminus = ele = void 0;\r
+    },\r
+    \r
+    /*stringプロパティを解析して、\r
+     * 開始フレーム数の算出や、イベントリスナーの登録をするメソッド*/\r
+    parse: function() {\r
+      /*初期値を設定*/\r
+      this.begin = 0;\r
+      this.isResolved = false;\r
+      /*$listオブジェクトを更新*/\r
+      this.$list = this.$list.up();\r
+      /*beginとend属性を考慮に入れないで、活動継続時間を求める*/\r
+      var s = this.$activate.up();\r
+      this.activeTime = s.call() || Number.MAX_VALUE;\r
+      this.simpleDuration = s.simpleDur;\r
+      var str = this.trim(this.string);\r
+      if (str.indexOf(";") > -1){\r
+        /*;で区切られたリストを一つずつ解析*/\r
+        var list = str.split(";");\r
+        for (var i=0;i<list.length;++i) {\r
+          this._parse(list[i]);\r
+        }\r
+      } else {\r
+        this._parse(str);\r
+      }\r
+      s = str = void 0;\r
       return this;\r
     },\r
     \r
@@ -431,6 +508,7 @@ base("$frame").mix ( {
     \r
     /*関数型の呼び出しメソッド\r
      * base.jsのofメソッドを活用して活動継続時間を算出\r
+     * ただし、begin属性とend属性については、別途、$frame.$listで定める\r
      * 計算方法はSMILアニメーション 3.3.4節を参照\r
      * http://www.w3.org/TR/smil-animation/#ComputingActiveDur\r
      */\r
@@ -439,9 +517,7 @@ base("$frame").mix ( {
           dur = this.simpleDur,\r
           isIndefRepeatCount = (this.repeatCount === ind),\r
           isIndefRepeatDur = (this.repeatDur === ind),\r
-          isIndefEnd = (this.end === ind),\r
           isDur = dur || (dur === 0),\r
-          isEnd = this.end || (this.end === 0),\r
           isRepeatCount = this.repeatCount || (this.repeatCount === 0),\r
           isRepeatDur = this.repeatDur || (this.repeatDur === 0),\r
           actList = [],\r
@@ -462,22 +538,15 @@ base("$frame").mix ( {
       if (isRepeatDur && !isIndefRepeatDur) {\r
         actList.push( Math.floor( this.offset(this.repeatDur) * this.fpms) );\r
       }\r
-      if (isEnd && !isIndefEnd) {\r
-        actList.push( this.end - this.begin );\r
-      }\r
       if (isDur && !isRepeatCount && !isRepeatDur) {\r
         /*repeatCountやrepeatDur属性が指定されていない場合*/\r
         actList.push( dur );\r
       }\r
 \r
       /*長くなるため、インライン関数を活用\r
-       * indef関数は活動継続時間が不定かどうか、もし、不定なら真を返す*/\r
+       * indef関数はbeginとend属性を考慮せずに、\r
+       * 活動継続時間が不定かどうか、もし、不定なら真を返す*/\r
       function indef() {\r
-        if(isIndefEnd) {\r
-          return true;\r
-        } else if (isEnd) {\r
-          return false;\r
-        }\r
         return !!( (!isDur && !isRepeatDur)\r
                    || (isIndefRepeatCount && !isRepeatDur)\r
                    || (isIndefRepeatDur && !isRepeatCount)\r
@@ -508,11 +577,15 @@ base("$frame").mix ( {
       if (!this.string) {\r
         return null;\r
       }\r
+      /*addListメソッドには、addBeginList関数が入っているはずなので、それを変更する*/\r
+      this.$list.addList = this.$list.addEndList;\r
       this.parse(this.string);\r
       return this.isResolved ? this.begin\r
                              : "indefinite";\r
     }\r
   } ).mix( {\r
+    $list: $frame.$begin.$list.up(),\r
+    \r
     /*イベントリスナー用の関数*/\r
     listener: function(evt) {\r
       if (this.begin <= 0) {\r
@@ -1237,46 +1310,17 @@ base("$calcMode").up("$attribute").mix( {
   to: "",\r
   \r
   /*initメソッドで使われるアニメーション関数*/\r
-  _setFrame: function (frame) {\r
-    this.state = "playing";\r
+  _setFrame: function ($list) {\r
     this.setAttribute(this.to);\r
   },\r
   \r
-  /*アニメーション中かどうかの判別\r
-   * 1, idling アニメがまだ始まっていない待機状態 (規定値)\r
-   * 2, playing アニメーションの再生中\r
-   */\r
-  state: "idling",\r
-  \r
   /*開始を設定されたタイムライン ($beginオブジェクト)*/\r
   timeline: base("$frame").$begin,\r
   \r
-  /*_setEndFrameメソッドで終了処理をさせたいときに、呼び出されるメソッド\r
-   * 終了処理が必要なときだけ、trueを返す*/\r
-  checkEnd: function (frame) {\r
-    var line = this.timeline,\r
-        end = line.begin + line.activeTime;\r
-    if (!line.isResolved || isNaN(end)) {\r
-      /*未解決など問題が発生したとき*/\r
-      line = frame = void 0;\r
-      return false;\r
-    } else if (\r
-          ( ( frame < line.begin ) || ( end <= frame )\r
-          ) && (this.state === "playing") ) {\r
-      /*stateプロパティを書き換えることで、一度のみ、終了処理させる*/\r
-      this.state = "idling";\r
-      line = frame = void 0;\r
-      return true;\r
-    } else {\r
-      line = frame = void 0;\r
-      return false;\r
-    }\r
-  },\r
-  \r
   /*アニメが終了した際の後処理*/\r
-  _setEndFrame: function (frame) {\r
+  _setEndFrame: function ($list) {\r
     /*removeの場合、アニメーションを凍結せずに、もとに戻す*/\r
-    if (this.checkEnd(frame) && (this.fill === "remove")) {\r
+    if (this.fill === "remove") {\r
       this.removeAttribute();\r
     }\r
   },\r
@@ -1294,22 +1338,14 @@ base("$calcMode").up("$attribute").mix( {
     var thisele = this.element;\r
     if (line && thisele) {\r
       this.timeline = line;\r
-      /*ラインの中に、属性処理をするためのラインを追加*/\r
-      line.addLine(\r
-       { setFrame: this._setFrame.bind(this),\r
-         begin: 1,\r
-         activeTime: 1\r
-       }\r
-      );\r
-      base("$frame").$endFrame.addLine(\r
-        { setFrame: this._setEndFrame.bind(this),\r
-          begin: 1,\r
-          activeTime: 1\r
-        }\r
-      );\r
+      /*$begin.$listのイベントに属性処理を追加*/\r
+      line.$list.addEvent("begin", this._setFrame.bind(this));\r
+      line.$list.addEvent("play", this._setFrame.bind(this));\r
+      line.$list.addEvent("end", this._setEndFrame.bind(this));\r
+      base("$frame").addLine(line.$list);\r
+      /*アニメーションが再起動する可能性もあるため、$listのstateプロパティはここで初期化*/\r
+      line.$list.state = line.$list.WAITING;\r
     }\r
-    /*アニメーションが再起動する可能性もあるため、stateプロパティはここで初期化*/\r
-    this.state = "idling";\r
     line = thisele = void 0;\r
   }\r
 }).up("$animateElement").mix( {\r
@@ -1342,7 +1378,8 @@ base("$calcMode").up("$attribute").mix( {
     return "";\r
   },\r
   \r
-  _setFrame: function(currentTime) {\r
+  _setFrame: function($list) {\r
+    var currentTime = $list.currentFrame;\r
     /*durationは単純継続時間\r
      *advanceは継続時間内での、進捗率\r
      *  仕様を参照 http://www.w3.org/TR/smil-animation/#AnimFuncValues\r
@@ -1357,16 +1394,13 @@ base("$calcMode").up("$attribute").mix( {
         advance = duration ? ( (currentTime - line.begin) % duration ) / duration\r
                     : 0;\r
     this.setAttribute(this.tocall(advance));\r
-    this.state = "playing";\r
     line = duration = advance = void 0;\r
   },\r
   \r
   /*_setEndFrameメソッドは、終了処理と凍結作業をするときに、falseを返す*/\r
-  _setEndFrame: function(frame) {\r
+  _setEndFrame: function($list) {\r
+    var frame = $list.currentFrame;\r
     /*上書きされたメソッドを呼び出してアニメーションの凍結作業をする*/\r
-    if (!this.checkEnd(frame)) {\r
-      return;\r
-    }\r
     if (this.fill === "freeze") {\r
       var line = this.timeline,\r
           duration = line.simpleDuration;\r
@@ -1745,7 +1779,7 @@ base("$calcMode").up("$attribute").mix( {
    \r
    _setEndFrame: function(currentFrame) {\r
      var list = this.element.__transformList;\r
-     if (!this.checkEnd(currentFrame) || (this.fill !== "remove") || !list) {\r
+     if ((this.fill !== "remove") || !list) {\r
        return;\r
      }\r
      if (!this.isSum) {\r