🤷‍♂️ RStudio Addin to Search and Copy Emoji
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

222 lines
7.0KB

  1. #' The ermoji emoji gadget
  2. #'
  3. #' Opens a miniUI based Shiny gadget in the RStudio Viewer pane with a
  4. #' searchable table of emoji. Select a row and click the copy desired button.
  5. #'
  6. #' @param clipout Should the gadget attempt to write to the clipboard?
  7. #' @param ... Ignored at this time
  8. #' @name ermoji
  9. #' @return nothing
  10. #' @import shiny
  11. #' @import miniUI
  12. #' @export
  13. ermoji_gadget <- function(clipout = clipr::clipr_available(), ...) {
  14. runGadget(ermoji_ui, ermoji_server(clipout, ...), viewer = paneViewer(500), stopOnCancel = FALSE)
  15. }
  16. #' @rdname ermoji
  17. #' @export
  18. ermoji_shiny <- function(clipout = clipr::clipr_available(), ...) {
  19. shinyApp(ui = ermoji_ui, server = ermoji_server(clipout, ...))
  20. }
  21. ermoji_ui <- miniPage(
  22. title = "ermoji",
  23. tags$head(
  24. tags$style(
  25. HTML("
  26. .dropdown-item {
  27. display: block;
  28. width: 100%;
  29. padding: .25rem 1.5rem;
  30. clear: both;
  31. font-weight: 400;
  32. color: #212529;
  33. text-align: inherit;
  34. white-space: nowrap;
  35. background-color: transparent;
  36. border: 0;
  37. }
  38. .dropdown-menu {
  39. color: #212529;
  40. text-align: left;
  41. list-style: none;
  42. }
  43. @media (min-height: 600px) {
  44. td.big { font-size: 2em; }
  45. }
  46. @media (max-height: 599px) {
  47. td.big { font-size: 1.5em; }
  48. }
  49. table.dataTable tbody td {
  50. vertical-align: middle;
  51. }
  52. ")
  53. )
  54. ),
  55. gadgetTitleBar("ermoji"),
  56. miniContentPanel(
  57. padding = 10,
  58. DT::dataTableOutput('emojis', height = "100%", width = "98%")
  59. ),
  60. miniButtonBlock(
  61. actionButton("copy_name", "Copy :emoji_name:", class = "btn-success"),
  62. tags$div(class = "btn-group dropup", style = "width: 33%",
  63. tags$button(class = "btn btn-warning dropdown-toggle", href = "#",
  64. role = "button", id = "dropdownMenuLink", style = "width: 100%",
  65. "data-toggle" = "dropdown", "aria-haspopup" = "true",
  66. "aria-expanded" = "false",
  67. "Copy Unicode"),
  68. tags$div(class = "dropdown-menu", style = "width: 100%",
  69. "aria-labelledby"="dropdownMenuLink",
  70. actionLink("copy_utf", "Copy unicode", class = "dropdown-item"),
  71. actionLink("copy_html", "Copy HTML", class = "dropdown-item")
  72. )
  73. ),
  74. actionButton("copy_gliph", "Copy Emoji", class = "btn-primary")
  75. )
  76. )
  77. ermoji_server <- function(clipout = clipr::clipr_available()) {
  78. function(input, output, session) {
  79. output$emojis <- DT::renderDataTable({
  80. emojis <- emo::jis
  81. emojis <- emojis[, c('emoji', 'name', "group", "keywords", "aliases")]
  82. emojis$group <- factor(emojis$group)
  83. emojis$keywords <- vapply(emojis$keywords, function(x) paste(x, collapse = ", "), character(1))
  84. emojis$aliases <- vapply(emojis$aliases, function(x) paste(x, collapse = ", "), character(1))
  85. DT::datatable(
  86. emojis,
  87. rownames = FALSE,
  88. colnames = c("Emoji", "Name", "Group", "Keywords", "Aliases"),
  89. filter = "top",
  90. selection = "single",
  91. fillContainer = TRUE,
  92. style = 'bootstrap',
  93. class = 'compact stripe hover',
  94. extensions = c("Scroller"),
  95. options = list(
  96. dom = "<'row'<'col-sm-6 col-sm-offset-2 text-center'f>>tir",
  97. searchHighlight = TRUE,
  98. search = list(regex = TRUE, caseInsensitive = FALSE),
  99. autoWidth = FALSE,
  100. columnDefs = list(
  101. list(
  102. className = "dt-center big", searchable = FALSE, width = "10%", targets = 0
  103. ),
  104. list(width = "20%", targets = c(1, 3, 4)),
  105. list(width = "10%", targets = 2)
  106. ),
  107. deferRender = TRUE,
  108. scrollY = 500,
  109. scroller = TRUE
  110. )
  111. )
  112. })
  113. this_emoji <- reactive({
  114. req(input$emojis_rows_selected)
  115. as.list(emo::jis[input$emojis_rows_selected, ])
  116. })
  117. this_emoji_name <- reactive({
  118. # name <- this_emoji()$name
  119. name <- this_emoji()$aliases[[1]][1]
  120. paste0(":", gsub(" ", "_", name), ":")
  121. })
  122. this_emoji_uni <- reactive({
  123. uni <- paste0("\\U", this_emoji()$runes)
  124. gsub(" ", "\\\\U", uni)
  125. })
  126. this_emoji_html <- reactive({
  127. rune2html(this_emoji()$runes)
  128. })
  129. truncate <- function(x, n = 10) {
  130. if (nchar(x) > n) {
  131. paste0(strtrim(x, n), "...")
  132. } else x
  133. }
  134. observeEvent(input$emojis_rows_selected, {
  135. if (!isTruthy(input$emojis_rows_selected)) {
  136. updateActionButton(session, "copy_name", "Copy :emoji_name:")
  137. updateActionButton(session, "copy_utf", "Copy Unicode")
  138. updateActionButton(session, "copy_html", "Copy HTML")
  139. updateActionButton(session, "copy_gliph", "Copy Emoji")
  140. } else {
  141. updateActionButton(session, "copy_name", paste0("Copy <code>", this_emoji_name(), "</code>"))
  142. updateActionButton(session, "copy_utf", paste("Copy Unicode: <code>", truncate(this_emoji_uni()), "</code>"))
  143. updateActionButton(session, "copy_html", paste("Copy HTML: <code>", escape_html(truncate(this_emoji_html())), "</code>"))
  144. updateActionButton(session, "copy_gliph", paste("Copy", this_emoji()$emoji))
  145. }
  146. })
  147. copy_modal <- function(text) {
  148. showModal(
  149. modalDialog(
  150. title = "Select and Copy",
  151. tags$p("I don't have access to your clipboard. Select the text and", tags$kbd("Ctrl/Cmd"), "+", tags$kbd("c"), "to copy."),
  152. tags$pre(text),
  153. easyClose = TRUE
  154. )
  155. )
  156. }
  157. observeEvent(input$copy_name, {
  158. if (clipout) clipr::write_clip(this_emoji_name()) else copy_modal(this_emoji_name())
  159. })
  160. observeEvent(input$copy_utf, {
  161. if (clipout) clipr::write_clip(this_emoji_uni()) else copy_modal(this_emoji_uni())
  162. })
  163. observeEvent(input$copy_html, {
  164. if (clipout) clipr::write_clip(this_emoji_html()) else copy_modal(this_emoji_html())
  165. })
  166. observeEvent(input$copy_gliph, {
  167. if (clipout) clipr::write_clip(this_emoji()$emoji) else copy_modal(this_emoji()$emoji)
  168. })
  169. observeEvent(input$done, {
  170. stopApp(invisible())
  171. })
  172. observeEvent(input$cancel, {
  173. stopApp(invisible())
  174. })
  175. }
  176. }
  177. escape_html <- function(x) {
  178. x = gsub('&', '&amp;', x)
  179. x = gsub('<', '&lt;', x)
  180. x = gsub('>', '&gt;', x)
  181. x = gsub('"', '&quot;', x)
  182. x
  183. }
  184. #' Convert Emoji to HTML
  185. #'
  186. #' Uses [emo::ji()] to look up emoji, but return the escaped HTML.
  187. #'
  188. #' @param x A search term passed to [emo::ji()] or the result of [emo::ji()].
  189. #' @param copy Should the result be copied to the clipboard?
  190. #' @export
  191. emoji2html <- function(x, copy = clipr::clipr_available()) {
  192. emojis <- emo::jis$runes
  193. names(emojis) <- emo::jis$emoji
  194. if (!inherits(x, "emoji")) {
  195. x <- emo::ji(x)
  196. }
  197. emoji <- emojis[x]
  198. emoji_html <- rune2html(unname(emoji))
  199. if (copy) {
  200. clipr::write_clip(emoji_html)
  201. message(emoji_html, " copied to clipboard")
  202. return(invisible(emoji_html))
  203. }
  204. emoji_html
  205. }
  206. rune2html <- function(runes) {
  207. gsub("([0-9A-F]{4,8}) ?", "&#x\\1;", runes)
  208. }