Insira um componente glimmer após a primeira postagem

Tenho um componente Glimmer. Ele está funcionando. Mas preciso que ele vá depois do primeiro post em um tópico. Não há um plugin outlet lá.

Eu descobri como inserir algum texto no innerHTML da tag <article>, e isso coloca o texto onde eu quero, mas não parece haver uma maneira de fazer isso com um componente.

Estou perdendo alguma coisa?

Eu olhei como o adplugin insere anúncios entre os posts, mas não consegui entender completamente.

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

....

Vamos adicionar um! Onde você gostaria?

(Existem maneiras legadas de realizar o que você está fazendo, mas elas quebrarão quando modernizarmos a visualização do tópico. Se adicionarmos um ponto de extensão de plugin, será muito mais à prova de futuro)

2 curtidas

Esta saída corresponderia à funcionalidade de decorateWidget("post:after, que é o que o adplugin usa:

3 curtidas

Isso é incrível! Reclame e você receberá!

Na verdade, eu “sei” que é “fácil” adicionar saídas de plugin, mas quando eu “sabia” como adicioná-las, era em um arquivo hbs.

Isso será depois de cada post? Então eu precisarei descobrir alguma mágica para que seja apenas depois do primeiro?

article:after é o que eu tinha inventado em algum momento em minhas tentativas anteriores.

1 curtida

A postagem é passada como um dos argumentos de saída, então você pode verificar post.post_number == 1

Haha! Sempre feliz em ajudar com esse tipo de pergunta. Muito melhor para todos se pudermos fazer com que temas e plugins usem APIs padrão como esta em vez de soluções alternativas de widgets (que serão descontinuadas em um futuro não tão distante).

Sim, isso é justo. Adicioná-los dentro de widgets é uma dor de cabeça no lado do core. Mas do lado do tema/plugin deve ser super limpo :crossed_fingers:


Tentarei descobrir as falhas nos testes e mesclar o PR amanhã. (Parece que o elemento HTML extra está atrapalhando alguns seletores frágeis nos testes qunit)

2 curtidas

Aha! @outletArgs={{hash post=@data.post}}. Há uma chance razoável de eu descobrir como fazer isso. :slight_smile:

Obrigado novamente!

2 curtidas

Receio ter sido um pouco otimista demais aqui @pfaffman, desculpe! O PR que fiz introduziria um novo wrapper <div> entre cada postagem, mesmo que o outlet não estivesse sendo usado. Isso não é algo que realmente queremos fazer.

Pode haver maneiras de evitar o wrapper… mas nada simples que possamos fazer imediatamente.

Portanto, acho que a melhor solução imediata para você será copiar a implementação do adplugin que você referenciou no OP.

Essencialmente:

  1. Crie um componente (Glimmer ou clássico, não importa) que renderize o que você quiser

  2. Use registerWidgetShim para tornar esse componente disponível como um widget. O exemplo do adplugin está criando um widget chamado “after-post-ad”, que renderiza o componente PostBottomAd. Ele está passando todos os atributos do widget (@data) para o argumento @model do componente.

  3. Use api.decorateWidget para renderizar seu novo widget shim na posição post:after. No seu caso, como você só o quer na primeira postagem, você poderia fazer algo como:

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

Quando eventualmente fizermos o glimmer-ify da página do tópico, você precisará remover o widget shim/decoração e substituí-lo por um plugin outlet. Isso deve ser bem fácil, já que toda a sua lógica de exibição no componente será reutilizável no plugin outlet.

Nos diga como você se sai! Ficarei feliz em ajudar com quaisquer perguntas de acompanhamento - sei que há muitas partes móveis aqui.

3 curtidas

Estou tão perto!

O único problema é que o componente precisa de currentUser e não consigo descobrir como passá-lo. Veja o que não funciona.

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 curtida

No seu componente Banner, você pode injetar o serviço currentUser assim:

class Banner extends Component {
  @service currentUser;
}

então você não precisará passá-lo do widget.

2 curtidas

Eu sabia que era estúpido passar o currentUser, mas não consegui descobrir isso!

A outra parte, caso alguém ache útil, é

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

Sim!

Neste caso, acho que você não precisará importar a classe Service. Isso só seria necessário se você estivesse criando seu próprio Service. Você só precisa do decorador de injeção service.

E na versão mais recente do Discourse/Ember, isso pode ser simplificado ainda mais para evitar a necessidade do alias ‘inject as’. O Ember agora disponibiliza o decorador de injeção diretamente como service.

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

(mas o antigo { inject as service } ainda funciona, e não estou ciente de quaisquer planos para depreciá-lo no Ember)

EDIT: Mas talvez eu possa usar decorateWidget em vez de um plugin outlet. . .

1 curtida

É o que o linter também pensa :slight_smile:

Eu prefiro assim. O plugin de anúncios da casa ainda faz do jeito antigo. :slight_smile:

1 curtida

Este tópico foi fechado automaticamente 30 dias após a última resposta. Novas respostas não são mais permitidas.