Добавление редактора tinyMCE в моде Shiny - PullRequest
2 голосов
/ 14 апреля 2020

Я бы хотел создать редактор HTML в приложении Shiny, используя пакет shinyMCE.

Это хорошо работает в приведенном ниже примере.

library(shiny)
library(shinyMCE)
library(shinyjs)
library(shinyWidgets)
library(shinydashboard)

ui <- dashboardPage(
  useShinyjs(),
  header = dashboardHeader(disable = T),
  sidebar = dashboardSidebar(disable = T),
  body = dashboardBody(
    tags$script(src = "http://cdn.tinymce.com/4/tinymce.min.js",
                referrerpolicy = "origin"),

    tinyMCE("editor", "The content"),
    actionButton("ok", "OK")
    ))

server <- function(input, output, session)
{
  observeEvent(
    input$ok,
    {
    print(input$editor)
    }
  )

  observeEvent(
    input$open,
    {
      showModal(myModal())
    })
}

shinyApp(ui, server = server)

Действительно , если вы нажмете ОК, содержимое редактора будет напечатано в консоли R.

Теперь я бы хотел поместить редактор в модальный режим. Если я сделаю следующее, появится редактор, но если я нажму OK, содержимое не будет обновлено. То есть консоль R всегда показывает «содержимое», независимо от того, что написано в текстовой области.

library(shiny)
library(shinyMCE)
library(shinyjs)
library(shinyWidgets)
library(shinydashboard)

ui <- dashboardPage(
  useShinyjs(),
  header = dashboardHeader(disable = T),
  sidebar = dashboardSidebar(disable = T),
  body = dashboardBody(
    tags$script(src = "http://cdn.tinymce.com/4/tinymce.min.js",
                referrerpolicy = "origin"),

    flowLayout (
      actionButton("open", "Open")
      )))

myModal <- function()
  {
  modalDialog(size = "l",
              title = "A modal dialog",
              tinyMCE("tinyTxt", "the content"),
              actionButton("ok", "OK"),
              easyClose = T)
  }

server <- function(input, output, session)
  {
  observeEvent(
    input$ok,
      {
      print(input$tinyTxt)
      }
    )

observeEvent(
    input$open,
    {
    showModal(myModal())
    })
  }

shinyApp(ui, server = server)

В консоли JS я получаю

Uncaught TypeError: Cannot read property 'getContent' of null
    at exports.InputBinding.getValue (<anonymous>:9:41)
    at c (init_shiny.js:117)
    at init_shiny.js:163
    at eN.<anonymous> (<anonymous>:16:18)
    at mp.c.fire (tinymce.min.js:2)
    at eN.fire (tinymce.min.js:2)
    at eN.<anonymous> (tinymce.min.js:2)
    at mp.c.fire (tinymce.min.js:2)
    at eN.fire (tinymce.min.js:2)
    at Rp (tinymce.min.js:2)

Любая идея о том, как обойти проблему?

РЕДАКТИРОВАТЬ: Еще одно наблюдение. В первом (работающем) примере tinyMCE.editors содержит один экземпляр редактора, а во втором он пуст (хотя редактор действительно отображается!).

1 Ответ

1 голос
/ 16 апреля 2020

Мне удалось решить эту проблему, вручную создав редактор TinyMCE (который решает проблему с редактором, отсутствующим в tinymce.editors), а затем использовал некоторый пользовательский JS для получения значения. Мне это кажется немного хакерским, но это работает ... Вот пример

library(shiny)
library(shinyjs)
library(shinyWidgets)
library(shinydashboard)

ui <- dashboardPage(
  useShinyjs(),
  header = dashboardHeader(disable = T),
  sidebar = dashboardSidebar(disable = T),
  body = dashboardBody(
    singleton(tags$head(tags$script(src = "http://cdn.tinymce.com/4/tinymce.min.js",
                referrerpolicy = "origin"))),

    # Register a custom message handler that gets the content of the editor
    # and forces update of the textarea
    singleton(tags$head(tags$script("Shiny.addCustomMessageHandler('getTxt', 
        function(message) {
          var content = tinyMCE.get('tinyTxt').getContent();
          Shiny.onInputChange('tinyTxt', content);
          })"))),

    flowLayout (
      actionButton("open", "Open"),
      htmlOutput("content")
      )))

myModal <- function()
  {
  modalDialog(size = "l",
              title = "A modal dialog",
              textAreaInput("tinyTxt", "the content"),
              actionButton("ok", "OK"),
              easyClose = T)
  }

server <- function(input, output, session)
  {
  observeEvent(
    input$ok,
      {
      # Retrieve the content of the editor
      session$sendCustomMessage("getTxt", "")
      removeModal()
      })

  output$content <- renderText(       
    input$tinyTxt
    )


  observeEvent(
    input$open,
    {
    showModal(myModal())

    # Create the tinyMCE editor
    runjs("var ed = new tinymce.Editor('tinyTxt', {
        selector: 'tinyTxt',
        theme: 'modern'}, 
        tinymce.EditorManager);
        ed.render();")
    })
  }

shinyApp(ui, server = server)
...