🤷‍♂️ RStudio Addin to Search and Copy Emoji
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

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. }