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 */ 016package com.github.gwtbootstrap.client.ui.base; 017 018import com.github.gwtbootstrap.client.ui.Icon; 019import com.github.gwtbootstrap.client.ui.constants.*; 020import com.google.gwt.dom.client.AnchorElement; 021import com.google.gwt.dom.client.Node; 022import com.google.gwt.dom.client.Text; 023import com.google.gwt.event.dom.client.ClickEvent; 024import com.google.gwt.event.dom.client.ClickHandler; 025import com.google.gwt.event.dom.client.HasClickHandlers; 026import com.google.gwt.event.dom.client.HasMouseDownHandlers; 027import com.google.gwt.event.dom.client.MouseDownEvent; 028import com.google.gwt.event.dom.client.MouseDownHandler; 029import com.google.gwt.event.shared.HandlerRegistration; 030import com.google.gwt.user.client.DOM; 031import com.google.gwt.user.client.Event; 032import com.google.gwt.user.client.ui.Focusable; 033import com.google.gwt.user.client.ui.HasEnabled; 034import com.google.gwt.user.client.ui.HasName; 035import com.google.gwt.user.client.ui.HasText; 036import com.google.gwt.user.client.ui.impl.FocusImpl; 037 038/** 039 * An Anchor with optional image and caret. 040 * 041 * <p> 042 * It uses a HTML {@code <a>} tag and can contain text and child widgets. But 043 * not both at the same time. 044 * </p> 045 * 046 * <p> 047 * <h3>UiBinder Usage:</h3> 048 * {@code <b:IconAnchor icon="plane" href="www.twitter.com">Some Text</b:IconAnchor>} 049 * </p> 050 * 051 * <p> 052 * Here we add a second Icon: 053 * 054 * <pre> 055 * {@code <b:IconAnchor icon="STAR" text="There is a widget so the text goes here"> 056 * <b:Icon type="STAR" /> 057 * </b:IconAnchor>} 058 * </pre> 059 * 060 * All parameter are optional. All setters can be used as parameters. 061 * </p> 062 * 063 * @since 2.0.4.0 064 * 065 * @author Dominik Mayer 066 * @author ohashi keisuke 067 */ 068public class IconAnchor extends ComplexWidget implements HasText, HasIcon, HasHref, HasClickHandlers, HasEnabled, 069 Focusable, HasName, HasMouseDownHandlers { 070 071 private static final FocusImpl impl = FocusImpl.getFocusImplForWidget(); 072 073 protected Icon icon = new Icon(); 074 075 private TextNode text = new TextNode(""); 076 077 private Caret caret = new Caret(); 078 079 private IconPosition iconPosition; 080 081 /** 082 * Creates the widget and sets the {@code href} property to 083 * {@code javascript:;} in order to avoid problems when clicking on it. 084 */ 085 public IconAnchor() { 086 super("a"); 087 setIconPosition(IconPosition.LEFT); 088 setEmptyHref(); 089 } 090 091 /** 092 * {@inheritDoc} 093 */ 094 @Override 095 public void setIconPosition(IconPosition position) { 096 097 this.iconPosition = position; 098 icon.removeFromParent(); 099 text.removeFromParent(); 100 101 if(IconPosition.RIGHT == position) { 102 this.insert(text , 0); 103 this.insert(icon , 1); 104 return; 105 106 } else if(IconPosition.LEFT == position){ 107 this.insert(icon, 0); 108 this.insert(text, 1); 109 return; 110 } 111 112 } 113 114 /** 115 * {@inheritDoc} 116 */ 117 @Override 118 public void setIcon(IconType type) { 119 setBaseIcon(type); 120 } 121 122 /** 123 * {@inheritDoc} 124 */ 125 @Override 126 public void setBaseIcon(BaseIconType type) { 127 this.icon.setBaseType(type); 128 } 129 130 /** 131 * {@inheritDoc} 132 */ 133 @Override 134 public void setIconSize(IconSize size) { 135 icon.setIconSize(size); 136 } 137 138 /** 139 * {@inheritDoc} 140 */ 141 public void setText(String text) { 142 if ( !this.getElement().isOrHasChild( this.text.getElement() ) ) { 143 Node toRemove = null; 144 for ( int i = 0; i < this.getElement().getChildCount(); i++) { 145 Node n = this.getElement().getChildNodes().getItem( i ); 146 if ( n.getNodeType() == 3 /*TEXT_NODE*/ ) { 147 Text t = n.<Text>cast(); 148 if ( t.getNodeValue().equals( this.text.getText() ) || t.getNodeValue().equals( text ) ) { 149 toRemove = t; 150 } 151 } 152 } 153 if ( toRemove != null ) { 154 this.getElement().removeChild(toRemove); 155 } 156 this.getElement().appendChild( this.text.getElement() ); 157 } 158 this.text.removeFromParent(); 159 this.text = new TextNode(" " + text + " "); 160 setIconPosition(iconPosition); 161 } 162 163 /** 164 * {@inheritDoc} 165 */ 166 public String getText() { 167 return text.getText(); 168 } 169 170 /** 171 * {@inheritDoc} 172 */ 173 public void setHref(String href) { 174 getElement().setAttribute("href", href); 175 } 176 177 /** 178 * {@inheritDoc} 179 */ 180 public String getHref() { 181 return getElement().getAttribute("href"); 182 } 183 184 /** 185 * Shows or hides the caret. 186 * 187 * @param visible 188 * <code>true</code> if the caret should be shown. 189 */ 190 public void setCaret(boolean visible) { 191 if (visible) 192 super.add(caret); 193 else 194 super.remove(caret); 195 } 196 197 /** 198 * {@inheritDoc} 199 */ 200 public void setTargetHistoryToken(String targetHistoryToken) { 201 setHref("#" + targetHistoryToken); 202 } 203 204 /** 205 * {@inheritDoc} 206 */ 207 public String getTargetHistoryToken() { 208 String[] hrefs = getHref().split("#"); 209 return hrefs[1]; 210 } 211 212 /** 213 * Sets the <code>href</code>property of this element to "javascript:;" in 214 * order to get another cursor (hand). 215 */ 216 public void setEmptyHref() { 217 setHref(Constants.EMPTY_HREF); 218 } 219 220 /** 221 * {@inheritDoc} 222 */ 223 @Override 224 public HandlerRegistration addClickHandler(ClickHandler handler) { 225 return addDomHandler(handler, ClickEvent.getType()); 226 } 227 228 /** 229 * {@inheritDoc} 230 */ 231 @Override 232 public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) { 233 return addDomHandler(handler, MouseDownEvent.getType()); 234 } 235 236 /** 237 * {@inheritDoc} 238 */ 239 @Override 240 public boolean isEnabled() { 241 return !DOM.getElementPropertyBoolean(getElement(), "disabled"); 242 } 243 244 /** 245 * {@inheritDoc} 246 */ 247 @Override 248 public void setEnabled(boolean enabled) { 249 DOM.setElementPropertyBoolean(getElement(), "disabled", !enabled); 250 } 251 252 /** 253 * {@inheritDoc} 254 */ 255 @Override 256 public void onBrowserEvent(Event event) { 257 switch (DOM.eventGetType(event)) { 258 case Event.ONCLICK: 259 if (isEnabled()) { 260 super.onBrowserEvent(event); 261 } 262 break; 263 default: 264 super.onBrowserEvent(event); 265 break; 266 } 267 268 } 269 270 @Override 271 public int getTabIndex() { 272 return impl.getTabIndex(getElement()); 273 } 274 275 @Override 276 public void setAccessKey(char key) { 277 DOM.setElementProperty(getElement(), "accessKey", "" + key); 278 } 279 280 @Override 281 public void setFocus(boolean focused) { 282 if (focused) { 283 impl.focus(getElement()); 284 } else { 285 impl.blur(getElement()); 286 } 287 } 288 289 @Override 290 public void setTabIndex(int index) { 291 impl.setTabIndex(getElement(), index); 292 } 293 294 @Override 295 protected void onAttach() { 296 super.onAttach(); 297 298 // Accessibility: setting tab index to be 0 by default, ensuring element 299 // appears in tab sequence. We must ensure that the element doesn't already 300 // have a tabIndex set. This is not a problem for normal widgets, but when 301 // a widget is used to wrap an existing static element, it can already have 302 // a tabIndex. 303 int tabIndex = getTabIndex(); 304 if (-1 == tabIndex) { 305 setTabIndex(0); 306 } 307 } 308 309 /** 310 * Set active style name. 311 * @param active <code>true</code> : set active <code>false</code> : unset active 312 */ 313 public void setActive(boolean active) { 314 setStyleName(Constants.ACTIVE, active); 315 } 316 317 /** 318 * Has the active css style name? 319 * @return <code>true</code>: has <code>false</code> : none. 320 */ 321 public boolean isActive() { 322 return getStyleName().contains(Constants.ACTIVE); 323 } 324 325 /** 326 * {@inheritDoc} 327 */ 328 @Override 329 public void setName(String name) { 330 getAnchorElement().setName(name); 331 } 332 333 /** 334 * {@inheritDoc} 335 */ 336 @Override 337 public String getName() { 338 return getAnchorElement().getName(); 339 } 340 341 /** 342 * Set target attribute 343 * @param target target name 344 */ 345 public void setTarget(String target) { 346 getAnchorElement().setTarget(target); 347 } 348 349 /** 350 * Get target attribute value 351 * @return target attribute value 352 */ 353 public String getTarget() { 354 return getAnchorElement().getTarget(); 355 } 356 357 protected AnchorElement getAnchorElement() { 358 return AnchorElement.as(getElement()); 359 } 360 361 /** 362 * {@inheritDoc} 363 */ 364 @Override 365 public void setCustomIconStyle(String customIconStyle) { 366 icon.addStyleName(customIconStyle); 367 } 368 369}