OSDN Git Service

Version 0.6.121, iScroll5 is working on iPhone touch 1G, update X.Audio.
[pettanr/clientJs.git] / 0.6.x / js / 02_dom / 06_XNodeCSS.js
1
2
3 /*
4  * style 値の変更は、enterFrame 後にまとめて適用
5  * width(), height(), x(), y() 1em の取得時にも適用
6  * css3 の ie用 fix は X.UI レベルで行う
7  * 
8  * use X.Dom.Event
9  */
10
11 /* font-size -> fontSize */
12 function X_Node_CSS_camelize( cssProp ){
13         var parts, l, i, parts0, camelized;
14         
15         if( camelized = X_Node_CSS__DICTIONARY_CAMELIZE[ cssProp ] ) return camelized;
16         parts  = cssProp.split( ' ' ).join( '' ).split( '-' );
17         parts0 = parts[ 0 ];
18         l      = parts.length;
19         if( l === 1 ) return parts0;
20         
21         camelized = cssProp.charAt(0) === '-'
22           ? parts0.charAt( 0 ).toUpperCase() + parts0.substring( 1 )
23           : parts0;
24         
25         for( i = 1; i < l; ++i ){
26                 camelized += parts[ i ].charAt( 0 ).toUpperCase() + parts[ i ].substring( 1 );
27         };
28         return X_Node_CSS__DICTIONARY_CAMELIZE[ cssProp ] = camelized;
29 };
30
31 // TODO use X_HTMLParser_CHARS
32 /* fontSize -> font-size */
33 function X_Node_CSS_uncamelize( str ){
34         var A = X_Node_CSS_CHAR_CODE_A,
35                 Z = A + 25,
36                 uncamelized, l, chr, code, i;
37         str = str.split( ' ' ).join( '' );
38         if( uncamelized = X_Node_CSS__DICTIONARY_UNCAMELIZE[ str ] ) return uncamelized;
39         uncamelized = '';
40         for( i = 0, l = str.length; i < l; ++i ){
41                 chr = str.charAt( i );
42                 code = chr.charCodeAt( 0 );
43                 uncamelized += ( A <= code && code <= Z ) ? '-' + chr : chr;
44         };
45         return X_Node_CSS__DICTIONARY_UNCAMELIZE[ str ] = uncamelized.toLowerCase();
46 };
47
48 var
49
50 X_node_CSS_getComputedStyle = window.getComputedStyle || document.defaultView && document.defaultView.getComputedStyle,
51
52         /* font-size -> fontSize */
53 X_Node_CSS__DICTIONARY_CAMELIZE = {},
54
55         /* fontSize -> font-size */
56 X_Node_CSS_CHAR_CODE_A = 'A'.charCodeAt( 0 ),
57         
58 X_Node_CSS__DICTIONARY_UNCAMELIZE = {},
59         
60 /*
61  * CSS における display, position, float プロパティの相互関係
62  * http://d.hatena.ne.jp/elm200/20080201/1201874740
63  * 
64  * CSS21:9.7 Relationships between ’display’, ’position’, and ’float’ 
65  * http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo
66  * 
67  *   display:none? -yes-> 非表示
68  *    ↓
69  *   position:absolute? -yes-> float:none,display:block;
70  *    ↓
71  *   float:none? -no-> display:block;
72  *    ↓
73  *   display:そのまま
74  * 
75  *
76 display         position                        float
77 block           static|relative         none
78 block           static|relative         right|left
79 block           absolute                        none
80 inline          static|relative         none
81
82 _DISPLAY_NONE
83 _ABSOLUTE_BOX
84 _FLOAT_BOX
85 _GRNERAL
86  */
87 X_Node_CSS_VENDER_PREFIX = {},
88         
89 X_Node_CSS__CLIP_SEPARATOR = X_UA.IE < 8 ? ' ' : ',',
90         
91 X_Node_CSS__UNIT_RATIO      = {},
92 X_Node_CSS__FONT_SIZE_RATIO = {},
93
94         //  https://developer.mozilla.org/en-US/docs/Web/CSS/transform
95         //  Firefox 3.5, ie9, Opera 10.5, Safari 3.1, Chrome
96         //  3D support Firefox 10, ie10, Safari 4.0, Chrome 12.0
97         // transform : void 0,
98         
99         //  https://developer.mozilla.org/ja/docs/Web/Guide/CSS/Using_CSS_transitions
100         //  Chrome 1.0, Firefox 4.0, ie10, Opera 10.5, Safari 3.2
101         //  Android 2.1, Firefox Android 4.0, Opera Mobile 10, Safari Mobile 3.2        
102         // transition : void 0
103         
104         // ブラウザ毎の getComputedStyle の戻り値 http://d.hatena.ne.jp/uupaa/20080928/1222543331
105
106 X_Node_CSS_COLOR = {
107                 BLACK         : 0x0,
108                 RED           : 0xFF0000,
109                 LIME          : 0x00FF00,
110                 BLUE          : 0x0000FF,
111                 YELLOW        : 0xFFFF00,
112                 AQUA          : 0x00FFFF,
113                 CYAN          : 0x00FFFF,
114                 MAGENTA       : 0xFF00FF,
115                 FUCHSIA       : 0xFF00FF,
116                 WHITE         : 0xFFFFFF,
117                 GREEN         : 0x008000,
118                 PURPLE        : 0x800080,
119                 MAROON        : 0x800000,
120                 NAVY          : 0x000080,
121                 OLIVE         : 0x808000,
122                 TEAL          : 0x008080,
123                 GRAY          : 0x808080,
124                 SILVER        : 0xC0C0C0,
125                 DIMGRAY       : 0x696969,
126                 SLATEGRAY     : 0x708090,
127                 DARKGRAY      : 0xA9A9A9,
128                 GAINSBORO     : 0xDCDCDC,
129                 MIDNIGHTBLUE  : 0x191970,
130                 SLATEBLUE     : 0x6A5ACD,
131                 MEDIUMBLUE    : 0x0000CD,
132                 ROYALBLUE     : 0x4169E1,
133                 DODGERBLUE    : 0x1E90FF,
134                 SKYBLUE       : 0x87CEEB,
135                 STEELBLUE     : 0x4682B4,
136                 LIGHTBLUE     : 0xADD8E6,
137                 PALETURQUOISE : 0xAFEEEE,
138                 TURQUOISE     : 0x40E0D0,
139                 LIGHTCYAN     : 0xE0FFFF,
140                 AQUAMARINE    : 0x7FFFD4,
141                 DARKGREEN     : 0x006400,
142                 SEAGREEN      : 0x2E8B57,
143                 LIGHTGREEN    : 0x90EE90,
144                 CHARTREUSE    : 0x7FFF00,
145                 GREENYELLOW   : 0xADFF2F,
146                 LIMEGREEN     : 0x32CD32,
147                 YELLOWGREEN   : 0x9ACD32,
148                 OLIVEDRAB     : 0x6B8E23,
149                 DARKKHAKI     : 0xBCB76B,
150                 PALEGOLDENROD : 0xEEE8AA,
151                 LIGHTYELLOW   : 0xFFFFE0,
152                 GOLD          : 0xFFD700,
153                 GOLDENROD     : 0xDAA520,
154                 DARKGOLDENROD : 0xB8860B,
155                 ROSYBROWN     : 0xBC8F8F,
156                 INDIANRED     : 0xCD5C5C,
157                 SADDLEBROWN   : 0x8B4513,
158                 SIENNA        : 0xA0522D,
159                 PERU          : 0xCD853F,
160                 BURLYWOOD     : 0xDEB887,
161                 BEIGE         : 0xF5F5DC,
162                 WHEAT         : 0xF5DEB3,
163                 SANDYBROWN    : 0xF4A460,
164                 TAN           : 0xD2B48C,
165                 CHOCOLATE     : 0xD2691E,
166                 FIREBRICK     : 0xB22222,
167                 BROWN         : 0xA52A2A,
168                 SALMON        : 0xFA8072,
169                 ORANGE        : 0xFFA500,
170                 CORAL         : 0xFF7F50,
171                 TOMATO        : 0xFF6347,
172                 HOTPINK       : 0xFF69B4,
173                 PINK          : 0xFFC0CB,
174                 DEEPPINK      : 0xFF1493,
175                 PALEVIOLETRED : 0xDB7093,
176                 VIOLET        : 0xEE82EE,
177                 PLUM          : 0xDDA0DD,
178                 ORCHILD       : 0xDA70D6,
179                 DARKVIOLET    : 0x9400D3,
180                 BLUEVIOLET    : 0x8A2BE2,
181                 MEDIUMPURPLE  : 0x9370DB,
182                 THISTLE       : 0xD8BFD8,
183                 LAVENDER      : 0xE6E6FA,
184                 MISTYROSE     : 0xFFE4E1,
185                 IVORY         : 0xFFFFF0,
186                 LEMONCHIFFON  : 0xFFFACD
187 };
188         
189 function X_Node_CSS_parseColor( x ){
190         var rgb, r, g, b;
191         
192         if( X.Type.isNumber( x ) ){
193                 return ( 0x0 <= x && x <= 0xFFFFFF ) ? x : undefined;
194         } else
195         if( !X.Type.isString( x ) ) return;
196         
197         if( X.Type.isNumber( rgb = X_Node_CSS_COLOR[ x.toUpperCase() ] ) && 0x0 <= rgb && rgb <= 0xFFFFFF ){
198                 return rgb;
199         } else
200         if( x.charAt( 0 ) === '#' ){
201                 switch( x.length ){
202                         case 7 :
203                                 r = parseInt( x.substr( 1, 2 ), 16 );
204                                 g = parseInt( x.substr( 3, 2 ), 16 );
205                                 b = parseInt( x.substr( 5, 2 ), 16 );
206                                 break;
207                         case 4 :
208                                 r = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 );
209                                 g = parseInt( x.charAt( 2 ) + x.charAt( 2 ), 16 );
210                                 b = parseInt( x.charAt( 3 ) + x.charAt( 3 ), 16 );
211                                 break;
212                         case 2 :
213                                 r = g = b = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 );
214                                 break;
215                         default :
216                                 return;                                                                                 
217                 };
218         } else
219         if( x.indexOf( 'rgb(' ) === 0 ){
220                 rgb = x.substr( 4 ).split( ',' );
221                 r = parseFloat( rgb[ 0 ] );
222                 g = parseFloat( rgb[ 1 ] );
223                 b = parseFloat( rgb[ 2 ] );
224                 if( x.indexOf( '%' ) !== -1 ){
225                         r *= 2.55;
226                         g *= 2.55;
227                         b *= 2.55;
228                 };
229         } else
230         if( x.indexOf( 'rgba(' ) === 0 ){
231                 rgb = x.substr( 5 ).split( ',' );
232                 r = parseFloat( rgb[ 0 ] );
233                 g = parseFloat( rgb[ 1 ] );
234                 b = parseFloat( rgb[ 2 ] );
235                 //a = parseFloat( rgb[ 3 ] );
236                 if( x.indexOf( '%' ) !== -1 ){
237                         r *= 2.55;
238                         g *= 2.55;
239                         b *= 2.55;
240                 };
241         } else {
242                 return undefined;
243         };
244         return isFinite( r + b + g ) ? ( r << 16 ) + ( g << 8 ) + b : undefined;
245 };
246
247 function X_Node_CSS_objToCssText( that ){
248         var obj   = that._css,
249                 plain = X_EMPTY_OBJECT,
250                 css   = [],
251                 n     = -1,
252                 p, v, specialFix, filterFix;
253                 
254         if( !obj ) return ''; // Opera7.5 未満?
255         
256         for( p in obj ){
257                 // object の拡張に備えて plain なオブジェクトを用意し、そのメンバーと一致するものは処理の対象外。
258                 if( plain[ p ] ) continue;
259                         
260                 v = obj[ p ];
261                 
262                 p = X_Node_CSS_uncamelize( X_Node_CSS_VENDER_PREFIX[ p ] || p );
263                 
264                 if( specialFix = X_Node_CSS_SPECIAL_FIX_PROP[ p ] ){
265                         css[ ++n ] = p + ':' + specialFix( v );
266                         
267                 } else
268                 if( X_Node_CSS_FILTER_FIX_PROPS && X_Node_CSS_FILTER_FIX_PROPS[ p ] ){
269                         ( filterFix || ( filterFix = {} ) )[ p ] = v;
270                         
271                 } else {
272                         css[ ++n ] = p + ':' + v;
273                 };
274         };
275         
276         filterFix && ( css[ ++n ] = 'filter:' + X_Node_CSS_objToIEFilterText( that, filterFix ) );
277         
278         return css.join( ';' );
279 };
280
281 var
282 X_Node_CSS_FILTER_FIX_PROPS =
283         X_UA.ActiveX && X_UA.IE < 9 && !X_UA.MacIE ?
284                 {
285                         opacity    : 2,
286                         boxShadow  : 3,
287                         textShadow : 4
288                 } :
289         X_UA.ActiveX && X_UA.IE9 ? // == 9
290                 {
291                         textShadow : 4
292                 } :
293                 null;
294
295 function X_Node_CSS_objToIEFilterText( that, opt_css ){
296         var obj     = opt_css || that._css,
297                 test    = X_Node_CSS_FILTER_FIX_PROPS,
298                 filters = [],
299                 n       = -1,
300                 p, id, v, num, ary, params, i, l, dir,
301                 afterUpdate, impossible;
302         for( p in obj ){
303                 if( X_EMPTY_OBJECT[ p ] ) continue;
304                 
305                 if( !( id = test[ p ] ) ) continue;
306                 v = obj[ p ];
307                 
308                 switch( id ){
309                         case 1 : //'filter' :
310                                 filters[ ++n ] = v;
311                                 break;
312                         case 2 : //'opacity' :
313                                 filters[ ++n ] = 'alpha(opacity=' + ( v * 100 | 0 ) +')';
314                                 break;
315                         case 3 : //'boxShadow' :
316                                 // TODO カンマ区切りの複数指定
317                                 // box-shadow: 10px 10px 10px 10px rgba(0,0,0,0.4) inset;
318                                 // スペース区切りで、水平方向の距離 垂直方向の距離 ぼかし距離 広がり距離 影の色 insetキーワードを指定する。 ぼかし距離 広がり距離 影の色 insetキーワードは省略可
319                                 // https://developer.mozilla.org/ja/docs/Web/CSS/box-shadow
320                                 // <length> に絶対値は不可? <color> 省略した場合は、文字の色が使われる(webkit以外)
321                                 // shadow(color=#cccccc, strength=10, direction=135);
322                                 ary = v.split( ' ' );
323                                 params = [ 0, 0, 0, 0 ]; // offset-x, offset-y, blur-radius, spread-radius
324                                 for( i = 0, l = ary.length; i < l; ++i ){
325                                         v = ary[ i ];
326                                         num = i < 4 && parsetFloat( v );
327                                         
328                                         if( num === num ){
329                                                 vu = X_Node_CSS__splitValueAndUnit( v );
330                                                 v  = vu[ 0 ];
331                                                 u  = vu[ 1 ];
332                                                 if( v ){
333                                                         if( _v = X_Node_CSS__UNIT_RATIO[ u ] ){
334                                                                 params[ i ] = v / _v;
335                                                         } else {
336                                                                 switch( u ){
337                                                                         case 'px' :
338                                                                                 params[ i ] = v;
339                                                                                 break;
340                                                                         case 'em' :
341                                                                                 if( X_Node_updateTimerID ){
342                                                                                         afterUpdate = true;
343                                                                                 } else {
344                                                                                         params[ i ] = X_Node_CSS_getCharSize( that ) * v;
345                                                                                 };
346                                                                         default :
347                                                                                 params[ i ] = 0;
348                                                                                 break;
349                                                                 };                                                              
350                                                         };
351                                                 } else {
352                                                         params[ i ] = 0;
353                                                 };
354                                         } else
355                                         if( v.charAt( 0 ) === '#' || v.indexOf( 'rgb' ) === 0 || X_Node_CSS_COLOR[ v.toUpperCase() ] ){
356                                                 v = X_Node_CSS_parseColor( v );
357                                                 if( 0 <= v && v < 0x100000 ){
358                                                         color = '00000' + v.toString( 16 );
359                                                         color = '#' + color.substr( color.length - 6 );
360                                                 } else
361                                                 if( v ){
362                                                         color = '#' + v.toString( 16 );
363                                                 };
364                                         } else                                  
365                                         if( v === 'inset' ){
366                                                 impossible = true;
367                                         } else {
368                                                 // unknown
369                                         };
370                                 };
371                                 if( impossible || !color ){
372                                         break;
373                                 };
374                                 if( afterUpdate ){
375                                         // AFTER_UPDATE 時に 再計算
376                                         X_ViewPort.listenOnce( X_Event.AFTER_UPDATE, that, X_Node_CSS_onAfterUpdateForIEFilterFix );
377                                         break;
378                                 };
379                                 dir = Math.atan2( params[ 1 ] + params[ 3 ], params[ 0 ] + params[ 3 ] ) * 180 / Math.PI + 90;
380                                 dir += dir < 0 ? 360 : 0;
381                                 filters[ ++n ] = 'shadow(color=' + color + ',strength=' + params[ 3 ] + ',direction=' + ( dir | 0 ) + ')';
382                                 break;
383                         case 4 : //'textShadow' :
384                                 //text-shadow: 5px 5px 2px blue; 水平方向の距離 垂直方向の距離 影のぼかし半径 影の色 none
385                                 //glow(Color=yellow,Strength=10);
386                                 //どうやらCSSのbackgroundプロパティと同時に使えないようです。 s
387                                 break;
388                         case 5 : //'backgroundImage' :
389                                 //
390                 };
391         };
392         return filters.join( ' ' );
393 };
394
395 function X_Node_CSS_onAfterUpdateForIEFilterFix(){
396         if( this._root ){ // 要素があり、要素がツリーに属している
397                 this._dirty |= X_Node_Dirty.IE_FILTER;
398                 X_Node_reserveUpdate();
399         };
400 };
401
402
403         /*
404          * http://css-eblog.com/ie-css-problems/rgba-pe.html
405          * ie67 では rgb() は background-color で反応しない、、、
406          */
407         
408 var     
409 X_Node_CSS_UNIT = {
410                 'px'   : 0,
411                 'em'   : 1,
412                 // ex, rem, vh, vw, vmin, vmax
413                 'cm'   : 2,
414                 'mm'   : 3,
415                 'in'   : 4,
416                 // pt, pc, mozmm
417                 '%'    : 5,
418                 'pct'  : 5,
419                 'ms'   : 6,
420                 's'    : 7,
421                 '#'    : 8,
422                 'rgb'  : 9,
423                 'rgba' : 10
424 };
425
426 /*
427  * .2, -.1 といったケースに対処
428  * 
429  */
430 function X_Node_CSS__splitValueAndUnit( v ){
431         var num, _num, u;
432         if( X.Type.isNumber( v ) ) return [ v || 0, '' ];
433         num = parseFloat( v );
434         if( num !== num ) return [ 0, '' ];
435         _num = '' + num;
436         if(  0 < num && num < 1 && v.charAt( 0 ) === '.' ) _num = _num.slice( 1 );
437         if( -1 < num && num < 0 && v.charAt( 1 ) === '.' ) _num = '-.' + _num.substr( 2 );
438         u = v.substr( v.indexOf( _num ) + _num.length );
439         return [ num, X_Node_CSS_UNIT[ u ] ? u : 'px' ];
440 };
441                 /*
442                 (function( obj ){
443                         var test    = X_Node_CSS_SPECIAL_FIX_PROP,
444                                 ret = [], p, id, v, bgpX, bgpY, clipT, clipB, clipL, clipR;
445                         for( p in obj ){
446                                 if( !( id = test[ p ] ) ) continue;
447                                 v = obj[ p ];
448                                 switch( id ){
449                                         case 1 : //'backgroundPositionX' :
450                                                 bgpX = v;
451                                                 break;
452                                         case 2 : //'backgroundPositionY' :
453                                                 bgpY = v;
454                                                 break;
455                                         case 3 : //'clipTop' :
456                                                 clipT = v;
457                                                 break;
458                                         case 4 : //'clipBottom' :
459                                                 clipB = v;
460                                                 break;
461                                         case 5 : //'clipLeft' :
462                                                 clipL = v;
463                                                 break;
464                                         case 6 : //'clipRight' :
465                                                 clipR = v;
466                                                 break;
467                                 };
468                         };
469                         if( bgpX || bgpY ) ret[ ret.length ] = 'background-position:';
470                         if( clipT || clipB || clipL || clipR ){
471                                 ret[ ret.length ] = 'clip:rect(';
472                         };
473                         return ret.join( ';' );
474                 }); */
475
476
477
478
479 // export
480 // name getter
481 // unitID, name 単位指定のプロパティ取得 geter
482 // obj setter
483 // name, value setter
484
485 Node.prototype.css = function( nameOrObj /* orUnitID, valuOrUnitOrName */ ){
486         var plain = X_EMPTY_OBJECT,
487                 args  = arguments,
488                 css   = this._css,
489                 p, name, v, camelize, unit, ieFix;
490         if( this._xnodeType !== 1 ) return this;
491 // setter:object
492         if( X.Type.isObject( nameOrObj ) ){
493                 if( !css ) css = this._css = {};
494                 camelize = X_Node_CSS_camelize;
495                 ieFix    = X_Node_CSS_FILTER_FIX_PROPS;
496                 for( p in nameOrObj ){
497                         if( plain[ p ] ) continue;
498                         
499                         if( ieFix && ieFix[ p ] ){
500                                 this._dirty |= X_Node_Dirty.IE_FILTER;
501                         };
502                         v = nameOrObj[ p ];
503                         v || v === 0 ? css[ camelize( p ) ] = v : delete css[ camelize( p ) ];
504                         if( p === 'display' ){
505                                 v === 'none' ? ( this._state |= X_Node_State.IE5_DISPLAY_NONE_FIX ) : ( this._state &= ~X_Node_State.IE5_DISPLAY_NONE_FIX );
506                                 v === 'none' ? ( this._state |= X_Node_State.DISPLAY_NONE ) : ( this._state &= ~X_Node_State.DISPLAY_NONE );
507                         };
508                 };
509                 this._dirty |= X_Node_Dirty.CSS;
510                 this.parent && X_Node_reserveUpdate();
511                 delete this._cssText;
512                 return this;
513         } else
514         if( 1 < args.length ){
515 // setter name, value
516                 if( !css ) css = this._css = {};
517                 name = X_Node_CSS_camelize( nameOrObj );
518                 v    = args[ 1 ];
519                 if( css[ name ] === v ) return this;
520                 if( X_Node_CSS_FILTER_FIX_PROPS && X_Node_CSS_FILTER_FIX_PROPS[ name ] ){
521                         this._dirty |= X_Node_Dirty.IE_FILTER;
522                 };
523                 if( !v && v !== 0 ){
524                         delete css[ name ];
525                 } else {
526                         css[ name ] = v;
527                 };
528                 delete this._cssText;
529                 this._dirty |= X_Node_Dirty.CSS;
530                 if( name === 'display' ){
531                         v === 'none' ? ( this._state |= X_Node_State.IE5_DISPLAY_NONE_FIX ) : ( this._state &= ~X_Node_State.IE5_DISPLAY_NONE_FIX );
532                         v === 'none' ? ( this._state |= X_Node_State.DISPLAY_NONE ) : ( this._state &= ~X_Node_State.DISPLAY_NONE );
533                 };
534                 // parent でなく this._root! でなくて this._state & in tree
535                 this.parent && X_Node_reserveUpdate();
536                 return this;
537         };
538 // getter
539         if( !css ) return;
540         // 集計 border, padding, margin, backgroundPosition, clip
541         // border で正確なデータを返せない時は、null を返す
542         return css[ X_Node_CSS_camelize( nameOrObj ) ];
543 };
544
545 Node.prototype.cssText = function( v ){
546         var obj, i, l, attr, name;
547         if( v === '' ){
548                 delete this._css;
549                 this._state &= ~X_Node_State.IE5_DISPLAY_NONE_FIX;
550                 this._dirty |= X_Node_Dirty.CSS;
551                 this.parent && X_Node_reserveUpdate();
552                 delete this._cssText;
553                 return this;
554         } else
555         if( X.Type.isString( v ) ){
556                 delete this._css;
557                 this._state &= ~X_Node_State.IE5_DISPLAY_NONE_FIX;
558                 obj = {};
559                 v   = v.split( ';' ); // TODO content ";" などにも対応
560                 for( i = 0, l = v.length; i < l; ++i ){
561                         attr = v[ i ].split( ':' );
562                         ( name = attr[ 0 ] ) && ( obj[ name ] = attr[ 1 ] || true );
563                 };
564                 return this.css( obj );
565         };
566         // getter
567         if( this._dirty & X_Node_Dirty.CSS && !( this._cssText = X_Node_CSS_objToCssText( this ) ) ){
568                 delete this._cssText;
569         };
570         return this._cssText;
571 };
572
573 /*
574  * ここでは HTMLElement のチ1ェックは行わない!
575  * TODO
576  * body に css attr がセットされた場合には X_ViewPort_baseFontSize をクリア
577  * class, id, attr(<font size><basefont>) の変更があった場合は、変更の適用の後、charSize を取得
578  * css の場合は、計算で求めることが可能、content は影響しない
579  * :hover, #target, が絡む場合、正しく扱えない
580  */
581 var
582 X_Node_CSS_getCharSize =
583         X_node_CSS_getComputedStyle ?
584                 (function( that ){
585                         X_Node_updateTimerID && X_Node_startUpdate();
586                         if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
587                         if( that._fontSize ) return that._fontSize;
588                         return that._fontSize = parseFloat( X_node_CSS_getComputedStyle( that._rawObject, null ).fontSize );
589                 }) :
590
591         5.5 <= X_UA.IE ?
592                 (function( that ){
593                         var font, vu, v, u, _v;
594                         X_Node_updateTimerID && X_Node_startUpdate();
595                         if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
596                         if( that._fontSize ) return that._fontSize;
597                         
598                         font = that._rawObject.currentStyle.fontSize;
599                         //font = that._css && that._css.fontSize || '1em';
600                         vu   = X_Node_CSS__splitValueAndUnit( font );
601                         v    = vu[ 0 ];
602                         u    = vu[ 1 ];
603
604                         if( v === 0 ){
605                                 if( v = X_Node_CSS__FONT_SIZE_RATIO[ font ] ) return that._fontSize = v;
606                         } else {
607                                 if( _v = X_Node_CSS__UNIT_RATIO[ u ] ) return that._fontSize = v / _v;
608                         };
609                         switch( u ){
610                                 case 'px' :
611                                         return that._fontSize = v;
612                                 case 'em' :
613                                 // body まで辿ってしまった場合は?
614                                         if( that.parent ) return that._fontSize = X_Node_CSS_getCharSize( that.parent ) * v;
615                                         break;
616                                 case '%' :
617                                 // body まで辿ってしまった場合は?
618                                         if( that.parent ) return that._fontSize = X_Node_CSS_getCharSize( that.parent ) * v / 100;
619                         };
620                         return 0;
621                 }) :
622         X_UA_DOM.W3C ?
623                 (function( that ){
624                         var elm, v;
625                         X_Node_updateTimerID && X_Node_startUpdate();
626                         if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
627                         if( that._fontSize ) return that._fontSize;
628
629                         that._rawObject.appendChild( elm = document.createElement( 'span' ) );
630                         elm.style.cssText = 'display:block;position:absolute;top:0;left:0;visivility:hidden;line-height:1;height:1em;';
631                         elm.innerHTML = 'X';
632                         v = elm.offsetHeight;
633                         that._rawObject.removeChild( elm );
634                         return that._fontSize = v;
635                 }) :
636         X_UA_DOM.IE4 ?
637                 (function( that ){
638                         var font, vu, v, u, _v;
639                         X_Node_updateTimerID && X_Node_startUpdate();
640                         if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
641                         if( that._fontSize ) return that._fontSize;
642                         
643                         if( that._css && ( font = that._css.fontSize ) ){
644                                 vu = X_Node_CSS__splitValueAndUnit( font );
645                                 v  = vu[ 0 ];
646                                 u  = vu[ 1 ];
647                                 
648                                 if( v === 0 ){
649                                         if( _v = X_Node_CSS__FONT_SIZE_RATIO[ font ] ) return that._fontSize = _v;
650                                 } else {
651                                         if( _v = X_Node_CSS__UNIT_RATIO[ u ] ) return that._fontSize = v / _v;
652                                 };
653                         } else {
654                                 v = 1;
655                                 u = 'em';
656                         };
657
658                         switch( u ){
659                                 case 'px' :
660                                         return that._fontSize = v;
661                                 case 'em' :
662                                 // body まで辿ってしまった場合は?
663                                         if( that.parent ) return that._fontSize = X_Node_CSS_getCharSize( that.parent ) * v;
664                                         break;
665                                 case '%' :
666                                 // body まで辿ってしまった場合は?
667                                         if( that.parent ) return that._fontSize = X_Node_CSS_getCharSize( that.parent ) * v / 100;
668                         };
669                         return 0;
670                 }) :
671                 0;
672
673 var X_Node_CSS_Support = {},
674
675         X_Node_CSS_SPECIAL_FIX_PROP = {
676                 
677                 transitionDuration : X_UA.Android && !X_UA.Chrome && function( v ){ // bad Android
678                                 return parseFloat( v ) === 0 ? '0.001s' : v;
679                         }
680                 
681                 //webkit boxShadow <color> が省略された場合。transparent になるのを color に
682                 //webkit boxShadow が border-radius をはみ出す, background-image に グラデーションのないグラデーション指定
683                 // http://melty.koume.in/android-bug-boxshadow-radius/
684                 
685         };
686
687 X.CSS = {
688         
689         VENDER_PREFIX : X_Node_CSS_VENDER_PREFIX,
690         // iscroll で使用
691         uncamelize    : X_Node_CSS_uncamelize,
692         
693         Support       : X_Node_CSS_Support
694 };
695
696 /*
697  *                              backgroundPositionX : testStyle.backgroundPositionX === undefined ? 3 : 0,
698                                 backgroundPosiitonY : testStyle.backgroundPositionX === undefined ? 3 : 0,
699                                 clipTop             : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 3 : 0,
700                                 clipBottom          : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 4 : 0,
701                                 clipLeft            : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 5 : 0,
702                                 clipRight           : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 6 : 0
703  */
704
705 (function(){
706         var testStyle = X_UA.IE4 ? {} : ( /*document.documentElement ||*/ document.createElement( 'div' ) ).style,
707                 temp      = testStyle.cssText,
708                 vendors   = 'webkit,Webkit,Moz,moz,Ms,ms,O,o,khtml,Khtml'.split( ',' ),
709                 searches  = (
710                         'opacity,boxSizing,boxShadow,' +
711                         'transform,transformOrigin,perspective,' +
712                         'transisiton,transitionDelay,transitionProperty,transitionDuration,transitionTimingFunction,backfaceVisibility,willChange,filter,' +
713                         'userSelect,touchSelect,touchAction,touchCallout,contentZooming,userDrag,tapHighlightColor' ).split( ',' ),
714                 vendor, i, search, prop, j, v;
715
716         for( i = searches.length; i; ){
717                 search = prop = searches[ --i ];
718                 
719                 if( testStyle[ prop ] === undefined ){
720                         prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 );
721                         for( j = vendors.length; j; ){
722                                 v = vendors[ --j ];
723                                 if( testStyle[ v + prop ] !== undefined ){
724                                         if( v === 'ms' ) v = 'Ms';// for ie9
725                                         if( v === 'o' ) v = 'O';//for opera12
726                                         X_Node_CSS_VENDER_PREFIX[ search ] = v + prop;
727                                         break;
728                                 };
729                         };                              
730                 } else {
731                         X_Node_CSS_VENDER_PREFIX[ search ] = prop;
732                 };
733         };
734         
735         testStyle.cssText = 'background:rgba(0,0,0,0.5);border-color:transparent';
736         X_Node_CSS_Support[ 'rgba' ] = !!testStyle[ 'background' ];
737         X_Node_CSS_Support[ 'transparent' ] = !!testStyle[ 'borderColor' ];
738         // TODO border による三角形の可否
739         // 2:完全、 1:透過に非対応(IE7-) 0:borderの描画が非標準で三角形が作れない
740         
741                 /*
742                  * chrome 1+, ff3.5(1.9.1), ie9+, opera10.5+, Safari3+(522)
743                  */
744         if( prop = X_Node_CSS_VENDER_PREFIX[ 'boxShadow' ] ){
745                 
746                 testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0';
747                 X_Node_CSS_Support[ 'boxShadow' ] = !!testStyle[ prop ];
748
749                 /*
750                  * chrome 4+, ff3.5(1.9.1), ie9+, opera10.5+, Safari5+(533)
751                  */
752                 testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0, 0 0';
753                 X_Node_CSS_Support[ 'boxShadowMulti' ] = !!testStyle[ prop ];
754                 
755                 /*
756                  * https://developer.mozilla.org/ja/docs/Web/CSS/box-shadow
757                  * この値を用いる場合には、spread-radius を省略出来ません。box-shadow が効かないケースに遭遇した時はこの事を思い出して下さい。
758                  * chrome 4+, ff3.5(1.9.1), ie9+, opera10.5+, Safari5+(533)
759                  * 
760                  * http://unformedbuilding.com/articles/considerations-when-using-the-box-shadow/
761                  *  box-shadow:inset と border-radius を指定しているときの Google Chrome の表示
762                  *  このバグは Windows と Linux で発生するようです。
763                  *  Windows 版 Chrome 10.0.648.127 で修正されているのを確認しました。
764                  */
765                 testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0 inset';
766                 X_Node_CSS_Support[ 'boxShadowInset' ] = testStyle[ prop ] && testStyle[ prop ].indexOf( 'inset' ) !== -1;
767
768         };
769
770         
771         testStyle.cssText = temp;
772
773 })();
774
775 X_ViewPort.listenOnce( X_TEMP.SYSTEM_EVENT_INIT, function(){
776         var xnode  = X_Node_systemNode,
777                 output = X_Node_CSS__UNIT_RATIO,
778                 list   = 'cm,mm,in,pt,pc'.split( ',' ),
779                 unit, size, base, i;
780         
781         for( i = list.length; i; ){
782                 unit = list[ --i ];
783                 output[ unit ] = xnode.css( 'width', 10 + unit ).width() / 10;
784         };
785
786         output = X_Node_CSS__FONT_SIZE_RATIO,
787         list   = 'xx-large,x-large,large,larger,medium,small,smaller,x-small,xx-small'.split( ',' );
788         xnode.css( { lineHeight : '100%', height : '1em' } ).text( 'X' );
789         
790         for( i = list.length; i; ){
791                 size = list[ --i ];
792                 output[ size ] = xnode.css( 'fontSize', size ).height();// / base;
793         };
794         
795         xnode.cssText( '' ).empty();
796 });
797