<component lightWeight="true"> <attach event="onpropertychange" onevent="handlePropertychange()" /> <attach event="ondetach" onevent="restore()" /> <attach event="onresize" for="window" onevent="handleResize()" /> <script type="text/javascript"> var rsrc = /url\(["']?(.*?)["']?\)/, positions = { top: 0, left: 0, bottom: 1, right: 1, center: .5 }, doc = element.document; init(); // remove the background-image and emulate it with a wrapped <img/> function init() { var wrapper = doc.createElement( "div" ), img = doc.createElement( "img" ), expando, pos; wrapper.style.position = "absolute"; wrapper.style.zIndex = -1; wrapper.style.top = 0; wrapper.style.right = 0; wrapper.style.left = 0; wrapper.style.bottom = 0; wrapper.style.overflow = "hidden"; img.style.position = "absolute"; img.style.width = img.style.width = "auto"; wrapper.appendChild( img ); element.insertBefore( wrapper, element.firstChild ); pos = [ element.currentStyle.backgroundPositionX, element.currentStyle.backgroundPositionY ]; // save useful data for quick access element.bgsExpando = expando = { wrapper: wrapper, img: img, backgroundSize: element.currentStyle['background-size'], // Only keywords or percentage values are supported backgroundPositionX: positions[ pos[0] ] || parseFloat( pos[0] ) / 100, backgroundPositionY: positions[ pos[1] ] || parseFloat( pos[1] ) / 100 }; // This is the part where we mess with the existing DOM // to make sure that the background image is correctly zIndexed if ( element.currentStyle.zIndex == "auto" ) { element.style.zIndex = 0; } if ( element.currentStyle.position == "static" ) { element.style.position = "relative"; } if ( refreshDisplay( element, expando ) ) { refreshDimensions( element, expando ); refreshBackgroundImage( element, expando, function() { updateBackground( element, expando ); }); } } function refreshDisplay( element, expando ) { var display = element.currentStyle.display; if ( display != expando.display ) { expando.display = display; expando.somethingChanged = true; } return display != "none"; } function refreshDimensions( element, expando ) { var innerWidth = element.offsetWidth - ( parseFloat( element.currentStyle.borderLeftWidth ) || 0 ) - ( parseFloat( element.currentStyle.borderRightWidth ) || 0 ), innerHeight = element.offsetHeight - ( parseFloat( element.currentStyle.borderTopWidth ) || 0 ) - ( parseFloat( element.currentStyle.borderBottomWidth ) || 0 ); if ( innerWidth != expando.innerWidth || innerHeight != expando.innerHeight ) { expando.innerWidth = innerWidth; expando.innerHeight = innerHeight; expando.somethingChanged = true; } } function refreshBackgroundImage( element, expando, callback ) { var img = expando.img, src = ( rsrc.exec( element.currentStyle.backgroundImage ) || [] )[1]; if ( src && src != expando.backgroundSrc ) { expando.backgroundSrc = src; expando.somethingChanged = true; img.onload = function() { var width = img.width, height = img.height; // ignore onload on the proxy image if ( width == 1 && height == 1 ) { return; } expando.imgWidth = width; expando.imgHeight = height; expando.constrain = false; callback(); img.style.visibility = "visible"; img.onload = null; }; img.style.visibility = "hidden"; img.src = expando.backgroundSrc; // force onload execution if ( img.readyState || img.complete ) { img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; img.src = expando.backgroundSrc; } expando.ignoreNextPropertyChange = true; element.style.backgroundImage = "none"; } else { // the callback should be exacuted in all cases callback(); } } function updateBackground( element, expando ) { if ( !expando.somethingChanged ) { return; } var img = expando.img, elemRatio = expando.innerWidth / expando.innerHeight, imgRatio = expando.imgWidth / expando.imgHeight, prevConstrain = expando.constrain, curConstrain, delta; if ( expando.backgroundSize == "contain" ) { if ( imgRatio > elemRatio ) { expando.constrain = curConstrain = "width"; delta = Math.floor( ( expando.innerHeight - expando.innerWidth / imgRatio ) * expando.backgroundPositionY ); img.style.top = delta + "px"; // when switching from height to width constraint, // make sure to release constraint on height and reset left if ( curConstrain != prevConstrain ) { img.style.width = "100%"; img.style.height = "auto"; img.style.left = 0; } // elemRatio > imgRatio } else { expando.constrain = curConstrain = "height"; delta = Math.floor( ( expando.innerWidth - expando.innerHeight * imgRatio ) * expando.backgroundPositionX ); img.style.left = delta + "px"; if ( curConstrain != prevConstrain ) { img.style.width = "auto"; img.style.height = "100%"; img.style.top = 0; } } } else if ( expando.backgroundSize == "cover" ) { if ( imgRatio > elemRatio ) { expando.constrain = curConstrain = "height"; delta = Math.floor( ( expando.innerHeight * imgRatio - expando.innerWidth ) * expando.backgroundPositionX ); img.style.left = -delta + "px"; // when switching from height to width constraint, // make sure to release constraint on height and reset left if ( curConstrain != prevConstrain ) { img.style.width = "auto"; img.style.height = "100%"; img.style.top = 0; } // elemRatio > imgRatio } else { expando.constrain = curConstrain = "width"; delta = Math.floor( ( expando.innerWidth / imgRatio - expando.innerHeight ) * expando.backgroundPositionY ); img.style.top = -delta + "px"; if ( curConstrain != prevConstrain ) { img.style.width = "100%"; img.style.height = "auto"; img.style.left = 0; } } } expando.somethingChanged = false; } // handle different style changes function handlePropertychange() { var expando = element.bgsExpando; // this prevents handling propertychange events caused by this script // TODO: make it reliable if ( expando.ignoreNextPropertyChange ) { expando.ignoreNextPropertyChange = false; return; } if ( refreshDisplay( element, expando ) ) { refreshDimensions( element, expando ); refreshBackgroundImage( element, expando, function() { updateBackground( element, expando ); }); } } function handleResize() { // TODO: throttle resize events var expando = element.bgsExpando; if ( expando.display != "none" ) { refreshDimensions( element, expando ); updateBackground( element, expando ); } } function restore() { var expando = element.bgsExpando; try { element.style.backgroundImage = "url('" + expando.backgroundSrc + "')"; element.removeChild( expando.wrapper ); element.bgsExpando = null; } catch(e) {} } </script>