Last updatedMay 15, 2019

Including Javascript and CSS resources

Available:

Confluence 2.10 and later

Deprecated:

DWR was deprecated in Confluence 3.3

Good style for web applications requires that JavaScript and CSS for web pages are kept separate from 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.

If you develop 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 Web Resource module. See Web Resource module.

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

To include your custom Web Resource in a page where your plugin is used, use the #requireResource Velocity macro like this:

1
#requireResource("com.acme.example.plugin:web-resource-key")

Where "com.acme.example.plugin:web-resource-key" is your plugin key, a colon, and the key of the Web resource module in your plugin.

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 rich text editor does not currently use dynamic stylesheets provided by a macro rendered in this way.

Web Resource configuration

Within your Web Resource plugin module, you will define one or more resource definitions. See Adding plugin and module resources.

Note that you can declare the media type (for CSS resources) and whether the resource should be wrapped in an Internet Explorer conditional comment. This feature is also described in Adding plugin and module resources.

Here is a short example:

1
2
3
4
5
6
7
8
9
10
11
12
13
<web-resource key="my-macro-resources">
    <resource type="download" name="macro.js" location="path/inside/jar/to/js/macro.js"/>
    <resource type="download" name="more-macro-stuff.js" location="path/inside/jar/to/js/more-macro-stuff.js"/>
    <resource type="download" name="macro.css" location="path/inside/jar/to/css/macro.css"/>
    <resource type="download" name="macro-ie.css" location="path/inside/jar/to/css/macro-ie.css">
        <param name="ieonly" value="true"/>
        <param name="title" value="IE styles for My Awesome Macro"/>
    </resource>
    <resource type="download" name="macro-print.css" location="path/inside/jar/to/css/macro-print.css">
        <param name="media" value="print"/>
    </resource>
    <dependency>confluence.web.resources:ajs</dependency> <!-- depends on jQuery/AJS -->
</web-resource>

See below for the libraries provided by Confluence that you can include as a dependency.

Resource dependencies are not supported in 2.10. You will need to define the depending resources explicitly.

Including a JavaScript library provided by Confluence

Confluence currently includes several JavaScript libraries that plugins can use. 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

Confluence 3.3+

Confluence 6.7

Details

jQuery + AJS

1
2
3
confluence
  .web
  .resources:ajs

1.4.2

1.7.2

Atlassian's JS abstraction on top of jQuery provides a few additional pieces of functionality.

jQuery

1
2
3
confluence
  .web
  .resources:jquery

1.4.2

1.7.2

For compatibility with prototype, you must use 'jQuery()' not '$' to access jQuery.

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

1
#requireResource("confluence.web.resources:jquery")

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 avoids depending on a particular JavaScript library that may not remain in Confluence.

1
2
3
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

According to the design principles of progressive enhancement, we recommend you separate your markup, styles, and JavaScript when developing a Confluence plugin. 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, such as 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:

1
2
3
<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:

1
2
3
if (confirm(AJS.params.deleteCommentConfirmMessage)) {
    // ...
}
Getting the Context Path

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

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

Starting from Confluence 3.4, the best way of accessing this path is via the AJS.Data JavaScript method:

1
var relativeUrl = AJS.Data.get("context-path") + "/path/to/content";

More Information

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

Starting from Confluence 2.6, you've been able to use #includeJavascript that 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:

  • The JavaScript might override other script already present in the page, including scripts used by Confluence.
  • 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 get only 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 previously 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.