Inserisci un componente glimmer dopo il primo post

Ho un componente Glimmer. Funziona. Ma ho bisogno che vada dopo il primo post in un argomento. Non c’è un plugin outlet lì.

Ho capito come inserire del testo in innerHTML del tag <article>, e questo inserisce quel testo dove voglio, ma non sembra esserci un modo per farlo con un componente.

Mi sto perdendo qualcosa?

Ho guardato come adplugin inserisce annunci tra i post, ma non sono riuscito a capirlo del tutto.

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);
      });
    });

....

Aggiungiamone una! Dove la vorresti?

(ci sono modi legacy per realizzare ciò che stai facendo, ma si romperanno quando modernizzeremo la vista dell’argomento. Se aggiungiamo una presa per plugin, sarà molto più a prova di futuro)

2 Mi Piace

Questa uscita corrisponderebbe alla funzionalità di decorateWidget("post:after", che è ciò che utilizza l’adplugin:

3 Mi Piace

Fantastico! Lamenti e riceverai!

In realtà, “so” che è “facile” aggiungere prese per plugin, ma quando ho “saputo” come aggiungerle, era in un file hbs.

Sarà dopo ogni post? Quindi dovrò capire qualche trucco per farlo apparire solo dopo il primo?

article:after è quello che avevo escogitato a un certo punto nei miei tentativi precedenti.

1 Mi Piace

Il post viene passato come uno degli argomenti dell’output, quindi puoi controllare post.post_number == 1

Haha! Sempre felice di aiutare con questo tipo di domande. Molto meglio per tutti se possiamo far utilizzare a temi e plugin API standard come questa piuttosto che soluzioni alternative tramite widget (che saranno deprecate in un futuro non troppo lontano).

Sì, è giusto. Aggiungerli all’interno dei widget è un mal di testa per il core. Ma dal lato tema/plugin dovrebbe essere super pulito :crossed_fingers:


Cercherò di capire i fallimenti dei test e di unire il PR domani. (Sembra che l’elemento HTML aggiuntivo stia creando problemi con alcuni selettori fragili nei test qunit)

2 Mi Piace

Aha! @outletArgs={{hash post=@data.post}}. C’è una buona probabilità che io possa capire come farlo. :slight_smile:

Grazie ancora!

2 Mi Piace

Temo di essere stato un po’ troppo ottimista qui @pfaffman, scusa! Il PR che ho fatto introdurrebbe un nuovo wrapper <div> tra ogni singolo post, anche se l’outlet non veniva utilizzato. Non è proprio quello che vogliamo fare.

Potrebbero esserci modi per evitare il wrapper… ma niente di semplice che possiamo fare immediatamente.

Quindi penso che la migliore soluzione immediata per te sarà copiare l’implementazione di adplugin a cui hai fatto riferimento nell’OP.

Essenzialmente:

  1. Crea un componente (Glimmer o classico, non importa) che renderizza ciò che desideri

  2. Usa registerWidgetShim per rendere quel componente disponibile come widget. L’esempio di adplugin sta creando un widget chiamato “after-post-ad”, che renderizza il componente PostBottomAd. Sta passando tutti gli attributi del widget (@data) all’argomento @model del componente.

  3. Usa api.decorateWidget per renderizzare il tuo nuovo widget shim nella posizione post:after. Nel tuo caso, dato che lo desideri solo sul primo post, potresti fare qualcosa di simile

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

Quando alla fine faremo il glimmer-ify della pagina dell’argomento, dovrai rimuovere il widget shim/decorazione e sostituirlo con un plugin outlet. Dovrebbe essere abbastanza facile, dato che tutta la tua logica di visualizzazione nel componente sarà riutilizzabile nel plugin outlet.

Facci sapere come va! Felice di aiutarti con qualsiasi domanda di follow-up - so che ci sono molte parti in movimento qui.

3 Mi Piace

Sono così vicino!

L’unico problema è che il componente ha bisogno di currentUser e non riesco a capire come passarlo. Ecco cosa non funziona.

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 Mi Piace

Nel tuo componente Banner, puoi iniettare il servizio currentUser in questo modo:

class Banner extends Component {
  @service currentUser;
}

quindi non avrai bisogno di passarlo dal widget.

2 Mi Piace

Sapevo che era stupido passare currentUser, ma non riuscivo a capirlo!

L’altra parte, nell’improbabile eventualità che qualcun altro la trovi utile, è

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");
        }
      });
    });
  },
};

Sì!

In questo caso, non credo che avrai bisogno di importare la classe Service. Sarebbe necessaria solo se stessi creando il tuo Service. Hai solo bisogno del decoratore di iniezione service.

E nell’ultima versione di Discourse/Ember, può essere semplificata ulteriormente per evitare di aver bisogno dell’alias ‘inject as’. Ember ora rende il decoratore di iniezione disponibile direttamente come service.

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

(ma il vecchio { inject as service } funziona ancora e non sono a conoscenza di piani per deprecato in Ember)

EDIT: Ma forse posso usare decorateWidget invece di un plugin outlet. . .

1 Mi Piace

Anche il linter la pensa così :slight_smile:

Mi piace di più. Il plugin degli annunci interni lo fa ancora nel vecchio modo. :slight_smile:

1 Mi Piace

Questo argomento è stato chiuso automaticamente 30 giorni dopo l’ultima risposta. Non sono più consentite nuove risposte.