diff --git a/src/server/response.cpp b/src/server/response.cpp
index df0517e92..ddda140ac 100644
--- a/src/server/response.cpp
+++ b/src/server/response.cpp
@@ -321,17 +321,6 @@ void print_response_info(int retCode, MHD_Response* response)
}
-void ContentResponse::inject_externallinks_blocker()
-{
- kainjow::mustache::data data;
- data.set("root", m_root);
- auto script_tag = render_template(RESOURCE::templates::external_blocker_part_html, data);
- m_content = prependToFirstOccurence(
- m_content,
- "",
- script_tag);
-}
-
void ContentResponse::inject_root_link(){
m_content = prependToFirstOccurence(
m_content,
@@ -369,10 +358,6 @@ ContentResponse::create_mhd_response(const RequestContext& request)
{
if (contentDecorationAllowed()) {
inject_root_link();
-
- if (m_blockExternalLinks) {
- inject_externallinks_blocker();
- }
}
const bool isCompressed = can_compress(request) && compress(m_content);
diff --git a/src/server/response.h b/src/server/response.h
index ff78ff0a7..a19079b64 100644
--- a/src/server/response.h
+++ b/src/server/response.h
@@ -103,7 +103,6 @@ class ContentResponse : public Response {
private:
MHD_Response* create_mhd_response(const RequestContext& request);
- void inject_externallinks_blocker();
void inject_root_link();
bool can_compress(const RequestContext& request) const;
bool contentDecorationAllowed() const;
diff --git a/static/resources_list.txt b/static/resources_list.txt
index 6696343f8..5e1b30f73 100644
--- a/static/resources_list.txt
+++ b/static/resources_list.txt
@@ -12,7 +12,6 @@ skin/taskbar.css
skin/index.css
skin/fonts/Poppins.ttf
skin/fonts/Roboto.ttf
-skin/block_external.js
skin/search_results.css
skin/blank.html
skin/viewer.js
@@ -23,7 +22,6 @@ templates/error.html
templates/error.xml
templates/index.html
templates/suggestion.json
-templates/external_blocker_part.html
templates/captured_external.html
templates/catalog_entries.xml
templates/catalog_v2_root.xml
diff --git a/static/skin/block_external.js b/static/skin/block_external.js
deleted file mode 100644
index 6bc32baec..000000000
--- a/static/skin/block_external.js
+++ /dev/null
@@ -1,74 +0,0 @@
-const root = document.querySelector( `link[type='root']` ).getAttribute("href");
-// `block_path` variable used by openzim/warc2zim to detect whether URL blocking is enabled or not
-var block_path = `${root}/catch/external`;
-// called only on external links
-function capture_event(e, target) { target.setAttribute("href", encodeURI(block_path + "?source=" + target.href)); }
-
-// called on all link clicks. filters external and call capture_event
-function on_click_event(e) {
- var target = findParent("a", e.target);
- if (target !== null && "href" in target) {
- var href = target.href;
- if (window.location.pathname.indexOf(block_path) == 0) // already in catch page
- return;
- if (href.indexOf(window.location.origin) == 0)
- return;
- if (href.substr(0, 2) == "//")
- return capture_event(e, target);
- if (href.substr(0, 5) == "http:")
- return capture_event(e, target);
- if (href.substr(0, 6) == "https:")
- return capture_event(e, target);
- return;
- }
-}
-
-// script entrypoint (called on document ready)
-function run() { live('a', 'click', on_click_event); }
-
-// find first parent with tagname
-function findParent(tagname, el) {
- while (el) {
- if ((el.nodeName || el.tagName).toLowerCase() === tagname.toLowerCase()) {
- return el;
- }
- el = el.parentNode;
- }
- return null;
-}
-
-// matches polyfill
-this.Element && function(ElementPrototype) {
- ElementPrototype.matches = ElementPrototype.matches ||
- ElementPrototype.matchesSelector ||
- ElementPrototype.webkitMatchesSelector ||
- ElementPrototype.msMatchesSelector ||
- function(selector) {
- var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1;
- while (nodes[++i] && nodes[i] != node);
- return !!nodes[i];
- }
-}(Element.prototype);
-
-// helper for enabling IE 8 event bindings
-function addEvent(el, type, handler) {
- if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler);
-}
-
-// live binding helper using matchesSelector
-function live(selector, event, callback, context) {
- addEvent(context || document, event, function(e) {
- var found, el = e.target || e.srcElement;
- while (el && el.matches && el !== context && !(found = el.matches(selector))) el = el.parentElement;
- if (found) callback.call(el, e);
- });
-}
-
-// in case the document is already rendered
-if (document.readyState!='loading') run();
-// modern browsers
-else if (document.addEventListener) document.addEventListener('DOMContentLoaded', run);
-// IE <= 8
-else document.attachEvent('onreadystatechange', function(){
- if (document.readyState=='complete') run();
-});
diff --git a/static/skin/viewer.js b/static/skin/viewer.js
index 971c21220..021c05e0f 100644
--- a/static/skin/viewer.js
+++ b/static/skin/viewer.js
@@ -179,6 +179,88 @@ function handle_content_url_change() {
updateCurrentBookIfNeeded(newHash);
};
+////////////////////////////////////////////////////////////////////////////////
+// External link blocking
+////////////////////////////////////////////////////////////////////////////////
+
+function matchingAncestorElement(el, context, selector) {
+ while (el && el.matches && el !== context) {
+ if ( el.matches(selector) )
+ return el;
+ el = el.parentElement;
+ }
+ return null;
+}
+
+const block_path = `${root}/catch/external`;
+
+function blockLink(target) {
+ const encodedHref = encodeURIComponent(target.href);
+ target.setAttribute("href", block_path + "?source=" + encodedHref);
+ target.setAttribute("target", "_top");
+}
+
+function isExternalUrl(url) {
+ if ( url.startsWith(window.location.origin) )
+ return false;
+
+ return url.startsWith("//")
+ || url.startsWith("http:")
+ || url.startsWith("https:");
+}
+
+function onClickEvent(e) {
+ const iframeDocument = contentIframe.contentDocument;
+ const target = matchingAncestorElement(e.target, iframeDocument, "a");
+ if (target !== null && "href" in target) {
+ if ( isExternalUrl(target.href) )
+ return blockLink(target);
+ }
+}
+
+// helper for enabling IE 8 event bindings
+function addEventHandler(el, eventType, handler) {
+ if (el.attachEvent)
+ el.attachEvent('on'+eventType, handler);
+ else
+ el.addEventListener(eventType, handler);
+}
+
+function setupEventHandler(context, selector, eventType, callback) {
+ addEventHandler(context, eventType, function(e) {
+ const eventElement = e.target || e.srcElement;
+ const el = matchingAncestorElement(eventElement, context, selector);
+ if (el)
+ callback.call(el, e);
+ });
+}
+
+// matches polyfill
+this.Element && function(ElementPrototype) {
+ ElementPrototype.matches = ElementPrototype.matches ||
+ ElementPrototype.matchesSelector ||
+ ElementPrototype.webkitMatchesSelector ||
+ ElementPrototype.msMatchesSelector ||
+ function(selector) {
+ var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1;
+ while (nodes[++i] && nodes[i] != node);
+ return !!nodes[i];
+ }
+}(Element.prototype);
+
+function setup_external_link_blocker() {
+ setupEventHandler(contentIframe.contentDocument, 'a', 'click', onClickEvent);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// End of external link blocking
+////////////////////////////////////////////////////////////////////////////////
+
+function on_content_load() {
+ handle_content_url_change();
+ setup_external_link_blocker();
+}
+
window.onresize = handle_visual_viewport_change;
window.onhashchange = handle_location_hash_change;
diff --git a/static/templates/external_blocker_part.html b/static/templates/external_blocker_part.html
deleted file mode 100644
index 6bb0a0c21..000000000
--- a/static/templates/external_blocker_part.html
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/static/viewer.html b/static/viewer.html
index 7948cd17c..51667ffc2 100644
--- a/static/viewer.html
+++ b/static/viewer.html
@@ -56,7 +56,7 @@
diff --git a/test/server.cpp b/test/server.cpp
index 234890d2a..874b6cf36 100644
--- a/test/server.cpp
+++ b/test/server.cpp
@@ -46,7 +46,6 @@ const ResourceCollection resources200Compressible{
{ WITH_ETAG, "/ROOT/skin/autoComplete.min.js" },
{ WITH_ETAG, "/ROOT/skin/css/autoComplete.css" },
{ WITH_ETAG, "/ROOT/skin/taskbar.css" },
- { WITH_ETAG, "/ROOT/skin/block_external.js" },
{ NO_ETAG, "/ROOT/catalog/search" },