From b99155b6f9dd1aa044ed685ab6d447b738382cff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jens=20Preu=C3=9Fner?= <jens.preussner@mpi-bn.mpg.de>
Date: Fri, 3 May 2019 16:20:42 +0200
Subject: [PATCH] Components extension: Sidebar and layout templates

---
 .gitignore                             |  1 +
 DESCRIPTION                            |  3 +-
 R/assemble.R                           | 59 ++++++++++++++++++--------
 R/components.R                         | 13 ++++--
 R/i2dashboard.R                        |  2 +-
 R/pages.R                              |  4 +-
 inst/templates/i2dash-global-setup.Rmd |  3 +-
 inst/templates/layout_2x2_grid.Rmd     | 19 +++++++++
 inst/templates/layout_default.Rmd      | 10 +++++
 inst/templates/layout_focal_left.Rmd   | 17 ++++++++
 inst/templates/layout_storyboard.Rmd   |  6 +++
 inst/templates/page_template.Rmd       |  5 ---
 inst/templates/sidebar_template.Rmd    |  4 ++
 man/dot-render_page.Rd                 | 26 ++++++++++++
 man/idashboard-class.Rd                |  4 +-
 man/render_features_by_factors.Rd      | 21 ---------
 man/render_multiplot.Rd                | 23 ----------
 man/render_sequence_saturation.Rd      | 23 ----------
 18 files changed, 143 insertions(+), 100 deletions(-)
 create mode 100644 inst/templates/layout_2x2_grid.Rmd
 create mode 100644 inst/templates/layout_default.Rmd
 create mode 100644 inst/templates/layout_focal_left.Rmd
 create mode 100644 inst/templates/layout_storyboard.Rmd
 delete mode 100644 inst/templates/page_template.Rmd
 create mode 100644 inst/templates/sidebar_template.Rmd
 create mode 100644 man/dot-render_page.Rd
 delete mode 100644 man/render_features_by_factors.Rd
 delete mode 100644 man/render_multiplot.Rd
 delete mode 100644 man/render_sequence_saturation.Rd

diff --git a/.gitignore b/.gitignore
index ee0c663..c5b3e02 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 .RData
 .Ruserdata
 .DS_store
+*.html
diff --git a/DESCRIPTION b/DESCRIPTION
index 3fd2d48..f6533a1 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -15,4 +15,5 @@ RoxygenNote: 6.1.1
 Imports: 
     knitr,
     flexdashboard,
