Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member
0 Kudos

Top Level Navigation - Horizontal Drop-Down Menu

June, 2014

Prerequisites: 

§  Basic knowledge of SAP NetWeaver 7.3

§  Basic knowledge of SAP NWDS 7.3

§  Basic knowledge of HTML, Java Script, CSS

§  Basic knowledge of SAP NetWeaver Portal Adminstration

§  Basic knowledge of LSAPI's

II  Introduction:


This article will tell you how to develop a cutom top level naviagation using Navigation Tag Library and LSAPI's -- Horizontal Drop Down Menu which behaves like a SAP delivered TLN.  It works pefectly in IE 9 (Internet Explorer only).

 

Process for creation of TLN:   

Create a war file in NWDS studio.  Create a two jsp files namely header.jsp and header_style.jsp  with the code as shown below

Include the header_style.jsp file in header.jsp file.  The header_style.jsp file contains only the CSS. 

Download the com.sap.portal.navigation.afp.tln war file and import the war file into the NWDS studio or create a new war/ear file. Include the header.jsp and header_style.jsp file in jsp folder under dist folder.  Also make changes to the portalapp.xml file as mentioned below.

Using the cascading style sheet the top level navigation is displayed with different colors.

Using the Javascript the drop down menu will be visible for a hovered role if the role has child elements like roles/iviews.

header.jsp

<%@ taglib uri="NavigationTagLibrary" prefix="nav" %>

<%@ taglib uri="FrameworkTagLibrary" prefix="frm" %>


<%-- an include clause for css file --%>

<%@ include file="header_style.jsp" %>



<script type="text/javascript">


var clicked = false;

var currEl = 0;


function(navigationDiv) {


if (!document.all) return; // continue only for IE


var liEls = document.getElementById(navigationDiv).getElementsByTagName("LI");

var id21;

var countLevels1 = 0;

var brandingWidth = 0;


for (var i=0; i<liEls.length; i++) {

     liEls[i].setAttribute("idValue");

     liEls[i].idValue = i;

                   

     if(liEls[i].className == "current" || liEls[i].className == "Level1"){


     id21 = i; liEls[i].setAttribute("id2Value"); liEls[i].id2Value = id21;


     var contentAEl = document.getElementById("navigation").getElementsByTagName("A")[i].innerHTML;

// To set the width of the TLN we need to get the continue only for IE

     brandingWidth = brandingWidth + (contentAEl.length)*7 ;

     countLevels1++;

     }

The below figure is taken from the developer tools of IE 9.

/*

In the above figure it has four roles indicated as "Level1" and "current" class.  The class name assigned is “Level1” .

When the user clicks on the role for eg. “User Administration” the class name of that parent node / parent role is set to “current” and the current element’s parent node / parent role calss name is set to “currenthref”.  The font color of parent node / parent role is set to the shade of red ("#C51733").

If the roles do not have child elements, the idvalue will be same as of id2Value.

But for User Administration role  there are four child elements and so their idvalues will be different from id2Value. The class  name assigned is “Level2” for these child elements. These id2Values are same as of their parent node as shown in below figure.  This will help to distinguish the node of the parent from the child elements to set the color and background color when the child element is selected.

*/

// as shown in the above fiugre I have mainly added the above code to find out  the level one with level two node.

     if(liEls[i].className == "Level2"){

          liEls[i].setAttribute"id2Value");

          liEls[i].id2Value = id21;

     }

     liEls[i].onmouseover = function() {

          this.className += " hover";

          var aEl = document.getElementById(navigationDiv).getElementsByTagName("A");

          this.id2Value].style.color="#C51733";

          };


     liEls[i].onmouseout = function() {

          this.className = this.className.replace(new RegExp(" hover\\b"), "");

          var lEl = document.getElementById(navigationDiv).getElementsByTagName("LI");

          var aEl = document.getElementById(navigationDiv).getElementsByTagName("A");


          if(clicked)

          { 

            //  The if condition is used for used for work protect mode

               if(currEl != this.id2Value)

               {

                    this.id2Value].className = "Level1";

                    this.id2Value].className = "";

                    this.id2Value].style.color="#FFFFFF";


                    lEl[currEl].className = "current";

                    aEl[currEl].className = "currenthref";

                    aEl[currEl].style.color = "#C51733";

               }
          }
          else

          {

               this.id2Value].style.color="#FFFFFF";

              

               if(lEl[this.id2Value].className == "current")

                    this.id2Value].style.color="#C51733";

          }

     clicked = false;

     };


     liEls[i].onclick = function() {

          //

          //  one can uncomment the below code and can try also.  This was mainly used for work protect mode

             /*   var lEl = document.getElementById(navigationDiv).getElementsByTagName("LI");

             var aEl = document.getElementById(navigationDiv).getElementsByTagName("A");

             for(var j=0; j<lEl.length; j++)

             {

              if(lEl[j].className == "current") {

               lEl[j].className = "Level1"; aEl[j].className = "";

               aEl[j].style.color="#FFFFFF";

                break;

              }

        }

        lEl[this.id2Value].className = "current";//05/06/2014

        aEl[this.id2Value].className = "currenthref"; //05/06/2014

        aEl[this.id2Value].style.color="#C51733";

        //document.getElementById("level2").style.visibility="hidden";

        clicked = true;

        */

  };

}

