I am seeing a difference in behavior between the macros provided by Confluence, and a macro I am trying to develop.
For simplicity's sake, I have based this explanation on the Confluence XhtmlMacroDemo, with the addition of a parameter "foo" that is just copied to the macro body (see below). Tested using Confluence 4.1.6.
In the WYSIWYG editor, standard plugins can be entered/parametrized using wiki markup, but not a custom macro, like the XhtmlMacroDemo.
Example:
If I enter {status:colour=green}, the editor will immediately display a green status bar (I understand that there's additional magic involved in getting the WYSIWYG preview). The point is that the macro and its parameters can be fully specified using the old wiki markup.
(If I enter {xhtml-macro-demo} and press return on the autocomplete, I can parametrize the macro using the pop-up screen, but that's not my goal)
If I enter {xhtml-macro-demo:foo=bar}, the code will be put into a "wiki markup" macro block upon closing the curly brace. However, when I save or preview the page, it isn't interpreted correctly, and I get "Unknown macro: {xhtml-macro-tutorial}"
Motivation (why go through the trouble and not just use the macro dialog?):
I need to be able to specify a parametrized instance of my macro in the wiki markup language, since this is to be included in a menu bar created with Adaptavist ThemeBuilder. As far as I ahev understood, you cannot use the storage format in this circumstance (but I would be glad to be proved wrong).
Why is wiki markup entry of macros treated differently between "built-in" and "user-contributed" macros, and is there a way how I can get the built-in behavior?
atlassian-plugin-xml:
<atlassian-plugin key="${project.groupId}.${project.artifactId}" name="${project.name}" plugins-version="2"> <plugin-info> <description>${project.description}</description> <version>${project.version}</version> <vendor name="${project.organization.name}" url="${project.organization.url}" /> </plugin-info> <xhtml-macro name="xhtml-macro-tutorial" class="tutorial.XhtmlMacroDemo" key="xhtml-macro-tutorial"> <parameters> <parameter name="foo" type="string"/> </parameters> <category name ="development"/> </xhtml-macro> </atlassian-plugin>
XhtmlMacroDemo.java:
package tutorial; import com.atlassian.confluence.content.render.xhtml.ConversionContext; import com.atlassian.confluence.content.render.xhtml.DefaultConversionContext; import com.atlassian.confluence.content.render.xhtml.XhtmlException; import com.atlassian.confluence.macro.Macro; import com.atlassian.confluence.macro.MacroExecutionException; import com.atlassian.confluence.renderer.PageContext; import com.atlassian.confluence.xhtml.api.MacroDefinition; import com.atlassian.confluence.xhtml.api.MacroDefinitionHandler; import com.atlassian.confluence.xhtml.api.XhtmlContent; import java.util.ArrayList; import java.util.List; import java.util.Map; public class XhtmlMacroDemo implements Macro { private final XhtmlContent xhtmlUtils; public XhtmlMacroDemo(XhtmlContent xhtmlUtils) { this.xhtmlUtils = xhtmlUtils; } @Override public BodyType getBodyType() { return BodyType.NONE; } @Override public OutputType getOutputType() { return OutputType.BLOCK; } @Override public String execute(Map<String, String> parameters, String bodyContent, ConversionContext conversionContext) throws MacroExecutionException { String parameterEntered; if (parameters.containsKey("foo")) { parameterEntered = "You have passed the parameter: " + parameters.get("foo"); } else { parameterEntered = "You have not parametrized the macro"; } // We will eventually be able to get the page out of the conversion context, for the time being we have to do it this way. if (!(conversionContext instanceof DefaultConversionContext)) { return ""; } DefaultConversionContext defaultConversionContext = (DefaultConversionContext) conversionContext; String body = ((PageContext) defaultConversionContext.getRenderContext()).getEntity().getBodyAsString(); final List<MacroDefinition> macros = new ArrayList<MacroDefinition>(); try { xhtmlUtils.handleMacroDefinitions(body, conversionContext, new MacroDefinitionHandler() { @Override public void handle(MacroDefinition macroDefinition) { macros.add(macroDefinition); } }); } catch (XhtmlException e) { throw new MacroExecutionException(e); } StringBuilder builder = new StringBuilder(); builder.append("<p>"); if (!macros.isEmpty()) { builder.append("<table width=\"50%\">"); builder.append("<tr><th>Macro Name</th><th>Has Body?</th></tr>"); for (MacroDefinition defn : macros) { builder.append("<tr>"); builder.append("<td>").append(defn.getName()).append("</td><td>").append(defn.hasBody()).append("</td>"); builder.append("</tr>"); } builder.append("</table>"); } else { builder.append("How did this happen - I am a macro, where am I?!?!?!"); } builder.append("</p>"); return builder.toString() + "<p><b>" + parameterEntered +"</b></p>"; } }
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>tutorial</groupId> <artifactId>xhtml-macro-tutorial</artifactId> <version>1.0-SNAPSHOT</version> <organization> <name>Example Company</name> <url>http://www.example.com/</url> </organization> <name>xhtml-macro-tutorial</name> <description>This is the tutorial:xhtml-macro-tutorial plugin for Atlassian Confluence.</description> <packaging>atlassian-plugin</packaging> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.6</version> <scope>test</scope> </dependency> <dependency> <groupId>com.atlassian.confluence</groupId> <artifactId>confluence</artifactId> <version>${confluence.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.confluence.plugin</groupId> <artifactId>func-test</artifactId> <version>2.3</version> <scope>test</scope> </dependency> <dependency> <groupId>net.sourceforge.jwebunit</groupId> <artifactId>jwebunit-htmlunit-plugin</artifactId> <version>2.2</version> <scope>test</scope> </dependency> <dependency> <groupId>net.sourceforge.nekohtml</groupId> <artifactId>nekohtml</artifactId> <version>1.9.12</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>com.atlassian.maven.plugins</groupId> <artifactId>maven-confluence-plugin</artifactId> <version>${amps.version}</version> <extensions>true</extensions> <configuration> <productVersion>${confluence.version}</productVersion> <productDataVersion>${confluence.data.version}</productDataVersion> </configuration> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> <properties> <confluence.version>4.1.6</confluence.version> <confluence.data.version>3.5</confluence.data.version> <amps.version>3.10.2</amps.version> </properties> </project>
Community moderators have prevented the ability to post new answers.
You will need to add a legacy (ie 3.x style) macro in your plugin to get it to work in wiki markup.
Bob is correct - to use your xhtml macro with the wiki-markup renderer then you will need to declare a 3.x style macro.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
In my opinion, it is a bug that autoformatting of macros relies on us having a "legacy" macro definition.
It is covered in this issue.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
how can this be done?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
For instance, this is how to declare a 3.x style macro in atlassian-plugin.xml - https://bitbucket.org/bob_swift/confluence-wiki-plugin/src/a06aa7b1fc20/src/main/resources/atlassian-plugin.xml#cl-8 . Then create a implementation that follows the 3.x interfaces - usually just map that to your xhtml implementation.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
thanks! I have tried out the example, exactly how your post states. However, the macro is not found in the macro browser on Confluence 4.2. Source Code:
atlassian-plugin.xml
<macro name="wiki" key="wiki" class="path....macros.WikiMacro" state="enabled"> <description> Useful for testing legacy macro support and for those that need to hang onto wiki markup for a bit longer even on Confluence 4.x. </description> <category name="content"/> </macro>
WikiMacro.java
import java.util.Map; import com.atlassian.renderer.RenderContext; import com.atlassian.renderer.v2.RenderMode; import com.atlassian.renderer.v2.macro.BaseMacro; import com.atlassian.renderer.v2.macro.MacroException; /** * Simple wiki markup that will not be migrated on Confluence 4.x */ public class WikiMacro extends BaseMacro { @Override public String execute(@SuppressWarnings("rawtypes") Map parameters, String body, RenderContext renderContext) throws MacroException { return body; } @Override public RenderMode getBodyRenderMode() { return RenderMode.ALL; } @Override public boolean hasBody() { return true; } }
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
It is an example of how to declare a legacy macro in your plugin so that it is valid using insert wiki markup. Legacy macros do not appear in the macro browser, you need a xhtml macro for that.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
ok, but how to create a macro which can be used from the macro browser AND in a space or global template?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
So, include both macro (legacy) and xhtml (new) definitions in your atlassian-plugin.xml. Use the same macro name for both, but, the key needs to be different.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
thanks Bob! Atm the Macro is shown as markup within a "Wiki Markup" Macro. What I want, is to get a template with all (custom) macros already rendered. Do you know, how to do this?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
It is not clear what you are asking about now. Perhaps you need to ask another question.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Community moderators have prevented the ability to post new answers.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.