OSDN Git Service

Version 0.6.222, Fix the bug of X.TextRange.
authoritozyun <itozyun@user.sourceforge.jp>
Mon, 28 Nov 2016 05:21:24 +0000 (14:21 +0900)
committeritozyun <itozyun@user.sourceforge.jp>
Mon, 28 Nov 2016 05:21:24 +0000 (14:21 +0900)
add ExecuteAtEnd and FocusUtility.

0.6.x/js/01_core/14_XEvent.js
0.6.x/js/01_core/15_XEventDispatcher.js
0.6.x/js/01_core/16_XTimer.js
0.6.x/js/01_core/17_ExecuteAtEnd.js [new file with mode: 0644]
0.6.x/js/01_core/18_FocusUtility.js [new file with mode: 0644]
0.6.x/js/01_core/21_XViewPort.js
0.6.x/js/02_dom/20_XNode.js
0.6.x/js/02_dom/30_XTextRange.js
0.6.x/js/11_hid/01_KB.js
0.6.x/js/import.js

index 1771ecc..99991aa 100644 (file)
@@ -3,6 +3,8 @@ var X_Event_Rename    = {},
        X_Event_RenameTo  = {},\r
        \r
        // TODO IFRAMEload, SCRIPTload, LINKload raw.readyState !== 'complete' && raw.readyState !== 'loaded' && this.dispatch( 'load' )\r
+       \r
+       \r
        X_Event_proxy     = {\r
                \r
                'IFRAMEload' : function( eventDispatcher ){\r
@@ -13,9 +15,11 @@ var X_Event_Rename    = {},
                                var raw = this[ '_rawObject' ];\r
                                \r
                                return ( raw.readyState === 'complete' || raw.readyState === 'loaded' ) ?\r
-                                               this[ 'dispatch' ]( 'load' ) : X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_STOP_PROPAGATION;\r
+                                               X_EventDispatcher_actualHandleEvent( 'load' ) : X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_STOP_PROPAGATION;\r
                        },\r
                \r
+               // TODO  focusin focusout\r
+               \r
                // X_UA[ 'Opera' ]\r
                'contextmenu' : function( eventDispatcher ){\r
                        eventDispatcher[ 'listen' ]( 'mousedown', contextmenu_proxy );\r
index afa52c7..20701c3 100644 (file)
@@ -734,7 +734,8 @@ function X_EventDispatcher_actualRemoveEvent( that, type, raw, list, skip ){
 \r
 // TODO ブラウザからの呼び出しの最後に登録された関数を呼び出す機能(例えば画面の更新)\r
 var X_EventDispatcher_CURRENT_EVENTS    = [];\r
-var X_EventDispatcher_ignoreActualEvent = '';\r
+var X_EventDispatcher_ignoreActualEvent;\r
+var X_EventDispatcher_rawEvent;\r
 \r
 // handleEvent を拡張可能にするために、クロージャに移動した\r
 // Is this in regard to the Safari 1.x preventDefault bug on click/dblclick?\r
@@ -746,36 +747,48 @@ var X_EventDispatcher_actualHandleEvent =
                                elm = this[ '_rawObject' ],\r
                                ev, ret;\r
                        \r
-                       /* if( e.type === X_EventDispatcher_ignoreActualEvent ){\r
+                       if( X_EventDispatcher_ignoreActualEvent ){\r
                                e.cancelBubble = true;\r
                                return;\r
-                       }; */\r
+                       };\r
                        \r
-                       ev = new X_DomEvent( e, this, elm );\r
+                       X_EventDispatcher_rawEvent = e;\r
                        \r
+                       ev = new X_DomEvent( e, this, elm );\r
+\r
                        X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length ] = ev;\r
                        \r
                        ret = this[ 'dispatch' ]( ev );\r
 \r
+                       if( X_EventDispatcher_rawEvent === e ) X_EventDispatcher_rawEvent = null;\r
+\r
                        --X_EventDispatcher_CURRENT_EVENTS.length;\r
 \r
                        if( ret & X_CALLBACK_STOP_PROPAGATION ){\r
                                e.cancelBubble = true;\r
                        };\r
+                       \r
+                       if( !X_EventDispatcher_CURRENT_EVENTS.length ) ExecuteAtEnd_onEnd();\r
+                       \r
                        if( ret & X_CALLBACK_PREVENT_DEFAULT ){\r
-                               this[ '_tag' ] === 'A' && elm.blur();\r
+                               X_EventDispatcher_ignoreActualEvent = true;\r
+                               this[ '_tag' ] === 'A' && elm.blur(); // おかしくない??\r
+                               X_EventDispatcher_ignoreActualEvent = false;\r
                                return e.returnValue = false;\r
                        };\r
                }) :\r
        //X_UA_EVENT.W3C || X_UA_EVENT.DOM0\r
                (function( e ){\r
                        var ret = X_CALLBACK_NONE,\r
+                               elm = this[ '_rawObject' ],\r
                                ev, i, l;\r
                        \r
-                       /* if( e.type === X_EventDispatcher_ignoreActualEvent ){\r
+                       if( X_EventDispatcher_ignoreActualEvent ){\r
                                e.stopPropagation();\r
                                return;\r
-                       }; */\r
+                       };\r
+\r
+                       X_EventDispatcher_rawEvent = e;\r
                        \r
                        ev  = new X_DomEvent( e, this );\r
                        X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length ] = ev;\r
@@ -795,13 +808,20 @@ var X_EventDispatcher_actualHandleEvent =
                                ret = this[ 'dispatch' ]( ev );\r
                        };\r
                        \r
+                       if( X_EventDispatcher_rawEvent === e ) X_EventDispatcher_rawEvent = null;\r
+                       \r
                        --X_EventDispatcher_CURRENT_EVENTS.length;\r
                        \r
