Skip to content

Commit

Permalink
Merge pull request #128 from collective/fix-url-nav
Browse files Browse the repository at this point in the history
Fix page navigation in iframe
  • Loading branch information
djay authored Aug 17, 2024
2 parents 18a2fa0 + 7707fa0 commit 5e006a9
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 92 deletions.
73 changes: 46 additions & 27 deletions examples/hydra-vue-f7/src/js/hydra.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,39 +35,58 @@ class Bridge {
}

if (window.self !== window.top) {
this.navigationHandler = (e) => {
const newUrl = new URL(e.destination.url);
console.log('newhash:', newUrl.hash, 'prevHash', this.currentUrl.hash);
if (
this.currentUrl === null ||
newUrl.hash !== this.currentUrl.hash ||
(this.currentUrl.pathname !== newUrl.pathname &&
this.currentUrl.origin === newUrl.origin)
) {
// This will set the listners for hashchange & pushstate
function detectNavigation(callback) {
let currentUrl = window.location.href;

function checkNavigation() {
const newUrl = window.location.href;
if (newUrl !== currentUrl) {
callback(currentUrl);
currentUrl = newUrl;
}
}

// Handle hash changes & popstate events (only happens when browser back/forward buttons is clicked)
window.addEventListener('hashchange', checkNavigation);
window.addEventListener('popstate', checkNavigation);

// Intercept pushState and replaceState to detect navigation changes
const originalPushState = window.history.pushState;
window.history.pushState = function (...args) {
originalPushState.apply(this, args);
checkNavigation();
};

const originalReplaceState = window.history.replaceState;
window.history.replaceState = function (...args) {
originalReplaceState.apply(this, args);
checkNavigation();
};
}

detectNavigation((currentUrl) => {
const currentUrlObj = new URL(currentUrl);
if (window.location.pathname !== currentUrlObj.pathname) {
window.parent.postMessage(
{
type: 'URL_CHANGE',
url: newUrl.href,
isRoutingWithHash:
newUrl.hash !== this.currentUrl?.hash &&
newUrl.hash !== '' &&
newUrl.hash.startsWith('#/!'),
type: 'PATH_CHANGE',
path: window.location.pathname,
},
this.adminOrigin,
);
} else if (window.location.hash !== currentUrlObj.hash) {
const hash = window.location.hash;
const i = hash.indexOf('/');
window.parent.postMessage(
{
type: 'PATH_CHANGE',
path: i !== -1 ? hash.slice(i) || '/' : '/',
},
this.adminOrigin,
);
this.currentUrl = newUrl;
} else if (
this.currentUrl !== null &&
this.currentUrl.origin !== newUrl.origin
) {
e.preventDefault();
window.open(newUrl.href, '_blank').focus();
}
};

// Ensure we don't add multiple listeners
window.navigation.removeEventListener('navigate', this.navigationHandler);
window.navigation.addEventListener('navigate', this.navigationHandler);
});

// Get the access token from the URL
const url = new URL(window.location.href);
Expand Down
71 changes: 46 additions & 25 deletions packages/hydra-js/hydra.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,37 +35,58 @@ class Bridge {
}

if (window.self !== window.top) {
this.navigationHandler = (e) => {
const newUrl = new URL(e.destination.url);
if (
this.currentUrl === null ||
newUrl.hash !== this.currentUrl.hash ||
(this.currentUrl.pathname !== newUrl.pathname &&
this.currentUrl.origin === newUrl.origin)
) {
// This will set the listners for hashchange & pushstate
function detectNavigation(callback) {
let currentUrl = window.location.href;

function checkNavigation() {
const newUrl = window.location.href;
if (newUrl !== currentUrl) {
callback(currentUrl);
currentUrl = newUrl;
}
}

// Handle hash changes & popstate events (only happens when browser back/forward buttons is clicked)
window.addEventListener('hashchange', checkNavigation);
window.addEventListener('popstate', checkNavigation);

// Intercept pushState and replaceState to detect navigation changes
const originalPushState = window.history.pushState;
window.history.pushState = function (...args) {
originalPushState.apply(this, args);
checkNavigation();
};

const originalReplaceState = window.history.replaceState;
window.history.replaceState = function (...args) {
originalReplaceState.apply(this, args);
checkNavigation();
};
}

detectNavigation((currentUrl) => {
const currentUrlObj = new URL(currentUrl);
if (window.location.pathname !== currentUrlObj.pathname) {
window.parent.postMessage(
{
type: 'URL_CHANGE',
url: newUrl.href,
isRoutingWithHash:
newUrl.hash !== this.currentUrl?.hash &&
newUrl.hash.startsWith('#!'),
type: 'PATH_CHANGE',
path: window.location.pathname,
},
this.adminOrigin,
);
} else if (window.location.hash !== currentUrlObj.hash) {
const hash = window.location.hash;
const i = hash.indexOf('/');
window.parent.postMessage(
{
type: 'PATH_CHANGE',
path: i !== -1 ? hash.slice(i) || '/' : '/',
},
this.adminOrigin,
);
this.currentUrl = newUrl;
} else if (
this.currentUrl !== null &&
this.currentUrl.origin !== newUrl.origin
) {
e.preventDefault();
window.open(newUrl.href, '_blank').focus();
}
};

// Ensure we don't add multiple listeners
window.navigation.removeEventListener('navigate', this.navigationHandler);
window.navigation.addEventListener('navigate', this.navigationHandler);
});

// Get the access token from the URL
const url = new URL(window.location.href);
Expand Down
57 changes: 20 additions & 37 deletions packages/volto-hydra/src/components/Iframe/View.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ import {
} from '../../utils/allowedBlockList';
import toggleMark from '../../utils/toggleMark';

const addQueryParam = (url, params) => {
const addUrlParams = (url, qParams, pathname) => {
const newUrl = new URL(url);
for (const [key, value] of Object.entries(params)) {
for (const [key, value] of Object.entries(qParams)) {
newUrl.searchParams.set(key, value);
}
newUrl.pathname = pathname;
return newUrl.toString();
};

Expand All @@ -42,14 +43,19 @@ const addQueryParam = (url, params) => {
const getUrlWithAdminParams = (url, token) => {
return typeof window !== 'undefined'
? window.location.pathname.endsWith('/edit')
? addQueryParam(
`${url}${window.location.pathname.replace('/edit', '')}`,
? addUrlParams(
`${url}`,
{ access_token: token, _edit: true },
`${window.location.pathname.replace('/edit', '')}`,
)
: addUrlParams(
`${url}`,
{
access_token: token,
_edit: false,
},
`${window.location.pathname}`,
)
: addQueryParam(`${url}${window.location.pathname}`, {
access_token: token,
_edit: false,
})
: null;
};

Expand Down Expand Up @@ -112,6 +118,8 @@ const Iframe = (props) => {
urlFromEnv[0];

useEffect(() => {
console.log('settinf iframe url with token');

setIframeSrc(getUrlWithAdminParams(u, token));
u && Cookies.set('iframe_url', u, { expires: 7 });
}, [token, u]);
Expand Down Expand Up @@ -150,29 +158,6 @@ const Iframe = (props) => {
onChangeFormData(newFormData);
};
//---------------------------
/**
* Handle the navigation to a new URL
* @param {URL} givenUrlObject
* @param {Boolean} isRoutingWithHash
*/
const handleNavigateToUrl = useCallback(
(givenUrlObject, isRoutingWithHash) => {
if (!isValidUrl(givenUrlObject.href)) {
return;
}
// Update adminUI URL with the new URL
const hash = givenUrlObject.hash;
if (isRoutingWithHash) {
const pathname = hash.replace('#/!', '');
history.push(`${pathname === '' ? '/' : pathname}`);
} else {
history.push(
`${givenUrlObject.pathname === '' ? '/' : givenUrlObject.pathname}`,
);
}
},
[history],
);

useEffect(() => {
//----------------Experimental----------------
Expand All @@ -198,11 +183,9 @@ const Iframe = (props) => {
}
const { type } = event.data;
switch (type) {
case 'URL_CHANGE': // URL change from the iframe
handleNavigateToUrl(
new URL(event.data.url),
event.data.isRoutingWithHash,
);
case 'PATH_CHANGE': // PATH change from the iframe
history.push(event.data.path);

break;

case 'OPEN_SETTINGS':
Expand Down Expand Up @@ -306,7 +289,7 @@ const Iframe = (props) => {
dispatch,
form,
form?.blocks,
handleNavigateToUrl,
history,
history.location.pathname,
iframeSrc,
onChangeFormData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ class PersonalPreferences extends Component {
);
// Check if the URL is typed in or Selected from dropdown
if (data.urlCheck) {
// Custom URL is given
if (!isValidUrl(data.url)) {
// Check if the URL is valid
toast.error(
Expand All @@ -136,14 +137,15 @@ class PersonalPreferences extends Component {
return;
}
const url = new URL(data.url);
this.props.setFrontendPreviewUrl(url.href);
const urlList = [...new Set([this.urls, url])];
this.props.setFrontendPreviewUrl(url.origin);
const urlList = [...new Set([this.urls, url.origin])];
this.props.cookies.set('saved_urls', urlList.join(','), {
expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 Days
});
} else {
// URL is selected from the dropdown
const url = new URL(data.urls);
this.props.setFrontendPreviewUrl(url.href);
this.props.setFrontendPreviewUrl(url.origin);
}
this.props.closeMenu();
}
Expand Down

0 comments on commit 5e006a9

Please sign in to comment.