1
2
3
4
5
6
7
8
9
10
11
12
13
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
48
49
50
51
52
53
54
55
56
57
58
59
60
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
69
70 @Override
71 @JsxConstructor
72 public void jsConstructor() {
73 super.jsConstructor();
74 }
75
76
77
78
79
80 @JsxSetter
81 public void setHref(final String href) {
82 getDomNodeOrDie().setAttribute("href", href);
83 }
84
85
86
87
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
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
121
122
123 @JsxSetter
124 @Override
125 public void setName(final String name) {
126 getDomNodeOrDie().setAttribute(DomElement.NAME_ATTRIBUTE, name);
127 }
128
129
130
131
132
133 @JsxGetter
134 @Override
135 public String getName() {
136 return getDomNodeOrDie().getAttributeDirect(DomElement.NAME_ATTRIBUTE);
137 }
138
139
140
141
142
143 @JsxSetter
144 public void setTarget(final String target) {
145 getDomNodeOrDie().setAttribute("target", target);
146 }
147
148
149
150
151
152 @JsxGetter
153 public String getTarget() {
154 return getDomNodeOrDie().getAttributeDirect("target");
155 }
156
157
158
159
160
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
169
170
171 private void setUrl(final URL url) {
172 getDomNodeOrDie().setAttribute("href", url.toString());
173 }
174
175
176
177
178
179 @JsxSetter
180 public void setRel(final String rel) {
181 getDomNodeOrDie().setAttribute("rel", rel);
182 }
183
184
185
186
187
188 @JsxGetter
189 public String getRel() {
190 return ((HtmlAnchor) getDomNodeOrDie()).getRelAttribute();
191 }
192
193
194
195
196
197 @JsxGetter
198 public String getRev() {
199 return ((HtmlAnchor) getDomNodeOrDie()).getRevAttribute();
200 }
201
202
203
204
205
206 @JsxSetter
207 public void setRev(final String rel) {
208 getDomNodeOrDie().setAttribute("rev", rel);
209 }
210
211
212
213
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
230
231
232 @JsxSetter
233 public void setReferrerPolicy(final String referrerPolicy) {
234 getDomNodeOrDie().setAttribute("referrerPolicy", referrerPolicy);
235 }
236
237
238
239
240
241
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
255
256
257
258
259
260 @JsxSetter
261 public void setSearch(final String search) throws Exception {
262 setUrl(HTMLHyperlinkElementUtils.setSearch(getUrl(), search));
263 }
264
265
266
267
268
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
282
283
284
285
286 @JsxSetter
287 public void setHash(final String hash) throws Exception {
288 setUrl(HTMLHyperlinkElementUtils.setHash(getUrl(), hash));
289 }
290
291
292
293
294
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
315
316
317
318
319 @JsxSetter
320 public void setHost(final String host) throws Exception {
321 setUrl(HTMLHyperlinkElementUtils.setHost(getUrl(), host));
322 }
323
324
325
326
327
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
341
342
343
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
359
360
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
392
393
394
395
396 @JsxSetter
397 public void setPathname(final String pathname) throws Exception {
398 setUrl(HTMLHyperlinkElementUtils.setPathname(getUrl(), pathname));
399 }
400
401
402
403
404
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
423
424
425
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
441
442
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
469
470
471
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
483
484
485
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 "";
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
520
521
522 @JsxGetter
523 public String getText() {
524 final DomNode htmlElement = getDomNodeOrDie();
525 return htmlElement.asNormalizedText();
526 }
527
528
529
530
531
532 @JsxSetter
533 public void setText(final String text) {
534 final DomNode htmlElement = getDomNodeOrDie();
535 htmlElement.setTextContent(text);
536 }
537
538
539
540
541
542 @JsxGetter
543 public String getCharset() {
544 return getDomNodeOrDie().getAttributeDirect("charset");
545 }
546
547
548
549
550
551 @JsxSetter
552 public void setCharset(final String charset) {
553 getDomNodeOrDie().setAttribute("charset", charset);
554 }
555
556
557
558
559
560 @JsxGetter
561 public String getCoords() {
562 return getDomNodeOrDie().getAttributeDirect("coords");
563 }
564
565
566
567
568
569 @JsxSetter
570 public void setCoords(final String coords) {
571 getDomNodeOrDie().setAttribute("coords", coords);
572 }
573
574
575
576
577
578 @JsxGetter
579 public String getHreflang() {
580 return getDomNodeOrDie().getAttributeDirect("hreflang");
581 }
582
583
584
585
586
587 @JsxSetter
588 public void setHreflang(final String hreflang) {
589 getDomNodeOrDie().setAttribute("hreflang", hreflang);
590 }
591
592
593
594
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
612
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
626
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
642 }
643 }
644
645
646
647
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
661
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
677 }
678 }
679
680
681
682
683
684 @JsxGetter
685 public String getDownload() {
686 return ((HtmlAnchor) getDomNodeOrDie()).getDownloadAttribute();
687 }
688
689
690
691
692
693 @JsxSetter
694 public void setDownload(final String download) {
695 getDomNodeOrDie().setAttribute("download", download);
696 }
697
698
699
700
701
702 @JsxGetter
703 public String getPing() {
704 return ((HtmlAnchor) getDomNodeOrDie()).getPingAttribute();
705 }
706
707
708
709
710
711 @JsxSetter
712 public void setPing(final String ping) {
713 getDomNodeOrDie().setAttribute("ping", ping);
714 }
715
716
717
718
719
720 @JsxGetter
721 public String getShape() {
722 return getDomNodeOrDie().getAttribute("shape");
723 }
724
725
726
727
728
729 @JsxSetter
730 public void setShape(final String shape) {
731 getDomNodeOrDie().setAttribute("shape", shape);
732 }
733
734
735
736
737
738 @JsxGetter
739 public String getType() {
740 return getDomNodeOrDie().getAttributeDirect(DomElement.TYPE_ATTRIBUTE);
741 }
742
743
744
745
746
747 @JsxSetter
748 public void setType(final String type) {
749 getDomNodeOrDie().setAttribute(DomElement.TYPE_ATTRIBUTE, type);
750 }
751
752
753
754
755
756 @JsxGetter
757 public DOMTokenList getRelList() {
758 return new DOMTokenList(this, "rel");
759 }
760
761
762
763
764
765 @JsxSetter
766 public void setRelList(final Object rel) {
767 setRel(JavaScriptEngine.toString(rel));
768 }
769 }