Tutorial: Implementing a Custom Action

Implementing a Custom Action

In order to provide custom functionality to the editor, one can implement a custom action and add it to one of the toolbars, in the context menu or on a oxy_button form control.

We will consider the case of an action that converts a piece of XML content to a web link in DITA. The action will have to extend the sync.actions.AbstractAction class. A sample implementation is provided below.

/**
 * The action that shows a popup and then inserts the text in the pop-up.
 */
WebLinkAction = function(editor) {
  this.editor = editor;
};
// shortcut is Meta+L on Mac and Ctrl+L on other platforms.
WebLinkAction.prototype = new sync.actions.AbstractAction('M1 L');

WebLinkAction.prototype.getDisplayName = function() {
  return 'Convert to Web Link';
};

// The actual action execution.
WebLinkAction.prototype.actionPerformed = function(callback) {
  var text = window.prompt("Please enter the link attribute");
  if (text) {
    this.editor.getActionsManager().invokeOperation(
      'ro.sync.ecss.extensions.commons.operations.SurroundWithFragmentOperation', {
        fragment: '<' + 'xref href="' + text + '"/>'
      }, callback);
  } else {
    callback && callback();
  }
};

The action needs to be registered with the editor. This should be done before the editor is loaded so that the shortcut start working immediately:

goog.events.listen(workspace, sync.api.Workspace.EventType.EDITOR_LOADED, function(e) {
  var editor = e.editor;
  // Register the newly created action.
  editor.getActionsManager().registerAction('insert.link', new WebLinkAction(editor));
  addToDitaToolbar(editor, 'insert.link');
});

We also want to add the action on the DITA toolbar. To this end, we need to wait for the toolbar to be loaded and append our action to it:

function addToDitaToolbar(editor, actionId) {
  goog.events.listen(editor, sync.api.Editor.EventTypes.ACTIONS_LOADED, function(e) {
    var actionsConfig = e.actionsConfiguration;

    var ditaToolbar = null;
    if (actionsConfig.toolbars) {
      for (var i = 0; i < actionsConfig.toolbars.length; i++) {
        var toolbar = actionsConfig.toolbars[i];
        if (toolbar.name == "DITA") {
          ditaToolbar = toolbar;
        }
      }
    }

    if (ditaToolbar) {
      ditaToolbar.children.push({
        id: actionId,
        type: "action"
      });
    }
  });
}

The action should appear in the toolbar. In order to use it:

  1. select some text
  2. click the action button on the toolbar
  3. enter the link target address
  4. confirm the prompt

The text should now be converted to a web link.

More advanced use-cases

For a better UX, instead of a native browser prompt you can use a custom JavaScript dialog. You can find more details in the Presenting a dialog to the user tutorial.

If the dialog requires the user to provide a reference to a file, you can invoke workspace.getUrlChooser() to obtain a reference to the CMS-specific file chooser.

For the actual document edit usually the InsertFragmentOperation or SurroundWithFragmentOperation is enough. If not, you can also have a look at other builtin operations in the JavaDoc or even implement your own subclass of AuthorOperation.