diff --git a/dmoj/settings.py b/dmoj/settings.py index d41ff8a..e379e3e 100644 --- a/dmoj/settings.py +++ b/dmoj/settings.py @@ -33,6 +33,7 @@ SITE_ID = 1 SITE_NAME = "LQDOJ" SITE_LONG_NAME = "LQDOJ: Le Quy Don Online Judge" SITE_ADMIN_EMAIL = False +SITE_DOMAIN = "lqdoj.edu.vn" DMOJ_REQUIRE_STAFF_2FA = True diff --git a/judge/markdown.py b/judge/markdown.py index f5295ed..80eb21a 100644 --- a/judge/markdown.py +++ b/judge/markdown.py @@ -3,6 +3,8 @@ import bleach from django.utils.html import escape from bs4 import BeautifulSoup from pymdownx import superfences +from django.conf import settings +from urllib.parse import urlparse from judge.markdown_extensions import YouTubeExtension, EmoticonExtension @@ -96,6 +98,35 @@ ALLOWED_ATTRS = [ ] +def _wrap_img_iframe_with_lazy_load(soup): + for img in soup.findAll("img"): + if img.get("src"): + img["loading"] = "lazy" + for img in soup.findAll("iframe"): + if img.get("src"): + img["loading"] = "lazy" + return soup + + +def _wrap_images_with_featherlight(soup): + for img in soup.findAll("img"): + if img.get("src"): + link = soup.new_tag("a", href=img["src"], **{"data-featherlight": "image"}) + img.wrap(link) + return soup + + +def _open_external_links_in_new_tab(soup): + domain = settings.SITE_DOMAIN.lower() + for a in soup.findAll("a", href=True): + href = a["href"] + if href.startswith("http://") or href.startswith("https://"): + link_domain = urlparse(href).netloc.lower() + if link_domain != domain: + a["target"] = "_blank" + return soup + + def markdown(value, lazy_load=False): extensions = EXTENSIONS html = _markdown.markdown( @@ -106,13 +137,13 @@ def markdown(value, lazy_load=False): if not html: html = escape(value) + + soup = BeautifulSoup(html, features="html.parser") if lazy_load: - soup = BeautifulSoup(html, features="html.parser") - for img in soup.findAll("img"): - if img.get("src"): - img["loading"] = "lazy" - for img in soup.findAll("iframe"): - if img.get("src"): - img["loading"] = "lazy" - html = str(soup) + soup = _wrap_img_iframe_with_lazy_load(soup) + + soup = _wrap_images_with_featherlight(soup) + soup = _open_external_links_in_new_tab(soup) + html = str(soup) + return '
%s
' % html diff --git a/resources/base.scss b/resources/base.scss index 50e7c0e..7dc8152 100644 --- a/resources/base.scss +++ b/resources/base.scss @@ -923,4 +923,9 @@ input::placeholder{ font-size: 22.5px; margin-right: 0.1em; } +} + +.featherlight-content { + max-height: 80% !important; + border-radius: 10px; } \ No newline at end of file diff --git a/resources/common.js b/resources/common.js index 8bff4e3..386c244 100644 --- a/resources/common.js +++ b/resources/common.js @@ -475,7 +475,11 @@ function onWindowReady() { $('a').click(function() { var href = $(this).attr('href'); - if (!href || href === '#' || href.startsWith("javascript")) { + var target = $(this).attr('target'); + if (!href || href === '#' || href.startsWith("javascript") || + $(this).attr("data-featherlight") || + target === "_blank" + ) { return; } diff --git a/templates/base.html b/templates/base.html index 9abaa1e..3067a87 100644 --- a/templates/base.html +++ b/templates/base.html @@ -297,6 +297,7 @@ {% include "extra_js.html" %} + {% compress js %} {{ comment_form.media.js }} - - {% endblock %} diff --git a/templates/ticket/ticket.html b/templates/ticket/ticket.html index 2693455..dad7b97 100644 --- a/templates/ticket/ticket.html +++ b/templates/ticket/ticket.html @@ -5,7 +5,6 @@ {% block js_media %} {{ form.media.js }} -