I have a velocity User Macro that displays a navbar on a page. A page author can add the macro to a page, and use its parameters to alter the navbar contents.
The only problem I have is when the page contains an include to another page that also has the navbar macro.
I would like the User Macro to do nothing if it is on an included page.
Is there a way to detect, from inside the macro, whether it is being called on an included page, rather than the main page being rendered?
An alternative approach I tried is to edit the Page Layout decorator to find the macro (if it exists) on the main page source, and then parse its parameters, and then call the macro with a special "doit" parameter to actually build the navbar. (The macro would do nothing if the "doit" parameter is absent.) However, I also found no elegant way to parse the body, alter the macro call, and then call it. Any ideas?
Community moderators have prevented the ability to post new answers.
I found a solution that appears to work!
Inside the macro, you can get the current HttpServletRequest object $req, that has access to the URI for the page being rendered. (See Confluence Objects Accessible From Velocity.) If the macro is on an included page, then the page title of the $req and $content objects will be different.
The call $req.getParameter("title") gets the title found in the URL being rendered. And $content.getDisplayTitle() gets the title of the content page. If they are different, then the content is an include.
The only tricky part is that if the the title of the page contains non-displayable character (like ampersands), then $req.getParameter("title") returns nothing. So in that case you need to compare pageIDs instead ... using $req.getParameter("pageID") compared to $content.getIdAsString().
So this appears to work:
#set ($doit = true) #set ($TitleOfPageBeingRendered = $req.getParameter("title")) #if ($TitleOfPageBeingRendered) ## We found title in URL #if ($TitleOfPageBeingRendered != $content.getDisplayTitle()) #set ($doit = false) ## Titles didn't match. #end #else ## If we can't find title in URL, then compare pageIDs. #set ($IdOfPageBeingRendered = $req.getParameter("pageId")) #if (!$IdOfPageBeingRendered) #set ($doit = false) ## Couldn't find title or pageID. #elseif ($IdOfPageBeingRendered != $content.getIdAsString()) #set ($doit = false) ## pageIDs didn't match. #end #end #if ($doit) ## I.e., this is not an 'include'. ## Rest of macro code goes here. #end
If anybody sees any gotchas with this, please let me know. But it appears to work.
Hi Fred,
A bit late in replying, but I did figure out a way to do this, although it's really hacky.
You can access the HttpServletResponse item in velocity (although it's not recommended) as $res.
If you add some sort of HTTP header at the end of your user macro, like $res.addHeader("NAVBAR","") and then add a check at the beginning of your user macro, like #if ( !$res.containsHeader("NAVBAR") ), then you can ensure that your user macro will only be run once on the page.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks Stephen! I ended up finding a solution before I saw yours, and came here to post it when I saw your suggestion. My solution is similar to yours. The HttpServletResponse item is indeed accessible in the $req object (not $res). You don't need to add anything to the page ... just compare the pageTitle (or pageID) in the $req object, to that in the $content object. They will be different on an included page. I have written this up below.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Correction: $req is the HttpServletRequest object, not the HttpServletResponse object.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I guess that by default velocity variables are global. Not very elegant but working approach could be to set some global variable inside of your macro (something like "rendered") and then check it in the same macro and do nothing when it's set.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks Volodymyr ... I tried that, and confirmed that velocity variables are _not_ global in that sense. I.e., one cannot set a variable inside of a User Macro that then can be checked in a later call to the macro.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You could use the excerpt include macro to include the page and leave the macro out of the excerpt in the included page.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Interesting idea ... but then the author of the included page would have to remember to wrap all of the page in an *excerpt* macro, except for the navbar User Macro. Not something we can ask authors to remember (and it would prevent them from using the *excerpt* macro for other purposes).
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.