X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F01_dom%2F10_XDom.js;fp=0.6.x%2Fjs%2F01_dom%2F10_XDom.js;h=51443ea13eadbf49eb744432b6b5a6501a8baa68;hb=27420d0fbdf56a5cda68f5b10de6565de8a5c010;hp=0000000000000000000000000000000000000000;hpb=fb2a4b2dace3975474be1daa56659a861bbcbfbe;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/01_dom/10_XDom.js b/0.6.x/js/01_dom/10_XDom.js new file mode 100644 index 0000000..51443ea --- /dev/null +++ b/0.6.x/js/01_dom/10_XDom.js @@ -0,0 +1,438 @@ + +X.Dom = X.Class._override( + new X.EventDispatcher(), + { + readyState : -1, + active : !!window.parent || !!document.activeElement, // frameに読み込まれた場合のieのerror回避 + _root : null, + + _lock : false, + w : 0, + h : 0, + baseFontSize : 0, + +/* ----------------------------------------------- + * Resize + * original : uupaa.js + * + * TODO + * https://w3g.jp/blog/studies/ios7_1_minimal-ui_warning + * iOS7.0からあったiPad Safariの高さ100%コンテンツでlandscape(横向き)時に起きる不具合 + * + * getBoundingClientRect で fontsize の調査 + */ + _resize : + X.UA.IE < 9 ? + (function(){ + var size; + if( !X.Dom._lock ){ + size = X.Dom._getSize(); + if( X.Dom.w !== size[ 0 ] || X.Dom.h !== size[ 1 ] ){ + X.Dom.w = size[ 0 ]; + X.Dom.h = size[ 1 ]; + X.Timer.once( 100, X.Dom._detectFinishResizing ); + X.Dom._lock = true; + }; + }; + + size = Node._fontSizeNode._rawNode.offsetHeight; + if( X.Dom.baseFontSize !== size ){ + X.Dom.baseFontSize && X.Dom.asyncDispatch( 0, { type : X.Dom.Event.BASE_FONT_RESIZED, fontSize : size, w : X.Dom.w, h : X.Dom.h } ); + X.Dom.baseFontSize = size; + }; + + }) : + (function( e ){ + console.log( '-- resize : ' + X.getTime() ); + + !X.Dom._lock && ( X.Dom._lock = true ) && X.Timer.once( 100, X.Dom._detectFinishResizing ); + return X.Callback.PREVENT_DEFAULT | X.Callback.STOP_PROPAGATION; + }), + + _detectFinishResizing : function (){ + var size = X.Dom._getSize(); + if( X.Dom.w !== size[ 0 ] || X.Dom.h !== size[ 1 ] ){ + X.Dom.w = size[ 0 ]; + X.Dom.h = size[ 1 ]; + X.Timer.once( 100, X.Dom._detectFinishResizing ); + } else { + console.log( '-- detectFinishResizing : ' + X.getTime() ); + + X.Dom.asyncDispatch( 0, { type : X.Dom.Event.VIEW_RESIZED, w : X.Dom.w, h : X.Dom.h } ); + X.Dom._lock = false; + if( X.Dom._orientationFlag ){ + X.Dom._orientationFlag = false; + X.Dom.asyncDispatch( 100, { type : X.Dom.Event.VIEW_TURNED, orientation : window.orientation } ); + }; + }; + }, + + _init : function(){ + var s, size, h, r; + if( X.Dom.Event.DOM_PRE_INIT <= X.Dom.readyState ) return X.Callback.UN_LISTEN; + + console.log( 'X.Dom._init()' ); + + delete X.Dom._init; + // DOMContentLoaded の無いブラウザで X.Dom._init への参照が残り続けるのを回避 + Node._document.unlisten( 'DOMContentLoaded', X.Dom._init ); + + X.Dom.readyState = X.Dom.Event.DOM_PRE_INIT; + + X.Dom._root = document.compatMode !== 'CSS1Compat' ? document.body : document.documentElement || document.body; + + h = Node._html = document.documentElement ? + new Node( document.documentElement ) : + X.Dom.DOM_W3C ? + new Node( document.getElementsByTagName( 'html' )[ 0 ] ) : + X.Dom.DOM_IE4 ? + new Node( document.all.tags( 'html' )[ 0 ] ) : + null; + + r = Node._body = new Node( document.body ); + + Node.root = r; // 後方互換 + + h.appendTo = h.appendToRoot = h.before = h.after = h.clone = h.remove = h.destroy = h.prevNode = h.nextNode = h.createText = h.append = h.appendAt = h.empty = h.html = h.text = + r.appendTo = r.appendToRoot = r.before = r.after = r.clone = r.remove = r.destroy = r.prevNode = r.nextNode = new Function( 'return this' ); + + r._root = h._root = r; + r.parent = h; + h._xnodes = [ r ]; + + X.Dom.listenOnce( X.Dom.Event.DOM_PRE_INIT, function(){ + X.Dom.readyState = X.Dom.Event.DOM_BUILDER_COMPLETE; + !X.Dom._useBuilder && X.Dom.asyncDispatch( 0, { type : X.Dom.Event.DOM_BUILDER_COMPLETE } ); + } ); + + X.Dom.listenOnce( X.Dom.Event.DOM_BUILDER_COMPLETE, function(){ + X.Dom.readyState = X.Dom.Event.DOM_INIT; + //X.UA.Opera7 && alert( 'bc' ); + Node._body.appendAt( 0, + Node._systemNode = Node.create( 'div', { 'class' : 'hidden-system-node' } ), + Node._fontSizeNode = Node.create( 'div', { 'class' : 'hidden-system-node' } ).cssText( 'line-height:1;height:1em;' ).text( 'X' ) + )._startUpdate(); + + X.Dom.asyncDispatch( 0, { type : X.Dom.Event.DOM_INIT } ); + } ); + + X.Dom.listenOnce( X.Dom.Event.DOM_INIT, function(){ + var size = X.Dom._getSize(); + + if( X.Dom._orientationchange ){ + X.Dom.Node._window.listen( 'orientationchange', X.Dom._orientationchange ); + }; + + if( X.Dom._detectFontSize ){ + X.Dom.Node._window.listen( 'resize', X.Dom._resize ); + X.Timer.add( 333, X.Dom._detectFontSize ); + } else { + X.Timer.add( 333, X.Dom._resize ); + }; + + X.Dom.baseFontSize = Node._fontSizeNode._rawNode.offsetHeight; + + X.Dom.readyState = X.Dom.Event.XDOM_READY; + X.Dom.asyncDispatch( 0, { type : X.Dom.Event.XDOM_READY, w : X.Dom.w = size[ 0 ], h : X.Dom.h = size[ 1 ] } ); + } ); + + X.Dom.asyncDispatch( 0, { type : X.Dom.Event.DOM_PRE_INIT } ); + + Node._window + .listen( 'beforeunload', X.Dom ) + .listenOnce( 'unload', X.Dom ); + +//ブラウザの戻るボタンで戻ったときに呼ばれるイベントとかキャッシュとかそこらへんのこと +//http://d.hatena.ne.jp/koumiya/20080916/1221580149 + + if( document[ 'hidden' ] !== undefined ) {// iOS 7+ + Node._document.listen( 'visibilitychange', X.Dom ); + } else + if( document[ 'webkitHidden' ] !== undefined ) { + Node._document.listen( 'webkitvisibilitychange', X.Dom ); + } else + if( X.UA.iOS && window[ 'onpageshow' ] !== undefined ) { + Node._window.listen( 'pageshow', X.Dom ) + .listen( 'pagehide', X.Dom ); + } else { + Node._window.listen( 'focus', X.Dom ) + .listen( 'blur', X.Dom ); + }; + + return X.Callback.UN_LISTEN; + }, + + handleEvent : function( e ){ + var href; + switch( e.type ){ + case 'beforeunload' : + + // ie では a href="javascript" な要素でも beforeunload が起こる + href = e.target && e.target.attr( 'href' ); + if( href && href.indexOf && href.indexOf( 'javascript:' ) === 0 ) return X.Callback.PREVENT_DEFAULT | X.Callback.STOP_PROPAGATION; + + return X.Dom.dispatch( { type : X.Dom.Event.BEFORE_UNLOAD } ); + case 'unload' : + X.Dom.dispatch( { type : X.Dom.Event.UNLOAD } ); + + Node._window.unlisten(); + Node._document.unlisten(); + Node._html._actualRemove( true ); + break; + case 'visibilitychange' : + X.Dom.dispatch( { type : ( X.Dom.activate = document[ 'hidden' ] ) ? X.Dom.Event.VIEW_DEACTIVATE : X.Dom.Event.VIEW_ACTIVATE } ); + break; + case 'webkitvisibilitychange' : + X.Dom.dispatch( { type : ( X.Dom.activate = document[ 'webkitHidden' ] ) ? X.Dom.Event.VIEW_DEACTIVATE : X.Dom.Event.VIEW_ACTIVATE } ); + break; + case 'pageshow' : + case 'focus' : + X.Dom.activate = true; + X.Dom.dispatch( { type : X.Dom.Event.VIEW_ACTIVATE } ); + break; + case 'pagehide' : + case 'blur' : + X.Dom.activate = false; + X.Dom.dispatch( { type : X.Dom.Event.VIEW_DEACTIVATE } ); + break; + }; + }, + + listen : function( type ){ + if( type <= X.Dom.readyState ){ + /* + * X.Dom.Event.XDOM_READY 以後に listen した場合の対策 + */ + X.Dom.asyncDispatch( 0, { type : type, w : X.Dom.w, h : X.Dom.h } ); + }; + return X.EventDispatcher.prototype.listen.apply( X.Dom, arguments ); + }, + + getPointerPosition : function(){ + + }, + + /* 要素が視界に入った http://remysharp.com/2009/01/26/element-in-view-event-plugin/ */ + inView : function( elm ){ + + }, + + _getSize : + X.UA.IE ? + new Function( 'return[X.Dom._root.clientWidth,X.Dom._root.clientHeight]' ) : + new Function( 'return[window.innerWidth,window.innerHeight]' ), + + getSize : function(){ + return [ X.Dom.w, X.Dom.h ]; + }, +//https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect +//use window.pageXOffset and window.pageYOffset instead of window.scrollX and window.scrollY +//(((t = document.documentElement) || (t = document.body.parentNode)) && typeof t.ScrollLeft == 'number' ? t : document.body).ScrollLeft; +//(((t = document.documentElement) || (t = document.body.parentNode)) && typeof t.ScrollTop == 'number' ? t : document.body).ScrollTop + + getDocumentSize : function(){ + // Opera は互換モードでは document.body.scrollHeight、標準モードでは document.documentElement.scrollHeight でページの高さが取れる。と思ってたんだけど、例外があった。 + // http://orera.g.hatena.ne.jp/edvakf/20100515/1273908051 + //http://onozaty.hatenablog.com/entry/20060803/p1 + // Safari2.0.4では標準・互換どちらも document.body + + Node._body._updateTimerID && Node._body._startUpdate(); + /*X.UA.Opera ? + ( document.documentElement && document.documentElement.clientWidth ? + new Function( 'return[document.documentElement.clientWidth,document.documentElement.clientHeight]' ) : + new Function( 'return[document.body.clientWidth,document.body.clientHeight]' ) + ) :*/ + return [ + X.Dom._root.scrollWidth || X.Dom._root.offsetWidth, + X.Dom._root.scrollHeight || X.Dom._root.offsetHeight + ]; + }, + + getScrollPosition : + window.pageXOffset !== undefined ? + ( function(){ + Node._body._updateTimerID && Node._body._startUpdate(); + return[ window.pageXOffset, window.pageYOffset ]; + } ) : + window.scrollLeft !== undefined ? + ( function(){ + Node._body._updateTimerID && Node._body._startUpdate(); + return[ window.scrollLeft, window.scrollTop ]; + } ) : + ( function(){ + Node._body._updateTimerID && Node._body._startUpdate(); + // body は Safari2- + return[ X.Dom._root.scrollLeft || document.body.scrollLeft, X.Dom._root.scrollTop || document.body.scrollTop ]; + } ), + + getScrollbarSize : function(){ + return [ X.Dom.BoxModel.vScrollbarSize, X.Dom.BoxModel.hScrollbarSize ]; + } + } +); + +if( !( X.UA.IE < 9 ) ){ + X.Dom._detectFontSize = function(){ + var size = Node._fontSizeNode._rawNode.offsetHeight; + if( X.Dom.baseFontSize !== size ){ + X.Dom.baseFontSize && X.Dom.asyncDispatch( 0, { type : X.Dom.Event.BASE_FONT_RESIZED, fontSize : size, w : X.Dom.w, h : X.Dom.h } ); + X.Dom.baseFontSize = size; + }; + }; +}; + +/* + * http://d.hatena.ne.jp/t-uchima/20051003/p1 + * MacIEにはattachEventが一応あるけどwindow.attachEventとdocument.attachEventしかなく他の要素にはattachEventはない。 + */ +if( X.UA.MacIE ){ + X.Dom.DOM_W3C = true; + X.Dom.EVENT_DOM0 = true; +} else +if( X.UA.IE4 ){ // ie4 & iemobi4 + X.Dom.DOM_IE4 = true; + X.Dom.EVENT_DOM0 = true; +} else +if( document.getElementById ){ + X.Dom.DOM_W3C = true; + if( document.addEventListener ){ + X.Dom.EVENT_W3C = true; + } else + if( document.attachEvent ){ + X.Dom.EVENT_IE = true; + } else { + X.Dom.EVENT_DOM0 = true; + }; +} else +if( document.all ){ + X.Dom.DOM_IE4 = true; + X.Dom.EVENT_DOM0 = true; +} else +if( document.layers ){ + +} else { + +}; + +X.Dom.EVENT_POINTER = navigator.msPointerEnabled || navigator.pointerEnabled; +X.Dom.EVENT_TOUCH = !X.Dom.EVENT_POINTER && window.ontouchstart !== undefined; + +X.Dom.moveToHead = { + STYLE : true, + LINK : true, + TITLE : true, + BGSOUND : true, + AREA : true, + BASE : true, + META : true +}; + +X.Dom.cleanupTagNames = { + SCRIPT : true, + NOSCRIPT : true, + NOFRAMES : true, + '!' : true, // ie + COMMENT : true, // ie + NOEMBED : true, + NOLAYER : true + }; +X.Dom.skipCleanupTagNames = { + PRE : true, + TEXTAREA : true, + CODE : true, + KBD : true, + SAMP : true, + XMP : true, + PLAINTEXT : true, + LISTING : true +}; + +X.Dom.CRLF = String.fromCharCode( 13 ) + String.fromCharCode( 10 ); + +X.Dom.cleanupWhiteSpace = function( text ){ + var _ = ' ', __ = ' ', CRLF = X.Dom.CRLF; + //text.indexOf( CRLF ) !== -1 && ( text = text.split( CRLF ).join( _ ) ); + text.indexOf( '\n\r' ) !== -1 && ( text = text.split( '\n\r' ).join( _ ) ); + text.indexOf( '\t' ) !== -1 && ( text = text.split( '\t' ).join( _ ) ); + text.indexOf( '\r' ) !== -1 && ( text = text.split( '\r' ).join( _ ) ); + text.indexOf( '\n' ) !== -1 && ( text = text.split( '\n' ).join( _ ) ); + text.indexOf( '\f' ) !== -1 && ( text = text.split( '\f' ).join( _ ) ); + text.indexOf( '\b' ) !== -1 && ( text = text.split( '\b' ).join( _ ) ); + while( text.indexOf( __ ) !== -1 ){ + text = text.split( __ ).join( _ ); + }; + return text; +}; + +X.Dom.whiteSpaceToTag = function( text ){ + if( text == null ) return ''; + return text.toString() + //.split( '\r\n\r\n' ).join( '
' ) + //.split( '\n\r\n\r' ).join( '
' ) + //.split( '\r\n' ).join( '
' ) + .split( '\n\r' ).join( '
' ) + .split( '\r' ).join( '
' ) + .split( '\n' ).join( '
' ) + .split( '\t' ).join( '    ' ) + .split( '\f' ).join( '' ) + .split( '\b' ).join( '' ); +}; + +X.Dom.chrReferanceTo = function( str ){ + if( str == null ) return ''; + return str.toString() + .split( '&' ).join( '&' ) + .split( '<' ).join( '<' ) + .split( '>' ).join( '>' ) + .split( ' ' ).join( ' ' ); +}; + +/* + * original + * AS3で相対パスを絶対パスに変換する + * http://www.shin-go.net/motionlab/?p=449 + */ +X.Dom.baseURL = ( function( parts ){ + var last = 1 < parts.length && parts[ parts.length - 1 ]; + if( last !== false && ( last === '' || //末尾が/で終わるとき + last.indexOf( '.' ) !== -1 ) ){//末尾がファイル名で終わる時 + + --parts.length; + }; + return parts.join( '/' ); +})( location.href.split( '?' )[ 0 ].split( '#' )[ 0 ].split( '/' ) ); + +X.Dom.getAbsolutePath = function( path ){ + var s = '/', + ss = '//', + _ary, ary, i = 0; + + if( 'http:file'.indexOf( path.substr( 0, 4 ) ) !== -1 ) return path; + + _ary = X.Dom.baseURL.split( ss ); + ary = _ary[ 1 ].split( s ); + + if( path.charAt( 0 ) === s ) return [ _ary[ 0 ], ss, ary[ 0 ], path ].join( '' ); + + if( path.substr( 0, 2 ) === './' ){ + path = path.substr( 2 ); + } else { + while( path.substr( i, 3 ) === '../' ){ + --ary.length; + i += 3; + }; + if( i ) path = path.substr( i ); + }; + return [ _ary[ 0 ], ss, ary.join( s ), s, path ].join( '' ); +}; + +if( window[ 'orientation' ] !== undefined ){ + X.Dom._orientationchange = function( e ){ + X.Dom._orientationFlag = true; + !X.UA.Android && X.Dom._resize(); + console.log( '-- orientationchange : ' + X.getTime() ); + }; +}; + + +console.log( 'X.Dom dom:w3c=' + X.Dom.DOM_W3C + ' ev:w3c=' + X.Dom.EVENT_W3C );