Viewer chaperon mode

Viewer now rewrites internal links so that opening them in a new
tab/window keeps the viewer around. Thus the viewer acts as a chaperon
for the users preventing them from finding themselves out of the
viewer's supervision. Of course there are ways to circumvent such
oversight, however it has always been the case with chaperons in all
cultures in all epochs.
This commit is contained in:
Veloman Yunkan
2025-09-01 12:31:41 +04:00
parent e2186cfb7b
commit 334ca0295e
2 changed files with 25 additions and 7 deletions

View File

@@ -10,6 +10,8 @@ let viewerState = {
uiLanguage: 'en',
};
const FULL_ROOT_URL = `${window.location.origin}${root}`;
function dropUserLang(query) {
const q = new URLSearchParams(query);
q.delete('userlang');
@@ -347,6 +349,12 @@ function onClickEvent(e) {
if (target !== null && "href" in target) {
const target_href = getRealHref(target);
const target_url = new URL(target_href, iframeDocument.location);
if ( target_url.href.startsWith(`${FULL_ROOT_URL}/viewer#`) &&
!linkShouldBeOpenedInANewWindow(target, e) ) {
contentIframe.contentWindow.parent.location = target_url;
e.preventDefault();
return;
}
const isExternalAppUrl = urlMustBeHandledByAnExternalApp(target_url);
if ( (isExternalAppUrl && !viewerSettings.linkBlockingEnabled)
|| goingToOpenALinkToAnUndisplayableResource(target_url) ) {
@@ -398,14 +406,24 @@ this.Element && function(ElementPrototype) {
}
}(Element.prototype);
function setup_external_link_blocker() {
setupEventHandler(contentIframe.contentDocument, 'a', 'click', onClickEvent);
}
////////////////////////////////////////////////////////////////////////////////
// End of external link blocking
////////////////////////////////////////////////////////////////////////////////
const internalUrlPrefix = `${FULL_ROOT_URL}/content/`;
function setup_chaperon_mode() {
setupEventHandler(contentIframe.contentDocument, 'a', 'click', onClickEvent);
const links = contentIframe.contentDocument.getElementsByTagName('a');
for ( const a of links ) {
// XXX: wombat's possible involvement with href not taken into account
if ( a.hasAttribute('href') && a.href.startsWith(internalUrlPrefix) ) {
const userUrl = a.href.substr(internalUrlPrefix.length);
a.href = `${root}/viewer#${userUrl}`;
}
}
}
let viewerSetupComplete = false;
function on_content_load() {
@@ -416,7 +434,7 @@ function on_content_load() {
if ( viewerSetupComplete ) {
handle_content_url_change();
}
setup_external_link_blocker();
setup_chaperon_mode();
}
function htmlDecode(input) {

View File

@@ -77,7 +77,7 @@ const ResourceCollection resources200Compressible{
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/taskbar.css" },
{ STATIC_CONTENT, "/ROOT%23%3F/skin/taskbar.css?cacheid=42e90cb9" },
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/viewer.js" },
{ STATIC_CONTENT, "/ROOT%23%3F/skin/viewer.js?cacheid=7f05bf6c" },
{ STATIC_CONTENT, "/ROOT%23%3F/skin/viewer.js?cacheid=05ef466b" },
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/fonts/Poppins.ttf" },
{ STATIC_CONTENT, "/ROOT%23%3F/skin/fonts/Poppins.ttf?cacheid=af705837" },
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/fonts/Roboto.ttf" },
@@ -338,7 +338,7 @@ R"EXPECTEDRESULT( <link type="text/css" href="./skin/kiwix.css?cacheid=b4e29e
<script type="text/javascript" src="./skin/polyfills.js?cacheid=a0e0343d"></script>
<script type="module" src="./skin/i18n.js?cacheid=e9a10ac1" defer></script>
<script type="text/javascript" src="./skin/languages.js?cacheid=08955948" defer></script>
<script type="text/javascript" src="./skin/viewer.js?cacheid=7f05bf6c" defer></script>
<script type="text/javascript" src="./skin/viewer.js?cacheid=05ef466b" defer></script>
<script type="text/javascript" src="./skin/autoComplete/autoComplete.min.js?cacheid=1191aaaf"></script>
const blankPageUrl = root + "/skin/blank.html?cacheid=6b1fa032";
<label for="kiwix_button_show_toggle"><img src="./skin/caret.png?cacheid=22b942b4" alt=""></label>