2 * tr = X.Doc.createRange('selection')
\r
3 * X.Doc.createRange({from : num, to : num})
\r
4 * tr = xnode.createRange( from, to ),
\r
5 * ( 'selection' ) docment の slection のうち xnode の配下のもの
\r
6 * ( 'char', from, to )
\r
8 * ( 'point', x, y ) | ( 'point', e )
\r
9 * tr.move( startIndex, endIndex )
\r
10 * tr.getRect() { width, height, x, y }
\r
11 * tr.getOffset() { from, to }
\r
14 * naming は mozilla に寄せる
\r
17 var X_TextRange_range,
\r
19 X_TextRange_isW3C = !document.selection || 10 <= X_UA[ 'IE' ];
\r
22 * ユーザーによって選択されたテキストへの参照や文字の座標の取得
\r
23 * @alias X.TextRange
\r
24 * @class TextRange テキストレンジ
\r
25 * @extends {__ClassBase__}
\r
27 var X_TextRange = X_Class_create(
\r
30 /** @lends X.TextRange.prototype */
\r
37 'Constructor' : function( xnode, arg2, arg3, arg4 ){
\r
38 if( !X_TextRange_range ){
\r
39 X_TextRange_range = X_TextRange_isW3C ? document.createRange() : X_elmBody.createTextRange();
\r
40 if( !X_TextRange_isW3C ) X_TextRange_range2 = X_elmBody.createTextRange();
\r
50 this.createFrom = arg2;
\r
57 if( arg2 !== 'selection' ){
\r
58 this.v1 = arg3 || 0;
\r
59 this.v2 = arg4 || 0;
\r
63 'getRect' : X_TextRange_getRect,
\r
65 'getOffset' : X_TextRange_getOffset,
\r
67 'text' : X_TextRange_text
\r
71 // TextNode を探して flat な配列に格納する
\r
72 function X_TextRange_collectTextNodes( elm, ary ){
\r
73 var kids = elm.childNodes,
\r
76 if( !kids || !kids.length ) return;
\r
78 for( i = 0; e = kids[ i ]; ++i ){
\r
79 switch( e.nodeType ){
\r
81 X_TextRange_collectTextNodes( e, ary );
\r
84 ary[ ary.length ] = e;
\r
90 function X_TextRange_getRawRange( tr ){
\r
91 var xnode = tr.xnode,
\r
93 range = 10 <= X_UA[ 'IE' ] /* || X_UA[ 'iOS' ] */ ? document.createRange() :
\r
94 8 <= X_UA[ 'IE' ] ? X_elmBody.createTextRange() : X_TextRange_range,
\r
95 elm, selection, isPoint,
\r
96 texts, i, offset, j, l, x, y, rect;
\r
98 if( xnode[ '_flags' ] & X_NodeFlags_IN_TREE ){
\r
100 X_Node_updateTimerID && X_Node_startUpdate();
\r
102 elm = xnode[ '_rawObject' ];
\r
104 switch( tr.createFrom ){
\r
106 if( X_TextRange_isW3C ){
\r
107 selection = window.getSelection();
\r
108 return selection.rangeCount && selection.getRangeAt( 0 );
\r
110 switch( document.selection.type ){
\r
112 return document.selection.createRange();
\r
123 if( X_TextRange_isW3C ){
\r
127 // TextNode をフラットな配列に回収
\r
128 X_TextRange_collectTextNodes( elm, texts = [] );
\r
130 for( i = offset = 0; text = texts[ i ]; ++i ){
\r
131 range.selectNodeContents( text ); // selectNodeContents は TextNode のみ?? Firefox
\r
132 l = text.data.length;
\r
134 for( j = 0, x = tr.v1, y = tr.v2; j < l; ++j ){
\r
136 range.setStart( text, j );
\r
137 range.setEnd( text, j + 1 );
\r
138 rect = range.getBoundingClientRect();
\r
140 if( rect.left <= x && x <= rect.right && rect.top <= y && y <= rect.bottom ){
\r
154 range.setEnd( elm, l < tr.v2 ? l : tr.v2 );
\r
155 range.setStart( elm, tr.v1 );
\r
156 return { hitRange : range };
\r
159 // !save && ( text = text.split( '\r\n' ).join( '\n' ) ); textarea用
\r
161 // ie11 の ie10モード で moveToPoint がないといわれる. よって isW3C:false で動作するのは ie9 以下
\r
162 range.moveToPoint( tr.v1, tr.v2 );
\r
163 if( !range.expand( 'character' ) ) range = null;
\r
165 range.moveToElementText( elm );
\r
166 //range.collapse( true );
\r
167 range.moveEnd( 'character', l < tr.v2 ? l : tr.v2 );
\r
168 range.moveStart( 'character', tr.v1 );
\r
176 function X_TextRange_getRect(){
\r
177 var result = X_TextRange_getRawRange( this ),
\r
181 if( X_TextRange_isW3C ){
\r
182 rect = result.hitRange.getBoundingClientRect();
\r
186 'width' : rect.width,
\r
187 'height' : rect.height
\r
189 //range.detach && range.detach();
\r
192 'x' : result.boundingLeft,
\r
193 'y' : result.boundingTop,
\r
194 'width' : result.boundingWidth,
\r
195 'height' : result.boundingHeight // ie は right, bottom を持たない...
\r
199 return ret || { 'x' : 0, 'y' : 0, 'width' : 0, 'height' : 0 };
\r
202 // X.Text を探して flat な配列に格納する
\r
203 function X_TextRange_collectXTexts( xnode, ary ){
\r
204 var kids = xnode[ '_xnodes' ],
\r
207 if( !kids || !kids.length ) return;
\r
209 for( i = -1; xnode = kids[ ++i ]; ){
\r
210 if( xnode[ '_tag' ] ){
\r
211 X_TextRange_collectXTexts( xnode, ary );
\r
213 ary[ ary.length ] = xnode;
\r
218 function X_TextRange_getOffset(){
\r
219 var result = X_TextRange_getRawRange( this ),
\r
220 range, ret, all, from, xtexts, n, i, l, xtext;
\r
223 if( X_TextRange_isW3C ){
\r
224 range = result.hitRange;
\r
226 'offset' : result.offset,
\r
227 'from' : range.startOffset,
\r
228 'to' : range.endOffset,
\r
229 'text' : X_Node_getXNode( result.text )
\r
231 // range.detach && range.detach();
\r
233 // http://www.studio-freesky.net/programming/javascript/3/
\r
234 range = X_TextRange_range2;
\r
235 //var _rang = X_elmBody.createTextRange();
\r
238 //_rang.moveToElementText( this.xnode.getChildAt(1)[ '_rawObject' ] );
\r
239 range.moveToElementText( this.xnode[ '_rawObject' ] );
\r
240 range.setEndPoint( 'EndToStart', result ); //_rang )//
\r
241 from = range.text.length;// - result.text.length;
\r
243 X_TextRange_collectXTexts( this.xnode, xtexts = [] );
\r
245 if( xtexts.length ){
\r
246 // 改行が入ると正しく startIndex を取ることができない...
\r
247 for( n = l = 0, i = -1; xtext = xtexts[ ++i ]; ){
\r
248 l = xtext[ '_text' ].length;
\r
249 if( from < n + l ){
\r
258 'to' : from - n + result.text.length,
\r
265 return ret || { 'from' : -1, 'to' : -1 };
\r
268 function X_TextRange_text( v ){
\r
269 if( v === undefined ){
\r