Calendrier Discourse (et Événement)

:partying_face: Ce plugin est désormais inclus dans le cœur de Discourse dans le cadre de Bundling more popular plugins with Discourse core. Si vous auto-hébergez et utilisez le plugin, vous devez le supprimer de votre app.yml avant votre prochaine mise à niveau.

2 « J'aime »

Volontiers – voici la version révisée, un peu plus conviviale et ouverte pour votre publication en anglais :


Nous avons vraiment besoin de la possibilité de limiter le nombre de participants pour les événements, car bon nombre de nos événements ont une capacité limitée.

Actuellement, le système d’événements ne nous permet pas de :

  • définir un nombre maximum de participants,
  • voir qui s’est inscrit en premier (pas d’horodatages d’inscription),
  • gérer une liste d’attente ou d’informer les gens lorsqu’une place se libère.

Nous trouverions les fonctionnalités suivantes très utiles :

  1. Une limite de participants (plafond) qui empêche d’autres utilisateurs de s’inscrire une fois complet.
  2. Une liste d’attente pour ceux qui souhaitent toujours participer une fois l’événement complet.
  3. Des notifications automatiques lorsqu’une place se libère.
  4. Des horodatages optionnels pour voir l’ordre des inscriptions (utile pour une priorisation équitable).

Ce serait incroyablement utile pour les communautés organisant des événements en personne ou à capacité limitée.

Quelque chose comme cela est-il déjà prévu ou en cours de développement ?
Ou existe-t-il des solutions de contournement connues pour ce cas d’utilisation ?

Merci beaucoup d’avance !

4 « J'aime »

Merci Aurora — nous sommes vraiment ravis d’apprendre que le travail sur le calendrier natif est de nouveau actif !

Nous aimerions également mettre en avant une demande supplémentaire à fort impact qui a émergé dans plusieurs discussions communautaires : la synchronisation des flux iCal.

Celle-ci a été détaillée dans un sujet dédié ici :

La possibilité de s’abonner à des flux .ics externes (tels que les emplois du temps scolaires, les calendriers civiques ou les événements organisationnels) et de les voir reflétés dans un calendrier de sujet Discourse rendrait cette fonctionnalité beaucoup plus utile pour de nombreux déploiements réels. Sans cela, nous sommes obligés de copier manuellement les événements, ce qui est source d’erreurs et difficile à maintenir.

Nous apprécierions grandement tout commentaire de l’équipe Discourse quant à savoir si des parties de cette proposition — comme la synchronisation iCal unidirectionnelle, les paramètres d’intervalle de rafraîchissement des flux ou le marquage d’événements optionnel — font partie du périmètre de la prochaine implémentation.

Dans tous les cas, merci encore d’avoir redonné vie au calendrier Discourse — nous attendons avec impatience ce qui nous attend !

4 « J'aime »

Si vous souhaitez afficher le bouton Créer un événement directement à partir de l’éditeur, comme ci-dessous, utilisez le code ci-dessous dans l’en-tête de votre thème. admin > apparence > thème > modifier > modifier le code > head (assurez-vous qu’il est placé entre les balises <head>...</head>)

