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