Skip to content

Commit

Permalink
2310 fixes #33
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin van Rongen authored and Martin van Rongen committed Oct 23, 2024
1 parent 298b33b commit 77f7bab
Show file tree
Hide file tree
Showing 65 changed files with 405 additions and 24,057 deletions.
10 changes: 0 additions & 10 deletions _extensions/cambiotraining/courseformat/_extension 2.yml

This file was deleted.

10 changes: 0 additions & 10 deletions _extensions/cambiotraining/courseformat/_extension 3.yml

This file was deleted.

12 changes: 0 additions & 12 deletions _extensions/cambiotraining/courseformat/_extension 4.yml

This file was deleted.

7 changes: 5 additions & 2 deletions _extensions/cambiotraining/courseformat/_extension.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
title: Course Page Format
author: Cambridge Informatics Training
version: 1.0.5
version: 1.2.1
contributes:
formats:
html:
Expand All @@ -11,4 +11,7 @@ contributes:
code-link: true
code-copy: true
shortcodes:
- star_levels.lua
- star_levels.lua
- citation_cff.lua
filters:
- callout_exercise.lua
129 changes: 129 additions & 0 deletions _extensions/cambiotraining/courseformat/callout_exercise.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
local number_exercises = true
local hide_answers = false
local exercises = {} -- Table to store exercise IDs and titles
local exercise_counter = 0 -- Global counter for exercises
local seen_ids = {} -- Table to track seen IDs and check for duplicates

-- function to throw a yellow warning
function warn(message)
local yellow = "\27[33m"
local reset = "\27[0m"
io.stderr:write(yellow .. "WARN: " .. message .. reset .. "\n")
end

-- Meta function to read yml metadata
function Meta(meta)
if meta["exercises"] and meta["exercises"]["number"] == true then
number_exercises = true
end

if meta["exercises"] and meta["exercises"]["hide-answers"] == true then
hide_answers = true
end
end

-- Div function to process exercises and answers
function Div(div)
-- Process callout-exercise divs
if div.classes:includes("callout-exercise") then
exercise_counter = exercise_counter + 1
local exercise_number = "Exercise " .. exercise_counter -- Always generate the number

-- Store exercise ID and title if it has an ID starting with "ex-"
if div.identifier and div.identifier:match("^ex%-") then
-- Check for duplicate IDs
if seen_ids[div.identifier] then
warn("Duplicate exercise ID found: #" .. div.identifier)
end

seen_ids[div.identifier] = true
exercises[div.identifier] = exercise_number
end

-- Process the header within the exercise
if div.content[1] ~= nil and div.content[1].t == "Header" then
local title = pandoc.utils.stringify(div.content[1])
div.content:remove(1) -- Remove the original header from content
local final_title = number_exercises and exercise_number .. " - " .. title or title
return quarto.Callout({
type = "exercise",
content = { div },
title = final_title,
icon = false,
collapse = false
})
else
-- If no header, use just the exercise number (if numbering is on)
local final_title = number_exercises and exercise_number or nil
return quarto.Callout({
type = "exercise",
content = { div },
title = final_title,
icon = false,
collapse = false
})
end
end

-- Process callout-answer divs
if div.classes:includes("callout-answer") then
if (hide_answers and div.attributes["hide"] ~= "false") or div.attributes["hide"] == "true" then
return pandoc.RawBlock('html', '<div hidden></div>')
else
return quarto.Callout({
type = "answer",
content = { div },
title = "Answer",
icon = false,
collapse = true
})
end
end

-- Process callout-hint divs
if div.classes:includes("callout-hint") then
return quarto.Callout({
type = "hint",
content = { div },
title = "Hint",
icon = false,
collapse = true
})
end
end

-- Replace cross-references in Pandoc elements
function Pandoc(doc)
-- Walk through the document and replace any Str element that matches @ex-*
local function replace_xref(elem)
if elem.t == "Str" and elem.text:match("^@ex%-") then
local id = elem.text:sub(2) -- Remove the "@" prefix
local exercise_title = exercises[id]
if exercise_title then
-- Return the custom HTML link
local link_html = string.format(
'<a href="#%s"><u>%s</u></a>',
id,
exercise_title
)
return pandoc.RawInline('html', link_html)
else
-- If the ID is not found, throw a warning
warn("Undefined exercise cross-reference: @" .. id)
end
end
return elem
end

-- Apply the replacement to all inline elements
return doc:walk({
Str = replace_xref
})
end

-- Return the filter
return {
{ Meta = Meta },
{ Div = Div },
{ Pandoc = Pandoc }
}
159 changes: 159 additions & 0 deletions _extensions/cambiotraining/courseformat/citation_cff.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
-- Function to parse the CFF file
function parse_cff(file_path)
-- Initialize tables to store extracted information
local data = {
title = "",
year = "",
month = "",
url = "",
authors = {}
}

-- Function to trim whitespace from the beginning and end of a string
local function trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end