-    yaml
+    yaml,
+    assertive.sets
diff --git a/R/assemble.R b/R/assemble.R
index 473ea66..1bf0b20 100644
--- a/R/assemble.R
+++ b/R/assemble.R
@@ -29,13 +29,13 @@ setMethod("assemble", "i2dashboard", function(object, output_file, pages, ...) {
   cat(header_string,
       file = tmp_document,
       append = FALSE,
-      sep='')
+      sep="")
 
   # Add i2dash global setup
   cat(readLines(system.file("templates", "i2dash-global-setup.Rmd", package = "i2dash")),
       file = tmp_document,
-      append = T,
-      sep = "")
+      append = TRUE,
+      sep = "\n")
 
   # write page to tempfile
   for (pagename in pages){
@@ -48,20 +48,9 @@ setMethod("assemble", "i2dashboard", function(object, output_file, pages, ...) {
       title <- object@pages[[name]]$title
       menu <- object@pages[[name]]$menu
       layout <- object@pages[[name]]$layout
-      # Check menu argument
-      if (is.null(menu)){
-        menu <- ""
-      }
-      # Check layout argument
-      if (any(layout == "storyboard")){
-        layout <- ".storyboard"
-      } else {
-        if(!is.null(layout)) warning("layout argument is not known.")
-        layout <- ""
-      }
-      layout_with_menu <- sprintf('{%s data-navmenu="%s"}', layout, menu)
-      timestamp <- Sys.time()
-      full_content <- knitr::knit_expand(file = system.file("templates", "page_template.Rmd", package = "i2dash"), title = title, layout_with_menu = layout_with_menu, components = components, date = timestamp)
+      sidebar <- object@pages[[name]]$sidebar
+
+      full_content <- .render_page(title = title, components = components, layout = layout,  menu = menu, sidebar = sidebar)
       cat(full_content, file = tmp_document, append = TRUE, sep='')
     } else {
       warning(sprintf("i2dashboard object does not contain a page named '%s'", pagename))
@@ -69,4 +58,38 @@ setMethod("assemble", "i2dashboard", function(object, output_file, pages, ...) {
   }
   # copy tempfile to final_document
   file.copy(from = tmp_document, to = final_document, overwrite = TRUE)
-})
\ No newline at end of file
+
+  invisible(object)
+})
+
+
+#' Method for rendering a page with a given layout and components
+#'
+#' @param title The page title.
+#' @param components A list of page components.
+#' @param layout The pages overall layout.
+#' @param menu The menu under which the page will be filed.
+#' @param sidebar Character string with sidebar content.
+#'
+#' @return A markdown string with the final page.
+.render_page <- function(title, components, layout = c("default", "storyboard", "focal_left", "2x2_grid"), menu = NULL, sidebar = NULL) {
+  if(!is.null(sidebar)) {
+    sidebar <- knitr::knit_expand(file = system.file("templates", "sidebar_template.Rmd", package = "i2dash"),
+                                  content = sidebar)
+  }
+
+  template <- switch(layout,
+                     "default" = system.file("templates", "layout_default.Rmd", package = "i2dash"),
+                     "storyboard" = system.file("templates", "layout_storyboard.Rmd", package = "i2dash"),
+                     "focal_left" = system.file("templates", "layout_focal_left.Rmd", package = "i2dash"),
+                     "2x2_grid" = system.file("templates", "layout_2x2_grid.Rmd", package = "i2dash"))
+
+  knitr::knit_expand(file = template,
+                     delim = c("<%", "%>"),
+                     title = title,
+                     menu = menu,
+                     layout = layout,
+                     sidebar = sidebar,
+                     components = components,
+                     date = Sys.time())
+}
\ No newline at end of file
diff --git a/R/components.R b/R/components.R
index 28079f6..eb6e4a3 100644
--- a/R/components.R
+++ b/R/components.R
@@ -23,13 +23,20 @@ setMethod("add_component", "i2dashboard", function(object, page = "default", com
 
   pn <- strsplit(component, "::")[[1]]
   eval_function <- if(length(pn) == 1) {
-    get(paste0("render_", pn[[1]]), envir = asNamespace("i2dash"), mode = "function")
+    get(pn[[1]], envir = asNamespace("i2dash"), mode = "function")
   } else {
-    get(paste0("render_", pn[[2]]), envir = asNamespace(pn[[1]]), mode = "function")
+    get(pn[[2]], envir = asNamespace(pn[[1]]), mode = "function")
   }
 
   component <- do.call(eval_function, args = list(object, ...))
-  object@pages[[name]]$components <- append(object@pages[[name]]$components, component)
 
+  if(is.list(component)) {
+    assertive.sets::is_subset(c("appendix", "component", "sidebar"), names(component))
+    object@pages[[name]]$components <- append(object@pages[[name]]$components, component$component)
+    object@pages[[name]]$sidebar <- paste0(object@pages[[name]]$sidebar, component$sidebar)
+    # ToDo: Handle appendix
+  } else {
+    object@pages[[name]]$components <- append(object@pages[[name]]$components, component)
+  }
   return(object)
 })
diff --git a/R/i2dashboard.R b/R/i2dashboard.R
index ec866f8..4c9812a 100644
--- a/R/i2dashboard.R
+++ b/R/i2dashboard.R
@@ -22,7 +22,7 @@ setClass("i2dashboard",
     interactive = FALSE,
     theme = "yeti",
     workdir = getwd(),
-    pages = list(default = list(title = "Default page", layout = "default", menu = NULL, components = list(), max_components = Inf))
+    pages = list(default = list(title = "Default page", layout = "default", menu = NULL, components = list(), sidebar = NULL, max_components = Inf))
     )
   )
 
diff --git a/R/pages.R b/R/pages.R
index 2be433e..9ecb5ac 100644
--- a/R/pages.R
+++ b/R/pages.R
@@ -21,7 +21,7 @@ setGeneric("add_page", function(object, ...) standardGeneric("add_page"))
 #'
 #' @rdname idashboard-class
 #' @export
