Skip to content

Commit 60d2b6a

Browse files
committed
Reconcile changes from main
1 parent 6568772 commit 60d2b6a

File tree

5 files changed

+114
-15
lines changed

5 files changed

+114
-15
lines changed

docs/syntax/dropdowns.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,39 @@ Dropdown content for ECE and ECH
102102
::::
103103

104104
:::::
105+
106+
## Anchors and deep linking
107+
108+
Dropdowns automatically generate anchors from their titles, allowing you to link directly to them. The anchor is created by converting the title to lowercase and replacing spaces with hyphens (slugify).
109+
110+
For example, a dropdown with title "Installation Guide" will have the anchor `#installation-guide`.
111+
112+
### Custom anchors
113+
114+
You can specify a custom anchor using the `:name:` option:
115+
116+
:::::{tab-set}
117+
118+
::::{tab-item} Output
119+
120+
:::{dropdown} My Dropdown
121+
:name: custom-anchor
122+
Content that can be linked to via #custom-anchor
123+
:::
124+
125+
::::
126+
127+
::::{tab-item} Markdown
128+
```markdown
129+
:::{dropdown} My Dropdown
130+
:name: custom-anchor
131+
Content that can be linked to via #custom-anchor
132+
:::
133+
```
134+
::::
135+
136+
:::::
137+
138+
### Duplicate anchors
139+
140+
If multiple elements (dropdowns or headings) in the same document have the same anchor, the build will emit a hint warning. While this doesn't fail the build, it may cause linking issues. Ensure each dropdown has a unique title or use the `:name:` option to specify unique anchors.

