rstudio / addinexamples

An R package showcasing how RStudio addins can be registered and used.
Other
86 stars 69 forks source link

Pressing Done should close browser window #3

Open homerhanumat opened 8 years ago

homerhanumat commented 8 years ago

Suppose an Addin is written to open in a browser window. When the user clicks the Done button, the window darkens but does not disappear. It seems that the window should be made to disappear. However, when I write the app so as to force this action, I see no effect. For example, consider the following modification of the subset Addin:

library(miniUI)
subsetAddin2 <- function() {

  # Get the document context.
  context <- rstudioapi::getActiveDocumentContext()

  # Set the default data to use based on the selection.
  text <- context$selection[[1]]$text
  defaultData <- text

  #code to close browser window when done
  jscode <- "Shiny.addCustomMessageHandler('closeWindow', function(m) {window.close();});"

  # Generate UI for the gadget.
  ui <- miniPage(
    tags$head(tags$script(HTML(jscode))),
    gadgetTitleBar("Subset a data.frame"),
    miniContentPanel(
      stableColumnLayout(
        textInput("data", "Data", value = defaultData),
        textInput("subset", "Subset Expression")
      ),
      uiOutput("pending"),
      dataTableOutput("output")
    )
  )

  # Server code for the gadget.
  server <- function(input, output, session) {

    reactiveData <- reactive({

      # Collect inputs.
      dataString <- input$data
      subsetString <- input$subset

      # Check to see if there is data called 'data',
      # and access it if possible.
      if (!nzchar(dataString))
        return(errorMessage("data", "No dataset available."))

      if (!exists(dataString, envir = .GlobalEnv))
        return(errorMessage("data", paste("No dataset named '", dataString, "' available.")))

      data <- get(dataString, envir = .GlobalEnv)

      if (!nzchar(subsetString))
        return(data)

      # Try evaluating the subset expression within the data.
      condition <- try(parse(text = subsetString)[[1]], silent = TRUE)
      if (inherits(condition, "try-error"))
        return(errorMessage("expression", paste("Failed to parse expression '", subsetString, "'.")))

      call <- as.call(list(
        as.name("subset.data.frame"),
        data,
        condition
      ))

      eval(call, envir = .GlobalEnv)
    })

    output$pending <- renderUI({
      data <- reactiveData()
      if (isErrorMessage(data))
        h4(style = "color: #AA7732;", data$message)
    })

    output$output <- renderDataTable({
      data <- reactiveData()
      if (isErrorMessage(data))
        return(NULL)
      data
    })

    # Listen for 'done'.
    observeEvent(input$done, {
      # send message to close the window:
      session$sendCustomMessage(type = "closeWindow", message = "message")
      # Emit a subset call if a dataset has been specified.
      if (nzchar(input$data) && nzchar(input$subset)) {
        code <- paste("subset(", input$data, ", ", input$subset, ")", sep = "")
        rstudioapi::insertText(text = code)
      }

      invisible(stopApp())
    })
  }

  # Use a browser as a viewer.
  viewer <- browserViewer()
  runGadget(ui, server, viewer = viewer)

}

subsetAddin2()

I can verify that message-handler script makes it into the head of the document, but the message sent in observeEvent() appears to be ignored. Am I doing something wrong?

jjallaire commented 8 years ago

The problem is that when you are executing within a top-level browser window you can't programmatically close the window (this is a restriction that browsers impose). Shiny does post a "disconnected" message to the containing frame and when a Shiny app is running within an RStudio window this message is caught and the window is automatically closed.

@jcheng5 I think that the browserViewer should default to running within an RStudio window (I think to do this you just need to run the application just the way a normal runApp call would work). If you don't do this then the "Done" button is effectively broken for all instances of browserViewer.

homerhanumat commented 8 years ago

Thanks. I'll wait for a change like the one you describe.

On Fri, Jan 22, 2016 at 4:41 PM, JJ Allaire notifications@github.com wrote:

The problem is that when you are executing within a top-level browser window you can't programmatically close the window (this is a restriction that browsers impose). Shiny does post a "disconnected" message to the containing frame and when a Shiny app is running within an RStudio window this message is caught and the window is automatically closed.

@jcheng5 https://github.com/jcheng5 I think that the browserViewer should default to running within an RStudio window (I think to do this you just need to run the application just the way a normal runApp call would work). If you don't do this then the "Done" button is effectively broken for all instances of browserViewer.

— Reply to this email directly or view it on GitHub https://github.com/rstudio/addinexamples/issues/3#issuecomment-174059259 .

jcheng5 commented 8 years ago

@jjallaire I didn't think the captive browser window was directly exposed to us? The default runApp lets RStudio choose I think. I would love to be able to do this.

jjallaire commented 8 years ago

We set options(shiny.launch.browser) internally so I think if you just allow the default behavior to occur it will go to the captive browser window.

I think you might need a windowViewer function which has this behavior (then browserViewer can continue to force an external browser, perhaps with the proviso that the Done and Cancel buttons won't really work as intended in that case).

On Fri, Jan 22, 2016 at 8:41 PM, Joe Cheng notifications@github.com wrote:

@jjallaire https://github.com/jjallaire I didn't think the captive browser window was directly exposed to us? The default runApp lets RStudio choose I think. I would love to be able to do this.

— Reply to this email directly or view it on GitHub https://github.com/rstudio/addinexamples/issues/3#issuecomment-174106940 .