From 3be66f60f65818bffb43b1a1c1e6dc5e18a39aed Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Sun, 20 Nov 2011 12:58:41 -0700 Subject: [PATCH 01/12] Fix divide-by-zero error when the total width or height of the box-shadow shape is zero. --- sources/BoxShadowOutsetRenderer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/BoxShadowOutsetRenderer.js b/sources/BoxShadowOutsetRenderer.js index c3e51d5..d74e518 100644 --- a/sources/BoxShadowOutsetRenderer.js +++ b/sources/BoxShadowOutsetRenderer.js @@ -89,8 +89,8 @@ PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( { if( blur ) { totalW = ( spread + blur ) * 2 + w; totalH = ( spread + blur ) * 2 + h; - focusX = blur * 2 / totalW; - focusY = blur * 2 / totalH; + focusX = totalW ? blur * 2 / totalW : 0; + focusY = totalH ? blur * 2 / totalH : 0; if( blur - spread > w / 2 || blur - spread > h / 2 ) { // If the blur is larger than half the element's narrowest dimension, we cannot do // this with a single shape gradient, because its focussize would have to be less than From b9e6813e0879e7415896ca0b6c136cba53349b6a Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Sat, 31 Dec 2011 13:36:22 -0700 Subject: [PATCH 02/12] Make sure the element still exists after the add/removeClass delay. Fixes #191. --- sources/Element.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sources/Element.js b/sources/Element.js index 23ab073..35163c7 100644 --- a/sources/Element.js +++ b/sources/Element.js @@ -27,8 +27,10 @@ PIE.Element = (function() { var classes = dummyArray.slice.call( arguments, 1 ), i = classes.length; setTimeout( function() { - while( i-- ) { - addClass( el, classes[ i ] ); + if( el ) { + while( i-- ) { + addClass( el, classes[ i ] ); + } } }, 0 ); } @@ -37,8 +39,10 @@ PIE.Element = (function() { var classes = dummyArray.slice.call( arguments, 1 ), i = classes.length; setTimeout( function() { - while( i-- ) { - removeClass( el, classes[ i ] ); + if( el ) { + while( i-- ) { + removeClass( el, classes[ i ] ); + } } }, 0 ); } From 64f4e7d0bc5d823c7ff5214e20bd36d1695f7c4d Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Fri, 18 Nov 2011 21:48:39 -0700 Subject: [PATCH 03/12] Don't perform border rendering if there is no border-radius specified. --- sources/BorderRenderer.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sources/BorderRenderer.js b/sources/BorderRenderer.js index 5f48790..8177488 100644 --- a/sources/BorderRenderer.js +++ b/sources/BorderRenderer.js @@ -17,8 +17,7 @@ PIE.BorderRenderer = PIE.RendererBase.newRenderer( { isActive: function() { var si = this.styleInfos; - return ( si.borderRadiusInfo.isActive() || - si.backgroundInfo.isActive() ) && + return si.borderRadiusInfo.isActive() && !si.borderImageInfo.isActive() && si.borderInfo.isActive(); //check BorderStyleInfo last because it's the most expensive }, From 0c278f91ea38206c72aae5c4d4a6d270efe80e3d Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Sun, 6 Nov 2011 17:42:10 -0700 Subject: [PATCH 04/12] Put the length calc element into the body rather than the documentElement, fixes unit conversions in IE<8 --- sources/Length.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sources/Length.js b/sources/Length.js index 39bb0e4..09f5408 100644 --- a/sources/Length.js +++ b/sources/Length.js @@ -7,7 +7,7 @@ */ PIE.Length = (function() { var lengthCalcEl = doc.createElement( 'length-calc' ), - parent = doc.documentElement, + parent = doc.body, s = lengthCalcEl.style, conversions = {}, units = [ 'mm', 'cm', 'in', 'pt', 'pc' ], @@ -19,13 +19,13 @@ PIE.Length = (function() { parent.appendChild( lengthCalcEl ); while( i-- ) { - lengthCalcEl.style.width = '100' + units[i]; + s.width = '100' + units[i]; conversions[ units[i] ] = lengthCalcEl.offsetWidth / 100; } parent.removeChild( lengthCalcEl ); // All calcs from here on will use 1em - lengthCalcEl.style.width = '1em'; + s.width = '1em'; function Length( val ) { From afefebff936b7346e4766aaca646acf917fb420b Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Sun, 30 Oct 2011 08:26:04 -0600 Subject: [PATCH 05/12] Fix comma --- sources/BoxShadowOutsetRenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/BoxShadowOutsetRenderer.js b/sources/BoxShadowOutsetRenderer.js index d74e518..38841d3 100644 --- a/sources/BoxShadowOutsetRenderer.js +++ b/sources/BoxShadowOutsetRenderer.js @@ -74,7 +74,7 @@ PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( { shadowInfo = shadowInfos[ i ]; xOff = shadowInfo.xOffset.pixels( el ); yOff = shadowInfo.yOffset.pixels( el ); - spread = shadowInfo.spread.pixels( el ), + spread = shadowInfo.spread.pixels( el ); blur = shadowInfo.blur.pixels( el ); color = shadowInfo.color; // Shape path From 97991983b050fffdcff9d1a7588fcf6f3aced63d Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Mon, 5 Sep 2011 08:50:56 -0600 Subject: [PATCH 06/12] Partial fix for issue #79: explicitly set the size of the background image fill tile in pixels so that IE will automatically adjust it to the user's zoom level. --- sources/BackgroundRenderer.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sources/BackgroundRenderer.js b/sources/BackgroundRenderer.js index 396ec50..5c8ca9d 100644 --- a/sources/BackgroundRenderer.js +++ b/sources/BackgroundRenderer.js @@ -153,6 +153,11 @@ PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { pxY = Math.round( bgPos.y ) + bwT + 0.5; fill.position = ( pxX / elW ) + ',' + ( pxY / elH ); + // Set the size of the image. We have to actually set it to px values otherwise it will not honor + // the user's browser zoom level and always display at its natural screen size. + fill['size']['x'] = 1; //Can be any value, just has to be set to "prime" it so the next line works. Weird! + fill['size'] = size.w + 'px,' + size.h + 'px'; + // Repeating - clip the image shape if( repeat && repeat !== 'repeat' ) { if( repeat === 'repeat-x' || repeat === 'no-repeat' ) { From 862c62688ec32ed65db4195b4d4dd4bbe84adc01 Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Thu, 24 Nov 2011 22:33:13 -0700 Subject: [PATCH 07/12] Sometimes the body doesn't exist yet when doing length units calculation (e.g. inclusion of PIE*.js), so fall back to documentElement --- sources/Length.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/Length.js b/sources/Length.js index 09f5408..ebee603 100644 --- a/sources/Length.js +++ b/sources/Length.js @@ -7,7 +7,7 @@ */ PIE.Length = (function() { var lengthCalcEl = doc.createElement( 'length-calc' ), - parent = doc.body, + parent = doc.body || doc.documentElement, s = lengthCalcEl.style, conversions = {}, units = [ 'mm', 'cm', 'in', 'pt', 'pc' ], From 8d73e903927e4ceed89d37f25ae37c31a37bc198 Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Sat, 4 Feb 2012 18:44:24 -0700 Subject: [PATCH 08/12] Don't add any printing handlers in IE9, as they cause errors and aren't needed anyway. --- sources/OnPrint.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sources/OnPrint.js b/sources/OnPrint.js index a973473..126175c 100644 --- a/sources/OnPrint.js +++ b/sources/OnPrint.js @@ -19,7 +19,9 @@ } } - PIE.OnUnload.attachManagedEvent( window, 'onbeforeprint', beforePrint ); - PIE.OnUnload.attachManagedEvent( window, 'onafterprint', afterPrint ); + if( PIE.ieDocMode < 9 ) { + PIE.OnUnload.attachManagedEvent( window, 'onbeforeprint', beforePrint ); + PIE.OnUnload.attachManagedEvent( window, 'onafterprint', afterPrint ); + } })(); \ No newline at end of file From 6744f0440f4656cfe19f86d57e4e221c2eb2a51c Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Tue, 7 Feb 2012 20:43:15 -0700 Subject: [PATCH 09/12] Tweaks to polling heartbeat: use setTimeout rather than setInterval to prevent backing up. Allow setting html{-pie-poll-interval:N} to customize the interval on a page. --- sources/Heartbeat.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sources/Heartbeat.js b/sources/Heartbeat.js index 66879b7..a312174 100644 --- a/sources/Heartbeat.js +++ b/sources/Heartbeat.js @@ -2,15 +2,20 @@ * Simple heartbeat timer - this is a brute-force workaround for syncing issues caused by IE not * always firing the onmove and onresize events when elements are moved or resized. We check a few * times every second to make sure the elements have the correct position and size. See Element.js - * which adds heartbeat listeners based on the custom -pie-poll flag, which defaults to true in IE8 + * which adds heartbeat listeners based on the custom -pie-poll flag, which defaults to true in IE8-9 * and false elsewhere. */ PIE.Heartbeat = new PIE.Observable(); PIE.Heartbeat.run = function() { - var me = this; + var me = this, + interval; if( !me.running ) { - setInterval( function() { me.fire() }, 250 ); + interval = doc.documentElement.currentStyle.getAttribute( PIE.CSS_PREFIX + 'poll-interval' ) || 250; + (function beat() { + me.fire(); + setTimeout(beat, interval); + })(); me.running = 1; } }; From af1031c9281e63f3392c82352240e14dfb00f4a1 Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Tue, 7 Feb 2012 20:53:29 -0700 Subject: [PATCH 10/12] Bump build number --- build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.xml b/build.xml index 6d535fa..8c3ea07 100644 --- a/build.xml +++ b/build.xml @@ -2,7 +2,7 @@ - + From 0aa983e79d08dc1eb2fbbb850064e215518bafb4 Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Wed, 8 Feb 2012 20:44:21 -0700 Subject: [PATCH 11/12] Fix printing error in IE9 by putting the print media check before attempting to access window.PIE --- sources/htc_init.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/sources/htc_init.js b/sources/htc_init.js index 3a511f8..9edec0b 100644 --- a/sources/htc_init.js +++ b/sources/htc_init.js @@ -1,17 +1,21 @@ var el = element; function init() { - var PIE = window[ 'PIE' ]; - if( PIE && doc.media !== 'print' ) { // IE strangely attaches a second copy of the behavior to elements when printing - PIE['attach']( el ); + if ( doc.media !== 'print' ) { // IE strangely attaches a second copy of the behavior to elements when printing + var PIE = window[ 'PIE' ]; + if( PIE ) { + PIE['attach']( el ); + } } } function cleanup() { - var PIE = window[ 'PIE' ]; - if (PIE) { - PIE['detach']( el ); - PIE = el = 0; + if ( doc.media !== 'print' ) { + var PIE = window[ 'PIE' ]; + if (PIE) { + PIE['detach']( el ); + el = 0; + } } } From 80e4d100b6509c888109890d0058bed7290c25f2 Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Sun, 25 Mar 2012 10:59:10 -0600 Subject: [PATCH 12/12] Sometimes el.currentStyle does not yet exist; add a check at the start of each update and delay the update slightly if it's not present. --- sources/Element.js | 216 ++++++++++++++++++++++++--------------------- 1 file changed, 115 insertions(+), 101 deletions(-) diff --git a/sources/Element.js b/sources/Element.js index 35163c7..7f35998 100644 --- a/sources/Element.js +++ b/sources/Element.js @@ -72,117 +72,123 @@ PIE.Element = (function() { bounds, ieDocMode = PIE.ieDocMode, cs = el.currentStyle, - lazy = cs.getAttribute( lazyInitCssProp ) === 'true', - childRenderers; - - // Polling for size/position changes: default to on in IE8, off otherwise, overridable by -pie-poll - poll = cs.getAttribute( pollCssProp ); - poll = ieDocMode > 7 ? poll !== 'false' : poll === 'true'; - - // Force layout so move/resize events will fire. Set this as soon as possible to avoid layout changes - // after load, but make sure it only gets called the first time through to avoid recursive calls to init(). - if( !initializing ) { - initializing = 1; - el.runtimeStyle.zoom = 1; - initFirstChildPseudoClass(); - } - - boundsInfo.lock(); + lazy, childRenderers; - // If the -pie-lazy-init:true flag is set, check if the element is outside the viewport and if so, delay initialization - if( lazy && ( bounds = boundsInfo.getBounds() ) && ( docEl = doc.documentElement || doc.body ) && - ( bounds.y > docEl.clientHeight || bounds.x > docEl.clientWidth || bounds.y + bounds.h < 0 || bounds.x + bounds.w < 0 ) ) { - if( !delayed ) { - delayed = 1; - PIE.OnScroll.observe( init ); - } + if( !cs ) { + // currentStyle not yet initialized; delay slightly until it's ready + setTimeout(init, 1); } else { - initialized = 1; - delayed = initializing = 0; - PIE.OnScroll.unobserve( init ); - - // Create the style infos and renderers - if ( ieDocMode === 9 ) { - styleInfos = { - backgroundInfo: new PIE.BackgroundStyleInfo( el ), - borderImageInfo: new PIE.BorderImageStyleInfo( el ), - borderInfo: new PIE.BorderStyleInfo( el ) - }; - styleInfosArr = [ - styleInfos.backgroundInfo, - styleInfos.borderImageInfo - ]; - rootRenderer = new PIE.IE9RootRenderer( el, boundsInfo, styleInfos ); - childRenderers = [ - new PIE.IE9BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ), - new PIE.IE9BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ) - ]; - } else { + lazy = cs.getAttribute( lazyInitCssProp ) === 'true'; + + // Polling for size/position changes: default to on in IE8, off otherwise, overridable by -pie-poll + poll = cs.getAttribute( pollCssProp ); + poll = ieDocMode > 7 ? poll !== 'false' : poll === 'true'; + + // Force layout so move/resize events will fire. Set this as soon as possible to avoid layout changes + // after load, but make sure it only gets called the first time through to avoid recursive calls to init(). + if( !initializing ) { + initializing = 1; + el.runtimeStyle.zoom = 1; + initFirstChildPseudoClass(); + } - styleInfos = { - backgroundInfo: new PIE.BackgroundStyleInfo( el ), - borderInfo: new PIE.BorderStyleInfo( el ), - borderImageInfo: new PIE.BorderImageStyleInfo( el ), - borderRadiusInfo: new PIE.BorderRadiusStyleInfo( el ), - boxShadowInfo: new PIE.BoxShadowStyleInfo( el ), - visibilityInfo: new PIE.VisibilityStyleInfo( el ) - }; - styleInfosArr = [ - styleInfos.backgroundInfo, - styleInfos.borderInfo, - styleInfos.borderImageInfo, - styleInfos.borderRadiusInfo, - styleInfos.boxShadowInfo, - styleInfos.visibilityInfo - ]; - rootRenderer = new PIE.RootRenderer( el, boundsInfo, styleInfos ); - childRenderers = [ - new PIE.BoxShadowOutsetRenderer( el, boundsInfo, styleInfos, rootRenderer ), - new PIE.BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ), - //new PIE.BoxShadowInsetRenderer( el, boundsInfo, styleInfos, rootRenderer ), - new PIE.BorderRenderer( el, boundsInfo, styleInfos, rootRenderer ), - new PIE.BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ) - ]; - if( el.tagName === 'IMG' ) { - childRenderers.push( new PIE.ImgRenderer( el, boundsInfo, styleInfos, rootRenderer ) ); + boundsInfo.lock(); + + // If the -pie-lazy-init:true flag is set, check if the element is outside the viewport and if so, delay initialization + if( lazy && ( bounds = boundsInfo.getBounds() ) && ( docEl = doc.documentElement || doc.body ) && + ( bounds.y > docEl.clientHeight || bounds.x > docEl.clientWidth || bounds.y + bounds.h < 0 || bounds.x + bounds.w < 0 ) ) { + if( !delayed ) { + delayed = 1; + PIE.OnScroll.observe( init ); } - rootRenderer.childRenderers = childRenderers; // circular reference, can't pass in constructor; TODO is there a cleaner way? - } - renderers = [ rootRenderer ].concat( childRenderers ); + } else { + initialized = 1; + delayed = initializing = 0; + PIE.OnScroll.unobserve( init ); + + // Create the style infos and renderers + if ( ieDocMode === 9 ) { + styleInfos = { + backgroundInfo: new PIE.BackgroundStyleInfo( el ), + borderImageInfo: new PIE.BorderImageStyleInfo( el ), + borderInfo: new PIE.BorderStyleInfo( el ) + }; + styleInfosArr = [ + styleInfos.backgroundInfo, + styleInfos.borderImageInfo + ]; + rootRenderer = new PIE.IE9RootRenderer( el, boundsInfo, styleInfos ); + childRenderers = [ + new PIE.IE9BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.IE9BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ) + ]; + } else { + + styleInfos = { + backgroundInfo: new PIE.BackgroundStyleInfo( el ), + borderInfo: new PIE.BorderStyleInfo( el ), + borderImageInfo: new PIE.BorderImageStyleInfo( el ), + borderRadiusInfo: new PIE.BorderRadiusStyleInfo( el ), + boxShadowInfo: new PIE.BoxShadowStyleInfo( el ), + visibilityInfo: new PIE.VisibilityStyleInfo( el ) + }; + styleInfosArr = [ + styleInfos.backgroundInfo, + styleInfos.borderInfo, + styleInfos.borderImageInfo, + styleInfos.borderRadiusInfo, + styleInfos.boxShadowInfo, + styleInfos.visibilityInfo + ]; + rootRenderer = new PIE.RootRenderer( el, boundsInfo, styleInfos ); + childRenderers = [ + new PIE.BoxShadowOutsetRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ), + //new PIE.BoxShadowInsetRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.BorderRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ) + ]; + if( el.tagName === 'IMG' ) { + childRenderers.push( new PIE.ImgRenderer( el, boundsInfo, styleInfos, rootRenderer ) ); + } + rootRenderer.childRenderers = childRenderers; // circular reference, can't pass in constructor; TODO is there a cleaner way? + } + renderers = [ rootRenderer ].concat( childRenderers ); - // Add property change listeners to ancestors if requested - initAncestorEventListeners(); + // Add property change listeners to ancestors if requested + initAncestorEventListeners(); - // Add to list of polled elements in IE8 - if( poll ) { - PIE.Heartbeat.observe( update ); - PIE.Heartbeat.run(); + // Add to list of polled elements in IE8 + if( poll ) { + PIE.Heartbeat.observe( update ); + PIE.Heartbeat.run(); + } + + // Trigger rendering + update( 1 ); } - // Trigger rendering - update( 1 ); - } + if( !eventsAttached ) { + eventsAttached = 1; + if( ieDocMode < 9 ) { + addListener( el, 'onmove', handleMoveOrResize ); + } + addListener( el, 'onresize', handleMoveOrResize ); + addListener( el, 'onpropertychange', propChanged ); + addListener( el, 'onmouseenter', mouseEntered ); + addListener( el, 'onmouseleave', mouseLeft ); + addListener( el, 'onmousedown', mousePressed ); + if( el.tagName in PIE.focusableElements ) { + addListener( el, 'onfocus', focused ); + addListener( el, 'onblur', blurred ); + } + PIE.OnResize.observe( handleMoveOrResize ); - if( !eventsAttached ) { - eventsAttached = 1; - if( ieDocMode < 9 ) { - addListener( el, 'onmove', handleMoveOrResize ); + PIE.OnUnload.observe( removeEventListeners ); } - addListener( el, 'onresize', handleMoveOrResize ); - addListener( el, 'onpropertychange', propChanged ); - addListener( el, 'onmouseenter', mouseEntered ); - addListener( el, 'onmouseleave', mouseLeft ); - addListener( el, 'onmousedown', mousePressed ); - if( el.tagName in PIE.focusableElements ) { - addListener( el, 'onfocus', focused ); - addListener( el, 'onblur', blurred ); - } - PIE.OnResize.observe( handleMoveOrResize ); - PIE.OnUnload.observe( removeEventListeners ); + boundsInfo.unlock(); } - - boundsInfo.unlock(); } } @@ -208,7 +214,11 @@ PIE.Element = (function() { */ function update( force ) { if( !destroyed ) { - if( initialized ) { + if( !el.currentStyle ) { + // currentStyle not yet initialized; delay slightly until it's ready + setTimeout(update, 1); + } + else if( initialized ) { var i, len = renderers.length; lockAll(); @@ -255,7 +265,11 @@ PIE.Element = (function() { // is ignored because size calculations don't work correctly immediately when its onpropertychange // event fires, and because it will trigger an onresize event anyway. if( !destroyed && !( e && e.propertyName in ignorePropertyNames ) ) { - if( initialized ) { + if( !el.currentStyle ) { + // currentStyle not yet initialized; delay slightly until it's ready + setTimeout(propChanged, 1); + } + else if( initialized ) { lockAll(); for( i = 0; i < len; i++ ) { renderers[i].prepareUpdate();