package votorola.a.web.wic; // Copyright 2008, 2010, 2012, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. import java.util.*; import org.apache.wicket.*; import org.apache.wicket.markup.html.*; import org.apache.wicket.markup.html.panel.*; import org.apache.wicket.markup.repeater.*; import votorola.g.lang.*; import votorola.g.web.wic.*; /** A pile of navigation bars. Each bar represents a single level in the page hierarchy * and contains a horizontal array of tabs. Highlighted tabs function as a vertical * breadcrumb trail through the page hierarchy. * *

The complexity of tabs proved confusing for some and the top bar is now hidden. * Given our shallow page hierarchy, this limits the pile to a single bar with no * vertical breadcrumbs. We plan to offload navigation onto the {@linkplain * votorola.s.gwt.stage.link.LinkTrackV LinkTrackV} in 2012, in any case.

* * @see WC_NavPile.html */ public @ThreadRestricted("wicket") class WC_NavPile extends Panel { // Tabbed navigation, in general: // // - http://www.useit.com/alertbox/tabs.html // - http://www.jakeo.com/words/tabs.php // - http://www.lukew.com/ff/entry.asp?178 // - http://nontroppo.org/test/tab1.html // // CSS and image tricks: // // - http://icant.co.uk/articles/flexible-css-menu/ // - http://tutorials.mezane.org/tabbed-navigation-using-css/ // protected WC_NavPile( String id ) { super( id ); setRenderBodyOnly( true ); } /** Constructs a WC_NavPile. * * @param pageTab the navigation tab of the page */ public WC_NavPile( String id, final NavTab pageTab, final VRequestCycle cycle ) { this( id ); init( pageTab, cycle ); } protected final void init( final NavTab pageTab, final VRequestCycle cycle ) { final ArrayList pathTabList = new ArrayList( /*initial capacity*/8 ); // in document order (top down) for( NavTab pathTab = pageTab;; ) // populate list in reverse (upward) { pathTabList.add( 0, pathTab ); pathTab = pathTab.navBar().superTab(); if( pathTab == null ) break; } final RepeatingView barRepeating = new RepeatingView( "navRow" ); final NavBar.SessionScope scopeNavBar = VSession.get().scopeNavBar(); boolean isIndented = true; // for previous bar, first bar will negate this, to be unindented for( int b = 1, bN = pathTabList.size();; ) // top down, bar to bar (but skipping topmost) { final WebMarkupContainer navRow = new WebMarkupContainer( barRepeating.newChildId() ); final NavTab pathTab = pathTabList.get( b ); final NavBar bar = pathTab.navBar(); // bar of sister tabs navRow.add( newVBarLeader( "bar-leader", bar )); final WebMarkupContainer ul = newVBar( "bar", bar ); final RepeatingView tabRepeating = new RepeatingView( "tab" ); for( int t = 0, tN = bar.tabList().size();; ) // horizontal, tab to tab { final NavTab barTab = bar.tabList().get( t ); final boolean barTabOnPath = barTab == pathTab; if( barTabOnPath ) // persist the path, where it crosses this bar, as default { if( t == bar.defaultTabIndex() ) { scopeNavBar.removeLastIndexOnPath( bar.hashKey() ); } else scopeNavBar.putLastIndexOnPath( bar.hashKey(), t ); } final boolean isBarTabEnabled = barTab.isEnabled( cycle ); final BookmarkablePageLinkX li = newTabLink( tabRepeating.newChildId(), barTab ); // a JavaScript link VPageHTML.appendStyleClass( li, barTabOnPath? "on": "off" ); // style on/off path VPageHTML.appendStyleClass( li, isBarTabEnabled? "enabled": "disabled" ); li.setEnabled( isBarTabEnabled && !barTabOnPath ); li.add( t == 0? VPageHTML.newLabelNBSP( "tab-leader" ): // only for first tab VPage.newNullComponent( "tab-leader" )); final BookmarkablePageLinkX link = newTabLink( "tab-link", barTab ); link.setBody( barTab.shortTitle( cycle )); link.setEnabled( isBarTabEnabled && !barTabOnPath ); li.add( link ); final Component trailer = VPageHTML.newLabelNBSP( "tab-trailer" ); li.add( trailer ); tabRepeating.add( li ); ++t; if( t >= tN ) { VPageHTML.appendStyleClass( trailer, "bar-trailer" ); // only for last tab break; } } ul.add( tabRepeating ); isIndented = isIndented( bar, isIndented ); if( isIndented ) VPageHTML.appendStyleClass( ul, "indented" ); navRow.add( ul ); barRepeating.add( navRow ); ++b; if( b >= bN ) { VPageHTML.appendStyleClass( ul, "pile-trailer" ); // only for last bar, except subclasses may bend this rule when the following bar has a leader, per newVBarLeader() break; } } add( barRepeating ); } //// P r i v a t e /////////////////////////////////////////////////////////////////////// // - W C - N a v - P i l e ----------------------------------------------------------- /** Answers whether the view of the specified bar should be indented. The default * implementation of this method (in WC_NavPile) returns !wasIndented, for a * staggered effect. * * @param wasIndented whether the previous bar was indented */ protected boolean isIndented( NavBar bar, boolean wasIndented ) { return !wasIndented; } private static BookmarkablePageLinkX newTabLink( final String id, final NavTab tab ) { return new BookmarkablePageLinkX( id, tab.bookmark() ); } /** Constructs a view of the specified navigation bar. The default implementation of * this method (in WC_NavPile) returns a plain WebMarkupContainer. */ protected WebMarkupContainer newVBar( String id, NavBar bar ) { return new WebMarkupContainer( id ); } /** Constructs a component to precede the specified navigation bar. The default * implementation of this method (in WC_NavPile) returns a no-op component. */ protected Component newVBarLeader( String id, NavBar bar ) { return VPage.newNullComponent( id ); } }