Showing posts with label user macro. Show all posts
Showing posts with label user macro. Show all posts

Monday, October 14, 2019

Customizing Confluence: Last Modified Date

Introduction

At times of exporting content from Confluence, you may find yourself in a situation where a date stamp is required in the output files. Depending on your process for exporting content, by default, Confluence doesn't export time data (created or last updated) through its native means. If you have the budget, there are a number of plugins that can provide you with a macro to use in your documents but if you find your budget is tight, you can use the following code to create your own user macro to obtain a document's last updated date.

Required skills

You should be comfortable and/or knowledgable with the following:
  • HTML
  • jQuery
  • Creating user macros in Confluence
  • Modifying page layouts and space layouts in Confluence

Creating an user macro to display the last modified date

To create an user macro that display the last modified date, you can copy/paste the following code into your instance of Confluence:

Macro name: last-modified
Macro title: Last Modified
Description: Displays last modified date of the document.
Categories: Reporting
Macro Body Processing: No macro body
## @noparams
<span id="lastModifiedDate" style="font-size: 0.7em">Last Modified: $action.dateFormatter.formatDateTime($content.lastModificationDate)</span>


This simple little macro grabs the last modified date from Confluence and will display the value wherever you insert the user macro on your document. The font size is made to be purposely smaller so it won't be to noticeable on your document.

Modify layouts

If your process of exporting content includes the rendered HTML document, then instead of inserting a macro on every document can be replaced by updating the space layout with a little jQuery function to obtain the last updated date and insert it into the body of the wiki content element.

Note: Modifying the Content Layout of a space can be dangerous. If you remove a line from the Page Layout, you could corrupt the space and possibly make Confluence unstable. Use this method with care.

If you are using the Default Theme, insert the following code in Page Layout (Space Tools > Look and Feel > Layout > Create Custom under the Content Layouts in the Page Layout section) after the page setters:

<!-- last updated insertion -->
<script>
$(document).ready(function() {
$('div#main-content').append('<span style="font-size: 0.7em;">Last updated: ' + $('a.last-modified').text() + '</span>');
});
</script>
<!-- end last updated insertion -->

If you are using the Documentation Theme, insert the following code in the footer of the page layout:

<!-- last updated insertion -->
$(document).ready(function() {
$('div.wiki-content').append('<span style="font-size: 0.7em;">Last updated: ' + $('a.last-modified').text() + '</span>')
});
<!-- end last updated insertion -->


This method of inserting a last modified timestamp is, IMHO, the easiest and safest way to add a timestamp to every document in a space.

Tuesday, November 14, 2017

Build an user macro with parameters in Confluence

Overview

Continuing off of last month's post entitled "Build an user macro in Confluence", this document will show you how to write an user macro that accepts input from the user. We will be creating an feature that allows for page redirects in Confluence. The macro will accept two inputs from the user: 1- page title to redirect the current page to and 2- delay before current page is redirect (which should include a default of 10 seconds). From there, the macro will display a basic redirect message, derived in part from the user's input, and load the target page after the delay has passed.

For this tutorial, you should have completed either last month's tutorial and/or Guide to User Macro Templates, Velocity, and be comfortable with HTML and JavaScript.

Parameters

This user macro will take two user inputs: page title to redirect the current page to and a delay time. Let's take a look at these parameters and then break them down:

## @param URL:title=URL|type=string|required=true|desc=URL to redirect to.
## @param Time:title=Time|type=int|default=10|desc=Time to redirect (in seconds). Defaults to 10 seconds.


To declare a parameter, we use the ## @param <parameter name> definition. The parameter name can be anything as long as there are no spaces or starts with a number. It's a good habit to get into naming the parameter names by their purpose.

Next, we have the title of the parameter. The parameter is displayed in the macro's properties when entering the value for the parameter. Here, you can use any combination of characters and spaces as you see fit. The title value should be human readable.

To help the Confluence user macro determine what kind of value it is using and to make the user macro more user friendly, we define the type of input we are providing to the user macro. For the URL parameter, we declare the type to be a basic string (which means the value can be anything). For the Time parameter, we set the type to be int (integer (numbers only)).

For the URL parameter, we set a property called required to be true which tells Confluence that this parameter is mandatory. Not setting this parameter will result in an undefined value and thus disable the macro under it is defined.

For the Time parameter, we use the default property to provide the macro with a default value of 10 (seconds). This is a convenience for the user as they won't need to enter a value unless they want to use something other than the default value.

