Skip to content

Commit 835d607

Browse files
committed
feat: use referre in an iframe for resolving relative paths
1 parent b4c3c41 commit 835d607

2 files changed

Lines changed: 33 additions & 7 deletions

File tree

packages/scratch-gui/src/lib/fetch-project-file.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
* @returns {Promise<object>} Normalized project file object
66
*/
77
const fetchProjectFile = async function (url) {
8-
// Resolve the project file URL against the current page location
9-
const absoluteUrl = new URL(url, window.location.href).href;
8+
// Use document.referrer as base when in an iframe, otherwise fall back to page location
9+
const base = document.referrer || window.location.href;
10+
const absoluteUrl = new URL(url, base).href;
1011

1112
const response = await fetch(absoluteUrl);
1213
if (!response.ok) {

packages/scratch-gui/src/lib/project-file-hoc.jsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ const EXTERNAL_DECK_ID = '__external__';
3131
*/
3232
const isUrl = value => /^https?:\/\//.test(value) || value.startsWith('/') || value.startsWith('./');
3333

34+
// Resolve a relative URL against document.referrer (iframe) or window.location.href
35+
const resolveUrl = url => {
36+
if (!url) return url;
37+
if (/^https?:\/\//.test(url)) return url;
38+
const base = document.referrer || window.location.href;
39+
return new URL(url, base).href;
40+
};
41+
3442
const ProjectFileHOC = function (WrappedComponent) {
3543
class ProjectFileComponent extends React.Component {
3644
constructor (props) {
@@ -46,16 +54,17 @@ const ProjectFileHOC = function (WrappedComponent) {
4654
if (queryParams.project) {
4755
const value = queryParams.project;
4856
if (isUrl(value)) {
49-
this.setState({projectFileUrl: value});
50-
if (value.endsWith('.sb3')) {
57+
const resolvedValue = resolveUrl(value);
58+
this.setState({projectFileUrl: resolvedValue});
59+
if (resolvedValue.endsWith('.sb3')) {
5160
// Claim the loading state to prevent the default project from loading
5261
this.props.onRequestProjectUpload(this.props.loadingState);
53-
this.props.onSetProjectFile({sb3: value, title: ''});
62+
this.props.onSetProjectFile({sb3: resolvedValue, title: ''});
5463
if (this.props.vm) {
55-
this.loadSb3(value);
64+
this.loadSb3(resolvedValue);
5665
}
5766
} else {
58-
this.loadProjectFile(value);
67+
this.loadProjectFile(resolvedValue);
5968
}
6069
} else {
6170
// Treat as base64-encoded JSON
@@ -65,6 +74,22 @@ const ProjectFileHOC = function (WrappedComponent) {
6574
if (!projectFile.title || typeof projectFile.title !== 'string') {
6675
throw new Error('Project file must have a "title" string field');
6776
}
77+
// Resolve relative URLs against referrer when in an iframe
78+
if (projectFile.sb3) {
79+
projectFile.sb3 = resolveUrl(projectFile.sb3);
80+
}
81+
if (Array.isArray(projectFile.steps)) {
82+
projectFile.steps = projectFile.steps.map(step => {
83+
const resolved = Object.assign({}, step);
84+
if (resolved.image) {
85+
resolved.image = resolveUrl(resolved.image);
86+
}
87+
if (resolved.video) {
88+
resolved.video = resolveUrl(resolved.video);
89+
}
90+
return resolved;
91+
});
92+
}
6893
this.props.onSetProjectFile(projectFile);
6994
if (projectFile.sb3 && this.props.vm) {
7095
this.loadSb3(projectFile.sb3);

0 commit comments

Comments
 (0)