Skip to content

Commit

Permalink
Merge pull request #502 from tobyhodges/add-spoiler-class
Browse files Browse the repository at this point in the history
Add spoiler class of fenced div
  • Loading branch information
zkamvar authored Aug 30, 2023
2 parents 6394079 + 8d8e181 commit 8b2ac2c
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 26 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: sandpaper
Title: Create and Curate Carpentries Lessons
Version: 0.12.5
Version: 0.13.0
Authors@R: c(
person(given = "Zhian N.",
family = "Kamvar",
Expand Down
9 changes: 8 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# sandpaper 0.12.5 (unreleased)
# sandpaper 0.13.0 (unreleased)

## NEW FEATURES

* The new `spoiler` class of fenced div will allow authors to specify an
expandable section of content that is collapsed by default. This replaces the
former paradigm of using "floating solution" blocks to present options for
installation on different platforms. (implemented: @tobyhodges, #502)

## BUG FIX

Expand Down
32 changes: 24 additions & 8 deletions inst/rmarkdown/lua/lesson.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ local blocks = {
["checklist"] = "check-square",
["solution"] = "none",
["hint"] = "none",
["spoiler"] = "eye",
["discussion"] = "message-circle",
["testimonial"] = "heart",
["keypoints"] = "key",
Expand All @@ -31,6 +32,7 @@ local block_counts = {
["checklist"] = 0,
["solution"] = 0,
["hint"] = 0,
["spoiler"] = 0,
["discussion"] = 0,
["testimonial"] = 0,
["keypoints"] = 0,
Expand Down Expand Up @@ -185,12 +187,18 @@ local button_headings = {
<h4 class="accordion-header" id="heading{{id}}">
{{title}}
</h4>]],
["spoiler"] = [[
<h3 class="accordion-header" id="heading{{id}}">
<div class="note-square"><i aria-hidden="true" class="callout-icon" data-feather="eye"></i></div>
{{title}}
</h3>]],
}

local accordion_titles = {
["instructor"] = "Instructor Note",
["hint"] = "Give me a hint",
["solution"] = "Show me the solution"
["solution"] = "Show me the solution",
["spoiler"] = "Show details"
}

local accordion_button = [[
Expand Down Expand Up @@ -250,7 +258,9 @@ accordion = function(el, class)
-- the whole package
local main_div = pandoc.Div({accordion_item})
local main_class = {"accordion", "instructor-note", "accordion-flush"}
if class ~= "instructor" then
if class == "spoiler" then
main_class[2] = "spoiler-accordion"
elseif class ~= "instructor" then
main_class[2] = "challenge-accordion"
end
main_div.identifier = div_id
Expand Down Expand Up @@ -288,12 +298,12 @@ end

challenge_block = function(el)
-- The challenge blocks no longer contain solutions nested inside. Instead,
-- the soltuions (and hints) are piled at the end of the block, so series of
-- the solutions (and hints) are piled at the end of the block, so series of
-- challenge/solutions need to be separated.

-- The challenge train is a list to contain all the divs
local challenge_train = pandoc.List:new()
-- If the challenge contains multipl solutions or hints, we need to indicate
-- If the challenge contains multiple solutions or hints, we need to indicate
-- that the following challenges/solutions are continuations.
local this_head = get_header(el, 3)
local next_head = this_head:clone()
Expand Down Expand Up @@ -357,16 +367,22 @@ handle_our_divs = function(el)

-- Accordion blocks:
--
-- Instructor Notes, Solutions, and Hints are all blocks that are contained in
-- accordion blocks. For historical reasons, solutions are normally embedded
-- in challenge blocks, but because of the way pandoc traverses the AST, we
-- need to process these FIRST and then handle their positioning in the
-- Instructor Notes, Solutions, Hints, and Spoilers are all blocks
-- that are contained in accordion blocks.
-- For historical reasons, solutions are normally embedded
-- in challenge blocks, but because of the way pandoc traverses the AST,
-- we need to process these FIRST and then handle their positioning in the
-- challenge block phase.
v,i = el.classes:find("instructor")
if i ~= nil then
return(accordion(el, "instructor"))
end

v,i = el.classes:find("spoiler")
if i ~= nil then
return(accordion(el, "spoiler"))
end

v,i = el.classes:find("solution")
if i ~= nil then
return(accordion(el, "solution"))
Expand Down
77 changes: 68 additions & 9 deletions tests/testthat/_snaps/render_html.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@
, Div
( "collapseSolution1"
, [ "accordion-collapse" , "collapse" ]
, [ ( "[solution collapse]" )
, ( "[solution collapse]" )
, [ ( "[Solution hidden]" )
, ( "[Solution hidden]" )
]
)
[ Div
Expand Down Expand Up @@ -202,8 +202,8 @@
, Div
( "collapseInstructor1"
, [ "accordion-collapse" , "collapse" ]
, [ ( "[instructor collapse]" )
, ( "[instructor collapse]" )
, [ ( "[Instructor hidden]" )
, ( "[Instructor hidden]" )
]
)
[ Div
Expand All @@ -221,6 +221,48 @@
]
]
]
, Div
( "accordionSpoiler1"
, [ "accordion" , "spoiler-accordion" , "accordion-flush" ]
, []
)
[ Div
( "" , [ "accordion-item" ] , [] )
[ RawBlock
(Format "html")
"<button class=\"accordion-button spoiler-button collapsed\" type=\"button\" data-bs-toggle=\"collapse\" data-bs-target=\"#collapseSpoiler1\" aria-expanded=\"false\" aria-controls=\"collapseSpoiler1\">\n <h3 class=\"accordion-header\" id=\"headingSpoiler1\">\n <div class=\"note-square\"><i aria-hidden=\"true\" class=\"callout-icon\" data-feather=\"eye\"></i></div>\n Show details\n </h3>\n</button>"
, Div
( "collapseSpoiler1"
, [ "accordion-collapse" , "collapse" ]
, [ ( "[Spoiler hidden]" )
, ( "[Spoiler hidden]" )
]
)
[ Div
( "" , [ "accordion-body" ] , [] )
[ Para
[ Str "That"
, Space
, Str "fin"
, Space
, Str "on"
, Space
, Str "the"
, Space
, Str "rear"
, Space
, Str "end"
, Space
, Str "of"
, Space
, Str "a"
, Space
, Str "car"
]
]
]
]
]
, Div
( "" , [ "nothing" ] , [] )
[ Para
Expand Down Expand Up @@ -364,8 +406,8 @@
Write now
</h4>
</button>
[solution collapse]
[solution collapse]
<div id="Solution-[hidden..."
...done]>
<div class="accordion-body">
<p>just write it, silly.</p>
</div>
Expand All @@ -381,15 +423,32 @@
Instructor Note
</h3>
</button>
[instructor collapse]
[instructor collapse]
[instructor collapse]
<div id="Instructor-[hidden..."
...still hiding...
...done]>
<div class="accordion-body">
<p>This should be aside</p>
</div>
</div>
</div>
</div>
<div id="accordionSpoiler1"
class="accordion spoiler-accordion accordion-flush">
<div class="accordion-item">
<button class="accordion-button spoiler-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSpoiler1" aria-expanded="false" aria-controls="collapseSpoiler1">
<h3 class="accordion-header" id="headingSpoiler1">
<div class="note-square"><i aria-hidden="true" class="callout-icon" data-feather="eye"></i></div>
Show details
</h3>
</button>
<div id="Spoiler-[hidden..."
...done]>
<div class="accordion-body">
<p>That fin on the rear end of a car</p>
</div>
</div>
</div>
</div>
<div class="nothing">
<p>This should be</p>
</div>
Expand Down
6 changes: 6 additions & 0 deletions tests/testthat/examples/ex.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ This should be aside

:::

::: spoiler

That fin on the rear end of a car

:::

::: nothing

This should be
Expand Down
16 changes: 9 additions & 7 deletions tests/testthat/test-render_html.R
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ test_that("pandoc structure is rendered correctly", {
}
skip_on_os("windows")
formation = function(x) {
x <- sub("(data-bs-parent|aria-labelledby).+?Instructor1", "[instructor collapse]", x)
sub("(data-bs-parent|aria-labelledby).+?Solution1", "[solution collapse]", x)
rgx <- "(data-bs-parent|aria-labelledby).+?(Instructor|Solution|Spoiler)1"
return(sub(rgx, "[\\2 hidden]", x))
}
expect_snapshot(cat(readLines(out), sep = "\n"), transform = formation)
})
Expand Down Expand Up @@ -147,11 +147,13 @@ test_that("render_html applies the internal lua filter", {
}
skip_on_os("windows")
formation = function(x) {
x <- sub("[<]div id[=]\"collapseSolution1\".+", "[solution collapse]", x)
x <- sub("[<]div id[=]\"collapseInstructor1\".+", "[instructor collapse]", x)
x <- sub("(data-bs-parent|aria-labelledby).+?Instructor1.+$", "[instructor collapse]", x)
sub("(data-bs-parent|aria-labelledby).+?Solution1.+$", "[solution collapse]", x)

open <- "[<]div id[=]\"collapse(Instructor|Solution|Spoiler)\\d\".+"
mid <- "(data-bs-parent|aria-labelledby).+?(Instructor|Solution|Spoiler)\\d[\"]$"
close <- "(data-bs-parent|aria-labelledby).+?(Instructor|Solution|Spoiler)\\d.+[>]$"
x <- sub(open, "<div id=\"\\1-[hidden...\"", x)
x <- sub(mid, "...still hiding...", x)
x <- sub(close, "...done]>", x)
return(x)
}
expect_snapshot(cat(res), transform = formation)
})
Expand Down

0 comments on commit 8b2ac2c

Please sign in to comment.