The last property in both of these parameters is the description (desc). This is the text that will be displayed in the user macro window when filling out the various parameters. You should strive to keep it short, simple, and direct to the point.

Macro Browser Information

As mentioned in the previous tutorial, you don't necessarily need to fill out every field in this section of the user macro but you are required to at least fill out the Macro Name and Macro Title. The others are up to you fill out as needed. But for this user macro I included the following values:
  • Macro Name: redirect
  • Visibility: Visible to all users in the Macro Browser
  • Macro Title: redirect
  • Description: Redirect current page to a new URL within a user specified time (seconds).
  • Categories: Navigation

Definition of User Macro

Since we won't be including any body information in this user macro, we'll set the Macro Body Processing to No macro body.

Template

For the template (code) of the user macro, we'll break it down into two sections: Setting Velocity variables and the rest of the code.

Setting Velocity variables

We set Velocity variable like this:
#set($variable=value)

For our macro's delay, we need to use the following to set up the input variable as milliseconds:

#set($timeOut= $paramTime + "000")

Here, we are setting the variable $timeOut to be the value of the Time parameter which the user supplies in the macro or the macro provides via it's default value.

Basic redirect message

Next, we need to set up the basic message that this page will redirect the current page to the target page.

<div id="redirectBox">This page will be redirected to <a href="$paramURL">$paramURL</a> in $paramTime seconds.</div>


Note the usage of the parameter variables and not the Velocity $timeOut variable so far. The code provides the wiki page with a few elements that displays a basic redirect notice and provides the user with a link in case the redirect function doesn't work automatically or the user wants to forego the delay and visit the target page sooner than later.

Redirect function

The last bit is the JavaScript function to redirect the page after the specified delay:

<script type="text/javascript">
  function Redirect() {
    window.location="$paramURL";
  }


  setTimeout('Redirect()', $timeOut);
</script>


Ideally, this JavaScript function would be included in a library that your Confluence server makes available globally but since it's a small and, hopefully, rarely used macro, it wouldn't hurt the page load time too much if we just include this function on every instance of the macro.

Complete macro code

## @param URL:title=URL|type=string|required=true|desc=URL to redirect to.
## @param Time:title=Time|type=int|default=10|desc=Time to redirect (in seconds). Defaults to 10 seconds.
#set($timeOut= $paramTime + "000")
<div id="redirectBox">This page will be redirected to <a href="$paramURL">$paramURL</a> in $paramTime seconds.</div>

<script type="text/javascript">
function Redirect() {
  window.location="$paramURL";
  }
setTimeout('Redirect()', $timeOut);
</script>



Resources

Saturday, October 14, 2017

Build an user macro in Confluence

As a tech writer, I often find myself using a good collection of Confluence macros in my documentation. So of the most commonly used macros are the table of contents, style, Jira issues, align, attachment, children display, html, and live search. There's actually dozens of macros that I utilize on a regular basis but I commonly use these in some in some combination with each other. For example, I use the table of contents macro nested within the align macro so I can avoid the dreaded long list of anchor links at the top of a document and have the table of contents listed in a floating (left) element so the content of the page can flow around it.

Wouldn't it be nice to combine some of these macros into one "uber macro"? In this tutorial, I'll walk you through the process to do just that: create a table of contents nested within a float left element.

User macro anatomy

Writing an user macro isn't for everyone. It requires some basic knowledge of how HTML and Confluence XML macros works. Plus any skills with CSS, JavaScript, jQuery, and Velocity would be to your benefit to create more advanced user macros. If you don't feel comfortable getting started with this tutorial, you can check out Guide to User Macro Templates by Atlassian for a good overview of what user macros templates are and how to write a basic user macro.

The typical anatomy of an user macro in Confluence looks something like this:
  • Macro settings
  • Macro definition
    • In-macro comments
    • Declaration of parameter usage (or not)
    • Template (macro code)
  • Detailed documentation (external to the macro)

Macro settings

Every macro must declare the following items:
  • Macro Name
  • Macro Title
These parameters of the user macro are required and the Macro Name should be all lowercase and unique. The Macro Title should reflect the Macro Name but you should be write it so it's human readable as this is the name of the macro that will appear in the macro browser.

