This documentation relates to the latest version of Confluence.
If you are using an earlier version, please go to the documentation home page and select the relevant previous version.

Including Javascript and CSS resources

Confluence 2.8 Documentation

Index

Good style for web applications requires that Javascript and CSS for web pages are kept separate to the HTML they enhance. Confluence itself is moving towards this model, and the tools that Confluence uses to do this are also available to plugin developers.

This functionality is only available in Confluence 2.8 and later.
If are developing a theme plugin and would like to include css resources, see Theme Stylesheets instead.

Including a custom Javascript or CSS file from a plugin

In your atlassian-plugin.xml, you should add a new web resource module in this format:

<atlassian-plugin key="com.example.confluence.plugin.special" name="My Special Plugin" i18n-name-key="com.example.confluence.plugin.name">
    <!-- ... -->

    <web-resource key="mechanical-parts" name="Mechanical Parts" i18n-name-key="com.example.confluence.plugin.special.mechanical.parts.name">
        <resource type="download" name="widgets.js" location="js/widgets.js"/>
        <resource type="download" name="sprockets.css" location="styles/sprockets.css"/>
    </web-resource>

    <!-- ... -->
</atlassian-plugin>

For each resource, the location of the resource should match the path to the resource in your plugin JAR file. For example, 'widgets.js' in the above plugin JAR would be at js/widgets.js. Resource paths are namespaced to your plugin, so they can't conflict with resources in other plugins with the same location (unlike say i18n or Velocity resources). However, you may find it convenient to use a path name which is specific to your plugin to be consistent with these other types.

Then, in a Velocity template that requires that Javascript file, you use the #requireResource macro, with the plugin key followed by a colon and the key of the web-resource:

#requireResource("com.example.confluence.plugin.special:mechanical-parts")

In the HTML header of any page containing that Velocity template, all resources included in the web-resource plugin will be written out as script or link tags to include the relevant resource:

<html>
<head>
    <!-- ... -->
    <script type="text/javascript" src="/s/.../_/download/com.example.confluence.plugin.special:mechanical-parts/widgets.js"></script>
    <link type="text/css" rel="stylesheet" src="/s/.../_/download/com.example.confluence.plugin.special:mechanical-parts/spockets.css">
    <!-- ... -->
</head>

<!-- ... -->

</html>

Only one instance of each script or stylesheet will be included, and they will appear in the order they are requested in the Velocity rendering process.

The Javascript and CSS resources will be served with an expires header that means the browser will cache these resources forever. When you change these resources in your plugin, you will need to increment the version number of your plugin. This changes the URL generated above – one of the numbers between /s/ and /_/ is your plugin version – and results in the browser pulling down the updated resource.

The rich text editor and preview views do not currently use dynamic stylesheets provided by a macro rendered in this way.

Including a Javascript library provided by Confluence

Confluence currently includes several Javascript libraries which can be used by plugins. The versions of these libraries are subject to change, but only across major versions of Confluence.

In the Confluence source code, these libraries are included in a plugin XML file called web-resources.xml.

Library Web resource key Current version Details
Scriptaculous confluence.web.resources:scriptaculous 1.5rc3 Includes effects, dragdrop, controls and util.
Prototype confluence.web.resources:prototype 1.4.0_pre11 Version found in the scriptaculous lib directory. Also includes a domready extension, see domready.js.
jQuery confluence.web.resources:jquery 1.2.3 For compatibility with prototype, you must use 'jQuery()' not '$' to access jQuery.
DWR confluence.web.resources:dwr 1.1.4 Includes engine and util.

To include one of these libraries in all pages in which your Velocity template appear, simply use the #requireResource macro as above. For example, if your macro requires Scriptaculous, add the following to its Velocity template:

#requireResource("confluence.web.resources:scriptaculous")

Note: Confluence 2.8 includes a version of Yahoo UI, also called YUI. However, this will be removed in Confluence 2.9 and should not be used by plugin developers.

Running scripts when the page loads

The recommended way to load scripts when the page is ready, known as 'on-DOM-ready', is to use the Atlassian Javascript (AJS) abstraction. This avoid depending on a particular Javascript library which may not remain in Confluence.

AJS.toInit(function () {
    // ... your initialisation code here
});

This has the additional benefit of ensuring any functions or variables you declare here are not in the global scope, which is important for best interoperability with other plugins in Confluence.

Achieving progressive enhancement

We recommend you separate your markup, styles and Javascript when developing a Confluence plugin, according to the design principles of progressive enhancement. To assist with this, there are a few hooks in AJS and in Confluence in general to make this easier.

Dynamic content in Javascript

If you need to pass information from Velocity to Javascript, like for localised text, you can use AJS.params. This automatically looks up values inside fieldsets marked with a class of "parameters" inside your markup. For example, given the following markup:

<fieldset class="parameters hidden">
    <input type="hidden" id="deleteCommentConfirmMessage" value="$action.getText('remove.comment.confirmation.message')">
</fieldset>

You can have your Javascript access the localised text without embedding it by using AJS.params:

if (confirm(AJS.params.deleteCommentConfirmMessage)) {
    // ...
}

Getting the context path

Usually, you can use relative paths in stylesheets and Javascript to avoid the need for knowing the context path. However, Confluence makes this available through a meta tag in the header which looks like this:

<meta id="confluence-context-path" name="confluence-context-path" content="/confluence">

With jQuery, or even normal Javascript, it is quite easy to retrieve this for use in scripts:

