sourcforge > sotacs
 

NavigationBar

A JavaScript vertical navigation bar

Features

  • Permits you to design your navigation bar completely with static HTML
  • Add a static HTML row for each differently rendered item or its dynamic mode (like mouse over, selection or folder open-close).
    Note, that this offers perfect static page preview
  • At runtime on the client's browser, the component's JavaScript will take care of opening-closing folders, selection and mouse-over highlighting and the like
  • The model (content, links, hierarchical structure, etc...) is defined via XML or API
  • All standard Tapestry links are supported
  • No hassles with themes, JavaScript or predefined CSS names
  • You are completely free to design your bar with lists, paragraphs or (the default) tables with any number of columns. Use any CSS, images or whatever structure you like to design your items. In short, you can use possible layout stuff of static HTML to design your items.
    The component doesn't care about the inner structure of your items. It just replaces whole elements at mouse over/out or inserts/removes them on folder opening or closing.
  • Very good performance. There is a lot of (low memory use) caching behind the scenes.
    HTML-structure can be cached on the client now (version 0.8) -> very thin network usage and extremely performant

Problems

Screenshots

The following three screenshots are made from the examples, that are referenced in this docu.
Click on the images to see them with full JavaScript dynamics in action.

1 : Simple example 2 : Forrest 'reproduction' 3 : Advanced example
simple simple simple

Property reference

NavigationBar

Name Type Required Default Value Description
listener org.apache.tapestry.
IActionListener
No - The listener-method that is invoked by all items with DirectLink.
Per default, the DirectLink parameter is just the item id. In this case the method is supposed to have the signature (IRequestCycle, String).
To change the DirectLink (and ExternalLink) parameters, use the dynamicProperties-parameter
source Iterable<INavBarItem> No   The item model.
For XML-models, use the xmlSource parameter.
Exactly one of the parameters 'source' or 'xmlSource' must be provided.

See how to construct the model with the API
xmlSource IAsset No   An asset, that contains the item structure as XML.
DTD : http://sotacs.sourceforge.net/dtds/navigation-bar_0.7"/>.dtd
public id : -//sf//sotacs//NavigationBar//EN
Exactly one of the parameters 'source' and 'xmlSource' must be provided.
initiallyOpened String No null comma-separated list of item's ids that will be opened on page's start. The default (null) means, that all nodes start collapsed except for the path, that contains the selected node. The selected item is always visible.
selected String No   The item-id that will be rendered in 'selected' mode. This item will be visible, i.e. all its containing folders are open.
value INavBarItem No   If provided, the parameter is updated with the current value when the items are rendered. Within the nested NavigationItem components, this may be used to introduce content into the items.
level int No   If provided, the parameter is updated with the hierarchical level of the current item.

See the Forrest example of how this can be used.
itemMode ItemMode No   If provided, the parameter is updated with the current item mode while the items are rendered. Each NavigationItem tag can be declared to render several modes, if the appearance of those modes differs only by some icon, color or the like. This value can be used to distinguish the current mode.

See the Forrest example of how this can be used to render the open/closed folders within one table row.
dynamicProperties IDynamicItemPropertiesProvider No   Even though you could dynamically create a model for each request, the model is per default considered static. This increases performance dramatically.
In addition to the static model, you may want to dynamically hide some items. This is also used to provide link parameters others than the default parameter which is just the item's id.
dynamic boolean No false If you want your model or the 'type'-properties of the nested NavigationItems to change dynamically, set this parameter to true.
Otherwise (per default) the model and the type parameters are assumed to be static, which results in a significant performance gain.
This parameter shall not be set to true if the cache parameter is bound.
cache String No   An arbitrary caching key (application-wide) for caching the HTML-structure.
Only alphanumeric characters or '_'.
If caching is used, server-CPU-usage and network traffic caused by the navigation bar, decreasedramatically.
This can be used very effectively to cache navigation bars in border components.
See how to use caching