The following macro settings are optional but highly encouraged to be filled out:
  • Visibility
    • You must decide if this macro will be available to everyone or to just the system admins
  • Description
    • This is the description of the macro that your users will see when selecting this macro from the macro browser
  • Categories
    • The macro browser can be sorted by different categories of macro. Choose yours accordingly. 
  • Icon URL
    • If an icon is not defined, Confluence will assign it a generic icon. For faster load times, the macro should be internal to your system. Historically, an icon can be hosted somewhere within the server as long as it is reachable by the standard user. Or, it could be hosted on a wiki page as an attachment.
  • Documentation URL
    • To say the least, this macro should be documented somewhere on the wiki

Macro definition

The Definition of User Macro is the section of the user macro that allows you to define the Macro Body Processing and it's Template.

Macro Body Processing options

The Macro Body Processing allows you to instruct Confluence how the macro should process the body before passing it your macro. The macro body is what gets display on the Confluence page, if the macro has a body that is.

Option for processing includes:
  • No macro body
    • Use this option if your macro does not utilize a body
  • Escaped
    • Use this option to render the contents of the body as HTML markup
  • Unrendered
    • HTML content will be processed before being rendered
  • Rendered
    • HTML content is rendered but doesn't guarantee that it will be rendered before the page finishes rendering. 
For our macro, we'll set this parameter to No macro body as we won't be utilizing any body elements.

Template

The Template is where you provide you macro with the code that it will utilize to render the desired results. You can use a combination of HTML and Confluence-specific XML elements, and Velocity.

In-macro comments

As an good code is well commented, user macros should utilize comments as well. To add a comment, you must use the #* comment *# format.

While it's not 100% necessary, it is helpful to include the two comments at the top of your macro: one sentence description (if the description is not filled out) and a link to it's documentation (if no link is provided for the Documentation URL). For the macro we will build in this tutorial, our comment should look something like this:

#* floatLeftToC is a left floating table of content *#
#* for more info, see <tiny url> *#

Parameters

Parameters allows the users to pass in options that the macro may use. Discussing the different options and features of macro parameters can be a whole tutorial in itself.

For the macro we are going to build, it won't take any options or parameters. Therefore, the parameter line in our code should look something like this:

## @noparams desc=Creates a left aligned floating table of contents

Code

For this macro, we want to wrap whatever content into a div element so we can float the element and it's content to the left of the page. To accomplish these, we can do the following:

<div style="float: left; margin: 0 10px 10px 0; padding: 5px 10px 5px 0; min-width: 50px; max-width: 250px; border: solid thin black; border-radius: 5px;">
  <ac:structured-macro ac:name="toc"/>
</div>

Ideally, the CSS would not be inline to the element we are using to wrap around the ToC. In my experience, the CSS should be a globally declared rule that Confluence makes available throughout your wiki.
Note: the border attributes in the style attribute is complete superficial. I like to use this when developing and/or debugging user macros that act as a container.

The nested structured-macro handles the table of contents thanks to a native Confluence macro.

Documentation

The documentation should include the following information:
  • Purpose
  • Usage
    • Intent
    • Parameters
  • Change history
  • Creator info
    • Name, email, etc.
  • Known issues and/or limitations
  • Links to related content
  • Attachment of the code
The purpose of the macro should be clearly defined with it's intent. One doesn't need to justify it's existence (as one assumes this macro was created out of a request or to fulfill an existing need).

The usage section should plainly define it's intended usage, and the parameters (if any) are used, and provide a few examples of the macro in use.

Depending on your work environment, you can include the change history of this macro (if you're not using Github or similar services). The same is true with the creator info and attachments of the code sections.

Depending on it's usage, you may want to include a section about known issues or limitations. While the macro should be designed to work with everything in the Confluence environment, it may not due to a multitude of reasons. Sometimes, the most innocent macro make work perfectly by itself but when combined with another, it may break the other itself or other macros. One recent example that comes to mind is a macro that wrapped a div element around an existing Confluence macro that changes the appearance of it via CSS. While this macro was written to only affect that one macro wrapped within it, it caused several issues with the non-wrapped macro on the same page.

Gotchas

It should be noted that if you have a typo anywhere in your macro's template, it will either fail to render the macro, display an error message, or at the worse, cause the page where the user macro is utilized to fail to render completely.
As a happy accident, while I was exploring which macro I should create, I failed to include the closing parentheses for some CSS rules. This caused the macro to not render and Confluence didn't inform me of anything wrong with the macro.