HTML Macro: manipulate another macro's result
Asked by Stefan Mueller:

Can I use the HTML macro to manipulate the outcome of another macro such as the Page Tree Macro?


Answers:
author: Sven Schatter _Lively Apps_
body: Yes, as you can execute arbitrary JavaScript you can [manipulate anything in the DOM](https://plainjs.com/javascript/manipulation/). However it's not very advisable to vastly change HTML that other JavaScript might rely on. In the case of a Page Tree Macro it should be okay but generally you can always break functionality by manipulating HTML that is "not yours" (rendered/created by you).

comments: author: Stefan Mueller
body: That it good news but that get me to question how to do it ??.

I want to to filter the page tree. I want only shown what are labeled by certain label.

How can I loop through the result of the Page Tree Macro, check the page's label(s) and hide them if they don't match?


author: Sven Schatter _Lively Apps_
body: I'll try to give you a short JS lesson here but you'll quickly figure that this is not a beginner friendly problem and that doing it via JS is not the best solution in this case.

First you'll want to look at the HTML that is generated by the macro.

![pagetreemacrohtml.PNG](https://community.atlassian.com/t5/image/serverpage/image-id/71463i58C7502281BC4949/image-size/large?v=v2&px=999 "pagetreemacrohtml.PNG")

As you can see it is a **UL** with the class **plugin_pagetree_children_list** . Each direct child **LI** represents a top level item in the page tree. Using the selector **.plugin_pagetree_children_list \> li** we can grab all of those:

```
var listItems = $('.plugin_pagetree_children_list > li');
```

Once we got the **LI**s we need to look at the HTML again to find the node that contains the text.

![pagetreemacrohtml2.PNG](https://community.atlassian.com/t5/image/serverpage/image-id/71466i34427599D65AA584/image-size/large?v=v2&px=999 "pagetreemacrohtml2.PNG")

As you can see these nodes have the class**.plugin_pagetree_children_content** and we only want the **:first** one because we are in a tree and there might be children. Once we have the text we can perform a check against it to see if we should remove the item.

```
function yourFilter(text) {
  return true; // perform your own check here
}

$('.plugin_pagetree_children_list > li').each(function(index, item) {
  var $item = $(item);
  var text = $item.find('.plugin_pagetree_children_content:first').text().trim();

  if (yourFilter(text)) {
    $item.remove();
  }
});
```

Of course you will need to put your own logic into **yourFilter()**. As you said want to check the labels of these pages you will need to perform a REST call here to get the labels for each page. This is very inefficient and also problematic because you only have the page title at this point but not the page id.

Now we need to do the same thing again for all list items in the child tree of our list item (if there is one). Oh, and then we also need to check if we removed all children of an item because if there are no children anymore we need to alter the HTML so the node is not expandable anymore.

![pagetreemacrohtml3.PNG](https://community.atlassian.com/t5/image/serverpage/image-id/71468i43BCC841EA4EAEB1/image-size/large?v=v2&px=999 "pagetreemacrohtml3.PNG")

And this of course needs to be done for all child items as well...

I'm gonna stop here. As you see you got yourself in for a ride and this problem is not as simple as you might've thought. Especially if you're new to JavaScript.

I'd strongly suggest [writing your own Page Tree Macro](https://developer.atlassian.com/server/confluence/writing-macros/) instead of doing this via JS. That should be a whole lot simpler and much more stable and performant.


author: Stefan Mueller
body: wow, that is more than I could expect!
> **lugin_pagetree_children_list \> li**

why do you include '\> li'?
> we can grab all of those

what happens if the macro is used multiple times on the page. I reckon the *filter function*has to deal with it, isn't it?
> we only want the **first** one because we are in a tree

only first you say, as there could be child pages, isnt' it?
> And this of course needs to be done for all child items as well...

laborious but feasible :)
> I'm gonna stop here. As you see you got yourself in for a ride and this problem is not as simple as you might've thought. Especially if you're new to JavaScript

I'm not very new to JS but having problems understanding how to interact with Atlassian content
> To be honest my suggestion would be to go another route and [write your own special Page Tree Macro](https://developer.atlassian.com/server/confluence/writing-macros/) if you have these requirements

I would like but how to allow such user-driven development is still in discussion at IT (at a lower priority)

I could create a script and put it on a public repository. It could be called inside HTML Macro to create a customized page tree, but that would get me to the question how to loop through the child pages of a Space.  
May [Writing User Macro to list children of page limited by label - Where can I find Confluence Methods?](https://community.atlassian.com/t5/Confluence-questions/Writing-User-Macro-to-list-children-of-page-limited-by-label/qaq-p/383362) tells how to do it but I wondering how to get this in an HTML Macro to work?


author: Sven Schatter _Lively Apps_
body: > why do you include '\> li'?

Because we want the listitems (li) and not the ul. But there's 100 different ways to do this.
> what happens if the macro is used multiple times on the page. I reckon the *filter function* has to deal with it, isn't it?

I haven't handled this case. Another reason why you should just build your own macro instead.
> only first you say, as there could be child pages, isnt' it?

Yes.
> I could create a script and put it on a public repository. It could be called inside HTML Macro to create a customized page tree, but that would get me to the question how to loop through the child pages of a Space.

If you're doing this via JS your only choice is to use the [Confluence REST API](https://docs.atlassian.com/ConfluenceServer/rest/7.1.0/). Depending on the amount of pages in your tree this might require hundreds of HTTP requests for rendering a simple page tree. That is the reason why people are doing it via a User Macro as in your linked example. Doing it via a real self-written Java Macro would be even better.

I'll say it more clearly: JS is not the right tool here.


author: Stefan Mueller
body: > \> why do you include '\> li'?
>
> Because we want the listitems (li) and not the ul. But there's 100 different ways to do this.

sorry I have a mind like a sieve, there it is again [Child Selector ("parent \> child") \| jQuery API Documentation](https://api.jquery.com/child-selector/).
> If you're doing this via JS your only choice is to use the [Confluence REST API](https://docs.atlassian.com/ConfluenceServer/rest/7.1.0/).

thanks

I'll say it more clearly: JS is not the right tool here.

I wish I could create my own [use macro](https://developer.atlassian.com/server/confluence/user-macro-module/) or [Confluence macro](https://developer.atlassian.com/server/confluence/creating-a-new-confluence-macro/) but it is worthless as it won't be allowed within our Confluence currently.


Tags: confluence-server

javascript

macro

server