---
title: "Understanding the interface to sortable.js"
author: "Andrie de Vries and Kenton Russell"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
description: >
  Understanding the key idea of `sortable.js` will help you to write your own custom sortable widgets.
vignette: >
  %\VignetteIndexEntry{Understanding the interface to sortable.js}
  %\VignetteEngine{knitr::rmarkdown}
  %\usepackage[utf8]{inputenc}
---
```{r, echo = FALSE}
## get knitr just the way we like it
knitr::opts_chunk$set(
  message = FALSE,
  warning = FALSE,
  error = FALSE,
  tidy = FALSE,
  cache = FALSE
)
```
```{css, echo=FALSE}
pre {
  max-height: 20em;
  overflow-y: auto;
}
pre[class] {
  max-height: 20em;
}
```
With the `sortable` [`htmlwidget`](http://www.htmlwidgets.org) you can use powerful, dependency-free interactivity from [`SortableJS`](https://sortablejs.github.io/Sortable/) in the browser, RStudio Viewer, or Shiny apps.
```{r}
library(sortable)
library(htmltools)
```
## The central idea
The key idea to understand about `sortable`, and `SortableJS` in particular, is that the JavaScript will manipulate an HTML object based on it's CSS `id`.
Using `sortable` in markdown is a little tricky since markdown does not provide an easy way to provide an `id` that we'll need.  We can overcome this by using bare `HTML` or using `htmltools::tags`.  Let's make a simple `ul` list.  Note, however, that `sortable` works with nearly any `HTML` element, such as `div`.
### An example using raw HTML
The following example uses HTML to construct an unordered list (`
`), and then uses `sortable_js()` to link the JavaScript required to create interactivity.
Note:
1. The HTML `id` matches the `css_id` argument of `sortable_js()`.
2. You can drag and drop the list entries. Try it!
```html
You can drag and drop these items in any order (try it!):
  - Move
 
  - Or drag
 
  - Each of the items
 
  - To different positions
 
```
````r
```{r}`r ''`
sortable_js(css_id = "example01")
```
````
You can drag and drop these items in any order (try it!):
  - Move
 
  - Or drag
 
  - Each of the items
 
  - To different positions
 
```{r, echo=FALSE}
sortable_js(css_id = "example01")
```
### Use a tag list to achieve the same, but from R
You can use the functions `tags()` and `tagList()`, both from the `htmltools` package, to create HTML.
This means you can construct the sortable list using:
```{r}
library(htmltools)
tagList(
  tags$ul(
    id = "example02",
    tags$li("drag me"),
    tags$li("sort me"),
    tags$li("any way you like")
  ),
  sortable_js("example02")
)
```
### Little harder but better example
The `SortableJS` functionality works with any HTML object, not just lists.
In this next example, you can see how to drag and drop images (`
`).  To embed the plots on the page, you can use the `base64::img()` function to encode the png images into a format that HTML understands.
```{r}
library(base64enc)
library(withr)
# create two plots for demo purposes
pngfile_1 <- tempfile(fileext = ".png")
with_png(pngfile_1, width = 300, height = 200,{
  plot(1:100, rnorm(100), pch = 21, bg = "red")
  title(main = "Moves Like Jagger")
})
pngfile_2 <- tempfile(fileext = ".png")
with_png(pngfile_2, width = 300, height = 200,{
  barplot(1:9, col = blues9)
  title(main = "I Like the Way You Move")
})
```
Again, notice that the HTML `id` matches the `css_id`.
```{r}
tagList(
  tags$div(
    id = "example03",
    tags$image(src = base64enc::dataURI(file = pngfile_1, mime = "image/png")),
    tags$image(src = base64enc::dataURI(file = pngfile_2, mime = "image/png"))
  ),
  sortable_js(css_id = "example03")
)
```
## The power of groups
Looking at the [`SortableJS`](https://github.com/SortableJS/Sortable#options) excites me about the potential to use `sortable` as an important UI element in both a Shiny and non-Shiny context.  We could potentially demo a plot builder with something like this example.  You'll notice that it doesn't really do anything, but I hope the intent and direction is clear.
```{r shiny-drag-vars-to-plot, eval=FALSE}
knitr::read_chunk(
  system.file("shiny-examples/drag_vars_to_plot/app.R", package = "sortable")
)
```

## Dragging and dropping shiny tabs
The `sortable` JS library allows movable tabs inside a Shiny (and also not Shiny) app.  
By adding just one line of code and an `id` to this RStudio 
[Tabset example](https://github.com/rstudio/shiny-examples/tree/master/006-tabsets), 
you get tabs that the user can re-arrange.
You can copy and paste to see it for yourself, or `runGist("2dbe45f77b65e28acab9")`.
The modified code snippet is:
```r
# Show a tabset that includes a plot, summary, and table view
# of the generated distribution
mainPanel(
tabsetPanel(
type = "tabs",
id = "sortTab",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
),
sortable_js("sortTab")
```
And the full code:
```{r echo=FALSE, cache=FALSE}
knitr::read_chunk(
  system.file("shiny-examples/shiny_tabset/app.R", package = "sortable")
)
```
```{r shiny-tabset-app, eval=FALSE}
```
