* <h4>必須プロパティ</h4>\r
* <dl>\r
* <dt>url<dd>URL\r
- * <dt>type<dd>'xhr', 'jsonp', 'image', 'img'\r
+ * <dt>type<dd>'xhr', 'jsonp', 'form', 'image', 'img'\r
* <dt>xhr<dd>URL { url : 'hoge', type : 'xhr' } の省略形\r
* <dt>jsonp<dd>URL { url : 'hoge', type : 'jsonp' } の省略形\r
+ * <dt>form<dd>URL { url : 'hoge', type : 'form' } の省略形\r
* <dt>image, img<dd>URL { url : 'hoge', type : 'image' } の省略形\r
* </dl>\r
* <h4>XHR 用プロパティ</h4>\r
* <dt>params<dd>url パラメータを object で渡すことが出来る。\r
* <dt>callbackName<dd>callback(json) コールバック名が固定されている際に指定。または &callback=hoge 以外の名前でコールバックを指定する場合に params と callbackName に書いておく。url パラメータに callback が無く、callbackName もない場合、フレームワーク内で自動で設定される\r
* <dt>charset<dd>ページと異なるjsonpを読み込む場合に指定 'EUC-JP', 'Shift-JIS' 等 script タグの charset に入る。https://code.google.com/p/ajaxzip3/issues/detail?id=5\r
- * <dt>useFireWall<dd>異なるドメインに jsonp を読み込んだ後、xdomain iframe 通信を使ってデータを受け取る。不正なコードの実行を防ぐことが出来る、未実装\r
+ * <dt>useFireWall<dd>異なるドメインに jsonp を読み込んだ後、xdomain iframe 通信を使ってデータを受け取る。不正なコードの実行を防ぐことが出来る(はず)、未実装\r
* </dl>\r
* \r
* <h4>Form 用プロパティ</h4>\r
* <dl>\r
- * <dt>params<dd>url パラメータを object で渡すことが出来る。\r
* <dt>method<dd>'GET' or 'POST'\r
- * <dt>target<dd>'_self', '_parent', '_top' の場合、ページから離脱する。target を指定せず同一ドメインの場合 response に body.innerHTML が返る。\r
+ * <dt>params<dd>パラメータ object は input タグの name & value に展開される。object を入れ子にすることはできない。\r
+ * <dt>target<dd>'_self', '_parent', '_top' の場合、ページから離脱する。target を指定せず同一ドメインの場合 response に body.innerHTML が返る。TODO X.Window\r
+ * <dt>timeout<dd>ms タイムアウト時間、省略可能\r
+ * <dt>charset<dd>未実装\r
* </dl>\r
* \r
* @alias X.Net\r
opt[ 'auth' ] = auth; // auth は deep copy されるとまずい\r
};\r
\r
- // params を url に追加\r
- if( opt[ 'params' ] ){\r
+ // params を url に追加 但し form は除く\r
+ if( opt[ 'params' ] && type !== X_NET_TYPE_FORM ){\r
url = X_URL_create( url, opt[ 'params' ] );\r
delete opt[ 'params' ];\r
}; \r
load : function( option ){
//createURL
var url = option[ 'url' ],
- params = option[ 'params' ],
callback = option[ 'callbackName' ],
charset = option[ 'charset' ],
json2Path = window.RegExp ? 'js/libs/json2.js' : 'js/libs/json2_regfree.js',
if( !X_URL_isSameProtocol( url ) ){
return X_JSONP[ 'asyncDispatch' ]( X_EVENT_ERROR );
};
-
- url = X_URL_create( url, params );
-
+
if( !callback && !( callback = X_URL_paramToObj( url.split( '?' )[ 1 ] )[ 'callback' ] ) ){
url += '&callback=cb';
callback = 'cb';
//{+netform"<form>によるGETとPOST"(動的に生成したフォームによるGETとPOST。)[+net,+ninjaiframe]\r
\r
-var X_FormSender_errorTimerID, X_FormSender_onloadCount = 0;\r
+var X_FormSender_errorTimerID,\r
+ X_FormSender_isLeave,\r
+ X_FormSender_onloadCount = 0;\r
\r
X_TEMP.X_FormSender_init = function(){\r
X_FormSender = X_Class_override( X_NinjaIframe(), X_TEMP.X_FormSender_params );\r
\r
/*\r
* form 構築時に "><script> といった文字列の挿入を禁止するために " を エスケープする\r
- * TODO 改行文字を消す\r
+ * TODO 改行文字を消す escape?\r
*/\r
function X_FormSender_escapeQuote( str ){\r
\r
};\r
\r
X_TEMP.X_FormSender_params = {\r
- \r
+\r
_busy : false,\r
_canceled : false,\r
\r
- timeout : 1000,\r
- isJump : false, // ページを離脱するか?\r
- \r
load : function( option ){\r
//createURL\r
- var params = option[ 'params' ] || {},\r
- target = option[ 'target' ],\r
+ var params = option[ 'params' ] || {},\r
+ target = option[ 'target' ],\r
+ timeout = option[ 'timeout' ],\r
+ // http://search.web-sun.com/zatu/charset.html\r
+ // charset = option[ 'charset' ],\r
html, k;\r
\r
target = target === '_self' ? '_parent' : target === '_blank' ? '_self' : target || '_self',\r
html = [\r
+ // <meta http-equiv="Content-Type" content="text/html; charset=euc-jp">\r
'<form method="', X_FormSender_escapeQuote( option[ 'method' ] || 'GET' ), \r
'" action="', X_FormSender_escapeQuote( option[ 'url' ] || '' ), \r
'" target="', X_FormSender_escapeQuote( target ),\r
'">' ];\r
\r
- if( target === '_top' || target === '_parent' ) X_FormSender.isJump = true;\r
- if( 0 <= option[ 'timeout' ] ) X_FormSender.timeout = option[ 'timeout' ];\r
+ X_FormSender_isLeave = target === '_top' || target === '_parent';\r
+\r
\r
for( k in params ){\r
// TODO 使用すべきでない name\r
};\r
\r
html.push( '</form><script>document.forms[0].submit();</script>' );\r
- \r
+\r
X_FormSender\r
[ 'refresh' ]( html.join( '' ) )\r
[ 'listen' ]( [ 'ninjaload', 'ninjaerror' ], X_FormSender_iframeListener );\r
- \r
+ \r
+ if( 0 < timeout ){\r
+ X_FormSender_errorTimerID = X_FormSender[ 'asyncDispatch' ]( timeout, { type : X_EVENT_ERROR, 'timeout' : true } );\r
+ };\r
+ \r
X_FormSender._busy = true;\r
},\r
\r
\r
reset : function(){\r
X_FormSender._busy = X_FormSender._canceled = false;\r
- X_FormSender[ 'unlisten' ]( [ 'ninjaload', 'ninjaerror' ], X_FormSender_iframeListener );\r
- X_FormSender[ 'refresh' ]( '' );\r
+ X_FormSender\r
+ [ 'unlisten' ]( [ 'ninjaload', 'ninjaerror' ], X_FormSender_iframeListener )\r
+ [ 'refresh' ]( '' );\r
X_FormSender_errorTimerID && X_Timer_remove( X_FormSender_errorTimerID );\r
X_FormSender_errorTimerID = X_FormSender_onloadCount = 0;\r
}\r
\r
switch( e.type ){\r
case 'ninjaload' :\r
- if( X_FormSender.isJump ){\r
+ if( X_FormSender_isLeave ){\r
return;\r
};\r
\r
if( ++X_FormSender_onloadCount === 1 ){\r
- X_FormSender_errorTimerID = X_FormSender[ 'asyncDispatch' ]( X_FormSender.timeout, { type : X_EVENT_ERROR, 'timeout' : true } );\r
-\r
- // TODO レスポンスの html にアクセスしたい場合\r
- // TODO samedomain or xiframe-sender\r
- \r
idoc = this[ '_rawObject' ].contentDocument || this._iwin.document,\r
- \r
+\r
X_FormSender[ 'asyncDispatch' ]( { type : X_EVENT_SUCCESS, response : idoc && idoc.body ? idoc.body.innerHTML : '' } );\r
};\r
break;\r
var X_WebAudio_context = // 4s 以下ではない iPad 2G または iPad mini 1G 以下ではない, iPod touch 4G 以下ではない
- !X_UA[ 'iPhone_4s' ] && !X_UA[ 'iPad_2Mini1' ] && !X_UA[ 'iPod_4' ] &&
+ !X_UA[ 'iPhone_4s' ] && !X_UA[ 'iPad_2Mini1' ] && !X_UA[ 'iPod_4' ] &&
+ // iOS7 以上で HTML Audio が鳴らない問題を見ていくよ
+ // !X_UA[ 'iOS' ] &&
// Android2 + Gecko で WebAudio が極めて不安定
!( X_UA[ 'Fennec' ] && X_UA[ 'Android' ] < 3 ) &&
// AOSP でも WebAudio を不完全に実装するものがある, touch の有無も不明のため一律に切ってしまう
_onDecodeSuccess : function( buffer ){
this.onDecodeSuccess && this._onDecodeComplete();
- if ( !buffer ) {
+ if( !buffer ){
this.errorState = 2;
this[ 'asyncDispatch' ]( X_EVENT_COMPLETE );
return;
unregister : function( webAudio ){
var list = this.webAudioList,
i = list.indexOf( webAudio );
+
if( 0 < i ){
list.splice( i, 1 );
if( !list.length ){
if ( !buffer ) {
this.error = loader.errorState;
-
this.disatcher[ 'dispatch' ]({
type : X_EVENT_ERROR,
error : loader.errorState,
\r
var\r
X_HTMLAudio,\r
- \r
- // ended が発生しない timeupdate 内で play() を呼ぶ (未検証) 不具合確認は iOS4,6\r
+ // iOS7.1, 8.3 で確認.seeking -> seeked の間の currentTime の値が全くあてにならないので無視する。\r
+ X_HTMLAudio_seekingFixIOS = 7 <= X_UA[ 'iOS' ],\r
+ // ended が発生しない timeupdate 内で play() を呼ぶ (未検証) 不具合確認は iOS4,6 iOS7.1,8.3ではpause->ended起きてる 但し iOS7.1 でも 6 と同じ症状になることがある\r
X_HTMLAudio_endedFixIOS = X_UA[ 'iOS' ] < 7,\r
// Android 2.3.5 で ended 時に audio.src='';audio.src=src;audio.load() を実施。 2.3.4 でも問題なし。\r
X_HTMLAudio_endedFixAOSP2 = X_UA[ 'AOSP' ] < 3,\r
* win opera12 volume, mute の変更が2度目以降できない\r
*/\r
X_HTMLAudio_volumeEnabled = !( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ) && !X_UA[ 'Opera' ],\r
- // Gecko PC + Android でseek時に再生がしばしば止まる問題の修正\r
+ // Gecko PC + Android でseek時に再生がしばしば止まる問題の修正、iOS8でも確認\r
X_HTMLAudio_needPlayForSeek = X_UA[ 'iOS' ] || X_UA[ 'Gecko' ],\r
// \r
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
- X_HTMLAudio_playTrigger = ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ) ? 'canplay' : X_UA[ 'iOS' ] ? 'suspend' : X_UA[ 'Blink' ] < 32 ? 'stalled' : 'canplaythrough',\r
+ X_HTMLAudio_playTrigger = ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ) ? 'canplay' :\r
+ X_UA[ 'iOS' ] < 8 ? 'suspend' : // iOS7.x以下\r
+ X_UA[ 'iOS' ] ? 'loadedmetadata' : // iOS8以上は\r
+ X_UA[ 'Blink' ] < 32 ? 'stalled' : 'canplaythrough',\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' ] < 36 && X_UA[ 'Android' ] ),\r
+ X_HTMLAudio_durationFix = // iOS8.1(シュミレータでは不要)\r
+ X_UA[ 'iOS' ] < 8 || X_UA[ 'ChromeWV' ] || ( X_UA[ 'WinPhone' ] && X_UA[ 'IE9' ] ) ||\r
+ ( X_UA[ 'Windows' ] && 12 <= X_UA[ 'Opera' ] ) || ( X_UA[ 'Blink' ] < 36 && X_UA[ 'Android' ] ),\r
\r
X_HTMLAudio_shortPlayFix = X_UA[ 'AOSP' ],\r
\r
\r
_endedFixON : false,\r
\r
+ _seekingFixON : false,\r
+ \r
'Constructor' : function( disatcher, source, option ){\r
var raw;\r
\r
//'loadstart', 'load',\r
'progress', //'error',\r
// 'suspend', 'abort', 'emptied', 'stalled',\r
- // 'play', 'pause', 'seeked', 'ratechange', 'volumechange',\r
+ // 'play', 'pause', 'ratechange', 'volumechange',\r
+ 'seeked',\r
'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough',\r
'playing', 'waiting', 'seeking',\r
'durationchange', 'timeupdate', 'ended' ] );\r
'durationchange', 'timeupdate', 'ended' ], this.onDebug );\r
\r
if( X_HTMLAudio_endedFixAOSP2 || X_HTMLAudio_endedFixAOSP4 ){\r
- raw.loop = true; // loop を使えば ended で止まること回避できるかも 但し ended イベントが起きなくなる\r
+ raw.loop = true; // loop を使えば ended で止まること回避できる 但し ended イベントが起きなくなる\r
};\r
\r
if( X_HTMLAudio_need1stTouch ){\r
\r
// TODO firefox で 短い音声でtimeupdate, ended が発火しない <- 最後の音に無音部分を追加する\r
case 'timeupdate' : // 通常の再生が行われ現在の再生位置の変化が起こった場合に発生\r
+ if( this._seekingFixON ){\r
+ eventType = X_EVENT_MEDIA_SEEKING;\r
+ } else\r
if( this._durationFixPhase === 8 ){\r
this._durationFixPhase = 0;\r
this._readyState |= 1;\r
end = X_Audio_getEndTime( this ) + this._shortPlayFixTime;\r
//console.log( now + ' / ' + end );\r
if( ( 0 + end <= 0 + now ) || // 0+ なぜか iem9 で必要,,,\r
- ( now < this._lastCurrentTime ) ){ // loop した場合\r
+ ( now < this._lastCurrentTime && now < 2000 ) ){\r
+ //( ( X_HTMLAudio_endedFixAOSP2 || X_HTMLAudio_endedFixAOSP4 ) && ( now < this._lastCurrentTime && now < 1000 ) ) ){\r
+ // loop して0付近に戻った場合\r
+ // iOS8.4 ではこのタイミングで now が last より 0.1秒後退している場合がある\r
+ // iOS7.1 ではもっと小さい場合がある,,,\r
if( this.autoLoop ){\r
- console.log( '☆★☆ 曲の最後に到達 @timeupdate now-end:' + ( now - end ) );\r
+ console.log( '☆★☆ 曲の最後に到達 @timeupdate now-end:' + ( now - end ) + ' now:' + now + ' last:' + this._lastCurrentTime );\r
ended = true;\r
//if( X_HTMLAudio_endedFixIOS ) actualEnded = true;\r
} else {\r
eventType = !this._durationFixPhase && !this._endedFixON ? X_EVENT_MEDIA_PLAYING : X_EVENT_MEDIA_WAITING;\r
//case 'play' : // 再生が開始された。play()メソッドからの復帰後に発生する場合に発生\r
//case 'pause' : // 再生が一時停止された。pauseメソッドからの復帰後に発生する場合に発生\r
- //case 'seeked' : \r
//case 'ratechange' : // defaultPlaybackRate属性とplaybackRate属性のどちらかが更新された場合に発生\r
//case 'volumechange' : // volume属性とmuted属性のどちらかが変化した場合に発生\r
break;\r
\r
+ case 'seeked' :\r
+ if( this._seekingFixON ) this._seekingFixON = false;\r
+ break;\r
+ \r
case 'waiting' : // 次のフレームが利用不可のため再生を停止したが、そのフレームがやがて利用可能になると想定している場合に発生\r
eventType = X_EVENT_MEDIA_WAITING;\r
break;\r
case 'seeking' : // シークがtrueに変化し、イベントを発生させるのに十分な時間がシーク操作にかかっている場合に発生\r
eventType = X_EVENT_MEDIA_SEEKING;\r
+ if( X_HTMLAudio_seekingFixIOS ) this._seekingFixON = true;\r
break;\r
};\r
\r