--- /dev/null
+/*\r
+ * tr = X.Doc.createRange('selection')\r
+ * X.Doc.createRange({from : num, to : num})\r
+ * tr = xnode.createRange( from, to ),\r
+ * ( 'selection' ) docment の slection のうち xnode の配下のもの\r
+ * ( 'char', from, to )\r
+ * ( 'line', index ),\r
+ * ( 'point', x, y ) | ( 'point', e )\r
+ * tr.move( startIndex, endIndex )\r
+ * tr.getRect() { width, height, x, y }\r
+ * tr.getOffset() { from, to }\r
+ * tr.text()\r
+ * \r
+ * naming は mozilla に寄せる\r
+ */\r
+\r
+var X_TextRange_range,\r
+ X_TextRange_range2,\r
+ X_TextRange_isW3C = !document.selection || 10 <= X_UA[ 'IE' ];\r
+\r
+/**\r
+ * ユーザーによって選択されたテキストへの参照や文字の座標の取得\r
+ * @alias X.TextRange\r
+ * @class TextRange テキストレンジ\r
+ * @extends {__ClassBase__}\r
+ */\r
+var X_TextRange = X_Class_create(\r
+ 'X.TextRange',\r
+ \r
+ /** @lends X.TextRange.prototype */\r
+ {\r
+ xnode : null,\r
+ createFrom : '',\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
+ case 'point' :\r
+ case 'char' :\r
+ this.createFrom = arg2;\r
+ break;\r
+ default :\r
+ arg4 = arg3;\r
+ arg3 = arg2;\r
+ };\r
+ \r
+ if( arg2 !== 'selection' ){\r
+ this.v1 = arg3 || 0;\r
+ this.v2 = arg4 || 0;\r
+ };\r
+ },\r
+ \r
+ 'getRect' : X_TextRange_getRect,\r
+ \r
+ 'getOffset' : X_TextRange_getOffset,\r
+ \r
+ 'text' : X_TextRange_text\r
+ }\r
+);\r
+\r
+// TextNode を探して flat な配列に格納する\r
+function X_TextRange_collectTextNodes( elm, ary ){\r
+ var kids = elm.childNodes,\r
+ i, e;\r
+ \r
+ if( !kids || !kids.length ) return;\r
+ \r
+ for( i = 0; e = kids[ i ]; ++i ){\r
+ switch( e.nodeType ){\r
+ case 1 :\r
+ X_TextRange_collectTextNodes( e, ary );\r
+ break;\r
+ case 3 :\r
+ ary[ ary.length ] = e;\r
+ break;\r
+ };\r
+ };\r
+};\r
+\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
+ \r
+ if( xnode[ '_flags' ] & X_NodeFlags_IN_TREE ){\r
+ \r
+ X_Node_updateTimerID && X_Node_startUpdate();\r
+ \r
+ elm = xnode[ '_rawObject' ];\r
+ \r
+ switch( tr.createFrom ){\r
+ case 'selection' :\r
+ if( X_TextRange_isW3C ){\r
+ selection = window.getSelection();\r
+ return selection.rangeCount && selection.getRangeAt( 0 );\r
+ } else {\r
+ switch( document.selection.type ){\r
+ case 'text' :\r
+ return document.selection.createRange();\r
+ case 'Control' :\r
+ // TODO\r
+ case 'none' :\r
+ };\r
+ };\r
+ break;\r
+\r
+ case 'point' :\r
+ isPoint = true;\r
+ case 'char' :\r
+ if( X_TextRange_isW3C ){\r
+ // textarea で異なる\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
+ };\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.expand( 'character' ) ) range = null;\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
+ };\r
+ return range;\r
+ };\r
+ };\r
+};\r
+\r
+function X_TextRange_getRect(){\r
+ var result = X_TextRange_getRawRange( this ),\r
+ rect, ret;\r
+ \r
+ if( result ){\r
+ if( X_TextRange_isW3C ){\r
+ rect = result.hitRange.getBoundingClientRect();\r
+ ret = {\r
+ 'x' : rect.left,\r
+ 'y' : rect.top,\r
+ 'width' : rect.width,\r
+ 'height' : rect.height\r
+ };\r
+ //range.detach && range.detach(); \r
+ } else {\r
+ ret = {\r
+ 'x' : result.boundingLeft,\r
+ 'y' : result.boundingTop,\r
+ 'width' : result.boundingWidth,\r
+ 'height' : result.boundingHeight // ie は right, bottom を持たない...\r
+ };\r
+ };\r
+ };\r
+ return ret || { 'x' : 0, 'y' : 0, 'width' : 0, 'height' : 0 };\r
+};\r
+\r
+// X.Text を探して flat な配列に格納する\r
+function X_TextRange_collectXTexts( xnode, ary ){\r
+ var kids = xnode[ '_xnodes' ],\r
+ i;\r
+ \r
+ if( !kids || !kids.length ) return;\r
+ \r
+ for( i = -1; xnode = kids[ ++i ]; ){\r
+ if( xnode[ '_tag' ] ){\r
+ X_TextRange_collectXTexts( xnode, ary );\r
+ } else {\r
+ ary[ ary.length ] = xnode;\r
+ };\r
+ };\r
+};\r
+\r
+function X_TextRange_getOffset(){\r
+ var result = X_TextRange_getRawRange( this ),\r
+ range, ret, all, from, xtexts, n, i, l, xtext;\r
+ \r
+ if( result ){\r
+ if( X_TextRange_isW3C ){\r
+ range = result.hitRange;\r
+ ret = {\r
+ 'offset' : result.offset,\r
+ 'from' : range.startOffset,\r
+ 'to' : 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
+ range = X_TextRange_range2;\r
+ //var _rang = X_elmBody.createTextRange();\r
+ \r
+ \r
+ //_rang.moveToElementText( this.xnode.getChildAt(1)[ '_rawObject' ] );\r
+ range.moveToElementText( this.xnode[ '_rawObject' ] );\r
+ range.setEndPoint( 'EndToStart', result ); //_rang )//\r
+ from = range.text.length;// - result.text.length;\r
+\r
+ X_TextRange_collectXTexts( this.xnode, xtexts = [] );\r
+ \r
+ if( xtexts.length ){\r
+ // 改行が入ると正しく startIndex を取ることができない...\r
+ for( n = l = 0, i = -1; xtext = xtexts[ ++i ]; ){\r
+ l = xtext[ '_text' ].length;\r
+ if( from < n + l ){\r
+ break;\r
+ };\r
+ n += l;\r
+ };\r
+ \r
+ ret = {\r
+ 'offset' : n,\r
+ 'from' : from - n,\r
+ 'to' : from - n + result.text.length,\r
+ 'text' : xtext\r
+ }; \r
+ };\r
+ };\r
+ };\r
+ \r
+ return ret || { 'from' : -1, 'to' : -1 };\r
+};\r
+\r
+function X_TextRange_text( v ){\r
+ if( v === undefined ){\r
+ \r
+ } else {\r
+ \r
+ };\r
+};\r
+\r