From 375b5796d95774f152d5f85cb97dd3af8f307a59 Mon Sep 17 00:00:00 2001 From: Fabian Dill <Berserker66@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:28:42 +0200 Subject: [PATCH] WebHost: noscript faq and glossary (#4061) --- WebHostLib/misc.py | 23 +++++++-- WebHostLib/requirements.txt | 2 + WebHostLib/static/assets/faq.js | 51 ------------------- .../static/assets/faq/{faq_en.md => en.md} | 0 WebHostLib/static/assets/glossary.js | 51 ------------------- .../{faq/glossary_en.md => glossary/en.md} | 0 WebHostLib/templates/faq.html | 17 ------- WebHostLib/templates/glossary.html | 17 ------- WebHostLib/templates/markdown_document.html | 13 +++++ 9 files changed, 34 insertions(+), 140 deletions(-) delete mode 100644 WebHostLib/static/assets/faq.js rename WebHostLib/static/assets/faq/{faq_en.md => en.md} (100%) delete mode 100644 WebHostLib/static/assets/glossary.js rename WebHostLib/static/assets/{faq/glossary_en.md => glossary/en.md} (100%) delete mode 100644 WebHostLib/templates/faq.html delete mode 100644 WebHostLib/templates/glossary.html create mode 100644 WebHostLib/templates/markdown_document.html diff --git a/WebHostLib/misc.py b/WebHostLib/misc.py index 4784fcd9..1f86e210 100644 --- a/WebHostLib/misc.py +++ b/WebHostLib/misc.py @@ -5,6 +5,7 @@ from typing import Any, IO, Dict, Iterator, List, Tuple, Union import jinja2.exceptions from flask import request, redirect, url_for, render_template, Response, session, abort, send_from_directory from pony.orm import count, commit, db_session +from werkzeug.utils import secure_filename from worlds.AutoWorld import AutoWorldRegister from . import app, cache @@ -69,14 +70,28 @@ def tutorial_landing(): @app.route('/faq/<string:lang>/') @cache.cached() -def faq(lang): - return render_template("faq.html", lang=lang) +def faq(lang: str): + import markdown + with open(os.path.join(app.static_folder, "assets", "faq", secure_filename(lang)+".md")) as f: + document = f.read() + return render_template( + "markdown_document.html", + title="Frequently Asked Questions", + html_from_markdown=markdown.markdown(document, extensions=["mdx_breakless_lists"]), + ) @app.route('/glossary/<string:lang>/') @cache.cached() -def terms(lang): - return render_template("glossary.html", lang=lang) +def glossary(lang: str): + import markdown + with open(os.path.join(app.static_folder, "assets", "glossary", secure_filename(lang)+".md")) as f: + document = f.read() + return render_template( + "markdown_document.html", + title="Glossary", + html_from_markdown=markdown.markdown(document, extensions=["mdx_breakless_lists"]), + ) @app.route('/seed/<suuid:seed>') diff --git a/WebHostLib/requirements.txt b/WebHostLib/requirements.txt index c593cd63..20203870 100644 --- a/WebHostLib/requirements.txt +++ b/WebHostLib/requirements.txt @@ -9,3 +9,5 @@ bokeh>=3.1.1; python_version <= '3.8' bokeh>=3.4.3; python_version == '3.9' bokeh>=3.5.2; python_version >= '3.10' markupsafe>=2.1.5 +Markdown>=3.7 +mdx-breakless-lists>=1.0.1 diff --git a/WebHostLib/static/assets/faq.js b/WebHostLib/static/assets/faq.js deleted file mode 100644 index 1bf5e5a6..00000000 --- a/WebHostLib/static/assets/faq.js +++ /dev/null @@ -1,51 +0,0 @@ -window.addEventListener('load', () => { - const tutorialWrapper = document.getElementById('faq-wrapper'); - new Promise((resolve, reject) => { - const ajax = new XMLHttpRequest(); - ajax.onreadystatechange = () => { - if (ajax.readyState !== 4) { return; } - if (ajax.status === 404) { - reject("Sorry, the tutorial is not available in that language yet."); - return; - } - if (ajax.status !== 200) { - reject("Something went wrong while loading the tutorial."); - return; - } - resolve(ajax.responseText); - }; - ajax.open('GET', `${window.location.origin}/static/assets/faq/` + - `faq_${tutorialWrapper.getAttribute('data-lang')}.md`, true); - ajax.send(); - }).then((results) => { - // Populate page with HTML generated from markdown - showdown.setOption('tables', true); - showdown.setOption('strikethrough', true); - showdown.setOption('literalMidWordUnderscores', true); - tutorialWrapper.innerHTML += (new showdown.Converter()).makeHtml(results); - adjustHeaderWidth(); - - // Reset the id of all header divs to something nicer - for (const header of document.querySelectorAll('h1, h2, h3, h4, h5, h6')) { - const headerId = header.innerText.replace(/\s+/g, '-').toLowerCase(); - header.setAttribute('id', headerId); - header.addEventListener('click', () => { - window.location.hash = `#${headerId}`; - header.scrollIntoView(); - }); - } - - // Manually scroll the user to the appropriate header if anchor navigation is used - document.fonts.ready.finally(() => { - if (window.location.hash) { - const scrollTarget = document.getElementById(window.location.hash.substring(1)); - scrollTarget?.scrollIntoView(); - } - }); - }).catch((error) => { - console.error(error); - tutorialWrapper.innerHTML = - `<h2>This page is out of logic!</h2> - <h3>Click <a href="${window.location.origin}">here</a> to return to safety.</h3>`; - }); -}); diff --git a/WebHostLib/static/assets/faq/faq_en.md b/WebHostLib/static/assets/faq/en.md similarity index 100% rename from WebHostLib/static/assets/faq/faq_en.md rename to WebHostLib/static/assets/faq/en.md diff --git a/WebHostLib/static/assets/glossary.js b/WebHostLib/static/assets/glossary.js deleted file mode 100644 index 04a29200..00000000 --- a/WebHostLib/static/assets/glossary.js +++ /dev/null @@ -1,51 +0,0 @@ -window.addEventListener('load', () => { - const tutorialWrapper = document.getElementById('glossary-wrapper'); - new Promise((resolve, reject) => { - const ajax = new XMLHttpRequest(); - ajax.onreadystatechange = () => { - if (ajax.readyState !== 4) { return; } - if (ajax.status === 404) { - reject("Sorry, the glossary page is not available in that language yet."); - return; - } - if (ajax.status !== 200) { - reject("Something went wrong while loading the glossary."); - return; - } - resolve(ajax.responseText); - }; - ajax.open('GET', `${window.location.origin}/static/assets/faq/` + - `glossary_${tutorialWrapper.getAttribute('data-lang')}.md`, true); - ajax.send(); - }).then((results) => { - // Populate page with HTML generated from markdown - showdown.setOption('tables', true); - showdown.setOption('strikethrough', true); - showdown.setOption('literalMidWordUnderscores', true); - tutorialWrapper.innerHTML += (new showdown.Converter()).makeHtml(results); - adjustHeaderWidth(); - - // Reset the id of all header divs to something nicer - for (const header of document.querySelectorAll('h1, h2, h3, h4, h5, h6')) { - const headerId = header.innerText.replace(/\s+/g, '-').toLowerCase(); - header.setAttribute('id', headerId); - header.addEventListener('click', () => { - window.location.hash = `#${headerId}`; - header.scrollIntoView(); - }); - } - - // Manually scroll the user to the appropriate header if anchor navigation is used - document.fonts.ready.finally(() => { - if (window.location.hash) { - const scrollTarget = document.getElementById(window.location.hash.substring(1)); - scrollTarget?.scrollIntoView(); - } - }); - }).catch((error) => { - console.error(error); - tutorialWrapper.innerHTML = - `<h2>This page is out of logic!</h2> - <h3>Click <a href="${window.location.origin}">here</a> to return to safety.</h3>`; - }); -}); diff --git a/WebHostLib/static/assets/faq/glossary_en.md b/WebHostLib/static/assets/glossary/en.md similarity index 100% rename from WebHostLib/static/assets/faq/glossary_en.md rename to WebHostLib/static/assets/glossary/en.md diff --git a/WebHostLib/templates/faq.html b/WebHostLib/templates/faq.html deleted file mode 100644 index 76bdb96d..00000000 --- a/WebHostLib/templates/faq.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends 'pageWrapper.html' %} - -{% block head %} - {% include 'header/grassHeader.html' %} - <title>Frequently Asked Questions</title> - <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/markdown.css") }}" /> - <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js" - integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw==" - crossorigin="anonymous"></script> - <script type="application/ecmascript" src="{{ url_for('static', filename="assets/faq.js") }}"></script> -{% endblock %} - -{% block body %} - <div id="faq-wrapper" data-lang="{{ lang }}" class="markdown"> - <!-- Content generated by JavaScript --> - </div> -{% endblock %} diff --git a/WebHostLib/templates/glossary.html b/WebHostLib/templates/glossary.html deleted file mode 100644 index 921f6781..00000000 --- a/WebHostLib/templates/glossary.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends 'pageWrapper.html' %} - -{% block head %} - {% include 'header/grassHeader.html' %} - <title>Glossary</title> - <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/markdown.css") }}" /> - <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js" - integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw==" - crossorigin="anonymous"></script> - <script type="application/ecmascript" src="{{ url_for('static', filename="assets/glossary.js") }}"></script> -{% endblock %} - -{% block body %} - <div id="glossary-wrapper" data-lang="{{ lang }}" class="markdown"> - <!-- Content generated by JavaScript --> - </div> -{% endblock %} diff --git a/WebHostLib/templates/markdown_document.html b/WebHostLib/templates/markdown_document.html new file mode 100644 index 00000000..07b3c835 --- /dev/null +++ b/WebHostLib/templates/markdown_document.html @@ -0,0 +1,13 @@ +{% extends 'pageWrapper.html' %} + +{% block head %} + {% include 'header/grassHeader.html' %} + <title>{{ title }}</title> + <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/markdown.css") }}" /> +{% endblock %} + +{% block body %} + <div class="markdown"> + {{ html_from_markdown | safe}} + </div> +{% endblock %}