Skip to content

Commit 40d54a6

Browse files
authored
Merge pull request #1127 from sphinx-contrib/always-register-section-anchors
translator: register section anchors for all editors
2 parents 9fa481e + 41e572d commit 40d54a6

File tree

5 files changed

+46
-30
lines changed

5 files changed

+46
-30
lines changed

sphinxcontrib/confluencebuilder/storage/translator.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -273,21 +273,22 @@ def visit_title(self, node):
273273
else:
274274
docname = self.docname
275275

276-
# For v2, will will generate section anchors inside the title
277-
# area for the following reasons:
276+
# Generate section anchors inside the title area for the following
277+
# reasons:
278278
# - We want to create inside the header inside if we input anchors
279279
# before the header, it increase the space above the anchor
280280
# due to how v2 styles a page.
281281
# - We are generating compatible anchor links (prefixed with the
282282
# repsective document name) which helps allow `ac:link` macros
283283
# properly link when coming from v1 or v2 editor pages.
284-
if self.v2 and 'names' in node.parent:
284+
# - Helps support anchor links for legacy editor on Confluence Cloud
285+
if 'names' in node.parent:
285286
for name in node.parent['names']:
286287
anchor = name.replace(' ', '-')
287288
target_name = f'{docname}/#{anchor}'
288289
target = self.state.target(target_name)
289290
if target and target not in new_targets:
290-
self._build_anchor(node, target)
291+
self._build_anchor(node, target, force_compat=True)
291292
new_targets.append(target)
292293

293294
# For MyST sections with an auto-generated slug, we will use this
@@ -3497,7 +3498,7 @@ def _build_id_anchors(self, node):
34973498
for id_ in node['ids']:
34983499
self._build_anchor(node, id_)
34993500

3500-
def _build_anchor(self, node, anchor):
3501+
def _build_anchor(self, node, anchor, *, force_compat=False):
35013502
"""
35023503
build an anchor on a page
35033504
@@ -3514,14 +3515,15 @@ def _build_anchor(self, node, anchor):
35143515
Args:
35153516
node: the node adding the anchor
35163517
anchor: the name of the anchor to create
3518+
force_compat (optional): always force compat anchor
35173519
"""
35183520

35193521
self.verbose(f'build anchor ({self.docname}): {anchor}')
35203522
self.body.append(self.start_ac_macro(node, 'anchor'))
35213523
self.body.append(self.build_ac_param(node, '', anchor))
35223524
self.body.append(self.end_ac_macro(node, suffix=''))
35233525

3524-
if self.v2:
3526+
if self.builder.cloud or self.v2 or force_compat:
35253527
doctitle = self.state.title(self.docname)
35263528
doctitle = self.encode(doctitle.replace(' ', ''))
35273529

tests/unit-tests/test_rst_contents.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ def test_storage_rst_contents_backlinks_none(self):
6060
self.assertEqual(len(headers), 5)
6161

6262
for header, expected in zip(headers, expected_header_text):
63-
self.assertEqual(header.text, expected)
63+
txt = ''.join(
64+
header.find_all(string=True, recursive=False)).strip()
65+
self.assertEqual(txt, expected)
6466

6567
@setup_builder('confluence')
6668
def test_storage_rst_contents_backlinks_top(self):

tests/unit-tests/test_rst_headings.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
from tests.lib.testcase import setup_builder
77

88

9+
def strval(obj):
10+
return ''.join(obj.find_all(string=True, recursive=False)).strip()
11+
12+
913
class TestConfluenceRstHeadings(ConfluenceTestCase):
1014
@classmethod
1115
def setUpClass(cls):
@@ -23,21 +27,21 @@ def test_storage_rst_headings_default(self):
2327

2428
header_lvl2 = data.find('h2')
2529
self.assertIsNotNone(header_lvl2)
26-
self.assertEqual(header_lvl2.text, 'header 2')
30+
self.assertEqual(strval(header_lvl2), 'header 2')
2731

2832
header_lvl3 = data.find_all('h3')
2933
self.assertIsNotNone(header_lvl3)
3034
self.assertEqual(len(header_lvl3), 2)
31-
self.assertEqual(header_lvl3[0].text, 'header 3')
32-
self.assertEqual(header_lvl3[1].text, 'header 12')
35+
self.assertEqual(strval(header_lvl3[0]), 'header 3')
36+
self.assertEqual(strval(header_lvl3[1]), 'header 12')
3337

