// ------------------------------------------------------------------------- //\r
// ------------ local variables -------------------------------------------- //\r
// ------------------------------------------------------------------------- //\r
-var X_String_CRLF = String.fromCharCode( 13 ) + String.fromCharCode( 10 );\r
+var X_String_CRLF = String.fromCharCode( 13 ) + String.fromCharCode( 10 ),\r
X_String_CHAR_REFS = {"¡":161,"¢":162,"£":163,"¤":164,"¥":165,"¦":166,"§":167,"¨":168,"©":169,\r
"ª":170,"«":171,\r
"¬":172,"­":173,"®":174,"¯":175,"°":176,"±":177,"²":178,"³":179,"´":180,"µ":181,"¶":182,\r
// http://orera.g.hatena.ne.jp/edvakf/20100515/1273908051
//http://onozaty.hatenablog.com/entry/20060803/p1
// Safari2.0.4では標準・互換どちらも document.body
+ // http://hisasann.com/housetect/2008/08/jqueryheightwidthopera95.html このdocument.body[ "client" + name ]はおそらくOpera9.5未満のバージョンで有効なんじゃないかな?
X_Node_updateTimerID && X_Node_startUpdate();
/*X_UA[ 'Opera' ] ?
'3' : 'pen',\r
'4' : 'mouse'\r
}; */\r
+ /*\r
+ * https://github.com/markleusink/ios-html5-drag-drop-shim/blob/master/ios-drag-drop.js\r
+ */\r
+ X_Dom_Event_coordinateSystemForElementFromPoint = X_UA[ 'iOS' ] < 5 ? 'page' : 'client', // iOS4 以下は clientX が undeifned...\r
+ \r
X_Dom_Event_CANCEL_MOUSE = {},\r
X_DomEvent;\r
\r
if( !X_UA[ 'IE' ] || 9 <= X_UA[ 'IE' ] ){\r
X_DomEvent = function( e, xnode ){\r
var originalType = e.type,\r
+ isNum = X_Type_isNumber,\r
type, pointerEventType,\r
touches, events,\r
- altKey, ctrlKey, metaKey, shiftKey, target, related, force,\r
+ altKey, ctrlKey, metaKey, shiftKey, target, xtarget, offset, related, force,\r
elm, i, n, time, touch, ev;\r
\r
//this._event = e;\r
//console.log( 'original : ' + originalType + ' > ' + type );\r
// http://msdn.microsoft.com/ja-jp/library/ie/dn304886%28v=vs.85%29.aspx\r
// ポインター イベントの更新\r
- if( e.pointerType ){\r
+ if( e.pointerType ||\r
+ // IE11 の IE10 モードで click イベントの pointerType が undefined\r
+ ( X_UA[ 'IE' ] === 10 && type === 'click' && ( e.pointerType = 'mouse' ) ) ){\r
// PointerEvent;\r
if( X_Dom_Event_convertMSPointerType ){\r
this[ 'pointerType' ] = X_Dom_Event_convertMSPointerType[ e.pointerType ];\r
- this[ 'pressure' ] = e.pressure || ( e.button !== -1 ? 0.5 : 0 );\r
+ this[ 'pressure' ] = isNum( e.pressure ) ? e.pressure : ( e.button !== -1 ? 0.5 : 0 );\r
// ポインターの接触形状の スクリーン ピクセル単位の幅と高さ なので変換。(多分、、、)\r
this[ 'width' ] = e.width / X_Dom_Event_devicePixelRatio;\r
this[ 'height' ] = e.height / X_Dom_Event_devicePixelRatio;\r
for( i = touches.length; i; ){\r
touch = touches[ --i ];\r
target = touch.target;\r
+ target = target.nodeType === 3 ? target.parentNode : target;\r
+ xtarget = X_Node_getXNode( target );\r
+ // https://developer.mozilla.org/en/docs/Web/API/Element/getBoundingClientRect\r
+ // Android 2+, iOS4+\r
+ offset = X_UA[ 'iOS' ] < 5 ? xtarget.offset() : target.getBoundingClientRect();\r
related = touch.relatedTarget;\r
events[ i ] = {\r
'type' : pointerEventType,\r
'pointerType' : 'touch',\r
- 'target' : X_Node_getXNode( target.nodeType === 3 ? target.parentNode : target ),// defeat Safari bug // xnodetouch.target,\r
+ 'target' : xtarget,// defeat Safari bug // xnodetouch.target,\r
'currentTarget' : xnode,\r
'relatedTarget' : related && X_Node_getXNode( related.nodeType === 3 ? related.parentNode : related ), // xnode iOS3 には relatedTarget がない\r
'isPrimary' : true,\r
'pointerId' : touch.identifier + 2, // iOS4 は 変換が必要!\r
//screenX : touch.screenX,\r
//screenY : touch.screenY,\r
- 'clientX' : touch.clientX || ( touch.pageX - X_ViewPort_scrollX ), // iOS4以下は clientX が undefined, コードでは入れ子のスクロールに対応できない\r
- 'clientY' : touch.clientY || ( touch.pageY - X_ViewPort_scrollY ),\r
'pageX' : touch.pageX,\r
- 'pageY' : touch.pageY,\r
- 'offsetX' : touch.offsetX, // 要素上の座標を取得 \r
- 'offsetY' : touch.offsetY,\r
+ 'pageY' : touch.pageY, \r
+ // iOS4 以下では clientX が undef, pageX から scrollLeft を引く.\r
+ // TODO getter にする?\r
+ 'clientX' : isNum( touch.clientX ) ? touch.clientX : ( touch.pageX - X_ViewPort_scrollX ),\r
+ 'clientY' : isNum( touch.clientY ) ? touch.clientY : ( touch.pageY - X_ViewPort_scrollY ),\r
+ // 要素上の座標を取得\r
+ // iOS8 でも offsetX が undef, iOS4 以下では pageX - offset.x, iOS5 以上は clientX - getBCR.left\r
+ // TODO getter にする?\r
+ 'offsetX' : isNum( touch.offsetX ) ? touch.offsetX : touch[ X_Dom_Event_coordinateSystemForElementFromPoint + 'X' ] - ( offset.x || offset.left || 0 ), \r
+ 'offsetY' : isNum( touch.offsetY ) ? touch.offsetY : touch[ X_Dom_Event_coordinateSystemForElementFromPoint + 'Y' ] - ( offset.y || offset.top || 0 ),\r
'radiusX' : touch.radiusX || 0,\r
'radiusY' : touch.radiusY || 0,\r
'rotationAngle' : touch.rotationAngle || 0,\r
'height' : touch.height || 0\r
};\r
//console.log( 'e.pointerId = ' + touch.identifier );\r
+ //X_UA[ 'iOS' ] < 5 && console.log( pointerEventType + ':[' + events[ i ].pageX + ',' + events[ i ].pageY + ']' + events[ i ].pointerId );\r
};\r
return events.length === 1 ? events[ 0 ] : events;\r
} else {\r
this[ 'clientY' ] = e.clientY;\r
this[ 'pageX' ] = e.pageX;\r
this[ 'pageY' ] = e.pageY;\r
- this[ 'offsetX' ] = e.offsetX || e.layerX; // 要素上の座標を取得 \r
- this[ 'offsetY' ] = e.offsetY || e.layerY;\r
+ this[ 'offsetX' ] = isNum( e.offsetX ) ? e.offsetX : e.layerX; // 要素上の座標を取得 \r
+ this[ 'offsetY' ] = isNum( e.offsetY ) ? e.offsetY : e.layerY;\r
\r
// http://www.programming-magic.com/20090127231544/\r
// Opera で button==2の場合、コンテキストメニューイベントを発火 「ツール」->「設定」->「詳細設定」->「コンテンツ」->「Javascriptオプション」で「右クリックを制御するスクリプトを許可する」\r
// エレメントの座標取得 ~スクロール要素~\r
// http://n-yagi.0r2.net/script/2009/07/post_16.html\r
\r
+// TODO getClientRects Safari2- ?\r
+\r
//■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■\r
// エレメントの絶対座標を得たい\r
//------------------------------------------------------------------------------\r
(\r
document.compatMode === 'CSS1Compat' && !X_UA[ 'Webkit' ] ? function( el ){\r
var pos = el.getBoundingClientRect(),\r
- html = document.documentElement;\r
+ html = X_elmHtml;\r
return { x:(pos.left + html.scrollLeft - html.clientLeft)\r
, y:(pos.top + html.scrollTop - html.clientTop) };\r
} :\r
var l = xnodes.length,\r
i = 0,\r
j, child, _xnodes;\r
+\r
for( ; i < l; ++i ){\r
child = xnodes[ i ];\r
if( !child[ '_tag' ] ) continue;\r
var l = xnodes.length,\r
i = 0,\r
child, uid, _tag, _xnodes;\r
- for( ; i < l; ++i ){\r
+\r
+ for( ; i < l; ++i ){ // for( ; child = xnodes[ ++i ]; )\r
child = xnodes[ i ];\r
uid = child[ '_uid' ];\r
_tag = child[ '_tag' ];\r
/* Opera mobile で translateZ(0) が有効だと XY が 0 0 になる */\r
/* GPUレイヤーにいる間に要素のコンテンツを変更をすると transitionend が動かなくなるっぽい Mac safari と firefox */\r
X_NodeAnime_translateZ = X_Node_CSS_VENDER_PREFIX[ 'perspective' ] &&\r
- !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] //&&\r
- /* ハードウェアによると思うが IE11 と Win8.1 で画面(塗)が乱れる */\r
- /* !( ( X_UA[ 'IE' ] === 11 || X_UA[ 'IEHost' ] === 11 ) && X_UA[ 'Windows' ] === 8.1 ) */ ? ' translateZ(0)' : '',\r
+ !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] ? ' translateZ(0)' : '',\r
\r
/*\r
* phase:\r
now = X_Timer_now(),\r
c = false,\r
i, xnode, obj, _xnode,\r
- rm, easing, lazy;\r
+ rm, progress, easing, lazy;\r
\r
if( X_NodeAnime_needsDetection ){\r
X_NodeAnime_needsDetection = false;\r
switch( obj.phase ){\r
case 7 : // アニメーション中\r
if( now < obj.toTime ){\r
- obj.progress = ( now - obj.fromTime ) / obj.duration;\r
- easing = obj.easing( obj.progress );\r
+ obj.progress = progress = ( now - obj.fromTime ) / obj.duration;\r
+ easing = obj.easing( progress );\r
obj.x = ( obj.toX - obj.fromX ) * easing + obj.fromX;\r
obj.y = ( obj.toY - obj.fromY ) * easing + obj.fromY;\r
obj.rotate = ( obj.toRotate - obj.fromRotate ) * easing + obj.fromRotate;\r
obj.alpha = ( obj.toAlpha - obj.fromAlpha ) * easing + obj.fromAlpha;\r
obj.scrollX = ( obj.toScrollX - obj.fromScrollX ) * easing + obj.fromScrollX;\r
obj.scrollY = ( obj.toScrollY - obj.fromScrollY ) * easing + obj.fromScrollY;\r
- X_NodeAnime_updatePosition( xnode, obj, obj.progress, true );\r
+ X_NodeAnime_updatePosition( xnode, obj, progress, true );\r
c = true;\r
break;\r
};\r
'createTextAt' : X_Node_createTextAt,
+ 'createRange' : X_Node_createRange,
+
'clone' : X_Node_clone,
'append' : X_Node_append,
};
/**
+ * 選択されたテキストへの参照やテキスト座標情報
+ * @alias Node.prototype.createRange
+ * @return {TextRange} 新規作成されたテキストレンジ
+ */
+function X_Node_createRange( a, b, c ){
+ return X_TextRange( this, a, b, c );
+};
+
+/**
* Node のクローンを作成し返す。id もクローンされる点に注意。イベントリスナはクローンされない。
* http://d.hatena.ne.jp/think49/20110724/1311472811
* http://d.hatena.ne.jp/uupaa/20100508/1273299874
--- /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
var l = xmlList.length,\r
i = 0,\r
j, child, _xmlList;\r
+\r
for( ; i < l; ++i ){\r
child = xmlList[ i ];\r
//if( child.nodeType !== 1 ) continue;\r
l = xmlList.length,\r
i = 0,\r
child;\r
+\r
for( ; i < l; ++i ){\r
child = xmlList[ i ];\r
if( child.nodeType === 1 ){\r
} else\r
if( this.playing ){\r
end = X_Audio_getEndTime( this ) + this._shortPlayFixTime;\r
- //console.log( now + ' / ' + end );\r
+ \r
+ console.log( now + ' / ' + end );// Firefox44.0.2 で音声の再生開始に難あり...\r
+ \r
if( ( 0 + end <= 0 + now ) || // 0+ なぜか iem9 で必要,,,\r
( now < this._lastCurrentTime && now < 2000 ) ){\r
//( ( X_HTMLAudio_endedFixAOSP2 || X_HTMLAudio_endedFixAOSP4 ) && ( now < this._lastCurrentTime && now < 1000 ) ) ){\r
'js/02_dom/10_XNodeAnime.js',\r
'js/02_dom/20_XNode.js',\r
'js/02_dom/22_XTreeBuilder.js',\r
+ 'js/02_dom/30_XTextRange.js',\r
\r
'js/03_plugin/00_XPlugin.js',\r
\r