Plugin Tutorial #1 - How to manipulate the text in the composer?


(Régis Hanol) #1

So, you want to manipulate the text in the composer but have no idea how? Let met guide you through the creation of a basic plugin that will turn the text into Pirate Speak.

:tada: Update August 2018: you can create a complete discourse plugin skeleton in your plugins directory with Rails plugin generator :tada:

First of all, you need to create a plugin.rb file that will be your entry point.

# name: pirate-speak
# about: plugin that transform the text into pirate speak
# version: 0.1
# authors: Régis Hanol

register_asset "javascripts/pirate_speak.js", :server_side

I highly recommend that you add at least the following pieces of meta data:

  • name: the name of your plugin
  • about: a one line description of your plugin
  • version: the version of your plugin

Then you can add the code of your plugin. Here, we’re only registering a javascript asset that will also be used on the server side. Why? Because we use the same javascript code for baking and cooking (ie. post processing) the posts on the client-side and on the server-side. If you want your text-manipulation plugin to work properly, you have to indicate that this file must be used when post-processing the posts on the server, hence the :server_side argument.

Let’s have a look at the file we’ve just registered:

function piratize (text) {
  return text.replace(/\b(am|are|is)\b/ig, "be")
             .replace(/ing\b/ig, "in'")
             .replace(/v/ig, "'");
}

Discourse.Dialect.postProcessText(function (text) {
  text = [].concat(text);
  for (var i = 0; i < text.length; i++) {
    if (text[i].length > 0 && text[i][0] !== "<") {
      text[i] = piratize(text[i]);
    }
  }
  return text;
});

First, there’s our core function: piratize. It takes a string as argument and uses regular expressions to transform the text into a basic pirate speak. You are more than welcome to improve that function and submit pull requests :wink:

But the most important part is the call to the Discourse.Dialect.postProcessText function. This tells Discourse to call our anonymous function whenever the text in the composer/post needs to be post-processed. The text argument might be a string or an array of string. That’s why we use text = [].concat(text) at the beginning to convert that string into an array if needs be. Then we go through the array and call our piratize function for each element in the array except when the element is an html tag (ie. it starts with a <). Finally, we return the text array so that it can be used in the rest of the post-processing pipeline.

The finished Pirate Speak plugin source code is available on GitHub if you want to have a look.

Another great example is @sam’s ALL CAPS plugin which converts the text to UPPERCASE.

Also, if you want advanced text manipulation plugins, you might want to check out


Basic plugin template
Installing javascript only plugins as admin
Help me debug plugin
"How to tinker your discourse" advice for beginners using the Docker install?
How to rewrite some URLs in posts (Amazon Affiliate)
Converting keywords in posts on the fly
Dynamic replace string to another
Hiding uploaded files for specific users
Help me debug plugin
Posts on-save processing with regex/replace configurable in admin panel
Allow reply-to individual instead of topic/forum (mailing list feature)
TypeError: Discourse.Dialect.postProcessText is not a function
Bootstrap-style labels as markdown
Moving the discourse search box and making it functional - how?
(Nelson) #2

Good tutorial!

I am also looking for ways to add hook into the backend controller (ruby-side). It would be great to have a tutorial as well.


(Rémi Rousseau) #3

Thanks for the tutorial! This is really useful!


#4

I want to override the youtube one box. Is it possible to do it from with a plugin? I inspected a littlebit the libs and I’m not sure if I can do that with a plugin.

Just want to update the width of the videos, to has a wider view, more similar to youtube. I was wondering if that can be done with a plugin.

Tks!


(NomNuggetNom ) #5

How can you not run adjustments in code blocks or other raw text, without resorting to a "<" check?


(Claus Strasburger) #6

You could look at this piece of code to override the whole plugin – extend my plugin, I’d be happy about pull reqs :smile:


(Tuan Anh Tran) #7

i added this to app.yml to test and it doesn’t seem to work.

any idea how to check if the plugin is properly loaded?


(Jay Pfaffman) #9

This tutorial doesn’t work with the new plugin scheme, right?

My trivial doi resolver quit working a couple upgrades ago & I’m assuming that’s why.

I’m working on re-writing my plugin based on the current Spoiler Alert. Once I do that, should I submit a PR for Pirate Speak? It seems that having a trivial plugin example is pretty valuable for novices like me.

Similarly should this brand new plugin interface post be archived?


Beginner's Guide to Creating Discourse Plugins - Part 1
#10

I’m very new to git and plugin stuff, but I made a pull request according to @cpradio’s comment.

I’ve also been trying to enable a similar fix for the doi resolver, but haven’t been able to make it work in my dev setup…