OSDN Git Service

Version 0.6.13, X.UI use X.Dom.Node.
[pettanr/clientJs.git] / 0.6.x / js / dom / 13_XDomStyle.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 X.Dom.Style = {
11         
12         Type : {
13                 LENGTH            : 1,
14                 PERCENT           : 2,
15                 COLOR             : 2 < 2,
16                 U_DECIMAL         : 2 < 3,
17                 NUMERICAL         : 2 < 4,
18                 BOOLEAN           : 2 < 5,
19                 QUARTET           : 2 < 6,
20                 URL               : 2 < 7,
21                 FONT_NAME         : 2 < 8,
22                 TIME              : 2 < 9,
23                 CONTENT           : 2 < 10,
24                 LIST              : 2 < 11,
25                 AUTO              : 2 < 12,
26                 COMBI             : 2 < 13
27         },
28         
29         SPECIAL_VALUES : {
30                 AUTO : Number.POSITIVE_INFINITY,
31                 FULL : X.Dom // something unigue value; 100%
32         },
33         
34         PropNo : {},
35         
36         UNIT : {
37                 'px'   : 0,
38                 'em'   : 1,
39                 'cm'   : 2,
40                 'mm'   : 3,
41                 'in'   : 4,
42                 '%'    : 5,
43                 'pct'  : 5,
44                 'ms'   : 6,
45                 's'    : 7,
46                 '#'    : 8,
47                 'rgb'  : 9,
48                 'rgba' : 10
49         },
50         
51         /* font-size -> fontSize */
52         _DICTIONARY_CAMELIZE : {},
53         
54         camelize : function( cssProp ){
55                 var me  = X.Dom.Style,
56                         parts, l, i, camelized;
57                 
58                 if( camelized = me._DICTIONARY_CAMELIZE[ cssProp ] ) return camelized;
59                 parts = cssProp.split( ' ' ).join( '' ).split( '-' );
60                 l     = parts.length;
61                 if( l === 1 ) return parts[ 0 ];
62                 
63                 camelized = cssProp.charAt(0) === '-'
64                   ? parts[ 0 ].charAt( 0 ).toUpperCase() + parts[ 0 ].substring( 1 )
65                   : parts[ 0 ];
66                 
67                 for( i = 1; i < l; ++i ){
68                         camelized += parts[ i ].charAt( 0 ).toUpperCase() + parts[ i ].substring( 1 );
69                 };
70                 return me._DICTIONARY_CAMELIZE[ cssProp ] = camelized;
71         },
72         
73         /* fontSize -> font-size */
74         /*
75         REG_LARGE : /[A-Z]/g,
76         uncamelize: function( str ){
77                 return str.split( ' ' ).join( '' ).replace( X.Dom.Style.REG_LARGE, '-$&' ).toLowerCase();
78         }, */
79         
80         CHAR_CODE_A : 'A'.charCodeAt( 0 ),
81         
82         _DICTIONARY_UNCAMELIZE : {},
83         
84         uncamelize : function( str ){
85                 var me  = X.Dom.Style,
86                         A   = me.CHAR_CODE_A,
87                         Z   = A + 25,
88                         uncamelized, l, chr, code;
89                 str = str.split( ' ' ).join( '' );
90                 if( uncamelized = me._DICTIONARY_UNCAMELIZE[ str ] ) return uncamelized;
91                 uncamelized = '';
92                 for( i = 0, l = str.length; i < l; ++i ){
93                         chr = str.charAt( i );
94                         code = chr.charCodeAt( 0 );
95                         uncamelized += ( A <= code && code <= Z ) ? '-' + chr : chr;
96                 };
97                 return me._DICTIONARY_UNCAMELIZE[ str ] = uncamelized.toLowerCase();
98         },
99         
100         objToCssText : function( obj ){
101                 var css           = [],
102                         me            = X.Dom.Style,
103                         uncamelize    = me.uncamelize,
104                         VENDER_PREFIX = me.VENDER_PREFIX,
105                         FIX_PROP      = me.SPECIAL_FIX_PROP,
106                         SPECIAL_FIX   = me.SPECIAL_FIX,
107                         p, name, sp;
108                 for( p in obj ){
109                         name = uncamelize( p );
110                         if( FIX_PROP[ name ] ){
111                                 sp = 1;
112                         } else {
113                                 css[ css.length ] = [ VENDER_PREFIX[ name ] || name, obj[ p ] ].join( ':' );
114                         };
115                 };
116                 sp && ( css[ css.length ] = SPECIAL_FIX( obj ) );
117                 return css.join( ';' );
118         },
119         
120         _UNIT_RATIO      : null,
121         _FONT_SIZE_RATIO : null,
122         
123         absoluteFontSizeToPx : function( fontsize ){
124                 return X.Dom.Style._FONT_SIZE_RATIO[ fontsize ] || 0;
125         }
126
127         //  https://developer.mozilla.org/en-US/docs/Web/CSS/transform
128         //  Firefox 3.5, ie9, Opera 10.5, Safari 3.1, Chrome
129         //  3D support Firefox 10, ie10, Safari 4.0, Chrome 12.0
130         // transform : void 0,
131         
132         //  https://developer.mozilla.org/ja/docs/Web/Guide/CSS/Using_CSS_transitions
133         //  Chrome 1.0, Firefox 4.0, ie10, Opera 10.5, Safari 3.2
134         //  Android 2.1, Firefox Android 4.0, Opera Mobile 10, Safari Mobile 3.2        
135         // transition : void 0
136 };
137
138 X.Dom.Style.Option = {
139         BORDER_STYLE      : 'none,hidden,dotted,dashed,solid,double,groove,ridge,inset,outset'.split(','),
140         POSITION_X        : 'left,center,right'.split(','),
141         POSITION_Y        : 'top,center,bottom'.split(','),
142         ALIGN             : 'left,center,right,justify'.split(','),
143         TEXT_DECORATION   : 'none,underline,overline,line-through,blink'.split(','),
144         TEXT_TRANSFORM    : 'none,capitalize,lowercase,uppercase'.split(','),
145         WIDTH_HEIGHT      : [ 'auto' ],
146         BOX_SIZING        : 'content-box,padding-box,border-box'.split(',') // ,margin-box
147 };
148 X.Dom.Style.Props = {
149         borderWidth       : [ X.Dom.Dirty.REFLOW,  0, X.Dom.Style.Type.QUARTET | X.Dom.Style.Type.LENGTH  ], // em [ top, right, bottom, left ]
150         borderColor       : [ X.Dom.Dirty.PAINT,   4, X.Dom.Style.Type.QUARTET | X.Dom.Style.Type.COLOR   ], // color [ top, right, bottom, left ]
151         borderStyle       : [ X.Dom.Dirty.PAINT,   8, X.Dom.Style.Type.QUARTET | X.Dom.Style.Type.LIST, X.Dom.Style.Option.BORDER_STYLE ], // string [ top, right, bottom, left ]
152         cornerRadius      : [ X.Dom.Dirty.PAINT,  12, X.Dom.Style.Type.QUARTET | X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ], // em, px [ top, right, bottom, left ]
153         bgColor           : [ X.Dom.Dirty.PAINT,  16, X.Dom.Style.Type.COLOR     ], // color
154         bgAlpha           : [ X.Dom.Dirty.PAINT,  17, X.Dom.Style.Type.U_DECIMAL ], // 0 - 1
155         bgImgUrl          : [ X.Dom.Dirty.PAINT,  18, X.Dom.Style.Type.URL       ], // url
156         bgImgRepeatX      : [ X.Dom.Dirty.PAINT,  19, X.Dom.Style.Type.BOOLEAN   ], // true / false
157         bgImgRepeatY      : [ X.Dom.Dirty.PAINT,  20, X.Dom.Style.Type.BOOLEAN   ], // true / false
158         bgImgPositionX    : [ X.Dom.Dirty.PAINT,  21, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT | X.Dom.Style.Type.LIST, X.Dom.Style.Option.POSITION_X ], // em %, px, string
159         bgImgPositionY    : [ X.Dom.Dirty.PAINT,  22, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT | X.Dom.Style.Type.LIST, X.Dom.Style.Option.POSITION_Y ], // em %, px, string
160         shadowColor       : [ X.Dom.Dirty.PAINT,  23, X.Dom.Style.Type.COLOR     ], // color
161         shadowAlpha       : [ X.Dom.Dirty.PAINT,  24, X.Dom.Style.Type.U_DECIMAL ], // 0 - 1
162         shadowOffsetX     : [ X.Dom.Dirty.PAINT,  25, X.Dom.Style.Type.LENGTH    ], // em
163         shadowOffsetY     : [ X.Dom.Dirty.PAINT,  26, X.Dom.Style.Type.LENGTH    ], // em
164         shadowBlur        : [ X.Dom.Dirty.PAINT,  27, X.Dom.Style.Type.LENGTH    ], // em
165         shadowSpread      : [ X.Dom.Dirty.PAINT,  28, X.Dom.Style.Type.LENGTH    ], // em
166         shadowInset       : [ X.Dom.Dirty.PAINT,  29, X.Dom.Style.Type.BOOLEAN   ], // true / false
167         
168         color             : [ X.Dom.Dirty.PAINT,  30, X.Dom.Style.Type.COLOR     ], // color
169         fontFamily        : [ X.Dom.Dirty.FONT,   31, X.Dom.Style.Type.FONT_NAME ], // string
170         fontSize          : [ X.Dom.Dirty.FONT,   32, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ], // em, %
171         bold              : [ X.Dom.Dirty.FONT,   33, X.Dom.Style.Type.BOOLEAN   ], // true / false
172         italic            : [ X.Dom.Dirty.FONT,   34, X.Dom.Style.Type.BOOLEAN   ], // true / false
173         lineHeight        : [ X.Dom.Dirty.FONT,   35, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT | X.Dom.Style.Type.NUMERICAL ], // em, %, 
174         letterSpacing     : [ X.Dom.Dirty.FONT,   36, X.Dom.Style.Type.LENGTH    ], // em
175         wordSpacing       : [ X.Dom.Dirty.FONT,   37, X.Dom.Style.Type.LENGTH    ],
176         align             : [ X.Dom.Dirty.FONT,   38, X.Dom.Style.Type.LIST, X.Dom.Style.Type.ALIGN           ],
177         decoration        : [ X.Dom.Dirty.PAINT,  39, X.Dom.Style.Type.LIST, X.Dom.Style.Type.TEXT_DECORATION ],
178         transform         : [ X.Dom.Dirty.FONT,   40, X.Dom.Style.Type.LIST, X.Dom.Style.Type.TEXT_TRANSFORM  ],
179         textShadowColor   : [ X.Dom.Dirty.PAINT,  41, X.Dom.Style.Type.COLOR     ],
180         textShadowOffsetX : [ X.Dom.Dirty.PAINT,  42, X.Dom.Style.Type.LENGTH    ],
181         textShadowOffsetY : [ X.Dom.Dirty.PAINT,  43, X.Dom.Style.Type.LENGTH    ],
182         shadowBlur        : [ X.Dom.Dirty.PAINT,  44, X.Dom.Style.Type.LENGTH    ],
183         
184         width             : [ X.Dom.Dirty.REFLOW, 45, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT, X.Dom.Style.Option.WIDTH_HEIGHT ],
185         minWidth          : [ X.Dom.Dirty.REFLOW, 46, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ],
186         maxWidth          : [ X.Dom.Dirty.REFLOW, 47, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ],
187         height            : [ X.Dom.Dirty.REFLOW, 48, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT, X.Dom.Style.Option.WIDTH_HEIGHT ],
188         minHeight         : [ X.Dom.Dirty.REFLOW, 49, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ],
189         maxHeight         : [ X.Dom.Dirty.REFLOW, 50, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ],
190         padding           : [ X.Dom.Dirty.REFLOW, 51, X.Dom.Style.Type.QUARTET | X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ],
191         margin            : [ X.Dom.Dirty.REFLOW, 55, X.Dom.Style.Type.QUARTET | X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ],
192         sizing            : [ X.Dom.Dirty.REFLOW, 59, X.Dom.Style.Type.LIST, X.Dom.Style.Option.BOX_SIZING ],
193         pageBox           : [ X.Dom.Dirty.REFLOW, 60, X.Dom.Style.Type.BOOLEAN ], // true / false
194         left              : [ X.Dom.Dirty.REFLOW, 61, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ],
195         top               : [ X.Dom.Dirty.REFLOW, 62, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ],
196         bottom            : [ X.Dom.Dirty.REFLOW, 63, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ],
197         right             : [ X.Dom.Dirty.REFLOW, 64, X.Dom.Style.Type.LENGTH | X.Dom.Style.Type.PERCENT ]
198 };
199         
200 X.Dom.Style.SPECIAL_FIX =
201         // ~IE8
202         X.UA.IE && X.UA.IE < 9 ?
203                 (function( obj ){
204                         var test    = X.Dom.Style.SPECIAL_FIX_PROP,
205                                 filters = [], p, id, v;
206                         for( p in obj ){
207                                 if( !( id = test[ p ] ) ) continue;
208                                 v = obj[ p ];
209                                 switch( id ){
210                                         case 1 : //'filter' :
211                                                 filters[ filters.length ] = v;
212                                                 break;
213                                         case 2 : //'opacity' :
214                                                 filters[ filters.length ] = 'aplha(opacity=' + v +')';
215                                                 break;
216                                         case 3 : //'boxShadow' :
217                                                 // box-shadow: 10px 10px 10px 10px rgba(0,0,0,0.4) inset;
218                                                 // スペース区切りで、水平方向の距離 垂直方向の距離 ぼかし距離 広がり距離 影の色 insetキーワードを指定する。 ぼかし距離 広がり距離 影の色 insetキーワードは省略可
219                                                 // shadow(color=#cccccc, strength=10, direction=135);
220                                                 parseValue( 'boxShadow', v, 'px' );
221                                                 dir = Math.atan2( ary[1], ary[0] ) * 180 / Math.PI + 90;
222                                                 dir += dir < 0 ? 360 : 0;
223                                                 break;
224                                         case 4 : //'textShadow' :
225                                                 //text-shadow: 5px 5px 2px blue; 水平方向の距離 垂直方向の距離 影のぼかし半径 影の色 none
226                                                 //glow(Color=yellow,Strength=10);
227                                                 //どうやらCSSのbackgroundプロパティと同時に使えないようです。 
228                                                 break;
229                                         case 5 : //'backgroundImage' :
230                                                 //
231                                 };
232                         };
233                         if( filters ) return filters.join( ' ' );
234                 }) :
235         // IE9
236         X.UA.IE && 9 <= X.UA.IE && X.UA.IE < 10 ?
237                 (function( obj ){
238                         var test    = X.Dom.Style.SPECIAL_FIX_PROP,
239                                 filters = [], p, id, v;
240                         for( p in obj ){
241                                 if( !( id = test[ p ] ) ) continue;
242                                 v = obj[ p ];
243                                 switch( id ){
244                                         case 1 : //'filter' :
245                                                 filters[ filters.length ] = v;
246                                                 break;
247                                 };
248                         };
249                         if( filters ) return filters.join( ' ' );
250                 }) :
251                 (function( obj ){
252                         var test    = X.Dom.Style.SPECIAL_FIX_PROP,
253                                 ret = [], p, id, v;
254                         for( p in obj ){
255                                 if( !( id = test[ p ] ) ) continue;
256                                 v = obj[ p ];
257                                 switch( id ){
258                                         case 1 : //'backgroundPositionX' :
259                                                 bgpX = v;
260                                                 break;
261                                         case 2 : //'backgroundPositionY' :
262                                                 bgpY = v;
263                                                 break;
264                                         case 3 : //'backgroundPositionX' :
265                                                 clipT = v;
266                                                 break;
267                                         case 4 : //'backgroundPositionX' :
268                                                 clipB = v;
269                                                 break;
270                                         case 5 : //'backgroundPositionX' :
271                                                 clipL = v;
272                                                 break;
273                                         case 6 : //'backgroundPositionX' :
274                                                 clipR = v;
275                                                 break;
276                                 };
277                         };
278                         if( bgpX || bgpY ) ret[ ret.length ] = 'background-position:';
279                         if( clipT || clipB || clipL || clipR ){
280                                 ret[ ret.length ] = 'clip:rect(';
281                         };
282                         return ret.join( ';' );
283                 });
284
285
286
287
288 // export
289 // name getter
290 // unitID, name 単位指定のプロパティ取得 geter
291 // obj setter
292 // name, value setter
293 X.Dom.Node.prototype.css = function( nameOrObj /* orUnitID, valuOrUnitOrName */ ){
294         var XDomStyle = X.Dom.Style,
295                 args = arguments,
296                 css  = this._css,
297                 p, valOrUnit, name, v, node, camelize;
298         if( this._xnodeType !== 1 ) return this;
299         // setter
300         if( X.Type.isObject( nameOrObj ) ){
301                 if( !css ) css = this._css = {};
302                 camelize = XDomStyle.camelize;
303                 for( p in nameOrObj ){
304                         css[ camelize( p ) ] = nameOrObj[ p ];
305                 };
306                 this._cssText = XDomStyle.objToCssText( this._css );
307                 if( node = this._ie4getRawNode ? this._ie4getRawNode() : this._rawNode ){
308                         if( this._cssText ){
309                                 node.style.cssText = this._cssText;
310                                 this._styleText = ' style="' + this._cssText + '"';
311                         } else {
312                                 node.removeAttribute( 'style' );
313                                 delete this._cssText;
314                                 delete this._styleText;
315                         };
316                 };
317                 return this;
318         } else
319         if( 1 < args.length && !XDomStyle.UNIT[ nameOrObj ] ){
320                 if( !css ) css = this._css = {};
321                 name = XDomStyle.camelize( nameOrObj );
322                 v    = args[ 1 ];
323                 node = this._ie4getRawNode ? this._ie4getRawNode() : this._rawNode;
324                 if( css[ name ] === v ) return this;
325                 if( !v && v !== 0 ){
326                         delete css[ name ];
327                         if( node ){
328                                 node.style[ name ] = ''; // val
329                         };
330                         this._cssText = XDomStyle.objToCssText( css );
331                         if( !this._cssText ){
332                                 delete this._cssText;
333                                 delete this._styleText;
334                                 node && node.removeAttribute( 'style' );
335                         };
336                         return this;
337                 };
338                 if( node ){
339                         node.style[ name ] = v; // val
340                 };
341                 if( !css[ name ] ){
342                         this._cssText = [ this._cssText, this._cssText ? ';' : '', XDomStyle.uncamelize( nameOrObj ), ':', v ].join( '' );
343                         css[ name ] = v;
344                 } else {
345                         css[ name ] = v;
346                         this._cssText = XDomStyle.objToCssText( css );
347                 };
348                 this._styleText = ' style="' + this._cssText + '"';
349                 return this;
350         };
351         // getter
352         if( !css ) return;
353         if( 1 < args.length && XDomStyle.UNIT[ nameOrObj ] ){ // unit
354                 // To do
355                 return XDomStyle.getValue( this, args[ 1 ], name );
356         };
357         // 集計 border, padding, margin, backgroundPosition, clip
358         // border で正確なデータを返せない時は、null を返す
359         return css[ XDomStyle.camelize( nameOrObj ) ];
360 };
361
362 X.Dom.Node.prototype.cssText = function( v ){
363         var camelize, obj, i, l, attr, name;
364         if( X.Type.isString( v ) ){
365                 camelize = X.Dom.Style.camelize;
366                 obj = {};
367                 v   = v.split( ';' );
368                 delete this._css;
369                 for( i = 0, l = v.length; i < l; ++i ){
370                         attr = v[ i ].split( ':' );
371                         name = camelize( attr[ 0 ] );
372                         name && ( obj[ name ] = attr[ 1 ] || true );
373                 };
374                 return this.css( obj );
375         };
376         return this._cssText;
377 };
378
379 X.Dom.Node.prototype._getCharSize =
380         document.defaultView && document.defaultView.getComputedStyle ?
381                 (function(){
382                         document.defaultView.getComputedStyle( this._rawNode, null );
383                 }) :
384         X.UA.IE && 5 <= X.UA.IE ?
385                 (function(){
386                         //this._rawNode.currentStyle;
387                 }) :
388         document.removeChild ?
389                 (function(){
390                         
391                 }) :
392                 (function(){
393                         
394                 });
395
396 X.Dom.listenOnce( X.Dom.Event.DOM_PRE_INIT, function(){
397         var testStyle = X.Dom._view;
398         
399         X.Dom.Style.VENDER_PREFIX = (function(){
400                 var ret       = {},
401                         vendors   = ',webkit,Webkit,Moz,moz,ms,Ms,O,o,khtml,Khtml'.split( ',' ),
402                         searches  =
403                                 'opacity,boxSizing,' +
404                                 'transform,transformOrigin,perspective,' +
405                                 'transisiton,transitionDelay,transitionProperty,transitionDuration,transitionTimingFunction,' +
406                                 'userSelect,touchAction,touchCallout,contentZooming,userDrag,tapHighlightColor'.split( ',' ),
407                         vendor, i, search, prop;
408                         
409                 function findVenderPrefix( prop ){
410                         var v, i = vendors.length;
411                         vendor = null;
412                         for( ; i; ){
413                                 v = vendors[ --i ];
414                                 if( testStyle[ v + prop ] !== undefined ){
415                                         vendor = v;
416                                         return v + prop;
417                                 };
418                         };      
419                 };
420                 
421                 for( i = searches.length; i; ){
422                         search = searches[ --i ];
423                         prop = findVenderPrefix( search );
424                         if( search === 'transform' ) ret.transVender = vendor;
425                         if( prop ) ret[ search ] = prop;
426                 };
427                 return ret;
428         })();
429                 
430         X.Dom.Style.SPECIAL_FIX_PROP =
431                 // ~IE8
432                 X.UA.IE && X.UA.IE < 9 ?
433                         {
434                                 filter          : 1,
435                                 opacity         : 2//, uinode ChromeNode で行う
436                                 //boxShadow       : 3,
437                                 //textShadow      : 4,
438                                 //backgroundImage : 5
439                         } :
440                 // IE9
441                 X.UA.IE && 9 <= X.UA.IE && X.UA.IE < 10 ?
442                         {
443                                 filter          : 1//,
444                                 //textShadow      : 1
445                         } :
446                 {
447                         backgroundPositionX : testStyle.backgroundPositionX === undefined ? 3 : 0,
448                         backgroundPosiitonY : testStyle.backgroundPositionX === undefined ? 3 : 0,
449                         clipTop             : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 3 : 0,
450                         clipBottom          : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 4 : 0,
451                         clipLeft            : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 5 : 0,
452                         clipRight           : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 6 : 0
453                 };
454 } );
455
456 X.Dom.listenOnce( X.Dom.Event.DOM_INIT, function(){
457         var xnode  = Node._systemNode,
458                 output = X.Dom.Style._UNIT_RATIO = {},
459                 list   = 'em,cm,mm,in,pt,pc'.split( ',' ),
460                 unit,size, base, i;
461         
462         for( i = list.length; i; ){
463                 unit = list[ --i ];
464                 output[ unit ] = xnode.css( 'width', 100 + unit ).width() / 100;
465         };
466
467         output = X.Dom.Style._FONT_SIZE_RATIO = {},
468         list   = 'xx-large,x-large,large,larger,medium,small,smaller,x-small,xx-small'.split( ',' );
469         base   = xnode.css( 'lineHeight', 1 ).text( 'X' ).height();
470         
471         for( i = list.length; i; ){
472                 size = list[ --i ];
473                 output[ size ] = xnode.css( 'fontSize', size ).height() / base;
474         };
475         
476         xnode.empty().cssText( '' );
477 } );