* 但し for( name in object ) については構文解析エラーになる環境はありません。\r
* @alias X.Object.inObject\r
* @function\r
- * @param {string} name \r
+ * @param {string|number} name \r
* @param {object} obj \r
* @return {boolean} name が定義されている(値が undefined や null でも) -> true\r
*/\r
var X_Object_inObject = X_UA[ 'IE' ] < 5.5 ? // TODO JScript で判定\r
- (function( name, obj ){\r
- var p;\r
+ (function( name, obj, p ){\r
if( obj[ name ] ) return true; // quick\r
name += ''; // 数値も許可\r
for( p in obj ){\r
};\r
return false;\r
}) :\r
- new Function( 'a,b', 'return a in b' );// なぜか ie5 でもerror\r
+ new Function( 'a,b', 'return a in b' );\r
\r
\r
// ------------------------------------------------------------------------- //\r
function X_String_chrReferanceTo( str ){\r
if( str == null ) return '';\r
return str.toString()\r
- .split( '"' ).join( '"' )\r
+ .split( '"' ).join( '"' ) // first!\r
.split( '&' ).join( '&' )\r
.split( '<' ).join( '<' )\r
.split( '>' ).join( '>' )\r
\r
function X_String_toChrReferance( str ){\r
if( str == null ) return '';\r
+ str += '';\r
return str.toString()\r
- .split( '"' ).join( '"' )\r
.split( '&' ).join( '&' )\r
+ .split( '"' ).join( '"' )\r
.split( '<' ).join( '<' )\r
.split( '>' ).join( '>' )\r
.split( ' ' ).join( ' ' );\r
X_Callback_HANDLEEVENT = 2,\r
/** @const */\r
X_Callback_FUNC_ONLY = 3,\r
+ /** @const */\r
+ X_Callback_THIS_FUNCNAME = 4,\r
\r
/** @const */\r
X_Callback_NONE = 0,\r
_obj = ret( X_Closure_COMMAND_BACK );\r
\r
_obj.kind = obj.kind;\r
+ _obj.name = obj.name;\r
_obj.func = obj.func;\r
_obj.context = obj.context;\r
_obj.supplement = obj.supplement;\r
function X_Callback_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){\r
var obj;\r
\r
- if( arg1 && X_Type_isFunction( arg2 ) ){\r
+ if( X_Type_isObject( arg1 ) && X_Type_isFunction( arg2 ) ){\r
obj = { context : arg1, func : arg2, kind : X_Callback_THIS_FUNC };\r
} else\r
- if( arg1 && X_Type_isFunction( arg1[ 'handleEvent' ] ) ){\r
- obj = { context : arg1, kind : X_Callback_HANDLEEVENT };\r
- arg3 = arg2;\r
+ if( X_Type_isObject( arg1 ) ){\r
+ if( arg2 && X_Type_isString( arg2 ) ){\r
+ obj = { context : arg1, name : arg2, kind : X_Callback_THIS_FUNCNAME };\r
+ } else {\r
+ obj = { context : arg1, kind : X_Callback_HANDLEEVENT };\r
+ arg3 = arg2; \r
+ };\r
} else\r
if( X_Type_isFunction( arg1 ) ){\r
arg3 = arg2;\r
obj = { func : arg2, kind : X_Callback_FUNC_ONLY };\r
};\r
} else\r
+ if( alt_context && X_Type_isString( arg1 ) ){\r
+ arg3 = arg2;\r
+ obj = { context : alt_context, name : arg1, kind : X_Callback_THIS_FUNCNAME };\r
+ } else\r
if( alt_context ){\r
obj = { context : alt_context, kind : X_Callback_HANDLEEVENT };\r
arg3 = arg1;\r
thisObj = xfunc.context,\r
func = xfunc.func,\r
supp = xfunc.supplement,\r
- temp, ret; \r
+ temp, ret, funcName; \r
\r
if( supp && supp.length ){\r
temp = [];\r
\r
case X_Callback_THIS_FUNC :\r
return args.length === 0 ? func.call( thisObj ) : func.apply( thisObj, args );\r
- \r
+ \r
+ case X_Callback_THIS_FUNCNAME :\r
+ funcName = xfunc.name;\r
case X_Callback_HANDLEEVENT :\r
- temp = thisObj[ 'handleEvent' ];\r
+ funcName = funcName || 'handleEvent';\r
+ temp = thisObj[ funcName ];\r
if( X_Type_isFunction( temp ) ){\r
return args.length === 0 ? thisObj[ 'handleEvent' ]() :\r
args.length === 1 ? thisObj[ 'handleEvent' ]( args[ 0 ] ) : temp.apply( thisObj, args );\r
X_Callback_POOL_LIST[ X_Callback_POOL_LIST.length ] = f;\r
obj = f( X_Closure_COMMAND_BACK );\r
delete obj.kind;\r
+ if( obj.name ) delete obj.name;\r
if( obj.func ) delete obj.func;\r
if( obj.context ) delete obj.context;\r
if( obj.supplement ) delete obj.supplement;\r
* @alias X.Doc.html
* @type {Node}
*/
- X[ 'Doc' ][ 'html' ] = html = X_Node_html = elmHtml && new Node( elmHtml )[ 'removeClass' ]( 'js-disabled' )[ 'addClass' ]( X_UA_classNameForHTML );
+ X[ 'Doc' ][ 'html' ] = html = X_Node_html = elmHtml && Node( 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 && new Node( elmHead );
+ X[ 'Doc' ][ 'head' ] = head = X_Node_head = elmHead && Node( elmHead );
/**
* Node( documentElement )
* @alias X.Doc.body
* @type {Node}
*/
- X[ 'Doc' ][ 'body' ] = body = X_Node_body = new Node( elmBody );
+ X[ 'Doc' ][ 'body' ] = body = X_Node_body = Node( elmBody );
body[ 'parent ' ] = head[ 'parent' ] = html;
html[ '_xnodes' ] = [ head, body ];
if( !opt_contentHTML && opt_contentHTML !== '' ) return this;\r
\r
this._contentHTML = opt_contentHTML;\r
- X_UA[ 'IE' ] < 9 || X_Util_NinjaIframe_writeToIframe( this );\r
+\r
+ if( !( X_UA[ 'IE' ] < 9 ) ){\r
+ X_Util_NinjaIframe_writeToIframe( this );\r
+ this._ready = true;\r
+ };\r
\r
return this;\r
},\r
html = that._contentHTML;\r
\r
delete that._contentHTML;\r
- that._ready = true;\r
\r
idoc.open();\r
idoc.writeln( html );\r
+var X_JSON = X[ 'JSON' ] = window.JSON || {\r
+ 'stringify' : X_JSON_stringify,\r
+ \r
+ 'parse' : X_String_parseTrustedJsonString\r
+};\r
+\r
+function X_JSON_stringify( obj ){\r
+ var json = '', k, v;\r
+ for( k in obj ){\r
+ if( json ) json += ',';\r
+ v = obj[ k ];\r
+ v = v || v === 0 ? v : null;\r
+ json += '"' + k + '":' + ( X_Type_isObject( v ) ? X_NET_GIMR_toJSONString( v ) : X_Type_isString( v ) ? '"' + v + '"' : v );\r
+ };\r
+ //console.log( json );\r
+ return '{' + json + '}';\r
+};
\ No newline at end of file
* // JSONP\r
* var net = X.Net( { jsonp : urlString, staticCallbackName : callbackName, useXDomainWall : false } );\r
* \r
+ * // Form\r
+ * var net = X.Net( { form : urlString, method : 'POST', target : '_self', params : {} } ); // _self, _parent, _top の場合、ページから離脱する\r
+ * \r
* // Image preload & getSize\r
* var net = X.Net( { image : src, sizeDetection : true } );\r
* \r
var v, opt, url, type, auth;\r
\r
if( X_Type_isObject( opt = urlOrObject ) ){\r
- if( v = opt[ 'xhr' ] ){\r
+ if( X_Type_isString( v = opt[ 'xhr' ] ) ){\r
url = v;\r
type = X_NET_TYPE_XHR;\r
} else\r
- if( v = opt[ 'jsonp' ] ){\r
+ if( X_Type_isString( v = opt[ 'jsonp' ] ) ){\r
url = v;\r
type = X_NET_TYPE_JSONP;\r
} else\r
- if( v = opt[ 'img' ] || opt[ 'image' ] ){\r
+ if( X_Type_isString( v = opt[ 'img' ] || opt[ 'image' ] ) ){\r
url = v;\r
type = X_NET_TYPE_IMAGE;\r
} else\r
- if( v = opt[ 'form' ] ){\r
+ if( X_Type_isString( v = opt[ 'form' ] ) ){\r
url = v;\r
type = X_NET_TYPE_FORM;\r
} else\r
- if( v = opt[ 'type' ] ){\r
+ if( X_Type_isString( v = opt[ 'type' ] ) ){\r
\r
switch( v ){\r
case 'xhr' :\r
alert( 'X.Net args error' );\r
return; \r
};\r
- url = opt[ 'url' ];\r
+ url = opt[ 'url' ];\r
};\r
\r
if( !X_Type_isString( url ) ){\r
X_NET_currentWrapper = X_NET_JSONPWrapper || X_TEMP.X_NET_JSONP_init();\r
break;\r
case X_NET_TYPE_FORM :\r
- X_NET_currentWrapper = X_NET_FormWrapper;\r
+ X_NET_currentWrapper = X_NET_FormWrapper || X_TEMP.X_NET_Form_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_JSONP_errorTimerID;
X_TEMP.X_NET_JSONP_init = function(){
+ X_NET_JSONPWrapper = X_Class_override( X[ 'Util' ][ 'NinjaIframe' ](), X_TEMP.X_NET_JSONP_params );
delete X_TEMP.X_NET_JSONP_init;
+ delete X_TEMP.X_NET_JSONP_params;
- return X_NET_JSONPWrapper = X_Class_override(
- X[ 'Util' ][ 'NinjaIframe' ](),
- {
+ return X_NET_JSONPWrapper;
+};
+
+X_TEMP.X_NET_JSONP_params = {
_busy : false,
_canceled : false,
reset : function(){
X_NET_JSONPWrapper._busy = X_NET_JSONPWrapper._canceled = false;
- X_Net_JSONP_onloadCount = 0;
X_NET_JSONPWrapper[ 'unlisten' ]( [ 'ninjaload', 'ninjaerror' ], X_NET_JSONP_iframeListener );
X_NET_JSONPWrapper[ 'refresh' ]( '' );
X_Net_JSONP_errorTimerID && X_Timer_remove( X_Net_JSONP_errorTimerID );
+ X_Net_JSONP_errorTimerID = X_Net_JSONP_onloadCount = 0;
}
- }
- );
-};
+ };
function X_NET_JSONP_iframeListener( e ){
switch( e.type ){
--- /dev/null
+X[ 'Net' ][ 'Form' ] = {\r
+ // 隠し iframe 使用の可否\r
+};\r
+\r
+var X_NET_Form_errorTimerID, X_Net_Form_onloadCount = 0;\r
+\r
+X_TEMP.X_NET_Form_init = function(){\r
+ X_NET_FormWrapper = X_Class_override( X[ 'Util' ][ 'NinjaIframe' ](), X_TEMP.X_NET_Form_params );\r
+ \r
+ delete X_TEMP.X_NET_Form_init;\r
+ delete X_TEMP.X_NET_Form_params;\r
+ \r
+ return X_NET_FormWrapper;\r
+};\r
+\r
+/*\r
+ * form 構築時に "><script> といった文字列の挿入を禁止するために " を エスケープする、併せて改行文字を消す\r
+ */\r
+function X_NET_Form_escapeQuote( str ){\r
+ return X_String_toChrReferance( str );\r
+};\r
+\r
+X_TEMP.X_NET_Form_params = {\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
+ html, k;\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
+ '">' ],\r
+ k;\r
+ \r
+ if( target === '_top' || target === '_parent' ) this.isJump = true;\r
+ if( 0 <= option[ 'timeout' ] ) this.timeout = option[ 'timeout' ];\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
+ };\r
+ \r
+ html.push( '</form><script>document.forms[0].submit();</script>' );\r
+ \r
+ X_NET_FormWrapper\r
+ [ 'refresh' ]( html.join( '' ) )\r
+ [ 'listen' ]( [ 'ninjaload', 'ninjaerror' ], X_NET_Form_iframeListener );\r
+ \r
+ X_NET_FormWrapper._busy = true;\r
+ },\r
+ \r
+ cancel : function(){\r
+ X_NET_FormWrapper.reset();\r
+ X_NET_FormWrapper._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
+ }\r
+ };\r
+\r
+function X_NET_Form_iframeListener( e ){\r
+ var idoc;\r
+ \r
+ switch( e.type ){\r
+ case 'ninjaload' :\r
+ if( this.isJump ){\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
+\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, responce : 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
+ break;\r
+ };\r
+ return X_Callback_UN_LISTEN;\r
+};\r
obj.updateRequest = X_NET_OAUTH2_updateRequest;
if( _getAccessToken( this ) && ( expires_at = _getAccessTokenExpiry( this ) ) ){
- if( expires_at < X_Timer_now() + 300000 ){ // 寿命が5分を切った
+ if( expires_at < X_Timer_now() + ( obj[ 'refreshMargin' ] || 300000 ) ){ // 寿命が5分を切った
this[ 'refreshToken' ]();
} else {
obj.oauth2State = 4;
this[ 'asyncDispatch' ]( X_EVENT_NEED_AUTH );
};
- // TODO canUse
- // TODO kill の cancel
+ // TODO canUse gadgetProxy
+ this[ 'listen' ]( [ X_EVENT_KILL_INSTANCE, X_EVENT_SUCCESS, X_EVENT_ERROR, X_EVENT_NEED_AUTH ], X_NET_OAUTH2_handleEvent );
},
/**
delete pair.net;
};
+ if( pair.oauth2State !== 1 ){
+ return;
+ };
+
// http://kojikoji75.hatenablog.com/entry/2013/12/15/223839
X_NET_OAUTH2_authorizationWindow && X_NET_OAUTH2_authorizationWindow.open( 'about:blank', '_self' ).close();
X_NET_OAUTH2_authorizationWindow = null;
* アクセストークンのリフレッシュ。
*/
'refreshToken' : function(){
- // TODO 自動リフレッシュ
-
var pair = X_Pair_get( this );
if( pair.net ) return;
+ if( pair.refreshTimerID ){
+ X_Timer_remove( pair.refreshTimerID );
+ delete pair.refreshTimerID;
+ };
+
pair.oauth2State = 3;
pair.net = X.Net( {
}
);
+function X_NET_OAUTH2_handleEvent( e ){
+ var pair = X_Pair_get( this );
+
+ switch( e.type ){
+ case X_EVENT_KILL_INSTANCE :
+ this[ 'cancelAuth' ]();
+
+ case X_EVENT_ERROR :
+ case X_EVENT_NEED_AUTH :
+ pair.refreshTimerID && X_Timer_remove( pair.refreshTimerID );
+ break;
+
+ case X_EVENT_SUCCESS :
+ pair.refreshTimerID && X_Timer_remove( pair.refreshTimerID );
+ if( _getRefreshToken( this ) ){
+ // 自動リフレッシュ
+ pair.refreshTimerID = X_Timer_once( _getAccessTokenExpiry( this ) - X_Timer_now() - pair[ 'refreshMargin' ], this, this[ 'refreshToken' ] );
+ };
+ };
+};
+
function X_Net_OAuth2_detectAuthPopup(){
var closed, search, pair = X_Pair_get( this );
}\r
);\r
\r
+// TODO\r
+X[ 'Audio' ][ 'canPlay' ] = {};\r
+\r
function X_Audio_handleEvent( e ){\r
var backend;\r
\r
textShadowAlpha : true\r
},\r
XUI_Attr_Rename = {\r
- bgColor : 'background-color',\r
+ bgColor : 'backgroundColor',\r
fontColor : 'color',\r
fontBold : 'fontWeight',\r
fontItalic : 'fontStyle',\r
*/\r
XUI_Attr_Support = XUI_Attr_createAttrDef( 0,\r
{\r
- className : [ null, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.DEFAULT_ONLY | XUI_Attr_Type.STRING ],\r
- pointerHoverClass : [ null, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.DEFAULT_ONLY | XUI_Attr_Type.STRING ],\r
+ className : [ '', XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.DEFAULT_ONLY | XUI_Attr_Type.STRING ],\r
+ pointerHoverClass : [ '', XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.DEFAULT_ONLY | XUI_Attr_Type.STRING ],\r
pointerDownClass : [ null, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.DEFAULT_ONLY | XUI_Attr_Type.STRING ],\r
invalidLayoutColor: [ null, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.DEFAULT_ONLY | XUI_Attr_Type.COLOR ],\r
\r
- dataFeild : [ null, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.DEFAULT_ONLY | XUI_Attr_Type.STRING ],\r
+ dataFeild : [ '', XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.INIT_ONLY | XUI_Attr_Type.STRING ],\r
\r
role : [ 1, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.INIT_ONLY | XUI_Attr_Type.LIST, 'none,chrome' ],\r
selectable : [ false, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.INIT_ONLY | XUI_Attr_Type.BOOLEAN ],\r
pointerEnabled : [ false, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ],\r
pointerChildren : [ true, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.BOOLEAN ],\r
cursor : [ 1, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.LIST, XUI_Attr_Option.CURSOR ],\r
- tooltip : [ null, XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.STRING ],\r
+ tooltip : [ '', XUI_Dirty.CLEAN, XUI_Attr_USER.UINODE, XUI_Attr_Type.STRING ],\r
\r
borderWidth : [ 0, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.QUARTET | XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT ], // em [ top, right, bottom, left ]\r
padding : [ 0, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.QUARTET | XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT ],\r
\r
- width : [ XUI_Attr_AUTO, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT | XUI_Attr_Type.AUTO ],\r
+ width : [ XUI_Attr_AUTO, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT | XUI_Attr_Type.AUTO ],\r
minWidth : [ 0, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT ],\r
- maxWidth : [ XUI_Attr_AUTO, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT | XUI_Attr_Type.AUTO ],\r
- height : [ XUI_Attr_AUTO, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT | XUI_Attr_Type.AUTO ],\r
+ maxWidth : [ XUI_Attr_AUTO, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT | XUI_Attr_Type.AUTO ],\r
+ height : [ XUI_Attr_AUTO, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT | XUI_Attr_Type.AUTO ],\r
minHeight : [ 0, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT ],\r
- maxHeight : [ XUI_Attr_AUTO, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT | XUI_Attr_Type.AUTO ],\r
+ maxHeight : [ XUI_Attr_AUTO, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT | XUI_Attr_Type.AUTO ],\r
sizing : [ 1, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LIST, XUI_Attr_Option.BOX_SIZING ],\r
left : [ null, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT | XUI_Attr_Type.MINUS_LENGTH | XUI_Attr_Type.MINUS_PERCENT ],\r
top : [ null, XUI_Dirty.LAYOUT, XUI_Attr_USER.LAYOUT, XUI_Attr_Type.LENGTH | XUI_Attr_Type.PERCENT | XUI_Attr_Type.MINUS_LENGTH | XUI_Attr_Type.MINUS_PERCENT ],\r
PAGE_AFTER_HIDE : ++X_Event_last,\r
\r
// X.UI.Form\r
- CHANGE : ++X_Event_last,\r
- SUBMIT : ++X_Event_last,\r
- SELECT : ++X_Event_last, // click or tap or enterkey\r
+ CHANGE : ++X_Event_last,\r
+ SUBMIT : ++X_Event_last,\r
+ SELECT : ++X_Event_last, // click or tap or enterkey\r
+ \r
+ ITEMDATA_CHANGED : ++X_Event_last,\r
\r
IdToName : {},\r
NameToID : {}\r
'X.UI._AbstractUINode',\r
X_Class.ABSTRACT,\r
{\r
+ itemData : null,\r
+ \r
phase : 0,\r
dirty : XUI_Dirty.CLEAN,\r
\r
},\r
\r
addToParent : function( xnodeParent ){\r
+ var attr = this.attrObject || this.attrClass.prototype,\r
+ usableAttrs = this.usableAttrs,\r
+ i = 0, l = usableAttrs.length, def;\r
+ \r
xnodeParent && xnodeParent[ 'append' ]( this.xnode );\r
\r
+ if( attr ){\r
+ for( k in usableAttrs ){\r
+ def = usableAttrs[ k ];\r
+ if( def[ 2 ] === XUI_Attr_USER.XNODE && X_Object_inObject( def.No, attr ) && attr[ k ] !== def[ 0 ] ){\r
+ this.xnode[ 'css' ]( XUI_Attr_Rename[ k ] || k, XUI_AbstractUINode_createCssText( this, k ) );\r
+ };\r
+ };\r
+ };\r
+ \r
this.phase = 2;\r
this[ 'dispatch' ]( XUI_Event.ADDED );\r
},\r
this.User[ 'dispatch' ]( XUI_Event.CREATION_COMPLETE );\r
\r
// html 要素が親に追加されるまで控えていたイベントの登録\r
+ // TODO listenOnce\r
if( events && ( l = events.length ) ){\r
for( i = 0; i < l; ++i ){\r
this.listen.apply( this, events[ i ] );\r
\r
if( !v && v !== 0 ) v = defaultVal;\r
\r
+ // UIAttrClass の初期設定の場合、ここで終わる\r
if( XUI_attrClassProto ){\r
attrs[ propID ] = v;\r
return; \r
return ret;\r
},\r
\r
- setItemData : function(){\r
- // this[ 'dispatch' ]( UI_Event.ITEMDATA_CHANGED );\r
+ setItemData : function( itemData ){\r
+ if( this.itemData === itemData ) return;\r
+\r
+ this.itemData = itemData;\r
+\r
+ this[ 'dispatch' ]( { type : XUI_Event.ITEMDATA_CHANGED, itemData : itemData } );\r
+ // itemData && itemData.listen( X_Event_CHANGED )\r
+ // dataFeild dataFormatter dataValidator\r
+ \r
// itemData.listen( X_Event_CHANGED ) -> this[ 'dispatch' ]( UI_Event.ITEMDATA_UPDATED );\r
}\r
\r
};\r
};\r
} else\r
- if( X_Type_isString( nameOrObject ) ){\r
+ if( X_Type_isString( nameOrObject ) && ( def = p.usableAttrs[ nameOrObject ] ) ){\r
if( valueOrUnit !== undefined ){\r
if( 'em,%'.indexOf( valueOrUnit ) === -1 ){\r
// setter\r
- p.setAttr( nameOrObject, valueOrUnit );\r
+ p.setAttr( nameOrObject, def, valueOrUnit );\r
} else {\r
// getter with unit\r
return p.getAttrWithUnit( nameOrObject, valueOrUnit );\r
* Repeater に於いて、繰り返されるアイテムの元(itemRenderer)からの複製に使用\r
*/\r
clone : function( opt_cloneListener ){\r
- var newNode = this.constructor(),\r
- newPair = X_Pair_get( newNode ),\r
+ var newNode,\r
+ //newPair = X_Pair_get( newNode ),\r
pair = X_Pair_get( this ),\r
attr, listeners, type, list, i, l;\r
\r
+ // attr もコピー\r
+ if( pair.attrObject ){\r
+ attr = {};\r
+ for( k in pair.usableAttrs ){\r
+ def = pair.usableAttrs[ k ];\r
+ attr[ k ] = pair.attrObject[ def.No ];\r
+ };\r
+ newNode = this.constructor( attr );\r
+ };\r
+\r
// handleEvent 等の拡張されたオブジェクトもコピーする!\r
for( k in this ){\r
if( this[ k ] !== newNode[ k ] && !newNode[ k ] ) newNode[ k ] = this[ k ];\r
\r
// User.UINODE な値は pair にコピーされているのでこれをコピー\r
for( k in pair ){\r
- if( pair[ k ] !== newPair[ k ] && !newPair[ k ] ) newPair[ k ] = pair[ k ];\r
+ //pair[ k ] !== newPair[ k ] && !newPair[ k ] && console.log( k );\r
+ //if( pair[ k ] !== newPair[ k ] && !newPair[ k ] && k !== 'attrObject' && k !== '_listeners' ){\r
+ //newPair[ k ] = pair[ k ];\r
+ //console.log( k );\r
+ //};\r
};\r
\r
- // attr もコピー\r
- if( pair.attrObject ){\r
- attr = pair.attrClass();\r
- for( k in pair.attrObject ){\r
- if( pair.attrObject[ k ] !== attr[ k ] ) attr[ k ] = pair.attrObject[ k ];\r
- };\r
- newPair.attrObject = attr;\r
- };\r
+\r
\r
// listener もコピーする!\r
if( opt_cloneListener && ( listeners = pair[ '_listeners' ] ) ){\r
};\r
}; \r
};\r
+ } else\r
+ if( opt_cloneListener && ( list = this.reserveEvents ) ){\r
+ for( i = 0, l = list.length; i < l; ++i ){\r
+ f = list[ i ];\r
+ newNode[ f.once ? 'listenOnce' : 'listen' ]( f[ 0 ], newNode, f[ 1 ], f[ 2 ] );\r
+ }; \r
};\r
\r
return newNode;\r
initialize : function( root, rootData, parent, parentData ){\r
var uinodes = this.uinodes,\r
i = uinodes && uinodes.length;\r
- this.root = root;\r
- this.rootData = rootData;\r
- this.parent = parent;\r
- this.parentData = parentData;\r
\r
if( i ){\r
for( ; i; ){\r
}; \r
};\r
\r
- this.phase = 1;\r
- this.User[ 'dispatch' ]( { type : XUI_Event.INIT } );\r
+ XUI_AbstractUINode.prototype.initialize.apply( this, arguments );\r
},\r
\r
addToParent : function( parentXNode ){\r
l = uinodes && uinodes.length,\r
i;\r
\r
- parentXNode && parentXNode[ 'append' ]( this.xnode );\r
- \r
if( l ){\r
for( i = 0; i < l; ++i ){\r
uinodes[ i ].addToParent( this.xnode );\r
};\r
};\r
\r
- this.phase = 2;\r
- this.User[ 'dispatch' ]( { type : XUI_Event.ADDED } );\r
+ XUI_AbstractUINode.prototype.addToParent.apply( this, arguments );\r
},\r
\r
/* Rellay */\r
\r
addAt : function( index, _uinodes ){\r
//console.log( '# AddAt ' + this.phase )\r
- var uinodes = this.uinodes,\r
+ var uinodes = this.uinodes || ( this.uinodes = [] ),\r
num = uinodes.length,\r
p1 = 1 <= this.phase,\r
p2 = 2 <= this.phase,\r
directionLocked : '',\r
startTime : 0,\r
endTime : 0,\r
- isAnimating : false,\r
isInTransition : false,\r
\r
hasHScroll : false,\r
this.startTime = X_Timer_now();\r
\r
// スクロール中の停止\r
- if( this.isInTransition || this.isAnimating ){\r
- this.isInTransition = this.isAnimating = false;\r
+ if( this.isInTransition ){\r
+ this.isInTransition = false;\r
this[ 'dispatch' ]( XUI_Event.SCROLL_END );\r
+ // TODO current位置\r
this.xnodeSlider.stop();\r
}; \r
\r
absDistX, absDistY;\r
// 規定以上の move でスクロール開始\r
\r
-console.log( 'scrollmove ' + e.buttons + ' ' + e.button );\r
+//console.log( 'scrollmove ' + e.buttons + ' ' + e.button );\r
\r
if( !this.scrollEnabled || e.pointerType !== this.initiated ){\r
return ret;\r
return false;\r
};\r
\r
- //console.log( 'バウンド!' );\r
- //console.log( 'rese x:' + x + ' y:' + y );\r
+ console.log( ' ===> resetPosition - バウンド!' );\r
+ console.log( ' x:' + x + ' y:' + y );\r
that.scrollTo( x, y, time, that.bounceEasing, 1000 );\r
\r
return true;\r
};\r
};\r
\r
-// TODO Box の継承に!\r
X.UI.ScrollBox = X.UI.ChromeBox.inherits(\r
'ScrollBox',\r
X_Class.NONE,\r
if( XUI_ScrollBox.prototype.usableAttrs === XUI_ChromeBox.prototype.usableAttrs ){\r
XUI_ScrollBox.prototype.usableAttrs = supports = XUI_Attr_createAttrDef( XUI_Attr_Support, X_UI_ScrollBox_SUPPORT_ATTRS );\r
\r
- XUI_ScrollBox.prototype.attrClass = XUI_Attr_preset( XUI_Box.prototype.attrClass, supports, { width : '100%', height : '100%', bgColor : 0x111111 } );\r
+ XUI_ScrollBox.prototype.attrClass = XUI_Attr_preset( XUI_Box.prototype.attrClass, supports, { width : '100%', height : '100%', bgColor : 0x111111 } );\r
};\r
\r
var args = [\r
\r
}\r
}\r
-);
\ No newline at end of file
+);\r
+\r
\r
itemRenderer : null,\r
\r
+ itemNodes : null,\r
\r
startIndex : 0,\r
startRenderIndex : 0,\r
numItemsParPage : 0,\r
+ numItemsPrev : 0,\r
numItems : 0,\r
+ itemHeightLast : 0,\r
+ itemHeightLastEM : 0,\r
\r
Constructor : function( user, dataSource, itemRenderer, attr ){\r
this.Super( user, null, [ attr ] );\r
this.dataSource = dataSource;\r
this.itemRenderer = itemRenderer;\r
+ this.itemNodes = [];\r
+ this.__item__ = X_Pair_get( itemRenderer );\r
+ },\r
+ \r
+ initialize : function(){\r
+ XUI_AbstractUINode.prototype.initialize.apply( this, arguments );\r
+ \r
+ this.parent[ 'listen' ]( XUI_Event.SCROLL_END, this );\r
},\r
\r
/*\r
},\r
\r
handleEvent : function( e ){\r
- var scrollBox, scrollY, dataSource, offsetY, startIndex, maxIndex, offset, uinodes;\r
+ var scrollBox, scrollY, dataSource, offsetY, startIndex, maxIndex, offset, itemNodes, ary, i, l;\r
\r
switch( e.type ){\r
case XUI_Event.SCROLL_END :\r
scrollBox = this.parentData;\r
- scrollY = scrollBox.scrollY;\r
+ scrollY = - scrollBox.scrollY;\r
dataSource = this[ 'dataSource' ];\r
- uinodes = this.uinodes;\r
+ itemNodes = this.itemNodes;\r
+ itemH = this.itemHeightLast;\r
+ \r
// transition Y を 0 付近に。\r
- offsetY = scrollY % this.itemHeightLast;\r
- scrollBox.scrollTo( 0, offsetY, 0, '', 0 ); // anime無し\r
+ \r
+ \r
// startIndex の計算\r
- startIndex = scrollY / this.itemHeightLast | 0;\r
- maxIndex = dataSource.length <= this.numItems ? 0 : dataSource.length - this.numItems;\r
+ startIndex = scrollY / itemH | 0;\r
+ \r
+ /*maxIndex = dataSource.length <= this.numItems ? 0 : dataSource.length - this.numItems;\r
+ console.log( ' >>> ' + startIndex + ' ' + maxIndex );\r
+ \r
startIndex =\r
startIndex < 0 ? 0 :\r
- maxIndex < startIndex ? maxIndex : startIndex;\r
+ maxIndex < startIndex ? maxIndex : startIndex; */\r
// アイテムの座標の修正とレンジ外のアイテムを配列内で再配置\r
offset = startIndex - this.startIndex; // visible な stratIndex renderStartIndex\r
+ this.startIndex = startIndex;\r
+ \r
+ console.log( this.numItemsPrev + ' oo ' + offset )\r
\r
if( 0 < offset ){\r
- this.addAt( last, uinodes.splice( 0, offset ) );\r
+ itemNodes.push.apply( itemNodes, itemNodes.splice( 0, offset ) );\r
} else\r
- if( offset < 0 ){\r
- this.addAt( 0, uinodes.splice( uinodes.length - offset ) );\r
+ if( offset < - 0 ){\r
+ itemNodes.unshift.apply( itemNodes, itemNodes.splice( itemNodes.length + offset ) );\r
};\r
+\r
// 再配置されたアイテムにitemData のセット\r
this.updateItemRenderer( this.contentWidth, this.scrollPortHeight );\r
+ \r
+ \r
+ \r
+ offsetY = scrollY % itemH;\r
+ offsetY = offsetY === 0 ? 0 : ( offsetY - itemH );\r
+ offsetY += ( this.startRenderIndex - this.startIndex ) * itemH;\r
+ //console.log( ' ====> ' + this.startRenderIndex + ' -> ' + this.startIndex + ' scrollY:' + offsetY );\r
+\r
+ //scrollBox.scrollTo( 0, - scrollY, 0, '', 0 ); // anime無し \r
+ //console.log( ' <==== ' );\r
break;\r
};\r
},\r
\r
updateItemRenderer : function( _w, _h ){\r
- var uinodes = this.uinodes || ( this.uinodes = [] ),\r
+ var itemNodes = this.itemNodes,\r
attrs = this.attrObject || this.attrClass.prototype,\r
gapY = XUI_AbstractUINode_calcValue( attrs[ this.usableAttrs.gapY.No ], _w ),\r
dataSource = this[ 'dataSource' ],\r
render = this[ 'itemRenderer' ],\r
l = dataSource.length,\r
- start = this.startIndex - ( this.numItems - this.numItemsParPage ) / 2 | 0,\r
- itemH = this.itemHeightLast,\r
- i, node, data, _y = 0, last, n;\r
+ start = this.startIndex - this.numItemsPrev,\r
+ itemH = this.itemHeightLastEM,\r
+ i, data, node, _y = 0, last, n;\r
+ \r
+ i = this.startRenderIndex = start = start < 0 ? 0 : start;\r
\r
- i = start = start < 0 ? 0 : start;\r
+ _y = ( itemH + gapY ) * i;\r
\r
for( ; i < l; ++i ){\r
- if( !( node = uinodes[ i ] ) ){\r
+ if( !( data = itemNodes[ i ] ) ){\r
node = render.clone( true );\r
this.addAt( i, [ node ] );\r
- data = X_Pair_get( node );\r
+ data = itemNodes[ i ] = X_Pair_get( node );\r
// init -> addToParent -> creationComplete\r
};\r
data.setItemData( dataSource[ i ] );\r
// 一番最初のループ。ここでページあたりのアイテム数を計算\r
if( !itemH && i === start ){\r
itemH = _y - gapY;\r
- this.itemHeightLast = itemH * X_ViewPort_baseFontSize,\r
+ this.itemHeightLastEM = itemH;\r
+ this.itemHeightLast = itemH * X_ViewPort_baseFontSize,\r
// scroller の miniHeight は(例えば)親の高さの300% そこにいくつのアイテムを並べることが出来るか?端数切り上げ\r
this.numItemsParPage = _h / itemH + 0.999 | 0;\r
n = this.numItems = ( _h * 3 ) / itemH + 0.999 | 0; // TODO boxHeight\r
+ this.numItemsPrev = ( this.numItems - this.numItemsParPage ) / 2 | 0;\r
last = i + n;\r
// データの最後まで、または、開始位置から 3ページ分を生成する\r
l = last < l ? last : l;\r
};\r
};\r
\r
- for( l = uinodes.length; i < l; ++i ){\r
- // uinodes[ i ] hide\r
+ for( l = itemNodes.length; i < l; ++i ){\r
+ // itemNodes[ i ] hide\r
};\r
\r
// TODO contentHeight は attr を無視する -> 未表示領域につくるアイテム数 GPU の有無で変わる\r
- this.contentHeight = _y - gapY;\r
+ this.contentHeight = dataSource.length * ( itemH + gapY ) - gapY;\r
},\r
\r
onPropertyChange : function( name, newValue ){\r
- var uinodes, i, l, uinode, dataList, from;\r
+ var itemNodes, i, l, uinode, dataList, from;\r
\r
switch( name ){\r
case 'itemRenderer' :\r
- for( uinodes = this.uinodes, i = uinodes && uinodes.length; i; ){\r
- uinodes[ --i ][ 'kill' ]();\r
+ for( itemNodes = this.itemNodes, i = itemNodes && itemNodes.length; i; ){\r
+ itemNodes[ --i ][ 'kill' ]();\r
};\r
\r
case 'dataSource' :\r
- if( uinodes = this.uinodes ){\r
- i = uinodes.length;\r
+ if( itemNodes = this.itemNodes ){\r
+ i = itemNodes.length;\r
l = this[ 'dataSource' ].length;\r
while( l < i ){\r
- uinodes[ --i ][ 'kill' ]();\r
- uinodes.length = i;\r
+ itemNodes[ --i ][ 'kill' ]();\r
+ itemNodes.length = i;\r
}; \r
};\r
\r
var supports;\r
\r
if( XUI_Repeater.prototype.usableAttrs === XUI_Box.prototype.usableAttrs ){\r
- XUI_Repeater.prototype.usableAttrs = supports = XUI_Attr_createAttrDef( XUI_Attr_Support, XUI_Layout_Vertical.overrideAttrsForSelf );\r
+ supports = XUI_Attr_createAttrDef( XUI_Attr_Support, X_UI_Repeater_SUPPORT_ATTRS );\r
+ XUI_Repeater.prototype.usableAttrs = supports = XUI_Attr_createAttrDef( supports, XUI_Layout_Vertical.overrideAttrsForSelf );\r
\r
XUI_Repeater.prototype.attrClass = XUI_Attr_preset( XUI_Box.prototype.attrClass, supports );\r
};\r
width : 'auto',\r
minWidth : '100%',\r
height : 'auto',\r
- minHeight : '100%'\r
+ minHeight : '100%',\r
+ borderColor : 0x252527,\r
+ borderWidth : [ 0.15, 0, 0 ],\r
+ borderStyle : 'solid',\r
+ height : 'auto',\r
+ bgColor : 0x444643,\r
+ gapY : 0.15\r
}));\r
},\r
\r
{\r
borderColor : 0x252527,\r
borderWidth : [ 0.15, 0, 0 ],\r
+ borderStyle : 'solid',\r
height : 'auto',\r
bgColor : 0x444643,\r
- gapY : 0.1,\r
+ gapY : 0.15,\r
scrollSlider : X.UI.Repeater.apply( 0, [ dataSource, itemRenderer ] )\r
}\r
);\r
+var X_UI_Text_SUPPORT_ATTRS = {\r
+ content : [ '', XUI_Dirty.CONTENT, XUI_Attr_USER.UINODE, XUI_Attr_Type.STRING ]\r
+};\r
+\r
var XUI_Text = XUI_AbstractUINode.inherits(\r
'_Text',\r
X_Class.NONE,\r
{\r
content : '',\r
\r
+ usableAttrs : XUI_Attr_createAttrDef( XUI_AbstractUINode.prototype.usableAttrs, X_UI_Text_SUPPORT_ATTRS ),\r
+ \r
Constructor : function( user, content ){\r
if( !( user[ 'instanceOf' ]( X.UI.Text ) ) ){\r
alert( 'Text を継承したインスタンスだけが _Text のオーナーになれます' );\r
};\r
\r
XUI_AbstractUINode.prototype.creationComplete.apply( this, arguments ); \r
+ },\r
+ \r
+ setItemData : function( itemData ){\r
+ if( this.itemData === itemData ) return;\r
+ \r
+ XUI_AbstractUINode.prototype.setItemData.apply( this, arguments );\r
+ \r
+ if( X_Type_isObject( itemData = this.itemData ) && this.dataFeild ){\r
+ this.User.content( itemData[ this.dataFeild ] || '' );\r
+ };\r
}\r
}\r
);\r