This parameter shall not be provided if the 'dynamic'-parameter is set to true.
encoding String No   If caching is used and there are non-ascii characters included in the menu's html, set this to the charset encoding. utf-16 is a good value for many exotic character sets.
element String No TABLE The HTML-tag that contains the items. Per default this is a TABLE (in this case all NavigationItems must be TR elements) but you are free to use UL, OL, DIV, or whatever you like.
(Of course the nested NavigationItem's HTML-elements must correspond to the surrounding element)

Body : allowed all elements with Tapestry-type NavigationItem are considered as view elements. All other elements inside the body are ignored.

Informal parameters : allowed. The informal parameters are added to the top-level navigation bar element (in most cases the 'table'-tag)

Reserver parameters : id

NavigationItem

Name Type Required Default Value Description
type String Yes - Comma separated list specifying the item-types and dynamic modes, you want this element to render

See the detailed description of what are the dynamic modes and how to use this parameter.
element String No TR The HTML tag for the rendered item.
In most cases this is the same element name as the static preview element. All informal parameters and some event-handlers are added to this tag

Body : allowed:

Informal parameters : allowed. The informal parameters are added to the rendered element

Reserved parameters : onmousedown, onmouseover, id

How to build a Navigation Bar

See the tutorial of how to build a simple and instructive Example

  1. Build a static preview (a table or list or whatever you want).
    Add a row for each different item type or mode. To have a nice preview feeling, you may want to add several rows of some type.
  2. Specify an XML-model or construct the model with the Java model API.
    Each item has at least a value (caption), an id and a type atrribute.
  3. Specify the item-types and modes, you want each HTML-row to render. This is accompished with the NavigationItem component and its type attribute.
    See the details about the modes and how to specifiy the type attribute.

The dynamic Modes and how to use the NavigationItems type attribute

Each item has a type and a mode. The type parameter of the NavigationItem is the place, you declare which type(s) and mode(s) you want to be rendered by the corresponding HTML-row.
Now, what is a type and a mode?

  • The items type is specified in the model. it never changes (unless you make a dynamic model)
    Type names are free. You can use as many as you like.
  • The mode changes frequently. It changes on user actions on the browser (mouse-over, mouse-out, open/close folders) or changes on the server, when an item gets or looses selection status.
    There are 6 item modes. They are the String reprsentations of the enumeration net.sf.sotacs.navbar.api.ItemMode

The Modes

NameRequiredDefaultDescription
OUT Yes - Mouse out, not-selected.
If the item has children, this is the 'closed mode'
This mode must be declared for each item type in some NavigationItems type attribute!
OVER NO OUT Mouse over, not-selected.
If the item has children, this is the 'closed mode'
OUT_OPEN NO OUT Mouse out, not-selected.
If the item has children, this is the 'open mode'
OVER_OPEN NO OVER Mouse over, not-selected.
If the item has children, this is the 'open mode'
OUT_SEL NO OVER_OPEN Mouse out, selected.
selected folders are always open
OVER_SEL NO OUT_SEL Mouse over, selected.
selected folders are always open

The type attribute specifies the type and mode in the general form

  type="type-1;mode-1[|mode-2|...|mode-n], ... ,type-2;mode-1[|mode-2|...|mode-n]"

For example

  type="folder;OUT"

just declares the row to render the folder type in mode OUT
The following declares the row to render the folder type in mode OVER and the item type in the mouse-over and selected mode.

  type="folder;OVER, item;OVER|OUT_SEL"
Note
You don't have to declare all possible modes for each type.
All modes except OUT default to some other mode. OUT must be declared for each type.

If some modes differ only by some icon or a CSS-class you can declare these modes in a single NavigationItem and use the itemMode binding parameter to distinguish between the modes in the rendering. The ItemMode enum has some boolean-valued methods like isOpened() or isOver() to facilitate this.

Construct the model with XML

Links

All Tapestry standard links (DirectLink, ExternalLink, PageLink, GenericLink, Servicelink) with their corresponding attributes are supported.
The model of the Simple example demonstrates the different links and their options.

New Window links
There is additional limited new window functionality :
The attributes newWindowName and newWindowInitString are the 2nd and (optional) 3rd arguments of the JavaScript window.open(..) function.

Warning
The new windows links open in a new browser window only if the browsers pop-up blocker allows this. Otherwise the links open in the current window/tab.

Call JavaScripts
To call JavaScripts, use the notation:

    <genericLink href="javascript:someFunction()" />

Icons and item-individual properties

Sometimes you may want to assign more information to an item than the value (caption) and the type. This is what the icon, property and boolean elements are made for. You can assign icon-urls, String properties and boolean properties to each individual item and access them with OGNL using the methods of the current item's INavBarItem interface which can be bound to the value parameter of NavigationBar.
The Advanced example demonstrates the use of individual icons.

Localization of captions

To localize the captions, use the notation

    ... value="message:myMessageKey"

The property files are looked up in the page's namespace (standard i18n of Tapestry)
The Simple example demonstrates how to localize captions.

<?xml version="1.0" encoding="UTF-8"?>
<!--
The DTD for the NavigationBar component of the 'sotacs' collection of Tapestry components.
Associated with the public identifier:

	-//sf//sotacs//NavigationBar0.7//EN
	
The canonical location for the DTD is:

	http://sotacs.sourceforge.net/dtds/navigation-bar_0.7.dtd

the root element is navigation. -->

<!ELEMENT navigation (item+) >

<!ELEMENT item ((directLink|genericLink|pageLink|externalLink|serviceLink)?,(icon|property|boolean)*,item*)>
<!ATTLIST item type CDATA #REQUIRED>
<!ATTLIST item value CDATA #REQUIRED>
<!ATTLIST item id CDATA #REQUIRED>

<!ELEMENT icon EMPTY>
<!ATTLIST icon type (classpath|context|generic) #REQUIRED>
<!ATTLIST icon path CDATA #REQUIRED>
<!ATTLIST icon key CDATA #REQUIRED>

<!ELEMENT property EMPTY>
<!ATTLIST property key CDATA #REQUIRED>
<!ATTLIST property value CDATA #REQUIRED>

<!ELEMENT boolean EMPTY>
<!ATTLIST boolean key CDATA #REQUIRED>
<!ATTLIST boolean value (true|false) #REQUIRED>

<!ELEMENT directLink EMPTY>
<!ATTLIST directLink anchor CDATA #IMPLIED>
<!ATTLIST directLink target CDATA #IMPLIED>
<!ATTLIST directLink newWindowName CDATA #IMPLIED>
<!ATTLIST directLink newWindowInitString CDATA #IMPLIED>
<!ATTLIST directLink scheme (http|https) #IMPLIED>

<!ELEMENT genericLink EMPTY>
<!ATTLIST genericLink href CDATA #REQUIRED>
<!ATTLIST genericLink target CDATA #IMPLIED>
<!ATTLIST genericLink newWindowName CDATA #IMPLIED>
<!ATTLIST genericLink newWindowInitString CDATA #IMPLIED>

<!ELEMENT pageLink EMPTY>
<!ATTLIST pageLink page CDATA #REQUIRED>
<!ATTLIST pageLink anchor CDATA #IMPLIED>
<!ATTLIST pageLink target CDATA #IMPLIED>
<!ATTLIST pageLink scheme (http|https) #IMPLIED>
<!ATTLIST pageLink newWindowName CDATA #IMPLIED>
<!ATTLIST pageLink newWindowInitString CDATA #IMPLIED>

<!ELEMENT externalLink EMPTY>
<!ATTLIST externalLink page CDATA #REQUIRED>
<!ATTLIST externalLink anchor CDATA #IMPLIED>
<!ATTLIST externalLink target CDATA #IMPLIED>
<!ATTLIST externalLink scheme (http|https) #IMPLIED>
<!ATTLIST externalLink newWindowName CDATA #IMPLIED>
<!ATTLIST externalLink newWindowInitString CDATA #IMPLIED>

<!ELEMENT serviceLink EMPTY>
<!ATTLIST serviceLink service CDATA #REQUIRED>
<!ATTLIST serviceLink target CDATA #IMPLIED>
<!ATTLIST serviceLink scheme (http|https) #IMPLIED>
<!ATTLIST serviceLink newWindowName CDATA #IMPLIED>
<!ATTLIST serviceLink newWindowInitString CDATA #IMPLIED>

Build the model with the API

Alternatively to the XML-model, you can construct the model per API using the package
net.sf.sotacs.navbar.api.item

  1. Bind the model to the source parameter
  2. Construct the model

Example

public class ModelPerAPI {	
	public Iterable<INavBarItem> getModel(){
	  ArrayList<INavBarItem> model = new ArrayList<INavBarItem>();
	  
	  NonLinkedItem folder = new NonLinkedItem("folder","id1","caption 1");
		  folder.addItem(new GenericLinkedItem("subitem","generic1", "sf.net", "http://www.sf.net"));
		  folder.addItem(new ExternalLinkedItem("subitem","ext1", "start", "Home"));
		  folder.addItem(new PageLinkedItem("subitem","page1", "contact us", "Contact"));
	  model.add(folder);
	  DirectLinkedItem folder2 = new DirectLinkedItem("folder","id2","I have a link");
	      folder2.setAnchor("theAnchor");
		  folder2.addItem(new GenericLinkedItem("subitem","generic2", "sf.net", "http://www.sf.net"));
		  ExternalLinkedItem extItem = new ExternalLinkedItem("subitem","ext2", "start", "Home");
			  extItem.setScheme("https");
			  extItem.setTarget("top.right");
		  folder2.addItem(extItem);		  
		  folder2.addItem(new PageLinkedItem("subitem","page2", "contact us", "Contact"));
	  model.add(folder2);
	  model.add(new DirectLinkedItem("toplevelitem", "item3", "news"));
	  model.add(new DirectLinkedItem("toplevelitem", "item4", "events"));
	  return model;
	}
}

Caching and Dynamics

There are several components, that determine the appearance of the final navigation bar on the client:

  1. The model
  2. Localization
  3. Dynamic item-hiding or dynamic link-parameters that are provided by the IDynamicItemPropertiesProvider instance bound to the dynamicProperties parameter.
  4. The selected item
  5. The content of the type-parameters of the NavigationItem components
  6. And last but not least any dynamic Tapestry components like @If, @Any, @Insert, etc.. that are nested in the NavigationItem-rows to render the items.

Very Dynamic Navigation Bars

If the model is dynamic (constructed on each request per API) or the values bound to the type-parameters are not constant, you must set the dynamic-parameter to true. The default is 'false', since both conditions are really unusual. 'Very dynamic' bars give rise to some additional processing overhead on the server.

Cacheable Navigation Bars

If a navigation bar is not very dynamic in the above sense, it is usually even cachable.

  • The model is static (component 1 in the above list)
  • The binding to the type parameters of the NavigationItem-rows remains the same (component 5 in the above list)
  • The rendering (component 6 in the above list) gives the same result on each request. This means that dynamic components (like @If, @Any, @insert, etc..) depend only on values from the model, localization or other static ressources.

Note that this is a very weak requirement because

  • localization doesn't affect caching. There is a version cached for each local.
  • You can still dynamically hide items or provide dynamic link parameters, using a IDynamicItemPropertiesProvider together with the component's dynamicProperties parameter.
  • The item's destination urls are completely unaffected from caching. So, any dynamic state information, encoded by Tapestry in the urls works dynamically as expected

Caching is recommended because otherwise, the generated HTML may result quite large, since there is gererated a hidden element of each item and all its different dynamic modes.
To switch on caching, just provide a caching key to the cache-parameter. That's all! With caching you get very thin HTML and reduce nearly completely the server's CPU processing for the component!
The cache-parameter doesn't expect a boolean but a String-valued caching key, because usually this component will be included in a border-component appearing on many different pages and all those components are 'different components' in the Tapestry logic. To mark all these 'different' components to have the same cached structure, just specify a caching-key to the navigation bar component.
As a result, the large HTML structure is shifted into a .js library (and hence is cached even on the browser).

Note
To see the difference between cached and not cached navigation bars, look at the generated source code of the three examples: The forrest-example is the only one without use of caching (just to show the difference. It could be cached as well). Note the large list of items in the generated HTML, each of them rendered in all its dynamic modes