diff --git a/NEWS.md b/NEWS.md index 96961d20b..33fda6962 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,14 @@ # sandpaper 0.11.18 (unreleased) +## BUG FIX + +* Callout block anchor links now point to the correct ID of the block derived + from the title of the block (as opposed to the generic ID). + (reported: @debpaul, + https://github.com/datacarpentry/OpenRefine-ecology-lesson/issues/292 and + @bencomp, #454; fixed: @zkamvar, #467) + + ## MISC * The internal function `sandpaper:::render_html()` now explicitly sets the diff --git a/R/utils-xml.R b/R/utils-xml.R index f8be4d5ce..b9a50072f 100644 --- a/R/utils-xml.R +++ b/R/utils-xml.R @@ -88,8 +88,22 @@ fix_callouts <- function(nodes = NULL) { h3 <- xml2::xml_find_all(callouts, "./div/h3") xml2::xml_set_attr(h3, "class", "callout-title") inner_div <- xml2::xml_parent(h3) + # remove the "section level3 callout-title" attrs xml2::xml_set_attr(inner_div, "class", "callout-inner") - add_anchors(h3, xml2::xml_attr(callouts, "id")) + # Get the heading IDS (because we use section headings, the IDs are anchored + # to the section div and not the heading element) + #
+ #

Heading for this callout

+ #
+ ids <- xml2::xml_attr(inner_div, "id") + # get the callout ID in the cases where they are missing + replacements <- xml2::xml_attr(callouts, "id") + ids <- ifelse(is.na(ids), replacements, ids) + # add the anchors and then set the attributes in the correct places. + add_anchors(h3, ids) + xml2::xml_set_attr(h3, "id", NULL) + # we replace the callout ID with the correct ID + xml2::xml_set_attr(callouts, "id", ids) invisible(nodes) } diff --git a/inst/rmarkdown/lua/lesson.lua b/inst/rmarkdown/lua/lesson.lua index 2e226f333..68b47c3f3 100644 --- a/inst/rmarkdown/lua/lesson.lua +++ b/inst/rmarkdown/lua/lesson.lua @@ -9,7 +9,6 @@ function Set (list) return set end - local blocks = { ["callout"] = "bell", ["objectives"] = "none", @@ -265,10 +264,12 @@ callout_block = function(el) if this_icon == nil then return el end + -- Get the header and create the ID + local header = get_header(el, 3) + block_counts[classes[1]] = block_counts[classes[1]] + 1 callout_id = classes[1]..block_counts[classes[1]] classes:insert(1, "callout") - local header = get_header(el, 3) local icon = pandoc.RawBlock("html", "") diff --git a/tests/testthat/examples/callout-ids.html b/tests/testthat/examples/callout-ids.html new file mode 100644 index 000000000..063f8a3d1 --- /dev/null +++ b/tests/testthat/examples/callout-ids.html @@ -0,0 +1,31 @@ + + + +
+

Markdown

+

Here is an example of a callout block

+
+
+ +
+
+

Challenge

+
+

How do you write markdown divs?

+
+
+
+
+
+
+ +
+
+

Wait what?

+
+

preeeee

+
+
+
+ + diff --git a/tests/testthat/test-utils-xml.R b/tests/testthat/test-utils-xml.R index 30e8d60b1..03450beb6 100644 --- a/tests/testthat/test-utils-xml.R +++ b/tests/testthat/test-utils-xml.R @@ -24,6 +24,27 @@ test_that("paths in instructor view that are nested or not HTML get diverted", { }) +test_that("callout ids are processed correctly", { + html_test <- xml2::read_html(test_path("examples/callout-ids.html")) + fix_callouts(html_test) + anchors <- xml2::xml_find_all(html_test, ".//a") + headings <- xml2::xml_find_all(html_test, ".//h3") + callouts <- xml2::xml_find_all(html_test, + ".//div[starts-with(@class, 'callout ')]") + expect_length(anchors, 2) + expect_length(callouts, 2) + expect_length(headings, 2) + # headings should not have IDS + expect_equal(xml2::xml_has_attr(headings, "id"), c(FALSE, FALSE)) + # callouts should have these IDS + expect_equal(xml2::xml_has_attr(callouts, "id"), c(TRUE, TRUE)) + # The IDs should be what we expect + ids <- xml2::xml_attr(callouts, "id") + expect_equal(ids, c("discussion1", "wait-what")) + # The IDs should match the anchors + expect_equal(paste0("#", ids), xml2::xml_attr(anchors, "href")) +}) + test_that("empty args result in nothing happening", { expect_null(fix_nodes())