Testé sur discourse 3.5.0.beta9-dev sur ordinateur de bureau dans Firefox

    <!-- Bouton personnalisé Créer un événement (basé sur une icône, indépendant de la langue) -->
    <script>
    (() => {
        const composerSelector = ".d-editor-button-bar";
        const menuTriggerSelector = ".btn.no-text.fk-d-menu__trigger.toolbar-menu__options-trigger.toolbar__button.options.toolbar-popup-menu-options";
        const menuContentSelector = ".fk-d-menu__inner-content";
        const modalSelector = ".d-modal.fk-d-menu-modal";

        // Fonction pour trouver le bouton de menu existant qui ouvre le menu du calendrier
        const findCalendarMenuButton = (container) => {
            const calendarIcon = container.querySelector('svg use[href="#calendar-day"]');
            return calendarIcon ? calendarIcon.closest("button") : null;
        };

        // Fonction pour attendre qu'un élément apparaisse ou qu'un délai d'attente soit atteint
        const waitForElement = (container, selectorFn, timeout = 4000) =>
            new Promise((resolve, reject) => {
                const element = selectorFn(container);
                if (element) return resolve(element);

                const observer = new MutationObserver(() => {
                    const foundElement = selectorFn(container);
                    if (foundElement) {
                        observer.disconnect();
                        resolve(foundElement);
                    }
                });
                observer.observe(container, { childList: true, subtree: true });
                setTimeout(() => {
                    observer.disconnect();
                    reject(new Error("Element not found within timeout"));
                }, timeout);
            });

        // Fonction pour attendre que la fenêtre modale du menu apparaisse
        const waitForModal = (timeout = 4000) => {
            const observer = new MutationObserver(() => {
                if (document.querySelector(modalSelector)) {
                    observer.disconnect();
                }
            });
            observer.observe(document.body, { childList: true, subtree: true });
            setTimeout(() => observer.disconnect(), timeout);
        };

        // Fonction pour ajouter le bouton personnalisé et gérer son clic
        const addCustomCreateEventButton = (container) => {
            if (container.querySelector(".custom-create-event-btn")) return;

            const newButton = document.createElement("button");
            newButton.className = "btn no-text btn-icon toolbar__button link custom-create-event-btn";
            newButton.title = "Create event"; // Texte alternatif pour l'accessibilité
            newButton.innerHTML = `
                <svg class="fa d-icon d-icon-calendar-day svg-icon">
                    <use href="#calendar-day"></use>
                </svg>
            `;
            container.appendChild(newButton);

            newButton.addEventListener("click", async () => {
                const menuTrigger = document.querySelector(menuTriggerSelector);
                if (!menuTrigger) return;

                menuTrigger.click(); // Ouvre le menu des options

                let menuContent = document.querySelector(menuContentSelector);
                if (!menuContent) {
                    // Attend que le contenu du menu apparaisse s'il n'est pas immédiatement disponible
                    await new Promise((resolve, reject) => {
                        const observer = new MutationObserver(() => {
                            menuContent = document.querySelector(menuContentSelector);
                            if (menuContent) {
                                observer.disconnect();
                                resolve();
                            }
                        });
                        observer.observe(document.body, { childList: true, subtree: true });
                        setTimeout(() => {
                            observer.disconnect();
                            reject(new Error("Menu content not found within timeout"));
                        }, 2000);
                    });
                }

                try {
                    // Clique sur l'élément du menu qui ouvre le modal de création d'événement
                    await waitForElement(menuContent, findCalendarMenuButton);
                    const calendarButton = findCalendarMenuButton(menuContent);
                    if (calendarButton) {
                        calendarButton.click();
                        waitForModal(); // Attend que le modal de création d'événement apparaisse
                    }
                } catch (error) {
                    console.error("Error clicking calendar menu item:", error);
                }
            });
        };

        // Observe les changements dans le DOM pour trouver le conteneur de l'éditeur et y ajouter le bouton
        const observer = new MutationObserver(() => {
            const composerContainer = document.querySelector(composerSelector);
            if (composerContainer) {
                addCustomCreateEventButton(composerContainer);
            }
        });
        observer.observe(document.body, { childList: true, subtree: true });

        // Ajoute le bouton si le conteneur de l'éditeur est déjà présent au chargement initial
        const initialComposerContainer = document.querySelector(composerSelector);
        if (initialComposerContainer) {
            addCustomCreateEventButton(initialComposerContainer);
        }
    })();
    </script>

J’ai essayé le script, le bouton creation evenement est bien crée mais quand je clique dessus j’ai le même menu contextuel que le bouton plus . J’ai peut être fait une mauvaise manipulation

1 « J'aime »

Après la mise à jour, cela s’est amélioré, il n’y a au moins que « Créer un événement » qui apparaît

Capture d’écran en allemand, désolé.

Salut,

Cela fonctionne sur la dernière version avec 3.5.0.beta9-dev, je ne connais pas votre version ?

Et ceci est du javascript, vous devriez donc fournir l’erreur javascript de la console lorsque vous appuyez sur F12 dans votre navigateur.

J’ai la même version 3.5.0.beta9-dev
voici le message de la console


Je dois forcement faire un truc mal :sweat_smile:

Je n’utilise pas Edge, pouvez-vous réessayer avec le script que je viens de mettre à jour dans le post original car j’ai trouvé des erreurs que j’ai corrigées. S’il ne fonctionne pas, je mettrai à jour plus tard après avoir installé Edge.

J’ai mis à jour le script pour qu’il soit plus compatible avec les mobiles, il devrait fonctionner maintenant, veuillez copier-coller le script du post original

Je confirme que le code mis à jour fonctionne bien dans Edge. Si vous avez quelque chose comme ublock, vous pouvez toujours le désactiver pour votre page discourse, mais je ne pense pas que ce soit lié.

Désolé toujours le même problème pour moi, je dois mal faire quelque chose

Pourtant je colle bien ton script ici

1 « J'aime »

Bien, grâce à la situation de Gilles, j’ai pu configurer un sélecteur basé sur la classe .svg de l’icône qui est unique au lieu d’un attribut title qui varierait selon la langue, le script est également maintenant minifié et encapsulé dans une IIFE.

Vous pouvez trouver le script mis à jour ici Discourse Calendar (and Event) - #535 by opcourdis

1 « J'aime »

merci de ton aide :+1:

1 « J'aime »

Il serait très utile d’avoir votre script encapsulé en tant que Theme component, et que les catégories où il s’applique soient sélectionnables.

Le cas d’utilisation que j’ai en tête est une catégorie « Événements », où je veux rendre la publication d’événements super évidente.

1 « J'aime »

