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