src/Elastic.Documentation.Site/Assets/open-details-with-anchor.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,12 @@ export function openDetailsWithAnchor() {
1212
if (closestDetails && !closestDetails.open) {
1313
// Only open if it's not already open by default
1414
if (!closestDetails.dataset.openDefault) {
15-
if (browser.name !== 'Chrome') {
1615
closestDetails.open = true
1716
}
1817
}
1918

2019
// Chrome automatically ensures parent content is visible, scroll immediately
2120
// Other browsers need manual scroll handling
22-
const browser = getBrowser()
2321
if (browser.name !== 'Chrome') {
2422
target.scrollIntoView({
2523
behavior: 'instant',

tests/Elastic.Markdown.Tests/Directives/AdmonitionTests.cs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ A regular paragraph.
124124
public void SetsDropdownOpen() => Block!.DropdownOpen.Should().BeTrue();
125125

126126
[Fact]
127-
public void SetsName() => Block!.Name.Should().Be("test-dropdown");
127+
public void SetsCrossReferenceName() => Block!.CrossReferenceName.Should().Be("test-dropdown");
128128
}
129129

130130
public class DropdownAppliesToTests(ITestOutputHelper output) : DirectiveTest<AdmonitionBlock>(output,
@@ -144,6 +144,60 @@ A regular paragraph.
144144
public void SetsCustomTitle() => Block!.Title.Should().Be("This is my custom dropdown");
145145

146146
[Fact]
147-
public void SetsAppliesTo() => Block!.AppliesTo.Should().Be("stack: ga 9.0");
147+
public void SetsAppliesToDefinition() => Block!.AppliesToDefinition.Should().Be("stack: ga 9.0");
148+
149+
[Fact]
150+
public void ParsesAppliesTo() => Block!.AppliesTo.Should().NotBeNull();
151+
}
152+
153+
public class DuplicateDropdownAnchorTests(ITestOutputHelper output) : DirectiveTest(output,
154+
"""
155+
:::{dropdown} Same title
156+
First dropdown content
157+
:::
158+
159+
:::{dropdown} Same title
160+
Second dropdown content
161+
:::
162+
""")
163+
{
164+
[Fact]
165+
public void ReportsHintForDuplicateAnchors()
166+
{
167+
Collector.Diagnostics.Should().Contain(m =>
168+
m.Severity == Severity.Hint &&
169+
m.Message.Contains("Duplicate anchor") &&
170+
m.Message.Contains("'same-title'"));
171+
172+
// Should report hint for both duplicate dropdowns
173+
Collector.Diagnostics.Where(m =>
174+
m.Severity == Severity.Hint &&
175+
m.Message.Contains("Duplicate anchor") &&
176+
m.Message.Contains("'same-title'")).Should().HaveCount(2);
177+
}
178+
}
179+
180+
public class DuplicateDropdownAndHeadingAnchorTests(ITestOutputHelper output) : DirectiveTest(output,
181+
"""
182+
## Test Heading
183+
184+
:::{dropdown} Test Heading
185+
Dropdown content with same anchor as heading
186+
:::
187+
""")
188+
{
189+
[Fact]
190+
public void ReportsHintForDuplicateAnchorsAcrossTypes()
191+
{
192+
Collector.Diagnostics.Should().Contain(m =>
193+
m.Severity == Severity.Hint &&
194+
m.Message.Contains("Duplicate anchor") &&
195+
m.Message.Contains("'test-heading'"));
196+
197+
// Should report hint for both the heading and dropdown
198+
Collector.Diagnostics.Where(m =>
199+
m.Severity == Severity.Hint &&
200+
m.Message.Contains("Duplicate anchor") &&
201+
m.Message.Contains("'test-heading'")).Should().HaveCount(2);
148202
}
149203
}

tests/authoring/Framework/MarkdownDocumentAssertions.fs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ module MarkdownDocumentAssertions =
3434
match matter with
3535
| NonNull m ->
3636
match expectedAvailability with
37-
| NonNull a -> m.AppliesTo.Diagnostics <- a.Diagnostics
37+
| NonNull a ->
38+
match m.AppliesTo with
39+
| NonNull appliesTo -> appliesTo.Diagnostics <- a.Diagnostics
40+
| _ -> ()
3841
| _ -> ()
39-
42+
4043
let apply = m.AppliesTo
4144
test <@ apply = expectedAvailability @>
4245
| _ -> failwithf $"%s{result.File.RelativePath} has no yamlfront matter"

tests/authoring/FrontMatter/ProductsFrontMatter.fs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,17 @@ This is a test page without products frontmatter.
6868
let defaultFile = results.MarkdownResults |> Seq.find (fun r -> r.File.RelativePath = "index.md")
6969

7070
// Test that the file has the correct products
71-
test <@ defaultFile.File.YamlFrontMatter <> null @>
72-
test <@ defaultFile.File.YamlFrontMatter.Products <> null @>
73-
test <@ defaultFile.File.YamlFrontMatter.Products.Count = 2 @>
74-
75-
// Test that the products are correctly identified
76-
let productIds = defaultFile.File.YamlFrontMatter.Products |> Seq.map (fun p -> p.Id) |> Set.ofSeq
77-
test <@ productIds.Contains("elasticsearch") @>
78-
test <@ productIds.Contains("ecctl") @>
71+
match defaultFile.File.YamlFrontMatter with
72+
| NonNull fm ->
73+
match fm.Products with
74+
| NonNull products ->
75+
test <@ products.Count = 2 @>
76+
// Test that the products are correctly identified
77+
let productIds = products |> Seq.map (fun p -> p.Id) |> Set.ofSeq
78+
test <@ productIds.Contains("elasticsearch") @>
79+
test <@ productIds.Contains("ecctl") @>
80+
| _ -> failwith "Products should not be null"
81+
| _ -> failwith "YamlFrontMatter should not be null"
7982

8083
[<Fact>]
8184
let ``does not include products in frontmatter when no products are specified`` () =
@@ -84,4 +87,9 @@ This is a test page without products frontmatter.
8487
let defaultFile = results.MarkdownResults |> Seq.find (fun r -> r.File.RelativePath = "index.md")
8588

8689
// Test that the file has no products
87-
test <@ defaultFile.File.YamlFrontMatter = null || defaultFile.File.YamlFrontMatter.Products = null || defaultFile.File.YamlFrontMatter.Products.Count = 0 @>
90+
match defaultFile.File.YamlFrontMatter with
91+
| NonNull fm ->
92+
match fm.Products with
93+
| NonNull products -> test <@ products.Count = 0 @>
94+
| _ -> () // null is acceptable
95+
| _ -> () // null is acceptable

0 commit comments

Comments
 (0)