Skip to contents

The url_prefix and remote_dir arguments are only needed if your question includes images. See move_images for details on how these parameters work.

Usage

wiseflow_export_items(
  items,
  ignore_images = FALSE,
  default_shuffle = TRUE,
  add_question_number = FALSE,
  url_prefix = NULL,
  remote_dir = NULL,
  abstain = NULL,
  penalty = NULL
)

Arguments

items

Named list of items: : items[["item title"]][[i]] is the .Rmd file name for question i in a given item.

ignore_images

Set this to TRUE to not copy generated or local images to a web server. Any such images will appear broken on import, and you must manually replace them.

default_shuffle

Whether to set shuffle=TRUE for questions if the setting is not stated. Default TRUE. Note that WISEflow and Canvas both default to FALSE.

add_question_number

Whether to prepend "Question 1" etc to each question (WISEflow does not offer a global numbering).

url_prefix

URL to root path on server, e.g. https://example.org/~user/doc.

remote_dir

Optional scp destination path, e.g. user@server.example.org:~/public_html/doc.

abstain

Text for an optional extra option (!) like "I wish to leave this question unanswered" for multiple-choice questions. This is useful because WISEflow offers to way to bring a multiple-choice question back to an unanswered state. abstain=TRUE is a shortcut for abstain="I wish to leave this question unanswered".

penalty

penalty=TRUE is a synonym for abstain=TRUE. If both abstain and penalty are given, abstain takes precedence.

Value

Nested list which can be passed to jsonlite::write_json(..., auto_unbox = TRUE) to produce a valid WISEflow import file.

Details

The JSON format had to be reverse engineered, constructing R lists corresponding to exports from WISEflow. This is an error-prone task, but at least the Data API error codes are documented by Learnosity.

Maybe also the Data API's list of Item Bank Endpoints could be useful.

Examples

# EXPORTING ITEMS

items <- rlang::list2(
  "A simple multiple choice question" = rlang::list2(
    system.file("multiple_choice_question.Rmd", package = "examiner", mustWork = TRUE),
  ),
  "A multiple choice question with all the bells and whistles" = rlang::list2(
    system.file("xhtml-features.Rmd", package = "examiner", mustWork = TRUE),
    system.file("multiple_choice_question_random.Rmd", package = "examiner", mustWork = TRUE),
  ),
)
items |>
  wiseflow_export_items()
