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