From 51efc0765d302f6b048518fc381aa866f847313d Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Wed, 13 Oct 2021 12:21:41 +0100 Subject: [PATCH] Improved rendering/re-rendering of `` no issue There was noticeable flickering as content is loaded into the iframe or re-rendered because we show everything from the moment html is injected in, meaning the full loading and layout process is shown. - changed to using two iframes with one being hidden - when `@html` changes we inject the html into the hidden iframe - once all loading finishes on the hidden iframe (or 500ms timeout occurs to account for slower connections) we swap the iframe visibility so we end up switching between two fully (mostly) rendered displays resulting in much less flicker --- ghost/admin/app/components/gh-html-iframe.hbs | 9 ++- ghost/admin/app/components/gh-html-iframe.js | 62 ++++++++++++++++++- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/ghost/admin/app/components/gh-html-iframe.hbs b/ghost/admin/app/components/gh-html-iframe.hbs index 2ec3e18467..4b3eb429ce 100644 --- a/ghost/admin/app/components/gh-html-iframe.hbs +++ b/ghost/admin/app/components/gh-html-iframe.hbs @@ -1,5 +1,8 @@ - \ No newline at end of file + ...attributes +> + + + \ No newline at end of file diff --git a/ghost/admin/app/components/gh-html-iframe.js b/ghost/admin/app/components/gh-html-iframe.js index 412ac1c21f..a101539a96 100644 --- a/ghost/admin/app/components/gh-html-iframe.js +++ b/ghost/admin/app/components/gh-html-iframe.js @@ -2,12 +2,70 @@ import Component from '@glimmer/component'; import {action} from '@ember/object'; export default class GhHtmlIframeComponent extends Component { + iframes = []; + renderedIframe = 0; + toRenderIframe = 1; + + get hiddenIframeStyle() { + return 'position: absolute; visibility: hidden; border: none;'; + } + + get visibleIframeStyle() { + return 'border: none;'; + } + @action - replaceIframeContents(iframe) { - if (iframe) { + replaceIframeContents() { + const iframe = this.iframes[this.toRenderIframe]; + + if (iframe && this.args.html) { iframe.contentWindow.document.open(); iframe.contentWindow.document.write(this.args.html); iframe.contentWindow.document.close(); + + // force swap of iframes after a set timeout to account for slower connections + // so we display _something_ in the iframe even though it's still loading + this.swapTimeout = setTimeout(() => { + this.swapIframes(iframe); + }, 500); + } + } + + @action + registerIframe(iframe) { + this.iframes.push(iframe); + + if (this.iframes.indexOf(iframe) === 0) { + iframe.style = this.visibleIframeStyle; + this.replaceIframeContents(); + } + + if (this.iframes.indexOf(iframe) === 1) { + iframe.style = this.hiddenIframeStyle; + } + } + + @action + didLoad(event) { + if (this.isDestroyed || this.isDestroying) { + return; + } + + this.swapIframes(event.target); + } + + swapIframes(renderedIframe) { + if (this.isDestroyed || this.isDestroying) { + return; + } + + window.clearTimeout(this.swapTimeout); + + if (this.iframes.indexOf(renderedIframe) !== this.renderedIframe) { + this.iframes[this.toRenderIframe].style = this.visibleIframeStyle; + this.renderedIframe = this.toRenderIframe; + this.toRenderIframe = this.toRenderIframe === 0 ? 1 : 0; + this.iframes[this.toRenderIframe].style = this.hiddenIframeStyle; } } }