| /* |
| * Copyright 2008 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.user.client.ui; |
| |
| import com.google.gwt.dom.client.AnchorElement; |
| import com.google.gwt.dom.client.Document; |
| import com.google.gwt.dom.client.Element; |
| import com.google.gwt.dom.client.Style.WhiteSpace; |
| import com.google.gwt.event.dom.client.ClickEvent; |
| import com.google.gwt.event.dom.client.ClickHandler; |
| import com.google.gwt.i18n.client.BidiUtils; |
| import com.google.gwt.i18n.client.HasDirection; |
| import com.google.gwt.i18n.shared.DirectionEstimator; |
| import com.google.gwt.i18n.shared.HasDirectionEstimator; |
| import com.google.gwt.safehtml.shared.SafeHtml; |
| import com.google.gwt.safehtml.shared.SafeUri; |
| import com.google.gwt.safehtml.shared.annotations.IsSafeHtml; |
| import com.google.gwt.safehtml.shared.annotations.IsSafeUri; |
| import com.google.gwt.safehtml.shared.annotations.SuppressIsSafeHtmlCastCheck; |
| |
| /** |
| * A widget that represents a simple <a> element. |
| * |
| * <p> |
| * If you want use this anchor only for changing history states, use |
| * {@link Hyperlink} instead. |
| * </p> |
| * |
| * <p> |
| * <h3>Built-in Bidi Text Support</h3> |
| * This widget is capable of automatically adjusting its direction according to |
| * its content. This feature is controlled by {@link #setDirectionEstimator} or |
| * passing a DirectionEstimator parameter to the constructor, and is off by |
| * default. |
| * </p> |
| * |
| * <h3>CSS Style Rules</h3> |
| * <ul class='css'> |
| * <li>.gwt-Anchor { }</li> |
| * </ul> |
| * |
| * @see Hyperlink |
| */ |
| public class Anchor extends FocusWidget implements HasHorizontalAlignment, |
| HasName, HasHTML, HasWordWrap, HasDirection, |
| HasDirectionEstimator, HasDirectionalSafeHtml { |
| |
| public static final DirectionEstimator DEFAULT_DIRECTION_ESTIMATOR = |
| DirectionalTextHelper.DEFAULT_DIRECTION_ESTIMATOR; |
| |
| /** |
| * The default HREF is a no-op javascript statement. We need an href to ensure |
| * that the browser renders the anchor with native styles, such as underline |
| * and font color. |
| */ |
| private static final String DEFAULT_HREF = "javascript:;"; |
| |
| /** |
| * Creates an Anchor widget that wraps an existing <a> element. |
| * |
| * This element must already be attached to the document. If the element is |
| * removed from the document, you must call |
| * {@link RootPanel#detachNow(Widget)}. |
| * |
| * @param element the element to be wrapped |
| */ |
| public static Anchor wrap(Element element) { |
| // Assert that the element is attached. |
| assert Document.get().getBody().isOrHasChild(element); |
| |
| Anchor anchor = new Anchor(element); |
| |
| // Mark it attached and remember it for cleanup. |
| anchor.onAttach(); |
| RootPanel.detachOnWindowClose(anchor); |
| |
| return anchor; |
| } |
| |
| private final DirectionalTextHelper directionalTextHelper; |
| |
| private HorizontalAlignmentConstant horzAlign; |
| |
| /** |
| * Creates an empty anchor. |
| * |
| * <p> |
| * The anchor's href is <em>not</em> set, which means that the widget will not |
| * not be styled with the browser's native link styles (such as underline and |
| * font color). Use {@link #Anchor(boolean)} to add a default no-op href that |
| * does not open a link but ensures the native link styles are applied. |
| * </p> |
| * |
| * @see #Anchor(boolean) |
| */ |
| public Anchor() { |
| this(false); |
| } |
| |
| /** |
| * Creates an anchor. |
| * |
| * The anchor's href is optionally set to <code>javascript:;</code>, based on |
| * the expectation that listeners will be added to the anchor. |
| * |
| * @param useDefaultHref true to set the default href to |
| * <code>javascript:;</code>, false to leave it blank |
| */ |
| public Anchor(boolean useDefaultHref) { |
| setElement(Document.get().createAnchorElement()); |
| setStyleName("gwt-Anchor"); |
| directionalTextHelper = new DirectionalTextHelper(getAnchorElement(), |
| /* is inline */true); |
| if (useDefaultHref) { |
| setHref(DEFAULT_HREF); |
| } |
| |
| // The following click handler is used to support users of CSP (Content |
| // Security Policy). When a CSP policy is in place, clicking on a link with |
| // the DEFAULT_HREF as the href can trigger a CSP violation. As a |
| // work-around, we prevent execution using preventDefault() when the href is |
| // set to DEFAULT_HREF. |
| if ("true".equals(System.getProperty("gwt.cspCompatModeEnabled"))) { |
| addClickHandler(new ClickHandler() { |
| @Override |
| public void onClick(ClickEvent event) { |
| if (DEFAULT_HREF.equals(getAnchorElement().getHref())) { |
| event.preventDefault(); |
| } |
| } |
| }); |
| } |
| } |
| |
| /** |
| * Creates an anchor for scripting. |
| * |
| * @param html the anchor's html |
| */ |
| public Anchor(SafeHtml html) { |
| this(html.asString(), true); |
| } |
| |
| /** |
| * Creates an anchor for scripting. |
| * |
| * The anchor's href is set to <code>javascript : ;</code>, based on the |
| * expectation that listeners will be added to the anchor. |
| * |
| * @param html the anchor's html |
| * @param dir the html's direction |
| */ |
| public Anchor(SafeHtml html, Direction dir) { |
| this(html.asString(), true, dir, DEFAULT_HREF); |
| } |
| |
| /** |
| * Creates an anchor for scripting. |
| * |
| * The anchor's href is set to <code>javascript : ;</code>, based on the |
| * expectation that listeners will be added to the anchor. |
| * |
| * @param html the anchor's html |
| * @param directionEstimator A DirectionEstimator object used for automatic |
| * direction adjustment. For convenience, |
| * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used. |
| */ |
| public Anchor(SafeHtml html, DirectionEstimator directionEstimator) { |
| this(html.asString(), true, directionEstimator, DEFAULT_HREF); |
| } |
| |
| /** |
| * Creates an anchor for scripting. |
| * |
| * The anchor's href is set to <code>javascript:;</code>, based on the |
| * expectation that listeners will be added to the anchor. |
| * |
| * @param text the anchor's text |
| */ |
| public Anchor(String text) { |
| this(text, DEFAULT_HREF); |
| } |
| |
| /** |
| * Creates an anchor for scripting. |
| * |
| * The anchor's href is set to <code>javascript : ;</code>, based on the |
| * expectation that listeners will be added to the anchor. |
| * |
| * @param text the anchor's text |
| * @param dir the text's direction |
| */ |
| public Anchor(String text, Direction dir) { |
| this(text, dir, DEFAULT_HREF); |
| } |
| |
| /** |
| * Creates an anchor for scripting. |
| * |
| * The anchor's href is set to <code>javascript : ;</code>, based on the |
| * expectation that listeners will be added to the anchor. |
| * |
| * @param text the anchor's text |
| * @param directionEstimator A DirectionEstimator object used for automatic |
| * direction adjustment. For convenience, |
| * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used. |
| */ |
| public Anchor(String text, DirectionEstimator directionEstimator) { |
| this(text, directionEstimator, DEFAULT_HREF); |
| } |
| |
| /** |
| * Creates an anchor for scripting. |
| * |
| * The anchor's href is set to <code>javascript:;</code>, based on the |
| * expectation that listeners will be added to the anchor. |
| * |
| * @param text the anchor's text |
| * @param asHtml <code>true</code> to treat the specified text as html |
| */ |
| public Anchor(@IsSafeHtml String text, boolean asHtml) { |
| this(text, asHtml, DEFAULT_HREF); |
| } |
| |
| /** |
| * Creates an anchor with its html and href (target URL) specified. |
| * |
| * @param html the anchor's html |
| * @param href the url to which it will link |
| */ |
| public Anchor(SafeHtml html, @IsSafeUri String href) { |
| this(html.asString(), true, href); |
| } |
| |
| /** |
| * Creates an anchor with its html and href (target URL) specified. |
| * |
| * @param html the anchor's html |
| * @param href the url to which it will link |
| */ |
| public Anchor(SafeHtml html, SafeUri href) { |
| this(html.asString(), true, href.asString()); |
| } |
| |
| /** |
| * Creates an anchor with its html and href (target URL) specified. |
| * |
| * @param html the anchor's html |
| * @param dir the html's direction |
| * @param href the url to which it will link |
| */ |
| public Anchor(SafeHtml html, Direction dir, @IsSafeUri String href) { |
| this(html.asString(), true, dir, href); |
| } |
| |
| /** |
| * Creates an anchor with its html and href (target URL) specified. |
| * |
| * @param html the anchor's html |
| * @param dir the html's direction |
| * @param href the url to which it will link |
| */ |
| public Anchor(SafeHtml html, Direction dir, SafeUri href) { |
| this(html.asString(), true, dir, href.asString()); |
| } |
| |
| /** |
| * Creates an anchor with its html and href (target URL) specified. |
| * |
| * @param html the anchor's html |
| * @param directionEstimator A DirectionEstimator object used for automatic |
| * direction adjustment. For convenience, |
| * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used. |
| * @param href the url to which it will link |
| */ |
| public Anchor(SafeHtml html, DirectionEstimator directionEstimator, @IsSafeUri String href) { |
| this(html.asString(), true, directionEstimator, href); |
| } |
| |
| /** |
| * Creates an anchor with its html and href (target URL) specified. |
| * |
| * @param html the anchor's html |
| * @param directionEstimator A DirectionEstimator object used for automatic |
| * direction adjustment. For convenience, |
| * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used. |
| * @param href the url to which it will link |
| */ |
| public Anchor(SafeHtml html, DirectionEstimator directionEstimator, |
| SafeUri href) { |
| this(html.asString(), true, directionEstimator, href.asString()); |
| } |
| |
| /** |
| * Creates an anchor with its text and href (target URL) specified. |
| * |
| * @param text the anchor's text |
| * @param href the url to which it will link |
| */ |
| @SuppressIsSafeHtmlCastCheck |
| public Anchor(String text, @IsSafeUri String href) { |
| this(text, false, href); |
| } |
| |
| /** |
| * Creates an anchor with its text and href (target URL) specified. |
| * |
| * @param text the anchor's text |
| * @param dir the text's direction |
| * @param href the url to which it will link |
| */ |
| @SuppressIsSafeHtmlCastCheck |
| public Anchor(String text, Direction dir, @IsSafeUri String href) { |
| this(text, false, dir, href); |
| } |
| |
| /** |
| * Creates an anchor with its text and href (target URL) specified. |
| * |
| * @param text the anchor's text |
| * @param directionEstimator A DirectionEstimator object used for automatic |
| * direction adjustment. For convenience, |
| * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used. |
| * @param href the url to which it will link |
| */ |
| @SuppressIsSafeHtmlCastCheck |
| public Anchor(String text, DirectionEstimator directionEstimator, @IsSafeUri String href) { |
| this(text, false, directionEstimator, href); |
| } |
| |
| /** |
| * Creates an anchor with its text and href (target URL) specified. |
| * |
| * @param text the anchor's text |
| * @param asHTML <code>true</code> to treat the specified text as html |
| * @param href the url to which it will link |
| */ |
| public Anchor(@IsSafeHtml String text, boolean asHTML, @IsSafeUri String href) { |
| this(); |
| directionalTextHelper.setTextOrHtml(text, asHTML); |
| setHref(href); |
| } |
| |
| /** |
| * Creates a source anchor (link to URI). |
| * |
| * That is, an anchor with an href attribute specifying the destination URI. |
| * |
| * @param html the anchor's html |
| * @param href the url to which it will link |
| * @param target the target frame (e.g. "_blank" to open the link in a new |
| * window) |
| */ |
| public Anchor(SafeHtml html, @IsSafeUri String href, String target) { |
| this(html.asString(), true, href, target); |
| } |
| |
| /** |
| * Creates a source anchor (link to URI). |
| * |
| * That is, an anchor with an href attribute specifying the destination URI. |
| * |
| * @param html the anchor's html |
| * @param href the url to which it will link |
| * @param target the target frame (e.g. "_blank" to open the link in a new |
| * window) |
| */ |
| public Anchor(SafeHtml html, SafeUri href, String target) { |
| this(html.asString(), true, href.asString(), target); |
| } |
| |
| /** |
| * Creates a source anchor with a frame target. |
| * |
| * @param text the anchor's text |
| * @param href the url to which it will link |
| * @param target the target frame (e.g. "_blank" to open the link in a new |
| * window) |
| */ |
| @SuppressIsSafeHtmlCastCheck |
| public Anchor(String text, @IsSafeUri String href, String target) { |
| this(text, false, href, target); |
| } |
| |
| /** |
| * Creates a source anchor (link to URI). |
| * |
| * That is, an anchor with an href attribute specifying the destination URI. |
| * |
| * @param text the anchor's text |
| * @param asHtml asHTML <code>true</code> to treat the specified text as html |
| * @param href the url to which it will link |
| * @param target the target frame (e.g. "_blank" to open the link in a new |
| * window) |
| */ |
| public Anchor(@IsSafeHtml String text, boolean asHtml, @IsSafeUri String href, String target) { |
| this(text, asHtml, href); |
| setTarget(target); |
| } |
| |
| /** |
| * This constructor may be used by subclasses to explicitly use an existing |
| * element. This element must be an <a> element. |
| * |
| * @param element the element to be used |
| */ |
| protected Anchor(Element element) { |
| AnchorElement.as(element); |
| setElement(element); |
| directionalTextHelper = new DirectionalTextHelper(getAnchorElement(), |
| /* is inline */ true); |
| } |
| |
| /** |
| * Creates an anchor with its text, direction and href (target URL) specified. |
| * |
| * @param text the anchor's text |
| * @param asHTML <code>true</code> to treat the specified text as html |
| * @param dir the text's direction |
| * @param href the url to which it will link |
| */ |
| private Anchor(@IsSafeHtml String text, boolean asHTML, Direction dir, @IsSafeUri String href) { |
| this(); |
| directionalTextHelper.setTextOrHtml(text, dir, asHTML); |
| setHref(href); |
| } |
| |
| /** |
| * Creates an anchor with its text, direction and href (target URL) specified. |
| * |
| * @param text the anchor's text |
| * @param asHTML <code>true</code> to treat the specified text as html |
| * @param directionEstimator A DirectionEstimator object used for automatic |
| * direction adjustment. For convenience, |
| * {@link #DEFAULT_DIRECTION_ESTIMATOR} can be used. |
| * @param href the url to which it will link |
| */ |
| private Anchor( |
| @IsSafeHtml String text, |
| boolean asHTML, |
| DirectionEstimator directionEstimator, |
| @IsSafeUri String href) { |
| this(); |
| directionalTextHelper.setDirectionEstimator(directionEstimator); |
| directionalTextHelper.setTextOrHtml(text, asHTML); |
| setHref(href); |
| } |
| |
| @Override |
| public Direction getDirection() { |
| return BidiUtils.getDirectionOnElement(getElement()); |
| } |
| |
| @Override |
| public DirectionEstimator getDirectionEstimator() { |
| return directionalTextHelper.getDirectionEstimator(); |
| } |
| |
| @Override |
| public HorizontalAlignmentConstant getHorizontalAlignment() { |
| return horzAlign; |
| } |
| |
| /** |
| * Gets the anchor's href (the url to which it links). |
| * |
| * @return the anchor's href |
| */ |
| public String getHref() { |
| return getAnchorElement().getHref(); |
| } |
| |
| @Override |
| public String getHTML() { |
| return getElement().getInnerHTML(); |
| } |
| |
| @Override |
| public String getName() { |
| return getAnchorElement().getName(); |
| } |
| |
| @Override |
| public int getTabIndex() { |
| return getAnchorElement().getTabIndex(); |
| } |
| |
| /** |
| * Gets the anchor's target frame (the frame in which navigation will occur |
| * when the link is selected). |
| * |
| * @return the target frame |
| */ |
| public String getTarget() { |
| return getAnchorElement().getTarget(); |
| } |
| |
| @Override |
| public String getText() { |
| return directionalTextHelper.getText(); |
| } |
| |
| @Override |
| public Direction getTextDirection() { |
| return directionalTextHelper.getTextDirection(); |
| } |
| |
| @Override |
| public boolean getWordWrap() { |
| return !WhiteSpace.NOWRAP.getCssName().equals(getElement().getStyle().getWhiteSpace()); |
| } |
| |
| @Override |
| public void setAccessKey(char key) { |
| getAnchorElement().setAccessKey(Character.toString(key)); |
| } |
| |
| /** |
| * @deprecated Use {@link #setDirectionEstimator} and / or pass explicit |
| * direction to {@link #setText}, {@link #setHTML} instead |
| */ |
| @Override |
| @Deprecated |
| public void setDirection(Direction direction) { |
| directionalTextHelper.setDirection(direction); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * <p> |
| * See note at {@link #setDirectionEstimator(DirectionEstimator)}. |
| */ |
| @Override |
| public void setDirectionEstimator(boolean enabled) { |
| directionalTextHelper.setDirectionEstimator(enabled); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * <p> |
| * Note: DirectionEstimator should be set before the widget has any content; |
| * it's highly recommended to set it using a constructor. Reason: if the |
| * widget already has non-empty content, this will update its direction |
| * according to the new estimator's result. This may cause flicker, and thus |
| * should be avoided. |
| */ |
| @Override |
| public void setDirectionEstimator(DirectionEstimator directionEstimator) { |
| directionalTextHelper.setDirectionEstimator(directionEstimator); |
| } |
| |
| @Override |
| public void setFocus(boolean focused) { |
| if (focused) { |
| getAnchorElement().focus(); |
| } else { |
| getAnchorElement().blur(); |
| } |
| } |
| |
| @Override |
| public void setHorizontalAlignment(HorizontalAlignmentConstant align) { |
| horzAlign = align; |
| getElement().getStyle().setProperty("textAlign", align.getTextAlignString()); |
| } |
| |
| /** |
| * Sets the anchor's href (the url to which it links). |
| * |
| * @param href the anchor's href |
| */ |
| public void setHref(SafeUri href) { |
| getAnchorElement().setHref(href); |
| } |
| |
| /** |
| * Sets the anchor's href (the url to which it links). |
| * |
| * @param href the anchor's href |
| */ |
| public void setHref(@IsSafeUri String href) { |
| getAnchorElement().setHref(href); |
| } |
| |
| @Override |
| public void setHTML(SafeHtml html) { |
| directionalTextHelper.setHtml(html); |
| } |
| |
| @Override |
| public void setHTML(@IsSafeHtml String html) { |
| directionalTextHelper.setHtml(html); |
| } |
| |
| @Override |
| public void setHTML(SafeHtml html, Direction dir) { |
| directionalTextHelper.setHtml(html, dir); |
| } |
| |
| @Override |
| public void setName(String name) { |
| getAnchorElement().setName(name); |
| } |
| |
| @Override |
| public void setTabIndex(int index) { |
| getAnchorElement().setTabIndex(index); |
| } |
| |
| /** |
| * Sets the anchor's target frame (the frame in which navigation will occur |
| * when the link is selected). |
| * |
| * @param target the target frame |
| */ |
| public void setTarget(String target) { |
| getAnchorElement().setTarget(target); |
| } |
| |
| @Override |
| public void setText(String text) { |
| directionalTextHelper.setText(text); |
| } |
| |
| @Override |
| public void setText(String text, Direction dir) { |
| directionalTextHelper.setText(text, dir); |
| } |
| |
| @Override |
| public void setWordWrap(boolean wrap) { |
| getElement().getStyle().setWhiteSpace(wrap ? WhiteSpace.NORMAL : WhiteSpace.NOWRAP); |
| } |
| |
| private AnchorElement getAnchorElement() { |
| return AnchorElement.as(getElement()); |
| } |
| } |