X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F02_dom%2F05_XNodeAttr.js;h=6dcd5c7150429ed807f82837afa5e8c88e2c4536;hb=66ccef8a1fdd3994dd3c75dcfede668ea55f1d2e;hp=186496920d8d4a7fc0a5099be812755b092011c8;hpb=9f5ab564d20a8bd6438693146ae73209c78a2c5e;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/02_dom/05_XNodeAttr.js b/0.6.x/js/02_dom/05_XNodeAttr.js index 1864969..6dcd5c7 100644 --- a/0.6.x/js/02_dom/05_XNodeAttr.js +++ b/0.6.x/js/02_dom/05_XNodeAttr.js @@ -1,114 +1,192 @@ var X_Node_Attr_noValue = { - checked : 1, - compact : 1, - declare : 1, - defer : 1, - disabled : 1, - ismap : 1, - multiple : 1, - nohref : 1, - noresize : 1, - noshade : 1, - nowrap : 1, - readonly : 1, - selected : 1 + 'checked' : 1, + 'compact' : 1, + 'declare' : 1, + 'defer' : 1, + 'disabled' : 1, + 'ismap' : 1, + 'multiple' : 1, + 'nohref' : 1, + 'noresize' : 1, + 'noshade' : 1, + 'nowrap' : 1, + 'readonly' : 1, + 'selected' : 1 }, X_Node_Attr_renameForDOM = { - 'class' : 'className', - accesskey : 'accessKey', - 'accept-charset' : 'acceptCharset', - bgcolor : 'bgColor', - cellpadding : 'cellPadding', - cellspacing : 'cellSpacing', - 'char' : 'ch', - charoff : 'chOff', - codebase : 'codeBase', - codetype : 'codeType', - colspan : 'colSpan', - datetime : 'dateTime', - 'for' : 'htmlFor', - frameborder : 'frameBorder', - 'http-equiv' : 'httpEquiv', - ismap : 'isMap', - longdesc : 'longDesc', - maxlength : 'maxLength', - nohref : 'noHref', - readonly : 'readOnly', - rowspan : 'rowSpan', - tabindex : 'tabIndex', - usemap : 'useMap', - valuetype : 'valueType', - checked : 'defaultChecked' + 'class' : 'className', + 'accesskey' : 'accessKey', + 'accept-charset' : 'acceptCharset', + 'bgcolor' : 'bgColor', + 'cellpadding' : 'cellPadding', + 'cellspacing' : 'cellSpacing', + 'char' : 'ch', + 'charoff' : 'chOff', + 'codebase' : 'codeBase', + 'codetype' : 'codeType', + 'colspan' : 'colSpan', + 'datetime' : 'dateTime', + 'for' : 'htmlFor', + 'frameborder' : 'frameBorder', + 'http-equiv' : 'httpEquiv', + 'ismap' : 'isMap', + 'longdesc' : 'longDesc', + 'maxlength' : 'maxLength', + 'nohref' : 'noHref', + 'readonly' : 'readOnly', + 'rowspan' : 'rowSpan', + 'tabindex' : 'tabIndex', + 'usemap' : 'useMap', + 'valuetype' : 'valueType', + 'checked' : 'defaultChecked' }, X_Node_Attr_HAS_VALUE = { - INPUT : true, - TEXTAREA : true, - SELECT : true, - BUTTON : true + 'INPUT' : true, + 'TEXTAREA' : true, + 'SELECT' : true, + 'BUTTON' : true, + 'OBJECT' : true, + 'PARAM' : true // FlashVars が flash 側から書き換えられるケースがある?? +}, + +// の場合、value の値はユーザーで変えることはない +// はユーザーによって常に変更される HTML5 ではこれにさらにいろいろ加わる +X_Node_Attr_STATIC_VALUE_TYPES = { + 'button' : true, + 'hidden' : true, + 'submit' : true, + 'reset' : true, + 'radio' : true, + 'checkbox' : true +}, + +// 自由な内容が入るため、参照文字への変換が必要 +X_Node_Attr_toChrReferance = { + 'value' : true, + 'title' : true, + 'alt' : true }, X_Node_Attr_renameForTag = {}; // http://nanto.asablo.jp/blog/2005/10/29/123294 // checked -> defaultChecked // 動的に生成した input 要素を文書ツリーに挿入する前に設定した checked 属性は反映されず、defaultChecked だと反映される - // 先頭にスペース -function X_Node_Attr_objToAttrText( obj ){ - var noValue = X_Node_Attr_noValue, - attrs = [ '' ], n = 0, p, v; - if( !obj ) return ''; // Opera7 - for( p in obj ){ - v = obj[ p ]; - if( p === 'value' ){ - v = v.split( '"' ).join( '"' ).split( '>' ).join( '>' ).split( '<' ).join( '<' ); + // ロードイベントを拾うために、要素生成時にネットワーク関連の属性を設定しない。 + // -> src (img, iframe, ), link の href, + // +function X_Node_Attr_objToAttrText( that, skipNetworkForElmCreation ){ + var obj = that[ '_attrs' ], + noValue = X_Node_Attr_noValue, + attrs = [ '' ], // 先頭にスペース + plain = X_EMPTY_OBJECT, + n = 0, k, check; + + if( skipNetworkForElmCreation ){ + delete that[ '_newAttrs' ]; + // このあとで _newAttr にネットワーク系の属性を控える, attrText には加えない + } else { + that[ '_flags' ] &= ~X_NodeFlags_OLD_ATTRTEXT; + // 完全な attrText + }; + + if( !obj ){ // Opera7 + delete that[ '_attrText' ]; + return ''; + }; + + for( k in obj ){ + if( plain[ k ] ) continue; + + if( skipNetworkForElmCreation ){ + check = false; + switch( that[ '_tag' ] + k ){ + case 'PARAMvalue' : + check = obj[ 'name' ] !== 'movie'; + case 'INPUTsrc' : + check = check || ( obj[ 'type' ] !== 'image' ); + case 'LINKhref' : + check = check || ( obj[ 'rel' ] !== 'stylesheet' ); + + if( !check ) break; + + case 'IMGsrc' : + case 'IFRAMEsrc' : + case 'FRAMEsrc' : + case 'SCRIPTsrc' : + case 'EMBEDsrc' : + case 'OBJECTdata' : + case 'BGSOUNDsrc' : + case 'APPLETcode' : + //case 'AUDIOsrc' : + //case 'VIDEOsrc' : + if( !that[ '_newAttrs' ] ) that[ '_newAttrs' ] = {}; + that[ '_newAttrs' ][ k ] = obj[ k ]; + continue; }; - attrs[ ++n ] = noValue[ p ] ? p : [ p, '="', v, '"' ].join( '' ); }; - return 0 < n ? attrs.join( ' ' ) : ''; + + attrs[ ++n ] = noValue[ k ] ? k : [ + k, '="', + X_Node_Attr_toChrReferance[ k ] ? X_String_toChrReferance( obj[ k ] ) : obj[ k ], + '"' ].join( '' ); + }; + + if( 0 < n ){ + return that[ '_attrText' ] = attrs.join( ' ' ); + }; + delete that[ '_attrText' ]; + return ''; }; (function( renameForDOM, renameForTag ){ - var name, i; - for( name in renameForDOM ){ - renameForTag[ renameForDOM[ name ] ] = name; + var k; + for( k in renameForDOM ){ + //if( X_EMPTY_OBJECT[ k ] ) continue; + renameForTag[ renameForDOM[ k ] ] = k; }; })( X_Node_Attr_renameForDOM, X_Node_Attr_renameForTag ); - -/* -------------------------------------- - * attribute - * X_Node_Attr_toIndex に定義されている 属性の場合 - * - * http://nanto.asablo.jp/blog/2005/10/29/123294 - * className, onclick等 はここで設定しない - * +/** + * 属性の getter と setter。onclick等はできないので listen, listenOnce を使うこと。http://nanto.asablo.jp/blog/2005/10/29/123294 + * @alias Node.prototype.attr + * @param {string|object} [nameOrObj] 属性名、または追加する属性のハッシュ + * @param {string|number} [value=] 属性の値 + * @return {Node|string|number} getter の場合は値を、setter の場合は自身を返す。(メソッドチェーン) + * @example // getter + * node.attr( 'tagName' ) === 'DIV'; + * // setter - 1 + * node.attr( { src : url, width : 100, height : 100 } ); + * // setter - 2 + * node.attr( 'src', url ); */ -Node.prototype.attr = function( nameOrObj /* v */ ){ - var attrs = this._attrs, newAttrs, f, p, elm, v; +function X_Node_attr( nameOrObj /* v */ ){ + var attrs = this[ '_attrs' ], newAttrs, f, k, elm, v; - if( this._xnodeType !== 1 ) return this; + if( !this[ '_tag' ] ) return this; - if( nameOrObj && X.Type.isObject( nameOrObj ) ){ - attrs || ( attrs = this._attrs = {} ); - newAttrs = this._newAttrs || ( this._newAttrs = {} ); + if( nameOrObj && X_Type_isObject( nameOrObj ) ){ + attrs || ( attrs = this[ '_attrs' ] = {} ); + newAttrs = this[ '_newAttrs' ] || ( this[ '_newAttrs' ] = {} ); - for( p in nameOrObj ){ - if( X_Node_Attr_setAttr( this, attrs, newAttrs, p, nameOrObj[ p ] ) === true ) f = true; + for( k in nameOrObj ){ + //if( X_EMPTY_OBJECT[ k ] ) continue; + if( X_Node_Attr_setAttr( this, attrs, newAttrs, k, nameOrObj[ k ] ) === true ) f = true; }; if( f ){ - this._attrText = false; - this._dirty |= X_Node_Dirty.ATTR; - this._root && X_Node_reserveUpdate(); + delete this[ '_attrText' ]; + this[ '_flags' ] |= X_NodeFlags_DIRTY_ATTR | X_NodeFlags_OLD_ATTRTEXT; + this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); }; return this; } else if( 1 < arguments.length ){ // setter - if( X_Node_Attr_setAttr( this, attrs || ( this._attrs = {} ), this._newAttrs || ( this._newAttrs = {} ), nameOrObj, arguments[ 1 ] ) === true ){ - this._attrText = false; - this._dirty |= X_Node_Dirty.ATTR; - this._root && X_Node_reserveUpdate(); + if( X_Node_Attr_setAttr( this, attrs || ( this[ '_attrs' ] = {} ), this[ '_newAttrs' ] || ( this[ '_newAttrs' ] = {} ), nameOrObj, arguments[ 1 ] ) === true ){ + delete this[ '_attrText' ]; + this[ '_flags' ] |= X_NodeFlags_DIRTY_ATTR | X_NodeFlags_OLD_ATTRTEXT; + this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); }; return this; } else @@ -116,25 +194,40 @@ Node.prototype.attr = function( nameOrObj /* v */ ){ // getter switch( nameOrObj ){ case 'id' : - return this._id; + return this[ '_id' ]; case 'class' : case 'className' : - return this._className; + return this[ '_className' ]; case 'tag' : case 'tagName' : - return this._tag; + return this[ '_tag' ]; case 'style' : case 'cssText' : - return this.cssText(); + return this[ 'cssText' ](); + + case 'src' : // src は遷移して変化する, name も? + if( this[ '_tag' ] !== 'IFRAME' ) break; + if( this[ '_newAttrs' ] && X_Object_inObject( nameOrObj, this[ '_newAttrs' ] ) ) return this[ '_newAttrs' ][ nameOrObj ]; + if( elm = X_UA_DOM.IE4 ? this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) : this[ '_rawObject' ] ){ + if( !attrs ) attrs = this[ '_attrs' ] = {}; + return attrs[ nameOrObj ] = elm[ nameOrObj ]; // getAttribute( nameOrObj )? + }; + break; + + case 'selected' : + // kquery.js : safariのバグ対策 + // if ($.browser.safari && key === "selected" && tmp) tmp.selectedIndex; + // 親ノードの selectedIndex の getter を呼んでおくと値が正しくなる、ということ?( by itozyun ) + if( X_UA[ 'WebKit' ] ) this[ '_rawObject' ].parentNode && this[ '_rawObject' ].parentNode.selectedIndex; case 'value' : + if( this[ '_tag' ] === 'INPUT' && X_Node_Attr_STATIC_VALUE_TYPES[ attrs[ 'type' ] ] ) break; case 'checked' : - case 'selected' : case 'disabled' : case 'selectedIndex' : - if( X_Node_Attr_HAS_VALUE[ this._tag ] ){ - if( this._newAttrs && X_Object_inObject( nameOrObj, this._newAttrs ) ) return this._newAttrs[ nameOrObj ]; - if( elm = X_UA_DOM.IE4 ? this._rawObject || X_Node__ie4getRawNode( this ) : this._rawObject ){ - if( !attrs ) attrs = this._attrs = {}; + if( X_Node_Attr_HAS_VALUE[ this[ '_tag' ] ] ){ + if( this[ '_newAttrs' ] && X_Object_inObject( nameOrObj, this[ '_newAttrs' ] ) ) return this[ '_newAttrs' ][ nameOrObj ]; + if( elm = X_UA_DOM.IE4 ? this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) : this[ '_rawObject' ] ){ + if( !attrs ) attrs = this[ '_attrs' ] = {}; return attrs[ nameOrObj ] = elm[ nameOrObj ]; // getAttribute( nameOrObj )? }; }; @@ -145,25 +238,40 @@ Node.prototype.attr = function( nameOrObj /* v */ ){ }; function X_Node_Attr_setAttr( that, attrs, newAttrs, name, v ){ switch( name ){ + case 'ns' : + case 'NS' : + if( v === 'svg' || v === 'SVG' ){ + that[ '_flags' ] |= X_NodeFlags_IS_SVG; + }; + if( v === 'vml' || v === 'VML' ){ + that[ '_flags' ] |= X_NodeFlags_IS_VML; + }; + return; + // case 'type' : TODO IE は input, button, object に対して type の再設定が出来ない _state が要素生成済なら不可 case 'UID' : case 'tag' : case 'tagName' : return; case 'id' : - v = ( v !== 'ie4uid' + that._uid ) ? v : undefined; - if( v !== that._id ){ - that._id = v; - that._dirty |= X_Node_Dirty.ID; - that._root && X_Node_reserveUpdate(); + v = ( v !== 'ie4uid' + that[ '_uid' ] ) ? v : undefined; + // TODO unique の check + if( v !== that[ '_id' ] ){ + that[ '_id' ] = v; + that[ '_flags' ] |= X_NodeFlags_DIRTY_ID; + that[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); }; return; case 'class' : case 'className' : - return that.className( v ); + return that[ 'className' ]( v ); case 'style' : case 'cssText' : - return that.cssText( v ); + return that[ 'cssText' ]( v ); + case 'text' : + return that[ 'text' ]( v ); + case 'html' : + return that[ 'html' ]( v ); }; // debug if( name.indexOf( 'on' ) === 0 ){ @@ -176,7 +284,7 @@ function X_Node_Attr_setAttr( that, attrs, newAttrs, name, v ){ if( v == null ){ newAttrs[ name ] = undefined; - if( attrs.hasOwnProperty( name ) ) delete attrs[ name ]; + if( X_Object_inObject( name, attrs ) ) delete attrs[ name ]; } else { newAttrs[ name ] = attrs[ name ] = v; };