/* The below code help to set the branding width of the TLN. The top level width is set depending upon the number of roles.  The style set for the top level navigation are font family is Verdana with size of 12.  Each the role text length is taken and multipled by 7(on an average)  and then added to the brandingwidth.  The gap between the roles also need to be conisdered.  The gap between the roles is taken as 22 pixels and this gap is multipled by the number of roles and then added to the branding width. */

brandingWidth = brandingWidth + countLevels1*22;

document.geElementById("navigation").style.width = brandingWidth;


</script>


<%-- this is the main navigation section --%>


<table width="100%" cellpadding="0" cellspacing="0" border="0">


<tr>


<td  nowrap="nowrap">

<div id="branding">

<div id="navigation">


<%-- start the unordered list --%>


<ul>

<%-- go through all the level 1 navigation nodes --%>

<nav:iterateInitialNavNodes>

     <li class='Level1' style="font-size: 12px;"><nav:navNodeAnchor navigationMethod="byEPCM" />

     <%-- check to see if there are level 2 nodes, if so start another <ul> and assign a CSS class --%>

     <nav:ifNavNodeHasChildren>

          <ul>

          <%-- again go through all the nodes in level 2 --%>

               <nav:iterateNavNodeChildren>

               <%-- id l1 is written for second level hover and to set its css properties --%>

                    <li class='Level2' id='l1'><nav:navNodeAnchor navigationMethod="byEPCM" /></li>

               </nav:iterateNavNodeChildren>

          </ul>

     </nav:ifNavNodeHasChildren>

     </li>

</nav:iterateInitialNavNodes>

</ul>

</div>

</div>

</td>

</tr>

</table> 

<script>

  

TLNHover("navigation");

var nodeNameFromNaviagation;

/*

Whenever the navigation changes, the raiseEvent is fired with the current selected/clicked Node name. We can get the path of the current selected/clicked Node by using the LSAPI's. The first element in the pathArray will be have the node name of the "Level one/Parent Node" of the "Top Level Navigation".

This event is subscribed using the function as mentioned below in the header.jsp in top level navigation war file

*/

EPCM.subscribeEvent("urn:com.node.test", "currentNode", onCurrentNode );

function onCurrentNode( eventObj ) {

     var aEls = document.getElementById("navigation").getElementsByTagName("A");

     var lEls = document.getElementById("navigation").getElementsByTagName("LI");

     nodeNameFromNaviagation = eventObj.sourceId;

     aEls[currEl].style.color="#FFFFFF";


     for(var n1=0;n1<aEls.length;n1++)

     {
          if(lEls[n1].className == "current") {

               lEls[n1].className = "Level1"; aEls[n1].className = "";

               //aEls[n1].style.color="#FFFFFF";

               }
     }

     for(var n=0;n<aEls.length;n++)

     {
          if(aEls[n].innerHTML == eventObj.sourceId){

               aEls[n].className = "currenthref";

               lEls[n].className = "current";

               aEls[n].style.color = "#C51733";

               currEl = n;

               clicked =true;

               break;

               }

       }  

}
</script>



header_style.jsp

<style>

navigation, #navigation ul {

background-color: #414141;

font: 11px  verdana;

padding-top: 4px;

padding-bottom: 4px;

margin: 0;

list-style: none;

height: 22px;   
}

#navigation a {

