forked from DGNum/gestiojeux
Add markdown pages for customization by respos
This commit is contained in:
parent
ccd8ee9cc9
commit
d56d0b44f3
25 changed files with 221 additions and 60 deletions
|
@ -25,6 +25,7 @@ INSTALLED_APPS = [
|
||||||
"django.contrib.sessions",
|
"django.contrib.sessions",
|
||||||
"django.contrib.messages",
|
"django.contrib.messages",
|
||||||
"django.contrib.staticfiles",
|
"django.contrib.staticfiles",
|
||||||
|
"markdownx",
|
||||||
"haystack",
|
"haystack",
|
||||||
"mainsite",
|
"mainsite",
|
||||||
"inventory",
|
"inventory",
|
||||||
|
@ -80,6 +81,22 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||||
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
|
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Use markdown extensions
|
||||||
|
MARKDOWNX_MARKDOWN_EXTENSIONS = [
|
||||||
|
"markdown.extensions.extra",
|
||||||
|
"markdown.extensions.sane_lists",
|
||||||
|
"iconfonts",
|
||||||
|
"mainsite.markdown",
|
||||||
|
"inventory.markdown",
|
||||||
|
]
|
||||||
|
|
||||||
|
MARKDOWNX_MARKDOWN_EXTENSION_CONFIGS = {
|
||||||
|
"iconfonts": {
|
||||||
|
"prefix": "fa-",
|
||||||
|
"base": "fa",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Update the search database on save
|
# Update the search database on save
|
||||||
HAYSTACK_SIGNAL_PROCESSOR = "haystack.signals.RealtimeSignalProcessor"
|
HAYSTACK_SIGNAL_PROCESSOR = "haystack.signals.RealtimeSignalProcessor"
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ from django.conf.urls.static import static
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
|
path("markdownx/", include("markdownx.urls")),
|
||||||
path("inventory/", include("inventory.urls")),
|
path("inventory/", include("inventory.urls")),
|
||||||
path("auth/", include("gestiojeux_auth.urls")),
|
path("auth/", include("gestiojeux_auth.urls")),
|
||||||
path("", include("mainsite.urls")),
|
path("", include("mainsite.urls")),
|
||||||
|
|
52
inventory/markdown.py
Normal file
52
inventory/markdown.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import markdown
|
||||||
|
from django.template.loader import get_template
|
||||||
|
from .models import Category, Tag, Game
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryLinkProcessor(markdown.inlinepatterns.InlineProcessor):
|
||||||
|
model = None
|
||||||
|
pattern = None
|
||||||
|
context_object_name = "object"
|
||||||
|
template_name = None
|
||||||
|
|
||||||
|
def __init__(self, md):
|
||||||
|
super().__init__(self.pattern, md)
|
||||||
|
|
||||||
|
def handleMatch(self, m, data):
|
||||||
|
template = get_template(self.template_name)
|
||||||
|
object_instance = self.model.objects.get(slug=m.group(1))
|
||||||
|
html = template.render({self.context_object_name: object_instance})
|
||||||
|
placeholder = self.md.htmlStash.store(html)
|
||||||
|
return placeholder, m.start(0), m.end(0)
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryLinkProcessor(InventoryLinkProcessor):
|
||||||
|
model = Category
|
||||||
|
pattern = r"\[\[category:([\w-]+)\]\]"
|
||||||
|
context_object_name = "category"
|
||||||
|
template_name = "inventory/partials/category_item.html"
|
||||||
|
|
||||||
|
|
||||||
|
class TagLinkProcessor(InventoryLinkProcessor):
|
||||||
|
model = Tag
|
||||||
|
pattern = r"\[\[tag:([\w-]+)\]\]"
|
||||||
|
context_object_name = "tag"
|
||||||
|
template_name = "inventory/partials/tag_item.html"
|
||||||
|
|
||||||
|
|
||||||
|
class GameLinkProcessor(InventoryLinkProcessor):
|
||||||
|
model = Game
|
||||||
|
pattern = r"\[\[game:([\w-]+)\]\]"
|
||||||
|
context_object_name = "game"
|
||||||
|
template_name = "inventory/partials/game_item.html"
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryMarkdownExtension(markdown.extensions.Extension):
|
||||||
|
def extendMarkdown(self, md):
|
||||||
|
md.inlinePatterns.register(CategoryLinkProcessor(md), "category_link", 75)
|
||||||
|
md.inlinePatterns.register(TagLinkProcessor(md), "tag_link", 75)
|
||||||
|
md.inlinePatterns.register(GameLinkProcessor(md), "game_link", 75)
|
||||||
|
|
||||||
|
|
||||||
|
def makeExtension(**kwargs):
|
||||||
|
return InventoryMarkdownExtension(**kwargs)
|
|
@ -7,7 +7,7 @@
|
||||||
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} dans cette catégorie :
|
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} dans cette catégorie :
|
||||||
<ul>
|
<ul>
|
||||||
{% for game in game_list %}
|
{% for game in game_list %}
|
||||||
{% include "./partials/game_item.html" %}
|
<li>{% include "./partials/game_item.html" %}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
Il y a {{ category_list|length }} catégorie{{ category_list|pluralize }} de jeux :
|
Il y a {{ category_list|length }} catégorie{{ category_list|pluralize }} de jeux :
|
||||||
<ul>
|
<ul>
|
||||||
{% for category in category_list %}
|
{% for category in category_list %}
|
||||||
{% include "./partials/category_item.html" %}
|
<li>{% include "./partials/category_item.html" %}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} en salle jeux :
|
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} en salle jeux :
|
||||||
<ul>
|
<ul>
|
||||||
{% for game in game_list %}
|
{% for game in game_list %}
|
||||||
{% include "./partials/game_item.html" %}
|
<li>{% include "./partials/game_item.html" %}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
<li>
|
<a class="inventory_item category" href="{{ category.get_absolute_url }}">
|
||||||
<a href="{{ category.get_absolute_url }}"><i class="fa fa-bookmark" aria-hidden="true"></i> <span class="title">{{ category.name }}</span></a>
|
<i class="fa fa-bookmark" aria-hidden="true"></i> <span class="title">{{ category.name }}</span>
|
||||||
</li>
|
</a>
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
<li>
|
<a class="inventory_item game" href="{{ game.get_absolute_url }}">
|
||||||
<a href="{{ game.get_absolute_url }}">
|
<span class="title">{{ game.title }}</span>
|
||||||
<span class="title">{{ game.title }}</span>
|
<span class="details">
|
||||||
<div class="details">
|
<span><i class="fa fa-fw fa-users" aria-hidden="true"></i> {{ game.get_player_range }}</span>
|
||||||
<p><i class="fa fa-fw fa-users" aria-hidden="true"></i> {{ game.get_player_range }}</p>
|
{% if game.duration %}
|
||||||
<p><i class="fa fa-fw fa-clock-o" aria-hidden="true"></i> {{ game.duration }}
|
<span><i class="fa fa-fw fa-clock-o" aria-hidden="true"></i> {{ game.duration }}</span>
|
||||||
<p><i class="fa fa-fw fa-bookmark"></i> {{ game.category }}</p>
|
{% endif %}
|
||||||
{% for tag in game.tags.all %}
|
<span><i class="fa fa-fw fa-bookmark"></i> {{ game.category }}</span>
|
||||||
<p><i class="fa fa-fw fa-tag" aria-hidden="true"></i> {{ tag }}</p>
|
{% for tag in game.tags.all %}
|
||||||
{% endfor %}
|
<span><i class="fa fa-fw fa-tag" aria-hidden="true"></i> {{ tag }}</span>
|
||||||
{% if game.game_designer %}
|
{% endfor %}
|
||||||
<p><i class="fa fa-fw fa-wrench" aria-hidden="true"></i> {{ game.game_designer }}</p>
|
{% if game.game_designer %}
|
||||||
{% endif %}
|
<span><i class="fa fa-fw fa-wrench" aria-hidden="true"></i> {{ game.game_designer }}</span>
|
||||||
{% if game.illustrator %}
|
{% endif %}
|
||||||
<p><i class="fa fa-fw fa-paint-brush" aria-hidden="true"></i> {{ game.illustrator }}</p>
|
{% if game.illustrator %}
|
||||||
{% endif %}
|
<span><i class="fa fa-fw fa-paint-brush" aria-hidden="true"></i> {{ game.illustrator }}</span>
|
||||||
{% if game.editor %}
|
{% endif %}
|
||||||
<p><i class="fa fa-fw fa-cogs" aria-hidden="true"></i> {{ game.editor }}</p>
|
{% if game.editor %}
|
||||||
{% endif %}
|
<span><i class="fa fa-fw fa-cogs" aria-hidden="true"></i> {{ game.editor }}</span>
|
||||||
</div>
|
{% endif %}
|
||||||
</a>
|
</span>
|
||||||
</li>
|
</a>
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
<li>
|
<a class="inventory_item tag" href="{{ tag.get_absolute_url }}">
|
||||||
<a href="{{ tag.get_absolute_url }}"><i class="fa fa-tag" aria-hidden="true"></i> <span class="title">{{ tag.name }}</span></a>
|
<i class="fa fa-tag" aria-hidden="true"></i> <span class="title">{{ tag.name }}</span>
|
||||||
</li>
|
</a>
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{% for result in page_obj.object_list %}
|
{% for result in page_obj.object_list %}
|
||||||
|
<li>
|
||||||
{% if result.model_name == "game" %}
|
{% if result.model_name == "game" %}
|
||||||
{% include "./partials/game_item.html" with game=result.object %}
|
{% include "./partials/game_item.html" with game=result.object %}
|
||||||
{% elif result.model_name == "category" %}
|
{% elif result.model_name == "category" %}
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
{% elif result.model_name == "tag" %}
|
{% elif result.model_name == "tag" %}
|
||||||
{% include "./partials/tag_item.html" with tag=result.object %}
|
{% include "./partials/tag_item.html" with tag=result.object %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<li>Aucun résultat trouvé</li>
|
<li>Aucun résultat trouvé</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} marqué{{ game_list|pluralize }} avec ce tag :
|
Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} marqué{{ game_list|pluralize }} avec ce tag :
|
||||||
<ul>
|
<ul>
|
||||||
{% for game in game_list %}
|
{% for game in game_list %}
|
||||||
{% include "./partials/game_item.html" %}
|
<li>{% include "./partials/game_item.html" %}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
Il y a {{ tag_list|length }} tag{{ tag_list|pluralize }} dans la ludothèque :
|
Il y a {{ tag_list|length }} tag{{ tag_list|pluralize }} dans la ludothèque :
|
||||||
<ul>
|
<ul>
|
||||||
{% for tag in tag_list %}
|
{% for tag in tag_list %}
|
||||||
{% include "./partials/tag_item.html" %}
|
<li>{% include "./partials/tag_item.html" %}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
default_app_config = "mainsite.apps.MainsiteConfig"
|
|
@ -1,3 +1,5 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from .models import MarkdownPage
|
||||||
|
from markdownx.admin import MarkdownxModelAdmin
|
||||||
|
|
||||||
# Register your models here.
|
admin.site.register(MarkdownPage, MarkdownxModelAdmin)
|
||||||
|
|
|
@ -2,4 +2,5 @@ from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class MainsiteConfig(AppConfig):
|
class MainsiteConfig(AppConfig):
|
||||||
name = 'mainsite'
|
name = "mainsite"
|
||||||
|
verbose_name = "Site internet"
|
||||||
|
|
28
mainsite/markdown.py
Normal file
28
mainsite/markdown.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import markdown
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
class NbspPreprocessor(markdown.preprocessors.Preprocessor):
|
||||||
|
"""Replace regular spaces with non-breaking spaces within a text around relevant
|
||||||
|
symbols"""
|
||||||
|
|
||||||
|
NBSP_BEFORE = [":", "!", "?", "»", ":", ";", "—", "€"]
|
||||||
|
NBSP_AFTER = ["«", "—"]
|
||||||
|
|
||||||
|
def run(self, lines):
|
||||||
|
text = "\n".join(lines)
|
||||||
|
re_before = re.compile("(?: *\n *| +)([{}])".format("".join(self.NBSP_BEFORE)))
|
||||||
|
re_after = re.compile("([{}])(?: +| *\n *)".format("".join(self.NBSP_AFTER)))
|
||||||
|
|
||||||
|
text = re_before.sub(r" \1", text)
|
||||||
|
text = re_after.sub(r"\1 ", text)
|
||||||
|
return text.split("\n")
|
||||||
|
|
||||||
|
|
||||||
|
class MainSiteMarkdownExtension(markdown.extensions.Extension):
|
||||||
|
def extendMarkdown(self, md):
|
||||||
|
md.preprocessors.register(NbspPreprocessor(md), "nbsp", 10)
|
||||||
|
|
||||||
|
|
||||||
|
def makeExtension(**kwargs):
|
||||||
|
return MainSiteMarkdownExtension(**kwargs)
|
28
mainsite/migrations/0001_initial.py
Normal file
28
mainsite/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Generated by Django 3.1.2 on 2020-12-13 14:19
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import markdownx.models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='MarkdownPage',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('slug', models.SlugField(blank=True, help_text="Identifiant de la page qui se voit dans l'URL. Ne doit pas collisionner avec une page existante. Laisser vide pour la page d'accueil, requis sinon.", unique=True, verbose_name='Adresse de la page')),
|
||||||
|
('content', markdownx.models.MarkdownxField(verbose_name='Contenu')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'page Markdown',
|
||||||
|
'verbose_name_plural': 'pages Markdown',
|
||||||
|
'ordering': ['slug'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,3 +1,27 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.urls import reverse
|
||||||
|
from markdownx.models import MarkdownxField
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
|
class MarkdownPage(models.Model):
|
||||||
|
slug = models.SlugField(
|
||||||
|
blank=True,
|
||||||
|
unique=True,
|
||||||
|
verbose_name="Adresse de la page",
|
||||||
|
help_text="Identifiant de la page qui se voit dans l'URL. Ne doit pas collisionner avec une page existante. Laisser vide pour la page d'accueil, requis sinon.",
|
||||||
|
)
|
||||||
|
content = MarkdownxField(verbose_name="Contenu")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "page Markdown"
|
||||||
|
verbose_name_plural = "pages Markdown"
|
||||||
|
ordering = ["slug"]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.slug or "Page d'accueil"
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
if self.slug:
|
||||||
|
return reverse("mainsite:md_page", args=[self.slug])
|
||||||
|
else:
|
||||||
|
return reverse("mainsite:home")
|
||||||
|
|
|
@ -291,7 +291,7 @@ ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
li>a {
|
a.inventory_item {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
margin: 10px 5px;
|
margin: 10px 5px;
|
||||||
|
@ -309,10 +309,6 @@ li>a {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
gap: 5px 20px;
|
gap: 5px 20px;
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -440,29 +440,27 @@ ul {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
list-style-type: none; }
|
list-style-type: none; }
|
||||||
|
|
||||||
li > a {
|
a.inventory_item {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
margin: 10px 5px;
|
margin: 10px 5px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
text-decoration: none; }
|
text-decoration: none; }
|
||||||
li > a .title {
|
a.inventory_item .title {
|
||||||
text-decoration: underline #c9dbe0; }
|
text-decoration: underline #c9dbe0; }
|
||||||
li > a .details {
|
a.inventory_item .details {
|
||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
gap: 5px 20px; }
|
gap: 5px 20px; }
|
||||||
li > a .details p {
|
a.inventory_item:hover {
|
||||||
margin: 0; }
|
|
||||||
li > a:hover {
|
|
||||||
border-color: #51808c;
|
border-color: #51808c;
|
||||||
background-color: white; }
|
background-color: white; }
|
||||||
li > a:hover .title {
|
a.inventory_item:hover .title {
|
||||||
text-decoration-color: currentColor; }
|
text-decoration-color: currentColor; }
|
||||||
li > a:focus {
|
a.inventory_item:focus {
|
||||||
border-color: #51808c;
|
border-color: #51808c;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
box-shadow: 0 0 1.5px 1px #6bb8c4; }
|
box-shadow: 0 0 1.5px 1px #6bb8c4; }
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block "content" %}
|
|
||||||
<h1>Bienvenue en salle Jeux</h1>
|
|
||||||
Site d'inventaire et de gestion du club Jeux de l'ENS.
|
|
||||||
{% endblock %}
|
|
5
mainsite/templates/mainsite/markdown_page.html
Normal file
5
mainsite/templates/mainsite/markdown_page.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block "content" %}
|
||||||
|
{{ markdown_body }}
|
||||||
|
{% endblock %}
|
|
@ -1,8 +1,9 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from .views import HomepageView
|
from .views import MarkdownPageView
|
||||||
|
|
||||||
app_name = "mainsite"
|
app_name = "mainsite"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", HomepageView.as_view(), name="home"),
|
path("", MarkdownPageView.as_view(), {"slug": ""}, name="home"),
|
||||||
|
path("<slug:slug>/", MarkdownPageView.as_view(), name="md_page"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import DetailView
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
from markdownx.utils import markdownify
|
||||||
|
from .models import MarkdownPage
|
||||||
|
|
||||||
|
|
||||||
class HomepageView(TemplateView):
|
class MarkdownPageView(DetailView):
|
||||||
template_name = "mainsite/home.html"
|
model = MarkdownPage
|
||||||
|
template_name = "mainsite/markdown_page.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context["markdown_body"] = mark_safe(markdownify(self.object.content))
|
||||||
|
return context
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
Django
|
Django
|
||||||
django-autoslug
|
django-autoslug
|
||||||
|
django-markdownx
|
||||||
|
markdown-iconfonts
|
||||||
Pillow
|
Pillow
|
||||||
django-cas-ng
|
django-cas-ng
|
||||||
django-haystack
|
django-haystack
|
||||||
|
|
Loading…
Add table
Reference in a new issue