Insérer un composant Glimmer après le premier message

J’ai un composant Glimmer. Ça fonctionne. Mais j’ai besoin qu’il apparaisse après le premier message d’un sujet. Il n’y a pas de sortie de plugin à cet endroit.

J’ai trouvé comment insérer du texte dans le innerHTML de la balise <article>, et cela place ce texte là où je le souhaite, mais il ne semble pas y avoir de moyen de faire cela avec un composant.

Est-ce que je rate quelque chose ?

J’ai regardé comment le plugin publicitaire insère des publicités entre les messages, mais je n’ai pas réussi à tout comprendre.

export default {
  name: "initialize-ad-plugin",
  initialize(container) {
    registerWidgetShim(
      "after-post-ad",
      "div.widget-connector",
      hbs`<PostBottomAd @model={{@data}} />`
    );

    withPluginApi("0.1", (api) => {
      api.decorateWidget("post:after", (helper) => {
        return helper.attach("after-post-ad", helper.widget.model);
      });
    });

....

Ajoutons-en une ! Où la voudriez-vous ?

(Il existe des moyens hérités pour accomplir ce que vous faites, mais ils casseront lorsque nous moderniserons la vue du sujet. Si nous ajoutons une sortie de plugin, ce sera beaucoup plus pérenne)

2 « J'aime »

Cette sortie correspondrait à la fonctionnalité de decorateWidget("post:after, ce que le plugin publicitaire utilise :

3 « J'aime »

C’est génial ! Pleurniche et tu recevras !

En fait, je “sais” qu’il est “facile” d’ajouter des prises de plugin, mais quand j’ai “plus ou moins” su comment les ajouter, c’était dans un fichier hbs.

Est-ce que ce sera après chaque article ? Je devrai donc trouver une astuce pour que ce ne soit qu’après le premier ?

article:after est ce que j’avais imaginé à un moment donné dans mes tentatives précédentes.

1 « J'aime »

Le post est passé comme l’un des arguments de sortie, vous pouvez donc vérifier post.post_number == 1

Haha ! Toujours heureux d’aider avec ce genre de questions. C’est bien mieux pour tout le monde si nous pouvons faire en sorte que les thèmes et les plugins utilisent des API standard comme celle-ci plutôt que des solutions de contournement de widgets (qui seront dépréciées dans un avenir pas si lointain).

Oui, c’est juste. Les ajouter à l’intérieur des widgets est un casse-tête du côté du noyau. Mais du côté du thème/plugin, cela devrait être super propre :crossed_fingers:


J’essaierai de comprendre ces échecs de tests et de faire fusionner la PR demain. (Il semble que l’élément HTML supplémentaire perturbe certains sélecteurs fragiles dans les tests qunit)

2 « J'aime »

Aha ! @outletArgs={{hash post=@data.post}}. Il y a de fortes chances que je puisse comprendre comment faire ça. :slight_smile:

Merci encore !

2 « J'aime »

Je crains d’avoir été un peu trop optimiste ici @pfaffman, désolé ! Le PR que j’ai fait introduirait un nouveau wrapper <div> entre chaque publication, même si l’outlet n’était pas utilisé. Ce n’est pas vraiment ce que nous voulons faire.

Il peut y avoir des moyens d’éviter le wrapper… mais rien de simple que nous puissions faire immédiatement.

Je pense donc que la meilleure solution immédiate pour vous sera de copier l’implémentation de adplugin à laquelle vous avez fait référence dans l’OP.

Essentiellement :

  1. Créez un composant (Glimmer ou classique, peu importe) qui rend ce que vous voulez.

  2. Utilisez registerWidgetShim pour rendre ce composant disponible en tant que widget. L’exemple adplugin crée un widget appelé “after-post-ad”, qui rend le composant PostBottomAd. Il transmet tous les attributs du widget (@data) à l’argument @model du composant.

  3. Utilisez api.decorateWidget pour rendre votre nouveau widget shim dans la position post:after. Dans votre cas, puisque vous ne le voulez que sur la première publication, vous pourriez faire quelque chose comme :

    api.decorateWidget("post:after", (helper) => {
      if (helper.widget.model.post_number === 1) {
        return helper.attach("my-widget-shim");
      }
    });
    

Lorsque nous passerons enfin la page de sujet à glimmer, vous devrez supprimer le widget shim/décoration et le remplacer par un plugin outlet. Cela devrait être assez facile, car toute votre logique d’affichage dans le composant sera réutilisable dans le plugin outlet.

Faites-nous savoir comment vous vous en sortez ! Nous serons heureux de répondre à toutes vos questions de suivi - je sais qu’il y a beaucoup de pièces mobiles ici.

3 « J'aime »

Je suis si près !

Le seul problème est que le composant a besoin de currentUser et je n’arrive pas à comprendre comment le passer. Voici ce qui ne fonctionne pas.

import { hbs } from "ember-cli-htmlbars";
import { withPluginApi } from "discourse/lib/plugin-api";
import Site from "discourse/models/site";
import { registerWidgetShim } from "discourse/widgets/render-glimmer";
import Banner from "../components/banner";

export default {
  name: "initialize-banner-widget",
  initialize(container) {
    registerWidgetShim(
      "geo-banner-widget",
      "div.widget-connector",
      hbs`<Banner @currentUser={{currentUser}} />`
    );

    // withPluginApi("0.1", (api) => {
    //   console.log("doing plugin");
    //   api.decorateWidget("post:after", (helper) => {
    //     return helper.attach("geo-banner-widget", helper.widget.model);
    //   });
    // });

    withPluginApi("0.1", (api) => {
      const currentUser = container.lookup("service:current-user");
      api.decorateWidget("post:after", (helper) => {
        console.log(`decorate widget ${currentUser.username}`, );
        if(helper.widget.model.post_number === 1){
          return helper.attach("geo-banner-widget", { currentUser });
        }
      });
    });
  },
};
1 « J'aime »

Dans votre composant Banner, vous pouvez injecter le service currentUser comme ceci :

class Banner extends Component {
  @service currentUser;
}

vous n’aurez alors plus besoin de le passer depuis le widget.

2 « J'aime »

Je savais que c’était stupide de passer currentUser, mais je n’arrivais pas à comprendre !

L’autre morceau, au cas improbable où quelqu’un d’autre trouverait cela utile, est

import Service, { inject as service } from "@ember/service";
import { hbs } from "ember-cli-htmlbars";
import { withPluginApi } from "discourse/lib/plugin-api";
import { registerWidgetShim } from "discourse/widgets/render-glimmer";

export default {
  name: "initialize-banner-widget",
  initialize(container) {
    registerWidgetShim(
      "geo-banner-widget",
      "div.widget-connector",
      hbs`<Banner/>`
    );

    withPluginApi("0.1", (api) => {
      api.decorateWidget("post:after", (helper) => {
        const currentUser = container.lookup("service:current-user");
        if(helper.widget.model.post_number === 1){
          return helper.attach("geo-banner-widget");
        }
      });
    });
  },
};

Oui !

Dans ce cas, je ne pense pas que vous aurez besoin d’importer la classe Service. Ce ne serait nécessaire que si vous créiez votre propre Service. Vous avez juste besoin du décorateur d’injection service.

Et dans la dernière version de Discourse/Ember, cela peut être encore simplifié pour éviter d’avoir besoin de l’alias ‘inject as’. Ember rend maintenant le décorateur d’injection disponible directement sous le nom service.

import { service } from "@ember/service";

(mais l’ancien { inject as service } fonctionne toujours, et je ne suis au courant d’aucun plan pour le déprécier dans Ember)

EDIT : Mais peut-être que je peux utiliser decorateWidget à la place d’un plugin outlet. . .

1 « J'aime »

C’est ce que pense aussi le linter :slight_smile:

Je préfère ça. Le plugin d’annonces internes le fait encore à l’ancienne. :slight_smile:

1 « J'aime »

Ce sujet a été automatiquement fermé 30 jours après la dernière réponse. Les nouvelles réponses ne sont plus autorisées.