Permalink
Browse files

border-image fixes: fix parsing of unitless lengths in width and outs…

…et length parameters, force element border to solid transparent to prevent it from collapsing, override border-width with border-image width params if present.
  • Loading branch information...
1 parent dde610e commit 9359e7d82f650f61a3fdc52a772a503ac2d5bd25 Jason Johnston committed Jul 4, 2011
Showing with 83 additions and 39 deletions.
  1. +32 −4 sources/BorderImageRenderer.js
  2. +17 −20 sources/BorderImageStyleInfo.js
  3. +12 −5 sources/Element.js
  4. +15 −10 sources/IE9BorderImageRenderer.js
  5. +7 −0 sources/RendererBase.js
@@ -29,12 +29,14 @@ PIE.BorderImageRenderer = PIE.RendererBase.newRenderer( {
PIE.Util.withImageSize( props.src, function( imgSize ) {
var elW = bounds.w,
elH = bounds.h,
+ getLength = PIE.getLength,
+ cs = el.currentStyle,
widths = props.width,
- widthT = widths.t.pixels( el ),
- widthR = widths.r.pixels( el ),
- widthB = widths.b.pixels( el ),
- widthL = widths.l.pixels( el ),
+ widthT = ( widths ? widths.t : getLength( cs.borderTopWidth ) ).pixels( el ),
+ widthR = ( widths ? widths.r : getLength( cs.borderRightWidth ) ).pixels( el ),
+ widthB = ( widths ? widths.b : getLength( cs.borderBottomWidth ) ).pixels( el ),
+ widthL = ( widths ? widths.l : getLength( cs.borderLeftWidth ) ).pixels( el ),
slices = props.slice,
sliceT = slices.t.pixels( el ),
sliceR = slices.r.pixels( el ),
@@ -119,6 +121,32 @@ PIE.BorderImageRenderer = PIE.RendererBase.newRenderer( {
}
return box;
+ },
+
+ prepareUpdate: function() {
+ if (this.isActive()) {
+ var me = this,
+ rs = me.targetElement.runtimeStyle,
+ el = me.targetElement,
+ widths = me.styleInfos.borderImageInfo.getProps().width;
+
+ // Force border to solid transparent
+ rs.borderColor = 'transparent';
+ rs.borderStyle = 'solid';
+
+ // If widths specified in border-image shorthand, override border-width
+ if ( widths ) {
+ rs.borderTopWidth = widths.t.pixels( el ) + 'px';
+ rs.borderRightWidth = widths.r.pixels( el ) + 'px';
+ rs.borderBottomWidth = widths.b.pixels( el ) + 'px';
+ rs.borderLeftWidth = widths.l.pixels( el ) + 'px';
+ }
+ }
+ },
+
+ destroy: function() {
+ var rs = this.targetElement.runtimeStyle;
+ rs.borderColor = rs.borderStyle = rs.borderWidth = '';
}
} );
@@ -13,11 +13,10 @@ PIE.BorderImageStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
parseCss: function( css ) {
var p = null, tokenizer, token, type, value,
slices, widths, outsets,
- slashCount = 0, cs,
+ slashCount = 0,
Type = PIE.Tokenizer.Type,
IDENT = Type.IDENT,
NUMBER = Type.NUMBER,
- LENGTH = Type.LENGTH,
PERCENT = Type.PERCENT;
if( css ) {
@@ -45,14 +44,14 @@ PIE.BorderImageStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
if( isSlash( tokenizer.next() ) ) {
slashCount++;
- widths = tokenizer.until( function( tok ) {
- return !( token.tokenType & ( NUMBER | PERCENT | LENGTH ) ) && !( ( token.tokenType & IDENT ) && token.tokenValue === 'auto' );
+ widths = tokenizer.until( function( token ) {
+ return !token.isLengthOrPercent() && !( ( token.tokenType & IDENT ) && token.tokenValue === 'auto' );
} );
if( isSlash( tokenizer.next() ) ) {
slashCount++;
- outsets = tokenizer.until( function( tok ) {
- return !( token.tokenType & ( NUMBER | LENGTH ) );
+ outsets = tokenizer.until( function( token ) {
+ return !token.isLength();
} );
}
} else {
@@ -125,22 +124,20 @@ PIE.BorderImageStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
return PIE.getLength( ( tok.tokenType & NUMBER ) ? tok.tokenValue + 'px' : tok.tokenValue );
} );
- p.width = widths && widths.length > 0 ?
- distributeSides( widths, function( tok ) {
- return tok.tokenType & ( LENGTH | PERCENT ) ? PIE.getLength( tok.tokenValue ) : tok.tokenValue;
- } ) :
- ( cs = this.targetElement.currentStyle ) && {
- t: PIE.getLength( cs.borderTopWidth ),
- r: PIE.getLength( cs.borderRightWidth ),
- b: PIE.getLength( cs.borderBottomWidth ),
- l: PIE.getLength( cs.borderLeftWidth )
- };
-
- p.outset = distributeSides( outsets || [ 0 ], function( tok ) {
- return tok.tokenType & LENGTH ? PIE.getLength( tok.tokenValue ) : tok.tokenValue;
- } );
+ if( widths && widths[0] ) {
+ p.width = distributeSides( widths, function( tok ) {
+ return tok.isLengthOrPercent() ? PIE.getLength( tok.tokenValue ) : tok.tokenValue;
+ } );
+ }
+
+ if( outsets && outsets[0] ) {
+ p.outset = distributeSides( outsets, function( tok ) {
+ return tok.isLength() ? PIE.getLength( tok.tokenValue ) : tok.tokenValue;
+ } );
+ }
}
return p;
}
+
} );
View
@@ -171,9 +171,12 @@ PIE.Element = (function() {
function update( force ) {
if( !destroyed ) {
if( initialized ) {
- var i, len;
+ var i, len = renderers.length;
lockAll();
+ for( i = 0; i < len; i++ ) {
+ renderers[i].prepareUpdate();
+ }
if( force || boundsInfo.positionChanged() ) {
/* TODO just using getBoundingClientRect (used internally by BoundsInfo) for detecting
position changes may not always be accurate; it's possible that
@@ -182,12 +185,12 @@ PIE.Element = (function() {
track movement. The most accurate would be the same logic used in RootRenderer.updatePos()
but that is a more expensive operation since it does some DOM walking, and we want this
check to be as fast as possible. */
- for( i = 0, len = renderers.length; i < len; i++ ) {
+ for( i = 0; i < len; i++ ) {
renderers[i].updatePos();
}
}
if( force || boundsInfo.sizeChanged() ) {
- for( i = 0, len = renderers.length; i < len; i++ ) {
+ for( i = 0; i < len; i++ ) {
renderers[i].updateSize();
}
}
@@ -203,7 +206,8 @@ PIE.Element = (function() {
* Handle property changes to trigger update when appropriate.
*/
function propChanged() {
- var i, len, renderer,
+ var i, len = renderers.length,
+ renderer,
e = event;
// Some elements like <table> fire onpropertychange events for old-school background properties
@@ -214,7 +218,10 @@ PIE.Element = (function() {
if( !destroyed && !( e && e.propertyName in ignorePropertyNames ) ) {
if( initialized ) {
lockAll();
- for( i = 0, len = renderers.length; i < len; i++ ) {
+ for( i = 0; i < len; i++ ) {
+ renderers[i].prepareUpdate();
+ }
+ for( i = 0; i < len; i++ ) {
renderer = renderers[i];
// Make sure position is synced if the element hasn't already been rendered.
// TODO this feels sloppy - look into merging propChanged and update functions
@@ -26,13 +26,16 @@ PIE.IE9BorderImageRenderer = PIE.RendererBase.newRenderer( {
repeat = props.repeat,
repeatH = repeat.h,
repeatV = repeat.v,
- el = me.targetElement;
+ el = me.targetElement,
+ cs = el.currentStyle,
+ rs = el.runtimeStyle;
PIE.Util.withImageSize( props.src, function( imgSize ) {
var elW = bounds.w,
elH = bounds.h,
imgW = imgSize.w,
imgH = imgSize.h,
+ getLength = PIE.getLength,
// The image cannot be referenced as a URL directly in the SVG because IE9 throws a strange
// security exception (perhaps due to cross-origin policy within data URIs?) Therefore we
@@ -47,10 +50,10 @@ PIE.IE9BorderImageRenderer = PIE.RendererBase.newRenderer( {
ceil = Math.ceil,
widths = props.width,
- widthT = widths.t.pixels( el ),
- widthR = widths.r.pixels( el ),
- widthB = widths.b.pixels( el ),
- widthL = widths.l.pixels( el ),
+ widthT = ( widths ? widths.t : getLength( cs.borderTopWidth ) ).pixels( el ),
+ widthR = ( widths ? widths.r : getLength( cs.borderRightWidth ) ).pixels( el ),
+ widthB = ( widths ? widths.b : getLength( cs.borderBottomWidth ) ).pixels( el ),
+ widthL = ( widths ? widths.l : getLength( cs.borderLeftWidth ) ).pixels( el ),
slices = props.slice,
sliceT = slices.t.pixels( el ),
sliceR = slices.r.pixels( el ),
@@ -109,8 +112,9 @@ PIE.IE9BorderImageRenderer = PIE.RendererBase.newRenderer( {
addImage( widthL, 0, centerW, widthT, sliceL, 0, imgCenterW, sliceT, tileSizeT, widthT ); // top center
addImage( elW - widthR, 0, widthR, widthT, imgW - sliceR, 0, sliceR, sliceT, widthR, widthT ); // top right
addImage( 0, widthT, widthL, middleH, 0, sliceT, sliceL, imgMiddleH, widthL, tileSizeL ); // middle left
- if ( props.fill ) {
- addImage( widthL, widthT, centerW, middleH, sliceL, sliceT, imgCenterW, imgMiddleH, tileSizeT, tileSizeL ); // center fill
+ if ( props.fill ) { // center fill
+ addImage( widthL, widthT, centerW, middleH, sliceL, sliceT, imgCenterW, imgMiddleH,
+ tileSizeT || tileSizeB || imgCenterW, tileSizeL || tileSizeR || imgMiddleH );
}
addImage( elW - widthR, widthT, widthR, middleH, imgW - sliceR, sliceT, sliceR, imgMiddleH, widthR, tileSizeR ); // middle right
addImage( 0, elH - widthB, widthL, widthB, 0, imgH - sliceB, sliceL, sliceB, widthL, widthB ); // bottom left
@@ -125,8 +129,7 @@ PIE.IE9BorderImageRenderer = PIE.RendererBase.newRenderer( {
'</svg>'
);
- el.runtimeStyle.background = 'url(data:image/svg+xml,' + escape( svg.join( '' ) ) + ') no-repeat border-box border-box';
- el.runtimeStyle.borderColor = 'transparent';
+ rs.background = 'url(data:image/svg+xml,' + escape( svg.join( '' ) ) + ') no-repeat border-box border-box';
}, me );
},
@@ -151,9 +154,11 @@ PIE.IE9BorderImageRenderer = PIE.RendererBase.newRenderer( {
}
})(),
+ prepareUpdate: PIE.BorderImageRenderer.prototype.prepareUpdate,
+
destroy: function() {
var rs = this.targetElement.runtimeStyle;
- rs.background = rs.borderColor = '';
+ rs.background = rs.borderColor = rs.borderStyle = rs.borderWidth = '';
}
} );
View
@@ -31,6 +31,13 @@ PIE.RendererBase = {
},
/**
+ * Run any preparation logic that would affect the main update logic of this
+ * renderer or any of the other renderers, e.g. things that might affect the
+ * element's size or style properties.
+ */
+ prepareUpdate: function() {},
+
+ /**
* Tell the renderer to update based on modified properties
*/
updateProps: function() {

0 comments on commit 9359e7d

Please sign in to comment.