Vous pouvez utiliser ce qui suit et modifier les premières conditions pour spécifier vos catégories, et pour rendre le bouton plus visible, le CSS s’en chargera : .btn.no-text.btn-icon.toolbar__button.link.custom-create-event-btn {
order: -1;
}

<script>(()=>{if(!(document.body.classList.contains("category-events")||document.body.classList.contains("category-event2")||document.body.classList.contains("category-event3")))return;const e=".d-editor-button-bar",t=".btn.no-text.fk-d-menu__trigger.toolbar-menu__options-trigger.toolbar__button.options.toolbar-popup-menu-options",n=".fk-d-menu__inner-content",o=".d-modal.fk-d-menu-modal",c=e=>{"#calendar-day"===e.querySelector("svg use")?.getAttribute("href")?e.querySelector("svg use")?.closest("button"):null},r=(e,t,n=4e3)=>new Promise((o,c)=>{const r=t(e);if(r)return o(r);const l=new MutationObserver(()=>{const n=t(e);n&&(l.disconnect(),o(n))});l.observe(e,{childList:!0,subtree:!0}),setTimeout(()=>{l.disconnect(),c()},n)}),l=(e=4e3)=>{const t=new MutationObserver(()=>{document.querySelector(o)&&t.disconnect()});t.observe(document.body,{childList:!0,subtree:!0}),setTimeout(()=>t.disconnect(),e)},s=e=>{if(e.querySelector(".custom-create-event-btn"))return;const o=document.createElement("button");o.className="btn no-text btn-icon toolbar__button link custom-create-event-btn",o.title="Create event",o.innerHTML='<svg class="fa d-icon d-icon-calendar-day svg-icon"><use href="#calendar-day"></use></svg>',e.appendChild(o),o.addEventListener("click",async()=>{const e=document.querySelector(t);if(!e)return;e.click();let o=document.querySelector(n);o||(await new Promise((e,t)=>{const c=new MutationObserver(()=>{o=document.querySelector(n)&&c.disconnect()});c.observe(document.body,{childList:!0,subtree:!0}),setTimeout(()=>c.disconnect(),2e3)}));try{(await r(o,c)).click(),l()}catch{}})},u=new MutationObserver(()=>{const t=document.querySelector(e);t&&s(t)});u.observe(document.body,{childList:!0,subtree:!0});const d=document.querySelector(e);d&&s(d)})();</script>


Merci pour la suggestion, je suis encore un peu nouveau sur Discourse et je vais vérifier le composant de thème, le placement du bouton est en effet meilleur, mais mon autre script pour la limite de participants aux événements pourrait bientôt ne plus être nécessaire en raison de ceci https://github.com/discourse/discourse/pull/34313
4 « J'aime »

Après la mise à niveau vers la dernière version de Discourse et du plugin discourse-calendar, je vois l’avertissement suivant en tant qu’administrateur :

⚠️ Les publications peuvent ne pas s'afficher correctement car l'un des décorateurs de contenu de publication sur votre site a généré une erreur.
Causé par le plugin 'discourse-calendar'
(ce message n'est affiché qu'aux administrateurs du site)
  • Le plugin calendrier ne fonctionne plus : le contenu du calendrier et les événements ne s’affichent pas dans les sujets.
  • Le plugin fonctionnait correctement avant la récente mise à niveau.
  • Mon site Discourse et tous les plugins officiels sont maintenant à jour.

Nous utilisons le plugin Discourse Post Event sur notre forum.
Actuellement, lorsqu’un utilisateur rejoint (confirme sa présence) un événement, le sujet est automatiquement défini sur « Suivant », ce qui signifie que chaque nouvelle réponse au sujet de l’événement déclenche une notification pour tous les participants.

Nous aimerions conserver le niveau de notification sur « Normal » par défaut, même après que quelqu’un ait rejoint un événement.

J’ai vérifié les paramètres du site mais je n’ai pas trouvé d’option qui fonctionne.
Existe-t-il un moyen de désactiver ou de modifier ce comportement automatique de « Suivant » lorsque les utilisateurs confirment leur présence à un événement ?

Je ne pense pas. Mais ce serait une demande de fonctionnalité utile.

Une solution de contournement utile pourrait être de fermer le sujet pour arrêter les réponses, mais d’y associer un canal de discussion (ceux-ci ne notifient pas par défaut).

L’étiquette du bouton « Aujourd’hui » peut prêter à confusion.

Le bouton ne navigue pas réellement vers le jour actuel, il navigue vers la vue actuelle de l’onglet de période active (Jour/Semaine/Mois/Année). En Jour, Semaine et Mois, cela amène le jour actuel dans la vue. Mais en Année, cela ne navigue que vers l’année en cours (qui commence toujours en janvier).

Il devrait probablement être :

  • renommé pour décrire plus précisément sa fonctionnalité, comme « Actuel ».
  • ou, peut-être mieux, non seulement naviguer vers l’année en cours, mais faire défiler jusqu’au jour actuel dans la liste des années.
1 « J'aime »