2012-05-30 15:21:19 +02:00
/ * *
* DD _belatedPNG : Adds IE6 support : PNG images for CSS background - image and HTML < IMG / > .
* Author : Drew Diller
* Email : drew . diller @ gmail . com
* URL : http : //www.dillerdesign.com/experiment/DD_belatedPNG/
* Version : 0.0 . 8 a
* Licensed under the MIT License : http : //dillerdesign.com/experiment/DD_belatedPNG/#license
*
* Example usage :
* DD _belatedPNG . fix ( '.png_bg' ) ; // argument is a CSS selector
* DD _belatedPNG . fixPng ( someNode ) ; // argument is an HTMLDomElement
* * /
/ *
PLEASE READ :
Absolutely everything in this script is SILLY . I know this . IE 's rendering of certain pixels doesn' t make sense , so neither does this code !
* /
var DD _belatedPNG = {
ns : 'DD_belatedPNG' ,
imgSize : { } ,
delay : 10 ,
nodesFixed : 0 ,
createVmlNameSpace : function ( ) { /* enable VML */
if ( document . namespaces && ! document . namespaces [ this . ns ] ) {
document . namespaces . add ( this . ns , 'urn:schemas-microsoft-com:vml' ) ;
}
} ,
createVmlStyleSheet : function ( ) { /* style VML, enable behaviors */
/ *
Just in case lots of other developers have added
lots of other stylesheets using document . createStyleSheet
and hit the 31 - limit mark , let ' s not use that method !
further reading : http : //msdn.microsoft.com/en-us/library/ms531194(VS.85).aspx
* /
var screenStyleSheet , printStyleSheet ;
screenStyleSheet = document . createElement ( 'style' ) ;
screenStyleSheet . setAttribute ( 'media' , 'screen' ) ;
document . documentElement . firstChild . insertBefore ( screenStyleSheet , document . documentElement . firstChild . firstChild ) ;
if ( screenStyleSheet . styleSheet ) {
screenStyleSheet = screenStyleSheet . styleSheet ;
screenStyleSheet . addRule ( this . ns + '\\:*' , '{behavior:url(#default#VML)}' ) ;
screenStyleSheet . addRule ( this . ns + '\\:shape' , 'position:absolute;' ) ;
screenStyleSheet . addRule ( 'img.' + this . ns + '_sizeFinder' , 'behavior:none; border:none; position:absolute; z-index:-1; top:-10000px; visibility:hidden;' ) ; /* large negative top value for avoiding vertical scrollbars for large images, suggested by James O'Brien, http://www.thanatopsic.org/hendrik/ */
this . screenStyleSheet = screenStyleSheet ;
/* Add a print-media stylesheet, for preventing VML artifacts from showing up in print (including preview). */
/* Thanks to R<> mi Pr<50> vost for automating this! */
printStyleSheet = document . createElement ( 'style' ) ;
printStyleSheet . setAttribute ( 'media' , 'print' ) ;
document . documentElement . firstChild . insertBefore ( printStyleSheet , document . documentElement . firstChild . firstChild ) ;
printStyleSheet = printStyleSheet . styleSheet ;
printStyleSheet . addRule ( this . ns + '\\:*' , '{display: none !important;}' ) ;
printStyleSheet . addRule ( 'img.' + this . ns + '_sizeFinder' , '{display: none !important;}' ) ;
}
} ,
readPropertyChange : function ( ) {
var el , display , v ;
el = event . srcElement ;
if ( ! el . vmlInitiated ) {
return ;
}
if ( event . propertyName . search ( 'background' ) != - 1 || event . propertyName . search ( 'border' ) != - 1 ) {
DD _belatedPNG . applyVML ( el ) ;
}
if ( event . propertyName == 'style.display' ) {
display = ( el . currentStyle . display == 'none' ) ? 'none' : 'block' ;
for ( v in el . vml ) {
if ( el . vml . hasOwnProperty ( v ) ) {
el . vml [ v ] . shape . style . display = display ;
}
}
}
if ( event . propertyName . search ( 'filter' ) != - 1 ) {
DD _belatedPNG . vmlOpacity ( el ) ;
}
} ,
vmlOpacity : function ( el ) {
if ( el . currentStyle . filter . search ( 'lpha' ) != - 1 ) {
var trans = el . currentStyle . filter ;
trans = parseInt ( trans . substring ( trans . lastIndexOf ( '=' ) + 1 , trans . lastIndexOf ( ')' ) ) , 10 ) / 100 ;
el . vml . color . shape . style . filter = el . currentStyle . filter ; /* complete guesswork */
el . vml . image . fill . opacity = trans ; /* complete guesswork */
}
} ,
handlePseudoHover : function ( el ) {
setTimeout ( function ( ) { /* wouldn't work as intended without setTimeout */
DD _belatedPNG . applyVML ( el ) ;
} , 1 ) ;
} ,
/ * *
* This is the method to use in a document .
* @ param { String } selector - REQUIRED - a CSS selector , such as '#doc .container'
* * /
fix : function ( selector ) {
if ( this . screenStyleSheet ) {
var selectors , i ;
selectors = selector . split ( ',' ) ; /* multiple selectors supported, no need for multiple calls to this anymore */
for ( i = 0 ; i < selectors . length ; i ++ ) {
this . screenStyleSheet . addRule ( selectors [ i ] , 'behavior:expression(DD_belatedPNG.fixPng(this))' ) ; /* seems to execute the function without adding it to the stylesheet - interesting... */
}
}
} ,
applyVML : function ( el ) {
el . runtimeStyle . cssText = '' ;
this . vmlFill ( el ) ;
this . vmlOffsets ( el ) ;
this . vmlOpacity ( el ) ;
if ( el . isImg ) {
this . copyImageBorders ( el ) ;
}
} ,
attachHandlers : function ( el ) {
var self , handlers , handler , moreForAs , a , h ;
self = this ;
handlers = { resize : 'vmlOffsets' , move : 'vmlOffsets' } ;
if ( el . nodeName == 'A' ) {
moreForAs = { mouseleave : 'handlePseudoHover' , mouseenter : 'handlePseudoHover' , focus : 'handlePseudoHover' , blur : 'handlePseudoHover' } ;
for ( a in moreForAs ) {
if ( moreForAs . hasOwnProperty ( a ) ) {
handlers [ a ] = moreForAs [ a ] ;
}
}
}
for ( h in handlers ) {
if ( handlers . hasOwnProperty ( h ) ) {
handler = function ( ) {
self [ handlers [ h ] ] ( el ) ;
} ;
el . attachEvent ( 'on' + h , handler ) ;
}
}
el . attachEvent ( 'onpropertychange' , this . readPropertyChange ) ;
} ,
giveLayout : function ( el ) {
el . style . zoom = 1 ;
if ( el . currentStyle . position == 'static' ) {
el . style . position = 'relative' ;
}
} ,
copyImageBorders : function ( el ) {
var styles , s ;
styles = { 'borderStyle' : true , 'borderWidth' : true , 'borderColor' : true } ;
for ( s in styles ) {
if ( styles . hasOwnProperty ( s ) ) {
el . vml . color . shape . style [ s ] = el . currentStyle [ s ] ;
}
}
} ,
vmlFill : function ( el ) {
if ( ! el . currentStyle ) {
return ;
} else {
var elStyle , noImg , lib , v , img , imgLoaded ;
elStyle = el . currentStyle ;
}
for ( v in el . vml ) {
if ( el . vml . hasOwnProperty ( v ) ) {
el . vml [ v ] . shape . style . zIndex = elStyle . zIndex ;
}
}
el . runtimeStyle . backgroundColor = '' ;
el . runtimeStyle . backgroundImage = '' ;
noImg = true ;
if ( elStyle . backgroundImage != 'none' || el . isImg ) {
if ( ! el . isImg ) {
el . vmlBg = elStyle . backgroundImage ;
el . vmlBg = el . vmlBg . substr ( 5 , el . vmlBg . lastIndexOf ( '")' ) - 5 ) ;
}
else {
el . vmlBg = el . src ;
}
lib = this ;
if ( ! lib . imgSize [ el . vmlBg ] ) { /* determine size of loaded image */
img = document . createElement ( 'img' ) ;
lib . imgSize [ el . vmlBg ] = img ;
img . className = lib . ns + '_sizeFinder' ;
img . runtimeStyle . cssText = 'behavior:none; position:absolute; left:-10000px; top:-10000px; border:none; margin:0; padding:0;' ; /* make sure to set behavior to none to prevent accidental matching of the helper elements! */
imgLoaded = function ( ) {
this . width = this . offsetWidth ; /* weird cache-busting requirement! */
this . height = this . offsetHeight ;
lib . vmlOffsets ( el ) ;
} ;
img . attachEvent ( 'onload' , imgLoaded ) ;
img . src = el . vmlBg ;
img . removeAttribute ( 'width' ) ;
img . removeAttribute ( 'height' ) ;
document . body . insertBefore ( img , document . body . firstChild ) ;
}
el . vml . image . fill . src = el . vmlBg ;
noImg = false ;
}
el . vml . image . fill . on = ! noImg ;
el . vml . image . fill . color = 'none' ;
el . vml . color . shape . style . backgroundColor = elStyle . backgroundColor ;
el . runtimeStyle . backgroundImage = 'none' ;
el . runtimeStyle . backgroundColor = 'transparent' ;
} ,
/* IE can't figure out what do when the offsetLeft and the clientLeft add up to 1, and the VML ends up getting fuzzy... so we have to push/enlarge things by 1 pixel and then clip off the excess */
vmlOffsets : function ( el ) {
var thisStyle , size , fudge , makeVisible , bg , bgR , dC , altC , b , c , v ;
thisStyle = el . currentStyle ;
size = { 'W' : el . clientWidth + 1 , 'H' : el . clientHeight + 1 , 'w' : this . imgSize [ el . vmlBg ] . width , 'h' : this . imgSize [ el . vmlBg ] . height , 'L' : el . offsetLeft , 'T' : el . offsetTop , 'bLW' : el . clientLeft , 'bTW' : el . clientTop } ;
fudge = ( size . L + size . bLW == 1 ) ? 1 : 0 ;
/* vml shape, left, top, width, height, origin */
makeVisible = function ( vml , l , t , w , h , o ) {
vml . coordsize = w + ',' + h ;
vml . coordorigin = o + ',' + o ;
vml . path = 'm0,0l' + w + ',0l' + w + ',' + h + 'l0,' + h + ' xe' ;
vml . style . width = w + 'px' ;
vml . style . height = h + 'px' ;
vml . style . left = l + 'px' ;
vml . style . top = t + 'px' ;
} ;
makeVisible ( el . vml . color . shape , ( size . L + ( el . isImg ? 0 : size . bLW ) ) , ( size . T + ( el . isImg ? 0 : size . bTW ) ) , ( size . W - 1 ) , ( size . H - 1 ) , 0 ) ;
makeVisible ( el . vml . image . shape , ( size . L + size . bLW ) , ( size . T + size . bTW ) , ( size . W ) , ( size . H ) , 1 ) ;
bg = { 'X' : 0 , 'Y' : 0 } ;
if ( el . isImg ) {
bg . X = parseInt ( thisStyle . paddingLeft , 10 ) + 1 ;
bg . Y = parseInt ( thisStyle . paddingTop , 10 ) + 1 ;
}
else {
for ( b in bg ) {
if ( bg . hasOwnProperty ( b ) ) {
this . figurePercentage ( bg , size , b , thisStyle [ 'backgroundPosition' + b ] ) ;
}
}
}
el . vml . image . fill . position = ( bg . X / size . W ) + ',' + ( bg . Y / size . H ) ;
bgR = thisStyle . backgroundRepeat ;
dC = { 'T' : 1 , 'R' : size . W + fudge , 'B' : size . H , 'L' : 1 + fudge } ; /* these are defaults for repeat of any kind */
altC = { 'X' : { 'b1' : 'L' , 'b2' : 'R' , 'd' : 'W' } , 'Y' : { 'b1' : 'T' , 'b2' : 'B' , 'd' : 'H' } } ;
if ( bgR != 'repeat' || el . isImg ) {
c = { 'T' : ( bg . Y ) , 'R' : ( bg . X + size . w ) , 'B' : ( bg . Y + size . h ) , 'L' : ( bg . X ) } ; /* these are defaults for no-repeat - clips down to the image location */
if ( bgR . search ( 'repeat-' ) != - 1 ) { /* now let's revert to dC for repeat-x or repeat-y */
v = bgR . split ( 'repeat-' ) [ 1 ] . toUpperCase ( ) ;
c [ altC [ v ] . b1 ] = 1 ;
c [ altC [ v ] . b2 ] = size [ altC [ v ] . d ] ;
}
if ( c . B > size . H ) {
c . B = size . H ;
}
el . vml . image . shape . style . clip = 'rect(' + c . T + 'px ' + ( c . R + fudge ) + 'px ' + c . B + 'px ' + ( c . L + fudge ) + 'px)' ;
}
else {
el . vml . image . shape . style . clip = 'rect(' + dC . T + 'px ' + dC . R + 'px ' + dC . B + 'px ' + dC . L + 'px)' ;
}
} ,
figurePercentage : function ( bg , size , axis , position ) {
var horizontal , fraction ;
fraction = true ;
horizontal = ( axis == 'X' ) ;
switch ( position ) {
case 'left' :
case 'top' :
bg [ axis ] = 0 ;
break ;
case 'center' :
bg [ axis ] = 0.5 ;
break ;
case 'right' :
case 'bottom' :
bg [ axis ] = 1 ;
break ;
default :
if ( position . search ( '%' ) != - 1 ) {
bg [ axis ] = parseInt ( position , 10 ) / 100 ;
}
else {
fraction = false ;
}
}
bg [ axis ] = Math . ceil ( fraction ? ( ( size [ horizontal ? 'W' : 'H' ] * bg [ axis ] ) - ( size [ horizontal ? 'w' : 'h' ] * bg [ axis ] ) ) : parseInt ( position , 10 ) ) ;
if ( bg [ axis ] % 2 === 0 ) {
bg [ axis ] ++ ;
}
return bg [ axis ] ;
} ,
fixPng : function ( el ) {
el . style . behavior = 'none' ;
var lib , els , nodeStr , v , e ;
if ( el . nodeName == 'BODY' || el . nodeName == 'TD' || el . nodeName == 'TR' ) { /* elements not supported yet */
return ;
}
el . isImg = false ;
if ( el . nodeName == 'IMG' ) {
if ( el . src . toLowerCase ( ) . search ( /\.png$/ ) != - 1 ) {
el . isImg = true ;
el . style . visibility = 'hidden' ;
}
else {
return ;
}
}
else if ( el . currentStyle . backgroundImage . toLowerCase ( ) . search ( '.png' ) == - 1 ) {
return ;
}
lib = DD _belatedPNG ;
el . vml = { color : { } , image : { } } ;
els = { shape : { } , fill : { } } ;
for ( v in el . vml ) {
if ( el . vml . hasOwnProperty ( v ) ) {
for ( e in els ) {
if ( els . hasOwnProperty ( e ) ) {
nodeStr = lib . ns + ':' + e ;
el . vml [ v ] [ e ] = document . createElement ( nodeStr ) ;
}
}
el . vml [ v ] . shape . stroked = false ;
el . vml [ v ] . shape . appendChild ( el . vml [ v ] . fill ) ;
el . parentNode . insertBefore ( el . vml [ v ] . shape , el ) ;
}
}
el . vml . image . shape . fillcolor = 'none' ; /* Don't show blank white shapeangle when waiting for image to load. */
el . vml . image . fill . type = 'tile' ; /* Makes image show up. */
el . vml . color . fill . on = false ; /* Actually going to apply vml element's style.backgroundColor, so hide the whiteness. */
lib . attachHandlers ( el ) ;
lib . giveLayout ( el ) ;
lib . giveLayout ( el . offsetParent ) ;
el . vmlInitiated = true ;
lib . applyVML ( el ) ; /* Render! */
}
} ;
try {
document . execCommand ( "BackgroundImageCache" , false , true ) ; /* TredoSoft Multiple IE doesn't like this, so try{} it */
} catch ( r ) { }
DD _belatedPNG . createVmlNameSpace ( ) ;
DD _belatedPNG . createVmlStyleSheet ( ) ;