-setMethod("add_page", "i2dashboard", function(object, page, title, layout = "storyboard", menu = NULL, ...) {
+setMethod("add_page", "i2dashboard", function(object, page, title, layout = "default", menu = NULL, sidebar = NULL, ...) {
   name <- .create_page_name(page)
 
   max_components <- switch(layout,
@@ -42,7 +42,7 @@ setMethod("add_page", "i2dashboard", function(object, page, title, layout = "sto
     }
   }
 
-  object@pages[[name]] <- list(title = title, layout = layout, menu = menu, components = list(), max_components = max_components)
+  object@pages[[name]] <- list(title = title, layout = layout, menu = menu, components = list(), max_components = max_components, sidebar = sidebar)
   return(object)
 })
 
diff --git a/inst/templates/i2dash-global-setup.Rmd b/inst/templates/i2dash-global-setup.Rmd
index 0b02ae5..119b919 100644
--- a/inst/templates/i2dash-global-setup.Rmd
+++ b/inst/templates/i2dash-global-setup.Rmd
@@ -6,4 +6,5 @@ if (any(grepl(pattern = ".switchr", x = .libPaths()))) {
 
 # Make it possible to reuse chunk labels
 options(knitr.duplicate.label = "allow")
-```
\ No newline at end of file
+```
+
diff --git a/inst/templates/layout_2x2_grid.Rmd b/inst/templates/layout_2x2_grid.Rmd
new file mode 100644
index 0000000..8c84537
--- /dev/null
+++ b/inst/templates/layout_2x2_grid.Rmd
@@ -0,0 +1,19 @@
+<% title %> {data-navmenu="<% menu %>"}
+====================================================
+
+<!-- Page created on <% date %> -->
+<% if(!is.null(sidebar)) sidebar %>
+
+Column
+-------------------------------------
+    
+<% if(length(components) > 0) components[[1]] %>
+ 
+<% if(length(components) > 2) components[[3]] %>
+
+Column
+-------------------------------------
+    
+<% if(length(components) > 1) components[[2]] %>
+    
+<% if(length(components) > 3) components[[4]] %>
diff --git a/inst/templates/layout_default.Rmd b/inst/templates/layout_default.Rmd
new file mode 100644
index 0000000..89ee17b
--- /dev/null
+++ b/inst/templates/layout_default.Rmd
@@ -0,0 +1,10 @@
+<% title %> {data-navmenu="<% menu %>"}
+====================================================
+
+<!-- Page created on <% date %> -->
+<% if(!is.null(sidebar)) sidebar %>
+
+Column
+----------------------------------------------------
+
+<% components %>
\ No newline at end of file
diff --git a/inst/templates/layout_focal_left.Rmd b/inst/templates/layout_focal_left.Rmd
new file mode 100644
index 0000000..360fb26
--- /dev/null
+++ b/inst/templates/layout_focal_left.Rmd
@@ -0,0 +1,17 @@
+<% title %> {data-navmenu="<% menu %>"}
+====================================================
+
+<!-- Page created on <% date %> -->
+<% if(!is.null(sidebar)) sidebar %>
+
+Column {data-width=600}
+-------------------------------------
+    
+<% if(length(components) > 0) components[[1]] %>
+   
+Column {data-width=400}
+-------------------------------------
+   
+<% if(length(components) > 1) components[[2]] %>
+
+<% if(length(components) > 2) components[[3]] %>
\ No newline at end of file
diff --git a/inst/templates/layout_storyboard.Rmd b/inst/templates/layout_storyboard.Rmd
new file mode 100644
index 0000000..3a050ac
--- /dev/null
+++ b/inst/templates/layout_storyboard.Rmd
@@ -0,0 +1,6 @@
+<% title %> {.storyboard data-navmenu="<% menu %>"}
+====================================================
+
+<!-- Page created on <% date %> -->
+
+<% components %>
diff --git a/inst/templates/page_template.Rmd b/inst/templates/page_template.Rmd
deleted file mode 100644
index 76e6339..0000000
--- a/inst/templates/page_template.Rmd
+++ /dev/null
@@ -1,5 +0,0 @@
-{{ title }} {{ layout_with_menu }}
-=========================================
-
-<!-- Page created on {{ date }} -->
-{{ components }}
diff --git a/inst/templates/sidebar_template.Rmd b/inst/templates/sidebar_template.Rmd
new file mode 100644
index 0000000..18634ab
--- /dev/null
+++ b/inst/templates/sidebar_template.Rmd
@@ -0,0 +1,4 @@
+Inputs {.sidebar}
+-------------------------------------
+
+{{ content }}
diff --git a/man/dot-render_page.Rd b/man/dot-render_page.Rd
new file mode 100644
index 0000000..43ddd2f
--- /dev/null
+++ b/man/dot-render_page.Rd
@@ -0,0 +1,26 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/assemble.R
+\name{.render_page}
+\alias{.render_page}
+\title{Method for rendering a page with a given layout and components}
+\usage{
+.render_page(title, components, layout = c("default", "storyboard",
+  "focal_left", "2x2_grid"), menu = NULL, sidebar = NULL)
+}
+\arguments{
+\item{title}{The page title.}
+
+\item{components}{A list of page components.}
+
+\item{layout}{The pages overall layout.}
+
+\item{menu}{The menu under which the page will be filed.}
+
+\item{sidebar}{Character string with sidebar content.}
+}
+\value{
+A markdown string with the final page.
+}
+\description{
+Method for rendering a page with a given layout and components
+}
diff --git a/man/idashboard-class.Rd b/man/idashboard-class.Rd
index 3ed70c8..c2d3c6d 100644
--- a/man/idashboard-class.Rd
+++ b/man/idashboard-class.Rd
@@ -15,8 +15,8 @@
 \S4method{add_component}{i2dashboard}(object, page = "default",
   component, ...)
 
-\S4method{add_page}{i2dashboard}(object, page, title,
-  layout = "storyboard", menu = NULL, ...)
+\S4method{add_page}{i2dashboard}(object, page, title, layout = "default",
+  menu = NULL, sidebar = NULL, ...)
 
 \S4method{remove_page}{i2dashboard}(object, page)
 }
diff --git a/man/render_features_by_factors.Rd b/man/render_features_by_factors.Rd
deleted file mode 100644
index 7682cb9..0000000
--- a/man/render_features_by_factors.Rd
+++ /dev/null
@@ -1,21 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/features_by_factors.R
-\name{render_features_by_factors}
-\alias{render_features_by_factors}
-\title{Renders a features by factor violin plot}
-\usage{
-render_features_by_factors(object, plot_title, x, y)
-}
-\arguments{
-\item{plot_title}{The title of the Component}
-
-\item{x}{A list with the x-axis values. If it is a nested list, a dropdown-field will be provided in the interactive mode.}
-
-\item{y}{A list with the y-axis values. If it is a nested list, a dropdown-field will be provided in the interactive mode.(Needs to be categorial. Horizontal violinplots are not possible.)}
-}
-\value{
-A string containing markdown code for the rendered textbox
-}
-\description{
-Renders a features by factor violin plot
-}
diff --git a/man/render_multiplot.Rd b/man/render_multiplot.Rd
deleted file mode 100644
index ce78313..0000000
--- a/man/render_multiplot.Rd
+++ /dev/null
@@ -1,23 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/multiplot.R
-\name{render_multiplot}
-\alias{render_multiplot}
-\title{Renders a Sequence saturation plot}
-\usage{
-render_multiplot(object, plot_title, x, y, color_by)
-}
-\arguments{
-\item{plot_title}{The title of the Component}
-
-\item{x}{A list with the x-axis values. If it is a nested list, a dropdown-field will be provided in the interactive mode.}
-
-\item{y}{A list with the y-axis values. If it is a nested list, a dropdown-field will be provided in the interactive mode.}
-
-\item{color_by}{A list with the color_by values. If it is a nested list, a dropdown-field will be provided in the interactive mode.}
-}
-\value{
-A string containing markdown code for the rendered textbox
-}
-\description{
-Renders a Sequence saturation plot
-}
diff --git a/man/render_sequence_saturation.Rd b/man/render_sequence_saturation.Rd
deleted file mode 100644
index 1475843..0000000
--- a/man/render_sequence_saturation.Rd
+++ /dev/null
@@ -1,23 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/sequence_saturation.R
-\name{render_sequence_saturation}
-\alias{render_sequence_saturation}
-\title{Renders a Sequence saturation plot}
-\usage{
-render_sequence_saturation(object, plot_title, x, y, color_by)
-}
-\arguments{
-\item{plot_title}{The title of the Component}
-
-\item{x}{A list with the x-axis values. If it is a nested list, a dropdown-field will be provided in the interactive mode.}
-
-\item{y}{A list with the y-axis values. If it is a nested list, a dropdown-field will be provided in the interactive mode.}
-
-\item{color_by}{A list with the color_by values. If it is a nested list, a dropdown-field will be provided in the interactive mode.}
-}
-\value{
-A string containing markdown code for the rendered textbox
-}
-\description{
-Renders a Sequence saturation plot
-}
-- 
GitLab