Add markdown utils
- External links open in a new tab - Clicking on image open an image modal
This commit is contained in:
parent
a75a080b9c
commit
d7cc620a0a
12 changed files with 51 additions and 16 deletions
|
@ -33,6 +33,7 @@ SITE_ID = 1
|
||||||
SITE_NAME = "LQDOJ"
|
SITE_NAME = "LQDOJ"
|
||||||
SITE_LONG_NAME = "LQDOJ: Le Quy Don Online Judge"
|
SITE_LONG_NAME = "LQDOJ: Le Quy Don Online Judge"
|
||||||
SITE_ADMIN_EMAIL = False
|
SITE_ADMIN_EMAIL = False
|
||||||
|
SITE_DOMAIN = "lqdoj.edu.vn"
|
||||||
|
|
||||||
DMOJ_REQUIRE_STAFF_2FA = True
|
DMOJ_REQUIRE_STAFF_2FA = True
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ import bleach
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from pymdownx import superfences
|
from pymdownx import superfences
|
||||||
|
from django.conf import settings
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from judge.markdown_extensions import YouTubeExtension, EmoticonExtension
|
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):
|
def markdown(value, lazy_load=False):
|
||||||
extensions = EXTENSIONS
|
extensions = EXTENSIONS
|
||||||
html = _markdown.markdown(
|
html = _markdown.markdown(
|
||||||
|
@ -106,13 +137,13 @@ def markdown(value, lazy_load=False):
|
||||||
|
|
||||||
if not html:
|
if not html:
|
||||||
html = escape(value)
|
html = escape(value)
|
||||||
if lazy_load:
|
|
||||||
soup = BeautifulSoup(html, features="html.parser")
|
soup = BeautifulSoup(html, features="html.parser")
|
||||||
for img in soup.findAll("img"):
|
if lazy_load:
|
||||||
if img.get("src"):
|
soup = _wrap_img_iframe_with_lazy_load(soup)
|
||||||
img["loading"] = "lazy"
|
|
||||||
for img in soup.findAll("iframe"):
|
soup = _wrap_images_with_featherlight(soup)
|
||||||
if img.get("src"):
|
soup = _open_external_links_in_new_tab(soup)
|
||||||
img["loading"] = "lazy"
|
|
||||||
html = str(soup)
|
html = str(soup)
|
||||||
|
|
||||||
return '<div class="md-typeset content-description">%s</div>' % html
|
return '<div class="md-typeset content-description">%s</div>' % html
|
||||||
|
|
|
@ -924,3 +924,8 @@ input::placeholder{
|
||||||
margin-right: 0.1em;
|
margin-right: 0.1em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.featherlight-content {
|
||||||
|
max-height: 80% !important;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
|
@ -475,7 +475,11 @@ function onWindowReady() {
|
||||||
|
|
||||||
$('a').click(function() {
|
$('a').click(function() {
|
||||||
var href = $(this).attr('href');
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -297,6 +297,7 @@
|
||||||
{% include "extra_js.html" %}
|
{% include "extra_js.html" %}
|
||||||
<script src="{{ static('common.js') }}"></script>
|
<script src="{{ static('common.js') }}"></script>
|
||||||
<script src="{{ static('libs/clipboard/tooltip.js') }}"></script>
|
<script src="{{ static('libs/clipboard/tooltip.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ static('libs/featherlight/featherlight.min.js') }}"></script>
|
||||||
<script>
|
<script>
|
||||||
moment.locale('{{ LANGUAGE_CODE }}');
|
moment.locale('{{ LANGUAGE_CODE }}');
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
|
|
||||||
{% compress js %}
|
{% compress js %}
|
||||||
{{ comment_form.media.js }}
|
{{ comment_form.media.js }}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block three_col_js %}
|
{% block three_col_js %}
|
||||||
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function changeTabParameter(newTab) {
|
function changeTabParameter(newTab) {
|
||||||
const url = new URL(window.location);
|
const url = new URL(window.location);
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.featherlight-content {
|
.featherlight-content {
|
||||||
border-radius: 10px;
|
|
||||||
height: 80%;
|
height: 80%;
|
||||||
width: 60%;
|
width: 60%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
window.big_input = (window.valid_files.length > 100);
|
window.big_input = (window.valid_files.length > 100);
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript" src="{{ static('jquery-ui.min.js') }}"></script>
|
<script type="text/javascript" src="{{ static('jquery-ui.min.js') }}"></script>
|
||||||
<script type="text/javascript" src="{{ static('libs/featherlight/featherlight.min.js') }}"></script>
|
|
||||||
<script type="text/javascript" src="{{ static('fine-uploader/jquery.fine-uploader.js') }}"></script>
|
<script type="text/javascript" src="{{ static('fine-uploader/jquery.fine-uploader.js') }}"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript" src="{{ static('libs/featherlight/featherlight.min.js') }}"></script>
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
{% block js_media %}
|
{% block js_media %}
|
||||||
{{ form.media.js }}
|
{{ form.media.js }}
|
||||||
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
|
|
||||||
<script type="text/javascript" src="{{ static('event.js') }}"></script>
|
<script type="text/javascript" src="{{ static('event.js') }}"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
{% compress js %}
|
{% compress js %}
|
||||||
<script src="{{ static('libs/featherlight/featherlight.min.js') }}" type="text/javascript"></script>
|
|
||||||
<script type="text/javascript" src="{{ static('libs/timezone-map/timezone-picker.js') }}"></script>
|
<script type="text/javascript" src="{{ static('libs/timezone-map/timezone-picker.js') }}"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
Loading…
Reference in a new issue