console.log( ' platform : ' + n.platform );\r
console.log( '-' );\r
\r
+ if( n.platform.indexOf( 'Win' ) + 1 ){\r
+ console.log( 'Win' );\r
+ acme.Windows = true;\r
+ if( n.platform === 'Win16' ) acme.Win16 = true;\r
+ if( n.platform === 'Win32' ) acme.Win32 = true;\r
+ if( n.platform === 'Win64' ) acme.Win64 = true;\r
+ if( n.platform === 'WinCE' ) acme.WinCE = true;\r
+ } else\r
+ if( n.platform.indexOf( 'Mac' ) + 1 ){\r
+ console.log( 'Mac' );\r
+ acme.Mac = true;\r
+ if( n.platform === 'MacPPC' || n.platform === 'MacPowerPC' ) acme.MacPPC = true;\r
+ if( n.platform === 'Mac68K' ) acme.Mac68K = true;\r
+ if( n.platform === 'MacIntel' ) acme.MacIntel = true;\r
+ } else\r
+ if( n.platform.indexOf( 'Linux' ) + 1 ){\r
+ console.log( 'Linux' );\r
+ acme.Linux = true;\r
+ };\r
+\r
+/*\r
+ * http://bizmakoto.jp/bizid/articles/1207/31/news004.html\r
+Chrome Android 4.0以上 Google\r
+Dolphin Browser HD Android 2.0.1以上 Mobotap\r
+Firefox Android 2.2以上 Mozilla\r
+Opera Mobile Android 1.6以上 Opera Software ASA\r
+Sleipnir Mobile Android 2.1以上 Fenrir\r
+ */\r
+ \r
if( window.opera ){\r
i = dua.indexOf( 'Opera' ); // Opera/\r
j = dua.indexOf( 'Version/' );\r
acme.IE8 = 8 <= acme.IE && acme.IE < 9;\r
acme.IE9 = 9 <= acme.IE && acme.IE < 10;\r
acme.MacIE = dua.indexOf( 'Mac_PowerPC' ) !== -1 || dua.indexOf( 'Mac_PPC' ) !== -1 || dua.indexOf( 'Mac_68K' ) !== -1;\r
- acme.IEMobile = dua.toLowerCase().indexOf( 'iemobile' ) !== -1 || n.platform === 'WinCE';\r
+ acme.IEMobile = dua.toLowerCase().indexOf( 'iemobile' ) !== -1 || acme.WinCE;\r
acme.WinPhone = dua.toLowerCase().indexOf( 'windows phone' ) !== -1;\r
console.log( '>> IE : ' + acme.IE + ' ActiveX : ' + acme.ActiveX );\r
// TODO XBox360, XBox1, Modern or Desktop, Standalone\r
return acme;\r
};\r
\r
- if( n.platform === 'Linux' && tv === 2 && dua.indexOf( 'Sony\/COM2\/' ) !== -1 ){\r
+ if( acme.Linux && tv === 2 && dua.indexOf( 'Sony\/COM2\/' ) !== -1 ){\r
acme.NetFront = 3.4;\r
console.log( '>> NetFront : ' + acme.NetFront );\r
return acme;\r
// in_page_jump\r
// on_screen_keyboard_show\r
// on_screen_keyboard_hide\r
- BEFORE_UPDATE : 21,// このイベントで要素のサイズを取得すると無限ループに!\r
- UPDATED : 22,\r
+ BEFORE_UPDATE : 21,// X_System このイベントで要素のサイズを取得すると無限ループに!\r
+ UPDATED : 22,// X_System\r
AFTER_UPDATE : 23,\r
\r
HASH_CHANGED : 24,\r
BACKEND_CHANGED : 30\r
};\r
\r
-X_Event_last = 29;\r
+X_Event_last = 30;\r
\r
X_TEMP.onSystemReady.push(\r
function(){\r
* _rawObject には HTMLElement, window, document, XHR といったイベントターゲットオブジェクトを設定します。\r
* _rawObject が設定されていると listen(), unlisten() 時に addEventListener(DOM Level2) や detachEvent(ie5~8), on~(DOM0) 等を操作します。\r
* _rawObject は最初の listen() 前に設定しておかないと addEventListener 等が意図したように行われません。\r
- * X.Node では非同期に HTMLElement を生成していて、要素生成以前に on, off を呼び出すことができます。これは適宜に migrateEvent, restoreEvent を呼んで解決しているためです。\r
+ * X.Node では非同期に HTMLElement を生成していて、要素生成以前に listen, unlisten を呼び出すことができます。これは適宜に X_EventDispatcher_toggleAllEvents を呼んで解決しているためです。\r
* @private\r
* @type {Object}\r
*/\r
* animation も怪しい、、、\r
*/\r
function X_EventDispatcher_iOSTransitionEndDispatch( e ){\r
- return X_Node_getXNode( this ).dispatch( X_Event_RenameTo[ e.type ] );\r
+ return X_Node_getXNode( this ).dispatch( X_Event_RenameTo[ e.type ] || e.type );\r
};\r
\r
/*\r
X_Timer_REQ_ANIME_FRAME =\r
window.requestAnimationFrame ||\r
window.webkitRequestAnimationFrame ||\r
- window.mozRequestAnimationFrame && window.mozCancelRequestAnimationFrame ||\r
+ window.mozRequestAnimationFrame ||\r
window.oRequestAnimationFrame ||\r
window.msRequestAnimationFrame ||\r
false,\r
if( ( f = list[ --i ] ).uid < uid ) break;\r
if( f.uid === uid ){\r
list.splice( i, 1 );\r
- l === 1 && X_Timer_CANCEL_ANIME_FRAME( X_Timer_requestID );\r
+ // gecko では無い場合がある\r
+ l === 1 && X_Timer_CANCEL_ANIME_FRAME && X_Timer_CANCEL_ANIME_FRAME( X_Timer_requestID );\r
break;\r
};\r
}; \r
case 'visibilitychange' :
X_ViewPort.asyncDispatch( ( X_ViewPort_active = document[ 'hidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE );
break;
+ case 'mozvisibilitychange' :
+ X_ViewPort.asyncDispatch( ( X_ViewPort_active = document[ 'mozHidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE );
+ break;
case 'webkitvisibilitychange' :
X_ViewPort.asyncDispatch( ( X_ViewPort_active = document[ 'webkitHidden' ] ) ? X.Event.VIEW_DEACTIVATE : X.Event.VIEW_ACTIVATE );
break;
//ブラウザの戻るボタンで戻ったときに呼ばれるイベントとかキャッシュとかそこらへんのこと
//http://d.hatena.ne.jp/koumiya/20080916/1221580149
- if( document[ 'hidden' ] !== undefined ) {// iOS 7+
+ if( document[ 'hidden' ] !== undefined ){// iOS 7+
X_EventDispatcher_systemListen( X_ViewPort_document, 'visibilitychange', X_ViewPort );
} else
- if( document[ 'webkitHidden' ] !== undefined ) {
+ if( document[ 'mozHidden' ] !== undefined ){
+ X_EventDispatcher_systemListen( X_ViewPort_document, 'mozvisibilitychange', X_ViewPort );
+ } else
+ if( document[ 'webkitHidden' ] !== undefined ){
X_EventDispatcher_systemListen( X_ViewPort_document, 'webkitvisibilitychange', X_ViewPort );
} else
- if( X_UA.iOS && window[ 'onpageshow' ] !== undefined ) {
+ if( X_UA.iOS && window[ 'onpageshow' ] !== undefined ){
X_EventDispatcher_systemListen( X_ViewPort, [ 'pageshow', 'pagehide' ] );
} else {
X_EventDispatcher_systemListen( X_ViewPort, [ 'focus', 'blur' ] );
if( !X_Node_updateTimerID ) X_Node_updateTimerID = X.Timer.requestFrame( X_Node_startUpdate );\r
};\r
\r
-function X_Node_startUpdate(){\r
+function X_Node_startUpdate( time ){\r
var removal, i, xnode, tmp;\r
\r
if( !X_Node_updateTimerID || X_ViewPort_readyState < X_TEMP.SYSTEM_EVENT_INIT ){\r
X.Timer.cancelFrame( X_Node_updateTimerID );\r
X_Node_updateTimerID = 0;\r
\r
-\r
- // このイベントでサイズを取ると無限ループに\r
- X_System._listeners && X_System._listeners[ X.Event.BEFORE_UPDATE ] && X_System.dispatch( X.Event.BEFORE_UPDATE );\r
+ if( time ){\r
+ // X.Timer 経由でないと発火しない このイベントでサイズを取ると無限ループに\r
+ X_System._listeners && X_System._listeners[ X.Event.BEFORE_UPDATE ] && X_System.dispatch( X.Event.BEFORE_UPDATE );\r
+ };\r
\r
removal = X_Node_reserveRemoval;\r
\r
\r
//console.log( 'end of _startUpdate().' );\r
\r
- X_System._listeners && X_System._listeners[ X.Event.UPDATED ] && X_System.dispatch( X.Event.UPDATED );\r
+ if( time ){\r
+ // X.Timer 経由でないと発火しない このイベントでサイズを取ると無限ループに\r
+ X_System._listeners && X_System._listeners[ X.Event.UPDATED ] && X_System.dispatch( X.Event.UPDATED ); \r
+ };\r
\r
X_ViewPort._listeners && X_ViewPort._listeners[ X.Event.AFTER_UPDATE ] && X_ViewPort.asyncDispatch( X.Event.AFTER_UPDATE );\r
//this._rawObject.style.visibility = tmp;\r
X_Node__afterActualCreate( xnodes[ i ] );\r
};\r
// src の onload があるので先ではないか?\r
- // ie の str から要素を作る場合、srcだけ イベント設定後ではないか?\r
+ // TODO ie の str から要素を作る場合、srcだけ イベント設定後ではないか?\r
X_EventDispatcher_toggleAllEvents( that, true );// イベントの復帰\r
}) :\r
X_UA_DOM.IE4 ? (function( that ){\r
if( !X_UA.IE || 9 <= X_UA.IE ){\r
X.Dom.Event = function( e, xnode ){\r
var originalType = e.type,\r
- type, pointerType,\r
+ type, pointerEventType,\r
touches, events,\r
altKey, ctrlKey, metaKey, shiftKey, target, related, force,\r
elm, i, n, time, touch, ev;\r
this.source = e.source;\r
break;\r
case 'progress' :\r
+ this.lengthComputable = e.lengthComputable;\r
this.loaded = e.loaded;\r
this.total = e.total;\r
break;\r
this.offsetX = e.offsetX;\r
this.offsetY = e.offsetY;\r
} else\r
- if( pointerType = X_Event_toPointer[ originalType ] ){\r
+ if( pointerEventType = X_Event_toPointer[ originalType ] ){\r
// Touch or Mouse\r
- //console.log( originalType + ' => ' + pointerType );\r
+ //console.log( originalType + ' => ' + pointerEventType );\r
\r
/* e.constructor === window.TouchEvent -> e.touches for iOS3.13 */\r
if( touches = e.changedTouches ){\r
- //console.log( originalType + ' => ' + pointerType );\r
+ //console.log( originalType + ' => ' + pointerEventType );\r
if( touches.length === 0 ){\r
alert( 'e.changedTouches.length === 0' );\r
};\r
- xnode._cancelMouse = pointerType;\r
+ xnode._cancelMouse = pointerEventType;\r
\r
events = [];\r
altKey = e.altKey;\r
target = touch.target;\r
related = touch.relatedTarget;\r
events[ i ] = {\r
- type : pointerType,\r
+ type : pointerEventType,\r
pointerType : 'touch',\r
target : X_Node_getXNode( target.nodeType === 3 ? target.parentNode : target ),// defeat Safari bug // xnodetouch.target,\r
currentTarget : xnode,\r
return events.length === 1 ? events[ 0 ] : events;\r
} else {\r
\r
- if( xnode._cancelMouse === pointerType ){\r
+ if( xnode._cancelMouse === pointerEventType ){\r
delete xnode._cancelMouse;\r
console.log( '**** xnode._cancelMouse ' + xnode._cancelMouse );\r
return [];\r
};\r
\r
// MouseEvent;\r
- this.type = type;\r
+ this.type = pointerEventType;\r
this.pointerType = 'mouse';\r
\r
this.button = e.button !== undefined ? e.button :\r
if( e.deltaY !== undefined ){\r
this.deltaX = e.deltaX;\r
this.deltaY = e.deltaY;\r
- this.deltaZ = e.deltaZ;\r
+ this.deltaZ = e.deltaZ || 0;\r
} else\r
if( e.wheelDeltaY !== undefined ){\r
this.deltaX = e.wheelDeltaX / 120;\r
// アニメ中の remove\r
\r
var X_Node_ANIMATIONS = [],\r
+ X_Node_Anime_reserved = false,\r
X_Node_Anime_updateTimerID = 0,\r
X_Node_Anime_needsDetection = false,\r
X_Node_Anime_hasTransform = !!X_Node_CSS_VENDER_PREFIX[ 'transform' ],\r
X_Node_Anime_hasTransition = !!X_Node_CSS_VENDER_PREFIX[ 'transitionDelay' ] && !X.UA.Opera, // Opera12(XP,8.1) 切った方がスムース\r
X_Node_Anime_transitionProps = X_Node_Anime_hasTransform ? X_Node_CSS_VENDER_PREFIX[ 'transform' ] : 'left,top';\r
\r
+// gpu化だけ transformX , willChange\r
+// 終了位置の変更\r
+// 中断\r
+\r
+\r
Node.prototype.animate = function( start, dest, duration, easing, wait ){\r
- var obj = this._anime || ( this._anime = {} ), current;\r
- \r
- if( X_Node_Anime_hasTransition && this._rawObject ){\r
- current = {}; //X_Node_Anime_getComputedPosition( this );\r
- };\r
+ var obj = this._anime || ( this._anime = {} );\r
\r
- obj.duration = X.Type.isFinite( duration ) && 0 <= duration ? duration : 500;\r
+ obj.duration = 0 <= duration && X.Type.isFinite( duration ) ? duration : 500;\r
obj.easing = ease[ easing ] || ease.circular;\r
// 現在 GPUレイヤーのtop になっているか?将来については phase で判定\r
obj.gpuParent = obj.gpuParent || false;\r
- obj.phase = duration === 0 ? 9 : 0; //\r
+ obj.phase = duration === 0 ? 9 : obj.phase === 9 ? 9 : 0; //\r
obj.wait = X.Type.isFinite( wait ) ? wait : 1000;\r
\r
obj.startTime = X_Timer_now();\r
- obj.startX = ( start.x || start.x === 0 ) ? start.x : obj.x || current && current.x || 0;\r
- obj.startY = ( start.y || start.y === 0 ) ? start.y : obj.y || current && current.y || 0;\r
- obj.startA = 0 <= start.opacity && start.opacity <= 1 ? start.opacity : obj.a || current && current.a || 1;\r
+ obj.startX = ( start.x || start.x === 0 ) ? start.x : obj.x || 0;\r
+ obj.startY = ( start.y || start.y === 0 ) ? start.y : obj.y || 0;\r
+ obj.startA = 0 <= start.opacity && start.opacity <= 1 ? start.opacity : obj.a || 1;\r
\r
obj.destTime = obj.startTime + obj.duration;\r
obj.destX = ( dest.x || dest.x === 0 ) ? dest.x : obj.destX || 0;\r
\r
X_Node_Anime_needsDetection = true;\r
if( X_Node_Anime_hasTransition ){\r
- X_Node_Anime_reserveUpdate();\r
+ X_Node_Anime_reserveUpdate( true );\r
} else {\r
X_Node_Anime_updateTimerID || ( X_Node_Anime_updateTimerID = X.Timer.requestFrame( X_Node_Anime_updateAnimationsNoTransition ) ); \r
};\r
return this;\r
};\r
\r
-function X_Node_Anime_reserveUpdate(){\r
- if( !X_Node_Anime_updateTimerID ){\r
- // Opera12 requestAnimationFrame では transition が動かない、、、\r
- X_Node_Anime_updateTimerID =\r
- X_UA.Opera ?\r
- X.Timer.once( 0, X_Node_Anime_updateAnimations ) :\r
- X.Timer.requestFrame( X_Node_Anime_updateAnimations );\r
+function X_Node_Anime_reserveUpdate( before ){\r
+ if( !X_Node_Anime_reserved ){\r
+ X_Node_Anime_reserved = true;\r
+ \r
+ if( X_Node_updateTimerID ){\r
+ console.log( before ? '> BEFORE_UPDATE' : '> UPDATED' );\r
+ X_System.listenOnce( before ? X.Event.BEFORE_UPDATE : X.Event.UPDATED, X_Node_Anime_updateAnimations );\r
+ } else {\r
+ console.log( '> Timer' );\r
+ // Opera12 requestAnimationFrame では transition が動かない、、、\r
+ X_Node_Anime_updateTimerID =\r
+ X_UA.Opera ?\r
+ X.Timer.once( 0, X_Node_Anime_updateAnimations ) :\r
+ X.Timer.requestFrame( X_Node_Anime_updateAnimations ); \r
+ };\r
};\r
};\r
\r
-function X_Node_Anime_updateAnimations(){\r
+function X_Node_Anime_updateAnimations( v ){\r
var i = X_Node_ANIMATIONS.length, ret, c = false;\r
\r
+ console.log( v.type || v );\r
+ \r
//console.log( 'updateAnimations ' + i + ' ' + X_Node_Anime_needsDetection );\r
\r
if( X_Node_Anime_needsDetection ) X_Node_Anime_detectAnimationLayers();\r
};\r
};\r
\r
+ if( X_Node_Anime_updateTimerID && X_Node_updateTimerID ) X_Node_startUpdate();\r
+ \r
X_Node_Anime_updateTimerID = 0;\r
+ X_Node_Anime_reserved = false;\r
if( c ){\r
X_Node_Anime_reserveUpdate();\r
};\r
function X_Node_Anime_detectAnimationLayers(){\r
var i = X_Node_ANIMATIONS.length,\r
l = i,\r
- j, xnode, parent, hasGPUChild, changed, remove;\r
+ j, xnode, parent, hasGPUChild, remove;\r
\r
for( ; i; ){\r
xnode = X_Node_ANIMATIONS[ --i ];\r
parent = hasGPUChild = false;\r
- //console.log( 'koko- ' + xnode._id + ' ' + xnode._anime.phase );\r
for( j = l; j; ){\r
_xnode = X_Node_ANIMATIONS[ --j ];\r
\r
if( xnode.parent === _xnode.parent ){\r
- //console.log( 'cont ' + xnode._anime.phase );\r
continue;\r
} else\r
if( _xnode.contains( xnode ) ){\r
- if( _xnode._anime.phase === 3 || _xnode._anime.phase === 10 ){\r
+ if( ( _xnode._anime.phase === 3 && _xnode._anime.gpuParent ) || _xnode._anime.phase === 10 ){\r
_xnode._anime.phase = 15;\r
} else\r
if( xnode._anime.gpuParent ){\r
- changed = parent = true;\r
+ parent = true;\r
xnode._anime.phase = xnode._anime.phase === 2 ? 6 : 15;// GPU レイヤーの解除 > アニメーションは継続, すでに終了フェイズなら破棄\r
} else\r
if( [ 7, 8, 9, 13, 14 ].indexOf( xnode._anime.phase ) !== -1 ){// GPU レイヤーの中止\r
- changed = parent = true;\r
+ parent = true;\r
xnode._anime.phase -= 8;\r
};\r
break;\r
} else\r
if( xnode.contains( _xnode ) ){\r
- if( xnode._anime.phase === 3 || xnode._anime.phase === 10 ){\r
+ if( ( xnode._anime.phase === 3 && xnode._anime.gpuParent ) || xnode._anime.phase === 10 ){\r
xnode._anime.phase = 15;\r
} else\r
if( _xnode._anime.gpuParent ){\r
- changed = hasGPUChild = true;\r
+ hasGPUChild = true;\r
_xnode._anime.phase = _xnode._anime.phase === 2 ? 6 : 15;// GPU レイヤーの解除 > アニメーションは継続, すでに終了フェイズなら破棄\r
} else\r
if( [ 7, 8, 9, 13, 14 ].indexOf( _xnode._anime.phase ) !== -1 ){// GPU レイヤーの中止\r
- changed = hasGPUChild = true;\r
+ hasGPUChild = true;\r
_xnode._anime.phase -= 8;\r
};\r
break;\r
if( !parent && xnode._anime.phase !== 15 ){\r
if( xnode._anime.phase === 0 ){\r
// 新規\r
- changed = changed || !xnode._anime.gpuParent;\r
xnode._anime.phase = hasGPUChild ? 7 : 8;// 非GPU -> GPU 子に GPU アニメをもつなら、タイミングをずらす。\r
} else\r
if( [ 3, 4, 10, 100 ].indexOf( xnode._anime.phase ) === -1 ){\r
// 非GPU -> GPU\r
- changed = changed || !xnode._anime.gpuParent;\r
- //console.log( 'koko? ' + xnode._anime.phase );\r
xnode._anime.phase = hasGPUChild ? 13 : 14;// 非GPU -> GPU 子に GPU アニメをもつなら、タイミングをずらす。\r
};\r
};\r
break;\r
case 0 : // 開始位置+アニメーションの設定 \r
case 8 :\r
+ X_Node_Anime_readyTransition( xnode );\r
X_Node_Anime_updatePosition( xnode, obj.startX, obj.startY, obj.startA, phase === 8 );\r
++obj.phase;\r
break;\r
case 1 :\r
case 9 : // 終了位置の設定\r
obj.gpuParent = phase === 9;\r
- X_Node_Anime_updateTransition( xnode, obj.duration, obj.easing );\r
+ obj.duration ? X_Node_Anime_updateTransition( xnode ) : X_Node_Anime_clearTransition( xnode );\r
X_Node_Anime_updatePosition( xnode, obj.destX, obj.destY, obj.destA, obj.gpuParent );\r
obj.phase = 2;\r
break;\r
return false;\r
\r
case 3 : // アニメーションの解除\r
- X_Node_Anime_updateTransition( xnode, 0 );\r
+ X_Node_Anime_clearTransition( xnode );\r
obj.phase = obj.gpuParent ? 10 : 4;\r
break;\r
\r
now = X_Timer_now();\r
time = obj.duration - now + obj.startTime;\r
if( time < 16 ){\r
- X_Node_Anime_updateTransition( xnode, 0 );\r
+ X_Node_Anime_clearTransition( xnode );\r
X_Node_Anime_updatePosition( xnode, obj.destX, obj.destY, obj.destA, phase === 14 );\r
obj.phase = phase === 14 ? 10 : 4;\r
} else {\r
obj.startA = current.a;\r
obj.duration = time;\r
obj.startTime = now;\r
- //X_Node_Anime_updateTransition( xnode, time, obj.easing );\r
X_Node_Anime_updatePosition( xnode, current.x, current.y, current.a, phase === 14 );\r
obj.phase = phase === 14 ? 9 : 1;\r
};\r
case 15 :\r
// GPU有効で停止(待機)している xnode の解除\r
console.log( 'GPU有効で停止(待機)している xnode の解除' + xnode._tag + xnode.getOrder() );\r
- X_Node_Anime_updateTransition( xnode, 0 );\r
+ X_Node_Anime_clearTransition( xnode );\r
X_Node_Anime_updatePosition( xnode, obj.destX, obj.destY, obj.destA, false );\r
obj.gpuTimerID && X.Timer.remove( obj.gpuTimerID );\r
return true;\r
console.log( 'stop() gpu:' + obj.gpuParent );\r
current = X_Node_Anime_getComputedPosition( xnode );\r
\r
- X_Node_Anime_updateTransition( xnode, 0 );\r
+ X_Node_Anime_clearTransition( xnode );\r
X_Node_Anime_updatePosition( xnode, current.x, current.y, current.a, obj.gpuParent );\r
obj.phase = obj.gpuParent ? 10 : 4;\r
break;\r
X_Node_Anime_needsDetection = true;\r
X_Node_Anime_reserveUpdate();\r
console.log( 'トランジション終了' );\r
- return X.Callback.UN_LISTEN | X.Callback.PREVENT_DEFAULT;\r
+ return X.Callback.UN_LISTEN | X.Callback.PREVENT_DEFAULT | X.Callback.STOP_PROPAGATION;\r
};\r
\r
function X_Node_Anime_releaseGPULayer(){\r
console.log( 'GPUレイヤーの破棄' );\r
};\r
\r
-function X_Node_Anime_updateTransition( xnode, time, easing ){\r
+function X_Node_Anime_readyTransition( xnode ){\r
+ xnode.css({\r
+ willChange : X_Node_Anime_transitionProps + ',opacity,width,height',\r
+ backfaceVisibility : 'hidden',\r
+ transitionTimingFunction : xnode._anime.easing.style,\r
+ transitionDelay : '0s'\r
+ });\r
+};\r
+\r
+function X_Node_Anime_updateTransition( xnode ){\r
// 開始座標のセット(新規のみ)\r
// アニメーション指定のセット(または解除)(対象のみ)\r
// 目標座標のセット\r
- if( time ){\r
- xnode.listenOnce( 'transitionend', X_Node_Anime_onTransitionEnd );\r
- } else {\r
- xnode.unlisten( 'transitionend', X_Node_Anime_onTransitionEnd );\r
- };\r
+ xnode.listenOnce( 'transitionend', X_Node_Anime_onTransitionEnd );\r
+\r
+ xnode.css({\r
+ transitionProperty : X_Node_Anime_transitionProps + ',opacity,width,height',\r
+ transitionDuration : xnode._anime.duration + 'ms'\r
+ });\r
+};\r
+\r
+function X_Node_Anime_clearTransition( xnode ){\r
+ // 開始座標のセット(新規のみ)\r
+ // アニメーション指定のセット(または解除)(対象のみ)\r
+ // 目標座標のセット\r
+ xnode.unlisten( 'transitionend', X_Node_Anime_onTransitionEnd );\r
+\r
xnode.css({\r
- transitionProperty : X_Node_Anime_transitionProps + ',opacity',\r
- willChange : time ? X_Node_Anime_transitionProps + ',opacity' : '',\r
- backfaceVisibility : time ? 'hidden' : '',\r
- transitionTimingFunction : time ? easing.style : '',\r
- transitionDelay : '0s',\r
- transitionDuration : time ? time + 'ms' : ''\r
+ willChange : '',\r
+ backfaceVisibility : '',\r
+ transitionTimingFunction : '',\r
+ transitionDelay : '',\r
+ transitionDuration : ''\r
});\r
};\r
\r
* flash player 10, ie6+, ff2+, safari3, opera9.5
* flash player 11, ie7+, ff4(?), safari5, opera11
* flash player 12, ie8+, ff17, opera11
+ *
+ * http://helpx.adobe.com/jp/flash-player/kb/228683.html
+ * flash player 9, Mac 10.1-10.3, 98, ME
+ * flash player 10.1, Mac 10.4
+ * flash player 10.3, Mac 10.5
+ * flash player 11.1, Win2k, Android 2.x-4.x
*/
var X_Pulgin_FLASH_VERSION =
!X_UA.IE && navigator.plugins[ 'Shockwave Flash' ] ?
parseFloat( navigator.plugins[ 'Shockwave Flash' ].version ) :
!X_UA.IE4 && !X_UA.IE5 && X_UA.ActiveX ? (function(){
- var obj = eval( 'var a;try{a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash")}catch(e){}a' ),
+ var obj = eval( 'var a,e;try{a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash")}catch(e){}a' ),
ver = obj && obj.GetVariable( '$version' ).split( ' ' ).join( '.' );
return parseFloat( ver ) || 0;
})() :
!X_UA.IE && navigator.plugins[ 'Unity Player' ] ?
parseFloat( navigator.plugins[ 'Unity Player' ].version ) :
!X_UA.IE4 && !X_UA.IE5 && X_UA.ActiveX ? (function(){
- var obj = eval( 'var a;try{a=new ActiveXObject("UnityWebPlayer.UnityWebPlayer.1")}catch(e){}a' );
+ var obj = eval( 'var a,e;try{a=new ActiveXObject("UnityWebPlayer.UnityWebPlayer.1")}catch(e){}a' );
return obj ? parseFloat( obj.GetPluginVersion() ) : 0;
})() :
0,
X_UA.ActiveX ? !!X_Pulgin_UNITY_VERSION :
navigator.mimeTypes &&
navigator.mimeTypes[ 'application/vnd.unity' ] &&
- navigator.mimeTypes[ 'application/vnd.unity' ].enabledPlugin;
+ navigator.mimeTypes[ 'application/vnd.unity' ].enabledPlugin,
+
+ X_Pulgin_GEARS_ENABLED =
+ window.GearsFactory ||
+ ( X_UA.ActiveX && 6 <= X_UA.IE ?
+ (function(){
+ return eval( 'var a,e;try{a=new ActiveXObject("Gears.Factory")}catch(e){}!!a' );
+ })() :
+ navigator.mimeTypes &&
+ navigator.mimeTypes[ 'application/x-googlegears' ] &&
+ navigator.mimeTypes[ 'application/x-googlegears' ].enabledPlugin
+ );
X.Pulgin = {
Flash : X_Pulgin_FLASH_VERSION,
- FlashEnabled : X_Pulgin_FLASH_ENABLED,
+ FlashEnabled : !!X_Pulgin_FLASH_ENABLED,
Silverlight : X_Pulgin_SILVER_LIGHT_VERSION,
- SilverlightEnabled : X_Pulgin_SILVER_LIGHT_ENABLED,
+ SilverlightEnabled : !!X_Pulgin_SILVER_LIGHT_ENABLED,
Unity : X_Pulgin_UNITY_VERSION,
- UnityEnabled : X_Pulgin_UNITY_ENABLED
+ UnityEnabled : !!X_Pulgin_UNITY_ENABLED,
+
+ GearsEnabled : X_Pulgin_GEARS_ENABLED
};
+
+if( X_Pulgin_GEARS_ENABLED ) alert( 'X_Pulgin_GEARS_ENABLED' );
+
// local への通信に対しては、netspeed を更新しない\r
X.Net = {\r
\r
- xhrGet : function( url ){\r
- return new X_NET_Queue( X_NET_TYPE_XHR, { method : 'GET', url : url } );\r
+ xhrGet : function( url, type ){\r
+ return new X_NET_Queue( X_NET_TYPE_XHR, { method : 'GET', url : url, type : type } );\r
},\r
\r
xhrPost : function( url, postbody ){\r
_busy : false,\r
_canceled : false,\r
_percent : 0,\r
+ _timerID : 0,\r
\r
load : function( obj ){\r
var raw = this._rawObject,\r
password = obj[ 'password' ],\r
headers = obj[ 'headers' ],\r
postbody = obj[ 'postbody' ],\r
- timeout = obj[ 'timeout' ],\r
+ timeout = obj[ 'timeout' ] || 20000,\r
temp;\r
\r
if( obj[ 'type' ] ){\r
};\r
};\r
};\r
- //if( raw.timeout !== undefined ) raw.timeout = timeout || -1;\r
- raw.open( method, url, false );\r
+ \r
+ raw.open( method, url, true );\r
+ \r
+ if( raw.responseType !== undefined ){\r
+ switch( this._type ){\r
+ case '' :\r
+ case 'text' :\r
+ raw.responseType = 'text';\r
+ break;\r
+ case 'json' :\r
+ case 'moz-json' :\r
+ break;\r
+ case 'document' :\r
+ case 'xml' :\r
+ case 'html' :\r
+ case 'htm' :\r
+ raw.responseType = 'document';\r
+ break;\r
+ case 'blob' :\r
+ case 'arraybuffer' :\r
+ raw.responseType = this._type;\r
+ break;\r
+ };\r
+ };\r
\r
// http://www.quirksmode.org/blog/archives/2005/09/xmlhttp_notes_r_1.html\r
// raw.overrideMimeType()\r
}; \r
};\r
\r
+ if( raw.timeout !== undefined ){\r
+ raw.timeout = timeout; //Firefox33 でエラー,,,\r
+ } else {\r
+ this._timerID = X.Timer.once( timeout, this, this.onTimeout );\r
+ }; \r
+ \r
// send 前にフラグを立てる,回線が早いと raw.send() 内で onload -> _busy = false ののち、 _busy = true するため。\r
this._busy = true;\r
\r
},\r
\r
cancel : function(){\r
- X.Net.XHR.CANCELABLE && this._rawObject.abort();\r
+ /* X.Net.XHR.CANCELABLE && */ this._rawObject.abort && this._rawObject.abort();\r
this._canceled = true;\r
+ this.asyncDispatch( X.Event.CANCELED );\r
},\r
\r
reset : function(){\r
+ // XMLHttpRequest で順番にリソースを取得する\r
+ // http://note.chiebukuro.yahoo.co.jp/detail/n16248\r
+ // TODO Opera 10.10 と Safari 4.1 はエラーが起きた XHR を再利用できないので毎回作る\r
+ \r
+ // \r
+ // domes.lingua.heliohost.org/dom-intro/load-save2.html\r
+ // 規定上は open() を呼び出すと XMLHttpRequest オブジェクトが未送信状態に戻りますが、\r
+ // Opera 10.10、Safari 4.1 では、同一オリジン制限に違反した XMLHttpRequest オブジェクトは再度 open() しても未送信状態に戻りません。\r
+ if( X_UA.Opera || X_UA.Webkit ){\r
+ \r
+ };\r
+\r
+ // XMLHttpRequest の使い方\r
+ // http://webos-goodies.jp/archives/50548720.html\r
+ // XMLHttpRequest オブジェクトを再利用する際も、 abort メソッドを呼び出す必要があるようです。\r
+ this._rawObject.abort && this._rawObject.abort();\r
+\r
this._method = this._type = '';\r
this._canceled = this._busy = false;\r
- this._percent = 0;\r
+ this._timerID && X.Timer.remove( this._timerID );\r
+ this._percent = this._timerID = 0;\r
},\r
\r
handleEvent : function( e ){\r
break;\r
\r
case 'progress' :\r
- // TODO X.Dom.Event でコピーしていないのでまだ動かない、、、\r
if( e.lengthComputable ){\r
this._percent = e.loaded / e.total;\r
live && this.asyncDispatch( { type : X.Event.PROGRESS, percent : this._percent } );\r
this._busy = false;\r
live && this.asyncDispatch( { type : X.Event.ERROR, status : raw.status } );\r
break;\r
- \r
- //case 'abort' :\r
- // this._busy = false;\r
- // this.asyncDispatch( { type : X.Event.ERROR, status : raw.status } );\r
- // break;\r
+\r
case 'timeout' : // Gecko 12.0 https://developer.mozilla.org/ja/docs/XMLHttpRequest/Synchronous_and_Asynchronous_Requests\r
this._busy = false;\r
- live && this.asyncDispatch( { type : X.Event.ERROR, status : raw.status } );\r
+ this.asyncDispatch( X.Event.TIMEOUT );\r
break;\r
};\r
},\r
\r
+ onTimeout : function(){\r
+ var raw = this._rawObject,\r
+ live = !X_NET_XHRWrapper._canceled || !this._busy;\r
+\r
+ if( raw.readyState < 3 ){\r
+ this._busy = false;\r
+ live && this.asyncDispatch( X.Event.TIMEOUT );\r
+ };\r
+ this._timerID = 0;\r
+ },\r
+ \r
onUploadProgress : X.Net.XHR.UL_PROGRESS && function( e ){\r
var raw = X_NET_XHRWrapper._rawObject.upload,\r
live = !X_NET_XHRWrapper._canceled,\r
);\r
// 同期リクエストでなければならない場合, unload, beforeunload時\r
\r
-\r
- // ie8 では timeout が有効, MSXML のバージョンは関係なさそう、、、\r
if( X_UA.IE8 ){\r
- X_NET_XHRWrapper.listen( [ 'readystatechange', 'error', 'abort', 'timeout' ] );\r
+ X_NET_XHRWrapper.listen( [ 'readystatechange', 'error', 'timeout' ] ); //, 'abort'\r
} else\r
if( X_UA.IE7 ){\r
if( X_URL_IS_LOCAL ){\r
X_NET_XHRWrapper.listen( 'readystatechange' ); // ie7 ActiveX の場合、error は不可\r
} else {\r
- X_NET_XHRWrapper.listen( [ 'readystatechange', 'error' ] ); // ie7 ActiveX の場合、error は不可\r
+ X_NET_XHRWrapper.listen( [ 'readystatechange', 'error' ] );\r
};\r
} else\r
if( X_Net_XHR_ACTIVE_X ){ // win ie5-6\r
X_NET_XHRWrapper.listen( 'readystatechange' );\r
} else \r
if( X.Net.XHR.PROGRESS ){\r
- X_NET_XHRWrapper.listen( [ 'load', 'progress', 'error', 'abort', 'timeout' ] );\r
+ X_NET_XHRWrapper.listen( [ 'load', 'progress', 'error', 'timeout' ] ); //, 'abort'\r
} else {\r
- X_NET_XHRWrapper.listen( [ 'load', 'readystatechange', 'error', 'abort', 'timeout' ] );\r
+ X_NET_XHRWrapper.listen( [ 'load', 'readystatechange', 'error', 'timeout' ] ); //, 'abort'\r
};\r
\r
if( X.Net.XHR.UL_PROGRESS ){\r
\r
X.Audio = {\r
- HTML5 : 1,\r
- Flash : 2,\r
- Silverlight : 3,\r
- Unity : 4,\r
- WMP : 5,\r
- RealPlayer : 6,\r
- QuickTime : 7,\r
+ WebAudio : 1,\r
+ HTML5 : 2,\r
+ Flash : 3,\r
+ Silverlight : 4,\r
+ Unity : 5,\r
+ WMP : 6,\r
+ RealPlayer : 7,\r
+ QuickTime : 8,\r
\r
create : function( sourceList, opt_option ){\r
return new X_AudioProxy( X.Type.isArray( sourceList ) ? X_Object_cloneArray( sourceList ) : [ sourceList ], opt_option || {} );\r
*/\r
\r
function X_Audio_detectBackend( proxy, sourceList, option ){\r
- var source = sourceList.shift() || '', \r
- parts = source.split( '?' )[ 0 ].split( '#' )[ 0 ].split( '.' ),\r
- ext = parts[ parts.length - 1 ],\r
- backend, ext, sup;\r
+ var source = sourceList.shift() || '', \r
+ parts = source.split( '?' )[ 0 ].split( '#' )[ 0 ].split( '.' ),\r
+ ext = parts[ parts.length - 1 ],\r
+ backend = X_Audio_BACKENDS[ 0 ],\r
+ ext, sup;\r
\r
- if( source && X_Audio_BACKENDS.length ){\r
+ if( source && backend ){\r
sup = [ proxy, option, sourceList, source, ext ];\r
sup[ 5 ] = sup;\r
- X_Audio_BACKENDS[ 0 ]\r
- .detect( source, ext )\r
- .listenOnce( [ 'support', 'nosupport' ], X_Audio_detectComplete, sup );\r
+ \r
+ proxy.listenOnce( [ 'support', 'nosupport' ], backend, X_Audio_detectComplete, sup );\r
+ backend.detect( proxy, source, ext ); \r
} else {\r
- proxy.asyncDispatch( 0, 'nobackend' );\r
+ proxy.asyncDispatch( 'nobackend' );\r
};\r
};\r
\r
function X_Audio_detectComplete( e, proxy, option, sourceList, source, ext, sup ){\r
var i = X_Audio_BACKENDS.indexOf( this ), backend;\r
\r
- this.unlisten( [ 'support', 'nosupport' ], X_Audio_detectComplete, sup );\r
+ proxy.unlisten( [ 'support', 'nosupport' ], backend, X_Audio_detectComplete, sup );\r
\r
switch( e.type ){\r
case 'support' :\r
proxy._backend = i;\r
- proxy.asyncDispatch( 0, { type : 'backendfound', option : option, source : source } );\r
+ proxy.asyncDispatch( { type : 'backendfound', option : option, source : source } );\r
break;\r
case 'nosupport' :\r
if( backend = X_Audio_BACKENDS[ i + 1 ] ){\r
- backend.detect( source, ext ).listen( [ 'support', 'nosupport' ], X_Audio_detectComplete, sup );\r
+ proxy.listenOnce( [ 'support', 'nosupport' ], backend, X_Audio_detectComplete, sup );\r
+ backend.detect( proxy, source, ext );\r
} else\r
if( sourceList.length ){\r
X_Audio_detectBackend( proxy, sourceList, option );\r
} else {\r
- proxy.asyncDispatch( 0, 'nobackend' );\r
+ proxy.asyncDispatch( 'nobackend' );\r
};\r
break;\r
};\r
},\r
\r
close : function(){\r
- return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].close.call( this );\r
+ return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].close( this );\r
},\r
\r
- play : function( position ){\r
- //console.log( 'proxy play ' + this._backend );\r
- return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].play.call( this, position );\r
+ play : function( startTime, endTime, loop, loopStartTime ){\r
+ var state, duration;\r
+ if( startTime ){\r
+ this.state( {\r
+ startTime : startTime,\r
+ endTime : endTime,\r
+ loop : loop,\r
+ loopStartTime : loopStartTime\r
+ } );\r
+ };\r
+ this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].play( this );\r
+ return this;\r
},\r
\r
- pause : function(){\r
- return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].pause.call( this );\r
+ seek : function( seekTime ){\r
+ var state = this.state();\r
+ if( state.playing ){\r
+ seekTime < state.endTime && this.state( { currentTime : seekTime } );\r
+ } else {\r
+ this.state( { startTime : seekTime } );\r
+ };\r
+ return this;\r
},\r
\r
- stop : function(){\r
- return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].stop.call( this );\r
+ pause : function(){\r
+ this.state().playing && X_Audio_BACKENDS[ this._backend ].pause( this );\r
+ return this;\r
},\r
\r
- loop : function( v ){\r
- return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].loop.call( this, v );\r
- },\r
+ state : function( obj ){\r
+ var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];\r
\r
- state : function(){\r
- return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].state.call( this );\r
+ if( obj === undefined ){\r
+ return backend ?\r
+ backend.state( this ) :\r
+ {\r
+ startTime : -1,\r
+ endTime : -1,\r
+ loopStartTime : -1,\r
+ currentTime : -1,\r
+ loop : false,\r
+ loaded : false,\r
+ error : false,\r
+ playing : false,\r
+ \r
+ source : this.source || '',\r
+ duration : 0\r
+ };\r
+ };\r
+ backend && backend.state( this, obj );\r
+ return this;\r
+ }, \r
+ \r
+ loop : function( v ){\r
+ var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];\r
+ if( v === undefined ){\r
+ return backend && backend.state( this ).loop;\r
+ };\r
+ backend && backend.state( this, { loop : v } );\r
+ return this;\r
},\r
\r
volume : function( v ){\r
- return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].volume.call( this, v );\r
- },\r
-\r
- startTime : function( time ){\r
- return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].startTime.call( this, time );\r
+ var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];\r
+ if( v === undefined ){\r
+ return backend && backend.state( this ).volume;\r
+ };\r
+ backend && backend.state( this, { volume : v } );\r
+ return this;\r
},\r
\r
- currentTime : function( time ){\r
- return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].currentTime.call( this, time );\r
+ currentTime : function( v ){\r
+ var backend = this._backend !== -1 && X_Audio_BACKENDS[ this._backend ];\r
+ if( v === undefined ){\r
+ return backend && backend.state( this ).currentTime;\r
+ };\r
+ backend && backend.state( this, { currentTime : v } );\r
+ return this;\r
},\r
\r
isPlaying : function(){\r
- return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].isPlaying.call( this );\r
+ return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].state( this ).playing;\r
}\r
\r
}\r
};\r
};\r
\r
+function X_AudioWrapper_updateStates( audioWrapper, obj ){\r
+ var playing = audioWrapper.playing,\r
+ k, v,\r
+ end = 0, seek = 0, volume = 0;\r
+ \r
+ for( k in obj ){\r
+ v = obj[ k ];\r
+ switch( k ){\r
+ case 'currentTime' :\r
+ v = X_AudioWrapper_timeStringToNumber( v );\r
+ if( X.Type.isNumber( v ) ){\r
+ if( playing ){\r
+ if( audioWrapper.state().currentTime !== v ){\r
+ audioWrapper.seekTime = v;\r
+ seek = 2;\r
+ };\r
+ break;\r
+ }; \r
+ } else {\r
+ continue;\r
+ };\r
+ k = 'startTime';\r
+ \r
+ case 'startTime' :\r
+ case 'endTime' :\r
+ case 'loopStartTime' :\r
+ v = X_AudioWrapper_timeStringToNumber( v );\r
+ if( X.Type.isNumber( v ) && audioWrapper[ k ] !== v ){\r
+ audioWrapper[ k ] = v;\r
+ // 再生中の endTime, currentTime の変更\r
+ if( playing && k === 'endTime' ) end = 1;\r
+ };\r
+ break;\r
\r
+ case 'loop' :\r
+ if( X.Type.isBoolean( v ) && audioWrapper[ k ] !== v ){\r
+ audioWrapper[ k ] = v;\r
+ };\r
+ break;\r
+\r
+ case 'volume' :\r
+ if( X.Type.isNumber( v ) ){\r
+ v = v < 0 ? 0 : 1 < v ? 1 : v;\r
+ if( audioWrapper[ k ] !== v ){\r
+ audioWrapper[ k ] = v;\r
+ // if playing -> update\r
+ if( playing ) volume = 4;\r
+ };\r
+ };\r
+ break;\r
+ };\r
+ };\r
+ \r
+ if( audioWrapper.endTime <= audioWrapper.startTime ||\r
+ audioWrapper.endTime <= audioWrapper.loopStartTime ||\r
+ audioWrapper.endTime < audioWrapper.seekTime ||\r
+ audioWrapper.duration < audioWrapper.endTime\r
+ ){\r
+ //alert( 'error @updateStateObject() begin:' + audioWrapper.startTime + ' end:' + audioWrapper.endTime + ' d:' + audioWrapper.duration + ' ls:' + audioWrapper.loopStartTime );\r
+ return 0;\r
+ };\r
+ \r
+ return end + seek + volume;\r
+};\r
+\r
+function X_AudioWrapper_timeStringToNumber( time ){\r
+ var ary, ms, s = 0, m = 0, h = 0;\r
+ if( X.Type.isNumber( time ) ) return time;\r
+ if( !X.Type.isString( time ) || !time.length ) return;\r
+\r
+ ary = time.split( '.' );\r
+ ms = parseInt( ( ary[ 1 ] + '000' ).substr( 0, 3 ) ) || 0;\r
+ \r
+ ary = ary[ 0 ].split( ':' );\r
+ if( 3 < ary.length ) return;\r
+ \r
+ switch( ary.length ){\r
+ case 0 :\r
+ break;\r
+ case 1 :\r
+ s = parseInt( ary[ 0 ] ) || 0;\r
+ break;\r
+ case 2 :\r
+ m = parseInt( ary[ 0 ] ) || 0;\r
+ s = parseInt( ary[ 1 ] ) || 0;\r
+ if( 60 <= s ) alert( 'invalid time string ' + time );\r
+ break;\r
+ case 3 :\r
+ h = parseInt( ary[ 0 ] ) || 0;\r
+ m = parseInt( ary[ 1 ] ) || 0;\r
+ s = parseInt( ary[ 2 ] ) || 0;\r
+ if( 60 <= s ) alert( 'invalid time string ' + time );\r
+ if( 60 <= m ) alert( 'invalid time string ' + time );\r
+ break;\r
+ default :\r
+ alert( 'invalid time string ' + time );\r
+ };\r
+ ms = ( h * 3600 + m * 60 + s ) * 1000 + ms;\r
+ return ms < 0 ? 0 : ms;\r
+};\r
};\r
};\r
\r
- X_Audio_HTML5Audio = X_Class_override(\r
- new X.EventDispatcher(),\r
+ X_Audio_HTML5Audio = \r
{\r
backendName : 'HTML5 Audio',\r
/*\r
* - volume, muted iPhone(iOS4-6)、Android(2.3.6)では動作せず。\r
* - FireFox3.6, Android 2.3.6については、src変更後、load()を呼び出さないと切り替わらなかった。iPhoneはload()が不要。\r
*/ \r
- detect : function( source, ext ){\r
+ detect : function( proxy, source, ext ){\r
var ok, mineType = 'audio/' + ext;\r
switch( ext ){\r
case 'mp3' :\r
- ok = X_UA.IE || X_UA.Chrome || X_UA.Safari; //( X_UA.OS === 'windows' && X_UA.Safari );\r
+ ok = X_UA.IE || X_UA.Chrome || ( X_UA.Windows && X_UA.Safari );\r
mineType = 'audio/mpeg';\r
break;\r
case 'ogg' :\r
ok = 2 <= X_UA.Gecko || 10.6 <= X_UA.Opera; // firefox4+(Gecko2+)\r
break;\r
case 'wav' :\r
- ok = X_UA.Gecko || X_UA.Opera || X_UA.Safari; //( X_UA.OS === 'windows' && X_UA.Safari );\r
+ ok = X_UA.Gecko || X_UA.Opera || ( X_UA.Windows && X_UA.Safari );\r
//mineType = 'audio/wav'; // audio/x-wav ?\r
break;\r
default :\r
ok = X_Audio_rawAudio.canPlayType( mineType );\r
};\r
\r
- this.asyncDispatch( ok ? 'support' : 'nosupport' );\r
- \r
- return this;\r
+ proxy.asyncDispatch( ok ? 'support' : 'nosupport' );\r
},\r
\r
register : function( proxy, source, option ){\r
X_Audio_HTML5Audio_LIVE_LIST.push( new X_Audio_HTML5AudioWrapper( proxy, source, option ) );\r
},\r
\r
- close : function(){\r
- return getHTML5AudioWrapper( this ).close();\r
+ close : function( proxy ){\r
+ getHTML5AudioWrapper( proxy ).close();\r
},\r
\r
- play : function( position ){\r
- return getHTML5AudioWrapper( this ).play( position );\r
- },\r
- \r
- pause : function(){\r
- return getHTML5AudioWrapper( this ).pause();\r
+ play : function( proxy ){\r
+ getHTML5AudioWrapper( proxy ).play();\r
},\r
\r
- stop : function(){\r
- return getHTML5AudioWrapper( this ).stop();\r
- },\r
- \r
- loop : function( v ){\r
- return getHTML5AudioWrapper( this ).loop( v );\r
- },\r
- \r
- state : function(){\r
- return getHTML5AudioWrapper( this ).state();\r
+ pause : function( proxy ){\r
+ getHTML5AudioWrapper( proxy ).pause();\r
},\r
\r
- volume : function( v ){\r
- return getHTML5AudioWrapper( this ).volume( v );\r
- },\r
- \r
- startTime : function( time ){\r
- return getHTML5AudioWrapper( this ).startTime( time );\r
- },\r
- \r
- currentTime : function( time ){\r
- return getHTML5AudioWrapper( this ).currentTime( time );\r
- },\r
- \r
- isPlaying : function(){\r
- return getHTML5AudioWrapper( this ).isPlaying();\r
+ state : function( proxy, obj ){\r
+ return getHTML5AudioWrapper( proxy ).state( obj );\r
}\r
- }\r
- );\r
+ };\r
\r
X_Audio_BACKENDS.push( X_Audio_HTML5Audio );\r
\r
\r
proxy : null,\r
\r
- _closed : true,\r
- _lastUserAction : '',\r
+ startTime : 0,\r
+ endTime : 1 / 0,\r
+ loopStartTime : 0,\r
+ seekTime : 0,\r
+ duration : 1 / 0,\r
\r
- _loop : false,\r
- _startTime : 0,\r
- _volume : 0.5,\r
- _autoplay : false,\r
+ playing : false,\r
+ error : 0, \r
+ loop : false,\r
+ volume : 0.5,\r
+\r
+ _timerID : 0,\r
+ \r
+ _closed : true,\r
\r
Constructor : function( proxy, source, option ){\r
this.proxy = proxy;\r
this._closed = false;\r
\r
- if( option.loop ) this._loop = true;\r
- if( option.startTime ) this._startTime = option.startTime;\r
- if( option.volume ) this._volume = option.volume;\r
+ X_AudioWrapper_updateStates( this, option );\r
\r
this._rawObject = X_Audio_rawAudio || new Audio( source );//X.Node.create( 'audio', { src : source } ).appendToRoot();//( X.X_Node_systemNode );\r
\r
\r
//document.body.appendChild( this._rawObject );\r
\r
- this._rawObject.volume = this._volume;\r
this._rawObject.autoplay = false;\r
option.autoplay && X.Timer.once( 100, this, this.play );\r
\r
* http://uguisu.skr.jp/html/table3.html\r
*/\r
handleEventProxy : function( e ){\r
- console.log(e.type);\r
+ //console.log(e.type);\r
\r
switch( e.type ){\r
case 'loadstart' : // ブラウザがコンテンツの検索を開始した場合に発生\r
break;\r
case 'progress' : // ブラウザがコンテンツの取得を実行した場合に発生\r
//console.log( e.loaded + ' ' + e.total * 100 + '%' );\r
- console.log( this._rawObject.buffered.end(0) / this._rawObject.duration * 100 + '%' );\r
+ this._rawObject.duration && console.log( this._rawObject.buffered.end(0) / this._rawObject.duration * 100 + '%' );\r
break;\r
+ case 'loadedmetadata' : // ブラウザがメディアリソースの長さと寸法を判定した場合に発生\r
+ case 'loadeddata' : // コンテンツの表示を現在の再生位置で初めて行えるようになった場合に発生\r
+ case 'canplay' : // 今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生\r
+ case 'canplaythrough' : // 今すぐに再生を開始してもバッファリングで停止することなく最後まで表示できると予測している場合に発生\r
+ this.duration = this._rawObject.duration * 1000;\r
+ this.endTime = this.duration < this.endTime ? this.duration : this.endTime;\r
+ //console.log( this.duration );\r
+ break;\r
+ \r
case 'suspend' : // ブラウザが意図的にコンテンツの取得を現在行っていない場合に発生(ダウンロードは未完了)\r
case 'abort' : // ダウンロードの完了前にコンテンツの取得を停止した場合に発生(この停止はエラーによるものではない)\r
case 'error' : // コンテンツの取得実行中にエラーが発生した場合に発生\r
case 'stalled' : // ブラウザがコンテンツの取得を試みたが、データがまだ用意されていない場合に発生\r
case 'play' : // 再生が開始された。play()メソッドからの復帰後に発生する場合に発生\r
case 'pause' : // 再生が一時停止された。pauseメソッドからの復帰後に発生する場合に発生\r
- case 'loadedmetadata' : // ブラウザがメディアリソースの長さと寸法を判定した場合に発生\r
- case 'loadeddata' : // コンテンツの表示を現在の再生位置で初めて行えるようになった場合に発生\r
+\r
case 'waiting' : // 次のフレームが利用不可のため再生を停止したが、そのフレームがやがて利用可能になると想定している場合に発生\r
case 'playing' : // 再生が開始された場合に発生\r
- case 'canplay' : // 今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生\r
- case 'canplaythrough' : // 今すぐに再生を開始してもバッファリングで停止することなく最後まで表示できると予測している場合に発生\r
+\r
case 'seeking' : // シークがtrueに変化し、イベントを発生させるのに十分な時間がシーク操作にかかっている場合に発生\r
case 'seeked' : // シークがfalseに変化した場合に発生\r
case 'timeupdate' : // 通常の再生が行われ現在の再生位置の変化が起こった場合に発生\r
break;\r
\r
case 'ended' :\r
- //!this._closed && this._lastUserAction !== 'stop' && this._loop && this.play();\r
+ if( !this._closed && this.loop ){\r
+ this.play();\r
+ } else {\r
+ this._timerID && X.Timer.remove( this._timerID );\r
+ delete this._timerID;\r
+ delete this.playing;\r
+ };\r
break;\r
\r
case 'ratechange' : // defaultPlaybackRate属性とplaybackRate属性のどちらかが更新された場合に発生\r
},\r
\r
close : function(){\r
- // pool, proxy を外す\r
- //this.kill();\r
+ // 【javascript】モバイル向けブラウザでも音を鳴らしたい【WebAudio】\r
+ // http://ingaouhou.com/archives/3633\r
+ // ・使い終わったインスタンスはload()しておくとやや安定\r
+ this.playing && this.pause();\r
+ delete this._closed;\r
+ \r
+ this._rawObject.src = '';\r
+ this._rawObject.load();\r
},\r
\r
- play : function( position ){\r
+ play : function( seekTime ){\r
+ var begin, halfway;\r
+ \r
// もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気\r
- if( this._closed ) return;\r
- this._lastUserAction = 'play';\r
- \r
- if( X_UA.Chrome ){ // [CHROME][FIX] volume TODO どの version で 修正される?\r
- // [!] delay\r
- X.Timer.once( 0, this, this._fixForChrome, [ this._rawObject.volume ] );\r
- this._rawObject.volume = 0;\r
- };\r
+ if( this._closed ) return;\r
+\r
+ begin = ( seekTime || seekTime === 0 ) ? seekTime : this.playing ? this.loopStartTime : this.startTime;\r
+ this._rawObject.currentTime = begin / 1000;\r
\r
- if( !this._rawObject.paused ){\r
- this.currentTime( this._startTime );\r
+ if( !this.playing ){\r
+ if( X_UA.Chrome ){ // [CHROME][FIX] volume TODO どの version で 修正される?\r
+ // [!] delay\r
+ X.Timer.once( 0, this, this._fixForChrome );\r
+ this._rawObject.volume = 0;\r
+ } else {\r
+ this._rawObject.volume = this.volume;\r
+ };\r
+ this._rawObject.play();\r
+ this.playing = true;\r
};\r
- this._rawObject.play();\r
- },\r
- \r
- // [CHROME][FIX] volume\r
- _fixForChrome : X_UA.Chrome && function( volume ){\r
- !this._closed && ( this._rawObject.volume = volume );\r
+\r
+ halfway = this.endTime < this.duration;\r
+ this._timerID && X.Timer.remove( this._timerID );\r
+ \r
+ if( halfway ){\r
+ this._timerID = X.Timer.once( this.endTime - begin, this, this._onEnded );\r
+ } else {\r
+ delete this._timerID;\r
+ };\r
+ \r
+ if( !this._interval ){\r
+ this._interval = X.Timer.add( 1000, 0, this, this._onInterval );\r
+ };\r
},\r
+ \r
+ // [CHROME][FIX] volume\r
+ _fixForChrome : X_UA.Chrome && function(){\r
+ !this._closed && ( this._rawObject.volume = this.volume );\r
+ },\r
+\r
+ _onInterval : function(){\r
+ if( !this.playing ){\r
+ delete this._interval;\r
+ return X_Callback_UN_LISTEN;\r
+ };\r
+ this.proxy.dispatch( 'timeupdate' );\r
+ },\r
+ \r
+ _onEnded : function(){\r
+ delete this._timerID;\r
+ if( this.playing ){\r
+ if( this.loop ){\r
+ this.play();\r
+ } else {\r
+ console.log( '中断:' + this._rawObject.currentTime + ' ' + this.endTime );\r
+ this.pause();\r
+ this.dispatch( 'ended' );\r
+ };\r
+ };\r
+ },\r
\r
pause : function(){\r
- if( !this._closed && !this._rawObject.error ){\r
- this._lastUserAction = 'pause';\r
- this._rawObject.pause(); \r
- };\r
- },\r
- \r
- stop : function(){\r
- if( !this._closed && !this._rawObject.error ){\r
- this._lastUserAction = 'stop';\r
+ this._timerID && X.Timer.remove( this._timerID );\r
+ delete this._timerID;\r
+ \r
+ if( this.palying && !this._rawObject.error ){\r
this._rawObject.pause();\r
- this.currentTime( this._startTime );\r
+ delete this.playing;\r
};\r
},\r
- \r
- loop : function( v ){\r
- if( v === undefined ) return this._loop;\r
- this._rawObject.loop = this._loop = v;\r
- },\r
\r
- state : function(){\r
- var paused = !!this._rawObject.paused,\r
- ended = !!this._rawObject.ended;\r
- \r
- if( this._lastUserAction === 'stop' ){\r
- if( paused ){\r
- paused = false;\r
- ended = true;\r
- };\r
- };\r
+ state : function( obj ){\r
+ var result;\r
+ \r
+ if( obj === undefined ){\r
+ return {\r
+ startTime : this.startTime,\r
+ endTime : this.endTime,\r
+ loopStartTime : this.loopStartTime,\r
+ currentTime : this._rawObject.currentTime * 1000,\r
+ loop : this.loop,\r
+ volume : this.volume,\r
+ /*\r
+ http://www.w3schools.com/tags/av_prop_error.asp\r
+ 1 = MEDIA_ERR_ABORTED - fetching process aborted by user\r
+ 2 = MEDIA_ERR_NETWORK - error occurred when downloading\r
+ 3 = MEDIA_ERR_DECODE - error occurred when decoding\r
+ 4 = MEDIA_ERR_SRC_NOT_SUPPORTED - audio/video not supported\r
+ */\r
+ error : this._rawObject.error || 0, // 0, 1 ~ 4\r
+ playing : this.palying && !this._rawObject.error && !this._rawObject.paused && !this._rawObject.ended, \r
+ duration : this.duration || 0\r
+ }; \r
+ };\r
\r
- return {\r
- loop : this._rawObject.loop,\r
- error : this._rawObject.error || 0, // 0, 1 ~ 4\r
- paused : paused,\r
- ended : ended,\r
- source : this._rawObject.src || '',\r
- duration : this._rawObject.duration || 0\r
- };\r
- },\r
- \r
- volume : function( v ){\r
- if( v === undefined ) return this.audio.volume;\r
- this._rawObject.volume = v;\r
- },\r
- \r
- startTime : function( time ){\r
- if( time === undefined ) return this._startTime;\r
- this._startTime = time;\r
- },\r
- \r
- currentTime : function( time ){\r
- if( time === undefined ) return this._rawObject.currentTime;\r
- this._rawObject.currentTime = time;\r
- },\r
- \r
- isPlaying : function(){\r
- return !this._rawObject.error && !this._rawObject.paused && !this._rawObject.ended;\r
+ result = X_AudioWrapper_updateStates( this, obj );\r
+ \r
+ if( result & 2 ){ // seek\r
+ this.play( this.seekTime );\r
+ delete this.seekTime;\r
+ } else {\r
+ if( result & 1 ){\r
+ halfway = this.endTime < this.duration;\r
+ this._timerID && X.Timer.remove( this._timerID );\r
+ \r
+ if( halfway ){\r
+ this._timerID = X.Timer.once( this.endTime - this._rawObject.currentTime * 1000, this, this._onEnded ); \r
+ } else {\r
+ delete this._timerID;\r
+ };\r
+ };\r
+ if( result & 4 ){\r
+ this._rawObject.volume = this.volume;\r
+ };\r
+ };\r
+ \r
}\r
\r
}\r
};\r
};\r
\r
- X_Audio_SLAudio = X_Class_override(\r
- new X.EventDispatcher(),\r
+ X_Audio_SLAudio = \r
{\r
backendName : 'Silverlight Audio',\r
\r
- detect : function( source, ext ){\r
+ detect : function( proxy, source, ext ){\r
var ok = ext === 'mp3' || ext === 'wma';\r
- \r
- this.asyncDispatch( ok ? 'support' : 'nosupport' );\r
- \r
- return this;\r
+ proxy.asyncDispatch( ok ? 'support' : 'nosupport' ); \r
},\r
\r
register : function( proxy, source, option ){\r
X_Audio_SLAudio_LIVE_LIST.push( new X_Audio_SLAudioWrapper( proxy, source, option ) );\r
},\r
\r
- close : function(){\r
- return getSLAudioWrapper( this ).close();\r
- },\r
- \r
- play : function( position ){\r
- return getSLAudioWrapper( this ).play( position );\r
+ close : function( proxy ){\r
+ return getSLAudioWrapper( proxy ).close();\r
},\r
\r
- pause : function(){\r
- return getSLAudioWrapper( this ).pause();\r
- },\r
- \r
- stop : function(){\r
- return getSLAudioWrapper( this ).stop();\r
+ play : function( proxy ){\r
+ return getSLAudioWrapper( proxy ).play();\r
},\r
\r
- loop : function( v ){\r
- return getSLAudioWrapper( this ).loop( v );\r
- },\r
- \r
- state : function(){\r
- return getSLAudioWrapper( this ).state();\r
+ pause : function( proxy ){\r
+ return getSLAudioWrapper( proxy ).pause();\r
},\r
\r
- volume : function( v ){\r
- return getSLAudioWrapper( this ).volume( v );\r
- },\r
- \r
- startTime : function( time ){\r
- return getSLAudioWrapper( this ).startTime( time );\r
- },\r
- \r
- currentTime : function( time ){\r
- return getSLAudioWrapper( this ).currentTime( time );\r
- },\r
- \r
- isPlaying : function(){\r
- return getSLAudioWrapper( this ).isPlaying();\r
+ state : function( proxy, obj ){\r
+ return getSLAudioWrapper( proxy ).state( obj );\r
}\r
- }\r
- );\r
+ };\r
\r
X_Audio_BACKENDS.push( X_Audio_SLAudio );\r
\r
{\r
_isSilverlight : true, // for X.EventDispatcher.listen\r
proxy : null,\r
+ \r
+ startTime : 0,\r
+ endTime : 0,\r
+ loopStartTime : 0,\r
+ seekTime : 0,\r
+ duration : 0,\r
+ \r
+ playing : false,\r
+ error : 0, \r
+ loop : false,\r
+ volume : 0.5,\r
+ \r
_onload : '',\r
_callback : null, \r
xnodeObject : null,\r
- \r
- _loop : false,\r
_source : '',\r
- _error : 0,\r
_ended : true,\r
_paused : false,\r
- _volume : 0.5,\r
- _startTime : 0,\r
_lastUserAction : '',\r
_lastState : '',\r
- _duration : 0,\r
_interval : 0, // setInterval timer id\r
\r
Constructor : function( proxy, source, option ){\r
\r
// TODO embed\r
this.proxy = proxy;\r
+ this._source = source;\r
this._onload = 'XAudioSilverlightOnLoad' + ( ++X_Audio_SLAudio_uid );\r
this._callback = window[ this._onload ] = X_Callback_create( this, this.onSLReady, [ option.autoplay ] );\r
this.xnodeObject = X_Node_body\r
'<param name="background" value="#00000000">' + // transparent\r
'<param name="windowless" value="true">' +\r
'<param name="source" value="#silverlightaudio">' + // XAML ID\r
- '<param name="onload" value="' + this._onload + '">'// + // bond to global\r
+ '<param name="onload" value="' + this._onload + '">' // + // bond to global\r
//'<param value="2.0.31005.0" name="minRuntimeVersion">' +\r
//'<param value="true" name="autoUpgrade">' +\r
//'<param name="onerror" value="slerror">' // bond to global\r
);\r
- \r
- this._loop = option.loop;\r
- this._source = source;\r
- if( option.volume ) this._volume = option.volume;\r
- if( option.startTime ) this._startTime = option.startTime;\r
+ X_AudioWrapper_updateStates( this, option );\r
\r
this.listenOnce( X.Event.KILL_INSTANCE );\r
},\r
X_Callback_correct( this._callback );\r
delete this._callback;\r
\r
- //if( sender.findName('media') ) alert( 'exist' );\r
-\r
sender.children.add(\r
sender.GetHost().\r
content.\r
CreateFromXaml(\r
'<Canvas xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">' +\r
- '<MediaElement x:Name="media" Source="' + this._source + '" Volume="' + this._volume + '" AutoPlay="false" />' +\r
+ '<MediaElement x:Name="media" Source="' + this._source + '" Volume="' + this.volume + '" AutoPlay="false" />' +\r
'</Canvas>'));\r
\r
this._rawObject = sender.findName('media'); // x:Name='media'\r
switch( e.type ){\r
\r
case 'MediaFailed' :\r
- this._error = 4;\r
- this._ended = true;\r
+ this.error = 4;\r
+ this.playing = false;\r
+ this._ended = true;\r
this._paused = false;\r
- \r
this.proxy.dispatch( 'error' ); // open failed\r
break;\r
+\r
case 'MediaOpened' :\r
// http://msdn.microsoft.com/ja-jp/library/bb979710(VS.95).aspx\r
- this._duration = this._rawObject.NaturalDuration.Seconds;\r
- // TODO 'canplaythrough'\r
- this.proxy.dispatch( 'canplay' );\r
+ this.duration = this._rawObject.NaturalDuration.Seconds * 1000;\r
+ this.endTime = this.endTime || this.duration;\r
+ // TODO 'canplaythrough'\r
+ this.proxy.asyncDispatch( 'loadstart' );\r
+ this.proxy.asyncDispatch( 'loadedmetadata' );\r
+ this.proxy.asyncDispatch( 'loadeddata' );\r
+ this.proxy.asyncDispatch( 'canplay' );\r
+ this.proxy.asyncDispatch( 'canplaythrough' );\r
break;\r
- case 'MediaEnded' :\r
- this.currentTime(this._startTime);\r
- \r
- if (this._loop) {\r
- this._rawObject.play();\r
- }\r
+\r
+ case 'MediaEnded' : \r
+ this.loop && this.playing && this.play();\r
break;\r
+\r
case 'CurrentStateChanged' :\r
- lastState = this._lastState,\r
+ lastState = this._lastState,\r
currentState = this._rawObject.CurrentState;\r
\r
// ignore consecutive events or 'Closed' == 'Error'\r
};\r
this._lastState = currentState; // update last state\r
\r
- switch (currentState) {\r
- case 'Buffering':\r
- case 'Opening':\r
- break;\r
- \r
+ switch( currentState ){\r
+ case 'Buffering' :\r
+ case 'Opening' :\r
+ switch( this._lastUserAction ){\r
+ case 'play' :\r
+ this.proxy.dispatch( 'waiting' );\r
+ break;\r
+ case 'seek' :\r
+ this.proxy.dispatch( 'seeking' );\r
+ break;\r
+ case 'pause' :\r
+ break;\r
+ };\r
+ break;\r
+\r
// media.play(none supported file) -> 'Error'\r
// media.play(file not found) -> 'Closed'\r
// media.load -> 'Error'\r
case 'Error':\r
case 'Closed':\r
- this._error = 4;\r
- this._ended = true;\r
- this._paused = false;\r
- this.proxy.dispatch( 'error' );\r
- break;\r
- \r
+ this.error = 4;\r
+ this.playing = false;\r
+ this._ended = true;\r
+ this._paused = false;\r
+ this.proxy.dispatch( 'error' );\r
+ break;\r
+\r
// userAction.pause() -> MediaState('Paused') -> x\r
// userAction.stop() -> MediaState('Paused') -> x\r
// userAction.play() + file end -> MediaState('Paused') -> uueventfire('ended')\r
case 'Paused':\r
- switch (this._lastUserAction) {\r
- case 'play': // play() -> file end -> event('ended')\r
- this._ended = true;\r
- this._paused = false;\r
- this.proxy.dispatch( 'ended' );\r
- this.currentTime(this._startTime);\r
- break;\r
- case 'pause':\r
- this._ended = false;\r
- this._paused = true;\r
- break;\r
- case 'stop':\r
- this._ended = true;\r
- this._paused = false;\r
- }\r
- break;\r
- \r
+ this.playing = false;\r
+ \r
+ switch( this._lastUserAction ){\r
+ case 'play': // play() -> file end -> event('ended')\r
+ case 'seek':\r
+ this._ended = true;\r
+ this._paused = false;\r
+ this.proxy.dispatch( 'ended' );\r
+ this._currentTime( this.startTime );\r
+ break;\r
+ case 'pause':\r
+ this._ended = false;\r
+ this._paused = true;\r
+ break;\r
+ case 'stop':\r
+ this._ended = true;\r
+ this._paused = false;\r
+ };\r
+ break;\r
+\r
// media.play -> 'Playing'\r
case 'Playing':\r
- this._error = 0;\r
- this._ended = false;\r
- this._paused = false;\r
- this.proxy.dispatch( 'playing' );\r
- break;\r
- \r
+ this.error = 0;\r
+ this.playing = true;\r
+ this._ended = false;\r
+ this._paused = false;\r
+ this.proxy.dispatch( 'playing' );\r
+ break;\r
+\r
// stop()\r
case 'Stopped':\r
- this._ended = true;\r
- this._paused = false;\r
- this.currentTime(this._startTime);\r
- }\r
+ this.playing = false;\r
+ this._ended = true;\r
+ this._paused = false;\r
+ this._currentTime( this.startTime );\r
+ break;\r
+ };\r
break;\r
- \r
+\r
case X.Event.KILL_INSTANCE :\r
if( this._onload ){\r
- window[ this._onload ] = null;\r
- this._callback.kill();\r
+ // window への delete に ie5 は対応しないが、そもそも ie5 は Silverlight に非対応\r
+ delete window[ this._onload ];\r
+ delete this._onload;\r
+ X_Callback_correct( this._callback );\r
};\r
this.xnodeObject.destroy();\r
break;\r
},\r
\r
close : function(){\r
- if (this._interval) {\r
- X.Timer.remove( this._interval );\r
- delete this._interval;\r
- };\r
+ this.playing && this.pause();\r
this.proxy.dispatch( 'ended' );\r
this.kill();\r
},\r
\r
// SilverlightAudio.play\r
- play : function(){\r
- if (!this._error) {\r
- this._lastUserAction = 'play';\r
- if (this._ended) {\r
- this.currentTime(this._startTime);\r
- }\r
- \r
- this._rawObject.play();\r
- this.proxy.dispatch( 'play' );\r
- \r
- if (!this._interval) {\r
- this._interval = X.Timer.add( 1000, 0, this, this._onInterval );\r
- }\r
- }\r
- },\r
- \r
- _onInterval : function(){\r
- this.isPlaying() && this.proxy.dispatch( 'timeupdate' );\r
+ play : function( seekTime ){\r
+ var begin, halfway;\r
+ \r
+ // もし kill 後に autoplayTimer で呼ばれても、_closed==true なので平気\r
+ if( this.error ) return;\r
+\r
+ begin = ( seekTime || seekTime === 0 ) ? seekTime : this.playing ? this.loopStartTime : this.startTime;\r
+ this._lastUserAction = this.playing ? 'seek' : 'play';\r
+ \r
+ this._currentTime( begin );\r
+ this._rawObject.Volume = this.volume;\r
+ \r
+ if( !this.playing ){\r
+ this._rawObject.play();\r
+ this.proxy.dispatch( 'play' );\r
+ \r
+ this.playing = true;\r
+ };\r
+ \r
+ halfway = this.endTime < this.duration;\r
+ this._timerID && X.Timer.remove( this._timerID );\r
+ \r
+ if( halfway ){\r
+ this._timerID = X.Timer.once( this.endTime - begin, this, this._onEnded );\r
+ } else {\r
+ delete this._timerID;\r
+ };\r
+ \r
+ if( !this._interval ){\r
+ this._interval = X.Timer.add( 1000, 0, this, this._onInterval );\r
+ };\r
},\r
+ \r
+ _onInterval : function(){\r
+ if( !this.playing ){\r
+ delete this._interval;\r
+ return X_Callback_UN_LISTEN;\r
+ };\r
+ this.proxy.dispatch( 'timeupdate' );\r
+ },\r
+ \r
+ _onEnded : function(){\r
+ delete this._timerID;\r
+ if( this.playing ){\r
+ if( this.loop ){\r
+ this.play();\r
+ } else {\r
+ this.pause();\r
+ this.dispatch( 'ended' ); \r
+ };\r
+ };\r
+ },\r
\r
// SilverlightAudio.pause\r
pause : function(){\r
- if (!this._error) {\r
+ if( !this.error ){\r
this._lastUserAction = 'pause';\r
+ this.playing = false;\r
this._paused = true;\r
- this._ended = false;\r
+ this._ended = false;\r
this._rawObject.pause();\r
this.proxy.dispatch( 'pause' );\r
- }\r
- },\r
- \r
- // SilverlightAudio.stop\r
- stop : function(){\r
- if (!this._error) {\r
- this._lastUserAction = 'stop';\r
- this._rawObject.stop();\r
- this._ended = true;\r
- }\r
- },\r
- \r
- // SilverlightAudio.loop\r
- loop : function(value){ // @param Boolean: true is loop\r
- // @return Boolean/void: true is loop\r
- if (value === undefined) {\r
- return this._loop;\r
- }\r
- this._loop = value;\r
- },\r
- \r
- // SilverlightAudio.state\r
- state : function(){ // @return Hash: { loop, error, paused, ended, source, duration }\r
- return {\r
- loop : this._loop,\r
- error : this._error,\r
- paused : this._paused,\r
- ended : this._ended,\r
- source : this._source,\r
- duration : this._duration\r
};\r
},\r
\r
- // SilverlightAudio.volume\r
- volume : function(value){ // @param Number: 0.0 ~ 1.0\r
- // @return Number/void:\r
- if (value === undefined) {\r
- return this._volume;\r
- }\r
- this._volume = value;\r
- this._rawObject.Volume = value;\r
- },\r
- \r
- // SilverlightAudio.startTime\r
- startTime : function(time){ // @param Number: time\r
- // @return Number/void:\r
- if (time === undefined) {\r
- return this._startTime;\r
- }\r
- this._startTime = time;\r
- },\r
- \r
- // SilverlightAudio.currentTime\r
- currentTime : function(time){ // @param Number: time\r
- // @return Number/void:\r
- var position = this._rawObject.Position; // [!] create instance\r
+ // SilverlightAudio.state\r
+ state : function( obj ){ // @return Hash: { loop, error, paused, ended, source, duration }\r
+ var result;\r
\r
- if (time === undefined) {\r
- return position.Seconds;\r
+ if( obj === undefined ){\r
+ return {\r
+ startTime : this.startTime,\r
+ endTime : this.endTime,\r
+ loopStartTime : this.loopStartTime,\r
+ currentTime : this._rawObject.Position.Seconds * 1000,\r
+ loop : this.loop,\r
+ volume : this.volume,\r
+ error : this.error,\r
+ playing : this.playing,\r
+ duration : this.duration || 0 // this._rawObject.NaturalDuration.Seconds;\r
+ };\r
};\r
-\r
- position.Seconds = time; // set current time\r
\r
- this._rawObject.Position = position; // [!] reattach instance\r
+ result = X_AudioWrapper_updateStates( this, obj );\r
+ \r
+ if( result & 2 ){ // seek\r
+ this.play( this.seekTime );\r
+ delete this.seekTime;\r
+ } else {\r
+ if( result & 1 ){\r
+ halfway = this.endTime < this.duration;\r
+ this._timerID && X.Timer.remove( this._timerID );\r
+ \r
+ if( halfway ){\r
+ this._timerID = X.Timer.once( this.endTime - this._rawObject.Position.Seconds * 1000, this, this._onEnded );\r
+ } else {\r
+ delete this._timerID;\r
+ };\r
+\r
+ };\r
+ if( result & 4 ){\r
+ this._rawObject.Volume = this.volume;\r
+ };\r
+ };\r
},\r
\r
- // SilverlightAudio.isPlaying\r
- isPlaying : function(){ // @return Boolean:\r
- if (!this._error && !this._paused && !this._ended) {\r
- return true;\r
+ // SilverlightAudio.currentTime\r
+ _currentTime : function( time ){ // @param Number: time\r
+ var position = this._rawObject.Position; // [!] create instance\r
+ \r
+ position.Seconds = time / 1000; // set current time\r
+ \r
+ this._rawObject.Position = position; // [!] reattach instance\r
}\r
- return false;\r
- }\r
\r
}\r
);\r