001package org.gwtbootstrap3.client.ui; 002 003/* 004 * #%L 005 * GwtBootstrap3 006 * %% 007 * Copyright (C) 2016 GwtBootstrap3 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import com.google.gwt.dom.client.AnchorElement; 024import com.google.gwt.dom.client.Document; 025import com.google.gwt.event.dom.client.ClickEvent; 026import com.google.gwt.event.dom.client.ClickHandler; 027import com.google.gwt.event.dom.client.DoubleClickEvent; 028import com.google.gwt.event.dom.client.DoubleClickHandler; 029import com.google.gwt.event.dom.client.HasClickHandlers; 030import com.google.gwt.event.dom.client.HasDoubleClickHandlers; 031import com.google.gwt.event.shared.HandlerRegistration; 032import com.google.gwt.user.client.DOM; 033import com.google.gwt.user.client.Event; 034import com.google.gwt.user.client.History; 035import com.google.gwt.user.client.ui.Focusable; 036import com.google.gwt.user.client.ui.HasEnabled; 037import com.google.gwt.user.client.ui.HasHTML; 038import com.google.gwt.user.client.ui.Widget; 039import org.gwtbootstrap3.client.ui.base.ComplexWidget; 040import org.gwtbootstrap3.client.ui.base.HasBadge; 041import org.gwtbootstrap3.client.ui.base.HasDataParent; 042import org.gwtbootstrap3.client.ui.base.HasDataTarget; 043import org.gwtbootstrap3.client.ui.base.HasDataToggle; 044import org.gwtbootstrap3.client.ui.base.HasHref; 045import org.gwtbootstrap3.client.ui.base.HasIcon; 046import org.gwtbootstrap3.client.ui.base.HasIconPosition; 047import org.gwtbootstrap3.client.ui.base.HasPull; 048import org.gwtbootstrap3.client.ui.base.HasTarget; 049import org.gwtbootstrap3.client.ui.base.HasTargetHistoryToken; 050import org.gwtbootstrap3.client.ui.base.mixin.AttributeMixin; 051import org.gwtbootstrap3.client.ui.base.mixin.DataParentMixin; 052import org.gwtbootstrap3.client.ui.base.mixin.DataTargetMixin; 053import org.gwtbootstrap3.client.ui.base.mixin.DataToggleMixin; 054import org.gwtbootstrap3.client.ui.base.mixin.EnabledMixin; 055import org.gwtbootstrap3.client.ui.base.mixin.FocusableMixin; 056import org.gwtbootstrap3.client.ui.base.mixin.IconTextMixin; 057import org.gwtbootstrap3.client.ui.base.mixin.PullMixin; 058import org.gwtbootstrap3.client.ui.constants.Attributes; 059import org.gwtbootstrap3.client.ui.constants.BadgePosition; 060import org.gwtbootstrap3.client.ui.constants.IconFlip; 061import org.gwtbootstrap3.client.ui.constants.IconPosition; 062import org.gwtbootstrap3.client.ui.constants.IconRotate; 063import org.gwtbootstrap3.client.ui.constants.IconSize; 064import org.gwtbootstrap3.client.ui.constants.IconType; 065import org.gwtbootstrap3.client.ui.constants.Pull; 066import org.gwtbootstrap3.client.ui.constants.Styles; 067import org.gwtbootstrap3.client.ui.constants.Toggle; 068 069import java.util.List; 070 071/** 072 * Anchor {@code <a>} element with text and optional icon. 073 * 074 * @author Sven Jacobs 075 * @author Joshua Godi 076 * @author Grant Slender 077 * @author Drew Spencer 078 */ 079public class Anchor extends ComplexWidget implements HasEnabled, HasClickHandlers, HasDoubleClickHandlers, HasHref, HasDataToggle, HasDataParent, 080 HasTargetHistoryToken, HasHTML, HasIcon, HasIconPosition, Focusable, HasDataTarget, HasTarget, HasPull, HasBadge { 081 082 private final PullMixin<Anchor> pullMixin = new PullMixin<Anchor>(this); 083 private final DataToggleMixin<Anchor> toggleMixin = new DataToggleMixin<Anchor>(this); 084 private final DataParentMixin<Anchor> parentMixin = new DataParentMixin<Anchor>(this); 085 private final IconTextMixin<Anchor> iconTextMixin = new IconTextMixin<Anchor>(this); 086 private final DataTargetMixin<Anchor> targetMixin = new DataTargetMixin<Anchor>(this); 087 private final AttributeMixin<Anchor> attributeMixin = new AttributeMixin<Anchor>(this); 088 private final FocusableMixin<Anchor> focusableMixin = new FocusableMixin<Anchor>(this); 089 private final EnabledMixin<Anchor> enabledMixin = new EnabledMixin<Anchor>(this); 090 private String targetHistoryToken; 091 092 /** 093 * Creates an anchor widget with the desired HREF 094 * 095 * @param href href for the anchor 096 */ 097 public Anchor(final String href) { 098 setElement(Document.get().createAnchorElement()); 099 setHref(href); 100 iconTextMixin.addTextWidgetToParent(); 101 } 102 103 /** 104 * Creates an achor widget with the desired HREF and text 105 * 106 * @param text text for the anchor 107 * @param href href for the anchor 108 */ 109 public Anchor(final String text, final String href) { 110 this(href); 111 setText(text); 112 } 113 114 /** 115 * Creates a default anchor with a default href 116 */ 117 public Anchor() { 118 this(EMPTY_HREF); 119 } 120 121 /** 122 * {@inheritDoc} 123 */ 124 @Override 125 public HandlerRegistration addClickHandler(final ClickHandler handler) { 126 return addDomHandler(handler, ClickEvent.getType()); 127 } 128 129 /** 130 * {@inheritDoc} 131 */ 132 @Override 133 public HandlerRegistration addDoubleClickHandler(final DoubleClickHandler handler) { 134 return addDomHandler(handler, DoubleClickEvent.getType()); 135 } 136 137 /** 138 * {@inheritDoc} 139 */ 140 @Override 141 public void setText(final String text) { 142 iconTextMixin.setText(text); 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 public String getText() { 150 return iconTextMixin.getText(); 151 } 152 153 /** 154 * {@inheritDoc} 155 */ 156 @Override 157 public void setIcon(final IconType iconType) { 158 iconTextMixin.setIcon(iconType); 159 } 160 161 /** 162 * {@inheritDoc} 163 */ 164 @Override 165 public IconType getIcon() { 166 return iconTextMixin.getIcon(); 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 @Override 173 public void setIconPosition(final IconPosition iconPosition) { 174 iconTextMixin.setIconPosition(iconPosition); 175 } 176 177 /** 178 * {@inheritDoc} 179 */ 180 @Override 181 public IconPosition getIconPosition() { 182 return iconTextMixin.getIconPosition(); 183 } 184 185 /** 186 * {@inheritDoc} 187 */ 188 @Override 189 public void setIconSize(final IconSize iconSize) { 190 iconTextMixin.setIconSize(iconSize); 191 } 192 193 /** 194 * {@inheritDoc} 195 */ 196 @Override 197 public IconSize getIconSize() { 198 return iconTextMixin.getIconSize(); 199 } 200 201 /** 202 * {@inheritDoc} 203 */ 204 @Override 205 public void setIconFlip(final IconFlip iconFlip) { 206 iconTextMixin.setIconFlip(iconFlip); 207 } 208 209 /** 210 * {@inheritDoc} 211 */ 212 @Override 213 public IconFlip getIconFlip() { 214 return iconTextMixin.getIconFlip(); 215 } 216 217 /** 218 * {@inheritDoc} 219 */ 220 @Override 221 public void setIconRotate(final IconRotate iconRotate) { 222 iconTextMixin.setIconRotate(iconRotate); 223 } 224 225 /** 226 * {@inheritDoc} 227 */ 228 @Override 229 public IconRotate getIconRotate() { 230 return iconTextMixin.getIconRotate(); 231 } 232 233 /** 234 * {@inheritDoc} 235 */ 236 @Override 237 public void setIconBordered(final boolean iconBordered) { 238 iconTextMixin.setIconBordered(iconBordered); 239 } 240 241 /** 242 * {@inheritDoc} 243 */ 244 @Override 245 public boolean isIconBordered() { 246 return iconTextMixin.isIconBordered(); 247 } 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override 253 public void setIconInverse(final boolean iconInverse) { 254 iconTextMixin.setIconInverse(iconInverse); 255 } 256 257 /** 258 * {@inheritDoc} 259 */ 260 @Override 261 public boolean isIconInverse() { 262 return iconTextMixin.isIconInverse(); 263 } 264 265 /** 266 * {@inheritDoc} 267 */ 268 @Override 269 public void setIconSpin(final boolean iconSpin) { 270 iconTextMixin.setIconSpin(iconSpin); 271 } 272 273 /** 274 * {@inheritDoc} 275 */ 276 @Override 277 public boolean isIconSpin() { 278 return iconTextMixin.isIconSpin(); 279 } 280 281 /** 282 * {@inheritDoc} 283 */ 284 @Override 285 public void setIconPulse(boolean iconPulse) { 286 iconTextMixin.setIconPulse(iconPulse); 287 } 288 289 /** 290 * {@inheritDoc} 291 */ 292 @Override 293 public boolean isIconPulse() { 294 return iconTextMixin.isIconPulse(); 295 } 296 297 /** 298 * {@inheritDoc} 299 */ 300 @Override 301 public void setIconFixedWidth(final boolean iconFixedWidth) { 302 iconTextMixin.setIconFixedWidth(iconFixedWidth); 303 } 304 305 /** 306 * {@inheritDoc} 307 */ 308 @Override 309 public boolean isIconFixedWidth() { 310 return iconTextMixin.isIconFixedWidth(); 311 } 312 313 /** 314 * {@inheritDoc} 315 */ 316 @Override 317 public void setHref(final String href) { 318 AnchorElement.as(getElement()).setHref(href); 319 } 320 321 /** 322 * {@inheritDoc} 323 */ 324 @Override 325 public String getHref() { 326 return AnchorElement.as(getElement()).getHref(); 327 } 328 329 /** 330 * {@inheritDoc} 331 */ 332 @Override 333 public void setTargetHistoryToken(final String targetHistoryToken) { 334 this.targetHistoryToken = targetHistoryToken; 335 final String hash = History.encodeHistoryToken(targetHistoryToken); 336 setHref("#" + hash); 337 } 338 339 /** 340 * {@inheritDoc} 341 */ 342 @Override 343 public String getTargetHistoryToken() { 344 return targetHistoryToken; 345 } 346 347 /** 348 * {@inheritDoc} 349 */ 350 @Override 351 public void setDataParent(final String dataParent) { 352 parentMixin.setDataParent(dataParent); 353 } 354 355 /** 356 * {@inheritDoc} 357 */ 358 @Override 359 public String getDataParent() { 360 return parentMixin.getDataParent(); 361 } 362 363 /** 364 * {@inheritDoc} 365 */ 366 @Override 367 public void setDataToggle(final Toggle toggle) { 368 toggleMixin.setDataToggle(toggle); 369 } 370 371 /** 372 * {@inheritDoc} 373 */ 374 @Override 375 public Toggle getDataToggle() { 376 return toggleMixin.getDataToggle(); 377 } 378 379 /** 380 * {@inheritDoc} 381 */ 382 @Override 383 public int getTabIndex() { 384 return focusableMixin.getTabIndex(); 385 } 386 387 /** 388 * {@inheritDoc} 389 */ 390 @Override 391 public void setTabIndex(final int index) { 392 focusableMixin.setTabIndex(index); 393 } 394 395 /** 396 * {@inheritDoc} 397 */ 398 @Override 399 public void setAccessKey(final char key) { 400 focusableMixin.setAccessKey(key); 401 } 402 403 /** 404 * {@inheritDoc} 405 */ 406 @Override 407 public void setFocus(final boolean focused) { 408 focusableMixin.setFocus(focused); 409 } 410 411 /** 412 * {@inheritDoc} 413 */ 414 @Override 415 public String getHTML() { 416 return getElement().getInnerHTML(); 417 } 418 419 /** 420 * {@inheritDoc} 421 */ 422 @Override 423 public void setHTML(final String html) { 424 getElement().setInnerHTML(html); 425 } 426 427 @Override 428 public void setDataTargetWidgets(final List<Widget> widgets) { 429 targetMixin.setDataTargetWidgets(widgets); 430 } 431 432 @Override 433 public void setDataTargetWidget(final Widget widget) { 434 targetMixin.setDataTargetWidget(widget); 435 } 436 437 /** 438 * {@inheritDoc} 439 */ 440 @Override 441 public void setDataTarget(final String dataTarget) { 442 targetMixin.setDataTarget(dataTarget); 443 } 444 445 /** 446 * {@inheritDoc} 447 */ 448 @Override 449 public String getDataTarget() { 450 return targetMixin.getDataTarget(); 451 } 452 453 /** 454 * {@inheritDoc} 455 */ 456 @Override 457 public void setTarget(final String target) { 458 attributeMixin.setAttribute(Attributes.TARGET, target); 459 } 460 461 /** 462 * {@inheritDoc} 463 */ 464 @Override 465 public String getTarget() { 466 return attributeMixin.getAttribute(Attributes.TARGET); 467 } 468 469 /** 470 * {@inheritDoc} 471 */ 472 @Override 473 public void setPull(final Pull pull) { 474 pullMixin.setPull(pull); 475 } 476 477 /** 478 * {@inheritDoc} 479 */ 480 @Override 481 public Pull getPull() { 482 return pullMixin.getPull(); 483 } 484 485 /** 486 * {@inheritDoc} 487 */ 488 @Override 489 public boolean isEnabled() { 490 return enabledMixin.isEnabled(); 491 } 492 493 /** 494 * {@inheritDoc} 495 */ 496 @Override 497 public void setEnabled(final boolean enabled) { 498 enabledMixin.setEnabled(enabled); 499 } 500 501 @Override 502 public void setBadgeText(String badgeText) { 503 iconTextMixin.setBadgeText(badgeText); 504 } 505 506 @Override 507 public String getBadgeText() { 508 return iconTextMixin.getBadgeText(); 509 } 510 511 @Override 512 public void setBadgePosition(BadgePosition badgePosition) { 513 iconTextMixin.setBadgePosition(badgePosition); 514 } 515 516 @Override 517 public BadgePosition getBadgePosition() { 518 return iconTextMixin.getBadgePosition(); 519 } 520 521 /** 522 * {@inheritDoc} 523 */ 524 @Override 525 protected void onAttach() { 526 super.onAttach(); 527 528 // Adding styles to the heading depending on the parent 529 if (getParent() != null) { 530 if (getParent() instanceof Alert) { 531 addStyleName(Styles.ALERT_LINK); 532 } 533 } 534 } 535 536 /** 537 * We override this because the <a></a> tag doesn't support the disabled property. So on clicks and focus, if disabled then ignore 538 * 539 * @param event dom event 540 */ 541 @Override 542 public void onBrowserEvent(final Event event) { 543 switch (DOM.eventGetType(event)) { 544 case Event.ONDBLCLICK: 545 case Event.ONFOCUS: 546 case Event.ONCLICK: 547 if (!isEnabled()) { 548 return; 549 } 550 break; 551 } 552 super.onBrowserEvent(event); 553 } 554 555}