Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in
Deleted user
0 / 0 points
Next:
badges earned

Your Points Tracker
Challenges
Leaderboard
  • Global
  • Feed

Badge for your thoughts?

You're enrolled in our new beta rewards program. Join our group to get the inside scoop and share your feedback.

Join group
Recognition
Give the gift of kudos
You have 0 kudos available to give
Who do you want to recognize?
Why do you want to recognize them?
Kudos
Great job appreciating your peers!
Check back soon to give more kudos.

Past Kudos Given
No kudos given
You haven't given any kudos yet. Share the love above and you'll see it here.

It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

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.  :-)

CSS

#savespinner{
    margin-right: 5px;
}

#savedstatus{
    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;
}

JS

AJS.toInit(function() {
    FUME.init();
});

//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.
            AJS.$('#user-macros-admin').before(AJS.$('a[href="addusermacro-start.action"]').clone());
            
            //Verify that you really want to delete the user macro
            AJS.$('a.remove').click(function(event){
                var macroKey = AJS.$(this).parent().parent().attr('data-macro-key');

                if (!confirm('Do you really want to delete the "' + macroKey + '" user macro?')) { 
                    event.preventDefault();
                }
            });
        }
        
        //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('//cdn.jsdelivr.net/gh/ajaxorg/ace-builds@latest/src-min-noconflict/ace.js', 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.setShowPrintMargin(false);
                t.editor.setTheme('ace/theme/textmate');
                t.editor.getSession().setMode('ace/mode/velocity');
                t.editor.getSession().setValue(textarea.val());
                t.editor.getSession().on('change', function () {
                    textarea.val(t.editor.getSession().getValue());
                    t.isDirty = true;
                });
            });

            //Change up the cancel button a bit
            AJS.$('#cancel').removeClass('aui-button-link');
            AJS.$('#cancel').addClass('submit');
            AJS.$('#cancel').val('Close')

            //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
            AJS.whenIType('ctrl+s').click('#confirm');

            //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'){
                    event.preventDefault();

                    //Validation
                    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);
                        AJS.$('#savespinner').removeClass('invisible');

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

                        //Do the asynchronous save
                        AJS.$.ajax({
                            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.$('#savespinner').addClass('invisible');
                                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.$('#savespinner').addClass('invisible');
                                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?')) { 
                            event.preventDefault();
                        }
                    }
                }
            });
        }
    },
    postErrorMessage: function (title, body) {
        var errorFlag = AJS.flag({
            type: 'error',
            title: title,
            body: body
        });
    }
};

Screenshots

User Macro ListUserMacroListPage.png

User Macro Template EditorUserMacroTemplateEditor.png

13 comments

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.

Davin Studer Community Leader Mar 29, 2018

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 😉

Davin Studer Community Leader Apr 06, 2018

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.

Davin Studer Community Leader Apr 06, 2018

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 :)

Davin Studer Community Leader Apr 09, 2018

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

Enhanced User Macro Editor

Davin Studer Community Leader Aug 22, 2019

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.

Comment

Log in or Sign up to comment
TAGS
Community showcase
Published in Marketplace Apps & Integrations

Staying organized with Jira: best practices for a better project management

Project managers know this problem: A “mountain of work” lays in front of you, and you don’t know how and where to tackle them. Different to-dos lie ahead, but just one task after the other can be ha...

362 views 2 1
Read article

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you