X-Git-Url: http://git.osdn.jp/view?p=pettanr%2FclientJs.git;a=blobdiff_plain;f=0.6.x%2Fjs%2F02_dom%2F30_XTextRange.js;fp=0.6.x%2Fjs%2F02_dom%2F30_XTextRange.js;h=80ddf4c1000fca38cb89e8322b2f0f8fffc1fffa;hp=0000000000000000000000000000000000000000;hb=bafa8683f87b2f909d1301fca80684bf9ff221ed;hpb=d3d95fb0bc2ab2f61c7f15746b2d64078ef39af8 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 index 0000000..80ddf4c --- /dev/null +++ b/0.6.x/js/02_dom/30_XTextRange.js @@ -0,0 +1,275 @@ +/* + * tr = X.Doc.createRange('selection') + * X.Doc.createRange({from : num, to : num}) + * tr = xnode.createRange( from, to ), + *    ( 'selection' ) docment の slection のうち xnode の配下のもの + * ( 'char', from, to ) + * ( 'line', index ), + * ( 'point', x, y ) | ( 'point', e ) + * tr.move( startIndex, endIndex ) + * tr.getRect() { width, height, x, y } + * tr.getOffset() { from, to } + * tr.text() + * + * naming は mozilla に寄せる + */ + +var X_TextRange_range, + X_TextRange_range2, + X_TextRange_isW3C = !document.selection || 10 <= X_UA[ 'IE' ]; + +/** + * ユーザーによって選択されたテキストへの参照や文字の座標の取得 + * @alias X.TextRange + * @class TextRange テキストレンジ + * @extends {__ClassBase__} + */ +var X_TextRange = X_Class_create( + 'X.TextRange', + + /** @lends X.TextRange.prototype */ + { + xnode : null, + createFrom : '', + v1 : 0, + v2 : 0, + + 'Constructor' : function( xnode, arg2, arg3, arg4 ){ + if( !X_TextRange_range ){ + X_TextRange_range = X_TextRange_isW3C ? document.createRange() : X_elmBody.createTextRange(); + if( !X_TextRange_isW3C ) X_TextRange_range2 = X_elmBody.createTextRange(); + }; + + this.xnode = xnode; + + switch( arg2 ){ + case 'selection' : + //break; + case 'point' : + case 'char' : + this.createFrom = arg2; + break; + default : + arg4 = arg3; + arg3 = arg2; + }; + + if( arg2 !== 'selection' ){ + this.v1 = arg3 || 0; + this.v2 = arg4 || 0; + }; + }, + + 'getRect' : X_TextRange_getRect, + + 'getOffset' : X_TextRange_getOffset, + + 'text' : X_TextRange_text + } +); + +// TextNode を探して flat な配列に格納する +function X_TextRange_collectTextNodes( elm, ary ){ + var kids = elm.childNodes, + i, e; + + if( !kids || !kids.length ) return; + + for( i = 0; e = kids[ i ]; ++i ){ + switch( e.nodeType ){ + case 1 : + X_TextRange_collectTextNodes( e, ary ); + break; + case 3 : + ary[ ary.length ] = e; + break; + }; + }; +}; + +function X_TextRange_getRawRange( tr ){ + var xnode = tr.xnode, + // + range = 10 <= X_UA[ 'IE' ] /* || X_UA[ 'iOS' ] */ ? document.createRange() : + 8 <= X_UA[ 'IE' ] ? X_elmBody.createTextRange() : X_TextRange_range, + elm, selection, isPoint, + texts, i, offset, j, l, x, y, rect; + + if( xnode[ '_flags' ] & X_NodeFlags_IN_TREE ){ + + X_Node_updateTimerID && X_Node_startUpdate(); + + elm = xnode[ '_rawObject' ]; + + switch( tr.createFrom ){ + case 'selection' : + if( X_TextRange_isW3C ){ + selection = window.getSelection(); + return selection.rangeCount && selection.getRangeAt( 0 ); + } else { + switch( document.selection.type ){ + case 'text' : + return document.selection.createRange(); + case 'Control' : + // TODO + case 'none' : + }; + }; + break; + + case 'point' : + isPoint = true; + case 'char' : + if( X_TextRange_isW3C ){ + // textarea で異なる + + if( isPoint ){ + // TextNode をフラットな配列に回収 + X_TextRange_collectTextNodes( elm, texts = [] ); + + for( i = offset = 0; text = texts[ i ]; ++i ){ + range.selectNodeContents( text ); // selectNodeContents は TextNode のみ?? Firefox + l = text.data.length; + + for( j = 0, x = tr.v1, y = tr.v2; j < l; ++j ) { + if( range ){ + range.setStart( text, j ); + range.setEnd( text, j + 1 ); + rect = range.getBoundingClientRect(); + }; + if( rect.left <= x && x <= rect.right && rect.top <= y && y <= rect.bottom ){ + return { + hitRange : range, + rect : rect, + offset : offset, + text : text + }; + }; + }; + offset += l; + }; + range = null; + } else { + // 未チェック! + range.setEnd( elm, l < tr.v2 ? l : tr.v2 ); + range.setStart( elm, tr.v1 ); + return { hitRange : range }; + }; + } else { + // !save && ( text = text.split( '\r\n' ).join( '\n' ) ); textarea用 + if( isPoint ){ + // ie11 の ie10モード で moveToPoint がないといわれる. よって isW3C:false で動作するのは ie9 以下 + range.moveToPoint( tr.v1, tr.v2 ); + if( !range.expand( 'character' ) ) range = null; + } else { + range.moveToElementText( elm ); + //range.collapse( true ); + range.moveEnd( 'character', l < tr.v2 ? l : tr.v2 ); + range.moveStart( 'character', tr.v1 ); + }; + }; + return range; + }; + }; +}; + +function X_TextRange_getRect(){ + var result = X_TextRange_getRawRange( this ), + rect, ret; + + if( result ){ + if( X_TextRange_isW3C ){ + rect = result.hitRange.getBoundingClientRect(); + ret = { + 'x' : rect.left, + 'y' : rect.top, + 'width' : rect.width, + 'height' : rect.height + }; + //range.detach && range.detach(); + } else { + ret = { + 'x' : result.boundingLeft, + 'y' : result.boundingTop, + 'width' : result.boundingWidth, + 'height' : result.boundingHeight // ie は right, bottom を持たない... + }; + }; + }; + return ret || { 'x' : 0, 'y' : 0, 'width' : 0, 'height' : 0 }; +}; + +// X.Text を探して flat な配列に格納する +function X_TextRange_collectXTexts( xnode, ary ){ + var kids = xnode[ '_xnodes' ], + i; + + if( !kids || !kids.length ) return; + + for( i = -1; xnode = kids[ ++i ]; ){ + if( xnode[ '_tag' ] ){ + X_TextRange_collectXTexts( xnode, ary ); + } else { + ary[ ary.length ] = xnode; + }; + }; +}; + +function X_TextRange_getOffset(){ + var result = X_TextRange_getRawRange( this ), + range, ret, all, from, xtexts, n, i, l, xtext; + + if( result ){ + if( X_TextRange_isW3C ){ + range = result.hitRange; + ret = { + 'offset' : result.offset, + 'from' : range.startOffset, + 'to' : range.endOffset, + 'text' : X_Node_getXNode( result.text ) + }; + // range.detach && range.detach(); + } else { + // http://www.studio-freesky.net/programming/javascript/3/ + range = X_TextRange_range2; + //var _rang = X_elmBody.createTextRange(); + + + //_rang.moveToElementText( this.xnode.getChildAt(1)[ '_rawObject' ] ); + range.moveToElementText( this.xnode[ '_rawObject' ] ); + range.setEndPoint( 'EndToStart', result ); //_rang )// + from = range.text.length;// - result.text.length; + + X_TextRange_collectXTexts( this.xnode, xtexts = [] ); + + if( xtexts.length ){ + // 改行が入ると正しく startIndex を取ることができない... + for( n = l = 0, i = -1; xtext = xtexts[ ++i ]; ){ + l = xtext[ '_text' ].length; + if( from < n + l ){ + break; + }; + n += l; + }; + + ret = { + 'offset' : n, + 'from' : from - n, + 'to' : from - n + result.text.length, + 'text' : xtext + }; + }; + }; + }; + + return ret || { 'from' : -1, 'to' : -1 }; +}; + +function X_TextRange_text( v ){ + if( v === undefined ){ + + } else { + + }; +}; +