Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Earn badges and make progress

You're on your way to the next level! Join the Kudos program to earn points and save your progress.

Deleted user Avatar
Deleted user

Level 1: Seed

25 / 150 points

Next: Root


1 badge earned


Participate in fun challenges

Challenges come and go, but your rewards stay with you. Do more to earn more!


Gift kudos to your peers

What goes around comes around! Share the love by gifting kudos to your peers.


Rise up in the ranks

Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!


Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
Community Members
Community Events
Community Groups

FUME – A Better Confluence User Macro Editor Experience

One of the best and most overlooked aspects of Confluence is user macros. There are so many useful scenarios for user macros. Here are some:

  • Templated snippets
  • Overriding built in macros example with task list report
  • Quickly creating your own macros
  • Inserting arbitrary html/css/javascript into a page without having to enabled the html macro

However, there are some big usability issues with the user macro editor. First it’s super easy to accidentally delete one. The delete link is right next to the edit link and seriously, there is no confirmation on the delete link. It’s just gone. Ack!

Second, the link to create new user macros is at the bottom of the page. If you have more that what can fit on a screen you have to scroll down to get to the link to create a new one … this just gets worse over time as you create more.

Third, the template box in the editor is just a plain old text area … no line numbers, not syntax highlighting, it’s not even a mono-spaced font! Grr!

Fourth, the cancel button doesn’t ask you to confirm canceling the edit if you have made changes to the user macro and since it sits right next to the save button it’s easy to miss. Hope you can recreate your work quickly.

Finally, every time you save it kicks you back to the list page. So, if you want to make some changes and try it out on a page you have to click back into the editor every time you save and whoops you accidentally just clicked delete instead of edit! There goes all that work.

So, without further ado … FUME. Fantastic user macro editor. The fantastic part is really just because I needed a word that ended in “ume” and that was the only word I could think of. Really it’s not all that fantastic … maybe just great, but gume isn’t even a word. Then I thought “How about  great looking user macro editor”, but that would be glume and … well … yeah, that kinda defeats the purpose. So, FUME it is. All in all I think it is a much better editing experience than the default setup. Here are some of the features:

  • Copy that “Create a User Macro” link to the top of the list page … no more scrolling
  • Delete confirmation on the list page
  • Template box changed to a source code editor with (Ace editor):
    • monospaced font
    • line numbers
    • syntax highlighting
    • find and replace
    • code folding
    • column select
  • Confirmation on cancelling edits of the user macro if the template has been changed
  • Asynchronous user macro saves
  • It will do your dishes and laundry … ok, not quite yet

Update 4/9/2018:

Ignore the "How to Setup" section below. I'll leave it there, however, for the sake of continuity. After a good kick in the pants from @Boris Berenberg - Atlas Authority I packaged this up as an add-on. I named it Enhanced User Macro Editor (EUME ... pronounced you-me ... it's a stretch I know). It seemed a bit more humble of a name and is more descriptive of what it is. I hope it is as useful for you as it has been for me. Marketplace link below.

Enhanced User Macro Editor

How to Setup

  • Copy the below CSS and Javascript into files on your machine fume.css and fume.js respectively.
  • Place them on a web server where they will be web accessible to your user macro editors.
  • Add this to the end of Confluence Admin -> Custom HTML -> At end of the BODY
    • <!--
      * Fantastic User Macro Editor           *
      <link rel="stylesheet" type="text/css" href="http(s)://{your server}/path/to/fume.css">
      <script src="http(s)://{your server}/path/to/fume.js" type="text/javascript"></script>
  • Enjoy editing your user macros.  :-)


    margin-right: 5px;

    margin-left: 5px;
    font-weight: bold;

