X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F02_dom%2F06_XNodeCSS.js;h=9711a5ebec645fcadd67b009d0a1051ee98e833f;hb=475df4df9670f042764a99c80d7716e994d28033;hp=f0f3309fbf58b96c2b69d1dfc311028aee020e38;hpb=dd02887497fa95f13d112b7fc2e5e7aefd0ffb08;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/02_dom/06_XNodeCSS.js b/0.6.x/js/02_dom/06_XNodeCSS.js index f0f3309..9711a5e 100644 --- a/0.6.x/js/02_dom/06_XNodeCSS.js +++ b/0.6.x/js/02_dom/06_XNodeCSS.js @@ -7,79 +7,55 @@ * * use X.Dom.Event */ -var -X_Node_CSS_Type = { - LENGTH : 1, - PERCENT : 2, - COLOR : 2 < 2, - U_DECIMAL : 2 < 3, - NUMERICAL : 2 < 4, - BOOLEAN : 2 < 5, - QUARTET : 2 < 6, - URL : 2 < 7, - FONT_NAME : 2 < 8, - TIME : 2 < 9, - CONTENT : 2 < 10, - LIST : 2 < 11, - AUTO : 2 < 12, - COMBI : 2 < 13 - }, + +/* font-size -> fontSize */ +function X_Node_CSS_camelize( cssProp ){ + var parts, l, i, parts0, camelized; -X_Node_CSS_UNIT = { - 'px' : 0, - 'em' : 1, - 'cm' : 2, - 'mm' : 3, - 'in' : 4, - '%' : 5, - 'pct' : 5, - 'ms' : 6, - 's' : 7, - '#' : 8, - 'rgb' : 9, - 'rgba' : 10 - }, + if( camelized = X_Node_CSS__DICTIONARY_CAMELIZE[ cssProp ] ) return camelized; + parts = cssProp.split( ' ' ).join( '' ).split( '-' ); + parts0 = parts[ 0 ]; + l = parts.length; + if( l === 1 ) return parts0; - /* font-size -> fontSize */ -X_Node_CSS__DICTIONARY_CAMELIZE = {}, + camelized = cssProp.charAt(0) === '-' + ? parts0.charAt( 0 ).toUpperCase() + parts0.substring( 1 ) + : parts0; -X_Node_CSS_camelize = function( cssProp ){ - var parts, l, i, camelized; - - if( camelized = X_Node_CSS__DICTIONARY_CAMELIZE[ cssProp ] ) return camelized; - parts = cssProp.split( ' ' ).join( '' ).split( '-' ); - l = parts.length; - if( l === 1 ) return parts[ 0 ]; - - camelized = cssProp.charAt(0) === '-' - ? parts[ 0 ].charAt( 0 ).toUpperCase() + parts[ 0 ].substring( 1 ) - : parts[ 0 ]; - - for( i = 1; i < l; ++i ){ - camelized += parts[ i ].charAt( 0 ).toUpperCase() + parts[ i ].substring( 1 ); - }; - return X_Node_CSS__DICTIONARY_CAMELIZE[ cssProp ] = camelized; - }, - - /* fontSize -> font-size */ -X_Node_CSS_CHAR_CODE_A = 'A'.charCodeAt( 0 ), + for( i = 1; i < l; ++i ){ + camelized += parts[ i ].charAt( 0 ).toUpperCase() + parts[ i ].substring( 1 ); + }; + return X_Node_CSS__DICTIONARY_CAMELIZE[ cssProp ] = camelized; +}; + +// TODO use X_HTMLParser_CHARS +/* fontSize -> font-size */ +function X_Node_CSS_uncamelize( str ){ + var A = X_Node_CSS_CHAR_CODE_A, + Z = A + 25, + uncamelized, l, chr, code, i; + str = str.split( ' ' ).join( '' ); + if( uncamelized = X_Node_CSS__DICTIONARY_UNCAMELIZE[ str ] ) return uncamelized; + uncamelized = ''; + for( i = 0, l = str.length; i < l; ++i ){ + chr = str.charAt( i ); + code = chr.charCodeAt( 0 ); + uncamelized += ( A <= code && code <= Z ) ? '-' + chr : chr; + }; + return X_Node_CSS__DICTIONARY_UNCAMELIZE[ str ] = uncamelized.toLowerCase(); +}; + +var + + X_Node_CSS_getComputedStyle = window.getComputedStyle || document.defaultView && document.defaultView.getComputedStyle, -X_Node_CSS__DICTIONARY_UNCAMELIZE = {}, + /* font-size -> fontSize */ + X_Node_CSS__DICTIONARY_CAMELIZE = {}, -X_Node_CSS_uncamelize = function( str ){ - var A = X_Node_CSS_CHAR_CODE_A, - Z = A + 25, - uncamelized, l, chr, code, i; - str = str.split( ' ' ).join( '' ); - if( uncamelized = X_Node_CSS__DICTIONARY_UNCAMELIZE[ str ] ) return uncamelized; - uncamelized = ''; - for( i = 0, l = str.length; i < l; ++i ){ - chr = str.charAt( i ); - code = chr.charCodeAt( 0 ); - uncamelized += ( A <= code && code <= Z ) ? '-' + chr : chr; - }; - return X_Node_CSS__DICTIONARY_UNCAMELIZE[ str ] = uncamelized.toLowerCase(); - }, + /* fontSize -> font-size */ + X_Node_CSS_CHAR_CODE_A = 'A'.charCodeAt( 0 ), + + X_Node_CSS__DICTIONARY_UNCAMELIZE = {}, /* * CSS における display, position, float プロパティの相互関係 @@ -108,42 +84,12 @@ _ABSOLUTE_BOX _FLOAT_BOX _GRNERAL */ -X_Node_CSS_VENDER_PREFIX = {}, - -X_Node_CSS_objToCssText = function( obj ){ - var css = [], - uncamelize = X_Node_CSS_uncamelize, - VENDER_PREFIX = X_Node_CSS_VENDER_PREFIX, - FIX_PROP = X_Node_CSS_SPECIAL_FIX_PROP, - SPECIAL_FIX = X_Node_CSS_SPECIAL_FIX, - n = -1, - p, v, name, sp; - if( !obj ) return ''; // Opera7.5 未満? - for( p in obj ){ - // TODO Object が拡張されていると error... - name = uncamelize( VENDER_PREFIX[ p ] || p ); - if( FIX_PROP[ name ] ){ - sp = true; - } else { - css[ ++n ] = [ name, obj[ p ] ].join( ':' ); - }; - }; - sp && ( css[ ++n ] = 'filter:' + SPECIAL_FIX( obj ) ); - return css.join( ';' ); - }, - -X_Node_CSS_IE_FILTER_FIX = - X_UA.IE && X_UA.IE < 9 && !X_UA.MacIE ? - { - opacity : 1, - textShadow : 1 - } : - 9 <= X_UA.IE && X_UA.IE < 10 ? // == 9 - {} : - {}, - -X_Node_CSS__UNIT_RATIO = {}, -X_Node_CSS__FONT_SIZE_RATIO = {}, + X_Node_CSS_VENDER_PREFIX = {}, + + X_Node_CSS__CLIP_SEPARATOR = X_UA[ 'IE' ] < 8 ? ' ' : ',', + + X_Node_CSS__UNIT_RATIO = {}, + X_Node_CSS__FONT_SIZE_RATIO = {}, // https://developer.mozilla.org/en-US/docs/Web/CSS/transform // Firefox 3.5, ie9, Opera 10.5, Safari 3.1, Chrome @@ -157,773 +103,365 @@ X_Node_CSS__FONT_SIZE_RATIO = {}, // ブラウザ毎の getComputedStyle の戻り値 http://d.hatena.ne.jp/uupaa/20080928/1222543331 -X_Node_CSS_COLOR = { - BLACK : 0x0, - RED : 0xFF0000, - LIME : 0x00FF00, - BLUE : 0x0000FF, - YELLOW : 0xFFFF00, - AQUA : 0x00FFFF, - CYAN : 0x00FFFF, - MAGENTA : 0xFF00FF, - FUCHSIA : 0xFF00FF, - WHITE : 0xFFFFFF, - GREEN : 0x008000, - PURPLE : 0x800080, - MAROON : 0x800000, - NAVY : 0x000080, - OLIVE : 0x808000, - TEAL : 0x008080, - GRAY : 0x808080, - SILVER : 0xC0C0C0, - DIMGRAY : 0x696969, - SLATEGRAY : 0x708090, - DARKGRAY : 0xA9A9A9, - GAINSBORO : 0xDCDCDC, - MIDNIGHTBLUE : 0x191970, - SLATEBLUE : 0x6A5ACD, - MEDIUMBLUE : 0x0000CD, - ROYALBLUE : 0x4169E1, - DODGERBLUE : 0x1E90FF, - SKYBLUE : 0x87CEEB, - STEELBLUE : 0x4682B4, - LIGHTBLUE : 0xADD8E6, - PALETURQUOISE : 0xAFEEEE, - TURQUOISE : 0x40E0D0, - LIGHTCYAN : 0xE0FFFF, - AQUAMARINE : 0x7FFFD4, - DARKGREEN : 0x006400, - SEAGREEN : 0x2E8B57, - LIGHTGREEN : 0x90EE90, - CHARTREUSE : 0x7FFF00, - GREENYELLOW : 0xADFF2F, - LIMEGREEN : 0x32CD32, - YELLOWGREEN : 0x9ACD32, - OLIVEDRAB : 0x6B8E23, - DARKKHAKI : 0xBCB76B, - PALEGOLDENROD : 0xEEE8AA, - LIGHTYELLOW : 0xFFFFE0, - GOLD : 0xFFD700, - GOLDENROD : 0xDAA520, - DARKGOLDENROD : 0xB8860B, - ROSYBROWN : 0xBC8F8F, - INDIANRED : 0xCD5C5C, - SADDLEBROWN : 0x8B4513, - SIENNA : 0xA0522D, - PERU : 0xCD853F, - BURLYWOOD : 0xDEB887, - BEIGE : 0xF5F5DC, - WHEAT : 0xF5DEB3, - SANDYBROWN : 0xF4A460, - TAN : 0xD2B48C, - CHOCOLATE : 0xD2691E, - FIREBRICK : 0xB22222, - BROWN : 0xA52A2A, - SALMON : 0xFA8072, - ORANGE : 0xFFA500, - CORAL : 0xFF7F50, - TOMATO : 0xFF6347, - HOTPINK : 0xFF69B4, - PINK : 0xFFC0CB, - DEEPPINK : 0xFF1493, - PALEVIOLETRED : 0xDB7093, - VIOLET : 0xEE82EE, - PLUM : 0xDDA0DD, - ORCHILD : 0xDA70D6, - DARKVIOLET : 0x9400D3, - BLUEVIOLET : 0x8A2BE2, - MEDIUMPURPLE : 0x9370DB, - THISTLE : 0xD8BFD8, - LAVENDER : 0xE6E6FA, - MISTYROSE : 0xFFE4E1, - IVORY : 0xFFFFF0, - LEMONCHIFFON : 0xFFFACD - }, + X_Node_CSS_COLOR = { + 'BLACK' : 0x0, + 'RED' : 0xFF0000, + 'LIME' : 0x00FF00, + 'BLUE' : 0x0000FF, + 'YELLOW' : 0xFFFF00, + 'AQUA' : 0x00FFFF, + 'CYAN' : 0x00FFFF, + 'MAGENTA' : 0xFF00FF, + 'FUCHSIA' : 0xFF00FF, + 'WHITE' : 0xFFFFFF, + 'GREEN' : 0x008000, + 'PURPLE' : 0x800080, + 'MAROON' : 0x800000, + 'NAVY' : 0x000080, + 'OLIVE' : 0x808000, + 'TEAL' : 0x008080, + 'GRAY' : 0x808080, + 'SILVER' : 0xC0C0C0, + 'DIMGRAY' : 0x696969, + 'SLATEGRAY' : 0x708090, + 'DARKGRAY' : 0xA9A9A9, + 'GAINSBORO' : 0xDCDCDC, + 'MIDNIGHTBLUE' : 0x191970, + 'SLATEBLUE' : 0x6A5ACD, + 'MEDIUMBLUE' : 0x0000CD, + 'ROYALBLUE' : 0x4169E1, + 'DODGERBLUE' : 0x1E90FF, + 'SKYBLUE' : 0x87CEEB, + 'STEELBLUE' : 0x4682B4, + 'LIGHTBLUE' : 0xADD8E6, + 'PALETURQUOISE' : 0xAFEEEE, + 'TURQUOISE' : 0x40E0D0, + 'LIGHTCYAN' : 0xE0FFFF, + 'AQUAMARINE' : 0x7FFFD4, + 'DARKGREEN' : 0x006400, + 'SEAGREEN' : 0x2E8B57, + 'LIGHTGREEN' : 0x90EE90, + 'CHARTREUSE' : 0x7FFF00, + 'GREENYELLOW' : 0xADFF2F, + 'LIMEGREEN' : 0x32CD32, + 'YELLOWGREEN' : 0x9ACD32, + 'OLIVEDRAB' : 0x6B8E23, + 'DARKKHAKI' : 0xBCB76B, + 'PALEGOLDENROD' : 0xEEE8AA, + 'LIGHTYELLOW' : 0xFFFFE0, + 'GOLD' : 0xFFD700, + 'GOLDENROD' : 0xDAA520, + 'DARKGOLDENROD' : 0xB8860B, + 'ROSYBROWN' : 0xBC8F8F, + 'INDIANRED' : 0xCD5C5C, + 'SADDLEBROWN' : 0x8B4513, + 'SIENNA' : 0xA0522D, + 'PERU' : 0xCD853F, + 'BURLYWOOD' : 0xDEB887, + 'BEIGE' : 0xF5F5DC, + 'WHEAT' : 0xF5DEB3, + 'SANDYBROWN' : 0xF4A460, + 'TAN' : 0xD2B48C, + 'CHOCOLATE' : 0xD2691E, + 'FIREBRICK' : 0xB22222, + 'BROWN' : 0xA52A2A, + 'SALMON' : 0xFA8072, + 'ORANGE' : 0xFFA500, + 'CORAL' : 0xFF7F50, + 'TOMATO' : 0xFF6347, + 'HOTPINK' : 0xFF69B4, + 'PINK' : 0xFFC0CB, + 'DEEPPINK' : 0xFF1493, + 'PALEVIOLETRED' : 0xDB7093, + 'VIOLET' : 0xEE82EE, + 'PLUM' : 0xDDA0DD, + 'ORCHILD' : 0xDA70D6, + 'DARKVIOLET' : 0x9400D3, + 'BLUEVIOLET' : 0x8A2BE2, + 'MEDIUMPURPLE' : 0x9370DB, + 'THISTLE' : 0xD8BFD8, + 'LAVENDER' : 0xE6E6FA, + 'MISTYROSE' : 0xFFE4E1, + 'IVORY' : 0xFFFFF0, + 'LEMONCHIFFON' : 0xFFFACD + }; -X_Node_CSS_parseColor = function( x ){ - var rgb, r, g, b; - - if( X.Type.isNumber( x ) ){ - return ( 0x0 <= x && x <= 0xFFFFFF ) ? x : undefined; - } else - if( !X.Type.isString( x ) ) return; - - if( X.Type.isNumber( rgb = X_Node_CSS_COLOR[ x.toUpperCase() ] ) && 0x0 <= rgb && rgb <= 0xFFFFFF ){ - return rgb; - } else - if( x.charAt( 0 ) === '#' ){ - switch( x.length ){ - case 7 : - r = parseInt( x.substr( 1, 2 ), 16 ); - g = parseInt( x.substr( 3, 2 ), 16 ); - b = parseInt( x.substr( 5, 2 ), 16 ); - break; - case 4 : - r = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 ); - g = parseInt( x.charAt( 2 ) + x.charAt( 2 ), 16 ); - b = parseInt( x.charAt( 3 ) + x.charAt( 3 ), 16 ); - break; - case 2 : - r = g = b = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 ); - break; - default : - return; - }; - } else - if( x.indexOf( 'rgb(' ) === 0 ){ - rgb = x.substr( 4 ).split( ',' ); - r = parseFloat( rgb[ 0 ] ); - g = parseFloat( rgb[ 1 ] ); - b = parseFloat( rgb[ 2 ] ); - if( x.indexOf( '%' ) !== -1 ){ - r *= 2.55; - g *= 2.55; - b *= 2.55; - }; - } else - if( x.indexOf( 'rgba(' ) === 0 ){ - rgb = x.substr( 5 ).split( ',' ); - r = parseFloat( rgb[ 0 ] ); - g = parseFloat( rgb[ 1 ] ); - b = parseFloat( rgb[ 2 ] ); - //a = parseFloat( rgb[ 3 ] ); - if( x.indexOf( '%' ) !== -1 ){ - r *= 2.55; - g *= 2.55; - b *= 2.55; - }; - } else { - return undefined; +function X_Node_CSS_parseColor( x ){ + var rgb, r, g, b; + + if( X_Type_isNumber( x ) ){ + return ( 0x0 <= x && x <= 0xFFFFFF ) ? x : undefined; + } else + if( !X_Type_isString( x ) ) return; + + if( X_Type_isNumber( rgb = X_Node_CSS_COLOR[ x.toUpperCase() ] ) && 0x0 <= rgb && rgb <= 0xFFFFFF ){ + return rgb; + } else + if( x.charAt( 0 ) === '#' ){ + switch( x.length ){ + case 7 : + r = parseInt( x.substr( 1, 2 ), 16 ); + g = parseInt( x.substr( 3, 2 ), 16 ); + b = parseInt( x.substr( 5, 2 ), 16 ); + break; + case 4 : + r = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 ); + g = parseInt( x.charAt( 2 ) + x.charAt( 2 ), 16 ); + b = parseInt( x.charAt( 3 ) + x.charAt( 3 ), 16 ); + break; + case 2 : + r = g = b = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 ); + break; + default : + return; + }; + } else + if( x.indexOf( 'rgb(' ) === 0 ){ + rgb = x.substr( 4 ).split( ',' ); + r = parseFloat( rgb[ 0 ] ); + g = parseFloat( rgb[ 1 ] ); + b = parseFloat( rgb[ 2 ] ); + if( x.indexOf( '%' ) !== -1 ){ + r *= 2.55; + g *= 2.55; + b *= 2.55; }; - return isFinite( r + b + g ) ? ( r << 16 ) + ( g << 8 ) + b : undefined; - }, + } else + if( x.indexOf( 'rgba(' ) === 0 ){ + rgb = x.substr( 5 ).split( ',' ); + r = parseFloat( rgb[ 0 ] ); + g = parseFloat( rgb[ 1 ] ); + b = parseFloat( rgb[ 2 ] ); + //a = parseFloat( rgb[ 3 ] ); + if( x.indexOf( '%' ) !== -1 ){ + r *= 2.55; + g *= 2.55; + b *= 2.55; + }; + } else { + return undefined; + }; + return isFinite( r + b + g ) ? ( r << 16 ) + ( g << 8 ) + b : undefined; +}; + +function X_Node_CSS_objToCssText( that, skipFilter ){ + var obj = that[ '_css' ], + plain = X_EMPTY_OBJECT, + css = [], + n = -1, + p, v, specialFix, filterFix; + + that[ '_flags' ] &= ~X_NodeFlags_OLD_CSSTEXT; + + if( !obj ){ // Opera7.5 未満? + delete that[ '_cssText' ]; + return ''; + }; -X_Node_CSS_PARAMS = ( function(){ - var ret = {}; - register( ret.percent = {}, - 'marginBottom,marginLeft,marginRight,marginTop,paddingBottom,paddingLeft,paddingRight,paddingTop,fontSize,textIndent' - ); - register( ret.offset = {}, - 'height,width,bottom,left,right,top' - ); - register( ret.size = {}, - 'borderBottomWidth,borderLeftWidth,borderRightWidth,borderTopWidth,letterSpacing,wordSpacing' - ); - register( ret.color = {}, - 'backgroundColor,borderBottomColor,borderLeftColor,borderRightColor,borderTopColor,color' - ); - register( ret.region = {}, - 'margin,padding,borderWidth,borderColor' - ); - register( ret.special = {}, - 'clip,backgroundPosition,backgroundPositionX,backgroundPositionY,opacity,lineHeight,zIndex' - ); - register( ret.unit = {}, 'px,cm,mm,in,pt,pc,em,%' ); + for( p in obj ){ + // object の拡張に備えて plain なオブジェクトを用意し、そのメンバーと一致するものは処理の対象外。 + if( plain[ p ] ) continue; + + v = obj[ p ]; - register( ret.margin = {}, 'marginBottom,marginLeft,marginRight,marginTop,paddingBottom' ); - register( ret.padding = {}, 'paddingBottom,paddingLeft,paddingRight,paddingTop' ); - register( ret.borderWidth = {}, 'borderBottomWidth,borderLeftWidth,borderRightWidth,borderTopWidth' ); - register( ret.borderColor = {}, 'borderBottomColor,borderLeftColor,borderRightColor,borderTopColor' ); + p = X_Node_CSS_uncamelize( X_Node_CSS_VENDER_PREFIX[ p ] || p ); - function register( obj, params ){ - params = params.split( ',' ); - for( var i = params.length; i; ) obj[ params[ --i ] ] = true; + if( specialFix = X_Node_CSS_SPECIAL_FIX_PROP[ p ] ){ + css[ ++n ] = p + ':' + specialFix( v ); + } else + if( X_Node_CSS_FILTER_FIX_PROPS && X_Node_CSS_FILTER_FIX_PROPS[ p ] ){ + ( filterFix || ( filterFix = {} ) )[ p ] = v; + } else { + css[ ++n ] = p + ':' + v; }; - return ret; - })(), + }; -X_Node_CSS__CLIP_SEPARATOR = X_UA.IE && X_UA.IE < 8 ? ' ' : ',', + if( filterFix ){ + v = X_Node_CSS_objToIEFilterText( that, filterFix ); + if( v ) css[ ++n ] = 'filter:' + v; + skipFilter = skipFilter && v; + } else { + skipFilter = false; + }; - /* - * - */ -X_Node_CSS_Property = X.Class.create( - 'Property', - X.Class.POOL_OBJECT, + if( 0 <= n ){ + // cssText には完全なものを控えるが、戻すのは filter を抜いたもの + that[ '_cssText' ] = css.join( ';' ); + if( skipFilter ){ + --css.length; + return css.join( ';' ); + }; + return that[ '_cssText' ]; + }; + delete that[ '_cssText' ]; + return ''; +}; + +var +X_Node_CSS_FILTER_FIX_PROPS = + X_UA[ 'ActiveX' ] && X_UA[ 'IE' ] < 9 && !X_UA[ 'MacIE' ] ? { - Constructor : function( name, value, unit, xnode ){ - this.name = name; - this.value = value; - this.unit = unit; - this.xnode = xnode; - }, - name : '', - value : 0, - unit : '', - xnode : null, - equal : function( prop ){ - if( this.unit === prop.unit ){ - return this.value === prop.value; - }; - return Math.abs( this.toPx() - prop.toPx() ) < 1; - }, - convert: function( prop ){ - var u = prop.unit, v; - if( this.unit === u ) return; - this.value = v = this.toPx(); - this.unit = u; - // % - // bgpX, bgpY の場合 X.Util.Image.getActualDimension( backgroundImage url を使用 ) - if( u !== 'px' ){ - this.value = - u === 'em' ? - v / X_Node_CSS_getCharSize( this.xnode ) : - v / ( X_Node_CSS__UNIT_RATIO[ u ] || 1 ); - }; - }, - setValue: function( v ){ - this.value = v; - }, - getValue: function(){ - return this.value; - }, - getOffset: function( prop ){ - return prop.value - this.value; - }, - getUnit: function(){ - return this.unit; - }, - getValueText: function(){ - return this.value === 0 ? '0' : this.value + this.unit; - }, - toPx: function(){ - var v = this.value, u = this.unit; - return - u === 'px' ? - v : - ( u === 'em' || ( u === '' && this.name === 'lineHeight' ) ) ? - v * X_Node_CSS_getCharSize( this.xnode ) : - // u === '%' - v / ( X_Node_CSS__UNIT_RATIO[ u ] || 1 ); - }, - isValid: function(){ - var p = X_Node_CSS_PARAMS, - n = this.name, - v = this.value, - u = this.unit, - z = u !== '' ? true : v === 0; - if( p.percent[ n ] === true ) return z; - if( p.offset[ n ] === true ) return z; - if( p.size[ n ] === true ) return z && u !== '%'; - if( p.special[ n ] === true ){ - if( n === 'lineHeight' ) return true; - if( n === 'opacity' ) return 0 <= v && v <= 1 && u === ''; - if( n === 'zIndex' ) return u === ''; - }; - return false; - } - } - ), - - /** - * backgroundPosition, clip - */ -X_Node_CSS_PropertyGroup = X.Class.create( - 'PropertyGroup', - X.Class.POOL_OBJECT, + 'opacity' : 2, + 'boxShadow' : 3, + 'textShadow' : 4, + 'transform' : 5 + } : + X_UA[ 'ActiveX' ] && X_UA[ 'IE9' ] ? // == 9 { - Constructor : function( name ){ - this.name = name; - this.props = []; - for( var i = 1, l = arguments.length; i> 16; - g = ( rgb & 0xff00 ) >> 8; - b = ( rgb & 0xff ); - } else - if( x.charAt( 0 ) === '#' ){ - if( x.length === 7 ){ - r = parseInt( x.charAt( 1 ) + x.charAt( 2 ), 16 ); - g = parseInt( x.charAt( 3 ) + x.charAt( 4 ), 16 ); - b = parseInt( x.charAt( 5 ) + x.charAt( 6 ), 16 ); - } else - if( x.length === 4 ){ - r = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 ); - g = parseInt( x.charAt( 2 ) + x.charAt( 2 ), 16 ); - b = parseInt( x.charAt( 3 ) + x.charAt( 3 ), 16 ); + 'textShadow' : 4 + } : + null; + +function X_Node_CSS_objToIEFilterText( that, opt_css ){ + var obj = opt_css || that[ '_css' ], + test = X_Node_CSS_FILTER_FIX_PROPS, + filters = [], + n = -1, + p, id, v, num, ary, params, i, l, dir, + afterUpdate, impossible; + for( p in obj ){ + if( X_EMPTY_OBJECT[ p ] ) continue; + + if( !( id = test[ p ] ) ) continue; + v = obj[ p ]; + + switch( id ){ + case 1 : //'filter' : + filters[ ++n ] = v; + break; + case 2 : //'opacity' : + filters[ ++n ] = 'alpha(opacity=' + ( v * 100 | 0 ) +')'; + break; + case 3 : //'boxShadow' : + // TODO カンマ区切りの複数指定 + // box-shadow: 10px 10px 10px 10px rgba(0,0,0,0.4) inset; + // スペース区切りで、水平方向の距離 垂直方向の距離 ぼかし距離 広がり距離 影の色 insetキーワードを指定する。 ぼかし距離 広がり距離 影の色 insetキーワードは省略可 + // https://developer.mozilla.org/ja/docs/Web/CSS/box-shadow + // に絶対値は不可? 省略した場合は、文字の色が使われる(webkit以外) + // shadow(color=#cccccc, strength=10, direction=135); + ary = v.split( ' ' ); + params = [ 0, 0, 0, 0 ]; // offset-x, offset-y, blur-radius, spread-radius + for( i = 0, l = ary.length; i < l; ++i ){ + v = ary[ i ]; + num = i < 4 && parsetFloat( v ); + + if( num === num ){ + vu = X_Node_CSS__splitValueAndUnit( v ); + v = vu[ 0 ]; + u = vu[ 1 ]; + if( v ){ + if( _v = X_Node_CSS__UNIT_RATIO[ u ] ){ + params[ i ] = v / _v; + } else { + switch( u ){ + case 'px' : + params[ i ] = v; + break; + case 'em' : + if( X_Node_updateTimerID ){ + afterUpdate = true; + } else { + params[ i ] = X_Node_CSS_getCharSize( that ) * v; + }; + default : + params[ i ] = 0; + break; + }; + }; + } else { + params[ i ] = 0; + }; } else - if( x.length === 2 ){ - r = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 ); - g = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 ); - b = parseInt( x.charAt( 1 ) + x.charAt( 1 ), 16 ); + if( v.charAt( 0 ) === '#' || v.indexOf( 'rgb' ) === 0 || X_Node_CSS_COLOR[ v.toUpperCase() ] ){ + v = X_Node_CSS_parseColor( v ); + if( 0 <= v && v < 0x100000 ){ + color = '00000' + v.toString( 16 ); + color = '#' + color.substr( color.length - 6 ); + } else + if( v ){ + color = '#' + v.toString( 16 ); + }; + } else + if( v === 'inset' ){ + impossible = true; + } else { + // unknown }; - } else - if( x.indexOf( 'rgb(' ) === 0 ){ - rgb = x.substr( 4 ).split( ',' ); - r = parseFloat( rgb[ 0 ] ); - g = parseFloat( rgb[ 1 ] ); - b = parseFloat( rgb[ 2 ] ); - if( x.indexOf( '%' ) !== -1 ) pct = true; - } else - if( x.indexOf( 'rgba(' ) === 0 ){ - rgb = x.substr( 5 ).split( ',' ); - r = parseFloat( rgb[ 0 ] ); - g = parseFloat( rgb[ 1 ] ); - b = parseFloat( rgb[ 2 ] ); - a = parseFloat( rgb[ 3 ] ); - if( x.indexOf( '%' ) !== -1 ) pct = true; - } else { - r = 255; - g = 255; - b = 255; - }; - - this.name = name; - this.r = r; - this.g = g; - this.b = b; - this.a = a; - this.pct = pct; - }, - name : '', - r : 0, - g : 0, - b : 0, - a : 0, - pct : false, - equal : function( prop ){ - if( this.pct === prop.pct ){ - return this.r === prop.r && this.g === prop.g && this.b === prop.b; }; - var rgb = this._toPct(), - _rgb = prop._toPct(), - i = rgb.length; - for( ; i; ){ - --i; - if( Math.abs( rgb[ i ] - _rgb[ i ] ) > 1 ) return false; + if( impossible || !color ){ + break; }; - return true; - }, - convert : function( prop ){ - var u = prop.pct, x; - if( this.pct === u ) return; - x = u === true ? 100 / 255 : 2.55; - this.r *= x; - this.g *= x; - this.b *= x; - this.pct = u; - }, - setValue : function( rgb ){ - this.r = rgb[ 0 ]; - this.g = rgb[ 1 ]; - this.b = rgb[ 2 ]; - }, - getValue : function(){ - return [ this.r, this.g, this.b ]; - }, - getOffset : function( prop ){ - return [ prop.r - this.r, prop.g - this.g, prop.b - this.b ]; - }, - getUnit : function(){ - return this.pct === true ? '%' : ''; - }, - getValueText : function(){ - if( this.pct === true ){ - return [ 'rgb(', this.r, '%,', this.g, '%,', this.b, '%)' ].join( '' ); + if( afterUpdate ){ + // AFTER_UPDATE 時に 再計算 + X_ViewPort[ 'listenOnce' ]( X_EVENT_AFTER_UPDATE, that, X_Node_CSS_onAfterUpdateForIEFilterFix ); + break; }; - var round = Math.round; + dir = Math.atan2( params[ 1 ] + params[ 3 ], params[ 0 ] + params[ 3 ] ) * 180 / Math.PI + 90; + dir += dir < 0 ? 360 : 0; + filters[ ++n ] = 'shadow(color=' + color + ',strength=' + params[ 3 ] + ',direction=' + ( dir | 0 ) + ')'; + break; + case 4 : //'textShadow' : + //text-shadow: 5px 5px 2px blue; 水平方向の距離 垂直方向の距離 影のぼかし半径 影の色 none + //glow(Color=yellow,Strength=10); + //どうやらCSSのbackgroundプロパティと同時に使えないようです。 s + break; + case 6 : //'backgroundImage' : + // + + case 5 : // transform scale, matrix - var rgb = '00000' + ( ( round( this.r ) << 16 ) + ( round( this.g ) << 8 ) + round( this.b ) ).toString( 16 ); - return '#' + rgb.substr( rgb.length - 6 ); - }, - _toPct : function(){ - if( this.pct === true ) return [ this.r, this.g, this.b ]; - return [ this.r / 2.55, this.g / 2.55, this.b / 2.55 ]; - }, - isValid : function( t ){ - var isFinite = window.isFinite; - if( !isFinite( this.r ) || !isFinite( this.g ) || !isFinite( this.b ) ) return false; - if( 0 > this.r || 0 > this.g || 0 > this.b ) return false; - if( this.pct === true ) return this.r <= 100 && this.g <= 100 && this.b <= 100; - return this.r <= 255 && this.g <= 255 && this.b <= 255; - } - } - ); - -function X_Node_CSS__getProperty( xnode, css, unit, p ){ - - var me = X_Node_CSS__getProperty, - PARAMS = X_Node_CSS_PARAMS, - PropertyGroup = X_Node_CSS_PropertyGroup, - Property = X_Node_CSS_Property, - ColorProperty = X_Node_CSS_ColorProperty, - name, width; - - if( PARAMS.special[ p ] === true || PARAMS.region[ p ] === true ){ - switch( p ){ - case 'clip' : - // rect(...) クリップします。, は上端からの、 , は左端からのオフセットで指定します。Internet Explorer 4~7 では、カンマの代わりにスペースで区切る必要があります。 - // position:absolute または position:fixed を適用した要素に対してのみ有効です。 - var top = me( p + 'Top' ), - right = me( p + 'Right' ), - bottom = me( p + 'Bottom' ), - left = me( p + 'Left' ), - ret = new PropertyGroup( p, top, right, bottom, left ), - all; - if( ret.isValid() === true ) return ret; - ret.kill(); - all = css[ p ].split( '(' )[ 1 ].split( ')' )[ 0 ].split( X_Node_CSS__CLIP_SEPARATOR ); - return - new PropertyGroup( - p, - new Property( p + 'Top', all[ 0 ], 'px', xnode ), - new Property( p + 'Right', all[ 1 ], 'px', xnode ), - new Property( p + 'Bottom', all[ 2 ], 'px', xnode ), - new Property( p + 'Left', all[ 3 ], 'px', xnode ) - ); - - case 'margin' : - case 'padding' : - name = p; - width = ''; - case 'borderWidth' : - var props = '$1Top$2,$1Right$2,$1Bottom$2,$1Left$2'.split( '$1' ).join( name || 'border' ).split( '$2' ).join( width || 'Width' ).split( ',' ), - top = me( props[ 0 ] ), - right = me( props[ 1 ] ), - bottom = me( props[ 2 ] ), - left = me( props[ 3 ] ), - ret = new PropertyGroup( p, top, right, bottom, left ), - all, _0, _1, _2, _3, vu, v, u; - if( ret.isValid() === true ) return ret; - ret.kill(); - all = css[ p ].split( ' ' ); - _0 = all[ 0 ]; - _1 = all[ 1 ]; - _2 = all[ 2 ]; - _3 = all[ 3 ]; - vu = X_Node_CSS__splitValueAndUnit( _0 ); - v = vu[ 0 ]; - u = vu[ 1 ]; - switch( all.length ){ - case 1 : - top = new Property( props[ 0 ], v, u, xnode ); - right = new Property( props[ 1 ], v, u, xnode ); - bottom = new Property( props[ 2 ], v, u, xnode ); - left = new Property( props[ 3 ], v, u, xnode ); - break; - case 2 : - top = new Property( props[ 0 ], v, u, xnode ); - bottom = new Property( props[ 2 ], v, u, xnode ); - vu = X_Node_CSS__splitValueAndUnit( _1 ); - v = vu[ 0 ]; - u = vu[ 1 ]; - right = new Property( props[ 1 ], v, u, xnode ); - left = new Property( props[ 3 ], v, u, xnode ); - break; - case 3 : - top = new Property( props[ 0 ], v, u, xnode ); - vu = X_Node_CSS__splitValueAndUnit( _1 ); - v = vu[ 0 ]; - u = vu[ 1 ]; - right = new Property( props[ 1 ], v, u, xnode ); - left = new Property( props[ 3 ], v, u, xnode ); - vu = X_Node_CSS__splitValueAndUnit( _2 ); - v = vu[ 0 ]; - u = vu[ 1 ]; - bottom = new Property( props[ 2 ], v, u, xnode ); - break; - case 4 : - top = new Property( props[ 0 ], v, u, xnode ); - vu = X_Node_CSS__splitValueAndUnit( _1 ); - v = vu[ 0 ]; - u = vu[ 1 ]; - right = new Property( props[ 1 ], v, u, xnode ); - vu = X_Node_CSS__splitValueAndUnit( _2 ); - v = vu[ 0 ]; - u = vu[ 1 ]; - bottom = new Property( props[ 2 ], v,u, xnode ); - vu = X_Node_CSS__splitValueAndUnit( _3 ); - v = vu[ 0 ]; - u = vu[ 1 ]; - left = new Property( props[ 3 ], v, u, xnode ); - break; - }; - return new PropertyGroup( p, top, right, bottom, left ); - - case 'borderColor' : - var props = 'borderTopColor,borderRightColor,borderBottomColor,borderLeftColor'.split( ',' ), - top = me( props[ 0 ] ), - right = me( props[ 1 ] ), - bottom = me( props[ 2 ] ), - left = me( props[ 3 ] ), - ret = new PropertyGroup( p, top, right, bottom, left ), - all, _0, _1; - if( ret.isValid() === true ) return ret; - ret.kill(); - all = css[ p ].split( ' ' ); - _0 = all[ 0 ]; - _1 = all[ 1 ]; - switch( all.length ){ - case 1 : - top = new ColorProperty( props[ 0 ], _0 ); - right = new ColorProperty( props[ 1 ], _0 ); - bottom = new ColorProperty( props[ 2 ], _0 ); - left = new ColorProperty( props[ 3 ], _0 ); - break; - case 2 : - top = new ColorProperty( props[ 0 ], _0 ); - right = new ColorProperty( props[ 1 ], _1 ); - bottom = new ColorProperty( props[ 2 ], _0 ); - left = new ColorProperty( props[ 3 ], _1 ); - break; - case 3 : - top = new ColorProperty( props[ 0 ], _0 ); - right = new ColorProperty( props[ 1 ], _1 ); - bottom = new ColorProperty( props[ 2 ], all[ 2 ] ); - left = new ColorProperty( props[ 3 ], _1 ); - break; - case 4 : - top = new ColorProperty( props[ 0 ], _0 ); - right = new ColorProperty( props[ 1 ], _1 ); - bottom = new ColorProperty( props[ 2 ], all[ 2 ] ); - left = new ColorProperty( props[ 3 ], all[ 3 ] ); - break; - }; - return new PropertyGroup( p, top, right, bottom, left ); - - case 'backgroundPosition' : - var x = me( p + 'X' ), - y = me( p + 'Y' ), - ret = new PropertyGroup( p, x, y ), - xy; - if( ret.isValid() === true ) return ret; - ret.kill(); - xy = css[ p ].split( ' ' ); - x = X_Node_CSS__splitValueAndUnit( xy[ 0 ] ); - y = X_Node_CSS__splitValueAndUnit( xy[ 1 ] ); - return - new PropertyGroup( - p, - new Property( p + 'X', x[ 0 ], x[ 1 ], xnode ), - new Property( p + 'Y', y[ 0 ], y[ 1 ], xnode ) - ); - }; - // opacity, zindex, lineHeight - vu = X_Node_CSS__splitValueAndUnit( css[ p ] ); - return new Property( p, vu[ 0 ], vu[ 1 ], xnode ); - }; - var x = css[ p ], e, v, u; - /* - if( PARAMS.offset[ p ] === true ){ - return new Property( p, vu[ 0 ], vu[ 1 ], xnode ); - - e = this.elm; - if( p === 'width' ) v = e.offsetWidth; - if( p === 'height' ) v = e.offsetHeight; - if( p === 'top' ) v = e.offsetTop; - if( p === 'bottom' ) v = e.offsetBottom; - if( p === 'left' ) v = e.offsetLeft; - if( p === 'right' ) v = e.offsetRight; - u = _getUnit( x, p ); - // alert( p + X_Node_CSS__Util.pxTo( v, u ) + u ) - return new Property( p, X_Node_CSS__Util.pxTo( v, u ), u, xnode ); - }; */ - if( p === 'fontSize' && ( v = X_Node_CSS__FONT_SIZE_RATIO[ x ] ) ){ // xx-small 等 - return new Property( p, v, 'px', xnode ); }; - if( PARAMS.offset[ p ] || PARAMS.percent[ p ] || PARAMS.size[ p ] ){ - vu = X_Node_CSS__splitValueAndUnit( x ); - return new Property( p, vu[ 0 ], vu[ 1 ], xnode ); - }; - - if( PARAMS.color[ p ] ) return new ColorProperty( p, x ); }; - -function X_Node_CSS__splitValueAndUnit( v ){ - var num, _num, u; - if( X.Type.isNumber( v ) ) return [ v || 0, '' ]; - if( isNaN( num = parseFloat( v ) ) ) return [ 0, '' ]; - _num = '' + num; - if( _num.indexOf( '0.' ) === 0 ) _num = _num.slice( 1 ); - u = v.substr( v.indexOf( _num ) + _num.length ); - return [ num, X_Node_CSS_UNIT[ u ] ? u : 'px' ]; + return filters.join( ' ' ); +}; + +function X_Node_CSS_onAfterUpdateForIEFilterFix(){ + if( this[ '_flags' ] & X_NodeFlags_IN_TREE ){ // 要素があり、要素がツリーに属している + this[ '_flags' ] |= X_NodeFlags_DIRTY_IE_FILTER; + X_Node_reserveUpdate(); }; +}; + -var X_Node_CSS__GET_VALUE_WITH_UNIT = { - borderWidth : X_Node_CSS_Type.QUARTET | X_Node_CSS_Type.LENGTH, - //borderStyle : X_Node_CSS_Type.QUARTET, - borderRadius : X_Node_CSS_Type.QUARTET | X_Node_CSS_Type.LENGTH, - margin : X_Node_CSS_Type.QUARTET | X_Node_CSS_Type.LENGTH | X_Node_CSS_Type.PERCENT, - padding : X_Node_CSS_Type.QUARTET | X_Node_CSS_Type.LENGTH | X_Node_CSS_Type.PERCENT, - clip : X_Node_CSS_Type.QUARTET | X_Node_CSS_Type.LENGTH | X_Node_CSS_Type.PERCENT, - - backgroundColor : X_Node_CSS_Type.COLOR, - backgroundPosition : X_Node_CSS_Type.COMBI, - - // boxShadow - - fontSize : X_Node_CSS_Type.LENGTH, - lineHeight : X_Node_CSS_Type.LENGTH | X_Node_CSS_Type.PERCENT | X_Node_CSS_Type.NUMERICAL, - textIndent : X_Node_CSS_Type.LENGTH, - letterSpacing : X_Node_CSS_Type.LENGTH, - wordSpacing : X_Node_CSS_Type.LENGTH, /* - textShadowColor : X_Node_CSS_Type.COLOR, - textShadowOffsetX : X_Node_CSS_Type.LENGTH, - textShadowOffsetY : X_Node_CSS_Type.LENGTH, - textShadowBlur : X_Node_CSS_Type.LENGTH, */ - - width : X_Node_CSS_Type.LENGTH | X_Node_CSS_Type.PERCENT, - height : X_Node_CSS_Type.LENGTH | X_Node_CSS_Type.PERCENT, - - left : X_Node_CSS_Type.LENGTH | X_Node_CSS_Type.PERCENT, - top : X_Node_CSS_Type.LENGTH | X_Node_CSS_Type.PERCENT, - bottom : X_Node_CSS_Type.LENGTH | X_Node_CSS_Type.PERCENT, - right : X_Node_CSS_Type.LENGTH | X_Node_CSS_Type.PERCENT, + * http://css-eblog.com/ie-css-problems/rgba-pe.html + * ie67 では rgb() は background-color で反応しない、、、 + */ - // table - borderSpacing : X_Node_CSS_Type.LENGTH +var +X_Node_CSS_UNIT = { + 'px' : 0, + 'em' : 1, + // ex, rem, vh, vw, vmin, vmax + 'cm' : 2, + 'mm' : 3, + 'in' : 4, + // pt, pc, mozmm + '%' : 5, + 'pct' : 5, + 'ms' : 6, + 's' : 7, + '#' : 8, + 'rgb' : 9, + 'rgba' : 10 }; - -var X_Node_CSS_SPECIAL_FIX = - // ~IE8 - X_UA.IE && X_UA.IE < 9 && !X_UA.MacIE? - (function( obj ){ - var test = X_Node_CSS_SPECIAL_FIX_PROP, - filters = [], - n = -1, - p, id, v, dir; - for( p in obj ){ - if( !( id = test[ p ] ) ) continue; - v = obj[ p ]; - switch( id ){ - case 1 : //'filter' : - filters[ ++n ] = v; - break; - case 2 : //'opacity' : - filters[ ++n ] = 'alpha(opacity=' + v * 100 +')'; - break; - case 3 : //'boxShadow' : - // box-shadow: 10px 10px 10px 10px rgba(0,0,0,0.4) inset; - // スペース区切りで、水平方向の距離 垂直方向の距離 ぼかし距離 広がり距離 影の色 insetキーワードを指定する。 ぼかし距離 広がり距離 影の色 insetキーワードは省略可 - // shadow(color=#cccccc, strength=10, direction=135); - v = X_Node_CSS__getProperty( this, css, 'px', 'boxShadow' ); - dir = Math.atan2( v[ 1 ], v[ 0 ] ) * 180 / Math.PI + 90; - dir += dir < 0 ? 360 : 0; - filters[ ++n ] = 'shadow(color=' + v[ 4 ] + ',strength=' + v[ 3 ] + ',direction=' + dir + ')'; - break; - case 4 : //'textShadow' : - //text-shadow: 5px 5px 2px blue; 水平方向の距離 垂直方向の距離 影のぼかし半径 影の色 none - //glow(Color=yellow,Strength=10); - //どうやらCSSのbackgroundプロパティと同時に使えないようです。 - - - break; - case 5 : //'backgroundImage' : - // - }; - }; - return filters.join( ' ' ); - }) : - // IE9 textShadow に filter を使用 - X_UA.IE && 9 <= X_UA.IE && X_UA.IE < 10 ? - (function( obj ){ - var test = X_Node_CSS_SPECIAL_FIX_PROP, - filters = [], p, id, v; - for( p in obj ){ - if( !( id = test[ p ] ) ) continue; - v = obj[ p ]; - switch( id ){ - case 1 : //'filter' : - filters[ filters.length ] = v; - break; - }; - }; - if( filters ) return filters.join( ' ' ); - }) : +/* + * .2, -.1 といったケースに対処 + * + */ +function X_Node_CSS__splitValueAndUnit( v ){ + var num, _num, u; + if( X_Type_isNumber( v ) ) return [ v || 0, '' ]; + num = parseFloat( v ); + if( num !== num ) return [ 0, '' ]; + _num = '' + num; + if( 0 < num && num < 1 && v.charAt( 0 ) === '.' ) _num = _num.slice( 1 ); + if( -1 < num && num < 0 && v.charAt( 1 ) === '.' ) _num = '-.' + _num.substr( 2 ); + u = v.substr( v.indexOf( _num ) + _num.length ); + return [ num, X_Node_CSS_UNIT[ u ] ? u : 'px' ]; +}; + /* (function( obj ){ var test = X_Node_CSS_SPECIAL_FIX_PROP, ret = [], p, id, v, bgpX, bgpY, clipT, clipB, clipL, clipR; @@ -937,16 +475,16 @@ var X_Node_CSS_SPECIAL_FIX = case 2 : //'backgroundPositionY' : bgpY = v; break; - case 3 : //'backgroundPositionX' : + case 3 : //'clipTop' : clipT = v; break; - case 4 : //'backgroundPositionX' : + case 4 : //'clipBottom' : clipB = v; break; - case 5 : //'backgroundPositionX' : + case 5 : //'clipLeft' : clipL = v; break; - case 6 : //'backgroundPositionX' : + case 6 : //'clipRight' : clipR = v; break; }; @@ -956,7 +494,7 @@ var X_Node_CSS_SPECIAL_FIX = ret[ ret.length ] = 'clip:rect('; }; return ret.join( ';' ); - }); + }); */ @@ -966,153 +504,214 @@ var X_Node_CSS_SPECIAL_FIX = // unitID, name 単位指定のプロパティ取得 geter // obj setter // name, value setter - -Node.prototype.css = function( nameOrObj /* orUnitID, valuOrUnitOrName */ ){ +/** + * style の getter と setter。 + * @alias Node.prototype.css + * @param {string|object} [nameOrObj] style 名、または追加する style のハッシュ + * @param {string|number} [value=] style の値 + * @return {Node|string|number} getter の場合は値を、setter の場合は自身を返す。(メソッドチェーン) + * @example // getter + * node.css( 'color' ); + * // setter - 1 + * node.css( { width : w + 'px', height : h + 'px' } ); + * // setter - 2 + * node.css( 'color', 0x666666 ); + */ +function X_Node_css( nameOrObj /* value */ ){ var args = arguments, - css = this._css, - p, name, v, camelize, unit, ieFix; - if( this._xnodeType !== 1 ) return this; + css = this[ '_css' ], + p, name, v, plain, camelize, flags; + + if( !this[ '_tag' ] || X_Dom_DTD_MOVE_TO_HEAD[ this[ '_tag' ] ] || this[ '_tag' ] === 'SCRIPT' ) return this; // setter:object - if( X.Type.isObject( nameOrObj ) ){ - if( !css ) css = this._css = {}; + if( X_Type_isObject( nameOrObj ) ){ + if( !css ) css = this[ '_css' ] = {}; + plain = X_EMPTY_OBJECT; camelize = X_Node_CSS_camelize; - ieFix = X_Node_CSS_IE_FILTER_FIX; + flags = this[ '_flags' ]; for( p in nameOrObj ){ - if( ieFix[ p ] ){ - this._dirty |= X_Node_Dirty.IE_FILTER; - }; - v = nameOrObj[ p ]; - v || v === 0 ? css[ camelize( p ) ] = v : delete css[ camelize( p ) ]; - if( p === 'display' ){ - v === 'none' ? ( this._state |= X_Node_State.IE5_DISPLAY_NONE_FIX ) : ( this._state &= ~X_Node_State.IE5_DISPLAY_NONE_FIX ); - v === 'none' ? ( this._state |= X_Node_State.DISPLAY_NONE ) : ( this._state &= ~X_Node_State.DISPLAY_NONE ); - }; + if( plain[ p ] ) continue; + name = camelize( p ); + v = nameOrObj[ p ]; + if( css[ name ] === v ) continue; + flags = X_Node_CSS_setStyle( css, flags, name, v ); }; - this._dirty |= X_Node_Dirty.CSS; - this.parent && X_Node_reserveUpdate(); - delete this._cssText; + flags |= X_NodeFlags_DIRTY_CSS | X_NodeFlags_OLD_CSSTEXT; + this[ '_flags' ] = flags; + flags & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); + delete this[ '_cssText' ]; return this; } else if( 1 < args.length ){ - if( !X_Node_CSS_UNIT[ nameOrObj ] ){ // setter name, value - if( !css ) css = this._css = {}; - name = X_Node_CSS_camelize( nameOrObj ); - v = args[ 1 ]; - if( css[ name ] === v ) return this; - if( X_Node_CSS_IE_FILTER_FIX[ name ] ){ - this._dirty |= X_Node_Dirty.IE_FILTER; - }; - if( !v && v !== 0 ){ - delete css[ name ]; - } else { - css[ name ] = v; - }; - delete this._cssText; - this._dirty |= X_Node_Dirty.CSS; - if( name === 'display' ){ - v === 'none' ? ( this._state |= X_Node_State.IE5_DISPLAY_NONE_FIX ) : ( this._state &= ~X_Node_State.IE5_DISPLAY_NONE_FIX ); - v === 'none' ? ( this._state |= X_Node_State.DISPLAY_NONE ) : ( this._state &= ~X_Node_State.DISPLAY_NONE ); - }; - // parent でなく this._root! でなくて this._state & in tree - this.parent && X_Node_reserveUpdate(); - return this; - }; -// getter unit -// unit 付の値取得は fontSize と 画像サイズが確定していないと正確に取れない。内部のみにする? - if( !css ) return; - if( !X_Node_CSS__GET_VALUE_WITH_UNIT[ name = X_Node_CSS_camelize( args[ 1 ] ) ] ) return null; - p = X_Node_CSS__getProperty( this, css, nameOrObj, name ); - v = p.pxTo( nameOrObj ); - p.kill(); - return v; + if( !css ) css = this[ '_css' ] = {}; + name = X_Node_CSS_camelize( nameOrObj ); + v = args[ 1 ]; + if( css[ name ] === v ) return this; + this[ '_flags' ] = X_Node_CSS_setStyle( css, this[ '_flags' ], name, v ) | X_NodeFlags_DIRTY_CSS | X_NodeFlags_OLD_CSSTEXT; + this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); + delete this[ '_cssText' ]; + return this; }; // getter if( !css ) return; - // 集計 border, padding, margin, backgroundPosition, clip - // border で正確なデータを返せない時は、null を返す + // TODO 集計 border, padding, margin, backgroundPosition, clip + // TODO border で正確なデータを返せない時は、null を返す return css[ X_Node_CSS_camelize( nameOrObj ) ]; }; -Node.prototype.cssText = function( v ){ +function X_Node_CSS_setStyle( css, flags, name, newValue ){ + + if( X_Node_CSS_FILTER_FIX_PROPS && X_Node_CSS_FILTER_FIX_PROPS[ name ] ){ + flags |= X_NodeFlags_DIRTY_IE_FILTER; + }; + if( !newValue && newValue !== 0 ){ + delete css[ name ]; + } else { + css[ name ] = newValue; + }; + + switch( name ){ + case 'display' : + console.log( newValue ); + newValue === 'none' ? ( flags |= X_NodeFlags_STYLE_IS_DISPLAY_NONE ) : ( flags &= ~X_NodeFlags_STYLE_IS_DISPLAY_NONE ); + return flags; + + case 'visibility' : + // すでに opacity:0 で invisible + if( flags & X_NodeFlags_STYLE_IS_INVISIBLE && css[ 'opacity' ] == 0 ) return flags; + newValue === 'hidden' ? ( flags |= X_NodeFlags_STYLE_IS_INVISIBLE ) : ( flags &= ~X_NodeFlags_STYLE_IS_INVISIBLE ); + return flags; + + case 'opacity' : + // すでに visibility:hidden で invisible + if( flags & X_NodeFlags_STYLE_IS_INVISIBLE && css[ 'visibility' ] === 'hidden' ) return flags; + newValue == 0 ? // 0 or "0" + ( flags |= X_NodeFlags_STYLE_IS_INVISIBLE ) : ( flags &= ~X_NodeFlags_STYLE_IS_INVISIBLE ); + return flags; + + case 'overflow' : + newValue === 'hidden' ? ( flags |= X_NodeFlags_STYLE_IS_NO_OVERFLOW ) : ( flags &= ~X_NodeFlags_STYLE_IS_NO_OVERFLOW ); + return flags; + + case 'position' : + newValue === 'absolute' ? ( flags |= X_NodeFlags_STYLE_IS_POS_ABSOLUTE ) : ( flags &= ~X_NodeFlags_STYLE_IS_POS_ABSOLUTE ); + return flags; + + case 'width' : + newValue = X_Node_CSS__splitValueAndUnit( newValue ); + if( newValue[ 1 ] !== '%' ){ + flags |= X_NodeFlags_STYLE_IS_WIDTH_LENGTH; + flags &= ~X_NodeFlags_STYLE_IS_WIDTH_PCT; + } else { + flags &= ~X_NodeFlags_STYLE_IS_WIDTH_LENGTH; + flags |= X_NodeFlags_STYLE_IS_WIDTH_PCT; + }; + return flags; + + case 'height' : + newValue = X_Node_CSS__splitValueAndUnit( newValue ); + if( newValue[ 1 ] !== '%' ){ + flags |= X_NodeFlags_STYLE_IS_HEIGHT_LENGTH; + flags &= ~X_NodeFlags_STYLE_IS_HEIGHT_PCT; + } else { + flags &= ~X_NodeFlags_STYLE_IS_HEIGHT_LENGTH; + flags |= X_NodeFlags_STYLE_IS_HEIGHT_PCT; + }; + return flags; + + case 'fontSize' : + + }; + return flags; +}; + +/** + * cssText の getter と setter。setter の場合 css と異なり全ての style が書き変わる。 + * @alias Node.prototype.cssText + * @param {string=} v cssText 文字列名 + * @return {Node|string} getter の場合は cssText 文字列を、setter の場合は自身を返す。(メソッドチェーン) + * @example // getter + * node.cssText(); + * // setter + * node.cssText('color:red;width:20px'); + */ +function X_Node_cssText( v ){ var obj, i, l, attr, name; + + if( v === this[ '_cssText' ] && ( this[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT ) === 0 ){ + return this; + }; + if( v === '' ){ - delete this._css; - this._state &= ~X_Node_State.IE5_DISPLAY_NONE_FIX; - this._dirty |= X_Node_Dirty.CSS; - this.parent && X_Node_reserveUpdate(); - delete this._cssText; + delete this[ '_css' ]; + delete this[ '_cssText' ]; + this[ '_flags' ] |= X_NodeFlags_DIRTY_CSS | X_NodeFlags_DIRTY_IE_FILTER; + this[ '_flags' ] &= ~X_NodeFlags_OLD_CSSTEXT; + this[ '_flags' ] & X_NodeFlags_IN_TREE && X_Node_reserveUpdate(); return this; } else - if( X.Type.isString( v ) ){ - delete this._css; - this._state &= ~X_Node_State.IE5_DISPLAY_NONE_FIX; + if( X_Type_isString( v ) ){ + delete this[ '_css' ]; obj = {}; - v = v.split( ';' ); // TODO content ";" などにも対応 + v = v.split( ';' ); // TODO content ";" などにも対応 <- 不要 :before :after 疑似要素には触らない for( i = 0, l = v.length; i < l; ++i ){ attr = v[ i ].split( ':' ); ( name = attr[ 0 ] ) && ( obj[ name ] = attr[ 1 ] || true ); }; - return this.css( obj ); + return this[ 'css' ]( obj ); }; // getter - if( this._dirty & X_Node_Dirty.CSS && !( this._cssText = X_Node_CSS_objToCssText( this._css ) ) ){ - delete this._cssText; - }; - return this._cssText; + this[ '_flags' ] & X_NodeFlags_OLD_CSSTEXT && X_Node_CSS_objToCssText( this ); + return this[ '_cssText' ]; }; /* * ここでは HTMLElement のチ1ェックは行わない! * TODO * body に css attr がセットされた場合には X_ViewPort_baseFontSize をクリア + * class, id, attr() の変更があった場合は、変更の適用の後、charSize を取得 + * css の場合は、計算で求めることが可能、content は影響しない + * :hover, #target, が絡む場合、正しく扱えない */ var X_Node_CSS_getCharSize = - window.getComputedStyle ? - (function( that ){ - X_Node_updateTimerID && X_Node_startUpdate(); - if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize; - if( that._fontSize ) return that._fontSize; - return that._fontSize = parseFloat( getComputedStyle( that._rawObject, null ).fontSize ); - }) : - - document.defaultView && document.defaultView.getComputedStyle ? + X_Node_CSS_getComputedStyle ? (function( that ){ X_Node_updateTimerID && X_Node_startUpdate(); if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize; - if( that._fontSize ) return that._fontSize; - return that._fontSize = parseFloat( document.defaultView.getComputedStyle( that._rawObject, null ).fontSize ); + if( that[ '_fontSize' ] ) return that[ '_fontSize' ]; + return that[ '_fontSize' ] = parseFloat( X_Node_CSS_getComputedStyle( that[ '_rawObject' ], null ).fontSize ); }) : - 5.5 <= X_UA.IE ? + 5 <= X_UA[ 'IE' ] ? (function( that ){ var font, vu, v, u, _v; X_Node_updateTimerID && X_Node_startUpdate(); if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize; - if( that._fontSize ) return that._fontSize; + if( that[ '_fontSize' ] ) return that[ '_fontSize' ]; - font = that._rawObject.currentStyle.fontSize; - //font = that._css && that._css.fontSize || '1em'; + font = that[ '_rawObject' ].currentStyle.fontSize; + //font = that[ '_css' ] && that[ '_css' ].fontSize || '1em'; vu = X_Node_CSS__splitValueAndUnit( font ); v = vu[ 0 ]; u = vu[ 1 ]; if( v === 0 ){ - if( v = X_Node_CSS__FONT_SIZE_RATIO[ font ] ) return that._fontSize = v; + if( v = X_Node_CSS__FONT_SIZE_RATIO[ font ] ) return that[ '_fontSize' ] = v; } else { - if( _v = X_Node_CSS__UNIT_RATIO[ u ] ) return that._fontSize = v / _v; + if( _v = X_Node_CSS__UNIT_RATIO[ u ] ) return that[ '_fontSize' ] = v / _v; }; switch( u ){ case 'px' : - return that._fontSize = v; + return that[ '_fontSize' ] = v; case 'em' : // body まで辿ってしまった場合は? - if( that.parent ) return that._fontSize = X_Node_CSS_getCharSize( that.parent ) * v; + if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v; break; case '%' : // body まで辿ってしまった場合は? - if( that.parent ) return that._fontSize = X_Node_CSS_getCharSize( that.parent ) * v / 100; + if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v / 100; }; return 0; }) : @@ -1121,75 +720,100 @@ X_Node_CSS_getCharSize = var elm, v; X_Node_updateTimerID && X_Node_startUpdate(); if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize; - if( that._fontSize ) return that._fontSize; + if( that[ '_fontSize' ] ) return that[ '_fontSize' ]; - that._rawObject.appendChild( elm = document.createElement( 'span' ) ); + that[ '_rawObject' ].appendChild( elm = document.createElement( 'span' ) ); elm.style.cssText = 'display:block;position:absolute;top:0;left:0;visivility:hidden;line-height:1;height:1em;'; elm.innerHTML = 'X'; v = elm.offsetHeight; - that._rawObject.removeChild( elm ); - return that._fontSize = v; + that[ '_rawObject' ].removeChild( elm ); + return that[ '_fontSize' ] = v; }) : X_UA_DOM.IE4 ? (function( that ){ var font, vu, v, u, _v; X_Node_updateTimerID && X_Node_startUpdate(); if( that === X_Node_body && X_ViewPort_baseFontSize ) return X_ViewPort_baseFontSize; - if( that._fontSize ) return that._fontSize; + if( that[ '_fontSize' ] ) return that[ '_fontSize' ]; - if( that._css && ( font = that._css.fontSize ) ){ + if( that[ '_css' ] && ( font = that[ '_css' ].fontSize ) ){ vu = X_Node_CSS__splitValueAndUnit( font ); v = vu[ 0 ]; u = vu[ 1 ]; if( v === 0 ){ - if( _v = X_Node_CSS__FONT_SIZE_RATIO[ font ] ) return that._fontSize = _v; + if( _v = X_Node_CSS__FONT_SIZE_RATIO[ font ] ) return that[ '_fontSize' ] = _v; } else { - if( _v = X_Node_CSS__UNIT_RATIO[ u ] ) return that._fontSize = v / _v; + if( _v = X_Node_CSS__UNIT_RATIO[ u ] ) return that[ '_fontSize' ] = v / _v; }; } else { - v = 1; - u = 'em'; + // 要素を生成して測定! + ( that[ '_rawObject' ] || X_Node__ie4getRawNode( that ) ).insertAdjacentHTML( 'BeforeEnd', '
X
' ); + elm = document.all[ 'ie4charsize' ]; + v = elm.offsetHeight; + elm.removeAttribute( 'id' ); // ? + elm.outerHTML = ''; + return that[ '_fontSize' ] = v; }; switch( u ){ case 'px' : - return that._fontSize = v; + return that[ '_fontSize' ] = v; case 'em' : // body まで辿ってしまった場合は? - if( that.parent ) return that._fontSize = X_Node_CSS_getCharSize( that.parent ) * v; + if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v; break; case '%' : // body まで辿ってしまった場合は? - if( that.parent ) return that._fontSize = X_Node_CSS_getCharSize( that.parent ) * v / 100; + if( that.parent ) return that[ '_fontSize' ] = X_Node_CSS_getCharSize( that.parent ) * v / 100; }; return 0; }) : 0; +var X_Node_CSS_Support = {}, -X.CSS = { - - VENDER_PREFIX : X_Node_CSS_VENDER_PREFIX, + X_Node_CSS_SPECIAL_FIX_PROP = { + + 'transitionDuration' : X_UA[ 'Android' ] && !X_UA[ 'Chrome' ] && function( v ){ // bad Android + return parseFloat( v ) === 0 ? '0.001s' : v; + } + + //webkit boxShadow が省略された場合。transparent になるのを color に + //webkit boxShadow が border-radius をはみ出す, background-image に グラデーションのないグラデーション指定 + // http://melty.koume.in/android-bug-boxshadow-radius/ + + }; + +/** + * @namespace X.CSS + */ +X[ 'CSS' ] = { - parseColor : X_Node_CSS_parseColor, + 'VENDER_PREFIX' : X_Node_CSS_VENDER_PREFIX, + // iscroll で使用 + 'uncamelize' : X_Node_CSS_uncamelize, - uncamelize : X_Node_CSS_uncamelize + 'Support' : X_Node_CSS_Support }; +/* + * backgroundPositionX : testStyle.backgroundPositionX === undefined ? 3 : 0, + backgroundPosiitonY : testStyle.backgroundPositionX === undefined ? 3 : 0, + clipTop : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 3 : 0, + clipBottom : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 4 : 0, + clipLeft : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 5 : 0, + clipRight : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 6 : 0 + */ - -var X_Node_CSS_Support, X_Node_CSS_SPECIAL_FIX_PROP; - -( function(){ - var testStyle = X_UA.IE4 ? {} : ( document.documentElement || document.createElement( 'div' ) ).style, +(function(){ + var testStyle = X_UA[ 'IE4' ] ? {} : ( /*document.documentElement ||*/ document.createElement( 'div' ) ).style, temp = testStyle.cssText, - prefix = X_Node_CSS_VENDER_PREFIX, vendors = 'webkit,Webkit,Moz,moz,Ms,ms,O,o,khtml,Khtml'.split( ',' ), searches = ( - 'opacity,boxSizing,' + + 'opacity,boxSizing,boxShadow,' + 'transform,transformOrigin,perspective,' + - 'transisiton,transitionDelay,transitionProperty,transitionDuration,transitionTimingFunction,' + + 'transisiton,transitionDelay,transitionProperty,transitionDuration,transitionTimingFunction,backfaceVisibility,willChange,filter,' + 'userSelect,touchSelect,touchAction,touchCallout,contentZooming,userDrag,tapHighlightColor' ).split( ',' ), vendor, i, search, prop, j, v; @@ -1203,50 +827,56 @@ var X_Node_CSS_Support, X_Node_CSS_SPECIAL_FIX_PROP; if( testStyle[ v + prop ] !== undefined ){ if( v === 'ms' ) v = 'Ms';// for ie9 if( v === 'o' ) v = 'O';//for opera12 - prefix[ search ] = v + prop; + X_Node_CSS_VENDER_PREFIX[ search ] = v + prop; break; }; }; } else { - prefix[ search ] = prop; + X_Node_CSS_VENDER_PREFIX[ search ] = prop; }; }; - testStyle.cssText = 'background:rgba(0,0,0,0.5)'; + testStyle.cssText = 'background:rgba(0,0,0,0.5);border-color:transparent'; + X_Node_CSS_Support[ 'rgba' ] = !!testStyle[ 'background' ]; + X_Node_CSS_Support[ 'transparent' ] = !!testStyle[ 'borderColor' ]; + // TODO border による三角形の可否 + // 2:完全、 1:透過に非対応(IE7-) 0:borderの描画が非標準で三角形が作れない - X.CSS.Support = X_Node_CSS_Support = { - rgba : !!testStyle.background + /* + * chrome 1+, ff3.5(1.9.1), ie9+, opera10.5+, Safari3+(522) + */ + if( prop = X_Node_CSS_VENDER_PREFIX[ 'boxShadow' ] ){ + + testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0'; + X_Node_CSS_Support[ 'boxShadow' ] = !!testStyle[ prop ]; + + /* + * chrome 4+, ff3.5(1.9.1), ie9+, opera10.5+, Safari5+(533) + */ + testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0, 0 0'; + X_Node_CSS_Support[ 'boxShadowMulti' ] = !!testStyle[ prop ]; + + /* + * https://developer.mozilla.org/ja/docs/Web/CSS/box-shadow + * この値を用いる場合には、spread-radius を省略出来ません。box-shadow が効かないケースに遭遇した時はこの事を思い出して下さい。 + * chrome 4+, ff3.5(1.9.1), ie9+, opera10.5+, Safari5+(533) + * + * http://unformedbuilding.com/articles/considerations-when-using-the-box-shadow/ + * box-shadow:inset と border-radius を指定しているときの Google Chrome の表示 + * このバグは Windows と Linux で発生するようです。 + * Windows 版 Chrome 10.0.648.127 で修正されているのを確認しました。 + */ + testStyle.cssText = X_Node_CSS_uncamelize( prop ) + ':0 0 inset'; + X_Node_CSS_Support[ 'boxShadowInset' ] = testStyle[ prop ] && testStyle[ prop ].indexOf( 'inset' ) !== -1; + }; + testStyle.cssText = temp; - - X_Node_CSS_SPECIAL_FIX_PROP = - // ~IE8 - X_UA.IE < 9 && !X_UA.MacIE ? - { - filter : 1, - opacity : 2//, uinode ChromeNode で行う - //boxShadow : 3, - //textShadow : 4, - //backgroundImage : 5 - } : - // IE9 - 9 <= X_UA.IE && X_UA.IE < 10 ? - { - filter : 1//, - //textShadow : 1 - } : - { - backgroundPositionX : testStyle.backgroundPositionX === undefined ? 3 : 0, - backgroundPosiitonY : testStyle.backgroundPositionX === undefined ? 3 : 0, - clipTop : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 3 : 0, - clipBottom : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 4 : 0, - clipLeft : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 5 : 0, - clipRight : testStyle.clipTop === undefined && testStyle[ 'clip-top' ] === undefined ? 6 : 0 - }; -} )(); -X_ViewPort.listenOnce( X_TEMP.SYSTEM_EVENT_INIT, function(){ +})(); + +X_ViewPort[ 'listenOnce' ]( X_EVENT_INIT, function(){ var xnode = X_Node_systemNode, output = X_Node_CSS__UNIT_RATIO, list = 'cm,mm,in,pt,pc'.split( ',' ), @@ -1254,18 +884,19 @@ X_ViewPort.listenOnce( X_TEMP.SYSTEM_EVENT_INIT, function(){ for( i = list.length; i; ){ unit = list[ --i ]; - output[ unit ] = xnode.css( 'width', 10 + unit ).width() / 10; + output[ unit ] = xnode[ 'css' ]( 'width', 10 + unit )[ 'width' ]() / 10; }; output = X_Node_CSS__FONT_SIZE_RATIO, list = 'xx-large,x-large,large,larger,medium,small,smaller,x-small,xx-small'.split( ',' ); - xnode.css( { lineHeight : '100%', height : '1em' } ).text( 'X' ); + xnode[ 'css' ]( { lineHeight : '100%', height : '1em' } )[ 'text' ]( 'X' ); for( i = list.length; i; ){ size = list[ --i ]; - output[ size ] = xnode.css( 'fontSize', size ).height();// / base; + output[ size ] = xnode[ 'css' ]( 'fontSize', size )[ 'height' ]();// / base; }; - xnode.cssText( '' ).empty(); -} ); + xnode[ 'cssText' ]( '' )[ 'empty' ](); +}); +