How to: Add a Tab to a Place

    Originally written by Ryan King

    So any praise, please direct his way.  Any issues with content, please blame me...had to strip out some internal elements ... but I think the example should make sense.

    - Ryan Rutan

     

    Back in the day, adding a tab to a space or a social group meant simply adding an entry to the <components> entry in your plugin's plugin.xml file.

     

    In Jive 5, this is no longer the case.  But I know how.  And I will show you.

     

    The tabs of a place are now managed via Spring, in a MergeableCollection that contains a list of ActionLink instances.

     

    Here's how it's defined in the core product:

    spring-ui-components.xml

            <bean id="placeTabLinks" class="com.jivesoftware.community.util.spring.MergeableCollection" scope="prototype">
                <property name="source">
                    <util:list value-type="com.jivesoftware.community.web.component.ActionLink" scope="prototype">
                        <ref bean="placeTabOverviewLink"/>
                        <ref bean="placeTabTasksLink"/>
                        <ref bean="placeTabContentLink"/>
                        <ref bean="placeTabPeopleLink"/>
                        <ref bean="placeTabPlacesLink"/>
                    </util:list>
                </property>
            </bean>
    

     

    Adding a link is now very easy and flexible!  Here's how:

    In my plugin's spring.xml, all I need to do is add the following:

     

            <bean id="myPlaceTabLinks" class="com.jivesoftware.community.util.spring.MergeableCollection" scope="prototype" parent="placeTabLinks">
                <property name="source">
                    <util:list value-type="com.jivesoftware.community.web.component.ActionLink" scope="prototype">
                        <ref bean="myTabLink" />
                    </util:list>
                </property>
            </bean>
            <bean id="myTabLink" class="com.jivesoftware.community.xxx.MyTabLink" parent="actionLinkBase" scope="prototype">
                <property name="ID" value="jive-place-link-mylink" />
                <property name="nameKey" value="place.mylink.link" />
                <property name="url" value="place-mylink.jspa" />
            </bean>
    

     

    The myPlaceTabLinks adds a new link, myTabLink, to the parent list, placeTabLinks.

    (Note: the parent="placeTabLinks" reference)

     

    The myTabLink bean points to a new Java class, MyTabLink, which defines how the link itself behaves.  While most of the link's attributes are defined here, in the bean definition, the class is important because it is there that we define how the link's URL is rendered.

     

    Unfortunately, we can't just define the url as "place-mylink.jspa", and leave it at that.  The way the links are rendered make it impossible to do that.  Whatever value we specify for the url property will be prepended with <jiveURL>/community/<communityName>. Ideally, all we would need to do is define the url property as "my-link", and it would render as <jiveURL>/community/<communityName>/my-link, but that won't work, because that URL will be intercepted and interpreted by CommunityURLMapping, and since it doesn't recognize "my-link", it will default to <jiveURL/community/<communityName>, and our dream of a pretty URL is dead.

     

    Instead, we need to do some overriding and define how the URL will be formatted, as well as when the tab will show:

     

        public class MyTabLink extends PlaceTabLink {
            EntitlementCheckProvider<Event> entitlementCheckProvider;
            @Override
            public boolean isVisible() {
                JiveContainer container = uiComponentContext.getContainer();
              /*** INSERT LOGIC TO DETERMINE VISIBILITY BY USER, CONTAINER, ETC... ***/
                return true;
            }
        }
    

     

    Once this is in place, all that is required is to:

     

    Define the place-my-link action in the plugin's struts.xml file.

    <action name="place-my-link" class="com.jivesoftware.community.xxx.action.PlaceMyLinkAction" >
                <param name="tab">jive-place-link-mylink</param>
                <result name="success" type="soy">jive.xxx.mylink.place</result>
    </action>
    

     

    Create the Struts action class, such as:

    package com.jivesoftware.community.xxx.action;
    
    import com.jivesoftware.community.places.action.PlaceActionSupport;
    import com.jivesoftware.community.places.rest.Place;
    import com.jivesoftware.community.places.rest.impl.PlaceViewBean;
    import com.jivesoftware.community.util.JiveContainerPermHelper;
    
    public class PlaceMyLinkAction extends PlaceActionSupport {
    
        /**** CAN BE ANY OBJECT, ITS DATA WILL BE INTROSPECTED INTO SOY REFERENCES ****/
        private PlaceMyLinkBean model;
        
        @Override
        public String execute() {
            
            /*** REFERENCE FOR THE CURRENT PLACE ***/
            Place place = getPlace();
            
             /*** ASSIGN YOUR BEAN HOWEVER YOU NEED TO ***/
            model = new PlaceMyLinkBean("Hello World");
            
            return SUCCESS;
        }
    
        /*** OVERRIDE THE getModel METHOD TO RETURN TO SOY ***/
        @Override
        public Object getModel() {
            return model;
        }
    
    }
    d
    
    
    
    
    

     

    Create the soy template that will house the information you want to display

    The SOY template should include all the place header information so that the tabs display and function correctly.  That would look something like this:

     

    {namespace jive.xxx.mylink}
    
    /**
        * @param place
        * @depends template=jive.place.head
        * @depends template=jive.place.header
        */
        {template .place}
            <head>
                {call jive.place.head data="all" /}
            </head>
            <body class="j-body-place">
                {call jive.place.header data="all" /}
               
                <div class="j-layout j-layout-l j-contained j-contained-tabs j-contained-tabs-place j-rc4 clearfix">
                    <div class="j-column-wrap-l">
                        <div class="j-column j-column-l">
                            //your content here
                        </div>
                    </div>
                </div>
            </body>
        {/template}
    

     

    Hope this helps at least introduce people to concept of the MergeableCollection in Jive5, and how it can be used to:

    • Add Tabs to Container Bars
    • Add Buttons to Global Navigation
    • Add Values to Global Dropdowns
    • and more