Skip to main content
Skip table of contents

Create Custom Template Placeholders

Scroll PDF Exporter provides a variety of placeholders that can be used in templates to include dynamic data while exporting, such as the current space name or the page creator's name.

As an app developers you might want to contribute information from your app in exports as well. While you can always do this with macros, in order to make this available in a reusable export template, a custom placeholder is required.

Therefore, Scroll PDF Exporter supports 3rd-party placeholders through a Velocity based API. The velocity-based approach ensures that your app has neither runtime nor buildtime dependencies to Scroll PDF Exporter code.

Required steps

To create a custom placeholder you need to:

  1. Create or extend an existing App
  2. Add a new <velocity-context-item> plugin module
  3. Add two Java methods matching our API signatures to this module, one for returning the placeholder's values and one returning the placeholder specification format (see bottom of page) for making it appear in the template designer

After installing the app, the placeholder will appear in the template designer's Insert placeholder dialog:

Example of custom placeholder

To see an example of a custom placeholder, you can visit our Bitbucket page.

Register the placeholder 

In order to be recognized as placeholder by Scroll Exporters the placeholder modules must fulfil these requirements:

  • The placeholder must be implemented as a Velocity Context Item module: 

    CODE
        <velocity-context-item key="exp-my-placeholder"
                               name="Example Placeholder" context-key="exp-placeholder-example"
                               class="com.k15t.examples.ExamplePlaceholder"
                               global="true"/>
  • The context-key attribute's value must be prefixed with exp-. The value after the prefix must be unique, and it should be readable and indicative of the placeholder's function.
    (info) While not directly visible to the user in Scroll PDF Exporter, this value is used by other Scroll Exporter apps, for example by Scroll Word Exporter to identify the placeholder in custom templates.
  • The global attribute must be set to true
  • They must implement (at least) the following Java methods: 

    JAVA
    public class ExamplePlaceholder {
    
        public String render(Map<String, Supplier<String>> context) { ... }
    
    
        public String getPlaceholderSpec() { ... }
        
    }
  • The getPlaceholderSpec method must return a valid placeholder spec.


Java API

String render(Map<String, Supplier<String>> context)

Description

This method is called whenever the placeholder is rendered during the export process.

(warning) Each invocation of this method runs in its own transaction. There is no need for implementations to create their own transaction.

Parameters

The context object contains both general context information about the export, such as references to the space and page being exported, as well as the placeholder specific parameter as declared in the placeholder spec.

Keys in this this map follow this pattern:

  • export.* - for all general context parameters such as page ID or space key
  • parameter.<key> - for all placeholder specific parameters (with <key> being the parameters→key values from the placeholder spec)
  • placeholder.* - for information about the placeholder instance

Values in this map are always java.function.Suppliers, as it might be expensive to calculate their values.
Even if a parameter value is null or 0 because it falls back to the default value, still a supplier returning that value is contained in the map instead of null.

Return Value

Must return HTML representing the output of the placeholder. The returned HTML should be self-contained and only reference external resources if they are either publicly available without authentication or if they are served by Confluence and can be accessed by the user performing the export.

(warning) The implementation is responsible for properly escaping any user-supplied input before integrating it into the HTML output.

String getPlaceholderSpec()

DescriptionThis method is called whenever third-party placeholders are collected. The specification it returns contains requested parameters and information on how the placeholder will appear in user interfaces.
Parameters

-

Return ValueMust return JSON following the structure documented below.


Available parameters

KeyDescription
export.contentIdThe ID of the root page or blog post of the export.
export.spaceKeyThe key of the space that contains the root page or blog post.
export.templateIdThe ID of the template used in the export.
export.templateNameThe name of the template used in the export.
export.localeBCP 47 language tag representing the locale used for formatting dates and other data. It may be the exporting user's locale or a locale defined in the template.
export.productKeyThe key of the exporter add-on.
export.productVersionThe version of the exporter add-on.
placeholder.displayThe display mode for which to evaluate the placeholder: "inline" or "block". This value may be defined in the placeholder spec or set to "user-defined", in which case the user can choose the display mode when inserting the placeholder into the template.


Placeholder specification format

CODE
{
    "version": "1",                                                 // Optional. Defaults to "1".
    "metadata": {
        "title": "My person placeholder title",                     // Used as display title for the placeholder
        "description": "Returns some information on some person",   // Optional. Displayed in the placeholder list and in placeholder dialog. Defaults to "".
        "display": "inline"                                         // Optional, either "inline", "block" or "user-defined", defaults to "inline"
    },
    "parameters": [
        {
            "key":"name",                                           // Used in the context map as part of the keys
            "title": "Full Name",                                   // Displayed in the placeholder dialog
            "description": "Enter the first and last name here",    // Optional. Displayed in the placeholder dialog. Defaults to "".
            "type": "string",                                       // Displays as a single-line input field
            "defaultValue": ""                                      // Optional, defaults to null if not specified
        },
        {
            "key":"age",
            "title": "Age",
            "description": "Enter the age in months here",
            "type": "int",                                          // Displays as a input field accepting numbers
            "defaultValue": "273"                                   // Optional, defaults to 0 if not specified
        },
        {
            "key":"gender",
            "title": "Gender",
            "description": "Enter the gender here",
            "type": "enum",                                         // Displays as a dropdown
            "defaultValue": "unspecified",                          // Optional, defaults to first allowed value, must match one of the keys in 'allowedValues'
            "allowedValues": [                                      // Only available for enums. Must not be empty.
                {
                    "key": "female",                                // Used in the context map as value for this parameter 
                    "title": "Female"                               // Displayed in the dropdown
                },
                {
                    "key": "male",
                    "title": "Male"
                },
                {
                    "key": "unspecified",
                    "title": "No indication"
                }
            ]
        },
        {
            "key":"newsletter",
            "title": "Send Newsletter",
            "description": "Send hourly newsletter?",
            "type": "boolean",                                      // Displays as a checkbox
            "defaultValue": "true"                                  // Optional, defaults to false if not specified
        }
    ]
}


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.