OSDN Git Service

Version 0.6.137, fix X.EventDispatcher.unlisten & remove X.Node.destroy.
[pettanr/clientJs.git] / 0.6.x / js / 02_dom / 02_XNode.js
index b3e6576..ab3d01c 100644 (file)
@@ -109,7 +109,7 @@ var X_Node_BITMASK_RESET_STYLE  = ( ( 2 << 29 ) - 1 + ( 2 << 29 ) ) ^ (
  */\r
 var    Node = X[ 'Node' ] = X_EventDispatcher[ 'inherits' ](\r
        'X.Node',\r
-       X_Class.POOL_OBJECT, // X_Class.FINAL\r
+       X_Class.POOL_OBJECT,\r
        \r
        {\r
                /**\r
@@ -313,8 +313,8 @@ var Node = X[ 'Node' ] = X_EventDispatcher[ 'inherits' ](
                                                return X_Node_none;\r
 \r
                                        default :\r
-                                               this.length = 0;\r
                                                if( X_Node_none ) return X_Node_none;\r
+                                               this.length = 0;\r
                                                return;\r
                                };\r
                        };\r
@@ -324,6 +324,8 @@ var Node = X[ 'Node' ] = X_EventDispatcher[ 'inherits' ](
                        };\r
                        this[ '_flags' ] |= X_Node_State.EXIST;\r
                        X_Node_CHASHE[ this[ '_uid' ] = uid ] = this;\r
+                       \r
+                       X_EventDispatcher_systemListen( this, X_EVENT_BEFORE_KILL_INSTANCE, X_Node_onBeforeKill );\r
                },\r
                \r
                // attr\r
@@ -347,9 +349,9 @@ var Node = X[ 'Node' ] = X_EventDispatcher[ 'inherits' ](
                \r
                'appendTo'       : X_Node_appendTo,\r
                \r
-               'prev'           : X_Node_before,\r
+               'prev'           : X_Node_prev,\r
                \r
-               'next'           : X_Node_after,\r
+               'next'           : X_Node_next,\r
                \r
                'swap'           : X_Node_swap,\r
                \r
@@ -357,13 +359,11 @@ var       Node = X[ 'Node' ] = X_EventDispatcher[ 'inherits' ](
                \r
                'empty'          : X_Node_empty,\r
                \r
-               destroy          : X_Node_destroy, // -> kill && kill event\r
-               \r
                'contains'       : X_Node_contains,\r
                \r
                'getChildAt'     : X_Node_getChildAt,\r
                \r
-               'numChildren'    : X_Node_length,\r
+               'numChildren'    : X_Node_numChildren,\r
                \r
                'firstChild'     : X_Node_firstChild,\r
                \r
@@ -397,6 +397,7 @@ function X_Node_getType( v ){
        if( X_Type_isString( v ) ){\r
                return '<' === v.charAt( 0 ) && v.charAt( v.length - 1 ) === '>' ? X_Node_TYPE.HTML_STRING : X_Node_TYPE.STRING;\r
        };\r
+       if( v[ 'instanceOf' ] && v[ 'instanceOf' ]( Node ) ) return X_Node_TYPE.XNODE;\r
        return 0;\r
 };\r
 function X_Node_getXNode( v ){\r
@@ -437,7 +438,7 @@ var X_Node_isXmlDocument =
                                return root.isXML = root[ '_rawObject' ].createElement( 'p' ).tagName !== root[ '_rawObject' ].createElement( 'P' ).tagName;\r
                        }),\r
        X_Node_CHASHE     = [],\r
-       X_Node_none  = X_Node_CHASHE[ 0 ] = new Node(),\r
+       X_Node_none  = X_Node_CHASHE[ 0 ] = Node(),\r
        X_Node_html, // = X_Node_CHASHE[ 1 ] <html>\r
        X_Node_head, // = X_Node_CHASHE[ 2 ] <head>\r
        X_Node_body, // = X_Node_CHASHE[ 3 ] <body>\r
@@ -562,7 +563,7 @@ function X_Node_clone( opt_clone_children ){
        var xnode, xnodes, i, l;\r
        if( this[ '_tag' ] ){\r
                X_Node_newByTag = true;\r
-               xnode = new Node( this[ '_tag' ], X_Object_clone( this[ '_attrs' ] ), X_Object_clone( this[ '_css' ] ) )\r
+               xnode = Node( this[ '_tag' ], X_Object_clone( this[ '_attrs' ] ), X_Object_clone( this[ '_css' ] ) )\r
                        [ 'attr' ]( { 'id' : this[ '_id' ] } )\r
                        [ 'className' ]( this[ '_className' ] );\r
                if( opt_clone_children && ( xnodes = this[ '_xnodes' ] ) && ( l = xnodes.length ) ){\r
@@ -573,12 +574,12 @@ function X_Node_clone( opt_clone_children ){
                return xnode;           \r
        };\r
        X_Node_newByText = true;\r
-       return new Node( this[ '_text' ] );\r
+       return Node( this[ '_text' ] );\r
 };\r
 \r
 /**\r
  * ノードを子配列の最後に追加する。文字列が渡された場合、HTMLパーサーによって Node ツリーを作成して追加する。HtmlElement, TextNode の場合は内部使用専用。\r
- * @alias Node.prototype.clone\r
+ * @alias Node.prototype.append\r
  * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。\r
  * @return {Node} 自身。チェインメソッド\r
  * @example myNode.append( node );\r
@@ -600,7 +601,7 @@ function X_Node_append( v ){
        switch( X_Node_getType( v ) ){\r
                case X_Node_TYPE.RAW_HTML :\r
                case X_Node_TYPE.RAW_TEXT :\r
-                       v = new Node( v );\r
+                       v = Node( v );\r
                        break;\r
                case X_Node_TYPE.HTML_STRING :\r
                case X_Node_TYPE.STRING :\r
@@ -627,7 +628,7 @@ function X_Node_append( v ){
 \r
 /**\r
  * ノードを挿入位置に追加する。\r
- * @alias Node.prototype.clone\r
+ * @alias Node.prototype.appendAt\r
  * @param {number} index 挿入位置 0以上\r
  * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。\r
  * @return {Node} 自身。チェインメソッド\r
@@ -659,7 +660,7 @@ function X_Node_appendAt( start, v ){
        switch( X_Node_getType( v ) ){\r
                case X_Node_TYPE.RAW_HTML :\r
                case X_Node_TYPE.RAW_TEXT :\r
-                       v = new Node( v );\r
+                       v = Node( v );\r
                        break;\r
                case X_Node_TYPE.HTML_STRING :\r
                case X_Node_TYPE.STRING :\r
@@ -688,10 +689,18 @@ function X_Node_appendAt( start, v ){
        return this;\r
 };\r
 \r
+/**\r
+ * ノードを親に追加する。戻り値は子ノードなので、続けて操作が出来る。\r
+ * @alias Node.prototype.appendTo\r
+ * @param {Node|string|HTMLElement} [parent] HTMLElement は内部のみ。\r
+ * @param {number} [opt_index=-1] 挿入位置。省略した場合は最後に追加する。\r
+ * @return {Node} 自身。チェインメソッド\r
+ * @example childNode.appendTo( parentNode, 1 );\r
+ */\r
 function X_Node_appendTo( parent, opt_index ){\r
        switch( X_Node_getType( parent ) ){\r
                case X_Node_TYPE.RAW_HTML :\r
-                       parent = new Node( parent );\r
+                       parent = Node( parent );\r
                        break;\r
                case X_Node_TYPE.HTML_STRING :\r
                        parent = X_HtmlParser_parse( parent, true );\r
@@ -701,14 +710,19 @@ function X_Node_appendTo( parent, opt_index ){
                default :\r
                        return this;\r
        };\r
-       opt_index === undefined ? parent[ 'append' ]( this ) : parent[ 'appendAt' ]( opt_index, this );\r
+       X_Type_isFinite( opt_index ) ? parent[ 'appendAt' ]( opt_index, this ) : parent[ 'append' ]( this );\r
        return this;\r
 };\r
 \r
-/* --------------------------------------\r
- *  Before , After, Replace\r
+\r
+/**\r
+ * ノードの直前の要素を取得。または直前に挿入。\r
+ * @alias Node.prototype.prev\r
+ * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。\r
+ * @return {Node} 自身。チェインメソッド\r
+ * @example childNode.prev( prevNode );\r
  */\r
-function X_Node_before( v ){\r
+function X_Node_prev( v ){\r
        var parent = this.parent, xnodes, i, l, start;\r
        \r
        // getter\r
@@ -733,7 +747,14 @@ function X_Node_before( v ){
        return this;\r
 };\r
 \r
-function X_Node_after( v ){\r
+/**\r
+ * ノードの直後の要素を取得。または直後に挿入。\r
+ * @alias Node.prototype.next\r
+ * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。\r
+ * @return {Node} 自身。チェインメソッド\r
+ * @example childNode.next( prevNode );\r
+ */\r
+function X_Node_next( v ){\r
        var parent = this.parent, xnodes, i, l, start;\r
        \r
        // getter\r
@@ -768,13 +789,23 @@ function X_Node_after( v ){
        return this;\r
 };\r
 \r
+/**\r
+ * 要素の入れ替え。自身は remove() される。\r
+ * @alias Node.prototype.swap\r
+ * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。\r
+ * @return {Node} 自身。チェインメソッド\r
+ * @example node.swap( newNode );\r
+ */\r
 function X_Node_swap( v ){\r
        if( !this.parent ) return this;\r
-       return arguments.length === 1 ? this[ 'prev' ]( v )[ 'remove' ]() : X_Node_before.apply( this, arguments )[ 'remove' ]();\r
+       return arguments.length === 1 ? this[ 'prev' ]( v )[ 'remove' ]() : X_Node_prev.apply( this, arguments )[ 'remove' ]();\r
 };\r
 \r
-/* --------------------------------------\r
- *  Remove\r
+/**\r
+ * 要素を抜く。\r
+ * @alias Node.prototype.remove\r
+ * @return {Node} 自身。チェインメソッド\r
+ * @example node.remove();\r
  */\r
 function X_Node_remove(){\r
        var parent = this.parent,\r
@@ -809,54 +840,30 @@ function X_Node_remove(){
        return this;\r
 };\r
 \r
+/**\r
+ * 子要素を破棄する。子要素は kill() されます。\r
+ * @alias Node.prototype.empty\r
+ * @return {Node} 自身。チェインメソッド\r
+ * @example node.empty();\r
+ */\r
 function X_Node_empty(){\r
        var xnodes = this[ '_xnodes' ], i;\r
        if( xnodes && ( i = xnodes.length ) ){\r
                for( ; i; ){\r
-                       xnodes[ --i ].destroy();\r
+                       xnodes[ --i ][ 'kill' ]();\r
                };\r
                xnodes.length = 0;\r
        };\r
        return this;\r
 };\r
 \r
-/* --------------------------------------\r
- *  TODO destory -> kill\r
- */\r
-\r
-function X_Node_destroy( isChild ){\r
-       var xnodes = this[ '_xnodes' ], i, elm;\r
-       \r
-       if( ( this[ '_flags' ] & X_Node_State.EXIST ) === 0 ) return;\r
-       \r
-       elm = this[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this );\r
-       \r
-       if( xnodes && ( i = xnodes.length ) ){\r
-               //for( ; i; ){\r
-               //      xnodes[ --i ].destroy( true );\r
-               //};\r
-       };\r
-       elm && this[ '_listeners' ] && this[ 'unlisten' ](); // イベントの退避\r
-\r
-       if( this[ '_flags' ] & X_Node_State.IN_TREE ){\r
-               !isChild && this[ 'remove' ]();\r
-               this[ '_flags' ] &= ~X_Node_State.EXIST;\r
-       } else {\r
-               this.parent && this.parent[ '_xnodes' ].splice( this.parent[ '_xnodes' ].indexOf( this ), 1 );\r
-               elm && !isChild && X_Node__actualRemove( this );\r
-               this[ 'kill' ]();\r
-       };\r
-       \r
-       delete X_Node_CHASHE[ this[ '_uid' ] ];\r
-};\r
-\r
 function X_Node_onBeforeKill( e ){\r
        var xnodes = this[ '_xnodes' ], i, elm;\r
        \r
        if( ( this[ '_flags' ] & X_Node_State.EXIST ) === 0 ) return X_Callback_NONE;\r
        \r
        elm = this[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this );\r
-       elm && this[ '_listeners' ] && this[ 'unlisten' ](); // イベントの退避\r
+       elm && this[ '_listeners' ] && X_EventDispatcher_unlistenAll( this ); // イベントの退避\r
 \r
        if( xnodes && ( i = xnodes.length ) ){\r
                for( ; i; ){\r
@@ -877,64 +884,100 @@ function X_Node_onBeforeKill( e ){
 };\r
 \r
 \r
-/* --------------------------------------\r
- *  contains\r
+/**\r
+ * 要素を子以下に持つか?調べる。\r
+ * @alias Node.prototype.contains\r
+ * @param {Node|string|HTMLElement|TextNode} [v] HTMLElement と TextNode は内部のみ。\r
+ * @return {boolean} \r
+ * @example node.contains( testNode );\r
  */\r
 function X_Node_contains( v ){\r
        var elm, type, xnodes, i;\r
        if( !v || !this[ '_tag' ] || this === v ) return false;\r
        // contains ie4+\r
        if( ( elm = this[ '_rawObject' ] || X_UA_DOM.IE4 && X_Node__ie4getRawNode( this ) ) && document.contains && ( type = X_Node_getType( v ) ) && ( type === X_Node_TYPE.RAW_HTML || type === X_Node_TYPE.RAW_TEXT ) ){\r
-               return elm[ 'contains' ]( v );  \r
+               return elm.contains( v );\r
        };\r
+\r
        //if( document.compareDocumentPosition ){\r
        //      \r
        //};\r
        xnodes = this[ '_xnodes' ];\r
        if( !xnodes || !xnodes.length ) return false;\r
        if( xnodes.indexOf( v ) !== -1 ) return true; // fast\r
-       if( elm === v.parentNode ) return true;\r
        for( i = xnodes.length; i; ){\r
                if( xnodes[ --i ][ 'contains' ]( v ) ) return true;\r
        };\r
        return false;\r
 };\r
 \r
-/* --------------------------------------\r
- *  getChild\r
+/**\r
+ * index の子要素を取得する。\r
+ * @alias Node.prototype.getChildAt\r
+ * @param {number} index 取得する子ノードの位置。0~\r
+ * @return {Node} 子要素\r
+ * @example child1 = parent.getChildAt(1);\r
  */\r
 function X_Node_getChildAt( i ){\r
        var xnodes = this[ '_xnodes' ];\r
        return xnodes && 0 <= i && i < xnodes.length && xnodes[ i ];\r
 };\r
 \r
-function X_Node_length(){\r
+/**\r
+ * 子要素の数を取得する。\r
+ * @alias Node.prototype.numChildren\r
+ * @return {number} 子要素の数。\r
+ * @example n = parent.numChildren();\r
+ */\r
+function X_Node_numChildren(){\r
        var xnodes = this[ '_xnodes' ];\r
        return xnodes ? xnodes.length : 0;\r
 };\r
 \r
-/* --------------------------------------\r
- *  firstChild, lastChild\r
+/**\r
+ * 最初の子要素を取得する。\r
+ * @alias Node.prototype.firstChild\r
+ * @return {Node} 最初の子要素\r
+ * @example child0 = parent.firstChild();\r
  */\r
 function X_Node_firstChild(){\r
        return this[ '_xnodes' ] && this[ '_xnodes' ][ 0 ];\r
 };\r
+\r
+/**\r
+ * 最後の子要素を取得する。\r
+ * @alias Node.prototype.lastChild\r
+ * @return {Node} 最後の子要素\r
+ * @example lastChild = parent.lastChild();\r
+ */\r
 function X_Node_lastChild(){\r
        var xnodes = this[ '_xnodes' ];\r
        return xnodes && xnodes[ xnodes.length - 1 ];\r
 };\r
 \r
-/* --------------------------------------\r
- *  getOrder\r
+/**\r
+ * 要素の index 位置を取得する。\r
+ * @alias Node.prototype.getOrder\r
+ * @return {number} index -1 の場合、親を持たない。\r
+ * @example index = node.getOrder();\r
  */\r
 function X_Node_getOrder(){\r
        var parent = this.parent;\r
-       if( !parent ) return -1;\r
-       return parent[ '_xnodes' ].indexOf( this );\r
+       return this === X_Node_html ?\r
+                               0 :\r
+                  parent ?\r
+                               parent[ '_xnodes' ].indexOf( this ) :\r
+                               -1;\r
 };\r
 \r
-/* --------------------------------------\r
- *  className, addClass, removeClass, hasClass\r
+/**\r
+ * className の取得と設定。\r
+ * @alias Node.prototype.className\r
+ * @return {string|Node} getter の場合 class 文字列、setter の場合自身。\r
+ * @example // getter\r
+ * className = node.className();\r
+ * // setter\r
+ * node.className( 'myClass myClass_new' );\r
  */\r
 function X_Node_className( v ){\r
        var node, _, __;\r
@@ -960,9 +1003,18 @@ function X_Node_className( v ){
        this[ '_flags' ] & X_Node_State.IN_TREE && X_Node_reserveUpdate();\r
        return this;\r
 };\r
+\r
+/**\r
+ * className の追加。\r
+ * @alias Node.prototype.addClass\r
+ * @param {string} className スペース区切りで複数のクラスを追加できる。\r
+ * @return {Node} 自身。\r
+ * @example node.addClass( 'myClass myClass_new' );\r
+ */\r
 function X_Node_addClass( v ){\r
-       var names = v.split( ' ' ),\r
-               i     = names.length,\r
+       var names  = v.split( ' ' ),\r
+               i      = names.length,\r
+               _class = this[ '_className' ],\r
                name;\r
        v = '';\r
        for( ; i; ){\r
@@ -970,18 +1022,27 @@ function X_Node_addClass( v ){
                if( !name ) continue;\r
                !this[ 'hasClass' ]( name ) && ( v += ( v ? ' ' : '' ) + name );\r
        };\r
-       return v ? this[ 'className' ]( this[ '_className' ] + ( this[ '_className' ] ? ' ' : '' ) + v ) : this;\r
+       return v ? this[ 'className' ]( ( _class ? _class + ' ' : '' ) + v ) : this;\r
 };\r
+\r
+/**\r
+ * className の削除。\r
+ * @alias Node.prototype.removeClass\r
+ * @param {string} className スペース区切りで複数のクラスを削除できる。\r
+ * @return {Node} 自身。\r
+ * @example node.removeClass( 'myClass myClass_new' );\r
+ */\r
 function X_Node_removeClass( v ){\r
-       var _          = ' ',\r
-               className  = this[ '_className' ],\r
-               names      = v.split( _ ),\r
+       var _      = ' ',\r
+               _class = this[ '_className' ],\r
+               names  = v.split( _ ),\r
                classNames, i, f, j;\r
-       if( !className ) return this;\r
-       for( classNames = className.split( _ ), i = classNames.length; i; ){\r
-               className = classNames[ --i ];\r
+\r
+       if( !_class ) return this;\r
+       for( classNames = _class.split( _ ), i = classNames.length; i; ){\r
+               _class = classNames[ --i ];\r
                for( j = names.length; j; ){\r
-                       if( className === names[ --j ] ){\r
+                       if( _class === names[ --j ] ){\r
                                classNames.splice( i, 1 );\r
                                names.splice( j, 1 );\r
                                f = true;\r
@@ -991,10 +1052,19 @@ function X_Node_removeClass( v ){
        };\r
        return f ? this[ 'className' ]( classNames.join( _ ) ) : this;\r
 };\r
+\r
+/**\r
+ * className の更新。\r
+ * @alias Node.prototype.toggleClass\r
+ * @param {string} className スペース区切りで複数のクラスを削除できる。\r
+ * @param {boolean} [opt_toggle=] true はクラスの追加。false はクラスの削除。undefined はクラスのトグル。\r
+ * @return {Node} 自身。\r
+ * @example node.toggleClass( 'myClass myClass_new', !!n );\r
+ */\r
 function X_Node_toggleClass( v, opt_toggle ){\r
        var names, i, name;\r
        if( opt_toggle !== undefined ){\r
-               return !!opt_toggle ? this[ 'addClass' ]( v ) : this[ 'removeClass' ]( v );     \r
+               return !opt_toggle ? this[ 'removeClass' ]( v ) : this[ 'addClass' ]( v );      \r
        };\r
        names = v.split( ' ' );\r
        for( i = names.length; i; ){\r
@@ -1003,28 +1073,38 @@ function X_Node_toggleClass( v, opt_toggle ){
        };\r
        return this;\r
 };\r
+\r
+/**\r
+ * className を持つか。\r
+ * @alias Node.prototype.hasClass\r
+ * @param {string} className スペース区切りで複数のクラスを削除できる。\r
+ * @return {boolean} \r
+ * @example node.hasClass( 'myClass myClass_new' );\r
+ */\r
 function X_Node_hasClass( v ){\r
        var _ = ' ',\r
-               className = this[ '_className' ],\r
+               _class = this[ '_className' ],\r
                i, name;\r
-       if( className === v ) return true;\r
-       if( !className ) return false;\r
+       if( _class === v ) return true;\r
+       if( !_class ) return false;\r
        \r
-       className = _ + className + _;\r
-       if( className.indexOf( _ + v + _ ) !== -1 ) return true; // lucky hit\r
+       _class = _ + _class + _;\r
+       if( _class.indexOf( _ + v + _ ) !== -1 ) return true; // lucky hit\r
        \r
        for( v = v.split( _ ), i = v.length; i; ){\r
                name = v[ --i ];\r
                if( name === '' ) continue;\r
-               if( className.indexOf( _ + name + _ ) === -1 ) return false;\r
+               if( _class.indexOf( _ + name + _ ) === -1 ) return false;\r
        };\r
        return true;\r
 };\r
 \r
-/* --------------------------------------\r
- *  html, text\r
- * \r
- * outerHTML が欲しい場合は、xnode.call('outerHTML') とできる。\r
+/**\r
+ * innerHTML 取得・設定。outerHTML が欲しい場合は、xnode.call('outerHTML') とできる。\r
+ * @alias Node.prototype.html\r
+ * @param {string} [html=] html文字列\r
+ * @return {string|Node} \r
+ * @example node.html( '<img>' );\r
  */\r
 function X_Node_html( html ){\r
        var _ = '', q = '"', xnodes, n, i, l;\r
@@ -1065,6 +1145,13 @@ function X_Node_html( html ){
 /*\r
  * null が来たら '', 数値等が来たら文字列化\r
  */\r
+/**\r
+ * textContent 取得・設定。null が来たら '', 数値等が来たら文字列化\r
+ * @alias Node.prototype.text\r
+ * @param {string} [text=]\r
+ * @return {string|Node} \r
+ * @example node.text( 'Hello, world!' );\r
+ */\r
 function X_Node_text( text ){\r
        var xnodes, texts, i, l;\r
        // setter\r