OSDN Git Service

d6f88374229fd995cece6b10627efab37fa3bf6a
[pettanr/clientJs.git] / 0.6.x / js / 02_dom / 30_XTextRange.js
1 /*\r
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
7  *     ( 'line', index ),\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
12  * tr.text()\r
13  * \r
14  * naming は mozilla に寄せる\r
15  */\r
16 \r
17 var X_TextRange_range,\r
18         X_TextRange_range2,\r
19         X_TextRange_isW3C = !document.selection || 10 <= X_UA[ 'IE' ];\r
20 \r
21 /**\r
22  * ユーザーによって選択されたテキストへの参照や文字の座標の取得\r
23  * @alias X.TextRange\r
24  * @class TextRange テキストレンジ\r
25  * @extends {__ClassBase__}\r
26  */\r
27 var X_TextRange = X_Class_create(\r
28         'X.TextRange',\r
29         \r
30         /** @lends X.TextRange.prototype */\r
31         {\r
32                 xnode      : null,\r
33                 createFrom : '',\r
34                 v1         : 0,\r
35                 v2         : 0,\r
36                 \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
41                         };\r
42                         \r
43                         this.xnode = xnode;\r
44                         \r
45                         switch( arg2 ){\r
46                                 case 'selection' :\r
47                                         //break;\r
48                                 case 'point' :\r
49                                 case 'char' :\r
50                                         this.createFrom = arg2;\r
51                                         break;\r
52                                 default :\r
53                                         arg4 = arg3;\r
54                                         arg3 = arg2;\r
55                         };\r
56                         \r
57                         if( arg2 !== 'selection' ){\r
58                                 this.v1 = arg3 || 0;\r
59                                 this.v2 = arg4 || 0;\r
60                         };\r
61                 },\r
62                 \r
63                 'getRect'   : X_TextRange_getRect,\r
64                 \r
65                 'getOffset' : X_TextRange_getOffset,\r
66                 \r
67                 'text'      : X_TextRange_text\r
68         }\r
69 );\r
70 \r
71 // TextNode を探して flat な配列に格納する\r
72 function X_TextRange_collectTextNodes( elm, ary ){\r
73         var kids = elm.childNodes,\r
74                 i, e;\r
75         \r
76         if( !kids || !kids.length ) return;\r
77         \r
78         for( i = 0; e = kids[ i ]; ++i ){\r
79                 switch( e.nodeType ){\r
80                         case 1 :\r
81                                 X_TextRange_collectTextNodes( e, ary );\r
82                                 break;\r
83                         case 3 :\r
84                                 ary[ ary.length ] = e;\r
85                                 break;\r
86                 };\r
87         };\r
88 };\r
89 \r
90 function X_TextRange_getRawRange( tr ){\r
91         var xnode = tr.xnode,\r
92                                 //\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
97         \r
98         if( xnode[ '_flags' ] & X_NodeFlags_IN_TREE ){\r
99                 \r
100                 X_Node_updateTimerID && X_Node_startUpdate();\r
101                 \r
102                 elm = xnode[ '_rawObject' ];\r
103                 \r
104                 switch( tr.createFrom ){\r
105                         case 'selection' :\r
106                                 if( X_TextRange_isW3C ){\r
107                                         selection = window.getSelection();\r
108                                         return selection.rangeCount && selection.getRangeAt( 0 );\r
109                                 } else {\r
110                                         switch( document.selection.type ){\r
111                                                 case 'text' :\r
112                                                         return document.selection.createRange();\r
113                                                 case 'Control' :\r
114                                                         // TODO\r
115                                                 case 'none' :\r
116                                         };\r
117                                 };\r
118                                 break;\r
119 \r
120                         case 'point' :\r
121                                 isPoint = true;\r
122                         case 'char' :\r
123                                 if( X_TextRange_isW3C ){\r
124                                         // textarea で異なる\r
125 \r
126                                         if( isPoint ){\r
127                                                 // TextNode をフラットな配列に回収\r
128                                                 X_TextRange_collectTextNodes( elm, texts = [] );                                                \r
129                                                 \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
133 \r
134                                                 for( j = 0, x = tr.v1, y = tr.v2; j < l; ++j ){\r
135                                                         if( range ){\r
136                                                             range.setStart( text, j );\r
137                                                             range.setEnd( text, j + 1 );\r
138                                                             rect = range.getBoundingClientRect();\r
139                                                         };\r
140                                                     if( rect.left <= x && x <= rect.right && rect.top <= y && y <= rect.bottom ){\r
141                                                         return {\r
142                                                                 hitRange : range,\r
143                                                                 rect     : rect,\r
144                                                                 offset   : offset,\r
145                                                                 text     : text\r
146                                                         };\r
147                                                     };\r
148                                                 };\r
149                                                 offset += l;\r
150                                                 };\r
151                                                 range = null;\r
152                                         } else {\r
153                                                 // 未チェック!\r
154                                                 range.setEnd( elm, l < tr.v2 ? l : tr.v2 );\r
155                                     range.setStart( elm, tr.v1 );\r
156                                     return { hitRange : range };\r
157                                         };\r
158                                 } else {\r
159                                         // !save && ( text = text.split( '\r\n' ).join( '\n' ) ); textarea用\r
160                                         if( isPoint ){\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
164                                         } else {\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
169                                         };\r
170                                 };\r
171                                 return range;\r
172                 };\r
173         };\r
174 };\r
175 \r
176 function X_TextRange_getRect(){\r
177         var result = X_TextRange_getRawRange( this ),\r
178                 rect, ret;\r
179         \r
180         if( result ){\r
181                 if( X_TextRange_isW3C ){\r
182                         rect = result.hitRange.getBoundingClientRect();\r
183                         ret = {\r
184                                 'x'      : rect.left,\r
185                                 'y'      : rect.top,\r
186                                 'width'  : rect.width,\r
187                                 'height' : rect.height\r
188                         };\r
189                         //range.detach && range.detach();\r
190                 } else {\r
191                         ret = {\r
192                                 'x'      : result.boundingLeft,\r
193                                 'y'      : result.boundingTop,\r
194                                 'width'  : result.boundingWidth,\r
195                                 'height' : result.boundingHeight // ie は right, bottom を持たない...\r
196                         };\r
197                 };\r
198         };\r
199         return ret || { 'x' : 0, 'y' : 0, 'width' : 0, 'height' : 0 };\r
200 };\r
201 \r
202 // X.Text を探して flat な配列に格納する\r
203 function X_TextRange_collectXTexts( xnode, ary ){\r
204         var kids = xnode[ '_xnodes' ],\r
205                 i;\r
206         \r
207         if( !kids || !kids.length ) return;\r
208         \r
209         for( i = -1; xnode = kids[ ++i ]; ){\r
210                 if( xnode[ '_tag' ] ){\r
211                         X_TextRange_collectXTexts( xnode, ary );\r
212                 } else {\r
213                         ary[ ary.length ] = xnode;\r
214                 };\r
215         };\r
216 };\r
217 \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
221         \r
222         if( result ){\r
223                 if( X_TextRange_isW3C ){\r
224                         range = result.hitRange;\r
225                         ret = {\r
226                                 'offset' : result.offset,\r
227                                 'from'   : range.startOffset,\r
228                                 'to'     : range.endOffset,\r
229                                 'text'   : X_Node_getXNode( result.text )\r
230                         };\r
231                         // range.detach && range.detach();              \r
232                 } else {\r
233                         // http://www.studio-freesky.net/programming/javascript/3/\r
234                         range = X_TextRange_range2;\r
235                         //var _rang = X_elmBody.createTextRange();\r
236                         \r
237                         \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
242 \r
243                         X_TextRange_collectXTexts( this.xnode, xtexts = [] );\r
244                         \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
250                                                 break;\r
251                                         };\r
252                                         n += l;\r
253                                 };\r
254                                 \r
255                                 ret = {\r
256                                         'offset' : n,\r
257                                         'from'   : from - n,\r
258                                         'to'     : from - n + result.text.length,\r
259                                         'text'   : xtext\r
260                                 };                              \r
261                         };\r
262                 };\r
263         };\r
264         \r
265         return ret || { 'from' : -1, 'to' : -1 };\r
266 };\r
267 \r
268 function X_TextRange_text( v ){\r
269         if( v === undefined ){\r
270                 \r
271         } else {\r
272                 \r
273         };\r
274 };\r
275 \r