I am using the JS-extension rintrojs and extended its feature to unfold the menu sidebar when an sidebar item should be highlighted on the sidebar and the formerly unfolded sidebar submenu collapses. It extends as soon as an sidebar menu is "introduced".
Everything works fine except that the highlighting itself highlights the area where the menu would have been if the former menu would not have been collapsed. 
I tried some hacks like immediatly going to the next step when a certain step has been reached but to no success. It looks like area to highlight it determined before the JS is triggered.
# shiny
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyjs)
library(rintrojs)
# tidyverse
library(dplyr)
library(tibble)
library(stringi)
# allow IDs to be added to the menu item
menuItemID <- function (text, id = NULL, ..., icon = NULL, badgeLabel = NULL, badgeColor = "green",
tabName = NULL, href = NULL, newtab = TRUE, selected = NULL,
expandedName = as.character(gsub("[[:space:]]", "", text)),
startExpanded = FALSE)
{
subItems <- list(...)
if (!is.null(icon))
shinydashboard:::tagAssert(icon, type = "i")
if (!is.null(href) + !is.null(tabName) + (length(subItems) >
0) != 1) {
stop("Must have either href, tabName, or sub-items (contained in ...).")
}
if (!is.null(badgeLabel) && length(subItems) != 0) {
stop("Can't have both badge and subItems")
}
shinydashboard:::validateColor(badgeColor)
isTabItem <- FALSE
target <- NULL
if (!is.null(tabName)) {
shinydashboard:::validateTabName(tabName)
isTabItem <- TRUE
href <- paste0("#shiny-tab-", tabName)
}
else if (is.null(href)) {
href <- "#"
}
else {
if (newtab)
target <- "_blank"
}
if (!is.null(badgeLabel)) {
badgeTag <- tags$small(class = paste0("badge pull-right bg-",
badgeColor), badgeLabel)
}
else {
badgeTag <- NULL
}
if (length(subItems) == 0) {
return(tags$li(id = id, a(href = href, `data-toggle` = if (isTabItem) "tab",
`data-value` = if (!is.null(tabName)) tabName, `data-start-selected` = if (isTRUE(selected)) 1 else NULL,
target = target, icon, span(text), badgeTag)))
}
default <- if (startExpanded)
expandedName
else ""
dataExpanded <- shinydashboard:::`%OR%`(shiny::restoreInput(id = "sidebarItemExpanded",
default), "")
isExpanded <- nzchar(dataExpanded) && (dataExpanded == expandedName)
tags$li(id = id, class = "treeview", a(href = href, icon, span(text),
shiny::icon("angle-left", class = "pull-right")), do.call(tags$ul,
c(class = paste0("treeview-menu", if (isExpanded) " menu-open" else ""),
style = paste0("display: ", if (isExpanded) "block;" else "none;"),
`data-expanded` = expandedName, subItems)))
}
ui <- shinyUI(
dashboardPagePlus(
## Header ====
header = dashboardHeaderPlus(
enable_rightsidebar = FALSE,
tags$li(class = "dropdown",
actionButton("intro_btn", "Get Started")
)
),
## Sidebar ====
sidebar = dashboardSidebar(
fluidPage(fluidRow(sidebarMenu(
id = "sidebarmenu",
menuItemID(
id = "driv_sidebar",
text = "Section 1",
tabName = "driv_sidebar",
icon = icon("chevron-right", lib = "font-awesome"),
startExpanded = TRUE,
div(id = "env-intro", menuSubItem("Tab A", tabName = "env_tab", icon = icon("chevron-right", lib = "font-awesome"))),
div(id = "vic-intro", menuSubItem("Tab B", tabName = "vic_tab", icon = icon("chevron-right", lib = "font-awesome"))),
div(id = "gen-intro", menuSubItem("Tab C", tabName = "gen_tab", icon = icon("chevron-right", lib = "font-awesome"))),
div(id = "pow-intro", menuSubItem("Tab D", tabName = "pow_tab", icon = icon("chevron-right", lib = "font-awesome")))
),
menuItemID(
id = "hint_sidebar",
text = "Section 2",
tabName = "hint_sidebar",
icon = icon("chevron-right", lib = "font-awesome"),
div(id = "apps-intro",menuSubItem("Tab X", tabName = "apps_tab", icon = icon("chevron-right", lib = "font-awesome"))),
div(id = "ent-intro",menuSubItem("Tab Y", tabName = "ent_tab", icon = icon("chevron-right", lib = "font-awesome")))
)
)))
),
## Body ====
body = dashboardBody(
id = "dashbody",
useShinyjs(),
introjsUI(),
# SAVE THE JS in the same folder as the file app.R as switch_sidebar.js !!
tags$head(includeScript("switch_sidebar.js")),
tags$head(
tabItems(
)
)
)
)
)
server <- shinyServer(function(input, output, session) {
# Intro steps ----------------------------------------------------------------
intro_guide <- tibble(step = 1:6,
intro = c(stri_c(stri_rand_strings(8, 7), collapse = " "),
stri_c(stri_rand_strings(8, 7), collapse = " "),
stri_c(stri_rand_strings(8, 7), collapse = " "),
stri_c(stri_rand_strings(8, 7), collapse = " "),
stri_c(stri_rand_strings(8, 7), collapse = " "),
stri_c(stri_rand_strings(8, 7), collapse = " ")),
element = c("#driv_sidebar", "#gen-intro",
"#pow-intro", "#hint_sidebar", "#apps-intro", "#ent-intro"),
position = c("auto", "auto", "auto", "auto", "auto", "auto"))
# INTRO ----------------------------------------------------------------------
# https://shiny.rstudio.com/articles/js-introjs.html
observeEvent(input$intro_btn, {
introjs(session = session,
options = list(steps = intro_guide),
events = list(onbeforechange = I("rintrojs.callback.switchSidebars(targetElement)")))
})
})
shiny::shinyApp(ui, server)
rintrojs = function() {
return {
callback : {
switchSidebars : function(targetElement) {
console.log("Correct File");
// get nodelist of tab panes
var tabpanes = document.querySelectorAll("div.tab-pane");
var selector;
// iterate over the list of tab panes and click their corresponding link
// element if the node contains the upcoming target element
for (i = 0; i < tabpanes.length; i++) {
if (tabpanes[i].contains(targetElement)) {
selector = "a[href = \"#" + tabpanes[i].id + "\"]";
document.querySelector(selector).click();
}
}
// get nodelist of treeviews
var treeview = document.querySelectorAll(".treeview");
// iterate over the list of treeviews and click their corresponding link
// element if the node contains the upcoming target element
if(treeview.length > 0){
for (i = 0; i < treeview.length; i++) {
if (treeview[i].contains(targetElement)) {
if (document.querySelectorAll("#" + treeview[i].id + " > .treeview-menu")[0].className == "treeview-menu"){
selector = "a[href = \"#" + "shiny-tab-" + treeview[i].id + "\"]";
document.querySelector(selector).click();
}
}}
}
// hacky try: list an div-id twice and trigger next step right when the first one
// has been reached
// activate next sidebar menu
console.log(targetElement);
let count = Object.keys(window.introJs.instances).length-1;
let instance = window.introJs.instances[count];
console.log(instance._currentStep);
if(instance._currentStep == 4) {
console.log("Hello Check");
instance.refresh();
//document.getElementsByClassName("introjs-button introjs-nextbutton").click();
//instance.nextStep();
}
}
}
};
}();from Using (r)introjs to automatically highlight sidebar menus is not adjusted correctly
No comments:
Post a Comment