*\r
*/\r
\r
-X.Dom.Parser = {\r
+X_Dom_Parser = {\r
+ CHARS : {\r
+ A:1,B:1,C:1,D:1,E:1,F:1,G:1,H:1,I:1,J:1,K:1,L:1,M:1,N:1,O:1,P:1,Q:1,R:1,S:1,T:1,U:1,V:1,W:1,X:1,Y:1,Z:1,\r
+ a:2,b:2,c:2,d:2,e:2,f:2,g:2,h:2,i:2,j:2,k:2,l:2,m:2,n:2,o:2,p:2,q:2,r:2,s:2,t:2,u:2,v:2,w:2,x:2,y:2,z:2,\r
+ '0' : 4, '1' : 4, '2' : 4, '3' : 4, '4' : 4, '5' : 4, '6' : 4, '7' : 4, '8' : 4, '9' : 4,\r
+ \r
+ '\t' : 16, '\r\n' : 16, '\r' : 16, '\n' : 16, '\f' : 16, '\b' : 16, ' ' : 16\r
+ },\r
alphabets : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',\r
whiteSpace : '\t\r\n\f\b ',\r
\r
empty : X.Dom.DTD.EMPTY,\r
\r
// Block Elements - HTML 4.01\r
- block : {address:1,applet:1,blockquote:1,button:1,center:1,dd:1,del:1,dir:1,div:1,dl:1,dt:1,fieldset:1,form:1,frameset:1,hr:1,iframe:1,ins:1,isindex:1,li:1,map:1,menu:1,noframes:1,noscript:1,object:1,ol:1,p:1,pre:1,script:1,table:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1,ul:1},\r
-\r
+ block : {ADDRESS:1,APPLET:1,BLOCKQUOTE:1,BUTTON:1,CENTER:1,DD:1,DEL:1,DIR:1,DIV:1,DL:1,DT:1,FIELDSET:1,FORM:1,FRAMESET:1,HR:1,IFRAME:1,INS:1,\r
+ ISINDEX:1,LI:1,MAP:1,MENU:1,NOFRAMES:1,NOSCRIPT:1,OBJECT:1,OL:1,P:1,PRE:1,SCRIPT:1,TABLE:1,TBODY:1,TD:1,TFOOT:1,TH:1,THEAD:1,TR:1,UL:1 },\r
// Inline Elements - HTML 4.01\r
- inline : {a:1,abbr:1,acronym:1,applet:1,b:1,basefont:1,bdo:1,big:1,br:1,button:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,iframe:1,img:1,input:1,ins:1,kbd:1,label:1,map:1,object:1,q:1,s:1,samp:1,script:1,select:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,textarea:1,tt:1,u:1,'var':1},\r
-\r
+ inline : {A:1,ABBR:1,ACRONYM:1,APPLET:1,B:1,BASEFONT:1,BDO:1,BIG:1,BR:1,BUTTON:1,CITE:1,CODE:1,DEL:1,DFN:1,EM:1,FONT:1,I:1,IFRAME:1,IMG:1,\r
+ INPUT:1,INS:1,KBD:1,LABEL:1,MAP:1,OBJECT:1,Q:1,S:1,SAMP:1,SCRIPT:1,SELECT:1,SMALL:1,SPAN:1,STRIKE:1,STRONG:1,SUB:1,SUP:1,TEXTAREA:1,TT:1,U:1,VAR:1},\r
// Elements that you can, intentionally, leave open\r
// (and which close themselves)\r
- closeSelf : {colgroup:1,dd:1,dt:1,li:1,options:1,p:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1}, // add tbody\r
+ closeSelf : {OLGROUP:1,DD:1,DT:1,LI:1,OPTIONS:1,P:1,TBODY:1,TD:1,TFOOT:1,TH:1,THEAD:1,TR:1}, // add tbody\r
\r
sisters : {\r
- th : { td : 1 },\r
- td : { th : 1 },\r
- dt : { dd : 1 },\r
- dd : { dt : 1 },\r
- colgroup : { caption : 1 },\r
- thead : { caption : 1, colgroup : 1 },\r
- tfoot : { caption : 1, colgroup : 1, thead : 1, tbody : 1 },\r
- tbody : { caption : 1, colgroup : 1, thead : 1, tfoot : 1 }\r
+ TH : { TD : 1 },\r
+ TD : { TH : 1 },\r
+ DT : { DD : 1 },\r
+ DD : { DT : 1 },\r
+ COLGROUP : { CAPTION : 1 },\r
+ THEAD : { CAPTION : 1, COLGROUP : 1 },\r
+ TFOOT : { CAPTION : 1, COLGROUP : 1, THEAD : 1, TBODY : 1 },\r
+ TBODY : { CAPTION : 1, COLGROUP : 1, THEAD : 1, TFOOT : 1 }\r
},\r
/*\r
* http://www.tohoho-web.com/html/tbody.htm\r
fillAttrs : X.Dom.Attr.noValue, //{checked:1,compact:1,declare:1,defer:1,disabled:1,ismap:1,multiple:1,nohref:1,noresize:1,noshade:1,nowrap:1,readonly:1,selected:1};\r
\r
// Special Elements (can contain anything)\r
- special : { script : 1, style : 1, plaintext : 1, xmp : 1, textarea : 1 },\r
+ special : { SCRIPT : 1, STYLE : 1, PLAINTEXT : 1, XMP : 1, TEXTAREA : 1 },\r
\r
exec : function( html, handler, async ){\r
- var special = X.Dom.Parser.special,\r
- plainText = X.Dom.Parser.plainText,\r
+ var special = X_Dom_Parser.special,\r
+ //plainText = X_Dom_Parser.plainText,\r
startTime = async && X.getTime(),\r
- _parseStartTag = X.Dom.Parser._parseStartTag,\r
- _parseEndTag = X.Dom.Parser._parseEndTag,\r
+ _parseStartTag = X_Dom_Parser._parseStartTag,\r
+ _parseEndTag = X_Dom_Parser._parseEndTag,\r
stack = async ? async[ 1 ] : [],\r
lastHtml = html,\r
chars, last, text, index;\r
last = stack[ stack.length - 1 ];\r
\r
// Make sure we're not in a script or style element\r
- if ( last && special[ last.toLowerCase() ] === 1 ) {\r
- if( 0 <= ( index = html.toLowerCase().indexOf( '</' + last.toLowerCase() ) ) ){\r
+ if ( last && special[ last ] === 1 ) {\r
+ if( 0 <= ( index = html.toUpperCase().indexOf( '</' + last ) ) ){\r
handler.chars( html.substring( 0, index ) );\r
if( index = _parseEndTag( stack, handler, html ) ){\r
html = html.substring( index );\r
\r
if( async && startTime + 15 <= X.getTime() && html ){\r
handler.progress( 1 - html.length / async[ 0 ] );\r
- X.Timer.once( 0, X.Dom.Parser.exec, [ html, handler, async ] );\r
+ X.Timer.once( 0, X_Dom_Parser.exec, [ html, handler, async ] );\r
return;\r
};\r
\r
};\r
\r
// Clean up any remaining tags\r
- X.Dom.Parser.parseEndTag( stack, handler );\r
+ X_Dom_Parser.parseEndTag( stack, handler );\r
\r
async && handler.complete();\r
},\r
\r
_parseStartTag : function( stack, last, handler, html ){\r
- var alphabets = X.Dom.Parser.alphabets,\r
- whiteSpace = X.Dom.Parser.whiteSpace,\r
- saveAttr = X.Dom.Parser.saveAttr,\r
+ var alphabets = X_Dom_Parser.CHARS,\r
+ whiteSpace = X_Dom_Parser.CHARS,\r
+ saveAttr = X_Dom_Parser.saveAttr,\r
uri = X.Dom.DTD.ATTR_VAL_IS_URI,\r
phase = 0,\r
l = html.length,\r
chr === '<' && ( ++phase );\r
break;\r
case 1 : // タグ名の開始を待つ\r
- alphabets.indexOf( chr ) !== -1 && ( ++phase && ( start = i ) );\r
+ ( alphabets[ chr ] & 3 ) && ( ++phase && ( start = i ) );\r
break;\r
case 2 : // タグ名の終わりの空白文字を待つ\r
- whiteSpace.indexOf( chr ) !== -1 ?\r
+ ( whiteSpace[ chr ] & 16 ) ?\r
( ++phase && ( tagName = html.substring( start, i ) ) ) :\r
( chr === '>' || ( empty = html.substr( i, 2 ) === '/>' ) ) &&\r
( ( tagName = html.substring( start, i ) ) && ( phase = 9 ) );\r
break;\r
case 3 : // 属性名の開始を待つ\r
- alphabets.indexOf( chr ) !== -1 ?\r
+ ( alphabets[ chr ] & 3 ) ?\r
( ++phase && ( start = i ) ) :\r
( chr === '>' || ( empty = html.substr( i, 2 ) === '/>' ) ) &&\r
( phase = 9 );\r
case 4 : // 属性名の終わりを待つ\r
chr === '=' ?\r
( ( phase = 6 ) && ( attrName = html.substring( start, i ) ) ) :\r
- whiteSpace.indexOf( chr ) !== -1 &&\r
+ ( whiteSpace[ chr ] & 16 ) &&\r
( ( phase = 5 ) && ( attrName = html.substring( start, i ) ) );\r
break;\r
case 5 : // 属性の = または次の属性または htmlタグの閉じ\r
- whiteSpace.indexOf( chr ) !== -1 ?// ie4 未対応の属性には cite = http:// となる\r
+ ( whiteSpace[ chr ] & 16 ) ?// ie4 未対応の属性には cite = http:// となる\r
1 :\r
- alphabets.indexOf( chr ) !== -1 ?\r
+ ( alphabets[ chr ] & 3 ) ?\r
( ( phase = 4 ) && ( attrs[ attrs.length ] = attrName ) && ( start = i ) ) :\r
chr === '=' ?\r
( phase = 6 ) :\r
case 6 : // 属性値の開始 quot を待つ\r
( chr === '"' || chr === "'" ) ?\r
( ( phase = 7 ) && ( quot = chr ) && ( start = i + 1 ) ):\r
- whiteSpace.indexOf( chr ) === -1 &&\r
+ !( whiteSpace[ chr ] & 16 ) &&\r
( ( phase = 8 ) && ( start = i ) ); // no quot\r
break;\r
case 7 : //属性値の閉じ quot を待つ\r
!escape && ( chr === quot ) && ( phase = 3 ) && saveAttr( attrs, attrName, html.substring( start, i ) );\r
break;\r
case 8 : //閉じ quot のない属性の値\r
- whiteSpace.indexOf( chr ) !== -1 ?\r
+ ( whiteSpace[ chr ] & 16 ) ?\r
( ( phase = 3 ) && saveAttr( attrs, attrName, html.substring( start, i ) ) ) :\r
( chr === '>' ) ?\r
( ( phase = 9 ) && saveAttr( attrs, attrName, html.substring( start, i ) ) ) :\r
};\r
if( phase === 9 ){\r
if( empty ) ++i;\r
- if( X.Dom.Parser.parseStartTag( stack, last, handler, tagName, attrs, empty, i ) === false ) return false;\r
+ if( X_Dom_Parser.parseStartTag( stack, last, handler, tagName.toUpperCase(), attrs, empty, i ) === false ) return false;\r
return i;\r
};\r
return 0; // error\r
},\r
\r
_parseEndTag : function( stack, handler, html ){\r
- var alphabets = X.Dom.Parser.alphabets,\r
- whiteSpace = X.Dom.Parser.whiteSpace,\r
+ var alphabets = X_Dom_Parser.CHARS,\r
+ whiteSpace = X_Dom_Parser.CHARS,\r
phase = 0,\r
l = html.length,\r
i = 0,\r
html.substr( i, 2 ) === '</' && ( ++phase && ++i );\r
break;\r
case 1 : // タグ名の開始を待つ\r
- alphabets.indexOf( chr ) !== -1 && ( ++phase && ( start = i ) );\r
+ ( alphabets[ chr ] & 3 ) && ( ++phase && ( start = i ) );\r
break;\r
case 2 : // タグ名の終わりの空白文字を待つ\r
- whiteSpace.indexOf( chr ) !== -1 && ( ++phase );\r
+ ( whiteSpace[ chr ] & 16 ) && ( ++phase );\r
( chr === '>' ) && ( phase = 9 );\r
( phase !== 2 ) && ( tagName = html.substring( start, i ) );\r
break;\r
++i;\r
};\r
if( phase === 9 ){\r
- X.Dom.Parser.parseEndTag( stack, handler, tagName );\r
+ X_Dom_Parser.parseEndTag( stack, handler, tagName.toUpperCase() );\r
return i;\r
};\r
return 0; // error\r
\r
saveAttr : function( attrs, name, value ){\r
name = name.toLowerCase();\r
- value = X.Dom.Parser.fillAttrs[ name ] === 1 ? name : value;\r
+ value = X_Dom_Parser.fillAttrs[ name ] === 1 ? name : value;\r
attrs[ attrs.length ] = {\r
name : name,\r
value : value,\r
},\r
\r
parseStartTag : function( stack, last, handler, tagName, attrs, unary, index ) {\r
- var tagLower = tagName.toLowerCase(),\r
- inline = X.Dom.Parser.inline,\r
- parseEndTag = X.Dom.Parser.parseEndTag,\r
- sisters = X.Dom.Parser.sisters;\r
- if ( X.Dom.Parser.block[ tagLower ] === 1 ) {\r
- while ( last && inline[ last.toLowerCase() ] === 1 ) {\r
+ var inline = X_Dom_Parser.inline,\r
+ parseEndTag = X_Dom_Parser.parseEndTag,\r
+ sisters = X_Dom_Parser.sisters;\r
+ if ( X_Dom_Parser.block[ tagName ] === 1 ) {\r
+ while ( last && inline[ last ] === 1 ) {\r
parseEndTag( stack, handler, last );\r
last = stack[ stack.length - 1 ];\r
};\r
};\r
- X.Dom.Parser.closeSelf[ tagLower ] === 1 && ( last === tagName || ( sisters[ tagLower ] && sisters[ tagLower ][ last.toLowerCase() ] === 1 ) ) && parseEndTag( stack, handler, last );\r
- unary = unary || X.Dom.Parser.empty[ tagName.toUpperCase() ];\r
+ last && X_Dom_Parser.closeSelf[ tagName ] === 1 && ( last === tagName || ( sisters[ tagName ] && sisters[ tagName ][ last ] === 1 ) ) && parseEndTag( stack, handler, last );\r
+ unary = unary || X_Dom_Parser.empty[ tagName ];\r
!unary && ( stack[ stack.length ] = tagName );\r
\r
return handler.start( tagName, attrs, unary, index );\r
nest : [],\r
err : function( html ){\r
X.Dom._htmlStringToXNode.flat.length = 0;\r
- X.Dom._htmlStringToXNode.ignoreError !== true && X.Notification.warn( 'X.Dom.Parser() error ' + html );\r
+ X.Dom._htmlStringToXNode.ignoreError !== true && X.Notification.warn( 'X_Dom_Parser() error ' + html );\r
},\r
start : function( tagName, attrs, noChild, length ){\r
var xnode,\r
worker.flat = [];\r
worker.nest.length = 0;\r
worker.ignoreError = ignoreError;\r
- X.Dom.Parser.exec( html, worker );\r
+ X_Dom_Parser.exec( html, worker );\r
ret = worker.flat;\r
delete worker.flat;\r
return ret;\r
comment : X.emptyFunction,\r
\r
progress : function( pct ){\r
- this.asyncDispatch( 0, { type : X.Event.PROGRESS, progress : pct } );\r
+ this.asyncDispatch( 0, { type : X.Event.PROGRESS, percent : pct } );\r
},\r
complete : function(){\r
var ret = X.Dom._htmlStringToXNode.flat;\r
worker.flat = [];\r
worker.nest.length = 0;\r
worker.ignoreError = ignoreError;\r
- X.Dom.Parser.exec( html, dispatcher, [ html.length, [] ] );\r
+ X_Dom_Parser.exec( html, dispatcher, [ html.length, [] ] );\r
return dispatcher;\r
};\r
--- /dev/null
+X.Audio = {\r
+ HTML5 : 1,\r
+ Flash : 2,\r
+ SilverLight : 3,\r
+ Unity : 4,\r
+ WMP : 5,\r
+ RealPlayer : 6,\r
+ QuickTime : 7,\r
+ \r
+ create : function( sourceList, opt_option ){\r
+ return new X_AudioProxy( X.Type.isArray( sourceList ) ? X.copyArray( sourceList ) : [ sourceList ], opt_option || {} );\r
+ }\r
+};\r
+\r
+var X_Audio_BACKENDS = [];\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
+ \r
+ if( source && X_Audio_BACKENDS.length ){\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
+ } else {\r
+ proxy.asyncDispatch( 0, '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
+ \r
+ switch( e.type ){\r
+ case 'support' :\r
+ proxy._backend = i;\r
+ proxy.asyncDispatch( 0, { 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
+ } else\r
+ if( sourceList.length ){\r
+ X_Audio_detectBackend( proxy, sourceList, option );\r
+ } else {\r
+ proxy.asyncDispatch( 0, 'nobackend' );\r
+ };\r
+ break;\r
+ };\r
+};\r
+\r
+\r
+X_AudioProxy = X.EventDispatcher.inherits(\r
+ 'X.AV.AudioProxy',\r
+ X.Class.POOL_OBJECT,\r
+ {\r
+ source : '',\r
+ backendName : '',\r
+ _backend : -1,\r
+ \r
+ Constructor : function( sourceList, option ){\r
+ X_Audio_detectBackend( this, sourceList, option );\r
+ this.listenOnce( [ 'backendfound', 'nobackend', X.Event.KILL_INSTANCE ], X_AudioProxy_handleEvent );\r
+ },\r
+ \r
+ close : function(){\r
+ return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].close.call( 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
+ },\r
+ \r
+ pause : function(){\r
+ return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].pause.call( this );\r
+ },\r
+ \r
+ stop : function(){\r
+ return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].stop.call( this );\r
+ },\r
+ \r
+ loop : function( v ){\r
+ return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].loop.call( this, v );\r
+ },\r
+\r
+ state : function(){\r
+ return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].state.call( 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
+ },\r
+\r
+ currentTime : function( time ){\r
+ return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].currentTime.call( this, time );\r
+ },\r
+\r
+ isPlaying : function(){\r
+ return this._backend !== -1 && X_Audio_BACKENDS[ this._backend ].isPlaying.call( this );\r
+ }\r
+ \r
+ }\r
+);\r
+\r
+function X_AudioProxy_handleEvent( e ){\r
+ switch( e.type ){\r
+ case 'backendfound' :\r
+ this.unlisten( 'nobackend', X_AudioProxy_handleEvent );\r
+ this.source = e.source;\r
+ this.backendName = X_Audio_BACKENDS[ this._backend ].backendName;\r
+ X_Audio_BACKENDS[ this._backend ].register( this, e.source, e.option );\r
+ break;\r
+ \r
+ case 'nobackend' :\r
+ this.kill();\r
+ break;\r
+ \r
+ case X.Event.KILL_INSTANCE :\r
+ this.close();\r
+ break;\r
+ };\r
+};\r
--- /dev/null
+/*\r
+ * original : uupaa-js HTML5Audio.js\r
+ * https://code.google.com/p/uupaa-js/source/browse/trunk/0.8/src/Audio/HTML5Audio.js?r=568\r
+ */\r
+\r
+var X_Audio_HTML5Audio, X_Audio_HTML5AudioWrapper, X_Audio_rawAudio,\r
+ X_Audio_HTML5Audio_LIVE_LIST = [],\r
+ X_Audio_HTML5Audio_POOL_LIST = [];\r
+ \r
+\r
+if( window.HTMLAudioElement ){\r
+ \r
+ function getHTML5AudioWrapper( proxy ){\r
+ var i = X_Audio_HTML5Audio_LIVE_LIST.length;\r
+ for( ; i; ){\r
+ if( X_Audio_HTML5Audio_LIVE_LIST[ --i ].proxy === proxy ) return X_Audio_HTML5Audio_LIVE_LIST[ i ];\r
+ };\r
+ };\r
+ \r
+ X_Audio_HTML5Audio = X.Class._override(\r
+ new X.EventDispatcher(),\r
+ {\r
+ backendName : 'HTML5 Audio',\r
+ /*\r
+ * HTML5 の audio 要素と video 要素でサポートされているメディアフォーマット\r
+ * https://developer.mozilla.org/ja/docs/Web/HTML/Supported_media_formats\r
+ * \r
+ * 主要ブラウザのHTML5 audioタグで使えるファイル形式の再生対応状況を調べてみた\r
+ * http://sothis.blog.so-net.ne.jp/2010-10-27\r
+ * ダメ元で仕様に含まれていない SHOUTcast もテストしてみました。\r
+ * \r
+ * IE9 の HTML5 Audio について\r
+ * http://kentablog.cluscore.com/2011/05/ie9-html5-audio.html\r
+ * 1.Audioオブジェクトを作ることができないので、Audioタグを使う\r
+ * 2.クロスドメインアクセスには、「clientaccesspolicy.xml」か「crossdomain.xml」が必要\r
+ * 3.wav が不可\r
+ * \r
+ * IE9でHTML5 autio タグが無効になる\r
+ * http://bbs.wankuma.com/index.cgi?mode=al2&namber=64886&KLOG=109\r
+ * IEのバージョン9.0.8112.16421では、Audioオブジェクトのnewも対応してました。\r
+ * createElement等で動的生成すると、よろしくない\r
+ * \r
+ * media-can-play-wav-audio.html\r
+ * https://github.com/adobe/webkit/blob/master/LayoutTests/media/media-can-play-wav-audio.html\r
+ * testExpected("audio.canPlayType('audio/wav; codecs=1')", "probably");\r
+ * \r
+ * HTML5 audioタグ ブラウザ間の違い\r
+ * http://wiki.bit-hive.com/tomizoo/pg/HTML5%20audio%A5%BF%A5%B0%20%A5%D6%A5%E9%A5%A6%A5%B6%B4%D6%A4%CE%B0%E3%A4%A4\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
+ var ok, mineType;\r
+ switch( ext ){\r
+ case 'mp3' :\r
+ ok = X.UA.IE || X.UA.Chrome || ( X.UA.OS === 'windows' && X.UA.Safari );\r
+ mineType = 'audio/mpeg';\r
+ break;\r
+ case 'ogg' :\r
+ ok = 15 <= X.UA.Gecko || X.UA.Chrome || X.UA.Opera;\r
+ mineType = 'audio/ogg';\r
+ break;\r
+ case 'm4a' :\r
+ ok = X.UA.IE || X.UA.WebKit;\r
+ mineType = 'audio/mp4';\r
+ break;\r
+ case 'webm' :\r
+ ok = 2 <= X.UA.Gecko || 10.6 <= X.UA.Opera; // firefox4+(Gecko2+)\r
+ mineType = 'audio/webm';\r
+ break;\r
+ case 'wav' :\r
+ ok = X.UA.Gecko || X.UA.Opera || ( X.UA.OS === 'windows' && X.UA.Safari );\r
+ mineType = 'audio/wav'; // audio/x-wav ?\r
+ break;\r
+ };\r
+ \r
+ if( !ok && mineType ){\r
+ if( !X_Audio_rawAudio ) X_Audio_rawAudio = new Audio;\r
+ ok = X_Audio_rawAudio.canPlayType( mineType );\r
+ };\r
+ \r
+ // TODO canPlay\r
+ this.asyncDispatch( 0, ok ? 'support' : 'nosupport' );\r
+ \r
+ return this;\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
+ },\r
+ \r
+ play : function( position ){\r
+ return getHTML5AudioWrapper( this ).play( position );\r
+ },\r
+ \r
+ pause : function(){\r
+ return getHTML5AudioWrapper( this ).pause();\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
+ },\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
+ }\r
+ }\r
+ );\r
+ \r
+ X_Audio_BACKENDS.push( X_Audio_HTML5Audio );\r
+ \r
+ X_Audio_HTML5AudioWrapper = X.EventDispatcher.inherits(\r
+ 'X.AV.HTML5AudioWrapper',\r
+ X.Class.POOL_OBJECT,\r
+ {\r
+ \r
+ proxy : null,\r
+ xnodeAudio : null,\r
+ rawAudio : null,\r
+ \r
+ _closed : true,\r
+ _lastUserAction : '',\r
+ \r
+ _loop : false,\r
+ _startTime : 0,\r
+ _volume : 0.5,\r
+ _autoplay : false,\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
+ \r
+ this.xnodeAudio = new X.EventDispatcher( this.rawAudio = X_Audio_rawAudio || new Audio( source ) )//X.Dom.Node.create( 'audio', { src : source } ).appendToRoot();//( X.Dom.Node._systemNode );\r
+ .listen( [\r
+ 'loadstart', 'load', 'progress', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'play', 'pause', 'loadedmetadata',\r
+ 'loadeddata', 'waiting', 'playing', 'canplay', 'canplaythrough', 'seeking', 'seeked', 'timeupdate', 'ended',\r
+ 'ratechange', 'durationchange', 'volumechange' ], this, this.handleEventProxy ); \r
+ if( X_Audio_rawAudio ){\r
+ X_Audio_rawAudio.src = source;\r
+ X_Audio_rawAudio.load(); // 要る?\r
+ X_Audio_rawAudio = null;\r
+ };\r
+\r
+ this.rawAudio.volume = this._volume;\r
+ this.rawAudio.autoplay = false;\r
+ option.autoplay && X.Timer.once( 100, this, this.play );\r
+ \r
+ this.listenOnce( X.Event.KILL_INSTANCE );\r
+ },\r
+ \r
+ handleEvent : function( e ){\r
+ switch( e.type ){\r
+\r
+ case X.Event.KILL_INSTANCE :\r
+ this.xnodeAudio.unlisten();\r
+ this.xnodeAudio.kill(); // <img> と同じく <audio> は pool した方がいいかも\r
+ break;\r
+ };\r
+ },\r
+ /*\r
+ * http://uguisu.skr.jp/html/table3.html\r
+ */\r
+ handleEventProxy : function( e ){\r
+ switch( e.type ){\r
+ case 'loadstart' : // ブラウザがコンテンツの検索を開始した場合に発生\r
+ break;\r
+ case 'progress' : // ブラウザがコンテンツの取得を実行した場合に発生\r
+ console.log( e.loaded / e.total );\r
+ break;\r
+ case 'suspend' : // ブラウザが意図的にコンテンツの取得を現在行っていない場合に発生(ダウンロードは未完了)\r
+ case 'abort' : // ダウンロードの完了前にコンテンツの取得を停止した場合に発生(この停止はエラーによるものではない)\r
+ case 'error' : // コンテンツの取得実行中にエラーが発生した場合に発生\r
+ case 'emptied' : // 読み込み中に致命的なエラーが発生したか、実行状態ででload()メソッドが実行された場合に発生\r
+ case 'stalled' : // ブラウザがコンテンツの取得を試みたが、データがまだ用意されていない場合に発生\r
+ case 'play' : // 再生が開始された。play()メソッドからの復帰後に発生する場合に発生\r
+ case 'pause' : // 再生が一時停止された。pauseメソッドからの復帰後に発生する場合に発生\r
+ case 'loadedmetadata' : // ブラウザがメディアリソースの長さと寸法を判定した場合に発生\r
+ case 'loadeddata' : // コンテンツの表示を現在の再生位置で初めて行えるようになった場合に発生\r
+ case 'waiting' : // 次のフレームが利用不可のため再生を停止したが、そのフレームがやがて利用可能になると想定している場合に発生\r
+ case 'playing' : // 再生が開始された場合に発生\r
+ case 'canplay' : // 今すぐに再生を再開できるが、バッファリングが不十分でコンテンツを最後まで表示できないと予測している場合に発生\r
+ case 'canplaythrough' : // 今すぐに再生を開始してもバッファリングで停止することなく最後まで表示できると予測している場合に発生\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
+ break;\r
+ \r
+ case 'ratechange' : // defaultPlaybackRate属性とplaybackRate属性のどちらかが更新された場合に発生\r
+ case 'durationchange' : // duration属性が更新された場合に発生\r
+ case 'volumechange' : // volume属性とmuted属性のどちらかが変化した場合に発生\r
+ };\r
+ \r
+ //console.log( 'html5 ' + e.type + ' ' + ( this.proxy._listeners && this.proxy._listeners[ e.type ] && this.proxy._listeners[ e.type ].length ) );\r
+ //e.type === 'canplaythrough' && console.dir( e );\r
+ this.proxy.dispatch( e );\r
+ },\r
+ \r
+ close : function(){\r
+ // pool, proxy を外す\r
+ //this.kill();\r
+ },\r
+ \r
+ play : function( position ){\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.rawAudio.volume ] );\r
+ this.rawAudio.volume = 0;\r
+ };\r
+ \r
+ if( !this.rawAudio.paused ){\r
+ this.currentTime( this._startTime );\r
+ };\r
+ this.rawAudio.play();\r
+ },\r
+ \r
+ // [CHROME][FIX] volume\r
+ _fixForChrome : X.UA.Chrome && function( volume ){\r
+ !this._closed && ( this.rawAudio.volume = volume );\r
+ },\r
+ \r
+ pause : function(){\r
+ if( !this._closed && !this.rawAudio.error ){\r
+ this._lastUserAction = 'pause';\r
+ this.rawAudio.pause(); \r
+ };\r
+ },\r
+ \r
+ stop : function(){\r
+ if( !this._closed && !this.rawAudio.error ){\r
+ this._lastUserAction = 'stop';\r
+ this.rawAudio.pause();\r
+ this.currentTime( this._startTime );\r
+ };\r
+ },\r
+ \r
+ loop : function( v ){\r
+ if( v === undefined ) return this._loop;\r
+ this.rawAudio.loop = this._loop = v;\r
+ },\r
+ \r
+ state : function(){\r
+ var paused = !!this.rawAudio.paused,\r
+ ended = !!this.rawAudio.ended;\r
+ \r
+ if( this._lastUserAction === 'stop' ){\r
+ if( paused ){\r
+ paused = false;\r
+ ended = true;\r
+ };\r
+ };\r
+ \r
+ return {\r
+ loop : this.rawAudio.loop,\r
+ error : this.rawAudio.error || 0, // 0, 1 ~ 4\r
+ paused : paused,\r
+ ended : ended,\r
+ source : this.rawAudio.src || '',\r
+ duration : this.rawAudio.duration || 0\r
+ };\r
+ },\r
+ \r
+ volume : function( v ){\r
+ if( v === undefined ) return this.audio.volume;\r
+ this.rawAudio.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.rawAudio.currentTime;\r
+ this.rawAudio.currentTime = time;\r
+ },\r
+ \r
+ isPlaying : function(){\r
+ return !this.rawAudio.error && !this.rawAudio.paused && !this.rawAudio.ended;\r
+ }\r
+ \r
+ }\r
+ );\r
+ \r
+};\r
+\r