001    /*
002     *  Copyright 2012 GWT-Bootstrap
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package com.github.gwtbootstrap.client.ui;
017    
018    import com.github.gwtbootstrap.client.ui.base.DivWidget;
019    import com.github.gwtbootstrap.client.ui.constants.NavbarConstants;
020    import com.github.gwtbootstrap.client.ui.constants.NavbarPosition;
021    import com.google.gwt.dom.client.Document;
022    import com.google.gwt.user.client.Element;
023    import com.google.gwt.user.client.ui.RootPanel;
024    import com.google.gwt.user.client.ui.Widget;
025    
026    //@formatter:off
027    
028    /**
029     * Navbar with optional text, links and forms.
030     * <p>
031     * The Navbar can be fixed on the top or bottom of the site where it will stay
032     * when the user scrolls the page. For proper rendering, a fixed Navbar cannot
033     * be part of any container! It has to be attached directly to the
034     * {@link RootPanel}.
035     * <p/>
036     * <p>
037     * <h3>UiBinder Usage:</h3>
038     * <p/>
039     * <pre>
040     * {@code
041     * <g:FlowPanel>
042     *     <b:Navbar>
043     *         <b:Brand>Bootstrap</b:Brand>
044     *         <b:Nav>
045     *             <b:NavLink>Link 1</b:NavLink>
046     *             <b:NavLink>Link 2</b:NavLink>
047     *         </b:Nav>
048     *         <b:NavForm size="1" />
049     *         <b:Nav alignment="RIGHT">
050     *             <b:NavLink>Link 3</b:NavLink>
051     *         </b:Nav>
052     *     </b:Navbar>
053     *     <b:Container>
054     *         [...]
055     *     </b:Container>
056     * </g:FlowPanel>
057     *
058     * }
059     * </pre>
060     * </p>
061     *
062     * <b>NOTE</b>: We assume that most people will use the {@linkplain ResponsiveNavbar}, so, we automatically
063     * add a <code>padding-top: 50px</code> in <code>body</code>.If you don't want this, you have to put
064     * a <code>padding-top: 0px;</code> manually in your document <code>body</code> tag.
065     *
066     * @author Dominik Mayer
067     * @author Carlos Alexandro Becker
068     * @see <a href="http://twitter.github.com/bootstrap/components.html#navbar">Bootstrap documentation</a>
069     * @see ResponsiveNavbar
070     * @since 2.0.4.0
071     */
072    //@formatter:on
073    public class Navbar extends DivWidget {
074    
075            private class NavbarInner extends DivWidget {
076    
077                    public NavbarInner() {
078                            setStyleName(NavbarConstants.NAVBAR_INNER);
079                    }
080            }
081    
082            private final Container container = getContainer();
083    
084            private final NavbarInner navbarInner = new NavbarInner();
085    
086            private Scrollspy spy;
087    
088            private boolean scrollspy;
089    
090            /**
091             * Creates an empty Navbar.
092             */
093            public Navbar() {
094                    setStyleName(NavbarConstants.NAVBAR);
095                    navbarInner.add(container);
096                    super.add(navbarInner);
097                    
098                    setId(Document.get().createUniqueId());
099            }
100    
101            public void setId(String id) {
102                    getElement().setId(id);
103            }
104            
105            public String getId() {
106                    return getElement().getId();
107            }
108    
109            /**
110             * Defines the default container implementation. You can override this in a
111             * extended class if you want another implementation, like a
112             * {@link FluidContainer}.
113             */
114            protected Container getContainer() {
115                    return new Container();
116            }
117    
118            /**
119             * Defines whether the Navbar should contain a {@link Scrollspy}.
120             * 
121             * @param scrollspy
122             *            <code>true</code> to include a Scrollspy. Default:
123             *            <code>false</code>
124             */
125            public void setScrollspy(boolean scrollspy) {
126                    this.scrollspy = scrollspy;
127                    if(scrollspy) {
128                        spy = new Scrollspy(this);
129                    }
130            }
131    
132            /**
133             * Defines scrollspy target element.
134             * 
135             * @param spyElement
136             *            target element
137             */
138            public void setSpyElement(Element spyElement) {
139    
140                    assert spyElement != null;
141    
142                    if (spy == null)
143                            spy = new Scrollspy(this);
144    
145                    spy.setSpyElement(spyElement);
146                    this.scrollspy = true;
147            }
148    
149            @Override
150            protected void onAttach() {
151                    super.onAttach();
152                    if (spy == null)
153                            spy = new Scrollspy(this);
154    
155                    if (scrollspy) {
156                            spy.configure();
157                    }
158                    // TODO make a unconfigure feature.
159            }
160    
161            /**
162             * Fix the Navbar at the top or bottom of the screen.
163             * <p/>
164             * For this to work properly, the Navbar must not be a child of a
165             * {@link Container}.
166             * 
167             * @param position
168             *            the position of the Navbar
169             */
170            public void setPosition(NavbarPosition position) {
171                    for (NavbarPosition p : NavbarPosition.values()) {
172                            if (!p.get().isEmpty()) {
173                                    removeStyleName(p.get());
174                            }
175                    }
176                    addStyle(position);
177            }
178    
179            /**
180             * {@inheritDoc}
181             */
182            @Override
183            public void add(Widget child) {
184                    container.add(child);
185            }
186    
187            /**
188             * Adds a widget to the Navbar element, <b>not</b> the container.
189             * 
190             * @param widget
191             *            widget to add
192             */
193            protected void addWidget(Widget widget) {
194                    super.add(widget);
195            }
196        public Scrollspy getSpy() {
197            return spy;
198        }
199    }