padding-left: 10px;

padding-right: 10px;

padding-top: 4px;

padding-bottom: 4px;

text-decoration: none;

background-color: #414141;

color: #FFFFFF;

display: block;

width: auto;

}

#navigation a.currenthref {

padding-left: 10px;

padding-right: 10px;

padding-top: 4px;

padding-bottom: 4px;

text-decoration: none;

background-color: #FFFFFF;

color: #C51733;

display: block;

width: auto;

}

#navigation a:hover {

background-color: #F4F4F4;

color: #C51733;

display: block;

border-color: #FFFFFF;

font-weight: normal;

}

#navigation li {

bacground-color: #616F9E;

float: left;

}


#navigation li ul {

position: absolute;

width: 17em;

white-space: nowrap;

padding-top: 0px;

padding-bottom: 0px;

color: #ffff00;

left: -999em;

}


#navigation li:hover ul {

left: auto;

width: auto;

display: block;

position: relative;

}

#navigation li:hover ul,

#navigation li.hover ul{

left: auto;

display: block;

border: 1px solid #CBDBEA;

}

#navigation li.hover ul  a:hover{

left: auto;

display: block;

border: 0px solid #CBDBEA;

background-color: #F4F4F4;

color: #414141;

}

.current {

font: 0.4em  verdana;

font-size: 11 px;

border: 0px solid #000000;

font-weight: light;

background-color: #FFFFFF;

color: #C51733;

}

.Level1 {

font: 0.4em  verdana;

font-size: 11 px;

border: 0px solid #000000;

font-weight: light;

background-color: #FFFFFF;

color: #C51733;

}

.Level2 {

font: 11px  verdana;

border: 0px solid #000000;

font-size: 11px;

display: block;  

width: 17em;

white-space: nowrap;

background-color: #F4F4F4;

color: #414141;

}

.clicklink{

background-color: #FFFF00;

color: #0000FF;

}


#navigation ul li.hover a{

left: auto;

display: block;

border: 0px solid #CBDBEA;

background-color: #F4F4F4;

font-weight: normal;

color: #414141;

}


#navigation ul li.hover .Level2{

left: auto;

display: block;

border: 0px solid #CBDBEA;

background-color: #F4F4F4;

font-weight: normal;

color: #414141;

}

#navigation ul li.hover a:hover{

left: auto;

display: block;

border: 0px solid #CBDBEA;

background-color: #F4F4F4;

color: #C51733;

}

.Level2 a{

left: auto;

display: block;

border: 0px solid #CBDBEA;

background-color: #F4F4F4;

color: #FFFF00;

}

#l1 a {

width: auto;

border: 0px solid #000000;

background-color: #F4F4F4;

color: #414141;

}

#l1 a:hover {

width: auto;

border: 0px solid #000000;

background-color: #F4F4F4;

color: #414141;

}

</style>


portalapp.xml

<?xml version="1.0" encoding="utf-8" standalone="no"?>

<application name ="com.sap.portal.navigation.afp.tln">

<application-config>

     <property name="PrivateSharingReference" value="com.sap.portal.useragent,com.sap.portal.navigation.navigationtaglibrary, com.sap.portal.themes.lafservice,com.sap.portal.runtime.system.connection,com.sap.portal.pagebuilder, SAPJ2EE::library:com.sap.portal.common,SAPJ2EE::library:tc~cmi,com.sap.portal.common.commonservices, SAPJ2EE::library:com.sapportals.htmlb,com.sap.portal.navigation.api_service,com.sap.portal.navigation.helperservice, com.sap.portal.navigation.service,com.sap.portal.productivity.resolverservice,com.sap.portal.navigation.afp.helperservice, com.sap.portal.runtime.system.favorites,SAPJ2EE::service:engine.security.facade, SAPJ2EE::library:com.sap.base.technology.facade,S APJ2EE::library:engine.j2ee14.facade,com.sap.portal.search.provider_api,com.sap.portal.search.service,com.sap.portal.contenttaggingservice,S APJ2EE::library:tc~epbc~pcd~gl~api,com.sap.portal.themes.lafservice,com.sap.portal.runtime.system.connection,com.sap.portal.pagebuilder"/>

  <property name="SharingReference" value="com.sap.portal.themes.lafservice,com.sap.portal.navigation.navigationtaglibrary,com.sap.portal.runtime.application.jcoclient, com.sap.portal.ivs.connectorservice,com.sap.portal.htmlb"/>

