Accessing the createTopic action while on a topic route

javascript
plugins

(Angus McLeod) #1

I’m trying to write a little plugin to add a “New Topic” button to the header bar that is accessible on any page, including topic pages.

I know that some of you fellas aren’t a fan of this idea, but if you could humor me on this specific code issue I’m having it would be much appreciated.

I added the button without too many dramas, by overriding the header.hbs template. Simply by adding the template, the button works on “discovery” routes, as the the createTopic action is already available on those routes.

But it doesn’t work inside actual topics. It throws the error “Nothing handled the action ‘createTopic’”. Which, I have assumed, means I just need to make that action available in any topic. I’m largely making educated guesses based on how other parts of discourse function and what I read here, so I could be off-base.

My problem is that I can’t quite seem to get the createTopic action into (whatever is) the relevant controller.

These are the last two js iterations I’ve tried (separately of course):

Discourse.TopicRoute.on("setupTopicController", function(event) {
  Discourse.ObjectController.reopen({
    actions: {
        createTopic: function() {
        Discourse.__container__.lookup('controller:composer').send('open', {action: Discourse.Composer.CREATE_TOPIC, draftKey: Discourse.Composer.DRAFT});
        }
      }
  });
});
Discourse.TopicRoute.on("setupTopicController", function(event) {
  Discourse.ObjectController.extend({
    actions: {
        createTopic: function() {
          return this.get('controller.composer').open({
            categoryId: controller.get('category.id'),
            action: Discourse.Composer.CREATE_TOPIC,
            draftKey: controller.get('draft_key'),
            draftSequence: controller.get('draft_sequence')
          });
        }
      }
  });
});

Thanks in advance for any advice / pointers.


Open Composer with Prefilled information
How do you force a script to refire on every page load in Discourse?
(Kane York) #2

Note that you can also just use the c keyboard shortcut to do this.


ObjectController is a base class, you shouldn’t really be editing that… And your changes aren’t going to ever get used.


(Angus McLeod) #3

Right, this is actually where I got the function for first attempt listed above :slight_smile:

https://github.com/cpradio/discourse/commit/e013694734e5afe136e44937010106fd23d44910

ObjectController is a base class, you shouldn’t really be editing that… And your changes aren’t going to ever get used.

Any clue on what I should be editing instead to achieve my objective?

Perhaps I can ask the button to call something instead of the createTopic action?

Or am I just being dense :blush: ?

Thanks


(Kane York) #4

The cheesiest way I can think of doing it is defining createTopic as an action on ApplicationRoute, so Discourse.ApplicationRoute.reopen({ actions: { ... }});

That’s the Simplest Thing That Could Possibly Work.


(Angus McLeod) #5

@riking I finally got it working!

This is the js that worked:

Discourse.ApplicationRoute.reopen({
  actions: {
      createTopic: function() {
        composerController = Discourse.__container__.lookup('controller:composer')
        composerController.open({
        action: Discourse.Composer.CREATE_TOPIC,
        draftKey: Discourse.Composer.DRAFT
        })
      }
    }
});

I think I understand what the error message actually means now as well (“bubbling up” is a somewhat confusing metaphor), based on your pointer and these docs: http://emberjs.com/guides/templates/actions/

Cheers!


(Alexis Duran) #6

Hi, this reply may get too late and the code may be also deprecated, but I will try anyway. Where do you place this code? I want to open the composer with some prefilled information and I thing I can define an action as you do with params to prefill the composer object.


Issue open pre-filled composer
(Angus McLeod) #7

Wow this is a bit of throwback :slight_smile:

Note that @duranmla’s query has been dealt with here.

If anyone else comes across this, the way you add or override an action on a particular route is via the plugin api. e.g.

withPluginApi('0.8.18', api => {
  api.modifyClass('controller:topic', {
     actions: {
       // add or override an action
     }
  })
})

(Alexis Duran) #8

@angus is me again, sorry to bother but I am trying to use the approach to create a new action in a controller (I got an error if I try with controller:application or controller:header, but that’s no the issue) I have tried:

      api.modifyClass('controller:topic', {
         actions: {
           toggleCategoryBar() {
             console.log('hello');
           }
         }
      });

Nad rendering a button within the header that looks like:

              this.attach('button', {
                className: 'li.btn-flat.header-tag-toggle',
                action: 'toggleCategoryBar'
              }, h('i.icon.icon-icn_08tag'))

The event gets’ dispatched but the console shows:

toggleCategoryBar not found

So seems like the actions is not being created, Do you have any clue? Maybe I should open another topic for this. Cheers! Hope not bother.


(Angus McLeod) #9

Ah I see the confusion. In the first post in this topic (back in 2015), I mentioned I was trying to add a button to the header. My updated answer above about using the pluginApi relates generally to the task of adding an action to a route (i.e. the title of the topic), not specifically to the task of adding a button in the header.

Since 2015 the header has been ‘widgetized’. Typically actions relating to a virtual dom widget belong in the widget they are used, or they are passed up the widget hierarchy. There’s an explanation of how actions work in widgets here:

So in your case the action belongs in the header widget itself. Add it to the header widget however you added the button.