• R/O
  • HTTP
  • SSH
  • HTTPS

clientJs: コミット

クライアント側 js 開発用


コミットメタ情報

リビジョン604668ba9efa027d4bc77fd8020d6b6be55d03e1 (tree)
日時2016-11-28 14:21:24
作者itozyun <itozyun@user...>
コミッターitozyun

ログメッセージ

Version 0.6.222, Fix the bug of X.TextRange.
add ExecuteAtEnd and FocusUtility.

変更サマリ

差分

--- a/0.6.x/js/01_core/14_XEvent.js
+++ b/0.6.x/js/01_core/14_XEvent.js
@@ -3,6 +3,8 @@ var X_Event_Rename = {},
33 X_Event_RenameTo = {},
44
55 // TODO IFRAMEload, SCRIPTload, LINKload raw.readyState !== 'complete' && raw.readyState !== 'loaded' && this.dispatch( 'load' )
6+
7+
68 X_Event_proxy = {
79
810 'IFRAMEload' : function( eventDispatcher ){
@@ -13,9 +15,11 @@ var X_Event_Rename = {},
1315 var raw = this[ '_rawObject' ];
1416
1517 return ( raw.readyState === 'complete' || raw.readyState === 'loaded' ) ?
16- this[ 'dispatch' ]( 'load' ) : X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_STOP_PROPAGATION;
18+ X_EventDispatcher_actualHandleEvent( 'load' ) : X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_STOP_PROPAGATION;
1719 },
1820
21+ // TODO focusin focusout
22+
1923 // X_UA[ 'Opera' ]
2024 'contextmenu' : function( eventDispatcher ){
2125 eventDispatcher[ 'listen' ]( 'mousedown', contextmenu_proxy );
--- a/0.6.x/js/01_core/15_XEventDispatcher.js
+++ b/0.6.x/js/01_core/15_XEventDispatcher.js
@@ -734,7 +734,8 @@ function X_EventDispatcher_actualRemoveEvent( that, type, raw, list, skip ){
734734
735735 // TODO ブラウザからの呼び出しの最後に登録された関数を呼び出す機能(例えば画面の更新)
736736 var X_EventDispatcher_CURRENT_EVENTS = [];
737-var X_EventDispatcher_ignoreActualEvent = '';
737+var X_EventDispatcher_ignoreActualEvent;
738+var X_EventDispatcher_rawEvent;
738739
739740 // handleEvent を拡張可能にするために、クロージャに移動した
740741 // Is this in regard to the Safari 1.x preventDefault bug on click/dblclick?
@@ -746,36 +747,48 @@ var X_EventDispatcher_actualHandleEvent =
746747 elm = this[ '_rawObject' ],
747748 ev, ret;
748749
749- /* if( e.type === X_EventDispatcher_ignoreActualEvent ){
750+ if( X_EventDispatcher_ignoreActualEvent ){
750751 e.cancelBubble = true;
751752 return;
752- }; */
753+ };
753754
754- ev = new X_DomEvent( e, this, elm );
755+ X_EventDispatcher_rawEvent = e;
755756
757+ ev = new X_DomEvent( e, this, elm );
758+
756759 X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length ] = ev;
757760
758761 ret = this[ 'dispatch' ]( ev );
759762
763+ if( X_EventDispatcher_rawEvent === e ) X_EventDispatcher_rawEvent = null;
764+
760765 --X_EventDispatcher_CURRENT_EVENTS.length;
761766
762767 if( ret & X_CALLBACK_STOP_PROPAGATION ){
763768 e.cancelBubble = true;
764769 };
770+
771+ if( !X_EventDispatcher_CURRENT_EVENTS.length ) ExecuteAtEnd_onEnd();
772+
765773 if( ret & X_CALLBACK_PREVENT_DEFAULT ){
766- this[ '_tag' ] === 'A' && elm.blur();
774+ X_EventDispatcher_ignoreActualEvent = true;
775+ this[ '_tag' ] === 'A' && elm.blur(); // おかしくない??
776+ X_EventDispatcher_ignoreActualEvent = false;
767777 return e.returnValue = false;
768778 };
769779 }) :
770780 //X_UA_EVENT.W3C || X_UA_EVENT.DOM0
771781 (function( e ){
772782 var ret = X_CALLBACK_NONE,
783+ elm = this[ '_rawObject' ],
773784 ev, i, l;
774785
775- /* if( e.type === X_EventDispatcher_ignoreActualEvent ){
786+ if( X_EventDispatcher_ignoreActualEvent ){
776787 e.stopPropagation();
777788 return;
778- }; */
789+ };
790+
791+ X_EventDispatcher_rawEvent = e;
779792
780793 ev = new X_DomEvent( e, this );
781794 X_EventDispatcher_CURRENT_EVENTS[ X_EventDispatcher_CURRENT_EVENTS.length ] = ev;
@@ -795,13 +808,20 @@ var X_EventDispatcher_actualHandleEvent =
795808 ret = this[ 'dispatch' ]( ev );
796809 };
797810
811+ if( X_EventDispatcher_rawEvent === e ) X_EventDispatcher_rawEvent = null;
812+
798813 --X_EventDispatcher_CURRENT_EVENTS.length;
799814
815+ if( !X_EventDispatcher_CURRENT_EVENTS.length ) ExecuteAtEnd_onEnd();
816+
800817 if( ret & X_CALLBACK_STOP_PROPAGATION ){
801818 e.stopPropagation();
802819 };
803820 if( ret & X_CALLBACK_PREVENT_DEFAULT ){
804- this[ '_tag' ] === 'A' && this[ '_rawObject' ].blur();
821+ X_EventDispatcher_ignoreActualEvent = true;
822+ this[ '_tag' ] === 'A' && elm.blur();
823+ X_EventDispatcher_ignoreActualEvent = false;
824+
805825 e.preventDefault();
806826 if( X_UA[ 'WebKit' ] < 525.13 ){ // Safari3-
807827 if( e.type === 'click' || e.type === 'dbclick' ){
--- a/0.6.x/js/01_core/16_XTimer.js
+++ b/0.6.x/js/01_core/16_XTimer.js
@@ -362,6 +362,8 @@ function X_Timer_onTimeout(){
362362 X_Timer_removal = null;
363363 };
364364 X_Timer_update();
365+
366+ ExecuteAtEnd_onEnd();
365367 };
366368
367369 function X_Timer_update(){
@@ -453,6 +455,8 @@ function X_Timer_onEnterFrame( time ){
453455 };
454456 X_Timer_removal = null;
455457 };
458+
459+ ExecuteAtEnd_onEnd();
456460 };
457461
458462 console.log( 'X.Core.Timer' );
--- /dev/null
+++ b/0.6.x/js/01_core/17_ExecuteAtEnd.js
@@ -0,0 +1,17 @@
1+
2+var ExecuteAtEnd_CALLBACKS = [];
3+
4+function ExecuteAtEnd_add( func ){
5+ ExecuteAtEnd_CALLBACKS[ ExecuteAtEnd_CALLBACKS.length ] = func;
6+};
7+
8+function ExecuteAtEnd_onEnd(){
9+ var i = -1, func;
10+
11+ if( !ExecuteAtEnd_CALLBACKS.length ) return;
12+
13+ while( func = ExecuteAtEnd_CALLBACKS[ ++i ] ){
14+ func();
15+ };
16+ ExecuteAtEnd_CALLBACKS.length = 0;
17+};
--- /dev/null
+++ b/0.6.x/js/01_core/18_FocusUtility.js
@@ -0,0 +1,53 @@
1+
2+
3+var FocusUtility_lastElmFocused;
4+var FocusUtility_docActiveElmSupport = X_UA[ 'IE' ] || document.activeElement !== undefined;
5+var FocusUtility_fixActiveElm;
6+
7+// http://www.codingforums.com/javascript-programming/19503-determining-focus-ns6-ie6-context-sensitive-help.html
8+// https://developer.mozilla.org/ja/docs/Web/API/Document/activeElement
9+// IE 4+, Chrome 2+, Safari 4+, Firefox 3+ Opera 9.6+
10+
11+function FocusUtility_getFocusedElement(){
12+ return FocusUtility_fixActiveElm ||
13+ (
14+ X_Script_gte15 ?
15+ X_Script_try( X_Object_find, [ document, 'activeElement' ] ) :
16+ // ieは iframe 内で focus がない場合に activeElement に触ると エラーになる
17+ // VBS 経由で activeElement に触り安全確認する
18+ ( window[ 'vbs_testAE' ]() && document.activeElement )
19+ );
20+};
21+
22+/*
23+ * 通常の focus は xnode.call('focus') を使う.
24+ * フレームワーク内部で API の実行のために一時的に focus を当てたい場合に使う.focus の復帰は自動で行われる
25+ */
26+function FocusUtility_setTemporarilyFocus( elm ){
27+ var elmActive = FocusUtility_getFocusedElement();
28+
29+ if( elmActive !== elm ){
30+ X_EventDispatcher_ignoreActualEvent = true; // ignoreAllEvent focus, blur
31+ elm.focus();
32+ X_EventDispatcher_ignoreActualEvent = false;
33+ if( !FocusUtility_lastElmFocused ){
34+ FocusUtility_lastElmFocused = elmActive;
35+ // ie5(IE11のエミュレーション) でしばしば空なんですけど...
36+ elmActive && ExecuteAtEnd_add( FocusUtility_restoreFocus );
37+ };
38+ };
39+};
40+
41+// こっそり復帰
42+function FocusUtility_restoreFocus(){
43+ var elmActive = FocusUtility_getFocusedElement(),
44+ elm = FocusUtility_lastElmFocused;
45+
46+ if( elmActive !== elm ){
47+ X_EventDispatcher_ignoreActualEvent = true;
48+ elm.focus();
49+ X_EventDispatcher_ignoreActualEvent = false;
50+ };
51+ FocusUtility_lastElmFocused = null;
52+};
53+
--- a/0.6.x/js/01_core/21_XViewPort.js
+++ b/0.6.x/js/01_core/21_XViewPort.js
@@ -1,6 +1,6 @@
11
22 var X_ViewPort_readyState,
3- X_ViewPort_active = ( window.parent === window ) || !window.parent, // parent は frameに読み込まれた場合のieのerror回避
3+ X_ViewPort_active = ( window.parent === window ) || !window.parent, // parent は frameに読み込まれた場合のieのerror回避
44 X_ViewPort_activeTimerID,
55 X_ViewPort_rootElement,
66 X_ViewPort_lock,
@@ -35,11 +35,11 @@ X_ViewPort = X_Class_override(
3535 {
3636
3737 'handleEvent' : function( e ){
38- var href, i, name, active = false, xnode;
38+ var href, i, name, active = false, elm, xnode;
3939
4040 switch( e.type ){
4141 case 'beforeunload' :
42- // ie では a href='javascript' な要素でも beforeunload が起こる
42+ // ie では a href='javascript' な要素でも beforeunload が起こる
4343 href = e.target && e.target[ 'attr' ] && e.target[ 'attr' ]( 'href' );
4444 if( X_Type_isString( href ) && !href.toLowerCase().indexOf( 'javascript:' ) ) return X_CALLBACK_PREVENT_DEFAULT | X_CALLBACK_STOP_PROPAGATION;
4545
@@ -74,12 +74,8 @@ X_ViewPort = X_Class_override(
7474
7575 case 'blur' :
7676 case 'focusout' :
77- if( ( 5.5 < X_UA[ 'IE' ] && X_UA[ 'IE' ] < 9 )
78- ||
79- // TODO ie5... activeElement に障るとエラーになるため VBS 経由で activeElement に触り安全確認する(未確認)
80- ( 5 <= X_UA[ 'IE' ] && X_UA[ 'IE' ] < 5.5 && !window[ 'vbs_testAE' ]() )
81- ){
82- xnode = X_Node_getXNode( document.activeElement );
77+ if( X_UA[ 'IE' ] < 9 && ( elm = FocusUtility_getFocusedElement() ) ){
78+ xnode = X_Node_getXNode( elm );
8379 if( xnode ){
8480 xnode[ 'listenOnce' ]( [ 'focus', 'blur' ], X_ViewPort_detectFocusForIE );
8581 //break;
@@ -111,18 +107,18 @@ X_ViewPort = X_Class_override(
111107
112108 function X_ViewPort_detectFocusForIE( e ){
113109 //console.log( 'iefix! ' + e.type + ':' + this.attr( 'tag' ) + ' isActive?:' + ( this[ '_rawObject' ] === document.activeElement ) );
114- var elmActive = X_Script_try( X_Object_find, [ document, 'activeElement' ] );
110+ var elmActive = FocusUtility_getFocusedElement();
115111 X_ViewPort_active = e.type === 'focus';
116112
117113
118114 if( elmActive && this[ '_rawObject' ] !== elmActive ){
119115 this[ 'unlisten' ]( X_ViewPort_active ? 'blur' : 'focus', X_ViewPort_detectFocusForIE );
120- console.log( '>>>>>> activeElement 取得 不一致 ' + this._tag );
116+ console.log( '>>>>>> activeElement 取得 不一致 ' + this._tag );
121117 } else
122118 if( !elmActive ){
123- console.log( '******** activeElement 取得のエラー' );
119+ //console.log( '******** activeElement 取得のエラー' );
124120 } else if( elmActive ){
125- console.log( '>>>>>> activeElement 取得' );
121+ //console.log( '>>>>>> activeElement 取得' );
126122 };
127123
128124 if( X_ViewPort_activeTimerID ){
@@ -370,7 +366,7 @@ X[ 'ViewPort' ] = {
370366 * http://sssslide.com/www.slideshare.net/hiroakiwakamatsu/ss-12718639
371367 *
372368 *
373- * getBoundingClientRect で fontsize の調査
369+ * getBoundingClientRect で fontsize の調査
374370 */
375371 var X_ViewPort_resize =
376372 // iOS もループで回す,,,iOS3.1.3, iOS6 で確認
@@ -508,7 +504,7 @@ X[ 'ViewPort' ] = {
508504
509505 X_ViewPort_vScrollbarSize = w;
510506 X_ViewPort_hScrollbarSize = h;
511- if( h <= 0 ){ // ie6, ie11, firefox で 負の値が返る
507+ if( h <= 0 ){ // ie6, ie11, firefox で 負の値が返る
512508 console.log( 'invalid hScrollbarSize: ' + h );
513509 X_ViewPort_hScrollbarSize = w;
514510 };
@@ -538,16 +534,17 @@ X[ 'ViewPort' ] = {
538534 //ブラウザの戻るボタンで戻ったときに呼ばれるイベントとかキャッシュとかそこらへんのこと
539535 //http://d.hatena.ne.jp/koumiya/20080916/1221580149
540536
541- if( document[ 'webkitHidden' ] !== undefined ){
542- X_ViewPort_document[ 'listen' ]( 'webkitvisibilitychange', X_ViewPort );
543- } else
544537 if( document[ 'hidden' ] !== undefined ){// iOS 7+
545538 X_ViewPort_document[ 'listen' ]( 'visibilitychange', X_ViewPort );
546539 } else
540+ if( document[ 'webkitHidden' ] !== undefined ){
541+ X_ViewPort_document[ 'listen' ]( 'webkitvisibilitychange', X_ViewPort );
542+ } else
547543 if( document[ 'msHidden' ] !== undefined ){
548544 X_ViewPort_document[ 'listen' ]( 'msvisibilitychange', X_ViewPort );
549545 } else
550546 if( document[ 'mozHidden' ] !== undefined ){
547+ // TODO Firefox + Android2 でブラウザにフォーカスが戻ったことが判らない...
551548 X_ViewPort_document[ 'listen' ]( 'mozvisibilitychange', X_ViewPort );
552549 };
553550
@@ -560,11 +557,21 @@ X[ 'ViewPort' ] = {
560557 X_ViewPort_document[ 'listen' ]( [ 'focusin', 'focusout' ], X_ViewPort );
561558 };
562559
560+ // TODO activeElement が無い対策
561+ if( !FocusUtility_docActiveElmSupport ){
562+ X_ViewPort[ 'listen' ]( 'focus', X_ViewPort_fixActiveElm );
563+ };
564+
563565 X_ViewPort[ 'listen' ]( [ 'focus', 'blur' ] );
564566
565567 return X_CALLBACK_UN_LISTEN;
566568 };
567569
570+ function X_ViewPort_fixActiveElm( e ){
571+ // textNode を修正して elm にする処理は EventDisptcher に入っている
572+ FocusUtility_fixActiveElm = e.target[ '_rawObject' ];
573+ };
574+
568575 function X_ViewPort_getWindowSize(){
569576 return X_UA[ 'IE' ] ? // Opera10.1 では ズーム時に表示領域のサイズが取れない!
570577 [ X_ViewPort_rootElement.clientWidth, X_ViewPort_rootElement.clientHeight ] :
--- a/0.6.x/js/02_dom/20_XNode.js
+++ b/0.6.x/js/02_dom/20_XNode.js
@@ -1425,7 +1425,7 @@ function X_Node_startUpdate( time ){
14251425 // 強制的に再描画を起こす, 但し activeElement からフォーカスが外れるため復帰する
14261426 // IE5mode win10 で 確認
14271427 if( X_UA[ 'IE5' ] ){
1428- active = document.activeElement;
1428+ active = FocusUtility_getFocusedElement();
14291429 X_elmBody.style.visibility = 'hidden';
14301430 };
14311431
@@ -1438,7 +1438,7 @@ function X_Node_startUpdate( time ){
14381438
14391439 if( X_UA[ 'IE5' ] ){
14401440 X_elmBody.style.visibility = '';
1441- active && active.parentNode && active.focus();
1441+ active && active.parentNode && FocusUtility_setTemporarilyFocus( active );
14421442 };
14431443
14441444 if( X_Node_updateReservedByReleaseGPU ){
@@ -1530,7 +1530,7 @@ var X_Node__commitUpdate =
15301530 if( !that[ '_tag' ] ){
15311531 that[ '_flags' ] &= X_Node_BitMask_RESET_DIRTY;
15321532 if( X_UA[ 'IE' ] < 8 ){
1533- // \n -> \r\n に変換しないと pre タグで開業されない win10ie7(ie11 emu) で確認
1533+ // \n -> \r\n に変換しないと pre タグで改行されない win10ie7(ie11 emu) で確認
15341534 elm = document.createTextNode( X_String_chrReferanceTo( that[ '_text' ] ).split( '\n' ).join( X_String_CRLF ) );
15351535 } else {
15361536 elm = document.createTextNode( X_String_chrReferanceTo( that[ '_text' ] ) );
@@ -1811,7 +1811,7 @@ var X_Node__updateRawNode =
18111811 // textNode
18121812 if( !that[ '_tag' ] ){
18131813 if( X_UA[ 'IE' ] < 8 ){
1814- // \n -> \r\n に変換しないと pre タグで開業されない win10ie7(ie11 emu) で確認
1814+ // \n -> \r\n に変換しないと pre タグで改行されない win10ie7(ie11 emu) で確認
18151815 elm.data = X_String_chrReferanceTo( that[ '_text' ] ).split( '\n' ).join( X_String_CRLF );
18161816 } else {
18171817 elm.data = X_String_chrReferanceTo( that[ '_text' ] );
--- a/0.6.x/js/02_dom/30_XTextRange.js
+++ b/0.6.x/js/02_dom/30_XTextRange.js
@@ -18,8 +18,8 @@
1818 */
1919
2020 var X_TextRange_range,
21- X_TextRange_range2,
22- X_TextRange_isW3C = !document.selection || 10 <= X_UA[ 'IE' ];
21+ X_TextRange_selection,
22+ X_TextRange_isW3C = !document.selection || 9 <= X_UA[ 'IE' ] || X_UA[ 'Edge' ];
2323
2424 /**
2525 * ユーザーによって選択されたテキストへの参照や文字の座標の取得
@@ -34,25 +34,26 @@ var X_TextRange = X_Class_create(
3434
3535 /** @lends X.TextRange.prototype */
3636 {
37- xnode : null,
38- createFrom : '',
39- v1 : 0,
40- v2 : 0,
37+ 'xnode' : null,
38+ 'by' : '',
39+ 'v1' : 0,
40+ 'v2' : 0,
4141
4242 'Constructor' : function( xnode, arg2, arg3, arg4 ){
4343 if( !X_TextRange_range ){
4444 X_TextRange_range = X_TextRange_isW3C ? document.createRange() : X_elmBody.createTextRange();
45- if( !X_TextRange_isW3C ) X_TextRange_range2 = X_elmBody.createTextRange();
4645 };
4746
4847 this.xnode = xnode;
4948
5049 switch( arg2 ){
5150 case 'selection' :
52- //break;
51+ if( !X_TextRange_selection ){
52+ X_TextRange_selection = X_TextRange_isW3C ? window.getSelection() : document.selection.createRange;
53+ };
5354 case 'point' :
5455 case 'char' :
55- this.createFrom = arg2;
56+ this[ 'by' ] = arg2;
5657 break;
5758 default :
5859 arg4 = arg3;
@@ -60,8 +61,8 @@ var X_TextRange = X_Class_create(
6061 };
6162
6263 if( arg2 !== 'selection' ){
63- this.v1 = arg3 || 0;
64- this.v2 = arg4 || 0;
64+ this[ 'v1' ] = arg3 || 0;
65+ this[ 'v2' ] = arg4 || 0;
6566 } else {
6667 this[ 'getOffset' ]();
6768 };
@@ -98,13 +99,15 @@ function X_TextRange_collectTextNodes( elm, ary ){
9899 };
99100 };
100101
101-function X_TextRange_getRawRange( tr, createFrom ){
102+function X_TextRange_getRawRange( tr ){
102103 var xnode = tr.xnode,
103104 //
104- range = 10 <= X_UA[ 'IE' ] /* || X_UA[ 'iOS' ] */ ? document.createRange() :
105- 8 <= X_UA[ 'IE' ] ? X_elmBody.createTextRange() : X_TextRange_range,
106- elm, selection, isPoint,
107- texts, i, offset, j, l, x, y, rect;
105+ range = //10 <= X_UA[ 'IE' ] /* || X_UA[ 'iOS' ] */ ? document.createRange() :
106+ //8 <= X_UA[ 'IE' ] ? X_elmBody.createTextRange() :
107+ X_TextRange_range,
108+ selection = X_TextRange_selection,
109+ elm, isPoint,
110+ texts, i, offset, j, l, x, y, rect, top, btm, left;
108111
109112 if( xnode[ '_flags' ] & X_NodeFlags_IN_TREE ){
110113
@@ -112,24 +115,24 @@ function X_TextRange_getRawRange( tr, createFrom ){
112115
113116 elm = xnode[ '_rawObject' ];
114117
115- switch( createFrom || tr.createFrom ){
118+ switch( tr[ 'by' ] ){
116119 case 'selection' :
117120 if( X_TextRange_isW3C ){
118- selection = window.getSelection();
121+ //selection = window.getSelection();
119122
120123 if( selection.getRangeAt ){
121124 return selection.rangeCount && selection.getRangeAt( 0 );
122125 };
123126 // http://d.hatena.ne.jp/dayflower/20080423/1208941641
124127 // for Safari 1.3
125- range = document.createRange();
128+ //range = document.createRange();
126129 range.setStart( selection.anchorNode, selection.anchorOffset );
127130 range.setEnd( selection.focusNode, selection.focusOffset );
128131 return range;
129132 } else {
130133 switch( document.selection.type ){
131134 case 'text' :
132- return document.selection.createRange();
135+ return selection();
133136 case 'Control' :
134137 // TODO
135138 case 'none' :
@@ -138,57 +141,100 @@ function X_TextRange_getRawRange( tr, createFrom ){
138141 break;
139142
140143 case 'point' :
141- isPoint = true;
142- case 'char' :
143144 if( X_TextRange_isW3C ){
144145 // textarea で異なる
146+ // TextNode をフラットな配列に回収
147+ X_TextRange_collectTextNodes( elm, texts = [] );
148+
149+ x = tr[ 'v1' ];
150+ y = tr[ 'v2' ];
151+
152+ for( i = offset = 0; text = texts[ i ]; ++i ){
153+ range.selectNodeContents( text ); // selectNodeContents は TextNode のみ?? Firefox
154+ l = text.data.length;
145155
146- if( isPoint ){
147- // TextNode をフラットな配列に回収
148- X_TextRange_collectTextNodes( elm, texts = [] );
149-
150- for( i = offset = 0; text = texts[ i ]; ++i ){
151- range.selectNodeContents( text ); // selectNodeContents は TextNode のみ?? Firefox
152- l = text.data.length;
153-
154- for( j = 0, x = tr.v1, y = tr.v2; j < l; ++j ){
155- if( range ){
156- range.setStart( text, j );
157- range.setEnd( text, j + 1 );
158- rect = range.getBoundingClientRect();
159- };
160- if( rect.left <= x && x <= rect.right && rect.top <= y && y <= rect.bottom ){
161- return {
162- 'hitRange' : range,
163- 'rect' : rect,
164- 'offset' : offset,
165- 'text' : text
166- };
167- };
168- };
169- offset += l;
170- };
171- range = null;
172- } else {
173- // 未チェック!
174- range.setEnd( elm, l < tr.v2 ? l : tr.v2 );
175- range.setStart( elm, tr.v1 );
176- return { 'hitRange' : range };
156+ for( j = 0; j < l; ++j ){
157+ if( X_UA[ 'IE' ] || X_UA[ 'Edge' ] ){
158+ // 改行の直前の文字を選択すると rect が巨大になってしまう
159+ range.setEnd( text, j );
160+ range.setStart( text, j );
161+ rect = range.getBoundingClientRect();
162+ top = rect.top;
163+ btm = rect.bottom;
164+ left = rect.left;
165+ range.setEnd( text, j + 1 );
166+ rect = range.getBoundingClientRect();
167+
168+ if( rect.left < left ){
169+ //console.log( '= ', text.data.charAt( j ), ' x:', x, ' y:', y, ' top:', top | 0, ' left:', left | 0, ' bottom:', btm | 0, ' right:', rect.right | 0 );
170+ if( left <= x && x <= rect.right && top <= y && y <= btm ){
171+ return {
172+ 'hitRange' : range, // TODO startContainer, endContainer
173+ 'rect' : rect,
174+ 'offset' : offset,
175+ 'text' : text // TODO xtext じゃないの?
176+ };
177+ };
178+ continue;
179+ };
180+ } else {
181+ range.setEnd( text, j + 1 );
182+ range.setStart( text, j );
183+ rect = range.getBoundingClientRect();
184+ };
185+
186+ //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 );
187+ if( rect.left <= x && x <= rect.right && rect.top <= y && y <= rect.bottom ){
188+ return {
189+ 'hitRange' : range, // TODO startContainer, endContainer
190+ 'rect' : rect,
191+ 'offset' : offset,
192+ 'text' : text // TODO xtext じゃないの?
193+ };
194+ };
195+ };
196+ offset += l;
177197 };
198+ range = null;
178199 } else {
179- // !save && ( text = text.split( '\r\n' ).join( '\n' ) ); textarea用
180- if( isPoint ){
181- // ie11 の ie10モード で moveToPoint がないといわれる. よって isW3C:false で動作するのは ie9 以下
182- range.moveToPoint( tr.v1, tr.v2 );
183- if( !range.duplicate().expand( 'character' ) ) range = null;
200+ // ie11 の ie10モード で moveToPoint がないといわれる. よって isW3C:false で動作するのは ie9 以下
201+ // 行の最後の文字の端をクリックすると次の行の文字が選択されてしまう ie8, ie7
202+ // 選択を移動して補正する https://msdn.microsoft.com/ja-jp/library/ms535872(v=vs.85).aspx
203+ range.moveToPoint( x = tr[ 'v1' ], y = tr[ 'v2' ] );
204+
205+ // if( range.parentElement() !== elm  || elm.contains( range.parentElement() ) ){
206+
207+ if( range.expand( 'character' ) ){
208+ left = range.boundingLeft;
209+ top = range.boundingTop;
210+ if( x < left || left + range.boundingWidth < x || y < top || top + range.boundingHeight < y ){
211+ range.moveStart( 'character', -1 );
212+ range.moveEnd( 'character', -1 );
213+ left = range.boundingLeft;
214+ top = range.boundingTop;
215+ if( x < left || left + range.boundingWidth < x || y < top || top + range.boundingHeight < y ){
216+ range = null;
217+ };
218+ };
184219 } else {
185- range.moveToElementText( elm );
186- //range.collapse( true );
187- range.moveEnd( 'character', l < tr.v2 ? l : tr.v2 );
188- range.moveStart( 'character', tr.v1 );
220+ range = null;
189221 };
190222 };
191223 return range;
224+
225+ case 'char' :
226+ if( X_TextRange_isW3C ){
227+ // 未チェック!
228+ range.setEnd( elm, l < tr[ 'v2' ] ? l : tr[ 'v2' ] );
229+ range.setStart( elm, tr[ 'v1' ] );
230+ return { 'hitRange' : range };
231+ } else {
232+ range.moveToElementText( elm );
233+ //range.collapse( true );
234+ range.moveEnd( 'character', l < tr[ 'v2' ] ? l : tr[ 'v2' ] );
235+ range.moveStart( 'character', tr[ 'v1' ] );
236+ };
237+ return range;
192238 };
193239 };
194240 };
@@ -255,13 +301,13 @@ function X_TextRange_getOffset(){
255301 if( X_UA[ 'IE' ] < 12 ){
256302 l = elm.value.length;
257303 ret = {
258- 'from' : this.v1 = elm.selectionStart < l ? elm.selectionStart : l,
259- 'to' : this.v2 = elm.selectionEnd < l ? elm.selectionEnd : l
304+ 'from' : this[ 'v1' ] = elm.selectionStart < l ? elm.selectionStart : l,
305+ 'to' : this[ 'v2' ] = elm.selectionEnd < l ? elm.selectionEnd : l
260306 };
261307 } else {
262308 ret = {
263- 'from' : this.v1 = elm.selectionStart,
264- 'to' : this.v2 = elm.selectionEnd
309+ 'from' : this[ 'v1' ] = elm.selectionStart,
310+ 'to' : this[ 'v2' ] = elm.selectionEnd
265311 };
266312 };
267313 };
@@ -272,17 +318,18 @@ function X_TextRange_getOffset(){
272318 range = result.hitRange;
273319 ret = {
274320 'offset' : result.offset,
275- 'from' : this.v1 = range.startOffset,
276- 'to' : this.v2 = range.endOffset,
321+ 'from' : this[ 'v1' ] = range.startOffset,
322+ 'to' : this[ 'v2' ] = range.endOffset,
277323 'text' : X_Node_getXNode( result.text )
278324 };
279325 // range.detach && range.detach();
280326 } else {
281327 // http://www.studio-freesky.net/programming/javascript/3/
282328
283- range = X_TextRange_range2;
329+ range = X_TextRange_range.duplicate();
284330 range.moveToElementText( xnode[ '_rawObject' ] );
285331 range.setEndPoint( 'EndToStart', result );
332+ //range.text && range.moveEnd( 'character', -1 );
286333 from = range.text.length;
287334
288335 X_TextRange_collectXTexts( xnode, xtexts = [] );
@@ -298,8 +345,8 @@ function X_TextRange_getOffset(){
298345
299346 ret = {
300347 'offset' : n, // elm の何個目の node か?
301- 'from' : this.v1 = from - n,
302- 'to' : this.v2 = from - n + result.text.length,
348+ 'from' : this[ 'v1' ] = from - n,
349+ 'to' : this[ 'v2' ] = from - n + result.text.length,
303350 'text' : xtext
304351 };
305352 };
@@ -319,9 +366,9 @@ function X_TextRange_text( v ){
319366 elm = xnode[ '_rawObject' ];
320367 val = X_UA[ 'IE' ] < 9 ? X_Node_Attr_getValueForIE( elm ) : elm.value;
321368
322- if( this.createFrom === 'char' ){
369+ if( this[ 'by' ] === 'char' ){
323370 xnode.attr( {
324- 'value' : val.substr( 0, this.v1 ) + v + val.substr( this.v2 )
371+ 'value' : val.substr( 0, this[ 'v1' ] ) + v + val.substr( this[ 'v2' ] )
325372 } );
326373 } else {
327374 offset = this[ 'getOffset' ]();
@@ -330,7 +377,7 @@ function X_TextRange_text( v ){
330377 to = offset[ 'to' ];
331378
332379 if( X_UA[ 'IE' ] < 9 ){
333- range = document.selection.createRange();
380+ range = X_TextRange_selection();
334381 // TODO check textarea
335382 range.text = v;
336383 // ここには range.text がいない https://msdn.microsoft.com/ja-jp/library/cc427934.aspx
@@ -358,18 +405,18 @@ function X_TextRange_move( from, to ){
358405 len, range;
359406
360407 if( 0 <= from ){
361- this.v1 = from;
408+ this[ 'v1' ] = from;
362409 } else {
363- this.v1 = this.v1 + from;
364- this.v1 < 0 && ( this.v1 = 0 );
410+ this[ 'v1' ] = this[ 'v1' ] + from;
411+ this[ 'v1' ] < 0 && ( this[ 'v1' ] = 0 );
365412 };
366413
367414 if( X_Type_isNumber( to ) ){
368415 if( 0 <= to ){
369- this.v2 = to;
416+ this[ 'v2' ] = to;
370417 } else {
371- this.v2 = this.v2 + to;
372- this.v2 < this.v1 && ( this.v2 = this.v1 );
418+ this[ 'v2' ] = this[ 'v2' ] + to;
419+ this[ 'v2' ] < this[ 'v1' ] && ( this[ 'v2' ] = this[ 'v1' ] );
373420 };
374421 };
375422
@@ -380,24 +427,22 @@ function X_TextRange_move( from, to ){
380427 len = ( X_UA[ 'IE' ] < 9 ? X_Node_Attr_getValueForIE( elm ) : elm.value ).length;
381428
382429 if( X_UA[ 'Opera' ] ){
383- X_EventDispatcher_ignoreActualEvent = 'focus';
384- elm.focus(); // Operaの為(IEでは無くても大丈夫)
385- X_EventDispatcher_ignoreActualEvent = '';
430+ FocusUtility_setTemporarilyFocus( elm );
386431 };
387432
388433 range = elm.createTextRange();
389434
390- if( this.v1 === this.v2 && this.v1 === 0 ){
435+ if( this[ 'v1' ] === this[ 'v2' ] && this[ 'v1' ] === 0 ){
391436 range.collapse( true ); // 先頭に移動
392437 } else {
393- if( this.v1 !== this.v2 || this.v1 < len ){
438+ if( this[ 'v1' ] !== this[ 'v2' ] || this[ 'v1' ] < len ){
394439 range.collapse(); // おまじない?
395440
396- if( this.v1 === this.v2 ){
397- range.move( 'character', this.v1 );
441+ if( this[ 'v1' ] === this[ 'v2' ] ){
442+ range.move( 'character', this[ 'v1' ] );
398443 } else {
399- range.moveEnd( 'character', this.v2 );
400- range.moveStart( 'character', this.v1 );
444+ range.moveEnd( 'character', this[ 'v2' ] );
445+ range.moveStart( 'character', this[ 'v1' ] );
401446 };
402447 } else {
403448 range.collapse( false ); // 末美に移動
@@ -406,7 +451,7 @@ function X_TextRange_move( from, to ){
406451 range.select();
407452
408453 } else if( elm.setSelectionRange ){
409- elm.setSelectionRange( this.v1, this.v2 );
454+ elm.setSelectionRange( this[ 'v1' ], this[ 'v2' ] );
410455 };
411456 };
412457 };
@@ -422,15 +467,13 @@ function X_TextRange_select( v ){
422467 // https://web.archive.org/web/20090904183807/http://www.dedestruct.com/cursorPosition.html
423468 function cursorPosition( textarea ){
424469
425- var selection_range = document.selection.createRange().duplicate();
470+ var selection_range = X_TextRange_selection().duplicate();
426471
427472
428473 if (selection_range.parentElement() !== textarea) {
429474 // TODO 正しくはカーソル位置・選択範囲の復帰
430475
431- X_EventDispatcher_ignoreActualEvent = 'focus';
432- textarea.focus();
433- X_EventDispatcher_ignoreActualEvent = '';
476+ FocusUtility_setTemporarilyFocus( textarea );
434477
435478 // BODY要素のテキスト範囲を作成する
436479 selection_range = X_elmBody.createTextRange();
@@ -523,8 +566,8 @@ function X_TextRange_select( v ){
523566 var startPoint = untrimmed_before_text.split( '\r' ).join( '' ).length;
524567 // alert(startPoint);
525568 return {
526- 'from' : this.v1 = startPoint,
527- 'to' : this.v2 = startPoint + untrimmed_selection_text.split( '\r' ).join( '' ).length
569+ 'from' : this[ 'v1' ] = startPoint,
570+ 'to' : this[ 'v2' ] = startPoint + untrimmed_selection_text.split( '\r' ).join( '' ).length
528571 };
529572 //}
530573 }
--- a/0.6.x/js/11_hid/01_KB.js
+++ b/0.6.x/js/11_hid/01_KB.js
@@ -4,10 +4,6 @@
44 * keydown について。Firefox では押している間中リスナの関数が実行される
55 * デフォルトイベントの制御・抑止 (opera)keypress を用いる。
66 *
7- * キーイベント処理の工夫
8- * http://www.keynavi.net/ja/tipsj/kfunc.html
9- * keydown/up時にピリオドが文字化け (IE4-6) IE4+では「keypress」でキーコードを処理する 但しCtrlやALTが押されている場合は逆にkeydownで処理する必要があります
10- *
117 *
128 * keydown をトリガーにイベントを発火するもの
139 * 1. テンキーの 0~9 keyCode:96-105
@@ -25,8 +21,8 @@ var X_KB_SPECIALS = eval( // IE5- 対策
2521 "'33':'PAGE_UP','34':'PAGE_DOWN','35':'END','36':'HOME','37':'CSR_L','38':'CSR_U','39':'CSR_R','40':'CSR_D'," +
2622 "'44':'PRT_SCRN','45':'INS','46':'DEL'," +
2723 "'91':'LWIN','92':'RWIN','93':'APP'," +
28- "'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," +
29- "'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'," +
24+ "'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," +
25+ "'112':'F1','113':'F2','114':'F3','115':'F4','116':'F5','117':'F6','118':'F7','119':'F8','120':'F9','121':'F10','122':'F11','123':'F12'," +
3026 "'144':'NUM_LOCK','145':'SCROLL_LOCK','208':'CAPS_LOCK','240':'CAPS_LOCK','242':'K/H','243':'H/Z','244':'H/Z'})" ),
3127 X_KB_DOWN_KEYS = {},
3228 X_KB_CANCELED = {},
@@ -34,6 +30,8 @@ var X_KB_SPECIALS = eval( // IE5- 対策
3430 X_KB_lastKeyCode = 0,
3531 X_KB_TRANSFOEM = {},
3632
33+ // TODO keyevent のためには input 等にフォーカスが必要 -> iOS
34+
3735 X_kbManager =
3836 X_Class_override(
3937 X_EventDispatcher(),
@@ -42,14 +40,16 @@ var X_KB_SPECIALS = eval( // IE5- 対策
4240 var keyCode = e.keyCode, // keyCode says something about the actual keyboard key the user pressed
4341 chrCode = e.charCode, // while charCode gives the ASCII value of the resulting character
4442 cb = X_CALLBACK_NONE,
45- special, _keyCode;
43+ special;
4644
47- console.log( e.type + ' > keyCode:' + keyCode + ' chrCode:' + chrCode );
45+ // console.log( e.type + ' > keyCode:' + keyCode + ' chrCode:' + chrCode );
4846
4947 switch( e.type ){
5048 case 'keydown' :
5149 if( X_KB_DOWN_KEYS[ keyCode ] ){
5250 // 既に押されている、メタキー[shift,ctrl,alt]の変化はある?
51+ console.log( ' doen -- ' );
52+
5353 return X_KB_CANCELED[ keyCode ] ? X_CALLBACK_PREVENT_DEFAULT : cb;
5454 } else
5555 if( special = X_KB_SPECIALS[ keyCode ] ){
@@ -87,13 +87,32 @@ var X_KB_SPECIALS = eval( // IE5- 対策
8787 }; */
8888 } else {
8989 X_KB_lastKeyCode = keyCode;
90- };
90+
91+ if( e.ctrlKey || e.altKey || e.metaKey ){
92+ cb = this[ 'dispatch' ]( {
93+ type : 'keydown',
94+ keyCode : 0,
95+ charCode : chrCode,
96+ 'keyName' : '',
97+ 'is10key' : false,
98+ shiftKey : !!X_KB_DOWN_KEYS[ 16 ],
99+ ctrlKey : !!X_KB_DOWN_KEYS[ 17 ],
100+ altKey : !!X_KB_DOWN_KEYS[ 18 ],
101+ metaKey : !!X_KB_DOWN_KEYS[ 224 ]
102+ } );
103+
104+ if( cb & X_CALLBACK_PREVENT_DEFAULT ){
105+ X_KB_CANCELED[ keyCode ] = true;
106+ };
107+ };
108+ console.log( ' keydown[' + keyCode + ']' + String.fromCharCode( chrCode ) + chrCode );
109+ };
91110 return cb;
92111
93112 case 'keypress' :
94113 // keydown 側で発火しているものは再び発火しない
95-
96114 if( X_KB_DOWN_KEYS[ chrCode ] ){
115+ // TODO keypress
97116 return X_KB_CANCELED[ chrCode ] ? X_CALLBACK_PREVENT_DEFAULT : cb;
98117 } else
99118 if( keyCode === 32 ){
@@ -117,6 +136,8 @@ var X_KB_SPECIALS = eval( // IE5- 対策
117136 X_KB_lastIs10Key = false;
118137
119138 console.log( X_KB_lastKeyCode + 'keypress : chrCode:' + chrCode + ' down:' + X_KB_DOWN_KEYS[ chrCode ] + ( X_KB_CANCELED[ chrCode ] ? ' Cancel!' : '' ) );
139+ } else {
140+ console.log( '>> keypress : chrCode:' + chrCode + ' down:' + X_KB_DOWN_KEYS[ chrCode ] + ( X_KB_CANCELED[ chrCode ] ? ' Cancel!' : '' ) );
120141 };
121142 return cb;
122143
@@ -156,7 +177,7 @@ var X_KB_SPECIALS = eval( // IE5- 対策
156177 chrCode = 0;
157178 };
158179
159- console.log( keyCode + ' keyup ' + chrCode );
180+ //console.log( keyCode + ' keyup ' + chrCode );
160181
161182 cb |= this[ 'dispatch' ]( {
162183 type : 'keyup',
--- a/0.6.x/js/import.js
+++ b/0.6.x/js/import.js
@@ -24,6 +24,8 @@ document.write( [
2424 'js/01_core/14_XEvent.js',
2525 'js/01_core/15_XEventDispatcher.js',
2626 'js/01_core/16_XTimer.js',
27+ 'js/01_core/17_ExecuteAtEnd.js',
28+ 'js/01_core/18_FocusUtility.js',
2729
2830 'js/01_core/20_XSystem.js',
2931 'js/01_core/21_XViewPort.js',
旧リポジトリブラウザで表示