This server will be upgraded at 3pm Sydney time on December 3rd (December 2nd, 8pm PST) and will be down for up to 30 minutes.

Portlet, Script, Hidden and TOC Macros

Name Portlet, TOC, Hidden and Script macros
Vendor Paul Rene Jorgensen (Website)
Authors Paul Rene J���rgensen
Homepage http://confluence.atlassian.com/display/CONFEXT/Portlet%2C+Script%2C+Hidden+and+TOC+Macros
Issue Management
Continuous Integration n/a
Categories Content Macros
Most Recent Version 2.0
Availability Confluence v2.0 to v2.10
State Stable
Support Unsupported Plugins
License Freeware / Open Source (BSD)
Price Free
Release Docs http://confluence.atlassian.com/display/CONFEXT/Portlet%2C+Script%2C+Hidden+and+TOC+Macros
Java API Docs n/a
Download Source n/a
Download JAR portlet-os-plugin-for-v2.x.jar
This plugin now accessable through the Confluence Repository Client.

Macros for table of content generation, hidden content and easy extension point for scripts and portlets.
NEW! Version for Confluence 2.x
Ported to the new 2.x API, no functional changes.
Download portlet-os-plugin-for-v2.x.jar and deploy through the admin interface.

Version for Confluence 1.4
Bugfix release. Config is now parsed through the new Confluence v2 plugin framework.
Download confluence-portlet-macros-1.4.1.jar and deploy through the admin interface.

You may also take a look at the source code to debug any problems you may have.

Version for Confluence 1.3
Download confluence-portlet-macros-java-1.3.1.jar and place into the WEB-INF/lib folder of the Confluence war file.

If you only want the TOC macro download this jar instead: confluence-toc-macro-java-1.3.1.jar

If you run into problems you could try to email me at paulrene@gmail.com. I would also appreciate if you would let me know what you're using it for.

Hidden

no parameters

Example of usage
This text is meant for the reader of the page.
\{hidden\}This is a comment for the page editors, and will not be shown to the end user.\{hidden\}
This is also for the reader.
Example of output

This text is meant for the reader of the page.
This is also for the reader.

TOC

Parameter Values Optional?
anchor false (default) - Ignore anchors
true - Render anchors
layout list (default) - Generates the TOC as an bullet point list
simple - Generated the TOC as a simple concatenated string
squared - The same as simple, but adds [ ] around the names
Example of usage
\{toc:anchor=true|layout=list\}
\\
\{anchor:one\}
h1. One heading
Some text here.
\{anchor:two\}
h2. Another heading
Some more text here.
\{anchor:tree\}
h3. Yet another heading
Even more text here.
\{anchor:four\}
h2. Whoops, I did it again
Can find anything usefull here.

The example above generates the following output

Example of output
Example of output with layout=squared

[ One heading ] [ Another heading ] [ Yet another heading ] [ Whoops, I did it again ]

The rest of the page content here...

Script

Parameter Values Optional?
output html (default) - Output from the script will be passed right thru to the page
wiki - Ouput will be piped thru Confluence's wiki rendering engine. This means you can use other macros in your output, even the script and portlet macros. Behave!
Example of usage (User and groups list script)
\{script:output=html\}
import com.atlassian.confluence.user.UserAccessor;
import bucket.container.ContainerManager;
import com.opensymphony.user.User;

UserAccessor userAccessor = (UserAccessor) ContainerManager.getInstance(). \\
getContainerContext().getComponent("userAccessor");

System.out.println("<hr><b>Dumping users and emails</b><br>");
ArrayList users = userAccessor.getUsers();
System.out.println("<TABLE CLASS=\"wikitable\">");
System.out.println("<TR>");
System.out.println("<TH>Username</TH>");
System.out.println("<TH>FullName</TH>");
System.out.println("<TH>Email</TH>");
System.out.println("<TH>Groups</TH>");
System.out.println("</TR>");
for(User user: users) {
  List groupList = user.getGroups();
  String groups = new String();
  for(String group: groupList) {
    groups += group+"<br>";
  }
  System.out.println("<TR>");
  System.out.println("<TD>"+user.getName()+"</TD>");
  System.out.println("<TD>"+user.getFullName()+"</TD>");
  System.out.println("<TD>"+user.getEmail()+"</TD>");
  System.out.println("<TD>"+groups+"</TD>");
  System.out.println("</TR>");
}
System.out.println("</TABLE>");
\{script\}

Portlet