<!-- <property name="PrivateSharingReference" value="com.sap.portal.useragent,com.sap.portal.navigation.afp.helperservice,com.sap.portal.navigation.helperservice, SAPJ2EE::library:tc~epbc~pcd~gl~api"/> -->

<property name="Vendor" value="sap.com"/>

<property name="SecurityArea" value="NetWeaver.Portal"/>

<property name="fail-over-enable" value="disable"/>

<property name="ClassLoadingPolicy" value="transitive"/>

</application-config>

<components>

<component name="TopLevel">

<component-config>

<property name="ClassName" value="com.sap.portal.navigation.afp.Tln"/>

<property name="ResourceBundleName" value="TopLevel_nls"/>

<property name="SafetyLevel" value="no_safety"/>

</component-config>

<component-profile>

<property name="resourceBundleToClient" value="true"/>

<property name="com.sap.portal.navigation.afp.numberOfLevels" value="2">

<property name="validvalues" value="1/11/2"/>

<property name="plainDescription" value="Number of Display Levels"/>

<property name="longDescription" value="Specifies the number of levels displayed in the top-level navigation. Levels following this number are continued in the detailed navigation area"/>

<property name="category" value="Navigation"/>

</property>

<property name="com.sap.portal.navigation.afp.removableTabs" value="false">

<property name="plainDescription" value="Enable Removable Tabs"/>

<property name="longDescription" value="Enable portal users to remove tabs from top-level navigation"/>

<property name="category" value="Navigation"/>

<property name="administration" value="NON-DIALOG"/>

</property>

<property name="com.sap.portal.navigation.afp.dragableTabs" value="true">

<property name="validvalues" value="4/true5/false"/>

<property name="plainDescription" value="Enable Dragging of Tabs"/>

<property name="longDescription" value="Enables portal users to rearrange the order of top-level navigation tabs"/>

<property name="category" value="Personalization"/>

<property name="configattribute" value="baseLevel"/>        

</property>

<property name="com.sap.portal.navigation.afp.numberOfFixedTabs" value="0">

<property name="validvalues" value="1/01/1"/>

<property name="plainDescription" value="Number of Fixed Entries"/>

<property name="longDescription" value="Defines the number of entries that will be fixed in top-level navigation. All other entries can be scrolled."/>

<property name="category" value="Personalization"/>

<property name="configattribute" value="baseLevel"/>

<property name="mandatory" value="true"/>

</property>

<property name="com.sap.portal.navigation.afp.displayMode" value="Default">

<property name="validvalues" value="7/Default9/No Images"/>

<property name="plainDescription" value="Display Mode"/>

<property name="longDescription" value="Specify the display mode for top-level navigation. Choose 'No Images' to display top-level navigation with smaller tabs and without tab images."/>

<property name="category" value="Top-Level Navigation"/>

<property name="configattribute" value="fullLevel"/>

<property name="mandatory" value="true"/>

</property>

<property name="com.sap.portal.navigation.afp.notifyOnFinishedLoading" value="true"/>

<property name="AuthScheme" value="anonymous"/>

<property name="com.sap.portal.prt.xhtml.compliant" value="true"/>

</component-profile>

</component>


<!-- Header -->


<component name="HoverTLN">

<component-config> 

<property name="JSP" value="jsp/header.jsp"/> 

<property name="ComponentType" value="jspnative"/>

<property name="AuthScheme" value="anonymous"/> 

</component-config>

<component-profile>

<property name="NavigationTagLibrary" value="/SERVICE/com.sap.portal.navigation.navigationtaglibrary/taglib/TagLibrary.tld"/>

<property name="FrameworkTagLibrary" value="/SERVICE/com.sap.portal.pagebuilder/taglib/framework.tld"/>

<property name="EPCFLevel" value="0"/> <property name="com.sap.portal.iview.ShowTray" value="false"/>

<property name="com.sap.portal.reserved.iview.IsolationMode" value="EMBEDDED"/>

</component-profile>


</component>


</components>


<services/>

</application>


Create another war/ear file where we use the LSAPI.  Create a JSPDyn page

nav.jsp

<%@ page import = "com.sapportals.portal.prt.component.IPortalComponentRequest" %>

