var Node = X[ 'Node' ] = X_EventDispatcher[ 'inherits' ](
'X.Node',
X_Class.POOL_OBJECT,
-
{
/**
* 要素に振られるユニークID
};
/**
- * 要素を抜く。
+ * 要素を親要素から抜く。jQuery の remove と異なり、インスタンスは破壊(kill)されず、再び別の親に挿入等できる
* @alias Node.prototype.remove
* @return {Node} 自身。チェインメソッド
* @example node.remove();
+ * parent.append( node ); 新しい親に追加できる
*/
function X_Node_remove(){
var parent = this.parent,
*/
function X_Node_empty(){
var xnodes = this[ '_xnodes' ], i;
+
if( xnodes && ( i = xnodes.length ) ){
+ delete this[ '_xnodes' ];
for( ; i; ){
xnodes[ --i ][ 'kill' ]();
};
if( ( that[ '_flags' ] & X_NodeFlags_EXIST ) === 0 ) return;
- parent && parent[ '_xnodes' ].splice( parent[ '_xnodes' ].indexOf( that ), 1 );
+ parent && parent[ '_xnodes' ] && parent[ '_xnodes' ].splice( parent[ '_xnodes' ].indexOf( that ), 1 );
elm = that[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( that );
- // elm && that[ '_listeners' ] && X_EventDispatcher_unlistenAll( that ); // イベントの退避
if( xnodes && ( i = xnodes.length ) ){
+ delete that[ '_xnodes' ];
for( ; i; ){
xnodes[ --i ][ 'kill' ]();
};
+ xnodes.length = 0;
};
- delete X_Node_CHASHE[ that[ '_uid' ] ];
+ X_Node_CHASHE[ that[ '_uid' ] ] = null; // array に対して delete X_Node_CHASHE[ uid ] はまずい!
+
// remove _xnodes
if( X_UA_DOM.IE4 ){
if( elm ){
} else {
if( elm && elm.parentNode && elm.parentNode.tagName ){
X_Node_reserveRemoval[ X_Node_reserveRemoval.length ] = elm;
- X_Node_reserveUpdate();
+ X_Node_reserveUpdate();
};
};
};
// setter
if( html !== undefined ){ // String 以外に Number や false null なども許可
if( !this[ '_tag' ] ) return this[ 'text' ]( html );
- return html ? this[ 'empty' ]()[ 'append' ].apply( this, X_HtmlParser_parse( html, true ) ) : this[ 'empty' ]();
+
+ this[ 'empty' ]();
+ if( html ){
+ X_Node_append.apply( this, X_HtmlParser_parse( html, true ) );
+ };
+ return this;
};
// getter
X_HTMLAudio_pauseFix = 12 <= X_UA[ 'Opera' ] && 0 < ' XP XPSP2 2003|XP64'.indexOf( X_UA[ 'Windows' ] ), // XP + Opera12 のみ?\r
\r
X_HTMLAudio_need1stTouch = X_UA[ 'iOS' ] || 4.2 <= X_UA[ 'AOSP' ] || X_UA[ 'ChromeWV' ] || X_UA[ 'WinPhone' ] || ( X_UA[ 'Blink' ] && X_UA[ 'Android' ] ),\r
- \r
+\r
X_HTMLAudio_playTrigger = ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ) ? 'canplay' : X_UA[ 'iOS' ] ? 'suspend' : X_UA[ 'Blink' ] ? 'stalled' : 'canplaythrough',\r
- \r
- X_HTMLAudio_durationFix = X_UA[ 'iOS' ] || X_UA[ 'ChromeWV' ] || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ) || ( X_UA[ 'Windows' ] && 12 <= X_UA[ 'Opera' ] ),\r
- \r
+\r
+ X_HTMLAudio_durationFix = X_UA[ 'iOS' ] || X_UA[ 'ChromeWV' ] || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ) ||\r
+ ( X_UA[ 'Windows' ] && 12 <= X_UA[ 'Opera' ] ) || ( X_UA[ 'Blink' ] && X_UA[ 'Android' ] ),\r
+\r
X_HTMLAudio_shortPlayFix = X_UA[ 'AOSP' ]; // Android 4.1.1 でも遭遇\r
\r
if( X_Audio_constructor ){\r
'X.HTMLAudio',\r
X_Class.POOL_OBJECT,\r
{\r
- _closed : true,\r
-\r
// 1: canplaythrought|timeupdateに達している、またはdurationFixが終了している\r
// 2: READY イベント発火済\r
_readyState : 0,\r
var raw;\r
\r
this.disatcher = disatcher || this;\r
- this._closed = false;\r
this._src = source;\r
\r
if( X_HTMLAudio_shortPlayFix ){\r
ready,\r
eventType, duration, end, now;\r
\r
- if( this._closed ) return;\r
+ if( !raw ) return;\r
\r
//e.type !== 'timeupdate' && console.log( ' > ' + e.type );\r
\r
switch( e.type ){\r
\r
case X_EVENT_KILL_INSTANCE :\r
- delete this._closed;\r
this.playing && this.actualPause();\r
\r
// 【javascript】モバイル向けブラウザでも音を鳴らしたい【WebAudio】\r
this._readyState |= 1;\r
};\r
case 'canplay' : // 今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生\r
- if( this._durationFixPhase === 1 && !X_HTMLAudio_need1stTouch ){\r
+ if( this._durationFixPhase === 1 && !X_HTMLAudio_need1stTouch ){ // PC Opera12 用 durationFix\r
this._durationFixPhase = 2;\r
this.actualPlay();\r
raw.currentTime = 0; // Win8 + Opera12 で必要\r
};\r
\r
// duration は Infinity, NaN, 0 の場合があるため、これを除外する\r
- if( 0 < duration && X_Type_isFinite( duration ) ){\r
+ // chrome18 for Android は duration = 100 の間はシークができない? 28 は可能\r
+ if( 0 < duration && X_Type_isFinite( duration ) && duration !== 100 ){\r
this.duration = duration * 1000;\r
\r
if( this._durationFixPhase === 4 ){\r
\r
if( this.autoplay || this._playReserved ){\r
console.log( '☆ 再生 <- DurationFix の終了' );\r
- delete this._playReserved;\r
this.actualPlay();\r
} else\r
if( X_HTMLAudio_pauseFix ){\r
};\r
} else\r
if( this._readyState === 1 && this.duration ){\r
- this._readyState = 3;\r
+ this._readyState = 2;\r
this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY );\r
console.log( '> Audio Loaded!! ' + e.type + ' d:' + ( this.duration | 0 ) );\r
} else\r
var raw = this[ '_rawObject' ],\r
e, begin, end;\r
\r
- if( this._closed ) return;\r
+ if( !raw ) return;\r
\r
- if( !raw.src ){ // X_HTMLAudio_pauseFix によって src が空になっている\r
- console.log( '○ 削除された audio.src の復帰' );\r
- raw.src = this._src;\r
- return;\r
- }; \r
+ this._playReserved = true;\r
+ \r
+ if( X_HTMLAudio_pauseFix ){\r
+ if( !raw.src ){ // X_HTMLAudio_pauseFix によって src が空になっている\r
+ console.log( '○ 削除された audio.src の復帰' );\r
+ raw.src = this._src;\r
+ return;\r
+ };\r
+ if( this._durationFixPhase < 2 ){\r
+ return;\r
+ }; \r
+ };\r
\r
if( this._touchState === 2 ){\r
e = X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length - 1 ];\r
};\r
this._touchState = 3;\r
} else\r
- if( this._readyState !== 3 && this._durationFixPhase < 2 ){\r
- this._playReserved = true;\r
+ if( this._readyState !== 2 && this._durationFixPhase < 2 ){\r
return;\r
};\r
\r
+ delete this._playReserved;\r
+ \r
if( this._durationFixPhase & 3 ){ // 1 or 2\r
console.log( '▲ DurationFix の開始' );\r
this._durationFixPhase = 4;\r
} else\r
if( X_HTMLAudio_needPlayForSeek || forcePlay ){\r
raw.play();\r
- //console.log( '[HTMLAudio] currentTime より先.' );\r
};\r
\r
//http://himaxoff.blog111.fc2.com/blog-entry-97.html\r
bgmPosition : 0,\r
bgmName : '',\r
bgmLooped : false,\r
- bgmPlaying : false\r
+ bgmPlaying : false,\r
+ event : null\r
},\r
X_AudioSprite,\r
X_AudioSprite_numTracks,\r
volume = setting[ 'volume' ],\r
k, i, v, track;\r
\r
- if( !X_AudioSprite ){\r
- X_AudioSprite = X_Class_override( X_EventDispatcher(), X_AudioSprite_members );\r
- X_ViewPort[ 'listen' ]( [ X_EVENT_VIEW_ACTIVATE, X_EVENT_VIEW_DEACTIVATE, X_EVENT_UNLOAD ], X_AudioSprite, X_AudioSprite_handleEvent );\r
- };\r
+\r
+ if( X_AudioSprite ) X_AudioSprite[ 'kill' ]();\r
+\r
+ X_AudioSprite = X_Class_override( X_EventDispatcher(), X_AudioSprite_members );\r
+ X_ViewPort[ 'listen' ]( [ X_EVENT_VIEW_ACTIVATE, X_EVENT_VIEW_DEACTIVATE, X_EVENT_UNLOAD ], X_AudioSprite_handleEvent );\r
\r
n = n <= X_AudioSprite_maxTracks ? n : X_AudioSprite_maxTracks;\r
\r
track = X_AudioSprite_TEMP.bgmTrack = tracks[ 0 ];\r
};\r
\r
- if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite, X_AudioSprite_handleEvent ).playing ){\r
+ if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite_handleEvent ).playing ){\r
track.setState({\r
'loop' : true,\r
'looped' : X_AudioSprite_TEMP.bgmLooped,\r
if( 1 < X_AudioSprite_numTracks ){\r
track = X_AudioSprite_getTrackEnded( X_AudioSprite_TEMP.bgmPlaying );\r
track\r
- [ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite, X_AudioSprite_handleEvent )\r
+ [ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite_handleEvent )\r
.setState( { 'looped' : false } );\r
track.play( preset[ 0 ], preset[ 1 ], true, 0, X_AudioSprite_lengthSilence );\r
} else {\r
};\r
track = tracks[ 0 ];\r
\r
- if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite, X_AudioSprite_handleEvent ).playing ){\r
+ if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], X_AudioSprite_handleEvent ).playing ){\r
track.setState({\r
'loop' : true,\r
'looped' : false,\r
'loopEndTime' : X_AudioSprite_lengthSilence\r
});\r
} else {\r
- \r
track.play( preset[ 0 ], preset[ 1 ], true, 0, X_AudioSprite_lengthSilence ); \r
};\r
};\r
};\r
// Audiobackend の owner として null を渡すとAudioBackend 自身へ dispatch する\r
X_AudioSprite_TEMP.tracks.push(\r
- last = backend.klass( null, e[ 'source' ], option )[ 'listen' ]( X_EVENT_DEBUG, X_AudioSprite, X_AudioSprite_handleEvent ) );\r
+ last = backend.klass( null, e[ 'source' ], option )[ 'listen' ]( X_EVENT_DEBUG, X_AudioSprite_handleEvent ) );\r
};\r
\r
_e = {\r
'source' : src,\r
'backendName' : name\r
};\r
- // touch 可能で backend ready\r
- // WebAudio\r
- if( backend.backendID === 1 && ( _e[ 'needTouchForPlay' ] = X_WebAudio_need1stTouch ) ){\r
- last[ 'listenOnce' ]( X_EVENT_READY, X_AudioSprite, X_AudioSprite[ 'asyncDispatch' ], [ _e ] );\r
- } else\r
- // HTMLAudio\r
- if( backend.backendID === 2 && ( _e[ 'needTouchForLoad' ] = X_HTMLAudio_need1stTouch ) ){\r
- last[ 'listenOnce' ]( X_EVENT_MEDIA_TOUCH_FOR_LOAD, X_AudioSprite, X_AudioSprite[ 'asyncDispatch' ], [ _e ] );\r
+ \r
+ // TODO 今は touch 可能で backend ready\r
+ if(\r
+ // WebAudio\r
+ ( backend.backendID === 1 && ( _e[ 'needTouchForPlay' ] = X_WebAudio_need1stTouch ) ) ||\r
+ // HTMLAudio\r
+ ( backend.backendID === 2 && ( _e[ 'needTouchForLoad' ] = X_HTMLAudio_need1stTouch ) )\r
+ ){\r
+ X_AudioSprite_TEMP.event = _e;\r
+ last[ 'listenOnce' ]( X_EVENT_MEDIA_TOUCH_FOR_LOAD, X_AudioSprite_backendHandler );\r
} else {\r
X_AudioSprite[ 'asyncDispatch' ]( _e );\r
};\r
\r
- last[ 'listenOnce' ]( X_EVENT_READY, X_AudioSprite, X_AudioSprite_backendHandler );\r
+ // TODO 全ての track の READY で!\r
+ last[ 'listenOnce' ]( X_EVENT_READY, X_AudioSprite_backendHandler );\r
return X_CALLBACK_STOP_NOW;\r
\r
case X_EVENT_BACKEND_NONE :\r
- X_AudioSprite[ 'unlisten' ]( X_EVENT_BACKEND_READY, X_AudioSprite, X_AudioSprite_backendHandler )\r
+ X_AudioSprite\r
+ [ 'listen' ]( X_EVENT_BACKEND_NONE, X_AudioSprite_handleEvent ) // kill を呼ぶ\r
[ 'asyncDispatch' ]( X_EVENT_BACKEND_NONE );\r
return X_CALLBACK_STOP_NOW;\r
\r
+ case X_EVENT_MEDIA_TOUCH_FOR_LOAD :\r
+ // TODO 全ての track の MEDIA_TOUCH_FOR_LOAD で!\r
+ X_AudioSprite[ 'asyncDispatch' ]( X_AudioSprite_TEMP.event );\r
+ delete X_AudioSprite_TEMP.event;\r
+ break;\r
+ \r
case X_EVENT_READY :\r
console.log( 'X.AudioSprite - Ready!' );\r
for( i = 0; i < X_AudioSprite_numTracks; ++i ){\r
\r
\r
function X_AudioSprite_handleEvent( e ){\r
- var i, tracks, track, _e, k;\r
+ var track = e.target, i, tracks, _e, k;\r
\r
switch( e.type ){\r
case X_EVENT_MEDIA_PLAYING :\r
- ( e.target === X_AudioSprite_TEMP.bgmTrack || !e.target.looped ) && X_AudioSprite[ 'asyncDispatch' ]( X_EVENT_MEDIA_PLAYING );\r
- break;\r
case X_EVENT_MEDIA_WAITING :\r
case X_EVENT_MEDIA_SEEKING :\r
- ( e.target === X_AudioSprite_TEMP.bgmTrack || !e.target.looped ) && X_AudioSprite[ 'asyncDispatch' ]( e.type );\r
+ ( track === X_AudioSprite_TEMP.bgmTrack || !track.looped ) && X_AudioSprite[ 'asyncDispatch' ]( e.type );\r
break;\r
\r
case X_EVENT_MEDIA_BEFORE_LOOP :\r
- if( e.target === X_AudioSprite_TEMP.bgmTrack ){\r
+ if( track === X_AudioSprite_TEMP.bgmTrack ){\r
X_AudioSprite_TEMP.bgmLooped = true;\r
X_AudioSprite[ 'asyncDispatch' ]( X_EVENT_MEDIA_LOOPED ); // TODO uid\r
} else {\r
- if( e.target.looped ){\r
+ if( track.looped ){\r
// X_AudioSprite[ 'asyncDispatch' ]( X_EVENT_MEDIA_LOOPED ); // TODO uid\r
} else {\r
X_AudioSprite[ 'asyncDispatch' ]( X_EVENT_MEDIA_ENDED ); // TODO uid\r
\r
// single track | iOS\r
if( X_AudioSprite_TEMP.bgmPlaying && !X_AudioSprite_TEMP.bgmTrack ){\r
- X_AudioSprite_TEMP.bgmTrack = e.target;\r
+ X_AudioSprite_TEMP.bgmTrack = track;\r
X_AudioSprite.play( X_AudioSprite_TEMP.bgmName );\r
return X_CALLBACK_PREVENT_DEFAULT;\r
};\r
\r
\r
case X_EVENT_DEBUG :\r
- i = X_AudioSprite_TEMP.tracks.indexOf( e.target );\r
+ i = X_AudioSprite_TEMP.tracks.indexOf( track );\r
if( 0 <= i ){\r
e[ 'trackID' ] = i;\r
X_AudioSprite[ 'dispatch' ]( e );\r
};\r
break;\r
\r
+ case X_EVENT_BACKEND_NONE :\r
case X_EVENT_UNLOAD :\r
- console.log( '■ unload' );\r
+ X_AudioSprite[ 'kill' ]();\r
+ break;\r
\r
case X_EVENT_KILL_INSTANCE :\r
+ X_AudioSprite_TEMP.pauseTracks.length = 0;\r
+ \r
while( X_AudioSprite_TEMP.tracks.length ){\r
X_AudioSprite_TEMP.tracks.pop()[ 'kill' ]();\r
};\r
\r
- for( k in X_AudioSprite_TEMP.bgms ){\r
- delete X_AudioSprite_TEMP.bgms[ k ];\r
+ for( k in X_AudioSprite_TEMP.BGMs ){\r
+ delete X_AudioSprite_TEMP.BGMs[ k ];\r
};\r
for( k in X_AudioSprite_TEMP.presets ){\r
delete X_AudioSprite_TEMP.presets[ k ];\r
X_AudioSprite_TEMP.bgmLooped = false;\r
X_AudioSprite_TEMP.bgmPlaying = false;\r
\r
- X_ViewPort[ 'unlisten' ]( [ X_EVENT_VIEW_ACTIVATE, X_EVENT_VIEW_DEACTIVATE, X_EVENT_UNLOAD ], X_AudioSprite, X_AudioSprite_handleEvent );\r
+ X_ViewPort[ 'unlisten' ]( [ X_EVENT_VIEW_ACTIVATE, X_EVENT_VIEW_DEACTIVATE, X_EVENT_UNLOAD ], X_AudioSprite_handleEvent );\r
+ X_AudioSprite = null;\r
break;\r
};\r
};\r