Fixed external links in the viewer iframe

Before this fix clicking an external link in the viewer iframe had no
effect (other than an error being reported in the browser dev tools
console) because the attempt to navigate the top browser context was
suppressed due to sandboxing.

A workaround is to let the external link blocker page to be loaded in the
viewer iframe and then detect that situation and handle it in the viewer JS
code.

This commit makes external links clickable but (temporarily)
handles them by unconditionally displaying the confirmation page (as if
kiwix-serve has been started with the --blockexternal option). This will
be fixed shortly.

A small defect is that the browsing history entry preceding the external
resource access confirmation page is duplicated.
This commit is contained in:
Veloman Yunkan 2023-05-09 16:28:59 +04:00
parent deb02d92e2
commit 9c4c37f183
2 changed files with 24 additions and 9 deletions

View File

@ -23,7 +23,7 @@ function userUrl2IframeUrl(url) {
} }
function getBookFromUserUrl(url) { function getBookFromUserUrl(url) {
if ( url == '' ) { if ( url == '' || url.startsWith('catch/external?') ) {
return null; return null;
} }
@ -131,6 +131,10 @@ function iframeUrl2UserUrl(url, query) {
return ''; return '';
} }
if ( url == `${root}/catch/external` ) {
return `catch/external${query}`;
}
if ( url == `${root}/search` ) { if ( url == `${root}/search` ) {
return `search${query}`; return `search${query}`;
} }
@ -224,8 +228,12 @@ function handle_content_url_change() {
const iframeContentUrl = iframeLocation.pathname; const iframeContentUrl = iframeLocation.pathname;
const iframeContentQuery = iframeLocation.search; const iframeContentQuery = iframeLocation.search;
const newHash = iframeUrl2UserUrl(iframeContentUrl, iframeContentQuery); const newHash = iframeUrl2UserUrl(iframeContentUrl, iframeContentQuery);
if ( newHash.startsWith('catch/external?') ) {
handleInterceptedExternalLink(newHash);
} else {
history.replaceState(viewerState, null, makeURL(location.search, newHash)); history.replaceState(viewerState, null, makeURL(location.search, newHash));
updateCurrentBookIfNeeded(newHash); updateCurrentBookIfNeeded(newHash);
}
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -262,13 +270,10 @@ function onClickEvent(e) {
const target = matchingAncestorElement(e.target, iframeDocument, "a"); const target = matchingAncestorElement(e.target, iframeDocument, "a");
if (target !== null && "href" in target) { if (target !== null && "href" in target) {
if ( isExternalUrl(target.href) ) { if ( isExternalUrl(target.href) ) {
target.setAttribute("target", "_top");
if ( viewerSettings.linkBlockingEnabled ) {
return blockLink(target); return blockLink(target);
} }
} }
} }
}
// helper for enabling IE 8 event bindings // helper for enabling IE 8 event bindings
function addEventHandler(el, eventType, handler) { function addEventHandler(el, eventType, handler) {
@ -304,6 +309,16 @@ function setup_external_link_blocker() {
setupEventHandler(contentIframe.contentDocument, 'a', 'click', onClickEvent); setupEventHandler(contentIframe.contentDocument, 'a', 'click', onClickEvent);
} }
function handleInterceptedExternalLink(catchExternalUrl) {
// The external link blocking page was loaded in the viewer iframe.
// We need to get rid of the viewer taskbar and display the confirmation
// page in the top frame.
const urlpath = `${root}/` + catchExternalUrl;
history.back(); // drop from the browsing history the state where the
// external link catcher page is loaded in the iframe ...
window.location = urlpath; // ... and load it in the top frame instead
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// End of external link blocking // End of external link blocking
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -73,7 +73,7 @@ const ResourceCollection resources200Compressible{
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/taskbar.css" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/taskbar.css" },
{ STATIC_CONTENT, "/ROOT%23%3F/skin/taskbar.css?cacheid=bbdaf425" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/taskbar.css?cacheid=bbdaf425" },
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/viewer.js" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/viewer.js" },
{ STATIC_CONTENT, "/ROOT%23%3F/skin/viewer.js?cacheid=b9a574d4" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/viewer.js?cacheid=202f8641" },
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/fonts/Poppins.ttf" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/fonts/Poppins.ttf" },
{ STATIC_CONTENT, "/ROOT%23%3F/skin/fonts/Poppins.ttf?cacheid=af705837" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/fonts/Poppins.ttf?cacheid=af705837" },
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/fonts/Roboto.ttf" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/fonts/Roboto.ttf" },
@ -312,7 +312,7 @@ R"EXPECTEDRESULT( <link type="text/css" href="./skin/taskbar.css?cacheid=bbda
<link type="text/css" href="./skin/css/autoComplete.css?cacheid=08951e06" rel="Stylesheet" /> <link type="text/css" href="./skin/css/autoComplete.css?cacheid=08951e06" rel="Stylesheet" />
<script type="module" src="./skin/i18n.js?cacheid=2cf0f8c5" defer></script> <script type="module" src="./skin/i18n.js?cacheid=2cf0f8c5" defer></script>
<script type="text/javascript" src="./skin/languages.js?cacheid=b00b12db" defer></script> <script type="text/javascript" src="./skin/languages.js?cacheid=b00b12db" defer></script>
<script type="text/javascript" src="./skin/viewer.js?cacheid=b9a574d4" defer></script> <script type="text/javascript" src="./skin/viewer.js?cacheid=202f8641" defer></script>
<script type="text/javascript" src="./skin/autoComplete.min.js?cacheid=1191aaaf"></script> <script type="text/javascript" src="./skin/autoComplete.min.js?cacheid=1191aaaf"></script>
const blankPageUrl = root + "/skin/blank.html?cacheid=6b1fa032"; const blankPageUrl = root + "/skin/blank.html?cacheid=6b1fa032";
<img src="./skin/langSelector.svg?cacheid=00b59961"> <img src="./skin/langSelector.svg?cacheid=00b59961">