Merge branch 'master' of https://github.com/haozhu233/kableExtra
diff --git a/R/collapse_rows.R b/R/collapse_rows.R
index 86956aa..4ae0145 100644
--- a/R/collapse_rows.R
+++ b/R/collapse_rows.R
@@ -7,7 +7,8 @@
 #' specify column styles, you should use `column_spec` before `collapse_rows`.
 #'
 #' @param kable_input Output of `knitr::kable()` with `format` specified
-#' @param columns Numeric column positions where rows need to be collapsed.
+#' @param columns A numeric value or vector indicating in which column(s) rows 
+#' need to be collapsed.
 #' @param valign Select from "top", "middle"(default), "bottom". The reason why
 #' "top" is not default is that the multirow package on CRAN win-builder is
 #' not up to date.
@@ -139,19 +140,19 @@
   collapse_matrix <- collapse_row_matrix(kable_dt, columns, html = FALSE)
 
   new_kable_dt <- kable_dt
-  for (j in seq(1:ncol(collapse_matrix))) {
+  for (j in seq_along(columns)) {
     column_align <- table_info$align_vector_origin[columns[j]]
     column_width <- ifelse(
       is.null(table_info$column_width[[paste0("column_", columns[j])]]),
       "*", table_info$column_width[paste0("column_", columns[j])])
     for (i in seq(1:nrow(collapse_matrix))) {
       if(row_group_label_position == 'stack'){
-        if(j < ncol(collapse_matrix)|(collapse_matrix_rev[i, j] == 0)){
-          new_kable_dt[i, j] <- ''
+        if(columns[j] < ncol(collapse_matrix) || collapse_matrix_rev[i, j] == 0){
+          new_kable_dt[i, columns[j]] <- ''
         }
       } else {
-        new_kable_dt[i, j] <- collapse_new_dt_item(
-          kable_dt[i, j], collapse_matrix[i, j], column_width,
+        new_kable_dt[i, columns[j]] <- collapse_new_dt_item(
+          kable_dt[i, columns[j]], collapse_matrix[i, j], column_width,
           align = column_align, valign = valign
         )
       }
diff --git a/R/scroll_box.R b/R/scroll_box.R
index 3d1b805..b0660ed 100644
--- a/R/scroll_box.R
+++ b/R/scroll_box.R
@@ -8,6 +8,8 @@
 #' @param width A character string indicating the width of the box, e.g. "100px"
 #' @param box_css CSS text for the box
 #' @param extra_css Extra CSS styles
+#' @param fixed_thead A list of two named element. enabled and background.
+#' Default is F and white, e.g. "list(enabled = T, background = "#fff")"
 #'
 #' @export
 #'
@@ -26,23 +28,45 @@
 
 scroll_box <- function(kable_input, height = NULL, width = NULL,
                        box_css = "border: 1px solid #ddd; padding: 5px; ",
-                       extra_css = NULL) {
+                       extra_css = NULL, fixed_thead = list(enabled = F, background = "#fff")) {
+
   kable_attrs <- attributes(kable_input)
-  out <- as.character(kable_input)
+
+  if (fixed_thead$enabled) {
+    box_css = "border: 1px solid #ddd; padding: 0px; "
+    kable_xml <- read_kable_as_xml(kable_input)
+    kable_thead <- xml_tpart(kable_xml, "thead")
+    original_header_row <- xml_child(kable_thead, length(xml_children(kable_thead)))
+    for (theader_i in 1:length(xml_children(original_header_row))) {
+      target_header_cell <- xml_child(original_header_row, theader_i)
+      xml_attr(target_header_cell, "style") <- paste0(xml_attr(target_header_cell, "style"),
+                                                      "position: sticky; top:0; background: ",
+                                                      fixed_thead$background,";")
+    }
+    out <- as.character(as_kable_xml(kable_xml))
+  } else {
+    out <- as.character(kable_input)
+  }
+
   box_styles <- c(box_css, extra_css)
+
   if (!is.null(height)) {
     box_styles <- c(box_styles,
                     paste0("overflow-y: scroll; height:", height, "; "))
   }
+
   if (!is.null(width)) {
     box_styles <- c(box_styles,
                     paste0("overflow-x: scroll; width:", width, "; "))
   }
+
   out <- paste0('<div style="', paste(box_styles, collapse = ""), '">',
                 out, '</div>')
   out <- structure(out, format = "html",
                    class = "knitr_kable")
   attributes(out) <- kable_attrs
+
   if (!"kableExtra" %in% class(out)) class(out) <- c("kableExtra", class(out))
+
   return(out)
 }
diff --git a/man/collapse_rows.Rd b/man/collapse_rows.Rd
index 9508bd4..4752d80 100644
--- a/man/collapse_rows.Rd
+++ b/man/collapse_rows.Rd
@@ -13,7 +13,8 @@
 \arguments{
 \item{kable_input}{Output of \code{knitr::kable()} with \code{format} specified}
 
-\item{columns}{Numeric column positions where rows need to be collapsed.}
+\item{columns}{A numeric value or vector indicating in which column(s) rows
+need to be collapsed.}
 
 \item{valign}{Select from "top", "middle"(default), "bottom". The reason why
 "top" is not default is that the multirow package on CRAN win-builder is