mayan/apps/appearance/ — la couche de présentation de Mayan. Elle ne manipule aucune donnée métier : elle gère les librairies JavaScript, le comportement AJAX, la pagination, les thèmes et les templates partagés.
Appearance remplit quatre fonctions :
head.html, foot.html)Déclarées dans dependencies.py via JavaScriptDependency et installées dans static/appearance/node_modules/ :
| Librairie | Version | Usage |
|---|---|---|
| jQuery | 3.7.1 | Base de tout le JS de Mayan |
| jQuery Form | 4.3.0 | Soumission de formulaires en AJAX |
| jQuery Match Height | 0.7.2 | Alignement visuel des cartes |
| Select2 | 4.0.13 | Champs de sélection enrichis (avec recherche) |
| Fancybox | 3.3.5 | Visionneuse d'images en lightbox |
| Toastr | 2.1.4 | Notifications toast (messages système) |
Ces librairies sont incluses dans toutes les pages via les templates head.html et foot.html.
Chaque app peut avoir besoin d'injecter du HTML dans <head> (CSS, meta) ou en bas de page (scripts). Sans mécanisme central, chaque app modifierait le template de base — créant des couplages fragiles.
{% appearance_app_templates %}Le tag template {% appearance_app_templates 'head' %} (dans templatetags/appearance_tags.py) parcourt toutes les apps actives et cherche le template {app_label}/app/head.html. S'il existe, il est rendu et inclus.
{% appearance_app_templates 'head' %}
→ cherche appearance/app/head.html → rendu (jQuery, CSS)
→ cherche documents/app/head.html → absent, ignoré
→ cherche acls/app/head.html → absent, ignoré
→ cherche my_custom_app/app/head.html → rendu si présent
→ concatène tout
Les rendus sont mis en cache dans app_templates_cache (dict en mémoire). Le cache est bypassé si :
settings.DEBUG = True{# appearance_app_template_nocache #}Cela permet à une app de forcer un rendu dynamique (ex : contenu dépendant de la configuration).
mayan/apps/my_app/
templates/
my_app/
app/
head.html ← <link> CSS, <meta>, etc.
foot.html ← <script>, initialisation JS
| Clé | Défaut | Rôle |
|---|---|---|
APPEARANCE_AJAX_REDIRECTION_CODE |
278 |
Code HTTP custom pour les redirections AJAX (évite que le navigateur suive la redirection lui-même) |
APPEARANCE_MENU_POLLING_INTERVAL |
5000 |
Délai (ms) entre deux vérifications de mise à jour des menus |
APPEARANCE_MESSAGE_POSITION |
bottom-right |
Position des toasts Toastr (top-left, top-center, top-right, bottom-left, bottom-center, bottom-right) |
APPEARANCE_MAXIMUM_TITLE_LENGTH |
120 |
Longueur maximale des titres de vue affichés dans l'interface |
APPEARANCE_ELIDED_PAGER_ON_EACH_SIDE |
3 |
Pages affichées de chaque côté de la page courante dans le paginateur |
APPEARANCE_ELIDED_PAGER_ON_ENDS |
1 |
Pages affichées aux extrémités du paginateur |
APPEARANCE_PAGINATION_DROPDOWN_ENABLE |
false |
Active un dropdown de sélection de page |
APPEARANCE_PAGINATION_DROPDOWN_RANGE |
100 |
Nombre de pages dans le dropdown |
APPEARANCE_PAGINATION_INPUT_ENABLE |
false |
Active un champ texte de saisie directe de page |
APPEARANCE_THROTTLING_MAXIMUM_REQUESTS |
5 |
Nombre de requêtes AJAX autorisées avant throttling |
APPEARANCE_THROTTLING_TIMEOUT |
4000 |
Délai (ms) après lequel le throttling se réinitialise |
Django renvoie 302 pour les redirections. Le problème : le navigateur suit le 302 de façon transparente avant même que jQuery puisse intercepter la réponse. Mayan utilise le code 278 (non-standard) pour signaler "c'est une redirection mais c'est toi, JavaScript, qui dois la gérer". Le JS front-end intercepte ce code et navigue manuellement vers l'URL de redirection.
Le throttling côté client limite les doubles-clics et les soumissions en rafale :
THROTTLING_MAXIMUM_REQUESTS requêtes rapides, les suivantes sont bloquéesTHROTTLING_TIMEOUT ms d'inactivitéDéfinis dans templatetags/appearance_tags.py :
| Tag / Filtre | Usage |
|---|---|
{% appearance_app_templates 'name' %} |
Injecte les templates {app}/app/name.html de toutes les apps |
\|appearance_form_get_visile_fields_map |
Retourne un dict {field_name: field} des champs visibles d'un formulaire |
\|appearance_get_choice_value |
Retourne le label affiché d'un champ Select (gère les multi-select) |
\|appearance_get_form_media_js |
Retourne la liste des JS requis par un formulaire (pour inclusion conditionnelle) |
\|appearance_object_list_count |
Retourne queryset.count() ou len(list) selon le type |
| Événement | Déclencheur |
|---|---|
event_theme_created |
Création d'un thème CSS personnalisé |
event_theme_edited |
Modification d'un thème |
event_user_theme_settings_edited |
Un utilisateur change son thème personnel |
Les thèmes permettent de personnaliser le CSS de l'interface par utilisateur (géré par l'app appearance_bootstrap ou similaire).
link_ajax_refresh est enregistré dans menu_topbar. Il déclenche un rechargement AJAX du contenu de la vue courante sans recharger la page entière — utile quand une tâche Celery vient de se terminer.
| Fichier | Contenu |
|---|---|
apps.py |
AppearanceApp — enregistre link_ajax_refresh dans menu_topbar |
settings.py |
Tous les settings APPEARANCE_* |
dependencies.py |
Librairies JS (jQuery, Select2, Fancybox, Toastr…) |
templatetags/appearance_tags.py |
appearance_app_templates et filtres de formulaire |
templates/appearance/app/head.html |
CSS et JS injectés dans <head> |
templates/appearance/app/foot.html |
JS injectés en bas de page |
literals.py |
Valeurs par défaut des settings |
events.py |
Événements thèmes |