<%@ page import = "com.sapportals.portal.prt.component.IPortalComponentContext" %>


<script type="text/javascript">


function updateNavigationMenu(currentNode){

     EPCM.getSAPTop().LSAPI.AFPPlugin.model.getNavigationSubTree(null,drawTree,null);

     }

function drawTree(nodes, container)

{
     var pathArray = EPCM.getSAPTop().LSAPI.AFPPlugin.model.getCurrentSelectedPath();

     //alert(pathArray[0].getTitle());

     EPCM.raiseEvent( "urn:com.node.test", "currentNode", "Current Node", pathArray[0].getTitle());

}

</script>


Whenever the navigation changes the raiseEvent is fired which with the current selected/clicked Node name.  We can get the path of the current selected/clicked Node by using the LSAPI's.  The first element in the pathArray will be have the node name of the "Level one" of the "top level naviagation".

portalapp.xml

<?xml version="1.0" encoding="utf-8"?>

<application>

<application-config>

<property name="SecurityArea" value="NetWeaver.Portal"/>

<property name="fail-over-enable" value="disable"/>

<property name="ClassLoadingPolicy" value="transitive"/>

<property name="PrivateSharingReference" value="com.sap.portal.navigation.navigationtaglibrary,com.sap.portal.themes.lafservice,com.sap.portal.runtime.system.connection,com.sap.portal.pagebuilder,SAPJ2EE::library:com.sap.portal.common,SAPJ2EE::library:tc~cmi,com.sap.portal.common.commonservices,SAPJ2EE::library:com.sapportals.htmlb,com.sap.portal.navigation.api_service,com.sap.portal.navigation.helperservice,com.sap.portal.navigation.service,com.sap.portal.productivity.resolverservice,com.sap.portal.navigation.afp.helperservice,com.sap.portal.runtime.system.favorites,SAPJ2EE::service:engine.security.facade,SAPJ2EE::library:com.sap.base.technology.facade,SAPJ2EE::library:engine.j2ee14.facade,com.sap.portal.search.provider_api,com.sap.portal.search.service,com.sap.portal.contenttaggingservice,SAPJ2EE::library:tc~epbc~pcd~gl~api,com.sap.portal.themes.lafservice,com.sap.portal.runtime.system.connection,com.sap.portal.pagebuilder"/>

<property name="SharingReference" value="com.sap.portal.themes.lafservice,com.sap.portal.navigation.navigationtaglibrary,com.sap.portal.runtime.application.jcoclient,com.sap.portal.ivs.connectorservice,com.sap.portal.htmlb"/>

</application-config>

<components>

<component name="TlnNode">

<component-config>

<property name="ClassName" value="com.test.TlnNode"/>

</component-config>

<component-profile/>

</component>

</components>

<services/>

</application>

Deploy this war/ear file in the server and create a iview for this component with isloation property as "Embedded". Set the height property as 0.

Create an page and copy the iview mentioned above as delta link into the page with isloation property as "URL". Set the height property of the page as 0 fo the page.

Add the above created page to your framework page as delta link and check the checkbox of visible for this page.

In the framework page i have selected the container for HoverTLN and TlnNodePage in Page Tool Bar Container because when I add it in the Top Level Navigation Container I am not able to see the drop down menu.

As shown in the above figure the TLN works fine.  When the user moves the mouse over other nodes  the second level of navigatin will come as drop down menu as shown in above figure with the background color in the shade of light yellow.  The current selected node will is identified with background color white and font color as red shade.

By using Java Script I have hidden the blue arrow which appears on the left side of the browser to display the detailed navigation.

Till here the code work fine.

For the above code I am trying to restrict the width to 900 px and trying to put the horizontal scroll using buttons but could not proceed further.  So If anyone has the solution please add your comments which is the only thing I am missing for this code.

For the above shown figure I tried it using html file and it worked fine for the horizontal scroll using the buton but the horizontal scroll  did work  but the dorp down menu in not visisble outside when I  included in the framework page. This is because it is div tags are inside the table cells. I tired with "<div id="branding" style="border:1px; solid #414141; width:300px; overflow-x:hidden;" >".  If I remove the style overlfow-x:hidden, the drop down menu is visible on hover but the scroll does not work as the full width of the navigation will be visible.

Any suggestions welcome.

 

11 Comments
Labels in this area