s = s.parentElement || s.parentNode || s;// s is for opera7.11\r
return s.tagName.toLowerCase() === 'head';// opera7.23 s.tagName is 'HTML'\r
})( document.scripts || document.getElementsByTagName && document.getElementsByTagName( 'script' ) || document.all && document.all.tags( 'script' ) );\r
+\r
};\r
\r
// Android 標準ブラウザ AOSP と ChromeWeb View, Sブラウザがある\r
- if( X_UA[ 'Android' ] &&\r
- ( dua.indexOf( 'Chrome\/' ) === -1 || dua.indexOf( 'Version\/' ) !== -1 ) ){ // Chrome/ を含まない または Version/ を含む\r
+ if( ( v = X_UA[ 'Android' ] ) &&\r
+ ( dua.indexOf( 'Chrome\/' ) < 0 || 0 < dua.indexOf( 'Version\/' ) ) ){ // Chrome/ を含まない または Version/ を含む\r
\r
/* if( window.chrome ){ // Android3.1 のAOSPブラウザで .chrome がいた、、、\r
} else */\r
- if( dua.indexOf( 'Version\/' ) === -1 && ( v = parseFloat( dua.split( 'Chrome\/' )[ 1 ] ) ) ){\r
+ if( dua.indexOf( 'Version\/' ) < 0 && 0 < dua.indexOf( 'Chrome\/' ) ){\r
/**\r
* Android 標準ブラウザ Chrome WebView ブラウザ\r
* @alias X.UA.ChromeWV\r
// CustomElement の有無で判定\r
if( document[ 'registerElement' ] ){\r
// UA が偽装された Chrome WebView\r
- X_UA[ 'ChromeWV' ] = tv;\r
- alert( 'UA が偽装された Chrome WebView' );\r
+ X_UA[ 'ChromeWV' ] = v;\r
} else {\r
/**\r
* Android 標準ブラウザ AOSP\r
* @alias X.UA.AOSP\r
* @type {number}\r
*/\r
- X_UA[ 'AOSP' ] = X_UA[ 'Android' ]; \r
+ X_UA[ 'AOSP' ] = v;\r
};\r
\r
/*\r
};\r
};\r
\r
+var X_elmHtml = document.documentElement ||\r
+ X_UA_DOM.W3C ? document.getElementsByTagName( 'html' )[ 0 ] :\r
+ X_UA_DOM.IE4 ? document.all.tags( 'html' )[ 0 ] : null,\r
+ \r
+ X_elmHead = \r
+ X_UA_DOM.W3C ? document.getElementsByTagName( 'head' )[ 0 ] :\r
+ X_UA_DOM.IE4 ? document.all.tags( 'head' )[ 0 ] : null,\r
+ \r
+ X_elmBody;\r
+\r
if( navigator.msPointerEnabled || navigator.pointerEnabled ) X_UA_HID.POINTER = true;\r
if( !X_UA_HID.POINTER && window.ontouchstart !== undefined ) X_UA_HID.TOUCH = true;\r
\r
* @type {object}\r
*/\r
X[ 'Script' ] = {\r
- 'try' : X_Script_try\r
+ 'tryCatch' : X_Script_try\r
};\r
\r
if( X_UA[ 'IE' ] < 9 && X_Script_VBS_ENABLED ){\r
(function( lines ){\r
var s = document.createElement( 'script' );\r
- document.getElementsByTagName("head")[ 0 ].appendChild( s );\r
+ X_elmHead.appendChild( s );\r
s.type = 'text/vbscript';\r
s.text = lines.join( '\n' );\r
\r
\r
function X_Script_try( func, args ){\r
if( X_UA[ 'IE' ] < 5.5 ){\r
- return func.apply( {}, args );\r
+ //return func.apply( {}, args );\r
+ return;\r
};\r
return ( new Function( 'f,a', 'try{return f.apply({},a)}catch(e){}' ) )( func, args || [] );\r
};\r
* multipleIEs IE6 standalone 版では不可, IE5.5 は可,,,\r
* @alias X.UA.ieExeComError */ \r
( X_UA[ 'ieExeComError' ] = true )\r
- //eval( 'var a=1;try{document.execCommand&&document.execCommand("BackgroundImageCache",!1,!0)}catch(e){a=0}!a' )\r
);\r
};\r
*/\r
function X_String_cleanupWhiteSpace( text ){\r
var _ = ' ', __ = ' ', CRLF = X_String_CRLF;\r
+ \r
+ if( !text ) return '';\r
+ \r
//text.indexOf( CRLF ) !== -1 && ( text = text.split( CRLF ).join( _ ) );\r
text.indexOf( '\n\r' ) !== -1 && ( text = text.split( '\n\r' ).join( _ ) );\r
text.indexOf( '\t' ) !== -1 && ( text = text.split( '\t' ).join( _ ) );\r
text.indexOf( '\n' ) !== -1 && ( text = text.split( '\n' ).join( _ ) );\r
text.indexOf( '\f' ) !== -1 && ( text = text.split( '\f' ).join( _ ) );\r
text.indexOf( '\b' ) !== -1 && ( text = text.split( '\b' ).join( _ ) );\r
- //while( text.indexOf( __ ) !== -1 ){\r
- // text = text.split( __ ).join( _ );\r
- //};\r
- //return text;\r
+\r
while( true ){\r
text = text.split( __ );\r
- if( text.length < 2 ) return text.join( _ );\r
+ if( text.length < 2 ) return text[ 0 ];\r
text = text.join( _ );\r
};\r
};\r
return str.toString()\r
.split( '&' ).join( '&' )\r
.split( '"' ).join( '"' )\r
+ .split( '"' ).join( ''' )\r
.split( '<' ).join( '<' )\r
.split( '>' ).join( '>' )\r
.split( ' ' ).join( ' ' );\r
},
//https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect
//use window.pageXOffset and window.pageYOffset instead of window.scrollX and window.scrollY
-//(((t = document.documentElement) || (t = document.body.parentNode)) && typeof t.ScrollLeft == 'number' ? t : document.body).ScrollLeft;
-//(((t = document.documentElement) || (t = document.body.parentNode)) && typeof t.ScrollTop == 'number' ? t : document.body).ScrollTop
+//(((t = document.documentElement) || (t = X_elmBody.parentNode)) && typeof t.ScrollLeft == 'number' ? t : X_elmBody).ScrollLeft;
+//(((t = document.documentElement) || (t = X_elmBody.parentNode)) && typeof t.ScrollTop == 'number' ? t : X_elmBody).ScrollTop
// TODO X.Doc へ
/**
/*X_UA[ 'Opera' ] ?
( document.documentElement && document.documentElement.clientWidth ?
new Function( 'return[document.documentElement.clientWidth,document.documentElement.clientHeight]' ) :
- new Function( 'return[document.body.clientWidth,document.body.clientHeight]' )
+ new Function( 'return[X_elmBody.clientWidth,X_elmBody.clientHeight]' )
) :*/
return [
X_ViewPort_rootElement.scrollWidth || X_ViewPort_rootElement.offsetWidth,
( function(){
X_Node_updateTimerID && X_Node_startUpdate();
// body は Safari2-
- return[ X_ViewPort_scrollX = X_ViewPort_rootElement.scrollLeft || document.body.scrollLeft, X_ViewPort_scrollY = X_ViewPort_rootElement.scrollTop || document.body.scrollTop ];
+ return[ X_ViewPort_scrollX = X_ViewPort_rootElement.scrollLeft || X_elmBody.scrollLeft, X_ViewPort_scrollY = X_ViewPort_rootElement.scrollTop || X_elmBody.scrollTop ];
} ),
/**
};
X_TEMP.onDomContentLoaded = function(){
- var s, size, elmHtml, elmHead, elmBody, html, head, body;
+ var s, size, html, head, body;
console.log( '> X_TEMP.onDomContentLoaded rs:' + X_ViewPort_readyState );
// DOMContentLoaded の無いブラウザで X_TEMP.onDomContentLoaded への参照が残り続けるのを回避
X_TEMP.onDomContentLoaded && X_ViewPort_document[ 'unlisten' ]( 'DOMContentLoaded', X_TEMP.onDomContentLoaded );
delete X_TEMP.onDomContentLoaded;
-
- elmHtml = document.documentElement ||
- X_UA_DOM.W3C ? document.getElementsByTagName( 'html' )[ 0 ] :
- X_UA_DOM.IE4 ? document.all.tags( 'html' )[ 0 ] : null;
-
- elmHead =
- X_UA_DOM.W3C ? document.getElementsByTagName( 'head' )[ 0 ] :
- X_UA_DOM.IE4 ? document.all.tags( 'head' )[ 0 ] : null;
- elmBody = document.body;
+ X_elmBody = document.body;
- X_ViewPort_rootElement = document.compatMode !== 'CSS1Compat' ? elmBody : elmHtml || elmBody;
+ X_ViewPort_rootElement = document.compatMode !== 'CSS1Compat' ? X_elmBody : X_elmHtml || X_elmBody;
/**
* Node( documentElement )
* @alias X.Doc.html
* @type {Node}
*/
- X[ 'Doc' ][ 'html' ] = html = X_Node_html = elmHtml && Node( elmHtml )[ 'removeClass' ]( 'js-disabled' )[ 'addClass' ]( X_UA_classNameForHTML );
+ X[ 'Doc' ][ 'html' ] = html = X_Node_html = X_elmHtml && Node( X_elmHtml )[ 'removeClass' ]( 'js-disabled' )[ 'addClass' ]( X_UA_classNameForHTML );
html[ '_flags' ] |= X_NodeFlags_IN_TREE;
/**
* @alias X.Doc.head
* @type {Node}
*/
- X[ 'Doc' ][ 'head' ] = head = X_Node_head = elmHead && Node( elmHead );
+ X[ 'Doc' ][ 'head' ] = head = X_Node_head = X_elmHead && Node( X_elmHead );
/**
* Node( documentElement )
* @alias X.Doc.body
* @type {Node}
*/
- X[ 'Doc' ][ 'body' ] = body = X_Node_body = Node( elmBody );
+ X[ 'Doc' ][ 'body' ] = body = X_Node_body = Node( X_elmBody );
body[ 'parent ' ] = head[ 'parent' ] = html;
html[ '_xnodes' ] = [ head, body ];
html[ 'appendTo' ] = html[ 'prev' ] = html[ 'next' ] = html[ 'clone' ] = html[ 'remove' ] = html[ 'kill' ] =
html[ 'create' ] = html[ 'createText' ] = html[ 'createAt' ] = html[ 'createTextAt' ] = html[ 'append' ] = html[ 'appendAt' ] = html[ 'empty' ] = html[ 'html' ] = html[ 'text' ] =
html[ 'css' ] = html[ 'cssText' ] =
- head[ 'appendTo' ] = head[ 'prev' ] = head[ 'next' ] = head[ 'clone' ] = head[ 'remove' ] = head[ 'kill' ] =
+ head[ 'appendTo' ] = head[ 'prev' ] = head[ 'clone' ] = head[ 'remove' ] = head[ 'kill' ] =
head[ 'createText' ] = head[ 'createTextAt' ] = head[ 'empty' ] = head[ 'html' ] = head[ 'text' ] = head[ 'css' ] = head[ 'cssText' ] =
- body[ 'appendTo' ] = body[ 'prev' ] = body[ 'next' ] = body[ 'clone' ] = body[ 'remove' ] = body[ 'kill' ] = new Function( 'return this' );
+ body[ 'appendTo' ] = body[ 'next' ] = body[ 'clone' ] = body[ 'remove' ] = body[ 'kill' ] = new Function( 'return this' );
X_ViewPort[ 'listenOnce' ]( X_EVENT_PRE_INIT, function(){
X_ViewPort_readyState = X_EVENT_XTREE_READY;
- if( X_TEMP.X_Dom_useBuilder ) X_TEMP.X_Dom_useBuilder = !!document.body.children.length;
+ if( X_TEMP.X_Dom_useBuilder ) X_TEMP.X_Dom_useBuilder = !!X_elmBody.children.length;
!X_TEMP.X_Dom_useBuilder && X_ViewPort[ 'asyncDispatch' ]( X_EVENT_XTREE_READY );
} );
var size = X_ViewPort_getWindowSize(),
// http://jsdo.it/imaya/kTYg
- body = document.body,
- defaultOverflow = document.body.style.overflow,
+ defaultOverflow = X_elmBody.style.overflow,
w, h;
X_ViewPort_width = size[ 0 ];
X_ViewPort_height = size[ 1 ];
- body.style.overflow = 'hidden';
- w = body.clientWidth;
- h = body.clientHeight;
+ X_elmBody.style.overflow = 'hidden';
+ w = X_elmBody.clientWidth;
+ h = X_elmBody.clientHeight;
- body.style.overflow = 'scroll';
- w -= body.clientWidth;
- h -= body.clientHeight;
+ X_elmBody.style.overflow = 'scroll';
+ w -= X_elmBody.clientWidth;
+ h -= X_elmBody.clientHeight;
- if( !w ) w = body.offsetWidth - body.clientWidth;
- if( !h ) h = body.offsetHeight - body.clientHeight;
- body.style.overflow = defaultOverflow;
+ if( !w ) w = X_elmBody.offsetWidth - X_elmBody.clientWidth;
+ if( !h ) h = X_elmBody.offsetHeight - X_elmBody.clientHeight;
+ X_elmBody.style.overflow = defaultOverflow;
X_ViewPort_vScrollbarSize = w;
X_ViewPort_hScrollbarSize = h;
//X_TEMP._script = document.getElementById( '__ieonload' );
// 上のコードはスタンドアローン版ie6でエラー
- X_TEMP._script = document.createElement( '<script id=__ieonload defer src=javascript:void(0)></script>' ) ;
- document.getElementsByTagName( 'head' )[ 0 ].appendChild( X_TEMP._script );
-
+ X_TEMP._script = document.createElement( '<script id=__ieonload defer src=javascript:void(0)></script>' );
+ X_elmHead.appendChild( X_TEMP._script );
+
X_TEMP._script.onreadystatechange = function(){
var s = X_TEMP._script;
if( s && s.readyState === 'complete' ){
x = + ( matrix[ 12 ] || matrix[ 4 ] );\r
y = + ( matrix[ 13 ] || matrix[ 5 ] );\r
} else {\r
- x = + parseInt( matrix.left );\r
- y = + parseInt( matrix.top );\r
+ x = + parseFloat( matrix.left );\r
+ y = + parseFloat( matrix.top );\r
};\r
\r
return { x : x, y : y, a : matrix[ X_Node_CSS_Support[ 'opacity' ] ] };\r
case 'number' :\r
return parseFloat( v );\r
case 'int' :\r
- return parseInt( v );\r
+ return parseFloat( v ) | 0;\r
case 'boolean' :\r
return v && v !== '0' && v !== 'false' && v !== 'null' && v !== 'undefined' && v !== 'NaN';\r
//case 'string' :\r
\r
// XDomain 不可 -> Flash, Gears, Silverlight, canUseGadget なら gadget に切替?\r
// PUT DELETE UPDATE 不可 -> Flash, Gears, Silverlight, canUseGadget なら gadget に切替?\r
- // xプロトコル な binary のロード -> gadget 内で proxyURL による XHR\r
+ // xプロトコル(X_URL_isSameProtocol) な binary のロード -> gadget 内で proxyURL による XHR\r
// or X_EVENT_ERROR\r
\r
opt[ 'dataType' ] = opt[ 'dataType' ] || X_URL_getEXT( url );\r
\r
X_XHR,\r
X_JSONP,\r
- X_NET_FormWrapper,\r
- X_NET_ImageWrapper,\r
+ X_FormSender,\r
+ X_ImgLoader,\r
X_GadgetXHR,\r
\r
X_NET_currentWrapper,\r
X_NET_currentWrapper = X_JSONP || X_TEMP.X_JSONP_init();\r
break;\r
case X_NET_TYPE_FORM :\r
- X_NET_currentWrapper = X_NET_FormWrapper || X_TEMP.X_NET_Form_init();\r
+ X_NET_currentWrapper = X_FormSender || X_TEMP.X_FormSender_init();\r
break;\r
case X_NET_TYPE_IMAGE :\r
- X_NET_currentWrapper = X_NET_ImageWrapper || X_TEMP.X_NET_Image_init();\r
+ X_NET_currentWrapper = X_ImgLoader || X_TEMP.X_ImgLoader_init();\r
break;\r
};\r
\r
json2FileSize = 18103,
html;
+ // file プロトコルで外部アクセスの禁止
+ 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' ] ) ){
//{+netform"<form>によるGETとPOST"(動的に生成したフォームによるGETとPOST。)[+net,+ninjaiframe]\r
\r
-var X_NET_Form_errorTimerID, X_Net_Form_onloadCount = 0;\r
+var X_FormSender_errorTimerID, X_FormSender_onloadCount = 0;\r
\r
-X_TEMP.X_NET_Form_init = function(){\r
- X_NET_FormWrapper = X_Class_override( X_NinjaIframe(), X_TEMP.X_NET_Form_params );\r
+X_TEMP.X_FormSender_init = function(){\r
+ X_FormSender = X_Class_override( X_NinjaIframe(), X_TEMP.X_FormSender_params );\r
\r
- delete X_TEMP.X_NET_Form_init;\r
- delete X_TEMP.X_NET_Form_params;\r
+ delete X_TEMP.X_FormSender_init;\r
+ delete X_TEMP.X_FormSender_params;\r
\r
- return X_NET_FormWrapper;\r
+ return X_FormSender;\r
};\r
\r
/*\r
- * form 構築時に "><script> といった文字列の挿入を禁止するために " を エスケープする、併せて改行文字を消す\r
+ * form 構築時に "><script> といった文字列の挿入を禁止するために " を エスケープする\r
+ * TODO 改行文字を消す\r
*/\r
-function X_NET_Form_escapeQuote( str ){\r
+function X_FormSender_escapeQuote( str ){\r
+ \r
return X_String_toChrReferance( str );\r
};\r
\r
-X_TEMP.X_NET_Form_params = {\r
+X_TEMP.X_FormSender_params = {\r
\r
_busy : false,\r
_canceled : false,\r
\r
target = target === '_self' ? '_parent' : target === '_blank' ? '_self' : target,\r
html = [\r
- '<form method="', X_NET_Form_escapeQuote( option[ 'method' ] || 'GET' ), \r
- '" action="', X_NET_Form_escapeQuote( option[ 'url' ] || '' ), \r
- '" target="', X_NET_Form_escapeQuote( target || '_self' ),\r
+ '<form method="', X_FormSender_escapeQuote( option[ 'method' ] || 'GET' ), \r
+ '" action="', X_FormSender_escapeQuote( option[ 'url' ] || '' ), \r
+ '" target="', X_FormSender_escapeQuote( target || '_self' ),\r
'">' ];\r
\r
if( target === '_top' || target === '_parent' ) this.isJump = true;\r
\r
for( k in params ){\r
// TODO 使用すべきでない name\r
- html.push( '<input type="hidden" name="', X_NET_Form_escapeQuote( k ), '" value="', X_NET_Form_escapeQuote( params[ k ] || '' ), '">' );\r
+ html.push( '<input type="hidden" name="', X_FormSender_escapeQuote( k ), '" value="', X_FormSender_escapeQuote( params[ k ] || '' ), '">' );\r
};\r
\r
html.push( '</form><script>document.forms[0].submit();</script>' );\r
\r
- X_NET_FormWrapper\r
+ X_FormSender\r
[ 'refresh' ]( html.join( '' ) )\r
- [ 'listen' ]( [ 'ninjaload', 'ninjaerror' ], X_NET_Form_iframeListener );\r
+ [ 'listen' ]( [ 'ninjaload', 'ninjaerror' ], X_FormSender_iframeListener );\r
\r
- X_NET_FormWrapper._busy = true;\r
+ X_FormSender._busy = true;\r
},\r
\r
cancel : function(){\r
- X_NET_FormWrapper.reset();\r
- X_NET_FormWrapper._canceled = true;\r
+ X_FormSender.reset();\r
+ X_FormSender._canceled = true;\r
},\r
\r
reset : function(){\r
- X_NET_FormWrapper._busy = X_NET_FormWrapper._canceled = false;\r
- X_NET_FormWrapper[ 'unlisten' ]( [ 'ninjaload', 'ninjaerror' ], X_NET_Form_iframeListener );\r
- X_NET_FormWrapper[ 'refresh' ]( '' );\r
- X_NET_Form_errorTimerID && X_Timer_remove( X_NET_Form_errorTimerID );\r
- X_NET_Form_errorTimerID = X_Net_Form_onloadCount = 0;\r
+ X_FormSender._busy = X_FormSender._canceled = false;\r
+ X_FormSender[ 'unlisten' ]( [ 'ninjaload', 'ninjaerror' ], X_FormSender_iframeListener );\r
+ X_FormSender[ 'refresh' ]( '' );\r
+ X_FormSender_errorTimerID && X_Timer_remove( X_FormSender_errorTimerID );\r
+ X_FormSender_errorTimerID = X_FormSender_onloadCount = 0;\r
}\r
};\r
\r
-function X_NET_Form_iframeListener( e ){\r
+function X_FormSender_iframeListener( e ){\r
var idoc;\r
\r
switch( e.type ){\r
return;\r
};\r
\r
- if( ++X_Net_Form_onloadCount === 1 ){\r
- X_NET_Form_errorTimerID = X_NET_FormWrapper[ 'asyncDispatch' ]( this.timeout, X_EVENT_ERROR );\r
+ if( ++X_FormSender_onloadCount === 1 ){\r
+ X_FormSender_errorTimerID = X_FormSender[ 'asyncDispatch' ]( this.timeout, X_EVENT_ERROR );\r
\r
// TODO レスポンスの html にアクセスしたい場合\r
// TODO samedomain or xiframe-sender\r
\r
idoc = this[ '_rawObject' ].contentDocument || this._iwin.document,\r
\r
- X_NET_FormWrapper[ 'asyncDispatch' ]( { type : X_EVENT_SUCCESS, response : idoc && idoc.body ? idoc.body.innerHTML : '' } );\r
+ X_FormSender[ 'asyncDispatch' ]( { type : X_EVENT_SUCCESS, response : idoc && idoc.body ? idoc.body.innerHTML : '' } );\r
};\r
break;\r
case 'ninjaerror' :\r
console.log( 'iframe onerror' );\r
- X_NET_FormWrapper[ 'asyncDispatch' ]( X_EVENT_ERROR );\r
+ X_FormSender[ 'asyncDispatch' ]( X_EVENT_ERROR );\r
break;\r
};\r
return X_CALLBACK_UN_LISTEN;\r
* AUTHOR: uupaa.js@gmail.com\r
* \r
*/\r
-var X_Net_Image_hasImage = !!window[ 'Image' ],\r
- X_Net_Image_image = X_Net_Image_hasImage && new Image(),\r
+var X_ImgLoader_hasImage = !!window[ 'Image' ],\r
+ X_ImgLoader_image = X_ImgLoader_hasImage && new Image(),\r
// IE では厳密には HTMLImageElement ではなく、appendChild してもサイズが取れず、removeChild に失敗する\r
- X_Net_Image_isElement = !( X_UA[ 'IE' ] < 9 ) && X_Type_isHTMLElement( X_Net_Image_image );\r
+ X_ImgLoader_isElement = !( X_UA[ 'IE' ] < 9 ) && X_Type_isHTMLElement( X_ImgLoader_image );\r
\r
/*\r
* TODO\r
* Image は、X.EventDispatcher で、<img> は X.Node で。 \r
*/\r
\r
-X_TEMP.X_NET_Image_init = function(){\r
- X_NET_ImageWrapper = X_Class_override(\r
- X_Net_Image_isElement ? Node( X_Net_Image_image ) : X_EventDispatcher( X_Net_Image_image ),\r
- X_TEMP.X_NET_Image_params\r
+X_TEMP.X_ImgLoader_init = function(){\r
+ X_ImgLoader = X_Class_override(\r
+ X_ImgLoader_isElement ? Node( X_ImgLoader_image ) : X_EventDispatcher( X_ImgLoader_image ),\r
+ X_TEMP.X_ImgLoader_params\r
);\r
\r
- X_NET_ImageWrapper[ 'listen' ]( [ 'load', 'error' /*, 'abort'*/, X_EVENT_KILL_INSTANCE ], X_NET_Image_handleEvent );\r
+ X_ImgLoader[ 'listen' ]( [ 'load', 'error' /*, 'abort'*/, X_EVENT_KILL_INSTANCE ], X_ImgLoader_handleEvent );\r
\r
- delete X_TEMP.X_NET_Image_init;\r
- delete X_TEMP.X_NET_Image_params; \r
+ delete X_TEMP.X_ImgLoader_init;\r
+ delete X_TEMP.X_ImgLoader_params; \r
\r
- return X_NET_ImageWrapper;\r
+ return X_ImgLoader;\r
};\r
\r
-X_TEMP.X_NET_Image_params = {\r
+X_TEMP.X_ImgLoader_params = {\r
_busy : false,\r
tick : 0,\r
timerID : 0,\r
if( X_UA[ 'Opera7' ] && this[ '_rawObject' ].complete ){\r
this[ 'asyncDispatch' ]( 'load' );\r
} else {\r
- this.timerID = X_Timer_add( this.delay, 0, this, X_NET_Image_detect );\r
+ this.timerID = X_Timer_add( this.delay, 0, this, X_ImgLoader_detect );\r
};\r
},\r
\r
console.log( 'X.Net.Image:reset ' + this.abspath + ' timerID:' + this.timerID );\r
\r
this.timerID && X_Timer_remove( this.timerID );\r
- //X_Net_Image_isElement ? this[ '_rawObject' ].removeAttribute( 'src' ) : ( this[ '_rawObject' ].src = '' );\r
+ //X_ImgLoader_isElement ? this[ '_rawObject' ].removeAttribute( 'src' ) : ( this[ '_rawObject' ].src = '' );\r
this[ '_rawObject' ].src = '';\r
this.timerID = 0;\r
this._busy = false;\r
}\r
};\r
\r
-function X_NET_Image_detect(){\r
+function X_ImgLoader_detect(){\r
var raw = this[ '_rawObject' ];\r
\r
if( this.finish ) return;\r
};\r
};\r
\r
-function X_NET_Image_handleEvent( e ){\r
+function X_ImgLoader_handleEvent( e ){\r
var size;\r
\r
console.log( 'X.Net.Image:handleEvent ' + e.type );\r
return;\r
};\r
\r
- size = X_Util_Image_getActualDimension( !X_Net_Image_isElement ? this.abspath : this );\r
+ size = X_Util_Image_getActualDimension( !X_ImgLoader_isElement ? this.abspath : this );\r
this.timerID = this[ 'asyncDispatch' ]( {\r
'type' : X_EVENT_SUCCESS,\r
'src' : this.abspath,\r
};\r
\r
\r
-// X_Net_Image_isElement && X_NET_ImageWrapper[ 'appendAt' ]( X.X_Node_systemNode );\r
+// X_ImgLoader_isElement && X_ImgLoader[ 'appendAt' ]( X_Node_systemNode );\r
case 2 : // _waiting_ 通信結果待ち\r
// 分割受信モードか?\r
ret = ret.substr( 1 );\r
- n = parseInt( ret );\r
+ n = parseFloat( ret );\r
\r
if( X_GadgetXHR_isReceiveBatches ){\r
X_GadgetXHR_receivedString += X_GadgetXHR_decodeLocationHash( ret ); \r
function X_OAuth2_getAccessToken( that ){ return X_OAuth2_updateLocalStorage( '', that, 'accessToken' ); }
function X_OAuth2_getRefreshToken( that ){ return X_OAuth2_updateLocalStorage( '', that, 'refreshToken' ); }
-function X_OAuth2_getAccessTokenExpiry( that ){ return parseInt( X_OAuth2_updateLocalStorage( '', that, 'tokenExpiry' ) ) || 0; }
+function X_OAuth2_getAccessTokenExpiry( that ){ return parseFloat( X_OAuth2_updateLocalStorage( '', that, 'tokenExpiry' ) ) || 0; }
function X_OAuth2_getAuthMechanism( that ){
// TODO use gadget | flash ...
// IE's XDomainRequest doesn't support sending headers, so don't try.
'X.AudioBase',\r
X_Class.ABSTRACT,\r
{\r
- url : '', //\r
- target : null, //\r
+ disatcher : null,\r
\r
startTime : 0, //\r
endTime : -1, //\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
+ ms = parseFloat( ( ary[ 1 ] + '000' ).substr( 0, 3 ) ) || 0;\r
\r
ary = ary[ 0 ].split( ':' );\r
if( 3 < ary.length ) return;\r
case 0 :\r
break;\r
case 1 :\r
- s = parseInt( ary[ 0 ] ) || 0;\r
+ s = parseFloat( ary[ 0 ] ) || 0;\r
break;\r
case 2 :\r
- m = parseInt( ary[ 0 ] ) || 0;\r
- s = parseInt( ary[ 1 ] ) || 0;\r
+ m = parseFloat( ary[ 0 ] ) || 0;\r
+ s = parseFloat( 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
+ h = parseFloat( ary[ 0 ] ) || 0;\r
+ m = parseFloat( ary[ 1 ] ) || 0;\r
+ s = parseFloat( ary[ 2 ] ) || 0;\r
if( 60 <= s ) alert( 'invalid time string ' + time );\r
if( 60 <= m ) alert( 'invalid time string ' + time );\r
break;\r
gainNode : null,
_onended : null,
- 'Constructor' : function( target, url, option ){
+ 'Constructor' : function( disatcher, url, option ){
var i = 0,
l = X_WebAudio_BUFFER_LIST.length,
loader;
this.loader = loader = X_WebAudio_BufferLoader( this, url );
};
- this.target = target || this;
-
+ this.disatcher = disatcher || this;
this.setState( option );
this[ 'listenOnce' ]( X_EVENT_KILL_INSTANCE, this.onKill );
if ( !buffer ) {
this.error = loader.errorState;
- this.target[ 'dispatch' ]({
+ this.disatcher[ 'dispatch' ]({
type : X_EVENT_ERROR,
error : loader.errorState,
message : loader.errorState === 1 ?
this.audioBuffer = buffer;
this.duration = buffer.duration * 1000;
- this.target[ 'asyncDispatch' ]( X_EVENT_READY );
+ this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY );
console.log( 'WebAudio buffer ready' );
actualPlay : function(){
var begin, end;
+ console.log( '[WebAudio] play abuf:' + !!this.audioBuffe );
+
if( !this.audioBuffer ){
this.autoplay = true;
return;
delete this._interval;
return X_CALLBACK_UN_LISTEN;
};
- this.target[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );
+ this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_PLAYING );
},
_onEnded : function(){
};
if( this.autoLoop ){
- if( !( this.target[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){
+ if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){
this.looped = true;
- this.target[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );
+ this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );
this.actualPlay();
};
} else {
this.actualPause();
- this.target[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );
+ this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );
};
};
},
* 1. iOS4(iPod 2G) で ended に達すると音が鳴らなくなる fix で解決\r
* 2. iOS6(iPod 4G) で ended に達すると音が鳴らなくなる fix で頻度が改善 emded イベントは発しないので、timeupdate 時に currentTime で判断する\r
* 3. WP7(IS12T) で最後の方にある音が鳴らない? mp3 cbr を使えばいい? 裏に回っても音が鳴り続ける\r
- * 4. Android 3.x で ended に達すると音が鳴らなくなる -> リロード(audio.src='';audio.sr=src)で解決、但し 2.x 4.x より遅延が大きく 1 秒弱程度ある\r
- * 5. Android 2.x で ended に達すると音が鳴らなくなる -> リロード(audio.src='';audio.src=src;audio.load())でで解決\r
- * 6. Android 4.4.2- は ended に達した際に currentTime が変更できなくなり、リロードが必要になる, 4.0, 4.1, 4.2, 4.3 で確認\r
- * 7. Blink5 Opera32 Win8 は HTMLAudio が壊れている、WebAudio は mp3 がデコードに失敗、ogg が動作\r
+ * 4. AOSP 2.x で ended に達すると音が鳴らなくなる -> リロード(audio.src='';audio.src=src;audio.load())でで解決\r
+ * 5. AOSP 3.x で ended に達すると音が鳴らなくなる -> リロード(audio.src='';audio.sr=src)で解決、但し 2.x 4.x より遅延が大きく 1 秒弱程度ある\r
+ * 6. AOSP 4.4.2- は ended に達した際に currentTime が変更できなくなり、リロードが必要になる, 4.0, 4.1, 4.2, 4.3 で確認, play() で頻度低下\r
+ * 7. Android 4.4.4 Chrome WebView は ended に達した際に play() が必要\r
+ * 8. BlinkOpera32 Win8 は HTMLAudio が壊れている、WebAudio は mp3 がデコードに失敗、ogg が動作\r
* \r
* memo\r
* 1. Android4.1 iframe 内の Audio は親に focus が移っても再生を継続する\r
// Android 3.1 で ended 時に src='';src=src を実施。\r
X_HTMLAudio_endedFixAOSP3 = !X_HTMLAudio_endedFixAOSP2 && X_UA[ 'AOSP' ] < 4,\r
// ended 時に play() を実施, currentTime が duration に張り付き更新されなければ src='';src=src を実施。\r
- X_HTMLAudio_endedFixAOSP4 = 4 <= X_UA[ 'AOSP' ],\r
+ X_HTMLAudio_endedFixAOSP4 = 4 <= X_UA[ 'AOSP' ] || X_UA[ 'ChromeWV' ],\r
\r
// Opera Mobile 12 は 2回目以降の currentTime へのセットで currentTime が更新されなくなるため、タイマーを使用する\r
X_HTMLAudio_currentTimeFix = !!X_UA[ 'OperaMobile' ] || !!X_UA[ 'OperaTablet' ],\r
X_HTMLAudio_pauseFix = ( X_UA[ 'Windows' ] && 12 <= X_UA[ 'Opera' ] && 0 < ' XP XPSP2 2003|XP64'.indexOf( X_UA[ 'Windows' ] ) ), // XP + Opera12 のみ?\r
/*\r
* durationFix\r
- * duration が取得できるタイミングが遅くそれまでは infinity(PC Opera12), NaN(WP9), 0(Android 標準ブラウザ ChromeWebkit 系) が入っている\r
+ * duration が取得できるタイミングが遅くそれまでは infinity(PC Opera12), NaN(WP9), 0(Android 標準ブラウザ ChromeWebView) が入っている\r
* \r
* 1. touch が不要の場合、自動で再生を開始して duration を取得するまで再生する\r
* -> 取得後に pause or 通常再生\r
\r
_endedFixON : false,\r
\r
- 'Constructor' : function( target, source, option ){\r
+ _kickTimerID : false, // 処理が混み入ると AOSP で音声が再生されない\r
+ _lastKickTime : 0,\r
+ \r
+ 'Constructor' : function( disatcher, source, option ){\r
var raw;\r
\r
- this.target = target || this;\r
- this._closed = false;\r
- this._src = source;\r
+ this.disatcher = disatcher || this;\r
+ this._closed = false;\r
+ this._src = source;\r
\r
if( X_HTMLAudio_shortPlayFix ){\r
this._shortPlayFixON = X_URL_getEXT( source ) === 'm4a';\r
raw.controls = false;\r
raw.WebKitPlaysInline = true;\r
raw.src = source;\r
- document.body.appendChild( raw );\r
+ X_elmBody.appendChild( raw );\r
} else {\r
raw = X_TEMP.rawAudio || new X_Audio_constructor( source );\r
// X_Doc_create( 'audio', { src : source } )[ 'appendTo' ]( X.Doc.body );\r
// \r
if( ended ){\r
if( !this._closed && this.autoLoop ){\r
- if( !( this.target[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
+ if( !( this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_BEFORE_LOOP ) & X_CALLBACK_PREVENT_DEFAULT ) ){\r
this.looped = true;\r
- this.target[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
+ this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_LOOPED );\r
( X_HTMLAudio_endedFixAOSP3 || X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixIOS ) && actualEnded && console.log( '☆★☆ 音声の継続用の play() @ended' );\r
this.actualPlay(\r
( X_HTMLAudio_endedFixAOSP4 || X_HTMLAudio_endedFixIOS ) && actualEnded,\r
} else {\r
this.seekTime = 0;\r
delete this.playing;\r
- this.target[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
+ this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_ENDED );\r
};\r
} else\r
if( this._loaded && this.duration && !this._ready ){\r
this._ready = true;\r
this.autoplay && X_Timer_once( 16, this, this.play );\r
- this.target[ 'asyncDispatch' ]( X_EVENT_READY );\r
+ this.disatcher[ 'asyncDispatch' ]( X_EVENT_READY );\r
console.log( '> Audio Loaded!! ' + e.type + ' d:' + ( this.duration | 0 ) );\r
} else\r
if( eventType ){\r
- this.target[ 'dispatch' ]( eventType );\r
+ this.disatcher[ 'dispatch' ]( eventType );\r
eventType === X_EVENT_ERROR && this[ 'kill' ]();\r
};\r
},\r
};\r
raw.play();\r
this.playing = true;\r
+ \r
+ if( X_UA[ 'AOSP' ] && !this._kickTimerID ){\r
+ this._kickTimerID = X_Timer_add( 100, 0, this, this._kick );\r
+ };\r
} else\r
if( X_HTMLAudio_needPlayForSeek || forcePlay ){\r
raw.play();\r
//http://himaxoff.blog111.fc2.com/blog-entry-97.html\r
//Firefox3.6では一度も play() していない状態で currentTime = 0 を実行するとエラーになる。\r
//また、GoogleChrome7 では currentTime = 0 直後に play() すると、pause()した位置前後の音が混ざることがある。(少なくとも自分の環境では) \r
- raw.currentTime = this._lastCurrentTime;\r
+ raw.currentTime = this._lastKickTime = this._lastCurrentTime;\r
console.log( '[HTMLAudio] play ' + begin + ' -> ' + end + ' crt:' + ( raw.currentTime | 0 ) + ' last:' + this._lastCurrentTime );\r
\r
// Android4.0.5 で ended イベント時に currentTime が duration に張り付いたまま変更できない\r
- if( forceReload || ( raw.duration && raw.currentTime === raw.duration ) ){\r
+ if( forceReload || ( X_HTMLAudio_endedFixAOSP4 && raw.duration && raw.currentTime === raw.duration ) ){\r
raw.src = '';\r
raw.src = this._src;\r
this.playing = false;\r
this._endedFixON = true;\r
console.log( '△ onEndedFix の開始' );\r
raw.currentTime = this._lastCurrentTime;\r
- this.target[ 'dispatch' ]( X_EVENT_MEDIA_WAITING ); \r
+ this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
X_HTMLAudio_endedFixAOSP2 && raw.load();\r
}; \r
};\r
};\r
},\r
\r
+ _kick : function(){\r
+ var raw = this[ '_rawObject' ];\r
+ \r
+ console.log( ' >> KICK ? ct:' + ( raw.currentTime ) + ' lkt:' + this._lastKickTime );\r
+ if( this.playing && raw.currentTime === this._lastKickTime ){\r
+ this.disatcher[ 'dispatch' ]( X_EVENT_MEDIA_WAITING );\r
+ console.log( ' >> KICK !!' );\r
+ raw.play();\r
+ } else {\r
+ delete this._kickTimerID;\r
+ return X_CALLBACK_UN_LISTEN;\r
+ };\r
+ },\r
+ \r
actualPause : function(){\r
console.log( '[HTMLAudio] pause' );\r
\r
s.type = 'text/xaml';\r
};\r
\r
- document.getElementsByTagName( 'head' )[ 0 ].appendChild( s );\r
+ X_elmHead.appendChild( s );\r
s.text = '<Canvas xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"></Canvas>';\r
\r
delete X_TEMP.slaudioInit;\r
X[ 'AudioSprite' ][ 'enableMultiTrack' ] = !X_AudioSprite_disableMultiTrack;\r
\r
// 再生が終わっているもの、終わりかけのものを探す\r
-// TODO 終わりかけのもの、と一番古いもの、どちらを再利用するか?これ以上に細かい実装を望む場合は X.Audio.Sprite は使わず自力で実装\r
+// TODO 終わりかけのもの、と一番古いもの、どちらを再利用するか?これ以上に細かい実装を望む場合は X.AudioSprite は使わず自力で実装\r
function X_AudioSprite_getTrackEnded(){\r
var tracks = X_AudioSprite_TEMP.tracks,\r
l = tracks.length,\r
track = X_AudioSprite_TEMP.bgmTrack = tracks[ 0 ];\r
};\r
\r
- if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_BEFORE_LOOP ], this, X_AudioSprite_handleEvent ).playing ){\r
+ if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], this, X_AudioSprite_handleEvent ).playing ){\r
track.setState({\r
'loop' : true,\r
'looped' : X_AudioSprite_TEMP.bgmLooped,\r
if( 1 < tracks.length ){\r
track = X_AudioSprite_getTrackEnded( X_AudioSprite_TEMP.bgmPlaying );\r
track\r
- [ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_BEFORE_LOOP ], this, X_AudioSprite_handleEvent )\r
+ [ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], this, X_AudioSprite_handleEvent )\r
.setState( { 'looped' : false } );\r
track.play( preset[ 0 ], preset[ 1 ], true, 0, X_AudioSprite_lengthSilence );\r
} else {\r
};\r
track = tracks[ 0 ];\r
\r
- if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_BEFORE_LOOP ], this, X_AudioSprite_handleEvent ).playing ){\r
+ if( track[ 'listen' ]( [ X_EVENT_MEDIA_PLAYING, X_EVENT_MEDIA_WAITING, X_EVENT_MEDIA_SEEKING, X_EVENT_MEDIA_BEFORE_LOOP ], this, X_AudioSprite_handleEvent ).playing ){\r
track.setState({\r
'loop' : true,\r
'looped' : false,\r
*/\r
'pause' : function( uid ){\r
var track = X_AudioSprite_TEMP.tracks[ uid ];\r
+ \r
if( X_AudioSprite_TEMP.bgmTrack === track ){\r
X_AudioSprite_TEMP.bgmPosition = track.currentTime();\r
X_AudioSprite_TEMP.bgmPlaying = false;\r
};\r
\r
if( X_AudioSprite_needTouchFirst ){\r
- if( name === 'Web Audio' ){\r
+ if( name === 'WebAudio' ){\r
_e[ 'needTouchForPlay' ] = true;\r
} else {\r
_e[ 'needTouchForLoad' ] = true;\r
case X_EVENT_MEDIA_PLAYING :\r
( e.target === X_AudioSprite_TEMP.bgmTrack || !e.target.looped ) && this[ 'asyncDispatch' ]( X_EVENT_MEDIA_PLAYING );\r
break;\r
+ case X_EVENT_MEDIA_WAITING :\r
+ case X_EVENT_MEDIA_SEEKING :\r
+ ( e.target === X_AudioSprite_TEMP.bgmTrack || !e.target.looped ) && this[ 'asyncDispatch' ]( e.type );\r
+ break;\r
\r
case X_EVENT_MEDIA_BEFORE_LOOP :\r
if( e.target === X_AudioSprite_TEMP.bgmTrack ){\r
* \r
*/\r
\r
-var X_KB_SPECIALS = {\r
-\r
- \r
- '8' : 'BS',\r
- '9' : 'TAB',\r
- '13' : 'ENTER',\r
- '16' : 'SHIFT',\r
- '17' : 'CTRL',\r
- '18' : 'ALT',\r
- '19' : 'PAUSE_BREAK',\r
- '20' : 'SHIFT+CAPS_LOCK',\r
- \r
- '27' : 'ESC',\r
- '28' : 'trans',\r
- '29' : 'no trans',\r
-\r
- '33' : 'PAGE_UP',\r
- '34' : 'PAGE_DOWN',\r
- '35' : 'END',\r
- '36' : 'HOME', \r
- '37' : 'CSR_L',\r
- '38' : 'CSR_U',\r
- '39' : 'CSR_R',\r
- '40' : 'CSR_D',\r
- '44' : 'PRT_SCRN', \r
- '45' : 'INS',\r
- '46' : 'DEL',\r
- \r
- '91' : 'LWIN',\r
- '92' : 'RWIN',\r
- '93' : 'APP',\r
- \r
- '96' : 48,\r
- '97' : 49,\r
- '98' : 50,\r
- '99' : 51,\r
- '100' : 52,\r
- '101' : 53,\r
- '102' : 54,\r
- '103' : 55,\r
- '104' : 56,\r
- '105' : 57,\r
- '106' : 42,\r
- '107' : 43,\r
- '109' : 45,\r
- '111' : 47,\r
- '112' : 'F1',\r
- '113' : 'F2',\r
- '114' : 'F3',\r
- '115' : 'F4',\r
- '116' : 'F5',\r
- '117' : 'F6',\r
- '118' : 'F7',\r
- '119' : 'F8',\r
- '120' : 'F9',\r
- '121' : 'F10',\r
- '122' : 'F11',\r
- '123' : 'F12',\r
- \r
- '144' : 'NUM_LOCK',\r
- '145' : 'SCROLL_LOCK',\r
- '208' : 'CAPS_LOCK',\r
- '240' : 'CAPS_LOCK',\r
- '242' : 'K/H',\r
- '243' : 'H/Z',\r
- '244' : 'H/Z'\r
- },\r
+var X_KB_SPECIALS = eval( // IE5- 対策\r
+ "({'8':'BS','9':'TAB'," +\r
+ "'13':'ENTER','16':'SHIFT','17':'CTRL','18':'ALT','19':'PAUSE_BREAK','20':'SHIFT+CAPS_LOCK'," +\r
+ "'27':'ESC','28':'trans','29':'notrans'," +\r
+ "'33':'PAGE_UP','34':'PAGE_DOWN','35':'END','36':'HOME','37':'CSR_L','38':'CSR_U','39':'CSR_R','40':'CSR_D'," +\r
+ "'44':'PRT_SCRN','45':'INS','46':'DEL'," +\r
+ "'91':'LWIN','92':'RWIN','93':'APP'," +\r
+ "'96':48,'97':49,'98':50,'99':51,'100':52,'101':53,'102':54,'103':55,'104':56,'105':57,'106':42,'107':43,'109':45," +\r
+ "'111':47,'112':'F1','113':'F2','114':'F3','115':'F4','116':'F5','117':'F6','118':'F7','119':'F8','120':'F9','121':'F10','122':'F11','123':'F12'," +\r
+ "'144':'NUM_LOCK','145':'SCROLL_LOCK','208':'CAPS_LOCK','240':'CAPS_LOCK','242':'K/H','243':'H/Z','244':'H/Z'})" ),\r
X_KB_DOWN_KEYS = {},\r
X_KB_CANCELED = {},\r
X_KB_lastIs10Key = false,\r