1 /*
2 * Copyright (c) 2002-2026 Gargoyle Software Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 * https://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package org.htmlunit.html;
16
17 import java.io.IOException;
18 import java.net.MalformedURLException;
19 import java.net.URL;
20 import java.util.Map;
21
22 import org.htmlunit.Page;
23 import org.htmlunit.SgmlPage;
24 import org.htmlunit.WebWindow;
25 import org.htmlunit.javascript.host.event.Event;
26 import org.htmlunit.javascript.host.html.HTMLElement;
27
28 /**
29 * Wrapper for the HTML element "a".
30 *
31 * @author Mike Bowler
32 * @author David K. Taylor
33 * @author Christian Sell
34 * @author Ahmed Ashour
35 * @author Dmitri Zoubkov
36 * @author Ronald Brill
37 * @author Frank Danek
38 * @author Lai Quang Duong
39 */
40 public class HtmlAnchor extends HtmlElement implements HyperlinkElement {
41
42 /** The HTML tag represented by this element. */
43 public static final String TAG_NAME = "a";
44
45 /**
46 * Creates a new instance.
47 *
48 * @param qualifiedName the qualified name of the element type to instantiate
49 * @param page the page that contains this element
50 * @param attributes the initial attributes
51 */
52 HtmlAnchor(final String qualifiedName, final SgmlPage page,
53 final Map<String, DomAttr> attributes) {
54 super(qualifiedName, page, attributes);
55 }
56
57 /**
58 * {@inheritDoc}
59 */
60 @Override
61 @SuppressWarnings("unchecked")
62 public <P extends Page> P click(final Event event,
63 final boolean shiftKey, final boolean ctrlKey, final boolean altKey,
64 final boolean ignoreVisibility) throws IOException {
65 WebWindow oldWebWindow = null;
66 if (ctrlKey) {
67 oldWebWindow = ((HTMLElement) event.getSrcElement()).getDomNodeOrDie()
68 .getPage().getWebClient().getCurrentWindow();
69 }
70
71 P page = super.click(event, shiftKey, ctrlKey, altKey, ignoreVisibility);
72
73 if (ctrlKey) {
74 page.getEnclosingWindow().getWebClient().setCurrentWindow(oldWebWindow);
75 page = (P) oldWebWindow.getEnclosedPage();
76 }
77
78 return page;
79 }
80
81 /**
82 * Same as {@link #doClickStateUpdate(boolean, boolean)}, except that it accepts an {@code href} suffix,
83 * needed when a click is performed on an image map to pass information on the click position.
84 *
85 * @param shiftKey {@code true} if SHIFT is pressed
86 * @param ctrlKey {@code true} if CTRL is pressed
87 * @param hrefSuffix the suffix to add to the anchor's {@code href} attribute
88 * (for instance coordinates from an image map)
89 * @throws IOException if an IO error occurs
90 */
91 protected void doClickStateUpdate(final boolean shiftKey, final boolean ctrlKey, final String hrefSuffix)
92 throws IOException {
93 HyperlinkElementSupport.doClickStateUpdate(this, shiftKey, ctrlKey, hrefSuffix);
94 }
95
96 /**
97 * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
98 *
99 * @param href the href
100 * @param page the HtmlPage
101 * @return the calculated target url.
102 * @throws MalformedURLException if an IO error occurs
103 */
104 public static URL getTargetUrl(final String href, final HtmlPage page) throws MalformedURLException {
105 return HyperlinkElementSupport.getTargetUrl(href, page);
106 }
107
108 /**
109 * {@inheritDoc}
110 */
111 @Override
112 protected boolean doClickStateUpdate(final boolean shiftKey, final boolean ctrlKey) throws IOException {
113 doClickStateUpdate(shiftKey, ctrlKey, "");
114 return false;
115 }
116
117 /**
118 * Returns the value of the attribute {@code charset}. Refer to the
119 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
120 * documentation for details on the use of this attribute.
121 *
122 * @return the value of the attribute {@code charset} or an empty string if that attribute isn't defined
123 */
124 public final String getCharsetAttribute() {
125 return getAttributeDirect("charset");
126 }
127
128 /**
129 * Returns the value of the attribute {@code type}. Refer to the
130 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
131 * documentation for details on the use of this attribute.
132 *
133 * @return the value of the attribute {@code type} or an empty string if that attribute isn't defined
134 */
135 public final String getTypeAttribute() {
136 return getAttributeDirect(TYPE_ATTRIBUTE);
137 }
138
139 /**
140 * Returns the value of the attribute {@code name}. Refer to the
141 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
142 * documentation for details on the use of this attribute.
143 *
144 * @return the value of the attribute {@code name} or an empty string if that attribute isn't defined
145 */
146 public final String getNameAttribute() {
147 return getAttributeDirect(NAME_ATTRIBUTE);
148 }
149
150 /**
151 * Returns the value of the attribute {@code href}. Refer to the
152 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
153 * documentation for details on the use of this attribute.
154 *
155 * @return the value of the attribute {@code href} or an empty string if that attribute isn't defined
156 */
157 @Override
158 public final String getHrefAttribute() {
159 return getAttributeDirect("href").trim();
160 }
161
162 /**
163 * Returns the value of the attribute {@code hreflang}. Refer to the
164 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
165 * documentation for details on the use of this attribute.
166 *
167 * @return the value of the attribute {@code hreflang} or an empty string if that attribute isn't defined
168 */
169 public final String getHrefLangAttribute() {
170 return getAttributeDirect("hreflang");
171 }
172
173 /**
174 * Returns the value of the attribute {@code rel}. Refer to the
175 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
176 * documentation for details on the use of this attribute.
177 *
178 * @return the value of the attribute {@code rel} or an empty string if that attribute isn't defined
179 */
180 @Override
181 public final String getRelAttribute() {
182 return getAttributeDirect("rel");
183 }
184
185 /**
186 * Returns the value of the attribute {@code rev}. Refer to the
187 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
188 * documentation for details on the use of this attribute.
189 *
190 * @return the value of the attribute {@code rev} or an empty string if that attribute isn't defined
191 */
192 public final String getRevAttribute() {
193 return getAttributeDirect("rev");
194 }
195
196 /**
197 * Returns the value of the attribute {@code accesskey}. Refer to the
198 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
199 * documentation for details on the use of this attribute.
200 *
201 * @return the value of the attribute {@code accesskey} or an empty string if that attribute isn't defined
202 */
203 public final String getAccessKeyAttribute() {
204 return getAttributeDirect("accesskey");
205 }
206
207 /**
208 * Returns the value of the attribute {@code shape}. Refer to the
209 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
210 * documentation for details on the use of this attribute.
211 *
212 * @return the value of the attribute {@code shape} or an empty string if that attribute isn't defined
213 */
214 public final String getShapeAttribute() {
215 return getAttributeDirect("shape");
216 }
217
218 /**
219 * Returns the value of the attribute {@code coords}. Refer to the
220 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
221 * documentation for details on the use of this attribute.
222 *
223 * @return the value of the attribute {@code coords} or an empty string if that attribute isn't defined
224 */
225 public final String getCoordsAttribute() {
226 return getAttributeDirect("coords");
227 }
228
229 /**
230 * Returns the value of the attribute {@code tabindex}. Refer to the
231 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
232 * documentation for details on the use of this attribute.
233 *
234 * @return the value of the attribute {@code tabindex} or an empty string if that attribute isn't defined
235 */
236 public final String getTabIndexAttribute() {
237 return getAttributeDirect("tabindex");
238 }
239
240 /**
241 * Returns the value of the attribute {@code onfocus}. Refer to the
242 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
243 * documentation for details on the use of this attribute.
244 *
245 * @return the value of the attribute {@code onfocus} or an empty string if that attribute isn't defined
246 */
247 public final String getOnFocusAttribute() {
248 return getAttributeDirect("onfocus");
249 }
250
251 /**
252 * Returns the value of the attribute {@code onblur}. Refer to the
253 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
254 * documentation for details on the use of this attribute.
255 *
256 * @return the value of the attribute {@code onblur} or an empty string if that attribute isn't defined
257 */
258 public final String getOnBlurAttribute() {
259 return getAttributeDirect("onblur");
260 }
261
262 /**
263 * Returns the value of the attribute {@code target}. Refer to the
264 * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
265 * documentation for details on the use of this attribute.
266 *
267 * @return the value of the attribute {@code target} or an empty string if that attribute isn't defined
268 */
269 @Override
270 public final String getTargetAttribute() {
271 return getAttributeDirect("target");
272 }
273
274 /**
275 * Open this link in a new window, much as web browsers do when you shift-click a link or use the context
276 * menu to open in a new window.
277 * <p>
278 * It should be noted that even web browsers will sometimes not give the expected result when using this
279 * method of following links. Links that have no real href and rely on JavaScript to do their work will
280 * fail.
281 * </p>
282 *
283 * @return the page opened by this link, nested in a new {@link org.htmlunit.TopLevelWindow}
284 * @throws MalformedURLException if the href could not be converted to a valid URL
285 */
286 public final Page openLinkInNewWindow() throws MalformedURLException {
287 final URL target = ((HtmlPage) getPage()).getFullyQualifiedUrl(getHrefAttribute());
288 final String windowName = "HtmlAnchor.openLinkInNewWindow() target";
289 final WebWindow newWindow = getPage().getWebClient().openWindow(target, windowName);
290 return newWindow.getEnclosedPage();
291 }
292
293 @Override
294 protected boolean isEmptyXmlTagExpanded() {
295 return true;
296 }
297
298 /**
299 * {@inheritDoc}
300 */
301 @Override
302 public DisplayStyle getDefaultStyleDisplay() {
303 return DisplayStyle.INLINE;
304 }
305
306 /**
307 * {@inheritDoc}
308 */
309 @Override
310 public boolean handles(final Event event) {
311 if (Event.TYPE_BLUR.equals(event.getType()) || Event.TYPE_FOCUS.equals(event.getType())) {
312 return true;
313 }
314 return super.handles(event);
315 }
316
317 /**
318 * Returns the value of the attribute {@code ping}.
319 *
320 * @return the value of the attribute {@code ping}
321 */
322 @Override
323 public final String getPingAttribute() {
324 return getAttributeDirect("ping");
325 }
326
327 /**
328 * Returns the value of the attribute {@code download}.
329 *
330 * @return the value of the attribute {@code download}
331 */
332 @Override
333 public final String getDownloadAttribute() {
334 return getAttributeDirect("download");
335 }
336 }