feat(core): Ajoute les nouveaux modèles de fiches Réponse + permet leur saisie depuis le ModelAdmin des fiches Question
Parent
c5d6953564
révision
eea8773cfa
|
@ -0,0 +1,73 @@
|
|||
'use strict';
|
||||
|
||||
{
|
||||
function initTinyMCE(el) {
|
||||
if (el.closest('.empty-form') === null) { // Don't do empty inlines
|
||||
var mce_conf = JSON.parse(el.dataset.mceConf);
|
||||
// There is no way to pass a JavaScript function as an option
|
||||
// because all options are serialized as JSON.
|
||||
const fns = [
|
||||
'color_picker_callback',
|
||||
'file_browser_callback',
|
||||
'file_picker_callback',
|
||||
'images_dataimg_filter',
|
||||
'images_upload_handler',
|
||||
'paste_postprocess',
|
||||
'paste_preprocess',
|
||||
'setup',
|
||||
'urlconverter_callback',
|
||||
];
|
||||
fns.forEach((fn_name) => {
|
||||
if (typeof mce_conf[fn_name] != 'undefined') {
|
||||
if (mce_conf[fn_name].includes('(')) {
|
||||
mce_conf[fn_name] = eval('(' + mce_conf[fn_name] + ')');
|
||||
}
|
||||
else {
|
||||
mce_conf[fn_name] = window[mce_conf[fn_name]];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const id = el.id;
|
||||
if ('elements' in mce_conf && mce_conf['mode'] == 'exact') {
|
||||
mce_conf['elements'] = id;
|
||||
}
|
||||
if (el.dataset.mceGzConf) {
|
||||
tinyMCE_GZ.init(JSON.parse(el.dataset.mceGzConf));
|
||||
}
|
||||
if (!tinyMCE.get(id)) {
|
||||
tinyMCE.init(mce_conf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initializeTinyMCE(element, formsetName) {
|
||||
Array.from(element.querySelectorAll('.tinymce')).forEach(area => initTinyMCE(area));
|
||||
}
|
||||
|
||||
function ready(fn) {
|
||||
if (document.readyState !== 'loading') {
|
||||
fn();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', fn);
|
||||
}
|
||||
}
|
||||
|
||||
ready(function () {
|
||||
// Au clic sur les boutons d'ajout des InlinePanel, on recharge TinyMCE pour que l'éditeur s'affiche correctement.
|
||||
const addAgir = document.getElementById('id_fiches_agir-ADD');
|
||||
const addComprendre = document.getElementById('id_fiches_comprendre-ADD');
|
||||
|
||||
if (addAgir !== null) {
|
||||
addAgir.addEventListener('click', () => {
|
||||
initializeTinyMCE(document);
|
||||
});
|
||||
}
|
||||
|
||||
if (addComprendre !== null) {
|
||||
addComprendre.addEventListener('click', () => {
|
||||
initializeTinyMCE(document);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
|
@ -18,6 +18,7 @@ const CONFIG = {
|
|||
main: ['./assets/js/main.js', './assets/scss/main.scss'],
|
||||
'file-input-custom': './assets/js/file-input-custom.js',
|
||||
'words-count': './assets/js/words-count.js',
|
||||
'reload_tinymce': './assets/js/reload_tinymce.js',
|
||||
},
|
||||
|
||||
// Folders to create aliases for in JavaScript and SCSS
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
from django.forms import Textarea
|
||||
|
||||
from wagtail.admin.panels import FieldPanel, FieldRowPanel, MultiFieldPanel
|
||||
from wagtail.admin.panels import (
|
||||
FieldPanel,
|
||||
FieldRowPanel,
|
||||
InlinePanel,
|
||||
MultiFieldPanel,
|
||||
)
|
||||
from wagtail.contrib.modeladmin.options import ModelAdmin, ModelAdminGroup
|
||||
|
||||
from tinymce.widgets import TinyMCE
|
||||
|
||||
from . import models
|
||||
|
||||
|
||||
|
@ -24,20 +27,16 @@ class FicheQuestionAdmin(ModelAdmin):
|
|||
menu_icon = 'form'
|
||||
panels = [
|
||||
FieldPanel('question'),
|
||||
FieldPanel('description', widget=TinyMCE()),
|
||||
FieldPanel('description'),
|
||||
FieldPanel('thematique'),
|
||||
FieldPanel('published'),
|
||||
]
|
||||
|
||||
|
||||
class FicheMethodeAdmin(ModelAdmin):
|
||||
model = models.FicheMethode
|
||||
menu_icon = 'form'
|
||||
panels = [
|
||||
FieldPanel('name'),
|
||||
FieldPanel('fiche_question'),
|
||||
FieldPanel('contacts'),
|
||||
FieldPanel('contenu', widget=TinyMCE()),
|
||||
MultiFieldPanel(
|
||||
[
|
||||
InlinePanel('fiches_agir', label="Fiche Agir"),
|
||||
InlinePanel('fiches_comprendre', label="Fiche Comprendre"),
|
||||
],
|
||||
heading="Fiches Réponse",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -49,7 +48,7 @@ class StructureAdmin(ModelAdmin):
|
|||
FieldPanel('nom'),
|
||||
MultiFieldPanel(
|
||||
[
|
||||
FieldPanel('description', widget=TinyMCE()),
|
||||
FieldPanel('description'),
|
||||
FieldPanel('logo'),
|
||||
],
|
||||
heading='Identité',
|
||||
|
@ -125,7 +124,6 @@ class WWCAdminGroup(ModelAdminGroup):
|
|||
items = (
|
||||
ThematiqueAdmin,
|
||||
FicheQuestionAdmin,
|
||||
FicheMethodeAdmin,
|
||||
StructureAdmin,
|
||||
ContactAdmin,
|
||||
RessourceAdmin,
|
||||
|
@ -133,6 +131,6 @@ class WWCAdminGroup(ModelAdminGroup):
|
|||
|
||||
|
||||
models.SiteSettings.panels = [
|
||||
FieldPanel('site_description', widget=TinyMCE()),
|
||||
FieldPanel('questions_description', widget=TinyMCE()),
|
||||
FieldPanel('site_description'),
|
||||
FieldPanel('questions_description'),
|
||||
]
|
||||
|
|
|
@ -4,3 +4,14 @@ from django.apps import AppConfig
|
|||
class CoreConfig(AppConfig):
|
||||
name = 'wwc.core'
|
||||
verbose_name = "Core"
|
||||
|
||||
def ready(self):
|
||||
from django.db.models import TextField
|
||||
|
||||
from wagtail.admin.forms.models import register_form_field_override
|
||||
|
||||
from tinymce.widgets import TinyMCE
|
||||
|
||||
register_form_field_override(
|
||||
TextField, override={'widget': TinyMCE}, exact_class=True
|
||||
)
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# Generated by Django 3.2.18 on 2023-05-17 18:54
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import modelcluster.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0006_sitesettings_questions_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='fichequestion',
|
||||
name='description',
|
||||
field=models.TextField(null=True, verbose_name='Description'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FicheComprendre',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=128, verbose_name='titre')),
|
||||
('contexte', models.TextField(null=True, verbose_name='Contexte de la question')),
|
||||
('pdv', models.TextField(null=True, verbose_name='Points de vue')),
|
||||
('eclairages', models.TextField(null=True, verbose_name='Éclairages')),
|
||||
('portee', models.TextField(null=True, verbose_name='Portée et limites')),
|
||||
('fiche_question', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='fiches_comprendre', to='core.fichequestion')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Fiche Comprendre',
|
||||
'verbose_name_plural': 'Fiches Comprendre',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FicheAgir',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=128, verbose_name='titre')),
|
||||
('situation', models.TextField(null=True, verbose_name='Situation de départ')),
|
||||
('action', models.TextField(null=True, verbose_name='Action mise en oeuvre')),
|
||||
('moyens', models.TextField(null=True, verbose_name="Moyens nécessaires à l'action")),
|
||||
('preconisations', models.TextField(null=True, verbose_name='Préconisations')),
|
||||
('fiche_question', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='fiches_agir', to='core.fichequestion')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Fiche Agir',
|
||||
'verbose_name_plural': 'Fiches Agir',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='ressource',
|
||||
name='fiche_agir',
|
||||
field=modelcluster.fields.ParentalKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ressources', to='core.ficheagir', verbose_name='Ressource(s)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='ressource',
|
||||
name='fiche_comprendre',
|
||||
field=modelcluster.fields.ParentalKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ressources', to='core.fichecomprendre', verbose_name='Ressource(s)'),
|
||||
),
|
||||
]
|
|
@ -110,9 +110,7 @@ class FicheQuestion(index.Indexed, ClusterableModel):
|
|||
"""Une fiche qui pose un problème à résoudre"""
|
||||
|
||||
question = models.CharField(max_length=255)
|
||||
description = models.TextField(
|
||||
"Description",
|
||||
)
|
||||
description = models.TextField("Description", null=True)
|
||||
thematique = models.ManyToManyField(
|
||||
'Thematique',
|
||||
blank=True,
|
||||
|
@ -141,6 +139,53 @@ class FicheQuestion(index.Indexed, ClusterableModel):
|
|||
verbose_name_plural = "fiches Question"
|
||||
|
||||
|
||||
class FicheAgir(ClusterableModel):
|
||||
"""Une fiche qui propose une solution concrète à un problème."""
|
||||
|
||||
name = models.CharField("titre", max_length=128)
|
||||
fiche_question = ParentalKey(
|
||||
'core.FicheQuestion',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='fiches_agir',
|
||||
)
|
||||
situation = models.TextField("Situation de départ", null=True)
|
||||
action = models.TextField("Action mise en oeuvre", null=True)
|
||||
moyens = models.TextField("Moyens nécessaires à l'action", null=True)
|
||||
preconisations = models.TextField("Préconisations", null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Fiche Agir"
|
||||
verbose_name_plural = "Fiches Agir"
|
||||
|
||||
|
||||
class FicheComprendre(ClusterableModel):
|
||||
"""
|
||||
Une fiche qui vise à contextualiser un problème pour mieux le
|
||||
comprendre.
|
||||
"""
|
||||
|
||||
name = models.CharField("titre", max_length=128)
|
||||
fiche_question = ParentalKey(
|
||||
'core.FicheQuestion',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='fiches_comprendre',
|
||||
)
|
||||
contexte = models.TextField("Contexte de la question", null=True)
|
||||
pdv = models.TextField("Points de vue", null=True)
|
||||
eclairages = models.TextField("Éclairages", null=True)
|
||||
portee = models.TextField("Portée et limites", null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Fiche Comprendre"
|
||||
verbose_name_plural = "Fiches Comprendre"
|
||||
|
||||
|
||||
class FicheMethode(ClusterableModel):
|
||||
"""Une fiche qui propose des solutions à un problème"""
|
||||
|
||||
|
@ -258,6 +303,21 @@ class Ressource(index.Indexed, ClusterableModel):
|
|||
verbose_name="Thématique(s)",
|
||||
)
|
||||
|
||||
fiche_agir = ParentalKey(
|
||||
'core.FicheAgir',
|
||||
blank=True,
|
||||
null=True,
|
||||
related_name='ressources',
|
||||
verbose_name="Ressource(s)",
|
||||
)
|
||||
fiche_comprendre = ParentalKey(
|
||||
'core.FicheComprendre',
|
||||
blank=True,
|
||||
null=True,
|
||||
related_name='ressources',
|
||||
verbose_name='Ressource(s)',
|
||||
)
|
||||
|
||||
published = models.BooleanField("publié", default=True)
|
||||
publish_date = models.DateTimeField(
|
||||
"date de publication",
|
||||
|
@ -307,6 +367,11 @@ class Ressource(index.Indexed, ClusterableModel):
|
|||
"URL",
|
||||
code='document_and_url',
|
||||
)
|
||||
if self.fiche_agir and self.fiche_comprendre:
|
||||
raise ValidationError(
|
||||
"Une ressource ne peut être liée qu'à une fiche type Réponse.",
|
||||
code='too_many_fiches',
|
||||
)
|
||||
|
||||
|
||||
@register_setting(icon="view")
|
||||
|
@ -329,5 +394,5 @@ class SiteSettings(BaseSetting):
|
|||
help_text=(
|
||||
"Un ou plusieurs paragraphes qui seront affichés en haut "
|
||||
"de la page de liste des fiches Question."
|
||||
)
|
||||
),
|
||||
)
|
||||
|
|
|
@ -298,8 +298,14 @@ TINYMCE_DEFAULT_CONFIG = {
|
|||
"formats": {
|
||||
"italic": {"inline": 'i'},
|
||||
},
|
||||
"plugins": "autolink,link,paste,",
|
||||
"toolbar": "undo redo | bold italic | link",
|
||||
"plugins": "autolink,link,lists,paste,",
|
||||
"toolbar": "undo redo | bold italic | bullist | link",
|
||||
"branding": False,
|
||||
"extended_valid_elements": "i[*],em",
|
||||
}
|
||||
|
||||
TINYMCE_EXTRA_MEDIA = {
|
||||
'js': [
|
||||
'reload_tinymce.js',
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
{% load wagtailcore_tags %}
|
||||
|
||||
{% block title %}Fiche Question "{{ object.question }}"{% endblock %}
|
||||
|
||||
|
|
Chargement…
Référencer dans un nouveau ticket