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

🐛 Fixed portal preview resize when using split front-end/admin URLs (#1980)

no issue

- switched to listening to Portal's `message` events that now include a height
- removes need to reach into Portal preview iframe contents which is blocked by browser security when working cross-origin
This commit is contained in:
Kevin Ansfield 2021-05-27 13:20:37 +01:00 committed by GitHub
parent c8f1fb5b45
commit 3d43964bcd
4 changed files with 28 additions and 39 deletions

View file

@ -3,6 +3,7 @@
src={{this.srcUrl}}
frameborder="0"
allowtransparency="true"
{{did-insert (optional @onInserted)}}
{{did-insert this.attachMessageListener}}
{{did-update this.resetSrcAttribute @guid}}
{{on "load" this.onLoad}}

View file

@ -62,11 +62,15 @@ export default class GhSiteIframeComponent extends Component {
attachMessageListener() {
if (typeof this.args.invisibleUntilLoaded === 'string') {
this.messageListener = (event) => {
if (this.isDestroying || this.isDestroyed) {
return;
}
const srcURL = new URL(this.srcUrl);
const originURL = new URL(event.origin);
if (originURL.origin === srcURL.origin) {
if (event.data === this.args.invisibleUntilLoaded) {
if (event.data === this.args.invisibleUntilLoaded || event.data.type === this.args.invisibleUntilLoaded) {
this.makeVisible.perform();
}
}

View file

@ -4,7 +4,6 @@ import {action} from '@ember/object';
import {currencies, getCurrencyOptions, getSymbol} from 'ghost-admin/utils/currency';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency-decorators';
import {timeout} from 'ember-concurrency';
import {tracked} from '@glimmer/tracking';
const CURRENCIES = currencies.map((currency) => {
@ -241,20 +240,36 @@ export default class MembersAccessController extends Controller {
newUrl.searchParams.set('v', this.portalPreviewGuid);
this.portalPreviewUrl = newUrl;
this.resizePortalPreviewTask.perform();
}
@action
portalPreviewLoaded(iframe) {
portalPreviewInserted(iframe) {
this.portalPreviewIframe = iframe;
this.resizePortalPreviewTask.perform();
if (!this.portalMessageListener) {
this.portalMessageListener = (event) => {
// don't resize membership portal preview when events fire in customize portal modal
if (this.showPortalSettings) {
return;
}
const resizeEvents = ['portal-ready', 'portal-preview-updated'];
if (resizeEvents.includes(event.data.type) && event.data.payload?.height) {
this.portalPreviewIframe.parentNode.style.height = `${event.data.payload.height}px`;
}
};
window.addEventListener('message', this.portalMessageListener, true);
}
}
@action
portalPreviewDestroyed() {
this.portalPreviewIframe = null;
this.resizePortalPreviewTask.cancelAll();
if (this.portalMessageListener) {
window.removeEventListener('message', this.portalMessageListener);
}
}
@task
@ -262,37 +277,6 @@ export default class MembersAccessController extends Controller {
return yield this.saveSettingsTask.perform({forceRefresh: true});
}
@task({restartable: true})
*resizePortalPreviewTask() {
if (this.portalPreviewIframe && this.portalPreviewIframe.contentWindow) {
yield timeout(100); // give time for portal to re-render
try {
const portalIframe = this.portalPreviewIframe.contentWindow.document.querySelector('#ghost-portal-root iframe');
if (!portalIframe) {
return;
}
portalIframe.contentWindow.document.body.style.overflow = 'hidden';
portalIframe.contentWindow.document.body.style['scrollbar-width'] = 'none';
const portalContainer = portalIframe.contentWindow.document.querySelector('.gh-portal-popup-container');
if (!portalContainer) {
return;
}
const height = portalContainer.clientHeight;
this.portalPreviewIframe.parentNode.style.height = `${height}px`;
} catch (e) {
if (e.name === 'SecurityError') {
// cross-origin blocked
return;
}
throw e;
}
}
}
async saveProduct() {
const isStripeConnected = this.settings.get('stripeConnectAccountId');
if (this.product && isStripeConnected) {

View file

@ -59,7 +59,7 @@
scrolling="no"
@src={{this.portalPreviewUrl}}
@invisibleUntilLoaded="portal-ready"
@onLoad={{this.portalPreviewLoaded}}
@onInserted={{this.portalPreviewInserted}}
@onDestroyed={{this.portalPreviewDestroyed}} />
{{/if}}
</div>