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