├── .Rbuildignore ├── .gitignore ├── DESCRIPTION ├── NAMESPACE ├── R ├── utils-pipe.R ├── utils.R └── vue.R ├── README.md ├── _pkgdown.yml ├── docs ├── authors.html ├── docsearch.css ├── docsearch.js ├── index.html ├── link.svg ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml └── reference │ ├── appendDependencies.html │ ├── index.html │ ├── pipe.html │ ├── vue.html │ ├── vueProxy.html │ ├── vueUpdateShinyInputs.html │ └── vueUsePlugin.html ├── inst ├── examples │ ├── apexcharts.R │ ├── basic-vtags.R │ ├── basic.R │ ├── colorpicker.R │ ├── elementui.R │ ├── mint.R │ ├── sunburst.R │ └── treeview.R └── htmlwidgets │ ├── lib │ └── vue │ │ └── vue.js │ ├── vue.js │ └── vue.yaml ├── man ├── appendDependencies.Rd ├── pipe.Rd ├── vtag.Rd ├── vue.Rd ├── vueProxy.Rd ├── vueUpdateShinyInputs.Rd └── vueUsePlugin.Rd └── vuer.Rproj /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^docs$ 2 | ^_pkgdown\.yml$ 3 | ^.*\.Rproj$ 4 | ^\.Rproj\.user$ 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: vuer 2 | Title: Harness the Power of Vue in R 3 | Version: 0.1 4 | Authors@R: 5 | person(given = "Ramnath", 6 | family = "Vaidyanathan", 7 | role = c("aut", "cre"), 8 | email = "ramnath@datacamp.com") 9 | Description: vuer is an R package that makes it easy to use Vue components and build Vue apps. 10 | License: MIT + file LICENSE 11 | Encoding: UTF-8 12 | LazyData: true 13 | URL: https://github.com/ramnathv/vuer 14 | BugReports: https://github.com/ramnathv/vuer/issues 15 | RoxygenNote: 6.1.1 16 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export("%>%") 4 | export(Vue) 5 | export(appendDependencies) 6 | export(renderVue) 7 | export(vtag) 8 | export(vtags) 9 | export(vue) 10 | export(vueComponents) 11 | export(vueOutput) 12 | export(vueProxy) 13 | export(vueUpdateData) 14 | export(vueUpdateShinyInputs) 15 | export(vueUsePlugin) 16 | import(htmltools) 17 | import(htmlwidgets) 18 | importFrom(htmltools,tags) 19 | importFrom(magrittr,"%>%") 20 | importFrom(purrr,map) 21 | -------------------------------------------------------------------------------- /R/utils-pipe.R: -------------------------------------------------------------------------------- 1 | #' Pipe operator 2 | #' 3 | #' See \code{magrittr::\link[magrittr]{\%>\%}} for details. 4 | #' 5 | #' @name %>% 6 | #' @rdname pipe 7 | #' @keywords internal 8 | #' @export 9 | #' @importFrom magrittr %>% 10 | #' @usage lhs \%>\% rhs 11 | NULL 12 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | asPropsList <- function (x, name = "name", value = "value"){ 2 | x <- as.list(x) 3 | nms <- names(x) 4 | lapply(seq_along(x), function(i) { 5 | l <- list() 6 | l[name] <- nms[i] 7 | l[value] <- x[i] 8 | l 9 | }) 10 | } 11 | 12 | 13 | #' Use a vue Plugin 14 | #' 15 | #' 16 | #' @export 17 | vueUsePlugin <- function(fun){ 18 | tags$script(sprintf("Vue.use(%s)", fun)) 19 | } 20 | 21 | #' Append html dependencies 22 | #' 23 | #' NOTE: This function has been copied over from shinydashboard 24 | #' @export 25 | appendDependencies <- function (x, value){ 26 | if (inherits(value, "html_dependency")) 27 | value <- list(value) 28 | old <- attr(x, "html_dependencies", TRUE) 29 | htmlDependencies(x) <- c(old, value) 30 | x 31 | } 32 | 33 | #' @importFrom purrr map 34 | #' @importFrom htmltools tags 35 | #' @export vtags 36 | vtags <- names(htmltools::tags) %>% 37 | purrr::map(~ function(...){ 38 | vtag(.x, list(...)) 39 | }) %>% 40 | rlang::set_names(names(tags)) 41 | 42 | #' Vue Tag 43 | #' 44 | #' 45 | #' @export 46 | #' @examples 47 | #' vtag("input", list(type = "text", vmodel = "message")) 48 | vtag <- function(`_tag_name`, varArgs){ 49 | if (!is.null(names(varArgs))){ 50 | names(varArgs) <- gsub("^v(.*)", "v-\\1", names(varArgs)) 51 | names(varArgs) <- gsub( 52 | "^v-([^\\.]*)(\\.)(.*)$", "v-\\1:\\3", names(varArgs) 53 | ) 54 | } 55 | htmltools::tag(`_tag_name`, varArgs) 56 | } 57 | -------------------------------------------------------------------------------- /R/vue.R: -------------------------------------------------------------------------------- 1 | #' Create a Vue App 2 | #' 3 | #' 4 | #' @import htmlwidgets 5 | #' 6 | #' @export 7 | #' @import htmltools 8 | #' @import htmlwidgets 9 | vue <- function(html, data = list(), dependencies = list(), watch = list(), 10 | id = NULL, ..., width = "100%", height = "auto", elementId = NULL) { 11 | 12 | if (!is.null(html)){ 13 | if (is.null(html$attribs$id)){ 14 | html$attribs$id <- paste0('vue-', htmlwidgets:::createWidgetId()) 15 | } 16 | id <- html$attribs$id 17 | html_rendered <- htmltools::renderTags(html) 18 | } else { 19 | html_rendered <- list(html = "") 20 | } 21 | 22 | trim_underscore <- function(x){ 23 | as.list(gsub("(^.*)\\_$", "\\1", x)) 24 | } 25 | 26 | if (length(data) > 0 && is.list(data)){ 27 | to_watch <- names(data)[endsWith(names(data), "_")] 28 | watch <- if (length(to_watch) > 0){ 29 | append(watch, do.call(vueUpdateShinyInputs, trim_underscore(to_watch))) 30 | } else { 31 | list() 32 | } 33 | names(data) <- trim_underscore(names(data)) 34 | } 35 | 36 | # forward options using x 37 | x = list( 38 | html = html_rendered$html, 39 | app = list( 40 | el = paste0("#", id), 41 | data = data, 42 | watch = watch, 43 | components = vueComponents$get(), 44 | ... 45 | ) 46 | ) 47 | 48 | # create widget 49 | htmlwidgets::createWidget( 50 | name = 'vue', 51 | x, 52 | width = width, 53 | height = height, 54 | package = 'vuer', 55 | elementId = elementId, 56 | dependencies = append( 57 | html_rendered$dependencies, dependencies 58 | ) 59 | ) 60 | } 61 | 62 | #' Create a Vue App 63 | #' 64 | #' 65 | #' @export 66 | #' @import htmltools 67 | #' @examples 68 | #' library(htmltools) 69 | #' tags$div( 70 | #' tags$label('Enter your name'), 71 | #' tags$input(type = "text", "v-model" = "name"), 72 | #' tags$p("Hello {{name}}") 73 | #' ) %>% 74 | #' Vue(data = list(name = "")) 75 | #' 76 | #' if (interactive()){ 77 | #' library(shiny) 78 | #' ui <- tags$div( 79 | #' tags$label('Enter your name'), 80 | #' tags$input(type = "text", "v-model" = "name"), 81 | #' textOutput("greeting") 82 | #' ) %>% 83 | #' Vue(data = list(name_ = "")) 84 | #' server <- function(input, output, session){ 85 | #' output$greeting <- renderText({ 86 | #' paste("Hello", input$name) 87 | #' }) 88 | #' } 89 | #' shinyApp(ui = ui, server = server) 90 | #' } 91 | Vue <- function(html, data = list(), dependencies = list(), ..., 92 | elementId = NULL){ 93 | if (is.null(html$attribs$id)){ 94 | html$attribs$id <- paste0('vue-', htmlwidgets:::createWidgetId()) 95 | } 96 | tagList( 97 | html, 98 | vue(html = NULL, data = data, dependencies = dependencies, 99 | elementId = elementId, 100 | id = html$attribs$id, ... 101 | ) 102 | ) %>% 103 | browsable() 104 | } 105 | 106 | #' Shiny bindings for hello 107 | #' 108 | #' Output and render functions for using hello within Shiny 109 | #' applications and interactive Rmd documents. 110 | #' 111 | #' @param outputId output variable to read from 112 | #' @param width,height Must be a valid CSS unit (like \code{'100\%'}, 113 | #' \code{'400px'}, \code{'auto'}) or a number, which will be coerced to a 114 | #' string and have \code{'px'} appended. 115 | #' @param expr An expression that generates a hello 116 | #' @param env The environment in which to evaluate \code{expr}. 117 | #' @param quoted Is \code{expr} a quoted expression (with \code{quote()})? This 118 | #' is useful if you want to save an expression in a variable. 119 | #' 120 | #' @name vue 121 | #' 122 | #' @export 123 | vueOutput <- function(outputId, width = '100%', height = '400px'){ 124 | htmlwidgets::shinyWidgetOutput(outputId, 'vue', width, height, package = 'vuepkg') 125 | } 126 | 127 | #' @rdname vue 128 | #' @export 129 | renderVue <- function(expr, env = parent.frame(), quoted = FALSE) { 130 | if (!quoted) { expr <- substitute(expr) } # force quoted 131 | htmlwidgets::shinyRenderWidget(expr, helloOutput, env, quoted = TRUE) 132 | } 133 | 134 | 135 | #' Send commands to a Vue instance in a Shiny app 136 | #' 137 | #' 138 | #' @examples 139 | #' ui <- div( 140 | #' tags$label("Enter username"), 141 | #' tags$input(type = 'text', "v-model" = "username"), 142 | #' tags$p("Vue -> Vue: Hello {{username}}"), 143 | #' actionButton("set_name", "Shiny -> Vue"), 144 | #' verbatimTextOutput("username") 145 | #' ) %>% 146 | #' vue( 147 | #' data = list(username = ""), 148 | #' # Vue UI -> Shiny UI 149 | #' watch = vue_watch("username"), 150 | #' elementId = "app" 151 | #' ) 152 | #' server <- function(input, output, session){ 153 | #' # Shiny server -> Vue UI 154 | #' observeEvent(input$set_name, { 155 | #' vueProxy("app") %>% 156 | #' updateProp("username", "Ramnath") 157 | #' }) 158 | #' output$username <- renderPrint({ 159 | #' paste("Vue -> Shiny:", input$username) 160 | #' }) 161 | #' } 162 | #' shiny::shinyApp(ui = ui, server = server) 163 | #' @export 164 | vueProxy <- function(outputId, session = shiny::getDefaultReactiveDomain(), 165 | deferUntilFlush = TRUE){ 166 | if (is.null(session)){ 167 | stop("vueProxy() must be called from the server function of a Shiny app") 168 | } 169 | structure(list( 170 | id = session$ns(outputId), 171 | rawId = outputId, 172 | session = session, 173 | deferUntilFlush = deferUntilFlush 174 | ), class = 'vue_proxy' 175 | ) 176 | } 177 | 178 | #' Update data in a Vue instance 179 | #' @export 180 | #' @rdname vueProxy 181 | vueUpdateData <- function(proxy, ...){ 182 | message <- list(id = proxy$id, data = asPropsList(list(...))) 183 | proxy$session$sendCustomMessage(type = "updateProp", message = message) 184 | return(proxy) 185 | } 186 | 187 | #' Update Shiny Input 188 | #' 189 | #' @export 190 | vueUpdateShinyInputs <- function(...){ 191 | dots <- list(...) 192 | dots %>% 193 | purrr::map(~ { 194 | htmlwidgets::JS(sprintf("function(val){ 195 | console.log(val) 196 | Shiny.setInputValue('%s', val) 197 | }", .x)) 198 | }) %>% 199 | rlang::set_names(dots) 200 | } 201 | 202 | 203 | 204 | .generator <- function(){ 205 | .vueComponents <- list() 206 | list( 207 | get = function(){ 208 | return(.vueComponents) 209 | }, 210 | register = function(..., .list = NULL){ 211 | if (is.null(.list)) .list = list(...) 212 | .list <- .list %>% 213 | purrr::map(htmlwidgets::JS) 214 | .vueComponents <<- modifyList(.vueComponents, .list) 215 | }, 216 | reset = function(){ 217 | .vueComponents <<- list() 218 | } 219 | ) 220 | } 221 | 222 | #' @export 223 | vueComponents <- .generator() 224 | 225 | 226 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vuer 2 | 3 | [![lifecycle](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) 4 | 5 | `vuer` is an R package that makes it easy to use Vue components and build Vue apps. 6 | 7 | > Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. It is designed from the ground up to be incrementally adoptable, and can easily scale between a library and a framework depending on different use cases. 8 | 9 | 10 | ## Installation 11 | 12 | You can install `vuer` from github using `remotes` or `devtools`. 13 | 14 | ```r 15 | remotes::install_github('ramnathv/vuer') 16 | ``` 17 | 18 | ## Usage 19 | 20 | ### Example 1: Hello World 21 | 22 | We can use `vuer` to create purely client-side web-apps taking advantage of its simple API and two-way data bindings. In this simple example, we let a user enter their name and display a greeting message. 23 | 24 | ```r 25 | tags$div(style = 'height:100px;width:400px;', 26 | tags$label('Enter your name: '), 27 | tags$input(type = "text", "v-model" = "name"), 28 | tags$p(class = "lead", "Hello {{name}}") 29 | ) %>% 30 | appendDependencies( 31 | htmldeps::html_dependency_bootstrap('cosmo') 32 | ) %>% 33 | Vue(data = list(name = "")) 34 | ``` 35 | 36 | ![hello-world](https://media.giphy.com/media/QmKxl4fJZtAEHkepJM/giphy.gif) 37 | 38 | The power of `vuer` starts truly shining when we are able to let Vue communicate with Shiny. This opens up an unlimited range of possibilities that we will explore in detail. The next two examples explore how Vue and Shiny can communicate with each other. 39 | 40 | ### Example 2: Vue -> Shiny 41 | 42 | It is dead-simple to let Vue communicate with Shiny. All it takes is adding an underscore at the end of any data variable passed to `Vue`. This automatically sets up watcher functions to update shiny when the underlying value changes, thereby triggering any reactive paths that depend on it. This example is very similar to the first one in that we let a user enter their name and display a greeting message. The key difference is that the greeting message is from Shiny on the server side. 43 | 44 | ```r 45 | ui <- fluidPage(theme = shinythemes::shinytheme("cosmo"), 46 | tags$div( 47 | tags$label('Enter your name'), 48 | tags$input(type = "text", "v-model" = "name"), 49 | uiOutput("greeting") 50 | ) %>% 51 | Vue( 52 | data = list(name_ = "") 53 | ) 54 | ) 55 | 56 | 57 | server <- function(input, output, session){ 58 | output$greeting <- renderUI({ 59 | tags$p(paste("Hello", input$name)) 60 | }) 61 | } 62 | 63 | shinyApp(ui = ui, server = server) 64 | ``` 65 | 66 | 67 | ### Example 3: Shiny -> Vue 68 | 69 | It is equally easy to let Shiny communicate with Vue. In this example we pass the coordinates of a plot brush to Vue and display it as JSON. 70 | 71 | ```r 72 | library(shiny) 73 | library(ggplot2) 74 | library(vuer) 75 | ui <- fluidPage(theme = shinythemes::shinytheme("cosmo"), 76 | titlePanel(title = 'Shiny -> Vue'), 77 | mainPanel( 78 | plotOutput('plot', brush = brushOpts('plot_brush'), height = '300'), 79 | tags$pre("v-if" = "plot_brush !== null", 80 | tags$code("{{plot_brush}}") 81 | ) %>% 82 | Vue(data = list(plot_brush = c()), elementId = "app") 83 | ) 84 | ) 85 | 86 | server <- function(input, output, session){ 87 | output$plot <- renderPlot({ 88 | ggplot(mtcars, aes(x = mpg, y = wt)) + 89 | geom_point() 90 | }) 91 | observeEvent(input$plot_brush, { 92 | vueProxy("app") %>% 93 | vueUpdateData(plot_brush = input$plot_brush$coords_img) 94 | }) 95 | } 96 | shinyApp(ui = ui, server = server) 97 | ``` 98 | 99 | ![shiny-vue](https://media.giphy.com/media/c6XuxhQrLTUid7m76o/giphy.gif) 100 | 101 | 102 | ## Acknowledgements 103 | 104 | This package was inspired by Kenton Russell's [experiments](https://github.com/timelyportfolio/vueR) using Vue in R, as well as the efforts taken by the [react-R](https://github.com/react-R/reactR) team in integrating `React.js` with R. 105 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | template: 2 | params: 3 | bootswatch: cosmo 4 | 5 | navbar: 6 | type: inverse 7 | -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Authors • vuer 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 49 | 50 |
51 |
52 | 92 | 93 | 94 |
95 | 96 |
97 |
98 | 101 | 102 |
    103 |
  • 104 |

    Ramnath Vaidyanathan. Author, maintainer. 105 |

    106 |
  • 107 |
