<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.alt = "";
	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>
