VisualEditor/Gadgets/Add a tool

This page shows you a commented example for writing gadgets for the VisualEditor: The code creates an entry in the toolbar to insert a template with parameters.

Example code
To test the following code, you can execute it in your browser's console before VE is loaded and then start editing in VE, i.e., click "Edit". The new tool will be available under "Insert" → "More" → "My tool".

Explanation
Let's have a look at what the above code does:

Create and register command
First we create and register a command to insert our template. The variable  stores the VE-representation of the template we want to insert, it corresponds to the wikitext. The format is similar to XML: It starts with an opening tag (, use  for an inline template) with some attributes (the name of the template and the parameters) and is followed by a closing tag (preceded by a slash). If you want to see the data for the current page, just execute  in the browser console while editing.

To create and register the command we create a new instance of  (documentation) and register it with the. Let's have a look at some of the parameters: The parameters for the method are specified in the  array:
 * : That's the internal name of the tool. You should choose it in a way that makes it unique. If you are using scripts by other authors, too, you could prepend your username to make sure nobody else uses the same identifier.
 * , : That's the action and method we want to execute. In this case we use the   method of   (documentation) to insert our template.
 * The first entry is the content we want to insert. We stored it in the  variable above.
 * Next comes a flag whether the new content should take the current annotation. We set it to . This means that even if the cursor is inside an italic or bold text when the user inserts the template, the template will not take that text format.
 * Last comes another flag whether the selection should be collapsed, or whether the new content should be selected. We set it to, so the template will not be selected.

Create and register wikitext command
A source code editor mode inside VE is currently under development. Actually the following code isn't necessary, if you don't add it, the source code editor will use the above command and just work as expected. But you can tweak the command a bit for wikitext if you want to.

We wrap the code in an -clause, so it will not break when the wikitext editor isn't available. The code itself is very similar to the code that creates and registers the default command. We use the same name for the command. Actually we could even use the  method from above, only with wikitext instead of our   variable. But let's use the  method from   (documentation) instead. As above we specify the parameters in the  array: The content that should go before the cursor, the content to go after it, and the content that should be inserted and selected in the middle unless there is already a selection. If you programmed with the traditional wikitext editor before, you will now these parameters as,   and.

Create and register tool
Now that we have our command we create and register a tool to invoke it from the toolbar. To do so we create a new class, inheriting from   (documentation). To learn more about how inheriting works, you should read the OOjs documentation.

Note the, which will be shown in the toolbar, and the  , which links the tool to our command. Registering the tool is all we need to include it in the toolbar, as the definition has a “catch all” rule to include all tools that haven't been included explicitly (code). There are some more options you can configure, e.g. the icon (list of available icons, make sure to use a lowercase first letter, but otherwise keep the capitalization).

If you want the tool to be shown in some other place, you could change the. E.g. setting it to  will show the tool among the other text style tools.

Initialize
The initialization code makes sure the code is executed at the right time: After all necessary modules have been loaded, but before the editor is initialized.

Alternatively, you can split it up into two scripts. First, an unconditional script that listens for when VisualEditor is used, and then calls  to load the second script:

The second script then only contains the main plugin content, which would otherwise be inside the  function.

If you need to use additional modules as dependencies within the registration statements of your plugin, you can delay it by calling  first:

More ideas
Here are some more ideas to try out yourself.

Keyboard shortcut
Perhaps you don't want to use the mouse to insert the template but want to use a keyboard shortcut. No problem, create and register a trigger (documentation):

Keyboard sequence
Or you want the template to be inserted when you type. Create and register a sequence (documentation): The 3 at the end is the number of characters that should be deleted, in this case the length of.

Help entry
The sequence isn't obvious, so you might want to add it to the help dialog. You probably guessed how to do that: Register an entry with the correct registry. The registry is called, why don't you look up the documentation and try it yourself?

Open a dialog
Perhaps you want to open the dialog to edit the template parameters after inserting the template. To do so we use a custom command: This command just inserts the content as above, but then also opens the transclusion dialog for the selected content. Instead of the original command you now have to register this new command: We defined the command in such a way that the parameters are almost the same, you have to leave out the action and method, and you don't need to specify the “collapse to end” option, because the template will be selected anyway.

Add your own "toolgroup"
Adding a top-level group to the toolbar in a specific position is slightly complicated, due to the initialization order involved and how the toolbar's contents are specified. There's two approaches that you can take, depending on whether you can be confident your code will be loaded before or after VE is initialized.

If before, you can just add this to the example above. It will define a group and add it to the toolbar configuration that'll be used to create the toolbars. ...and adjust your tool definition to: If you can't guarantee that your code will be loaded before the VE surface is initialized, you can instead listen for the hook  and then use the   method of the already-initialized VE's toolbar object to add additional toolbar groups.