I’m working with Confluence to create a wiki for travel agents can record their research holidays. It is hoped that their colleagues can use first hand experiences of the resorts to promote them.
We wanted to have an easy and structured way for people to add pages, for which we’re using Confluence’s templates feature. Templates allow a two step page creation process:
- Enter information into a structured form (e.g. in our hotel page template, we ask for information on the food, accomodation and view), and select “insert variables” (I know, awful button title).
- Review what you’ve entered on the standard Confluence edit page (all the information from the form fields will have been inserted at the relevant points in the page).
A great piece of functionality but too many clicks involved. To create a templated page you have to:
- Click into the space administration section (already not ideal for a “regular” staff member)
- Select space templates from the menu
- Find the template you want
- Finally, select “create page from template”
With some technical jiggery-pokery I’ve managed to get this process down to one click, “create hotel page”, and I’ve done this without cracking into Java code (which is the programming language Confluence is written in).
The breakthrough discovery was that Confluence GET requests for this process. This meant I could create a link that would pass enough information so I could go straight to step 4 of the process above.
A quick diversion on POST vs GET: A form using GET sends it’s information by appending it to a URL (or web address); Google search is a good example of a GET form, have a look at the web address of a Google results page and you will see the words you searched for in the middle of a long string of other characters. A form using POST has a different method of sending the data, and does not append it to the URL. (Now back to my Confluence problem.)
The four pieces of information needed to make a page from a template are: the space key, the ID of new page’s parent, the title of the new page’s parent, the title of the new page and the ID of the template to use. To make a URL which would pass these pieces of information, I created a User Macro; User Macros are a way to define a site wide macro (i.e. Confluence wiki code). User Macros are created and edited from a page in the Confluence admin area.
Of the four pieces of information, the template ID was easiest to find: I looked at the web address in the link to edit the template, and there it was (e.g. pageTemplateId=1234).
Finding the ID of the parent was a bit more tricky, and I Googled around for quite a bit before discovering a way of getting it. There’s some Confluence data exposed in User Macros which you can use to add some limited additional information about the context of the User Macro (e.g. the page its in, the space that page is in, etc). One of the variables available is $content.id; when Confluence sees $content.id in a User Macro, it substitutes the ID of the current page when the User Macro is shown.
I could have hard coded the space key into the URL as it’s not going to change very often, but since I had discovered the use of variables in User Macros I wanted to be a bit smarter than that. Another variable available in User Macros is $space.key, which Confluence substitutes with the current space key (as you’d expect).
The user macro
My User Macro utilises the Adaptavist function compound-menuitem, which allows you to create a menu item and specify a custom URL for it. The completed User Macro looked as follows:
{compound-menuitem:custom|caption=make an activity page|link=/pages/createpage-entervariables.action?spaceKey=$space.key&parentPageString=@parent_title@&fromPageId=$content.id&title=@title@&linkCreation=false&templateId=360453|id=create_page}
You’ll need the following settings on the User Macro: untick “Macro has a body”, and set “Output” to “Macro generates Wiki markup”. You also need a unique value for the ID for every different User Macro.
You’ll notice that there’s two unspecified variables so far: the title of the parent page, and the title of the new page. I use a Javascript function to fill these in when the link is clicked.
The Javascript code
Once the link is on the page, we know (from the User Macro code above) the containing element will have an ID of “create_hotel”. From this we can write the following Javascript, using the excellent jQuery library (you’ll need to link in the jQuery library in order for this to work):
jQuery( document ).ready( docReady );
function docReady() {
initCreatePageButtons();
}
function initCreatePageButtons()
{
// Duplicate the next line and amend the text after the hash (#) to match your links
jQuery( '#create_page>ul>li>a' ).click( doCreatePage );
}
function doCreatePage()
{
var url = jQuery( this ).attr( 'href' );
// Fire a dialog to collect the new page title
var page_title_question = 'Please provide a title for your new page n(or press "cancel" to abandon creating the page)';
var page_title = requestPageName( page_title_question );
// If the user cancelled
if ( ! page_title ) {
// Return false, to prevent the link firing
return false;
}
// URL encode the page_title
var page_title_encoded = escape( page_title );
// Extract the page title from the H1 element. We could do this with Confluence in
// the user macro, using $content.title, but we can't URL encode from there so it's
// easier to do it here.
var parent_title_encoded = escape( jQuery( 'h1' ).text() );
// Replace the @parent_title@ token with the title gleaned from the dialog
var pt_re = /@parent_title@/gi;
url = url.replace(pt_re, parent_title_encoded);
// Replace the @title@ token with the title gleaned from the dialog
var t_re = /@title@/gi;
url = url.replace(t_re, page_title_encoded);
// Set the browser location to the new URL string
location.href = url;
return false;
}
function requestPageName( question )
{
var page_title = prompt( question, '' );
if ( page_title != null && page_title.length < 1 ) {
alert( "Sorry, but you must provide a page title for the new page." );
return requestPageName( question, '' );
}
// TODO: Validate title adheres to: page titles can not contain the following characters
// (:, @, /, , |, ^, #, ;, [, ], {, }, < , >) or start with ($, .., ~).
return page_title;
}
These functions do the following (not in order):
- jQuery( document ).ready calls the function docReady when the document is ready to be used by Javascript.
- docReady calls initCreatePageButtons.
- initCreatePageButtons sets the onClick event on the relevant links so they call the second function, doCreatePage, when clicked.
- requestPageName launches a prompt to the user for them to type in the title of the new page.
- doCreatePage does most of the work: it fires the third function, requestPageName, to get the title for the new page, then looks up the title of the current page and does a “find and replace” operation on the URL to create this new page, then it changes the location of the browser to the completed URL and begins the process of creating our templated page.
Including the Javascript on the page
Now I needed to include the Javascripts on the relevant pages, I used another User Macro for this. Create a new User Macro and paste in the following code:
<script src="http://www.someserver.com/somedir/jquery.js" type="text/javascript" language="JavaScript">
<script src="http://www.someserver.com/somedir/jq_functions.js" type="text/javascript" language="JavaScript"></script>
You’ll need the following settings on the User Macro: untick “Macro has a body”, and set “Output” to “Macro generates HTML markup”. Then you want to add this User Macro as early in the page as you can; I put it in the Header area in my Theme Builder Layout.
So, in summary
I wanted a one click way of creating pages in Confluence using a structured form to make it easy for people to create page of particular types (in my case to describe hotels, resorts, etc for a travel wiki). To do this, I use a User Macro to create a URL which, when selected and visited, will start this process (skipping the first few steps normally required). Some custom jQuery Javascript then prompts the user for a page title, does the final preparation on the URL and, ta da, the user’s got to the template entry page in one click.
Leave a Reply