6 Replies Latest reply on Apr 5, 2009 10:09 PM by soundspeace

    Custom navigation region

    johnnythehun

      The navigation tab portlet gets displayed on every page, that has a layout region called 'navigation'.

      In my scenario I need two navigation components - the default, tab-navigation on the top and a tree-like navigation of sub pages on the left.

      Is there any way I can hard code a portlet to appear on every page with my custom layout? For example a 'sidenavigation' region that always gets filled with my TreeNavigation portlet?

      (How does this work? How does the Navigation portlet always get injected into the navigation region?)

        • 1. Re: Custom navigation region
          johnnythehun

          I have found the solution, but I would like to ask the Portal developers if there is a more elegant solution.

          If not, will a later version of JBoss Portal support
          - injecting default portlets into "special" regions (like the navigation region, but with real portlets)
          - or support markup in layouts that specify portlets to be injected at the place of the markup, for example

          <p:injectPortlet instance="InjectMePortletInstance">
          <parameters/>
          </p:injectPortlet>
          



          And the solution for Injecting content to a custom region for the current version is:

          1. Create a class Named
          MyPageCustomizerInterceptor that extends ControllerInterceptor

          2. Get JBoss source and copy the contents of:
          org.jboss.portal.core.aspects.controller.PageCustomizerInterceptor
          into your class code.
          Import a bunch of JBoss libraries

          3. there is a part in the code in the "invoke" method:

          if (tabbedNav != null)
           {
          ....
           }
          
          


          instantly after this code insert the following (of course modified to your preferences). Modify the "BLAH2" and the "inject_region" strings to your needs.

          
           String toInject = "<h1>AT LAST! I have injected my custom stuff!</h1>";
           Map windowProps = new HashMap();
           windowProps.put(ThemeConstants.PORTAL_PROP_WINDOW_RENDERER, "emptyRenderer");
           windowProps.put(ThemeConstants.PORTAL_PROP_DECORATION_RENDERER, "emptyRenderer");
           windowProps.put(ThemeConstants.PORTAL_PROP_PORTLET_RENDERER, "emptyRenderer");
           WindowResult res = new WindowResult("", toInject, Collections.EMPTY_MAP, windowProps, null, WindowState.NORMAL, Mode.VIEW);
           WindowContext blah = new WindowContext("BLAH2", "inject_region", "0", res);
           rendition.getPageResult().addWindowContext(blah);
           Region region = rendition.getPageResult().getRegion2("inject_region");
           DynaRenderOptions.NO_AJAX.setOptions(region.getProperties());
          



          3. Put your classes into a jar and put them under
          JBOSS_HOME\server\default\lib\

          4. Modify
          JBOSS_HOME\server\default\deploy\jboss-portal.sar\META-INF\jboss-service.xml

          replace org.jboss.portal.core.aspects.controller.PageCustomizerInterceptor in
          <mbean code="org.jboss.portal.core.aspects.controller.PageCustomizerInterceptor"
          

          with the full classname of your class

          • 2. Re: Custom navigation region
            johnnythehun

            I have been thinking about this concept.

            Wouldn't it be a more elegant solution if I would use a custom regionRenderer, that renders a specific portlet if it finds a
            injectPortlet="MyPortletToInjectInstance"
            property in a region?

            But I don't know how to do this.

            What I found, is that the

            1. DivRegionRenderer iterates through RegionRendererContext.getWindows()
            Of course this getWindows() function will not return a WindowRendererContext for the injected portlet since it is not configured via xml or the admin page.

            2. For every WindowRendererContext it renders the window via RendererContext.render()


            So I assume I need to create a WindowRendererContext for every injected portlet too and call the RendererContext.render() with them.


            3. JBoss implements whis WindowRendererContext with the WindowContext class.
            The constructor of this class is:
            WindowContext(java.lang.String id, java.lang.String regionName, java.lang.String order, WindowResult result)

            - What is the id?
            - regionname I can handle
            - what is the order?

            I think the above parameters can be easily created, but for the last parameter - WindowResult - I have no idea what to write.

            The constructor of WindowResult is:
            WindowResult(java.lang.String title, java.lang.String content, java.util.Map actions, java.util.Map windowProperties, java.util.List<org.w3c.dom.Element> headerContent, org.jboss.portal.WindowState windowState, org.jboss.portal.Mode mode)


            Can anyone help me on this?

            • 3. Re: Custom navigation region
              johnnythehun

              Ok, I don't get where the portlet markup get's created.

              I see that the WindowContext already get's the markup via its String content parameter, so I need to create the portlet markup BEFORE instanciating a WindowContext

              But how do I create the markup for a specific portlet instance?
              What is the class that I can instanciate or the utility I can call to create the markup?

              I looked at DivPortletRenderer which calls PortletRendererContext.getMarkup() to get the markup.

              PortletRendererContext is implemented via PortletRendererContextImpl.
              The getMarkup() function of PortletRendererContextImpl gets the markup from the WindowContext.

              So now I'm in a circle - I have to create the markup before any XYContext comes into the picture. But I don't know what creates the markup for a Portlet instance.

              The best would be to have some Class or Function like:

              new PortletMarkupGenerator(String portletInstanceName).getMarkup();


              I found some code in the injectTabbedNav of PageCustomizerInterceptor class:

              public String injectTabbedNav(PageCommand rpc)
               {
              ControllerContext controllerCtx = rpc.getControllerContext();
               ControllerRequestDispatcher rd = controllerCtx.getRequestDispatcher(targetContextPath, tabsPath);
              
               //
               if (rd != null)
               {
               Page page = rpc.getPage();
               PortalAuthorizationManager pam = portalAuthorizationManagerFactory.getManager();
               PortalNodeImpl node = new PortalNodeImpl(pam, page);
              
               //
               rd.setAttribute("org.jboss.portal.api.PORTAL_NODE", node);
               rd.setAttribute("org.jboss.portal.api.PORTAL_RUNTIME_CONTEXT", Navigation.getPortalRuntimeContext());
              
               //
               rd.include();
               return rd.getMarkup();
               }
              return null;
              }
              



              The following lines are used to access the jsp to create the tabs:
              ControllerContext controllerCtx = rpc.getControllerContext();
               ControllerRequestDispatcher rd = controllerCtx.getRequestDispatcher(targetContextPath, tabsPath);
              



              1. This function renders a jsp file, it doesn't render a Portlet.

              2. This function uses a PageCommand instance to create the markup. But I don't see that a RegionRenderer gets a PageCommand parameter


              So the best would still be to have some Class or Function like:

              new PortletMarkupGenerator(String portletInstanceName).getMarkup();

              • 4. Re: Custom navigation region
                psevestre

                Hi,

                I've faced a similar problem: A main menu with top-level pages and an accordion-style sidebar menu.

                My solution:

                1. In tabs.jsp, I always render both menus (ul/li structures)
                2. In layout pages, I have two instances of the "navigation" region, using distinct "regionID" values.
                3. In the theme CSS files, I show/hide the unwanted menu for each case, using the different regionIDs.

                As an optimization, you can save the rendered markup on step 1 at session level when called from the first occurence of the nav region and use this cached data to render subsequent calls.




                • 5. How to implement custome navigation
                  nareshkumar.sanda

                  hai,
                  I have a portlet in that i have some links when i click that appropriate portlet should be displayed in the right side of the portal page.How can i implement these king of communication between the portlets.

                  Thanks
                  -naresh

                  • 6. Re: Custom navigation region
                    soundspeace

                    all the problem that you want to resolve.

                    just need edit in CSS only.
                    make sure make another id css such as :-

                    #navigationFooter {
                    }

                    #navigationFooter #tabHeader{
                    }

                    #navigationFooter #tabHeader ul{
                    }


                    something like this la... just give idea