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 version.

Including Javascript and CSS resources

All Versions

Confluence 3.0 Documentation

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 you are developing a theme plugin and would like to include css resources, see Theme Stylesheets instead.

On this page:

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 Plugins.

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 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.

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 and preview views do 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.

Including a JavaScript Library provided by Confluence

Confluence currently includes several JavaScript libraries which 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 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 jQuery, add the following to its Velocity template:

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

Note: Use of Scriptaculous and Prototype is deprecated as of Confluence 2.9. Use of these libraries in Confluence core will be gradually replaced with jQuery over the next few releases. Plugin developers should start doing the same with their front-end code, because both Prototype and Scriptaculous will be removed from a future release of Confluence.

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 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, 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:

<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 to know 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 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 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

Web Resource Plugins
Adding Plugin and Module Resources
Writing Confluence Plugins
Installing and Configuring Plugins Manually

Labels

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

    Anonymous says:

    css web template page (example) -- http://www.css-lessons.ucoz.com/css-t...
  2. May 28, 2008

    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, 2008

    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, 2008

      Thomas Junghans says:

      Here I go answering my own question If you want to override the colors-css.vm y...

      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, 2008

        Matt Ryall (Atlassian) 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, 2008

    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, 2008

      Matt Ryall (Atlassian) 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>
      
    2. Aug 07, 2008

      Daniel Berkich says:

      It works fine if I include my macro before the #setHeader statement. i.e. just a...

      It works fine if I include my macro before the #setHeader statement. i.e. just after the last #requireResource statement provided by Confluence.

      Thanks 

  5. Aug 07, 2008

    Daniel Berkich says:

    I have a plugin that includes javascript and stylesheets from a product that I p...

    I have a plugin that includes javascript and stylesheets from a product that I purchased.  The product's stylesheet contains relative URLs to access images which are not found when I load the page.  I currently have a resources tag in the atlassian-plugin.xml file and set a javascript variable in the VM file to the resource's context to access other images (I have updated this method as of yet using your example shown above).

    How can I get the stylesheet to find these images?  Will I have to modify the CSS file? If so, must I do it manually or use javascript? Can place the directory containing the images in a location where relative URLs will work?

    Any insight would be greatly appreciated. (version 2.8.1)

    Thanks Dan 

    1. Aug 10, 2008

      Matt Ryall (Atlassian) says:

      Dan, modifying the CSS to use URLs which point to the server running the other p...

      Dan, modifying the CSS to use URLs which point to the server running the other product is probably the easiest way to fix this. It should be a fairly simple search and replace job.

      The alternative of putting the image files inside the Confluence web application may work, but you'll need to remember to copy these across when you upgrade Confluence. If you put files inside a /foo/ directory in the Confluence webapp, they will be accessible from the web via the URL /foo/, relative to your Confluence base URL.

      1. Nov 23, 2008

        john martin says:

        I've had a background image that one of my styles uses, so I put it in the actua...

        I've had a background image that one of my styles uses, so I put it in the actual .vm as:

        div.task_card {
            text-align: left;
            position: absolute;
            z-index: 100;
        	
            width: 400px;
            height: 240px;
            padding: 10px;
            border: 2px solid #FFFFFF;
            background-image: url("$contextPath/download/resources/com.atsva.confluence.plugins.agiletoolkit:planningpoker/img/paper.gif");
        }
        

        If I want to move the css out into a stylesheet is there any way for it to understand the path to the image?

        1. Nov 23, 2008

          Matt Ryall (Atlassian) says:

          John, from web resource stylesheets you can use relative paths to refer to other...

          John, from web resource stylesheets you can use relative paths to refer to other resources. For example, if your plugin is set up like this:

          • /styles/card-styles.css
          • /img/paper.gif.

          You can use a relative path like this to load your image:

          div.task_card {
              background-image: url(../../com.atsva.confluence.plugins.agiletoolkit:planningpoker/img/paper.gif);
          }
          

          If you turn on Maven properties filtering for your stylesheet files, you can replace the key with something like ${project.key}, so you don't need to hard-code it.

          1. Jan 18

            Cody Burleson says:

            Or, in my case, it was: background:#D8D8D8 url(../com.burlesontech.popkong...

            Or, in my case, it was:

            
            background:#D8D8D8 url(../com.burlesontech.popkong:page-tabs-resources/img/sprite.png) repeat-x scroll 0 0;
            
            

            (i.e. one less '../')

            1. Feb 12

              Ki Alam says:

              i'm trying to include the ext javascript library in my plugin. one of the css fi...

              i'm trying to include the ext javascript library in my plugin. one of the css files (grid/grid.css) refers to 51 image files.  I tried to create a resource tag in my web-resource that used the namePattern instead of name, but my plugin won't load with this:

              <web-resource key="ext" name="extjs">
              
              <resource type="download" name="grid.css" location="resources/ext/resources/css/grid.css"/>
              
              <resource type="download" namePattern="images/.*" location="resources/ext/resources/images"/>
              
              <web-resource>
              

              Is there anyway to avoid listing each of those images in my webresource (which really shouldn't be included in #requireResource anyway)?

              Thanks, Ki

              1. Feb 12

                Ki Alam says:

                I'm not sure if this is the best way, but I got around this by creating a direct...

                I'm not sure if this is the best way, but I got around this by creating a directory resource outside of the web-resource plugin (1) and then using the Style @import rather than including the style in the head (2).

                1:

                <resource key="ext" type="download" name="ext/" location="resources/ext/"/>
                
                    <web-resource key="ext" name="extjs">
                        <resource type="download" name="ext/adapter/ext/ext-base.js" location="resources/ext/adapter/ext/ext-base.js"/>
                        <resource type="download" name="ext/ext-all.js" location="resources/ext/ext-all.js"/>
                        <resource type="download" name="ext/examples/shared/examples.js" location="resources/ext/adaptor/ext/examples/shared/examples.js"/>
                        <resource type="download" name="ext-grid.js" location="resources/js/grid.js"/>
                    </web-resource>
                
                

                2:

                 <STYLE TYPE="text/css" MEDIA="screen, projection">
                <!--
                  @import url('/download/resources/$plugin:$module/ext/resources/css/grid.css');
                  @import url('/download/resources/$plugin:$module/ext/resources/css/ext-all.css');
                  @import url('/download/resources/$plugin:$module/ext/examples/shared/examples.css');
                -->
                </STYLE>
                
                

                Hope this helps someone in the future!

          2. Apr 08

            Anonymous says:

            Hi Matt, just found this after a day of flailing, just wondering if there is an...

            Hi Matt,

            just found this after a day of flailing, just wondering if there is any issue relating to removing the need for resource modification?  It would be 'neat' if resources were scanned dynamically and pluginkey/bundlekeys inserted accordingly.  Maybe Im just lazy

            1. Apr 08

              Matt Ryall (Atlassian) says:

              Sounds like a good idea. Would you mind raising an issue in JIRA with your sugge...

              Sounds like a good idea. Would you mind raising an issue in JIRA with your suggestion?

  6. Oct 16, 2008

    Glenn Engel says:

    Hi, I tried using the webResourceManager.requireResource(String) method in my ma...

    Hi, I tried using the webResourceManager.requireResource(String) method in my macro to include a js resource but it got included as the very first js in the list before the system js.  Since I was using AJS.toInit() it is not defined yet! 

    Is there a way I can specify for my resource to be loaded after the system resources?

    1. Oct 16, 2008

      Matt Ryall (Atlassian) says:

      Glenn, the system doesn't support the notion of dependencies (yet), so you need ...

      Glenn, the system doesn't support the notion of dependencies (yet), so you need to add 'requestResource' call for each resource your JavaScript relies on. For example:

      webResourceManager.requireResource("confluence.web.resources:jquery"); // required for AJS
      webResourceManager.requireResource("confluence.web.resources:ajs"); // required for plugin JS
      webResourceManager.requireResource("com.example.plugin.custom:plugin-js");
      

      We're hoping to fix this in a future release of Confluence, so you can declare these dependencies in the XML file rather than doing multiple calls to requireResource(). This is the improvement request: CONF-10806.

      1. Jan 27

        Igor Minar says:

        Matt, This valuable piece of info should be on some highly visible place.

        Matt,

        This valuable piece of info should be on some highly visible place.

  7. Apr 08

    Gary S. Weaver says:

    Maybe someone can help me with the following issue: I wanted to come up with a ...

    Maybe someone can help me with the following issue:

    I wanted to come up with a way to include CSS and Javascript resources in the CSUM plugin such that they would be accessible in earlier versions of Confluence (pre-v2.8) as well as later versions (v2.8+).

    To this end, I tried the following in atlassian-plugin.xml:

        <!-- This is for earlier versions of Confluence (pre-v2.8) -->
        <resource type="download" name="css/" location="templates/css/"/>
        <resource type="download" name="js/" location="templates/js/"/>
    
        <!-- This is for later versions of Confluence (v2.8+) -->
        <web-resource key="csumresources" name="CSUMResources" >
            <resource type="download" name="csum.css" location="templates/css/csum.css" />
            <resource type="download" name="container-min.js" location="templates/js/container-min.js" />
            <resource type="download" name="element-beta-min.js" location="templates/js/element-beta-min.js" />
            <resource type="download" name="yahoo-dom-event.js" location="templates/js/yahoo-dom-event.js" />
            <context>space</context>
        </web-resource>
    

    And in the velocity template (display.vm), I put:

    <html>
        <head>
            <title>$action.getActionName($action.getClass().getName())</title>
        </head>
    
        #applyDecorator("root")
            #decoratorParam("helper" $action.helper)
            #decoratorParam("context" "space-custom-usermanagement") ##note this should be same as item.key defined in atlassian-plugin.xml
            #decoratorParam("mode" "view-edit-spaceUser")
    
            ## This is for later versions of Confluence (v2.8+)
            #requireResource("raju.kadam.confluence.permissionmgmt:csumresources")
            
                <content tag="spacekey">${action.space.key}</content>
        #set( $contextPath = "/customspacemgmt/permissions/custompermissionsmanage.action?key=$generalUtil.doubleUrlEncode($key)&" )
    
        #set( $refreshbugworkaround = "&redirect=" )
    
        <body>
            ## This is for earlier versions of Confluence (pre-v2.8)
    		<script type="text/javascript" src="$req.contextPath/download/resources/$action.pluginKey/js/yahoo-dom-event.js"></script>
    		<script type="text/javascript" src="$req.contextPath/download/resources/$action.pluginKey/js/element-beta-min.js"></script>        
    		<script type="text/javascript" src="$req.contextPath/download/resources/$action.pluginKey/js/container-min.js"></script>
    
    		<link rel="stylesheet" href="$req.contextPath/download/resources/$action.pluginKey/css/csum.css" type="text/css" media="screen" title="no title" charset="utf-8">
    

    This works in Confluence 2.10.2 without issue, but in Confluence 2.5.8, in the plugin description in Plugins under Confluence Administration I see:

    CSUMResources
    Error: Cannot find ModuleDescriptor class for plugin of type 'web-resource'.
    

    which is not a big deal, and I could just warn users about that, however in Confluence 2.5.8, the code:

     #requireResource("raju.kadam.confluence.permissionmgmt:csumresources")
    

    is rendered in the page under the space management tabs as literally '#requireResource("raju.kadam.confluence.permissionmgmt:csumresources")'

    Should I be including the requireResource in a different part of the velocity template for it not to display in versions of Confluence prior to 2.8, or must we just leave this visual atrocity in and then tell the user that they have to live with that unless they upgrade to Confluence 2.8 or later?

    1. Apr 08

      Matt Ryall (Atlassian) says:

      We added this functionality in Confluence 2.8, so there's no #requireResource eq...

      We added this functionality in Confluence 2.8, so there's no #requireResource equivalent in earlier versions. One way to hide it would be to customise macros.vm in earlier versions of Confluence to add the following empty macro:

      #macro (requireResource $resourceModuleKey)
      #end
      

      I can't think of any way to do this from your plugin, unfortunately.

      1. Apr 13

        Gary S. Weaver says:

        Matt, The way we just resolved this in CSUM v2.0.3 was to remove the '#requireR...

        Matt,

        The way we just resolved this in CSUM v2.0.3 was to remove the '#requireResource("raju.kadam.confluence.permissionmgmt:csumresources")' in the .vm and to use reflection (David Peterson taught me a similar trick sometime back):

            // this can't be done in the velocity template, and must be called via reflection because method doesn't exist in
            // earlier versions of Confluence < 2.8
            public void loadWebResourceIfConfluence2_8_OrHigher(WebResourceManager webResourceManager, String resource) {
                if (webResourceManager!=null) {
                    Class webResourceManagerClazz = webResourceManager.getClass();
                    try {
                        // Confluence >= 2.8(?) only has method (SUSR-75)
                        Method requireResourceMethod = webResourceManagerClazz.getMethod("requireResource", new Class[]{String.class});
                        requireResourceMethod.invoke(webResourceManager, new Object[]{resource});
        
                        if (log.isDebugEnabled()) {
                            log.debug("loaded webresource '" + resource + "'");
                        }
        
                    } catch (NoSuchMethodException nsme) {
                        // If this happens, we are most probably in Confluence < 2.8
                        if (log.isDebugEnabled()) {
                            log.debug("Ignore the following exception for Confluence versions < 2.8 that do not support the " +
                                      "method: webResourceManager.requireResource(String). Resource that wasn't loaded was '" +
                                      resource + "'", nsme);
                        }
                    } catch (Exception e) {
                        log.warn("Problem using reflection to load web resource: " + resource, e);
                    }
                }
                else
                {
                    log.warn("webResourceManager was not set on " + this.getClass() + " so didn't load webresource '" + resource + "'");
                }
            }
        

        I first went down the road of putting an "if" in the velocity template to check for a Confluence version and only doing #requireResource... there, however it appears that won't work, at least not in Confluence 2.10.2, even though I could see in the logging that the conditional was evaluating correctly.

        Hope that helps,
        Gary

        1. Apr 13

          Matt Ryall (Atlassian) says:

          Nice solution, Gary. Thanks for posting it. I'm sure this will be quite useful t...

          Nice solution, Gary. Thanks for posting it. I'm sure this will be quite useful to other plugin developers!

          One other idea I had while looking at your code was that you might want to consider registering a component like this as a Velocity context plugin module. Then, for example, you could just call this from Velocity:

          $csumWebResourceManager.requireResource("...")

          This might save you having to subclass your actions to share this logic between them. It would provide a pretty similar API to that provided by Confluence, and might make the code more reusable in different plugins.

Add Comment


Except where otherwise noted, content in this space is licensed under a Creative Commons Attribution 2.5 Australia License.