+                       if( !X_EventDispatcher_CURRENT_EVENTS.length ) ExecuteAtEnd_onEnd();\r
+                       \r
                        if( ret & X_CALLBACK_STOP_PROPAGATION ){\r
                                e.stopPropagation();\r
                        };\r
                        if( ret & X_CALLBACK_PREVENT_DEFAULT ){\r
-                               this[ '_tag' ] === 'A' && this[ '_rawObject' ].blur();\r
+                               X_EventDispatcher_ignoreActualEvent = true;\r
+                               this[ '_tag' ] === 'A' && elm.blur();\r
+                               X_EventDispatcher_ignoreActualEvent = false;\r
+                               \r
                                e.preventDefault();\r
                                if( X_UA[ 'WebKit' ] < 525.13 ){ // Safari3-\r
                                        if( e.type === 'click' || e.type === 'dbclick' ){\r
index 2c00513..b8c50ff 100644 (file)
@@ -362,6 +362,8 @@ function X_Timer_onTimeout(){
        X_Timer_removal = null;\r
     };\r
     X_Timer_update();\r
+    \r
+    ExecuteAtEnd_onEnd();\r
 };\r
 \r
 function X_Timer_update(){\r
@@ -453,6 +455,8 @@ function X_Timer_onEnterFrame( time ){
        };\r
        X_Timer_removal = null;\r
     };\r
+    \r
+    ExecuteAtEnd_onEnd();\r
 };\r
 \r
 console.log( 'X.Core.Timer' );\r
diff --git a/0.6.x/js/01_core/17_ExecuteAtEnd.js b/0.6.x/js/01_core/17_ExecuteAtEnd.js
new file mode 100644 (file)
index 0000000..624eb9d
--- /dev/null
@@ -0,0 +1,17 @@
+
+var ExecuteAtEnd_CALLBACKS = [];
+
+function ExecuteAtEnd_add( func ){
+       ExecuteAtEnd_CALLBACKS[ ExecuteAtEnd_CALLBACKS.length ] = func;
+};
+
+function ExecuteAtEnd_onEnd(){
+       var i = -1, func;
+       
+       if( !ExecuteAtEnd_CALLBACKS.length ) return;
+       
+       while( func = ExecuteAtEnd_CALLBACKS[ ++i ] ){
+               func();
+       };
+       ExecuteAtEnd_CALLBACKS.length = 0;
+};
diff --git a/0.6.x/js/01_core/18_FocusUtility.js b/0.6.x/js/01_core/18_FocusUtility.js
new file mode 100644 (file)
index 0000000..c986f9c
--- /dev/null
@@ -0,0 +1,53 @@
+
+
+var FocusUtility_lastElmFocused;
+var FocusUtility_docActiveElmSupport = X_UA[ 'IE' ] || document.activeElement !== undefined;
+var FocusUtility_fixActiveElm;
+
+// http://www.codingforums.com/javascript-programming/19503-determining-focus-ns6-ie6-context-sensitive-help.html
+// https://developer.mozilla.org/ja/docs/Web/API/Document/activeElement
+// IE 4+, Chrome 2+, Safari 4+, Firefox 3+ Opera 9.6+
+
+function FocusUtility_getFocusedElement(){
+       return FocusUtility_fixActiveElm ||
+               (
+                       X_Script_gte15 ?
+                               X_Script_try( X_Object_find, [ document, 'activeElement' ] ) :
+                               // ieは iframe 内で focus がない場合に activeElement に触ると エラーになる
+                               // VBS 経由で activeElement に触り安全確認する
+                               ( window[ 'vbs_testAE' ]() && document.activeElement )
+               );
+};
+
+/*
+ * 通常の focus は xnode.call('focus') を使う.
+ * フレームワーク内部で API の実行のために一時的に focus を当てたい場合に使う.focus の復帰は自動で行われる
+ */
+function FocusUtility_setTemporarilyFocus( elm ){
+       var elmActive = FocusUtility_getFocusedElement();
+       
+       if( elmActive !== elm ){
+               X_EventDispatcher_ignoreActualEvent = true; // ignoreAllEvent focus, blur
+               elm.focus();
+               X_EventDispatcher_ignoreActualEvent = false;
+               if( !FocusUtility_lastElmFocused ){
+                       FocusUtility_lastElmFocused = elmActive;
+                       // ie5(IE11のエミュレーション) でしばしば空なんですけど...
+                       elmActive && ExecuteAtEnd_add( FocusUtility_restoreFocus );
+               };
+       };
+};
+
+// こっそり復帰
+function FocusUtility_restoreFocus(){
+       var elmActive = FocusUtility_getFocusedElement(),
+               elm = FocusUtility_lastElmFocused;
+
+       if( elmActive !== elm ){
+               X_EventDispatcher_ignoreActualEvent = true;
+               elm.focus();
+               X_EventDispatcher_ignoreActualEvent = false;
+       };
+       FocusUtility_lastElmFocused = null;
+};
+
index 54a07fe..5c46902 100644 (file)
@@ -1,6 +1,6 @@
 
 var X_ViewPort_readyState,
-       X_ViewPort_active = ( window.parent === window ) || !window.parent, // parent は frameに読み込まれた場合のieのerror回避
+       X_ViewPort_active = ( window.parent === window ) || !window.parent, // parent は frameに読み込まれた場合のieのerror回避   
        X_ViewPort_activeTimerID,
        X_ViewPort_rootElement,
        X_ViewPort_lock,
@@ -35,11 +35,11 @@ X_ViewPort = X_Class_override(
        {
 
                'handleEvent' : function( e ){
-                       var href, i, name, active = false, xnode;
+                       var href, i, name, active = false, elm, xnode;
                        
                        switch( e.type ){
                                case 'beforeunload' :
-                                       // ie では a href='javascript' な要素でも beforeunload が起こる
+                                       // ie では a href='javascript' な要素でも beforeunload が起こる
                                        href = e.target && e.target[ 'attr' ] && e.target[ 'attr' ]( 'href' );
                                        if( X_Type_isString( href ) && !href.toLowerCase().indexOf( 'javascript:' ) ) return X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_STOP_PROPAGATION;
                                        
@@ -74,12 +74,8 @@ X_ViewPort = X_Class_override(
        
                                case 'blur' :
                                case 'focusout' :
-                                       if( ( 5.5 < X_UA[ 'IE' ] && X_UA[ 'IE' ] < 9 )
-                                                ||
-                                                // TODO ie5... activeElement に障るとエラーになるため VBS 経由で activeElement に触り安全確認する(未確認)
-                                                ( 5 <= X_UA[ 'IE' ] && X_UA[ 'IE' ] < 5.5 && !window[ 'vbs_testAE' ]() )
-                                        ){
-                                               xnode = X_Node_getXNode( document.activeElement );
+                                       if( X_UA[ 'IE' ] < 9 && ( elm = FocusUtility_getFocusedElement() ) ){
+                                               xnode = X_Node_getXNode( elm );
                                                if( xnode ){
                                                        xnode[ 'listenOnce' ]( [ 'focus', 'blur' ], X_ViewPort_detectFocusForIE );
                                                        //break;
@@ -111,18 +107,18 @@ X_ViewPort = X_Class_override(
 
 function X_ViewPort_detectFocusForIE( e ){
        //console.log( 'iefix! ' + e.type + ':' + this.attr( 'tag' ) + ' isActive?:' + ( this[ '_rawObject' ] === document.activeElement ) );
-       var elmActive = X_Script_try( X_Object_find, [ document, 'activeElement' ] );
+       var elmActive = FocusUtility_getFocusedElement();
        X_ViewPort_active = e.type === 'focus';
        
        
        if( elmActive && this[ '_rawObject' ] !== elmActive ){
                this[ 'unlisten' ]( X_ViewPort_active ? 'blur' : 'focus', X_ViewPort_detectFocusForIE );
-               console.log( '>>>>>> activeElement 取得 不一致 ' + this._tag );
+               console.log( '>>>>>> activeElement 取得 不一致 ' + this._tag );
        } else
        if( !elmActive ){
-               console.log( '******** activeElement 取得のエラー' );
+               //console.log( '******** activeElement 取得のエラー' );
        } else if( elmActive ){
-               console.log( '>>>>>> activeElement 取得' );
+               //console.log( '>>>>>> activeElement 取得' );
        };
 
        if( X_ViewPort_activeTimerID ){
@@ -370,7 +366,7 @@ X[ 'ViewPort' ] = {
  * http://sssslide.com/www.slideshare.net/hiroakiwakamatsu/ss-12718639
  * 
  * 
- * getBoundingClientRect で fontsize の調査
+ * getBoundingClientRect で fontsize の調査
  */
                var X_ViewPort_resize =
                        // iOS もループで回す,,,iOS3.1.3, iOS6 で確認
@@ -508,7 +504,7 @@ X[ 'ViewPort' ] = {
                        
                                X_ViewPort_vScrollbarSize = w;
                                X_ViewPort_hScrollbarSize = h;
-                               if( h <= 0 ){ // ie6, ie11, firefox で 負の値が返る
+                               if( h <= 0 ){ // ie6, ie11, firefox で 負の値が返る
                                        console.log( 'invalid hScrollbarSize: ' + h );
                                        X_ViewPort_hScrollbarSize = w;
                                };
@@ -538,16 +534,17 @@ X[ 'ViewPort' ] = {
                //ブラウザの戻るボタンで戻ったときに呼ばれるイベントとかキャッシュとかそこらへんのこと
                //http://d.hatena.ne.jp/koumiya/20080916/1221580149
 
-                       if( document[ 'webkitHidden' ] !== undefined ){
-                               X_ViewPort_document[ 'listen' ]( 'webkitvisibilitychange', X_ViewPort );
-                       } else
                        if( document[ 'hidden' ] !== undefined ){// iOS 7+
                                X_ViewPort_document[ 'listen' ]( 'visibilitychange', X_ViewPort );
                        } else
+                       if( document[ 'webkitHidden' ] !== undefined ){
+                               X_ViewPort_document[ 'listen' ]( 'webkitvisibilitychange', X_ViewPort );
+                       } else
                        if( document[ 'msHidden' ] !== undefined ){
                                X_ViewPort_document[ 'listen' ]( 'msvisibilitychange', X_ViewPort );
                        } else
                        if( document[ 'mozHidden' ] !== undefined ){
+                               // TODO Firefox + Android2 でブラウザにフォーカスが戻ったことが判らない...
                                X_ViewPort_document[ 'listen' ]( 'mozvisibilitychange', X_ViewPort );
                        };
                        
@@ -560,11 +557,21 @@ X[ 'ViewPort' ] = {
                                X_ViewPort_document[ 'listen' ]( [ 'focusin', 'focusout' ], X_ViewPort );
                        };
                        
+                       // TODO activeElement が無い対策
+                       if( !FocusUtility_docActiveElmSupport ){
+                               X_ViewPort[ 'listen' ]( 'focus', X_ViewPort_fixActiveElm );
+                       };
+                       
                        X_ViewPort[ 'listen' ]( [ 'focus', 'blur' ] );
 
                        return X_CALLBACK_UN_LISTEN;
                };
 
+               function X_ViewPort_fixActiveElm( e ){
+                       // textNode を修正して elm にする処理は EventDisptcher に入っている
+                       FocusUtility_fixActiveElm = e.target[ '_rawObject' ];
+               };
+
                function X_ViewPort_getWindowSize(){
                        return X_UA[ 'IE' ] ? // Opera10.1 では ズーム時に表示領域のサイズが取れない!
                                [ X_ViewPort_rootElement.clientWidth, X_ViewPort_rootElement.clientHeight ] :
index bb392e3..8ed979d 100644 (file)
@@ -1425,7 +1425,7 @@ function X_Node_startUpdate( time ){
        // 強制的に再描画を起こす, 但し activeElement からフォーカスが外れるため復帰する
        // IE5mode win10 で 確認
        if( X_UA[ 'IE5' ] ){
-               active = document.activeElement;
+               active = FocusUtility_getFocusedElement();
                X_elmBody.style.visibility = 'hidden';
        };
 
@@ -1438,7 +1438,7 @@ function X_Node_startUpdate( time ){
 
        if( X_UA[ 'IE5' ] ){
                X_elmBody.style.visibility = '';
-               active && active.parentNode && active.focus();
+               active && active.parentNode && FocusUtility_setTemporarilyFocus( active );
        };
        
        if( X_Node_updateReservedByReleaseGPU ){
@@ -1530,7 +1530,7 @@ var X_Node__commitUpdate =
                                if( !that[ '_tag' ] ){
                                        that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY;
                                        if( X_UA[ 'IE' ] < 8 ){
-                                               // \n -> \r\n に変換しないと pre タグで開業されない  win10ie7(ie11 emu) で確認
+                                               // \n -> \r\n に変換しないと pre タグで改行されない  win10ie7(ie11 emu) で確認
                                                elm = document.createTextNode( X_String_chrReferanceTo( that[ '_text' ] ).split( '\n' ).join( X_String_CRLF ) );
                                        } else {
                                                elm = document.createTextNode( X_String_chrReferanceTo( that[ '_text' ] ) );
@@ -1811,7 +1811,7 @@ var X_Node__updateRawNode =
                        // textNode
                        if( !that[ '_tag' ] ){
                                if( X_UA[ 'IE' ] < 8 ){
-                                       // \n -> \r\n に変換しないと pre タグで開業されない  win10ie7(ie11 emu) で確認
+                                       // \n -> \r\n に変換しないと pre タグで改行されない  win10ie7(ie11 emu) で確認
                                        elm.data = X_String_chrReferanceTo( that[ '_text' ] ).split( '\n' ).join( X_String_CRLF );
                                } else {
                                        elm.data = X_String_chrReferanceTo( that[ '_text' ] );
index a2fc552..b0712e5 100644 (file)
@@ -18,8 +18,8 @@
  */\r
 \r
 var X_TextRange_range,\r
-       X_TextRange_range2,\r
-       X_TextRange_isW3C = !document.selection || 10 <= X_UA[ 'IE' ];\r
+       X_TextRange_selection,\r
+       X_TextRange_isW3C = !document.selection || 9 <= X_UA[ 'IE' ] || X_UA[ 'Edge' ];\r
 \r
 /**\r
  * ユーザーによって選択されたテキストへの参照や文字の座標の取得\r
@@ -34,25 +34,26 @@ var X_TextRange = X_Class_create(
        \r
        /** @lends X.TextRange.prototype */\r
        {\r
-               xnode      : null,\r
-               createFrom : '',\r
-               v1         : 0,\r
-               v2         : 0,\r
+               'xnode' : null,\r
+               'by'    : '',\r
+               'v1'    : 0,\r
+               'v2'    : 0,\r
                \r
                'Constructor' : function( xnode, arg2, arg3, arg4 ){\r
                        if( !X_TextRange_range ){\r
                                X_TextRange_range = X_TextRange_isW3C ? document.createRange() : X_elmBody.createTextRange();\r
-                               if( !X_TextRange_isW3C ) X_TextRange_range2 = X_elmBody.createTextRange();\r
                        };\r
                        \r
                        this.xnode = xnode;\r
                        \r
                        switch( arg2 ){\r
                                case 'selection' :\r
-                                       //break;\r
+                                       if( !X_TextRange_selection ){\r
+                                               X_TextRange_selection = X_TextRange_isW3C ? window.getSelection() : document.selection.createRange;\r
+                                       };\r
                                case 'point' :\r
                                case 'char' :\r
-                                       this.createFrom = arg2;\r
+                                       this[ 'by' ] = arg2;\r
                                        break;\r
                                default :\r
                                        arg4 = arg3;\r
@@ -60,8 +61,8 @@ var X_TextRange = X_Class_create(
                        };\r
                        \r
                        if( arg2 !== 'selection' ){\r
-                               this.v1 = arg3 || 0;\r
-                               this.v2 = arg4 || 0;\r
+                               this[ 'v1' ] = arg3 || 0;\r
+                               this[ 'v2' ] = arg4 || 0;\r
                        } else {\r
                                this[ 'getOffset' ]();\r
                        };\r
@@ -98,13 +99,15 @@ function X_TextRange_collectTextNodes( elm, ary ){
        };\r
 };\r
 \r
-function X_TextRange_getRawRange( tr, createFrom ){\r
+function X_TextRange_getRawRange( tr ){\r
        var xnode = tr.xnode,\r
                                //\r
-               range = 10 <= X_UA[ 'IE' ] /* || X_UA[ 'iOS' ] */ ? document.createRange() :\r
-                               8 <= X_UA[ 'IE' ] ? X_elmBody.createTextRange() : X_TextRange_range,\r
-               elm, selection, isPoint,\r
-               texts, i, offset, j, l, x, y, rect;\r
+               range = //10 <= X_UA[ 'IE' ] /* || X_UA[ 'iOS' ] */ ? document.createRange() :\r
+                               //8 <= X_UA[ 'IE' ] ? X_elmBody.createTextRange() :\r
+                               X_TextRange_range,\r
+               selection = X_TextRange_selection, \r
+               elm, isPoint,\r
+               texts, i, offset, j, l, x, y, rect, top, btm, left;\r
        \r
        if( xnode[ '_flags' ] & X_NodeFlags_IN_TREE ){\r
                \r
@@ -112,24 +115,24 @@ function X_TextRange_getRawRange( tr, createFrom ){
                \r
                elm = xnode[ '_rawObject' ];\r
                \r
-               switch( createFrom || tr.createFrom ){\r
+               switch( tr[ 'by' ] ){\r
                        case 'selection' :\r
                                if( X_TextRange_isW3C ){\r
-                                       selection = window.getSelection();\r
+                                       //selection = window.getSelection();\r
                                        \r
                            if( selection.getRangeAt ){\r
                                return selection.rangeCount && selection.getRangeAt( 0 );\r
                            };\r
                            // http://d.hatena.ne.jp/dayflower/20080423/1208941641\r
                            // for Safari 1.3\r
-                           range = document.createRange();\r
+                           //range = document.createRange();\r
                            range.setStart( selection.anchorNode, selection.anchorOffset );\r
                            range.setEnd( selection.focusNode, selection.focusOffset );\r
                                        return range;\r
                                } else {\r
                                        switch( document.selection.type ){\r
                                                case 'text' :\r
-                                                       return document.selection.createRange();\r
+                                                       return selection();\r
                                                case 'Control' :\r
                                                        // TODO\r
                                                case 'none' :\r
@@ -138,57 +141,100 @@ function X_TextRange_getRawRange( tr, createFrom ){
                                break;\r
 \r
                        case 'point' :\r
-                               isPoint = true;\r
-                       case 'char' :\r
                                if( X_TextRange_isW3C ){\r
                                        // textarea で異なる\r
+                                       // TextNode をフラットな配列に回収\r
+                                       X_TextRange_collectTextNodes( elm, texts = [] );                                                \r
+                                       \r
+                                       x = tr[ 'v1' ];\r
+                                       y = tr[ 'v2' ];\r
+                                       \r
+                                       for( i = offset = 0; text = texts[ i ]; ++i ){\r
+                                               range.selectNodeContents( text ); // selectNodeContents は TextNode のみ?? Firefox\r
+                                               l = text.data.length;\r
 \r
-                                       if( isPoint ){\r
-                                               // TextNode をフラットな配列に回収\r
-                                               X_TextRange_collectTextNodes( elm, texts = [] );                                                \r
-                                               \r
-                                               for( i = offset = 0; text = texts[ i ]; ++i ){\r
-                                                       range.selectNodeContents( text ); // selectNodeContents は TextNode のみ?? Firefox\r
-                                                       l = text.data.length;\r
-\r
-                                               for( j = 0, x = tr.v1, y = tr.v2; j < l; ++j ){\r
-                                                       if( range ){\r
-                                                           range.setStart( text, j );\r
-                                                           range.setEnd( text, j + 1 );\r
-                                                           rect = range.getBoundingClientRect();\r
-                                                       };\r
-                                                   if( rect.left <= x && x <= rect.right && rect.top <= y && y <= rect.bottom ){\r
-                                                       return {\r
-                                                               'hitRange' : range,\r
-                                                               'rect'     : rect,\r
-                                                               'offset'   : offset,\r
-                                                               'text'     : text\r
-                                                       };\r
-                                                   };\r
-                                               };\r
-                                               offset += l;\r
-                                               };\r
-                                               range = null;\r
-                                       } else {\r
-                                               // 未チェック!\r
-                                               range.setEnd( elm, l < tr.v2 ? l : tr.v2 );\r
-                                   range.setStart( elm, tr.v1 );\r
-                                   return { 'hitRange' : range };\r
+                                       for( j = 0; j < l; ++j ){\r
+                                           if( X_UA[ 'IE' ] || X_UA[ 'Edge' ] ){\r
+                                               // 改行の直前の文字を選択すると rect が巨大になってしまう\r
+                                                       range.setEnd( text, j );\r
+                                                   range.setStart( text, j );\r
+                                                   rect = range.getBoundingClientRect();\r
+                                                   top  = rect.top;\r
+                                                   btm  = rect.bottom;\r
+                                                   left = rect.left;\r
+                                               range.setEnd( text, j + 1 );\r
+                                               rect = range.getBoundingClientRect();\r
+                                               \r
+                                               if( rect.left < left ){\r
+                                                       //console.log( '= ', text.data.charAt( j ), ' x:', x, ' y:', y, ' top:', top | 0, ' left:', left | 0, ' bottom:', btm | 0, ' right:', rect.right | 0 );\r
+                                                           if( left <= x && x <= rect.right && top <= y && y <= btm ){\r
+                                                               return {\r
+                                                                       'hitRange' : range, // TODO startContainer, endContainer\r
+                                                                       'rect'     : rect,\r
+                                                                       'offset'   : offset,\r
+                                                                       'text'     : text // TODO xtext じゃないの?\r
+                                                               };\r
+                                                           };\r
+                                                           continue;\r
+                                               };\r
+                                           } else {\r
+                                                       range.setEnd( text, j + 1 );\r
+                                                   range.setStart( text, j );\r
+                                                   rect = range.getBoundingClientRect();\r
+                                           };\r
+                                           \r
+                                               //console.log( text.data.charAt( j ), ' x:', x, ' y:', y, ' top:', rect.top | 0, ' left:', rect.left | 0, ' bottom:', rect.bottom | 0, ' right:', rect.right | 0 );\r
+                                           if( rect.left <= x && x <= rect.right && rect.top <= y && y <= rect.bottom ){\r
+                                               return {\r
+                                                       'hitRange' : range, // TODO startContainer, endContainer\r
+                                                       'rect'     : rect,\r
+                                                       'offset'   : offset,\r
+                                                       'text'     : text // TODO xtext じゃないの?\r
+                                               };\r
+                                           };\r
+                                       };\r
+                                       offset += l;\r
                                        };\r
+                                       range = null;\r
                                } else {\r
-                                       // !save && ( text = text.split( '\r\n' ).join( '\n' ) ); textarea用\r
-                                       if( isPoint ){\r
-                                               // ie11 の ie10モード で moveToPoint がないといわれる. よって isW3C:false で動作するのは ie9 以下\r
-                                               range.moveToPoint( tr.v1, tr.v2 );\r
-                                               if( !range.duplicate().expand( 'character' ) ) range = null;\r
+                                       // ie11 の ie10モード で moveToPoint がないといわれる. よって isW3C:false で動作するのは ie9 以下\r
+                                       // 行の最後の文字の端をクリックすると次の行の文字が選択されてしまう ie8, ie7\r
+                                       // 選択を移動して補正する https://msdn.microsoft.com/ja-jp/library/ms535872(v=vs.85).aspx\r
+                                       range.moveToPoint( x = tr[ 'v1' ], y = tr[ 'v2' ] );\r
+                                       \r
+                                       // if( range.parentElement() !== elm  || elm.contains( range.parentElement() ) ){\r
+                                       \r
+                                       if( range.expand( 'character' ) ){\r
+                                               left = range.boundingLeft;\r
+                                               top  = range.boundingTop;\r
+                                               if( x < left || left + range.boundingWidth  < x || y < top || top  + range.boundingHeight < y ){\r
+                                                       range.moveStart( 'character', -1 );\r
+                                                       range.moveEnd( 'character', -1 );\r
+                                                       left = range.boundingLeft;\r
+                                                       top  = range.boundingTop;\r
+                                                       if( x < left || left + range.boundingWidth  < x || y < top || top  + range.boundingHeight < y ){\r
+                                                               range = null;\r
+                                                       };\r
+                                               };\r
                                        } else {\r
-                                               range.moveToElementText( elm );\r
-                                               //range.collapse( true );                                               \r
-                                               range.moveEnd( 'character', l < tr.v2 ? l : tr.v2 );\r
-                                               range.moveStart( 'character', tr.v1 );\r
+                                               range = null;\r
                                        };\r
                                };\r
                                return range;\r
+\r
+                       case 'char' :\r
+                               if( X_TextRange_isW3C ){\r
+                                       // 未チェック!\r
+                                       range.setEnd( elm, l < tr[ 'v2' ] ? l : tr[ 'v2' ] );\r
+                           range.setStart( elm, tr[ 'v1' ] );\r
+                           return { 'hitRange' : range };\r
+                               } else {\r
+                                       range.moveToElementText( elm );\r
+                                       //range.collapse( true );                                               \r
+                                       range.moveEnd( 'character', l < tr[ 'v2' ] ? l : tr[ 'v2' ] );\r
+                                       range.moveStart( 'character', tr[ 'v1' ] );\r
+                               };\r
+                               return range;\r
                };\r
        };\r
 };\r
@@ -255,13 +301,13 @@ function X_TextRange_getOffset(){
                                if( X_UA[ 'IE' ] < 12 ){\r
                                        l = elm.value.length;\r
                                        ret = {\r
-                                               'from' : this.v1 = elm.selectionStart < l ? elm.selectionStart : l,\r
-                                               'to'   : this.v2 = elm.selectionEnd   < l ? elm.selectionEnd   : l\r
+                                               'from' : this[ 'v1' ] = elm.selectionStart < l ? elm.selectionStart : l,\r
+                                               'to'   : this[ 'v2' ] = elm.selectionEnd   < l ? elm.selectionEnd   : l\r
                                        };\r
                                } else {\r
                                        ret = {\r
-                                               'from' : this.v1 = elm.selectionStart,\r
-                                               'to'   : this.v2 = elm.selectionEnd\r
+                                               'from' : this[ 'v1' ] = elm.selectionStart,\r
+                                               'to'   : this[ 'v2' ] = elm.selectionEnd\r
                                        };      \r
                                };\r
                        };\r
@@ -272,17 +318,18 @@ function X_TextRange_getOffset(){
                        range = result.hitRange;\r
                        ret = {\r
                                'offset' : result.offset,\r
-                               'from'   : this.v1 = range.startOffset,\r
-                               'to'     : this.v2 = range.endOffset,\r
+                               'from'   : this[ 'v1' ] = range.startOffset,\r
+                               'to'     : this[ 'v2' ] = range.endOffset,\r
                                'text'   : X_Node_getXNode( result.text )\r
                        };\r
                        // range.detach && range.detach();              \r
                } else {\r
                        // http://www.studio-freesky.net/programming/javascript/3/\r
                        \r
-                       range = X_TextRange_range2;\r
+                       range = X_TextRange_range.duplicate();\r
                        range.moveToElementText( xnode[ '_rawObject' ] );\r
                        range.setEndPoint( 'EndToStart', result );\r
+                       //range.text && range.moveEnd( 'character', -1 );\r
                        from  = range.text.length;\r
                        \r
                        X_TextRange_collectXTexts( xnode, xtexts = [] );\r
@@ -298,8 +345,8 @@ function X_TextRange_getOffset(){
 \r
                                ret = {\r
                                        'offset' : n, // elm の何個目の node か?\r
-                                       'from'   : this.v1 = from - n,\r
-                                       'to'     : this.v2 = from - n + result.text.length,\r
+                                       'from'   : this[ 'v1' ] = from - n,\r
+                                       'to'     : this[ 'v2' ] = from - n + result.text.length,\r
                                        'text'   : xtext\r
                                };                              \r
                        };\r
@@ -319,9 +366,9 @@ function X_TextRange_text( v ){
                        elm = xnode[ '_rawObject' ];\r
                        val = X_UA[ 'IE' ] < 9 ? X_Node_Attr_getValueForIE( elm ) : elm.value;\r
                        \r
-                       if( this.createFrom === 'char' ){\r
+                       if( this[ 'by' ] === 'char' ){\r
                                xnode.attr( {\r
-                                       'value' : val.substr( 0, this.v1 ) + v + val.substr( this.v2 )\r
+                                       'value' : val.substr( 0, this[ 'v1' ] ) + v + val.substr( this[ 'v2' ] )\r
                                } );\r
                        } else {\r
                                offset = this[ 'getOffset' ]();\r
@@ -330,7 +377,7 @@ function X_TextRange_text( v ){
                                to     = offset[ 'to' ];\r
 \r
                                if( X_UA[ 'IE' ] < 9 ){\r
-                                       range = document.selection.createRange();\r
+                                       range = X_TextRange_selection();\r
                                        // TODO check textarea\r
                                        range.text = v;\r
                                        // ここには range.text がいない https://msdn.microsoft.com/ja-jp/library/cc427934.aspx\r
@@ -358,18 +405,18 @@ function X_TextRange_move( from, to ){
                len, range;\r
 \r
        if( 0 <= from ){\r
-               this.v1 = from;\r
+               this[ 'v1' ] = from;\r
        } else {\r
-               this.v1 = this.v1 + from;\r
-               this.v1 < 0 && ( this.v1 = 0 );\r
+               this[ 'v1' ] = this[ 'v1' ] + from;\r
+               this[ 'v1' ] < 0 && ( this[ 'v1' ] = 0 );\r
        };\r
 \r
        if( X_Type_isNumber( to ) ){\r
                if( 0 <= to ){\r
-                       this.v2 = to;\r
+                       this[ 'v2' ] = to;\r
                } else {\r
-                       this.v2 = this.v2 + to;\r
-                       this.v2 < this.v1 && ( this.v2 = this.v1 );\r
+                       this[ 'v2' ] = this[ 'v2' ] + to;\r
+                       this[ 'v2' ] < this[ 'v1' ] && ( this[ 'v2' ] = this[ 'v1' ] );\r
                };\r
        };\r
        \r
@@ -380,24 +427,22 @@ function X_TextRange_move( from, to ){
                        len = ( X_UA[ 'IE' ] < 9 ? X_Node_Attr_getValueForIE( elm ) : elm.value ).length;\r
                        \r
                        if( X_UA[ 'Opera' ] ){\r
-                               X_EventDispatcher_ignoreActualEvent = 'focus';\r
-                               elm.focus(); // Operaの為(IEでは無くても大丈夫)\r
-                               X_EventDispatcher_ignoreActualEvent = '';\r
+                               FocusUtility_setTemporarilyFocus( elm );\r
                        };\r
 \r
                        range = elm.createTextRange();\r
 \r
-                       if( this.v1 === this.v2 && this.v1 === 0 ){\r
+                       if( this[ 'v1' ] === this[ 'v2' ] && this[ 'v1' ] === 0 ){\r
                                range.collapse( true ); // 先頭に移動\r
                        } else {\r
-                               if( this.v1 !== this.v2 || this.v1 < len ){\r
+                               if( this[ 'v1' ] !== this[ 'v2' ] || this[ 'v1' ] < len ){\r
                                        range.collapse(); // おまじない?\r
 \r
-                                       if( this.v1 === this.v2 ){\r
-                                               range.move( 'character', this.v1 );\r
+                                       if( this[ 'v1' ] === this[ 'v2' ] ){\r
+                                               range.move( 'character', this[ 'v1' ] );\r
                                        } else {\r
-                                               range.moveEnd( 'character', this.v2 );\r
-                                               range.moveStart( 'character', this.v1 );\r
+                                               range.moveEnd( 'character', this[ 'v2' ] );\r
+                                               range.moveStart( 'character', this[ 'v1' ] );\r
                                        };\r
                                } else {\r
                                        range.collapse( false ); // 末美に移動\r
@@ -406,7 +451,7 @@ function X_TextRange_move( from, to ){
                        range.select();\r
 \r
                } else if( elm.setSelectionRange ){\r
-                       elm.setSelectionRange( this.v1, this.v2 );\r
+                       elm.setSelectionRange( this[ 'v1' ], this[ 'v2' ] );\r
                };\r
        };\r
 };\r
@@ -422,15 +467,13 @@ function X_TextRange_select( v ){
                                        // https://web.archive.org/web/20090904183807/http://www.dedestruct.com/cursorPosition.html\r
                                        function cursorPosition( textarea ){\r
 \r
-                                               var selection_range = document.selection.createRange().duplicate();\r
+                                               var selection_range = X_TextRange_selection().duplicate();\r
                                                \r
 \r
                                                if (selection_range.parentElement() !== textarea) {\r
                                                        // TODO 正しくはカーソル位置・選択範囲の復帰\r
                                                        \r
-                                                       X_EventDispatcher_ignoreActualEvent = 'focus';\r
-                                                       textarea.focus();\r
-                                                       X_EventDispatcher_ignoreActualEvent = '';\r
+                                                       FocusUtility_setTemporarilyFocus( textarea );\r
                                                                \r
                                                        // BODY要素のテキスト範囲を作成する\r
                                                        selection_range = X_elmBody.createTextRange();\r
@@ -523,8 +566,8 @@ function X_TextRange_select( v ){
                                                        var startPoint = untrimmed_before_text.split( '\r' ).join( '' ).length;\r
                                                        // alert(startPoint);\r
                                                        return {\r
-                                                               'from'   : this.v1 = startPoint,\r
-                                                               'to'     : this.v2 = startPoint + untrimmed_selection_text.split( '\r' ).join( '' ).length\r
+                                                               'from'   : this[ 'v1' ] = startPoint,\r
+                                                               'to'     : this[ 'v2' ] = startPoint + untrimmed_selection_text.split( '\r' ).join( '' ).length\r
                                                        };\r
                                                //}\r
                                        }\r
index 9d9646e..88df0ce 100644 (file)
@@ -4,10 +4,6 @@
  *  keydown について。Firefox では押している間中リスナの関数が実行される\r
  *  デフォルトイベントの制御・抑止 (opera)keypress を用いる。\r
  * \r
- * キーイベント処理の工夫\r
- * http://www.keynavi.net/ja/tipsj/kfunc.html\r
- *  keydown/up時にピリオドが文字化け (IE4-6) IE4+では「keypress」でキーコードを処理する 但しCtrlやALTが押されている場合は逆にkeydownで処理する必要があります\r
- * \r
  * \r
  * keydown をトリガーにイベントを発火するもの\r
  *  1. テンキーの 0~9 keyCode:96-105\r
@@ -25,8 +21,8 @@ var X_KB_SPECIALS = eval( // IE5- 対策
                "'33':'PAGE_UP','34':'PAGE_DOWN','35':'END','36':'HOME','37':'CSR_L','38':'CSR_U','39':'CSR_R','40':'CSR_D'," +\r
                "'44':'PRT_SCRN','45':'INS','46':'DEL'," +\r
                "'91':'LWIN','92':'RWIN','93':'APP'," +\r
-               "'96':48,'97':49,'98':50,'99':51,'100':52,'101':53,'102':54,'103':55,'104':56,'105':57,'106':42,'107':43,'109':45," +\r
-               "'111':47,'112':'F1','113':'F2','114':'F3','115':'F4','116':'F5','117':'F6','118':'F7','119':'F8','120':'F9','121':'F10','122':'F11','123':'F12'," +\r
+               "'96':48,'97':49,'98':50,'99':51,'100':52,'101':53,'102':54,'103':55,'104':56,'105':57,'106':42,'107':43,'109':45,'110':46,'111':47," +\r
+               "'112':'F1','113':'F2','114':'F3','115':'F4','116':'F5','117':'F6','118':'F7','119':'F8','120':'F9','121':'F10','122':'F11','123':'F12'," +\r
                "'144':'NUM_LOCK','145':'SCROLL_LOCK','208':'CAPS_LOCK','240':'CAPS_LOCK','242':'K/H','243':'H/Z','244':'H/Z'})" ),\r
        X_KB_DOWN_KEYS   = {},\r
        X_KB_CANCELED    = {},\r
@@ -34,6 +30,8 @@ var X_KB_SPECIALS = eval( // IE5- 対策
        X_KB_lastKeyCode = 0, \r
        X_KB_TRANSFOEM   = {},\r
        \r
+       // TODO keyevent のためには input 等にフォーカスが必要 -> iOS\r
+       \r
        X_kbManager    =\r
                X_Class_override(\r
                        X_EventDispatcher(),\r
@@ -42,14 +40,16 @@ var X_KB_SPECIALS = eval( // IE5- 対策
                                        var keyCode = e.keyCode,  // keyCode says something about the actual keyboard key the user pressed\r
                                                chrCode = e.charCode, // while charCode gives the ASCII value of the resulting character\r
                                                cb      = X_CALLBACK_NONE,\r
-                                               special, _keyCode;\r
+                                               special;\r
                                        \r
-                                       console.log( e.type + ' > keyCode:' + keyCode + ' chrCode:' + chrCode );\r
+                                       // console.log( e.type + ' > keyCode:' + keyCode + ' chrCode:' + chrCode );\r
                                        \r
                                        switch( e.type ){\r
                                                case 'keydown' :\r
                                                        if( X_KB_DOWN_KEYS[ keyCode ] ){\r
                                                                // 既に押されている、メタキー[shift,ctrl,alt]の変化はある?\r
+                                                               console.log( ' doen -- ' );\r
+                                                               \r
                                                                return X_KB_CANCELED[ keyCode ] ? X_CALLBACK_PREVENT_DEFAULT : cb;\r
                                                        } else\r
                                                        if( special = X_KB_SPECIALS[ keyCode ] ){\r
@@ -87,13 +87,32 @@ var X_KB_SPECIALS = eval( // IE5- 対策
                                                                }; */\r
                                                        } else {\r
                                                                X_KB_lastKeyCode = keyCode;\r
-                                                       };      \r
+                                                               \r
+                                                               if( e.ctrlKey || e.altKey || e.metaKey ){\r
+                                                                       cb = this[ 'dispatch' ]( {\r
+                                                                               type      : 'keydown',\r
+                                                                               keyCode   : 0,\r
+                                                                               charCode  : chrCode,\r
+                                                                               'keyName' : '',\r
+                                                                               'is10key' : false,\r
+                                                                               shiftKey  : !!X_KB_DOWN_KEYS[ 16 ],\r
+                                                                               ctrlKey   : !!X_KB_DOWN_KEYS[ 17 ],\r
+                                                                               altKey    : !!X_KB_DOWN_KEYS[ 18 ],\r
+                                                                               metaKey   : !!X_KB_DOWN_KEYS[ 224 ]\r
+                                                                       } );\r
+                                                                       \r
+                                                                       if( cb & X_CALLBACK_PREVENT_DEFAULT ){\r
+                                                                               X_KB_CANCELED[ keyCode ] = true;\r
+                                                                       };\r
+                                                               };\r
+                                                               console.log( ' keydown[' + keyCode + ']' + String.fromCharCode( chrCode ) + chrCode );\r
+                                                       };\r
                                                        return cb;\r
                                                        \r
                                                case 'keypress' :\r
                                                        // keydown 側で発火しているものは再び発火しない\r
-                                                       \r
                                                        if( X_KB_DOWN_KEYS[ chrCode ] ){\r
+                                                               // TODO keypress\r
                                                                return X_KB_CANCELED[ chrCode ] ? X_CALLBACK_PREVENT_DEFAULT : cb;\r
                                                        } else\r
                                                        if( keyCode === 32 ){\r
@@ -117,6 +136,8 @@ var X_KB_SPECIALS = eval( // IE5- 対策
                                                                X_KB_lastIs10Key = false;\r
                                                                \r
                                                                console.log( X_KB_lastKeyCode + 'keypress : chrCode:' + chrCode + ' down:' + X_KB_DOWN_KEYS[ chrCode ] + ( X_KB_CANCELED[ chrCode ] ? ' Cancel!' : '' ) );\r
+                                                       } else {\r
+                                                               console.log( '>> keypress : chrCode:' + chrCode + ' down:' + X_KB_DOWN_KEYS[ chrCode ] + ( X_KB_CANCELED[ chrCode ] ? ' Cancel!' : '' ) );\r
                                                        };\r
                                                        return cb;\r
                                                        \r
@@ -156,7 +177,7 @@ var X_KB_SPECIALS = eval( // IE5- 対策
                                                                chrCode = 0;\r
                                                        };\r
                                                        \r
-                                                       console.log( keyCode + ' keyup ' + chrCode );\r
+                                                       //console.log( keyCode + ' keyup ' + chrCode );\r
                                                        \r
                                                        cb |= this[ 'dispatch' ]( {\r
                                                                type      : 'keyup',\r
index 014ed63..4c1163c 100644 (file)
@@ -24,6 +24,8 @@ document.write( [
                'js/01_core/14_XEvent.js',\r
                'js/01_core/15_XEventDispatcher.js',\r
                'js/01_core/16_XTimer.js',\r
+               'js/01_core/17_ExecuteAtEnd.js',\r
+               'js/01_core/18_FocusUtility.js',\r
 \r
                'js/01_core/20_XSystem.js',\r
                'js/01_core/21_XViewPort.js',   \r