// normal JS
document.getElementById("confluence-context-path").content

// jQuery
$("#confluence-context-path").attr("content")

More information

Couldn't you do this already? What's changed in Confluence 2.8?

Since Confluence 2.6, you've been able to use #includeJavascript, which puts the script tag inline, exactly where that Velocity macro appears. You've also always been able to include inline scripts or styles in your macros. However, there are a couple of problems with this that we've solved in 2.8:

  1. The Javascript might override other script already present in the page, including scripts used by Confluence.
  2. Inline Javascript or styles might appear multiple times in the page, wasting bandwidth and potentially causing conflicts.

Many plugin authors found that including Javascript in their plugins meant the plugin broke in some places, such as in the preview window, if two copies of the macro were on the same page.

By using the new #requireResource, you're guaranteed to only get one instance of the script appearing on a page, and it will be cached by browsers until your plugin is upgraded.

Do I have to use Velocity to request these resources? What about in Java?

You can achieve the same result in Java via the WebResourceManager. Use the same method as described above for Velocity: webResourceManager.requireResource(String). The WebResourceManager is a bean you can get injected by Spring. Do this within the scope of the request.

In most cases, using Velocity makes more sense, because the declaration of the JS and CSS should be close to the code which uses it.

RELATED TOPICS

Confluence Plugin Guide
Writing Confluence Plugins

Labels:

plugin plugin Delete
resource resource Delete
library library Delete
javascript javascript Delete
confluence28 confluence28 Delete
Enter labels to add to this page:
Wait Image 
Looking for a label? Just start typing.
  1. May 13

    Anonymous says:

    css web template page (example) \\
  2. May 28

    Anonymous says:

    This page should probably mention that if you want to use any of the AJS functio...

    This page should probably mention that if you want to use any of the AJS functions, you need to include this to ensure that it gets loaded before your JavaScript files.

    #requireResource("confluence.web.resources:ajs")
  3. Jul 08

    Thomas Junghans says:

    I think the method displayed above is a better way of including CSS files, altho...

    I think the method displayed above is a better way of including CSS files, although there is one little flaw, which I noticed today (or maybe it's not and I've missed something out).

    I used this method of including css files in a theme plugin and realised that I could not change for example the heading colours because the combined-css.vm and colors-css.vm are included last, just before . This irritates me a bit, because the way I see it, I still have to use the method explained on http://confluence.atlassian.com/display/DOC/Including Cascading Stylesheets in Themes if I want to be 100% sure, my css overrides Confluence's css.

    Is this meant to be? Any help or advice is greatly appreciated. Thanks.

    1. Jul 08

      Thomas Junghans says:

      Here I go answering my own question :) If you want to override the colorscss.vm ...

      Here I go answering my own question If you want to override the colors-css.vm you need to put the following line in your atlassian-plugin.xml

      <theme ....>
      
      <resource type="download" name="colorsx.css" location="css/colorsx-css.vm" />
      </theme>

      No changes are needed in the main.vmd and you don't need to use the #pluginStylesheet macro either.

      colorsx.css, as I've called it, will be @imported in the combined.css and override anything declared or imported before it.

      1. Jul 08

        Matt Ryall says:

        Exactly right, Thomas. Any resources in your theme module with a name ending in...

        Exactly right, Thomas.

        Any resources in your theme module with a name ending in '.css' will be included as 'theme stylesheets' in combined.css, and appear after the default colours and instead of Confluence's default-theme.css (which is considered the 'theme stylesheet' for the default theme).

        If you don't need Velocity syntax in your stylesheet (because you're not handling the colour scheme colours, for example), you can use a vanilla CSS file as the location instead.

        Update: the rationale for this is that only stylesheets which are part of a theme should be changing the overall look and feel of Confluence. Plugin stylesheets from macros shouldn't be making major changes to the format of the rest of the page.

  4. Jul 10

    Daniel Berkich says:

    One aspect of a plugin I developed is to install some javascript files in the he...

    One aspect of a plugin I developed is to install some javascript files in the header of the Main Layout page. (Confluence V2.8.1)

    I setup the code exactly as outlined above. I have the following line installed in the header of the Main Layout page:

    $helper.renderConfluenceMacro("{labeler}")

    This action includes all the other code from the Velocity file but the following line does not include the javascript and CSS files.
    #requireResource("com.whatever.laber:labelerParts")
    Is there a problem with using the requireResource in a macro that is included using the renderConfluenceMacro in the Main layout?
    I first started developing this macro before I new much about Confluence. There is probably a better way of including the javascript in every page.
    Any suggestions?

    I have confirmed this by directly including the plugin in the body of page thru editing it.  It works when I do this. I also tried placing the "requireResource("com.whatever.laber:labelerParts") command line directly in the Main Layout and this did not work either.

    Thanks for any Info

    Dan

    1. Jul 10

      Matt Ryall says:

      Dan, this won't work as you expect. The main layout is the one responsible for p...

      Dan, this won't work as you expect. The main layout is the one responsible for printing out the resources, right near the top (in the included header.vm file). So anything you add to the list of resources later in the file just won't be printed out.

      You have two options:

      • put the #requireResource() line above the line that includes the header.vm file (there are a couple in main.vmd already)
      • just include your JavaScript URL in the page's <head> section directly, like this:
      <script type="text/javascript" src="$!webResourceManager.getStaticPluginResource("com.example.plugin.key", "resource-name.js")"></script>
      

Add Comment