3438
header_lvl4 = data.find('h4')
3539
self.assertIsNotNone(header_lvl4)
36-
self.assertEqual(header_lvl4.text, 'header 4')
40+
self.assertEqual(strval(header_lvl4), 'header 4')
3741

3842
header_lvl5 = data.find('h5')
3943
self.assertIsNotNone(header_lvl5)
40-
self.assertEqual(header_lvl5.text, 'header 5')
44+
self.assertEqual(strval(header_lvl5), 'header 5')
4145

4246
header_lvl6 = data.find_all('h6')
4347
self.assertIsNotNone(header_lvl6)
@@ -51,28 +55,29 @@ def test_storage_rst_headings_with_title(self):
5155
out_dir = self.build(self.dataset, config=config)
5256

5357
with parse('index', out_dir) as data:
54-
header_lvl1 = data.find('h1')
58+
header_lvl1 = data.find('h1', recursive=False)
59+
print(header_lvl1)
5560
self.assertIsNotNone(header_lvl1)
56-
self.assertEqual(header_lvl1.text, 'header 1')
61+
self.assertEqual(strval(header_lvl1), 'header 1')
5762

58-
header_lvl2 = data.find('h2')
63+
header_lvl2 = data.find('h2', recursive=False)
5964
self.assertIsNotNone(header_lvl2)
60-
self.assertEqual(header_lvl2.text, 'header 2')
65+
self.assertEqual(strval(header_lvl2), 'header 2')
6166

62-
header_lvl3 = data.find_all('h3')
67+
header_lvl3 = data.find_all('h3', recursive=False)
6368
self.assertIsNotNone(header_lvl3)
6469
self.assertEqual(len(header_lvl3), 2)
65-
self.assertEqual(header_lvl3[0].text, 'header 3')
66-
self.assertEqual(header_lvl3[1].text, 'header 12')
70+
self.assertEqual(strval(header_lvl3[0]), 'header 3')
71+
self.assertEqual(strval(header_lvl3[1]), 'header 12')
6772

68-
header_lvl4 = data.find('h4')
73+
header_lvl4 = data.find('h4', recursive=False)
6974
self.assertIsNotNone(header_lvl4)
70-
self.assertEqual(header_lvl4.text, 'header 4')
75+
self.assertEqual(strval(header_lvl4), 'header 4')
7176

72-
header_lvl5 = data.find('h5')
77+
header_lvl5 = data.find('h5', recursive=False)
7378
self.assertIsNotNone(header_lvl5)
74-
self.assertEqual(header_lvl5.text, 'header 5')
79+
self.assertEqual(strval(header_lvl5), 'header 5')
7580

76-
header_lvl6 = data.find_all('h6')
81+
header_lvl6 = data.find_all('h6', recursive=False)
7782
self.assertIsNotNone(header_lvl6)
7883
self.assertEqual(len(header_lvl6), 6)

tests/unit-tests/test_rst_references.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,8 @@ def test_storage_rst_references(self):
6565

6666
# anchors ##################################################
6767

68-
anchors = data.find_all('ac:structured-macro',
68+
anchor = data.find('ac:structured-macro',
6969
{'ac:name': 'anchor'})
70-
self.assertEqual(len(anchors), 1)
71-
72-
# (anchor 1)
73-
anchor = anchors.pop(0)
74-
7570
anchor_id = anchor.find('ac:parameter')
7671
self.assertIsNotNone(anchor_id)
7772
self.assertEqual(anchor_id.text, 'my-reference-label1')

tests/unit-tests/test_singlepage_toctree.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ def test_storage_singlepage_toctree_default(self):
1414
out_dir = self.build(dataset)
1515

1616
with parse('index', out_dir) as data:
17+
# ignore any anchor tags for these checks
18+
for tag in data.find_all(
19+
'ac:structured-macro', attrs={'ac:name': 'anchor'}):
20+
print(tag)
21+
tag.decompose()
22+
1723
tags = data.find_all()
1824
self.assertIsNotNone(tags)
1925
self.assertEqual(len(tags), 12)
@@ -76,6 +82,12 @@ def test_storage_singlepage_toctree_numbered(self):
7682
out_dir = self.build(dataset)
7783

7884
with parse('index', out_dir) as data:
85+
# ignore any anchor tags for these checks
86+
for tag in data.find_all(
87+
'ac:structured-macro', attrs={'ac:name': 'anchor'}):
88+
print(tag)
89+
tag.decompose()
90+
7991
tags = data.find_all()
8092
self.assertIsNotNone(tags)
8193
self.assertEqual(len(tags), 6)

0 commit comments

Comments
 (0)