use crate::tests::prelude::*;
track_file!("ref/asciidoc-lang/docs/modules/macros/pages/links.adoc");
non_normative!(
r#"
= Links
:url-url-def: https://en.wikipedia.org/wiki/URL
AsciiDoc offers a variety of ways of creating links (aka hyperlinks) to other addressable resources.
The pages in this section document how to add and customize links in AsciiDoc.
== URLs and links
The [.term]*target* of a link is a {url-url-def}[Uniform Resource Locator^] (URL), otherwise known as a web address.
The text the reader clicks to navigate to that target is referred to as the [.term]*link text*.
NOTE: You may sometimes see the term URI used in place of a URL.
Although the URI is more technically correct in some cases, URL is the accepted term.
The URL is the web address of a unique resource.
A URL can either be absolute or relative.
An absolute URL consists of a scheme, an authority (i.e., domain name), a path with an optional file extension, and metadata in the form of a query string and fragment (e.g., `\https://example.org/asciidoc/links.html?source=home`).
You may recognize an absolute URL as what you type in the location bar of a web browser, such as the one for this page.
A relative URL is the portion of an absolute URL that starts after either the root path or a subpath (e.g., `guides/getting-started.html`).
Since an absolute URL has a distinct, recognizable syntax, an AsciiDoc processor will detect URLs (unless escaped) and automatically convert them to links wherever the macros substitution step is applied.
This also works for bare email addresses.
You can learn more about this behavior in xref:autolinks.adoc[].
To make a link to a relative URL, you must be specify it explicitly as the target of a xref:link-macro.adoc[link macro].
== Link-related macros
Instead of showing the bare URL or email address as the link text, you may want to customize that text.
Or perhaps you want to apply attributes to the link, such as a role.
To do so, you'd use either the xref:url-macro.adoc[URL macro] or, if you're linking to xref:complex-urls.adoc[a complex URL], the more decisive xref:link-macro.adoc[link macro].
(You can also use the xref:link-macro.adoc[link macro] to make a link to an addressable resource using a relative URL or a URL that is not otherwise recognized as an absolute URL).
When linking to an email address, you can use the specialized xref:mailto-macro.adoc[mailto macro] to enhance the link with prepopulated subject and body text.
"#
);
mod encode_reserved_characters {
use crate::tests::prelude::*;
non_normative!(
r#"
== Encode reserved characters
If the URL contains reserved characters, such as double quote (`"`), space, or an unconstrained AsciiDoc formatting mark, you'll need to encode these characters using URI encoding.
For example, a double quote is encoded as `%22`.
An underscore is encoded as `%5F`.
If you do not encode these characters, the URL may be mangled or cause the processor to fail.
"#
);
#[test]
fn example() {
verifies!(
r#"
Let's assume we are creating a URL that contains a query string parameter named `q` that contains reserved characters:
....
https://example.org?q=label:"Requires docs"
....
To encode a URL, open the development tools in your browser and pass the URL to the `encodeURI` function:
[,js]
----
encodeURI('http://example.org?q=label:"Requires docs"')
----
Here's the encoded URL that we'd use in the AsciiDoc document:
....
https://example.org?q=label:%22Requires%20docs%22
....
Depending on the capabilities of the web application, the space character can be encoded as `+` instead of `%20`.
"#
);
let doc = Parser::default().parse("https://example.org?q=label:%22Requires%20docs%22");
assert_eq!(
doc,
Document {
header: Header {
title_source: None,
title: None,
attributes: &[],
author_line: None,
revision_line: None,
comments: &[],
source: Span {
data: "",
line: 1,
col: 1,
offset: 0,
},
},
blocks: &[Block::Simple(SimpleBlock {
content: Content {
original: Span {
data: "https://example.org?q=label:%22Requires%20docs%22",
line: 1,
col: 1,
offset: 0,
},
rendered: "<a href=\"https://example.org?q=label:%22Requires%20docs%22\" class=\"bare\">https://example.org?q=label:%22Requires%20docs%22</a>",
},
source: Span {
data: "https://example.org?q=label:%22Requires%20docs%22",
line: 1,
col: 1,
offset: 0,
},
style: SimpleBlockStyle::Paragraph,
title_source: None,
title: None,
caption: None,
number: None,
anchor: None,
anchor_reftext: None,
attrlist: None,
},),],
source: Span {
data: "https://example.org?q=label:%22Requires%20docs%22",
line: 1,
col: 1,
offset: 0,
},
warnings: &[],
source_map: SourceMap(&[]),
catalog: Catalog::default(),
}
);
}
}
mod hide_uri_scheme {
use crate::tests::prelude::*;
non_normative!(
r#"
[#hide-uri-scheme]
== Hide the URL scheme
If the link text is a bare URL (aka URI), whether that link was created automatically or using a link-related macro, you can configure the AsciiDoc processor to hide the scheme (e.g., _https://_).
Hiding the scheme can make the URL more readable--perhaps even recognizable--to a person less familiar with technical nomenclature.
"#
);
#[test]
fn example() {
verifies!(
r#"
To configure the AsciiDoc processor to display the linked URL without the scheme part, set the `hide-uri-scheme` attribute in the header of the AsciiDoc document.
[source]
----
= Document Title
:hide-uri-scheme: <.>
https://asciidoctor.org
----
<.> Note the use of `uri` instead of `url` in the attribute name.
When the `hide-uri-scheme` attribute is set, the above URL will be displayed to the reader as follows:
====
https://asciidoctor.org[asciidoctor.org]
====
Note the absence of _https://_ in the URL.
The prefix will still be present in the link target.
"#
);
let doc = Parser::default()
.parse("= Document Title\n:hide-uri-scheme:\n\nhttps://asciidoctor.org");
assert_eq!(
doc,
Document {
header: Header {
title_source: Some(Span {
data: "Document Title",
line: 1,
col: 3,
offset: 2,
},),
title: Some("Document Title",),
attributes: &[Attribute {
name: Span {
data: "hide-uri-scheme",
line: 2,
col: 2,
offset: 18,
},
value_source: None,
value: InterpretedValue::Set,
source: Span {
data: ":hide-uri-scheme:",
line: 2,
col: 1,
offset: 17,
},
},],
author_line: None,
revision_line: None,
comments: &[],
source: Span {
data: "= Document Title\n:hide-uri-scheme:",
line: 1,
col: 1,
offset: 0,
},
},
blocks: &[Block::Simple(SimpleBlock {
content: Content {
original: Span {
data: "https://asciidoctor.org",
line: 4,
col: 1,
offset: 36,
},
rendered: r#"<a href="https://asciidoctor.org" class="bare">asciidoctor.org</a>"#,
},
source: Span {
data: "https://asciidoctor.org",
line: 4,
col: 1,
offset: 36,
},
style: SimpleBlockStyle::Paragraph,
title_source: None,
title: None,
caption: None,
number: None,
anchor: None,
anchor_reftext: None,
attrlist: None,
},),],
source: Span {
data: "= Document Title\n:hide-uri-scheme:\n\nhttps://asciidoctor.org",
line: 1,
col: 1,
offset: 0,
},
warnings: &[],
source_map: SourceMap(&[]),
catalog: Catalog::default(),
}
);
}
}
non_normative!(
r#"
////
= URLs and Links
A Uniform Resource Link (URL) represents the location of a resource on the web.
Typical URLs contain a scheme, domain name, file name, and extension.
#move image#
//image::url.png[]
// tag::basic[]
AsciiDoc recognizes the following common schemes without the help of any markup.
[#schemes]
* http
* https
* ftp
* irc
* mailto
* \email@email.com
You can think of these schemas as implicit macro names (with the exception of a bare email address).
Since the URL in the example below begins with a protocol (in this case _https_ followed by a colon), the AsciiDoc processor will automatically turn it into a hyperlink.
We call this a URL macro.
[source]
----
include::example$url.adoc[tag=base-co]
----
<.> The trailing period will not get caught up in the link.
To prevent automatic linking of an URL, prepend it with a backslash (`\`).
[source]
----
Once launched, the site will be available at \https://example.org.
----
== Link text
To attach a URL to text, enclose the text in square brackets at the end of the URL, thus making it a URL macro.
[source]
----
include::example$url.adoc[tag=irc]
----
// end::basic[]
Additionally, you can format the link text.
[source]
----
include::example$url.adoc[tag=text]
----
.Rendered URLs
====
include::example$url.adoc[tag=base]
====
You may also want to append empty square brackets to force the URL to be parsed when it would not normally be recognized, such as if it's enclosed in double quotes:
[source]
----
Type "https://asciidoctor.org[]" into the location bar of your browser.
----
== The link macro
// tag::link[]
When a URL does not start with one of the <<schemes,common schemes>>, or the URL is not surrounded by word boundaries, you must use the `link` macro.
The `link` macro is a stronger version of a URI macro, which you can think of like an unconstrained macro.
The URL is preceded by `link:` and followed by square brackets.
The square brackets may include optional link text.
The URL is used for the text of the link if link text is not specified.
Attributes inside the square brackets are parsed automatically if an equal sign is found after a comma (e.g., `[link text,window=_blank]`).
.Anatomy of a link macro
[source]
----
link:url[optional link text, optional target attribute, optional role attribute]
----
Let's consider a case where we need to use the link macro (instead of just a URI macro) to expand a link when it's not adjacent to a word boundary (i.e., unconstrained).
[source]
----
include::example$url.adoc[tag=unconstrained]
----
====
include::example$url.adoc[tag=unconstrained]
====
If we didn't use the `link:` prefix in this case, the URL macro would not be detected by the parser.
// end::link[]
[#complex-urls]
.Troubleshooting Complex URLs
****
A URL may not display correctly when it contains characters such as underscores (`+_+`) or carets (`+^`).
include::partial$ts-url-format.adoc[tag=sb]
****
Next, we'll add a target and role to a link macro.
// tag::attr[]
[#link-macro-attributes]
=== Link macro attributes
AsciiDoc didn't used to recognize attributes in the link macro by default.
This is no longer the case.
The AsciiDoc processor automatically parses attributes in the link macro, but only under certain contains (introduced in Asciidoctor 1.5.7).
If the AsciiDoc processor detects an equal sign after the first comma, it must parse the attributes in the link macro.
For example, when attribute parsing is enabled, you can specify the name of the target window using the `window` attribute.
[source]
----
include::example$url.adoc[tag=linkattrs-h]
----
====
include::example$url.adoc[tag=linkattrs]
====
Since `_blank` is the most common window name, we've introduced shorthand for it.
Just end the link text with a caret (`+^+`):
[source]
----
include::example$url.adoc[tag=linkattrs-s]
----
CAUTION: If you use the caret syntax more than once in a single paragraph, you may need to escape the first occurrence with a backslash.
You can also add a role (i.e., CSS class) to the link using an attribute declaration (which implicitly enables attribute parsing).
[source]
----
include::example$url.adoc[tag=css]
----
====
include::example$url.adoc[tag=css]
====
TIP: Links with attributes (including the subject and body segments on mailto links) weren't always supported in AsciiDoc.
Now that they are, you must surround the link text in double quotes if it contains a comma.
// end::attr[]
////
"#
);