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_ANCHOR_HOSTNAME_IGNORE_BLANK;
18  import static org.htmlunit.BrowserVersionFeatures.JS_ANCHOR_PATHNAME_DETECT_WIN_DRIVES_URL_REPLACE;
19  import static org.htmlunit.BrowserVersionFeatures.JS_ANCHOR_PATHNAME_PREFIX_WIN_DRIVES_URL;
20  import static org.htmlunit.BrowserVersionFeatures.JS_ANCHOR_PROTOCOL_COLON_UPPER_CASE_DRIVE_LETTERS;
21  import static org.htmlunit.html.DomElement.ATTRIBUTE_NOT_DEFINED;
22  
23  import java.net.MalformedURLException;
24  import java.net.URL;
25  import java.util.Arrays;
26  import java.util.List;
27  import java.util.Locale;
28  
29  import org.htmlunit.BrowserVersion;
30  import org.htmlunit.HttpHeader;
31  import org.htmlunit.SgmlPage;
32  import org.htmlunit.html.DomElement;
33  import org.htmlunit.html.DomNode;
34  import org.htmlunit.html.HtmlAnchor;
35  import org.htmlunit.html.HtmlElement;
36  import org.htmlunit.html.HtmlPage;
37  import org.htmlunit.javascript.JavaScriptEngine;
38  import org.htmlunit.javascript.configuration.JsxClass;
39  import org.htmlunit.javascript.configuration.JsxConstructor;
40  import org.htmlunit.javascript.configuration.JsxGetter;
41  import org.htmlunit.javascript.configuration.JsxSetter;
42  import org.htmlunit.javascript.host.dom.DOMTokenList;
43  import org.htmlunit.util.StringUtils;
44  import org.htmlunit.util.UrlUtils;
45  
46  /**
47   * The JavaScript object that represents an anchor.
48   *
49   * @author Mike Bowler
50   * @author Alexei Goussev
51   * @author David D. Kilzer
52   * @author Marc Guillemot
53   * @author Chris Erskine
54   * @author Ahmed Ashour
55   * @author Sudhan Moghe
56   * @author Daniel Gredler
57   * @author Ronald Brill
58   * @author Lai Quang Duong
59   *
60   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement">MDN Documentation</a>
61   */
62  @JsxClass(domClass = HtmlAnchor.class)
63  public class HTMLAnchorElement extends HTMLElement {
64      private static final List<String> REFERRER_POLICIES = Arrays.asList(
65                                          "no-referrer", HttpHeader.ORIGIN_LC, "unsafe-url");
66  
67      /**
68       * JavaScript constructor.
69       */
70      @Override
71      @JsxConstructor
72      public void jsConstructor() {
73          super.jsConstructor();
74      }
75  
76      /**
77       * Sets the {@code href} property.
78       * @param href the {@code href} property value
79       */
80      @JsxSetter
81      public void setHref(final String href) {
82          getDomNodeOrDie().setAttribute("href", href);
83      }
84  
85      /**
86       * Returns the value of this link's {@code href} property.
87       * @return the value of this link's {@code href} property
88       */
89      @JsxGetter
90      public String getHref() {
91          final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
92          final String hrefAttr = anchor.getHrefAttribute();
93  
94          if (ATTRIBUTE_NOT_DEFINED == hrefAttr) {
95              return "";
96          }
97  
98          try {
99              return getUrl().toString();
100         }
101         catch (final MalformedURLException e) {
102             return hrefAttr;
103         }
104     }
105 
106     /**
107      * Sets the focus to this element.
108      */
109     @Override
110     public void focus() {
111         final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
112         final String hrefAttr = anchor.getHrefAttribute();
113 
114         if (ATTRIBUTE_NOT_DEFINED != hrefAttr) {
115             anchor.focus();
116         }
117     }
118 
119     /**
120      * Sets the {@code name} property.
121      * @param name the {@code name} property value
122      */
123     @JsxSetter
124     @Override
125     public void setName(final String name) {
126         getDomNodeOrDie().setAttribute(DomElement.NAME_ATTRIBUTE, name);
127     }
128 
129     /**
130      * Returns the value of this link's {@code name} property.
131      * @return the value of this link's {@code name} property
132      */
133     @JsxGetter
134     @Override
135     public String getName() {
136         return getDomNodeOrDie().getAttributeDirect(DomElement.NAME_ATTRIBUTE);
137     }
138 
139     /**
140      * Sets the {@code target} property of this link.
141      * @param target the {@code target} property value
142      */
143     @JsxSetter
144     public void setTarget(final String target) {
145         getDomNodeOrDie().setAttribute("target", target);
146     }
147 
148     /**
149      * Returns the value of this link's {@code target} property.
150      * @return the value of this link's {@code target} property
151      */
152     @JsxGetter
153     public String getTarget() {
154         return getDomNodeOrDie().getAttributeDirect("target");
155     }
156 
157     /**
158      * Returns this link's current URL.
159      * @return this link's current URL
160      * @throws MalformedURLException if an error occurs
161      */
162     private URL getUrl() throws MalformedURLException {
163         final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
164         return ((HtmlPage) anchor.getPage()).getFullyQualifiedUrl(anchor.getHrefAttribute());
165     }
166 
167     /**
168      * Sets the {@code href} attribute of this link to the specified URL.
169      * @param url the new value of the {@code href} attribute
170      */
171     private void setUrl(final URL url) {
172         getDomNodeOrDie().setAttribute("href", url.toString());
173     }
174 
175     /**
176      * Sets the {@code rel} property.
177      * @param rel the {@code rel} property value
178      */
179     @JsxSetter
180     public void setRel(final String rel) {
181         getDomNodeOrDie().setAttribute("rel", rel);
182     }
183 
184     /**
185      * Returns the value of this link's {@code rel} property.
186      * @return the value of this link's {@code rel} property
187      */
188     @JsxGetter
189     public String getRel() {
190         return ((HtmlAnchor) getDomNodeOrDie()).getRelAttribute();
191     }
192 
193     /**
194      * Returns the value of this link's {@code rev} property.
195      * @return the value of this link's {@code rev} property
196      */
197     @JsxGetter
198     public String getRev() {
199         return ((HtmlAnchor) getDomNodeOrDie()).getRevAttribute();
200     }
201 
202     /**
203      * Sets the {@code rev} property.
204      * @param rel the {@code rev} property value
205      */
206     @JsxSetter
207     public void setRev(final String rel) {
208         getDomNodeOrDie().setAttribute("rev", rel);
209     }
210 
211     /**
212      * Returns the value of this link's {@code referrerPolicy} property.
213      * @return the value of this link's {@code referrerPolicy} property
214      */
215     @JsxGetter
216     public String getReferrerPolicy() {
217         String attrib = getDomNodeOrDie().getAttribute("referrerPolicy");
218         if (StringUtils.isEmptyOrNull(attrib)) {
219             return "";
220         }
221         attrib = attrib.toLowerCase(Locale.ROOT);
222         if (REFERRER_POLICIES.contains(attrib)) {
223             return attrib;
224         }
225         return "";
226     }
227 
228     /**
229      * Sets the {@code referrerPolicy} property.
230      * @param referrerPolicy the {@code referrerPolicy} property value
231      */
232     @JsxSetter
233     public void setReferrerPolicy(final String referrerPolicy) {
234         getDomNodeOrDie().setAttribute("referrerPolicy", referrerPolicy);
235     }
236 
237     /**
238      * Returns the search portion of the link's URL (the portion starting with
239      * '?' and up to but not including any '#').
240      * @return the search portion of the link's URL
241      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/search">MDN Documentation</a>
242      */
243     @JsxGetter
244     public String getSearch() {
245         try {
246             return HTMLHyperlinkElementUtils.getSearch(getUrl());
247         }
248         catch (final MalformedURLException e) {
249             return "";
250         }
251     }
252 
253     /**
254      * Sets the search portion of the link's URL (the portion starting with '?'
255      * and up to but not including any '#').
256      * @param search the new search portion of the link's URL
257      * @throws Exception if an error occurs
258      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/search">MDN Documentation</a>
259      */
260     @JsxSetter
261     public void setSearch(final String search) throws Exception {
262         setUrl(HTMLHyperlinkElementUtils.setSearch(getUrl(), search));
263     }
264 
265     /**
266      * Returns the hash portion of the link's URL (the portion following the '#', including the '#').
267      * @return the hash portion of the link's URL
268      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/hash">MDN Documentation</a>
269      */
270     @JsxGetter
271     public String getHash() {
272         try {
273             return HTMLHyperlinkElementUtils.getHash(getUrl());
274         }
275         catch (final MalformedURLException e) {
276             return "";
277         }
278     }
279 
280     /**
281      * Sets the hash portion of the link's URL (the portion following the '#').
282      * @param hash the new hash portion of the link's URL
283      * @throws Exception if an error occurs
284      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/hash">MDN Documentation</a>
285      */
286     @JsxSetter
287     public void setHash(final String hash) throws Exception {
288         setUrl(HTMLHyperlinkElementUtils.setHash(getUrl(), hash));
289     }
290 
291     /**
292      * Returns the host portion of the link's URL (the '[hostname]:[port]' portion).
293      * @return the host portion of the link's URL
294      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/host">MDN Documentation</a>
295      */
296     @JsxGetter
297     public String getHost() {
298         try {
299             final URL url = getUrl();
300             final int port = url.getPort();
301             final String host = url.getHost();
302 
303             if (port == -1 || HTMLHyperlinkElementUtils.isDefaultPort(url.getProtocol(), port)) {
304                 return host;
305             }
306             return host + ":" + port;
307         }
308         catch (final MalformedURLException e) {
309             return "";
310         }
311     }
312 
313     /**
314      * Sets the host portion of the link's URL (the '[hostname]:[port]' portion).
315      * @param host the new host portion of the link's URL
316      * @throws Exception if an error occurs
317      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/host">MDN Documentation</a>
318      */
319     @JsxSetter
320     public void setHost(final String host) throws Exception {
321         setUrl(HTMLHyperlinkElementUtils.setHost(getUrl(), host));
322     }
323 
324     /**
325      * Returns the hostname portion of the link's URL.
326      * @return the hostname portion of the link's URL
327      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/hostname">MDN Documentation</a>
328      */
329     @JsxGetter
330     public String getHostname() {
331         try {
332             return HTMLHyperlinkElementUtils.getHostname(getUrl());
333         }
334         catch (final MalformedURLException e) {
335             return "";
336         }
337     }
338 
339     /**
340      * Sets the hostname portion of the link's URL.
341      * @param hostname the new hostname portion of the link's URL
342      * @throws Exception if an error occurs
343      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/hostname">MDN Documentation</a>
344      */
345     @JsxSetter
346     public void setHostname(final String hostname) throws Exception {
347         if (getBrowserVersion().hasFeature(JS_ANCHOR_HOSTNAME_IGNORE_BLANK)) {
348             if (!StringUtils.isBlank(hostname)) {
349                 setUrl(UrlUtils.getUrlWithNewHost(getUrl(), hostname));
350             }
351         }
352         else if (!StringUtils.isEmptyOrNull(hostname)) {
353             setUrl(UrlUtils.getUrlWithNewHost(getUrl(), hostname));
354         }
355     }
356 
357     /**
358      * Returns the pathname portion of the link's URL.
359      * @return the pathname portion of the link's URL
360      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/pathname">MDN Documentation</a>
361      */
362     @JsxGetter
363     public String getPathname() {
364         final BrowserVersion browser = getBrowserVersion();
365         try {
366             if (browser.hasFeature(JS_ANCHOR_PATHNAME_DETECT_WIN_DRIVES_URL_REPLACE)) {
367                 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
368                 String href = anchor.getHrefAttribute();
369                 if (href.length() > 1 && Character.isLetter(href.charAt(0)) && ':' == href.charAt(1)) {
370                     if (browser.hasFeature(JS_ANCHOR_PROTOCOL_COLON_UPPER_CASE_DRIVE_LETTERS)) {
371                         href = org.apache.commons.lang3.StringUtils.capitalize(href);
372                     }
373                     if (browser.hasFeature(JS_ANCHOR_PATHNAME_PREFIX_WIN_DRIVES_URL)) {
374                         href = "/" + href;
375                     }
376                     return href;
377                 }
378             }
379             return getUrl().getPath();
380         }
381         catch (final MalformedURLException e) {
382             final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
383             if (anchor.getHrefAttribute().startsWith("http")) {
384                 return "";
385             }
386             return "/";
387         }
388     }
389 
390     /**
391      * Sets the pathname portion of the link's URL.
392      * @param pathname the new pathname portion of the link's URL
393      * @throws Exception if an error occurs
394      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/pathname">MDN Documentation</a>
395      */
396     @JsxSetter
397     public void setPathname(final String pathname) throws Exception {
398         setUrl(HTMLHyperlinkElementUtils.setPathname(getUrl(), pathname));
399     }
400 
401     /**
402      * Returns the port portion of the link's URL.
403      * @return the port portion of the link's URL
404      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/port">MDN Documentation</a>
405      */
406     @JsxGetter
407     public String getPort() {
408         try {
409             final URL url = getUrl();
410             final int port = url.getPort();
411             if (port == -1 || HTMLHyperlinkElementUtils.isDefaultPort(url.getProtocol(), port)) {
412                 return "";
413             }
414             return Integer.toString(port);
415         }
416         catch (final MalformedURLException e) {
417             return "";
418         }
419     }
420 
421     /**
422      * Sets the port portion of the link's URL.
423      * @param port the new port portion of the link's URL
424      * @throws Exception if an error occurs
425      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/port">MDN Documentation</a>
426      */
427     @JsxSetter
428     public void setPort(final String port) throws Exception {
429         final URL url = getUrl();
430         final int newPort = Integer.parseInt(port);
431         if (HTMLHyperlinkElementUtils.isDefaultPort(url.getProtocol(), newPort)) {
432             setUrl(UrlUtils.getUrlWithNewPort(url, -1));
433         }
434         else {
435             setUrl(UrlUtils.getUrlWithNewPort(url, newPort));
436         }
437     }
438 
439     /**
440      * Returns the protocol portion of the link's URL, including the trailing ':'.
441      * @return the protocol portion of the link's URL, including the trailing ':'
442      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/protocol">MDN Documentation</a>
443      */
444     @JsxGetter
445     public String getProtocol() {
446         final BrowserVersion browser = getBrowserVersion();
447         try {
448             if (browser.hasFeature(JS_ANCHOR_PATHNAME_DETECT_WIN_DRIVES_URL_REPLACE)) {
449                 final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
450                 final String href = anchor.getHrefAttribute().toLowerCase(Locale.ROOT);
451                 if (href.length() > 1 && Character.isLetter(href.charAt(0)) && ':' == href.charAt(1)) {
452                     return "file:";
453                 }
454             }
455 
456             return getUrl().getProtocol() + ":";
457         }
458         catch (final MalformedURLException e) {
459             final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
460             if (anchor.getHrefAttribute().startsWith("http")) {
461                 return ":";
462             }
463             return StringUtils.substringBefore(anchor.getHrefAttribute(), "/");
464         }
465     }
466 
467     /**
468      * Sets the protocol portion of the link's URL.
469      * @param protocol the new protocol portion of the link's URL
470      * @throws Exception if an error occurs
471      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement/protocol">MDN Documentation</a>
472      */
473     @JsxSetter
474     public void setProtocol(final String protocol) throws Exception {
475         final URL result = HTMLHyperlinkElementUtils.setProtocol(getUrl(), protocol);
476         if (result != null) {
477             setUrl(result);
478         }
479     }
480 
481     /**
482      * Called, for instance, for implicit conversion to a string.
483      * @see org.htmlunit.javascript.HtmlUnitScriptable#getDefaultValue(java.lang.Class)
484      * @param hint the type hint
485      * @return the default value
486      */
487     @Override
488     public Object getDefaultValue(final Class<?> hint) {
489         final HtmlElement element = getDomNodeOrNull();
490         if (element == null) {
491             return super.getDefaultValue(null);
492         }
493         return getDefaultValue(element);
494     }
495 
496     static String getDefaultValue(final HtmlElement element) {
497         String href = element.getAttributeDirect("href");
498 
499         if (ATTRIBUTE_NOT_DEFINED == href) {
500             return ""; // for example for named anchors
501         }
502 
503         href = href.trim();
504 
505         final SgmlPage page = element.getPage();
506         if (page == null || !page.isHtmlPage()) {
507             return href;
508         }
509 
510         try {
511             return HtmlAnchor.getTargetUrl(href, (HtmlPage) page).toExternalForm();
512         }
513         catch (final MalformedURLException e) {
514             return href;
515         }
516     }
517 
518     /**
519      * Returns the {@code text} attribute.
520      * @return the {@code text} attribute
521      */
522     @JsxGetter
523     public String getText() {
524         final DomNode htmlElement = getDomNodeOrDie();
525         return htmlElement.asNormalizedText();
526     }
527 
528     /**
529      * Sets the {@code text} attribute.
530      * @param text the {@code text} attribute
531      */
532     @JsxSetter
533     public void setText(final String text) {
534         final DomNode htmlElement = getDomNodeOrDie();
535         htmlElement.setTextContent(text);
536     }
537 
538     /**
539      * Returns the {@code charset} attribute.
540      * @return the {@code charset} attribute
541      */
542     @JsxGetter
543     public String getCharset() {
544         return getDomNodeOrDie().getAttributeDirect("charset");
545     }
546 
547     /**
548      * Sets the {@code charset} attribute.
549      * @param charset the {@code charset} attribute
550      */
551     @JsxSetter
552     public void setCharset(final String charset) {
553         getDomNodeOrDie().setAttribute("charset", charset);
554     }
555 
556     /**
557      * Returns the {@code coords} attribute.
558      * @return the {@code coords} attribute
559      */
560     @JsxGetter
561     public String getCoords() {
562         return getDomNodeOrDie().getAttributeDirect("coords");
563     }
564 
565     /**
566      * Sets the {@code coords} attribute.
567      * @param coords the {@code coords} attribute value
568      */
569     @JsxSetter
570     public void setCoords(final String coords) {
571         getDomNodeOrDie().setAttribute("coords", coords);
572     }
573 
574     /**
575      * Returns the {@code hreflang} attribute.
576      * @return the {@code hreflang} attribute
577      */
578     @JsxGetter
579     public String getHreflang() {
580         return getDomNodeOrDie().getAttributeDirect("hreflang");
581     }
582 
583     /**
584      * Sets the {@code hreflang} attribute.
585      * @param hreflang the {@code hreflang} attribute value
586      */
587     @JsxSetter
588     public void setHreflang(final String hreflang) {
589         getDomNodeOrDie().setAttribute("hreflang", hreflang);
590     }
591 
592     /**
593      * Returns the {@code origin} attribute.
594      * @return the {@code origin} attribute
595      */
596     @JsxGetter
597     public String getOrigin() {
598         if (!getDomNodeOrDie().hasAttribute("href")) {
599             return "";
600         }
601 
602         try {
603             return getUrl().getProtocol() + "://" + getHost();
604         }
605         catch (final Exception e) {
606             return "";
607         }
608     }
609 
610     /**
611      * Returns the {@code username} attribute.
612      * @return the {@code username} attribute
613      */
614     @JsxGetter
615     public String getUsername() {
616         try {
617             return HTMLHyperlinkElementUtils.getUsername(getUrl());
618         }
619         catch (final MalformedURLException e) {
620             return "";
621         }
622     }
623 
624     /**
625      * Sets the {@code username} attribute.
626      * @param username the {@code username} attribute value
627      */
628     @JsxSetter
629     public void setUsername(final String username) {
630         try {
631             final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
632             final String href = anchor.getHrefAttribute();
633             if (ATTRIBUTE_NOT_DEFINED == href) {
634                 return;
635             }
636 
637             final URL url = ((HtmlPage) anchor.getPage()).getFullyQualifiedUrl(href);
638             setUrl(UrlUtils.getUrlWithNewUserName(url, username));
639         }
640         catch (final MalformedURLException ignored) {
641             // ignore
642         }
643     }
644 
645     /**
646      * Returns the {@code password} attribute.
647      * @return the {@code password} attribute
648      */
649     @JsxGetter
650     public String getPassword() {
651         try {
652             return HTMLHyperlinkElementUtils.getPassword(getUrl());
653         }
654         catch (final MalformedURLException e) {
655             return "";
656         }
657     }
658 
659     /**
660      * Sets the {@code password} attribute.
661      * @param password the {@code password} attribute value
662      */
663     @JsxSetter
664     public void setPassword(final String password) {
665         try {
666             final HtmlAnchor anchor = (HtmlAnchor) getDomNodeOrDie();
667             final String href = anchor.getHrefAttribute();
668             if (ATTRIBUTE_NOT_DEFINED == href) {
669                 return;
670             }
671 
672             final URL url = ((HtmlPage) anchor.getPage()).getFullyQualifiedUrl(href);
673             setUrl(UrlUtils.getUrlWithNewUserPassword(url, password));
674         }
675         catch (final MalformedURLException ignored) {
676             // ignore
677         }
678     }
679 
680     /**
681      * Returns the {@code download} attribute.
682      * @return the {@code download} attribute
683      */
684     @JsxGetter
685     public String getDownload() {
686         return ((HtmlAnchor) getDomNodeOrDie()).getDownloadAttribute();
687     }
688 
689     /**
690      * Sets the {@code download} attribute.
691      * @param download the {@code download} attribute value
692      */
693     @JsxSetter
694     public void setDownload(final String download) {
695         getDomNodeOrDie().setAttribute("download", download);
696     }
697 
698     /**
699      * Returns the {@code ping} attribute.
700      * @return the {@code ping} attribute
701      */
702     @JsxGetter
703     public String getPing() {
704         return ((HtmlAnchor) getDomNodeOrDie()).getPingAttribute();
705     }
706 
707     /**
708      * Sets the {@code ping} attribute.
709      * @param ping the {@code ping} attribute value
710      */
711     @JsxSetter
712     public void setPing(final String ping) {
713         getDomNodeOrDie().setAttribute("ping", ping);
714     }
715 
716     /**
717      * Returns the {@code shape} attribute.
718      * @return the {@code shape} attribute
719      */
720     @JsxGetter
721     public String getShape() {
722         return getDomNodeOrDie().getAttribute("shape");
723     }
724 
725     /**
726      * Sets the {@code shape} attribute.
727      * @param shape the {@code shape} attribute value
728      */
729     @JsxSetter
730     public void setShape(final String shape) {
731         getDomNodeOrDie().setAttribute("shape", shape);
732     }
733 
734     /**
735      * Returns the {@code type} attribute.
736      * @return the {@code type} attribute
737      */
738     @JsxGetter
739     public String getType() {
740         return getDomNodeOrDie().getAttributeDirect(DomElement.TYPE_ATTRIBUTE);
741     }
742 
743     /**
744      * Sets the {@code type} attribute.
745      * @param type the {@code type} attribute value
746      */
747     @JsxSetter
748     public void setType(final String type) {
749         getDomNodeOrDie().setAttribute(DomElement.TYPE_ATTRIBUTE, type);
750     }
751 
752     /**
753      * Returns the {@code relList} attribute.
754      * @return the {@code relList} attribute
755      */
756     @JsxGetter
757     public DOMTokenList getRelList() {
758         return new DOMTokenList(this, "rel");
759     }
760 
761     /**
762      * Sets the {@code relList} attribute.
763      * @param rel the {@code relList} attribute value
764      */
765     @JsxSetter
766     public void setRelList(final Object rel) {
767         setRel(JavaScriptEngine.toString(rel));
768     }
769 }