`);
+
$('.topics').prepend(tutorialTitle);
$('.bandContent.topicsListContainer').append(buildTopicsList());
@@ -443,7 +498,23 @@ $(document).ready(function() {
}
function handleResize() {
+ if (!$('header').hasClass('headroom')){
+ attachHeadroom();
+ }
$('.topicsList').css("max-height", window.innerHeight);
+ // When on a Mobile or width is mobile like, we want to hide the topicList
+ // and to pad the sections
+ if (isMobile() | window.innerWidth < 767) {
+ $('.topicsList').hide();
+ $(".section.level2").css("padding-top", $("header").height());
+ $("#tutorial-topic").css("padding-top", $("header").height());
+ } else {
+ $('.learnr-nav-items').removeClass('opened');
+ $(".section.level2").css("padding-top", "unset");
+ $("#tutorial-topic").css("padding-top", "unset");
+ $('.topicsList').show();
+ $(".section.level2").css("padding-top", 0)
+ }
}
handleResize();
@@ -468,12 +539,24 @@ $(document).ready(function() {
return topicIndex;
}
+ function setProgressBarFromHash(){
+ var next_topics = $(".btn.btn-primary.progress-mover");
+ var steps = range(0, 100, Math.round(100 / (next_topics.length + 1)));
+ var pct = steps[findTopicIndexFromHash()];
+ $("#progress_upper").css("width", pct + "%")
+ if (pct > parseInt(document.querySelector("#progress_middle").style.width)){
+ $("#progress_middle").css("width", pct + "%")
+ }
+ }
// select topic from hash on the url
- setCurrentTopic(findTopicIndexFromHash());
+ // Restore the progress bar css
+ setCurrentTopic(findTopicIndexFromHash());
+ setProgressBarFromHash()
// navigate to a topic when the history changes
window.addEventListener("popstate", function(e) {
setCurrentTopic(findTopicIndexFromHash());
+ setProgressBarFromHash()
});
}
@@ -619,6 +702,7 @@ $(document).ready(function() {
transformDOM();
handleLocationHash();
+ attachHeadroom();
// initialize components within tutorial.onInit event
tutorial.onInit(function() {
@@ -631,6 +715,61 @@ $(document).ready(function() {
sectionSkipped(progressEvent.element);
});
+ // We want the css to move 100/(next_topics.length + 1) %
+ // When clicking on each "Next Topic" button
+ var next_topics = $(".btn.btn-primary.progress-mover");
+ // We need to create a range of next_topics.length + 1, so that the
+ // first progression is not 0
+ var steps = range(0, 100, Math.round(100 / (next_topics.length + 1)));
+ var steps_not_shifted = range(0, 100, Math.round(100 / (next_topics.length + 1)));
+ steps.shift()
+ // adding a data-css-progress attribute to all
+ // we start at 1 cause we don't need the 0%
+ for( var i = 0; i < next_topics.length; i ++){
+ $(next_topics[i]).attr("data-css-progress", steps[i]);
+ $(next_topics[i]).click(function(e){updateCssUpper(e)});
+ }
+
+ // Same for topics on the left
+ var topic = $(".topic");
+ for( var i = 0; i < topic.length; i ++){
+ $(topic[i]).attr("data-css-progress", steps_not_shifted[i]);
+ $(topic[i]).click(function(e){updateCssUpper(e)});
+ }
+
+ // Add the css progress amount to previous Topic
+ var previous_topic = $(".previous-mover");
+ for( var i = 0; i < previous_topic.length; i ++){
+ $(previous_topic[i]).attr("data-css-progress", steps_not_shifted[i]);
+ $(previous_topic[i]).click(function(e){updateCssUpper(e)});
+ }
+
+ // Make the progress bar move on click on Continue button
+ // To do that, we need to compute steps between each `Next Topic` buttons
+ // In each section level2, Potential Continue buttons. We'll use Next and previous
+ // values to compute the range
+ var section_2 = $(".section.level2")
+
+ for( var i = 0; i < section_2.length; i ++){
+ let current = $(section_2[i]);
+ let continue_button = current.find(".btn.btn-default.progress-mover")
+ if (continue_button.length > 0){
+ // Get the lower range. If none, it's because it's the first topic, so we set it to 0
+ let lower_boundary = current.find(".previous-mover").attr("data-css-progress") || 0
+ // Get the upper range. If none, it's because it's the last topic, so we set it to 0
+ let upper_boundary = current.find(".btn.btn-primary.progress-mover").attr("data-css-progress") || 100
+ // build the steps
+ let steps = range(lower_boundary, upper_boundary, Math.round(upper_boundary - lower_boundary) / (continue_button.length + 1));
+ steps.shift()
+ for( var i = 0; i < next_topics.length; i ++){
+ $(continue_button[i]).attr("data-css-progress", steps[i]);
+ $(continue_button[i]).click(function(e){updateCssUpper(e)});
+ }
+ }
+ }
+
+
+
});
});
diff --git a/man/tutorial.Rd b/man/tutorial.Rd
index 824bec8af..9db0f4604 100644
--- a/man/tutorial.Rd
+++ b/man/tutorial.Rd
@@ -23,6 +23,7 @@ tutorial(
includes = NULL,
md_extensions = NULL,
pandoc_args = NULL,
+ with_headroom = FALSE,
...
)
}
@@ -95,6 +96,8 @@ additional details.}
\item{pandoc_args}{Additional command line options to pass to pandoc}
+\item{with_headroom}{Should the menu be dynamically hidden when the user scroll? Defaults to \code{FALSE}.}
+
\item{...}{Forward parameters to html_document}
}
\description{
diff --git a/sandbox/sandbox_with_headroom.Rmd b/sandbox/sandbox_with_headroom.Rmd
new file mode 100644
index 000000000..134468a34
--- /dev/null
+++ b/sandbox/sandbox_with_headroom.Rmd
@@ -0,0 +1,191 @@
+---
+title: "Tutorial"
+output:
+ learnr::tutorial:
+ progressive: true
+ allow_skip: true
+ with_headroom: true
+runtime: shiny_prerendered
+---
+
+
+
+```{r setup, include=FALSE}
+library(learnr)
+library(nycflights13)
+options(tutorial.event_recorder = learnr:::debug_event_recorder)
+tutorial_options(
+ exercise.eval = FALSE,
+ exercise.checker = function(label, user_code, envir_result, ...) {
+ if (is.null(envir_result))
+ list(message = "Bad code!",
+ correct = FALSE)
+ else
+ list(message = "Nice job!",
+ correct = TRUE,
+ location = "append")
+ }
+)
+```
+
+
+
+## intro
+
+This is the intro to the whole ball of wax.
+
+### flights
+
+```{r filter, exercise=TRUE}
+# filter the flights table to include only United and American flights
+flights
+```
+
+```{r filter-hint-1}
+filter(flights, ...)
+```
+
+```{r filter-hint-2}
+filter(flights, UniqueCarrier=="AA")
+```
+
+```{r filter-hint-3}
+filter(flights, UniqueCarrier=="AA" | UniqueCarrier=="UA")
+```
+
+### YouTube Video
+
+
+
+### Vimeo Video
+
+
+
+
+### in between
+
+In betwixt and in between.
+
+### solution {style="margin-top: 50px;"}
+
+```{r exercise1-setup}
+library(dplyr)
+nycflights <- nycflights13::flights
+```
+
+```{r exercise1, exercise=TRUE}
+# Change the filter to select February rather than January
+nycflights <- filter(nycflights, month == 1)
+```
+
+
+
+This is the hint for the exercise which I just provided.
+
+
+
+
+## Viewing Data
+
+Modify this code so that it prints only the first 5 rows of the `mtcars` dataset:
+
+```{r cars, exercise=TRUE, exercise.eval=TRUE, exercise.timelimit = 10}
+head(mtcars, n = 5)
+```
+
+
+```{r cars-solution}
+mtcars <- head(mtcars, n = 5)
+print(mtcars)
+mtcars <- head(mtcars, n = 5)
+print(mtcars)
+mtcars <- head(mtcars, n = 5)
+print(mtcars)
+```
+
+```{r cars-code-check}
+#
+```
+
+```{r cars-check}
+#
+```
+
+
+
+Modify this plot to use the `cyl` variable rather than the `wt` variable:
+
+```{r ggplot, exercise=TRUE, exercise.eval=TRUE, fig.width=8}
+library(ggplot2)
+qplot(mpg, cyl, data = mtcars)
+```
+
+```{r ggplot-check}
+mtcars <- head(mtcars, n = 5)
+mtcars
+```
+
+## dygraphs
+
+Add a range selector to the following dygraph:
+
+```{r dygraphs, exercise=TRUE}
+library(dygraphs)
+dygraph(ldeaths)
+```
+
+## quiz
+
+
+```{r letter-a, echo=FALSE}
+question("What number is the letter A in the English alphabet?", allow_retry = TRUE,
+ answer("8"),
+ answer("14"),
+ answer("1", correct = TRUE),
+ answer("23")
+)
+```
+
+
+```{r quiz1, echo=FALSE}
+quiz(
+ question("What number is the letter A in the *English* alphabet?",
+ answer("8"),
+ answer("14", message = "That's $x+ 1$ **insane!**"),
+ answer("1", correct = TRUE, message = "Good job!"),
+ answer("23")
+ ),
+ question("Where are you right now? (select ALL that apply)",
+ answer("Planet Earth", correct = TRUE),
+ answer("Pluto", message = "How could you think we are on Pluto?"),
+ answer("At a computing device", correct = TRUE),
+ answer("In the Milky Way", correct = TRUE),
+ incorrect = "Incorrect. You're on Earth, in the Milky Way, at a computer."
+ ),
+ question(sprintf("Suppose $x = %s$. Choose the correct statement:", 42),
+ answer(sprintf("$\\sqrt{x} = %d$", 42 + 1)),
+ answer(sprintf("$x ^ 2 = %d$", 42^2), correct = TRUE),
+ answer("$\\sin x = 1$")
+ )
+)
+```
+
+## diagnostics buglet
+
+```{r diagnostics-comma, exercise=TRUE}
+# a false 'unexpected comma' diagnostic was printed at the end of line 4 below
+GapMinderPlot(
+ LifeExpectency,
+ countries = c("Germany", "United States", "New Zealand", "China",
+ "India", "Japan"))
+GapMinderPlot(LifeExpectency)
+```
+
+## for in
+
+```{r diagnostics-for, exercise=TRUE}
+for (i in seq(1,5)){
+ x <- i
+ }
+```
+
diff --git a/sandbox/sandbox_with_headroom_gradethis.Rmd b/sandbox/sandbox_with_headroom_gradethis.Rmd
new file mode 100644
index 000000000..6a827f784
--- /dev/null
+++ b/sandbox/sandbox_with_headroom_gradethis.Rmd
@@ -0,0 +1,46 @@
+---
+title: "Tutorial"
+output:
+ learnr::tutorial:
+ progressive: true
+ allow_skip: true
+ with_headroom: true
+runtime: shiny_prerendered
+---
+
+
+
+```{r setup, include=FALSE}
+library(learnr)
+library(dplyr)
+#options(tutorial.event_recorder = learnr:::debug_event_recorder)
+gradethis::gradethis_setup()
+```
+
+
+
+## intro
+
+This is the intro to the whole ball of wax.
+
+### flights
+
+```{r mtcars2, exercise = TRUE}
+
+```
+
+```{r mtcars2-solution}
+mtcars
+```
+
+```{r mtcars2-hint}
+mt
+```
+
+
+```{r mtcars2-check }
+grade_result(
+ fail_if(~identical(.result, cars), "This is the cars (not mtcars) dataset."),
+ pass_if(~identical(.result, mtcars))
+)
+```