javascript - Using (r)introjs to automatically highlight sidebar menus is not adjusted correctly
问题描述
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();
}
}
}
};
}();
解决方案
推荐阅读
- r - 如何找到泊松分布的1000个随机数的期望值
- chart.js - 如何在charts.js中显示第二个y轴的标签?
- ios - 如何根据存储在另一个数组中的索引获取数组的项
- python - python中sinc函数的傅里叶变换
- javascript - 使用 Jquery 围绕博客文章 avada wordpress 主题包装引导轮播
- ios - 如何在swift中为自定义按钮操作制作globe方法
- angular11 - Angular Object 可能为“null”。输入电子邮件地址时出错
- r - 如何使用 R 在缺少某些值的唯一标识符中添加缺少的零?
- windows - 未找到 Docker entrypoint.sh
- delphi - Delphi 7 - DCPCrypt - TDCP_rijndael - DecryptString - 如何让它工作?