OSDN Git Service

Version 0.6.213, add X.Node.TextRange.
[pettanr/clientJs.git] / 0.6.x / js / 02_dom / 30_XTextRange.js
diff --git a/0.6.x/js/02_dom/30_XTextRange.js b/0.6.x/js/02_dom/30_XTextRange.js
new file mode 100644 (file)
index 0000000..80ddf4c
--- /dev/null
@@ -0,0 +1,275 @@
+/*\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