OSDN Git Service

Version 0.6.215, bug fixes X.Net.Image & X.HTMLAudio.
[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 : NaN;
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 NaN;
243         };
244         return X_Type_isFinite( r + b + g ) ? ( r << 16 ) + ( g << 8 ) + b : NaN;
245 };
246
247 function X_Node_CSS_objToCssText( that, skipFilter ){
248         var obj   = that[ '_css' ],
249                 //plain = X_EMPTY_OBJECT,
250                 css   = [],
251                 n     = -1,
252                 p, v, specialFix, filterFix;
253         
254         that[ '_flags' ] &= ~X_NodeFlags_OLD_CSSTEXT;
255         
256         if( !obj ){ // Opera7.5 未満?
257                 delete that[ '_cssText' ];
258                 return '';
259         };
260         
261         for( p in obj ){
262                 // object の拡張に備えて plain なオブジェクトを用意し、そのメンバーと一致するものは処理の対象外。
263                 //if( plain[ p ] ) continue;
264                         
265                 v = obj[ p ];
266                 
267                 p = X_Node_CSS_uncamelize( X_Node_CSS_VENDER_PREFIX[ p ] || p );
268                 
269                 if( specialFix = X_Node_CSS_SPECIAL_FIX_PROP[ p ] ){
270                         css[ ++n ] = p + ':' + specialFix( v );
271                 } else
272                 if( X_Node_CSS_FILTER_FIX_PROPS && X_Node_CSS_FILTER_FIX_PROPS[ p ] ){
273                         ( filterFix || ( filterFix = {} ) )[ p ] = v;
274                 } else {
275                         css[ ++n ] = p + ':' + v;
276                 };
277         };
278         
279         if( filterFix ){
280                 v = X_Node_CSS_objToIEFilterText( that, filterFix, css );
281                 n = css.length; /* css が変更されている場合あり */
282                 if( v ){
283                         css[ ++n ] = 'filter:' + v;
284                 };
285                 skipFilter = skipFilter && v;
286         } else {
287                 skipFilter = false;
288         };
289         
290         if( 0 <= n ){
291                 // cssText には完全なものを控えるが、戻すのは filter を抜いたもの
292                 that[ '_cssText' ] = css.join( ';' );
293                 //console.log( that[ '_cssText' ] );
294                 if( skipFilter ){
295                         --css.length;
296                         return css.join( ';' );
297                 };
298                 return that[ '_cssText' ];
299         };
300         delete that[ '_cssText' ];
301         return '';
302 };
303
304 var
305 X_Node_CSS_FILTER_FIX_PROPS =
306         X_UA[ 'ActiveX' ] && X_UA[ 'IE' ] < 9 ?
307                 {
308                         'opacity'     : 2,
309                         'boxShadow'   : 3,
310                         'textShadow'  : 4,
311                         'transform'   : 5,
312                         'dxtransform' : 7 // X.NodeAnime で使用
313                 } :
314         X_UA[ 'ActiveX' ] && X_UA[ 'IE9' ] ? // == 9
315                 {
316                         'textShadow' : 4
317                 } :
318                 null;
319
320 function X_Node_CSS_objToIEFilterText( that, opt_css, opt_cssList ){
321         var obj     = opt_css || that[ '_css' ],
322                 test    = X_Node_CSS_FILTER_FIX_PROPS,
323                 filters = [],
324                 n       = -1,
325                 p, id, v, num, vu, u, _v, ary, params, i, l, dir,
326                 afterUpdate, impossible, color;
327
328         for( p in obj ){
329                 //if( X_EMPTY_OBJECT[ p ] ) continue;
330                 
331                 if( !( id = test[ p ] ) ) continue;
332                 v = obj[ p ];
333                 
334                 switch( id ){
335                         case 1 : //'filter' :
336                                 filters[ ++n ] = v;
337                                 break;
338                         case 2 : //'opacity' :
339                                 if( v === 0 ){
340                                         console.log( '@opacity:0 ' + !!opt_cssList );
341                                         opt_cssList && ( opt_cssList[ opt_cssList.length ] = 'visibility:hidden' );
342                                 } else
343                                 if( v < 1 ) filters[ ++n ] = 'alpha(opacity=' + ( v * 100 | 0 ) +')';
344                                 break;
345                         case 3 : //'boxShadow' :
346                                 // TODO カンマ区切りの複数指定
347                                 // box-shadow: 10px 10px 10px 10px rgba(0,0,0,0.4) inset;
348                                 // スペース区切りで、水平方向の距離 垂直方向の距離 ぼかし距離 広がり距離 影の色 insetキーワードを指定する。 ぼかし距離 広がり距離 影の色 insetキーワードは省略可
349                                 // https://developer.mozilla.org/ja/docs/Web/CSS/box-shadow
350                                 // <length> に絶対値は不可? <color> 省略した場合は、文字の色が使われる(webkit以外)
351                                 // shadow(color=#cccccc, strength=10, direction=135);
352                                 ary = v.split( ' ' );
353                                 params = [ 0, 0, 0, 0 ]; // offset-x, offset-y, blur-radius, spread-radius
354                                 for( i = 0, l = ary.length; i < l; ++i ){
355                                         v = ary[ i ];
356                                         num = i < 4 && parsetFloat( v );
357                                         
358                                         if( num === num ){
359                                                 vu = X_Node_CSS__splitValueAndUnit( v );
360                                                 v  = vu[ 0 ];
361                                                 u  = vu[ 1 ];
362                                                 if( v ){
363                                                         if( _v = X_Node_CSS__UNIT_RATIO[ u ] ){
364                                                                 params[ i ] = v / _v;
365                                                         } else {
366                                                                 switch( u ){
367                                                                         case 'px' :
368                                                                                 params[ i ] = v;
369                                                                                 break;
370                                                                         case 'em' :
371                                                                                 if( X_Node_updateTimerID ){
372                                                                                         afterUpdate = true;
373                                                                                 } else {
374                                                                                         params[ i ] = X_Node_CSS_getCharSize( that ) * v;
375                                                                                 };
376                                                                         default :
377                                                                                 params[ i ] = 0;
378                                                                                 break;
379                                                                 };                                                              
380                                                         };
381                                                 } else {
382                                                         params[ i ] = 0;
383                                                 };
384                                         } else
385                                         if( v.charAt( 0 ) === '#' || v.indexOf( 'rgb' ) === 0 || X_Node_CSS_COLOR[ v.toUpperCase() ] ){
386                                                 v = X_Node_CSS_parseColor( v );
387                                                 if( 0 <= v && v < 0x100000 ){
388                                                         color = '00000' + v.toString( 16 );
389                                                         color = '#' + color.substr( color.length - 6 );
390                                                 } else
391                                                 if( v ){
392                                                         color = '#' + v.toString( 16 );
393                                                 };
394                                         } else                                  
395                                         if( v === 'inset' ){
396                                                 impossible = true;
397                                         } else {
398                                                 // unknown
399                                         };
400                                 };
401                                 if( impossible || !color ){
402                                         break;
403                                 };
404                                 if( afterUpdate ){
405                                         // AFTER_UPDATE 時に 再計算
406                                         X_ViewPort[ 'listenOnce' ]( X_EVENT_AFTER_UPDATE, that, X_Node_CSS_onAfterUpdateForIEFilterFix );
407                                         break;
408                                 };
409                                 dir = X_Node_CSS_ieMathRangeFix( Math.atan2( params[ 1 ] + params[ 3 ], params[ 0 ] + params[ 3 ] ) * 180 / Math.PI + 90 );
410                                 filters[ ++n ] = 'shadow(color=' + color + ',strength=' + params[ 3 ] + ',direction=' + ( dir | 0 ) + ')';
411                                 break;
412                         case 4 : //'textShadow' :
413                                 //text-shadow: 5px 5px 2px blue; 水平方向の距離 垂直方向の距離 影のぼかし半径 影の色 none
414                                 //glow(Color=yellow,Strength=10);
415                                 //どうやらCSSのbackgroundプロパティと同時に使えないようです。 
416                                 break;
417                         case 6 : //'backgroundImage' :
418                                 //
419                                 break;
420
421                         case 5 : // transform scale, matrix
422                                 break;
423                         case 7 : // dxtransform
424                                 that[ '_flags' ] |= X_NodeFlags_IE_FILTER_FIX_AFTER;
425                                 break;
426                 };
427         };
428         return filters.join( ' ' );//n !== -1 ? filters.join( ' ' ) : '';
429 };
430
431
432         //0 ~ 360の範囲に収める.
433         function X_Node_CSS_ieMathRangeFix( a ){
434                 a %= 360;
435                 return a < 0 ? 360 + a : a;
436         };
437
438 /*
439  * http://p2b.jp/200912-CSS3-Transform-for-IE8
440  * http://rtilabs.rti-giken.jp/files/2011_09_16/rotate.html
441  */
442         function X_Node_CSS_IETransform( elm, params ){
443                 var PI_180 = Math.PI / 180,
444
445                         rotate = X_Node_CSS_ieMathRangeFix( params[ 2 ] ),//回転
446                         radian = rotate * PI_180,
447                         cosX   = Math.cos( radian ),
448                         sinY   = Math.sin( radian ),
449                         
450                         skewX  = X_Node_CSS_ieMathRangeFix( params[ 3 ] ), //skew
451                         skewY  = X_Node_CSS_ieMathRangeFix( params[ 4 ] ),
452                         
453                         _skX   = Math.tan( skewX * PI_180 ),
454                         _skY   = Math.tan( skewY * PI_180 ),
455                         
456                         scaleX = params[ 5 ], //拡大
457                         scaleY = params[ 6 ],
458                         
459                         m11    = cosX * scaleX,
460                         m12    = ( -sinY + _skX ) * scaleX,
461                         m21    = (  sinY + _skY ) * scaleY,
462                         m22    = cosX * scaleY,
463
464                         //absolute時には軸を補正してあげないとだめだ。
465                         //ブラウザとして軸がずれている。
466                         //計算式元ネタ http://p2b.jp/200912-CSS3-Transform-for-IE8
467         
468                         //offset*系のサイズは回転によって生じたゆがみも考慮されるらしい。
469         
470                         //拡大縮小も同じ.
471                         //this.get(0).style.width や height には拡縮の影響を受けない元の数字が入っている
472                         ow = elm.offsetWidth,
473                         oh = elm.offsetHeight,
474         
475                         absCosX = Math.abs( cosX ),
476                         absSinY = Math.abs( sinY ),
477         
478                                 //回転の補正
479                         dx = ( ow - ( ow * absCosX + oh * absSinY ) ) / 2
480                                 //skewの補正(rotate しながらskew すると補正がおかしくなります。 これがわからない)
481                                  - ow / 2 * _skX
482                                 //拡大の補正
483                                  - ( ( ow * scaleX - ow ) / 2 | 0 )
484                                 // x
485                                  + params[ 0 ],
486                         dy = ( oh - ( ow * absSinY + oh * absCosX ) ) / 2
487                                 //skewの補正(
488                                  - oh / 2 * _skY
489                                 //拡大の補正
490                                  - ( ( oh * scaleY - oh ) / 2 | 0 )
491                                 // y
492                                  + params[ 1 ];
493
494                 //console.log( ow +  ' ' + oh )
495                 elm.style[ params[ 7 ] ] = dx + 'px'; // left or right
496                 elm.style[ params[ 8 ] ] = dy + 'px'; // top  or bottom
497                 
498                 //フィルターで回転と拡大縮小を加えます。
499                 return 'progid:DXImageTransform.Microsoft.Matrix(' +
500                                                                 // 'Dx='  + dx +
501                                                                 //',Dy='  + dy +
502                                                                  'M11=' + m11 + 
503                                                                 ',M12=' + m12 + 
504                                                                 ',M21=' + m21 + 
505                                                                 ',M22=' + m22 + 
506                                                                 ',FilterType="bilinear",sizingMethod="auto expand")';
507         };
508
509 function X_Node_CSS_onAfterUpdateIEFilterFix( that ){
510         var PI_180 = Math.PI / 180,
511                 test   = X_Node_CSS_FILTER_FIX_PROPS,
512                 css    = that[ '_css' ],
513                 elm    = that[ '_rawObject' ],
514                 filter = elm.style.filter || '',
515                 origin = filter,
516                 p, v, plus, id;
517
518         for( p in css ){
519                 if( !( id = test[ p ] ) ) continue;
520                 plus = 0;
521                 switch( id ){
522                         case 7 : // dxtransform
523                                 plus = X_Node_CSS_IETransform( elm, css[ p ] );
524                                 break;
525                         default :
526                                 continue;
527                 };
528                 if( plus ) filter += ( filter ? ' ' : '' ) + plus;
529         };
530         if( filter !== origin ) elm.style.filter = filter;
531 };
532
533
534 function X_Node_CSS_onAfterUpdateForIEFilterFix(){
535         if( this[ '_flags' ] & X_NodeFlags_IN_TREE ){ // 要素があり、要素がツリーに属している
536                 this[ '_flags' ] |= X_NodeFlags_DIRTY_IE_FILTER;
537                 X_Node_reserveUpdate();
538         };
539 };
540
541
542         /*
543          * http://css-eblog.com/ie-css-problems/rgba-pe.html
544          * ie67 では rgb() は background-color で反応しない、、、
545          */
546         
547 var     
548 X_Node_CSS_UNIT = {
549                 'px'   : 0,
550                 'em'   : 1,
551                 // ex, rem, vh, vw, vmin, vmax
552                 'cm'   : 2,
553                 'mm'   : 3,
554                 'in'   : 4,
555                 // pt, pc, mozmm
556                 '%'    : 5,
557                 'pct'  : 5,
558                 'ms'   : 6,
559                 's'    : 7,
560                 '#'    : 8,
561                 'rgb'  : 9,
562                 'rgba' : 10
563 };
564
565 /*
566  * .2, -.1 といったケースに対処
567  * 
568  */
569 function X_Node_CSS__splitValueAndUnit( v ){
570         var num, _num, u;
571         if( X_Type_isNumber( v ) ) return [ v || 0, '' ];
572         num = parseFloat( v );
573         if( num !== num ) return [ 0, '' ];
574         _num = '' + num;
575         if(  0 < num && num < 1 && v.charAt( 0 ) === '.' ) _num = _num.slice( 1 );
576         if( -1 < num && num < 0 && v.charAt( 1 ) === '.' ) _num = '-.' + _num.substr( 2 );
577         u = v.substr( v.indexOf( _num ) + _num.length );
578         return [ num, X_Node_CSS_UNIT[ u ] ? u : 'px' ];
579 };
580                 /*
581                 (function( obj ){
582                         var test    = X_Node_CSS_SPECIAL_FIX_PROP,
583                                 ret = [], p, id, v, bgpX, bgpY, clipT, clipB, clipL, clipR;
584                         for( p in obj ){
585                                 if( !( id = test[ p ] ) ) continue;
586                                 v = obj[ p ];
587                                 switch( id ){
588                                         case 1 : //'backgroundPositionX' :
589                                                 bgpX = v;
590                                                 break;
591                                         case 2 : //'backgroundPositionY' :
592                                                 bgpY = v;
593                                                 break;
594                                         case 3 : //'clipTop' :
595                                                 clipT = v;
596                                                 break;
597                                         case 4 : //'clipBottom' :
598                                                 clipB = v;
599                                                 break;
600                                         case 5 : //'clipLeft' :
601                                                 clipL = v;
602                                                 break;
603                                         case 6 : //'clipRight' :
604                                                 clipR = v;
605                                                 break;
606                                 };
607                         };
608                         if( bgpX || bgpY ) ret[ ret.length ] = 'background-position:';
609                         if( clipT || clipB || clipL || clipR ){
610                                 ret[ ret.length ] = 'clip:rect(';
611                         };
612                         return ret.join( ';' );
613                 }); */
614
615
616
617
618 // export
619 // name getter
620 // unitID, name 単位指定のプロパティ取得 geter
621 // obj setter
622 // name, value setter
623 /**
624  * style の getter と setter。
625  * @alias Node.prototype.css
626  * @param {string|object} [nameOrObj] style 名、または追加する style のハッシュ
627  * @param {string|number} [value=] style の値
628  * @return {Node|string|number} getter の場合は値を、setter の場合は自身を返す。(メソッドチェーン)
629  * @example // getter
630  * node.css( 'color' );
631  * // setter - 1
632  * node.css( { width : w + 'px', height : h + 'px' } );
633  * // setter - 2
634  * node.css( 'color', 0x666666 );
635  */
636 function X_Node_css( nameOrObj /* value */ ){
637         var args = arguments,
638                 css  = this[ '_css' ],
639                 p, name, v, plain, camelize, flags;
640
641         if( !this[ '_tag' ] || X_Dom_DTD_MOVE_TO_HEAD[ this[ '_tag' ] ] || this[ '_tag' ] === 'SCRIPT' ) return this;
642 // setter:object
643         if( X_Type_isObject( nameOrObj ) ){
644                 if( !css ) css = this[ '_css' ] = {};
645                 //plain    = X_EMPTY_OBJECT;
646                 camelize = X_Node_CSS_camelize;
647                 flags    = this[ '_flags' ];
648                 for( p in nameOrObj ){
649                         //if( plain[ p ] ) continue;
650                         name = camelize( p );
651                         v    = nameOrObj[ p ];
652                         if( css[ name ] === v ) continue;
653                         flags = X_Node_CSS_setStyle( css, flags, name, v );
654                 };
655                 flags |= X_NodeFlags_DIRTY_CSS | X_NodeFlags_OLD_CSSTEXT;
656                 this[ '_flags' ] = flags;
657                 flags & X_NodeFlags_IN_TREE && X_Node_reserveUpdate();
658                 delete this[ '_cssText' ];
659                 return this;
660         } else
661         if( 1 < args.length ){
662 // setter name, value
663                 if( !css ) css = this[ '_css' ] = {};
664                 name = X_Node_CSS_camelize( nameOrObj );
665                 v    = args[ 1 ];
666                 if( css[ name ] === v ) return this;
667                 this[ '_flags' ] = X_Node_CSS_setStyle( css, this[ '_flags' ], name, v ) | X_NodeFlags_DIRTY_CSS | X_NodeFlags_OLD_CSSTEXT;
668                 this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate();
669                 delete this[ '_cssText' ];
670                 return this;
671         };
672 // getter
673         if( !css ) return;
674         // TODO 集計 border, padding, margin, backgroundPosition, clip
675         // TODO border で正確なデータを返せない時は、null を返す
676         return css[ X_Node_CSS_camelize( nameOrObj ) ];
677 };
678
679 function X_Node_CSS_setStyle( css, flags, name, newValue ){
680
681         if( X_Node_CSS_FILTER_FIX_PROPS && X_Node_CSS_FILTER_FIX_PROPS[ name ] ){
682                 flags |= X_NodeFlags_DIRTY_IE_FILTER;
683         };
684         if( !newValue && newValue !== 0 ){
685                 delete css[ name ];
686         } else {
687                 css[ name ] = newValue;
688         };
689         
690         switch( name ){
691                 case 'display' :
692                         console.log( newValue );
693                         newValue === 'none' ? ( flags |= X_NodeFlags_STYLE_IS_DISPLAY_NONE ) : ( flags &= ~X_NodeFlags_STYLE_IS_DISPLAY_NONE );
694                         return flags;
695                         
696                 case 'visibility' :
697                         // すでに opacity:0 で invisible
698                         if( flags & X_NodeFlags_STYLE_IS_INVISIBLE && css[ 'opacity' ] == 0 ) return flags;
699                         newValue === 'hidden' ? ( flags |= X_NodeFlags_STYLE_IS_INVISIBLE ) : ( flags &= ~X_NodeFlags_STYLE_IS_INVISIBLE );
700                         return flags;
701                         
702                 case 'opacity' :
703                         flags |= X_NodeFlags_IE8_OPACITY_FIX;
704                         // すでに visibility:hidden で invisible
705                         if( flags & X_NodeFlags_STYLE_IS_INVISIBLE && css[ 'visibility' ] === 'hidden' ) return flags;
706                         newValue == 0 ? // 0 or "0"
707                                 ( flags |= X_NodeFlags_STYLE_IS_INVISIBLE ) : ( flags &= ~X_NodeFlags_STYLE_IS_INVISIBLE );
708                         return flags;
709                         
710                 case 'overflow' :
711                         newValue === 'hidden' ? ( flags |= X_NodeFlags_STYLE_IS_NO_OVERFLOW ) : ( flags &= ~X_NodeFlags_STYLE_IS_NO_OVERFLOW );
712                         return flags;
713                         
714                 case 'position' :
715                         newValue === 'absolute' ? ( flags |= X_NodeFlags_STYLE_IS_POS_ABSOLUTE ) : ( flags &= ~X_NodeFlags_STYLE_IS_POS_ABSOLUTE );
716                         return flags;
717                         
718                 case 'width'    :
719                         newValue = X_Node_CSS__splitValueAndUnit( newValue );
720                         if( newValue[ 1 ] !== '%' ){
721                                 flags |= X_NodeFlags_STYLE_IS_WIDTH_LENGTH;
722                                 flags &= ~X_NodeFlags_STYLE_IS_WIDTH_PCT;
723                         } else {
724                                 flags &= ~X_NodeFlags_STYLE_IS_WIDTH_LENGTH;
725                                 flags |= X_NodeFlags_STYLE_IS_WIDTH_PCT;
726                         };
727                         return flags;
728                         
729                 case 'height'   :
730                         newValue = X_Node_CSS__splitValueAndUnit( newValue );
731                         if( newValue[ 1 ] !== '%' ){
732                                 flags |= X_NodeFlags_STYLE_IS_HEIGHT_LENGTH;
733                                 flags &= ~X_NodeFlags_STYLE_IS_HEIGHT_PCT;
734                         } else {
735                                 flags &= ~X_NodeFlags_STYLE_IS_HEIGHT_LENGTH;
736                                 flags |= X_NodeFlags_STYLE_IS_HEIGHT_PCT;
737                         };
738                         return flags;
739                         
740                 case 'fontSize' :
741                         
742         };
743         return flags;
744 };
745
746 /**
747  * cssText の getter と setter。setter の場合 css と異なり全ての style が書き変わる。
748  * @alias Node.prototype.cssText
749  * @param {string=} v cssText 文字列名
750  * @return {Node|string} getter の場合は cssText 文字列を、setter の場合は自身を返す。(メソッドチェーン)
751  * @example // getter
752  * node.cssText();
753  * // setter
754  * node.cssText('color:red;width:20px');
755  */
756 function X_Node_cssText( v ){
757         var obj, i, l, attr, name;
758         
759         if( v === this[ '_cssText' ] && ( ( this[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT ) === 0 ) ){
760                 return this;
761         };      
762         
763         if( v === '' ){
764                 delete this[ '_css' ];
765                 delete this[ '_cssText' ];
766                 this[ '_flags' ] |= X_NodeFlags_DIRTY_CSS | X_NodeFlags_DIRTY_IE_FILTER;
767                 this[ '_flags' ] &= ~X_NodeFlags_OLD_CSSTEXT;
768                 this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate();
769                 return this;
770         } else
771         if( X_Type_isString( v ) ){
772                 delete this[ '_css' ];
773                 obj = {};
774                 v   = v.split( ';' ); // TODO content ";" などにも対応 <- 不要 :before :after 疑似要素には触らない
775                 for( i = 0, l = v.length; i < l; ++i ){
776                         attr = v[ i ].split( ':' );
777                         ( name = attr[ 0 ] ) && ( obj[ name ] = attr[ 1 ] || true );
778                 };
779                 return this[ 'css' ]( obj );
780         };
781         // getter
782         this[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT && X_Node_CSS_objToCssText( this );
783         return this[ '_cssText' ];
784 };
785
786 /*
787  * ここでは HTMLElement のチ1ェックは行わない! <- 行う!
788  * TODO
789  * body に css attr がセットされた場合には X_ViewPort_baseFontSize をクリア
790  * class, id, attr(<font size><basefont>) の変更があった場合は、変更の適用の後、charSize を取得
791  * css の場合は、計算で求めることが可能、content は影響しない
792  * :hover, #target, が絡む場合、正しく扱えない
793  */
794 var
795 X_Node_CSS_getCharSize =
796         X_Node_CSS_getComputedStyle ?
797                 (function( that ){
798                         X_Node_updateTimerID && X_Node_startUpdate();
799                         if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
800                         if( that[ '_fontSize' ] ) return that[ '_fontSize' ];
801                         return that[ '_fontSize' ] = that[ '_rawObject' ] ? parseFloat( X_Node_CSS_getComputedStyle( that[ '_rawObject' ], null ).fontSize ) : 0;
802                 }) :
803
804         5 <= X_UA[ 'IE' ] ?
805                 (function( that ){
806                         var font, vu, v, u, _v;
807                         
808                         X_Node_updateTimerID && X_Node_startUpdate();
809                         if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
810                         if( that[ '_fontSize' ] ) return that[ '_fontSize' ];
811                         
812                         font = that[ '_rawObject' ].currentStyle.fontSize;
813                         //font = that[ '_css' ] && that[ '_css' ].fontSize || '1em';
814                         vu   = X_Node_CSS__splitValueAndUnit( font );
815                         v    = vu[ 0 ];
816                         u    = vu[ 1 ];
817
818                         if( v === 0 ){
819                                 if( v = X_Node_CSS__FONT_SIZE_RATIO[ font ] ) return that[ '_fontSize' ] = v;
820                         } else {
821                                 if( _v = X_Node_CSS__UNIT_RATIO[ u ] ) return that[ '_fontSize' ] = v / _v;
822                         };
823                         switch( u ){
824                                 case 'px' :
825                                         return that[ '_fontSize' ] = v;
826                                 case 'em' :
827                                 // body まで辿ってしまった場合は?
828                                         if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v;
829                                         break;
830                                 case '%' :
831                                 // body まで辿ってしまった場合は?
832                                         if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v / 100;
833                         };
834                         return 0;
835                 }) :
836         X_UA_DOM.W3C ?
837                 (function( that ){
838                         var elm, v;
839                         X_Node_updateTimerID && X_Node_startUpdate();
840                         if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
841                         if( that[ '_fontSize' ] ) return that[ '_fontSize' ];
842
843                         that[ '_rawObject' ].appendChild( elm = document.createElement( 'span' ) );
844                         elm.style.cssText = 'display:block;position:absolute;top:0;left:0;visivility:hidden;line-height:1;height:1em;';
845                         elm.innerHTML = 'X';
846                         v = elm.offsetHeight;
847                         that[ '_rawObject' ].removeChild( elm );
848                         return that[ '_fontSize' ] = v;
849                 }) :
850         X_UA_DOM.IE4 ?
851                 (function( that ){
852                         var font, vu, v, u, _v, elm;
853                         
854                         X_Node_updateTimerID && X_Node_startUpdate();
855                         if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize;
856                         if( that[ '_fontSize' ] ) return that[ '_fontSize' ];
857
858                         if( that[ '_css' ] && ( font = that[ '_css' ].fontSize ) ){
859                                 vu = X_Node_CSS__splitValueAndUnit( font );
860                                 v  = vu[ 0 ];
861                                 u  = vu[ 1 ];
862                                 
863                                 if( v === 0 ){
864                                         if( _v = X_Node_CSS__FONT_SIZE_RATIO[ font ] ) return that[ '_fontSize' ] = _v;
865                                 } else {
866                                         if( _v = X_Node_CSS__UNIT_RATIO[ u ] ) return that[ '_fontSize' ] = v / _v;
867                                 };
868                         } else {
869                                 // TODO 要素を生成して測定! ではなくて elm.style.fontSize が使えそう
870                                 ( that[ '_rawObject' ] || X_Node__ie4getRawNode( that ) ).insertAdjacentHTML( 'BeforeEnd', '<div id="ie4charsize" style="position:absolute;top:0;left:0;visivility:hidden;line-height:1;height:1em;">X</div>' );
871                                 elm = document.all[ 'ie4charsize' ];
872                                 v = elm.offsetHeight;
873                                 elm.removeAttribute( 'id' ); // ?
874                                 elm.outerHTML = '';
875                                 return that[ '_fontSize' ] = v;
876                         };
877
878                         switch( u ){
879                                 case 'px' :
880                                         return that[ '_fontSize' ] = v;
881                                 case 'em' :
882                                 // body まで辿ってしまった場合は?
883                                         if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v;
884                                         break;
885                                 case '%' :
886                                 // body まで辿ってしまった場合は?
887                                         if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v / 100;
888                         };
889                         return 0;
890                 }) :
891                 0;
892
893 var X_Node_CSS_Support = {},
894
895         X_Node_CSS_SPECIAL_FIX_PROP = {
896                 
897                 'transitionDuration' : X_UA[ 'Android' ] && !X_UA[ 'Chrome' ] && function( v ){ // bad Android
898                                 return parseFloat( v ) === 0 ? '0.001s' : v;
899                         }
900                 
901                 //webkit boxShadow <color> が省略された場合。transparent になるのを color に
902                 //webkit boxShadow が border-radius をはみ出す, background-image に グラデーションのないグラデーション指定
903                 // http://melty.koume.in/android-bug-boxshadow-radius/
904                 
905         };
906
907 /**
908  * @namespace X.CSS
909  */
910 X[ 'CSS' ] = {
911         /**
912          * @alias X.CSS.VENDER_PREFIX
913          */
914         'VENDER_PREFIX' : X_Node_CSS_VENDER_PREFIX,
915
916         /**
917          * @alias X.CSS.Support
918          */
919         'Support'       : X_Node_CSS_Support
920 };
921
922 /*
923  *                              backgroundPositionX : testStyle.backgroundPositionX === undefined ? 3 : 0,
924                                 backgroundPosiitonY : testStyle.backgroundPositionX === undefined ? 3 : 0,
925                                 clipTop             : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 3 : 0,
926                                 clipBottom          : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 4 : 0,
927                                 clipLeft            : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 5 : 0,
928                                 clipRight           : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 6 : 0
929  */
930
931 (function(){
932         var testStyle = X_UA[ 'IE4' ] ? {} : ( /*document.documentElement ||*/ document.createElement( 'div' ) ).style,
933                 temp      = testStyle.cssText,
934                 vendors   = 'webkit,Webkit,Moz,moz,Ms,ms,O,o,khtml,Khtml'.split( ',' ),
935                 searches  = (
936                         'opacity,boxSizing,boxShadow,' +
937                         'transform,transformOrigin,perspective,' +
938                         'transisiton,transitionDelay,transitionProperty,transitionDuration,transitionTimingFunction,backfaceVisibility,willChange,filter,' +
939                         'userSelect,touchSelect,touchAction,touchCallout,contentZooming,userDrag,tapHighlightColor' ).split( ',' ),
940                 vendor, i, search, prop, j, v;
941
942         for( i = searches.length; i; ){
943                 search = prop = searches[ --i ];
944                 
945                 if( testStyle[ prop ] === undefined ){
946                         prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 );
947                         for( j = vendors.length; j; ){
948                                 v = vendors[ --j ];
949                                 if( testStyle[ v + prop ] !== undefined ){
950                                         if( v === 'ms'/* && !( 10 <= X_UA[ 'IEHost' ] )*/ ) v = 'Ms';// for ie9, 但し ie11 のieには不要
951                                         if( v === 'o' ) v = 'O';//for opera12
952                                         X_Node_CSS_VENDER_PREFIX[ search ] = v + prop;
953                                         break;
954                                 };
955                         };                              
956                 } else {
957                         X_Node_CSS_VENDER_PREFIX[ search ] = prop;
958                 };
959         };
960         
961         testStyle.cssText = 'background:rgba(0,0,0,0.5);border-color:transparent';
962 /**
963  * 色指定に rgba() が使用できるか?
964  * @alias X.CSS.Support.rgba
965  * @type {boolean}
966  */
967         X_Node_CSS_Support[ 'rgba' ] = !!testStyle[ 'background' ];
968         
969 /**
970  * 色指定に transparent が使用できるか?
971  * @alias X.CSS.Support.transparent
972  * @type {boolean}
973  */
974         X_Node_CSS_Support[ 'transparent' ] = !!testStyle[ 'borderColor' ];
975         // TODO border による三角形の可否
976         // 2:完全、 1:透過に非対応(IE7-) 0:borderの描画が非標準で三角形が作れない
977
978         if( prop = X_Node_CSS_VENDER_PREFIX[ 'boxShadow' ] ){
979                 
980                 testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0';
981                 
982                 /**
983                  * boxShadow が使用できるか?
984                  * chrome 1+, ff3.5(1.9.1), ie9+, opera10.5+, Safari3+(522)
985                  * @alias X.CSS.Support.boxShadow
986                  * @type {boolean}
987                  */
988                 X_Node_CSS_Support[ 'boxShadow' ] = !!testStyle[ prop ];
989
990                 testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0, 0 0';
991                 
992                 /**
993                  * boxShadow の複数指定が使用できるか?<br>
994                  * chrome 4+, ff3.5(1.9.1), ie9+, opera10.5+, Safari5+(533)
995                  * @alias X.CSS.Support.boxShadowMulti
996                  * @type {boolean}
997                  */
998                 X_Node_CSS_Support[ 'boxShadowMulti' ] = !!testStyle[ prop ];
999                 
1000                 testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0 inset';
1001                 
1002                 /**
1003                  * https://developer.mozilla.org/ja/docs/Web/CSS/box-shadow<br>
1004                  * この値を用いる場合には、spread-radius を省略出来ません。box-shadow が効かないケースに遭遇した時はこの事を思い出して下さい。<br>
1005                  * chrome 4+, ff3.5(1.9.1), ie9+, opera10.5+, Safari5+(533)<br>
1006                  * 
1007                  * http://unformedbuilding.com/articles/considerations-when-using-the-box-shadow/<br>
1008                  *  box-shadow:inset と border-radius を指定しているときの Google Chrome の表示<br>
1009                  *  このバグは Windows と Linux で発生するようです。<br>
1010                  *  Windows 版 Chrome 10.0.648.127 で修正されているのを確認しました。<br>
1011                  * @alias X.CSS.Support.boxShadowInset
1012                  * @type {boolean}
1013                  */
1014                 X_Node_CSS_Support[ 'boxShadowInset' ] = testStyle[ prop ] && testStyle[ prop ].indexOf( 'inset' ) !== -1;
1015
1016         };
1017
1018         testStyle.cssText = temp;
1019
1020 })();
1021
1022 X_ViewPort[ 'listenOnce' ]( X_EVENT_INIT, function(){
1023         var xnode  = X_Node_systemNode,
1024                 output = X_Node_CSS__UNIT_RATIO,
1025                 list   = 'cm,mm,in,pt,pc'.split( ',' ),
1026                 unit, size, base, i;
1027         
1028         for( i = list.length; i; ){
1029                 unit = list[ --i ];
1030                 output[ unit ] = xnode[ 'css' ]( 'width', 10 + unit )[ 'width' ]() / 10;
1031         };
1032
1033         output = X_Node_CSS__FONT_SIZE_RATIO,
1034         list   = 'xx-large,x-large,large,larger,medium,small,smaller,x-small,xx-small'.split( ',' );
1035         xnode[ 'css' ]( { lineHeight : '100%', height : '1em' } )[ 'text' ]( 'X' );
1036         
1037         for( i = list.length; i; ){
1038                 size = list[ --i ];
1039                 output[ size ] = xnode[ 'css' ]( 'fontSize', size )[ 'height' ]();// / base;
1040         };
1041         
1042         xnode[ 'cssText' ]( '' )[ 'empty' ]();
1043 });
1044
1045