Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for seeing original, markup, and edited versions for HTML and PDF #5

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# Critic-markup Extension For Quarto

This extension provide a filter for processing [critic markup](https://github.com/CriticMarkup/CriticMarkup-toolkit) syntax when rendering to html. The rendered html provide a flexible interface with
This extension provide a filter for processing [critic markup](https://github.com/CriticMarkup/CriticMarkup-toolkit) syntax when rendering to html or pdf. The rendered html provide a flexible interface with

- The markup document with changes highlighted
- The original version
- The updated version with the changes applied


This extension was inspired by the critic markup processing for [ScholarlyMarkdown](http://scholarlymarkdown.com/) available under MIT license as well [ScholarlyMarkdown.git](https://github.com/slimgroup/ScholarlyMarkdown)
## Installing

Expand All @@ -33,4 +32,29 @@ filters:

Here is a minimal example showing the critic markup syntax and its rendering: [example.qmd](example.qmd).

This is the output of [example.qmd](https://mloubout.github.io/critic-markup/).
This is the output of [example.qmd](https://mloubout.github.io/critic-markup/).


## Multi-format example

Here is a minimal example showing the critic markup syntax and its rendering: [example-multiformat.qmd](example-multiformat.qmd).

## Usage

This filter reads the Quarto meta variable `critic-markup-version`. Valid values are `all` (default), `markup`, `edited` or `original`.

The default `all` shows all three version of the document.

- `markup` shows changes highlighted.
- `edited` shows the updated version of document with applied changes.
- `original` shows the original document.


## Supported formats

Formats other than html and pdf simply show the raw critic markup syntax.

Support for pdf relies on the following LaTeX packages (included in TinyTeX and therefore Quarto by default):

- [pdfcomment](https://ctan.org/pkg/pdfcomment)
- [draftwatermark](https://ctan.org/pkg/draftwatermark)
141 changes: 130 additions & 11 deletions _extensions/critic-markup/critic-markup.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,21 @@
local maybesubs = false
local stk_end = false

if FORMAT:match 'html' then
local valid_versions = {all=true, markup=true, edited=true, original=true}
local modifier = PANDOC_STATE.output_file:match("%+([^.]+)%..+$")
if modifier then
for s in modifier:gmatch("[^-]+") do
if valid_versions[s] then
CRITIC_VERSION_default = s
gbruer15 marked this conversation as resolved.
Show resolved Hide resolved
end
end
end

if not valid_versions[CRITIC_VERSION_default] then
CRITIC_VERSION_default = "all"
end

if quarto.doc.is_format('html') then
add = pandoc.RawInline('html', "<ins>")
adde = pandoc.RawInline('html', "</ins>")

Expand All @@ -15,7 +29,7 @@ if FORMAT:match 'html' then

comm = pandoc.RawInline('html', [[<span class="critic comment">]])
comme = pandoc.RawInline('html', "</span>")
elseif FORMAT:match 'latex' then
elseif quarto.doc.is_format('latex') then
add = pandoc.RawInline('latex', "\\criticmarkupadd{")
adde = pandoc.RawInline('latex', "}")

Expand All @@ -28,9 +42,17 @@ elseif FORMAT:match 'latex' then

comm = pandoc.RawInline('latex', "\\criticmarkupcomm{")
comme = pandoc.RawInline('latex', "}")
else
unsupported = true
adde = pandoc.Str("++}")
mloubout marked this conversation as resolved.
Show resolved Hide resolved
rm = pandoc.Str("{--")
end
if unsupported then
ruless = {}
else
ruless = {['{%+%+']=add, ['{\u{2013}']=rm, ['{==']=mark, ['{>>']=comm, ['{~~']=rm,
['%+%+}']=adde, ['\u{2013}}']=rme, ['==}']=marke, ['<<}']=comme, ['~~}']=rme, ['~>']=rmeadd}
end
ruless = {['{%+%+']=add, ['{\u{2013}']=rm, ['{==']=mark, ['{>>']=comm, ['{~~']=rm,
['%+%+}']=adde, ['\u{2013}}']=rme, ['==}']=marke, ['<<}']=comme, ['~~}']=rme, ['~>']=rmeadd}

-- Strikeout before/after
st_b = '{'
Expand Down Expand Up @@ -90,14 +112,15 @@ local scriptcode = [[
var e = document.getElementById("edited-button");
var m = document.getElementById("markup-button");

window.onload = critic();
window.addEventListener('load', critic)
o.onclick = original;
e.onclick = edited;
m.onclick = markup;
</script>
]]

local latexcode = [[
local latexcode = {}
latexcode.header = [[
\IfFileExists{pdfcomment.sty}
{
\usepackage{pdfcomment}
Expand All @@ -112,6 +135,57 @@ local latexcode = [[
\newcommand{\criticmarkupmark}[1]{\{=={##1}==\}}
\newcommand{\criticmarkupcomm}[1]{\{>{}>{##1}<{}<\}}
}
\IfFileExists{draftwatermark.sty}
{
\usepackage{draftwatermark}
\DraftwatermarkOptions{%
pos={5mm,5mm},
anchor=lt,
alignment=l,
fontsize=10mm,
angle=0
}
\DraftwatermarkOptions{text=Markup}
}

\newcounter{criticmarkupfirstpage}

]]

latexcode.edited = [[
\renewcommand{\criticmarkupadd}[1]{#1}
\renewcommand{\criticmarkuprm}[1]{}
\renewcommand{\criticmarkupmark}[1]{#1}
\renewcommand{\criticmarkupcomm}[1]{}
\IfFileExists{draftwatermark.sty}
{
\DraftwatermarkOptions{text=Edited}
}
]]

latexcode.original = [[
\renewcommand{\criticmarkupadd}[1]{}
\renewcommand{\criticmarkuprm}[1]{#1}
\renewcommand{\criticmarkupmark}[1]{#1}
\renewcommand{\criticmarkupcomm}[1]{}
\IfFileExists{draftwatermark.sty}
{
\DraftwatermarkOptions{text=Original}
}
]]

latexcode.reset = [[

\clearpage

]]

latexcode.newpage = [[

\maketitle

\setcounter{page}{\value{criticmarkupfirstpage}}

]]

function cirtiblock(blocks, k, v)
Expand Down Expand Up @@ -189,18 +263,63 @@ end


function criticheader (meta)
if FORMAT:match 'html' then
local version = meta["critic-markup-version"]
CRITIC_VERSION = version and pandoc.utils.stringify(version) or CRITIC_VERSION_default
if not valid_versions[CRITIC_VERSION] then
error("Invalid critic-markup-version: " .. CRITIC_VERSION)
end
if quarto.doc.is_format('html') then
quarto.doc.add_html_dependency({
name = 'critic',
scripts = {'critic.min.js'},
stylesheets = {'critic.css'}
})
-- inject the rendering code
quarto.doc.include_text("after-body", scriptcode)
else
quarto.doc.include_text("in-header", latexcode)
quarto.doc.include_text("in-header", scriptcode)
if CRITIC_VERSION == "all" then
return
end
-- inject the code selecting a specific version.
local activate = [[
<script>
document.getElementById("criticnav").style.display = "none";
window.addEventListener('load', CRITIC_VERSION)
</script>
]]
activate = activate:gsub("CRITIC_VERSION", CRITIC_VERSION)
quarto.doc.include_text("in-header", activate)
elseif quarto.doc.is_format('latex') then
quarto.doc.include_text("in-header", latexcode.header)
quarto.doc.include_text("before-body", "\\setcounter{criticmarkupfirstpage}{\\value{page}}")
end
end

if quarto.doc.is_format('latex') then
function Pandoc(doc)
local n = #doc.blocks

if CRITIC_VERSION == "all" then
-- Insert edited version of document.
local code = latexcode.reset .. latexcode.edited .. latexcode.newpage
table.insert(doc.blocks, pandoc.RawInline('latex', code))
for i = 0,n-1 do -- TODO: maybe this should be 1 to n.
table.insert(doc.blocks, doc.blocks[i])
end

-- Insert original version of document.
code = latexcode.reset .. latexcode.original .. latexcode.newpage
table.insert(doc.blocks, pandoc.RawInline('latex', code))
for i = 0,n-1 do
table.insert(doc.blocks, doc.blocks[i])
end
elseif CRITIC_VERSION == "edited" then
quarto.doc.include_text("in-header", latexcode.edited)
elseif CRITIC_VERSION == "original" then
quarto.doc.include_text("in-header", latexcode.original)
end
return doc
end
end

-- All pass with Meta first
return {{Meta = criticheader}, {Inlines = Inlines}, {Strikeout = Strikeout}, {Str = Str}}
return {{Meta = criticheader}, {Inlines = Inlines}, {Strikeout = Strikeout}, {Str = Str}, {Pandoc = Pandoc}}
2 changes: 1 addition & 1 deletion _extensions/critic-markup/critic.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.fullcontent {
#quarto-content {
padding-top: 30px !important;
}

Expand Down
65 changes: 65 additions & 0 deletions example-multiformat.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
title: "Critic-markdown multi-format example"
format:
html: default
html+markup:
output-file: example-multiformat+markup.html
html+edited:
output-file: example-multiformat+edited.html
html+original:
output-file: example-multiformat+original.html
pdf: default
pdf+markup: default
pdf+edited: default
pdf+original: default
filters:
- critic-markup
format-links:
- text: HTML
href: ./example-multiformat.html
- text: HTML+markup
href: ./example-multiformat+markup.html
- text: HTML+edited
href: ./example-multiformat+edited.html
- text: HTML+original
href: ./example-multiformat+original.html
- pdf
- format: pdf+edited
text: PDF+edited
- format: pdf+original
text: PDF+original
- format: pdf+markup
text: PDF+markup

---


## Critic Markdown

This filter adds processing of critic markdown syntax. Below are examples of usage.

## Highlighting

`{==Highlighted text==}` {==Highlighted text==}

`{== Highlighted text with a comment==}{>>First comment<<}` {== Highlighted text with a comment==}{>>First comment<<}

`{>>Single comment <<}` {>>Single comment <<}


## Addition

`{++This is added text++}` {++This is added text++}

`{++This is added text with some removed++}{-- removed--}` {++This is added text with some removed++}{-- removed--}


## Deletion

`{--This is removed text--}` {--This is removed text--}

`{--This is removed text with some added--}{++added ++}` {--This is removed text with some added--}{++added ++}

## Replacement

`{~~This is original text~> this is the replacement~~}` {~~This is original text~> this is the replacement~~}