From 0d757814e55bf795762e4c9d30f5ee4b0076a111 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Fri, 3 Jan 2020 15:15:42 +1100 Subject: [PATCH] FIX: correctly account for onebox height when lazy loading images Page used to jitter when oneboxes loaded images lazily. Previously we inserted the the "shadow" loading image before the "real" image. This meant that certain styling with `firstChild` CSS selectors would apply incorrectly to the shadow image. Additionally we had special case code for onebox and quoted images that was not really needed due to this fix. We had an old fix that used computed style for image height and width in specific scenarios, we now run it all the time. On slow devices there was a possibility that the cache fetch after amending src at the end of the process would cause a flash, this is avoided using a new onload handler. --- .../discourse/lib/lazy-load-images.js.es6 | 57 ++++++++----------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/app/assets/javascripts/discourse/lib/lazy-load-images.js.es6 b/app/assets/javascripts/discourse/lib/lazy-load-images.js.es6 index 284c5a3be46..a8f30a3998c 100644 --- a/app/assets/javascripts/discourse/lib/lazy-load-images.js.es6 +++ b/app/assets/javascripts/discourse/lib/lazy-load-images.js.es6 @@ -40,7 +40,18 @@ function show(image) { image.srcset = copyImg.srcset; } image.classList.remove("d-lazyload-hidden"); - image.parentNode.removeChild(copyImg); + + if (image.onload) { + // don't bother fighting with existing handler + // this can mean a slight flash on mobile + image.parentNode.removeChild(copyImg); + } else { + image.onload = () => { + image.parentNode.removeChild(copyImg); + image.onload = null; + }; + } + copyImg.onload = null; }; @@ -50,43 +61,23 @@ function show(image) { copyImg.srcset = imageData.srcset; } + // width of image may not match, use computed style which + // is the actual size of the image + const computedStyle = window.getComputedStyle(image); + const actualWidth = parseInt(computedStyle.width, 10); + const actualHeight = parseInt(computedStyle.height, 10); + copyImg.style.position = "absolute"; copyImg.style.top = `${image.offsetTop}px`; copyImg.style.left = `${image.offsetLeft}px`; + copyImg.style.width = `${actualWidth}px`; + copyImg.style.height = `${actualHeight}px`; + copyImg.className = imageData.className; - let inOnebox = false; - let inQuote = false; - for (let element = image; element; element = element.parentElement) { - if (element.tagName === "ARTICLE" && element.dataset.postId) { - break; - } - if (element.classList.contains("onebox")) { - inOnebox = true; - } - if (element.tagName === "BLOCKQUOTE") { - inQuote = true; - } - } - - if (!inOnebox) { - copyImg.style.width = `${imageData.width}px`; - copyImg.style.height = `${imageData.height}px`; - } - - if (inQuote && imageData.width && imageData.height) { - const computedStyle = window.getComputedStyle(image); - const width = parseInt(computedStyle.width, 10); - const height = width * (imageData.height / imageData.width); - - image.width = width; - image.height = height; - - copyImg.style.width = `${width}px`; - copyImg.style.height = `${height}px`; - } - - image.parentNode.insertBefore(copyImg, image); + // insert after the current element so styling still will + // apply to original image firstChild selectors + image.parentNode.insertBefore(copyImg, image.nextSibling); } else { image.classList.remove("d-lazyload-hidden"); }