Parameter Values Optional?
classname Fully qualifed class name of class implementing the Portlet interface or extending the GenericPortlet class
config key=value, key2=value - List of key value pairs available to the portlet thru the PortletConfig object

The portlet macro has two modes. Either it's in scripting mode or in native mode. I'll try to explain the difference using two examples. In native mode you must compile your class(es) and put them in the app server classpath (eg. in Confluence's WEB-INF/lib path). In script mode the portlet code is inserted directly into the page between the portlet macro tags. This is useful for development / testing. Any output to System.err is displayed in a error box on top of the page in both modes. I usually develop portlets in script mode, and then compiles them and use native mode when entering production.

Example of usage (native mode)
\{portlet:classname=org.test.portlet.TestPortlet\}
Example of (simple) usage (script mode, wiki style)
\{portlet:classname=org.test.portlet.SimpleScriptedPortlet\}
public void init(PortletConfig config) {
	// Do nothing here in this example.
}
public void service(PortletRequest req, PortletResponse resp) {
	PrintWriter out = resp.getWriter();
	out.println("Hello, *"+req.getUser().getFullName()+"!*");
	out.println("----");
	out.println("\\\\");
	out.println("\\\\");
	out.println("[A page]");
	out.println("\\\\");
	out.println("\\\\");
	out.println("{script:output=wiki}");
	out.println("System.out.println(\"*Xyzzy*!\");");
	out.println("{script}");
	out.println("\\\\");
	out.println("\\\\");

	// Tell the container that the output from the portlet is in wiki style and should be put thru
	// the Confluence rendering engine.
	resp.setContentType(PortletResponse.CONTENT_TYPE_TEXT_WIKI);
}
\{portlet\}


- means I had to split the line over several lines to get the formatting pretty. When you use the code please remove the
, and stitch the line together again.

Example of (advanced) usage (script mode, html style)
\{portlet:classname=org.test.portlet.NewsPortlet\}
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import bucket.container.ContainerManager;

import com.atlassian.confluence.pages.BlogPost;
import com.atlassian.confluence.pages.PageManager;
import com.atlassian.confluence.renderer.PageContext;
import com.atlassian.confluence.renderer.PortletConfig;
import com.atlassian.confluence.renderer.WikiStyleRenderer;
import com.atlassian.confluence.spaces.Space;
import com.atlassian.confluence.spaces.SpaceManager;
import com.telenor.confluence.macros.portlet.GenericPortlet;
import com.telenor.confluence.macros.portlet.PortletConfig;
import com.telenor.confluence.macros.portlet.PortletRequest;
import com.telenor.confluence.macros.portlet.PortletResponse;
import com.telenor.confluence.utils.TextHtml;

public void init(PortletConfig config) throws PortletException {
}


SpaceManager spaceManager = (SpaceManager) ContainerManager.getInstance().getContainerContext().\\
getComponent("spaceManager");
PageManager pageManager = (PageManager) ContainerManager.getInstance().getContainerContext().\\
getComponent("pageManager");
WikiStyleRenderer renderBean = (WikiStyleRenderer) ContainerManager.getInstance().\\
getContainerContext().getComponent("wikiStyleRenderer");
SimpleDateFormat dateformat = new SimpleDateFormat("d.M.yy H:mm");

public void service(PortletRequest req, PortletResponse resp) {
	ArrayList spaces = (ArrayList) spaceManager.getSpaces();

	// Retrieve Blogs
	ArrayList allBlogs = new ArrayList();
	StringBuffer newsList = new StringBuffer();
	for(int n=0;n<spaces.size();n++) {
		Space space = (Space) spaces.get(n);
		ArrayList blogs = (ArrayList) pageManager.getRecentlyAddedBlogPosts(5, space.getKey());
		allBlogs.addAll(blogs);
		if (blogs.size() > 0) {
			newsList.append("<b>" + TextHtml.text2html(space.getName()) + "</b><br>\n");
			for(int t=0;t<blogs.size();t++) {
				BlogPost blog = (BlogPost) blogs.get(t);
				newsList.append("<a href=\"/confluence" + \\
blog.getUrlPath() + "\"><small>" + TextHtml.text2html(blog.getTitle()) + "</small></a><br><small>" + \\
dateformat.format(blog.getCreationDate()) + "</small><br>\n");
			}
			newsList.append("<br>\n");
		}
	}

	// Initialize Blogs sorter
	Comparator dateCompare = new Comparator() {
		public int compare(Object o1, Object o2) {
			if ((o1 instanceof BlogPost) && (o2 instanceof BlogPost)) {
				BlogPost bp1 = (BlogPost) o1;
				BlogPost bp2 = (BlogPost) o2;
				return bp2.getCreationDate(). \\
compareTo(bp1.getCreationDate());
			}
			return 0;
		}
	};

	// Sort blogs
	Collections.sort(allBlogs, dateCompare);

	// Display blogs
	resp.getWriter().print(displayBlogsAsNews(allBlogs, newsList));
}

public String renderContent(BlogPost blog) {
	String excerptTag = "{excerpt}";
	String beginTag = "{anchor:begintease}";
	String endTag = "{anchor:endtease}";
	PageContext ctx = blog.toPageContext();
	String content = blog.getContent();
	int aBegin = content.toLowerCase().indexOf(beginTag);
	int aEnd = content.toLowerCase().lastIndexOf(endTag);
	int eBegin = content.toLowerCase().indexOf(excerptTag);
	int eEnd = content.toLowerCase().lastIndexOf(excerptTag);

	int begin, end, beginTagLen, endTagLen;
	if(aBegin>=0 && aBegin<eBegin) {
		begin = aBegin;
		beginTagLen = beginTag.length();
	} else {
		begin = eBegin;
		beginTagLen = excerptTag.length();
	}
	if(aEnd>=0 && aEnd>eEnd) {
		end = aEnd;
		endTagLen = endTag.length();
	} else {
		end = eEnd;
		endTagLen = excerptTag.length();
	}

	if (begin >= 0 && end >= 0) {
		content = content.substring(begin+beginTagLen, end);
	}
	while(content.startsWith("\n")) {
		content = content.substring(1);
	}
	while(content.endsWith("\n")) {
		content = content.substring(0,content.length()-1);
	}
	return renderBean.convertWikiToXHtml(ctx, content);
}

public String insertArticle(BlogPost blog) {
	StringBuffer r = new StringBuffer();
	r.append("<small>" + \\
TextHtml.text2html(blog.getSpace().getName()) + ":</small><br>\n");
	r.append("<b>" + TextHtml.text2html(blog.getTitle()) + "</b><br>\n");
	r.append(TextHtml.text2html(renderContent(blog)) + "\n");
	r.append("<A HREF=\"/confluence" + blog.getUrlPath() + "\">Read story</A>\n");
	r.append("<small>[" + dateformat.format(blog.getCreationDate()) + "]</small>\n");
	return r.toString();
}

public String displayBlogsAsNews(ArrayList blogs, StringBuffer newsList) {
	StringBuffer out = new StringBuffer();
	out.append("<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"0\">\n");
	out.append("<TR><TD WIDTH=\"75%\" VALIGN=\"TOP\">");
	out.append("<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLPADDING=\"4\" CELLSPACING=\"0\">\n");
	out.append("<TR>");
	int n = 0;
	int count = 0;
	boolean first = true;
	String categoryName;
	while (n < blogs.size()) {
		BlogPost blog = (BlogPost) blogs.get(n);
		if (first) {
			out.append("<TD COLSPAN=\"2\" VALIGN=\"TOP\">" + \\
insertArticle(blog) + "</TD>\n");
			first = false;
			count--;
		} else {
			out.append("<TD WIDTH=\"50%\" VALIGN=\"TOP\">" + \\
insertArticle(blog) + "</TD>\n");
		}
		count++;
		if (count % 2 == 0) {
			out.append("</TR>\n<TR><TD COLSPAN=\"2\">"+ \\
"<IMG SRC=\"images/blank.gif\" WIDTH=1 HEIGHT=1></TD></TR>\n<TR>");
		}
		n++;
	}
	out.append("</TR>");
	out.append("</TABLE></TD>");
	out.append("<TD>&nbsp;&nbsp;</TD>");
	out.append("<TD WIDTH=\"25%\" VALIGN=\"TOP\">");
	out.append("<b>News Archive</b><hr>\n");
	out.append(newsList.toString());
	out.append("</TD></TR></TABLE><br><br>\n");
	return out.toString();
}
\{portlet\}



Labels

plugin plugin Delete
portlet portlet Delete
hidden hidden Delete
toc toc Delete
script script Delete
repository_current repository_current Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Aug 23, 2005

    Bob Swift says:

    Here is the same example as above using a wiki table with links. {script:outpu...

    Here is the same example as above using a wiki table with links.

    {script:output=wiki}
    import com.atlassian.confluence.user.UserAccessor;
    import bucket.container.ContainerManager;
    import com.opensymphony.user.User;
    
    UserAccessor userAccessor = (UserAccessor) ContainerManager.getInstance().getContainerContext().getComponent("userAccessor");
    ArrayList users = userAccessor.getUsers();
    System.out.println("|| User ID || Full name || Email || Groups ||");
    
    for(User user: users) {
      List groupList = user.getGroups();
      String groups = new String();
      for(String group: groupList) {
        groups += group + " \\\\ ";
      }
      System.out.println("| " + user.getName() + " | [~" + user.getName() + "] | [mailto:" + user.getEmail() + "] | " + groups + "|");
    }
    {script}
    
  2. Jan 07, 2006

    Bob Swift says:

    The {script} macro causes problems with Confluence 2.x. It has been replaced wit...

    The {script} macro causes problems with Confluence 2.x. It has been replaced with the Beanshell Macro. The {script} macro is also defined for source compatibility. Make sure you disable the {script} macro in this plugin once you install the new support.

  3. Feb 12, 2007

    Kelly Heese says:

    We have v 2.0 of this plugin installed in our Confluence v229.  I can't get...

    We have v 2.0 of this plugin installed in our Confluence v229.  I can't get any link to appear in the toc. 


    Just renders plain text toc. How can I get links to appear??

    1. Feb 12, 2007

      Kelly Heese says:

      This didn't copy over in to my original comment above. This is the code I'm usin...

      This didn't copy over in to my original comment above. This is the code I'm using.

      {toc:anchor=true}
      
      
  4. Feb 13, 2007

    Tom Moore says:

    I cannot install this plugin into Confluence 2.3.2.  Get a Java exception e...

    I cannot install this plugin into Confluence 2.3.2.  Get a Java exception error

    2007-02-13 14:53:29,122 ERROR [http-8080-Processor23] [com.atlassian.plugin.DefaultPluginManager] enablePluginModules There was an error loading the descriptor 'script' of plugin 'confluence.extra.portlet'. Disabling.
    java.lang.NoClassDefFoundError: bucket/container/ComponentNotFoundException
            at java.lang.Class.getDeclaredMethods0(Native Method)

    ... 

    ...

    etc

  5. Feb 28, 2007

    Brandon Whitehead says:

    I have version 2.0 of this plugin installed on Confluence 2.3.3 and the hidden m...

    I have version 2.0 of this plugin installed on Confluence 2.3.3 and the hidden macro is not recognized.

    1. Mar 16, 2007

      Bob Swift says:

      I don't install this plugin anymore for the following reasons: Hidden macro - ...

      I don't install this plugin anymore for the following reasons:

      1. Hidden macro - define a user macro called hidden, check macro has body, and leave the template blank
      2. TOC - [Table of Contents Plugin] is much better to use
      3. Script - Java Scripting Plugin is more recent
      4. Portlet - not using this
      1. Aug 01, 2007

        David Goldstein says:

        Bob-  Thanks for the clever tip on replacing the hidden macro from this plu...

        Bob-  Thanks for the clever tip on replacing the hidden macro from this plugin with a user macro.

        Since we upgraded to 2.5.4 this plugin has never installed properly and required us to remember every restart of Confluence to go to the Plugin Repository and check the Configure checkbox to enable the plugin.  Then go to the standard Plugin admin page to verify that the 'hidden' macro was enabled.  Note -- if you don't use the Plugin Repos Config enable first, you can't get the 'hidden' macro enabled from just the standard Plugin admin.

        So, I'm able to finally uninstall this plugin by just using the simple 'hidden' user macro instead. 

  6. Apr 16, 2008

    jms says:

    In case someone else is looking for the source, the table above should read Do...

    In case someone else is looking for the source, the table above should read

    Download Source included in the jar below
    Download JAR portlet-os-plugin-for-v2.x.jar

    as the jar actually contains the source code.

  7. Sep 26

    Monaury Cécile says:

    Hello,  I have trouble with toc macro in french language (confluence 2.9):...

    Hello,

     I have trouble with toc macro in french language (confluence 2.9): it can't deal with é à è and co !

    1. Oct 01

      Monaury Cécile says:

      It's a knowing bug of 2.9.

      It's a knowing bug of 2.9.

  8. Oct 01

    Ben Whitehouse says:

    Hello, Does the portlet macro support the JSR-168 standard i.e. could I drop so...

    Hello,

    Does the portlet macro support the JSR-168 standard i.e. could I drop something like the Syncex Calendar portlet directly in to it?

    Thanks