OSDN Git Service

Fix the bug of X.NodeAnime.
[pettanr/clientJs.git] / 0.6.x / js / 02_dom / 05_XNodeAttr.js
1 var X_Node_Attr_noValue = {\r
2                 'checked'  : 1,\r
3                 'compact'  : 1,\r
4                 'declare'  : 1,\r
5                 'defer'    : 1,\r
6                 'disabled' : 1,\r
7                 'ismap'    : 1,\r
8                 'multiple' : 1,\r
9                 'nohref'   : 1,\r
10                 'noresize' : 1,\r
11                 'noshade'  : 1,\r
12                 'nowrap'   : 1,\r
13                 'readonly' : 1,\r
14                 'selected' : 1\r
15 },\r
16 X_Node_Attr_renameForDOM = {\r
17                 'class'            : 'className',\r
18                 'accesskey'        : 'accessKey',\r
19                 'accept-charset'   : 'acceptCharset',\r
20                 'bgcolor'          : 'bgColor',\r
21                 'cellpadding'      : 'cellPadding',\r
22                 'cellspacing'      : 'cellSpacing',\r
23                 'char'             : 'ch',\r
24                 'charoff'          : 'chOff',\r
25                 'codebase'         : 'codeBase',\r
26                 'codetype'         : 'codeType',\r
27                 'colspan'          : 'colSpan',\r
28                 'datetime'         : 'dateTime',\r
29                 'for'              : 'htmlFor',\r
30                 'frameborder'      : 'frameBorder',\r
31                 'http-equiv'       : 'httpEquiv',\r
32                 'ismap'            : 'isMap',\r
33                 'longdesc'         : 'longDesc',\r
34                 'maxlength'        : 'maxLength',\r
35                 'nohref'           : 'noHref',\r
36                 'readonly'         : 'readOnly',\r
37                 'rowspan'          : 'rowSpan',\r
38                 'tabindex'         : 'tabIndex',\r
39                 'usemap'           : 'useMap',\r
40                 'valuetype'        : 'valueType',\r
41                 'checked'          : 'defaultChecked'\r
42 },\r
43 \r
44 X_Node_Attr_HAS_VALUE = {\r
45                 'INPUT'    : true,\r
46                 'TEXTAREA' : true,\r
47                 'SELECT'   : true,\r
48                 'BUTTON'   : true,\r
49                 'OBJECT'   : true,\r
50                 'PARAM'    : true // FlashVars が flash 側から書き換えられるケースがある??\r
51 },\r
52 \r
53 // <input type=button,hidden,submit,reset,radio,checkbox> の場合、value の値はユーザーで変えることはない\r
54 // <input type=text,password,file> はユーザーによって常に変更される HTML5 ではこれにさらにいろいろ加わる\r
55 X_Node_Attr_STATIC_VALUE_TYPES = {\r
56         'button'   : true,\r
57         'hidden'   : true,\r
58         'submit'   : true,\r
59         'reset'    : true,\r
60         'radio'    : true,\r
61         'checkbox' : true\r
62 },\r
63 \r
64 // 自由な内容が入るため、参照文字への変換が必要\r
65 X_Node_Attr_toChrReferance = {\r
66         'value' : true,\r
67         'title' : true,\r
68         'alt'   : true\r
69 },\r
70 \r
71 X_Node_Attr_renameForTag = {};\r
72         // http://nanto.asablo.jp/blog/2005/10/29/123294\r
73         // checked -> defaultChecked\r
74         // 動的に生成した input 要素を文書ツリーに挿入する前に設定した checked 属性は反映されず、defaultChecked だと反映される\r
75         // ロードイベントを拾うために、要素生成時にネットワーク関連の属性を設定しない。\r
76         //  -> src (img, iframe, ), link の href, <param name="movie" src=>\r
77         // \r
78 function X_Node_Attr_objToAttrText( that, skipNetworkForElmCreation ){\r
79         var obj     = that[ '_attrs' ],\r
80                 noValue = X_Node_Attr_noValue,\r
81                 attrs   = [ '' ], // 先頭にスペース\r
82                 plain   = X_EMPTY_OBJECT,\r
83                 n = 0, k, check;\r
84 \r
85         if( skipNetworkForElmCreation ){\r
86                 delete that[ '_newAttrs' ];\r
87                 // このあとで _newAttr にネットワーク系の属性を控える, attrText には加えない\r
88         } else {\r
89                 that[ '_flags' ] &= ~X_NodeFlags_OLD_ATTRTEXT;\r
90                 // 完全な attrText\r
91         };\r
92         \r
93         if( !obj ){ // Opera7\r
94                 delete that[ '_attrText' ];\r
95                 return '';\r
96         };\r
97         \r
98         for( k in obj ){\r
99                 if( plain[ k ] ) continue;\r
100                 \r
101                 if( skipNetworkForElmCreation ){\r
102                         check = false;\r
103                         switch( that[ '_tag' ] + k ){\r
104                                 case 'PARAMvalue' :\r
105                                         check = obj[ 'name' ] !== 'movie';\r
106                                 case 'INPUTsrc'  :\r
107                                         check = check || ( obj[ 'type' ] !== 'image' );\r
108                                 case 'LINKhref' :\r
109                                         check = check || ( obj[ 'rel' ] !== 'stylesheet' );\r
110                                         \r
111                                         if( !check ) break;\r
112 \r
113                                 case 'IMGsrc'     :\r
114                                 case 'IFRAMEsrc'  :\r
115                                 case 'FRAMEsrc'   :\r
116                                 case 'SCRIPTsrc'  :\r
117                                 case 'EMBEDsrc'   :\r
118                                 case 'OBJECTdata' :\r
119                                 case 'BGSOUNDsrc' :\r
120                                 case 'APPLETcode' :\r
121                                 //case 'AUDIOsrc' :\r
122                                 //case 'VIDEOsrc' :\r
123                                         if( !that[ '_newAttrs' ] ) that[ '_newAttrs' ] = {};\r
124                                         that[ '_newAttrs' ][ k ] = obj[ k ];\r
125                                         continue;\r
126                         };\r
127                 };\r
128 \r
129                 attrs[ ++n ] = noValue[ k ] ? k : [\r
130                         k, '="',\r
131                         X_Node_Attr_toChrReferance[ k ] ? X_String_toChrReferance( obj[ k ] ) : obj[ k ],\r
132                         '"' ].join( '' );\r
133         };\r
134         \r
135         if( 0 < n ){\r
136                 return that[ '_attrText' ] = attrs.join( ' ' );\r
137         };\r
138         delete that[ '_attrText' ];\r
139         return '';\r
140 };\r
141 \r
142 (function( renameForDOM, renameForTag ){\r
143         var k;\r
144         for( k in renameForDOM ){\r
145                 //if( X_EMPTY_OBJECT[ k ] ) continue;\r
146                 renameForTag[ renameForDOM[ k ] ] = k;\r
147         };\r
148 })( X_Node_Attr_renameForDOM, X_Node_Attr_renameForTag );\r
149 \r
150 \r
151 /**\r
152  * 属性の getter と setter。onclick等はできないので listen, listenOnce を使うこと。http://nanto.asablo.jp/blog/2005/10/29/123294\r
153  * @alias Node.prototype.attr\r
154  * @param {string|object} [nameOrObj] 属性名、または追加する属性のハッシュ\r
155  * @param {string|number} [value=] 属性の値\r
156  * @return {Node|string|number} getter の場合は値を、setter の場合は自身を返す。(メソッドチェーン)\r
157  * @example // getter\r
158  * node.attr( 'tagName' ) === 'DIV';\r
159  * // setter - 1\r
160  * node.attr( { src : url, width : 100, height : 100 } );\r
161  * // setter - 2\r
162  * node.attr( 'src', url );\r
163  */\r
164 function X_Node_attr( nameOrObj /* v */ ){\r
165         var attrs = this[ '_attrs' ], newAttrs, f, k, elm, v;\r
166         \r
167         if( !this[ '_tag' ] ) return this;\r
168         \r
169         if( nameOrObj && X_Type_isObject( nameOrObj ) ){\r
170                 attrs || ( attrs = this[ '_attrs' ] = {} );\r
171                 newAttrs = this[ '_newAttrs' ] || ( this[ '_newAttrs' ] = {} );\r
172                 \r
173                 for( k in nameOrObj ){\r
174                         //if( X_EMPTY_OBJECT[ k ] ) continue;\r
175                         if( X_Node_Attr_setAttr( this, attrs, newAttrs, k, nameOrObj[ k ] ) === true ) f = true;\r
176                 };\r
177                 if( f ){\r
178                         delete this[ '_attrText' ];\r
179                         this[ '_flags' ] |= X_NodeFlags_DIRTY_ATTR | X_NodeFlags_OLD_ATTRTEXT;\r
180                         this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate();\r
181                 };\r
182                 return this;\r
183         } else\r
184         if( 1 < arguments.length ){\r
185                 // setter\r
186                 if( X_Node_Attr_setAttr( this, attrs || ( this[ '_attrs' ] = {} ), this[ '_newAttrs' ] || ( this[ '_newAttrs' ] = {} ), nameOrObj, arguments[ 1 ] ) === true ){\r
187                         delete this[ '_attrText' ];\r
188                         this[ '_flags' ] |= X_NodeFlags_DIRTY_ATTR | X_NodeFlags_OLD_ATTRTEXT;\r
189                         this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate();\r
190                 };\r
191                 return this;\r
192         } else\r
193         if( X_Type_isString( nameOrObj ) ){\r
194                 // getter\r
195                 switch( nameOrObj ){\r
196                         case 'id' :\r
197                                 return this[ '_id' ];\r
198                         case 'class' :\r
199                         case 'className' :\r
200                                 return this[ '_className' ];\r
201                         case 'tag' :\r
202                         case 'tagName' :\r
203                                 return this[ '_tag' ];\r
204                         case 'style' :\r
205                         case 'cssText' :\r
206                                 return this[ 'cssText' ]();\r
207 \r
208                         case 'src' : // src は遷移して変化する, name も?\r
209                                 if( this[ '_tag' ] !== 'IFRAME' ) break;\r
210                                 if( this[ '_newAttrs' ] && X_Object_inObject( nameOrObj, this[ '_newAttrs' ] ) ) return this[ '_newAttrs' ][ nameOrObj ];\r
211                                 if( elm = X_UA_DOM.IE4 ? this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) : this[ '_rawObject' ] ){\r
212                                         if( !attrs ) attrs = this[ '_attrs' ] = {};\r
213                                         return attrs[ nameOrObj ] = elm[ nameOrObj ]; // getAttribute( nameOrObj )?\r
214                                 };\r
215                                 break;\r
216                                 \r
217                         case 'selected' :\r
218                                 // kquery.js : safariのバグ対策\r
219                                 // if ($.browser.safari && key === "selected" && tmp) tmp.selectedIndex;\r
220                                 // 親ノードの selectedIndex の getter を呼んでおくと値が正しくなる、ということ?( by itozyun )\r
221                                 if( X_UA[ 'WebKit' ] ) this[ '_rawObject' ].parentNode && this[ '_rawObject' ].parentNode.selectedIndex;\r
222                         case 'value' :\r
223                                 if( this[ '_tag' ] === 'INPUT' && X_Node_Attr_STATIC_VALUE_TYPES[ attrs[ 'type' ] ] ) break;\r
224                         case 'checked' :\r
225                         case 'disabled' :                       \r
226                         case 'selectedIndex' :\r
227                                 if( X_Node_Attr_HAS_VALUE[ this[ '_tag' ] ] ){\r
228                                         if( this[ '_newAttrs' ] && X_Object_inObject( nameOrObj, this[ '_newAttrs' ] ) ) return this[ '_newAttrs' ][ nameOrObj ];\r
229                                         if( elm = X_UA_DOM.IE4 ? this[ '_rawObject' ] || X_Node__ie4getRawNode( this ) : this[ '_rawObject' ] ){\r
230                                                 if( !attrs ) attrs = this[ '_attrs' ] = {};\r
231                                                 \r
232                                                 if( this[ '_tag' ] === 'TEXTAREA' && nameOrObj === 'value' && X_UA[ 'IE' ] < 9 ){\r
233                                                         return attrs[ nameOrObj ] = X_Node_Attr_getValueForIE( elm );\r
234                                                 };\r
235                                                 return attrs[ nameOrObj ] = elm[ nameOrObj ]; // getAttribute( nameOrObj )?\r
236                                         };\r
237                                 };\r
238                                 break;\r
239                 };\r
240                 return attrs && attrs[ X_Node_Attr_renameForTag[ nameOrObj ] || nameOrObj ];\r
241         };\r
242 };\r
243 \r
244 \r
245                 // ie8- 用に改行文字が \n の場合、 \r\n に変換しておく <- fromawork 内に移動\r
246                 // http://qiita.com/hanoopy/items/71456afe32f207369d24\r
247 function X_Node_Attr_getValueForIE( elm ){\r
248         // console.log( elm[ nameOrObj ].length + ' -> ' + elm[ nameOrObj ].split( '\r' ).join( '' ).length );\r
249         // IE は改行文字が /r/n になるがこれを /n に変換\r
250         return elm.value.split( '\r' ).join( '' );\r
251 };\r
252 \r
253 function X_Node_Attr_setAttr( that, attrs, newAttrs, name, v ){\r
254         switch( name ){\r
255                 case 'ns' :\r
256                 case 'NS' :\r
257                         if( v === 'svg' || v === 'SVG' ){\r
258                                 that[ '_flags' ] |= X_NodeFlags_IS_SVG;\r
259                         };\r
260                         if( v === 'vml' || v === 'VML' ){\r
261                                 that[ '_flags' ] |= X_NodeFlags_IS_VML;\r
262                         };\r
263                         return;\r
264                 \r
265                 // case 'type' : TODO IE は input, button, object に対して type の再設定が出来ない _state が要素生成済なら不可\r
266                 case 'UID' :\r
267                 case 'tag' :\r
268                 case 'tagName' :\r
269                         return;\r
270                 case 'id' :\r
271                         v = ( v !== 'ie4uid' + that[ '_uid' ] ) ? v : undefined;\r
272                         // TODO unique の check\r
273                         if( v !== that[ '_id' ] ){\r
274                                 that[ '_id' ] = v;\r
275                                 that[ '_flags' ] |= X_NodeFlags_DIRTY_ID;\r
276                                 that[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate();\r
277                         };\r
278                         return; \r
279                 case 'class' :\r
280                 case 'className' :\r
281                         return that[ 'className' ]( v );\r
282                 case 'style' :\r
283                 case 'cssText' :\r
284                         return that[ 'cssText' ]( v );\r
285                 case 'text' :\r
286                         return that[ 'text' ]( v );\r
287                 case 'html' :\r
288                         return that[ 'html' ]( v );\r
289         };\r
290         // debug\r
291         if( name.indexOf( 'on' ) === 0 ){\r
292                 X.Logger.warn( 'xnode.attr("' + name + '") is wrong, xnode.listen() & xnode.unlisten().' );\r
293                 return;\r
294         };\r
295         \r
296         name = X_Node_Attr_renameForTag[ name ] || name;\r
297         if( attrs[ name ] === v ) return;\r
298         \r
299         if( v == null ){\r
300                 newAttrs[ name ] = undefined;\r
301                 if( X_Object_inObject( name, attrs ) ) delete attrs[ name ];\r
302         } else {\r
303                 newAttrs[ name ] = attrs[ name ] = v;\r
304         };\r
305         return true;\r
306 };\r
307 \r