View Javadoc
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.javascript.host.html;
16  
17  import static org.htmlunit.BrowserVersionFeatures.JS_AREA_WITHOUT_HREF_FOCUSABLE;
18  import static org.htmlunit.html.DomElement.ATTRIBUTE_NOT_DEFINED;
19  
20  import java.net.MalformedURLException;
21  import java.net.URL;
22  
23  import org.htmlunit.html.HtmlArea;
24  import org.htmlunit.html.HtmlElement;
25  import org.htmlunit.html.HtmlPage;
26  import org.htmlunit.javascript.configuration.JsxClass;
27  import org.htmlunit.javascript.configuration.JsxConstructor;
28  import org.htmlunit.javascript.configuration.JsxGetter;
29  import org.htmlunit.javascript.configuration.JsxSetter;
30  import org.htmlunit.javascript.host.dom.DOMTokenList;
31  import org.htmlunit.util.StringUtils;
32  import org.htmlunit.util.UrlUtils;
33  
34  /**
35   * The JavaScript object {@code HTMLAreaElement}.
36   *
37   * @author Ahmed Ashour
38   * @author Ronald Brill
39   * @author Frank Danek
40   * @author Lai Quang Duong
41   */
42  @JsxClass(domClass = HtmlArea.class)
43  public class HTMLAreaElement extends HTMLElement {
44  
45      /**
46       * JavaScript constructor.
47       */
48      @Override
49      @JsxConstructor
50      public void jsConstructor() {
51          super.jsConstructor();
52      }
53  
54      /**
55       * Calls for instance for implicit conversion to string.
56       * @see org.htmlunit.javascript.HtmlUnitScriptable#getDefaultValue(java.lang.Class)
57       * @param hint the type hint
58       * @return the default value
59       */
60      @Override
61      public Object getDefaultValue(final Class<?> hint) {
62          final HtmlElement element = getDomNodeOrNull();
63          if (element == null) {
64              return super.getDefaultValue(null);
65          }
66          return HTMLAnchorElement.getDefaultValue(element);
67      }
68  
69      /**
70       * Returns the value of the {@code alt} property.
71       * @return the value of the {@code alt} property
72       */
73      @JsxGetter
74      public String getAlt() {
75          return getDomNodeOrDie().getAttributeDirect("alt");
76      }
77  
78      /**
79       * Returns the value of the {@code alt} property.
80       * @param alt the value
81       */
82      @JsxSetter
83      public void setAlt(final String alt) {
84          getDomNodeOrDie().setAttribute("alt", alt);
85      }
86  
87      /**
88       * {@inheritDoc}
89       */
90      @Override
91      protected boolean isEndTagForbidden() {
92          return true;
93      }
94  
95      /**
96       * Returns the value of the {@code rel} property.
97       * @return the value of the {@code rel} property
98       */
99      @JsxGetter
100     public String getRel() {
101         return getDomNodeOrDie().getAttributeDirect("rel");
102     }
103 
104     /**
105      * Returns the value of the {@code rel} property.
106      * @param rel the value
107      */
108     @JsxSetter
109     public void setRel(final String rel) {
110         getDomNodeOrDie().setAttribute("rel", rel);
111     }
112 
113     /**
114      * Returns the {@code relList} attribute.
115      * @return the {@code relList} attribute
116      */
117     @JsxGetter
118     public DOMTokenList getRelList() {
119         return new DOMTokenList(this, "rel");
120     }
121 
122     /**
123      * Sets the focus to this element.
124      */
125     @Override
126     public void focus() {
127         // in reality this depends also on the visibility of the area itself
128         final HtmlArea area = (HtmlArea) getDomNodeOrDie();
129         final String hrefAttr = area.getHrefAttribute();
130 
131         if (ATTRIBUTE_NOT_DEFINED != hrefAttr
132                 || getBrowserVersion().hasFeature(JS_AREA_WITHOUT_HREF_FOCUSABLE)) {
133             area.focus();
134         }
135     }
136 
137     /**
138      * Returns the {@code coords} attribute.
139      * @return the {@code coords} attribute
140      */
141     @JsxGetter
142     public String getCoords() {
143         return getDomNodeOrDie().getAttributeDirect("coords");
144     }
145 
146     /**
147      * Sets the {@code coords} attribute.
148      * @param coords {@code coords} attribute
149      */
150     @JsxSetter
151     public void setCoords(final String coords) {
152         getDomNodeOrDie().setAttribute("coords", coords);
153     }
154 
155     /**
156      * Returns the {@code href} property.
157      * @return the {@code href} property
158      */
159     @JsxGetter
160     public String getHref() {
161         final HtmlArea area = (HtmlArea) getDomNodeOrDie();
162         final String hrefAttr = area.getHrefAttribute();
163 
164         if (ATTRIBUTE_NOT_DEFINED == hrefAttr) {
165             return "";
166         }
167 
168         try {
169             return getUrl().toString();
170         }
171         catch (final MalformedURLException e) {
172             return hrefAttr;
173         }
174     }
175 
176     /**
177      * Sets the {@code href} property.
178      * @param href the {@code href} value
179      */
180     @JsxSetter
181     public void setHref(final String href) {
182         getDomNodeOrDie().setAttribute("href", href);
183     }
184 
185     /**
186      * Returns the {@code protocol} property.
187      * @return the {@code protocol} property
188      */
189     @JsxGetter
190     public String getProtocol() {
191         try {
192             return getUrl().getProtocol() + ":";
193         }
194         catch (final MalformedURLException e) {
195             return ":";
196         }
197     }
198 
199     /**
200      * Sets the {@code protocol} property.
201      * @param protocol the {@code protocol} value
202      * @throws Exception if an error occurs
203      */
204     @JsxSetter
205     public void setProtocol(final String protocol) throws Exception {
206         final URL result = HTMLHyperlinkElementUtils.setProtocol(getUrl(), protocol);
207         if (result != null) {
208             setUrl(result);
209         }
210     }
211 
212     /**
213      * Returns the {@code hostname} property.
214      * @return the {@code hostname} property
215      */
216     @JsxGetter
217     public String getHostname() {
218         try {
219             return HTMLHyperlinkElementUtils.getHostname(getUrl());
220         }
221         catch (final MalformedURLException e) {
222             return "";
223         }
224     }
225 
226     /**
227      * Sets the {@code hostname} property.
228      * @param hostname the {@code hostname} value
229      * @throws Exception if an error occurs
230      */
231     @JsxSetter
232     public void setHostname(final String hostname) throws Exception {
233         if (!StringUtils.isEmptyOrNull(hostname)) {
234             setUrl(UrlUtils.getUrlWithNewHost(getUrl(), hostname));
235         }
236     }
237 
238     /**
239      * Returns the {@code host} property.
240      * @return the {@code host} property
241      */
242     @JsxGetter
243     public String getHost() {
244         try {
245             final URL url = getUrl();
246             final int port = url.getPort();
247             final String host = url.getHost();
248 
249             if (port == -1 || HTMLHyperlinkElementUtils.isDefaultPort(url.getProtocol(), port)) {
250                 return host;
251             }
252             return host + ":" + port;
253         }
254         catch (final MalformedURLException e) {
255             return "";
256         }
257     }
258 
259     /**
260      * Sets the {@code host} property.
261      * @param host the {@code host} value
262      * @throws Exception if an error occurs
263      */
264     @JsxSetter
265     public void setHost(final String host) throws Exception {
266         setUrl(HTMLHyperlinkElementUtils.setHost(getUrl(), host));
267     }
268 
269     /**
270      * Returns the {@code port} property.
271      * @return the {@code port} property
272      */
273     @JsxGetter
274     public String getPort() {
275         try {
276             final URL url = getUrl();
277             final int port = url.getPort();
278             if (port == -1 || HTMLHyperlinkElementUtils.isDefaultPort(url.getProtocol(), port)) {
279                 return "";
280             }
281             return Integer.toString(port);
282         }
283         catch (final MalformedURLException e) {
284             return "";
285         }
286     }
287 
288     /**
289      * Sets the {@code port} property.
290      * @param port the {@code port} value
291      * @throws Exception if an error occurs
292      */
293     @JsxSetter
294     public void setPort(final String port) throws Exception {
295         final URL url = getUrl();
296         final int newPort = Integer.parseInt(port);
297         if (HTMLHyperlinkElementUtils.isDefaultPort(url.getProtocol(), newPort)) {
298             setUrl(UrlUtils.getUrlWithNewPort(url, -1));
299         }
300         else {
301             setUrl(UrlUtils.getUrlWithNewPort(url, newPort));
302         }
303     }
304 
305     /**
306      * Returns the {@code pathname} property.
307      * @return the {@code pathname} property
308      */
309     @JsxGetter
310     public String getPathname() {
311         try {
312             return getUrl().getPath();
313         }
314         catch (final MalformedURLException e) {
315             return "";
316         }
317     }
318 
319     /**
320      * Sets the {@code pathname} property.
321      * @param pathname the {@code pathname} value
322      * @throws Exception if an error occurs
323      */
324     @JsxSetter
325     public void setPathname(final String pathname) throws Exception {
326         setUrl(HTMLHyperlinkElementUtils.setPathname(getUrl(), pathname));
327     }
328 
329     /**
330      * Returns the {@code search} property.
331      * @return the {@code search} property
332      */
333     @JsxGetter
334     public String getSearch() {
335         try {
336             return HTMLHyperlinkElementUtils.getSearch(getUrl());
337         }
338         catch (final MalformedURLException e) {
339             return "";
340         }
341     }
342 
343     /**
344      * Sets the {@code search} property.
345      * @param search the {@code search} value
346      * @throws Exception if an error occurs
347      */
348     @JsxSetter
349     public void setSearch(final String search) throws Exception {
350         setUrl(HTMLHyperlinkElementUtils.setSearch(getUrl(), search));
351     }
352 
353     /**
354      * Returns the {@code hash} property.
355      * @return the {@code hash} property
356      */
357     @JsxGetter
358     public String getHash() {
359         try {
360             return HTMLHyperlinkElementUtils.getHash(getUrl());
361         }
362         catch (final MalformedURLException e) {
363             return "";
364         }
365     }
366 
367     /**
368      * Sets the {@code hash} property.
369      * @param hash the {@code hash} value
370      * @throws Exception if an error occurs
371      */
372     @JsxSetter
373     public void setHash(final String hash) throws Exception {
374         setUrl(HTMLHyperlinkElementUtils.setHash(getUrl(), hash));
375     }
376 
377     /**
378      * Returns the {@code origin} property.
379      * @return the {@code origin} property
380      */
381     @JsxGetter
382     public String getOrigin() {
383         if (!getDomNodeOrDie().hasAttribute("href")) {
384             return "";
385         }
386 
387         try {
388             return getUrl().getProtocol() + "://" + getHost();
389         }
390         catch (final Exception e) {
391             return "";
392         }
393     }
394 
395     /**
396      * Returns the {@code username} property.
397      * @return the {@code username} property
398      */
399     @JsxGetter
400     public String getUsername() {
401         try {
402             return HTMLHyperlinkElementUtils.getUsername(getUrl());
403         }
404         catch (final MalformedURLException e) {
405             return "";
406         }
407     }
408 
409     /**
410      * Sets the {@code username} property.
411      * @param username the {@code username} value
412      */
413     @JsxSetter
414     public void setUsername(final String username) {
415         try {
416             final HtmlArea area = (HtmlArea) getDomNodeOrDie();
417             final String href = area.getHrefAttribute();
418             if (ATTRIBUTE_NOT_DEFINED == href) {
419                 return;
420             }
421 
422             final URL url = ((HtmlPage) area.getPage()).getFullyQualifiedUrl(href);
423             setUrl(UrlUtils.getUrlWithNewUserName(url, username));
424         }
425         catch (final MalformedURLException ignored) {
426             // ignore
427         }
428     }
429 
430     /**
431      * Returns the {@code password} property.
432      * @return the {@code password} property
433      */
434     @JsxGetter
435     public String getPassword() {
436         try {
437             return HTMLHyperlinkElementUtils.getPassword(getUrl());
438         }
439         catch (final MalformedURLException e) {
440             return "";
441         }
442     }
443 
444     /**
445      * Sets the {@code password} property.
446      * @param password the {@code password} value
447      */
448     @JsxSetter
449     public void setPassword(final String password) {
450         try {
451             final HtmlArea area = (HtmlArea) getDomNodeOrDie();
452             final String href = area.getHrefAttribute();
453             if (ATTRIBUTE_NOT_DEFINED == href) {
454                 return;
455             }
456 
457             final URL url = ((HtmlPage) area.getPage()).getFullyQualifiedUrl(href);
458             setUrl(UrlUtils.getUrlWithNewUserPassword(url, password));
459         }
460         catch (final MalformedURLException ignored) {
461             // ignore
462         }
463     }
464 
465     /**
466      * Returns this area's current URL.
467      * @return this area's current URL
468      * @throws MalformedURLException if an error occurs
469      */
470     private URL getUrl() throws MalformedURLException {
471         final HtmlArea area = (HtmlArea) getDomNodeOrDie();
472         final String href = area.getHrefAttribute();
473         if (ATTRIBUTE_NOT_DEFINED == href) {
474             throw new MalformedURLException("no href attribute");
475         }
476         return ((HtmlPage) area.getPage()).getFullyQualifiedUrl(href);
477     }
478 
479     /**
480      * Sets the {@code href} attribute of this area to the specified URL.
481      * @param url the new value of the {@code href} attribute
482      */
483     private void setUrl(final URL url) {
484         getDomNodeOrDie().setAttribute("href", url.toString());
485     }
486 }