The Admin's tale - User Macro filtering a Confluence table Edited

 admin.png

Once upon a time, there was a Confluence holding pages with very very large tables with lots of columns and even more rows. People used the browser's search function to jump to the data they need, but they asked for something that would hide all rows except the ones they were searching for. 

The Admin thought about it and this is what he found out:

What if one could add a search field on top of the table to filter out all unnecessary rows?

So, how can this be done? There is no built-in-feature like that and the admin didn't find a plugin for a reasonable prize, his budget was already spent for this year. So he decided to create a small custom user macro to implement this feature. 

User Macros can be implemented by Confluence administrators. The admin decides, whether the macro is just available for other admins or for all the other users when editing pages. 

The place where user macros are created is in the admin's section of Confluence. Here you find the menue item "User Macros".

Creating a new User Macro results in a form with these fields:

 usermacro5.png

Macro Name is the the name of the macro, of course... - but not the title of the macro (which is displayed in the macro browser).

Visibility - hide User Macros as long as they are not really really tested !

Macro Title - is displayed in the macro browser

Description - tell your users what your macro is doing - the description is displayed in the macro browser:

usermacro7.png

Next, the admin had to define, how the macro body should be processed. The processing options are described in detail on this page: https://confluence.atlassian.com/conf510/writing-user-macros-829077960.html

The admin tried a little bit and then decided that "No macro body" would be the right option, since the macro has just one parameter, but no body:

usermacro3.png

 So now take a look at the heart of the user macro, the template itself:

Each macro has a header consisting of these lines:

## Macro title: <your macro-title as stated above>
## Macro has a body: <Y or N>
## Developed by:
## Date created:
## Installed by:

I think, these parts are self-explanatory, but the next is not:

## @noparams

Parameter are the values, you enter when you click on a macro's edit button when you edit a page. So, yes, there are macros that don't have parameters. @noparams is the default.

But the admin thought, the user should decide, how wide the input field should be: short, medium, medium-long, long or full-width. These values were defined by Atlassian in their CSS and the admin used these, so that the new field has the look and feel of the other Atlassian page elements.

So he added the parameter as param0 to the template:

## @param 0:title=Length of the input field|type=enum|enumValues=short-field,medium-field,medium-long-field,long-field,full-width-field|default=long-field

And then, the user could set the length of the input field:

 usermacro4.png

Next, the admin had to define the input field. It is a regular HTML form with an input element. The class aui refers to the Atlassian User Interface CSS:

<form class="aui">
<input class="text $param0" type="text" id="searchInput" placeholder="Enter Search term"></form>

At last, the admin needed a script to filter out all the rows, where the search term is not included. He used JQuery, a "cross-platform JavaScript library designed to simplify the client-side scripting of HTML" (Wikipedia).

The Script is doing the following

  • if you type something into the field "searchInput", it hides every row of your table
  • then it looks at every row again: 
    • if it finds the term, the row is shown
    • if not, it stays hidden
  • table headers are always shown

And this is the script:

<script type="text/javascript">
AJS.$("#searchInput").keyup(function () {
var jqry = AJS.$
var rows = jqry("tr").hide();
if (this.value.length) {
        var data = this.value.split(" ");
        jqry.each(data, function (i, v) {
                rows.filter(":contains('" + v + "')").show();
        });
} else rows.show();
AJS.$('thead tr').show();
});
</script>

And this is how it looks on the Confluence page:

The unfiltered table:

 usermacro-unfiltered.png

 

The same table filtered with the term "12":

 usermacro-filtered.png

What's left?

This is just a very simple basic filter. Soon, the admin's people asked for more:

  • search in a specific column
  • filter with wildcard characters
  • filter a specific table (in this example, each table on the page is filtered with the one and only input field)

But the admin had a lot more things do do and so, this filter remained the same until now ...and they all lived happily ever after.

Maybe another admin will add some new features to the basic filter... Sometimes

And here is another Admin's Tale: Adding an image to the page title

13 comments

This is how I would do bullet point three ....

Set the macro body processing to Rendered. Put your table inside the macro body. Then in your template do something like this ...

## provides a unique number that can be used to target this user macro only
#set( $id = $action.dateFormatter.calendar.timeInMillis )

<div id="tableFilter$id">
$body
</div>

Now you can target each table individually in jQuery like this ...

AJS.$('#tableFilter$id tr')
Thomas Community Champion Apr 06, 2017

Hi Davin,

thank you for your suggestion! I will try that as soon as possible.

Very good article. Thanks for sharing!

Daniel Eads Community Champion Apr 12, 2017

Nice! The Table Filter and Charts plugin can provide this functionality as well as more gravy, but this is a great example of doing something with a user macro. There's a lot of possibilities without having to develop an entire plugin!

I love this, thanks for sharing! :)

 

Nice!  This is helpful!

Thomas Community Champion Apr 24, 2017

@Fabian, Daniel, Arni and David - thank you. I'm glad you like the article :-)

Dennis Guse Community Champion May 05, 2017

Thanks for sharing this useful article.

Thanks for sharing! Just implemented this and it's very useful. I like the fact that it doesn't require to move tables into a macro body, which can be really painful (especially if, for some reason, the macro gets broken and you have to move all tables out of the macro body again).

On a sidenote... is there a way to make this filter case insensitive?

Thomas Community Champion May 12, 2017 • edited

Hi Thomas, Hi Denis,

glad you like the article, thank you.

Making the filter insensitive should be no problem. But I have not implemented that yet. The ":contains"-part of the script will be a bit longer then. 

Here is an example script for case insensitive search: http://stackoverflow.com/questions/8746882/jquery-contains-selector-uppercase-and-lower-case-issue 

But, as I said, the Admin did not have the time to test that script yet :-)

 

This is great, thank you!  For anyone that is looking to make this filter work for a JIRA issues table, you can use the following modified javascript since the JQL tables do not include a 'thead' definding the header row.  Code includes a check looking for that row so that it works for both 'regular' and JQL (Jira issues) tables at the same time.

 

<script type="text/javascript">
AJS.$("#searchInput").keyup(function () {
var jqry = AJS.$
var rows = jqry("tr").hide();
var searchData = this.value;
if (searchData.length) {
        var data = searchData.split(" ");
        jqry.each(data, function (i, v) {
                rows.filter(":contains('" + v + "')").show();
        });
} else rows.show();
if (AJS.$('thead tr').length){
AJS.$('thead tr').show(); //show the header row for tables
}
else{
AJS.$('tbody tr').eq(1).show(); //show the header row for Jira-Issues Tables (no thead and first tr is empty, so show the second tr)
}
});
</script>

 

Unfortunately, I know next to nothing about javascripting (and currently lack the time to change this). My pathetic attempts at making the filter case insensitive were all for naught.

So I'm hoping for some nice person to step in. ;-)

Comment

Log in or Register to comment