NONE : 0,\r
UN_LISTEN : 1,\r
STOP_PROPAGATION : 2, // 上位階層への伝播のキャンセル\r
- STOP_NOW : 4, // 同一階層のリスナーのキャンセル\r
+ STOP_NOW : 4 | 2, // 同一階層のリスナーのキャンセル(上位へもキャンセル)\r
PREVENT_DEFAULT : 8, // 結果動作のキャンセル,\r
MONOPOLY : 16, // move event を独占する\r
- SYS_CANCEL : 32,\r
+ SYS_CANCEL : 32 | 4 | 2,\r
\r
_LIVE_LIST : [],\r
_POOL_LIST : [],\r
/**\r
* use X.Callback\r
+ * \r
+ * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.addEventListener\r
+ * イベント発送中のリスナーの追加\r
+ * EventListener がイベント処理中に EventTarget に追加された場合、それが現在のアクションによって実行されることはありませんが、浮上フェーズのように、後の段階のイベントフローで実行されるかもしれません。\r
+ * \r
+ * https://developer.mozilla.org/ja/docs/Web/API/EventTarget.removeEventListener\r
+ * イベントリスナーが イベントを処理中であるイベントターゲットから削除された場合、現在のアクションによってそのイベントリスナーが実行されることはありません。\r
+ * イベントリスナーは、決して削除された後に実行されることはありません。\r
+ * イベントターゲット上にある現在のどのイベントリスナーも指定していない引数付きの removeEventListener は、何の効果もありません。\r
*/\r
\r
X.Event = {\r
// todo\r
// reserve\r
if( !this._reserves ) this._reserves = [];\r
- this._reserves[ this._reserves.length ] = [ type, arg1, arg2, arg3 ];\r
+ this._reserves[ this._reserves.length ] = [ type, arg1, arg2, arg3, X.EventDispatcher._once ];\r
return this;\r
} else\r
if( this.listening( type, arg1, arg2, arg3 ) ) return this;\r
if( list = this._reserves ){\r
for( i = 0, l = list.length; i < l; ++i ){\r
f = list[ i ];\r
+ X.EventDispatcher._once = f[ 4 ];\r
this.listen( f[ 0 ], f[ 1 ], f[ 2 ], f[ 3 ] );\r
+ X.EventDispatcher._once = false;\r
f.length = 0;\r
};\r
list.length = 0;\r
X.Dom.EVENT_DOM0 = true;\r
};\r
\r
+X.Dom.moveToHead = {\r
+ STYLE : true,\r
+ BGSOUND : true,\r
+ AREA : true,\r
+ BASE : true,\r
+ META : true\r
+};\r
+\r
X.Dom.cleanupTagNames = {\r
- noscript : 1,\r
- noframes : 1,\r
- '!' : 1,\r
- noembed : 1,\r
- nolayer : 1\r
+ SCRIPT : true,\r
+ NOSCRIPT : true,\r
+ NOFRAMES : true,\r
+ '!' : true, // ie\r
+ COMMENT : true, // ie\r
+ NOEMBED : true,\r
+ NOLAYER : true\r
};\r
-X.Dom.skipCleanupTagNames = 'pre,textarea,code,kbd,samp,xmp,plaintext,listing'.split( ',' );\r
+X.Dom.skipCleanupTagNames = {\r
+ PRE : true,\r
+ TEXTAREA : true,\r
+ CODE : true,\r
+ KBD : true,\r
+ SAMP : true,\r
+ XMP : true,\r
+ PLAINTEXT : true,\r
+ LISTING : true\r
+};\r
\r
X.Dom.cleanupWhiteSpace = function( text ){\r
var _ = ' ', __ = ' ';\r
\r
X.Dom.DTD = {\r
- EMPTY : {area:1,base:1,basefont:1,br:1,col:1,frame:1,hr:1,img:1,input:1,isindex:1,link:1,meta:1,param:1,embed:1 },//,\r
+ EMPTY : {\r
+ AREA:true,\r
+ BASE:true,\r
+ BASEFONT:true,\r
+ BR:true,\r
+ COL:true,\r
+ FRAME:true,\r
+ HR:true,\r
+ IMG:true,\r
+ INPUT:true,\r
+ ISINDEX:true,\r
+ LINK:true,\r
+ META:true,\r
+ PARAM:true,\r
+ EMBED:true\r
+ },//,\r
\r
TAG_FIX :\r
X.UA.IE && 4 <= X.UA.IE && X.UA.IE < 5 ?\r
- { ABBR : 'acronym', BDO : '', RUBY : '' } :\r
+ { ABBR : 'ACRONYM', BDO : '', RUBY : '' } :\r
X.UA.IE && 5 <= X.UA.IE && X.UA.IE < 7 ?\r
- { ABBR : 'acronym' } :\r
+ { ABBR : 'ACRONYM' } :\r
{},\r
\r
// video:1,audio:1}\r
this._xnodeType = 1;\r
this._state = X.Dom.State.DISPLAY_INLINE; // todo\r
arguments[ 1 ] && this.attr( arguments[ 1 ] );\r
- css = arguments[ 2 ];\r
+ css = arguments[ 2 ] || arguments[ 1 ];\r
css && this[ X.Type.isString( css ) ? 'cssText' : 'css' ]( css );\r
} else\r
if( Node._newByText ){\r
if( xnodes.length ) return xnodes[ 0 ];\r
return Node.none;\r
case Node.IS_IMAGE :\r
- v.UID = uid;\r
- this._isImage = true;\r
+ if( xnode = Node._getXNode( v ) ) return xnode;\r
+ this._rawNode = v;\r
+ this._xnodeType = 4;\r
+ v.UID = uid;\r
+ this._state = X.Dom.State.EXIST;\r
+ break;\r
case Node.IS_WINDOW :\r
case Node.IS_DOCUMENT :\r
if( xnode = Node._getXNode( v ) ) return xnode;\r
case Node.IS_DOCUMENT :\r
return Node._document;\r
case Node.IS_RAW_TEXT :\r
+ if( v.UID ) return Node._chashe[ v.UID ];\r
for( chashe = Node._chashe, i = chashe.length; i; ){\r
if( ( xnode = Node._chashe[ --i ] ) && ( xnode._rawNode === v ) ) return xnode;\r
};\r
X.Dom.DOM_IE4 ?\r
X.emptyFunction :\r
(function( root ){\r
- return root._rawNode.createElement( 'p' ).tagName !== root._rawNode.createElement( 'P' ).tagName;\r
+ if( X.Type.isBoolean( root.isXML ) ) return root.isXML;\r
+ return root.isXML = root._rawNode.createElement( 'p' ).tagName !== root._rawNode.createElement( 'P' ).tagName;\r
});\r
\r
Node._chashe = [];\r
};\r
if( Node._outerFlag === this ) Node._outerFlag = null;\r
};\r
- !Node._outerFlag || X.Dom.DTD.EMPTY[ this._tag.toLowerCase() ] || ( html[ n ] = '<\/' + this._tag + '>' );\r
+ !Node._outerFlag || X.Dom.DTD.EMPTY[ this._tag ] || ( html[ n ] = '<\/' + this._tag + '>' );\r
return html.join( _ );\r
};\r
\r
};\r
( v = attrs[ k ] ) === undefined ?\r
elm.removeAttribute( rename[ k ] || k ) :\r
- ( elm[ rename[ k ] || k ] = v );\r
+ ( elm[ rename[ k ] || k ] = v ); \r
+\r
};\r
delete this._newAttrs;\r
};\r
}; \r
};\r
};\r
- X.Dom.DTD.EMPTY[ this._tag.toLowerCase() ] || ( html[ n ] = '<\/' + this._tag + '>' );\r
+ X.Dom.DTD.EMPTY[ this._tag ] || ( html[ n ] = '<\/' + this._tag + '>' );\r
\r
delete this._newAttrs;\r
};\r
var raw = this._rawNode;\r
if( !raw ) return;\r
this._handleEvent = this._handleEvent || X.Callback.create( this );\r
- if( this._isImage ){\r
+ if( this._xnodeType === 4 ){ // Image\r
raw[ 'on' + type ] = this._handleEvent;\r
} else {\r
raw.addEventListener( type, this._handleEvent, false );\r
var raw = this._rawNode;\r
if( !raw ) return;\r
\r
- if( raw.constructor === Image ){\r
+ if( this._xnodeType === 4 ){ // Image\r
raw[ 'on' + type ] = '';\r
} else {\r
raw.removeEventListener( type, this._handleEvent, false );\r
// safari1.3 可\r
// http://shimax.cocolog-nifty.com/search/2006/09/safarijavascrip_c54d.html\r
\r
-// Re: onLoad doesn't work with Safari?\r
-// http://lists.apple.com/archives/web-dev/2003/Oct/msg00036.html\r
-if( X.UA.Safari && X.UA.Safari < 3 ){\r
- X.Timer.add( 10, function(){\r
- if( !X.Dom._init ) return X.Callback.UN_LISTEN;\r
- if( 'loaded|complete'.indexOf( document.readyState ) !== -1 ) return X.Dom._init();\r
- } );\r
-} else\r
-\r
/* for ie9+/Mozilla/Opera9 */\r
if( X.Dom.DOM_W3C ){\r
Node._document.listenOnce( 'DOMContentLoaded', X.Dom._init );\r
this.readyState === 'complete' && X.Dom._init();\r
};\r
} else\r
-if( X.UA.WebKit ){ // sniff\r
+// Re: onLoad doesn't work with Safari?\r
+// http://lists.apple.com/archives/web-dev/2003/Oct/msg00036.html\r
+if( X.UA.WebKit || ( X.UA.Safari && X.UA.Safari < 3 ) ){ // sniff\r
X.Timer.add( 10, function(){\r
if( !X.Dom._init ) return X.Callback.UN_LISTEN;\r
if( 'loaded|complete'.indexOf( document.readyState ) !== -1 ) return X.Dom._init();\r
* \r
*/\r
X.Dom.Node.prototype.attr = function( nameOrObj /* v */ ){\r
- var attrs = this._attrs, newAttrs, f, p;\r
+ var attrs = this._attrs, newAttrs, f, p, elm;\r
\r
if( this._xnodeType !== 1 ) return this;\r
\r
uid, tmp, xnode, filter, key, op, val, toLower, useName,\r
links, className, attr, flag;\r
\r
- /*@cc_debug[ */\r
- if( X.Dom.readyState < X.Dom.Event.XDOM_READY ){ alert( 'not ready! X.Dom.listen( X.Dom.Event.XDOM_READY, callback )' ); };\r
- /*]@cc_debug */\r
+ /*@+debug[*/\r
+ if( X.Dom.readyState < X.Dom.Event.XDOM_READY ){\r
+ alert( 'not ready! X.Dom.listen( X.Dom.Event.XDOM_READY, callback )' );\r
+ return;\r
+ };\r
+ /*]@+debug*/\r
\r
// 文字列以外は空で返す\r
if( typeof queryString !== 'string' ) return ret;\r
};\r
};\r
X.Dom.Parser.closeSelf[ tagLower ] === 1 && ( last === tagName || ( sisters[ tagLower ] && sisters[ tagLower ][ last.toLowerCase() ] === 1 ) ) && parseEndTag( stack, handler, last );\r
- unary = X.Dom.Parser.empty[ tagLower ] === 1 || !!unary;\r
+ unary = X.Dom.Parser.empty[ tagName.toUpperCase() ] || !!unary;\r
!unary && ( stack[ stack.length ] = tagName );\r
\r
return handler.start( tagName, attrs, unary, index );\r
delay : null,\r
timeout : 0,\r
Constructor : function( abspath, delay, timeout ){\r
- var img, s, p;\r
+ var img;\r
\r
this.abspath = abspath;\r
this.delay = delay || 100;\r
/* --------------------------------------\r
* 通常のwebページに対して使用する場合、dom ready で dom tree を写し取るために使う.\r
* 完全にワンページアプリで<body/>が空な場合、このコードはビルドに含める必要はない\r
+ * \r
+ * TODO (注4) IE6 の空白に関する“癖”について\r
+ * http://kojs.sukobuto.com/docs/visible-binding\r
+ * IE6 には、「空の span エレメントに続く空白は無視される」という謎な癖があります。 \r
*/\r
X.Dom.listenOnce( X.Dom.Event.DOM_PRE_INIT,\r
X.Dom.DOM_W3C ?\r
\r
// cleanup tree \r
(function/*cleanUpTree*/( elm, skip, head ){\r
- var moveToHead = 'style,bgsound,area,base,meta'.split( ',' ),\r
- remove = 'script,noscript,noframes,comment,!,noembed,nolayer'.split( ',' ),\r
- noncleanup = 'pre,textarea,code,kbd,samp,xmp,plaintext,listing'.split( ',' ),\r
- nodes = X.copyArray( elm.childNodes ),\r
+ var nodes = X.copyArray( elm.childNodes ),\r
i = 0,\r
l = nodes.length,\r
node, tag, textNode, content;\r
node = nodes[ i ];\r
switch( node.nodeType ){\r
case 1 :\r
- tag = node.tagName.toLowerCase();\r
- if( moveToHead.indexOf( tag ) !== -1 ){\r
+ tag = node.tagName.toUpperCase();\r
+ if( X.Dom.moveToHead[ tag ] ){\r
head = head || document.getElementsByTagName( 'head' )[ 0 ];\r
head.appendChild( node );\r
continue;\r
} else\r
- if( remove.indexOf( tag ) !== -1 ){\r
+ if( X.Dom.cleanupTagNames[ tag ] ){\r
elm.removeChild( node );\r
continue;\r
} else {\r
// pre タグ以下はスペースの置換は行わない\r
- node.childNodes && node.childNodes.length && /*cleanUpTree*/arguments.callee( node, skip || noncleanup.indexOf( tag ) !== -1, head );\r
+ node.childNodes && node.childNodes.length && /*cleanUpTree*/arguments.callee( node, skip || X.Dom.skipCleanupTagNames[ tag ], head );\r
};\r
textNode = null;\r
break;\r
\r
for( ; current.j < m; ++current.j ){\r
elm = elems[ current.j ];\r
- tag = elm.tagName;\r
+ tag = elm.tagName && elm.tagName.toUpperCase();\r
if( ( elm.nodeType !== 1 && elm.nodeType !== 3 ) || tag === '!' || ( tag && tag.charAt( 0 ) === '/' ) ){\r
elm.parentNode.removeChild( elm );\r
continue;\r
//};\r
alert( '[' +parent._tag + '>' +xnode._tag + '] !== ' + elm.nodeType + '\n' + elm.data );\r
} else\r
- if( xnode._tag.toUpperCase() !== tag ){\r
+ if( xnode._tag !== tag ){\r
alert( '[' +parent._tag + '>' +xnode._tag + ' ' + (xnode._xnodes ? xnode._xnodes.length : '' ) + '] !== ' + tag + ' ' + (elm.childNodes ? elm.childNodes.length : '' ) + '\n' + elm.outerHTML );\r
} else {\r
xnode._rawNode = elm;\r
//if( ( doc = elm.ownerDocument || elm.document ) && ( doc.createElement( 'p' ).tagName === doc.createElement( 'P' ).tagName ) ){\r
if( tag.charAt( 0 ) === '/' ) tag = tag.slice( 1 );\r
- xnode._tag = tag; // .toUpperCase()\r
+ xnode._tag = tag;\r
//};\r
xnode._root = parent._root;\r
elm.UID = xnode._uid;\r
xnode.attr( 'value', xnode.html() ).empty();\r
current.xtext = null;\r
} else\r
- if( !xnode.hasClass( 'skip-cleanup' ) && ( X.Dom.cleanupTagNames[ tag.toLowerCase() ] || tag === 'SCRIPT' || xnode.hasClass( 'cleanup-target' ) ) ){ // ie で body 内の script が2度よばれるのに対処\r
+ if( !xnode.hasClass( 'skip-cleanup' ) && ( X.Dom.cleanupTagNames[ tag ] || xnode.hasClass( 'cleanup-target' ) ) ){ // ie で body 内の script が2度よばれるのに対処\r
//alert( '[' +parent._tag + '>' + xnode._tag + '] remove ... ' );\r
xnode.destroy();\r
} else\r
l : xnode._xnodes.length,\r
elems : X.copyArray( elm.childNodes ),\r
j : 0,\r
- skipCleanup : skipCleanup || 0 <= X.Dom.skipCleanupTagNames.indexOf( tag.toLowerCase() )\r
+ skipCleanup : skipCleanup || X.Dom.skipCleanupTagNames[ tag ]\r
};\r
};\r
};\r
xnode._rawNode = elm;\r
xnode._root = parent._root;\r
//xnode._tag = X.Dom.DTD.TAG_FIX[ tag ] || tag;\r
- if( !xnode.hasClass( 'skip-cleanup' ) && ( X.Dom.cleanupTagNames[ tag.toLowerCase() ] || tag === 'SCRIPT' || xnode.hasClass( 'cleanup-target' ) ) ){\r
+ if( !xnode.hasClass( 'skip-cleanup' ) && ( X.Dom.cleanupTagNames[ tag ] || xnode.hasClass( 'cleanup-target' ) ) ){\r
xnode.destroy();\r
break;\r
};\r
l : xnode._xnodes.length,\r
elems : X.copyArray( elm.children ),\r
j : 0,\r
- skipCleanup : skipCleanup || 0 <= X.Dom.skipCleanupTagNames.indexOf( tag.toLowerCase() )\r
+ skipCleanup : skipCleanup || X.Dom.skipCleanupTagNames[ tag ]\r
};\r
};\r
break;\r