0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

Improved rendering/re-rendering of <GhHtmlIframe>

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
This commit is contained in:
Kevin Ansfield 2021-10-13 12:21:41 +01:00
parent 34e4add038
commit 51efc0765d
2 changed files with 66 additions and 5 deletions

View file

@ -1,5 +1,8 @@
<iframe <div
{{did-insert this.replaceIframeContents}} {{did-insert this.replaceIframeContents}}
{{did-update this.replaceIframeContents @html}} {{did-update this.replaceIframeContents @html}}
...attributes> ...attributes
</iframe> >
<iframe class="w-100 h-100" {{did-insert this.registerIframe}} {{on "load" this.didLoad}}></iframe>
<iframe class="w-100 h-100" {{did-insert this.registerIframe}} {{on "load" this.didLoad}}></iframe>
</div>

View file

@ -2,12 +2,70 @@ import Component from '@glimmer/component';
import {action} from '@ember/object'; import {action} from '@ember/object';
export default class GhHtmlIframeComponent extends Component { 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 @action
replaceIframeContents(iframe) { replaceIframeContents() {
if (iframe) { const iframe = this.iframes[this.toRenderIframe];
if (iframe && this.args.html) {
iframe.contentWindow.document.open(); iframe.contentWindow.document.open();
iframe.contentWindow.document.write(this.args.html); iframe.contentWindow.document.write(this.args.html);
iframe.contentWindow.document.close(); 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;
} }
} }
} }