.ace_editor {
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace !important;
    border: 1px solid gray;
    border-radius: 3px;
    color: #333 !important;

.invisible {
    visibility: hidden;

.saved {
    color: #59DB4D;

.error {
    color: #FF0000;


AJS.toInit(function() {

//FUME = Fantastic User Macro Editor
var FUME = {
    editorJQuery: 'userMacro\\.template',
    nameJQuery: 'userMacro\\.name',
    titleJQuery: 'userMacro\\.title',
    editorDiv: 'userMacroEditorDiv',
    isNew: function(){
        return AJS.$('#user-macro-form').prop('name') == 'addusermacro' ? true : false;
    editor: null,
    isDirty: false,
    init: function() {
        var t = this;
        //What page are we on?
        var url = window.location.pathname;

        //If it is the user macro list page do this stuff
        if(url.indexOf('usermacros.action') != -1) {
            //Put a copy of the create user macro link at the top of the page.
            //Verify that you really want to delete the user macro
                var macroKey = AJS.$(this).parent().parent().attr('data-macro-key');

                if (!confirm('Do you really want to delete the "' + macroKey + '" user macro?')) { 
        //If it is the user macro edit page do this stuff
        if(url.indexOf('addusermacro-start.action') != -1 || url.indexOf('updateusermacro-start.action') != -1) {
            AJS.$('#' + t.editorJQuery).css('visibility', 'hidden');
            AJS.$('#' + t.editorJQuery).css('height', '800px');

            //Load ACE editor
            AJS.$.getScript('//', function () {
                //Get editor textarea
                var textarea = AJS.$('#' + t.editorJQuery);

                //New editor div
                var editDiv = AJS.$('<div id="' + t.editorDiv + '">').insertBefore(textarea);
                AJS.$('#' + t.editorDiv).css({
                    'position': 'absolute',
                    'width': textarea.width(),
                    'height': textarea.height(),

                t.editor = ace.edit(editDiv[0]);
                t.editor.getSession().on('change', function () {
                    t.isDirty = true;

            //Change up the cancel button a bit

            //Add save spinner
            AJS.$('#confirm').before('<span id="savespinner" class="aui-icon aui-icon-wait invisible">Saving...</span> ');

            //Add ctrl+s keyboard shortcut for save

            //Add clicked attribute to submit buttons when they are clicked so that I can tell which was clicked in the form submission event
            AJS.$('form input[type=submit]').click(function(){
                AJS.$('input[type=submit]', AJS.$(this).parents('form')).removeAttr('clicked');
                AJS.$(this).attr('clicked', 'true');

            //Set up the save to be asynchronous
            AJS.$('#user-macro-form').submit(function(event) {
                var clicked = AJS.$('input[type=submit][clicked=true]').val();
                var err = "";
                //If Save button was clicked then do asynchronous stuff.
                if(clicked === 'Save'){

                    if(AJS.$('#' + t.nameJQuery).val() === "") {
                        err += '* User macro name cannot be empty<br>';
                    if(AJS.$('#' + t.titleJQuery).val() === "") {
                        err += '* User macro title cannot be empty<br>';
                    if(AJS.$('#' + t.editorJQuery).val() === "") {
                        err += '* User template cannot be empty<br>';
                    if(err === "") {
                        //disable save button and show spinner
                        AJS.$('#confirm').attr('disabled', true);

                        if(AJS.$('#savedstatus').length > 0) {

                        //Do the asynchronous save
                            type: 'POST',
                            data: AJS.$(this).serialize(),
                            url: AJS.$(this).attr('action'),
                            success: function(data) {
                                //hide the spinner, re-enable the save button, display status, and clear dirty flag
                                AJS.$('#confirm').attr('disabled', false);
                                AJS.$('#cancel').after('<span id="savedstatus" class="saved">Saved</span>')
                                t.isDirty = false;
                                //if this is a new user macro redirect to new url
                                if(t.isNew()) {
                                    location.href = AJS.Meta.get('base-url') + '/admin/updateusermacro-start.action?macro=' + AJS.$('#' + t.nameJQuery).val();
                            error: function() {
                                //hide the spinner, re-enable the save button, and display status
                                AJS.$('#confirm').attr('disabled', false);
                                AJS.$('#cancel').after('<span id="savedstatus" class="error">Error saving</span>')
                    } else {
                        t.postErrorMessage('Error', err);
                } else {
                    if(t.isDirty) {
                        if (!confirm('Changes have been made. Do you really want to close and lose those changes?')) { 
    postErrorMessage: function (title, body) {
        var errorFlag = AJS.flag({
            type: 'error',
            title: title,
            body: body


User Macro ListUserMacroListPage.png

User Macro Template EditorUserMacroTemplateEditor.png


Have you considered just putting this into a plugin? Shouldn't be too hard, and then it doesn't require self hosting of the assets. Plus users would get updates as you evolve the tool.

I've totally thought about it, but then I would have to learn how to create a Confluence add-on. :) I fear that if I try to cram another programming environment into my head it might actually explode. But maybe this is a good place to start with actually learning the Confluence SDK. Well shoot, now you have me thinking about learning something new! :)

Voluptuous User Macro Editor? Volume!

There's also assume... Okay I'm done ;)

This is kinda amazing though... I gave up on a project to create a user macro 'cause I deleted it on accident and didn't have a backup.

Bill Bailey Community Leader Mar 29, 2018

I started using Notepad++ with Velocity highlighting. Works really well.

Incredibly useful.

Ditto on putting this into a plugin, if you need help, don't hesitate to reach out.

One other note, if you post a license for this code, then someone else could build the plugin for you 😉

So, @Boris Berenberg - Atlas Authoritythrew down the gauntlet and I took it up. Thanks for the push. It took me a few days to figure out how create an add-on and how to bundle it up (I'm a .NET guy not a Java guy). But anyway ... success!! I submitted it to the marketplace a few days ago and once it is approved I will edit the above article and post a link to the add-on.

In fact I've already got v 1.1.0 waiting to push to the marketplace once v1.0.0 gets the go ahead. So good call @Boris Berenberg - Atlas Authority.

Okay THAT is cool. Good job :)

Alrighty it's up. Here's the link.

Enhanced User Macro Editor

As of today version 1.2.0 is up on the marketplace. This version adds the ability to have user macro changes saved as historical versions.


Log in or Sign up to comment

Atlassian Community Events