108 | 109 |
110 | 111 |
112 | 113 | 114 | 123 |
124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /docs/docsearch.css: -------------------------------------------------------------------------------- 1 | /* Docsearch -------------------------------------------------------------- */ 2 | /* 3 | Source: https://github.com/algolia/docsearch/ 4 | License: MIT 5 | */ 6 | 7 | .algolia-autocomplete { 8 | display: block; 9 | -webkit-box-flex: 1; 10 | -ms-flex: 1; 11 | flex: 1 12 | } 13 | 14 | .algolia-autocomplete .ds-dropdown-menu { 15 | width: 100%; 16 | min-width: none; 17 | max-width: none; 18 | padding: .75rem 0; 19 | background-color: #fff; 20 | background-clip: padding-box; 21 | border: 1px solid rgba(0, 0, 0, .1); 22 | box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175); 23 | } 24 | 25 | @media (min-width:768px) { 26 | .algolia-autocomplete .ds-dropdown-menu { 27 | width: 175% 28 | } 29 | } 30 | 31 | .algolia-autocomplete .ds-dropdown-menu::before { 32 | display: none 33 | } 34 | 35 | .algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] { 36 | padding: 0; 37 | background-color: rgb(255,255,255); 38 | border: 0; 39 | max-height: 80vh; 40 | } 41 | 42 | .algolia-autocomplete .ds-dropdown-menu .ds-suggestions { 43 | margin-top: 0 44 | } 45 | 46 | .algolia-autocomplete .algolia-docsearch-suggestion { 47 | padding: 0; 48 | overflow: visible 49 | } 50 | 51 | .algolia-autocomplete .algolia-docsearch-suggestion--category-header { 52 | padding: .125rem 1rem; 53 | margin-top: 0; 54 | font-size: 1.3em; 55 | font-weight: 500; 56 | color: #00008B; 57 | border-bottom: 0 58 | } 59 | 60 | .algolia-autocomplete .algolia-docsearch-suggestion--wrapper { 61 | float: none; 62 | padding-top: 0 63 | } 64 | 65 | .algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column { 66 | float: none; 67 | width: auto; 68 | padding: 0; 69 | text-align: left 70 | } 71 | 72 | .algolia-autocomplete .algolia-docsearch-suggestion--content { 73 | float: none; 74 | width: auto; 75 | padding: 0 76 | } 77 | 78 | .algolia-autocomplete .algolia-docsearch-suggestion--content::before { 79 | display: none 80 | } 81 | 82 | .algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header { 83 | padding-top: .75rem; 84 | margin-top: .75rem; 85 | border-top: 1px solid rgba(0, 0, 0, .1) 86 | } 87 | 88 | .algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column { 89 | display: block; 90 | padding: .1rem 1rem; 91 | margin-bottom: 0.1; 92 | font-size: 1.0em; 93 | font-weight: 400 94 | /* display: none */ 95 | } 96 | 97 | .algolia-autocomplete .algolia-docsearch-suggestion--title { 98 | display: block; 99 | padding: .25rem 1rem; 100 | margin-bottom: 0; 101 | font-size: 0.9em; 102 | font-weight: 400 103 | } 104 | 105 | .algolia-autocomplete .algolia-docsearch-suggestion--text { 106 | padding: 0 1rem .5rem; 107 | margin-top: -.25rem; 108 | font-size: 0.8em; 109 | font-weight: 400; 110 | line-height: 1.25 111 | } 112 | 113 | .algolia-autocomplete .algolia-docsearch-footer { 114 | width: 110px; 115 | height: 20px; 116 | z-index: 3; 117 | margin-top: 10.66667px; 118 | float: right; 119 | font-size: 0; 120 | line-height: 0; 121 | } 122 | 123 | .algolia-autocomplete .algolia-docsearch-footer--logo { 124 | background-image: url("data:image/svg+xml;utf8,"); 125 | background-repeat: no-repeat; 126 | background-position: 50%; 127 | background-size: 100%; 128 | overflow: hidden; 129 | text-indent: -9000px; 130 | width: 100%; 131 | height: 100%; 132 | display: block; 133 | transform: translate(-8px); 134 | } 135 | 136 | .algolia-autocomplete .algolia-docsearch-suggestion--highlight { 137 | color: #FF8C00; 138 | background: rgba(232, 189, 54, 0.1) 139 | } 140 | 141 | 142 | .algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { 143 | box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) 144 | } 145 | 146 | .algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { 147 | background-color: rgba(192, 192, 192, .15) 148 | } 149 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Harness the Power of Vue in R • vuer 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 |
22 |
62 | 63 | 64 | 65 |
66 |
67 |
68 | 71 | 72 |

vuer is an R package that makes it easy to use Vue components and build Vue apps.

73 |
74 |

Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. It is designed from the ground up to be incrementally adoptable, and can easily scale between a library and a framework depending on different use cases.

75 |
76 |
77 |

78 | Installation

79 |

You can install vuer from github using remotes or devtools.

80 |
remotes::install_github('ramnathv/vuer')
81 |
82 |
83 |

84 | Usage

85 |
86 |

87 | Example 1: Hello World

88 |

We can use vuer to create purely client-side web-apps taking advantage of its simple API and two-way data bindings. In this simple example, we let a user enter their name and display a greeting message.

89 | 98 |

hello-world

99 |

The power of vuer starts truly shining when we are able to let Vue communicate with Shiny. This opens up an unlimited range of possibilities that we will explore in detail. The next two examples explore how Vue and Shiny can communicate with each other.

100 |
101 |
102 |

103 | Example 2: Vue -> Shiny

104 |

It is dead-simple to let Vue communicate with Shiny. All it takes is adding an underscore at the end of any data variable passed to Vue. This automatically sets up watcher functions to update shiny when the underlying value changes, thereby triggering any reactive paths that depend on it. This example is very similar to the first one in that we let a user enter their name and display a greeting message. The key difference is that the greeting message is from Shiny on the server side.

105 | 124 |
125 |
126 |

127 | Example 3: Shiny -> Vue

128 |

It is equally easy to let Shiny communicate with Vue. In this example we pass the coordinates of a plot brush to Vue and display it as JSON.

129 |
library(shiny)
130 | library(ggplot2)
131 | library(vuer)
132 | ui <- fluidPage(theme = shinythemes::shinytheme("cosmo"),
133 |   titlePanel(title = 'Shiny -> Vue'),
134 |   mainPanel(
135 |     plotOutput('plot', brush = brushOpts('plot_brush'), height = '300'),
136 |     tags$pre("v-if" = "plot_brush !== null", 
137 |       tags$code("{{plot_brush}}")
138 |     ) %>% 
139 |       Vue(data = list(plot_brush = c()), elementId = "app")
140 |   )
141 | )
142 | 
143 | server <- function(input, output, session){
144 |   output$plot <- renderPlot({
145 |     ggplot(mtcars, aes(x = mpg, y = wt)) +
146 |       geom_point()
147 |   })
148 |   observeEvent(input$plot_brush, {
149 |     vueProxy("app") %>% 
150 |       vueUpdateData(plot_brush = input$plot_brush$coords_img)
151 |   })
152 | }
153 | shinyApp(ui = ui, server = server)
154 |

shiny-vue

155 |
156 |
157 |
158 |

159 | Acknowledgements

160 |

This package was inspired by Kenton Russell’s experiments using Vue in R, as well as the efforts taken by the react-R team in integrating React.js with R.

161 |
162 |
163 |
164 | 165 | 197 |
198 | 199 | 207 |
208 | 209 | 210 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/pkgdown.css: -------------------------------------------------------------------------------- 1 | /* Sticky footer */ 2 | 3 | /** 4 | * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ 5 | * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css 6 | * 7 | * .Site -> body > .container 8 | * .Site-content -> body > .container .row 9 | * .footer -> footer 10 | * 11 | * Key idea seems to be to ensure that .container and __all its parents__ 12 | * have height set to 100% 13 | * 14 | */ 15 | 16 | html, body { 17 | height: 100%; 18 | } 19 | 20 | body > .container { 21 | display: flex; 22 | height: 100%; 23 | flex-direction: column; 24 | 25 | padding-top: 60px; 26 | } 27 | 28 | body > .container .row { 29 | flex: 1 0 auto; 30 | } 31 | 32 | footer { 33 | margin-top: 45px; 34 | padding: 35px 0 36px; 35 | border-top: 1px solid #e5e5e5; 36 | color: #666; 37 | display: flex; 38 | flex-shrink: 0; 39 | } 40 | footer p { 41 | margin-bottom: 0; 42 | } 43 | footer div { 44 | flex: 1; 45 | } 46 | footer .pkgdown { 47 | text-align: right; 48 | } 49 | footer p { 50 | margin-bottom: 0; 51 | } 52 | 53 | img.icon { 54 | float: right; 55 | } 56 | 57 | img { 58 | max-width: 100%; 59 | } 60 | 61 | /* Fix bug in bootstrap (only seen in firefox) */ 62 | summary { 63 | display: list-item; 64 | } 65 | 66 | /* Typographic tweaking ---------------------------------*/ 67 | 68 | .contents .page-header { 69 | margin-top: calc(-60px + 1em); 70 | } 71 | 72 | /* Section anchors ---------------------------------*/ 73 | 74 | a.anchor { 75 | margin-left: -30px; 76 | display:inline-block; 77 | width: 30px; 78 | height: 30px; 79 | visibility: hidden; 80 | 81 | background-image: url(./link.svg); 82 | background-repeat: no-repeat; 83 | background-size: 20px 20px; 84 | background-position: center center; 85 | } 86 | 87 | .hasAnchor:hover a.anchor { 88 | visibility: visible; 89 | } 90 | 91 | @media (max-width: 767px) { 92 | .hasAnchor:hover a.anchor { 93 | visibility: hidden; 94 | } 95 | } 96 | 97 | 98 | /* Fixes for fixed navbar --------------------------*/ 99 | 100 | .contents h1, .contents h2, .contents h3, .contents h4 { 101 | padding-top: 60px; 102 | margin-top: -40px; 103 | } 104 | 105 | /* Static header placement on mobile devices */ 106 | @media (max-width: 767px) { 107 | .navbar-fixed-top { 108 | position: absolute; 109 | } 110 | .navbar { 111 | padding: 0; 112 | } 113 | } 114 | 115 | 116 | /* Sidebar --------------------------*/ 117 | 118 | #sidebar { 119 | margin-top: 30px; 120 | } 121 | #sidebar h2 { 122 | font-size: 1.5em; 123 | margin-top: 1em; 124 | } 125 | 126 | #sidebar h2:first-child { 127 | margin-top: 0; 128 | } 129 | 130 | #sidebar .list-unstyled li { 131 | margin-bottom: 0.5em; 132 | } 133 | 134 | .orcid { 135 | height: 16px; 136 | vertical-align: middle; 137 | } 138 | 139 | /* Reference index & topics ----------------------------------------------- */ 140 | 141 | .ref-index th {font-weight: normal;} 142 | 143 | .ref-index td {vertical-align: top;} 144 | .ref-index .icon {width: 40px;} 145 | .ref-index .alias {width: 40%;} 146 | .ref-index-icons .alias {width: calc(40% - 40px);} 147 | .ref-index .title {width: 60%;} 148 | 149 | .ref-arguments th {text-align: right; padding-right: 10px;} 150 | .ref-arguments th, .ref-arguments td {vertical-align: top;} 151 | .ref-arguments .name {width: 20%;} 152 | .ref-arguments .desc {width: 80%;} 153 | 154 | /* Nice scrolling for wide elements --------------------------------------- */ 155 | 156 | table { 157 | display: block; 158 | overflow: auto; 159 | } 160 | 161 | /* Syntax highlighting ---------------------------------------------------- */ 162 | 163 | pre { 164 | word-wrap: normal; 165 | word-break: normal; 166 | border: 1px solid #eee; 167 | } 168 | 169 | pre, code { 170 | background-color: #f8f8f8; 171 | color: #333; 172 | } 173 | 174 | pre code { 175 | overflow: auto; 176 | word-wrap: normal; 177 | white-space: pre; 178 | } 179 | 180 | pre .img { 181 | margin: 5px 0; 182 | } 183 | 184 | pre .img img { 185 | background-color: #fff; 186 | display: block; 187 | height: auto; 188 | } 189 | 190 | code a, pre a { 191 | color: #375f84; 192 | } 193 | 194 | a.sourceLine:hover { 195 | text-decoration: none; 196 | } 197 | 198 | .fl {color: #1514b5;} 199 | .fu {color: #000000;} /* function */ 200 | .ch,.st {color: #036a07;} /* string */ 201 | .kw {color: #264D66;} /* keyword */ 202 | .co {color: #888888;} /* comment */ 203 | 204 | .message { color: black; font-weight: bolder;} 205 | .error { color: orange; font-weight: bolder;} 206 | .warning { color: #6A0366; font-weight: bolder;} 207 | 208 | /* Clipboard --------------------------*/ 209 | 210 | .hasCopyButton { 211 | position: relative; 212 | } 213 | 214 | .btn-copy-ex { 215 | position: absolute; 216 | right: 0; 217 | top: 0; 218 | visibility: hidden; 219 | } 220 | 221 | .hasCopyButton:hover button.btn-copy-ex { 222 | visibility: visible; 223 | } 224 | 225 | /* mark.js ----------------------------*/ 226 | 227 | mark { 228 | background-color: rgba(255, 255, 51, 0.5); 229 | border-bottom: 2px solid rgba(255, 153, 51, 0.3); 230 | padding: 1px; 231 | } 232 | 233 | /* vertical spacing after htmlwidgets */ 234 | .html-widget { 235 | margin-bottom: 10px; 236 | } 237 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $("#sidebar") 6 | .stick_in_parent({offset_top: 40}) 7 | .on('sticky_kit:bottom', function(e) { 8 | $(this).parent().css('position', 'static'); 9 | }) 10 | .on('sticky_kit:unbottom', function(e) { 11 | $(this).parent().css('position', 'relative'); 12 | }); 13 | 14 | $('body').scrollspy({ 15 | target: '#sidebar', 16 | offset: 60 17 | }); 18 | 19 | $('[data-toggle="tooltip"]').tooltip(); 20 | 21 | var cur_path = paths(location.pathname); 22 | var links = $("#navbar ul li a"); 23 | var max_length = -1; 24 | var pos = -1; 25 | for (var i = 0; i < links.length; i++) { 26 | if (links[i].getAttribute("href") === "#") 27 | continue; 28 | // Ignore external links 29 | if (links[i].host !== location.host) 30 | continue; 31 | 32 | var nav_path = paths(links[i].pathname); 33 | 34 | var length = prefix_length(nav_path, cur_path); 35 | if (length > max_length) { 36 | max_length = length; 37 | pos = i; 38 | } 39 | } 40 | 41 | // Add class to parent
  • , and enclosing
  • if in dropdown 42 | if (pos >= 0) { 43 | var menu_anchor = $(links[pos]); 44 | menu_anchor.parent().addClass("active"); 45 | menu_anchor.closest("li.dropdown").addClass("active"); 46 | } 47 | }); 48 | 49 | function paths(pathname) { 50 | var pieces = pathname.split("/"); 51 | pieces.shift(); // always starts with / 52 | 53 | var end = pieces[pieces.length - 1]; 54 | if (end === "index.html" || end === "") 55 | pieces.pop(); 56 | return(pieces); 57 | } 58 | 59 | // Returns -1 if not found 60 | function prefix_length(needle, haystack) { 61 | if (needle.length > haystack.length) 62 | return(-1); 63 | 64 | // Special case for length-0 haystack, since for loop won't run 65 | if (haystack.length === 0) { 66 | return(needle.length === 0 ? 0 : -1); 67 | } 68 | 69 | for (var i = 0; i < haystack.length; i++) { 70 | if (needle[i] != haystack[i]) 71 | return(i); 72 | } 73 | 74 | return(haystack.length); 75 | } 76 | 77 | /* Clipboard --------------------------*/ 78 | 79 | function changeTooltipMessage(element, msg) { 80 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 81 | element.setAttribute('data-original-title', msg); 82 | $(element).tooltip('show'); 83 | element.setAttribute('data-original-title', tooltipOriginalTitle); 84 | } 85 | 86 | if(ClipboardJS.isSupported()) { 87 | $(document).ready(function() { 88 | var copyButton = ""; 89 | 90 | $(".examples, div.sourceCode").addClass("hasCopyButton"); 91 | 92 | // Insert copy buttons: 93 | $(copyButton).prependTo(".hasCopyButton"); 94 | 95 | // Initialize tooltips: 96 | $('.btn-copy-ex').tooltip({container: 'body'}); 97 | 98 | // Initialize clipboard: 99 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 100 | text: function(trigger) { 101 | return trigger.parentNode.textContent; 102 | } 103 | }); 104 | 105 | clipboardBtnCopies.on('success', function(e) { 106 | changeTooltipMessage(e.trigger, 'Copied!'); 107 | e.clearSelection(); 108 | }); 109 | 110 | clipboardBtnCopies.on('error', function() { 111 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 112 | }); 113 | }); 114 | } 115 | })(window.jQuery || window.$) 116 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 2.3.1 2 | pkgdown: 1.3.0 3 | pkgdown_sha: ~ 4 | articles: [] 5 | 6 | -------------------------------------------------------------------------------- /docs/reference/appendDependencies.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Append html dependencies — appendDependencies • vuer 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 51 | 52 | 53 |
    54 |
    55 | 95 | 96 | 97 |
    98 | 99 |
    100 |
    101 | 106 | 107 |
    108 | 109 |

    NOTE: This function has been copied over from shinydashboard

    110 | 111 |
    112 | 113 |
    appendDependencies(x, value)
    114 | 115 | 116 |
    117 | 123 |
    124 | 125 |
    126 | 129 | 130 |
    131 |

    Site built with pkgdown 1.3.0.

    132 |
    133 |
    134 |
    135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/reference/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Function reference • vuer 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 49 | 50 |
    51 |
    52 | 92 | 93 | 94 |
    95 | 96 |
    97 |
    98 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 116 | 117 | 118 | 119 | 122 | 123 | 124 | 125 | 128 | 129 | 130 | 131 | 134 | 135 | 136 | 137 | 140 | 141 | 142 | 143 | 146 | 147 | 148 | 149 |
    113 |

    All functions

    114 |

    115 |
    120 |

    appendDependencies()

    121 |

    Append html dependencies

    126 |

    Vue()

    127 |

    Create a Vue App

    132 |

    vueProxy() vueUpdateData()

    133 |

    Send commands to a Vue instance in a Shiny app

    138 |

    vueUpdateShinyInputs()

    139 |

    Update Shiny Input

    144 |

    vueUsePlugin()

    145 |

    Use a vue Plugin

    150 |
    151 | 152 | 158 |
    159 | 160 |
    161 | 164 | 165 |
    166 |

    Site built with pkgdown 1.3.0.

    167 |
    168 |
    169 |
    170 | 171 | 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /docs/reference/pipe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Pipe operator — %>% • vuer 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 51 | 52 | 53 |
    54 |
    55 | 95 | 96 | 97 |
    98 | 99 |
    100 |
    101 | 106 | 107 |
    108 | 109 |

    See magrittr::%>% for details.

    110 | 111 |
    112 | 113 |
    lhs %>% rhs
    114 | 115 | 116 |
    117 | 123 |
    124 | 125 |
    126 | 129 | 130 |
    131 |

    Site built with pkgdown 1.3.0.

    132 |
    133 |
    134 |
    135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/reference/vue.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Create a Vue App — Vue • vuer 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 51 | 52 | 53 |
    54 |
    55 | 95 | 96 | 97 |
    98 | 99 |
    100 |
    101 | 106 | 107 |
    108 | 109 |

    Create a Vue App

    110 | 111 |
    112 | 113 |
    Vue(html, data = list(), dependencies = list(), ...,
    114 |   elementId = NULL)
    115 | 116 | 117 |

    Examples

    118 |
    # NOT RUN {
    119 | library(htmltools)
    120 | tags$div(
    121 |   tags$label('Enter your name'),
    122 |   tags$input(type = "text", "v-model" = "name"),
    123 |   tags$p("Hello {{name}}")
    124 |   ) %>%
    125 |   Vue(data = list(name = ""))
    126 | 
    127 | if (interactive()){
    128 |   library(shiny)
    129 |   ui <- tags$div(
    130 |     tags$label('Enter your name'),
    131 |     tags$input(type = "text", "v-model" = "name"),
    132 |     textOutput("greeting")
    133 |   ) %>%
    134 |     Vue(data = list(name_ = ""))
    135 |   server <- function(input, output, session){
    136 |     output$greeting <- renderText({
    137 |       paste("Hello", input$name)
    138 |     })
    139 |   }
    140 |   shinyApp(ui = ui, server = server)
    141 | }
    142 | # }
    143 |
    144 | 152 |
    153 | 154 |
    155 | 158 | 159 |
    160 |

    Site built with pkgdown 1.3.0.

    161 |
    162 |
    163 |
    164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /docs/reference/vueProxy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Send commands to a Vue instance in a Shiny app — vueProxy • vuer 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 50 | 51 | 52 | 53 | 54 |
    55 |
    56 | 96 | 97 | 98 |
    99 | 100 |
    101 |
    102 | 107 | 108 |
    109 | 110 |

    Send commands to a Vue instance in a Shiny app

    111 |

    Update data in a Vue instance

    112 | 113 |
    114 | 115 |
    vueProxy(outputId, session = shiny::getDefaultReactiveDomain(),
    116 |   deferUntilFlush = TRUE)
    117 | 
    118 | vueUpdateData(proxy, ...)
    119 | 120 | 121 |

    Examples

    122 |
    # NOT RUN {
    123 | ui <- div(
    124 |   tags$label("Enter username"),
    125 |   tags$input(type = 'text', "v-model" = "username"),
    126 |   tags$p("Vue -> Vue: Hello {{username}}"),
    127 |   actionButton("set_name", "Shiny -> Vue"),
    128 |   verbatimTextOutput("username")
    129 | ) %>%
    130 |   vue(
    131 |     data = list(username = ""),
    132 |     # Vue UI -> Shiny UI
    133 |     watch = vue_watch("username"),
    134 |    elementId = "app"
    135 |  )
    136 | server <- function(input, output, session){
    137 |   # Shiny server -> Vue UI
    138 |   observeEvent(input$set_name, {
    139 |     vueProxy("app") %>%
    140 |       updateProp("username", "Ramnath")
    141 |   })
    142 |   output$username <- renderPrint({
    143 |     paste("Vue -> Shiny:", input$username)
    144 |   })
    145 | }
    146 | shiny::shinyApp(ui = ui, server = server)
    147 | # }
    148 |
    149 | 157 |
    158 | 159 |
    160 | 163 | 164 |
    165 |

    Site built with pkgdown 1.3.0.

    166 |
    167 |
    168 |
    169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/reference/vueUpdateShinyInputs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Update Shiny Input — vueUpdateShinyInputs • vuer 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 51 | 52 | 53 |
    54 |
    55 | 95 | 96 | 97 |
    98 | 99 |
    100 |
    101 | 106 | 107 |
    108 | 109 |

    Update Shiny Input

    110 | 111 |
    112 | 113 |
    vueUpdateShinyInputs(...)
    114 | 115 | 116 |
    117 | 123 |
    124 | 125 |
    126 | 129 | 130 |
    131 |

    Site built with pkgdown 1.3.0.

    132 |
    133 |
    134 |
    135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/reference/vueUsePlugin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Use a vue Plugin — vueUsePlugin • vuer 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 51 | 52 | 53 |
    54 |
    55 | 95 | 96 | 97 |
    98 | 99 |
    100 |
    101 | 106 | 107 |
    108 | 109 |

    Use a vue Plugin

    110 | 111 |
    112 | 113 |
    vueUsePlugin(fun)
    114 | 115 | 116 |
    117 | 123 |
    124 | 125 |
    126 | 129 | 130 |
    131 |

    Site built with pkgdown 1.3.0.

    132 |
    133 |
    134 |
    135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /inst/examples/apexcharts.R: -------------------------------------------------------------------------------- 1 | library(vuer) 2 | 3 | htmlDependenciesApexCharts <- function(){ 4 | list( 5 | htmltools::htmlDependency( 6 | name = 'apexcharts', 7 | version = '2.7.0', 8 | src = c(href = 'https://unpkg.com/apexcharts/dist'), 9 | script = 'apexcharts.js' 10 | ), 11 | htmltools::htmlDependency( 12 | name = 'vue-apexcharts', 13 | version = '1.3.0', 14 | src = c(href = "https://unpkg.com/vue-apexcharts/dist"), 15 | script = 'vue-apexcharts.js' 16 | ) 17 | ) 18 | } 19 | 20 | vueApexChart <- function(...){ 21 | vueComponents$register(apexchart = 'VueApexCharts') 22 | htmltools::tag("apexchart", list(...)) %>% 23 | appendDependencies(htmlDependenciesApexCharts()) 24 | } 25 | 26 | data <- list( 27 | chartOptions = list( 28 | chart = list( 29 | xaxis = list( 30 | categories = as.character(1991:1998) 31 | ) 32 | ) 33 | ), 34 | series = list( 35 | list(name = 'series-1', data = sample(40:100, 8)) 36 | ) 37 | ) 38 | 39 | library(shiny) 40 | ui <- div( 41 | vueApexChart(height = 350, ":series" = "series", type = "bar", 42 | ":options" = "chartOptions" 43 | ), 44 | actionButton("update_data", "Update Data") 45 | ) %>% 46 | vue(data = data, elementId = "chart") 47 | 48 | server <- function(input, output, session){ 49 | observeEvent(input$update_data, { 50 | vueProxy("chart") %>% 51 | vueUpdateData(series = list(list(data = sample(40:80, 8)))) 52 | }) 53 | } 54 | 55 | shinyApp(ui = ui, server = server) 56 | -------------------------------------------------------------------------------- /inst/examples/basic-vtags.R: -------------------------------------------------------------------------------- 1 | library(htmltools) 2 | library(vuer) 3 | 4 | # Example 1: Hello World 5 | 6 | vtags$div("{{ message }}") %>% 7 | Vue(data = list(message = 'Hello World')) 8 | 9 | # Example 2: 10 | 11 | 12 | vtags$span( 13 | vbind.title = "message", 14 | "Hover your mouse over me for a few seconds to see my dynamically bound title!" 15 | ) %>% 16 | Vue(data = list( 17 | message = htmlwidgets::JS("'You loaded me on ' + new Date()") 18 | )) 19 | 20 | # Example 3: 21 | 22 | tags$div(id = 'app', 23 | vtags$h3("Use the checkbox to toggle visibility of the message"), 24 | vtags$input(type = "checkbox", vmodel = "seen"), 25 | vtags$span(vif = "seen", "Now you see me again") 26 | ) %>% 27 | Vue(data = list(seen = TRUE)) 28 | 29 | # Example 4: Lists 30 | 31 | vtags$li(vfor = "column in columns", "{{ column }}") %>% 32 | tags$ul(id = 'app') %>% 33 | Vue(data = list(columns = names(mtcars))) 34 | 35 | # Example 5: 36 | 37 | tags$div(id = 'app', 38 | vtags$input(type = 'text', vmodel = "message"), 39 | tags$p("{{ message }}"), 40 | vtags$button(von.click = "reverseMessage", "Reverse Message") 41 | ) %>% 42 | Vue( 43 | data = list(message = 'Hello World'), 44 | methods = list( 45 | reverseMessage = htmlwidgets::JS("function(){ 46 | this.message = this.message.split('').reverse().join('') 47 | }") 48 | ) 49 | ) 50 | 51 | -------------------------------------------------------------------------------- /inst/examples/basic.R: -------------------------------------------------------------------------------- 1 | library(htmltools) 2 | library(vuer) 3 | library(magrittr) 4 | 5 | # Example 1: Hello World 6 | 7 | tags$div("{{ message }}") %>% 8 | Vue(data = list(message = 'Hello World')) 9 | 10 | # Example 2: 11 | 12 | 13 | tags$span( 14 | "v-bind:title" = "message", 15 | "Hover your mouse over me for a few seconds to see my dynamically bound title!" 16 | ) %>% 17 | Vue(data = list( 18 | message = htmlwidgets::JS("'You loaded me on ' + new Date()") 19 | )) 20 | 21 | # Example 3: 22 | 23 | tags$div(id = 'app', 24 | tags$h3("Use the checkbox to toggle visibility of the message"), 25 | tags$input(type = "checkbox", "v-model" = "seen"), 26 | tags$span("v-if" = "seen", "Now you see me again") 27 | ) %>% 28 | Vue(data = list(seen = TRUE)) 29 | 30 | # Example 4: Lists 31 | 32 | tags$li("v-for" = "column in columns", "{{ column }}") %>% 33 | tags$ul(id = 'app') %>% 34 | Vue(data = list(columns = names(mtcars))) 35 | 36 | # Example 5: 37 | 38 | tags$div(id = 'app', 39 | tags$input(type = 'text', "v-model" = "message"), 40 | tags$p("{{ message }}"), 41 | tags$button("v-on:click" = "reverseMessage", "Reverse Message") 42 | ) %>% 43 | Vue( 44 | data = list(message = 'Hello World'), 45 | methods = list( 46 | reverseMessage = htmlwidgets::JS("function(){ 47 | this.message = this.message.split('').reverse().join('') 48 | }") 49 | ) 50 | ) 51 | 52 | # Example 6 53 | 54 | tags$div(id = "app", 55 | tags$button("v-on:click" = "handleClick", 56 | "Clicked {{ count }} {{ count === 1 ? 'time' : 'times' }}" 57 | ) 58 | ) %>% 59 | Vue( 60 | data = list(count = 0), 61 | methods = list( 62 | handleClick = htmlwidgets::JS("function(){ 63 | this.count += 1 64 | }") 65 | ) 66 | ) 67 | -------------------------------------------------------------------------------- /inst/examples/colorpicker.R: -------------------------------------------------------------------------------- 1 | library(vuer) 2 | library(ggplot2) 3 | library(shiny) 4 | 5 | html_dependencies_vue_color <- function(){ 6 | list( 7 | htmltools::htmlDependency( 8 | name = 'vue-color', 9 | version = '2.7.0', 10 | src = c(href = 'https://unpkg.com/vue-color/dist'), 11 | script = 'vue-color.min.js' 12 | ) 13 | ) 14 | } 15 | 16 | vueColorPickerInput <- function(type = types, ...){ 17 | types <- c('compact', 'chrome', 'swatches', 'sketch') 18 | types %>% 19 | purrr::map(~ { 20 | .x %>% 21 | stringi::stri_trans_totitle() %>% 22 | paste0('VueColor.', .) 23 | }) %>% 24 | rlang::set_names(paste0(types, '-picker')) %>% 25 | vueComponents$register(.list = .) 26 | type <- match.arg(type) 27 | htmltools::tag( 28 | sprintf("%s-picker", type), list("v-model" = "colors", ...) 29 | ) %>% 30 | appendDependencies(html_dependencies_vue_color()) 31 | } 32 | 33 | 34 | vueColorPickerInput(type = "sketch") %>% 35 | Vue(data = list(colors_ = '#fff')) 36 | 37 | ui <- div( 38 | vueColorPickerInput(type = "sketch"), 39 | shiny::plotOutput('plot') 40 | ) %>% 41 | Vue( 42 | data = list(colors_ = '#fff') 43 | ) 44 | 45 | server <- function(input, output, session){ 46 | output$plot <- renderPlot({ 47 | mycolor <- if (is.null(input$colors)) 'black' else input$colors$hex[1] 48 | ggplot(mtcars, (aes(x = wt, y = mpg))) + 49 | geom_point(color = mycolor) 50 | }) 51 | output$colors <- renderText({ 52 | input$colors$hex[1] 53 | }) 54 | } 55 | 56 | shiny::shinyApp(ui = ui, server = server) 57 | -------------------------------------------------------------------------------- /inst/examples/elementui.R: -------------------------------------------------------------------------------- 1 | library(vuer) 2 | 3 | htmlDependenciesElementUI <- function(){ 4 | list( 5 | htmlDependency( 6 | name = 'vue', 7 | version = '2.6.6', 8 | src = system.file('htmlwidgets', 'lib','vue', package = 'vuer'), 9 | script = "vue.js" 10 | ), 11 | htmlDependency( 12 | name = 'element-ui', 13 | version = '2.6.0', 14 | src = c(href = "https://unpkg.com/element-ui/lib"), 15 | script = "index.js", 16 | stylesheet = "theme-chalk/index.css" 17 | ) 18 | ) 19 | } 20 | 21 | 22 | 23 | create_tags <- function(types, prefix){ 24 | types %>% 25 | purrr::map(~ { 26 | function(...){ 27 | vtag(paste0(prefix, '-', .x), list(...)) 28 | } 29 | }) %>% 30 | rlang::set_names( 31 | types %>% 32 | stringr::str_replace("-", "_") 33 | ) 34 | } 35 | 36 | 37 | types <- c('button', 'color-picker') 38 | el_tags <- create_tags(types, 'el') 39 | 40 | el_tags$button(type = 'Primary', "Primary") %>% 41 | appendDependencies(htmlDependenciesElementUI()) %>% 42 | Vue() 43 | 44 | el_tags$color_picker("v-model" = "color") %>% 45 | appendDependencies(htmlDependenciesElementUI()) %>% 46 | Vue(data = list(color = '#fff')) 47 | 48 | -------------------------------------------------------------------------------- /inst/examples/mint.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | #### Mint examples ####################################### 3 | mint <- htmlDependency( 4 | name = "mint-ui", 5 | version = "2.0.5", 6 | src = c(href="https://unpkg.com/mint-ui/lib"), 7 | script = "index.js", 8 | stylesheet = "style.css" 9 | ) 10 | 11 | ui <- tags$div( 12 | #tags$script("Vue.use(MINT)"), 13 | vtag("mt-switch",list(vmodel ="value","{{value ? 'on' : 'off'}}")), 14 | vtag( 15 | "mt-checklist", 16 | list( 17 | title="checkbox list", 18 | vmodel = "checkbox_value", 19 | vbind.options = "['Item A', 'Item B', 'Item C']" 20 | ) 21 | ), 22 | tags$p("Vue: {{ value }}"), 23 | textOutput('value'), 24 | textOutput('checkbox_value') 25 | ) %>% 26 | Vue( 27 | data = list( 28 | value_ = TRUE, 29 | checkbox_value_ = list() 30 | ) 31 | ) %>% 32 | shinydashboard:::appendDependencies(mint) 33 | 34 | 35 | 36 | server <- function(input, output, session){ 37 | output$value <- renderText({ 38 | paste("Shiny:", input$value) 39 | }) 40 | output$checkbox_value <- renderText({ 41 | paste("Shiny:", input$checkbox_value) 42 | }) 43 | } 44 | 45 | shinyApp(ui = ui, server = server) 46 | -------------------------------------------------------------------------------- /inst/examples/sunburst.R: -------------------------------------------------------------------------------- 1 | # Load Libraries ---- 2 | library(shiny) 3 | library(treemap) 4 | library(vuer) 5 | library(magrittr) 6 | library(htmltools) 7 | library(htmlwidgets) 8 | library(d3r) 9 | jsFun <- function(body, ...){ 10 | args <- paste(c(...), collapse = ",") 11 | htmlwidgets::JS(sprintf("function(%s){%s}", args, body)) 12 | } 13 | 14 | # Define Dependencies ---- 15 | html_dependencies_d2b <- function(){ 16 | list( 17 | d3r::d3_dep_v4(offline = FALSE), 18 | htmltools::htmlDependency( 19 | name = "d2b", 20 | version = "0.0.24", 21 | src = c(href = "https://unpkg.com/d2b@0.0.24/build/"), 22 | script = "d2b.min.js" 23 | ) 24 | ) 25 | } 26 | 27 | # Define Chart Generator 28 | vueSunburstChart <- function(...){ 29 | vuer::vueComponents$register( 30 | "sunburst-chart" = "d2b.vueChartSunburst" 31 | ) 32 | tag('sunburst-chart', list(...)) %>% 33 | appendDependencies(html_dependencies_d2b()) 34 | } 35 | 36 | 37 | 38 | # UI ---- 39 | ui <- tags$div(style = 'height:400px', 40 | vueSunburstChart(":data" = "chart_data", ":config" = "chart_config"), 41 | actionButton('update_data', 'Update Data') 42 | ) %>% 43 | Vue( 44 | data = list( 45 | chart_data_ = d3r::d3_nest( 46 | treemap::random.hierarchical.data(), 47 | value_cols = "x" 48 | ), 49 | chart_config = jsFun(" 50 | chart.label((d) => d.name); 51 | chart.sunburst().size((d) => d.x); 52 | ", "chart") 53 | ), 54 | elementId = 'mychart', 55 | width = '100%' 56 | ) 57 | 58 | 59 | # Server ---- 60 | server <- function(input, output, session){ 61 | observeEvent(input$update_data, { 62 | vueProxy('mychart') %>% 63 | vueUpdateData( 64 | chart_data = d3r::d3_nest( 65 | treemap::random.hierarchical.data(), 66 | value_cols = "x" 67 | ) 68 | ) 69 | }) 70 | } 71 | 72 | shinyApp(ui = ui, server = server) 73 | -------------------------------------------------------------------------------- /inst/examples/treeview.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(vuer) 3 | 4 | html_deps_vue_tree_view <- function(){ 5 | htmltools::htmlDependency( 6 | name = 'vue-json-tree-view', 7 | version = '2.0.6', 8 | src = c(href = "https://unpkg.com/vue-json-tree-view@2.0.6/dist"), 9 | script = 'vue-json-tree-view.min.js' 10 | ) 11 | } 12 | 13 | vueJsonTreeOutput <- function(...){ 14 | tagList( 15 | tag('tree-view', list(...)) %>% 16 | appendDependencies(html_deps_vue_tree_view()), 17 | tags$script('Vue.use(TreeView)') 18 | ) 19 | } 20 | 21 | ## Example 1: 22 | div(vueJsonTreeOutput(":data" = "data")) %>% 23 | Vue(data = list(data = list(x = 1, y = 2))) 24 | 25 | 26 | ## Example 2: 27 | ui <- fluidPage( 28 | titlePanel("Shiny with Vue"), 29 | mainPanel( 30 | fluidRow( 31 | plotOutput('plot1', brush = brushOpts(id = 'plot_brush')), 32 | vueJsonTreeOutput(":data" = "data") 33 | ) %>% 34 | vuepkg::Vue( 35 | data = list(data = list()), 36 | elementId = "app" 37 | ) 38 | ) 39 | ) 40 | 41 | server <- function(input,output,session){ 42 | output$plot1 <- renderPlot({ 43 | require(ggplot2) 44 | ggplot(mtcars, aes(x = mpg, y = wt)) + 45 | geom_point() 46 | }) 47 | observeEvent(input$plot_brush, { 48 | vueProxy("app") %>% 49 | vueUpdateData(data = input$plot_brush) 50 | }) 51 | } 52 | 53 | shinyApp(ui = ui, server = server) 54 | 55 | -------------------------------------------------------------------------------- /inst/htmlwidgets/lib/vue/vue.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Vue.js v2.6.6 3 | * (c) 2014-2019 Evan You 4 | * Released under the MIT License. 5 | */ 6 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).Vue=t()}(this,function(){"use strict";var e=Object.freeze({});function t(e){return null==e}function n(e){return null!=e}function r(e){return!0===e}function i(e){return"string"==typeof e||"number"==typeof e||"symbol"==typeof e||"boolean"==typeof e}function o(e){return null!==e&&"object"==typeof e}var a=Object.prototype.toString;function s(e){return"[object Object]"===a.call(e)}function c(e){var t=parseFloat(String(e));return t>=0&&Math.floor(t)===t&&isFinite(e)}function u(e){return n(e)&&"function"==typeof e.then&&"function"==typeof e.catch}function l(e){return null==e?"":Array.isArray(e)||s(e)&&e.toString===a?JSON.stringify(e,null,2):String(e)}function f(e){var t=parseFloat(e);return isNaN(t)?e:t}function p(e,t){for(var n=Object.create(null),r=e.split(","),i=0;i-1)return e.splice(n,1)}}var m=Object.prototype.hasOwnProperty;function y(e,t){return m.call(e,t)}function g(e){var t=Object.create(null);return function(n){return t[n]||(t[n]=e(n))}}var _=/-(\w)/g,b=g(function(e){return e.replace(_,function(e,t){return t?t.toUpperCase():""})}),$=g(function(e){return e.charAt(0).toUpperCase()+e.slice(1)}),w=/\B([A-Z])/g,x=g(function(e){return e.replace(w,"-$1").toLowerCase()});var C=Function.prototype.bind?function(e,t){return e.bind(t)}:function(e,t){function n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}return n._length=e.length,n};function A(e,t){t=t||0;for(var n=e.length-t,r=new Array(n);n--;)r[n]=e[n+t];return r}function k(e,t){for(var n in t)e[n]=t[n];return e}function O(e){for(var t={},n=0;n0,W=K&&K.indexOf("edge/")>0,Z=(K&&K.indexOf("android"),K&&/iphone|ipad|ipod|ios/.test(K)||"ios"===V),G=(K&&/chrome\/\d+/.test(K),K&&/phantomjs/.test(K),K&&K.match(/firefox\/(\d+)/)),X={}.watch,Y=!1;if(U)try{var Q={};Object.defineProperty(Q,"passive",{get:function(){Y=!0}}),window.addEventListener("test-passive",null,Q)}catch(e){}var ee=function(){return void 0===H&&(H=!U&&!z&&"undefined"!=typeof global&&(global.process&&"server"===global.process.env.VUE_ENV)),H},te=U&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function ne(e){return"function"==typeof e&&/native code/.test(e.toString())}var re,ie="undefined"!=typeof Symbol&&ne(Symbol)&&"undefined"!=typeof Reflect&&ne(Reflect.ownKeys);re="undefined"!=typeof Set&&ne(Set)?Set:function(){function e(){this.set=Object.create(null)}return e.prototype.has=function(e){return!0===this.set[e]},e.prototype.add=function(e){this.set[e]=!0},e.prototype.clear=function(){this.set=Object.create(null)},e}();var oe=S,ae=0,se=function(){this.id=ae++,this.subs=[]};se.prototype.addSub=function(e){this.subs.push(e)},se.prototype.removeSub=function(e){h(this.subs,e)},se.prototype.depend=function(){se.target&&se.target.addDep(this)},se.prototype.notify=function(){for(var e=this.subs.slice(),t=0,n=e.length;t-1)if(o&&!y(i,"default"))a=!1;else if(""===a||a===x(e)){var c=Pe(String,i.type);(c<0||s0&&(at((u=e(u,(a||"")+"_"+c))[0])&&at(f)&&(s[l]=ve(f.text+u[0].text),u.shift()),s.push.apply(s,u)):i(u)?at(f)?s[l]=ve(f.text+u):""!==u&&s.push(ve(u)):at(u)&&at(f)?s[l]=ve(f.text+u.text):(r(o._isVList)&&n(u.tag)&&t(u.key)&&n(a)&&(u.key="__vlist"+a+"_"+c+"__"),s.push(u)));return s}(e):void 0}function at(e){return n(e)&&n(e.text)&&!1===e.isComment}function st(e,t){if(e){for(var n=Object.create(null),r=ie?Reflect.ownKeys(e):Object.keys(e),i=0;idocument.createEvent("Event").timeStamp&&(an=function(){return performance.now()});var cn=0,un=function(e,t,n,r,i){this.vm=e,i&&(e._watcher=this),e._watchers.push(this),r?(this.deep=!!r.deep,this.user=!!r.user,this.lazy=!!r.lazy,this.sync=!!r.sync,this.before=r.before):this.deep=this.user=this.lazy=this.sync=!1,this.cb=n,this.id=++cn,this.active=!0,this.dirty=this.lazy,this.deps=[],this.newDeps=[],this.depIds=new re,this.newDepIds=new re,this.expression="","function"==typeof t?this.getter=t:(this.getter=function(e){if(!F.test(e)){var t=e.split(".");return function(e){for(var n=0;nrn&&Yt[n].id>e.id;)n--;Yt.splice(n+1,0,e)}else Yt.push(e);tn||(tn=!0,Xe(sn))}}(this)},un.prototype.run=function(){if(this.active){var e=this.get();if(e!==this.value||o(e)||this.deep){var t=this.value;if(this.value=e,this.user)try{this.cb.call(this.vm,e,t)}catch(e){Re(e,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,e,t)}}},un.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},un.prototype.depend=function(){for(var e=this.deps.length;e--;)this.deps[e].depend()},un.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||h(this.vm._watchers,this);for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1}};var ln={enumerable:!0,configurable:!0,get:S,set:S};function fn(e,t,n){ln.get=function(){return this[t][n]},ln.set=function(e){this[t][n]=e},Object.defineProperty(e,n,ln)}function pn(e){e._watchers=[];var t=e.$options;t.props&&function(e,t){var n=e.$options.propsData||{},r=e._props={},i=e.$options._propKeys=[];e.$parent&&be(!1);var o=function(o){i.push(o);var a=Me(o,t,n,e);xe(r,o,a),o in e||fn(e,"_props",o)};for(var a in t)o(a);be(!0)}(e,t.props),t.methods&&function(e,t){e.$options.props;for(var n in t)e[n]="function"!=typeof t[n]?S:C(t[n],e)}(e,t.methods),t.data?function(e){var t=e.$options.data;s(t=e._data="function"==typeof t?function(e,t){ue();try{return e.call(t,t)}catch(e){return Re(e,t,"data()"),{}}finally{le()}}(t,e):t||{})||(t={});var n=Object.keys(t),r=e.$options.props,i=(e.$options.methods,n.length);for(;i--;){var o=n[i];r&&y(r,o)||(a=void 0,36!==(a=(o+"").charCodeAt(0))&&95!==a&&fn(e,"_data",o))}var a;we(t,!0)}(e):we(e._data={},!0),t.computed&&function(e,t){var n=e._computedWatchers=Object.create(null),r=ee();for(var i in t){var o=t[i],a="function"==typeof o?o:o.get;r||(n[i]=new un(e,a||S,S,dn)),i in e||vn(e,i,o)}}(e,t.computed),t.watch&&t.watch!==X&&function(e,t){for(var n in t){var r=t[n];if(Array.isArray(r))for(var i=0;i-1:"string"==typeof e?e.split(",").indexOf(t)>-1:(n=e,"[object RegExp]"===a.call(n)&&e.test(t));var n}function Cn(e,t){var n=e.cache,r=e.keys,i=e._vnode;for(var o in n){var a=n[o];if(a){var s=wn(a.componentOptions);s&&!t(s)&&An(n,o,r,i)}}}function An(e,t,n,r){var i=e[t];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),e[t]=null,h(n,t)}!function(t){t.prototype._init=function(t){var n=this;n._uid=gn++,n._isVue=!0,t&&t._isComponent?function(e,t){var n=e.$options=Object.create(e.constructor.options),r=t._parentVnode;n.parent=t.parent,n._parentVnode=r;var i=r.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,t.render&&(n.render=t.render,n.staticRenderFns=t.staticRenderFns)}(n,t):n.$options=Ne(_n(n.constructor),t||{},n),n._renderProxy=n,n._self=n,function(e){var t=e.$options,n=t.parent;if(n&&!t.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(e)}e.$parent=n,e.$root=n?n.$root:e,e.$children=[],e.$refs={},e._watcher=null,e._inactive=null,e._directInactive=!1,e._isMounted=!1,e._isDestroyed=!1,e._isBeingDestroyed=!1}(n),function(e){e._events=Object.create(null),e._hasHookEvent=!1;var t=e.$options._parentListeners;t&&Jt(e,t)}(n),function(t){t._vnode=null,t._staticTrees=null;var n=t.$options,r=t.$vnode=n._parentVnode,i=r&&r.context;t.$slots=ct(n._renderChildren,i),t.$scopedSlots=e,t._c=function(e,n,r,i){return Pt(t,e,n,r,i,!1)},t.$createElement=function(e,n,r,i){return Pt(t,e,n,r,i,!0)};var o=r&&r.data;xe(t,"$attrs",o&&o.attrs||e,null,!0),xe(t,"$listeners",n._parentListeners||e,null,!0)}(n),Xt(n,"beforeCreate"),function(e){var t=st(e.$options.inject,e);t&&(be(!1),Object.keys(t).forEach(function(n){xe(e,n,t[n])}),be(!0))}(n),pn(n),function(e){var t=e.$options.provide;t&&(e._provided="function"==typeof t?t.call(e):t)}(n),Xt(n,"created"),n.$options.el&&n.$mount(n.$options.el)}}(bn),function(e){var t={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(e.prototype,"$data",t),Object.defineProperty(e.prototype,"$props",n),e.prototype.$set=Ce,e.prototype.$delete=Ae,e.prototype.$watch=function(e,t,n){if(s(t))return yn(this,e,t,n);(n=n||{}).user=!0;var r=new un(this,e,t,n);if(n.immediate)try{t.call(this,r.value)}catch(e){Re(e,this,'callback for immediate watcher "'+r.expression+'"')}return function(){r.teardown()}}}(bn),function(e){var t=/^hook:/;e.prototype.$on=function(e,n){var r=this;if(Array.isArray(e))for(var i=0,o=e.length;i1?A(t):t;for(var n=A(arguments,1),r='event handler for "'+e+'"',i=0,o=t.length;iparseInt(this.max)&&An(a,s[0],s,this._vnode)),t.data.keepAlive=!0}return t||e&&e[0]}}};!function(e){var t={get:function(){return P}};Object.defineProperty(e,"config",t),e.util={warn:oe,extend:k,mergeOptions:Ne,defineReactive:xe},e.set=Ce,e.delete=Ae,e.nextTick=Xe,e.observable=function(e){return we(e),e},e.options=Object.create(null),I.forEach(function(t){e.options[t+"s"]=Object.create(null)}),e.options._base=e,k(e.options.components,On),function(e){e.use=function(e){var t=this._installedPlugins||(this._installedPlugins=[]);if(t.indexOf(e)>-1)return this;var n=A(arguments,1);return n.unshift(this),"function"==typeof e.install?e.install.apply(e,n):"function"==typeof e&&e.apply(null,n),t.push(e),this}}(e),function(e){e.mixin=function(e){return this.options=Ne(this.options,e),this}}(e),$n(e),function(e){I.forEach(function(t){e[t]=function(e,n){return n?("component"===t&&s(n)&&(n.name=n.name||e,n=this.options._base.extend(n)),"directive"===t&&"function"==typeof n&&(n={bind:n,update:n}),this.options[t+"s"][e]=n,n):this.options[t+"s"][e]}})}(e)}(bn),Object.defineProperty(bn.prototype,"$isServer",{get:ee}),Object.defineProperty(bn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(bn,"FunctionalRenderContext",{value:St}),bn.version="2.6.6";var Sn=p("style,class"),Tn=p("input,textarea,option,select,progress"),En=function(e,t,n){return"value"===n&&Tn(e)&&"button"!==t||"selected"===n&&"option"===e||"checked"===n&&"input"===e||"muted"===n&&"video"===e},jn=p("contenteditable,draggable,spellcheck"),Nn=p("events,caret,typing,plaintext-only"),Ln=function(e,t){return Rn(t)||"false"===t?"false":"contenteditable"===e&&Nn(t)?t:"true"},Mn=p("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible"),In="http://www.w3.org/1999/xlink",Dn=function(e){return":"===e.charAt(5)&&"xlink"===e.slice(0,5)},Pn=function(e){return Dn(e)?e.slice(6,e.length):""},Rn=function(e){return null==e||!1===e};function Fn(e){for(var t=e.data,r=e,i=e;n(i.componentInstance);)(i=i.componentInstance._vnode)&&i.data&&(t=Hn(i.data,t));for(;n(r=r.parent);)r&&r.data&&(t=Hn(t,r.data));return function(e,t){if(n(e)||n(t))return Bn(e,Un(t));return""}(t.staticClass,t.class)}function Hn(e,t){return{staticClass:Bn(e.staticClass,t.staticClass),class:n(e.class)?[e.class,t.class]:t.class}}function Bn(e,t){return e?t?e+" "+t:e:t||""}function Un(e){return Array.isArray(e)?function(e){for(var t,r="",i=0,o=e.length;i-1?dr(e,t,n):Mn(t)?Rn(n)?e.removeAttribute(t):(n="allowfullscreen"===t&&"EMBED"===e.tagName?"true":t,e.setAttribute(t,n)):jn(t)?e.setAttribute(t,Ln(t,n)):Dn(t)?Rn(n)?e.removeAttributeNS(In,Pn(t)):e.setAttributeNS(In,t,n):dr(e,t,n)}function dr(e,t,n){if(Rn(n))e.removeAttribute(t);else{if(J&&!q&&"TEXTAREA"===e.tagName&&"placeholder"===t&&""!==n&&!e.__ieph){var r=function(t){t.stopImmediatePropagation(),e.removeEventListener("input",r)};e.addEventListener("input",r),e.__ieph=!0}e.setAttribute(t,n)}}var vr={create:fr,update:fr};function hr(e,r){var i=r.elm,o=r.data,a=e.data;if(!(t(o.staticClass)&&t(o.class)&&(t(a)||t(a.staticClass)&&t(a.class)))){var s=Fn(r),c=i._transitionClasses;n(c)&&(s=Bn(s,Un(c))),s!==i._prevClass&&(i.setAttribute("class",s),i._prevClass=s)}}var mr,yr,gr,_r,br,$r,wr={create:hr,update:hr},xr=/[\w).+\-_$\]]/;function Cr(e){var t,n,r,i,o,a=!1,s=!1,c=!1,u=!1,l=0,f=0,p=0,d=0;for(r=0;r=0&&" "===(h=e.charAt(v));v--);h&&xr.test(h)||(u=!0)}}else void 0===i?(d=r+1,i=e.slice(0,r).trim()):m();function m(){(o||(o=[])).push(e.slice(d,r).trim()),d=r+1}if(void 0===i?i=e.slice(0,r).trim():0!==d&&m(),o)for(r=0;r-1?{exp:e.slice(0,_r),key:'"'+e.slice(_r+1)+'"'}:{exp:e,key:null};yr=e,_r=br=$r=0;for(;!Br();)Ur(gr=Hr())?Vr(gr):91===gr&&zr(gr);return{exp:e.slice(0,br),key:e.slice(br+1,$r)}}(e);return null===n.key?e+"="+t:"$set("+n.exp+", "+n.key+", "+t+")"}function Hr(){return yr.charCodeAt(++_r)}function Br(){return _r>=mr}function Ur(e){return 34===e||39===e}function zr(e){var t=1;for(br=_r;!Br();)if(Ur(e=Hr()))Vr(e);else if(91===e&&t++,93===e&&t--,0===t){$r=_r;break}}function Vr(e){for(var t=e;!Br()&&(e=Hr())!==t;);}var Kr,Jr="__r",qr="__c";function Wr(e,t,n){var r=Kr;return function i(){null!==t.apply(null,arguments)&&Xr(e,i,n,r)}}var Zr=ze&&!(G&&Number(G[1])<=53);function Gr(e,t,n,r){if(Zr){var i=on,o=t;t=o._wrapper=function(e){if(e.target===e.currentTarget||e.timeStamp>=i||0===e.timeStamp||e.target.ownerDocument!==document)return o.apply(this,arguments)}}Kr.addEventListener(e,t,Y?{capture:n,passive:r}:n)}function Xr(e,t,n,r){(r||Kr).removeEventListener(e,t._wrapper||t,n)}function Yr(e,r){if(!t(e.data.on)||!t(r.data.on)){var i=r.data.on||{},o=e.data.on||{};Kr=r.elm,function(e){if(n(e[Jr])){var t=J?"change":"input";e[t]=[].concat(e[Jr],e[t]||[]),delete e[Jr]}n(e[qr])&&(e.change=[].concat(e[qr],e.change||[]),delete e[qr])}(i),nt(i,o,Gr,Xr,Wr,r.context),Kr=void 0}}var Qr,ei={create:Yr,update:Yr};function ti(e,r){if(!t(e.data.domProps)||!t(r.data.domProps)){var i,o,a=r.elm,s=e.data.domProps||{},c=r.data.domProps||{};for(i in n(c.__ob__)&&(c=r.data.domProps=k({},c)),s)t(c[i])&&(a[i]="");for(i in c){if(o=c[i],"textContent"===i||"innerHTML"===i){if(r.children&&(r.children.length=0),o===s[i])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===i||o!==s[i])if("value"===i){a._value=o;var u=t(o)?"":String(o);ni(a,u)&&(a.value=u)}else if("innerHTML"===i&&Kn(a.tagName)&&t(a.innerHTML)){(Qr=Qr||document.createElement("div")).innerHTML=""+o+"";for(var l=Qr.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;l.firstChild;)a.appendChild(l.firstChild)}else a[i]=o}}}function ni(e,t){return!e.composing&&("OPTION"===e.tagName||function(e,t){var n=!0;try{n=document.activeElement!==e}catch(e){}return n&&e.value!==t}(e,t)||function(e,t){var r=e.value,i=e._vModifiers;if(n(i)){if(i.number)return f(r)!==f(t);if(i.trim)return r.trim()!==t.trim()}return r!==t}(e,t))}var ri={create:ti,update:ti},ii=g(function(e){var t={},n=/:(.+)/;return e.split(/;(?![^(]*\))/g).forEach(function(e){if(e){var r=e.split(n);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t});function oi(e){var t=ai(e.style);return e.staticStyle?k(e.staticStyle,t):t}function ai(e){return Array.isArray(e)?O(e):"string"==typeof e?ii(e):e}var si,ci=/^--/,ui=/\s*!important$/,li=function(e,t,n){if(ci.test(t))e.style.setProperty(t,n);else if(ui.test(n))e.style.setProperty(x(t),n.replace(ui,""),"important");else{var r=pi(t);if(Array.isArray(n))for(var i=0,o=n.length;i-1?t.split(hi).forEach(function(t){return e.classList.add(t)}):e.classList.add(t);else{var n=" "+(e.getAttribute("class")||"")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function yi(e,t){if(t&&(t=t.trim()))if(e.classList)t.indexOf(" ")>-1?t.split(hi).forEach(function(t){return e.classList.remove(t)}):e.classList.remove(t),e.classList.length||e.removeAttribute("class");else{for(var n=" "+(e.getAttribute("class")||"")+" ",r=" "+t+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?e.setAttribute("class",n):e.removeAttribute("class")}}function gi(e){if(e){if("object"==typeof e){var t={};return!1!==e.css&&k(t,_i(e.name||"v")),k(t,e),t}return"string"==typeof e?_i(e):void 0}}var _i=g(function(e){return{enterClass:e+"-enter",enterToClass:e+"-enter-to",enterActiveClass:e+"-enter-active",leaveClass:e+"-leave",leaveToClass:e+"-leave-to",leaveActiveClass:e+"-leave-active"}}),bi=U&&!q,$i="transition",wi="animation",xi="transition",Ci="transitionend",Ai="animation",ki="animationend";bi&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(xi="WebkitTransition",Ci="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(Ai="WebkitAnimation",ki="webkitAnimationEnd"));var Oi=U?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(e){return e()};function Si(e){Oi(function(){Oi(e)})}function Ti(e,t){var n=e._transitionClasses||(e._transitionClasses=[]);n.indexOf(t)<0&&(n.push(t),mi(e,t))}function Ei(e,t){e._transitionClasses&&h(e._transitionClasses,t),yi(e,t)}function ji(e,t,n){var r=Li(e,t),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var s=i===$i?Ci:ki,c=0,u=function(){e.removeEventListener(s,l),n()},l=function(t){t.target===e&&++c>=a&&u()};setTimeout(function(){c0&&(n=$i,l=a,f=o.length):t===wi?u>0&&(n=wi,l=u,f=c.length):f=(n=(l=Math.max(a,u))>0?a>u?$i:wi:null)?n===$i?o.length:c.length:0,{type:n,timeout:l,propCount:f,hasTransform:n===$i&&Ni.test(r[xi+"Property"])}}function Mi(e,t){for(;e.length1}function Hi(e,t){!0!==t.data.show&&Di(t)}var Bi=function(e){var o,a,s={},c=e.modules,u=e.nodeOps;for(o=0;ov?_(e,t(i[y+1])?null:i[y+1].elm,i,d,y,o):d>y&&$(0,r,p,v)}(p,h,y,o,l):n(y)?(n(e.text)&&u.setTextContent(p,""),_(p,null,y,0,y.length-1,o)):n(h)?$(0,h,0,h.length-1):n(e.text)&&u.setTextContent(p,""):e.text!==i.text&&u.setTextContent(p,i.text),n(v)&&n(d=v.hook)&&n(d=d.postpatch)&&d(e,i)}}}function A(e,t,i){if(r(i)&&n(e.parent))e.parent.data.pendingInsert=t;else for(var o=0;o-1,a.selected!==o&&(a.selected=o);else if(j(Ji(a),r))return void(e.selectedIndex!==s&&(e.selectedIndex=s));i||(e.selectedIndex=-1)}}function Ki(e,t){return t.every(function(t){return!j(t,e)})}function Ji(e){return"_value"in e?e._value:e.value}function qi(e){e.target.composing=!0}function Wi(e){e.target.composing&&(e.target.composing=!1,Zi(e.target,"input"))}function Zi(e,t){var n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}function Gi(e){return!e.componentInstance||e.data&&e.data.transition?e:Gi(e.componentInstance._vnode)}var Xi={model:Ui,show:{bind:function(e,t,n){var r=t.value,i=(n=Gi(n)).data&&n.data.transition,o=e.__vOriginalDisplay="none"===e.style.display?"":e.style.display;r&&i?(n.data.show=!0,Di(n,function(){e.style.display=o})):e.style.display=r?o:"none"},update:function(e,t,n){var r=t.value;!r!=!t.oldValue&&((n=Gi(n)).data&&n.data.transition?(n.data.show=!0,r?Di(n,function(){e.style.display=e.__vOriginalDisplay}):Pi(n,function(){e.style.display="none"})):e.style.display=r?e.__vOriginalDisplay:"none")},unbind:function(e,t,n,r,i){i||(e.style.display=e.__vOriginalDisplay)}}},Yi={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function Qi(e){var t=e&&e.componentOptions;return t&&t.Ctor.options.abstract?Qi(Ut(t.children)):e}function eo(e){var t={},n=e.$options;for(var r in n.propsData)t[r]=e[r];var i=n._parentListeners;for(var o in i)t[b(o)]=i[o];return t}function to(e,t){if(/\d-keep-alive$/.test(t.tag))return e("keep-alive",{props:t.componentOptions.propsData})}var no=function(e){return e.tag||Bt(e)},ro=function(e){return"show"===e.name},io={name:"transition",props:Yi,abstract:!0,render:function(e){var t=this,n=this.$slots.default;if(n&&(n=n.filter(no)).length){var r=this.mode,o=n[0];if(function(e){for(;e=e.parent;)if(e.data.transition)return!0}(this.$vnode))return o;var a=Qi(o);if(!a)return o;if(this._leaving)return to(e,o);var s="__transition-"+this._uid+"-";a.key=null==a.key?a.isComment?s+"comment":s+a.tag:i(a.key)?0===String(a.key).indexOf(s)?a.key:s+a.key:a.key;var c=(a.data||(a.data={})).transition=eo(this),u=this._vnode,l=Qi(u);if(a.data.directives&&a.data.directives.some(ro)&&(a.data.show=!0),l&&l.data&&!function(e,t){return t.key===e.key&&t.tag===e.tag}(a,l)&&!Bt(l)&&(!l.componentInstance||!l.componentInstance._vnode.isComment)){var f=l.data.transition=k({},c);if("out-in"===r)return this._leaving=!0,rt(f,"afterLeave",function(){t._leaving=!1,t.$forceUpdate()}),to(e,o);if("in-out"===r){if(Bt(a))return u;var p,d=function(){p()};rt(c,"afterEnter",d),rt(c,"enterCancelled",d),rt(f,"delayLeave",function(e){p=e})}}return o}}},oo=k({tag:String,moveClass:String},Yi);function ao(e){e.elm._moveCb&&e.elm._moveCb(),e.elm._enterCb&&e.elm._enterCb()}function so(e){e.data.newPos=e.elm.getBoundingClientRect()}function co(e){var t=e.data.pos,n=e.data.newPos,r=t.left-n.left,i=t.top-n.top;if(r||i){e.data.moved=!0;var o=e.elm.style;o.transform=o.WebkitTransform="translate("+r+"px,"+i+"px)",o.transitionDuration="0s"}}delete oo.mode;var uo={Transition:io,TransitionGroup:{props:oo,beforeMount:function(){var e=this,t=this._update;this._update=function(n,r){var i=Wt(e);e.__patch__(e._vnode,e.kept,!1,!0),e._vnode=e.kept,i(),t.call(e,n,r)}},render:function(e){for(var t=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,i=this.$slots.default||[],o=this.children=[],a=eo(this),s=0;s-1?Wn[e]=t.constructor===window.HTMLUnknownElement||t.constructor===window.HTMLElement:Wn[e]=/HTMLUnknownElement/.test(t.toString())},k(bn.options.directives,Xi),k(bn.options.components,uo),bn.prototype.__patch__=U?Bi:S,bn.prototype.$mount=function(e,t){return function(e,t,n){var r;return e.$el=t,e.$options.render||(e.$options.render=de),Xt(e,"beforeMount"),r=function(){e._update(e._render(),n)},new un(e,r,S,{before:function(){e._isMounted&&!e._isDestroyed&&Xt(e,"beforeUpdate")}},!0),n=!1,null==e.$vnode&&(e._isMounted=!0,Xt(e,"mounted")),e}(this,e=e&&U?Gn(e):void 0,t)},U&&setTimeout(function(){P.devtools&&te&&te.emit("init",bn)},0);var lo=/\{\{((?:.|\r?\n)+?)\}\}/g,fo=/[-.*+?^${}()|[\]\/\\]/g,po=g(function(e){var t=e[0].replace(fo,"\\$&"),n=e[1].replace(fo,"\\$&");return new RegExp(t+"((?:.|\\n)+?)"+n,"g")});var vo={staticKeys:["staticClass"],transformNode:function(e,t){t.warn;var n=Ir(e,"class");n&&(e.staticClass=JSON.stringify(n));var r=Mr(e,"class",!1);r&&(e.classBinding=r)},genData:function(e){var t="";return e.staticClass&&(t+="staticClass:"+e.staticClass+","),e.classBinding&&(t+="class:"+e.classBinding+","),t}};var ho,mo={staticKeys:["staticStyle"],transformNode:function(e,t){t.warn;var n=Ir(e,"style");n&&(e.staticStyle=JSON.stringify(ii(n)));var r=Mr(e,"style",!1);r&&(e.styleBinding=r)},genData:function(e){var t="";return e.staticStyle&&(t+="staticStyle:"+e.staticStyle+","),e.styleBinding&&(t+="style:("+e.styleBinding+"),"),t}},yo=function(e){return(ho=ho||document.createElement("div")).innerHTML=e,ho.textContent},go=p("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),_o=p("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),bo=p("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),$o=/^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,wo=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,xo="[a-zA-Z_][\\-\\.0-9_a-zA-Za-zA-Z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]*",Co="((?:"+xo+"\\:)?"+xo+")",Ao=new RegExp("^<"+Co),ko=/^\s*(\/?)>/,Oo=new RegExp("^<\\/"+Co+"[^>]*>"),So=/^]+>/i,To=/^",""":'"',"&":"&"," ":"\n"," ":"\t","'":"'"},Mo=/&(?:lt|gt|quot|amp|#39);/g,Io=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,Do=p("pre,textarea",!0),Po=function(e,t){return e&&Do(e)&&"\n"===t[0]};function Ro(e,t){var n=t?Io:Mo;return e.replace(n,function(e){return Lo[e]})}var Fo,Ho,Bo,Uo,zo,Vo,Ko,Jo,qo=/^@|^v-on:/,Wo=/^v-|^@|^:/,Zo=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,Go=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,Xo=/^\(|\)$/g,Yo=/^\[.*\]$/,Qo=/:(.*)$/,ea=/^:|^\.|^v-bind:/,ta=/\.[^.]+/g,na=/^v-slot(:|$)|^#/,ra=/[\r\n]/,ia=/\s+/g,oa=g(yo),aa="_empty_";function sa(e,t,n){return{type:1,tag:e,attrsList:t,attrsMap:va(t),rawAttrsMap:{},parent:n,children:[]}}function ca(e,t){Fo=t.warn||kr,Vo=t.isPreTag||T,Ko=t.mustUseProp||T,Jo=t.getTagNamespace||T;t.isReservedTag;Bo=Or(t.modules,"transformNode"),Uo=Or(t.modules,"preTransformNode"),zo=Or(t.modules,"postTransformNode"),Ho=t.delimiters;var n,r,i=[],o=!1!==t.preserveWhitespace,a=t.whitespace,s=!1,c=!1;function u(e){if(l(e),s||e.processed||(e=ua(e,t)),i.length||e===n||n.if&&(e.elseif||e.else)&&fa(n,{exp:e.elseif,block:e}),r&&!e.forbidden)if(e.elseif||e.else)a=e,(u=function(e){var t=e.length;for(;t--;){if(1===e[t].type)return e[t];e.pop()}}(r.children))&&u.if&&fa(u,{exp:a.elseif,block:a});else{if(e.slotScope){var o=e.slotTarget||'"default"';(r.scopedSlots||(r.scopedSlots={}))[o]=e}r.children.push(e),e.parent=r}var a,u;e.children=e.children.filter(function(e){return!e.slotScope}),l(e),e.pre&&(s=!1),Vo(e.tag)&&(c=!1);for(var f=0;f]*>)","i")),p=e.replace(f,function(e,n,r){return u=r.length,jo(l)||"noscript"===l||(n=n.replace(//g,"$1").replace(//g,"$1")),Po(l,n)&&(n=n.slice(1)),t.chars&&t.chars(n),""});c+=e.length-p.length,e=p,k(l,c-u,c)}else{var d=e.indexOf("<");if(0===d){if(To.test(e)){var v=e.indexOf("--\x3e");if(v>=0){t.shouldKeepComment&&t.comment(e.substring(4,v),c,c+v+3),x(v+3);continue}}if(Eo.test(e)){var h=e.indexOf("]>");if(h>=0){x(h+2);continue}}var m=e.match(So);if(m){x(m[0].length);continue}var y=e.match(Oo);if(y){var g=c;x(y[0].length),k(y[1],g,c);continue}var _=C();if(_){A(_),Po(_.tagName,e)&&x(1);continue}}var b=void 0,$=void 0,w=void 0;if(d>=0){for($=e.slice(d);!(Oo.test($)||Ao.test($)||To.test($)||Eo.test($)||(w=$.indexOf("<",1))<0);)d+=w,$=e.slice(d);b=e.substring(0,d)}d<0&&(b=e),b&&x(b.length),t.chars&&b&&t.chars(b,c-b.length,c)}if(e===n){t.chars&&t.chars(e);break}}function x(t){c+=t,e=e.substring(t)}function C(){var t=e.match(Ao);if(t){var n,r,i={tagName:t[1],attrs:[],start:c};for(x(t[0].length);!(n=e.match(ko))&&(r=e.match(wo)||e.match($o));)r.start=c,x(r[0].length),r.end=c,i.attrs.push(r);if(n)return i.unarySlash=n[1],x(n[0].length),i.end=c,i}}function A(e){var n=e.tagName,c=e.unarySlash;o&&("p"===r&&bo(n)&&k(r),s(n)&&r===n&&k(n));for(var u=a(n)||!!c,l=e.attrs.length,f=new Array(l),p=0;p=0&&i[a].lowerCasedTag!==s;a--);else a=0;if(a>=0){for(var u=i.length-1;u>=a;u--)t.end&&t.end(i[u].tag,n,o);i.length=a,r=a&&i[a-1].tag}else"br"===s?t.start&&t.start(e,[],!0,n,o):"p"===s&&(t.start&&t.start(e,[],!1,n,o),t.end&&t.end(e,n,o))}k()}(e,{warn:Fo,expectHTML:t.expectHTML,isUnaryTag:t.isUnaryTag,canBeLeftOpenTag:t.canBeLeftOpenTag,shouldDecodeNewlines:t.shouldDecodeNewlines,shouldDecodeNewlinesForHref:t.shouldDecodeNewlinesForHref,shouldKeepComment:t.comments,outputSourceRange:t.outputSourceRange,start:function(e,o,a,l){var f=r&&r.ns||Jo(e);J&&"svg"===f&&(o=function(e){for(var t=[],n=0;nc&&(s.push(o=e.slice(c,i)),a.push(JSON.stringify(o)));var u=Cr(r[1].trim());a.push("_s("+u+")"),s.push({"@binding":u}),c=i+r[0].length}return c-1"+("true"===o?":("+t+")":":_q("+t+","+o+")")),Lr(e,"change","var $$a="+t+",$$el=$event.target,$$c=$$el.checked?("+o+"):("+a+");if(Array.isArray($$a)){var $$v="+(r?"_n("+i+")":i)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Fr(t,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Fr(t,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Fr(t,"$$c")+"}",null,!0)}(e,r,i);else if("input"===o&&"radio"===a)!function(e,t,n){var r=n&&n.number,i=Mr(e,"value")||"null";Sr(e,"checked","_q("+t+","+(i=r?"_n("+i+")":i)+")"),Lr(e,"change",Fr(t,i),null,!0)}(e,r,i);else if("input"===o||"textarea"===o)!function(e,t,n){var r=e.attrsMap.type,i=n||{},o=i.lazy,a=i.number,s=i.trim,c=!o&&"range"!==r,u=o?"change":"range"===r?Jr:"input",l="$event.target.value";s&&(l="$event.target.value.trim()"),a&&(l="_n("+l+")");var f=Fr(t,l);c&&(f="if($event.target.composing)return;"+f),Sr(e,"value","("+t+")"),Lr(e,u,f,null,!0),(s||a)&&Lr(e,"blur","$forceUpdate()")}(e,r,i);else if(!P.isReservedTag(o))return Rr(e,r,i),!1;return!0},text:function(e,t){t.value&&Sr(e,"textContent","_s("+t.value+")",t)},html:function(e,t){t.value&&Sr(e,"innerHTML","_s("+t.value+")",t)}},isPreTag:function(e){return"pre"===e},isUnaryTag:go,mustUseProp:En,canBeLeftOpenTag:_o,isReservedTag:Jn,getTagNamespace:qn,staticKeys:function(e){return e.reduce(function(e,t){return e.concat(t.staticKeys||[])},[]).join(",")}(ga)},wa=g(function(e){return p("type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap"+(e?","+e:""))});function xa(e,t){e&&(_a=wa(t.staticKeys||""),ba=t.isReservedTag||T,function e(t){t.static=function(e){if(2===e.type)return!1;if(3===e.type)return!0;return!(!e.pre&&(e.hasBindings||e.if||e.for||d(e.tag)||!ba(e.tag)||function(e){for(;e.parent;){if("template"!==(e=e.parent).tag)return!1;if(e.for)return!0}return!1}(e)||!Object.keys(e).every(_a)))}(t);if(1===t.type){if(!ba(t.tag)&&"slot"!==t.tag&&null==t.attrsMap["inline-template"])return;for(var n=0,r=t.children.length;n|^function\s*\(/,Aa=/\([^)]*?\);*$/,ka=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,Oa={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},Sa={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},Ta=function(e){return"if("+e+")return null;"},Ea={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:Ta("$event.target !== $event.currentTarget"),ctrl:Ta("!$event.ctrlKey"),shift:Ta("!$event.shiftKey"),alt:Ta("!$event.altKey"),meta:Ta("!$event.metaKey"),left:Ta("'button' in $event && $event.button !== 0"),middle:Ta("'button' in $event && $event.button !== 1"),right:Ta("'button' in $event && $event.button !== 2")};function ja(e,t){var n=t?"nativeOn:":"on:",r="",i="";for(var o in e){var a=Na(e[o]);e[o]&&e[o].dynamic?i+=o+","+a+",":r+='"'+o+'":'+a+","}return r="{"+r.slice(0,-1)+"}",i?n+"_d("+r+",["+i.slice(0,-1)+"])":n+r}function Na(e){if(!e)return"function(){}";if(Array.isArray(e))return"["+e.map(function(e){return Na(e)}).join(",")+"]";var t=ka.test(e.value),n=Ca.test(e.value),r=ka.test(e.value.replace(Aa,""));if(e.modifiers){var i="",o="",a=[];for(var s in e.modifiers)if(Ea[s])o+=Ea[s],Oa[s]&&a.push(s);else if("exact"===s){var c=e.modifiers;o+=Ta(["ctrl","shift","alt","meta"].filter(function(e){return!c[e]}).map(function(e){return"$event."+e+"Key"}).join("||"))}else a.push(s);return a.length&&(i+=function(e){return"if(!$event.type.indexOf('key')&&"+e.map(La).join("&&")+")return null;"}(a)),o&&(i+=o),"function($event){"+i+(t?"return "+e.value+"($event)":n?"return ("+e.value+")($event)":r?"return "+e.value:e.value)+"}"}return t||n?e.value:"function($event){"+(r?"return "+e.value:e.value)+"}"}function La(e){var t=parseInt(e,10);if(t)return"$event.keyCode!=="+t;var n=Oa[e],r=Sa[e];return"_k($event.keyCode,"+JSON.stringify(e)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(r)+")"}var Ma={on:function(e,t){e.wrapListeners=function(e){return"_g("+e+","+t.value+")"}},bind:function(e,t){e.wrapData=function(n){return"_b("+n+",'"+e.tag+"',"+t.value+","+(t.modifiers&&t.modifiers.prop?"true":"false")+(t.modifiers&&t.modifiers.sync?",true":"")+")"}},cloak:S},Ia=function(e){this.options=e,this.warn=e.warn||kr,this.transforms=Or(e.modules,"transformCode"),this.dataGenFns=Or(e.modules,"genData"),this.directives=k(k({},Ma),e.directives);var t=e.isReservedTag||T;this.maybeComponent=function(e){return!!e.component||!t(e.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1};function Da(e,t){var n=new Ia(t);return{render:"with(this){return "+(e?Pa(e,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function Pa(e,t){if(e.parent&&(e.pre=e.pre||e.parent.pre),e.staticRoot&&!e.staticProcessed)return Ra(e,t);if(e.once&&!e.onceProcessed)return Fa(e,t);if(e.for&&!e.forProcessed)return Ba(e,t);if(e.if&&!e.ifProcessed)return Ha(e,t);if("template"!==e.tag||e.slotTarget||t.pre){if("slot"===e.tag)return function(e,t){var n=e.slotName||'"default"',r=Ka(e,t),i="_t("+n+(r?","+r:""),o=e.attrs||e.dynamicAttrs?Wa((e.attrs||[]).concat(e.dynamicAttrs||[]).map(function(e){return{name:b(e.name),value:e.value,dynamic:e.dynamic}})):null,a=e.attrsMap["v-bind"];!o&&!a||r||(i+=",null");o&&(i+=","+o);a&&(i+=(o?"":",null")+","+a);return i+")"}(e,t);var n;if(e.component)n=function(e,t,n){var r=t.inlineTemplate?null:Ka(t,n,!0);return"_c("+e+","+Ua(t,n)+(r?","+r:"")+")"}(e.component,e,t);else{var r;(!e.plain||e.pre&&t.maybeComponent(e))&&(r=Ua(e,t));var i=e.inlineTemplate?null:Ka(e,t,!0);n="_c('"+e.tag+"'"+(r?","+r:"")+(i?","+i:"")+")"}for(var o=0;o':'
    ',Qa.innerHTML.indexOf(" ")>0}var rs=!!U&&ns(!1),is=!!U&&ns(!0),os=g(function(e){var t=Gn(e);return t&&t.innerHTML}),as=bn.prototype.$mount;return bn.prototype.$mount=function(e,t){if((e=e&&Gn(e))===document.body||e===document.documentElement)return this;var n=this.$options;if(!n.render){var r=n.template;if(r)if("string"==typeof r)"#"===r.charAt(0)&&(r=os(r));else{if(!r.nodeType)return this;r=r.innerHTML}else e&&(r=function(e){if(e.outerHTML)return e.outerHTML;var t=document.createElement("div");return t.appendChild(e.cloneNode(!0)),t.innerHTML}(e));if(r){var i=ts(r,{outputSourceRange:!1,shouldDecodeNewlines:rs,shouldDecodeNewlinesForHref:is,delimiters:n.delimiters,comments:n.comments},this),o=i.render,a=i.staticRenderFns;n.render=o,n.staticRenderFns=a}}return as.call(this,e,t)},bn.compile=ts,bn}); -------------------------------------------------------------------------------- /inst/htmlwidgets/vue.js: -------------------------------------------------------------------------------- 1 | HTMLWidgets.widget({ 2 | 3 | name: 'vue', 4 | 5 | type: 'output', 6 | 7 | factory: function(el, width, height) { 8 | 9 | // TODO: define shared variables for this instance 10 | var app = {}; 11 | Vue.config.devtools = true; 12 | 13 | return { 14 | 15 | renderValue: function(x) { 16 | if (x.html !== ""){ 17 | el.innerHTML = x.html; 18 | } 19 | // x.app.el = "#" + el.id; 20 | app = new Vue(x.app); 21 | }, 22 | 23 | resize: function(width, height) { 24 | 25 | // TODO: code to re-render the widget with a new size 26 | 27 | }, 28 | 29 | getApp: function(){ 30 | return(app); 31 | } 32 | 33 | }; 34 | } 35 | }); 36 | 37 | function get_vue_app(id){ 38 | 39 | var htmlWidgetsObj = HTMLWidgets.find("#" + id); 40 | 41 | var app; 42 | 43 | if (typeof htmlWidgetsObj != 'undefined') { 44 | app = htmlWidgetsObj.getApp(); 45 | } 46 | 47 | return(app); 48 | } 49 | 50 | if (HTMLWidgets.shinyMode) { 51 | Shiny.addCustomMessageHandler('updateProp', 52 | function(message) { 53 | console.log(JSON.stringify(message)); 54 | // var app = HTMLWidgets.find("#" + message.id).getApp(); 55 | var app = get_vue_app(message.id); 56 | var data = message.data; 57 | if (typeof app != 'undefined'){ 58 | message.data.map(d => app[d.name] = d.value); 59 | } 60 | }); 61 | } 62 | -------------------------------------------------------------------------------- /inst/htmlwidgets/vue.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: vue 3 | version: 2.6.6 4 | src: htmlwidgets/lib/vue 5 | script: vue.js 6 | -------------------------------------------------------------------------------- /man/appendDependencies.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{appendDependencies} 4 | \alias{appendDependencies} 5 | \title{Append html dependencies} 6 | \usage{ 7 | appendDependencies(x, value) 8 | } 9 | \description{ 10 | NOTE: This function has been copied over from shinydashboard 11 | } 12 | -------------------------------------------------------------------------------- /man/pipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-pipe.R 3 | \name{\%>\%} 4 | \alias{\%>\%} 5 | \title{Pipe operator} 6 | \usage{ 7 | lhs \%>\% rhs 8 | } 9 | \description{ 10 | See \code{magrittr::\link[magrittr]{\%>\%}} for details. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/vtag.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{vtag} 4 | \alias{vtag} 5 | \title{Vue Tag} 6 | \usage{ 7 | vtag(`_tag_name`, varArgs) 8 | } 9 | \description{ 10 | Vue Tag 11 | } 12 | \examples{ 13 | vtag("input", list(type = "text", vmodel = "message")) 14 | } 15 | -------------------------------------------------------------------------------- /man/vue.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/vue.R 3 | \name{Vue} 4 | \alias{Vue} 5 | \title{Create a Vue App} 6 | \usage{ 7 | Vue(html, data = list(), dependencies = list(), ..., 8 | elementId = NULL) 9 | } 10 | \description{ 11 | Create a Vue App 12 | } 13 | \examples{ 14 | library(htmltools) 15 | tags$div( 16 | tags$label('Enter your name'), 17 | tags$input(type = "text", "v-model" = "name"), 18 | tags$p("Hello {{name}}") 19 | ) \%>\% 20 | Vue(data = list(name = "")) 21 | 22 | if (interactive()){ 23 | library(shiny) 24 | ui <- tags$div( 25 | tags$label('Enter your name'), 26 | tags$input(type = "text", "v-model" = "name"), 27 | textOutput("greeting") 28 | ) \%>\% 29 | Vue(data = list(name_ = "")) 30 | server <- function(input, output, session){ 31 | output$greeting <- renderText({ 32 | paste("Hello", input$name) 33 | }) 34 | } 35 | shinyApp(ui = ui, server = server) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /man/vueProxy.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/vue.R 3 | \name{vueProxy} 4 | \alias{vueProxy} 5 | \alias{vueUpdateData} 6 | \title{Send commands to a Vue instance in a Shiny app} 7 | \usage{ 8 | vueProxy(outputId, session = shiny::getDefaultReactiveDomain(), 9 | deferUntilFlush = TRUE) 10 | 11 | vueUpdateData(proxy, ...) 12 | } 13 | \description{ 14 | Send commands to a Vue instance in a Shiny app 15 | 16 | Update data in a Vue instance 17 | } 18 | \examples{ 19 | ui <- div( 20 | tags$label("Enter username"), 21 | tags$input(type = 'text', "v-model" = "username"), 22 | tags$p("Vue -> Vue: Hello {{username}}"), 23 | actionButton("set_name", "Shiny -> Vue"), 24 | verbatimTextOutput("username") 25 | ) \%>\% 26 | vue( 27 | data = list(username = ""), 28 | # Vue UI -> Shiny UI 29 | watch = vue_watch("username"), 30 | elementId = "app" 31 | ) 32 | server <- function(input, output, session){ 33 | # Shiny server -> Vue UI 34 | observeEvent(input$set_name, { 35 | vueProxy("app") \%>\% 36 | updateProp("username", "Ramnath") 37 | }) 38 | output$username <- renderPrint({ 39 | paste("Vue -> Shiny:", input$username) 40 | }) 41 | } 42 | shiny::shinyApp(ui = ui, server = server) 43 | } 44 | -------------------------------------------------------------------------------- /man/vueUpdateShinyInputs.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/vue.R 3 | \name{vueUpdateShinyInputs} 4 | \alias{vueUpdateShinyInputs} 5 | \title{Update Shiny Input} 6 | \usage{ 7 | vueUpdateShinyInputs(...) 8 | } 9 | \description{ 10 | Update Shiny Input 11 | } 12 | -------------------------------------------------------------------------------- /man/vueUsePlugin.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{vueUsePlugin} 4 | \alias{vueUsePlugin} 5 | \title{Use a vue Plugin} 6 | \usage{ 7 | vueUsePlugin(fun) 8 | } 9 | \description{ 10 | Use a vue Plugin 11 | } 12 | -------------------------------------------------------------------------------- /vuer.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: XeLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | --------------------------------------------------------------------------------