-- Read the YAML content from the file
local file = io.open(file_path, "r")
local yaml_content = file:read("*all")
file:close()

-- Parse the YAML content line by line
local current_author = nil
local in_authors_section = false
for line in yaml_content:gmatch("[^\r\n]+") do
line = trim(line)

-- Detect the start of the authors section
if line:match("^authors:") then
in_authors_section = true
end

-- Parse the title
if line:match("^title:") then
data.title = trim(line:gsub("title:", ""))
end

-- Parse the URL
if line:match("^url:") then
data.url = trim(line:gsub("url:", ""):gsub("'", ""))
end

-- Parse the release date and extract year and month
if line:match("^date%-released:") then
local date = trim(line:gsub("date%-released:", ""):gsub("'", ""))
data.year, data.month = date:match("(%d%d%d%d)%-(%d%d)")
end

-- Start processing authors once in the authors section
if in_authors_section then
-- Detect a new author block by a line starting with "-"
if line:match("^%- ") then
-- Add the previous author to the authors list if it's not nil
if current_author then
table.insert(data.authors, current_author)
end
-- Start a new author
current_author = {}
end

-- Populate author fields
if line:match("given%-names:") then
current_author["given-names"] = trim(line:gsub("%-?%s*given%-names:", ""):gsub("'", ""))
elseif line:match("family%-names:") then
current_author["family-names"] = trim(line:gsub("%-?%s*family%-names:", ""):gsub("'", ""))
elseif line:match("affiliation:") then
current_author["affiliation"] = trim(line:gsub("%-?%s*affiliation:", ""):gsub("'", ""))
elseif line:match("website:") then
current_author["website"] = trim(line:gsub("%-?%s*website:", ""):gsub("'", ""))
elseif line:match("orcid:") then
current_author["orcid"] = trim(line:gsub("%-?%s*orcid:", ""):gsub("'", ""))
elseif line:match("alias:") then
current_author["alias"] = trim(line:gsub("%-?%s*alias:", ""):gsub("'", ""))
end
end
end

-- Add the last author if it exists
if current_author then
table.insert(data.authors, current_author)
end

-- Return the extracted data
return data
end

return {
["citation"] = function(args, kwargs)
-- Read the CFF file into a table
local cff_data = parse_cff("CITATION.cff")

-- Extract relevant data from the parsed CFF
local title = cff_data.title
local year = cff_data.year
local month = cff_data.month
local url = cff_data.url
local authors = cff_data.authors

-- Generate APA-style author list
local apa_authors = {}
for _, author in ipairs(authors) do
local name = author["family-names"] .. ", " .. string.sub(author["given-names"], 1, 1) .. "."
table.insert(apa_authors, name)
end
local apa_author_str = table.concat(apa_authors, ", ")

-- Generate APA citation
local apa_citation = apa_author_str .. " (" .. year .. "). " .. title .. ". " .. url

-- Generate BibTeX citation
local bibtex_authors = {}
for _, author in ipairs(authors) do
local name = author["family-names"] .. ", " .. author["given-names"]
table.insert(bibtex_authors, name)
end
local bibtex_author_str = table.concat(bibtex_authors, " and ")

local bibtex_citation = string.format([[
@misc{YourReferenceHere,
author = {%s},
month = {%d},
title = {%s},
url = {%s},
year = {%s}
}]], bibtex_author_str, tonumber(month), title, url, year)

-- Generate the author information HTML
local author_info = "<ul>"
for _, author in ipairs(authors) do
local name = author["given-names"] .. " " .. author["family-names"]
local orcid_icon = author.orcid and '<a href="' .. author.orcid .. '" target="_blank"><i class="fa-brands fa-orcid" style="color:#a6ce39"></i></a>' or ""
local email_icon = author.website and '<a href="' .. author.website .. '" target="_blank"><i class="fa-solid fa-envelope" style="color:#003E74"></i></a>' or ""
local affiliation = author.affiliation and '<em>Affiliation</em>: ' .. author.affiliation .. '<br>' or ""
local roles = author.alias and '<em>Roles</em>: ' .. author.alias or ""

author_info = author_info .. string.format([[
<li><strong>%s</strong> %s %s<br>
%s %s
</li>
]], name, orcid_icon, email_icon, affiliation, roles)
end
author_info = author_info .. "</ul>"

-- Generate the final output in HTML format
local output = [[
<p>You can cite these materials as:</p>
<blockquote>
<p>]] .. apa_citation .. [[</p>
</blockquote>
<p>Or in BibTeX format:</p>
<pre class="sourceCode bibtex"><code class="sourceCode bibtex">]] .. bibtex_citation .. [[</code></pre>
<p><strong>About the authors:</strong></p>
]] .. author_info .. [[
]]

-- Return the output as raw HTML
return pandoc.RawBlock("html", output)
end
}
36 changes: 0 additions & 36 deletions _extensions/cambiotraining/courseformat/footer 2.html

This file was deleted.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 77f7bab

Please sign in to comment.