Retort - a reaction-style plugin for Discourse

@cpradio I’m not sure if this is the problem you’re having, but make sure the subscription to the messageBus in the topic route is actually working properly.

Currently I’m trying to find the best hook or event to trigger the subscription on the client as it seems as though the setupTopicController event in the topic route actually gets fired before the topic controller subscription() method gets fired and that the controller subscription() method unsubscribes before it subscribes (see here). So (I think) it’s possible that the subscription in this plugin will get unsubscribed just after it is subscribed.

@gdpelican @riking thoughts?

Having a peek at this this evening. (Haven’t gotten as far as the message bus stuff yet, sorry.)

@cpradio 's written some code that looks like this:

    var html = '<div class="post-retorts">';
    post.retorts.forEach(function (item, index, enumerable){ /* do more html stuff */ }
    html += '</div>';
    return dec.rawHtml(html); 

…which (no offense to him!) is making me pretty sad. I know these days that templates all get bundled up and popped into javascript anyway, but I still would really rather have a way to separate my initializer code from my template, rather than string-building templates like Mom used to make, React/JSX be damned.

It also makes me a bit weary to think of porting all of the Babble views (they’re relatively extensive!) into a javascript initializer.

What would be super neat would be

api.decorateWidget('post-contents:after-cooked', 'templates/post_retorts.hbs')

Is there a way to do this that I’m missing @eviltrout?

EDIT: Ah, I’ve found the connect method after some source code diving, which seems to be what I’m looking for. Didn’t realize there were performance tradeoffs to be considered by rendering this way, so it’ll be interesting to see what works best for the plugins which have some somewhat extensive template code. :sunny:


Ah, yeah, sorry, I didn’t look for a template way primarily because @eviltrout put a lot of emphasis on using rawHtml and the like, but it may be that converting it to a widget would be best? But there aren’t many examples of that “yet”. Although I do agree that I don’t really like the idea of building HTML to output, instead of extracting it out into a template.

(still trying to find where @eviltrout recommended the usage of rawHtml and similar methods, but not finding it)

I wouldn’t recommend rawHtml unless you absolutely need to, so I would be curious to see where I suggested that :slightly_smiling: Having said that it’s useful if you want to share some code with a previous version of the plugin that was already creating HTML by hand. It is slower due to overhead in jQuery parsing the HTML but it is probably not significant.

I’ll be writing up some documentation on the widget stuff today. Hopefully that will help people understand how to build stuff that will appear in the post stream.

1 Like

Okay, could be I misinterpretted something that was said. But I thought that was the encouraged way for interacting with the post stream. It was something along the lines of “if the plugin doesn’t have a lot of HTML to output building it within JavaScript is preferred and shouldn’t be overly complicated, but those with a lot of HTML output may need to use a widget” (or so I thought).

Oh right, I think I understand the confusion.

If you have a lot of pre-computed HTML from elsewhere, (for example the contents of a cooked post, or if you have an existing helper that already produces HTML), you can use rawHtml to wrap it. However, going forward if you want to build controls and widgets, the best way is via the widget system.


I believe last update screwed up something?

I, [2016-03-01T06:39:50.507171 #40]  INFO -- : > cd /var/www/discourse && su dis                                                                         course -c 'bundle exec rake db:migrate'
rake aborted!
SyntaxError: /var/www/discourse/plugins/retort/plugin.rb:93: syntax error, unexp                                                                         ected ')'
/var/www/discourse/plugins/retort/plugin.rb:99: syntax error, unexpected ')'
/var/www/discourse/plugins/retort/plugin.rb:103: syntax error, unexpected ','
    def self.find_by(post:, retort:)
/var/www/discourse/plugins/retort/plugin.rb:105: syntax error, unexpected keywor                                                                         d_end, expecting end-of-input

RuntimeError: cd /var/www/discourse && su discourse -c 'bundle exec rake db:migr                                                                         ate' failed with return #<Process::Status: pid 19644 exit 1>
Location of failure: /pups/lib/pups/exec_command.rb:105:in `spawn'
exec failed with the params {"cd"=>"$home", "hook"=>"bundle_exec", "cmd"=>["su d                                                                         iscourse -c 'bundle install --deployment --verbose --without test --without deve                                                                         lopment'", "su discourse -c 'bundle exec rake db:migrate'", "su discourse -c 'bu                                                                         ndle exec rake assets:precompile'"]}
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages,                                                                          there may be more than one
1 Like

Seeing the same issue, yep

Retort is now causing rebuilds to fail.

1 Like

Ack, that syntax is valid as of ruby 2.1 (which was released in 2013…); is Discourse running all the way back on ruby 2.0 on rebuilds? :confused:

We are going to drop 2.0 after the next major release

At the moment we release on 2.0

2.1 and up have slightly higher memory reqs so we held off on the upgrade


Alright, I’ve updated the offending line and merged in the live update fixes.

Also it now does grouping, yay!


I’m wondering if this might be caused by a conflict with my own customizations, but is anybody else seeing the following in console after replying?

Uncaught TypeError: Cannot read property 'length' of undefined

Which points to:

api.decorateWidget('post-contents:after-cooked', function (dec) {
        var post = dec.getModel();
        Discourse.Retort = Discourse.Retort || { widgets: {} };
        Discourse.Retort.widgets[] = dec.widget;

      if (post.retorts.length === 0) {

And then it appears that it doesn’t properly close the submit-panel

This is on v1.5.0.beta11 +277. If nobody else is seeing it, it must be a conflict with my own plugins.

1 Like

You know there’s a really easy way to test that, right? :wink:

1 Like

Just installed - this plugin is working great! :clap: :raised_hands: :thumbsup:

Thank you @gdpelican and @cpradio for all your hard work! :slight_smile:


Thanks for the report, I’ve fixed this in the latest. :palm_tree:!


Hoping there will soon be a way to remove reactions. I added a couple of issues about this.

After a fun little muck about with the new plugin api features, I’ve updated this to use the virtual dom, and allowed for adding / removing reactions via click.


Great! I love it. You’re making very good stuff man


@gdpelican I noticed in your plugin you have:

import PostMenuComponent from 'discourse/components/post-menu';

However, I believe post menu has moved from a component to a widget. With that said though, it still seems to work, why?

EDIT: I see you are using that for priorToApi…and then for current version creating a retort widget?