From 35daae003b3b017a92d0c883f120bf3baf604fba Mon Sep 17 00:00:00 2001 From: itozyun Date: Sat, 7 Nov 2015 07:20:29 +0900 Subject: [PATCH] Version 0.6.190, fix X.UI.ScrollBox & X.UI.Gesture. --- 0.6.x/css/xui.css | 90 +-- 0.6.x/img/loading.gif | Bin 0 -> 225 bytes 0.6.x/js/01_core/02_XUA.js | 24 +- 0.6.x/js/01_core/13_XClass.js | 128 ++- 0.6.x/js/01_core/14_XEvent.js | 4 +- 0.6.x/js/01_core/15_XEventDispatcher.js | 2 +- 0.6.x/js/01_core/20_XSystem.js | 2 +- 0.6.x/js/02_dom/03_XDomEvent.js | 19 +- 0.6.x/js/02_dom/06_XNodeCSS.js | 6 +- 0.6.x/js/02_dom/10_XNodeAnime.js | 62 +- 0.6.x/js/02_dom/20_XNode.js | 10 +- 0.6.x/js/06_net/03_XNetForm.js | 13 +- 0.6.x/js/07_audio/01_XWebAudio.js | 2 +- 0.6.x/js/20_ui/01_XUI_LayoutBase.js | 2 +- 0.6.x/js/20_ui/02_XUI_Attr.js | 2 +- 0.6.x/js/20_ui/04_XUI_Event.js | 10 +- 0.6.x/js/20_ui/05_XUI_Gesture.js | 1332 +++++++++++-------------------- 0.6.x/js/20_ui/06_AbstractUINode.js | 101 ++- 0.6.x/js/20_ui/08_Box.js | 12 +- 0.6.x/js/20_ui/15_ScrollBox.js | 95 ++- 0.6.x/js/20_ui/17_Text.js | 35 +- 0.6.x/js/20_ui/20_Root.js | 86 +- 0.6.x/js/main.js | 175 ++-- 23 files changed, 993 insertions(+), 1219 deletions(-) create mode 100644 0.6.x/img/loading.gif diff --git a/0.6.x/css/xui.css b/0.6.x/css/xui.css index e676fed..41efe9a 100644 --- a/0.6.x/css/xui.css +++ b/0.6.x/css/xui.css @@ -35,6 +35,11 @@ font-family: 'MS Pゴシック',sans-serif; } + .js-disabled { + background : #111 url( "../img/loading.gif" ) 50% 50% no-repeat; + } + + .Root { height : 100%; } @@ -52,7 +57,7 @@ /* ブラウザのレイアウト機能による auto なサイズ指定は行わない */ overflow : hidden; border-style : solid; - + border-width : 0; /* border-box がデフォルト box-sizing : border-box; -o-box-sizing : border-box; @@ -113,10 +118,6 @@ tap-highlight-color : rgba(0,0,0,0); -webkit-tap-highlight-color : rgba(0,0,0,0); } - .ActiveX .mouse-operation-catcher { - background-color : #fff; - filter : alpha( opacity=0 ); - } /* * ie では、背景を設定しないと、 mousemove が働かない。 * activeX 有効の場合は背景を着色して filter で透明に。 @@ -124,65 +125,13 @@ * background: url(4x4.gif) fixed repeat; */ .mouse-operation-catcher { - background : url( "../img/opacity0.gif" ) fixed repeat; - } - - -.slidein, .slideout { - position : relative; - width : 200px; - height : 200px; - margin : 1em auto; - background : #000; + background : url( "../img/opacity0.gif" ) fixed repeat; + } - -webkit-transition : 0.5s ease-in-out; /* win safari3.2 */ - -webkit-transition : -webkit-transform 0.5s ease-in-out; /* win safari4 delay は指定しない */ - -moz-transition : -moz-transform 0.5s ease-in-out 0s; - -ms-transition : -ms-transform 0.5s ease-in-out 0s; - -o-transition : -o-transform 0.5s ease-in-out 0s; - transition : transform 0.5s ease-in-out 0s; - - /* http://blog.webcreativepark.net/2012/10/19-161432.html */ - -webkit-backface-visibility : hidden; - -moz-backface-visibility : hidden; - backface-visibility : hidden; -} -.slidein .slider { - -webkit-transform : translate(100px,0); /* win safari3.2 */ - -webkit-transform : translateX(100px) translateZ(0); /* safari4 */ - -moz-transform : translateX(100px) translateZ(0); - -ms-transform : translateX(100px) translateZ(0); - -o-transform : translateX(100px) translateZ(0); - transform : translateX(100px) translateZ(0); -} -.slideout .slider { - -webkit-transform : translate(0,0); /* win safari3.2 */ - -webkit-transform : translateX(0) translateZ(0); /* safari4 */ - -moz-transform : translateX(0) translateZ(0); - -ms-transform : translateX(0) translateZ(0); - -o-transform : translateX(0) translateZ(0); - transform : translateX(0) translateZ(0); -} -.slider { - position : absolute; - top : 0; - height : 0; -} -.slider div { - position : absolute; - top : 0; - width : 200px; - height : 200px; -} -.slider-red { - left : 0; - background : #f00; -} -.slider-blue { - left : 200; - background : #00f; -} - + .ActiveX .mouse-operation-catcher { + background : #fff; + filter : alpha( opacity=0 ); + } /*------------------------------------------------------------------------------------ * hidden-sysyem-node @@ -235,17 +184,14 @@ /* Scrollbox --------------------------------------------------------------------------------------*/ .ScrollBox-Scroller { - transform : translate( 0, 0 ); - transformOrigin : '0 0'; position : absolute; } .Root .ScrollBox-IndicatorV, .Root .ScrollBox-IndicatorH { - position : absolute; - overflow : hidden; - background : #000; - background : rgba(0,0,0,0.5); - border : 0; + position : absolute; + overflow : hidden; + background : #000; + background : rgba(0,0,0,0.5); } .Root .ScrollBox-IndicatorV { top : 0; @@ -259,3 +205,7 @@ left : 0; height : 0.5em; } + .IE4 .ScrollBox-IndicatorH, + .IE5x .ScrollBox-IndicatorH { + line-height : 0.5; + } diff --git a/0.6.x/img/loading.gif b/0.6.x/img/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..2f533695e161a87c3dde19c3246b69a6ab02155f GIT binary patch literal 225 zcmZ?wbhEHb6ldUIn8?KN?%lhzw6y>K|1&T!DE{a6a}5c0b_{Se(lcOY1PT3QVKri4 zV$cDy89-VXnB-b?7tWI2%U9Izq0vCmHt3)q<6Af=y-vnv7Q&h68$Z+ohQPM+AMg;8?QE;&N{3gF}hQ%ANP6 MX6f8?Vr8%f08u7CX8-^I literal 0 HcmV?d00001 diff --git a/0.6.x/js/01_core/02_XUA.js b/0.6.x/js/01_core/02_XUA.js index 6f6e58b..78b62f2 100644 --- a/0.6.x/js/01_core/02_XUA.js +++ b/0.6.x/js/01_core/02_XUA.js @@ -323,9 +323,26 @@ var X_UA = X[ 'UA' ] = {}, console.log( '>> Opera : ' + v ); } else - + if( v = parseFloat( dav.split( 'Edge/' )[ 1 ] ) ){ + /** + * Microsoft Edge + * @alias X.UA.Edge + * @type {number} + */ + X_UA[ 'Edge' ] = v; + + if( dav.indexOf( 'Mobile' ) ){ + /** + * Microsoft Edge for Windows 10 Mobile + * @alias X.UA.EdgeMobile + * @type {number} + */ + X_UA[ 'EdgeMobile' ] = v; + }; + + } else // Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko - if( ( v = dav.split( 'Trident/' )[ 1 ] ) || document.all ){ + if( ( v = dav.split( 'Trident/' )[ 1 ] ) || document.all ){ // .all は Opera にもいるので Opera の判定が先 if( v = parseFloat( v ) ) /** * IE11 の互換モードの navigator.appVersion にも Trident/7.0 が書かれているため互換モードか?判定ができるc @@ -342,8 +359,7 @@ var X_UA = X[ 'UA' ] = {}, X_UA[ 'ActiveX' ] = true; v = parseFloat( dua.split( 'MSIE ' )[ 1 ] ) || - parseFloat( dua.split( 'rv:' )[ 1 ] ) || - parseFloat( dav.split( 'MSIE ' )[ 1 ] ) || 0; + parseFloat( dua.split( 'rv:' )[ 1 ] ) || 0; tridentToVer = X_UA[ 'Trident' ] ? ( X_UA[ 'Trident' ] + 4 | 0 ) : v; diff --git a/0.6.x/js/01_core/13_XClass.js b/0.6.x/js/01_core/13_XClass.js index bf86574..dc1166b 100644 --- a/0.6.x/js/01_core/13_XClass.js +++ b/0.6.x/js/01_core/13_XClass.js @@ -22,10 +22,13 @@ var X_Class_DEF_LIST = [], X_Class_CALLING_SUPER = [], X_Class_CALL_SUPER_STACK = [], + X_Class_SUPER_CALLER = [], + X_Class_SUPER_STACKS = [], X_Class_traits = null, X_Class_useObjectCreate = false, // !!Object.create, http://jsperf.com/prototype-vs-object-create-perf // Opera Mobile 12.10 Android11 IS01 でクラスのメンバが欠落する問題に遭遇。__proto__ を辞めると動作,,, X_Class_use_proto_ = !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] && !!X_emptyFunction.prototype.__proto__, + X_Class_constructorFix = X_UA[ 'AOSP' ] < 3 || X_UA[ 'iOS' ] < 5, X_Class_SEAL_KILLING = [], X_Class_CommonMethods = @@ -128,14 +131,15 @@ X_Class_CommonMethods = */ // TODO 現在 new しているインスタンスを保持してチェックする 'Super' : function( var_args ){ - var sClass = this, - i = X_Class_CALLING_SUPER.indexOf( sClass ), + var me = this, + sClass = me, + i = X_Class_CALLING_SUPER.indexOf( me ), l, sList, def, sConst, ret; if( i === -1 ){ - X_Class_CALLING_SUPER[ l = X_Class_CALLING_SUPER.length ] = sClass; + X_Class_CALLING_SUPER[ l = X_Class_CALLING_SUPER.length ] = me; X_Class_CALL_SUPER_STACK[ l ] = sList = []; - def = X_Class_getClassDef( sClass ); + def = X_Class_getClassDef( me ); if( !def.Constructor ) sClass = def.SuperClass;// 現在のクラスがコンストラクタを持たない場合 SuperConstructor を new で呼んでいるため再び呼ばないようにする } else { sList = X_Class_CALL_SUPER_STACK[ i ]; @@ -148,13 +152,13 @@ X_Class_CommonMethods = if( !sConst ) break; if( sList.indexOf( sConst ) === -1 ){ sList[ sList.length ] = sConst; - ret = sConst.apply( this, arguments ); + ret = sConst.apply( me, arguments ); --sList.length; if( !sList.length ){ X_Class_CALLING_SUPER.splice( i, 1 ); X_Class_CALL_SUPER_STACK.splice( i, 1 ); }; - return ret; + return ret || me; }; }; console.log( 'スーパークラスのコンストラクタが見つかりません' ); @@ -162,20 +166,38 @@ X_Class_CommonMethods = /** * func について、親クラスで設定されている同名の関数メンバーを呼び出す。
- * 第一引数に関数を指定し、2つ以上の異なる名前で同じ関数がメンバーがいた場合、動作が不確実になります。
+ * 第一引数にオーバーライド済の自身の(自身から参照できる)関数を指定します。内部では関数名を調べた上で prototype チェーンをゴリゴリ辿る、特別なことはしていません。 + * superCall がネストする場合、arguments.callee でないと正しく現在階層を取得して親関数を知ることができない + * 次の理由によって、関数名で辿ることはやめました + *
    + *
  1. closur compiler でメソッド名が変更される + *
  2. superCall 内からさらに superCall が呼ばれた場合に、起点となる関数を特定できない + *
+ * 次の場合、意図した動作が得られません + *
    + *
  1. 2つ以上の異なる名前で同じ関数がメンバーがいた場合
    + *
  2. または、サブクラスのメンバーにスーパークラスと同じ関数が出現する + *
  3. superCall 以外の手段で親関数を呼び、そのなかで superCall を読んだ + *
+ * 通常の X.Class.create の書き方ではこのような状況は起きませんが、js はなんでもできるので * 参考:ES5なJavascriptでモダンなクラス的継承&スーパー呼び出し - * @param funcNameOrFunc {Function|string} スーパークラスの関数名 または、オーバーライド済の自身の関数。 + * @param myFunc {Function|string} オーバーライド済の自身の(自身から参照できる)関数。 * @param var_args {...*} オーバーライド元関数に渡す任意の数の引数 * @example return this.superCall( arguments.callee, param0, param1, ... ); * @return {*} オーバーライド元の関数を呼び出した戻り値。 */ - 'superCall' : function( funcNameOrFunc, var_args ){ - var sClass = this, + 'superCall' : function( myFunc, var_args ){ + var me = this, + sClass = me.constructor, + proto = sClass.prototype, + i = X_Class_SUPER_CALLER.indexOf( me ), + l, d, ret, args = arguments, - name, p, sFunc, hit = false; - if( X_Type_isFunction( funcNameOrFunc ) ){ - for( p in this.constructor.prototype ){ - if( this.constructor.prototype[ p ] === funcNameOrFunc ){ + name, p, sFunc, hit; + + if( X_Type_isFunction( myFunc ) ){ + for( p in proto ){ + if( proto[ p ] === myFunc ){ name = p; break; }; @@ -184,41 +206,76 @@ X_Class_CommonMethods = } else { return; }; + + if( i === -1 ){ + X_Class_SUPER_CALLER[ l = X_Class_SUPER_CALLER.length ] = me; + X_Class_SUPER_STACKS[ l ] = d = {}; + } else { + d = X_Class_SUPER_STACKS[ i ]; + }; - if( X_EMPTY_OBJECT[ name ] ) return; - + if( stack = d[ name ] ){ + myFunc = stack[ stack.length - 1 ]; + } else { + stack = d[ name ] = []; + }; + + /* + while( t ){ + sClass = X_Class_getClassDef( sClass ).SuperClass; + --t; + }; + mysFunc = sClass.prototype[ name ]; */ + + + // TODO while( sClass ){ - def = X_Class_getClassDef( sClass ); - sClass = def.SuperClass; - sFunc = sClass.prototype[ name ]; - if( sFunc === funcNameOrFunc ){ - hit = true; // 現在の関数にヒット + sFunc = sClass.prototype[ name ]; + + if( !hit && sFunc === myFunc ){ + hit = true; // 現在の関数にヒット, さらにスーパークラスを辿って同名のプロパティの関数が現れたらそれが目指すもの } else - if( hit && X_Object_inObject( name, this ) ){ + if( hit && sFunc !== myFunc /* X_Object_own( name, sClass.prototype ) */ ){ + // this の関数と異なり、値が設定されていたら、今は手を抜いて undef か?見ている、正しくは hasOwnProperty if( X_Type_isFunction( sFunc ) ){ + stack[ stack.length ] = sFunc; switch( args.length ){ + case 0 : + ret = sFunc.call( me ); + break; case 1 : - return sFunc.call( this ); + ret = sFunc.call( me, args[ 0 ] ); + break; case 2 : - return sFunc.call( this, args[ 1 ] ); + ret = sFunc.call( me, args[ 0 ], args[ 1 ] ); + break; case 3 : - return sFunc.call( this, args[ 1 ], args[ 2 ] ); - case 4 : - return sFunc.call( this, args[ 1 ], args[ 2 ], args[ 3 ] ); + ret = sFunc.call( me, args[ 0 ], args[ 1 ], args[ 2 ] ); + break; default : args = X_Array_copy( args ); args.shift(); - return sFunc.apply( this, args ); + ret = sFunc.apply( me, args ); + break; }; + --stack.length; }; break; }; + sClass = X_Class_getClassDef( sClass ).SuperClass; + }; + + if( !stack.length ) delete d[ name ]; + if( X_Object_isEmpty( d ) ){ + X_Class_SUPER_CALLER.splice( l, 1 ); + X_Class_SUPER_STACKS.splice( l, 1 ); }; + return ret; }, /** * インスタンスのクラスか?またはスーパークラスか?調べる。
- * instanceof 構文をサポートしない環境(IE4,Mac IE5)を想定する場合、必ずこのメソッドを使用すること。
+ * instanceof 構文をサポートしない環境(IE5以下)を想定する場合、必ずこのメソッドを使用すること。
* クラスのインスタンスか?だけ調べたい場合は this.constructor === klass が高速。 * @param klass {__ClassBase__} クラス定義 * @return {boolean} @@ -429,16 +486,13 @@ X[ 'Class' ] = /** @lends X.Class */ { function X_Class_getClass( instance ){ - var cList = X_Class_CLASS_LIST, - i = cList.length, - klass; - for( ; i; ){ - klass = cList[ --i ]; - if( instance.constructor === klass ) return klass; - }; + var cList = X_Class_CLASS_LIST, i; + + if( ( i = cList.indexOf( instance.constructor ) ) !== -1 ) return cList[ i ]; if( cList.indexOf( instance ) !== -1 ) return instance; }; +// TODO def = klass( X_Closure_COMMAND_BACK ) function X_Class_getClassDef( KlassOrInstance ){ var i = X_Class_CLASS_LIST.indexOf( KlassOrInstance ); if( i === -1 ) i = X_Class_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) ); @@ -584,7 +638,7 @@ function X_Class_actualConstructor( f, args ){ def.live && def.live.push( instance ); - if( ( X_UA[ 'AOSP' ] < 3 || X_UA[ 'iOS' ] < 5 ) && instance.constructor !== klass ){ + if( X_Class_constructorFix && instance.constructor !== klass ){ console.log( '------- constructor の不一致!' ); // Android2.3.7 instance.constructor = klass; }; diff --git a/0.6.x/js/01_core/14_XEvent.js b/0.6.x/js/01_core/14_XEvent.js index 01ded21..fa236ac 100644 --- a/0.6.x/js/01_core/14_XEvent.js +++ b/0.6.x/js/01_core/14_XEvent.js @@ -35,7 +35,7 @@ var X_Event_Rename = {}, 'touchmove' : 'pointermove', 'mousemove' : 'pointermove', 'touchleave' : 'pointerleave', - 'mouseout' : 'pointerleave', + 'mouseout' : 'pointerout', 'mouseleave' : 'pointerleave', 'touchcancel' : 'pointercancel', 'contextmenu' : 'contextmenu', @@ -46,7 +46,7 @@ var X_Event_Rename = {}, 'mousedown' : 'pointerdown', 'mouseup' : 'pointerup', 'mousemove' : 'pointermove', - 'mouseout' : 'pointerleave', + 'mouseout' : 'pointerout', 'mouseleave' : 'pointerleave', 'contextmenu' : 'contextmenu', 'dbclick' : 'dbclick', diff --git a/0.6.x/js/01_core/15_XEventDispatcher.js b/0.6.x/js/01_core/15_XEventDispatcher.js index 4ae7f15..34a5933 100644 --- a/0.6.x/js/01_core/15_XEventDispatcher.js +++ b/0.6.x/js/01_core/15_XEventDispatcher.js @@ -54,7 +54,7 @@ var X_EventDispatcher_once = false, // iOS と MacOSX Iron36 で発生。連続してアニメーションが起こると、クロージャの束縛された obj へのアクセスに失敗する。Win では起きない? // むしろ、MacOSX のブラウザ全般で起こる?? - X_EventDispatcher_ANIME_EVENTS = false && ( X_UA[ 'WebKit' ] || X_UA[ 'Blink' ] ) && { + X_EventDispatcher_ANIME_EVENTS = ( X_UA[ 'WebKit' ] || X_UA[ 'Blink' ] ) && { 'transitionend' : true, 'webkitTransitionEnd' : true, 'mozTransitionEnd' : true, 'oTransitionEnd' : true, 'otransitionEnd' : true, 'animationend' : true, 'webkitAnimationEnd' : true, 'oAnimationEnd' : true, 'animationstart' : true, 'webkitAnimationStart' : true, 'oAnimationStart' : true, diff --git a/0.6.x/js/01_core/20_XSystem.js b/0.6.x/js/01_core/20_XSystem.js index feef443..111dbcb 100644 --- a/0.6.x/js/01_core/20_XSystem.js +++ b/0.6.x/js/01_core/20_XSystem.js @@ -58,7 +58,7 @@ X_TEMP.onRearchEndOfScript = function(){ now = X_Timer_now(), speed = now - X[ 'bootTime' ]; - X_System_javascriptScore = speed; + X[ 'bootSpeed' ] = X_System_javascriptScore = speed; console.log( 'js score ' + speed ); delete X_TEMP.onRearchEndOfScript; diff --git a/0.6.x/js/02_dom/03_XDomEvent.js b/0.6.x/js/02_dom/03_XDomEvent.js index 70cffaa..7c94b06 100644 --- a/0.6.x/js/02_dom/03_XDomEvent.js +++ b/0.6.x/js/02_dom/03_XDomEvent.js @@ -171,7 +171,7 @@ if( !X_UA[ 'IE' ] || 9 <= X_UA[ 'IE' ] ){ 'width' : touch.width || 0, 'height' : touch.height || 0 }; - console.log( 'e.pointerId = ' + touch.identifier ); + //console.log( 'e.pointerId = ' + touch.identifier ); }; return events.length === 1 ? events[ 0 ] : events; } else { @@ -185,15 +185,14 @@ if( !X_UA[ 'IE' ] || 9 <= X_UA[ 'IE' ] ){ this[ 'type' ] = pointerEventType; this[ 'pointerType' ] = 'mouse'; - this[ 'button' ] = e.button !== undefined ? e.button : - e.which !== undefined ? e.which - 1 : -1; + this[ 'button' ] = e.button !== undefined ? e.button : e.which !== undefined ? e.which - 1 : -1; this[ 'buttons' ] = e.buttons !== undefined ? e.buttons : this[ 'button' ] === 0 ? 1 : this[ 'button' ] === 1 ? 2 : this[ 'button' ] === 2 ? 4 : 0; this[ 'pressure' ] = ( this[ 'button' ] !== -1 ? 0.5 : 0 ); elm = e.target; this[ 'target' ] = X_Node_getXNode( elm.nodeType === 3 ? elm.parentNode : elm );// defeat Safari bug // xnodetouch.target; this[ 'isPrimary' ] = true; - this[ 'hwTimestamp' ] = this[ 'timestamp' ] = X_Timer_now(); + this[ 'hwTimestamp' ] = this[ 'timestamp' ] = X_Timer_now(); this[ 'altKey' ] = e.altKey; this[ 'ctrlKey' ] = e.ctrlKey; this[ 'metaKey' ] = e.metaKey; @@ -350,7 +349,9 @@ if( !X_UA[ 'IE' ] || 9 <= X_UA[ 'IE' ] ){ // this[ 'offsetX' ] = e.x - e.srcElement.offsetLeft; // e.x はイベント発生要素の親要素を基準にした座標。 // this[ 'offsetY' ] = e.y - e.srcElement.offsetTop; //}; - + this[ 'pressure' ] = ( this[ 'button' ] !== -1 ? 0.5 : 0 ); + this[ 'isPrimary' ] = true; + this[ 'hwTimestamp' ] = this[ 'timestamp' ] = X_Timer_now(); this[ 'pointerId' ] = 1; this[ 'radiusX' ] = 0; this[ 'radiusY' ] = 0; @@ -453,16 +454,16 @@ if( !navigator.pointerEnabled ){ X_Event_Rename[ 'pointerup' ] = [ 'touchend', 'mouseup' ]; X_Event_Rename[ 'pointermove' ] = [ 'touchmove', 'mousemove' ]; X_Event_Rename[ 'pointercancel' ] = 'touchcancel'; - X_Event_Rename[ 'pointerout' ] = + //X_Event_Rename[ 'pointerout' ] = X_Event_Rename[ 'pointerleave' ] = 'touchleave'; // X_Event_Rename[ 'click' ] = [ 'touchstart', 'touchmove', 'touchend' ]; // ループになってしまう!直した!直ってない! } else { X_Event_Rename[ 'pointerdown' ] = 'mousedown'; X_Event_Rename[ 'pointerup' ] = 'mouseup'; X_Event_Rename[ 'pointermove' ] = 'mousemove'; - X_Event_Rename[ 'pointercancel' ] = - X_Event_Rename[ 'pointerleave' ] = - X_Event_Rename[ 'pointerleave' ] = document.documentElement.onmouseleave !== undefined ? 'mouseleave' : 'mouseout'; + //X_Event_Rename[ 'pointercancel' ] = + //X_Event_Rename[ 'pointerout' ] = + X_Event_Rename[ 'pointerleave' ] = X_elmHtml.onmouseleave !== undefined ? 'mouseleave' : 'mouseout'; // Opera は ブラウザ設定から右クリックの通知を許可すると mousedown で e.button==2 が返る,キャンセルは可能?? X_UA[ 'Opera' ] && ( X_Event_Rename[ 'contextmenu' ] = 'mousedown' ); diff --git a/0.6.x/js/02_dom/06_XNodeCSS.js b/0.6.x/js/02_dom/06_XNodeCSS.js index 22b3e02..1f1fe70 100644 --- a/0.6.x/js/02_dom/06_XNodeCSS.js +++ b/0.6.x/js/02_dom/06_XNodeCSS.js @@ -190,7 +190,7 @@ function X_Node_CSS_parseColor( x ){ var rgb, r, g, b; if( X_Type_isNumber( x ) ){ - return ( 0x0 <= x && x <= 0xFFFFFF ) ? x : undefined; + return ( 0x0 <= x && x <= 0xFFFFFF ) ? x : NaN; } else if( !X_Type_isString( x ) ) return; @@ -239,9 +239,9 @@ function X_Node_CSS_parseColor( x ){ b *= 2.55; }; } else { - return undefined; + return NaN; }; - return X_Type_isFinite( r + b + g ) ? ( r << 16 ) + ( g << 8 ) + b : undefined; + return X_Type_isFinite( r + b + g ) ? ( r << 16 ) + ( g << 8 ) + b : NaN; }; function X_Node_CSS_objToCssText( that, skipFilter ){ diff --git a/0.6.x/js/02_dom/10_XNodeAnime.js b/0.6.x/js/02_dom/10_XNodeAnime.js index 7064166..2520f14 100644 --- a/0.6.x/js/02_dom/10_XNodeAnime.js +++ b/0.6.x/js/02_dom/10_XNodeAnime.js @@ -47,7 +47,10 @@ var } } }; - + +// お約束 +// transform や transition animation は スタイルシートに書かない + // 新規アニメーションが追加された場合、 // tree が dirty なら AFTER_COMMIT を待つ // 1) xnode の既存アニメーションとの親子関係の調査 @@ -68,11 +71,11 @@ var X_Node_ANIMATIONS = [], /* GPUレイヤーにいる間に要素のコンテンツを変更をすると transitionend が動かなくなるっぽい Mac safari と firefox */ X_Node_Anime_translateZ = X_Node_CSS_VENDER_PREFIX[ 'perspective' ] && !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] ? ' translateZ(0)' : '', /* Opera12(XP,8.1) 切った方がスムース, win Safari3 で、たまに動作が止まってしまう、、、 */ - X_Node_Anime_hasTransition = !!X_Node_CSS_VENDER_PREFIX[ 'transitionDelay' ] && !X_UA[ 'Opera' ], // && !( X_UA[ 'Webkit' ] <= 528.16 ), + X_Node_Anime_hasTransition = false && !!X_Node_CSS_VENDER_PREFIX[ 'transitionDelay' ] && !( X_UA[ 'iOS' ] < 6 ) && !X_UA[ 'Opera' ] && !X_UA[ 'Blink' ], // && !( X_UA[ 'Webkit' ] <= 528.16 ), X_Node_Anime_transitionProps = X_Node_Anime_hasTransform ? X_Node_CSS_VENDER_PREFIX[ 'transform' ] : 'left,top', // transitionEnd イベント中に要素の更新( X_Node_startUpdate() )ができるか? // iOS3+4 では可能、iOS6.1.5 で不可。TODO iOS5 及び他の環境で調査。ダメな場合、anime.html が正しく描画されない。 - X_Node_updateOnTransitionEnd = false; //X_UA[ 'iOS' ] < 6; + X_Node_updateOnTransitionEnd = false; // gpu化だけ transformX , willChange // 終了位置の変更 @@ -101,7 +104,14 @@ var X_Node_ANIMATIONS = [], */ function X_Node_animate( start, dest, duration, easing, wait ){ var isNew = !this[ '_anime' ], - obj = this[ '_anime' ] || ( this[ '_anime' ] = {} ); + obj = this[ '_anime' ]; + + if( !obj ){ + this[ '_anime' ] = obj = X_Node_Anime_getComputedPosition( this ); + obj.destX = obj.x; + obj.destY = obj.y; + obj.destA = obj.a; + }; obj.duration = 0 <= duration && X_Type_isFinite( duration ) ? duration : 500; obj.easing = ease[ easing ] || ease[ 'circular' ]; @@ -344,7 +354,7 @@ function X_Node_Anime_updateAnimation( xnode ){ case 3 : // TransitionEnd -> アニメーションの解除 obj.phase = obj.gpuParent ? 10 : 4; - console.log( '#### アニメーションの解除 ' + obj.phase ); + //console.log( '#### アニメーションの解除 ' + obj.phase ); // このタイミングで animation 関連の css を削除したところ(X_Node_Anime_clearTransition)、iOS3、4 で再描画忘れが度々起きるように、、、 if( !obj.gpuParent ) X_Node_Anime_clearTransition( xnode ); @@ -358,7 +368,7 @@ function X_Node_Anime_updateAnimation( xnode ){ case 10 : // アニメーションは停止・GPUレイヤーは解除していない(再アニメーションに備えて待機) if( !obj.gpuTimerID ){ - console.log( '#### アニメーションは停止 ' + obj.wait ); + //console.log( '#### アニメーションは停止 ' + obj.wait ); if( obj.wait ){ obj.gpuTimerID = X_Timer_once( obj.wait, xnode, X_Node_Anime_releaseGPULayer ); } else { @@ -419,20 +429,32 @@ function X_Node_Anime_updateAnimation( xnode ){ }; }; -function X_Node_Anime_getComputedPosition( that ) { - var matrix = X_Node_CSS_getComputedStyle( that[ '_rawObject' ], null ), - x, y; +function X_Node_Anime_getComputedPosition( that ){ + var raw = that[ '_rawObject' ], + x = 0, y = 0, a = 1, matrix; - if ( X_Node_Anime_hasTransform ) { - matrix = matrix[ X_Node_CSS_VENDER_PREFIX[ 'transform' ] ].split( ')' )[ 0 ].split( ', ' ); - x = + ( matrix[ 12 ] || matrix[ 4 ] ); - y = + ( matrix[ 13 ] || matrix[ 5 ] ); - } else { - x = + parseFloat( matrix.left ); - y = + parseFloat( matrix.top ); + if( raw ){ + if( X_Node_Anime_hasTransform ){ + matrix = X_Node_CSS_getComputedStyle( raw, null ); + matrix = matrix[ X_Node_CSS_VENDER_PREFIX[ 'transform' ] ].split( ')' )[ 0 ].split( ', ' ); + x = + ( matrix[ 12 ] || matrix[ 4 ] ); + y = + ( matrix[ 13 ] || matrix[ 5 ] ); + a = matrix[ X_Node_CSS_Support[ 'opacity' ] ]; + } else + if( X_Node_CSS_getComputedStyle ){ + matrix = X_Node_CSS_getComputedStyle( raw, null ); + x = parseFloat( matrix[ 'left' ] ); + y = parseFloat( matrix[ 'top' ] ); + a = matrix[ X_Node_CSS_Support[ 'opacity' ] ]; + } else + if( matrix = raw.currentStyle || raw.style ){ + x = parseFloat( matrix[ 'left' ] ); + y = parseFloat( matrix[ 'top' ] ); + a = matrix[ 'opacity' ]; + }; }; - - return { x : x, y : y, a : matrix[ X_Node_CSS_Support[ 'opacity' ] ] }; + + return { x : x, y : y, a : a }; }; function X_Node_Anime_onTransitionEnd( e ){ @@ -471,7 +493,7 @@ function X_Node_Anime_releaseGPULayer(){ X_Node_ANIMATIONS.splice( X_Node_ANIMATIONS.indexOf( this ), 1 ); delete obj.gpuTimerID; delete this[ '_anime' ]; - console.log( 'GPUレイヤーの破棄を指示' ); + //console.log( 'GPUレイヤーの破棄を指示' ); X_ViewPort[ 'listenOnce' ]( X_EVENT_AFTER_UPDATE, this, X_Node_Anime_gpuReleased ); }; @@ -547,7 +569,7 @@ function X_Node_Anime_updateAnimationsNoTransition( e ){ delete xnode[ '_anime' ]; X_Node_ANIMATIONS.splice( i, 1 ); - console.log( obj.destA ); + //console.log( obj.destA ); // filter な 親が解除されないと子要素への filter が反映されない xnode[ 'asyncDispatch' ]( { type : X_EVENT_ANIME_END, 'gpu' : false } ); } else { diff --git a/0.6.x/js/02_dom/20_XNode.js b/0.6.x/js/02_dom/20_XNode.js index ca28821..d0a2185 100644 --- a/0.6.x/js/02_dom/20_XNode.js +++ b/0.6.x/js/02_dom/20_XNode.js @@ -151,6 +151,7 @@ var Node = X[ 'Node' ] = X_EventDispatcher[ 'inherits' ]( * TODO Node の継承ができない! */ 'Constructor' : function( v ){ + // TODO uid = X_Node_CHASHE.indexOf( null ), uid === -1 ? X_Node_CHASHE.length : uid; var uid = X_Node_CHASHE.length, css, xnodes, xnode, parent; @@ -382,7 +383,7 @@ function X_Node_getXNode( v ){ case X_NodeType_RAW_TEXT : if( v[ 'UID' ] ) return X_Node_CHASHE[ v[ 'UID' ] ]; for( chashe = X_Node_CHASHE, i = chashe.length; i; ){ - if( ( xnode = X_Node_CHASHE[ --i ] ) && ( xnode[ '_rawObject' ] === v ) ) return xnode; + if( ( xnode = chashe[ --i ] ) && ( xnode[ '_rawObject' ] === v ) ) return xnode; }; }; }; @@ -393,11 +394,10 @@ function X_Node_getRoot( xnode ){ }; - +// TODO document.all[ uid ] -> document[ uid ] var X_Node__ie4getRawNode = X_UA_DOM.IE4 && function ( that ){ return that[ '_rawObject' ] || - ( that[ '_rawObject' ] = document.all[ 'ie4uid' + that[ '_uid' ] ] ) || - ( that[ '_id' ] && ( that[ '_rawObject' ] = document.all[ that[ '_id' ] ] ) ); + ( that[ '_rawObject' ] = document.all[ 'ie4uid' + that[ '_uid' ] ] || that[ '_id' ] && document.all[ that[ '_id' ] ] ); }; @@ -1423,7 +1423,7 @@ var X_Node__commitUpdate = // 1. GPU 一切の更新をスキップ if( that[ '_flags' ] & X_NodeFlags_GPU_NOW ){ - console.log( '更新のskip ' + !!( that[ '_flags' ] & X_Node_BitMask_IS_DIRTY ) ); + //console.log( '更新のskip ' + !!( that[ '_flags' ] & X_Node_BitMask_IS_DIRTY ) ); that[ '_flags' ] & X_Node_BitMask_IS_DIRTY && X_Node__updateRawNode( that, elm ); return elm; }; diff --git a/0.6.x/js/06_net/03_XNetForm.js b/0.6.x/js/06_net/03_XNetForm.js index dd2ab0e..244e5d3 100644 --- a/0.6.x/js/06_net/03_XNetForm.js +++ b/0.6.x/js/06_net/03_XNetForm.js @@ -34,19 +34,20 @@ X_TEMP.X_FormSender_params = { target = option[ 'target' ], html, k; - target = target === '_self' ? '_parent' : target === '_blank' ? '_self' : target, + target = target === '_self' ? '_parent' : target === '_blank' ? '_self' : target || '_self', html = [ '
' ]; - if( target === '_top' || target === '_parent' ) this.isJump = true; - if( 0 <= option[ 'timeout' ] ) this.timeout = option[ 'timeout' ]; + if( target === '_top' || target === '_parent' ) X_FormSender.isJump = true; + if( 0 <= option[ 'timeout' ] ) X_FormSender.timeout = option[ 'timeout' ]; for( k in params ){ // TODO 使用すべきでない name html.push( '' ); + // TODO 改行を含む text には textarea }; html.push( '
' ); @@ -77,12 +78,12 @@ function X_FormSender_iframeListener( e ){ switch( e.type ){ case 'ninjaload' : - if( this.isJump ){ + if( X_FormSender.isJump ){ return; }; if( ++X_FormSender_onloadCount === 1 ){ - X_FormSender_errorTimerID = X_FormSender[ 'asyncDispatch' ]( this.timeout, X_EVENT_ERROR ); + X_FormSender_errorTimerID = X_FormSender[ 'asyncDispatch' ]( X_FormSender.timeout, { type : X_EVENT_ERROR, 'timeout' : true } ); // TODO レスポンスの html にアクセスしたい場合 // TODO samedomain or xiframe-sender diff --git a/0.6.x/js/07_audio/01_XWebAudio.js b/0.6.x/js/07_audio/01_XWebAudio.js index 7361e99..fb43240 100644 --- a/0.6.x/js/07_audio/01_XWebAudio.js +++ b/0.6.x/js/07_audio/01_XWebAudio.js @@ -82,7 +82,7 @@ var X_WebAudio_context = // 4s 以下ではない iPad 2G または iPad mi !X_UA[ 'iPhone_4s' ] && !X_UA[ 'iPad_2Mini1' ] && !X_UA[ 'iPod_4' ] && // Android2 + Gecko で WebAudio が極めて不安定 !( X_UA[ 'Fennec' ] && X_UA[ 'Android' ] < 3 ) && - // AOSP でも WebAudio を不完全に実装するものがある + // AOSP でも WebAudio を不完全に実装するものがある, touch の有無も不明のため一律に切ってしまう !X_UA[ 'AOSP' ] && !( X_UA[ 'ChromeWV' ] < 5 ) && // Blink HTMLAudio 調査用 //!X_UA[ 'Blink' ] && diff --git a/0.6.x/js/20_ui/01_XUI_LayoutBase.js b/0.6.x/js/20_ui/01_XUI_LayoutBase.js index 3e537f4..01ac91c 100644 --- a/0.6.x/js/20_ui/01_XUI_LayoutBase.js +++ b/0.6.x/js/20_ui/01_XUI_LayoutBase.js @@ -34,5 +34,5 @@ X[ 'UI' ][ 'Layout' ] = { }; function XUI_createLayout( props ){ - return X_Class_override( new XUI_LayoutBase, props, true ); + return X_Class_override( XUI_LayoutBase(), props, true ); } diff --git a/0.6.x/js/20_ui/02_XUI_Attr.js b/0.6.x/js/20_ui/02_XUI_Attr.js index b33ea9d..4a43d65 100644 --- a/0.6.x/js/20_ui/02_XUI_Attr.js +++ b/0.6.x/js/20_ui/02_XUI_Attr.js @@ -152,7 +152,7 @@ function XUI_createChecker( str ){ // 属性定義の上書き for( p in defs ){ - if( X_EMPTY_OBJECT[ p ] ) continue; + //if( X_EMPTY_OBJECT[ p ] ) continue; if( p === '_last' ) continue; if( !X_Type_isArray( def = defs[ p ] ) ) continue; F[ p ] = def; diff --git a/0.6.x/js/20_ui/04_XUI_Event.js b/0.6.x/js/20_ui/04_XUI_Event.js index bea9f04..afd289f 100644 --- a/0.6.x/js/20_ui/04_XUI_Event.js +++ b/0.6.x/js/20_ui/04_XUI_Event.js @@ -11,8 +11,8 @@ var XUI_Event = X[ 'UI' ][ 'Event' ] = { // http://d.hatena.ne.jp/edvakf/20100205/1265338487 // http://d.hatena.ne.jp/uupaa/20100401/1270097629 - ENTER_VIEW : ++X_Event_last, // 要素が視界に入った - OUT_VIEW : ++X_Event_last, + VIEW_IN : ++X_Event_last, // 要素が視界に入った + VIEW_OUT : ++X_Event_last, POINTER_OUT : ++X_Event_last, POINTER_IN : ++X_Event_last, @@ -32,8 +32,8 @@ var XUI_Event = X[ 'UI' ][ 'Event' ] = { // raw pointing device event _POINTER_DOWN : ++X_Event_last, + _POINTER_MOVE : ++X_Event_last, _POINTER_UP : ++X_Event_last, - _POINTER_MOVE : ++X_Event_last, _POINTER_CANCEL : ++X_Event_last, FILE_DRAG : ++X_Event_last, @@ -130,8 +130,8 @@ var XUI_Event = X[ 'UI' ][ 'Event' ] = { ( function( IdToName, NameToID, p ){ for( p in IdToName ){ - if( X_EMPTY_OBJECT[ p ] ) continue; - NameToID[ IdToName[ p ] ] = p; + // if( X_EMPTY_OBJECT[ p ] ) continue; + NameToID[ IdToName[ p ] ] = parseFloat( p ); }; })( XUI_Event.IdToName, XUI_Event.NameToID ); diff --git a/0.6.x/js/20_ui/05_XUI_Gesture.js b/0.6.x/js/20_ui/05_XUI_Gesture.js index ed6bfec..3aab9e1 100644 --- a/0.6.x/js/20_ui/05_XUI_Gesture.js +++ b/0.6.x/js/20_ui/05_XUI_Gesture.js @@ -1,387 +1,14 @@ -/* original: - * Hammer.JS - v1.0.5 - 2013-04-07 - * http://eightmedia.github.com/hammer.js - * Jorik Tangelder , MIT license - **/ - - - var ELEENT_LIST = [], - HAMMER_LIST = [], - POINTERS = [], - ABS = new Function( 'v', 'return v<0?-v:v' ); - - function Hammer( uinodeRoot, uinode, type ){ - this.uinode = uinode; - this.enabled = true; - - Hammer.startup && Hammer.startup( uinodeRoot ); - - this.options = Hammer.defaults; - - // start detection on touchstart - Utils.addEvents( uinode, Hammer.EVENT_TYPES_START, this ); - - this[ 'listen' ]( type ); - }; - - Hammer.defaults = {}; - - Hammer.prototype.handleEvent = function( e ){ - //var sourceEventType = e.type.toLowerCase(); - - var type = IdToGestureID[ e.type ], - gestures = Detection.gestures, - numTouches = 0,// count the total touches on the screen - pointerType, i, l, touches, ret, active, gesture, startEv, - hammer, deltaTime, deltaX, deltaY, velocity, center; - - //console.log( 'Hammer@handleEvent ' + XUI_Event.IdToName[ e.type ] + ' ' + e.pointerType + ' ' + type ); - if( !type ) return; - - //console.log( e.type + ' dw:' + XUI_Event._POINTER_DOWN + ' up:' + XUI_Event._POINTER_UP + ' mv:' + XUI_Event._POINTER_MOVE ); - - if( e.pointerType ){ - type |= POINTER; - switch( e.pointerType ){ - case 'touch' : - type |= TOUCH; break; - case 'pen' : - type |= PEN; break; - case 'mouse' : - type |= MOUSE; break; - default : - return; - }; - }; - - // onmouseup, but when touchend has been fired we do nothing. - // this is for touchdevices which also fire a mouseup on touchend - if( type & MOUSE && touch_triggered ){ - return X_CALLBACK_STOP_NOW | X_CALLBACK_PREVENT_DEFAULT; - } else - // mousebutton must be down or a touch event - if( type & TOUCH || //sourceEventType.match(/touch/) || // touch events are always on screen - ( type & POINTER && type & START ) || //sourceEventType.match(/pointerdown/) || // pointerevents touch - ( type & MOUSE && e.button === 0 ) //(sourceEventType.match(/mouse/) && e.which === 1) // mouse is pressed - ){ - enable_detect = true; - }; - - //console.log( 'Hammer@handleEvent ' + IdToGestureID[ e.type ] + ' ' + e.type + ' ' + XUI_Event._POINTER_DOWN + ' ' + enable_detect ); - - // we are in a touch event, set the touch triggered bool to true, - // this for the conflicts that may occur on ios and android - //type & ( TOUCH | POINTER ) && ( touch_triggered = true ); - type & TOUCH && ( touch_triggered = true ); - //if (sourceEventType.match(/touch|pointer/)) { touch_triggered = true;} - - // when touch has been triggered in this detection session - // and we are now handling a mouse event, we stop that to prevent conflicts - if( enable_detect ){ - // update pointerevent - - POINTERS[ e.pointerId ] = type & END ? null : e; - touches = []; - numTouches = -1; - // we can use forEach since pointerEvents only is in IE10 - for( i in POINTERS ){ - POINTERS[ i ] && ( touches[ ++numTouches ] = POINTERS[ i ] ); - }; - ++numTouches; - ///console.log( 'numTouches ' + numTouches ); - - // if we are in a end event, but when we remove one touch and - // we still have enough, set eventType to move - if( 0 < numTouches && type & END ){ // eventType === Hammer.EVENT_END ){ - type = type & POINTER_TYPE_MASK | MOVE; - //eventType = Hammer.EVENT_MOVE; - } else if( !numTouches ){ - // no touches, force the end event - type = type & POINTER_TYPE_MASK | END; - //eventType = Hammer.EVENT_END; - }; - - // because touchend has no touches, and we often want to use these in our gestures, - // we send the last move event as our eventData in touchend - ( !numTouches && last_move_event !== null ) ? - ( e = last_move_event ): - ( last_move_event = e ); // store the last move event - - e = { - center : Utils.getCenter( touches ), - timeStamp : e.timeStamp, - target : e.target, - touches : touches, - eventType : type & EVENT_TYPE_MASK, - pointerType : type & POINTER_TYPE_MASK - }; - - if( type & START ){ - if( !this.enabled ) return; - // already busy with a Hammer.gesture detection on an element - if( Detection.current ) return; - Detection.current = { - hammer : this, // reference to HammerInstance we're working for - startEvent : Utils.extend( {}, e ), // start eventData for distances, timing etc - lastEvent : false, // last eventData - name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc - }; - Detection.stopped = false; - hammer = this; - active = hammer.activeGesture; - } else - if( !Detection.current || Detection.stopped ){ - return; - } else { - hammer = Detection.current.hammer; - active = hammer.activeGesture; - }; - - // ---------------------------------------------------------------------------------------------------------------- - // ret = Detection.detect( e ); - - // ---------------------------------------------------------------------------------------------------------------- - // extend event data with calculations about scale, distance etc - // e = Detection.extendEventData( e ); - startEv = Detection.current.startEvent; - center = e.center; - - // if the touches change, set the new touches over the startEvent touches - // this because touchevents don't have all the touches on touchstart, or the - // user must place his fingers at the EXACT same time on the screen, which is not realistic - // but, sometimes it happens that both fingers are touching at the EXACT same time - if( startEv && ( numTouches !== startEv.touches.length || touches === startEv.touches ) ){ - // extend 1 level deep to get the touchlist with the touch objects - startEv.touches.length = i = 0; - for( ; i < numTouches; ++i ){ - startEv.touches[ startEv.touches.length ] = Utils.extend( {}, touches[ i ] ); - }; - }; - - deltaTime = e.timeStamp - startEv.timeStamp; - deltaX = center.pageX - startEv.center.pageX; - deltaY = center.pageY - startEv.center.pageY; - velocity = Utils.getVelocity( deltaTime, deltaX, deltaY ); - - Utils.extend( e, { - deltaTime : deltaTime, - - deltaX : deltaX, - deltaY : deltaY, - - velocityX : velocity.x, - velocityY : velocity.y, - - distance : Utils.getDistance( startEv.center, center ), - angle : Utils.getAngle( startEv.center, center ), - direction : Utils.getDirection( startEv.center, center ), - - scale : Utils.getScale( startEv.touches, touches ), - rotation : Utils.getRotation( startEv.touches, touches ), - - startEvent : startEv - }); - - // store as previous event event - Detection.current.lastEvent = e; - - // call Hammer.gesture handlers - for( i = 0, l = gestures.length; i < l; ++i ){ - gesture = gestures[ i ]; - if( Detection.stopped ) break; - //if( active[ gesture.name ] ) console.log( gesture.name ); - // only when the instance options have enabled this gesture - active[ gesture.name ] && - // if a handler returns false, we stop with the detection - ( ret |= ( gesture.handler( e, hammer ) || X_CALLBACK_NONE ) ); - }; - - // endevent, but not the last touch, so dont stop - type & END && numTouches === 0 && Detection.stopDetect(); - - // ---------------------------------------------------------------------------------------------------------------- - // trigger the handler - //handler.call( context, HamEvent.collectEventData( element, eventType, e ) ); - - // remove pointerevent from list - if( Hammer.HAS_POINTEREVENTS && type & END ){ // eventType === Hammer.EVENT_END ){ - numTouches = 0; - }; - }; - - //debug(sourceEventType +" "+ eventType); - - // on the end we reset everything - if( numTouches === 0 ){ - last_move_event = null; - enable_detect = false; - touch_triggered = false; - POINTERS.length = 0; - }; - - return ret; - }; - - Hammer.startup = function( uinodeRoot ){ - // find what eventtypes we add listeners to - /** - * we have different events for each device/browser - * determine what we need and set them in the Hammer.EVENT_TYPES constant - */ - // determine the eventtype we want to set - // for non pointer events browsers and mixed browsers, - // like chrome on windows8 touch laptop - var types, name; - - // Register all gestures inside Gestures - for( name in Gestures ){ - //Gestures.hasOwnProperty( name ) && - Detection.register( Gestures[ name ] ); - }; - - Hammer.EVENT_TYPES_START = [ XUI_Event._POINTER_DOWN ]; - types = [ XUI_Event._POINTER_MOVE, XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL ]; - - // Add touch events on the document - Utils.addEvents( uinodeRoot, types, Hammer.prototype.handleEvent ); - - // Hammer is ready...! - delete Hammer.startup; - }; - - Hammer.prototype.trigger = function( type, gesture ){ - if( !this.types[ type ] ) return; - var e = Utils.extend( {}, gesture ); - e.type = type; - return this.uinode[ 'dispatch' ]( e ); - }; - - Hammer.prototype.listen = function( type ){ - var gestures = Detection.gestures, - i = gestures.length, g; - for( ; i; ){ - g = gestures[ --i ]; - if( g.startID <= type && type <= g.endID ){ - if( !this.activeGesture ) this.activeGesture = {}; - if( !this.types ) this.types = {}; - this.activeGesture[ g.name ] = this.types[ type ] = 1; - return; - }; - }; - }; - - Hammer.prototype.unlisten = function( type ){ - var gestures = Detection.gestures, - i = gestures.length, g; - if( !this.activeGesture ) return; - for( ; i; ){ - g = gestures[ --i ]; - if( g.startID <= type && type <= g.endID ){ - if( this.activeGesture[ g.name ] ){ - if( this.types[ type ] ) delete this.types[ type ]; - for( i = g.startID; i <= g.endID; ++i ){ - if( this.types[ i ] ) return; - }; - delete this.activeGesture[ g.name ]; - }; - return; - }; - }; - }; - - /* - * "Android version < 2.2" return ev.touches.length === 1 when touchend, others return ev.touches.length === 0 - */ - Hammer.DO_TOUCHES_FIX = Hammer.HAS_TOUCHEVENTS && ( X_UA[ 'Android' ] < 2.2 || X_UA[ 'Blink' ] || X_UA[ 'Opera' ] ); - - // detect touchevents - Hammer.HAS_POINTEREVENTS = true; // navigator.pointerEnabled || navigator.msPointerEnabled; - Hammer.HAS_POINTEREVENTS && console.log( 'Hammer.HAS_POINTEREVENTS : true' ); - - - // eventtypes per touchevent (start, move, end) - // are filled by HamEvent.determineEventTypes on setup - Hammer.EVENT_TYPES_START = null; - - // direction defines - Hammer.DIRECTION_DOWN = 'down'; - Hammer.DIRECTION_LEFT = 'left'; - Hammer.DIRECTION_UP = 'up'; - Hammer.DIRECTION_RIGHT = 'right'; - - // plugins namespace - Hammer.plugins = {}; - - var POINTER = 1, - TOUCH = 2, - PEN = 8, //4, - MOUSE = 8, - START = 16, - MOVE = 32, - END = 64, - CANCEL = 128, - EVENT_TYPE_MASK = START | MOVE | END, - POINTER_TYPE_MASK = POINTER | TOUCH | MOUSE | PEN, - IdToGestureID = {}; - IdToGestureID[ XUI_Event._POINTER_DOWN ] = START; - IdToGestureID[ XUI_Event._POINTER_MOVE ] = MOVE; - IdToGestureID[ XUI_Event._POINTER_UP ] = END; - IdToGestureID[ XUI_Event._POINTER_CANCEL ] = END; - - var Utils = { - - /** - * touch events with mouse fallback - * @param {HTMLElement} element - * @param {String} eventType like Hammer.EVENT_MOVE - * @param {Function} handler - */ - addEvents : function( uinode, types, context ){ - for( var i = 0; i < types.length; ++i ){ - uinode[ 'listen' ]( types[ i ], context ); - }; - }, - - /** - * extend method, - * also used for cloning when dest is an empty object - * @param {Object} dest - * @param {Object} src - * @parm {Boolean} merge do a merge - * @returns {Object} dest - */ - extend : function extend( dest, src, merge ){ - for( var key in src ){ - if( dest[ key ] !== undefined && merge ) continue; - dest[ key ] = src[ key ]; - }; - return dest; - }, - - /** - * find if a node is in the given parent - * used for event delegation tricks - * @param {HTMLElement} node - * @param {HTMLElement} parent - * @returns {boolean} has_parent - */ - hasParent : function( node, parent ){ - while( node && node.tagName ){ /* tagName for ie */ - if( node === parent ) return true; - node = node.parentNode; - }; - return false; - }, - +var XUI_GestureUtils = { /** * get the center of all the touches * @param {Array} touches * @returns {Object} center */ - getCenter : function getCenter(touches) { + getCenter : function( touches ){ var i = 0, l = touches.length, - valuesX, valuesY; + x, y, minX, minY, maxX, maxY; + switch( l ){ case 0 : return {}; @@ -396,15 +23,19 @@ pageY : ( touches[ 0 ].pageY + touches[ 1 ].pageY ) / 2 }; }; - valuesX = []; - valuesY = []; + minX = minY = 1 / 0; + maxX = maxY = - 1 / 0; for( ; i < l; ++i ){ - valuesX[ valuesX.length ] = touches[ i ].pageX; - valuesY[ valuesY.length ] = touches[ i ].pageY; + x = touches[ i ].pageX; + minX = x < minX ? x : minX; + maxX = maxX < x ? x : maxX; + y = touches[ i ].pageY; + minY = y < minY ? y : minY; + maxY = maxY < y ? y : maxY; }; return { - pageX : ( ( Math.min.apply( null, valuesX ) + Math.max.apply( null, valuesX ) ) / 2 ), - pageY : ( ( Math.min.apply( null, valuesY ) + Math.max.apply( null, valuesY ) ) / 2 ) + pageX : ( minX + maxX ) / 2 | 0, + pageY : ( minY + maxY ) / 2 | 0 }; }, @@ -415,10 +46,10 @@ * @param {Number} deltaY * @returns {Object} velocity */ - getVelocity : function getVelocity( deltaTime, deltaX, deltaY ) { + getVelocity : function( deltaTime, deltaX, deltaY ) { return { - x : ABS( deltaX / deltaTime ) || 0, - y : ABS( deltaY / deltaTime ) || 0 + x : Math.abs( deltaX / deltaTime ) || 0, + y : Math.abs( deltaY / deltaTime ) || 0 }; }, @@ -428,7 +59,7 @@ * @param {Touch} touch2 * @returns {Number} angle */ - getAngle : function getAngle(touch1, touch2) { + getAngle : function( touch1, touch2 ){ var y = touch2.pageY - touch1.pageY, x = touch2.pageX - touch1.pageX; return Math.atan2( y, x ) * 180 / Math.PI; @@ -438,14 +69,14 @@ * angle to direction define * @param {Touch} touch1 * @param {Touch} touch2 - * @returns {String} direction constant, like Hammer.DIRECTION_LEFT + * @returns {String} direction constant, like 'left' */ - getDirection : function getDirection( touch1, touch2 ){ + getDirection : function( touch1, touch2 ){ var x = touch1.pageX - touch2.pageX, y = touch1.pageY - touch2.pageY; - return ABS( y ) <= ABS( x ) ? - ( x > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT ) : - ( y > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN ); + return Math.abs( y ) <= Math.abs( x ) ? + ( x > 0 ? 'left' : 'right' ) : + ( y > 0 ? 'up' : 'down' ); }, /** @@ -454,7 +85,7 @@ * @param {Touch} touch2 * @returns {Number} distance */ - getDistance : function getDistance( touch1, touch2 ){ + getDistance : function( touch1, touch2 ){ var x = touch2.pageX - touch1.pageX, y = touch2.pageY - touch1.pageY; return Math.sqrt( ( x * x ) + ( y * y ) ); @@ -467,10 +98,10 @@ * @param {Array} end * @returns {Number} scale */ - getScale : function getScale( start, end ){ + getScale : function( start, end ){ // need two fingers... return ( 2 <= start.length && 2 <= end.length ) ? - Utils.getDistance( end[ 0 ], end[ 1 ] ) / Utils.getDistance( start[ 0 ], start[ 1 ] ) : + XUI_GestureUtils.getDistance( end[ 0 ], end[ 1 ] ) / XUI_GestureUtils.getDistance( start[ 0 ], start[ 1 ] ) : 1; }, @@ -483,7 +114,7 @@ getRotation : function getRotation( start, end ){ // need two fingers return ( 2 <= start.length && 2 <= end.length ) ? - Utils.getAngle( end[ 1 ], end[ 0 ] ) - Utils.getAngle( start[ 1 ], start[ 0 ] ) : + XUI_GestureUtils.getAngle( end[ 1 ], end[ 0 ] ) - XUI_GestureUtils.getAngle( start[ 1 ], start[ 0 ] ) : 0; }, @@ -493,349 +124,393 @@ * @returns {Boolean} is_vertical */ isVertical : function isVertical( direction ){ - return direction === Hammer.DIRECTION_UP || direction === Hammer.DIRECTION_DOWN; + return direction === 'up' || direction === 'down'; } }; - - /* - * this holds the last move event, - * used to fix empty touchend issue - * see the onTouch event for an explanation - * @type {Object} - */ - var last_move_event = null; - /* - * when the mouse is hold down, this is true - * @type {Boolean} - */ - var enable_detect = false; +var XUI_Gesture_POINTERS = {}, + XUI_Gesture_CAPTURED = {}, + XUI_Gesture_DEFAULTS = {}; - /* - * when touch events have been fired, this is true - * @type {Boolean} - */ - var touch_triggered = false; - - var Detection = { - // contains all registred Gestures in the correct order - gestures : [], +// AbstractUINode に移動 - // data of the current Hammer.gesture detection session - current : null, +var XUI_Gesture = Hammer = X_Class_create( + 'X.UI.Gesture', + X_Class.NONE, + { + uinodeRoot : null, + uinode : null, + options : null, + + activated : null, + types : null, - // the previous Hammer.gesture session data - // is a full clone of the previous gesture.current object - previous : null, + triggered : null, + canceled : null, + + currentName : '', + startEvent : null, + lastEvent : null, + lastMoveEvent : null, + + 'Constructor' : function( uinodeRoot, uinode, type, opt_options ){ + this.uinodeRoot = uinodeRoot; + this.uinode = uinode; + this.options = X_Object_override( X_Object_copy( XUI_Gesture_DEFAULTS ), opt_options ); + + this.triggered = {}; + this.canceled = {}; - // when this becomes true, no gestures are fired - stopped : false, + uinode[ 'listen' ]( XUI_Event._POINTER_DOWN, this, XUI_Gesture_handleEvent ); + + this[ 'listen' ]( type ); + }, + + trigger : function( type, gesture ){ + var e; + + if( !this.types[ type ] ) return X_CALLBACK_NONE; + e = X_Object_copy( gesture ); + e.type = type; + return this.uinode[ 'dispatch' ]( e ) || X_CALLBACK_NONE; + }, + + listen : function( type ){ + var gestures = XUI_Gesture_LIST, + i = gestures.length, g; + + for( ; i; ){ + g = gestures[ --i ]; + if( g.startID <= type && type <= g.endID ){ + if( !this.activated ) this.activated = {}; + if( !this.types ) this.types = {}; + this.activated[ g.name ] = this.types[ type ] = 1; + break; + }; + }; + }, + + unlisten : function( type ){ + var gestures = XUI_Gesture_LIST, + i = gestures.length, + active = this.activated, g; + + if( !active ) return; + for( ; i; ){ + g = gestures[ --i ]; + if( g.startID <= type && type <= g.endID ){ + if( active[ g.name ] ){ + if( this.types[ type ] ) delete this.types[ type ]; + for( i = g.startID; i <= g.endID; ++i ){ + if( this.types[ i ] ) return; + }; + delete active[ g.name ]; + }; + break; + }; + }; + } + } +); + +function XUI_Gesture_handleEvent( e ){ + var gestures = XUI_Gesture_LIST, + type = e.type, + uid = e[ 'pointerId' ], + isStart = type === XUI_Event._POINTER_DOWN, + isEnd = type === XUI_Event._POINTER_UP || type === XUI_Event._POINTER_CANCEL || type === XUI_Event.POINTER_OUT, + hammer = this, + isMouse = e.pointerType === 'mouse', + touches = [], + numTouches = 0,// count the total touches on the screen + i, p, l, j, captured, ret, activated, gesture, startEv, + deltaTime, deltaX, deltaY, velocity, center, startCenter; - /** - * clear the Hammer.gesture vars - * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected - * to stop other Gestures from being fired - */ - stopDetect : function stopDetect() { - // clone current data to the store as the previous gesture - // used for the double tap gesture, since this is an other gesture detect session - Detection.previous = Utils.extend( {}, Detection.current ); + if( !isStart && !hammer.startEvent ) return; - // reset the current - Detection.current = null; +if( type === XUI_Event.POINTER_OUT ) console.log( 'canceled ...' + e.button ) - // stopped! - Detection.stopped = true; - }, + if( isEnd ){ + if( XUI_Gesture_POINTERS[ uid ] ){ + delete XUI_Gesture_POINTERS[ uid ]; + if( XUI_Gesture_CAPTURED[ uid ] ) delete XUI_Gesture_CAPTURED[ uid ]; + }; + } else { + XUI_Gesture_POINTERS[ uid ] = e; + }; - /** - * register new gesture - * @param {Object} gesture object, see gestures.js for documentation - * @returns {Array} gestures - */ - register : function( gesture ){ - // add an enable gesture options if there is no given - var options = gesture.defaults || {}, - list = Detection.gestures, - _index, i = 0, l = list.length, index; - if( options[ gesture.name ] === undefined ) options[ gesture.name ] = true; - - // extend Hammer default options with the Hammer.gesture options - Utils.extend( Hammer.defaults, options, true ); - - // set its index - gesture.index = gesture.index || 1000; - - // add Hammer.gesture to the list - //Detection.gestures.push( gesture ); - - // sort the list by index - //Detection.gestures.sort( function( a, b ){ - // return - // a.index < b.index ? -1 : - // a.index > b.index ? 1 : 0; - //}); - if( l === 0 ){ - list[ 0 ] = gesture; - return; + // mousebutton must be down or a touch event + if( ( isEnd || !isMouse || e.button === 0 ) ){ + numTouches = -1; + + for( i in XUI_Gesture_POINTERS ){ + if( p = XUI_Gesture_POINTERS[ i ] ){ + // いずれかの hammer によって束縛されている場合、その束縛している hammer なら + captured = XUI_Gesture_CAPTURED[ p[ 'pointerId' ] ]; + if( captured && captured !== hammer ){ + continue; + }; + touches[ ++numTouches ] = p; + }; }; - _index = gesture.index; - for( i = 0; i < l; ++i ){ - index = list[ i ].index; - if( i === 0 && _index < index ){ - list.unshift( gesture ); - return; - } else - if( i === l - 1 ){ - list[ l ] = gesture; - return; - } else - if( index <= _index && _index < list[ i + 1 ].index ){ - list.splice( i, 0, gesture ); - return; + ++numTouches; + + // if we are in a end event, but when we remove one touch and + // we still have enough, set eventType to move + if( !numTouches ){ // no touches, force the end event + isEnd = true; + }; + + // because touchend has no touches, and we often want to use these in our gestures, + // we send the last move event as our eventData in touchend + ( isEnd && hammer.lastMoveEvent ) ? ( e = hammer.lastMoveEvent ) : ( hammer.lastMoveEvent = e ); // store the last move event + + hammerEvent = X_Object_copy( e ); + hammerEvent.touches = touches; + + if( isStart && !hammer.startEvent ){ + console.log( '=- add -=' ); + // already busy with a Hammer.gesture detection on an element + hammer.startEvent = hammerEvent; + hammer.uinodeRoot[ 'listen' ]( [ XUI_Event._POINTER_MOVE, XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL, XUI_Event.POINTER_OUT ], hammer, XUI_Gesture_handleEvent ); + }; + + startEv = hammer.startEvent; + + + // if the touches change, set the new touches over the startEvent touches + // this because touchevents don't have all the touches on touchstart, or the + // user must place his fingers at the EXACT same time on the screen, which is not realistic + // but, sometimes it happens that both fingers are touching at the EXACT same time + if( startEv && ( numTouches !== startEv.touches.length || touches !== startEv.touches ) ){ + // extend 1 level deep to get the touchlist with the touch objects + startEv.touches.length = i = 0; + j = -1; + for( ; i < numTouches; ++i ){ + startEv.touches[ ++j ] = touches[ i ]; }; }; - } - }; - var Gestures = Gestures || {}; + deltaTime = hammerEvent.timestamp - startEv.timestamp; + center = XUI_GestureUtils.getCenter( touches ); + startCenter = startEv.center; + deltaX = startCenter ? ( center.pageX - startCenter.pageX ) : 0; + deltaY = startCenter ? ( center.pageY - startCenter.pageY ) : 0; + velocity = XUI_GestureUtils.getVelocity( deltaTime, deltaX, deltaY ); - /** - * Custom gestures - * ============================== - * - * Gesture object - * -------------------- - * The object structure of a gesture: - * - * { name: 'mygesture', - * index: 1337, - * defaults: { - * mygesture_option: true - * } - * handler: function(type, e, inst) { - * // trigger gesture event - * inst.trigger(this.name, e ); - * } - * } - - * @param {String} name - * this should be the name of the gesture, lowercase - * it is also being used to disable/enable the gesture per instance config. - * - * @param {Number} [index=1000] - * the index of the gesture, where it is going to be in the stack of gestures detection - * like when you build an gesture that depends on the drag gesture, it is a good - * idea to place it after the index of the drag gesture. - * - * @param {Object} [defaults={}] - * the default settings of the gesture. these are added to the instance settings, - * and can be overruled per instance. you can also add the name of the gesture, - * but this is also added by default (and set to true). - * - * @param {Function} handler - * this handles the gesture detection of your custom gesture and receives the - * following arguments: - * - * @param {Object} eventData - * event data containing the following properties: - * timeStamp {Number} time the event occurred - * target {HTMLElement} target element - * touches {Array} touches (fingers, pointers, mouse) on the screen - * pointerType {String} kind of pointer that was used. matches Hammer.POINTER_MOUSE|TOUCH - * center {Object} center position of the touches. contains pageX and pageY - * deltaTime {Number} the total time of the touches in the screen - * deltaX {Number} the delta on x axis we haved moved - * deltaY {Number} the delta on y axis we haved moved - * velocityX {Number} the velocity on the x - * velocityY {Number} the velocity on y - * angle {Number} the angle we are moving - * direction {String} the direction we are moving. matches Hammer.DIRECTION_UP|DOWN|LEFT|RIGHT - * distance {Number} the distance we haved moved - * scale {Number} scaling of the touches, needs 2 touches - * rotation {Number} rotation of the touches, needs 2 touches * - * eventType {String} matches Hammer.EVENT_START|MOVE|END - * srcEvent {Object} the source event, like TouchStart or MouseDown * - * startEvent {Object} contains the same properties as above, - * but from the first touch. this is used to calculate - * distances, deltaTime, scaling etc - * - * @param {Hammer.Instance} inst - * the instance we are doing the detection for. you can get the options from - * the inst.options object and trigger the gesture event by calling inst.trigger - * - * - * Handle gestures - * -------------------- - * inside the handler you can get/set Detection.current. This is the current - * detection session. It has the following properties - * @param {String} name - * contains the name of the gesture we have detected. it has not a real function, - * only to check in other gestures if something is detected. - * like in the drag gesture we set it to 'drag' and in the swipe gesture we can - * check if the current gesture is 'drag' by accessing Detection.current.name - * - * @readonly - * @param {Hammer.Instance} inst - * the instance we do the detection for - * - * @readonly - * @param {Object} startEvent - * contains the properties of the first gesture detection in this session. - * Used for calculations about timing, distance, etc. - * - * @readonly - * @param {Object} lastEvent - * contains all the properties of the last gesture detect in this session. - * - * after the gesture detection session has been completed (user has released the screen) - * the Detection.current object is copied into Detection.previous, - * this is usefull for gestures like doubletap, where you need to know if the - * previous gesture was a tap - * - * options that have been set by the instance can be received by calling inst.options - * - * You can trigger a gesture event by calling inst.trigger("mygesture", event). - * The first param is the name of your gesture, the second the event argument - * - * - * Register gestures - * -------------------- - * When an gesture is added to the Gestures object, it is auto registered - * at the setup of the first Hammer instance. You can also call Detection.register - * manually and pass your gesture object as a param - * - */ + X_Object_override( hammerEvent, { + type : isEnd ? XUI_Event._POINTER_UP : type, + + deltaTime : deltaTime, - /** - * Hold - * Touch stays at the same place for x time - * @events hold holdend - */ - Gestures.Hold = { - name : 'hold', - index : 10, - startID : XUI_Event.HOLD, - endID : XUI_Event.HOLD_END, - defaults : { - hold_timeout : 500, - hold_threshold : 1 - }, - timerID : null, - holding : false, - handler : function holdGesture( e, hammer ){ - switch( e.eventType ){ - case START : - // clear any running timers - this.timerID && X_Timer_remove( this.timerID ); - - // set the gesture so we can check in the timeout if it still is - Detection.current.name = this.name; - Gestures.Hold.holding = false; - - // set timer and if after the timeout it still is hold, - // we trigger the hold event - this.timerID = X_Timer_add( hammer.options.hold_timeout, 1, Gestures.Hold._onTimer, [ e, hammer ] ); - return; - - // when you move or end we clear the timer - case MOVE : - if( e.distance <= hammer.options.hold_threshold ) return; - case END : - this.timerID && X_Timer_remove( this.timerID ); - if( Gestures.Hold.holding === true ){ - Gestures.Hold.holding = false; - return hammer.trigger( XUI_Event.HOLD_END, e ); + deltaX : deltaX, + deltaY : deltaY, + + velocityX : velocity.x, + velocityY : velocity.y, + + center : center, + distance : startCenter ? XUI_GestureUtils.getDistance( startCenter, center ) : 0, + angle : startCenter ? XUI_GestureUtils.getAngle( startCenter, center ) : 0, + direction : startCenter ? XUI_GestureUtils.getDirection( startCenter, center ) : 0, + + scale : XUI_GestureUtils.getScale( startEv.touches, touches ), + rotation : XUI_GestureUtils.getRotation( startEv.touches, touches ), + + startEvent : startEv + }); + + // store as previous event event + hammer.lastEvent = hammerEvent; + activated = hammer.activated; + + // call Hammer.gesture handlers + for( i = 0, l = gestures.length; i < l; ++i ){ + gesture = gestures[ i ]; + + if( activated[ gesture.name ] && !hammer.canceled[ gesture.name ] ){ + ( console.log( '... ' + i + ' ' + gesture.name ) ); + // if a handler returns false, we stop with the detection + ( ret |= ( gesture.handler( hammerEvent, hammer ) || X_CALLBACK_NONE ) ); + }; + + if( ret & X_CALLBACK_CAPTURE_POINTER ){ + for( i = touches.length; i; ){ + uid = touches[ --i ][ 'pointerId' ]; + XUI_Gesture_CAPTURED[ uid ] = hammer; + //console.log( 'captured. ' + uid ); }; break; + } else + if( ret & X_CALLBACK_STOP_NOW ){ + break; + }; }; - }, - _onTimer : function( e, hammer ){ - if( Detection.current.name === 'hold' ){ - hammer.trigger( XUI_Event.HOLD, e ); - Gestures.Hold.holding = true; + //console.log( '----' ); + } else { + + }; + + if( isEnd || ( ret & X_CALLBACK_RELEASE_POINTER ) ){ + for( i = touches.length; i; ){ + uid = touches[ --i ][ 'pointerId' ]; + if( XUI_Gesture_CAPTURED[ uid ] === hammer ){ + console.log( 'released. ' + uid ); + delete XUI_Gesture_CAPTURED[ uid ]; + }; }; - } - }; + }; + + if( isEnd ){ + console.log( '=- clear -=' ); + hammer.uinodeRoot[ 'unlisten' ]( [ XUI_Event._POINTER_MOVE, XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL, XUI_Event.POINTER_OUT ], hammer, XUI_Gesture_handleEvent ); + + hammer.previous = { + currentName : hammer.currentName, + startEvent : hammer.startEvent, + lastEvent : hammer.lastEvent, + lastMoveEvent : hammer.lastMoveEvent + }; + + X_Object_clear( hammer.triggered ); + X_Object_clear( hammer.canceled ); + + delete hammer.currentName; + delete hammer.startEvent; + delete hammer.lastEvent; + delete hammer.lastMoveEvent; + + ret |= X_CALLBACK_RELEASE_POINTER; + }; + + return ret; +}; + + +var XUI_Gesture_LIST = [ /** - * Tap/DoubleTap - * Quick touch at a place or double at the same place - * @events tap, doubletap + * Touch + * Called as first, tells the user has touched the screen + * @events touch */ - Gestures.Tap = { - name : 'tap', - index : 100, - startID : XUI_Event.TAP, - endID : XUI_Event.DOUBLE_TAP, + { + name : 'touch', + index : -Infinity, defaults : { - tap_max_touchtime : 250, - tap_max_distance : 10, - tap_always : true, - doubletap_distance : 20, - doubletap_interval : 300 - }, - handler : function tapGesture( e, hammer ){ - // previous gesture, for the double tap since these are two different gesture detections - var prev = Detection.previous; - if( e.eventType === END ){ - // when the touchtime is higher then the max touch time - // or when the moving distance is too much - if( hammer.options.tap_max_touchtime < e.deltaTime || hammer.options.tap_max_distance < e.distance ) return; + // call preventDefault at touchstart, and makes the element blocking by + // disabling the scrolling of the page, but it improves gestures like + // transforming and dragging. + // be careful with using this, it can be very annoying for users to be stuck + // on the page + prevent_default : false, - // check if double tap - if( prev && prev.name === 'tap' && ( e.timeStamp - prev.lastEvent.timeStamp ) < hammer.options.doubletap_interval && e.distance < hammer.options.doubletap_distance ){ - return hammer.trigger( XUI_Event.DOUBLE_TAP, e ); - } else - // do a single tap - if( hammer.options.tap_always && Detection.current.name !== 'tap' ){ // EventFire中にalert すると mouseleave で再び呼ばれるのを防ぐ - Detection.current.name = 'tap'; - return hammer.trigger( XUI_Event.TAP, e ); - }; + // disable mouse events, so only touch (or pen!) input triggers events + prevent_mouseevents : false + }, + handler : function( e, hammer ){ + if( hammer.options.prevent_mouseevents && e[ 'pointerType' ] === 'mouse' ){ + return X_CALLBACK_STOP_NOW; }; - } - }; + //hammer.options.prevent_default && e.preventDefault(); + + return e.type === XUI_Event._POINTER_DOWN && hammer.trigger( XUI_Event.TOUCH, e ); + } + }, + /** - * Swipe - * triggers swipe events when the end velocity is above the threshold - * @events swipe, swipeleft, swiperight, swipeup, swipedown + * Transform + * User want to scale or rotate with 2 fingers + * @events transform, transformstart, transformend, pinch, pinchin, pinchout, rotate */ - Gestures.Swipe = { - name : 'swipe', - index : 40, - startID : XUI_Event.SWIP, - endID : XUI_Event.SWIP_DOWN, + { + name : 'transform', + index : 45, + startID : XUI_Event.TRANSFORM, + endID : XUI_Event.ROTATE, defaults : { - // set 0 for unlimited, but this can conflict with transform - swipe_max_touches : 1, - swipe_velocity : 0.7 + // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 + transform_min_scale : 0.01, + // rotation in degrees + transform_min_rotation : 1, + // prevent default browser behavior when two touches are on the screen + // but it makes the element a blocking element + // when you are using the transform gesture, it is a good practice to set this true + transform_always_block : false }, - handler : function swipeGesture(e, hammer) { - if( e.eventType === END ){ - // max touches - if( 0 < hammer.options.swipe_max_touches && hammer.options.swipe_max_touches < e.touches.length ) return; - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if( hammer.options.swipe_velocity < e.velocityX || hammer.options.swipe_velocity < e.velocityY ){ - // trigger swipe events - hammer.trigger( XUI_Event.SWIP, e ); - hammer.trigger( - e.direction === Hammer.DIRECTION_UP ? - XUI_Event.SWIP_UP : - e.direction === Hammer.DIRECTION_DOWN ? - XUI_Event.SWIP_DOWN : - e.direction === Hammer.DIRECTION_LEFT ? - XUI_Event.SWIP_LEFT : - XUI_Event.SWIP_RIGHT, - e - ); - }; + + handler : function( e, hammer ){ + var transform = this, ret = X_CALLBACK_NONE, scale_threshold, rotation_threshold; + + // current gesture isnt drag, but dragged is true + // this means an other gesture is busy. now call dragend + if( hammer.currentName !== transform.name && hammer.triggered[ transform.name ] ){ + ret = hammer.trigger( XUI_Event.TRANSFORM_END, e ); + delete hammer.triggered[ transform.name ]; + return ret; }; - } - }; + // atleast multitouch + if( e.touches.length < 2 ) return; + + // prevent default when two fingers are on the screen + //hammer.options.transform_always_block && e.preventDefault(); + + switch( e.type ){ + case XUI_Event._POINTER_DOWN : + //hammer.triggered[ transform.name ] = false; + break; + + case XUI_Event._POINTER_MOVE: + scale_threshold = Math.abs( 1 - e.scale ); + rotation_threshold = Math.abs( e.rotation ); + + // when the distance we moved is too small we skip this gesture + // or we can be already in dragging + if( scale_threshold < hammer.options.transform_min_scale && rotation_threshold < hammer.options.transform_min_rotation ) return; + + // we are transforming! + hammer.currentName = transform.name; + + // first time, trigger dragstart event + if( !hammer.triggered[ transform.name ] ){ + ret = hammer.trigger( XUI_Event.TRANSFORM_START, e ); + if( ret & X_CALLBACK_PREVENT_DEFAULT ){ + hammer.canceled[ transform.name ] = true; + break; + }; + hammer.triggered[ transform.name ] = true; + break; + }; + + ret |= hammer.trigger( XUI_Event.TRANSFORM, e ); + // basic transform event + + // trigger rotate event + if( hammer.options.transform_min_rotation < rotation_threshold ){ + ret |= hammer.trigger( XUI_Event.ROTATE, e ); + }; + + // trigger pinch event + if( scale_threshold > hammer.options.transform_min_scale ){ + ret |= hammer.trigger( XUI_Event.PINCH, e ); + ret |= hammer.trigger( e.scale < 1 ? XUI_Event.PINCH_IN : XUI_Event.PINCH_OUT, e ); + }; + break; + + case XUI_Event.POINTER_OUT : + case XUI_Event._POINTER_CANCEL : + case XUI_Event._POINTER_UP : + // trigger dragend + ret = hammer.triggered[ transform.name ] && hammer.trigger( XUI_Event.TRANSFORM_END, e ); + hammer.triggered[ transform.name ] = false; + break; + }; + return ret; + } + }, + /** * Drag * Move with x fingers (default 1) around on the page. Blocking the scrolling when @@ -843,11 +518,12 @@ * you disable scrolling on that area. * @events drag, dragstart, dragend, drapleft, dragright, dragup, dragdown */ - Gestures.Drag = { + { name : 'drag', index : 50, startID : XUI_Event.DRAG, endID : XUI_Event.DRAG_DOWN, + defaults : { drag_min_distance : 10, // set 0 for unlimited, but this can conflict with transform @@ -864,202 +540,150 @@ // This way, locking occurs only when the distance has become large enough to reliably determine the direction drag_lock_min_distance : 25 }, - triggered : false, - handler : function dragGesture( e, hammer ){ - var last_direction; + + handler : function( e, hammer ){ + var drag = this, last_direction, ret; + // current gesture isnt drag, but dragged is true // this means an other gesture is busy. now call dragend - if( Detection.current.name !== this.name && this.triggered ){ - hammer.trigger( XUI_Event.DRAG_END, e ); - this.triggered = false; - return; + if( hammer.currentName !== drag.name && hammer.triggered[ drag.name ] ){ + ret = hammer.trigger( XUI_Event.DRAG_END, e ); + hammer.triggered[ drag.name ] = false; + return ret; }; // max touches if( 0 < hammer.options.drag_max_touches && hammer.options.drag_max_touches < e.touches.length ) return; - - switch( e.eventType ){ - case START: - this.triggered = false; + + switch( e.type ){ + case XUI_Event._POINTER_DOWN : + hammer.triggered[ drag.name ] = false; break; - case MOVE : + case XUI_Event._POINTER_MOVE : // when the distance we moved is too small we skip this gesture // or we can be already in dragging - if( e.distance < hammer.options.drag_min_distance && Detection.current.name !== this.name ) return; + if( e.distance < hammer.options.drag_min_distance && hammer.currentName !== drag.name ) return; // we are dragging! - Detection.current.name = this.name; + hammer.currentName = drag.name; // lock drag to axis? - if( Detection.current.lastEvent.drag_locked_to_axis || ( hammer.options.drag_lock_to_axis && hammer.options.drag_lock_min_distance <= e.distance ) ){ + if( hammer.lastEvent.drag_locked_to_axis || ( hammer.options.drag_lock_to_axis && hammer.options.drag_lock_min_distance <= e.distance ) ){ e.drag_locked_to_axis = true; }; - last_direction = Detection.current.lastEvent.direction; + last_direction = hammer.lastEvent.direction; if( e.drag_locked_to_axis && last_direction !== e.direction ){ // keep direction on the axis that the drag gesture started on - e.direction = Utils.isVertical( last_direction ) ? - ( e.deltaY < 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN ) : - ( e.deltaX < 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT ); + e.direction = XUI_GestureUtils.isVertical( last_direction ) ? + ( e.deltaY < 0 ? 'up' : 'down' ) : + ( e.deltaX < 0 ? 'left' : 'right' ); }; + ret = X_CALLBACK_NONE; + // first time, trigger dragstart event - if( !this.triggered ){ - hammer.trigger( XUI_Event.DRAG_START, e ); - this.triggered = true; + if( !hammer.triggered[ drag.name ] ){ + ret = hammer.trigger( XUI_Event.DRAG_START, e ); + //if( ret & X_CALLBACK_PREVENT_DEFAULT ){ + // hammer.canceled[ drag.name ] = true; + // break; + //}; + ret |= X_CALLBACK_CAPTURE_POINTER; + console.log( '----- drag start ....' + e.type ); + hammer.triggered[ drag.name ] = true; + break; }; + //console.log( '----- drag ....' + e.type ); // trigger normal event - hammer.trigger( XUI_Event.DRAG, e ); + ret = hammer.trigger( XUI_Event.DRAG, e ) | X_CALLBACK_CAPTURE_POINTER; // direction event, like dragdown - hammer.trigger( - e.direction === Hammer.DIRECTION_UP ? + ret |= hammer.trigger( + e.direction === 'up' ? XUI_Event.DRAG_UP : - e.direction === Hammer.DIRECTION_DOWN ? + e.direction === 'down' ? XUI_Event.DRAG_DOWN : - e.direction === Hammer.DIRECTION_LEFT ? + e.direction === 'left' ? XUI_Event.DRAG_LEFT : XUI_Event.DRAG_RIGHT, e ); // block the browser events - ( - ( hammer.options.drag_block_vertical && Utils.isVertical( e.direction ) ) || - ( hammer.options.drag_block_horizontal && !Utils.isVertical( e.direction ) ) - ) && e.preventDefault(); + /* ( + ( hammer.options.drag_block_vertical && XUI_GestureUtils.isVertical( e.direction ) ) || + ( hammer.options.drag_block_horizontal && !XUI_GestureUtils.isVertical( e.direction ) ) + ) && e.preventDefault(); */ break; - case END: + case XUI_Event.POINTER_OUT : + console.log( 'cancel!!' ); + case XUI_Event._POINTER_CANCEL : + case XUI_Event._POINTER_UP: // trigger dragend - this.triggered && hammer.trigger( XUI_Event.DRAG_END, e ); - this.triggered = false; - break; - } - } - }; - - /** - * Transform - * User want to scale or rotate with 2 fingers - * @events transform, transformstart, transformend, pinch, pinchin, pinchout, rotate - */ - Gestures.Transform = { - name : 'transform', - index : 45, - startID : XUI_Event.TRANSFORM, - endID : XUI_Event.ROTATE, - defaults : { - // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 - transform_min_scale : 0.01, - // rotation in degrees - transform_min_rotation : 1, - // prevent default browser behavior when two touches are on the screen - // but it makes the element a blocking element - // when you are using the transform gesture, it is a good practice to set this true - transform_always_block : false - }, - triggered : false, - handler : function transformGesture( e, hammer ){ - // current gesture isnt drag, but dragged is true - // this means an other gesture is busy. now call dragend - if( Detection.current.name !== this.name && this.triggered ){ - hammer.trigger( XUI_Event.TRANSFORM_END, e ); - this.triggered = false; - return; - }; - - // atleast multitouch - if( e.touches.length < 2 ) return; - - // prevent default when two fingers are on the screen - hammer.options.transform_always_block && e.preventDefault(); - - switch(e.eventType) { - case START: - this.triggered = false; - break; - - case MOVE: - var scale_threshold = ABS( 1 - e.scale ), - rotation_threshold = ABS( e.rotation ); - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if( scale_threshold < hammer.options.transform_min_scale && rotation_threshold < hammer.options.transform_min_rotation ) return; - - // we are transforming! - Detection.current.name = this.name; - - // first time, trigger dragstart event - if( !this.triggered ){ - hammer.trigger( XUI_Event.TRANSFORM_START, e ); - this.triggered = true; + if( hammer.triggered[ drag.name ] ){ + ret = hammer.trigger( XUI_Event.DRAG_END, e ) | X_CALLBACK_CAPTURE_POINTER; + console.log( '----- drag end ....' + e.type ); + hammer.triggered[ drag.name ] = false; }; - - hammer.trigger( XUI_Event.TRANSFORM, e ); - // basic transform event - - // trigger rotate event - hammer.options.transform_min_rotation < rotation_threshold && hammer.trigger( XUI_Event.ROTATE, e ); - - // trigger pinch event - if( scale_threshold > hammer.options.transform_min_scale ){ - hammer.trigger( XUI_Event.PINCH, e ); - hammer.trigger( e.scale < 1 ? XUI_Event.PINCH_IN : XUI_Event.PINCH_OUT, e ); - }; - break; - - case END: - // trigger dragend - this.triggered && hammer.trigger( XUI_Event.TRANSFORM_END, e ); - this.triggered = false; break; }; + return ret; } - }; + }, /** - * Touch - * Called as first, tells the user has touched the screen - * @events touch + * Tap/DoubleTap + * Quick touch at a place or double at the same place + * @events tap, doubletap */ - Gestures.Touch = { - name : 'touch', - index : -Infinity, + { + name : 'tap', + index : 100, + startID : XUI_Event.TAP, + endID : XUI_Event.DOUBLE_TAP, defaults : { - // call preventDefault at touchstart, and makes the element blocking by - // disabling the scrolling of the page, but it improves gestures like - // transforming and dragging. - // be careful with using this, it can be very annoying for users to be stuck - // on the page - prevent_default : false, - - // disable mouse events, so only touch (or pen!) input triggers events - prevent_mouseevents : false + tap_min_touchtime : 75, + tap_max_touchtime : 250, + tap_max_distance : 3, + tap_always : true, + doubletap_distance : 20, + doubletap_interval : 300 }, - handler : function touchGesture( e, hammer ){ - if( hammer.options.prevent_mouseevents && e.pointerType === MOUSE ){ - Detection.stopDetect(); - return; + handler : function( e, hammer ){ + // previous gesture, for the double tap since these are two different gesture detections + var prev = hammer.previous; + + if( e.type === XUI_Event._POINTER_UP ){ + // when the touchtime is higher then the max touch time + // or when the moving distance is too much + if( hammer.options.tap_max_touchtime < e.deltaTime || hammer.options.tap_max_distance < e.distance ) return; +//console.log( ' rap? ' + e.deltaTime + 'ms' ); + //if( e.deltaTime < hammer.options.tap_min_touchtime ) return; + + // check if double tap + if( prev && prev.currentName === 'tap' && ( e.timestamp - prev.lastEvent.timestamp ) < hammer.options.doubletap_interval && e.distance < hammer.options.doubletap_distance ){ + return hammer.trigger( XUI_Event.DOUBLE_TAP, e ); + } else + // do a single tap + if( hammer.options.tap_always && hammer.currentName !== 'tap' ){ // EventFire中にalert すると mouseleave で再び呼ばれるのを防ぐ + //hammer.currentName = 'tap'; + console.log( 'tap! ' + e.deltaTime + 'ms' ); + return hammer.trigger( XUI_Event.TAP, e ); + }; }; + } + } - hammer.options.prevent_default && e.preventDefault(); +]; - e.eventType === START && hammer.trigger( this.name, e ); - } +(function( i, g ){ + for( ; i; ){ + g = XUI_Gesture_LIST[ --i ]; + X_Object_override( XUI_Gesture_DEFAULTS, g.defaults ); + delete g.defaults; }; +})( XUI_Gesture_LIST.length ); - /** - * Release - * Called as last, tells the user has released the screen - * @events release - */ - Gestures.Release = { - name : 'release', - index : Infinity, - handler : function releaseGesture( e, hammer ){ - e.eventType === END && hammer.trigger( this.name, e ); - } - }; diff --git a/0.6.x/js/20_ui/06_AbstractUINode.js b/0.6.x/js/20_ui/06_AbstractUINode.js index 63bddf4..16f8234 100644 --- a/0.6.x/js/20_ui/06_AbstractUINode.js +++ b/0.6.x/js/20_ui/06_AbstractUINode.js @@ -88,7 +88,7 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( if( attr ){ for( k in usableAttrs ){ def = usableAttrs[ k ]; - if( def[ 2 ] === XUI_Attr_USER.XNODE && X_Object_inObject( def.No, attr ) && attr[ k ] !== def[ 0 ] ){ + if( def[ 2 ] === XUI_Attr_USER.XNODE && X_Object_inObject( def.No, attr ) && attr[ def.No ] !== def[ 0 ] ){ this.xnode[ 'css' ]( XUI_Attr_Rename[ k ] || k, XUI_AbstractUINode_createCssText( this, k ) ); }; }; @@ -165,8 +165,8 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( if( v.indexOf( ' ' ) !== -1 ){ v = v.split( ' ' ); } else - if( color && X_Type_isNumber( _v = X_Node_CSS_objToIEFilterText( v ) ) ){ - v = _v; + if( color && X_Type_isNumber( _v = X_Node_CSS_parseColor( v ) ) ){ + v = _v; } else { // bad return; @@ -185,7 +185,7 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( ( minusPct && -1 <= v && v < 0 ) || ( numerical && 0 <= v ) || ( auto && v === XUI_Attr_AUTO ) || - ( color && 0 <= v && v <= 0xFFFFFF ) || + ( color && ( 0 <= v && v <= 0xFFFFFF ) || ( v !== v ) ) || // isNaN ( list && list[ v ] ) ){ // good @@ -705,12 +705,13 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( if( 0 <= x && x < this.boxWidth && 0 <= y && y < this.boxHeight ){ !this.hovering && ( this.rootData.hoverList[ this.rootData.hoverList.length ] = this ); this.rootData.targetNodeData = this; + //console.log( 'hit ' + this.xnode.className() ) return true; }; }, /* - * context を明示しない場合、User が context になる! + * TODO context を明示しない場合、User が context になる! の処理は User 側へ */ listen : function( type, arg1, arg2, arg3 ){ var root, events, counter, f; @@ -721,6 +722,12 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( events[ events.length ] = [ type, arg1, arg2, arg3 ]; return this; }; + + if( this[ 'listening' ]( type, arg1, arg2, arg3 ) ){ + console.log( '. listening' ) + return this; + }; + if( XUI_Event._START_XUI_EVENT < type && type < XUI_Event._END_XUI_EVENT ){ if( !this.gesture ){ this.gesture = new Hammer( this.rootData, this, type ); @@ -735,28 +742,23 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( ++counter[ type ]; } else { counter[ type ] = 1; - root.xnodeInteractiveLayer[ 'listen' ]( XUI_Event.IdToName[ type ], X_UI_eventRellay ); + XUI_xnodeIneraction[ 'listen' ]( XUI_Event.IdToName[ type ], X_UI_eventRellay ); }; + if( type === XUI_Event._POINTER_UP ) console.log( '... addEvent ' + counter[ type ] ); }; }; - arg1 && arg1.cbKind ? ( f = arg1 ) : ( f = X_Closure_classifyCallbackArgs( arg1, arg2, arg3 ) ); - if( !f.cbKind ){ - return X_EventDispatcher_listen.call( this, type, this.User, f ); - } else - if( f.cbKind === X_CLOSURE_FUNC_ONLY ){ - return X_EventDispatcher_listen.call( this, type, this.User, f.func, f.supplement ); - }; return X_EventDispatcher_listen.apply( this, arguments ); }, unlisten : function( type, arg1, arg2, arg3 ){ - var root, events, i, ev, counter, f; + var root, events, i, ev, counter; + if( XUI_Event._START_POINTER <= type && type <= XUI_Event._END_POINTER ){ if( this.phase < 3 ){ if( !( events = this.reserveEvents ) ) return this; for( i = events.length; i; ){ ev = events[ --i ]; - if( ev[ 0 ] === type && ev[ 1 ] === arg1 && ev[ 2 ] === arg2 ){ + if( ev[ 0 ] === type && ev[ 1 ] === arg1 && ev[ 2 ] === arg2 && ev[ 3 ] === arg3 ){ events.split( i, 1 ); return this; }; @@ -764,44 +766,52 @@ var XUI_AbstractUINode = X_EventDispatcher[ 'inherits' ]( return this; }; + if( !this[ 'listening' ]( type, arg1, arg2, arg3 ) ){ + return this; + }; + if( XUI_Event._START_XUI_EVENT < type && type < XUI_Event._END_XUI_EVENT ){ this.gesture && this.gesture[ 'unlisten' ]( type ); } else { root = this.rootData; counter = root.eventCounter; - if( !counter[ type ] ) return this; - --counter[ type ]; - if( counter[ type ] === 0 ){ - root.xnodeInteractiveLayer[ 'unlisten' ]( XUI_Event.IdToName[ type ], X_UI_eventRellay ); - delete counter[ type ]; + + if( !counter[ type ] ){ + console.log( '... no event ... ' + counter[ type ] ); + }; + + if( type === XUI_Event._POINTER_UP ) console.log( '... removeEvent ' + counter[ type ] ); + + if( counter[ type ] === 1 ){ + XUI_xnodeIneraction[ 'unlisten' ]( XUI_Event.IdToName[ type ], X_UI_eventRellay ); + counter[ type ] = 0; + } else + if( counter[ type ] ){ + --counter[ type ]; }; }; }; - arg1 && arg1.cbKind ? ( f = arg1 ) : ( f = X_Closure_classifyCallbackArgs( arg1, arg2, arg3 ) ); - if( !f.cbKind ){ - return X_EventDispatcher_unlisten.apply( this, [ type, this.User, f ] ); - } else - if( f.cbKind === X_CLOSURE_FUNC_ONLY ){ - return X_EventDispatcher_unlisten.apply( this, [ type, this.User, f.func, f.supplement ] ); - }; + return X_EventDispatcher_unlisten.apply( this, arguments ); }, + /* dispatch : function( e ){ //console.log( e.type + ' ' + ( this[ '_listeners' ] && this[ '_listeners' ][ e.type ] ) ); - var xve = XUI_Event, - ret = X_EventDispatcher_dispatch.call( this, e ), + var ret = X_EventDispatcher_dispatch.call( this, e ), type = e.type || e; // TODO captureEvent PointerEvent - if( ret & X_CALLBACK_CAPTURE_POINTER && !this.hitChildData && XUI_Event._POINTER_MOVE === type ){ + if( ret & X_CALLBACK_CAPTURE_POINTER ){ this.rootData.monopolyNodeData = this; return ret; }; - this.rootData.monopolyNodeData = null; - if( xve._START_BUBLEUP < type && this.parentData && !( ret & X_CALLBACK_STOP_PROPAGATION ) && !( ret & X_CALLBACK_STOP_NOW ) ) return this.parentData[ 'dispatch' ]( e ); + if( this.rootData.monopolyNodeData === this ) this.rootData.monopolyNodeData = null; + if( XUI_Event._START_BUBLEUP < type && this.parentData && !( ret & X_CALLBACK_STOP_PROPAGATION ) ){ + return this.parentData[ 'dispatch' ]( e ); + }; return ret; - }, + }, */ setItemData : function( itemData ){ if( this.itemData === itemData ) return; @@ -878,13 +888,16 @@ function XUI_AbstractUINode_createCssValue( v, type, list ){ if( X_Type_isNumber( v ) ){ if( auto && v === XUI_Attr_AUTO ) return 'auto'; - if( length || minusLen ) return v + 'em'; + if( length || minusLen ) return v ? v + 'em' : 0; if( numerical ) return v; if( list && list[ v ] ) return list[ v ]; if( color ){ if( v < 0x100000 ){ v = '00000' + v.toString( 16 ); return '#' + v.substr( v.length - 6 ); + } else + if( v !== v ){ // iSNaN + return 'none'; }; return '#' + v.toString( 16 ); }; @@ -971,7 +984,15 @@ X.UI.AbstractUINode = X_Class_create( }, listen : function( type, arg1, arg2, arg3 ){ - X_Pair_get( this )[ 'listen' ]( type, arg1, arg2, arg3 ); + var pair = X_Pair_get( this ); + + ( !arg1 || !arg1.cbKind ) && ( arg1 = X_Closure_classifyCallbackArgs( arg1, arg2, arg3, this ) ); + + if( arg1.cbKind === X_CLOSURE_FUNC_ONLY ){ + pair[ 'listen' ].apply( pair, [ type, this, arg1.func, arg1.supplement ] ); + } else { + pair[ 'listen' ]( type, arg1.context, arg1.func, arg1.supplement ); + }; return this; }, listenOnce : function( type, arg1, arg2, arg3 ){ @@ -982,7 +1003,15 @@ X.UI.AbstractUINode = X_Class_create( return X_Pair_get( this )[ 'listening' ]( type, arg1, arg2, arg3 ); }, unlisten : function( type, arg1, arg2, arg3 ){ - X_Pair_get( this )[ 'unlisten' ]( type, arg1, arg2, arg3 ); + var pair = X_Pair_get( this ); + + ( !arg1 || !arg1.cbKind ) && ( arg1 = X_Closure_classifyCallbackArgs( arg1, arg2, arg3, this ) ); + + if( arg1.cbKind === X_CLOSURE_FUNC_ONLY ){ + pair[ 'unlisten' ].apply( pair, [ type, this, arg1.func, arg1.supplement ] ); + } else { + pair[ 'unlisten' ]( type, arg1.context, arg1.func, arg1.supplement ); + }; return this; }, dispatch : function( e ){ diff --git a/0.6.x/js/20_ui/08_Box.js b/0.6.x/js/20_ui/08_Box.js index 0aa07e1..d0c7818 100644 --- a/0.6.x/js/20_ui/08_Box.js +++ b/0.6.x/js/20_ui/08_Box.js @@ -24,7 +24,7 @@ var XUI_Layout_Canvas = X[ 'UI' ][ 'Layout' ][ 'Canvas' ] = XUI_createLayout( { data.preMesure( w, h ); - console.log( w + ' > ' + data.boxWidth ); + //console.log( w + ' > ' + data.boxWidth ); // data.boxWidth と data.boxHeight のどちらかでも Infinity if( isNeedsDetection && data.boxWidth + data.boxHeight === XUI_Attr_AUTO ) return false; @@ -35,7 +35,7 @@ var XUI_Layout_Canvas = X[ 'UI' ][ 'Layout' ][ 'Canvas' ] = XUI_createLayout( { _h = data.contentHeight; if( ( uinodes = data.uinodes ) && ( l = uinodes.length ) ){ - console.log( _w + ' x ' + _h + ' l:' + l ); + //console.log( _w + ' x ' + _h + ' l:' + l ); for( i = 0; i < l; ++i ){ node = uinodes[ i ]; node.calculate( false, _x, _y, _w, _h ); @@ -176,7 +176,9 @@ var XUI_Box = XUI_AbstractUINode.inherits( capcher : function( x, y ){ var uinodes, child, _x, _y, hit, i; + if( this.pointerDisabled ) return false; + delete this.hitChildData; x -= this.boxX; y -= this.boxY; @@ -198,7 +200,9 @@ var XUI_Box = XUI_AbstractUINode.inherits( }; hit = 0 <= x && x < this.boxWidth && 0 <= y && y < this.boxHeight; ( this.hitChildData || hit ) && !this.hovering && ( this.rootData.hoverList[ this.rootData.hoverList.length ] = this ); - if( hit && this.hitChildData === null ) this.rootData.targetNodeData = this; + if( hit && this.hitChildData === null ){ + this.rootData.targetNodeData = this; + }; return hit || !!this.hitChildData; }, @@ -342,7 +346,7 @@ X.UI.Box = X.UI.AbstractUINode.inherits( }, clone : function( opt_cloneListener ){ - var clone = XUI_AbstractUINode.prototype.clone.call( this, opt_cloneListener ), + var clone = X.UI.AbstractUINode.prototype.clone.call( this, opt_cloneListener ), uinodes = X_Pair_get( this ).uinodes, i = 0, l = uinodes && uinodes.length, diff --git a/0.6.x/js/20_ui/15_ScrollBox.js b/0.6.x/js/20_ui/15_ScrollBox.js index 2d160a1..4948a7b 100644 --- a/0.6.x/js/20_ui/15_ScrollBox.js +++ b/0.6.x/js/20_ui/15_ScrollBox.js @@ -131,7 +131,7 @@ var XUI_ScrollBox = XUI_ChromeBox.inherits( Constructor : function( user, layout, args ){ this[ 'Super' ]( user, layout, args ); this._containerNode = X_Pair_get( this.containerNode ); - this.xnodeSlider = this._containerNode.xnode[ 'className' ]( 'ScrollSlider' ).listen( X_EVENT_ANIME_END, this, X_UI_ScrollBox_onAnimeEnd ); + this.xnodeSlider = this._containerNode.xnode[ 'className' ]( 'ScrollSlider' )[ 'listen' ]( X_EVENT_ANIME_END, this, X_UI_ScrollBox_onAnimeEnd ); this.xnode[ 'className' ]( 'ScrollBox' ); }, @@ -224,7 +224,11 @@ function X_UI_ScrollBox_onLayoutComplete( e ){ X_UI_ScrollBox_translate( this, this.scrollXMax * this.scrollXRatio, this.scrollYMax * this.scrollYRatio, 100, '', 300 ); } else { // scroller 作る - this[ 'listen' ]( XUI_Event._POINTER_DOWN, this, X_UI_ScrollBox_onStart ); + // shadow の listen には this が必要! + // TODO AbstractUI の listen が悪い! + this[ 'listen' ]( XUI_Event._POINTER_DOWN, this, X_UI_ScrollBox_onStart ) + [ 'listen' ]( XUI_Event.DRAG, this, X_UI_ScrollBox_onMove ); + this[ 'listen' ]( XUI_Event.DRAG_END, this, X_UI_ScrollBox_onEnd ); X_UI_rootData[ 'listen' ]( XUI_Event.LAYOUT_BEFORE, this, X_UI_ScrollBox_onLayoutBefore ); X_UI_ScrollBox_translate( this, this.scrollXMax * this.scrollXRatio, this.scrollYMax * this.scrollYRatio, 100, '', 300 ); @@ -234,7 +238,9 @@ function X_UI_ScrollBox_onLayoutComplete( e ){ // scroll 不要 if( this.scrolling ){ // scroller 削除 - this[ 'unlisten' ]( XUI_Event._POINTER_DOWN, this, X_UI_ScrollBox_onStart ); + this[ 'unlisten' ]( XUI_Event._POINTER_DOWN, this, X_UI_ScrollBox_onStart ) + [ 'unlisten' ]( XUI_Event.DRAG, this, X_UI_ScrollBox_onMove ); + this[ 'unlisten' ]( XUI_Event.DRAG_END, this, X_UI_ScrollBox_onEnd ); X_UI_rootData[ 'unlisten' ]( XUI_Event.LAYOUT_BEFORE, this, X_UI_ScrollBox_onLayoutBefore ); ( this.scrollX !== 0 || this.scrollY !== 0 ) && X_UI_ScrollBox_translate( this, 0, 0, 100, '', 300 ); @@ -247,7 +253,9 @@ function X_UI_ScrollBox_onLayoutComplete( e ){ // TODO use scrollLeft, scrollTop function X_UI_ScrollBox_translate( that, x, y, opt_time, opt_easing, opt_release ){ - var scrollBoxSize, indicatorSize; + var scrollBoxH = that.fontSize * that.boxHeight, + scrollBoxW = that.fontSize * that.boxWidth, + indicatorH, indicatorW; opt_time = 0 <= opt_time ? opt_time : 0; opt_easing = opt_easing === '' ? '' : opt_easing || 'circular'; @@ -265,39 +273,43 @@ function X_UI_ScrollBox_translate( that, x, y, opt_time, opt_easing, opt_release opt_time, opt_easing, opt_release ); + if( X_UA[ 'IE' ] < 6 ){ + XUI_ScrollBox_indicatorV && XUI_ScrollBox_indicatorV[ 'css' ]( 'left', ( scrollBoxW - that.fontSize * 0.6 | 0 ) + 'px' ); + XUI_ScrollBox_indicatorH && XUI_ScrollBox_indicatorH[ 'css' ]( 'top' , ( scrollBoxH - that.fontSize * 0.6 | 0 ) + 'px' ); + }; + if( that.hasVScroll && XUI_ScrollBox_indicatorV ){ - scrollBoxSize = that.fontSize * that.boxHeight; - indicatorSize = scrollBoxSize * scrollBoxSize / ( - that.scrollYMax + scrollBoxSize ); - scrollBoxSize -= indicatorSize; + indicatorH = scrollBoxH * scrollBoxH / ( - that.scrollYMax + scrollBoxH ); + scrollBoxH -= indicatorH; + XUI_ScrollBox_indicatorV [ 'css' ]({ - height : ( indicatorSize | 0 ) + 'px' + height : ( indicatorH | 0 ) + 'px' }) [ 'animate' ]( { - y : scrollBoxSize * that.scrollY / that.scrollYMax + y : scrollBoxH * that.scrollY / that.scrollYMax }, { - y : scrollBoxSize * y / that.scrollYMax, + y : scrollBoxH * y / that.scrollYMax, opacity : 1 }, opt_time, opt_easing, opt_release ); }; if( that.hasHScroll && XUI_ScrollBox_indicatorH ){ - scrollBoxSize = that.fontSize * that.boxWidth; - indicatorSize = scrollBoxSize * scrollBoxSize / ( - that.scrollXMax + scrollBoxSize ); - scrollBoxSize -= indicatorSize; + indicatorW = scrollBoxW * scrollBoxW / ( - that.scrollXMax + scrollBoxW ); + scrollBoxW -= indicatorW; XUI_ScrollBox_indicatorH [ 'css' ]({ - width : ( indicatorSize | 0 ) + 'px' + width : ( indicatorW | 0 ) + 'px' }) [ 'animate' ]( { - x : scrollBoxSize * that.scrollX / that.scrollXMax + x : scrollBoxW * that.scrollX / that.scrollXMax }, { - x : scrollBoxSize * x / that.scrollXMax, + x : scrollBoxW * x / that.scrollXMax, opacity : 1 }, opt_time, opt_easing, opt_release @@ -310,11 +322,6 @@ function X_UI_ScrollBox_translate( that, x, y, opt_time, opt_easing, opt_release function X_UI_ScrollBox_onStart( e ){ var ret = X_CALLBACK_NONE; - - // React to left mouse button only - if( e.pointerType === 'mouse' && e.button !== 0 ){ - return ret; - }; if( !this.scrollEnabled || ( this.initiated && e.pointerType !== this.initiated ) ){ return ret; @@ -332,7 +339,7 @@ function X_UI_ScrollBox_onStart( e ){ // スクロール中の停止 if( this.isInTransition ){ this.isInTransition = false; - console.log( '-1-' ); + //console.log( '-1-' ); this[ 'dispatch' ]( XUI_Event.SCROLL_END ); // TODO current位置 this.xnodeSlider[ 'stop' ](); @@ -345,10 +352,7 @@ function X_UI_ScrollBox_onStart( e ){ this.pointX = e.pageX; this.pointY = e.pageY; - console.log( 'scrollstart ' + e.pageY ); - - this[ 'listen' ]( XUI_Event._POINTER_MOVE, this, X_UI_ScrollBox_onMove ); - this[ 'listen' ]( [ XUI_Event._POINTER_UP, XUI_Event.POINTER_OUT, XUI_Event._POINTER_CANCEL ], this, X_UI_ScrollBox_onEnd ); + console.log( 'scrollstart ' + e.pageY + e.target.className() ); return ret | X_CALLBACK_PREVENT_DEFAULT; }; @@ -365,10 +369,6 @@ function X_UI_ScrollBox_onMove( e ){ if( !this.scrollEnabled || e.pointerType !== this.initiated ){ return ret; }; - - if( e.buttons !== 1 ){ - return X_UI_ScrollBox_onEnd.call( this, e ); - }; // gpu の用意 if( !this.xnodeSlider[ '_anime' ] ){ @@ -464,13 +464,10 @@ function X_UI_ScrollBox_onEnd( e ){ momentumX, momentumY, duration, distanceX, distanceY; - console.log( e.type + ' onend ' + XUI_Event.POINTER_OUT ); - - this[ 'unlisten' ]( XUI_Event._POINTER_MOVE, this, X_UI_ScrollBox_onMove ); - this[ 'unlisten' ]( [ XUI_Event._POINTER_UP, XUI_Event.POINTER_OUT, XUI_Event._POINTER_CANCEL ], this, X_UI_ScrollBox_onEnd ); + //console.log( e.type + ' onend ' + XUI_Event.POINTER_OUT ); if( !this.scrollEnabled || e.pointerType !== this.initiated ){ - console.log( e.type + ' onend 1 ' + e.pointerType + ' ' + this.initiated ); + //console.log( e.type + ' onend 1 ' + e.pointerType + ' ' + this.initiated ); return ret; }; @@ -486,15 +483,15 @@ function X_UI_ScrollBox_onEnd( e ){ // reset if we are outside of the boundaries if( X_UI_ScrollBox_resetPosition( this, this.bounceTime ) ){ - console.log( e.type + ' onend 2 ' + XUI_Event.POINTER_OUT ); - return ret; + //console.log( e.type + ' onend 2 ' + XUI_Event.POINTER_OUT ); + return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_RELEASE_POINTER; }; // we scrolled less than 10 pixels if( !this.moved ){ this[ 'dispatch' ]( X_EVENT_CANCELED ); - console.log( 'we scrolled less than 10 pixels ' + e.pageY ); - return ret; + //console.log( 'we scrolled less than 10 pixels ' + e.pageY ); + return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_RELEASE_POINTER; }; // start momentum animation if needed @@ -510,7 +507,7 @@ function X_UI_ScrollBox_onEnd( e ){ time = Math.max( momentumX.duration, momentumY.duration ) | 0; this.isInTransition = true; } else { - console.log( '慣性無し' ); + //console.log( '慣性無し' ); }; if( newX != this.scrollX || newY != this.scrollY ){ @@ -519,15 +516,15 @@ function X_UI_ScrollBox_onEnd( e ){ easing = 'quadratic'; }; - console.log( 'end2 x:' + newX + ' y:' + newY + '<-y:' + this.scrollY + ' t:' + time ); + //console.log( 'end2 x:' + newX + ' y:' + newY + '<-y:' + this.scrollY + ' t:' + time ); this.scrollTo( newX, newY, time, easing, 1000 ); } else { - console.log( 'end1 x:' + newX + ' y:' + newY ); + //console.log( 'end1 x:' + newX + ' y:' + newY ); this.scrollTo( newX, newY, 0, '', 1000 ); // ensures that the last position is rounded - console.log( '-3-' ); + //console.log( '-3-' ); this[ 'dispatch' ]( XUI_Event.SCROLL_END ); }; - return ret; + return ret | X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_RELEASE_POINTER; }; function X_UI_ScrollBox_resetPosition( that, time ){ @@ -551,12 +548,12 @@ function X_UI_ScrollBox_resetPosition( that, time ){ }; if( x === that.scrollX && y === that.scrollY ){ - console.log( 'no バウンド y:' + y + ' max:' + that.scrollYMax ); + //console.log( 'no バウンド y:' + y + ' max:' + that.scrollYMax ); return false; }; - console.log( ' ===> resetPosition - バウンド!' ); - console.log( ' x:' + x + ' y:' + y ); + //console.log( ' ===> resetPosition - バウンド!' ); + //console.log( ' x:' + x + ' y:' + y ); that.scrollTo( x, y, time, that.bounceEasing, 1000 ); return true; @@ -569,10 +566,10 @@ function X_UI_ScrollBox_onAnimeEnd( e ){ }; if( e.target === this.xnodeSlider && this.isInTransition && !X_UI_ScrollBox_resetPosition( this, this.bounceTime ) ){ this.isInTransition = false; - console.log( '-2-' ); + //console.log( '-2-' ); this[ 'dispatch' ]( XUI_Event.SCROLL_END ); }; - console.log(' -2.1- '+this.isInTransition ); + //console.log(' -2.1- '+this.isInTransition ); return X_CALLBACK_NONE; }; diff --git a/0.6.x/js/20_ui/17_Text.js b/0.6.x/js/20_ui/17_Text.js index 5dacb25..08cec6d 100644 --- a/0.6.x/js/20_ui/17_Text.js +++ b/0.6.x/js/20_ui/17_Text.js @@ -1,6 +1,9 @@ var X_UI_Text_SUPPORT_ATTRS = { - content : [ '', XUI_Dirty.CONTENT, XUI_Attr_USER.UINODE, XUI_Attr_Type.STRING ] -}; + content : [ '' , XUI_Dirty.CONTENT, XUI_Attr_USER.UINODE, XUI_Attr_Type.STRING ], + bgColor : [ NaN, XUI_Dirty.PAINT, XUI_Attr_USER.XNODE, XUI_Attr_Type.COLOR ] +}, + +X_UI_Text_usableAttrs = XUI_Attr_createAttrDef( XUI_AbstractUINode.prototype.usableAttrs, X_UI_Text_SUPPORT_ATTRS ); var XUI_Text = XUI_AbstractUINode.inherits( '_Text', @@ -8,7 +11,9 @@ var XUI_Text = XUI_AbstractUINode.inherits( { content : '', - usableAttrs : XUI_Attr_createAttrDef( XUI_AbstractUINode.prototype.usableAttrs, X_UI_Text_SUPPORT_ATTRS ), + usableAttrs : __textAttrs = X_UI_Text_usableAttrs, + + attrClass : XUI_Attr_preset( XUI_AbstractUINode.prototype.attrClass, X_UI_Text_usableAttrs ), Constructor : function( user, content ){ if( !( user[ 'instanceOf' ]( X.UI.Text ) ) ){ @@ -31,13 +36,23 @@ var XUI_Text = XUI_AbstractUINode.inherits( XUI_AbstractUINode.prototype.creationComplete.apply( this, arguments ); }, + setContent : function( v ){ + if( this.content !== v ){ + this.content = v; + this.xnode && this.xnode[ 'text' ]( v ); + this.rootData.reserveCalc(); + if( this.dirty < XUI_Dirty.CONTENT ) this.dirty = XUI_Dirty.CONTENT; + }; + return this; + }, + setItemData : function( itemData ){ if( this.itemData === itemData ) return; XUI_AbstractUINode.prototype.setItemData.apply( this, arguments ); if( X_Type_isObject( itemData = this.itemData ) && this.dataFeild ){ - this.User.content( itemData[ this.dataFeild ] || '' ); + this.setContent( itemData[ this.dataFeild ] || '' ); }; } } @@ -53,12 +68,14 @@ X.UI.Text = X.UI.AbstractUINode.inherits( X_Type_isObject( opt_attrObj = opt_attrObj || opt_content ) && this[ 'attr' ]( opt_attrObj ); }, content : function( v ){ - var data = X_Pair_get( this ); - if( data.content !== v ){ - data.xnode && data.xnode[ 'text' ]( v ); - data.rootData.reserveCalc(); - if( data.dirty < XUI_Dirty.CONTENT ) data.dirty = XUI_Dirty.CONTENT; + var data = X_Pair_get( this ), + content = data.content; + + if( v === undefined ){ + return content; }; + content !== v && data.setContent( v ); + return this; } } ); \ No newline at end of file diff --git a/0.6.x/js/20_ui/20_Root.js b/0.6.x/js/20_ui/20_Root.js index 6c2dd6b..d5b794d 100644 --- a/0.6.x/js/20_ui/20_Root.js +++ b/0.6.x/js/20_ui/20_Root.js @@ -1,5 +1,6 @@ var X_UI_rootData = null, - X_UI_eventBusy = false; + XUI_xnodeIneraction = null, + XUI_interactionBusy = false; function X_UI_eventRellay( e ){ var font = X_ViewPort_baseFontSize, @@ -10,35 +11,63 @@ function X_UI_eventRellay( e ){ data = X_UI_rootData, sysOnly = false, ret = X_CALLBACK_NONE, - list, parent, _ret; + list, parent, _ret, eventIn, eventOut; // mouseup で alert を出すと mouseleave が発生、ということでイベント中のイベント発火を禁止 - if( !data || X_UI_eventBusy ) return ret; - data._eventBusy = true; + if( !data || XUI_interactionBusy ) return ret; + XUI_interactionBusy = true; - if( type !== '' + XUI_Event._POINTER_MOVE ){ - //console.log( e.type + ' ' + type + ' x:' + x + ', y:' + y ); - }; + e.type = type; + // TODO capture は pointer 毎に! if( data && ( data = data.monopolyNodeData ) && ( ret = data[ 'dispatch' ]( e ) ) & X_CALLBACK_CAPTURE_POINTER ){ - X_UI_eventBusy = false; + console.log( 'capture ' + data.xnode.className() ); + XUI_interactionBusy = false; return ret | X_CALLBACK_PREVENT_DEFAULT; }; + //if( ret & X_CALLBACK_RELEASE_POINTER ){ + data && ( data.monopolyNodeData = null ); + //return ret | X_CALLBACK_PREVENT_DEFAULT; + //}; list = X_UI_rootData.hoverList; ( X_UI_rootData.targetNodeData = X_UI_rootData ).capcher( x, y ); data = X_UI_rootData.targetNodeData; - //data !== X_UI_rootData && console.log( data.xnode[ 'text' ]() ); + if( type !== XUI_Event._POINTER_MOVE ){ + //console.log( data.xnode.className() + '>' + e.type + ' ' + type + ' x:' + x + ', y:' + y ); + //console.dir( data ) + //data !== X_UI_rootData && console.log( ( data.xnode[ 'className' ]() + data.xnode[ 'text' ]() ).substr( 0, 15 ) ); + }; - while( data ){ + + + while( true ){ _ret = data[ 'dispatch' ]( e, sysOnly ); ret |= _ret; - if( _ret & X_CALLBACK_CAPTURE_POINTER || _ret & X_CALLBACK_STOP_PROPAGATION || _ret & X_CALLBACK_STOP_NOW ) break; // sysOnly = true; + if( X_UI_rootData !== data && _ret & X_CALLBACK_CAPTURE_POINTER ){ + X_UI_rootData.monopolyNodeData = data; + break; + }; + if( X_UI_rootData.monopolyNodeData === data ) X_UI_rootData.monopolyNodeData = null; + if( type < XUI_Event._START_BUBLEUP || ret & X_CALLBACK_STOP_PROPAGATION ){ + break; + }; + if( !data.parentData ) break; data = data.parentData; + if( type !== XUI_Event._POINTER_MOVE ){ + //data !== X_UI_rootData && console.log( ( data.xnode[ 'className' ]() + data.xnode[ 'text' ]() ).substr( 0, 15 ) ); + }; }; + if( data !== X_UI_rootData ) ret |= X_UI_rootData[ 'dispatch' ]( e, sysOnly ); + + eventOut = X_Object_copy( e ); + eventOut.type = XUI_Event.POINTER_OUT; + + eventIn = X_Object_copy( e ); + eventIn.type = XUI_Event.POINTER_IN; for( i = list.length; i; ){ parent = data = list[ --i ]; @@ -47,31 +76,34 @@ function X_UI_eventRellay( e ){ }; if( parent !== X_UI_rootData ){ data.hoverClassName && data.xnode[ 'removeClass' ]( data.hoverClassName ); - data[ '_listeners' ] && data[ '_listeners' ][ XUI_Event.POINTER_OUT ] && data[ 'dispatch' ]( XUI_Event.POINTER_OUT, false ); // new Event + data[ '_listeners' ] && data[ '_listeners' ][ XUI_Event.POINTER_OUT ] && data[ 'dispatch' ]( eventOut, false ); // new Event delete data.hovering; list.splice( i, 1 ); continue; }; if( !data.hovering ){ data.hoverClassName && data.xnode.addClassName( data.hoverClassName ); - data[ '_listeners' ] && data[ '_listeners' ][ XUI_Event.POINTER_IN ] && data[ 'dispatch' ]( XUI_Event.POINTER_IN, true ); // new Event + data[ '_listeners' ] && data[ '_listeners' ][ XUI_Event.POINTER_IN ] && data[ 'dispatch' ]( eventIn, true ); // new Event data.hovering = true; }; }; - X_UI_eventBusy = false; + XUI_interactionBusy = false; return ret | X_CALLBACK_PREVENT_DEFAULT; }; function X_UI_onMouseOut( e ){ var list = X_UI_rootData.hoverList, i = list.length; -console.log( e.type + i + ' ' + e.pointerType ) + console.log( 'pointer out!!' + e.type + i + ' ' + e.pointerType ); + + e = X_Object_copy( e ); + e.type = XUI_Event.POINTER_OUT; + for( ; i; ){ data = list[ --i ]; - console.log( data.xnode.className() ); + //console.log( data.xnode.className() ); data.hoverClassName && data.xnode[ 'removeClass' ]( data.hoverClassName ); - data[ '_listeners' ] && data[ '_listeners' ][ XUI_Event.POINTER_OUT ] && data[ 'dispatch' ]( - { type : XUI_Event.POINTER_OUT, pointerType : e.pointerType }, false ); // new Event + data[ '_listeners' ] && data[ '_listeners' ][ XUI_Event.POINTER_OUT ] && data[ 'dispatch' ]( e, false ); // new Event delete data.hovering; }; list.length = 0; @@ -113,24 +145,28 @@ var XUI_Root = XUI_Box.inherits( }, start : function(){ + // hover や rollover rollout のための move イベントの追加 + // TODO この切り替えを ViewPort へ + XUI_xnodeIneraction = ( X_UA[ 'IE' ] < 9 ? X_ViewPort_document : X_UA[ 'Opera' ] < 8 ? X_Node_body : X_ViewPort ); + this.initialize( this.User, this, null, null ); X_Timer_once( 0, this, this.addToView ); }, addToView : function(){ - var counter = this.eventCounter, flg; + var counter = this.eventCounter; // this.xnodeInteractiveLayer の前に追加する! - this.addToParent( X.Doc.body ); + this.addToParent( X_Node_body ); - this.xnodeInteractiveLayer = X.Doc.body.create( 'div', { + this.xnodeInteractiveLayer = X_Node_body.create( 'div', { 'class' : 'mouse-operation-catcher', unselectable : 'on' - } )[ 'listen' ]( 'pointerleave', this, X_UI_onMouseOut ); + } ); - // hover や rollover rollout のための move イベントの追加 - // TODO この切り替えを ViewPort へ - ( X_UA[ 'IE' ] < 9 ? X_ViewPort_document : X_UA[ 'Opera' ] < 8 ? X_Node_body : X_ViewPort )[ 'listen' ]( 'pointermove', X_UI_eventRellay ); + X_Node_body[ 'listen' ]( 'pointerleave', this, X_UI_onMouseOut ); + + XUI_xnodeIneraction[ 'listen' ]( 'pointermove', X_UI_eventRellay ); if( counter[ XUI_Event._POINTER_MOVE ] ){ ++counter[ XUI_Event._POINTER_MOVE ]; } else { diff --git a/0.6.x/js/main.js b/0.6.x/js/main.js index 13fe971..8f76774 100644 --- a/0.6.x/js/main.js +++ b/0.6.x/js/main.js @@ -1,86 +1,109 @@ -var scroll; + +X( + function(){ + var source = [ + { + label : 'ぺったんR', + summary : X.VERSION + ( X.buildTimeStamp ? ' ' + X.buildTimeStamp : '' ) + }, + { + label : 'レンダリングエンジン', + summary : X.UA.IE ? 'Trident' : + X.UA.Opera ? 'Presto' : + X.UA.Gecko ? 'Gecko' : + X.UA.KHTML ? 'KHTML' : X.UA.WebKit ? 'WebKit' : X.UA.Blink ? 'Blink' : + X.UA.Edge ? 'Edge' : 'Other' + }, + { + label : 'OS', + summary : X.UA.Windows ? 'Windows' : X.UA.Mac ? 'Mac' : X.UA.Android ? 'Android' : X.UA.iOS ? 'iOS' : 'Other' + }, + { + label : '起動時間', + summary : X.bootSpeed + 'ms' + }, + { + label : '設定' + }, + { + label : '情報' + }, + { + label : 'ローカルストレージ' + }, + { + label : '外部API接続' + }, + { + label : 'HID' + } + ]; -var css = { - //width : '100%', - sizing : 'border', - fontColor : 0xAAAAAA, - fontBold : true, - bgColor : 0x34383B, - borderColor : 0x252527, - borderStyle : 'solid', - padding : [ 1.35, 1, 1.5 ], - borderWidth : [ 0, 0, 0.15 ], - height : 4, - left : 0, - right : 0 - }; -with( X.UI ){ + with( X.UI ){ + Root( + List( + source, + AndroidItem().listen( X.UI.Event.ITEMDATA_CHANGED ) + ) + ); + }; + } +); + var AndroidItem = X.UI.Box.inherits( 'AndroidItem', X.Class.NONE, { - Constructor : function( label, discription, value ){ - this.Super( css ); - this.add( Text( label ) ); - } - } -); - - - Root( - scroll = ScrollBox( - Layout.Vertical, - { + Constructor : function(){ + this.Super( { + sizing : 'border', + bgColor : 0x34383B, borderColor : 0x252527, - borderWidth : [ 0.15, 0, 0 ], borderStyle : 'solid', - height : 'auto', - bgColor : 0x444643, - gapY : 0.15 - }, - AndroidItem( - 'ぺったんR ' + X.VERSION - ), - Text( - 'システム情報', - css - ), - Text( - 'ユーザー設定', - css - ), - Text( - 'ソーシャル設定', - css - ), - Text( - 'ローカルストレージ利用設定', - css - ), - Text( - 'システム環境設定', - css - ), - Text( - 'ブラウザ情報', - css - ), - Text( - '端末スコア', - css - ), - Text( - 'ブラウザ・プラグイン', - css - ), - Text( - 'デバッグ情報', - css - ) - ) - ); -} + borderWidth : [ 0, 0, 0.15 ], + height : 4, + left : 0, + right : 0 + } ).listen( X.UI.Event.TAP ); + }, + + handleEvent : function( e ){ + var txt; + + switch( e.type ){ + case X.UI.Event.ITEMDATA_CHANGED : + if( e.itemData.summary ){ + this.add( X.UI.Text( e.itemData.label, { + fontColor : 0xAAAAAA, + fontBold : true, + top : 0.7, + left : 1 + } ) ) + .add( X.UI.Text( e.itemData.summary, { + fontColor : 0x777777, + fontSize : 0.8, + top : 3.1, + left : 1.27 + } ) ); + } else { + this.add( X.UI.Text( e.itemData.label, { + fontColor : 0xAAAAAA, + fontBold : true, + top : 1.35, + left : 1 + } ) ); + }; + break; + + case X.UI.Event.TAP : + txt = this.getNodeAt( 0 ); + txt.content( txt.content() + '+' ); + }; + } + } +); + + -var __scroll = X.Pair.get( scroll ); -- 2.11.0