add ExecuteAtEnd and FocusUtility.
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
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
\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
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
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
X_Timer_removal = null;\r
};\r
X_Timer_update();\r
+ \r
+ ExecuteAtEnd_onEnd();\r
};\r
\r
function X_Timer_update(){\r
};\r
X_Timer_removal = null;\r
};\r
+ \r
+ ExecuteAtEnd_onEnd();\r
};\r
\r
console.log( 'X.Core.Timer' );\r
--- /dev/null
+
+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;
+};
--- /dev/null
+
+
+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;
+};
+
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,
{
'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;
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;
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 ){
* http://sssslide.com/www.slideshare.net/hiroakiwakamatsu/ss-12718639
*
*
- * getBoundingClientRect で fontsize の調査
+ * getBoundingClientRect で fontsize の調査
*/
var X_ViewPort_resize =
// iOS もループで回す,,,iOS3.1.3, iOS6 で確認
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;
};
//ブラウザの戻るボタンで戻ったときに呼ばれるイベントとかキャッシュとかそこらへんのこと
//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 );
};
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 ] :
// 強制的に再描画を起こす, 但し activeElement からフォーカスが外れるため復帰する
// IE5mode win10 で 確認
if( X_UA[ 'IE5' ] ){
- active = document.activeElement;
+ active = FocusUtility_getFocusedElement();
X_elmBody.style.visibility = 'hidden';
};
if( X_UA[ 'IE5' ] ){
X_elmBody.style.visibility = '';
- active && active.parentNode && active.focus();
+ active && active.parentNode && FocusUtility_setTemporarilyFocus( active );
};
if( X_Node_updateReservedByReleaseGPU ){
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' ] ) );
// 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' ] );
*/\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
\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
};\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
};\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
\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
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
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
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
\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
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
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
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
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
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
// 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
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
* 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
"'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
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
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
}; */\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
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
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
'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