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.base;
017    
018    import com.github.gwtbootstrap.client.ui.Icon;
019    import com.github.gwtbootstrap.client.ui.constants.Constants;
020    import com.github.gwtbootstrap.client.ui.constants.IconSize;
021    import com.github.gwtbootstrap.client.ui.constants.IconType;
022    import com.google.gwt.event.dom.client.ClickEvent;
023    import com.google.gwt.event.dom.client.ClickHandler;
024    import com.google.gwt.event.dom.client.HasClickHandlers;
025    import com.google.gwt.event.shared.HandlerRegistration;
026    import com.google.gwt.user.client.DOM;
027    import com.google.gwt.user.client.Event;
028    import com.google.gwt.user.client.ui.Focusable;
029    import com.google.gwt.user.client.ui.HasEnabled;
030    import com.google.gwt.user.client.ui.HasText;
031    import com.google.gwt.user.client.ui.impl.FocusImpl;
032    
033    /**
034     * An Anchor with optional image and caret.
035     * 
036     * <p>
037     * It uses a HTML {@code <a>} tag and can contain text and child widgets. But
038     * not both at the same time.
039     * </p>
040     * 
041     * <p>
042     * <h3>UiBinder Usage:</h3>
043     * {@code <b:IconAnchor icon="plane" href="www.twitter.com">Some Text</b:IconAnchor>}
044     * </p>
045     * 
046     * <p>
047     * Here we add a second Icon:
048     * 
049     * <pre>
050     * {@code <b:IconAnchor icon="STAR" text="There is a widget so the text goes here">
051     *     <b:Icon type="STAR" />
052     * </b:IconAnchor>}
053     * </pre>
054     * 
055     * All parameter are optional. All setters can be used as parameters.
056     * </p>
057     * 
058     * @since 2.0.4.0
059     * 
060     * @author Dominik Mayer
061     * @author ohashi keisuke
062     */
063    public class IconAnchor extends ComplexWidget implements HasText, HasIcon, HasHref, HasClickHandlers, HasEnabled, Focusable {
064    
065        private static final FocusImpl impl = FocusImpl.getFocusImplForWidget();
066    
067            private Icon icon = new Icon();
068    
069            private InlineLabel label = new InlineLabel();
070    
071            private String text = "";
072    
073            private Caret caret = new Caret();
074    
075            /**
076             * Creates the widget and sets the {@code href} property to
077             * {@code javascript:;} in order to avoid problems when clicking on it.
078             */
079            public IconAnchor() {
080                    super("a");
081                    super.add(icon);
082                    super.add(label);
083                    setEmptyHref();
084            }
085    
086            /**
087             * {@inheritDoc}
088             */
089            public void setIcon(IconType type) {
090                    if (type != null)
091                            this.icon.setType(type);
092            }
093    
094            /**
095             * {@inheritDoc}
096             */
097            @Override
098            public void setIconSize(IconSize size) {
099                    icon.setIconSize(size);
100            }
101    
102            /**
103             * {@inheritDoc}
104             */
105            public void setText(String text) {
106                    this.text = text;
107                    label.setText(" " + text + " ");
108            }
109    
110            /**
111             * {@inheritDoc}
112             */
113            public String getText() {
114                    return text;
115            }
116    
117            /**
118             * {@inheritDoc}
119             */
120            public void setHref(String href) {
121                    getElement().setAttribute("href", href);
122            }
123    
124            /**
125             * {@inheritDoc}
126             */
127            public String getHref() {
128                    return getElement().getAttribute("href");
129            }
130    
131            /**
132             * Shows or hides the caret.
133             * 
134             * @param visible
135             *            <code>true</code> if the caret should be shown.
136             */
137            public void setCaret(boolean visible) {
138                    if (visible)
139                            super.add(caret);
140                    else
141                            super.remove(caret);
142            }
143    
144            /**
145             * {@inheritDoc}
146             */
147            public void setTargetHistoryToken(String targetHistoryToken) {
148                    setHref("#" + targetHistoryToken);
149            }
150    
151            /**
152             * {@inheritDoc}
153             */
154            public String getTargetHistoryToken() {
155                    String[] hrefs = getHref().split("#");
156                    return hrefs[1];
157            }
158    
159            /**
160             * Sets the <code>href</code>property of this element to "javascript:;" in
161             * order to get another cursor (hand).
162             */
163            public void setEmptyHref() {
164                    setHref(Constants.EMPTY_HREF);
165            }
166    
167            /**
168             * {@inheritDoc}
169             */
170            @Override
171            public HandlerRegistration addClickHandler(ClickHandler handler) {
172                    return addDomHandler(handler, ClickEvent.getType());
173            }
174    
175            /**
176             * {@inheritDoc}
177             */
178            @Override
179            public boolean isEnabled() {
180                    return !DOM.getElementPropertyBoolean(getElement(), "disabled");
181            }
182    
183            /**
184             * {@inheritDoc}
185             */
186            @Override
187            public void setEnabled(boolean enabled) {
188                    DOM.setElementPropertyBoolean(getElement(), "disabled", !enabled);
189            }
190    
191            /**
192             * {@inheritDoc}
193             */
194            @Override
195            public void onBrowserEvent(Event event) {
196                    switch (DOM.eventGetType(event)) {
197                    case Event.ONCLICK:
198                            if (isEnabled()) {
199                                    super.onBrowserEvent(event);
200                            }
201                            break;
202                    default:
203                            super.onBrowserEvent(event);
204                            break;
205                    }
206    
207            }
208    
209        @Override
210        public int getTabIndex() {
211            return impl.getTabIndex(getElement());
212        }
213    
214        @Override
215        public void setAccessKey(char key) {
216            DOM.setElementProperty(getElement(), "accessKey", "" + key);
217        }
218    
219        @Override
220        public void setFocus(boolean focused) {
221            if (focused) {
222                impl.focus(getElement());
223            } else {
224                impl.blur(getElement());
225            }
226        }
227    
228        @Override
229        public void setTabIndex(int index) {
230            impl.setTabIndex(getElement(), index);
231        }
232    
233        @Override
234        protected void onAttach() {
235            super.onAttach();
236    
237            // Accessibility: setting tab index to be 0 by default, ensuring element
238            // appears in tab sequence. We must ensure that the element doesn't already
239            // have a tabIndex set. This is not a problem for normal widgets, but when
240            // a widget is used to wrap an existing static element, it can already have
241            // a tabIndex.
242            int tabIndex = getTabIndex();
243            if (-1 == tabIndex) {
244                setTabIndex(0);
245            }
246        }
247    }