Skip to content
sschafft edited this page Mar 28, 2013 · 17 revisions

This page explains the different ways that you can customize Mercury for your specific needs. One of the easiest ways is to add your own toolbar buttons to expose additional functionality, which you can do directly from the configuration.

Building Mercury (updating css and javascript etc)

There is a rake task that will compile the coffeescript into javascript assets -- this requires you to setup ruby and various gems to get the dev environment working.

You can setup the project like you would any ruby project (or just run from the git clone) and run rake mercury:build. You can use rake -T to get a list of all of the tasks.. the build tasks are all namespaced under mercury, so mercury:build:javascripts, mercury:build:stylesheets, etc.. but the mercury:build task runs all of them.

This will update the files in the distro directory.

Adding Actions (Buttons and Behaviors)

Let's say you want to provide some basic markup, like a title, paragraph tag, and a styled link. You can add a new button to the toolbar configuration (inside the mercury.js @ MercurySetup.config.toolbars.editable):

titleAndContent: ['Simple Markup', 'Inserts a title, paragraph tag, and a button']

Now, define a behavior for it in the behaviors section of the configuration (MercurySetup.config.behaviors):

titleAndContent: function(selection) {
  var url = prompt('Enter the link for the button');
  selection.replace('<div><h2>Title</h2><p>content</p><a href="' + url + '" class="button">button</a><hr/></div>');
}

That's it. Now you have a button that will insert a predefined set of markup, along with a user provided url. You can also style this button using your own methods, or by putting them inside the mercury_overrides.css. Here's some example CSS for a primary and editable button:

.mercury-primary-toolbar .mercury-inspector-button em,
.mercury-expander-button[data-button="inspector"] em {
  background-image: url(/assets/mercury/toolbar/primary/inspectorpanel.png);
}
.mercury-editable-toolbar .mercury-titleAndContent-button {
  background: url(/assets/mercury/toolbar/editable/title_and_content.png) no-repeat 0 0;
}
.mercury-editable-toolbar .mercury-titleAndContent-button.active {
  background-position: 0 -18px;
}

To change existing functionality you can follow a very similar pattern. Let's say you want to insert an image instead of an HR tag when a user clicks the Insert HR button. Because behaviors are used before the default actions defined in Mercury.Regions.Full.actions you can override existing behavior, which you can check for all the default actions.

Define a behavior in the configuration:

horizontalRule: function(selection) {
  selection.replace('<img src="/rule.gif" class="horizontal-rule">');
}

Now when a user inserts a horizontal rule, they'll actually get the image tag.

Modals, Panels, etc.

Modals and dialogs have the concept of a handler function. An example of setting the handler function can be seen in the configuration.

Mercury.modal('/mercury/modals/htmleditor.html', { title: 'HTML Editor', fullHeight: true, handler: 'htmlEditor' });

Note that the handler function is 'htmlEditor' in this example. If that method is found in Mercury.modalHandlers it'll be called while the modal, panel or whatever is being opened. The alternative is for buttons in the toolbar. In these cases the "name" of the button will be used.

insertLink: ['Link', 'Insert Link', { modal: '/mercury/modals/link.html', regions: ['full', 'markdown'] }]

In the above case, the handler function would be insertLink.

  • Mercury.dialogHandlers contains the methods for when selects, palettes, and panels are loaded.
  • Mercury.modalHandlers contains the methods for when modal windows are loaded (the one's that come down from the top and are centered).
  • Mercury.lightviewHandlers contains the methods for lightviews (the ones that are black and in the center of the window -- the about dialog for instance)

There's basically two ways to mix in your own handlers. The first is to define a method after mercury has loaded:

jQuery(window).bind('mercury:ready', function() {
  Mercury.modalHandlers.foo = function() { alert('foo') };
});

And the second is to define a method inside your configuration:

modalHandlers: {
  foo: function() { alert('foo') }
}

Now if you had a button named foo your function will be called when it's loaded.

foo: ['Foo', 'Foo', { modal: '/mercury/modals/link.html' }]

Note: To override existing functionality, you will have to include a script after the Mercury scripts that defines whatever method you want to change. For instance, if you wanted to change how the insertLink modal works, you can define a Mercury.modalHandlers.insertLink function after the mercury:ready event, or in a script that's included after the Mercury script has loaded (changing the predefined packages for the loader, or adding one into the mercury template if you're using Rails.)

Changing Functionality

If you want to change the functionality of Mercury, you'll have to dive into the source a bit more. But let's say you wanted to change how the PageEditor saves content (to make it use PUT instead of POST). You can configure a lot of this in the configuration, but if that falls short for your needs, you have a few options. If you want to work in coffeescript you're welcome to define a new file /assets/mercury/custom_page_editor.js.coffee and put something like the following:

class @Mercury.CustomPageEditor extends @Mercury.PageEditor
  
  constructor: ->
    super

  save: ->
    data = @serialize()
    Mercury.log('saving', data)
    data = jQuery.toJSON(data) unless @options.saveStyle == 'form'
    jQuery.ajax '/contents', {
      type: 'POST'
      data: {_method: 'PUT', content: data}
      success: =>
        Mercury.changes = false
      error: =>
        alert("Mercury was unable to save.")
    }

Instead of instantiating Mercury.PageEditor, you can instantiate Mercury.CustomPageEditor and saving will be an update action instead of a create action. For instance, inside your mercury.html.erb change the line that says new Mercury.PageEditor(saveUrl, options); to new Mercury.CustomPageEditor(saveUrl, options);.

Alternatively, and perhaps more simply, in javascript just put the following after Mercury.PageEditor has been defined:

Mercury.PageEditor.prototype.save = function() {
  var data = this.serialize();
  Mercury.log('saving', data);
  var data = jQuery.toJSON(data);
  jQuery.ajax('/contents', {
    type: 'POST',
    data: {_method: 'PUT', content: data},
    success: function() { Mercury.changes = false },
    error: function() { alert("Mercury was unable to save.") }
  });
};

Writing / Using Plugins

Writing Plugins

The project includes a simple plugin that will serialize the data for save as XML instead of JSON, or form data. This is provided as a simple example of how you can start, and only uses coffeescript in it's examples. You can check out the example plugin source as a simple tutorial.

Using Plugins

Just include the plugin you'd like to use after the mercury assets have been loaded.