#> C:/r-library/examiner/multiple_choice_question.Rmd
#> C:/r-library/examiner/xhtml-features.Rmd
#> C:/r-library/examiner/multiple_choice_question_random.Rmd
#> $data
#> $data[[1]]
#> $data[[1]]$title
#> [1] "A simple multiple choice question"
#> 
#> $data[[1]]$status
#> [1] "published"
#> 
#> $data[[1]]$definition
#> $data[[1]]$definition$template
#> [1] "dynamic"
#> 
#> $data[[1]]$definition$widgets
#> $data[[1]]$definition$widgets[[1]]
#> $data[[1]]$definition$widgets[[1]]$reference
#> [1] "b7d10976-7bd4-41ca-b600-8cd66cd38849"
#> 
#> $data[[1]]$definition$widgets[[1]]$widget_type
#> [1] "response"
#> 
#> 
#> 
#> 
#> $data[[1]]$questions
#> $data[[1]]$questions[[1]]
#> $data[[1]]$questions[[1]]$data
#> $data[[1]]$questions[[1]]$data$stimulus
#> [1] "<p>This is a <strong>Multiple Choice</strong> question (multiple_choice_question).</p>\n<p>What is the colour of blood?</p>"
#> 
#> $data[[1]]$questions[[1]]$data$validation
#> $data[[1]]$questions[[1]]$data$validation$valid_response
#> $data[[1]]$questions[[1]]$data$validation$valid_response$value
#> $data[[1]]$questions[[1]]$data$validation$valid_response$value[[1]]
#> [1] "0"
#> 
#> 
#> $data[[1]]$questions[[1]]$data$validation$valid_response$score
#> [1] 1
#> 
#> 
#> $data[[1]]$questions[[1]]$data$validation$scoring_type
#> [1] "exactMatch"
#> 
#> 
#> $data[[1]]$questions[[1]]$data$metadata
#> $data[[1]]$questions[[1]]$data$metadata$distractor_rationale_response_level
#> $data[[1]]$questions[[1]]$data$metadata$distractor_rationale_response_level[[1]]
#> NULL
#> 
#> $data[[1]]$questions[[1]]$data$metadata$distractor_rationale_response_level[[2]]
#> NULL
#> 
#> $data[[1]]$questions[[1]]$data$metadata$distractor_rationale_response_level[[3]]
#> NULL
#> 
#> 
#> 
#> $data[[1]]$questions[[1]]$data$shuffle_options
#> [1] TRUE
#> 
#> $data[[1]]$questions[[1]]$data$options
#> $data[[1]]$questions[[1]]$data$options[[1]]
#> $data[[1]]$questions[[1]]$data$options[[1]]$label
#> [1] "<div>Red</div>"
#> 
#> $data[[1]]$questions[[1]]$data$options[[1]]$value
#> [1] "0"
#> 
#> 
#> $data[[1]]$questions[[1]]$data$options[[2]]
#> $data[[1]]$questions[[1]]$data$options[[2]]$label
#> [1] "<div>White</div>"
#> 
#> $data[[1]]$questions[[1]]$data$options[[2]]$value
#> [1] "1"
#> 
#> 
#> $data[[1]]$questions[[1]]$data$options[[3]]
#> $data[[1]]$questions[[1]]$data$options[[3]]$label
#> [1] "<div>Blue</div>"
#> 
#> $data[[1]]$questions[[1]]$data$options[[3]]$value
#> [1] "2"
#> 
#> 
#> 
#> $data[[1]]$questions[[1]]$data$type
#> [1] "mcq"
#> 
#> $data[[1]]$questions[[1]]$data$ui_style
#> $data[[1]]$questions[[1]]$data$ui_style$choice_label
#> [1] "upper-alpha"
#> 
#> $data[[1]]$questions[[1]]$data$ui_style$type
#> [1] "horizontal"
#> 
#> 
#> 
#> $data[[1]]$questions[[1]]$widget_type
#> [1] "response"
#> 
#> $data[[1]]$questions[[1]]$reference
#> [1] "b7d10976-7bd4-41ca-b600-8cd66cd38849"
#> 
#> $data[[1]]$questions[[1]]$type
#> [1] "mcq"
#> 
#> $data[[1]]$questions[[1]]$metadata
#> $data[[1]]$questions[[1]]$metadata$name
#> [1] "Multiple responses"
#> 
#> 
#> 
#> 
#> 
#> $data[[2]]
#> $data[[2]]$title
#> [1] "A multiple choice question with all the bells and whistles"
#> 
#> $data[[2]]$status
#> [1] "published"
#> 
#> $data[[2]]$definition
#> $data[[2]]$definition$template
#> [1] "dynamic"
#> 
#> $data[[2]]$definition$widgets
#> $data[[2]]$definition$widgets[[1]]
#> $data[[2]]$definition$widgets[[1]]$reference
#> [1] "8ced45a2-51bd-4536-b5fc-cd139033da4e"
#> 
#> $data[[2]]$definition$widgets[[1]]$widget_type
#> [1] "response"
#> 
#> 
#> $data[[2]]$definition$widgets[[2]]
#> $data[[2]]$definition$widgets[[2]]$reference
#> [1] "441db8bb-e010-4124-9de9-ef4080b81350"
#> 
#> $data[[2]]$definition$widgets[[2]]$widget_type
#> [1] "response"
#> 
#> 
#> 
#> 
#> $data[[2]]$questions
#> $data[[2]]$questions[[1]]
#> $data[[2]]$questions[[1]]$data
#> $data[[2]]$questions[[1]]$data$stimulus
#> [1] "<hr/><p>This question checks whether library(examiner) works with Wiseflow for the <a href=\"http://www.imsglobal.org/question/qtiv2p2/QTIv2p2-ASI-InformationModelv1p0/imsqtiv2p2_asi_v1p0_InfoModelv1p0.html#XHTML\">xhtml elements supported by QTI</a>.</p>\n<p><strong>Math:</strong></p>\n<p>Inline <span class=\"math inline\">\\(\\pi r^2\\)</span> math.</p>\n<p>Typeset math:</p>\n<p><span class=\"math display\">\\[\n\\sqrt{\\frac{x}{y}}\n\\]</span></p>\n<p><strong>Text elements:</strong></p>\n<p><abbr title=\"Abbreviation\">abbr</abbr> should show \"Abbreviation\" as a tooltip on hover.</p>\n<p><code>acronym</code> is also supported, but has been superseded by <code>abbr</code>.</p>\n<blockquote>\n<p>This is an HTML <code>blockquote</code> with lots of lots of lots of lots of lots of lots of lots of lots of lots of lots of lots of lots of lots of lots of lots of lots of lots of text that spans multiple lines.</p>\n<a href=\"https://www.w3schools.com/tags/tag_blockquote.asp\">According to xhtml specs</a>, it needs to contain <em>block-level</em> elements.\n</blockquote>\n<blockquote>\nIn Wiseflow, a blockqoute with just a text node without a paragraph tag displays normally.\n</blockquote>\n<blockquote>\n<p>This is a Markdown blockquote.</p>\n</blockquote>\n<p>The <code>br</code><br/>element adds a newline.\nOr you can do it<br/>\nwith two trailing spaces at the end of a markdown line.</p>\n<div id=\"to-be-tested\" class=\"section level3\">\n<h3>To be tested</h3>\n<p>Cite tag: <cite>The Scream</cite> by Edward Munch. Painted in 1893.</p>\n<p>Code tags generated in <code>HTML</code> and by <code>single backticks</code> in markdown.</p>\n<p><dfn>dfn</dfn> is the html tag for a definition.</p>\n<div style=\"color: red;\">\nThis is a division made by a div tag. However, it's not much use when we can't customize CSS within Wiseflow.\n</div>\n<p>Italics using an <em>em</em> tag or <em>markdown</em>.</p>\n</div>\n</div>\n<div id=\"heading-levels\" class=\"section level1\">\n<h1>Heading levels</h1>\n<p>The \"Questions\" heading in Wiseflow is H2, as is the \"Quiz instructions\" heading in Canvas, so we probably want to stick to H3 and below.</p>\n</div>\n<div id=\"h1\" class=\"section level1\">\n<h1>H1</h1>\n<div id=\"h2\" class=\"section level2\">\n<h2>H2</h2>\n<div id=\"h3\" class=\"section level3\">\n<h3>H3</h3>\n<div id=\"h4\" class=\"section level4\">\n<h4>H4</h4>\n<div id=\"h5\" class=\"section level5\">\n<h5>H5</h5>\n<div id=\"h6\" class=\"section level6\">\n<h6>H6</h6>\n<p><kbd>Keyboard input</kbd> using a <code>kbd</code> tag.</p>\n<p>\nA paragraph using a <code>p</code> tag.\n</p>\n<p>A paragraph using markdown, i.e. normal text with a blank line above and below.</p>\n<pre>Preformatted text using a `pre` tag.</pre>\n<pre><code>Preformatted text using markdown, indenting with four spaces.</code></pre>\n<p><q>Inspirational quote using a <code>q</code> tag.</q></p>\n<p><samp>The samp tag is intended for output from a computer program</samp></p>\n<p>The <span style=\"color: red;\">span tag</span> lets us apply CSS with the <code>style</code> attribute.\nWe can get a span tag in Markdown using <span id=\"test\" class=\"test\" style=\"color: darkgreen;\">square braces followed by curly braces with ID, classes or styling</span>.</p>\n<p>Bold text using a <strong>strong</strong> tag or <strong>markdown</strong>.</p>\n<p>The <var>var</var> tag indicates a variable.</p>\n<hr/><p><strong>List elements:</strong></p>\n<dl><dt>\ndl\n</dt>\n<dd>\nDefinition list tag.\n</dd>\n<dt>\ndt\n</dt>\n<dd>\nDefinition term tag.\n</dd>\n<dt>\ndd\n</dt>\n<dd>\nDefinition definition (uh...) tag.\n</dd>\n</dl><p>Markdown is good for building li, ol and ul tags:</p>\n<ul><li>Unnumbered</li>\n<li>List</li>\n</ul><ol style=\"list-style-type: decimal\"><li>Numbered</li>\n<li>List</li>\n</ol><p><strong>Presentation elements:</strong></p>\n<p><b>b</b> is superseded by <strong>strong</strong> and is easier done with <strong>markdown</strong>.</p>\n<p><big>big</big> is not supported in html5 nor in Wiseflow.</p>\n<p>A hr tag must be on its own line, or it will swallow the beginning of the line:</p>\n<hr/><p>hr using markdown:</p>\n<hr/><p><i>i</i> is superseded by <em>em</em> but easier done with <em>markdown</em>.</p>\n<p><small>small</small> is supported in html.</p>\n<p>Both<sub>subscripts</sub> and<sup>superscripts</sup> work.</p>\n<p><tt>Teletype text</tt> is not supported in html5 nor in Wiseflow.</p>\n<p><strong>Table elements:</strong></p>\n<p><a href=\"https://www.w3schools.com/html/html_tables.asp\">Example</a> using html:</p>\n<table><tr><th>\nFirstname\n</th>\n<th>\nLastname\n</th>\n<th>\nAge\n</th>\n</tr><tr><td>\nJill\n</td>\n<td>\nSmith\n</td>\n<td>\n50\n</td>\n</tr><tr><td>\nEve\n</td>\n<td>\nJackson\n</td>\n<td>\n94\n</td>\n</tr></table><p>Example using markdown generated by <code>knitr::kable(iris[1:2,3:5])</code>.</p>\n<table><thead><tr class=\"header\"><th align=\"right\">Petal.Length</th>\n<th align=\"right\">Petal.Width</th>\n<th align=\"left\">Species</th>\n</tr></thead><tbody><tr class=\"odd\"><td align=\"right\">1.4</td>\n<td align=\"right\">0.2</td>\n<td align=\"left\">setosa</td>\n</tr><tr class=\"even\"><td align=\"right\">1.4</td>\n<td align=\"right\">0.2</td>\n<td align=\"left\">setosa</td>\n</tr></tbody></table><p><strong>Image elements:</strong></p>\n<p><strong>Since spring 2024, WISEflow no longer accepts images in data URIs.</strong>\nInstead, <code>examiner</code> must upload images to a web server, as described in the Configuration section of the <a href=\"https://arken.nmbu.no/~jonvi/examiner/examiner.html\">Get started</a> guide.</p>\n<p>Image tag using html:\n<img src=\"https://www.w3schools.com/images/colorpicker.gif\" alt=\"\"/></p>\n<p>Image tag using markdown:\n<img src=\"https://www.w3schools.com/images/colorpicker.gif\" alt=\"Colour picker\"/></p>\n<p>Image from R code:</p>\n<pre class=\"r\"><code>oldpar &lt;- par(mar = rep(0, 4))\nplot(sin(seq(-pi, pi, length.out = 257)), xlab = \"\", ylab = \"\")\npar(oldpar)</code></pre>\n<p><img src=\"https://nmbu.test.instructure.com/courses/6074/files/2416767/preview\" width=\"192\"/></p>\n<p>Animated gif from R using <a href=\"https://github.com/thomasp85/gganimate\">gganimate</a>.\n(Depends on <code>library(gifski)</code>.)</p>\n<p>Here we save the gif to file, then embed it.\nThis <a href=\"https://stackoverflow.com/a/54849281\">avoids noisy progress messages</a> when knitting in an interactive session.</p>\n<p>I suspect a bug in gganimate 1.0.9:\nWhen knitting, we need to include <code>units = \"px\"</code> when specifying pixel dimensions.\nFor some reason, it defaults to <code>in</code> (inches) when knitting or using <code>rmarkdown::render()</code>, but works fine when running the chunk in RStudio.</p>\n<pre class=\"r\"><code>library(ggplot2)\nlibrary(gganimate)\no &lt;- ggplot(mtcars, aes(factor(cyl), mpg)) + \n  geom_boxplot() + \n  # Here comes the gganimate code\n  transition_states(\n    gear,\n    transition_length = 2,\n    state_length = 1\n  ) +\n  enter_fade() + \n  exit_shrink() +\n  ease_aes('sine-in-out')\n# For some reason, saving the animation does not work under devtools::check()\nif (!nzchar(Sys.getenv(\"_R_CHECK_TIMINGS_\")))\n  anim_save(\"animation.gif\", o, nframes = 15, fps = 5, width = 400, height = 300, units = \"px\")</code></pre>\n<p><img src=\"https://nmbu.test.instructure.com/courses/6074/files/2416768/preview\"/><!-- --></p>\n<p><strong>Hypertext element:</strong></p>\n<p>Anchor tag using <a href=\"https://wikipedia.org\" alt=\"\">html</a> or <a href=\"https://wikipedia.org\">markdown</a>.</p>\n<p><strong>HTML5 elements:</strong></p>\n<p>(Not yet tested.)</p>\n<p>'article', 'aside' and 'audio';\n'bdi';\n'figcaption', 'figure' and 'footer';\n'header';\n'label';\n'nav';\n'rb', 'rp', 'rt', 'rtc' and 'ruby';\n'section' and 'source';\n'track';</p>\n<hr/><p>This was...</p>\n</div>\n</div>\n</div>\n</div>\n</div>"
#> 
#> $data[[2]]$questions[[1]]$data$is_math
#> [1] TRUE
#> 
#> $data[[2]]$questions[[1]]$data$validation
#> $data[[2]]$questions[[1]]$data$validation$valid_response
#> $data[[2]]$questions[[1]]$data$validation$valid_response$value
#> $data[[2]]$questions[[1]]$data$validation$valid_response$value[[1]]
#> [1] "1"
#> 
#> 
#> $data[[2]]$questions[[1]]$data$validation$valid_response$score
#> [1] 1
#> 
#> 
#> $data[[2]]$questions[[1]]$data$validation$scoring_type
#> [1] "exactMatch"
#> 
#> 
#> $data[[2]]$questions[[1]]$data$metadata
#> $data[[2]]$questions[[1]]$data$metadata$distractor_rationale_response_level
#> $data[[2]]$questions[[1]]$data$metadata$distractor_rationale_response_level[[1]]
#> NULL
#> 
#> $data[[2]]$questions[[1]]$data$metadata$distractor_rationale_response_level[[2]]
#> NULL
#> 
#> 
#> 
#> $data[[2]]$questions[[1]]$data$shuffle_options
#> [1] TRUE
#> 
#> $data[[2]]$questions[[1]]$data$options
#> $data[[2]]$questions[[1]]$data$options[[1]]
#> $data[[2]]$questions[[1]]$data$options[[1]]$label
#> [1] "<div>Fast, reliable and a joy to use.</div>"
#> 
#> $data[[2]]$questions[[1]]$data$options[[1]]$value
#> [1] "0"
#> 
#> 
#> $data[[2]]$questions[[1]]$data$options[[2]]
#> $data[[2]]$questions[[1]]$data$options[[2]]$label
#> [1] "<div>Not as easy as authoring the questions within WISEflow itself.</div>"
#> 
#> $data[[2]]$questions[[1]]$data$options[[2]]$value
#> [1] "1"
#> 
#> 
#> 
#> $data[[2]]$questions[[1]]$data$type
#> [1] "mcq"
#> 
#> $data[[2]]$questions[[1]]$data$ui_style
#> $data[[2]]$questions[[1]]$data$ui_style$choice_label
#> [1] "upper-alpha"
#> 
#> $data[[2]]$questions[[1]]$data$ui_style$type
#> [1] "horizontal"
#> 
#> 
#> 
#> $data[[2]]$questions[[1]]$widget_type
#> [1] "response"
#> 
#> $data[[2]]$questions[[1]]$reference
#> [1] "8ced45a2-51bd-4536-b5fc-cd139033da4e"
#> 
#> $data[[2]]$questions[[1]]$type
#> [1] "mcq"
#> 
#> $data[[2]]$questions[[1]]$metadata
#> $data[[2]]$questions[[1]]$metadata$name
#> [1] "Multiple responses"
#> 
#> 
#> 
#> $data[[2]]$questions[[2]]
#> $data[[2]]$questions[[2]]$data
#> $data[[2]]$questions[[2]]$data$stimulus
#> [1] "<p>This question is randomized and could be used to create a question bank.</p>\n<p>What is 45 × 23?</p>"
#> 
#> $data[[2]]$questions[[2]]$data$validation
#> $data[[2]]$questions[[2]]$data$validation$valid_response
#> $data[[2]]$questions[[2]]$data$validation$valid_response$value
#> $data[[2]]$questions[[2]]$data$validation$valid_response$value[[1]]
#> [1] "0"
#> 
#> 
#> $data[[2]]$questions[[2]]$data$validation$valid_response$score
#> [1] 1
#> 
#> 
#> $data[[2]]$questions[[2]]$data$validation$scoring_type
#> [1] "exactMatch"
#> 
#> 
#> $data[[2]]$questions[[2]]$data$metadata
#> $data[[2]]$questions[[2]]$data$metadata$distractor_rationale_response_level
#> $data[[2]]$questions[[2]]$data$metadata$distractor_rationale_response_level[[1]]
#> NULL
#> 
#> $data[[2]]$questions[[2]]$data$metadata$distractor_rationale_response_level[[2]]
#> NULL
#> 
#> $data[[2]]$questions[[2]]$data$metadata$distractor_rationale_response_level[[3]]
#> NULL
#> 
#> 
#> 
#> $data[[2]]$questions[[2]]$data$shuffle_options
#> [1] TRUE
#> 
#> $data[[2]]$questions[[2]]$data$options
#> $data[[2]]$questions[[2]]$data$options[[1]]
#> $data[[2]]$questions[[2]]$data$options[[1]]$label
#> [1] "<div>1035</div>"
#> 
#> $data[[2]]$questions[[2]]$data$options[[1]]$value
#> [1] "0"
#> 
#> 
#> $data[[2]]$questions[[2]]$data$options[[2]]
#> $data[[2]]$questions[[2]]$data$options[[2]]$label
#> [1] "<div>68</div>"
#> 
#> $data[[2]]$questions[[2]]$data$options[[2]]$value
#> [1] "1"
#> 
#> 
#> $data[[2]]$questions[[2]]$data$options[[3]]
#> $data[[2]]$questions[[2]]$data$options[[3]]$label
#> [1] "<div>22</div>"
#> 
#> $data[[2]]$questions[[2]]$data$options[[3]]$value
#> [1] "2"
#> 
#> 
#> 
#> $data[[2]]$questions[[2]]$data$type
#> [1] "mcq"
#> 
#> $data[[2]]$questions[[2]]$data$ui_style
#> $data[[2]]$questions[[2]]$data$ui_style$choice_label
#> [1] "upper-alpha"
#> 
#> $data[[2]]$questions[[2]]$data$ui_style$type
#> [1] "horizontal"
#> 
#> 
#> 
#> $data[[2]]$questions[[2]]$widget_type
#> [1] "response"
#> 
#> $data[[2]]$questions[[2]]$reference
#> [1] "441db8bb-e010-4124-9de9-ef4080b81350"
#> 
#> $data[[2]]$questions[[2]]$type
#> [1] "mcq"
#> 
#> $data[[2]]$questions[[2]]$metadata
#> $data[[2]]$questions[[2]]$metadata$name
#> [1] "Multiple responses"
#> 
#> 
#> 
#> 
#> 
#> 
#> $metadata
#> $metadata$author_version
#> [1] "4.2.0"
#> 
#> $metadata$date_created
#> [1] 1742552876
#> 
#> $metadata$created_by
#> [1] "library(examiner)"
#> 
#> $metadata$content
#> [1] "item"
#> 
#>